Skip to content

Commit

Permalink
physnet: use replicate client for cube state
Browse files Browse the repository at this point in the history
  • Loading branch information
TheButlah committed Jun 11, 2024
1 parent 563d4c8 commit f441f70
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 3 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ rust-version = "1.78.0"

[workspace.dependencies]
base64 = "0.21.7"
bevy = "0.13"
bevy = { version = "0.13", features = ["serialize"] }
bevy-inspector-egui = "0.23.4"
bevy_egui = { git = "https://github.com/Schmarni-Dev/bevy_egui/", branch = "nexus-use-bevy-0.13" }
bevy_egui_keyboard.path = "crates/bevy_egui_keyboard"
Expand Down
2 changes: 2 additions & 0 deletions apps/networked_physics_demo/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ bevy-inspector-egui.workspace = true
bevy.workspace = true
bevy_flycam.workspace = true
bevy_rapier3d.workspace = true
bytes.workspace = true
color-eyre.workspace = true
derive_more.workspace = true
rand.workspace = true
rand_xoshiro.workspace = true
replicate-client.workspace = true
serde_json.workspace = true
3 changes: 3 additions & 0 deletions apps/networked_physics_demo/client/src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use bevy_rapier3d::{
};
use rand::Rng;

use crate::netcode::LocalAuthority;
use crate::rng::seed_rng;
use crate::{AppExt, GameModeState};

Expand Down Expand Up @@ -160,6 +161,8 @@ fn handle_spawn_cube(
RigidBody::Dynamic,
spawner.collider.clone(),
));
cube_entity.insert(LocalAuthority);

if let Some(name) = &spawn_cube_evt.name {
cube_entity.insert(Name::new(name.clone()));
} else {
Expand Down
133 changes: 131 additions & 2 deletions apps/networked_physics_demo/client/src/netcode.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
use std::ops::{Deref, DerefMut};

use bevy::{
app::{Plugin, Update},
app::{Plugin, PostUpdate, PreUpdate, Update},
ecs::{
component::Component,
entity::Entity,
event::{Event, EventReader},
query::{Added, With, Without},
schedule::NextState,
system::ResMut,
system::{Commands, Query, Res, ResMut, Resource},
},
log::trace,
reflect::Reflect,
transform::components::{GlobalTransform, Transform},
};
use replicate_client::common::data_model::{DataModel, Entity as DmEntity};

use crate::GameModeState;

Expand All @@ -17,6 +25,9 @@ impl Plugin for NetcodePlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app.register_type::<ConnectToManager>()
.add_event::<ConnectToManager>()
.init_resource::<NetcodeDataModel>()
.add_systems(PreUpdate, from_data_model)
.add_systems(PostUpdate, (spawn_entities, to_data_model))
.add_systems(Update, on_connect_to_manager_evt);
}
}
Expand All @@ -37,3 +48,121 @@ fn on_connect_to_manager_evt(
next_state.set(GameModeState::InMinecraft);
}
}

/// Add this to entities that should be synchronized over the network
#[derive(Debug, Eq, PartialEq, Component)]
pub struct Synchronized(pub DmEntity);

/// Add to entities that we claim to have authority over. Entities that are
/// `Synchronized` but don't have this component are entities that we do not
/// have authority over.
///
/// Note that according to its ownership rules, the data model may remove this
/// component and start overwriting the state in the data model, indicating that
/// remote peers have authority.
#[derive(Debug, Component)]
pub struct LocalAuthority;

#[derive(Debug, Default, Resource)]
pub struct NetcodeDataModel {
dm: DmEnum,
}

impl Deref for NetcodeDataModel {
type Target = DataModel;

fn deref(&self) -> &Self::Target {
&self.dm
}
}

impl DerefMut for NetcodeDataModel {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.dm
}
}

#[derive(Debug)]
pub enum DmEnum {
#[allow(dead_code)]
Remote(replicate_client::instance::Instance),
Local(DataModel),
}

impl Deref for DmEnum {
type Target = DataModel;

fn deref(&self) -> &Self::Target {
match self {
Self::Remote(instance) => instance.data_model(),
Self::Local(dm) => dm,
}
}
}

impl DerefMut for DmEnum {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Self::Remote(instance) => instance.data_model_mut(),
Self::Local(dm) => dm,
}
}
}

impl Default for DmEnum {
fn default() -> Self {
Self::Local(DataModel::default())
}
}

// TODO: we should have some sort of state extractor trait that the netcode plugin can
// use instead of hard coding this
fn to_data_model(
mut dm: ResMut<NetcodeDataModel>,
query: Query<(&GlobalTransform, &Synchronized), With<LocalAuthority>>,
) {
for (trans, sync) in query.iter() {
trace!(entity=?sync.0, "wrote state");
let serialized = serialize_transform(&trans.compute_transform());
dm.dm
.update(sync.0, serialized.into())
.expect("todo: figure out what to do when server despawns entities")
}
}

fn spawn_entities(
mut dm: ResMut<NetcodeDataModel>,
query: Query<
(Entity, &GlobalTransform),
(Added<LocalAuthority>, Without<Synchronized>),
>,
mut commands: Commands,
) {
for (entity, trans) in query.iter() {
trace!(bevy_entity=?entity, "spawning DataModel entity");
let dm_entity =
dm.spawn(serialize_transform(&trans.compute_transform()).into());

commands.entity(entity).insert(Synchronized(dm_entity));
}
}

fn from_data_model(
dm: Res<NetcodeDataModel>,
mut query: Query<(&mut Transform, &Synchronized), Without<LocalAuthority>>,
) {
for (mut trans, sync) in query.iter_mut() {
let serialized = dm
.get(sync.0)
.expect("todo: figure out what to do when server despawns entities");
*trans = deserialize_transform(serialized);
}
}

fn serialize_transform(trans: &Transform) -> Vec<u8> {
serde_json::ser::to_vec(trans).expect("serialization should always succeed")
}

fn deserialize_transform(bytes: &[u8]) -> Transform {
serde_json::from_slice(bytes).expect("todo: handle deserialization failure")
}
2 changes: 2 additions & 0 deletions crates/replicate/client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub use replicate_common as common;

pub mod instance;
pub mod manager;

Expand Down

0 comments on commit f441f70

Please sign in to comment.