use super::SysTimer; use common::{ comp::{ Body, CanBuild, Gravity, Item, LightEmitter, Mass, MountState, Mounting, Player, Projectile, Scale, Stats, Sticky, }, msg::{EcsCompPacket, EcsResPacket}, state::{Time, TimeOfDay}, sync::{ CompPacket, EntityPackage, ResSyncPackage, StatePackage, SyncPackage, Uid, UpdateTracker, WorldSyncExt, }, }; use shred_derive::SystemData; use specs::{ Entity as EcsEntity, Join, ReadExpect, ReadStorage, System, World, Write, WriteExpect, }; use std::ops::Deref; /// Always watching /// This system will monitor specific components for insertion, removal, and modification pub struct Sys; impl<'a> System<'a> for Sys { type SystemData = ( Write<'a, SysTimer>, TrackedComps<'a>, WriteTrackers<'a>, ); fn run(&mut self, (mut timer, comps, mut trackers): Self::SystemData) { timer.start(); record_changes(&comps, &mut trackers); timer.end(); } } // Probably more difficult than it needs to be :p #[derive(SystemData)] pub struct TrackedComps<'a> { uid: ReadStorage<'a, Uid>, body: ReadStorage<'a, Body>, player: ReadStorage<'a, Player>, stats: ReadStorage<'a, Stats>, can_build: ReadStorage<'a, CanBuild>, light_emitter: ReadStorage<'a, LightEmitter>, item: ReadStorage<'a, Item>, scale: ReadStorage<'a, Scale>, mounting: ReadStorage<'a, Mounting>, mount_state: ReadStorage<'a, MountState>, mass: ReadStorage<'a, Mass>, sticky: ReadStorage<'a, Sticky>, gravity: ReadStorage<'a, Gravity>, projectile: ReadStorage<'a, Projectile>, } impl<'a> TrackedComps<'a> { pub fn create_entity_package(&self, entity: EcsEntity) -> EntityPackage { let uid = self .uid .get(entity) .copied() .expect("No uid to create an entity package") .0; let mut packets = Vec::new(); self.body .get(entity) .copied() .map(|c| packets.push(c.into())); self.player .get(entity) .cloned() .map(|c| packets.push(c.into())); self.stats .get(entity) .cloned() .map(|c| packets.push(c.into())); self.can_build .get(entity) .cloned() .map(|c| packets.push(c.into())); self.light_emitter .get(entity) .copied() .map(|c| packets.push(c.into())); self.item .get(entity) .cloned() .map(|c| packets.push(c.into())); self.scale .get(entity) .copied() .map(|c| packets.push(c.into())); self.mounting .get(entity) .cloned() .map(|c| packets.push(c.into())); self.mount_state .get(entity) .cloned() .map(|c| packets.push(c.into())); self.mass .get(entity) .copied() .map(|c| packets.push(c.into())); self.sticky .get(entity) .copied() .map(|c| packets.push(c.into())); self.gravity .get(entity) .copied() .map(|c| packets.push(c.into())); self.projectile .get(entity) .cloned() .map(|c| packets.push(c.into())); EntityPackage(uid, packets) } } #[derive(SystemData)] pub struct ReadTrackers<'a> { uid: ReadExpect<'a, UpdateTracker>, body: ReadExpect<'a, UpdateTracker>, player: ReadExpect<'a, UpdateTracker>, stats: ReadExpect<'a, UpdateTracker>, can_build: ReadExpect<'a, UpdateTracker>, light_emitter: ReadExpect<'a, UpdateTracker>, item: ReadExpect<'a, UpdateTracker>, scale: ReadExpect<'a, UpdateTracker>, mounting: ReadExpect<'a, UpdateTracker>, mount_state: ReadExpect<'a, UpdateTracker>, mass: ReadExpect<'a, UpdateTracker>, sticky: ReadExpect<'a, UpdateTracker>, gravity: ReadExpect<'a, UpdateTracker>, projectile: ReadExpect<'a, UpdateTracker>, } impl<'a> ReadTrackers<'a> { pub fn create_sync_package( &self, comps: &TrackedComps, filter: impl Join + Copy, ) -> SyncPackage { SyncPackage::new(&comps.uid, &self.uid, filter) .with_component( &comps.uid, &self.uid, self.body.deref(), &comps.body, filter, ) .with_component( &comps.uid, &self.uid, self.player.deref(), &comps.player, filter, ) .with_component( &comps.uid, &self.uid, self.stats.deref(), &comps.stats, filter, ) .with_component( &comps.uid, &self.uid, self.can_build.deref(), &comps.can_build, filter, ) .with_component( &comps.uid, &self.uid, self.light_emitter.deref(), &comps.light_emitter, filter, ) .with_component( &comps.uid, &self.uid, self.item.deref(), &comps.item, filter, ) .with_component( &comps.uid, &self.uid, self.scale.deref(), &comps.scale, filter, ) .with_component( &comps.uid, &self.uid, self.mounting.deref(), &comps.mounting, filter, ) .with_component( &comps.uid, &self.uid, self.mount_state.deref(), &comps.mount_state, filter, ) .with_component( &comps.uid, &self.uid, self.mass.deref(), &comps.mass, filter, ) .with_component( &comps.uid, &self.uid, self.sticky.deref(), &comps.sticky, filter, ) .with_component( &comps.uid, &self.uid, self.gravity.deref(), &comps.gravity, filter, ) .with_component( &comps.uid, &self.uid, self.projectile.deref(), &comps.projectile, filter, ) } } #[derive(SystemData)] pub struct WriteTrackers<'a> { uid: WriteExpect<'a, UpdateTracker>, body: WriteExpect<'a, UpdateTracker>, player: WriteExpect<'a, UpdateTracker>, stats: WriteExpect<'a, UpdateTracker>, can_build: WriteExpect<'a, UpdateTracker>, light_emitter: WriteExpect<'a, UpdateTracker>, item: WriteExpect<'a, UpdateTracker>, scale: WriteExpect<'a, UpdateTracker>, mounting: WriteExpect<'a, UpdateTracker>, mount_state: WriteExpect<'a, UpdateTracker>, mass: WriteExpect<'a, UpdateTracker>, sticky: WriteExpect<'a, UpdateTracker>, gravity: WriteExpect<'a, UpdateTracker>, projectile: WriteExpect<'a, UpdateTracker>, } fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) { // Update trackers trackers.uid.record_changes(&comps.uid); trackers.body.record_changes(&comps.body); trackers.player.record_changes(&comps.player); trackers.stats.record_changes(&comps.stats); trackers.can_build.record_changes(&comps.can_build); trackers.light_emitter.record_changes(&comps.light_emitter); trackers.item.record_changes(&comps.item); trackers.scale.record_changes(&comps.scale); trackers.mounting.record_changes(&comps.mounting); trackers.mount_state.record_changes(&comps.mount_state); trackers.mass.record_changes(&comps.mass); trackers.sticky.record_changes(&comps.sticky); trackers.gravity.record_changes(&comps.gravity); trackers.projectile.record_changes(&comps.projectile); } pub fn register_trackers(world: &mut World) { world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); } #[derive(SystemData)] pub struct TrackedResources<'a> { time: ReadExpect<'a, Time>, time_of_day: ReadExpect<'a, TimeOfDay>, } impl<'a> TrackedResources<'a> { pub fn create_res_sync_package(&self) -> ResSyncPackage { ResSyncPackage::new() .with_res(self.time.deref()) .with_res(self.time_of_day.deref()) } /// Create state package with resources included pub fn state_package(&self) -> StatePackage { StatePackage::new() .with_res(self.time.deref()) .with_res(self.time_of_day.deref()) } }