gschup / bevy_ggrs

Bevy plugin for the GGRS P2P rollback networking library.
Other
294 stars 41 forks source link

3d example, and other questions #101

Closed blueforesticarus closed 4 months ago

blueforesticarus commented 7 months ago

This is less a feature request an more a request for clarification on the documentation/examples side, that might help steer people in the right direction.

Is your feature request related to a problem? Please describe. I am evaluating GGRS for a bevy 3d coop game. Things that make me interested are

  1. it is the only p2p multiplayer framework for bevy (perhaps someone can correct me)
  2. deterministic rollback feels like the correct solution

However there are things that concern me:

  1. All examples I have seen are 2d, use a single int for exchanging inputs.

    • how would a 3d game even represent mouse movement (or do we treat the view vector itself as an input?)
    • what about games with complex context dependant ui (minecraft crafting table, lets say) . I can maybe imagine creating an input struct with all possible actions in the game a player can take. But this breaks alot of the modularity of ecs, is there a better way?
    • the input struct seems to require Pod, which I have a hard time wrapping my head around the implications of.
  2. Even very simple examples have desync issue, that are tricky to fix. ex: https://johanhelsing.studio/posts/extreme-bevy-desync-detection

    • Intuition warns me this might become unmanageable in a more complex game.
    • Ggrs has tools for desync detection, but none for recovery. I do not understand the model well enough to know whether an out of band system for resyncing is even possible (would ggrs play nice).
  3. All the example I have seen freeze the game until both characters connect. What about games that might have dynamic players, or dynamic NPCs?

    • how hard would it be to get ggrs to play nice with players that spawn in as they load.
    • how would a game using ggrs handle NPCs spawned via RNG

Describe the solution you'd like A 3d "fps" example (ideally with physics). Players are just capsules and if you click on another player (determined by raycast) that players color changes or something.

Describe alternatives you've considered Simply having a discussion here over some of these questions and perhaps adding "who is this for" section of the README. I am still unsure if ggrs is viable for my usecase.

gschup commented 7 months ago

Hi! thanks for looking into GGRS!

Inspired by GGPO, GGRS is intended to be used to synchronise state for short p2p sessions (think a single match of a fighting game) between a small amount of players (think 2-4). The use case is quite specific, but the strong assumptions allow for strong results (in this case, this is "playing online with no added input latency").

From the few pointers you have given me, it seems like you should probably look into other options, as well. I recommend a server/host-based architecture that allows both for flexible drop-in and -out of players and maybe an event-driven synchronisation of state to cater your inventory/crafting needs.

I'll answer each point separately, hope that will shed some light on your issue ;)

Inputs

how would a 3d game even represent mouse movement (or do we treat the view vector itself as an input?)

you could encode the mouse dx and dy with fixed precision into a u32 or similar.

what about games with complex context dependant ui (minecraft crafting table, lets say) . I can maybe imagine creating an input struct with all possible actions in the game a player can take. But this breaks alot of the modularity of ecs, is there a better way?

I think that games with menu and inventory are probably better off with event-based networking. Deriving the outcomes of menu interaction from dx/dy alone seems very unnecessary.

the input struct seems to require Pod, which I have a hard time wrapping my head around the implications of.

It's basically a more modular way of saying "this can be represented through a fixed-size sequence of bits"

Desync

Intuition warns me this might become unmanageable in a more complex game.

The assumption that all state can be derived from inputs alone is quite strong, but it leads to a very efficient networking model. Making sure the state is actually deterministic is quite hard in practice.

Ggrs has tools for desync detection, but none for recovery. I do not understand the model well enough to know whether an out of band system for resyncing is even possible (would ggrs play nice).

There currently is no way to sync state other than through inputs. Desync detection is intended for debugging only. A feature like this could potentially be added, but I am very unsure this is actually a good thing for the purposes of this library.

Drop-In players

how hard would it be to get ggrs to play nice with players that spawn in as they load.

currently not possible, but potentially doable (by adding the functionality to GGRS). In usecases like this, I usually suggest a server-based architecture to handle flexible drop-in and drop-out at any time.

how would a game using ggrs handle NPCs spawned via RNG

All RNG has to be fixed through seeding in order to assure that a pseudo-randomly generated number is exactly the same across all clients.

gschup commented 7 months ago

On the topic of a 3D example: I am sure we could enrich the repository by providing one. Thanks for the recommendation!

clinuxrulz commented 6 months ago

There is a gotcha too.

If you are using a SceneBundle (to use a gltf model for example), the SceneBundle will have child entities that get spawned automatically that will not be rolled back.

A workaround is to keep the player components simple, and have a separate non-rollback entity with the SceneBundle setting it's Transform to the same Transform as the player.

Rollbacks with parent/child entities leads to the Parent component and Children component pointing to entities that do not exist. So rollback of parent/child entity stuff needs to be either avoided, or the user need to reimplement their own parent/child stuff using Stable IDs rather than the Entity IDs to link them up.

Here is a little demo:

I use a FollowPlayer component to get the SceneBundle to follow the player on a separate entity.

gschup commented 4 months ago

closing this for now. feel free to reach out if further questions come up.