Bevy plugin for the GGRS P2P rollback networking library.

Overview

Bevy_GGRS

Bevy plugin for the ๐Ÿ‘‰ GGRS P2P rollback networking library. The plugin creates a custom stage with a separate schedule, which handles correctly advancing the gamestate, including rollbacks. It efficiently handles saving and loading of the gamestate by only snapshotting relevant parts of the world, as defined by the user. It is supposed to work with the latest released version of bevy.

For explanation on how to use it, check the ๐Ÿ‘‰ examples!

How it works

The GGRS plugin creates a custom GGRSStage which owns a separate schedule. Inside this schedule, the user can add stages and systems as they wish. When the default schedule runs the GGRSStage, it polls the session and executes resulting GGRSRequests, such as loading, saving and advancing the gamestate.

  • advancing the gamestate is done by running the internal schedule once.
  • saving the gamestate is done by creating a snapshot of entities tagged with a bevy_ggrs::Rollback component and saving only the components that were registered through register_rollback_type::(). The plugin internally keeps track of the snapshots together with the GGRS session.
  • loading the gamestate applies the snapshot by overwriting, creating and deleting entities tagged with a bevy_ggrs::Rollback component and updating the registered components values.

Since bevy_ggrs operates with a separate schedule, compatibility with other plugins might be complicated to achieve out of the box, as all gamestate-relevant systems needs to somehow end up inside the internal GGRS schedule to be updated together the rest of the game systems.

Development Status

โš ๏ธ Disclaimer โš ๏ธ : bevy_ggrs is in a very early stage. This plugin currently depends on the latest bevy developments and is thus incompatible with bevy releases on crates.io. Once bevy 0.6 releases, I will also make a stable release!

Licensing

Bevy_GGRS is dual-licensed under either

at your option.

Comments
  • Invalidated Entity's

    Invalidated Entity's

    To answer your side question:

    GGRS rewinds by loading an old state and overwriting current values. When loading a snapshot, items that have been deleted will have to be recreated and thus get a new entity id. In the same time, your inventory will be overwritten with the entity id vector it had at that point in time. These IDs will then probably be invalid.

    Originally posted by @gschup in https://github.com/gschup/bevy_ggrs/issues/11#issuecomment-1306735337


    I started a new thread to avoid cluttering the other one.

    So, if the entities in an inventory component could end up invalidated by the rollback, does that mean Bevy's hierarchy could get corrupted too?

    Because the hierarchy works by having Parent and Children components where Entitys are used for references, similar to an inventory.

    opened by zicklag 6
  • Map Entity IDs When Writing Snapshot to World

    Map Entity IDs When Writing Snapshot to World

    Resolves #29.

    I haven't really tested this yet, but this should fix entity mapping and hierarchy problems.

    If this works it'd be good to have some documentation on how this effects types that store entities.

    For instance, if you create your own Inventory component that needs to be synced, you must implement and reflect MapEntities for it, so that it will get the new entity IDs when the snapshots are applied.

    opened by zicklag 5
  • Fix PR Bevy 0.9 Update

    Fix PR Bevy 0.9 Update

    My attempt to help with #36.

    What I added with commit 63dc9afbcb548004bd7e1e5455eb969adda47767:

    cargo test passing with bevy 0.9.1

    • renamed and split register_rollback_type in register_rollback_component and register_rollback_resource
    • all examples now compile
    • up dependency to bevy 0.9.1 to use resources.iter()
    • remove refect_resource mod

    What I tested

    • cargo test.
    • run the examples (2 players + 1 spectator) on mac.
    opened by Vrixyz 2
  • [Question] What Will Be the New Snapshot Strategy?

    [Question] What Will Be the New Snapshot Strategy?

    Hey there!

    I saw this in the README:

    Since I am not happy with using bevy-reflect to save and load snapshots of the world, I am looking forward to this refactoring!

    I've been working on and exploring some Bevy networking stuff and I ended up using Reflect and a custom CompactReflectSerializer/Deserializer to serialize byte-efficient versions of all the components for snapshots.

    It sounds like you were using Reflect too, but aren't going to be anymore and I was curious how you were going to do the snapshots when the new stageless implementation lands, if it isn't going to use reflection.

    I might be able to make use of whatever it is.

    opened by zicklag 2
  • update for 0.8 with some more changes

    update for 0.8 with some more changes

    I tried to get #25 working and ran into some more issues. I don't know how to add more changes to someone else's PR, so here's a new one.

    Apparently a bevy 0.8 TypeRegistry contains some primitive types by default, which caused a "Unregistered Type in GGRS Type Registry" panic. I couldn't find a convenient way to construct a TypeRegistryArc that's actually empty in the new docs, so we have to construct one directly?

    I also had into short_name and type_name on a TypeRegistration actually returning different names for the same type. This made write_to_world overlook the components that were saved in the snapshot and delete them from the world instead.

    opened by thwischm 2
  • Trouble implementing the Config trait

    Trouble implementing the Config trait

    Describe the bug I'm having trouble implementing Config and wonder if something unusual is being required by this trait or some of it's dependencies. Maybe the bytemuck version fixing, though I don't know for sure.

    error[E0599]: the function or associated item `new` exists for struct `GGRSPlugin<GGRSConfig>`, but its trait bounds were not satisfied
       --> src/main.rs:79:31
        |
    63  | pub struct GGRSConfig;
        | ---------------------- doesn't satisfy `GGRSConfig: ggrs::Config`
    ...
    79  |     GGRSPlugin::<GGRSConfig>::new()
        |                               ^^^ function or associated item cannot be called on `GGRSPlugin<GGRSConfig>` due to unsatisfied trait bounds
        |
        = note: the following trait bounds were not satisfied:
                `GGRSConfig: ggrs::Config`
    note: the following trait must be implemented
       --> /Users/paul/.cargo/git/checkouts/ggrs-151f8bd9eb75dc5d/37b83c3/src/lib.rs:178:1
        |
    178 | / pub trait Config: 'static + Send + Sync {
    179 | |     /// The input type for a session. This is the only game-related data
    180 | |     /// transmitted over the network.
    181 | |     ///
    ...   |
    193 | |     type Address: Clone + PartialEq + Eq + Hash + Send + Sync;
    194 | | }
        | |_^
    
    error[E0277]: the trait bound `GGRSConfig: ggrs::Config` is not satisfied
      --> src/main.rs:79:5
       |
    79 |     GGRSPlugin::<GGRSConfig>::new()
       |     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ggrs::Config` is not implemented for `GGRSConfig`
       |
    note: required by a bound in `GGRSPlugin`
      --> /Users/paul/.cargo/git/checkouts/bevy_ggrs-8ac41541d9ef4c9f/928376d/src/lib.rs:73:26
       |
    73 | pub struct GGRSPlugin<T: Config + Send + Sync> {
       |                          ^^^^^^ required by this bound in `GGRSPlugin`
    

    To Reproduce Steps to reproduce the behavior:

    1. Update bevy_ggrs_demo to use bevy 0.7, and update ggrs and bevy_ggrs to git based versions.
    2. Try to run the project with cargo run

    Updated Cargo.toml in the bevy_ggrs_demo:

    [package]
    name = "bevy_ggrs_demo"
    version = "0.1.0"
    edition = "2021"
    
    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
    
    [dependencies]
    bevy_asset_loader = "0.8"
    bevy = "0.7"
    bytemuck = {version="1.7.3", features= ["derive"]}
    ggrs = { git = "https://github.com/gschup/ggrs", features=["sync-send"], rev="37b83c3478114e2876c133f255bc00b29c6af796" }
    bevy_ggrs = {git = "https://github.com/gschup/bevy_ggrs", rev="928376df6b37f391ef6593e0355ba5a737ec1492"}
    matchbox_socket = { git = "https://github.com/johanhelsing/matchbox", features = ["ggrs-socket"], rev="50c1e69e9f1c0f1e07e0ffd5161db0ce3f9267b5" }
    log = "0.4"
    
    [target.'cfg(target_arch = "wasm32")'.dependencies]
    ggrs = { git = "https://github.com/gschup/ggrs", features=["sync-send", "wasm-bindgen"], rev="37b83c3478114e2876c133f255bc00b29c6af796" }
    bevy_ggrs = {git = "https://github.com/gschup/bevy_ggrs", features=["wasm-bindgen"], rev="928376df6b37f391ef6593e0355ba5a737ec1492"}
    bevy-web-resizer = "0.1.0"
    web-sys = "0.3"
    

    Expected behavior Errors only related to the bevy 0.6 -> 0.7 upgrade.

    Desktop (please complete the following information):

    • OS: Only tested w/ an M1 Macbook.
    bug 
    opened by paul-english 2
  • Docs are broken

    Docs are broken

    Describe the bug The newest docs are broken

    To Reproduce Steps to reproduce the behavior:

    1. Go to https://docs.rs/crate/bevy_ggrs/latest
    2. See error

    Expected behavior I see the newest docs

    Screenshots image

    Desktop (please complete the following information):

    • OS: macOS
    • Browser [e.g. chrome, safari]: Firefox Nightly
    • Version [e.g. 22]: 101.0a1 (2022-04-29)

    Additional context Last working docs were 0.1.3

    bug 
    opened by janhohenheim 2
  • Fix Component Apply in Certain Cases

    Fix Component Apply in Certain Cases

    Removes and re-inserts components during snapshot restore, instead of using apply() which does an "update" not a "replace" of the current component data.

    For example, an apply() will do an in-place update such that apply an array to an array will add items to the array instead of completely replacing the current array with the new one.

    In Jumpy this caused a difficult to trace bug when updating the Children component for the Bevy hierarchy, where setting children to an empty array, actually left the component un-modified.

    opened by zicklag 1
  • Re-export `ggrs` Crate

    Re-export `ggrs` Crate

    This makes it easier to make sure your version of ggrs is the one compatible with bevy_ggrs and saves you from adding an extra dependency to your Cargo.toml.

    opened by zicklag 1
  • Only Depend on Bevy `bevy_render` not `render`

    Only Depend on Bevy `bevy_render` not `render`

    This removes this crate's dependency on the Bevy renderers such as bevy_text/ui/pbr, etc.

    It definitely was a little unintuitive that the render feature is different than the bevy_render feature.

    opened by zicklag 1
  • Despawned entities do not get respawned properly

    Despawned entities do not get respawned properly

    Describe the bug Despawned entities do not get respawned properly. this issue came up during the bevy_jam and is here to remind myself to look into it later.

    bug 
    opened by gschup 1
  • Invalidated Entities

    Invalidated Entities

    I just found that invalidating entities is still an issue, ~~but luckily I also discovered the fix we need in the bevy_hierarchy crate~~. Just posting here for a heads-up in case anybody runs into it:

    https://github.com/bevyengine/bevy/issues/6790

    For now, in my game I've just patched Bevy with the PR linked in the issue above to fix it.

    Originally posted by @zicklag in https://github.com/gschup/bevy_ggrs/issues/29#issuecomment-1329993581


    I'm re-opening this issue because the fix I opened in Bevy wasn't accepted, because it could cause hierarchy inconsistencies. That's a valid point, but we need the behavior I added to make our entity updates work right.

    I think what we have to do is we have to make a RollbackMapEntities trait that works essentially similar to the MapEntities trait, but with a slight behavior change, that we can implement for Parent and Children and that users can implement for their own component types that need entity mapping.

    opened by zicklag 0
  • Avoid triggering `Added` and `Changed` queries on all rollbacks?

    Avoid triggering `Added` and `Changed` queries on all rollbacks?

    When a rollback is triggered, bevy_ggrs restores a saved world snapshot. It updates components by first removing them, and then adding them again. This triggers all queries with Added<Component> or Changed<Component> in it, regardless of whether the component was already there and whether it changed.

    https://github.com/gschup/bevy_ggrs/blob/b730a0b1a765bca2cb79466c36d86cac08ae1a12/src/world_snapshot.rs#L177

    Sometimes systems have queries that react to other components being added or changed, triggering changes on every rollback. Sometimes, this just causes a small performance hit, other times, it leads to buggy behavior because setup code runs multiple times.

    Describe the solution you'd like Perhaps it's possible to only update the component if it's different?

    Additional context In regular game code, this is usually quite easy to fix or work around, but sometimes the affected code belongs to 3rd party crates, which are a lot harder to solve.

    enhancement 
    opened by johanhelsing 1
  • Document Non-Synced Bevy Gotcha's ( Events, etc. )

    Document Non-Synced Bevy Gotcha's ( Events, etc. )

    Is your feature request related to a problem? Please describe. The current design of Bevy GGRS doesn't snapshot and restore Bevy events, so events that are handled in a frame may not get handled again if the frame is rolled back to.

    Describe the solution you'd like We might need a custom event resource type that is compatible with the rollback and snapshot system.

    Describe alternatives you've considered A quick attempt to snapshot the Events<T> resource from Bevy didn't turn out so well. Events<T> isn't Clone even if T: Clone, which presents challenges, and the exposed public API doesn't allow us enough access to reasonably snapshot and restore it. Even if we could, we'd have to have a way to reset the read counters on the Local<ManualEventReader<T>> storage that powers the EventReader<T> system param.

    Essentially bevy's built-in event system probably just isn't suitable for snapshot and restore, and we need some alternative, or we just have to make this as a caveat and say that you have to use components for sending events or something like that.

    Additional context I'm actually a little confused why some events in my game seem to be working fine after rollback and restore. I'm still debugging. I'm still trying to get my game working in the SyncTest mode, and things get a little confusing to debug when the world is rolling back and forth the whole time. :D

    There's a small chance that I'm misunderstanding something and events could work fine without changes, but I highly doubt it.

    enhancement 
    opened by zicklag 8
  • Add a RollbackEventHook Trait

    Add a RollbackEventHook Trait

    This allows you to register functions that will be called in response to GGRS messages.

    I think I'm going to need this or something like it for my game, but I haven't tested it yet, so it's pending evaluation. I just wanted to get it up so you could look at it and give your thoughts on the idea.

    opened by zicklag 3
Releases(v0.10.0)
Owner
Georg Friedrich Schuppe
PhD Student @ KTH Stockholm
Georg Friedrich Schuppe
Lightweight p2p library. Support build robust stable connection on p2p/distributed network.

Chamomile Build a robust stable connection on p2p network features Support build a robust stable connection between two peers on the p2p network. Supp

CympleTech 94 Jan 6, 2023
A simple message based networking library for the bevy framework

Spicy Networking for Bevy bevy_spicy_networking is a solution to the "How do I connect multiple clients to a single server" problem in your bevy games

Cabbit Studios 67 Jan 1, 2023
Cross-platform, low level networking using the Rust programming language.

libpnet Linux โˆช OS X Build Status: Windows Build Status: Discussion and support: #libpnet on freenode / #rust-networking on irc.mozilla.org / #rust on

null 1.8k Jan 6, 2023
A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...

Tokio A runtime for writing reliable, asynchronous, and slim applications with the Rust programming language. It is: Fast: Tokio's zero-cost abstracti

Tokio 18.7k Dec 30, 2022
The Rust Implementation of libp2p networking stack.

Central repository for work on libp2p This repository is the central place for Rust development of the libp2p spec. Warning: While we are trying our b

libp2p 3k Jan 4, 2023
Painless peer-to-peer WebRTC networking for rust wasm

Matchbox Painless peer-to-peer WebRTC networking for rust wasm applications. The goal of the Matchbox project is to enable udp-like, unordered, unreli

Johan Klokkhammer Helsing 363 Jan 5, 2023
Final Project for "Computer Networking Security": A Layer-3 VPN implementation over TLS

Final Project for "Computer Networking Security": A Layer-3 VPN implementation over TLS

Siger Yang 2 Jun 7, 2022
a decentralized p2p chatroom app built for practice

Yosup is an app made for the purpose of learning libp2p technology, asynchronous rust, ways to incorporate a single protocol over multiple interfaces, and cryptography.

Louis Birla 2 Jan 14, 2022
Reliable p2p network connections in Rust with NAT traversal

Reliable p2p network connections in Rust with NAT traversal. One of the most needed libraries for any server-less / decentralised projects

MaidSafe-Archive 948 Dec 20, 2022
Prototype for Koru, a parametrized p2p monetary system.Checkout

Koru About This is a prototype for Koru, a parametrized p2p monetary system consisting of: Mutual credit Voting and decision making platform (for econ

Koru 6 Oct 9, 2022
Reliable p2p network connections in Rust with NAT traversal

Reliable p2p network connections in Rust with NAT traversal. One of the most needed libraries for any server-less, decentralised project.

MaidSafe-Archive 948 Dec 20, 2022
P2P File Transfer

P2P File Transfer Overview This is a small project to help solve a problem that should've been solved by now: file transfer. For in-person file transf

Saksham Mittal 2 Dec 15, 2022
A proof of concept implementation of RTSP over Dahua P2P protocol.

RTSP Streaming with Dahua P2P Protocol Implementation This is a proof of concept implementation of RTSP over Dahua P2P protocol. It works with Dahua a

null 6 Dec 21, 2023
A Rust compiler plugin and support library to annotate overflow behavior

overflower This project contains a compiler plugin and supporting library to allow the programmer to annotate their code to declare how integer overfl

null 104 Nov 28, 2022
Barebones egui_baseview vst2 plugin with basic parameter control

egui_baseview_test_vst2 Based on baseview_test_vst2 Barebones baseview/egui_baseview vst2 plugin. It implements an egui ui for the vst gain effect exa

null 16 Dec 18, 2022
Barebones imgui_baseview vst2 plugin with basic parameter control

imgui_baseview_test_vst2 Based on baseview_test_vst2 Barebones baseview/imgui_baseview vst2 plugin. It implements a imgui-rs ui for the vst gain effec

null 3 Nov 16, 2021
A WireGuard UWP VPN plugin.

WireGuard UWP A Universal Windows Platform (UWP) VPN Plug-in for WireGuardยฎ written in Rust. Windows provides a plug-in based model for adding 3rd-par

Luqman Aden 92 Dec 13, 2022
Hammerspoon plugin and API to interact with Yabai socket directly

Yabai.spoon NOTE: no longer using it or intending to maintain it see #2. Yabai.spoon is lua 5.4 library to interact with yabai socket directly within

null 2 May 17, 2022
A mini-CI as a Zellij plugin

About This Zellij plugin is a "mini-ci". It allows you to specify commands that will run in parallel, keeping track of completed commands and their ex

Aram Drevekenin 10 Jun 22, 2023