| @@ -1,5 +1,5 @@ | |||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{Fleet, Orbit, Position}, | |||||
| components::{Fleet, MeetingPoint, Position}, | |||||
| continue_if_none, | continue_if_none, | ||||
| misc::LogResult, | misc::LogResult, | ||||
| }; | }; | ||||
| @@ -20,7 +20,7 @@ pub struct FleetData<'a> { | |||||
| game_state: ReadExpect<'a, GameState>, | game_state: ReadExpect<'a, GameState>, | ||||
| camera: ReadExpect<'a, Camera>, | camera: ReadExpect<'a, Camera>, | ||||
| positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
| orbits: ReadStorage<'a, Orbit>, | |||||
| meeting_points: ReadStorage<'a, MeetingPoint>, | |||||
| fleets: ReadStorage<'a, Fleet>, | fleets: ReadStorage<'a, Fleet>, | ||||
| } | } | ||||
| @@ -49,7 +49,7 @@ impl<'a> System<'a> for Fleets { | |||||
| game_state, | game_state, | ||||
| camera, | camera, | ||||
| positions, | positions, | ||||
| orbits, | |||||
| meeting_points, | |||||
| fleets, | fleets, | ||||
| } = data; | } = data; | ||||
| @@ -57,8 +57,8 @@ impl<'a> System<'a> for Fleets { | |||||
| gl::enable(gl::BLEND); | gl::enable(gl::BLEND); | ||||
| for (position, orbit) in (&positions, &orbits).join() { | |||||
| let fleet_id = continue_if_none!(orbit.fleet(player_index)); | |||||
| for (position, meeting_point) in (&positions, &meeting_points).join() { | |||||
| let fleet_id = continue_if_none!(meeting_point.fleet(player_index)); | |||||
| let fleet = continue_if_none!(fleets.get(fleet_id)); | let fleet = continue_if_none!(fleets.get(fleet_id)); | ||||
| gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | ||||
| @@ -1,6 +1,6 @@ | |||||
| use glc::vector::{Angle, Vector2f, Vector4f}; | use glc::vector::{Angle, Vector2f, Vector4f}; | ||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{Orbit, Position}, | |||||
| components::{MeetingPoint, Position}, | |||||
| constants::SHIP_ORBIT_DISTANCE_MAX, | constants::SHIP_ORBIT_DISTANCE_MAX, | ||||
| }; | }; | ||||
| use specs::{prelude::*, ReadStorage, System, World, WriteExpect}; | use specs::{prelude::*, ReadStorage, System, World, WriteExpect}; | ||||
| @@ -8,41 +8,44 @@ use specs::{prelude::*, ReadStorage, System, World, WriteExpect}; | |||||
| use crate::resources::Geometry; | use crate::resources::Geometry; | ||||
| #[derive(Default)] | #[derive(Default)] | ||||
| pub struct Orbits {} | |||||
| pub struct MeetingPoints {} | |||||
| #[derive(SystemData)] | #[derive(SystemData)] | ||||
| pub struct OrbitsData<'a> { | |||||
| pub struct MeetingPointsData<'a> { | |||||
| geometry: WriteExpect<'a, Geometry>, | geometry: WriteExpect<'a, Geometry>, | ||||
| positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
| orbits: ReadStorage<'a, Orbit>, | |||||
| meeting_points: ReadStorage<'a, MeetingPoint>, | |||||
| } | } | ||||
| impl<'a> System<'a> for Orbits { | |||||
| type SystemData = OrbitsData<'a>; | |||||
| impl<'a> System<'a> for MeetingPoints { | |||||
| type SystemData = MeetingPointsData<'a>; | |||||
| fn run(&mut self, data: Self::SystemData) { | fn run(&mut self, data: Self::SystemData) { | ||||
| let OrbitsData { | |||||
| let MeetingPointsData { | |||||
| mut geometry, | mut geometry, | ||||
| positions, | positions, | ||||
| orbits, | |||||
| meeting_points, | |||||
| } = data; | } = data; | ||||
| gl::enable(gl::BLEND); | gl::enable(gl::BLEND); | ||||
| for (position, orbit) in (&positions, &orbits).join() { | |||||
| for (position, meeting_point) in (&positions, &meeting_points).join() { | |||||
| gl::blend_func(gl::SRC_ALPHA, gl::ONE); | gl::blend_func(gl::SRC_ALPHA, gl::ONE); | ||||
| gl::blend_equation(gl::FUNC_ADD); | gl::blend_equation(gl::FUNC_ADD); | ||||
| geometry.render_lines( | geometry.render_lines( | ||||
| Vector4f::new(0.5, 0.5, 0.5, 0.05), | Vector4f::new(0.5, 0.5, 0.5, 0.05), | ||||
| &create_circle(position.pos(), orbit.min()), | |||||
| &create_circle(position.pos(), meeting_point.min()), | |||||
| ); | ); | ||||
| geometry.render_lines( | geometry.render_lines( | ||||
| Vector4f::new(0.5, 0.5, 0.5, 0.05), | Vector4f::new(0.5, 0.5, 0.5, 0.05), | ||||
| &create_circle(position.pos(), orbit.max()), | |||||
| &create_circle(position.pos(), meeting_point.max()), | |||||
| ); | ); | ||||
| geometry.render_lines( | geometry.render_lines( | ||||
| Vector4f::new(0.5, 0.5, 0.5, 0.05), | Vector4f::new(0.5, 0.5, 0.5, 0.05), | ||||
| &create_circle(position.pos(), SHIP_ORBIT_DISTANCE_MAX * orbit.max()), | |||||
| &create_circle( | |||||
| position.pos(), | |||||
| SHIP_ORBIT_DISTANCE_MAX * meeting_point.max(), | |||||
| ), | |||||
| ); | ); | ||||
| } | } | ||||
| @@ -1,9 +1,9 @@ | |||||
| mod fleets; | mod fleets; | ||||
| mod orbits; | |||||
| mod meeting_points; | |||||
| mod ships; | mod ships; | ||||
| mod summary; | mod summary; | ||||
| pub use fleets::Fleets; | pub use fleets::Fleets; | ||||
| pub use orbits::Orbits; | |||||
| pub use meeting_points::MeetingPoints; | |||||
| pub use ships::Ships; | pub use ships::Ships; | ||||
| pub use summary::Summary; | pub use summary::Summary; | ||||
| @@ -12,7 +12,8 @@ use specs::{Dispatcher, DispatcherBuilder, Entity, World}; | |||||
| pub use error::Error; | pub use error::Error; | ||||
| use debug::{ | use debug::{ | ||||
| Fleets as DebugFleets, Orbits as DebugOrbits, Ships as DebugShips, Summary as DebugSummary, | |||||
| Fleets as DebugFleets, MeetingPoints as DebugMeetingPoints, Ships as DebugShips, | |||||
| Summary as DebugSummary, | |||||
| }; | }; | ||||
| use misc::{Events, TextManager, Window}; | use misc::{Events, TextManager, Window}; | ||||
| use render::{Asteroids, FleetMove, FleetSelect, Init, Planets, Ships}; | use render::{Asteroids, FleetMove, FleetSelect, Init, Planets, Ships}; | ||||
| @@ -58,7 +59,7 @@ impl<'a, 'b> App<'a, 'b> { | |||||
| .with_thread_local(FleetSelect::new(world, &text_manager)?) | .with_thread_local(FleetSelect::new(world, &text_manager)?) | ||||
| .with_thread_local(FleetMove::new(world)?) | .with_thread_local(FleetMove::new(world)?) | ||||
| .with_thread_local(DebugShips::default()) | .with_thread_local(DebugShips::default()) | ||||
| .with_thread_local(DebugOrbits::default()) | |||||
| .with_thread_local(DebugMeetingPoints::default()) | |||||
| .with_thread_local(DebugFleets::new(&text_manager)?) | .with_thread_local(DebugFleets::new(&text_manager)?) | ||||
| .with_thread_local(DebugSummary::new(&text_manager)?) | .with_thread_local(DebugSummary::new(&text_manager)?) | ||||
| .build(); | .build(); | ||||
| @@ -60,8 +60,8 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
| use glc::{matrix::Angle, vector::Vector2f}; | use glc::{matrix::Angle, vector::Vector2f}; | ||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{ | components::{ | ||||
| Asteroid, AsteroidType, Fleet, FleetOwned, Obstacle, Orbit, OrbitOwned, Planet, | |||||
| PlayerOwned, Position, Ship, ShipType, Velocity, | |||||
| Asteroid, AsteroidType, Fleet, FleetOwned, MeetingPoint, MeetingPointOwned, Obstacle, | |||||
| Planet, PlayerOwned, Position, Ship, ShipType, Velocity, | |||||
| }, | }, | ||||
| misc::{PersistWorld, Persistence}, | misc::{PersistWorld, Persistence}, | ||||
| }; | }; | ||||
| @@ -79,7 +79,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
| .marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
| .with(PlayerOwned::new(player_id)) | .with(PlayerOwned::new(player_id)) | ||||
| .with(Position::circle(Vector2f::new(x, y), 250.0)) | .with(Position::circle(Vector2f::new(x, y), 250.0)) | ||||
| .with(Orbit::new(325.0, 425.0)) | |||||
| .with(MeetingPoint::new(325.0, 425.0)) | |||||
| .with(Obstacle {}) | .with(Obstacle {}) | ||||
| .with(Planet {}) | .with(Planet {}) | ||||
| .build() | .build() | ||||
| @@ -97,7 +97,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
| .create_entity() | .create_entity() | ||||
| .marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
| .with(Position::circle(Vector2f::new(x, y), 100.0)) | .with(Position::circle(Vector2f::new(x, y), 100.0)) | ||||
| .with(Orbit::new(125.0, 175.0)) | |||||
| .with(MeetingPoint::new(125.0, 175.0)) | |||||
| .with(Obstacle {}) | .with(Obstacle {}) | ||||
| .with(Asteroid::new(match i_x * i_y { | .with(Asteroid::new(match i_x * i_y { | ||||
| -1 => AsteroidType::Metal, | -1 => AsteroidType::Metal, | ||||
| @@ -111,7 +111,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
| .create_entity() | .create_entity() | ||||
| .marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
| .with(PlayerOwned::new(player_id)) | .with(PlayerOwned::new(player_id)) | ||||
| .with(OrbitOwned::new(planets[1])) | |||||
| .with(MeetingPointOwned::new(planets[1])) | |||||
| .with(Fleet::default()) | .with(Fleet::default()) | ||||
| .build(); | .build(); | ||||
| @@ -1,6 +1,6 @@ | |||||
| use shrev::{EventChannel, ReaderId}; | use shrev::{EventChannel, ReaderId}; | ||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{Orbit, Position}, | |||||
| components::{MeetingPoint, Position}, | |||||
| continue_if_none, | continue_if_none, | ||||
| misc::WorldHelper, | misc::WorldHelper, | ||||
| systems::FleetControlEvent, | systems::FleetControlEvent, | ||||
| @@ -15,7 +15,7 @@ use crate::{ | |||||
| pub struct FleetMove { | pub struct FleetMove { | ||||
| mouse_event_id: ReaderId<MouseEvent>, | mouse_event_id: ReaderId<MouseEvent>, | ||||
| target_orbit: Option<Entity>, | |||||
| target_meeting_point: Option<Entity>, | |||||
| } | } | ||||
| #[derive(SystemData)] | #[derive(SystemData)] | ||||
| @@ -29,17 +29,17 @@ pub struct FleetMoveData<'a> { | |||||
| entities: Entities<'a>, | entities: Entities<'a>, | ||||
| positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
| orbits: ReadStorage<'a, Orbit>, | |||||
| meeting_points: ReadStorage<'a, MeetingPoint>, | |||||
| } | } | ||||
| impl FleetMove { | impl FleetMove { | ||||
| pub fn new(world: &mut World) -> Result<Self, Error> { | pub fn new(world: &mut World) -> Result<Self, Error> { | ||||
| let mouse_event_id = world.register_event_reader::<MouseEvent>()?; | let mouse_event_id = world.register_event_reader::<MouseEvent>()?; | ||||
| let target_orbit = None; | |||||
| let target_meeting_point = None; | |||||
| Ok(Self { | Ok(Self { | ||||
| mouse_event_id, | mouse_event_id, | ||||
| target_orbit, | |||||
| target_meeting_point, | |||||
| }) | }) | ||||
| } | } | ||||
| } | } | ||||
| @@ -57,7 +57,7 @@ impl<'a> System<'a> for FleetMove { | |||||
| config, | config, | ||||
| entities, | entities, | ||||
| positions, | positions, | ||||
| orbits, | |||||
| meeting_points, | |||||
| } = data; | } = data; | ||||
| let events = mouse_events.read(&mut self.mouse_event_id); | let events = mouse_events.read(&mut self.mouse_event_id); | ||||
| @@ -65,10 +65,12 @@ impl<'a> System<'a> for FleetMove { | |||||
| match event { | match event { | ||||
| MouseEvent::ButtonDown(button) if button == &config.input.fleet_move_button => { | MouseEvent::ButtonDown(button) if button == &config.input.fleet_move_button => { | ||||
| let pos = camera.view_to_world(input_state.mouse_pos); | let pos = camera.view_to_world(input_state.mouse_pos); | ||||
| for (id, position, orbit) in (&entities, &positions, &orbits).join() { | |||||
| let r = orbit.max() * orbit.max(); | |||||
| for (id, position, meeting_point) in | |||||
| (&entities, &positions, &meeting_points).join() | |||||
| { | |||||
| let r = meeting_point.max() * meeting_point.max(); | |||||
| if (position.pos() - pos).length_sqr() <= r { | if (position.pos() - pos).length_sqr() <= r { | ||||
| self.target_orbit = Some(id); | |||||
| self.target_meeting_point = Some(id); | |||||
| break; | break; | ||||
| } | } | ||||
| @@ -78,14 +80,14 @@ impl<'a> System<'a> for FleetMove { | |||||
| let selection = game_state.selection_mut().take(); | let selection = game_state.selection_mut().take(); | ||||
| let selection = continue_if_none!(selection); | let selection = continue_if_none!(selection); | ||||
| let Selection { fleet, count } = selection; | let Selection { fleet, count } = selection; | ||||
| let target = continue_if_none!(self.target_orbit); | |||||
| let target = continue_if_none!(self.target_meeting_point); | |||||
| let player = game_state.player_id(); | let player = game_state.player_id(); | ||||
| let event = FleetControlEvent::move_(player, target, fleet, count); | let event = FleetControlEvent::move_(player, target, fleet, count); | ||||
| fleet_control.single_write(event); | fleet_control.single_write(event); | ||||
| } | } | ||||
| MouseEvent::Move(_, _) => { | MouseEvent::Move(_, _) => { | ||||
| self.target_orbit = None; | |||||
| self.target_meeting_point = None; | |||||
| } | } | ||||
| _ => (), | _ => (), | ||||
| } | } | ||||
| @@ -10,7 +10,7 @@ use glc::{ | |||||
| }; | }; | ||||
| use shrev::{EventChannel, ReaderId}; | use shrev::{EventChannel, ReaderId}; | ||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{Fleet, Orbit, OrbitOwned, Position, ShipCount}, | |||||
| components::{Fleet, MeetingPoint, MeetingPointOwned, Position, ShipCount}, | |||||
| constants::VECTOR_2F_POS_X, | constants::VECTOR_2F_POS_X, | ||||
| continue_if_none, | continue_if_none, | ||||
| misc::{LogResult, WorldHelper as _}, | misc::{LogResult, WorldHelper as _}, | ||||
| @@ -80,9 +80,9 @@ pub struct FleetSelectData<'a> { | |||||
| global: ReadExpect<'a, Global>, | global: ReadExpect<'a, Global>, | ||||
| config: ReadExpect<'a, Config>, | config: ReadExpect<'a, Config>, | ||||
| orbit_owned: ReadStorage<'a, OrbitOwned>, | |||||
| meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, | |||||
| positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
| orbits: ReadStorage<'a, Orbit>, | |||||
| meeting_points: ReadStorage<'a, MeetingPoint>, | |||||
| fleets: ReadStorage<'a, Fleet>, | fleets: ReadStorage<'a, Fleet>, | ||||
| } | } | ||||
| @@ -107,9 +107,9 @@ macro_rules! position { | |||||
| }; | }; | ||||
| } | } | ||||
| macro_rules! orbit_owned { | |||||
| macro_rules! meeting_point_owned { | |||||
| (&$data:expr, $id:expr) => { | (&$data:expr, $id:expr) => { | ||||
| return_if_none!($data.orbit_owned.get($id)) | |||||
| return_if_none!($data.meeting_point_owned.get($id)) | |||||
| }; | }; | ||||
| } | } | ||||
| @@ -186,12 +186,11 @@ impl FleetSelect { | |||||
| MouseEvent::ButtonDown(button) if button == &d.config.input.fleet_select_button => { | MouseEvent::ButtonDown(button) if button == &d.config.input.fleet_select_button => { | ||||
| let pos = d.camera.view_to_world(d.input_state.mouse_pos); | let pos = d.camera.view_to_world(d.input_state.mouse_pos); | ||||
| let selection = d.game_state.selection_mut().take(); | let selection = d.game_state.selection_mut().take(); | ||||
| for (position, orbit) in (&d.positions, &d.orbits).join() { | |||||
| let r = orbit.max() * orbit.max(); | |||||
| for (position, meeting_point) in (&d.positions, &d.meeting_points).join() { | |||||
| let r = meeting_point.max() * meeting_point.max(); | |||||
| if (position.pos() - pos).length_sqr() <= r { | if (position.pos() - pos).length_sqr() <= r { | ||||
| let player_index = d.game_state.player_index(); | let player_index = d.game_state.player_index(); | ||||
| let fleet_id = continue_if_none!(orbit.fleets().get(player_index)); | |||||
| let fleet_id = *continue_if_none!(fleet_id); | |||||
| let fleet_id = continue_if_none!(meeting_point.fleet(player_index)); | |||||
| *d.game_state.selection_mut() = match selection { | *d.game_state.selection_mut() = match selection { | ||||
| Some(s) if s.fleet == fleet_id => { | Some(s) if s.fleet == fleet_id => { | ||||
| @@ -272,8 +271,8 @@ impl FleetSelect { | |||||
| /* calculate values */ | /* calculate values */ | ||||
| let selection = selection!(&d); | let selection = selection!(&d); | ||||
| let orbit_owned = orbit_owned!(&d, selection.fleet); | |||||
| let position = position!(&d, orbit_owned.owner()); | |||||
| let meeting_point_owned = meeting_point_owned!(&d, selection.fleet); | |||||
| let position = position!(&d, meeting_point_owned.owner()); | |||||
| let fleet = fleet!(&d, selection.fleet); | let fleet = fleet!(&d, selection.fleet); | ||||
| self.marker = d.camera.view_to_world(self.mouse_pos) - position.pos(); | self.marker = d.camera.view_to_world(self.mouse_pos) - position.pos(); | ||||
| @@ -426,8 +425,8 @@ impl FleetSelect { | |||||
| /* extract system data */ | /* extract system data */ | ||||
| let selection = selection!(&d); | let selection = selection!(&d); | ||||
| let orbit_owned = orbit_owned!(&d, selection.fleet); | |||||
| let position = position!(&d, orbit_owned.owner()); | |||||
| let meeting_point_owned = meeting_point_owned!(&d, selection.fleet); | |||||
| let position = position!(&d, meeting_point_owned.owner()); | |||||
| /* calculate shared values */ | /* calculate shared values */ | ||||
| let size = self.ring1 + 50.0; | let size = self.ring1 + 50.0; | ||||
| @@ -10,19 +10,21 @@ use specs::{ | |||||
| use crate::{components::ShipCount, misc::FlaggedStorage}; | use crate::{components::ShipCount, misc::FlaggedStorage}; | ||||
| /// A fleet is a group of ships that share the same operation | |||||
| #[derive(Default, Debug, Clone)] | #[derive(Default, Debug, Clone)] | ||||
| pub struct Fleet { | pub struct Fleet { | ||||
| owned: BitSet, | owned: BitSet, | ||||
| count: ShipCount, | count: ShipCount, | ||||
| } | } | ||||
| /// Entities with this component are owned by a certain fleet entity | |||||
| #[derive(Copy, Clone, Debug)] | #[derive(Copy, Clone, Debug)] | ||||
| pub struct Owned { | |||||
| pub struct FleetOwned { | |||||
| owner: Entity, | owner: Entity, | ||||
| } | } | ||||
| #[derive(Serialize, Deserialize)] | #[derive(Serialize, Deserialize)] | ||||
| pub struct OwnedData<M> { | |||||
| pub struct FleetOwnedData<M> { | |||||
| pub owner: M, | pub owner: M, | ||||
| } | } | ||||
| @@ -52,7 +54,7 @@ impl Component for Fleet { | |||||
| type Storage = HashMapStorage<Self>; | type Storage = HashMapStorage<Self>; | ||||
| } | } | ||||
| impl Owned { | |||||
| impl FleetOwned { | |||||
| pub fn new(owner: Entity) -> Self { | pub fn new(owner: Entity) -> Self { | ||||
| Self { owner } | Self { owner } | ||||
| } | } | ||||
| @@ -66,15 +68,15 @@ impl Owned { | |||||
| } | } | ||||
| } | } | ||||
| impl Component for Owned { | |||||
| impl Component for FleetOwned { | |||||
| type Storage = FlaggedStorage<Self, VecStorage<Self>>; | type Storage = FlaggedStorage<Self, VecStorage<Self>>; | ||||
| } | } | ||||
| impl<M> ConvertSaveload<M> for Owned | |||||
| impl<M> ConvertSaveload<M> for FleetOwned | |||||
| where | where | ||||
| for<'de> M: Marker + Serialize + Deserialize<'de>, | for<'de> M: Marker + Serialize + Deserialize<'de>, | ||||
| { | { | ||||
| type Data = OwnedData<M>; | |||||
| type Data = FleetOwnedData<M>; | |||||
| type Error = NoError; | type Error = NoError; | ||||
| fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error> | fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error> | ||||
| @@ -83,7 +85,7 @@ where | |||||
| { | { | ||||
| let owner = ids(self.owner).unwrap(); | let owner = ids(self.owner).unwrap(); | ||||
| Ok(OwnedData { owner }) | |||||
| Ok(FleetOwnedData { owner }) | |||||
| } | } | ||||
| fn convert_from<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error> | fn convert_from<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error> | ||||
| @@ -92,6 +94,6 @@ where | |||||
| { | { | ||||
| let owner = ids(data.owner).unwrap(); | let owner = ids(data.owner).unwrap(); | ||||
| Ok(Owned { owner }) | |||||
| Ok(FleetOwned { owner }) | |||||
| } | } | ||||
| } | } | ||||
| @@ -9,33 +9,35 @@ use specs::{ | |||||
| use crate::misc::FlaggedStorage; | use crate::misc::FlaggedStorage; | ||||
| /// Point in the universe fleets can meet | |||||
| #[derive(Clone, Debug, Default)] | #[derive(Clone, Debug, Default)] | ||||
| pub struct Orbit { | |||||
| pub struct MeetingPoint { | |||||
| min: f32, | min: f32, | ||||
| max: f32, | max: f32, | ||||
| fleets: Fleets, | fleets: Fleets, | ||||
| } | } | ||||
| /// Entities with this component are fleets by an meeting point | |||||
| #[derive(Copy, Clone, Debug)] | |||||
| pub struct MeetingPointOwned { | |||||
| owner: Entity, | |||||
| } | |||||
| #[derive(Serialize, Deserialize)] | #[derive(Serialize, Deserialize)] | ||||
| pub struct OrbitData<M> { | |||||
| pub struct MeetingPointData<M> { | |||||
| pub min: f32, | pub min: f32, | ||||
| pub max: f32, | pub max: f32, | ||||
| pub fleets: Vec<Option<M>>, | pub fleets: Vec<Option<M>>, | ||||
| } | } | ||||
| #[derive(Copy, Clone, Debug)] | |||||
| pub struct Owned { | |||||
| owner: Entity, | |||||
| } | |||||
| #[derive(Serialize, Deserialize)] | #[derive(Serialize, Deserialize)] | ||||
| pub struct OwnedData<M> { | |||||
| pub struct MeetingPointOwnedData<M> { | |||||
| pub owner: M, | pub owner: M, | ||||
| } | } | ||||
| type Fleets = SmallVec<[Option<Entity>; 8]>; | type Fleets = SmallVec<[Option<Entity>; 8]>; | ||||
| impl Orbit { | |||||
| impl MeetingPoint { | |||||
| #[inline] | #[inline] | ||||
| pub fn new(min: f32, max: f32) -> Self { | pub fn new(min: f32, max: f32) -> Self { | ||||
| Self { | Self { | ||||
| @@ -78,22 +80,22 @@ impl Orbit { | |||||
| } | } | ||||
| } | } | ||||
| impl Component for Orbit { | |||||
| impl Component for MeetingPoint { | |||||
| type Storage = HashMapStorage<Self>; | type Storage = HashMapStorage<Self>; | ||||
| } | } | ||||
| impl<M> ConvertSaveload<M> for Orbit | |||||
| impl<M> ConvertSaveload<M> for MeetingPoint | |||||
| where | where | ||||
| for<'de> M: Marker + Serialize + Deserialize<'de>, | for<'de> M: Marker + Serialize + Deserialize<'de>, | ||||
| { | { | ||||
| type Data = OrbitData<M>; | |||||
| type Data = MeetingPointData<M>; | |||||
| type Error = NoError; | type Error = NoError; | ||||
| fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error> | fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error> | ||||
| where | where | ||||
| F: FnMut(Entity) -> Option<M>, | F: FnMut(Entity) -> Option<M>, | ||||
| { | { | ||||
| let Orbit { min, max, fleets } = self; | |||||
| let MeetingPoint { min, max, fleets } = self; | |||||
| let min = *min; | let min = *min; | ||||
| let max = *max; | let max = *max; | ||||
| @@ -103,21 +105,21 @@ where | |||||
| .map(|e| e.and_then(|e| ids(e))) | .map(|e| e.and_then(|e| ids(e))) | ||||
| .collect(); | .collect(); | ||||
| Ok(OrbitData { min, max, fleets }) | |||||
| Ok(MeetingPointData { min, max, fleets }) | |||||
| } | } | ||||
| fn convert_from<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error> | fn convert_from<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error> | ||||
| where | where | ||||
| F: FnMut(M) -> Option<Entity>, | F: FnMut(M) -> Option<Entity>, | ||||
| { | { | ||||
| let OrbitData { min, max, fleets } = data; | |||||
| let MeetingPointData { min, max, fleets } = data; | |||||
| let fleets = fleets.into_iter().map(|e| e.and_then(|e| ids(e))).collect(); | let fleets = fleets.into_iter().map(|e| e.and_then(|e| ids(e))).collect(); | ||||
| Ok(Orbit { min, max, fleets }) | |||||
| Ok(MeetingPoint { min, max, fleets }) | |||||
| } | } | ||||
| } | } | ||||
| impl Owned { | |||||
| impl MeetingPointOwned { | |||||
| pub fn new(owner: Entity) -> Self { | pub fn new(owner: Entity) -> Self { | ||||
| Self { owner } | Self { owner } | ||||
| } | } | ||||
| @@ -131,15 +133,15 @@ impl Owned { | |||||
| } | } | ||||
| } | } | ||||
| impl Component for Owned { | |||||
| impl Component for MeetingPointOwned { | |||||
| type Storage = FlaggedStorage<Self, HashMapStorage<Self>>; | type Storage = FlaggedStorage<Self, HashMapStorage<Self>>; | ||||
| } | } | ||||
| impl<M> ConvertSaveload<M> for Owned | |||||
| impl<M> ConvertSaveload<M> for MeetingPointOwned | |||||
| where | where | ||||
| for<'de> M: Marker + Serialize + Deserialize<'de>, | for<'de> M: Marker + Serialize + Deserialize<'de>, | ||||
| { | { | ||||
| type Data = OwnedData<M>; | |||||
| type Data = MeetingPointOwnedData<M>; | |||||
| type Error = NoError; | type Error = NoError; | ||||
| fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error> | fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error> | ||||
| @@ -148,7 +150,7 @@ where | |||||
| { | { | ||||
| let owner = ids(self.owner).unwrap(); | let owner = ids(self.owner).unwrap(); | ||||
| Ok(OwnedData { owner }) | |||||
| Ok(MeetingPointOwnedData { owner }) | |||||
| } | } | ||||
| fn convert_from<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error> | fn convert_from<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error> | ||||
| @@ -157,6 +159,6 @@ where | |||||
| { | { | ||||
| let owner = ids(data.owner).unwrap(); | let owner = ids(data.owner).unwrap(); | ||||
| Ok(Owned { owner }) | |||||
| Ok(MeetingPointOwned { owner }) | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,7 +1,7 @@ | |||||
| mod asteroid; | mod asteroid; | ||||
| mod fleet; | mod fleet; | ||||
| mod meeting_point; | |||||
| mod obstacle; | mod obstacle; | ||||
| mod orbit; | |||||
| mod planet; | mod planet; | ||||
| mod player; | mod player; | ||||
| mod position; | mod position; | ||||
| @@ -9,9 +9,9 @@ mod ship; | |||||
| mod velocity; | mod velocity; | ||||
| pub use asteroid::{Asteroid, Type as AsteroidType}; | pub use asteroid::{Asteroid, Type as AsteroidType}; | ||||
| pub use fleet::{Fleet, Owned as FleetOwned}; | |||||
| pub use fleet::{Fleet, FleetOwned}; | |||||
| pub use meeting_point::{MeetingPoint, MeetingPointOwned}; | |||||
| pub use obstacle::Obstacle; | pub use obstacle::Obstacle; | ||||
| pub use orbit::{Orbit, Owned as OrbitOwned}; | |||||
| pub use planet::Planet; | pub use planet::Planet; | ||||
| pub use player::{Owned as PlayerOwned, Player}; | pub use player::{Owned as PlayerOwned, Player}; | ||||
| pub use position::{Position, Shape}; | pub use position::{Position, Shape}; | ||||
| @@ -1,6 +1,7 @@ | |||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||
| use specs::{Component, NullStorage}; | use specs::{Component, NullStorage}; | ||||
| /// Objects that ships can not pass through | |||||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | ||||
| pub struct Obstacle {} | pub struct Obstacle {} | ||||
| @@ -3,7 +3,7 @@ use specs::{Dispatcher as Inner, DispatcherBuilder, World, WorldExt}; | |||||
| use crate::{ | use crate::{ | ||||
| components::Player, | components::Player, | ||||
| resources::Global, | resources::Global, | ||||
| systems::{FleetControl, FleetOwnedUpdate, Movement, OrbitOwnedUpdate, Process, Ships}, | |||||
| systems::{FleetControl, FleetOwnedUpdate, MeetingPointOwnedUpdate, Movement, Process, Ships}, | |||||
| Error, | Error, | ||||
| }; | }; | ||||
| @@ -23,7 +23,11 @@ impl<'a, 'b> Dispatcher<'a, 'b> { | |||||
| .with(Ships::new(world), "ships", &[]) | .with(Ships::new(world), "ships", &[]) | ||||
| .with(FleetControl::new(world)?, "fleet_control", &[]) | .with(FleetControl::new(world)?, "fleet_control", &[]) | ||||
| .with(FleetOwnedUpdate::new(world), "fleet_owned_update", &[]) | .with(FleetOwnedUpdate::new(world), "fleet_owned_update", &[]) | ||||
| .with(OrbitOwnedUpdate::new(world), "orbit_owned_update", &[]) | |||||
| .with( | |||||
| MeetingPointOwnedUpdate::new(world), | |||||
| "meeting_point_owned_update", | |||||
| &[], | |||||
| ) | |||||
| .build(); | .build(); | ||||
| dispatcher.setup(world); | dispatcher.setup(world); | ||||
| @@ -6,8 +6,8 @@ use specs::{ | |||||
| }; | }; | ||||
| use crate::components::{ | use crate::components::{ | ||||
| Asteroid, FleetOwned, Obstacle, Orbit, OrbitOwned, Planet, Player, PlayerOwned, Position, Ship, | |||||
| Velocity, | |||||
| Asteroid, FleetOwned, MeetingPoint, MeetingPointOwned, Obstacle, Planet, Player, PlayerOwned, | |||||
| Position, Ship, Velocity, | |||||
| }; | }; | ||||
| /* PersistWorld */ | /* PersistWorld */ | ||||
| @@ -22,8 +22,8 @@ impl Persistence for PersistWorld { | |||||
| Velocity, | Velocity, | ||||
| Player, | Player, | ||||
| PlayerOwned, | PlayerOwned, | ||||
| Orbit, | |||||
| OrbitOwned, | |||||
| MeetingPoint, | |||||
| MeetingPointOwned, | |||||
| FleetOwned, | FleetOwned, | ||||
| Ship, | Ship, | ||||
| Obstacle, | Obstacle, | ||||
| @@ -6,7 +6,8 @@ use specs::{ | |||||
| use crate::{ | use crate::{ | ||||
| components::{ | components::{ | ||||
| Fleet, FleetOwned, Orbit, OrbitOwned, Player, PlayerOwned, Ship, ShipCount, ShipType, | |||||
| Fleet, FleetOwned, MeetingPoint, MeetingPointOwned, Player, PlayerOwned, Ship, ShipCount, | |||||
| ShipType, | |||||
| }, | }, | ||||
| continue_if_none, | continue_if_none, | ||||
| misc::{LogResult, PersistWorld, Persistence, WorldHelper}, | misc::{LogResult, PersistWorld, Persistence, WorldHelper}, | ||||
| @@ -36,9 +37,9 @@ pub struct FleetControlData<'a> { | |||||
| entities: Entities<'a>, | entities: Entities<'a>, | ||||
| fleet_control_events: ReadExpect<'a, EventChannel<FleetControlEvent>>, | fleet_control_events: ReadExpect<'a, EventChannel<FleetControlEvent>>, | ||||
| player_owned: WriteStorage<'a, PlayerOwned>, | player_owned: WriteStorage<'a, PlayerOwned>, | ||||
| orbit_owned: WriteStorage<'a, OrbitOwned>, | |||||
| meeting_point_owned: WriteStorage<'a, MeetingPointOwned>, | |||||
| fleet_owned: WriteStorage<'a, FleetOwned>, | fleet_owned: WriteStorage<'a, FleetOwned>, | ||||
| orbits: WriteStorage<'a, Orbit>, | |||||
| meeting_points: WriteStorage<'a, MeetingPoint>, | |||||
| fleets: WriteStorage<'a, Fleet>, | fleets: WriteStorage<'a, Fleet>, | ||||
| players: ReadStorage<'a, Player>, | players: ReadStorage<'a, Player>, | ||||
| ships: ReadStorage<'a, Ship>, | ships: ReadStorage<'a, Ship>, | ||||
| @@ -65,9 +66,9 @@ impl<'a> System<'a> for FleetControl { | |||||
| entities, | entities, | ||||
| fleet_control_events, | fleet_control_events, | ||||
| mut player_owned, | mut player_owned, | ||||
| mut orbit_owned, | |||||
| mut meeting_point_owned, | |||||
| mut fleet_owned, | mut fleet_owned, | ||||
| mut orbits, | |||||
| mut meeting_points, | |||||
| mut fleets, | mut fleets, | ||||
| players, | players, | ||||
| ships, | ships, | ||||
| @@ -77,11 +78,11 @@ impl<'a> System<'a> for FleetControl { | |||||
| for event in events { | for event in events { | ||||
| match event { | match event { | ||||
| FleetControlEvent::Move(args) if args.count.is_all() => { | FleetControlEvent::Move(args) if args.count.is_all() => { | ||||
| let orbit_owned = continue_if_none!(orbit_owned.get_mut(args.fleet)); | |||||
| let orbit_owned = continue_if_none!(meeting_point_owned.get_mut(args.fleet)); | |||||
| orbit_owned.set_owner(args.target); | orbit_owned.set_owner(args.target); | ||||
| } | } | ||||
| FleetControlEvent::Move(args) => { | FleetControlEvent::Move(args) => { | ||||
| let target_orbit = continue_if_none!(orbits.get_mut(args.target)); | |||||
| let target_orbit = continue_if_none!(meeting_points.get_mut(args.target)); | |||||
| let player = continue_if_none!(players.get(args.player)); | let player = continue_if_none!(players.get(args.player)); | ||||
| let mut count = args.count; | let mut count = args.count; | ||||
| @@ -96,9 +97,9 @@ impl<'a> System<'a> for FleetControl { | |||||
| player_owned | player_owned | ||||
| .insert(fleet, PlayerOwned::new(args.player)) | .insert(fleet, PlayerOwned::new(args.player)) | ||||
| .error("Unable to insert component: PlayerOwned"); | .error("Unable to insert component: PlayerOwned"); | ||||
| orbit_owned | |||||
| .insert(fleet, OrbitOwned::new(args.target)) | |||||
| .error("Unable to insert component: OrbitOwned"); | |||||
| meeting_point_owned | |||||
| .insert(fleet, MeetingPointOwned::new(args.target)) | |||||
| .error("Unable to insert component: MeetingPointOwned"); | |||||
| fleets | fleets | ||||
| .insert(fleet, Fleet::default()) | .insert(fleet, Fleet::default()) | ||||
| .error("Unable to insert component: Fleet"); | .error("Unable to insert component: Fleet"); | ||||
| @@ -0,0 +1,130 @@ | |||||
| 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, PlayerOwned}, | |||||
| misc::{ComponentEvent, StorageHelper, StorageHelperMut}, | |||||
| }; | |||||
| pub struct MeetingPointOwnedUpdate { | |||||
| meeting_point_ids: BitSet, | |||||
| meeting_point_owned_ids: BitSet, | |||||
| old_meeting_point_ids: HashMap<Index, Entity>, | |||||
| meeting_point_owned_event_id: ReaderId<crate::misc::ComponentEvent<MeetingPointOwned>>, | |||||
| } | |||||
| impl MeetingPointOwnedUpdate { | |||||
| pub fn new(world: &mut World) -> Self { | |||||
| WriteStorage::<MeetingPointOwned>::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::<WriteStorage<MeetingPointOwned>>() | |||||
| .register_event_reader(); | |||||
| Self { | |||||
| meeting_point_ids, | |||||
| meeting_point_owned_ids, | |||||
| old_meeting_point_ids, | |||||
| meeting_point_owned_event_id, | |||||
| } | |||||
| } | |||||
| } | |||||
| #[derive(SystemData)] | |||||
| pub struct MeetingPointOwnedUpdateData<'a> { | |||||
| entities: Entities<'a>, | |||||
| meeting_points: WriteStorage<'a, MeetingPoint>, | |||||
| player_owned: ReadStorage<'a, PlayerOwned>, | |||||
| meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, | |||||
| } | |||||
| impl<'a> System<'a> for MeetingPointOwnedUpdate { | |||||
| type SystemData = MeetingPointOwnedUpdateData<'a>; | |||||
| fn run(&mut self, data: Self::SystemData) { | |||||
| let MeetingPointOwnedUpdateData { | |||||
| entities, | |||||
| mut meeting_points, | |||||
| player_owned, | |||||
| meeting_point_owned, | |||||
| } = 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().id() as usize; | |||||
| if old_match && !new_match { | |||||
| if let Some(fleet) = meeting_point.fleets_mut().get_mut(player_id) { | |||||
| *fleet = None; | |||||
| } | |||||
| } else if !old_match && new_match { | |||||
| *meeting_point.fleet_mut(player_id) = Some(fleet_id); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,13 +1,13 @@ | |||||
| mod fleet_control; | mod fleet_control; | ||||
| mod fleet_owned_update; | mod fleet_owned_update; | ||||
| mod meeting_point_owned_update; | |||||
| mod movement; | mod movement; | ||||
| mod orbit_owned_update; | |||||
| mod process; | mod process; | ||||
| mod ships; | mod ships; | ||||
| pub use fleet_control::{FleetControl, FleetControlEvent}; | pub use fleet_control::{FleetControl, FleetControlEvent}; | ||||
| pub use fleet_owned_update::FleetOwnedUpdate; | pub use fleet_owned_update::FleetOwnedUpdate; | ||||
| pub use meeting_point_owned_update::MeetingPointOwnedUpdate; | |||||
| pub use movement::Movement; | pub use movement::Movement; | ||||
| pub use orbit_owned_update::OrbitOwnedUpdate; | |||||
| pub use process::Process; | pub use process::Process; | ||||
| pub use ships::Ships; | pub use ships::Ships; | ||||
| @@ -1,127 +0,0 @@ | |||||
| use std::collections::HashMap; | |||||
| use shrev::ReaderId; | |||||
| use specs::{ | |||||
| hibitset::BitSet, prelude::*, world::Index, Entities, Entity, ReadStorage, System, World, | |||||
| WriteStorage, | |||||
| }; | |||||
| use crate::{ | |||||
| components::{Orbit, OrbitOwned, PlayerOwned}, | |||||
| misc::{ComponentEvent, StorageHelper, StorageHelperMut}, | |||||
| }; | |||||
| pub struct OrbitOwnedUpdate { | |||||
| orbit_ids: BitSet, | |||||
| orbit_owned_ids: BitSet, | |||||
| old_orbit_ids: HashMap<Index, Entity>, | |||||
| orbit_owned_event_id: ReaderId<crate::misc::ComponentEvent<OrbitOwned>>, | |||||
| } | |||||
| impl OrbitOwnedUpdate { | |||||
| pub fn new(world: &mut World) -> Self { | |||||
| WriteStorage::<OrbitOwned>::setup(world); | |||||
| let orbit_ids = BitSet::new(); | |||||
| let orbit_owned_ids = BitSet::new(); | |||||
| let old_orbit_ids = HashMap::new(); | |||||
| let orbit_owned_event_id = world | |||||
| .system_data::<WriteStorage<OrbitOwned>>() | |||||
| .register_event_reader(); | |||||
| Self { | |||||
| orbit_ids, | |||||
| orbit_owned_ids, | |||||
| old_orbit_ids, | |||||
| orbit_owned_event_id, | |||||
| } | |||||
| } | |||||
| } | |||||
| #[derive(SystemData)] | |||||
| pub struct OrbitOwnedUpdateData<'a> { | |||||
| entities: Entities<'a>, | |||||
| orbits: WriteStorage<'a, Orbit>, | |||||
| player_owned: ReadStorage<'a, PlayerOwned>, | |||||
| orbit_owned: ReadStorage<'a, OrbitOwned>, | |||||
| } | |||||
| impl<'a> System<'a> for OrbitOwnedUpdate { | |||||
| type SystemData = OrbitOwnedUpdateData<'a>; | |||||
| fn run(&mut self, data: Self::SystemData) { | |||||
| let OrbitOwnedUpdateData { | |||||
| entities, | |||||
| mut orbits, | |||||
| player_owned, | |||||
| orbit_owned, | |||||
| } = data; | |||||
| self.orbit_ids.clear(); | |||||
| self.orbit_owned_ids.clear(); | |||||
| self.old_orbit_ids.clear(); | |||||
| /* handle events */ | |||||
| let events = orbit_owned.channel().read(&mut self.orbit_owned_event_id); | |||||
| for event in events { | |||||
| match event { | |||||
| ComponentEvent::Inserted(id, orbit_owned) => { | |||||
| self.orbit_ids.add(orbit_owned.owner().id()); | |||||
| self.orbit_owned_ids.add(*id); | |||||
| } | |||||
| ComponentEvent::Modified(id, orbit_owned) => { | |||||
| self.orbit_ids.add(orbit_owned.owner().id()); | |||||
| self.orbit_owned_ids.add(*id); | |||||
| *self | |||||
| .old_orbit_ids | |||||
| .entry(*id) | |||||
| .or_insert_with(|| orbit_owned.owner()) = orbit_owned.owner(); | |||||
| } | |||||
| ComponentEvent::Removed(id, orbit_owned) => { | |||||
| self.orbit_ids.add(orbit_owned.owner().id()); | |||||
| self.orbit_owned_ids.add(*id); | |||||
| *self | |||||
| .old_orbit_ids | |||||
| .entry(*id) | |||||
| .or_insert_with(|| orbit_owned.owner()) = orbit_owned.owner(); | |||||
| } | |||||
| } | |||||
| } | |||||
| /* find new orbit ids */ | |||||
| for (orbit_owned, _) in (&orbit_owned, &self.orbit_owned_ids).join() { | |||||
| self.orbit_ids.add(orbit_owned.owner().id()); | |||||
| } | |||||
| /* update orbits */ | |||||
| for (orbit_id, orbit, _) in (&entities, &mut orbits, &self.orbit_ids).join() { | |||||
| let data = ( | |||||
| &entities, | |||||
| &orbit_owned, | |||||
| &player_owned, | |||||
| &self.orbit_owned_ids, | |||||
| ); | |||||
| for (fleet_id, orbit_owned, player_owned, _) in data.join() { | |||||
| let new_match = orbit_id == orbit_owned.owner(); | |||||
| let old_match = match self.old_orbit_ids.get(&fleet_id.id()) { | |||||
| Some(old_orbit_id) => orbit_id == *old_orbit_id, | |||||
| None => false, | |||||
| }; | |||||
| let player_id = player_owned.owner().id() as usize; | |||||
| if old_match && !new_match { | |||||
| if let Some(fleet) = orbit.fleets_mut().get_mut(player_id) { | |||||
| *fleet = None; | |||||
| } | |||||
| } else if !old_match && new_match { | |||||
| orbit | |||||
| .fleets_mut() | |||||
| .resize_with(player_id + 1, Default::default); | |||||
| // TODO: merge fleets if player already have a fleet on this orbit | |||||
| orbit.fleets_mut()[player_id] = Some(fleet_id); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -11,7 +11,10 @@ use specs::{ | |||||
| }; | }; | ||||
| use crate::{ | use crate::{ | ||||
| components::{FleetOwned, Obstacle, Orbit, OrbitOwned, Position, Ship, ShipObstacle, Velocity}, | |||||
| components::{ | |||||
| FleetOwned, MeetingPoint, MeetingPointOwned, Obstacle, Position, Ship, ShipObstacle, | |||||
| Velocity, | |||||
| }, | |||||
| constants::{ | constants::{ | ||||
| SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND, | SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND, | ||||
| SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X, | SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X, | ||||
| @@ -33,10 +36,10 @@ pub struct ShipsData<'a> { | |||||
| ships: WriteStorage<'a, Ship>, | ships: WriteStorage<'a, Ship>, | ||||
| velocities: WriteStorage<'a, Velocity>, | velocities: WriteStorage<'a, Velocity>, | ||||
| fleet_owned: ReadStorage<'a, FleetOwned>, | fleet_owned: ReadStorage<'a, FleetOwned>, | ||||
| orbit_owned: ReadStorage<'a, OrbitOwned>, | |||||
| meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, | |||||
| positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
| obstacles: ReadStorage<'a, Obstacle>, | obstacles: ReadStorage<'a, Obstacle>, | ||||
| orbits: ReadStorage<'a, Orbit>, | |||||
| meeting_points: ReadStorage<'a, MeetingPoint>, | |||||
| } | } | ||||
| struct Processor<'a> { | struct Processor<'a> { | ||||
| @@ -44,8 +47,8 @@ struct Processor<'a> { | |||||
| entities: &'a Entities<'a>, | entities: &'a Entities<'a>, | ||||
| positions: &'a ReadStorage<'a, Position>, | positions: &'a ReadStorage<'a, Position>, | ||||
| obstacles: &'a ReadStorage<'a, Obstacle>, | obstacles: &'a ReadStorage<'a, Obstacle>, | ||||
| orbits: &'a ReadStorage<'a, Orbit>, | |||||
| orbit_owned: &'a ReadStorage<'a, OrbitOwned>, | |||||
| meeting_points: &'a ReadStorage<'a, MeetingPoint>, | |||||
| meeting_point_owned: &'a ReadStorage<'a, MeetingPointOwned>, | |||||
| delta: f32, | delta: f32, | ||||
| } | } | ||||
| @@ -89,10 +92,10 @@ impl<'a> System<'a> for Ships { | |||||
| mut ships, | mut ships, | ||||
| mut velocities, | mut velocities, | ||||
| fleet_owned, | fleet_owned, | ||||
| orbit_owned, | |||||
| meeting_point_owned, | |||||
| positions, | positions, | ||||
| obstacles, | obstacles, | ||||
| orbits, | |||||
| meeting_points, | |||||
| } = data; | } = data; | ||||
| self.progress_events(&fleet_owned); | self.progress_events(&fleet_owned); | ||||
| @@ -103,8 +106,8 @@ impl<'a> System<'a> for Ships { | |||||
| entities: &entities, | entities: &entities, | ||||
| positions: &positions, | positions: &positions, | ||||
| obstacles: &obstacles, | obstacles: &obstacles, | ||||
| orbit_owned: &orbit_owned, | |||||
| orbits: &orbits, | |||||
| meeting_point_owned: &meeting_point_owned, | |||||
| meeting_points: &meeting_points, | |||||
| delta: global.delta * global.world_speed, | delta: global.delta * global.world_speed, | ||||
| }; | }; | ||||
| @@ -137,58 +140,66 @@ impl Processor<'_> { | |||||
| fleet_owned: &FleetOwned, | fleet_owned: &FleetOwned, | ||||
| ) { | ) { | ||||
| let fleet_id = fleet_owned.owner(); | let fleet_id = fleet_owned.owner(); | ||||
| let orbit_owned = return_if_none!(self.orbit_owned.get(fleet_id)); | |||||
| let orbit_id = orbit_owned.owner(); | |||||
| let orbit = return_if_none!(self.orbits.get(orbit_id)); | |||||
| let orbit_pos = return_if_none!(self.positions.get(orbit_id)).pos(); | |||||
| let meeting_point_owned = return_if_none!(self.meeting_point_owned.get(fleet_id)); | |||||
| let meeting_point_id = meeting_point_owned.owner(); | |||||
| let meeting_point = return_if_none!(self.meeting_points.get(meeting_point_id)); | |||||
| let meeting_point_pos = return_if_none!(self.positions.get(meeting_point_id)).pos(); | |||||
| let ship_pos = position.pos(); | let ship_pos = position.pos(); | ||||
| let target_pos = ship.target_pos(); | let target_pos = ship.target_pos(); | ||||
| let target_dir = ship.target_dir(); | let target_dir = ship.target_dir(); | ||||
| let orbit_to_target = target_pos - orbit_pos; | |||||
| let orbit_to_ship = ship_pos - orbit_pos; | |||||
| let meeting_point_to_target = target_pos - meeting_point_pos; | |||||
| let meeting_point_to_ship = ship_pos - meeting_point_pos; | |||||
| let mut ship_to_target = target_pos - ship_pos; | let mut ship_to_target = target_pos - ship_pos; | ||||
| let r_ship = orbit_to_ship.length_sqr(); | |||||
| let r_target = orbit_to_target.length_sqr(); | |||||
| let r_ship = meeting_point_to_ship.length_sqr(); | |||||
| let r_target = meeting_point_to_target.length_sqr(); | |||||
| let orbit_min = orbit.min(); | |||||
| let orbit_max = orbit.max(); | |||||
| let meeting_point_min = meeting_point.min(); | |||||
| let meeting_point_max = meeting_point.max(); | |||||
| let target_in_orbit = (r_target <= sqr(orbit_max)) && (r_target >= sqr(orbit_min)); | |||||
| let ship_in_orbit = r_ship < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit_max); | |||||
| let target_in_meeting_point = | |||||
| (r_target <= sqr(meeting_point_max)) && (r_target >= sqr(meeting_point_min)); | |||||
| let ship_in_meeting_point = r_ship < sqr(SHIP_ORBIT_DISTANCE_MAX * meeting_point_max); | |||||
| let need_update = self.need_update.contains(id); | let need_update = self.need_update.contains(id); | ||||
| let has_target = target_dir.length_sqr() != 0.0; | let has_target = target_dir.length_sqr() != 0.0; | ||||
| let passed_target = target_dir * ship_to_target <= 0.0; | let passed_target = target_dir * ship_to_target <= 0.0; | ||||
| /* check and update target posistion */ | /* check and update target posistion */ | ||||
| if need_update || !has_target || passed_target || ship_in_orbit != target_in_orbit { | |||||
| let target_pos = if ship_in_orbit && orbit_max > 0.0 { | |||||
| let orbit_to_ship_vec3 = Vector3f::new(orbit_to_ship.x, orbit_to_ship.y, 0.0); | |||||
| if need_update | |||||
| || !has_target | |||||
| || passed_target | |||||
| || ship_in_meeting_point != target_in_meeting_point | |||||
| { | |||||
| let target_pos = if ship_in_meeting_point && meeting_point_max > 0.0 { | |||||
| let meeting_point_to_ship_vec3 = | |||||
| Vector3f::new(meeting_point_to_ship.x, meeting_point_to_ship.y, 0.0); | |||||
| let ship_dir_vec3 = velocity.dir().into_vec3(); | let ship_dir_vec3 = velocity.dir().into_vec3(); | ||||
| let dir = if orbit_to_ship_vec3.cross(&ship_dir_vec3).z > 0.0 { | |||||
| let dir = if meeting_point_to_ship_vec3.cross(&ship_dir_vec3).z > 0.0 { | |||||
| 1.0 | 1.0 | ||||
| } else { | } else { | ||||
| -1.0 | -1.0 | ||||
| }; | }; | ||||
| let orbit_min = orbit.min(); | |||||
| let orbit_max = orbit.max(); | |||||
| let meeting_point_min = meeting_point.min(); | |||||
| let meeting_point_max = meeting_point.max(); | |||||
| let add = SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random::<f32>(); | let add = SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random::<f32>(); | ||||
| let angle = orbit_to_ship.angle2(&VECTOR_2F_POS_X) + (add * dir / orbit_max); | |||||
| let radius = orbit_min + (orbit_max - orbit_min) * random::<f32>(); | |||||
| let angle = meeting_point_to_ship.angle2(&VECTOR_2F_POS_X) | |||||
| + (add * dir / meeting_point_max); | |||||
| let radius = | |||||
| meeting_point_min + (meeting_point_max - meeting_point_min) * random::<f32>(); | |||||
| Vector2f::new( | Vector2f::new( | ||||
| orbit_pos.x + radius * angle.cos(), | |||||
| orbit_pos.y + radius * angle.sin(), | |||||
| meeting_point_pos.x + radius * angle.cos(), | |||||
| meeting_point_pos.y + radius * angle.sin(), | |||||
| ) | ) | ||||
| } else { | } else { | ||||
| ship.set_obstacle(ShipObstacle::Search); | ship.set_obstacle(ShipObstacle::Search); | ||||
| *orbit_pos | |||||
| *meeting_point_pos | |||||
| }; | }; | ||||
| ship.set_target(target_pos, (target_pos - ship_pos).normalize()); | ship.set_target(target_pos, (target_pos - ship_pos).normalize()); | ||||
| @@ -197,11 +208,11 @@ impl Processor<'_> { | |||||
| } | } | ||||
| /* check if obstacle is still valid */ | /* check if obstacle is still valid */ | ||||
| if ship_in_orbit { | |||||
| if ship_in_meeting_point { | |||||
| ship.set_obstacle(ShipObstacle::Done); | ship.set_obstacle(ShipObstacle::Done); | ||||
| } else if let ShipObstacle::Known(obstacle) = ship.obstacle() { | } else if let ShipObstacle::Known(obstacle) = ship.obstacle() { | ||||
| if let Some(position) = self.positions.get(obstacle) { | if let Some(position) = self.positions.get(obstacle) { | ||||
| let obstacle_orbit = self.orbits.get(obstacle).unwrap(); | |||||
| let obstacle_meeting_point = self.meeting_points.get(obstacle).unwrap(); | |||||
| let obstacle_pos = position.pos(); | let obstacle_pos = position.pos(); | ||||
| let ship_to_obstacle = obstacle_pos - ship_pos; | let ship_to_obstacle = obstacle_pos - ship_pos; | ||||
| @@ -211,8 +222,8 @@ impl Processor<'_> { | |||||
| .into_inner() | .into_inner() | ||||
| .abs(); | .abs(); | ||||
| let orbit_sqr = obstacle_orbit.max() * obstacle_orbit.max(); | |||||
| if (obstacle_angle > 90.0 && ship_to_obstacle.length_sqr() > orbit_sqr) | |||||
| let meeting_point_sqr = obstacle_meeting_point.max() * obstacle_meeting_point.max(); | |||||
| if (obstacle_angle > 90.0 && ship_to_obstacle.length_sqr() > meeting_point_sqr) | |||||
| || obstacle_angle > 170.0 | || obstacle_angle > 170.0 | ||||
| { | { | ||||
| ship.set_obstacle(ShipObstacle::Search); | ship.set_obstacle(ShipObstacle::Search); | ||||
| @@ -223,7 +234,7 @@ impl Processor<'_> { | |||||
| } | } | ||||
| /* find obstacle */ | /* find obstacle */ | ||||
| if !ship_in_orbit && ship.obstacle() == ShipObstacle::Search { | |||||
| if !ship_in_meeting_point && ship.obstacle() == ShipObstacle::Search { | |||||
| let mut dist_sqr = f32::MAX; | let mut dist_sqr = f32::MAX; | ||||
| for (e, position, _) in (self.entities, self.positions, self.obstacles).join() { | for (e, position, _) in (self.entities, self.positions, self.obstacles).join() { | ||||
| let obstacle_pos = position.pos(); | let obstacle_pos = position.pos(); | ||||
| @@ -251,19 +262,20 @@ impl Processor<'_> { | |||||
| let mut expected_dir = ship_to_target; | let mut expected_dir = ship_to_target; | ||||
| if let ShipObstacle::Known(obstacle) = ship.obstacle() { | if let ShipObstacle::Known(obstacle) = ship.obstacle() { | ||||
| let obstacle_pos = self.positions.get(obstacle).unwrap(); | let obstacle_pos = self.positions.get(obstacle).unwrap(); | ||||
| let obstacle_orbit = self.orbits.get(obstacle).unwrap(); | |||||
| let obstacle_meeting_point = self.meeting_points.get(obstacle).unwrap(); | |||||
| let ship_to_obstacle = obstacle_pos.pos() - ship_pos; | let ship_to_obstacle = obstacle_pos.pos() - ship_pos; | ||||
| let orbit_min = obstacle_orbit.min(); | |||||
| let orbit_max = obstacle_orbit.max(); | |||||
| let meeting_point_min = obstacle_meeting_point.min(); | |||||
| let meeting_point_max = obstacle_meeting_point.max(); | |||||
| let orbit = ship_to_obstacle.length(); | |||||
| if orbit < orbit_max { | |||||
| let meeting_point = ship_to_obstacle.length(); | |||||
| if meeting_point < meeting_point_max { | |||||
| let mut tangent = Vector2f::new(-ship_to_obstacle.y, ship_to_obstacle.x); | let mut tangent = Vector2f::new(-ship_to_obstacle.y, ship_to_obstacle.x); | ||||
| let radius = obstacle_pos.shape().radius(); | let radius = obstacle_pos.shape().radius(); | ||||
| let mut adjust_low = linear_step(orbit_min, radius, orbit); | |||||
| let adjust_high = 1.0 - linear_step(orbit_max, orbit_min, orbit); | |||||
| let mut adjust_low = linear_step(meeting_point_min, radius, meeting_point); | |||||
| let adjust_high = | |||||
| 1.0 - linear_step(meeting_point_max, meeting_point_min, meeting_point); | |||||
| if ship_to_target * tangent < 0.0 { | if ship_to_target * tangent < 0.0 { | ||||
| tangent = -tangent; | tangent = -tangent; | ||||