Skip to content
This repository has been archived by the owner on Dec 19, 2024. It is now read-only.

Improved documentation (core 0.4.2) #27

Merged
merged 10 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions LICENSE-MIT
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
MIT License

Copyright (c) 2023 Veritius

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
Expand Down
119 changes: 117 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ You can use any transport layer you want. Use UDP, TCP, QUIC, HTTP, some homebre

You can use any replication or extra features you want. If you prefer a specific crate for replication, it's really easy to integrate it into Stardust, as long as it has some kind of API for taking in and outputting bytes.

## Planned features
## Planned extensions
The following features are planned to be created as additional crates, as part of the overall project.

- Replication plugin
Expand All @@ -36,4 +36,119 @@ The following features are planned to be created as additional crates, as part o
| ---- | -------- |
| 0.13 | 0.4 |
| 0.12 | 0.2 |
| 0.11 | 0.1 |
| 0.11 | 0.1 |

<br>

`bevy_stardust` is the core 'interface' crate. It provides everything you need to write netcode, but doesn't deal with Internet communication or things like replication - that's left up to other crates.


**A simple example project:**
```rust
// This example assumes that you don't have the reflect feature flag.
// If you do, make sure your channel types implement TypePath.
// Additionally, spawning NetworkPeer entities is handled by transport layer plugins.
// For the purpose of this example, we'll assume they magically appeared somehow.

use std::any::TypeId;
use bevy_ecs::prelude::*;
use bevy_app::{prelude::*, ScheduleRunnerPlugin, MainSchedulePlugin};
use bevy_stardust::prelude::*;

// Channels are accessed with types in the type system.
// Simply put, you just need to create simple types like this.
// You can use Rust's privacy system to control channel access.
struct MyChannel;

fn main() {
let mut app = App::new();

// At the very least, Stardust needs the MainSchedulePlugin to work.
app.add_plugins((
ScheduleRunnerPlugin::default(),
StardustPlugin,
));

// Each channel needs to be added (or 'registered') to the app.
// Once you do this, it becomes visible in the ChannelRegistry.
// The ChannelRegistry is effectively a giant table of every registered channel.
app.add_channel::<MyChannel>(ChannelConfiguration {
// 'Reliable' messages will be detected if lost.
reliable: ReliabilityGuarantee::Reliable,

// 'Ordered' messages will be received in the same order they're sent.
ordered: OrderingGuarantee::Ordered,

// 'Fragmentable' messages will be broken up for transmission if need be.
// This is actually just a flag to say that the messages *might* need to be fragmented.
// Whether or not things are fragmented is up to the transport layer.
fragmented: true,

// Higher priority messages will be sent before others.
priority: 0,
});

// Any transport layers should be added after you register all channels.
// This is just a rule of thumb, though, some might not need to be.
// Make sure to check the relevant documentation.

// Your systems can be added at any point, but we'll do them here.
// Also see the scheduling types in the scheduling module for advanced usage.
// Most of the time, you just need to put things in the update schedule.
// Also, note that since these systems have disjoint accesses, they run in parallel.
app.add_systems(Update, (send_words_system, read_words_system));
}

// Messages use the Bytes type.
// This is cheaply clonable and you can send the same message to multiple peers.
// For this example, we create one from the bytes of a static str.
const MESSAGE: Bytes = Bytes::from_static("Hello, world!".as_bytes());

// Queueing messages just requires component access.
// This means you can use query filters to achieve better parallelism.
fn send_words_system(
registry: ChannelRegistry,
mut query: Query<(Entity, &mut NetworkMessages<Outgoing>), With<NetworkPeer>>
) {
// The ChannelId must be retrieved from the registry.
// These are more friendly to store since they're just numbers.
// You can cache them if you want, as long as they aren't used in different Worlds.
let channel = registry.channel_id(TypeId::of::<MyChannel>()).unwrap();

// You can also iterate in parallel, if you have a lot of things.
for (entity, mut outgoing) in query.iter_mut() {
// Bytes objects are cheaply clonable, reference counted storages.
// You can send them to as many peers as you want once created.
outgoing.push(channel, MESSAGE);
println!("Sent a message to {entity:?}");
}
}

// Reading messages also just requires component accesses.
// The reading queue is a different component from the sending queue.
// This means you can read and send bytes in parallel, or in different systems.
fn read_words_system(
registry: ChannelRegistry,
query: Query<(Entity, &NetworkMessages<Incoming>), With<NetworkPeer>>
) {
let channel = registry.channel_id(TypeId::of::<MyChannel>()).unwrap();
for (entity, incoming) in query.iter() {
let messages = incoming.channel_queue(channel);
for message in messages.iter() {
// Stardust only outputs bytes, so you need to convert to the desired type.
// Also, in real products, don't unwrap, write checks. Never trust user data.
let string = std::str::from_utf8(&*message).unwrap();
println!("Received a message from {entity:?}: {string:?}");
}
}
}
```

## License
bevy_stardust is free and open source software. It's licensed under:
* MIT License ([LICENSE-MIT](LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT))
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0))

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
6 changes: 0 additions & 6 deletions docs/book.toml

This file was deleted.

6 changes: 0 additions & 6 deletions docs/src/SUMMARY.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/src/guide/channels.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/src/guide/introduction.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/src/guide/plugins.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/src/guide/scheduling.md

This file was deleted.

2 changes: 1 addition & 1 deletion stardust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name="bevy_stardust"
version="0.4.1"
version="0.4.2"
edition="2021"
authors=["Veritius <veritiusgaming@gmail.com>"]
readme="../README.md"
Expand Down
16 changes: 11 additions & 5 deletions stardust/src/channels/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ impl StableHash for &ChannelConfiguration {
/// The reliability guarantee of a channel.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReliabilityGuarantee {
/// If a message is lost, it's lost. There will be no attempt to get it back.
/// Messages are not guaranteed to arrive.
Unreliable,
/// If a message is lost, it will be resent. This incurs some overhead.

/// Lost messages will be detected and resent.
Reliable,
}

Expand All @@ -55,11 +56,16 @@ impl StableHash for ReliabilityGuarantee {
/// The ordering guarantee of a channel.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OrderingGuarantee {
/// Messages will be read in the order they are received.
/// Messages will be available in the order they are received.
/// This is not necessarily the order they were sent. If that matters, use a different variant.
Unordered,
/// Messages that are out of order will be discarded.

/// Messages that are older than the most recent value will be discarded.
/// Therefore, messages will be available in order, but out of order messages are lost.
Sequenced,
/// Messages will be reordered to be in the order they were sent.

/// Messages will be available in the exact order they were sent.
/// If [reliability](ReliabilityGuarantee::Reliable) is used, this can 'block' messages temporarily due to data loss.
Ordered,
}

Expand Down
2 changes: 1 addition & 1 deletion stardust/src/channels/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod sealed {

/// Adds channel-related functions to the `App`.
pub trait ChannelSetupAppExt: sealed::Sealed {
/// Registers a channel with type `T` and the config and components given.
/// Registers a channel with type `C` and the config and components given.
fn add_channel<C: Channel>(&mut self, config: ChannelConfiguration);
}

Expand Down
11 changes: 1 addition & 10 deletions stardust/src/channels/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,7 @@
//! reliable: ReliabilityGuarantee::Unreliable,
//! ordered: OrderingGuarantee::Unordered,
//! fragmented: false,
//! string_size: ..=16,
//! });
//!
//! app.add_systems(PostUpdate, |mut events: EventReader<MovementEvent>, mut writer: NetworkWriter<MovementEvent>| {
//! let target = Entity::PLACEHOLDER;
//! for event in events.read() {
//! // Serialisation logic goes here.
//! let bytes = Bytes::from("Hello, world!");
//! writer.send(target, bytes);
//! }
//! priority: 0,
//! });
//! }
//! ```
Expand Down
37 changes: 20 additions & 17 deletions stardust/src/connections/peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@
use std::time::Instant;
use bevy_ecs::prelude::*;

/// Another peer that this peer is aware of, representing someone else over the Internet.
/// An active connection to a remote peer.
///
/// - If you're writing server-side code, you can think of this as a client.
/// - If you're writing client-side code, you can think of this as the server.
/// - If you're writing peer-to-peer code, you can think of this as another peer in the mesh.
/// The term 'peer' is used interchangeably for any kind of connection to another instance of the application.
/// If you're writing a star-topology system, you can treat these as servers and clients.
/// If you're writing a mesh-topology system, you can treat these as another peer in the mesh.
///
/// `NetworkPeer`s don't have any associated transport layer information by themselves.
/// However, they are always treated as an entity that stores information related to the network.
/// You shouldn't create, mutate, or delete this component unless you know what you're doing.
/// Managing these entities should be (and usually is) done by the transport layer.
/// The `NetworkPeer` component is intended to be queried freely, but not created by the developer.
/// Instead, it should be managed by transport layer plugins.
///
/// Entities with `NetworkPeer` have their entity IDs used in the writing and reading APIs.
/// They are used as the 'target' of messages, and the transport layer will handle the actual sending and receiving.
/// Entities with this component may also have the following components:
/// - [`NetworkMessages`](crate::messages::NetworkMessages), relating to messages
/// - [`NetworkPeerUid`], relating to persistent data
/// - [`NetworkPeerLifestage`], relating to connection state
/// - [`SecurityLevel`](super::security::SecurityLevel), relating to encryption
#[derive(Debug, Component)]
#[cfg_attr(feature="reflect", derive(bevy_reflect::Reflect))]
pub struct NetworkPeer {
Expand Down Expand Up @@ -66,6 +67,7 @@ impl NetworkPeer {
#[non_exhaustive]
pub enum NetworkPeerLifestage {
/// Midway through a [handshake].
/// Messages sent to peers in this stage will likely be ignored.
///
/// [handshake]: https://en.wikipedia.org/wiki/Handshake_(computing)
Handshaking,
Expand All @@ -85,23 +87,24 @@ pub enum NetworkPeerLifestage {
/// A unique identifier for a [`NetworkPeer`], to store persistent data across multiple connections.
/// This component should only be constructed by the app developer, but can be read by any plugins.
///
/// This value is intended only for use within memory and local databases, like savegames.
/// If you need to share a unique player identifier, use UUIDs.
///
/// If you're working with another ID namespace, like UUIDs and Steam IDs, you should
/// map the ids from that space into a unique value here through some kind of associative array.
///
/// The `Display` implementation will display the internal integer in hexadecimal.
#[derive(Debug, Component, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Component, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature="reflect", derive(bevy_reflect::Reflect))]
pub struct NetworkPeerUid(pub u64);

impl std::fmt::Display for NetworkPeerUid {
impl std::fmt::Debug for NetworkPeerUid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{:X}", self.0))
}
}

impl std::fmt::Display for NetworkPeerUid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<Self as std::fmt::Debug>::fmt(self, f)
}
}

impl From<u64> for NetworkPeerUid {
#[inline]
fn from(value: u64) -> Self {
Expand Down
4 changes: 1 addition & 3 deletions stardust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
//! # bevy_stardust
//! A networking crate for the Bevy game engine.

#![doc = include_str!("../../README.md")]
#![warn(missing_docs)]

pub mod channels;
Expand Down
8 changes: 4 additions & 4 deletions stardust/src/messages/direction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ pub enum Direction {
/// The direction a message is going, as a trait for use in the type system.
///
/// Implemented by:
/// - [Outgoing], corresponding to [Direction::Outgoing]
/// - [Incoming], corresponding to [Direction::Incoming]
/// - [`Outgoing`], corresponding to [`Direction::Outgoing`]
/// - [`Incoming`], corresponding to [`Direction::Incoming`]
#[cfg(not(feature="reflect"))]
pub trait DirectionType: Debug + Send + Sync + Any + sealed::Sealed {
/// Returns the corresponding [`Direction`].
Expand All @@ -24,8 +24,8 @@ pub trait DirectionType: Debug + Send + Sync + Any + sealed::Sealed {
/// The direction a message is going, as a trait for use in the type system.
///
/// Implemented by:
/// - [Outgoing], corresponding to [Direction::Outgoing]
/// - [Incoming], corresponding to [Direction::Incoming]
/// - [`Outgoing`], corresponding to [`Direction::Outgoing`]
/// - [`Incoming`], corresponding to [`Direction::Incoming`]
#[cfg(feature="reflect")]
pub trait DirectionType: Debug + Send + Sync + Any + bevy_reflect::Reflect + sealed::Sealed {
/// Returns the corresponding [`Direction`].
Expand Down
12 changes: 6 additions & 6 deletions stardust/src/scheduling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
use bevy_ecs::prelude::*;
use bevy_app::prelude::*;

/// Systems dealing with incoming octet strings. Run in the `PreUpdate` schedule.
/// Systems dealing with receiving messages. Run in the [`PreUpdate`] schedule.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, SystemSet)]
pub enum NetworkRead {
/// Transport layers receive packets from the OS.
/// Transport layers receive packets or other transmission media.
Receive,
/// Game systems process octet strings and mutate the World before [Update].
/// You can still read octet strings at any time, not just in this component.
/// Game systems process messages and mutate the World before [`Update`].
/// You can still read messages at any time before [`Receive`](NetworkRead::Receive).
Read,
}

/// Systems dealing with outgoing octet strings. Run in the `PostUpdate` schedule.
/// Systems dealing with outgoing octet strings. Run in the [`PostUpdate`] schedule.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, SystemSet)]
pub enum NetworkWrite {
/// Transport layers send packets written by game systems.
/// Transport layers send messages queued by game systems.
Send,
/// Queued messages (both the incoming and outgoing buffers) are cleared.
Clear,
Expand Down
Loading