use std::{io::Cursor, marker::PhantomData};
use bevy::{
ecs::{component::ComponentId, world::EntityMut},
prelude::*,
ptr::Ptr,
utils::HashMap,
};
use bevy_renet::renet::Bytes;
use bincode::{DefaultOptions, Options};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use super::replicon_tick::RepliconTick;
use crate::client::{ClientMapper, ServerEntityMap};
pub trait AppReplicationExt {
fn replicate<C>(&mut self) -> &mut Self
where
C: Component + Serialize + DeserializeOwned;
fn replicate_mapped<C>(&mut self) -> &mut Self
where
C: Component + Serialize + DeserializeOwned + MapNetworkEntities;
fn replicate_with<C>(
&mut self,
serialize: SerializeFn,
deserialize: DeserializeFn,
remove: RemoveComponentFn,
) -> &mut Self
where
C: Component;
}
impl AppReplicationExt for App {
fn replicate<C>(&mut self) -> &mut Self
where
C: Component + Serialize + DeserializeOwned,
{
self.replicate_with::<C>(
serialize_component::<C>,
deserialize_component::<C>,
remove_component::<C>,
)
}
fn replicate_mapped<C>(&mut self) -> &mut Self
where
C: Component + Serialize + DeserializeOwned + MapNetworkEntities,
{
self.replicate_with::<C>(
serialize_component::<C>,
deserialize_mapped_component::<C>,
remove_component::<C>,
)
}
fn replicate_with<C>(
&mut self,
serialize: SerializeFn,
deserialize: DeserializeFn,
remove: RemoveComponentFn,
) -> &mut Self
where
C: Component,
{
let component_id = self.world.init_component::<C>();
let ignored_id = self.world.init_component::<Ignored<C>>();
let replicated_component = ReplicationInfo {
ignored_id,
serialize,
deserialize,
remove,
};
let mut replication_rules = self.world.resource_mut::<ReplicationRules>();
replication_rules.infos.push(replicated_component);
let replication_id = ReplicationId(replication_rules.infos.len() - 1);
replication_rules.ids.insert(component_id, replication_id);
self
}
}
#[derive(Resource)]
pub struct ReplicationRules {
pub despawn_fn: EntityDespawnFn,
ids: HashMap<ComponentId, ReplicationId>,
infos: Vec<ReplicationInfo>,
marker_id: ComponentId,
}
impl ReplicationRules {
pub(crate) fn get_marker_id(&self) -> ComponentId {
self.marker_id
}
pub(crate) fn get_ids(&self) -> &HashMap<ComponentId, ReplicationId> {
&self.ids
}
pub(crate) fn get(
&self,
component_id: ComponentId,
) -> Option<(ReplicationId, &ReplicationInfo)> {
let replication_id = self.ids.get(&component_id).copied()?;
let replication_info = unsafe { self.infos.get_unchecked(replication_id.0) };
Some((replication_id, replication_info))
}
pub(crate) unsafe fn get_info_unchecked(
&self,
replication_id: ReplicationId,
) -> &ReplicationInfo {
self.infos.get_unchecked(replication_id.0)
}
}
impl FromWorld for ReplicationRules {
fn from_world(world: &mut World) -> Self {
Self {
infos: Default::default(),
ids: Default::default(),
marker_id: world.init_component::<Replication>(),
despawn_fn: despawn_recursive,
}
}
}
pub type SerializeFn = fn(Ptr, &mut Cursor<Vec<u8>>) -> bincode::Result<()>;
pub type DeserializeFn = fn(
&mut EntityMut,
&mut ServerEntityMap,
&mut Cursor<Bytes>,
RepliconTick,
) -> bincode::Result<()>;
pub type RemoveComponentFn = fn(&mut EntityMut, RepliconTick);
pub type EntityDespawnFn = fn(EntityMut, RepliconTick);
pub(crate) struct ReplicationInfo {
pub(crate) ignored_id: ComponentId,
pub(crate) serialize: SerializeFn,
pub(crate) deserialize: DeserializeFn,
pub(crate) remove: RemoveComponentFn,
}
#[derive(Component, Clone, Copy, Default, Reflect)]
#[reflect(Component)]
pub struct Replication;
#[derive(Component)]
pub struct Ignored<T>(PhantomData<T>);
impl<T> Default for Ignored<T> {
fn default() -> Self {
Self(PhantomData)
}
}
#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub(crate) struct ReplicationId(usize);
pub trait MapNetworkEntities {
fn map_entities<T: Mapper>(&mut self, mapper: &mut T);
}
pub trait Mapper {
fn map(&mut self, entity: Entity) -> Entity;
}
pub fn serialize_component<C: Component + Serialize>(
component: Ptr,
cursor: &mut Cursor<Vec<u8>>,
) -> bincode::Result<()> {
let component: &C = unsafe { component.deref() };
DefaultOptions::new().serialize_into(cursor, component)
}
pub fn deserialize_component<C: Component + DeserializeOwned>(
entity: &mut EntityMut,
_entity_map: &mut ServerEntityMap,
cursor: &mut Cursor<Bytes>,
_tick: RepliconTick,
) -> bincode::Result<()> {
let component: C = DefaultOptions::new().deserialize_from(cursor)?;
entity.insert(component);
Ok(())
}
pub fn deserialize_mapped_component<C: Component + DeserializeOwned + MapNetworkEntities>(
entity: &mut EntityMut,
entity_map: &mut ServerEntityMap,
cursor: &mut Cursor<Bytes>,
_tick: RepliconTick,
) -> bincode::Result<()> {
let mut component: C = DefaultOptions::new().deserialize_from(cursor)?;
entity.world_scope(|world| {
component.map_entities(&mut ClientMapper::new(world, entity_map));
});
entity.insert(component);
Ok(())
}
pub fn remove_component<C: Component>(entity: &mut EntityMut, _tick: RepliconTick) {
entity.remove::<C>();
}
pub fn despawn_recursive(entity: EntityMut, _tick: RepliconTick) {
entity.despawn_recursive();
}