Skip to content
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
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ cargo run --bin move_box_server
cargo run --bin move_box_client
```

- [`lightyear`]: high-level server-authoritative networking library, using `aeronet` as the underlying IO library

# Overview

## Quickstart
Expand Down Expand Up @@ -127,11 +129,11 @@ cargo run --bin move_box_client
- Allows receiving acknowledgement of sent message acknowledgements
- Technically user-swappable, but most code above this layer relies on [`aeronet_transport`] specifically
- Component replication, rollback, etc.
- This is not provided as part of `aeronet`, but you can use a crate which integrates `aeronet` with one of these e.g. [`aeronet_replicon`]
- This is not provided as part of `aeronet`, but you can use a crate which integrates `aeronet` with one of these e.g. [`aeronet_replicon`], [`lightyear`]

## Writing an IO layer

If none of the first-party or third-party IO layer implementations don't suit your needs, you can write your own IO layer implementation for your needs. `aeronet_io` is designed to be as minimal as possible, to make writing your own IO layers simple, and allow them to integrate with higher levels of the stack seamlessly.
If none of the first-party or third-party IO layer implementations suit your needs, you can write your own IO layer implementation for your needs. `aeronet_io` is designed to be as minimal as possible, to make writing your own IO layers simple, and allow them to integrate with higher levels of the stack seamlessly.

You can use [`aeronet_channel`] as a simple reference implementation of an IO layer - it's [a single file](https://github.com/aecsocket/aeronet/blob/main/crates/aeronet_channel/src/lib.rs). It demonstrates how to poll a channel synchronously from the Bevy event loop, which is useful if your underlying IO layer is not async.

Expand Down Expand Up @@ -177,7 +179,7 @@ Some example tools you may use are:
- Windows
- [`clumsy`](https://github.com/jagt/clumsy)

`aeronet` does not provide support for conditioning within the networking crate itself, since conditioning testing is more effective (and representative of real-world results) when the conditioning is applied at the lowest level possible.
`aeronet` does not provide support for conditioning within the networking crate itself, since conditioning testing is more effective (and representative of real-world results) when the conditioning is applied at the lowest level possible (the OS layer).

# Contributing

Expand Down Expand Up @@ -213,6 +215,7 @@ When submitting a pull request, make sure that all continuous integration (CI) c
[`aeronet_steam`]: https://docs.rs/aeronet_steam
[`aeronet_replicon`]: https://docs.rs/aeronet_replicon
[`bevy_replicon`]: https://docs.rs/bevy_replicon
[`lightyear`]: https://docs.rs/lightyear
[`aeronet_transport`]: https://docs.rs/aeronet_transport
[`Session`]: io::Session
[`echo_client.rs`]: ./examples/src/bin/echo_client.rs
Expand Down
8 changes: 8 additions & 0 deletions crates/aeronet_steam/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ use {
};

/// Allows using [`SteamNetClient`].
///
/// This does not perform Steam initialization when the plugin is built;
/// instead, it defers initialization to when a [`SteamNetClient`] is added
/// to the world. This allows you to always add this plugin, but choose at
/// runtime whether you want to use Steam or not.
pub struct SteamNetClientPlugin<M: SteamManager> {
_phantom: PhantomData<M>,
}
Expand Down Expand Up @@ -86,6 +91,9 @@ impl<M: SteamManager> SteamNetClient<M> {
/// Creates an [`EntityCommand`] to set up a session and connect it to the
/// `target`.
///
/// [`SteamworksClient`] must be present in the world before this command is
/// applied.
///
/// # Examples
///
/// ```
Expand Down
8 changes: 8 additions & 0 deletions crates/aeronet_steam/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ use {
};

/// Allows using [`SteamNetServer`].
///
/// This does not perform Steam initialization when the plugin is built;
/// instead, it defers initialization to when a [`SteamNetServer`] is added
/// to the world. This allows you to always add this plugin, but choose at
/// runtime whether you want to use Steam or not.
pub struct SteamNetServerPlugin<M: SteamManager> {
_phantom: PhantomData<M>,
}
Expand Down Expand Up @@ -123,6 +128,9 @@ impl<M: SteamManager> SteamNetServer<M> {
/// Creates an [`EntityCommand`] to set up a server and have it start
/// listening for connections.
///
/// [`SteamworksClient`] must be present in the world before this command is
/// applied.
///
/// # Examples
///
/// ```
Expand Down
63 changes: 46 additions & 17 deletions crates/aeronet_steam/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,21 @@ impl<M: SteamManager> Plugin for SteamNetSessionPlugin<M> {
app.add_plugins(AeronetIoPlugin);
}

let steam = app.world().resource::<SteamworksClient<M>>();
// https://github.com/cBournhonesque/lightyear/issues/243
steam
.networking_sockets()
.init_authentication()
.expect("failed to initialize steamworks authentication");
// We don't do Steam init like `init_authentication` or poll groups here
// because this plugin just adds the *capability* of using Steam IO,
// but we don't know for sure at runtime if we'll be using Steam here.
// We leave that up to the user: if they decide to spawn an entity with
// a `SteamNetIo`, only *then* do we do Steam init (and thus assume that
// a Steam client is running on the user's machine).

let poll_group = steam.networking_sockets().create_poll_group();
app.insert_resource(PollGroup(poll_group))
.add_systems(
PreUpdate,
(poll_io::<M>, poll_messages::<M>).in_set(IoSet::Poll),
)
.add_systems(PostUpdate, flush::<M>.in_set(IoSet::Flush))
.add_observer(add_connection_to_poll_group::<M>);
app.add_systems(
PreUpdate,
(poll_io::<M>, poll_messages::<M>)
.in_set(IoSet::Poll)
.run_if(resource_exists::<PollGroup<M>>),
)
.add_systems(PostUpdate, flush::<M>.in_set(IoSet::Flush))
.add_observer(init_io::<M>);
}
}

Expand Down Expand Up @@ -96,16 +96,45 @@ pub enum SessionError {
#[derive(Deref, DerefMut, Resource)]
struct PollGroup<M>(NetPollGroup<M>);

fn add_connection_to_poll_group<M: SteamManager>(
fn init_io<M: SteamManager>(
trigger: Trigger<OnAdd, SteamNetIo<M>>,
steam: Option<Res<SteamworksClient<M>>>,
io: Query<&SteamNetIo<M>>,
poll_group: Res<PollGroup<M>>,
poll_group: Option<Res<PollGroup<M>>>,
mut commands: Commands,
) {
let steam = steam.unwrap_or_else(|| {
panic!(
"`{}` must be present before creating a Steam IO layer",
type_name::<Res<SteamworksClient<M>>>()
)
});

let entity = trigger.target();
let io = io
.get(entity)
.expect("we are adding this component to this entity");
io.conn.set_poll_group(&poll_group);

if let Some(poll_group) = poll_group {
io.conn.set_poll_group(&poll_group);
} else {
// we combine 2 steps into one "global steam init" step:
// - init authentication
// - create poll group
//
// this means that if the poll group is removed, we re-init authentication
// but this should be fine, I think

// https://github.com/cBournhonesque/lightyear/issues/243
steam
.networking_sockets()
.init_authentication()
.expect("failed to initialize steamworks authentication");

let poll_group = steam.networking_sockets().create_poll_group();
io.conn.set_poll_group(&poll_group);
commands.insert_resource(PollGroup(poll_group));
}
}

fn poll_io<M: SteamManager>(
Expand Down
6 changes: 1 addition & 5 deletions crates/aeronet_transport/src/rtt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,7 @@ impl RttEstimator {
self.latest = rtt;
self.min = self.min.min(rtt);

let var_sample = if self.smoothed > rtt {
self.smoothed - rtt
} else {
rtt - self.smoothed
};
let var_sample = self.smoothed.abs_diff(rtt);
self.var = (3 * self.var + var_sample) / 4;
self.smoothed = (7 * self.smoothed + rtt) / 8;
}
Expand Down
4 changes: 2 additions & 2 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# 0.15

- Add documentation to `aeronet::_doc` module, accessible in `docs.rs`
- Move changelog to `aeronet::_doc`
- Add documentation to `aeronet::_docs` module, accessible in `docs.rs`
- Move changelog to `aeronet::_docs`
- Update to `bevy_replicon 0.34.0`

# 0.14.0
Expand Down