Replication conditions
Sometimes it's useful to replicate not every change, but with some frequency. Maybe we could have some replication conditions to allow this.
When designing the API, we need to let clients evaluate it.
This could be used by rollback crates. So basically lets say we replicate a component with the policy of "Send once", a rollback crate needs the ability to check "Would this tick even have a valid authoritative value?". Same thing for something like "Only send once per second". Basically if an entity can be confirmed, without that value matching the server, it needs to be possible to check for that. Otherwise we'll see issues like "Well every previous value is confirmed so Position(0, 0, 0) must still be valid, when really the intended way to network it is: send the starting position, use deterministic replication afterwards.
I have the following idea.
Introduce a ReplicateMutations(bool) component. If it's missing, we assume the value is true. Otherwise, we check the value. If the value is false, we skip sending mutations for this entity. If true, we send mutations as usual (if the value is mutated and the client hasn't acknowledged this entity for the last mutation tick).
If users want to replicate only initial values, they can mark ReplicateMutations(false) as a required component on spawn.
This component is quite barebones, but it can easily be used to build custom abstractions. For example, we could provide a built-in ReplicateWithDelay component. This component would require ReplicateMutations(false) and would contain a configurable timer that would be updated in a separate system before replication starts. When the timer expires, the system would change ReplicateMutations to true for one tick. This approach gives users full ECS access to implement custom conditions.
Introduce a ReplicateMutations(bool) component.
This seems to have some overlap with entity visibility. Would like to see pros/cons.
hello ! this feature would be really cool.
my use case is only initially replicating multiples components, and then update them on both client and server. it would be per component per entity then. for example, I would replicate health, but troop and projectile transform, or timers, should not be replicated after insertion to save a lot of bandwidth.
my first idea was a .run_if like run condition, for example .replicate_with::<MyComponent>(|| false) where the argument impl https://docs.rs/bevy/latest/bevy/prelude/trait.Condition.html
Would like to see pros/cons.
Visibility affects both updates and mutations, while this feature would control only mutations. @mirsella provided a good use case above. This could also be useful for slowing down replication of distant entities.
After thinking more about it, we can't provide a component-based API since rules shouldn't be global. It needs to be per-client (or even per-component). I need to think more about the API design. Maybe we could unify it with the visibility API somehow 🤔
.run_if-like conditions
These would be too expensive to evaluate, and unfortunately we need this per-client.
We could merge it with visibility settings by using a tri-state instead of a boolean: visible, updates-only, and hidden. Then we could implement #304 for them. But I don't like the ergonomics of this approach.
"Replicate once" relates to a component, not a client. It would be unergonomic to configure the visibility each time you spawn a deterministically moving platform. Maybe we should make it a parameter in replication rules? With replicate_once helper for convenience. This would be a global rule.
~~Alternatively, instead of providing conditions, we could introduce a prioritization system. All updates would be packed up to the player's bandwidth limit, and you could configure these weights based on game conditions. For example, with better network conditions, you could receive more frequent updates even for distant entities.~~ No, let's make prioritization it's own separate thing. So I think we can go with tri-state, just make "replicate once" based on component/rule.