Skip to content

Releases: cBournhonesque/lightyear

Release 0.22.0

20 Jul 02:11
Compare
Choose a tag to compare

Release 0.22.0

Upgraded rollback detection

Previously there was only one way we could rollback: if we received a new state update on the Confirmed entity which did not match the prediction history.
Now we have separate a RollbackMode for state replication and input replication; the possible values are Always (rollback whenever we get a new state or input), Check (rollback whenever we get a new state that doesn't match the predicted history, or a new input that doesn't match the input history), Never.

The Always mode can be useful to force trigger rollbacks and to check if your game can handle a certain amount of rollbacks.

But the main benefit is that this change allows for deterministic replication; a networking model where only inputs are replicated (instead of state).

Deterministic Replication

Lightyear now supports deterministic replication! In this mode you can choose to replicate only inputs; each client should receive the inputs from all other clients and use that to deterministically simulate the game.
The API is extremely similar to state replication: instead of Predicted you need to add the DeterministicPredicted component!

By adjusting the InputDelayConfig you can decide the level of prediction that is applied:

  • InputDelayConfig::no_prediction: there is no prediction so the clients will progress in lockstep. NOTE: there currently is no check that for a given tick we have received all the inputs from all clients!
  • with input delay: the local client will predict all other clients' actions

A new example has been added that illustrates those 2 modes.

Note that you can also do a mix between state replication and input replication!

Rollback overhaul + bug fixes

The rollback logic has been overhauled, in particular the logic that was handling the smooth correction from the previously predicted value to the new corrected value. Thanks to the help of @maniwani for that!

I've also fixed a big number of subtle bugs related to rollback, timeline syncs and input buffers.
The result is that rollbacks are now MUCH smoother, as you can check yourself by running the deterministic_replication, avian_physics or avian_3d_character examples. This is a huge upgrade that I am extremely happy about.

Support for immutable components / deprecation of RelationshipSync

It is now possible to use immutable components in the protocol; you will have to use add_immutable_prediction instead of add_prediction, and they are not compatible with PredictionMode::Full.
With this change, the RelationshipSync plugins are not needed anymore.
To replicate Relationships you can just add them directly to your protocol, like so: app.register_component::<R>()

What's Changed

New Contributors

Full Changelog: 0.21.0...0.22.0

Release 0.21.0

04 Jul 01:43
86bf851
Compare
Choose a tag to compare

Lightyear 0.21.0

Multiple crates

This is a massive release that is basically a full rewrite of the crate. In particular, the crate has been split into multiple subcrates, for the following reasons:

  • faster compile times
  • more modularity by splitting up small pieces into different crates
  • encourages a better separation of concerns

This was definitely challenging but I think it's for the better.
Similarly to bevy, you will have lightyear_* subcrates and a main lightyear crate which imports every subcrate.
It is possible to use the subcrates directly if you want, as the main crate just imports the relevant plugins from the subcrates.

From Resources to Entities

Instead of managing the networking behaviour via a set of Resources (ClientConfig, ClientConnectionManager, etc.), we now switch to a model where you have one entity per network connection between the local peer and the remote peer. (this approach was pioneered by
aeronet)

  • at the transport layer (how to send/remove bytes):

    • you can add one of the IO components (UdpIO, WebTransportIO, etc.) to specify how you will send or receive bytes from the remote peer
    • the IO-agnostic Link component is used to abstract away from the actual io
    • you can access metadata about the io link using the LocalAddr and PeerAddr components
    • the state of the link can be accessed via various marker components (Linked, Unlinked)
    • the Transport component can be added to specify various channels that provide different reliability and ordering guarantees
    • the MessageSender<M> and MessageReceiver<M> components can be added to add the ability to send and receive structs instead of raw bytes. The MessageManager is responsible for handling the serialization and the entity mapping
  • at the connection layer (how to establish a persistent connection on top of the raw io):

    • you can add the Client or Server component to specify the role of the entity. In particular, the Server component will listen for incoming connections and spawn new ClientOf entities for each connected client
    • the state of the connection can be accessed via various marker components (Connected, Disconnected, Started, Stopped)
    • the NetcodeClient or NetcodeServer components can be added to use netcode as the layer providing authentication + persistent IDs on top of the raw IO
  • at the syncing layer (how to make sure that the local and remote peers are in sync)

    • there is now a new Timeline component that is used to represent the various networking timelines:
      • the LocalTimeline simply increments the tick whenever the FixedUpdate schedule runs
      • the RemoteTimeline is the local peer's best estimate of the remote peer's timeline; computed from the received packets. This is used to make sure that all the timelines remain in sync with the remote peer
      • the InterpolationTimeline is in the past compared to the Remote, and is used to define how to interpolate between the received remote packets
      • the InputTimeline is in the future to the Remote, and is used to define when ticks should be buffered
  • at the input layer (how do the clients send inputs to the server)

    • the ActionState component defines the current state of the inputs at the current tick. It is guaranteed to be the same between client and server for a given tick
    • the InputBuffer component can be used to access the received inputs that were locally buffered
    • lightyear now has a shared generic inputs plugin that makes sure input-handling is correct with rollback, input_delay, rebroadcasting to other clients, etc. There are 3 implementations: native, leafwing, and bevy-enhanced-input
  • at the replication layer (how to replicate the state of the World to the remote)

    • you can add the ReplicationSender and ReplicationReceiver components to specify if you want the peer to be part of replication
    • the PredictionManager and InterpolationManager mark a link entity as having prediction/interpolation enabled

The bevy ECS provides a lot of flexibility: you can add or remove these components from a subset of the peers to change their networking configuration. Usually if you make changes, they will be applied on the next connection attempt.
This change was mostly made possibly with the recent ECS innovations: observers and relationships.

Moving away from Client-Server

Lightyear was strongly tied to the concepts of client and server. You had to use some specialized client or server resources (ClientManager and ServerManager) and those would have very similar code that varied in subtle ways. For example the replication code was essentially duplicated between them, apart from some server-specific code.

With the new component-based approach, the code has become fairly agnostic to the roles of client and servers.
For example there is now a unique replication system that works on any entity that has a ReplicationSender component, so each local peer can replicate to a remote peer in the exact same way!

I think this is super exciting as this opens the door to handling P2P topology with code that is very similar to client-server topologies!

Total parity?

This refactor of the crate doesn't achieve total parity with the previous version. Some of the functionality that hasn't been ported is:

  • Resource replication: I believe bevy is moving towards resource-as-entities, where resources are simply components stored on an entity. I will just be waiting for this to be merged before re-adding resource replication
  • input broadcasting: we previously had convenience functions so that a client could send a message to another client (the message would be sent to the server, who would broadcast it to the correct client). This hasn't been re-added yet
  • authority: the handling of authority is still somewhat in flux, I have made steps towards it but it hasn't been properly tested, and the distributed_authority example is still outdated.

Extras

  • Instead of maintaining my own steam, webtransport, websocket io layers, I now defer to the excellent aeronet crate!

  • Special thanks to @hukasu for helping me improve the compile time of lightyear!

Next steps

With the increased flexibility and modularity, I would like to tackle:

  • handling networking modes where only inputs are replicated, such as deterministic lockstep! I believe this should now be very much within reach, as it mostly involves adding a LockstepTimeline to define how the local and remote peers stay in sync
  • handling P2P topologies

What's Changed

Read more

0.20.2

10 May 10:26
743beb3
Compare
Choose a tag to compare
  • Upgrade avian to 0.3
  • Fix wasm support

What's Changed

Full Changelog: 0.20.1...0.20.2

Release 0.20.1

07 May 15:00
c509cc0
Compare
Choose a tag to compare
  • Upgrade bevy-metrics-dashboard to 0.7.0
  • Includes an important replication fix

What's Changed

Full Changelog: 0.20.0...0.20.1

Release 0.20.0

05 May 23:21
Compare
Choose a tag to compare

0.20.0

Replication using required components

The Replicate bundles will be deprecated in the next version. Instead you can add the ReplicateToServer and ReplicateToClient which will insert any other required replication components (ReplicationGroup, Replicating, etc.) on the entity.

Batch replication support

Replicated components are now inserted on the replicated entity all at once; this guarantees that observers that rely on the presence of multiple of these components work correctly.
The same guarantee is also applied to components that are inserted on the Predicted or Interpolated entity, so observers like:

fn observer(
  trigger: Trigger<OnAdd, Player>,
  query: Query<&Color, With<Predicted>>
)

will work correctly because the components Player and Color are inserted at the same time on the replicated entity.

No std support

Following bevy's lead, lightyear now compiles without std! Note that all available transports (udp, webtransport, etc.) still require std as of now.

Simplified hierarchy replication

Hierarchy replication has been improved. The ReplicateHierarchy has been removed and replaced by the ReplicateLike component. You can insert ReplicateLike on any entity to specify that it should be replicated using the same settings as another entity. All the replication settings from the 'parent' entity will be conserved, including network visibility, disabled components, replication frequency, etc.
ReplicateLike will now be inserted by default on any child of a replicated entity. This can be prevented by inserting DisableReplicateHierarchy on the children entities.

Relationship replication

You can add the RelationshipSync<R> component on an entity to replicate the relationship R component.

What's Changed

New Contributors

Full Changelog: v0.19.1...0.20.0

Release 0.19.0

28 Jan 01:58
Compare
Choose a tag to compare

0.19.0

Visualizer

The visualizer features uses the excellent bevy_metrics_dashboard to display graphs for every metrics registered in lightyear. There are metrics related to rollbacks, replication, messages, latency, etc. which can be used to more easily inspect what lightyear is doing.

image

Lag Compensation

Lag compensation is the notion of the server 'rewinding time' to process certain user actions like bullets fired, so that client actions in the predictive timeline can impact replicated entities in the interpolated timeline. This is usually used in FPS games.
The fps example (previously bullet_prespawn) showcases how to enable lag compensation for hit detection.

Screen.Recording.2025-01-27.at.5.49.39.PM.mov

In this example, the red player and the blue enemy are predicted, and the green enemy is interpolated.
Bullets are pre-spawned on the client directly in the predicted timeline so they can interact normally with the blue predicted enemy.
To handle collisions with the green enemy we have to use the new LagCompensationPlugin. You can see that the server maintains a history (white bounding box) of the past positions of the green enemy to perform lag compensation (rewind time when computing the collision).

Bug fixes

  • Variable input delay had been added but didn't work correctly in some situations. This should now be fixed.
  • DeltaCompression, where replication updates are sent as a diff from a previous update, should now work in all situations
  • Fixed a lot of cases that were causing extra rollbacks, especially related to PrePrediction and PreSpawning
  • Fixed bugs related to transferring authority between client and server (in particular using prediction/interpolation in combination with authority transfer)
  • Fixed some edge cases related to visibility management via the Room api
  • Fixed issues related to hierarchy, in particular the Confirmed hierarchy is now correctly synced to the Predicted/Interpolated entities

What's Changed

Read more

Release 0.18.0

22 Dec 05:47
56afd9e
Compare
Choose a tag to compare

Release 0.18.0

  • Upgrades lightyear to be compatible with the latest versions of bevy, leafwing-input-manager, and edgegap
  • Provide support to rollback Resources thanks to @nick-e!
  • Various bug fixes
  • Paves the way to a deeper integration with @RJ 's bevygap, which is a framework to easily deploy Bevy apps on Edgegap, a multiplayer game server hosting service. In particular @RJ is hosting some of the lightyear examples on https://rj.github.io/lightyear!

What's Changed

New Contributors

Full Changelog: 0.17.0...0.18.0

Release 0.17.0

17 Aug 15:55
a4f0a20
Compare
Choose a tag to compare

Release 0.17.0

Upgrade to leafwing 0.15

Leafwing's newest version brings some improvements to the API, but also fixes an important bug where you couldn't use JustPressed and JustReleased in the FixedUpdate schedule. That was problematic since networking usually requires inputs to be handled in the FixedUpdate schedule. With this fix it is now much easier to use leafwing-inputs with lightyear.

Added rollback for non-networked components

Previously, only components that were registered in the ComponentRegistry (meaning that they can be networked) could be affected by rollback. However there's plenty of cases where you might want to rollback non-networked client components: for example rolling back animations or sounds. You can now call app.add_rollback::<C>() to enable rollback for a non-networked component.

Seamless entity mapping

Previously, entity-mapping was only done on the receiver. (i.e. server spawns E1, sends it to the client who spawns E2 and maintains a mapping from E1 to E2). The mapping wasn't applied when sending messages/updates, which meant that the client had to map the entity manually from E2 to E1 if they wanted to send a message about E2. Entity mapping is now correctly applied in all directions.

Introducing authority transfer

Lightyear now has the concept of Authority: which peer (client or server) is simulating the entity and sending replication updates for it? Only one peer can have authority over an entity at any given time.

The server can freely transfer authority over an entity to other peers with the EntityCommands::transfer_authority(new_owner) command.
The Replicate bundles automatically provide you with authority over the entity; make sure to remember to update them if you're just adding Replicate on the server to re-broadcast a client-authoritative entity to other clients.

You can find an example with authority transfer here.

Important fixes

  • Guarantee that inputs get synced correctly even in low bandwidth situations. PR

What's Changed

New Contributors

Full Changelog: 0.16.4...0.17.0

0.16.4

02 Aug 20:44
Compare
Choose a tag to compare

What's Changed

Full Changelog: 0.16.3...0.16.4

Release 0.16.0

08 Jul 01:48
61809eb
Compare
Choose a tag to compare

Release 0.16.0

Added

Support for Steam P2P

Thanks to a PR from @msvbg , it is now possible to connect to a client acting as host-server by using Steam P2P sockets

The network_send_interval is now configurable with more precision

Previously you only had access to 2 settings:

  • client_send_interval
  • server_send_interval
    which would control how often the client or the server sent packets to the remote.

Now the send_interval is configurable:

  • per ReplicationGroup (if you want to update an entity less frequently)
  • per Channel

This gives you more flexibility to control how often you want to send messages/packets.
For example, you can send replication updates every 100ms, but send client inputs every frame if available. (this setup is particularly useful if you want to predict other player's inputs, a la RocketLeague)

@RJ added an example with remote player prediction

Added better support for handling remote player inputs. Now inputs from other players can easily be forwarded to a given player so that they can run client-prediction on all entities (the local player entity and the remote player entities)
@RJ created an awesome example spaceships showcasing how to achieve something like this.

It uses input delay, remote player prediction, physics via xpbd, etc.

Updated the InputDelay/Prediction settings [EXPERIMENTAL]

Previously you could only set a fixed amount of input delay (for example 3 ticks).
Now the input delay depends on your network conditions: the settings are identical to what is described here.

Note that this feature is still being tested and might not work if the network conditions are varying.

Miscellaneous

  • Some common bevy RunConditions are now provided, such as is_started, is_disconnected, is_host_server, etc.
  • The serialization logic now uses bincode instead of bitcode. You can provide your own serialization function instead of bincode.
  • lightyear doesn't use anyhow anymore, instead functions now return typed errors such as ReplicationError, SerializationError, etc.
  • Extra diagnostics are provided, such as PingDiagnostics to track the jitter/RTT, or RollbackDiagnostics to track the number of rollbacks

Fixed

  • lightyear can now work properly when running on wasm even if the tab is put in the background! Thanks to https://github.com/Nul-led/bevy_web_keepalive/tree/main from @Nul-led
  • Tons of bugfixes for replication edge cases
  • Input handling has been refactored to be more robust and more independent from world replication. In particular inputs can be replicated every tick even if the world replication is less frequent

Breaking changes

  • The serialization logic now uses bincode instead of bitcode
  • The Controlled component now has an extra field lifetime that specified how to despawn the entity if the controlling client is disconnected
  • Visibility has been renamed to NetworkRelevance to avoid a name conflict with bevy's Visibility
  • The DisconnectEvent now returns a DisconnectReason explaining why the client was disconnected
  • The PredictionConfig, ReplicationConfig, SharedConfig now contain additional fields

What's Changed

Read more