#authoritative-server #replication #networking #bevy-networking #bevy

bevy_bundlication

Replication rules for bevy_replicon based on a bundle pattern

12 breaking releases

Uses new Rust 2024

new 0.12.0 Apr 27, 2025
0.11.0 Mar 24, 2025
0.10.0 Mar 14, 2025
0.8.0 Dec 2, 2024
0.0.2 Nov 14, 2023

#1078 in Game dev

Download history 116/week @ 2025-02-02 17/week @ 2025-02-09 17/week @ 2025-02-16 4/week @ 2025-02-23 15/week @ 2025-03-02 100/week @ 2025-03-09 27/week @ 2025-03-16 109/week @ 2025-03-23 11/week @ 2025-03-30 2/week @ 2025-04-13

122 downloads per month

MIT/Apache

18KB
104 lines

bevy_bundlication

Network replication for bevy based on a bundle pattern. Replication group rules for bevy_replicon using a bundle-like API.

Goals

  • Simplify the definition of replication groups
  • Simplify bandwidth optimization

Getting started

bevy_bundlication works with a pattern similar to a Bundle from bevy. Anything matching the bundle gets networked. Each field needs to implement NetworkedComponent, this can be done manually or trough a blanket impl on types that have Component, Serialze and Deserialize. For types where the blanket impl causes conflicts, the #[bundlication(as = Wrapper)] attribute can be used where Wrapper is a type that impletements NetworkedWrapper<YourType>.

Bundles can be registered to bevy_replicon using replicate_group::<Bundle>().

use bevy::prelude::*;
use bevy_replicon::prelude::*;

#[derive(NetworkedBundle)]
pub struct PlayerPositionBundle {
    // The content of this field doesn't get sent, and it will be received as the default value,
    // it therefor requires neither Serialize/Deserialize nor NetworkedComponent
    #[bundlication(no_send)]
    pub player: Player,
    // This component is sent and spawned as is
    pub speed: Speed,
    // We replicate Transform, but it is serialized/deserialized using the logic of JustTranslation
    #[bundlication(as = JustTranslation)]
    pub translation: Transform,
    // If we also use this as a bundle and have fields we don't want replicon to consider, we can
    // add the skip attribute
    #[bundlication(skip)]
    pub skipped: GlobalTransform,
}

pub struct MovementPlugin;

impl Plugin for MovementPlugin {
    fn build(&self, app: &mut App) {
        // To replicate the bundle, we register our bundle to bevy_replicon
        app.replicate_group::<PlayerPositionBundle>();
    }
}

use bevy_bundlication::prelude::*;
use serde::{Serialize, Deserialize};

// We need Default on Player because we use the no_send attribute
#[derive(Component, Default)]
pub struct Player(u128);

// Speed derives all required traits for the NetworkedBundle blanket impl
#[derive(Component, Serialize, Deserialize)]
pub struct Speed(f32);

// We define a type to network a type we don't own in a different way than its default behavior.
// This can also be used to network components without Serialize/Deserialize
// In this case we only network the translation part of Transform
#[derive(Serialize, Deserialize)]
pub struct JustTranslation(Vec3);

impl NetworkedWrapper<Transform> for JustTranslation {
    fn write_data(from: &Transform, w: impl std::io::Write, _: &SerializeCtx) -> Result<()> {
        serialize(w, &from.translation)?;
        Ok(())
    }

    fn read_new(r: impl std::io::Read, _: &mut DeserializeCtx) -> Result<Transform> {
        let translation: Vec3 = deserialize(r)?;
        Ok(Transform::from_translation(translation))
    }
}

License

All code in this repository is dual-licensed under either:

at your option.

Dependencies

~27MB
~446K SLoC