diff --git a/overview b/overview index 3c0d515..ddd9393 100644 --- a/overview +++ b/overview @@ -21,7 +21,7 @@ Player______________ \ \ \ \ \ \ \ \ \ \ \ \ \ +--------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+ | Player | x | | | | | | | | | | | | x | | Ship | | x | x | x | x | | | | | | | | x | -| Fleet | | | | | | x | x | | | | | | x | +| Fleet | | x | | | | x | x | | | | | | x | | Asteroid | | o | x | | | | | x | x | x | x | | x | | Planet | | o | x | | | | | x | x | x | | x | x | | MeetingPoint | | | x | | | | | | | x | | | x | diff --git a/space-crush-app/src/main.rs b/space-crush-app/src/main.rs index ef80313..c0c264a 100644 --- a/space-crush-app/src/main.rs +++ b/space-crush-app/src/main.rs @@ -92,7 +92,11 @@ fn create_world(world: &mut World, player_id: Entity) { .unwrap(); } - let fleet_id = Fleet::builder().owner(planets[1]).build(world).unwrap(); + let fleet_id = Fleet::builder() + .player(player_id) + .meeting_point(planets[1]) + .build(world) + .unwrap(); for i in 0..9 { let r = 325.0 + 100.0 * random::(); diff --git a/space-crush-common/src/builder/fleet.rs b/space-crush-common/src/builder/fleet.rs index a04a68e..a81e3fe 100644 --- a/space-crush-common/src/builder/fleet.rs +++ b/space-crush-common/src/builder/fleet.rs @@ -1,7 +1,7 @@ use specs::{saveload::MarkedBuilder, Builder, Entity, World, WorldExt}; use crate::{ - components::{Fleet, MeetingPointOwned}, + components::{Fleet, MeetingPointOwned, PlayerOwned}, misc::{Persistence, WorldPersistence}, }; @@ -9,28 +9,40 @@ use super::Error; #[derive(Default, Clone)] pub struct FleetBuilder { - owner: Option, + player: Option, + meeting_point: Option, } impl FleetBuilder { pub fn build(&self, world: &mut World) -> Result { - let owner = self.owner.ok_or(Error::MissingValue("owner"))?; + let player = self.player.ok_or(Error::MissingValue("player"))?; + let meeting_point = self + .meeting_point + .ok_or(Error::MissingValue("meeting_point"))?; - let meeting_point_owned = MeetingPointOwned::new(owner); + let player_owned = PlayerOwned::new(player); + let meeting_point_owned = MeetingPointOwned::new(meeting_point); let fleet = Fleet::new(); let entity = world .create_entity() .marked::<::Marker>() .with(meeting_point_owned) + .with(player_owned) .with(fleet) .build(); Ok(entity) } - pub fn owner(mut self, meeting_point: Entity) -> Self { - self.owner = Some(meeting_point); + pub fn player(mut self, player: Entity) -> Self { + self.player = Some(player); + + self + } + + pub fn meeting_point(mut self, meeting_point: Entity) -> Self { + self.meeting_point = Some(meeting_point); self } diff --git a/space-crush-common/src/components/meeting_point.rs b/space-crush-common/src/components/meeting_point.rs index cc589dd..d8c4820 100644 --- a/space-crush-common/src/components/meeting_point.rs +++ b/space-crush-common/src/components/meeting_point.rs @@ -70,6 +70,17 @@ impl MeetingPoint { fleets: smallvec![], } } + + pub(crate) fn add_fleet(&mut self, player: usize, fleet: Entity) { + self.fleets.resize_with(player + 1, Default::default); + self.fleets[player] = Some(fleet); + } + + pub(crate) fn remove_fleet(&mut self, player: usize) { + if let Some(fleet) = self.fleets.get_mut(player) { + *fleet = None; + } + } } impl Component for MeetingPoint { diff --git a/space-crush-common/src/dispatcher.rs b/space-crush-common/src/dispatcher.rs index 8243607..226e051 100644 --- a/space-crush-common/src/dispatcher.rs +++ b/space-crush-common/src/dispatcher.rs @@ -3,7 +3,9 @@ use specs::{Dispatcher as Inner, DispatcherBuilder, World, WorldExt}; use crate::{ components::Player, resources::Global, - systems::{FleetControl, FleetOwnedUpdate, Process, ShipMovement, Ships}, + systems::{ + FleetControl, FleetOwnedUpdate, MeetingPointOwnedUpdate, Process, ShipMovement, Ships, + }, Error, }; @@ -23,6 +25,11 @@ impl<'a, 'b> Dispatcher<'a, 'b> { .with(Ships::new(world), "ships", &[]) .with(FleetControl::new(world)?, "fleet_control", &[]) .with(FleetOwnedUpdate::new(world), "fleet_owned_update", &[]) + .with( + MeetingPointOwnedUpdate::new(world), + "meeting_point_owned_update", + &[], + ) .build(); dispatcher.setup(world); diff --git a/space-crush-common/src/systems/meeting_point_owned_update.rs b/space-crush-common/src/systems/meeting_point_owned_update.rs new file mode 100644 index 0000000..71ed179 --- /dev/null +++ b/space-crush-common/src/systems/meeting_point_owned_update.rs @@ -0,0 +1,134 @@ +use std::collections::HashMap; + +use shrev::ReaderId; +use specs::{ + hibitset::BitSet, prelude::*, world::Index, Entities, Entity, ReadStorage, System, World, + WriteStorage, +}; + +use crate::{ + components::{MeetingPoint, MeetingPointOwned, Player, PlayerOwned}, + continue_if_none, + misc::{ComponentEvent, StorageHelper, StorageHelperMut}, +}; + +pub struct MeetingPointOwnedUpdate { + meeting_point_ids: BitSet, + meeting_point_owned_ids: BitSet, + old_meeting_point_ids: HashMap, + meeting_point_owned_event_id: ReaderId>, +} + +#[derive(SystemData)] +pub struct MeetingPointOwnedUpdateData<'a> { + entities: Entities<'a>, + players: ReadStorage<'a, Player>, + player_owned: ReadStorage<'a, PlayerOwned>, + meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, + meeting_points: WriteStorage<'a, MeetingPoint>, +} + +impl MeetingPointOwnedUpdate { + pub fn new(world: &mut World) -> Self { + WriteStorage::::setup(world); + + let meeting_point_ids = BitSet::new(); + let meeting_point_owned_ids = BitSet::new(); + let old_meeting_point_ids = HashMap::new(); + let meeting_point_owned_event_id = world + .system_data::>() + .register_event_reader(); + + Self { + meeting_point_ids, + meeting_point_owned_ids, + old_meeting_point_ids, + meeting_point_owned_event_id, + } + } +} + +impl<'a> System<'a> for MeetingPointOwnedUpdate { + type SystemData = MeetingPointOwnedUpdateData<'a>; + + fn run(&mut self, data: Self::SystemData) { + let MeetingPointOwnedUpdateData { + entities, + players, + player_owned, + meeting_point_owned, + mut meeting_points, + } = data; + + self.meeting_point_ids.clear(); + self.meeting_point_owned_ids.clear(); + self.old_meeting_point_ids.clear(); + + /* handle events */ + let events = meeting_point_owned + .channel() + .read(&mut self.meeting_point_owned_event_id); + for event in events { + match event { + ComponentEvent::Inserted(id, meeting_point_owned) => { + self.meeting_point_ids.add(meeting_point_owned.owner().id()); + self.meeting_point_owned_ids.add(*id); + } + ComponentEvent::Modified(id, meeting_point_owned) => { + self.meeting_point_ids.add(meeting_point_owned.owner().id()); + self.meeting_point_owned_ids.add(*id); + *self + .old_meeting_point_ids + .entry(*id) + .or_insert_with(|| meeting_point_owned.owner()) = + meeting_point_owned.owner(); + } + ComponentEvent::Removed(id, meeting_point_owned) => { + self.meeting_point_ids.add(meeting_point_owned.owner().id()); + self.meeting_point_owned_ids.add(*id); + *self + .old_meeting_point_ids + .entry(*id) + .or_insert_with(|| meeting_point_owned.owner()) = + meeting_point_owned.owner(); + } + } + } + + /* find new meeting_point ids */ + for (meeting_point_owned, _) in (&meeting_point_owned, &self.meeting_point_owned_ids).join() + { + self.meeting_point_ids.add(meeting_point_owned.owner().id()); + } + + /* update meeting_points */ + for (meeting_point_id, meeting_point, _) in + (&entities, &mut meeting_points, &self.meeting_point_ids).join() + { + let data = ( + &entities, + &meeting_point_owned, + &player_owned, + &self.meeting_point_owned_ids, + ); + + for (fleet_id, meeting_point_owned, player_owned, _) in data.join() { + let new_match = meeting_point_id == meeting_point_owned.owner(); + let old_match = match self.old_meeting_point_ids.get(&fleet_id.id()) { + Some(old_meeting_point_id) => meeting_point_id == *old_meeting_point_id, + None => false, + }; + + let player_id = player_owned.owner(); + let player = continue_if_none!(players.get(player_id)); + let player_index = player.index(); + + if old_match && !new_match { + meeting_point.remove_fleet(player_index); + } else if !old_match && new_match { + meeting_point.add_fleet(player_index, fleet_id); + } + } + } + } +} diff --git a/space-crush-common/src/systems/mod.rs b/space-crush-common/src/systems/mod.rs index a028e42..a05babf 100644 --- a/space-crush-common/src/systems/mod.rs +++ b/space-crush-common/src/systems/mod.rs @@ -1,11 +1,13 @@ mod fleet_control; mod fleet_owned_update; +mod meeting_point_owned_update; mod process; mod ship_movement; mod ships; pub use fleet_control::{FleetControl, FleetControlEvent}; pub use fleet_owned_update::FleetOwnedUpdate; +pub use meeting_point_owned_update::MeetingPointOwnedUpdate; pub use process::Process; pub use ship_movement::ShipMovement; pub use ships::Ships;