use crate::_reexport::{ComponentProtocol, ComponentProtocolKind};
use anyhow::Result;
use bevy::ecs::component::Tick as BevyTick;
use bevy::ecs::system::SystemChangeTick;
use bevy::prelude::{Component, Entity, Resource};
use bevy::reflect::Map;
use bevy::utils::{EntityHashMap, HashMap};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use crate::channel::builder::{Channel, EntityActionsChannel, EntityUpdatesChannel};
use crate::netcode::ClientId;
use crate::packet::message::MessageId;
use crate::prelude::{EntityMap, MapEntities, NetworkTarget, Tick};
use crate::protocol::channel::ChannelKind;
use crate::protocol::Protocol;
use crate::shared::replication::components::{Replicate, ReplicationGroup, ReplicationGroupId};
pub mod components;
pub mod entity_map;
pub mod manager;
pub mod resources;
pub mod systems;
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct EntityActions<C, K> {
pub(crate) spawn: bool,
pub(crate) despawn: bool,
pub(crate) insert: Vec<C>,
pub(crate) remove: Vec<K>,
pub(crate) updates: Vec<C>,
}
impl<C, K> Default for EntityActions<C, K> {
fn default() -> Self {
Self {
spawn: false,
despawn: false,
insert: Vec::new(),
remove: Vec::new(),
updates: Vec::new(),
}
}
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct EntityActionMessage<C, K> {
sequence_id: MessageId,
pub(crate) actions: BTreeMap<Entity, EntityActions<C, K>>,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct EntityUpdatesMessage<C> {
last_action_tick: Tick,
pub(crate) updates: BTreeMap<Entity, Vec<C>>,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub enum ReplicationMessageData<C, K> {
Actions(EntityActionMessage<C, K>),
Updates(EntityUpdatesMessage<C>),
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct ReplicationMessage<C, K> {
pub(crate) group_id: ReplicationGroupId,
pub(crate) data: ReplicationMessageData<C, K>,
}
impl<C: MapEntities, K: MapEntities> MapEntities for ReplicationMessage<C, K> {
fn map_entities(&mut self, entity_map: &EntityMap) {
match &mut self.data {
ReplicationMessageData::Actions(m) => {
m.actions.values_mut().for_each(|entity_actions| {
entity_actions
.insert
.iter_mut()
.for_each(|c| c.map_entities(entity_map));
entity_actions
.updates
.iter_mut()
.for_each(|c| c.map_entities(entity_map));
})
}
ReplicationMessageData::Updates(m) => {
m.updates.values_mut().for_each(|entity_updates| {
entity_updates
.iter_mut()
.for_each(|c| c.map_entities(entity_map));
})
}
}
}
}
pub trait ReplicationSend<P: Protocol>: Resource {
fn new_connected_clients(&self) -> &Vec<ClientId>;
fn prepare_entity_spawn(
&mut self,
entity: Entity,
replicate: &Replicate,
target: NetworkTarget,
system_current_tick: BevyTick,
) -> Result<()>;
fn prepare_entity_despawn(
&mut self,
entity: Entity,
replicate: &Replicate,
target: NetworkTarget,
system_current_tick: BevyTick,
) -> Result<()>;
fn prepare_component_insert(
&mut self,
entity: Entity,
component: P::Components,
replicate: &Replicate,
target: NetworkTarget,
system_current_tick: BevyTick,
) -> Result<()>;
fn prepare_component_remove(
&mut self,
entity: Entity,
component_kind: P::ComponentKinds,
replicate: &Replicate,
target: NetworkTarget,
system_current_tick: BevyTick,
) -> Result<()>;
fn prepare_entity_update(
&mut self,
entity: Entity,
component: P::Components,
replicate: &Replicate,
target: NetworkTarget,
component_change_tick: BevyTick,
system_current_tick: BevyTick,
) -> Result<()>;
fn buffer_replication_messages(&mut self) -> Result<()>;
}
#[cfg(test)]
mod tests {
use crate::prelude::client::*;
use crate::prelude::*;
use crate::tests::protocol::*;
use crate::tests::stepper::{BevyStepper, Step};
use std::time::Duration;
#[test]
fn test_simple_component_remove() -> anyhow::Result<()> {
let frame_duration = Duration::from_millis(10);
let tick_duration = Duration::from_millis(10);
let shared_config = SharedConfig {
enable_replication: true,
tick: TickConfig::new(tick_duration),
..Default::default()
};
let link_conditioner = LinkConditionerConfig {
incoming_latency: Duration::from_millis(0),
incoming_jitter: Duration::from_millis(0),
incoming_loss: 0.0,
};
let sync_config = SyncConfig::default().speedup_factor(1.0);
let prediction_config = PredictionConfig::default().disable(false);
let interpolation_config = InterpolationConfig::default();
let mut stepper = BevyStepper::new(
shared_config,
sync_config,
prediction_config,
interpolation_config,
link_conditioner,
frame_duration,
);
stepper.client_mut().connect();
stepper.client_mut().set_synced();
for _ in 0..20 {
stepper.frame_step();
}
let server_entity = stepper
.server_app
.world
.spawn((Component1(0.0), Replicate::default()))
.id();
stepper.frame_step();
stepper.frame_step();
let client_entity = *stepper
.client()
.connection()
.base()
.replication_manager
.entity_map
.get_local(server_entity)
.unwrap();
assert_eq!(
stepper
.client_app
.world
.entity(client_entity)
.get::<Component1>()
.unwrap(),
&Component1(0.0)
);
stepper
.server_app
.world
.entity_mut(server_entity)
.remove::<Component1>();
stepper.frame_step();
stepper.frame_step();
assert!(stepper
.client_app
.world
.entity(client_entity)
.get::<Component1>()
.is_none());
Ok(())
}
}