use std::collections::HashMap; use shrev::ReaderId; use specs::{prelude::*, world::Index, Entities, ReadStorage, System, World, WriteStorage}; use crate::{ components::{Fleet, FleetOwned, Ship}, misc::ComponentEvent, }; pub struct FleetOwnedUpdate { fleet_ids: BitSet, fleet_owned_ids: BitSet, old_fleet_ids: HashMap, fleet_owned_event_id: ReaderId>, } impl FleetOwnedUpdate { pub fn new(world: &mut World) -> Self { let fleet_ids = BitSet::new(); let fleet_owned_ids = BitSet::new(); let old_fleet_ids = HashMap::new(); let fleet_owned_event_id = unsafe { WriteStorage::::setup(world); let mut fleet_owned = world.system_data::>(); fleet_owned .unprotected_storage_mut() .channel_mut() .register_reader() }; Self { fleet_ids, fleet_owned_ids, old_fleet_ids, fleet_owned_event_id, } } } #[derive(SystemData)] pub struct FleetOwnedUpdateData<'a> { entities: Entities<'a>, ships: ReadStorage<'a, Ship>, fleets: WriteStorage<'a, Fleet>, fleet_owned: ReadStorage<'a, FleetOwned>, } impl<'a> System<'a> for FleetOwnedUpdate { type SystemData = FleetOwnedUpdateData<'a>; fn run(&mut self, data: Self::SystemData) { let FleetOwnedUpdateData { entities, ships, mut fleets, fleet_owned, } = data; self.fleet_ids.clear(); self.fleet_owned_ids.clear(); self.old_fleet_ids.clear(); /* handle events */ let events = fleet_owned .unprotected_storage() .channel() .read(&mut self.fleet_owned_event_id); for event in events { match event { ComponentEvent::Inserted(id, fleet_owned) => { self.fleet_ids.add(fleet_owned.owner.id()); self.fleet_owned_ids.add(*id); } ComponentEvent::Modified(id, fleet_owned) => { self.fleet_ids.add(fleet_owned.owner.id()); self.fleet_owned_ids.add(*id); *self.old_fleet_ids.entry(*id).or_insert(fleet_owned.owner) = fleet_owned.owner; } ComponentEvent::Removed(id, fleet_owned) => { self.fleet_ids.add(fleet_owned.owner.id()); self.fleet_owned_ids.add(*id); *self.old_fleet_ids.entry(*id).or_insert(fleet_owned.owner) = fleet_owned.owner; } } } /* update fleets */ for (fleet_id, fleet_info, _) in (&entities, &mut fleets, &self.fleet_ids).join() { let data = (&entities, &ships, &fleet_owned, &self.fleet_owned_ids); for (ship_id, ship, fleet_owned, _) in data.join() { let new_match = fleet_id == fleet_owned.owner; let old_match = match self.old_fleet_ids.get(&ship_id.id()) { Some(old_fleet_id) => fleet_id == *old_fleet_id, None => false, }; if old_match && !new_match { fleet_info.owned.remove(ship_id.id()); fleet_info.count[ship.type_] = fleet_info.count[ship.type_].saturating_sub(1); } else if !old_match && new_match { fleet_info.owned.add(ship_id.id()); fleet_info.count[ship.type_] += 1; } } } } }