A networking library to make multiplayer games for the Bevy game engine
APACHE-2.0 License
Bot releases are visible (Hide)
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.
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.
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.
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.
Commands
instead of World
to apply replication updates by @cBournhonesque in https://github.com/cBournhonesque/lightyear/pull/581
Full Changelog: https://github.com/cBournhonesque/lightyear/compare/0.16.4...0.17.0
Published by cBournhonesque 3 months ago
Full Changelog: https://github.com/cBournhonesque/lightyear/compare/0.16.3...0.16.4
Published by cBournhonesque 4 months ago
Thanks to a PR from @msvbg , it is now possible to connect to a client acting as host-server by using Steam P2P sockets
network_send_interval
is now configurable with more precisionPreviously you only had access to 2 settings:
Now the send_interval
is configurable:
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)
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.
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.
RunConditions
are now provided, such as is_started
, is_disconnected
, is_host_server
, etc.bincode
instead of bitcode
. You can provide your own serialization function instead of bincode.anyhow
anymore, instead functions now return typed errors such as ReplicationError
, SerializationError
, etc.PingDiagnostics
to track the jitter/RTT, or RollbackDiagnostics
to track the number of rollbacksbincode
instead of bitcode
Controlled
component now has an extra field lifetime
that specified how to despawn the entity if the controlling client is disconnectedVisibility
has been renamed to NetworkRelevance
to avoid a name conflict with bevy's Visibility
DisconnectEvent
now returns a DisconnectReason
explaining why the client was disconnectedPredictionConfig
, ReplicationConfig
, SharedConfig
now contain additional fieldssend_interval
per Channel instead of globally by @cBournhonesque in https://github.com/cBournhonesque/lightyear/pull/466
Full Changelog: https://github.com/cBournhonesque/lightyear/compare/0.15.1...0.16.0
Published by cBournhonesque 5 months ago
Replicate
used to be a Component
describing all facets of how an entity should be replicated to a remote peer.
It is now a bundle composed of multiple smaller components:
ReplicationTarget
: which clients should receive the entitySyncTarget
: which clients should predict/interpolate the entityVisibilityMode
: do we use interest management or notControlledBy
: which clients are the 'owners' of the entity?ReplicateToServer
: marker component to initiate the replication to the serverReplicating
: marker component indicating that the entity should be actively replicated. If this component is removed, the replication is paused.ReplicateHierarchy
: whether we replicate the children of this entity or notReplicationGroup
: how do we group multiple entities into a single messageOn the receiver side, all replicated entities will have the Replicated
component.
For client->server replication, you can use Replicated::client_id()
to identify the client that replicated this entity.
You can also customize the replication of a specific component via the components:
DisabledComponent<C>
: the component is not replicated at allReplicateOnce<C>
: the component's insertion/removal are replicated, but no the updatesOverrideTargetComponent<C>
: override the replication target (the list of receiving clients) for this componentIt can be useful for the server to be aware of which client is 'owning' an entity.
For example, so that you can despawn all of a client's entities when the client disconnects.
You can add the ControlledBy
component on an entity in the server World to specify which clients 'own' the entity.
When this entity gets replicated, the owning clients will have the Controlled
marker component added.
This can be useful for the client to identify the entities it should apply client-side prediction on. (usually client-prediction is used only on the entities owned by the client)
When a client disconnects, lightyear automatically despawns the entities owned by that client. (this will be more configurable in the future).
How can you access this per-client metadata on the server? We now spawn one entity per client on the server, which can be used to hold metadata about that client. The entity can be accessed via ConnectionManager::client_entity(client_id)
.
For now, the only metadata has ControlledEntities
component which holds a list of all the entities controlled by a client; feel free to add more if you need!
Before, you could only add the Replicate
component once; it was not allowed to update the Replicate
component after the entity was first replicated.
Now you can freely update the replication components to make changes to the replication logic:
ReplicationTarget
component to spawn an entity on new clients, or despawn the entity on some clientsVisibilityMode
component to enable interest managementReplicateHierarchy
to start replicating the children of an entityThe ClientPlugin
and ServerPlugin
plugins have been replaced with the ClientPlugins
and ServerPlugins
plugin groups.
This means that you can freely override or disable any of the internal plugins that compose the plugin groups.
All internal plugins are enabled by default, but feel free to disable any that you don't need. For example you could disable the VisibilityPlugin
on the server if you don't need interest management, the ClientDiagnosticsPlugin
if you don't need to compute statistics on the connection, or ClientReplicationSendPlugin
if you don't need to replicate entities from the client to the server.
lightyear
used "rooms" to perform interest management. Clients and entities could join rooms, and an entity would only be replicated to a client if they shared a room.
This semi-static method is convenient in most cases, but sometimes you need a more immediate API to handle visibility.
You can now use the VisibilityManager
to directly specify the visibility of a (client, entity) pair:
VisibilityManager::gain_visibility
VisibilityManager::lose_visibility
PartialEq::ne
(rollback if the values are different) but you can override it with add_should_rollback_fn(custom_fn)
ConnectToken
to a client so that it can initiate a connection.[zstd]
feature to run zstd-compression on all packets.NetworkingState
is now correctly updated when the io gets disconnected (for example via a timeout). The io tasks now get disconnected if the NetworkingState
is set to disconnected (for example if the client requests disconnection).app.register_component::<PlayerId>(ChannelDirection::ServerToClient)
.add_prediction(ComponentSyncMode::Once)
.add_interpolation(ComponentSyncMode::Once);
Replicate
, ClientPlugin
, ServerPlugin
ComponentRegistry
must now implement PartialEq
RoomId
to be a u64Published by cBournhonesque 6 months ago
lightyear
used to require a Protocol
struct which contained 2 enums MessageProtocol
and ComponentProtocol
that held the list of messages that could be sent over the network.
Now you can split up a protocol into multiple pieces, each piece can be registered directly on the App
:
app.add_message::<Message1>(ChannelDirection::Bidirectional);
app.add_plugins(InputPlugin::<Inputs>::default());
app.register_component::<PlayerPosition>(ChannelDirection::ServerToClient)
.add_prediction::<PlayerPosition>(ComponentSyncMode::Full)
.add_interpolation::<PlayerPosition>(ComponentSyncMode::Full)
.add_linear_interpolation_fn::<PlayerPosition>();
app.add_channel::<Channel1>(ChannelSettings {
mode: ChannelMode::OrderedReliable(ReliableSettings::default()),
..default()
});
This approach provides more flexibility, since the Protocol can now be defined in various separate plugins; it also removes a lot of procedural macro magic that was hard to maintain.
Currently the only requirement is that the protocol registration must happen after the ClientPlugin
or the ServerPlugin
have been added.
Previously, your network configuration would be set in stone after adding the ClientPlugin
and ServerPlugin
.
Now, you can freely update the configuration (by updating the ClientConfig
and ServerConfig
resources) at any time, and the configuration change will take effect on the next connection attempt.
I also introduce the NetworkingState
state to track the status of the client or server (Connecting, Connected, Disconnected).
This means that a machine can dynamically become a client or a server depending on the configuration!
Here is an example where clients can choose at runtime whether to host the game by acting as 'host-servers', or just join the game as clients.
You can now easily replicate resources!
There are 2 steps:
app.register_resource::<R>(ChannelDirection::ServerToClient);
commands.replicate_resource::<R>(target)
starts the replicationcommands.pause_replicate_resource::<R>()
pauses the replication (without removing the resource)And every changes to your resource will now be replicated!
When a client gets disconnected, we now automatically cleanup all entities and resources that had been spawned on the client via replication.
In the future I have plans to make this behavior more configurable (we might want some entities to remain even when disconnected), but I chose to enable this currently for simplicity.
Previously, there was only one configuration shared between Prediction and Interpolation. But there are actually situations where one would want to only enable Prediction and not Interpolation, or vice-versa.
For example, you might need to turn on Prediction on a physics component like AngularVelocity
, but not turn on Interpolation since AngularVelocity
doesn't have any visual impact on the component.
You can now independently specify the prediction behavior and the interpolation behavior.
ClientPlugin
is now directly created from the ClientConfig
, same for ServerPlugin
App
after the ClientPlugin
and ServerPlugin
have been registered.Commands
:
commands.connect_client()
commands.disconnect_client()
commands.start_server()
commands.stop_server()
Published by cBournhonesque 7 months ago
You can now use Steam sockets as a networking Transport layer!
Note that the server can run multiple transports in parallel, so you can have cross-play between steam and non-steam users!
In the previous release, I updated all the examples to run in "listen server" mode (the server and client are running in the same machine). This was done by starting a client bevy app and a server bevy app in different threads, and sending messages between them via channels.
This works fine but has some disadvantages:
In this release, you can now run lightyear
in "host server" mode. In this mode, you can create a single bevy app where the server also acts as a client. There are no packets sent between client and server because the client and server plugins are running in the same bevy World
!
ClientId
: instead of a u64
it is now an enum
that depends on the type of Transport used by the clientGlobalMetadata
structs; the client_id is directly accessible via connection.id()
PrePredicted
component instead of ShouldBePredicted
ConnectEvent
and DisconnectedEvent
on the client side to also include the ClientId
of the client with event.client_id()
InputManager
resource, not the ClientConnection
anymorePublished by cBournhonesque 7 months ago
A lightyear
server can now listen simultaneously on different types of Transports: WebSocket, WebTransport, UDP, local channels, etc.
It requires almost no code change: instead of providing a single TransportConfig
when building the server, you can now provide a Vec<TransportConfig>
and the server will be listening on each config simultaneously!
All examples have been updated to showcase this behavior: the server listens for WebTransport connections on port 5000, UDP on port 5001 and WebSocket on port 5002!
This is very exciting for two main reasons:
lightyear
in "Listen Server" mode!"Listen Server" means that a player acts as both the server and the client. (the server will run on a separate thread on the client's machine). This could be useful for p2p games, or for some single-player game architectures where the client talks to a local server.
With the above change, it is now easy to run lightyear
as a Listen Server! The server and client apps run on different threads and use local channels to communicate with 0 latency, and other clients can still connect to the host.
All examples have been updated to be able to run like this with the command: cargo run -- listen-server
settings.ron
file to specify the networking configuration. (the previous cli-based approach wasn't flexibly enough when using multiple transports for a given server)My next priority will be to add Steam
as a connection option.
Published by cBournhonesque 8 months ago
Small release with mostly internal changes.
Moved some of the logic for the client and server into 3 new internal plugins:
receive
and send
systems that receive and send raw packetsEvents
whenever a networking event happens (MessageReceived, InputReceived, ConnectionReceived, etc.)The main server and client plugins are now relatively short and just consist in importing a few other plugins.
The vendored bitcode crate could not be compiled in nightly anymore, this has been fixed.
remove_replicate
commandAdded an EntityCommand
called remove_replicate
that lets you stop replicating an entity, and guarantees that any event related to that entity won't be replicated, including Despawns.
For example you can call
entity_commands.remove_replicate();
entity_commands.despawn()
on the server, and the entity's despawn won't be replicated to clients. (This could be useful if you want to play a despawn animation on the client)
SharedConfig
struct does not have a enable_replication
field anymore. This field was previously unused, so I am removing it for clarity. In the future, I will probably provide the ability to disable replication by turning the Client
and Server
plugins into PluginGroup
sPublished by cBournhonesque 8 months ago
Lightyear is updated for bevy 0.13!
There are still a couple of issues (a leafwing-input related problem on the bullet_prespawn example, and waiting for bevy_inspector_egui
to be updated for bevy 0.13) which will be fixed in a future minor release.
Lightyear now supports replicating bevy hierarchies (i.e. replicating the Parent
/Children
components).
You can just set replicate.replicate_hierarchy = true
on the Replicate
component of the root entity of your hierarchy; all entities in the hierarchy will be replicated in a single ReplicationGroup
(meaning that it is guaranteed that updates for all these entities will be received by the remote on the same tick).
Lightyear now makes use of the newly added FixedFirst
, FixedPreUpdate
, FixedPostUpdate
schedules, which means that you can now add all your logic in the FixedUpdate
schedule without worrying about ordering with other lightyear
systems. In particular, the FixedUpdateSet::Main
SystemSet
has been removed.
Most networked data is meant to be updated in the FixedUpdate
schedule so that they don't depend on framerate.
This can cause visual artifacts (jitter, etc.) because you could have multiple frames in a row without the FixedUpdate
schedule running, or the FixedUpdate
schedule could run multiple times in a single frame.
I've added a plugin VisualInterpolationPlugin
that smoothly interpolates the value of a component between the FixedUpdate values. This adds 1 tick (FixedUpdate timestep) of visual delay, which should be negligible in most cases.
You can read more about it in the book.
Time<Fixed>::overstep_fraction
to compute the interpolation percentageFixedUpdateSet::Main
SystemSet
has been removed, you can now just add your systems to the FixedUpdate
scheduleMapEntities
trait has been replaced with the LightyearMapEntities
traitinput_buffer
systems have to be added to the FixedPreUpdate
schedule. (this limitation is only present for native inputs, not for leafwing_inputs)LogConfig
setting in SharedConfig
has been removed. I will provide a custom tracing::subscriber
Layer
to add additional metrics/loggingPublished by cBournhonesque 8 months ago
Lightyear now supports putting a limit on the bandwidth between a client and a server.
You can set a cap (for example 50KB/sec).
If there are too many messages to send, lightyear will use a priority with accumulation scheme to decide which messages will be sent and which will be discarded. You can set a priority
score on each message, channel or entity to define its relative priority to other messages.
You can find more information in the book.
You can also check an example online
We already have a trait Transport
that represents how to send raw byte slices over the wire, with several implementations: UdpSocket
, WebTransport
, WebSocket
, etc. An Io
is a wrapper around a dyn Transport
, which lets us swap the different transport implementations effortlessly.
Similarly, I am introduce two new traits NetClient
and NetServer
that are an abstraction of a long-lived 'Connection': how to connect, do a handshake, get the list of connected clients, disconnect, etc.
The structs ClientConnection
and ServerConnection
becomes wrapped around dyn NetClient
and dyn NetServer
, so that we can use different 'connection' implementations. The only implementation currently is based on the netcode protocol, but this opens the door to other connection abstractions. In particular I plan to use this to add steam sockets support!
There is one new implementation of the Transport
trait using websockets! Those work on both native and wasm; they can be a good alternative to WebTransport on browsers that don't support WebTransport (Safari). They can be easier to work with as well as there is no need to generate a short-lived certificate.
Be mindful that websockets use TCP and can encounter head-of-line blocking.
io
connection (WebTransport, UDP socket, etc.) establishes the connection when the connect
function is called instead of when the lightyear Plugins are builtEq
bound on non-leafwing inputs, so that they can contain f32
sIo
struct anymore, instead the NetConfig
has an inner field IoConfig
which defines how the Io
will be constructed.IoTaskPool
provided by bevy! Take a look at https://github.com/cBournhonesque/lightyear/pull/141/files#diff-7baf4299a3291e8534a70ffcfa2eec44e80942e6525445b2222204d1100dde42L101 to see how to update the main entrypoint function.Published by cBournhonesque 9 months ago
I am super excited for this: thanks to @Nul-led and @MOZGIII's help I was able the wasm webtransport working!
This means that lightyear
is now available in the browser.
See here for an example running in WASM along with instructions.
lightyear
already had some support for prespawning entities on the Predicted timeline, but it was fairly awkward.
I'm introducing an easier way to do this, where the server and client can use the exact same system to spawn the entities. The only thing you need to do is add the component PreSpawnedPlayerObject
on the entity, on the client and the server.
When the client receives a server entity, it will first check if that entity corresponds to one of its prespawned entities by using a hash of the Archetype and the spawn tick of the entity.
See here for an example of how to use prespawning.
You can also read more about it in the book.
Published by cBournhonesque 9 months ago
Split the Client
and Server
monolithic resources into a bunch of smaller independent resources to remove coupling and improve parallelism. The new resources are:
I am still planning on further breaking up the remaining ConnectionManager
into different parts:
InputManager to handle inputs
SyncManager for handling time-syncing between client and server
maybe having a different resource per channel so that you can send messages to different channels in parallel
Added diagnostics to print the incoming/outgoing bandwidth that is being used
You can use enable the diagnostics like so:
app.add_plugins(LogDiagnosticsPlugin {
filter: Some(vec![
IoDiagnosticsPlugin::BYTES_IN,
IoDiagnosticsPlugin::BYTES_OUT,
]),
..default()
});
I am planning on adding more diagnostics in the future.
I fixed a LOT of bugs related to long-term connections after the Tick
wrapped-around (after around 15 minutes); all features (input handling, replication, time-syncing) should now work correctly even for long-term sessions, up to 46 days.
Fixed an issue where leafwing
ActionState
s could not be replicated correctly from client->server in some edge-cases. Now inputs are networked correctly whether the controlled Entity is Controlled
, Predicted
or Pre-Predicted
.
Client/ClientMut
and Server/ServerMut
. Otherwise you will mostly need to use the resources ClientConnectionManager
and ServerConnectionManager
.Published by cBournhonesque 9 months ago
WrappedTime
info!
and warn!
logs in client syncPublished by cBournhonesque 9 months ago
This release introduces the following changes:
leafwing
feature)bevy_xpbd_2d
now implement Message
and can be used directly in your replication protocol. (gated behind the xpbd_2d
feature)leafwing_input_manager
to handle inputsbevy_xpbd_2d
input_delay
and correction_ticks
to improve the handling of mispredictionsleafwing_input_manager
(feature leafwing
)The current input_handling is quite crude and has several limitations:
This release adds special support for networking inputs via leafwing_input_manager
, so that we can get all the benefits from that crate (handling chords, having multiple entities controlled by different keys).
IMPORTANT:
ActionState
resource. Only inputs attached to entities are supportedxpbd_2d
)It can be hard currently to directly use external components in your replication protocol, as every component must implement such custom lightyear traits such as Message
or MapEntities
.
I wanted to create a demo of a physics-based networked simulation so I manually implemented some good defaults for some components of bevy_xpbd_2d
, so that you can use them directly in your replication protocol.
Lightyear now supports adding some input delay: i.e. the user presses a button on tick 10 but their character only moves on tick 15.
This lets you choose a good trade-off between having a less responsive game (more input delay) vs a very responsive game but where there is more mispredictions because the client is far in the future (low input delay).
At the extreme where the input delay is higher than the RTT, the game won't have any mispredictions as both the client and server will have access to all inputs.
See more information here: https://www.snapnet.dev/docs/core-concepts/input-delay-vs-rollback/
This release adds the option to visually interpolate between the current position and the corrected position when there is a misprediction rollback. This is the technique used in RocketLeague to ensure that the game still runs smoothly even when all clients are being predicted.
The two default behaviours are:
InstantCorrector
(no correction, we just perform rollback as usual)InterpolatedCorrector
(we re-use the interpolation logic for the correction; which will happen over a few ticks)Note that the correction still has some jittery artifacts, but that's something that I will be working on in the future.
It is now possible to have some replication custom logic per component of an entity.
For instance, by default only components present in the ComponentProtocol
get replicated; but there could be situations where we don't want to replicate a component of an entity even it is present in the ComponentProtocol
.
This can be achieved simply by calling the following methods on the Replicate
component (which defines how this entity gets replicated):
replicate.disable_component<Component1>()
to disable replicationreplicate.enable_component<Component1>()
to enable replication.Another example is that we might want to replicate the ActionState
of an entity to all players except for the player who controls the entity (since they are the ones who are updating the ActionState
with their inputs). This can be done easily by calling:
replicate.add_target::<ActionState>(NetworkTarget::AllExceptSingle(client_id));
I used divan
to add CPU/memory benchmarks for replicating many entities to one client, or a few entities to many clients.
I still have to think about how to best interpret the results from the benchmarks. For example I suspect that I'm doing unnecessary clones:
I have cleaned-up the examples and tested them all in a real connection with a remote server.
The server now has the option to run in headless
mode, i.e. with all rendering-related plugins disabled. Only Bevy's MinimalPlugins
are enabled, so that only the simulation is running.
All examples are working with both UDP and WebTransport!
We are now exporting the type aliases:
type Client = Client<MyProtocol>
type Server = Server<MyProtocol>
type Replicate = Replicate<MyProtocol>
for convenience, so that we don't have to keep mentioning the protocol as generic parameter.
Added the AllExceptSingle
and Single
NetworkTarget
s
The trait Message
is now automatically implemented. You just need to implement the MapEntities
and Named
traits.
Fixed an issue where prediction time/interpolation time were not being computed properly when the client started, which would cause the Predicted
/Interpolated
entities to appear frozen
PredictionHistory
was being added even to entities that were not being Predicted
. This was consuming additional CPU/memory for no reason, and has been fixed
Removed warn
loggings being emitted by mistake for pre-Predicted
entities
We are no longer getting a panic when we try to despawn the entities of a client who has disconnected
Fixed an issue where if two entities were in the same ReplicationGroup and one of them rolled back, the other would not roll back as well. Now it is guaranteed that all components of all predicted entities will rollback if there is a mispredictions on any of them.
Fixed some issues with rollback (including an off-by-1 error in the rollback logic)
Fixed some issues with replication (we now compute the bevy ChangeTick correctly)
Client
instead of Client<Protocol>
, Replicate
instead of Replicate<Protocol>
UserInput
has been renamed to UserAction
SyncComponent
directly anymore (because this was preventing users from directly using components from external crates due to the orphan rule), instead the ComponentProtocol
implements SyncMetadata<C>
for each component. Use this to access the mode
, interpolator
, corrector
of each Component
Published by cBournhonesque 10 months ago
This release introduces the following changes:
You can know send messages from client to other clients. Previously we could only send messages between a client and the server. I added the method client.send_message_to_target
which allows a client to send a message to any other client (by routing via the server)
It is now possible to have replication from the client to the server!
Note that currently I do not provide any particular helper to broadcast an entity from a client to other clients; the only way to do that is to:
I might add some more ergonomic way to achieve this in the future (i.e specifying directly on the client how we want the entity to be replicated to other clients).
Currently, the only way to spawn Predicted entities (i.e. responsive and on the client's timeline) was to spawn them on the server and wait for them to be replicated. This would introduce a delay if the entity was spawned as part of a client action. We would have to wait for:
Instead, we can now spawn a pre-predicted entity on the client. Here is an example:
ShouldBePredicted { client_entity }
There are a lot of potential edge-cases with client-prediction, especially with the addition of spawning Pre-Predicted entities.
I have listed most of them in that link; for instance:
I have tested most them; almost all situations are supported correctly!
The only one that has some caveats is rolling back a predicted despawn; this only happens if we receive a server update for that entity after the despawn.
Added a new example client_replication
that show-cases the newly-added features:
buffer_send
->send_message
and send_to_target
-> send_message_to_target
for clarity.server.send_to_target
has been renamed to server.send_message_to_target
server.buffer_send
has been renamed to server.send_message
client.buffer_send
has been renamed to client.send_message
Replicate
on the server to re-replicate client entities to other clients must be done in the newly added MainSet::ClientReplication
SystemSet
Predicted
entities requires to use EntityCommands::prediction_despawn
instead of EntityCommands::despawn
Published by cBournhonesque 10 months ago
This release:
ReplicationGroups
that showcases:
ReplicationGroups
: where multiple entities are guaranteed to be replicated in a single message, so will always be in sync with each otherMapEntities
trait)Handle entity mappings more rigorourously now! By Entity Mapping
I mean Messages or Components that contain references to other entities, such as HasParent(Entity)
. The entity in the message is from the server's World, and it needs to be mapped to the client's World.
MapEntities
trait to be more flexibleHasParent(Entity)
on the Confirmed entity will be synced with the correct mapping on the Predicted/Interpolated entities)HasParent(A)
, B will be replicated after A has finished replicating.Updated the Input handling logic to get rid of some jitter around client prediction:
Refactored some of the interpolation logic:
Add
and Mul
if it uses LinearInterpolation
, not if it uses a custom interpolation functionNone
variant in your Input enum, like so:pub enum Inputs {
Direction(Direction),
Delete,
Spawn,
// *new*: inputs must be sent every tick, even if there is no action
NoAction,
}
/// Trait that Messages or Components must implement to be able to map entities
pub trait MapEntities<'a> {
/// Map the entities inside the message or component from the remote World to the local World
fn map_entities(&mut self, entity_mapper: Box<dyn EntityMapper + 'a>);
/// Get all the entities that are present in that message or component
fn entities(&self) -> EntityHashSet<Entity>;
}
Published by cBournhonesque 10 months ago
Room
, to be able to replicate only a subset entities to a certain client to save bandwidth and prevent cheating. See more information here
ReplicationGroup
) are replicated with a consistent state. See more information here
bevy_replicon
is doingUnreliableSenderWithAck
channel where senders can get notified when a given message has been ACK-edbevy
structs (Transform
, Color
, Visibility
) now implement the Message
trait and can be used for replicationComponentProtocol
now derives Debug
directly (which shows the type of the replicated Component, but not the value)Room
or not for replication)