use bevy::prelude::*;
use bytes::Bytes;
use super::{
FnsId, ReplicationRegistry,
ctx::{DespawnCtx, RemoveCtx, SerializeCtx, WriteCtx},
};
use crate::{
prelude::*,
shared::{
replication::{
deferred_entity::{DeferredChanges, DeferredEntity},
receive_markers::{EntityMarkers, ReceiveMarkers},
registry::ctx::EntitySpawner,
},
server_entity_map::ServerEntityMap,
},
};
pub trait TestFnsEntityExt {
#[must_use]
fn serialize(&mut self, fns_id: FnsId, server_tick: RepliconTick) -> Vec<u8>;
fn apply_write(
&mut self,
bytes: impl Into<Bytes>,
fns_id: FnsId,
message_tick: RepliconTick,
) -> &mut Self;
fn apply_remove(&mut self, fns_id: FnsId, message_tick: RepliconTick) -> &mut Self;
fn apply_despawn(self, message_tick: RepliconTick);
}
impl TestFnsEntityExt for EntityWorldMut<'_> {
fn serialize(&mut self, fns_id: FnsId, server_tick: RepliconTick) -> Vec<u8> {
let type_registry = self.world().resource::<AppTypeRegistry>();
let registry = self.world().resource::<ReplicationRegistry>();
let (_, component_id, fns) = registry.get(fns_id);
let mut message = Vec::new();
let ctx = SerializeCtx {
server_tick,
component_id,
type_registry,
};
let ptr = self.get_by_id(component_id).unwrap_or_else(|_| {
let components = self.world().components();
let component_name = components
.get_name(component_id)
.expect("function should require valid component ID");
panic!("serialization function require entity to have {component_name}");
});
unsafe {
fns.serialize(&ctx, ptr, &mut message)
.expect("serialization into memory should never fail");
}
message
}
fn apply_write(
&mut self,
data: impl Into<Bytes>,
fns_id: FnsId,
message_tick: RepliconTick,
) -> &mut Self {
let mut entity_markers = self.world_scope(EntityMarkers::from_world);
let receive_markers = self.world().resource::<ReceiveMarkers>();
entity_markers.read(receive_markers, &*self);
let entity = self.id();
self.world_scope(|world| {
world.resource_scope(|world, mut entity_map: Mut<ServerEntityMap>| {
world.resource_scope(|world, registry: Mut<ReplicationRegistry>| {
let type_registry = world.resource::<AppTypeRegistry>().clone();
let world_cell = world.as_unsafe_world_cell();
let mut spawner = EntitySpawner::new(unsafe { world_cell.world_mut() });
let world = unsafe { world_cell.world_mut() };
let mut changes = DeferredChanges::default();
let mut entity = DeferredEntity::new(world.entity_mut(entity), &mut changes);
let (_, component_id, fns) = registry.get(fns_id);
let mut ctx = WriteCtx {
entity_map: &mut entity_map,
type_registry: &type_registry,
component_id,
message_tick,
spawner: &mut spawner,
ignore_mapping: false,
};
fns.write(&mut ctx, &entity_markers, &mut entity, &mut data.into())
.expect("writing data into an entity shouldn't fail");
entity.flush();
})
})
});
self
}
fn apply_remove(&mut self, fns_id: FnsId, message_tick: RepliconTick) -> &mut Self {
let mut entity_markers = self.world_scope(EntityMarkers::from_world);
let receive_markers = self.world().resource::<ReceiveMarkers>();
entity_markers.read(receive_markers, &*self);
let entity = self.id();
self.world_scope(|world| {
world.resource_scope(|world, registry: Mut<ReplicationRegistry>| {
let mut changes = DeferredChanges::default();
let mut entity = DeferredEntity::new(world.entity_mut(entity), &mut changes);
let (_, component_id, fns) = registry.get(fns_id);
let mut ctx = RemoveCtx {
message_tick,
component_id,
};
fns.remove(&mut ctx, &entity_markers, &mut entity);
entity.flush();
})
});
self
}
fn apply_despawn(self, message_tick: RepliconTick) {
let registry = self.world().resource::<ReplicationRegistry>();
let ctx = DespawnCtx { message_tick };
(registry.despawn)(&ctx, self);
}
}