bevy_replicon/
lib.rs

1/*!
2A server-authoritative replication crate for [Bevy](https://bevyengine.org).
3
4# Quick start
5
6The library doesn't provide any I/O, so you need to add a
7[messaging backend](https://github.com/simgine/bevy_replicon#messaging-backends).
8If you want to write an integration yourself, see [`shared::backend`] module.
9
10## Prelude
11
12We provide a [`prelude`] module, which exports most of the typically used traits and types.
13
14## Plugins
15
16Add [`RepliconPlugins`] and plugins for your chosen messaging backend to your app:
17
18```
19use bevy::{prelude::*, state::app::StatesPlugin};
20use bevy_replicon::prelude::*;
21# use bevy::app::PluginGroupBuilder;
22
23let mut app = App::new();
24app.add_plugins((MinimalPlugins, StatesPlugin, RepliconPlugins, MyMessagingPlugins));
25# struct MyMessagingPlugins;
26# impl PluginGroup for MyMessagingPlugins {
27#     fn build(self) -> PluginGroupBuilder {
28#         PluginGroupBuilder::start::<Self>()
29#     }
30# }
31```
32
33If you use [`MinimalPlugins`], you need to add [`StatesPlugin`](bevy::state::app::StatesPlugin)
34manually. It's included by default with [`DefaultPlugins`].
35
36## Server and client creation
37
38This part is specific to your messaging backend. For `bevy_replicon_renet`,
39see [this section](https://docs.rs/bevy_replicon_renet#server-and-client-creation).
40
41On server connected clients represented as entities with [`ConnectedClient`] component.
42Their data represented as components, such as [`ClientStats`]. Users can also attach their
43own metadata to them or even replicate these entities back to clients.
44
45These entities are automatically spawned and despawned by the messaging backend. You can
46also despawn them yourself to trigger a disconnect or use the [`DisconnectRequest`] message
47to disconnect after sending messages.
48
49You can use [`On<Add, ConnectedClient>`] to react to new connections,
50or use backend-provided events if you need the disconnect reason.
51
52## States
53
54We provide [`ClientState`] and [`ServerState`], which are Bevy [`States`].
55These are managed by your messaging backend, and you can use them to control when your systems run.
56
57For systems that should run continuously while in a specific state, use [`IntoScheduleConfigs::run_if`]
58with the [`in_state`] run condition:
59
60```
61# use bevy::prelude::*;
62# use bevy_replicon::prelude::*;
63# let mut app = App::new();
64app.add_systems(
65    Update,
66    (
67        apply_damage.run_if(in_state(ServerState::Running)), // Runs every frame on the server.
68        display_vfx.run_if(in_state(ClientState::Connected)), // Runs every frame on the client.
69    ),
70);
71# fn apply_damage() {}
72# fn display_vfx() {}
73```
74
75To run systems when entering or exiting a state, use the [`OnEnter`] or [`OnExit`] schedules:
76
77```
78# use bevy::prelude::*;
79# use bevy_replicon::prelude::*;
80# let mut app = App::new();
81app.add_systems(OnEnter(ClientState::Connecting), display_connection_message) // Runs when the client starts connecting.
82    .add_systems(OnExit(ClientState::Connected), show_disconnected_message) // Runs when the client disconnects.
83    .add_systems(OnEnter(ServerState::Running), initialize_match); // Runs when the server starts.
84# fn display_connection_message() {}
85# fn show_disconnected_message() {}
86# fn initialize_match() {}
87```
88
89You can also use these states with [`DespawnOnExit`] to control the lifetime of entities.
90
91Read more about system patterns in the [Abstracting over configurations](#abstracting-over-configurations)
92section.
93
94## Replication
95
96It's a process of exchanging data in order to keep the world in sync. Replicon
97provides a high-level API to automate server-authoritative replication.
98
99Replication happens only from server to clients. It's necessary to prevent cheating.
100If you need to send information from clients to the server, use
101[messages](#network-messages-and-events).
102
103For implementation details see [`ServerChannel`](shared::backend::channels::ServerChannel).
104
105### Tick rate
106
107By default, updates are not sent every frame in order to save bandwidth. Replication runs
108in [`ServerSystems::Send`] whenever the [`ServerTick`](server::server_tick::ServerTick) resource
109changes and if the state is [`ServerState::Running`].
110
111By default, the tick is incremented in [`FixedPostUpdate`] each time [`FixedMain`](bevy::app::FixedMain)
112runs. You can configure how often it runs by inserting [`Time<Fixed>`], which is 64 Hz by default.
113
114```rust
115use bevy::{prelude::*, state::app::StatesPlugin};
116use bevy_replicon::prelude::*;
117
118# let mut app = App::new();
119// `Time::from_hz` is implemented only for `Fixed`, so the type is inferred.
120app.insert_resource(Time::from_hz(30.0)) // Run 30 times per second.
121    .add_plugins((MinimalPlugins, StatesPlugin, RepliconPlugins));
122```
123
124You can also configure the schedule via [`ServerPlugin::tick_schedule`].
125
126### Entities
127
128By default no entities are replicated. Add the [`Replicated`] marker
129component on the server for entities you want to replicate.
130
131On clients [`Replicated`] will be automatically inserted to newly-replicated entities.
132
133If you remove the [`Replicated`] component from an entity on the server, it will be despawned on all clients.
134
135Entity IDs differ between clients and server. As a result, clients maps server entities to local entities
136on receive. These mappings are stored in the [`ServerEntityMap`](shared::server_entity_map::ServerEntityMap)
137resource.
138
139### Components
140
141Components will be replicated only on entities marked for replication.
142By default no components are replicated, you need to define rules for it.
143
144Use [`AppRuleExt::replicate`] to create a replication rule for a single component:
145
146```
147# use bevy::{prelude::*, state::app::StatesPlugin};
148# use bevy_replicon::prelude::*;
149# use serde::{Deserialize, Serialize};
150# let mut app = App::new();
151# app.add_plugins((StatesPlugin, RepliconPlugins));
152app.replicate::<ExampleComponent>();
153
154#[derive(Component, Deserialize, Serialize)]
155struct ExampleComponent;
156```
157
158If your component contains an entity, it cannot be deserialized as is
159because entities inside components also need to be mapped. Therefore,
160to properly replicate such components, mark fields containing entities with
161`#[entities]`. See [`Component::map_entities`] for details.
162
163By default all components are serialized with [`postcard`].
164In order to serialize Bevy components you need to enable the `serialize` feature on Bevy.
165
166If your component doesn't implement serde traits or you want to customize the serialization
167(for example, quantize, skip some fields or apply compression), you can use
168[`AppRuleExt::replicate_as`] or [`AppRuleExt::replicate_with`].
169
170You can also create a rule for multiple components. Use [`AppRuleExt::replicate_bundle`],
171or pass a tuple of [`RuleFns`] to [`AppRuleExt::replicate_with`]. The components will only
172be replicated if all of them are present on the entity. This also allows you to specialize
173serialization and deserialization based on specific entity components.
174
175All functions also have `_filtered` variants that additionally accept archetypal filters,
176similar to [`Query`]. They are separate functions because Rust doesn't allow default generics
177for functions. For more details, see [`AppRuleExt::replicate_filtered`].
178
179#### Required components
180
181You don't want to replicate all components because not all of them are
182necessary to send over the network. Components that can be calculated on the client can
183be inserted using Bevy's required components feature.
184
185```
186# use bevy::{prelude::*, state::app::StatesPlugin};
187# use bevy_replicon::prelude::*;
188# use serde::{Deserialize, Serialize};
189# let mut app = App::new();
190# app.add_plugins((StatesPlugin, RepliconPlugins));
191// Replicate only transform and player marker.
192app.replicate::<Transform>()
193    .replicate::<Player>()
194    .add_observer(init_player_mesh);
195
196fn init_player_mesh(
197    add: On<Add, Mesh2d>,
198    mut meshes: ResMut<Assets<Mesh>>,
199    mut players: Query<&mut Mesh2d>,
200) {
201    let mut mesh = players.get_mut(add.entity).unwrap();
202    **mesh = meshes.add(Capsule2d::default());
203}
204
205/// Main player component.
206///
207/// [`NotReplicatedComponent`] and [`Replicated`] will be implicitly inserted after spawning on
208/// both the server and clients.
209///
210/// [`Replicated`] is always inserted on the client after replication, regardless of whether it is marked
211/// as required. However, it may still be useful to mark it as required if you want to avoid
212/// inserting it explicitly on the server.
213#[derive(Component, Deserialize, Serialize)]
214#[require(Replicated, NotReplicatedComponent, Mesh2d)]
215struct Player;
216
217#[derive(Default, Component)]
218struct NotReplicatedComponent;
219```
220
221This pairs nicely with server state serialization and keeps saves clean.
222You can use [`scene::replicate_into`] to fill [`DynamicScene`] with replicated entities and their components.
223On deserialization all missing required components will be inserted, and initialization
224systems will restore the correct game state.
225
226If a component can't be used with the required components due to the inability to insert it
227without world access, you can create an observer for a replicated marker and insert the actual
228component inside it. However, it's preferred to use required components when possible. For example,
229it's better to require a [`Handle<T>`] with a default value that doesn't point to any asset
230and initialize it later in a hook or observer. This way you avoid archetype moves in ECS.
231
232#### Mutability
233
234There are two ways to change a component value on an entity: re-inserting it or mutating it.
235
236We use Bevy’s change detection to track and send changes. However, it does not distinguish between modifications
237and re-insertions. This is why we simply send the list of changes and decide how to apply them on the client.
238By default, this behavior is based on [`Component::Mutability`].
239
240When a component is [`Mutable`](bevy::ecs::component::Mutable), we check whether it already exists on the entity.
241If it doesn’t, we insert it. If it does, we mutate it. This means that if you insert a component into an entity
242that already has it on the server, the client will treat it as a mutation. As a result, triggers may behave
243differently on the client and server. If your game logic relies on this semantic, mark your component as
244[`Immutable`](bevy::ecs::component::Immutable). For such components, replication will always be applied via insertion.
245
246This behavior is also configurable via [client markers](#client-markers).
247
248#### Component relations
249
250Some components depend on each other. For example, [`ChildOf`] and [`Children`]. You can enable
251replication only for [`ChildOf`] and [`Children`] will be updated automatically on insertion.
252This will emit a [`B0004`](https://bevy.org/learn/errors/b0004) warning which can be safely ignored.
253See [#19776](https://github.com/bevyengine/bevy/issues/19776) for more details.
254
255You can also ensure that their mutations arrive in sync by using [`SyncRelatedAppExt::sync_related_entities`].
256
257#### Deterministic replication
258
259Up until now, we've covered only authoritative replication (AR), where the server is the source of truth
260and continuously sends changes. However, sometimes you may want to send data only once and simulate independently,
261relying on determinism. This approach is called deterministic replication (DR).
262
263For example, you might use AR for things like player health, and DR for moving platform positions to reduce
264network traffic.
265
266Use [`AppRuleExt::replicate_once`] to replicate only the initial value of a component.
267You can configure this per-component within a replication rule using [`AppRuleExt::replicate_with`].
268
269See also [server messages](#from-server-to-client), which are also useful for DR.
270
271## Network messages and events
272
273This replaces RPCs (remote procedure calls) in other engines and,
274unlike replication, can be sent both from server to clients and from clients to
275server.
276
277### From client to server
278
279To send a message from client to server, you need to register the message
280with [`ClientMessageAppExt::add_client_message`] instead of [`App::add_message`].
281
282Messages include [`Channel`] to configure delivery guarantees (reliability and
283ordering).
284
285These messages will appear on server as [`FromClient`] wrapper message that
286contains sender ID and the message.
287
288```
289# use bevy::{prelude::*, state::app::StatesPlugin};
290# use bevy_replicon::prelude::*;
291# use serde::{Deserialize, Serialize};
292# let mut app = App::new();
293# app.add_plugins((StatesPlugin, RepliconPlugins));
294app.add_client_message::<Ping>(Channel::Ordered)
295    .add_systems(
296        PreUpdate,
297        receive
298            .after(ServerSystems::Receive)
299            .run_if(in_state(ServerState::Running)),
300    )
301    .add_systems(
302        PostUpdate,
303        send.before(ClientSystems::Send).run_if(in_state(ClientState::Connected)),
304    );
305
306fn send(mut ping: MessageWriter<Ping>) {
307    ping.write(Ping);
308}
309
310fn receive(mut pings: MessageReader<FromClient<Ping>>) {
311    for ping in pings.read() {
312        info!("received ping from client `{}`", ping.client_id);
313    }
314}
315
316#[derive(Message, Deserialize, Serialize)]
317struct Ping;
318```
319
320If a message contains an entity, implement
321[`MapEntities`](bevy::ecs::entity::MapEntities) for it and use use
322[`ClientMessageAppExt::add_mapped_client_message`] instead.
323
324There is also [`ClientMessageAppExt::add_client_message_with`] to register a message with special serialization and
325deserialization functions. This could be used for sending messages that contain [`Box<dyn PartialReflect>`], which
326require access to the [`AppTypeRegistry`] resource. Don't forget to validate the contents of every
327[`Box<dyn PartialReflect>`] from a client, it could be anything!
328
329Alternatively, you can use events with a similar API. First, you need to register the event
330using [`ClientEventAppExt::add_client_event`], and then use [`ClientTriggerExt::client_trigger`].
331
332```
333# use bevy::{prelude::*, state::app::StatesPlugin};
334# use bevy_replicon::prelude::*;
335# use serde::{Deserialize, Serialize};
336# let mut app = App::new();
337# app.add_plugins((StatesPlugin, RepliconPlugins));
338app.add_client_event::<Ping>(Channel::Ordered)
339    .add_observer(receive)
340    .add_systems(Update, send.run_if(in_state(ClientState::Connected)));
341
342fn send(mut commands: Commands) {
343    commands.client_trigger(Ping);
344}
345
346fn receive(ping: On<FromClient<Ping>>) {
347    info!("received ping from client `{}`", ping.client_id);
348}
349# #[derive(Event, Deserialize, Serialize)]
350# struct Ping;
351```
352
353For events with entities inside use [`ClientEventAppExt::add_mapped_client_event`].
354Similar to messages, serialization can also be customized with [`ClientEventAppExt::add_client_event_with`].
355
356### From server to client
357
358A similar technique is used to send messages from server to clients. To do this,
359register a message with [`ServerMessageAppExt::add_server_message`]
360and send it from server using [`ToClients`]. This wrapper contains send parameters
361and the message itself.
362
363```
364# use bevy::{prelude::*, state::app::StatesPlugin};
365# use bevy_replicon::prelude::*;
366# use serde::{Deserialize, Serialize};
367# let mut app = App::new();
368# app.add_plugins((StatesPlugin, RepliconPlugins));
369app.add_server_message::<Pong>(Channel::Ordered)
370    .add_systems(
371        PreUpdate,
372        receive
373            .after(ClientSystems::Receive)
374            .run_if(in_state(ClientState::Connected)),
375    )
376    .add_systems(
377        PostUpdate,
378        send.before(ServerSystems::Send).run_if(in_state(ServerState::Running)),
379    );
380
381fn send(mut pongs: MessageWriter<ToClients<Pong>>) {
382    pongs.write(ToClients {
383        mode: SendMode::Broadcast,
384        message: Pong,
385    });
386}
387
388fn receive(mut pongs: MessageReader<Pong>) {
389    for pong in pongs.read() {
390        info!("received pong from the server");
391    }
392}
393
394#[derive(Message, Deserialize, Serialize)]
395struct Pong;
396```
397
398Just like for client messages, we provide [`ServerMessageAppExt::add_mapped_server_message`]
399and [`ServerMessageAppExt::add_server_message_with`].
400
401Event API is available. First, you need to register an event with [`ServerEventAppExt::add_server_event`]
402and then use [`ServerTriggerExt::server_trigger`]:
403
404```
405# use bevy::{prelude::*, state::app::StatesPlugin};
406# use bevy_replicon::prelude::*;
407# use serde::{Deserialize, Serialize};
408# let mut app = App::new();
409# app.add_plugins((StatesPlugin, RepliconPlugins));
410app.add_server_event::<Pong>(Channel::Ordered)
411    .add_observer(receive)
412    .add_systems(Update, send.run_if(in_state(ServerState::Running)));
413
414fn send(mut commands: Commands) {
415    commands.server_trigger(ToClients {
416        mode: SendMode::Broadcast,
417        message: Pong,
418    });
419}
420
421fn receive(_on: On<Pong>) {
422    info!("received pong from the server");
423}
424# #[derive(Event, Deserialize, Serialize)]
425# struct Pong;
426```
427
428And just like for client events, we provide [`ServerEventAppExt::add_mapped_server_event`]
429and [`ServerEventAppExt::add_server_event_with`].
430
431We guarantee that clients will never receive events or messages that point to an entity or require specific
432component to be presentt which client haven't received yet. For more details see the documentation on
433[`ServerMessageAppExt::make_message_independent`].
434
435## Abstracting over configurations
436
437Depending on the game, you may need to support some of these configurations:
438
439- Client
440- Dedicated (headless) server
441- Listen server (where the server is also a client)
442- Singleplayer
443
444There are 2 ways to support multiple configurations at the same time.
445
446### Classic way
447
448Just split client and server logic. Then for listen server and singleplayer run both the server and client,
449just don't accept outside connections for singleplayer.
450
451However, **running the client and server in a single app is not supported**. We rely on change detection to
452decide on which data to send, and since the world is shared, applying replication will trigger changes.
453To avoid this, you can use one of the following workarounds:
454
455- Two Bevy apps inside a single process, running in separate threads.
456- Two executables. After starting the client app, the server starts in the background.
457
458It's not easy to set up and requires more resources due to the synchronization between two worlds.
459This is why, while it's possible to use Replicon this way, we recommend a different approach.
460
461### The recommended way
462
463Instead of recreating full client-server logic, we provide a way to emulate client and server functionality
464without actually running them:
465
466- Client configuration runs only the client and its logic.
467- Dedicated server configuration runs only the server and its logic (all client logic usually compiled out).
468- Listen server configuration runs only the server and both logics.
469- Singleplayer configuration doesn't run the client or server but runs both logics.
470
471To achieve this, use the provided [`ClientState`] and [`ServerState`] states:
472
473- Use [`ClientState::Disconnected`] for systems that require server authority.
474  For example, systems that apply damage or send server events. This basically means "run when not a client",
475  which applies to both server **and** singleplayer.
476- Use [`ClientState::Connecting`], [`ClientState::Connected`], [`ServerState::Running`], etc.
477  **only** for miscellaneous things, like display a connection message or a menu to kick connected players
478  (things that actually require server or client running)
479- For everything else don't use Replicon's states.
480
481Everything else is done automatically by the crate. All provided
482[examples](https://github.com/simgine/bevy_replicon/tree/master/example_backend/examples)
483use this approach.
484
485Internally we run replication sending system only in [`ServerState::Running`] and replication receiving
486only in [`ClientState::Connected`]. This way for singleplayer replication systems won't run at all and
487for listen server replication will only be sending (server world is already in the correct state).
488
489For messages, it's a bit trickier. For all client messages, we internally drain messages as `E` and send
490them as [`FromClient<E>`] locally with [`ClientId::Server`] in [`ClientState::Disconnected`].
491For server messages we drain [`ToClients<E>`] and, if the [`ClientId::Server`] is the recipient of the message,
492re-emit it as `E` locally. The same applies to the event API. This emulates message receiving for both server
493and singleplayer without actually transmitting data over the network.
494
495We also provide [`ClientSystems`] and [`ServerSystems`] to schedule your system at specific time in the frame.
496For example, you can run your systems right after receive using [`ClientSystems::Receive`] or [`ServerSystems::Receive`].
497
498## Organizing your game code
499
500If you support a dedicated server, it's recommended to split your game logic into "client", "server", and "shared"
501crates. This way, you can compile out all unnecessary code for the dedicated server configuration.
502Alternatively, you can use [Cargo features](https://doc.rust-lang.org/cargo/reference/features.html) and split
503the logic into modules.
504
505We provide `client` and `server` features to disable unneeded functionality for this use case.
506You will need to disable similar features on your messaging backend crate too.
507
508<div class="warning">
509
510Make sure that the component, event and message registration order is the same on the client and server. Simply put all
511registration code in your "shared" crate.
512
513</div>
514
515If you don't need to support a dedicated server configuration, it's easier to keep the logic grouped together.
516Splitting your game into crates is still useful, but it should be done logically rather than on server/client
517basis.
518
519## Advanced features
520
521### Authorization
522
523Connected clients are considered authorized when they have the [`AuthorizedClient`] component. Without this
524component, clients can only receive events and messages marked as independent via [`ServerMessageAppExt::make_message_independent`]
525or [`ServerEventAppExt::make_event_independent`]. Additionally, some components on connected clients are only present
526after replication starts. See the required components for [`AuthorizedClient`] for details.
527
528By default, this component is automatically inserted when the client and server [`ProtocolHash`] matches.
529This behavior can be customized via [`RepliconSharedPlugin::auth_method`].
530
531### Client visibility
532
533You can control which parts of the world are visible to each client by using components registered as visibility filters.
534This works similarly to collision layers in physics: you insert filters to both the client and gameplay entities.
535See [`AppVisibilityExt`] for API details.
536
537The server always sees the entire world, even in listen-server mode.
538
539### Prioritization
540
541By default, all unacknowledged mutations are sent every tick. This can be expensive if you
542have many entities with mutating components. The [`PriorityMap`] component lets you configure
543how often mutations are sent for each entity on authorized clients. See its documentation for
544more details.
545
546In addition, [client visibility](#client-visibility) can be used to further reduce bandwidth by hiding entities
547that are irrelevant to a given client.
548
549### Interpolation and/or client-side prediction
550
551Due to network round-trip time and [tick rate](#tick-rate), you may notice that the state isn't updated
552immediately. This might be fine depending on your type of game. However, sometimes this needs to be visually hidden.
553
554To make value updates look smooth, you can just to interpolate the received state. If the input delay doesn't matter
555for your type of game, it can be enough.
556
557But if your game is fast-paced, waiting for server to receive your inputs and replicate the state back might
558might be unacceptable. The solution is to predict simulation on the client.
559
560However, it introduces another problem - misspredictions. For example, player 1 might predict movement to point X,
561while player 2 might have stunned it, the player 1 just didn't receive it yet. To solve this, client must apply
562the received state from server and replay its inputs.
563
564How much to predict also depends on the game. Common approaches are:
565
566- Predict individual entities. Common for shooters or games where you don't have many entities. In the case of
567  a misprediction or non-deterministic mismatch, the state will be corrected. Determinism is important for this
568  approach to reduce the number of rollbacks.
569- Predict the entire world. Common for physics-based games or games with many entities. With this approach,
570  all predicted entities are rolled back to the oldest received tick. For example, if one entity have confirmed tick 1
571  and another entity have confirmed tick 2, both entities are rolled back to tick 1. This approach is usually more expensive
572  but produces better results for physics. Additionally, if there are many predicted entities, it might even be faster
573  since there's no need to check each entity for misprediction. The more entities you predict, the more likely it is
574  that at least one will trigger a world rollback. So with this approach client usually just always rollbacks.
575
576We don't have these features built-in, but we provide a low-level API to implement these abstractions on top.
577Check the [corresponding section](https://github.com/simgine/bevy_replicon#interpolation-andor-rollback)
578in our README for existing implementations.
579
580### Predicting spawns
581
582Sometimes it's necessary to spawn an entity on the client before receiving replication from the server.
583A common example is projectiles. By default, the client will end up with two entities: one locally spawned
584and one replicated from the server.
585
586We provide the [`Signature`] component, which allows replicated entities to be matched with entities
587previously spawned on the client.
588
589This is also useful for synchronizing scenes. Both the client and the server can load a level independently
590and then match level entities to synchronize certain things, such as opened doors.
591
592#### Client markers
593
594To apply interpolation or store value history for client-side prediction, you need to override how components are
595written. However, the server knows nothing about archetypes on the client, and while some entities need to be predicted,
596others might need to be interpolated.
597
598This is why writing functions are marker-based. First, you register a marker using [`AppMarkerExt::register_marker<M>`].
599Then you can override how specific component is written and removed using [`AppMarkerExt::set_marker_fns<M, C>`].
600
601You can control marker priority or enable processing of old values using [`AppMarkerExt::register_marker_with<M>`].
602
603### Ticks information
604
605This requires an understanding of how replication works. See the documentation on
606[`ServerChannel`](shared::backend::channels::ServerChannel) and [this section](#eventual-consistency) for more details.
607
608To get information about confirmed ticks for individual entities, we provide
609[`ConfirmHistory`](client::confirm_history::ConfirmHistory). This component is updated when any replication for its entity is received.
610For convenience, we also trigger the [`EntityReplicated`](client::confirm_history::EntityReplicated) to ergonomically react on it.
611
612However, an entity might not have any mutations at a given tick. To address this, you need to call
613[`TrackAppExt::track_mutate_messages`](shared::replication::track_mutate_messages::TrackAppExt::track_mutate_messages) during the [`App`]
614setup and use [`ServerMutateTicks`](client::server_mutate_ticks::ServerMutateTicks) resource to check whether all mutation messages were
615received for this tick.
616
617So, a tick for an entity is confirmed if one of the following is true:
618- [`ConfirmHistory`](client::confirm_history::ConfirmHistory) reports that the tick is received.
619- [`ServerMutateTicks`](client::server_mutate_ticks::ServerMutateTicks) reports that for at least one of the next ticks, all update
620  messages have been received.
621
622### Optimizing entity serialization
623
624Serialization of [`Entity`] is optimized for use in scenes, but it’s not very efficient for networking. Because of this, we use our own implementation.
625See the [`compact_entity`] module if you want to apply this optimization to entities in your own types. You can also use
626[`postcard_utils::entity_to_extend_mut`] and [`postcard_utils::entity_from_buf`] for manual writing.
627
628# Eventual consistency
629
630All events, messages, inserts, removals and despawns will be applied to clients in the same order as on the server.
631
632However, if you insert/mutate a component and immediately remove it, the client will only receive the removal because the component value
633won't exist in the [`World`] during the replication process. But removal followed by insertion will work as expected since we buffer removals.
634
635Entity component mutations may be applied to clients in a different order than on the server.
636For example, if two entities are spawned in tick 1 on the server and their components are mutated in tick 2,
637then the client is guaranteed to see the spawns at the same tick, but the component mutations may appear later (but not earlier).
638
639If a component is dependent on other data, mutations to the component will only be applied to the client when that data has arrived.
640So if your component references another entity, mutations to that component will only be applied when the referenced entity has been spawned on the client.
641
642Mutations for despawned entities will be discarded automatically, but events, messages or components may reference despawned entities and should be handled with that in mind.
643
644Clients should never assume their world state is the same as the server's on any given tick value-wise.
645World state on the client is only "eventually consistent" with the server's.
646
647# Troubleshooting
648
649If you face any issue, try to enable logging to see what is going on.
650To enable logging, you can temporarily set `RUST_LOG` environment variable to `bevy_replicon=debug`
651(or `bevy_replicon=trace` for more noisy output) like this:
652
653```bash
654RUST_LOG=bevy_replicon=debug cargo run
655```
656
657You can also filter by specific module like this:
658
659```bash
660RUST_LOG=bevy_replicon::shared::protocol=debug cargo run
661```
662
663The exact method depends on the OS shell.
664
665Alternatively you can configure `LogPlugin` from Bevy to make it permanent.
666
667For deserialization errors on client we use `error` level which should be visible by default.
668But on server we use `debug` for it to avoid flooding server logs with errors caused by clients.
669*/
670#![cfg_attr(docsrs, feature(doc_cfg))]
671#![no_std]
672
673extern crate alloc;
674
675#[cfg(feature = "client")]
676pub mod client;
677pub mod compact_entity;
678pub mod postcard_utils;
679#[cfg(feature = "scene")]
680pub mod scene;
681#[cfg(feature = "server")]
682pub mod server;
683pub mod shared;
684#[cfg(all(feature = "server", feature = "client"))]
685pub mod test_app;
686
687pub mod prelude {
688    pub use super::{
689        RepliconPlugins,
690        shared::{
691            AuthMethod, RepliconSharedPlugin,
692            backend::{
693                ClientState, ClientStats, DisconnectRequest, ServerState,
694                channels::{Channel, RepliconChannels},
695                client_messages::ClientMessages,
696                connected_client::ConnectedClient,
697                server_messages::ServerMessages,
698            },
699            client_id::ClientId,
700            message::{
701                client_event::{ClientEventAppExt, ClientTriggerExt},
702                client_message::{ClientMessageAppExt, FromClient},
703                server_event::{ServerEventAppExt, ServerTriggerExt},
704                server_message::{SendMode, ServerMessageAppExt, ToClients},
705            },
706            protocol::{ProtocolHash, ProtocolHasher, ProtocolMismatch},
707            replication::{
708                Replicated,
709                command_markers::AppMarkerExt,
710                registry::rule_fns::RuleFns,
711                rules::{AppRuleExt, component::ReplicationMode},
712                signature::Signature,
713            },
714            replicon_tick::RepliconTick,
715        },
716    };
717
718    #[cfg(feature = "client")]
719    pub use super::client::{
720        ClientPlugin, ClientReplicationStats, ClientSystems, message::ClientMessagePlugin,
721    };
722
723    #[cfg(feature = "server")]
724    pub use super::server::{
725        AuthorizedClient, PriorityMap, ServerPlugin, ServerSystems,
726        message::ServerMessagePlugin,
727        related_entities::SyncRelatedAppExt,
728        visibility::{AppVisibilityExt, ComponentScope, FilterScope, VisibilityFilter},
729    };
730
731    #[cfg(feature = "client_diagnostics")]
732    pub use super::client::diagnostics::ClientDiagnosticsPlugin;
733}
734
735pub use bytes;
736pub use postcard;
737
738use bevy::{app::PluginGroupBuilder, prelude::*};
739use prelude::*;
740
741/// Plugin group for all replicon plugins.
742///
743/// Contains the following:
744/// * [`RepliconSharedPlugin`].
745/// * [`ServerPlugin`] - with feature `server`.
746/// * [`ServerMessagePlugin`] - with feature `server`.
747/// * [`ClientPlugin`] - with feature `client`.
748/// * [`ClientMessagePlugin`] - with feature `client`.
749/// * [`ClientDiagnosticsPlugin`] - with feature `client_diagnostics`.
750pub struct RepliconPlugins;
751
752impl PluginGroup for RepliconPlugins {
753    fn build(self) -> PluginGroupBuilder {
754        let mut group = PluginGroupBuilder::start::<Self>();
755        group = group.add(RepliconSharedPlugin::default());
756
757        #[cfg(feature = "server")]
758        {
759            group = group.add(ServerPlugin::default()).add(ServerMessagePlugin);
760        }
761
762        #[cfg(feature = "client")]
763        {
764            group = group.add(ClientPlugin).add(ClientMessagePlugin);
765        }
766
767        #[cfg(feature = "client_diagnostics")]
768        {
769            group = group.add(ClientDiagnosticsPlugin);
770        }
771
772        group
773    }
774}