cBournhonesque / lightyear

A networking library to make multiplayer games for the Bevy game engine
https://cbournhonesque.github.io/lightyear/book
Apache License 2.0
422 stars 44 forks source link

Bandwidth reduction: enable setting a replication rate per entity? #126

Closed cBournhonesque closed 3 months ago

cBournhonesque commented 7 months ago

Unreal does this with NetUpdateFrequency: https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Actors/ReplicationFlow/

Clonkex commented 6 months ago

It's also worth considering the option of bandwidth-limited syncing, like Halo Reach uses. Instead of always syncing every entity, collect all the entities in need of syncing, sort them by some priority value (calculated, for instance, by a priority accumulator + closeness to the camera * some importance value), then start serialising them until you run reach some specified size. For any entities that got serialised, reset the accumulator to 0, for any others, increment the accumulator.

This risks increased mispredictions because dependant entities may be synchronised out of sync and thus the predictions may not always be accurate, but it allows very precise control of bandwidth and is still always moving towards "eventually accurate".

I have no idea if the precise bandwidth control is worth the extra complexity and slightly dodgy predictions but I've always liked the idea. I implemented it in my Godot networking system but I never got further than two capsules moving around so I never got as far as testing how it behaves in a real game.

cBournhonesque commented 5 months ago

Bandwidth-limiting syncing is already implemented :) See this section of the book for more information: https://cbournhonesque.github.io/lightyear/book/concepts/advanced_replication/bandwidth_management.html#prioritizing-replication-groups

It's pretty much exactly what you described:

Normally it shouldn't increase mispredictions too much, because entities within a ReplicationGroup are always replicated together.

Here is an example showcasing it: https://github.com/cBournhonesque/lightyear/tree/main/examples/priority

I was wondering if on top of that I could update the replication_rate for a given ReplicationGroup, primarily as a way to save on CPU usage. For example for some unimportant background element the replication rate could be 1Hz instead of 10Hz, and the entity wouldn't get included in the priority accumulation most of the time.

Clonkex commented 5 months ago

Aha! Well that'll teach me to comment before I finish reading the docs 🤦‍♂️

philpax commented 4 months ago

I'd also like to express my interest in this, or some variant of it.

I have a game world time (i.e. time of day) that I'd like to synchronise between the server and the client, and that time ticks at a regular rate (i.e. a game-minute every real-second).

I'd like to periodically synchronise the client's time with the server-authoritative time to make sure it doesn't drift too much, and to allow for the server changing the time. I think this would just be running the same system on both the server and the client with prediction, but I'd like to throttle how frequently that update occurs.

Is this currently possible, or will it depend on this issue? Additionally, should I store this in a resource or an entity?

cBournhonesque commented 4 months ago

I think this is already possible; you could either:

I think this issue is more focused on saving CPU usage by skipping some entities in the replication systems (for which we know we only want infrequent updates)

cBournhonesque commented 4 months ago

I have a use-case (see issue) where we might want to send some messages as soon as possible: when predicting other players, we want to rebroadcast a player's inputs immediately to other players.

This conflicts with the send_interval setting. I wonder if we should just get rid of it altogether, and add a send_interval for each Channel or ReplicationGroup. (or we could leave it, and then the user would be expected to set it to 0.0 if they need to send something every frame, such as client inputs).

So the general flow is:

cBournhonesque commented 3 months ago

Enabled sending a send_frequency per replication group here: https://github.com/cBournhonesque/lightyear/pull/465

cBournhonesque commented 3 months ago

The send_interval can now be sent per channel: https://github.com/cBournhonesque/lightyear/pull/466