From f98d2cbed96ad44bb84f5f489d64454a4b9237db Mon Sep 17 00:00:00 2001 From: Bergmann89 Date: Mon, 14 Dec 2020 02:52:45 +0100 Subject: [PATCH] Implemented FleetInfo component to count the player controlled ships --- Cargo.lock | 3 +- space-crush-app/Cargo.toml | 2 +- space-crush-app/src/components/fleet_info.rs | 11 ++ space-crush-app/src/components/mod.rs | 3 + space-crush-app/src/debug/fleets.rs | 6 +- space-crush-app/src/lib.rs | 26 +-- space-crush-app/src/main.rs | 81 +++------ space-crush-app/src/misc/window.rs | 1 - space-crush-app/src/render/asteroids.rs | 4 +- space-crush-app/src/render/planets.rs | 4 +- space-crush-app/src/render/ships.rs | 4 +- space-crush-app/src/resources/mod.rs | 2 + space-crush-app/src/resources/player_state.rs | 13 ++ .../src/systems/fleet_info_update.rs | 165 ++++++++++++++++++ space-crush-app/src/systems/mod.rs | 2 + space-crush-common/Cargo.toml | 3 +- space-crush-common/src/components/fleet.rs | 48 ++++- space-crush-common/src/components/mod.rs | 8 +- space-crush-common/src/components/owned.rs | 46 ----- space-crush-common/src/components/player.rs | 48 ++++- space-crush-common/src/components/ship.rs | 91 +++------- .../src/misc/flagged_storage.rs | 92 ++++++++++ space-crush-common/src/misc/mod.rs | 2 + space-crush-common/src/misc/persistence.rs | 13 +- space-crush-common/src/systems/fleets.rs | 21 ++- 25 files changed, 498 insertions(+), 201 deletions(-) create mode 100644 space-crush-app/src/components/fleet_info.rs create mode 100644 space-crush-app/src/components/mod.rs create mode 100644 space-crush-app/src/resources/player_state.rs create mode 100644 space-crush-app/src/systems/fleet_info_update.rs delete mode 100644 space-crush-common/src/components/owned.rs create mode 100644 space-crush-common/src/misc/flagged_storage.rs diff --git a/Cargo.lock b/Cargo.lock index c346b14..b71eb8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1530,6 +1530,7 @@ name = "space-crush-common" version = "0.1.0" dependencies = [ "glc", + "hibitset", "lazy_static", "log", "log4rs", @@ -1737,7 +1738,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d68a369614cd12ca384ca6e75ab0a5ac3a5acbfe8003622e20808a322b9bb652" dependencies = [ - "flate2 0.2.20", + "flate2 1.0.14", "vfs", "zip", ] diff --git a/space-crush-app/Cargo.toml b/space-crush-app/Cargo.toml index fc76efd..c35ed16 100644 --- a/space-crush-app/Cargo.toml +++ b/space-crush-app/Cargo.toml @@ -20,5 +20,5 @@ shred = { version = "0.10", features = [ "shred-derive" ] } shrev = "1.1" smallvec = { version = "1.5", features = [ "serde" ] } space-crush-common = "0.1" -specs = "0.16" +specs = "*" thiserror = "1.0" diff --git a/space-crush-app/src/components/fleet_info.rs b/space-crush-app/src/components/fleet_info.rs new file mode 100644 index 0000000..60a05cf --- /dev/null +++ b/space-crush-app/src/components/fleet_info.rs @@ -0,0 +1,11 @@ +use space_crush_common::components::ShipCount; +use specs::{Component, HashMapStorage}; + +#[derive(Default, Debug)] +pub struct FleetInfo { + pub count: ShipCount, +} + +impl Component for FleetInfo { + type Storage = HashMapStorage; +} diff --git a/space-crush-app/src/components/mod.rs b/space-crush-app/src/components/mod.rs new file mode 100644 index 0000000..6fc4956 --- /dev/null +++ b/space-crush-app/src/components/mod.rs @@ -0,0 +1,3 @@ +mod fleet_info; + +pub use fleet_info::FleetInfo; diff --git a/space-crush-app/src/debug/fleets.rs b/space-crush-app/src/debug/fleets.rs index b87deef..73adedc 100644 --- a/space-crush-app/src/debug/fleets.rs +++ b/space-crush-app/src/debug/fleets.rs @@ -32,15 +32,15 @@ impl<'a> System<'a> for Fleets { for (p, f) in (&position, &fleet).join() { geometry.render_lines( - Vector4f::new(0.5, 0.5, 0.5, 0.2), + Vector4f::new(0.5, 0.5, 0.5, 0.05), &create_circle(p.pos, f.orbit_min), ); geometry.render_lines( - Vector4f::new(0.5, 0.5, 0.5, 0.2), + Vector4f::new(0.5, 0.5, 0.5, 0.05), &create_circle(p.pos, f.orbit_max), ); geometry.render_lines( - Vector4f::new(0.5, 0.5, 0.5, 0.1), + Vector4f::new(0.5, 0.5, 0.5, 0.05), &create_circle(p.pos, SHIP_ORBIT_DISTANCE_MAX * f.orbit_max), ); } diff --git a/space-crush-app/src/lib.rs b/space-crush-app/src/lib.rs index a92910a..a9e4ff3 100644 --- a/space-crush-app/src/lib.rs +++ b/space-crush-app/src/lib.rs @@ -1,20 +1,21 @@ -mod constants; -mod debug; -mod error; -mod misc; -mod render; -mod resources; -mod systems; +pub mod components; +pub mod constants; +pub mod debug; +pub mod error; +pub mod misc; +pub mod render; +pub mod resources; +pub mod systems; -use specs::{Dispatcher, DispatcherBuilder, World}; +use specs::{Dispatcher, DispatcherBuilder, Entity, World}; pub use error::Error; use debug::{Fleets as DebugFleets, Ships as DebugShips, Summary as DebugSummary}; use misc::{Events, TextManager, Window}; use render::{Asteroids, Init, Planets, Ships}; -use resources::{Camera, Config, Geometry, State, Uniform}; -use systems::StateUpdate; +use resources::{Camera, Config, Geometry, PlayerState, State, Uniform}; +use systems::{FleetInfoUpdate, StateUpdate}; pub struct App<'a, 'b> { is_running: bool, @@ -24,7 +25,7 @@ pub struct App<'a, 'b> { } impl<'a, 'b> App<'a, 'b> { - pub fn new(world: &mut World) -> Result { + pub fn new(world: &mut World, player_id: Entity) -> Result { let config = Config::new(world)?; let events = Events::new(world)?; let window = Window::new(events.handle(), &config)?; @@ -33,17 +34,20 @@ impl<'a, 'b> App<'a, 'b> { let camera = Camera::new()?; let uniform = Uniform::new()?; let geometry = Geometry::new(world)?; + let player_state = PlayerState::new(player_id); world.insert(state); world.insert(config); world.insert(camera); world.insert(uniform); world.insert(geometry); + world.insert(player_state); let text_manager = TextManager::new(world)?; let mut dispatcher = DispatcherBuilder::new() .with(StateUpdate::new(world)?, "state_update", &[]) + .with(FleetInfoUpdate::new(world)?, "fleet_info_update", &[]) .with_thread_local(Init::new(world)?) .with_thread_local(Planets::new(world)?) .with_thread_local(Asteroids::new(world)?) diff --git a/space-crush-app/src/main.rs b/space-crush-app/src/main.rs index 76683b1..5f1c94a 100644 --- a/space-crush-app/src/main.rs +++ b/space-crush-app/src/main.rs @@ -5,7 +5,7 @@ use space_crush_common::{ misc::{init_logger, Vfs}, Dispatcher, }; -use specs::{World, WorldExt}; +use specs::{Builder, Entity, World, WorldExt}; fn main() -> Result<(), Error> { let vfs = Vfs::new(&["space-crush-app"])?; @@ -33,12 +33,12 @@ fn run(vfs: Vfs) -> Result<(), Error> { let mut world = World::new(); world.insert(vfs); + let player1 = world.create_entity().build(); + let mut common = Dispatcher::new(&mut world); - let mut app = App::new(&mut world)?; + let mut app = App::new(&mut world, player1)?; - if !load_world(&mut world, WORLD_FILEPATH)? { - create_world(&mut world); - } + create_world(&mut world, player1); info!("Application initialized"); @@ -49,31 +49,35 @@ fn run(vfs: Vfs) -> Result<(), Error> { app.process(&world)?; } - save_world(&mut world, WORLD_FILEPATH)?; - Ok(()) } -fn create_world(world: &mut World) { +fn create_world(world: &mut World, player_id: Entity) { use glc::{ matrix::Angle, vector::{Vector2f, Vector4f}, }; + use space_crush_app::components::FleetInfo; use space_crush_common::{ components::{ - Asteroid, AsteroidType, Fleet, Owned, Planet, Player, Position, Ship, ShipType, - Velocity, + Asteroid, AsteroidType, Fleet, FleetOwned, Planet, Player, PlayerOwned, Position, Ship, + ShipType, Velocity, }, misc::{PersistWorld, Persistence}, }; - use specs::{saveload::MarkedBuilder, Builder}; + use specs::{saveload::MarkedBuilder, WriteStorage}; - let player1 = world - .create_entity() - .with(Player { - color: Vector4f::new(0.0, 0.5, 1.0, 0.1), - }) - .build(); + PersistWorld::setup(world); + + world + .system_data::>() + .insert( + player_id, + Player { + color: Vector4f::new(0.0, 0.5, 1.0, 0.1), + }, + ) + .unwrap(); world .create_entity() @@ -86,6 +90,7 @@ fn create_world(world: &mut World) { orbit_min: 125.0, orbit_max: 175.0, }) + .with(FleetInfo::default()) .with(Asteroid { type_: AsteroidType::Metal, }) @@ -102,6 +107,7 @@ fn create_world(world: &mut World) { orbit_min: 125.0, orbit_max: 175.0, }) + .with(FleetInfo::default()) .with(Asteroid { type_: AsteroidType::Crystal, }) @@ -110,7 +116,7 @@ fn create_world(world: &mut World) { let planet = world .create_entity() .marked::<::Marker>() - .with(Owned { owner: player1 }) + .with(PlayerOwned { owner: player_id }) .with(Position { pos: Vector2f::default(), size: 250.0, @@ -119,6 +125,7 @@ fn create_world(world: &mut World) { orbit_min: 325.0, orbit_max: 425.0, }) + .with(FleetInfo::default()) .with(Planet {}) .build(); @@ -126,7 +133,7 @@ fn create_world(world: &mut World) { world .create_entity() .marked::<::Marker>() - .with(Owned { owner: player1 }) + .with(PlayerOwned { owner: player_id }) .with(Position { pos: Vector2f::new( 500.0 * random::() - 250.0, @@ -138,6 +145,7 @@ fn create_world(world: &mut World) { dir: Vector2f::new(random::() - 0.5, random::() - 0.5).normalize(), speed: 100.0, }) + .with(FleetOwned { owner: planet }) .with(Ship { type_: match i % 3 { 0 => ShipType::Fighter, @@ -145,7 +153,6 @@ fn create_world(world: &mut World) { 2 => ShipType::Transporter, _ => unreachable!(), }, - fleet: planet, agility: Angle::Deg(360.0), target_pos: Default::default(), target_dir: Default::default(), @@ -153,37 +160,3 @@ fn create_world(world: &mut World) { .build(); } } - -fn load_world(world: &mut World, path: &str) -> Result { - use serde_json::de::{Deserializer, IoRead}; - use space_crush_common::misc::{PersistWorld, Persistence, WorldHelper}; - - PersistWorld::setup(world); - - let vfs = world.resource::()?; - let path = vfs.join(path)?; - if !path.exists() { - return Ok(false); - } - - let mut file = path.open_file()?; - let mut read = IoRead::new(&mut file); - let mut deserializer = Deserializer::new(&mut read); - world.deserialize(PersistWorld, &mut deserializer)?; - - Ok(true) -} - -fn save_world(world: &mut World, path: &str) -> Result<(), Error> { - use serde_json::Serializer; - use space_crush_common::misc::{PersistWorld, WorldHelper}; - - let vfs = world.resource::()?; - let mut file = vfs.join(path)?.create_file()?; - let mut serializer = Serializer::new(&mut file); - world.serialize(PersistWorld, &mut serializer)?; - - Ok(()) -} - -const WORLD_FILEPATH: &str = "resources/world.json"; diff --git a/space-crush-app/src/misc/window.rs b/space-crush-app/src/misc/window.rs index 0342a6c..a7358db 100644 --- a/space-crush-app/src/misc/window.rs +++ b/space-crush-app/src/misc/window.rs @@ -99,7 +99,6 @@ impl Window { (monitor_size.width - window_size.width) / 2, (monitor_size.height - window_size.height) / 2, )); - window.set_cursor_grab(true).unwrap(); let context = unsafe { context.make_current().unwrap() }; gl::load_with(|s| context.get_proc_address(s)); diff --git a/space-crush-app/src/render/asteroids.rs b/space-crush-app/src/render/asteroids.rs index 69332bf..465e6db 100644 --- a/space-crush-app/src/render/asteroids.rs +++ b/space-crush-app/src/render/asteroids.rs @@ -6,7 +6,7 @@ use glc::{ vector::Vector4f, }; use space_crush_common::{ - components::{Asteroid, AsteroidType, Owned, Player, Position}, + components::{Asteroid, AsteroidType, Player, PlayerOwned, Position}, misc::LogResult, }; use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; @@ -61,7 +61,7 @@ pub struct AsteroidsData<'a> { geometry: ReadExpect<'a, Geometry>, position: ReadStorage<'a, Position>, asteroid: ReadStorage<'a, Asteroid>, - owned: ReadStorage<'a, Owned>, + owned: ReadStorage<'a, PlayerOwned>, player: ReadStorage<'a, Player>, } diff --git a/space-crush-app/src/render/planets.rs b/space-crush-app/src/render/planets.rs index 22c9168..7aeb5f4 100644 --- a/space-crush-app/src/render/planets.rs +++ b/space-crush-app/src/render/planets.rs @@ -6,7 +6,7 @@ use glc::{ vector::Vector4f, }; use space_crush_common::{ - components::{Owned, Planet, Player, Position}, + components::{Planet, Player, PlayerOwned, Position}, misc::LogResult, }; use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; @@ -58,7 +58,7 @@ pub struct PlanetsData<'a> { geometry: ReadExpect<'a, Geometry>, position: ReadStorage<'a, Position>, planet: ReadStorage<'a, Planet>, - owned: ReadStorage<'a, Owned>, + owned: ReadStorage<'a, PlayerOwned>, player: ReadStorage<'a, Player>, } diff --git a/space-crush-app/src/render/ships.rs b/space-crush-app/src/render/ships.rs index c03ffe1..ce97278 100644 --- a/space-crush-app/src/render/ships.rs +++ b/space-crush-app/src/render/ships.rs @@ -6,7 +6,7 @@ use glc::{ vector::Vector4f, }; use space_crush_common::{ - components::{Owned, Player, Position, Ship, ShipType, Velocity}, + components::{Player, PlayerOwned, Position, Ship, ShipType, Velocity}, misc::LogResult, }; use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; @@ -65,7 +65,7 @@ pub struct ShipsData<'a> { position: ReadStorage<'a, Position>, velocity: ReadStorage<'a, Velocity>, ship: ReadStorage<'a, Ship>, - owned: ReadStorage<'a, Owned>, + owned: ReadStorage<'a, PlayerOwned>, player: ReadStorage<'a, Player>, } diff --git a/space-crush-app/src/resources/mod.rs b/space-crush-app/src/resources/mod.rs index 3e78906..550dcb9 100644 --- a/space-crush-app/src/resources/mod.rs +++ b/space-crush-app/src/resources/mod.rs @@ -1,11 +1,13 @@ mod camera; mod config; mod geometry; +mod player_state; mod state; mod uniform; pub use camera::Camera; pub use config::Config; pub use geometry::Geometry; +pub use player_state::PlayerState; pub use state::State; pub use uniform::Uniform; diff --git a/space-crush-app/src/resources/player_state.rs b/space-crush-app/src/resources/player_state.rs new file mode 100644 index 0000000..a35f2d6 --- /dev/null +++ b/space-crush-app/src/resources/player_state.rs @@ -0,0 +1,13 @@ +#![allow(dead_code)] + +use specs::Entity; + +pub struct PlayerState { + pub player_id: Entity, +} + +impl PlayerState { + pub fn new(player_id: Entity) -> Self { + Self { player_id } + } +} diff --git a/space-crush-app/src/systems/fleet_info_update.rs b/space-crush-app/src/systems/fleet_info_update.rs new file mode 100644 index 0000000..02f9f2f --- /dev/null +++ b/space-crush-app/src/systems/fleet_info_update.rs @@ -0,0 +1,165 @@ +use std::collections::HashMap; + +use shrev::ReaderId; +use space_crush_common::{ + components::{FleetOwned, PlayerOwned, Ship}, + misc::ComponentEvent, +}; +use specs::{ + hibitset::BitSetLike, prelude::*, world::Index, Entities, ReadExpect, ReadStorage, System, + World, WriteStorage, +}; + +use crate::{components::FleetInfo, resources::PlayerState, Error}; + +pub struct FleetInfoUpdate { + modified: HashMap, + need_update: BitSet, + fleet_owned_id: ReaderId>, + player_owned_id: ReaderId>, +} + +#[derive(Default)] +struct Modified { + old_fleet_id: Option, + old_player_id: Option, +} + +impl FleetInfoUpdate { + pub fn new(world: &mut World) -> Result { + let modified = HashMap::new(); + let need_update = BitSet::new(); + + let fleet_owned_id = unsafe { + WriteStorage::::setup(world); + + let mut fleet_owned = world.system_data::>(); + fleet_owned + .unprotected_storage_mut() + .channel_mut() + .register_reader() + }; + + let player_owned_id = unsafe { + WriteStorage::::setup(world); + + let mut player_owned = world.system_data::>(); + player_owned + .unprotected_storage_mut() + .channel_mut() + .register_reader() + }; + + Ok(Self { + modified, + need_update, + fleet_owned_id, + player_owned_id, + }) + } +} + +#[derive(SystemData)] +pub struct FleetInfoUpdateData<'a> { + entities: Entities<'a>, + player_state: ReadExpect<'a, PlayerState>, + ships: ReadStorage<'a, Ship>, + fleet_infos: WriteStorage<'a, FleetInfo>, + fleet_owned: ReadStorage<'a, FleetOwned>, + player_owned: ReadStorage<'a, PlayerOwned>, +} + +impl<'a> System<'a> for FleetInfoUpdate { + type SystemData = FleetInfoUpdateData<'a>; + + fn run(&mut self, data: Self::SystemData) { + let FleetInfoUpdateData { + entities, + player_state, + ships, + mut fleet_infos, + fleet_owned, + player_owned, + } = data; + + self.modified.clear(); + self.need_update.clear(); + + /* player owned events */ + let events = player_owned + .unprotected_storage() + .channel() + .read(&mut self.player_owned_id); + for event in events { + match event { + ComponentEvent::Inserted(id) => { + self.need_update.add(*id); + } + ComponentEvent::Modified(id, player_owned) + | ComponentEvent::Removed(id, player_owned) => { + self.need_update.add(*id); + self.modified.entry(*id).or_default().old_player_id = Some(player_owned.owner); + } + } + } + + /* fleet owned events */ + let events = fleet_owned + .unprotected_storage() + .channel() + .read(&mut self.fleet_owned_id); + for event in events { + match event { + ComponentEvent::Inserted(id) => { + self.need_update.add(*id); + } + ComponentEvent::Modified(id, fleet_owned) + | ComponentEvent::Removed(id, fleet_owned) => { + self.need_update.add(*id); + self.modified.entry(*id).or_default().old_fleet_id = Some(fleet_owned.owner); + } + } + } + + if self.need_update.is_empty() { + return; + } + + /* update fleets */ + let player_id = player_state.player_id; + for (fleet_id, fleet_info) in (&entities, &mut fleet_infos).join() { + for (ship_id, ship, fleet_owned, player_owned, _) in ( + &entities, + &ships, + &fleet_owned, + &player_owned, + &self.need_update, + ) + .join() + { + let new_match = fleet_owned.owner == fleet_id && player_owned.owner == player_id; + let old_match = match self.modified.get(&ship_id.id()) { + None => false, + Some(modified) => match (modified.old_fleet_id, modified.old_player_id) { + (Some(old_fleet_id), Some(old_player_id)) => { + old_fleet_id != fleet_id && old_player_id == player_id + } + (Some(old_fleet_id), None) => { + old_fleet_id != fleet_id && player_owned.owner == player_id + } + (None, Some(old_player_id)) => { + fleet_owned.owner != fleet_id && old_player_id == player_id + } + (None, None) => false, + }, + }; + + if old_match && !new_match { + fleet_info.count[ship.type_] = fleet_info.count[ship.type_].saturating_sub(1); + } else if !old_match && new_match { + fleet_info.count[ship.type_] += 1; + } + } + } + } +} diff --git a/space-crush-app/src/systems/mod.rs b/space-crush-app/src/systems/mod.rs index acc1bbb..fe26e9d 100644 --- a/space-crush-app/src/systems/mod.rs +++ b/space-crush-app/src/systems/mod.rs @@ -1,3 +1,5 @@ +mod fleet_info_update; mod state_update; +pub use fleet_info_update::FleetInfoUpdate; pub use state_update::StateUpdate; diff --git a/space-crush-common/Cargo.toml b/space-crush-common/Cargo.toml index c6b64a4..d7b5de3 100644 --- a/space-crush-common/Cargo.toml +++ b/space-crush-common/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] glc = { version = "0.1", features = [ "serde" ] } +hibitset = "0.6" log = { version = "0.4", features = [ "max_level_trace", "release_max_level_warn" ] } lazy_static = "1.4" log4rs = "0.13" @@ -14,7 +15,7 @@ serde = "1.0" serde_yaml = "0.8" shred = { version = "0.10", features = [ "shred-derive" ] } shrev = "1.1" -specs = { version = "0.16", features = [ "serde" ] } +specs = { version = "*", features = [ "serde" ] } thiserror = "1.0" vfs = "0.4" vfs-zip = "0.2" diff --git a/space-crush-common/src/components/fleet.rs b/space-crush-common/src/components/fleet.rs index 23d5078..cf79514 100644 --- a/space-crush-common/src/components/fleet.rs +++ b/space-crush-common/src/components/fleet.rs @@ -1,5 +1,11 @@ use serde::{Deserialize, Serialize}; -use specs::{Component, HashMapStorage}; +use specs::{ + error::NoError, + saveload::{ConvertSaveload, Marker}, + Component, Entity, HashMapStorage, VecStorage, +}; + +use crate::misc::FlaggedStorage; #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct Fleet { @@ -7,6 +13,46 @@ pub struct Fleet { pub orbit_max: f32, } +#[derive(Copy, Clone, Debug)] +pub struct Owned { + pub owner: Entity, +} + +#[derive(Serialize, Deserialize)] +pub struct OwnedData { + pub owner: M, +} + impl Component for Fleet { type Storage = HashMapStorage; } + +impl Component for Owned { + type Storage = FlaggedStorage>; +} + +impl ConvertSaveload for Owned +where + for<'de> M: Marker + Serialize + Deserialize<'de>, +{ + type Data = OwnedData; + type Error = NoError; + + fn convert_into(&self, mut ids: F) -> Result + where + F: FnMut(Entity) -> Option, + { + let owner = ids(self.owner).unwrap(); + + Ok(OwnedData { owner }) + } + + fn convert_from(data: Self::Data, mut ids: F) -> Result + where + F: FnMut(M) -> Option, + { + let owner = ids(data.owner).unwrap(); + + Ok(Owned { owner }) + } +} diff --git a/space-crush-common/src/components/mod.rs b/space-crush-common/src/components/mod.rs index 2b04d23..51adf08 100644 --- a/space-crush-common/src/components/mod.rs +++ b/space-crush-common/src/components/mod.rs @@ -1,6 +1,5 @@ mod asteroid; mod fleet; -mod owned; mod planet; mod player; mod position; @@ -8,10 +7,9 @@ mod ship; mod velocity; pub use asteroid::{Asteroid, Type as AsteroidType}; -pub use fleet::Fleet; -pub use owned::Owned; +pub use fleet::{Fleet, Owned as FleetOwned}; pub use planet::Planet; -pub use player::Player; +pub use player::{Owned as PlayerOwned, Player}; pub use position::Position; -pub use ship::{Ship, Type as ShipType}; +pub use ship::{Count as ShipCount, Ship, Type as ShipType}; pub use velocity::Velocity; diff --git a/space-crush-common/src/components/owned.rs b/space-crush-common/src/components/owned.rs deleted file mode 100644 index 475f7a4..0000000 --- a/space-crush-common/src/components/owned.rs +++ /dev/null @@ -1,46 +0,0 @@ -use serde::{Deserialize, Serialize}; -use specs::{ - error::NoError, - saveload::{ConvertSaveload, Marker}, - Component, Entity, VecStorage, -}; - -#[derive(Clone, Debug)] -pub struct Owned { - pub owner: Entity, -} - -#[derive(Serialize, Deserialize)] -pub struct OwnedData { - pub owner: M, -} - -impl Component for Owned { - type Storage = VecStorage; -} - -impl ConvertSaveload for Owned -where - for<'de> M: Marker + Serialize + Deserialize<'de>, -{ - type Data = OwnedData; - type Error = NoError; - - fn convert_into(&self, mut ids: F) -> Result - where - F: FnMut(Entity) -> Option, - { - let owner = ids(self.owner).unwrap(); - - Ok(OwnedData { owner }) - } - - fn convert_from(data: Self::Data, mut ids: F) -> Result - where - F: FnMut(M) -> Option, - { - let owner = ids(data.owner).unwrap(); - - Ok(Owned { owner }) - } -} diff --git a/space-crush-common/src/components/player.rs b/space-crush-common/src/components/player.rs index e9998d1..949d449 100644 --- a/space-crush-common/src/components/player.rs +++ b/space-crush-common/src/components/player.rs @@ -1,12 +1,58 @@ use glc::vector::Vector4f; use serde::{Deserialize, Serialize}; -use specs::{Component, HashMapStorage}; +use specs::{ + error::NoError, + saveload::{ConvertSaveload, Marker}, + Component, Entity, HashMapStorage, VecStorage, +}; + +use crate::misc::FlaggedStorage; #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct Player { pub color: Vector4f, } +#[derive(Copy, Clone, Debug)] +pub struct Owned { + pub owner: Entity, +} + +#[derive(Serialize, Deserialize)] +pub struct OwnedData { + pub owner: M, +} + impl Component for Player { type Storage = HashMapStorage; } + +impl Component for Owned { + type Storage = FlaggedStorage>; +} + +impl ConvertSaveload for Owned +where + for<'de> M: Marker + Serialize + Deserialize<'de>, +{ + type Data = OwnedData; + type Error = NoError; + + fn convert_into(&self, mut ids: F) -> Result + where + F: FnMut(Entity) -> Option, + { + let owner = ids(self.owner).unwrap(); + + Ok(OwnedData { owner }) + } + + fn convert_from(data: Self::Data, mut ids: F) -> Result + where + F: FnMut(M) -> Option, + { + let owner = ids(data.owner).unwrap(); + + Ok(Owned { owner }) + } +} diff --git a/space-crush-common/src/components/ship.rs b/space-crush-common/src/components/ship.rs index 4a7582a..34eacc5 100644 --- a/space-crush-common/src/components/ship.rs +++ b/space-crush-common/src/components/ship.rs @@ -1,88 +1,53 @@ +use std::ops::{Index, IndexMut}; + use glc::{matrix::Angle, vector::Vector2f}; use serde::{Deserialize, Serialize}; -use specs::{ - error::NoError, - saveload::{ConvertSaveload, Marker}, - Component, Entity, VecStorage, -}; +use specs::{Component, VecStorage}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Ship { pub type_: Type, - pub fleet: Entity, pub agility: Angle, pub target_pos: Vector2f, pub target_dir: Vector2f, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Default)] +pub struct Count { + pub fighter: usize, + pub bomber: usize, + pub transporter: usize, +} + +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] pub enum Type { Fighter, Bomber, Transporter, } -#[derive(Serialize, Deserialize)] -pub struct ShipData { - pub type_: Type, - pub fleet: M, - pub agility: Angle, - pub target_pos: Vector2f, - pub target_dir: Vector2f, -} - impl Component for Ship { type Storage = VecStorage; } -impl ConvertSaveload for Ship -where - for<'de> M: Marker + Serialize + Deserialize<'de>, -{ - type Data = ShipData; - type Error = NoError; +impl Index for Count { + type Output = usize; - fn convert_into(&self, mut ids: F) -> Result - where - F: FnMut(Entity) -> Option, - { - let Ship { - type_, - fleet, - agility, - target_pos, - target_dir, - } = self.clone(); - let fleet = ids(fleet).unwrap(); - - Ok(ShipData { - type_, - fleet, - agility, - target_pos, - target_dir, - }) + fn index(&self, index: Type) -> &Self::Output { + match index { + Type::Fighter => &self.fighter, + Type::Bomber => &self.bomber, + Type::Transporter => &self.transporter, + } } +} - fn convert_from(data: Self::Data, mut ids: F) -> Result - where - F: FnMut(M) -> Option, - { - let ShipData { - type_, - fleet, - agility, - target_pos, - target_dir, - } = data; - let fleet = ids(fleet).unwrap(); - - Ok(Ship { - type_, - fleet, - agility, - target_pos, - target_dir, - }) +impl IndexMut for Count { + fn index_mut(&mut self, index: Type) -> &mut Self::Output { + match index { + Type::Fighter => &mut self.fighter, + Type::Bomber => &mut self.bomber, + Type::Transporter => &mut self.transporter, + } } } diff --git a/space-crush-common/src/misc/flagged_storage.rs b/space-crush-common/src/misc/flagged_storage.rs new file mode 100644 index 0000000..05e70c4 --- /dev/null +++ b/space-crush-common/src/misc/flagged_storage.rs @@ -0,0 +1,92 @@ +#![allow(dead_code)] + +use hibitset::BitSetLike; +use shrev::EventChannel; +use specs::{ + storage::{TryDefault, UnprotectedStorage}, + world::Index, + Component, DenseVecStorage, +}; + +pub struct FlaggedStorage> +where + C: Send + Sync + 'static, +{ + channel: EventChannel>, + storage: T, +} + +pub enum ComponentEvent +where + C: Send + Sync + 'static, +{ + Inserted(Index), + Modified(Index, C), + Removed(Index, C), +} + +impl FlaggedStorage +where + C: Send + Sync + 'static, +{ + pub fn channel(&self) -> &EventChannel> { + &self.channel + } + + pub fn channel_mut(&mut self) -> &mut EventChannel> { + &mut self.channel + } +} + +impl Default for FlaggedStorage +where + C: Send + Sync + 'static, + T: TryDefault, +{ + fn default() -> Self { + FlaggedStorage { + channel: EventChannel::new(), + storage: T::unwrap_default(), + } + } +} + +impl> UnprotectedStorage for FlaggedStorage +where + C: Send + Sync + 'static, +{ + unsafe fn clean(&mut self, has: B) + where + B: BitSetLike, + { + self.storage.clean(has); + } + + unsafe fn get(&self, id: Index) -> &C { + self.storage.get(id) + } + + unsafe fn get_mut(&mut self, id: Index) -> &mut C { + let ret = self.storage.get_mut(id); + + self.channel + .single_write(ComponentEvent::Modified(id, ret.clone())); + + ret + } + + unsafe fn insert(&mut self, id: Index, comp: C) { + self.storage.insert(id, comp); + + self.channel.single_write(ComponentEvent::Inserted(id)); + } + + unsafe fn remove(&mut self, id: Index) -> C { + let c = self.storage.remove(id); + + self.channel + .single_write(ComponentEvent::Removed(id, c.clone())); + + c + } +} diff --git a/space-crush-common/src/misc/mod.rs b/space-crush-common/src/misc/mod.rs index 279b132..0b596ac 100644 --- a/space-crush-common/src/misc/mod.rs +++ b/space-crush-common/src/misc/mod.rs @@ -1,3 +1,4 @@ +mod flagged_storage; mod log; mod log_result; mod persistence; @@ -6,6 +7,7 @@ mod world; pub use self::log::init as init_logger; pub use self::vfs::{Vfs, VfsError}; +pub use flagged_storage::{ComponentEvent, FlaggedStorage}; pub use log_result::LogResult; pub use persistence::{PersistWorld, Persistence}; pub use world::WorldHelper; diff --git a/space-crush-common/src/misc/persistence.rs b/space-crush-common/src/misc/persistence.rs index 77dbeef..d88e013 100644 --- a/space-crush-common/src/misc/persistence.rs +++ b/space-crush-common/src/misc/persistence.rs @@ -5,7 +5,7 @@ use specs::{ Component, Entities, ReadStorage, World, WorldExt, Write, WriteStorage, }; -use crate::components::{Fleet, Owned, Planet, Player, Position, Ship, Velocity}; +use crate::components::{Fleet, FleetOwned, Planet, Player, PlayerOwned, Position, Ship, Velocity}; /* PersistWorld */ @@ -14,7 +14,16 @@ pub struct PersistWorldMarker; impl Persistence for PersistWorld { type Marker = SimpleMarker; - type Components = (Position, Velocity, Planet, Ship, Owned, Player, Fleet); + type Components = ( + Position, + Velocity, + Planet, + Ship, + Player, + PlayerOwned, + Fleet, + FleetOwned, + ); } /* Persistence */ diff --git a/space-crush-common/src/systems/fleets.rs b/space-crush-common/src/systems/fleets.rs index 260bf68..404f642 100644 --- a/space-crush-common/src/systems/fleets.rs +++ b/space-crush-common/src/systems/fleets.rs @@ -7,7 +7,7 @@ use rand::random; use specs::{prelude::*, ParJoin, Read, ReadStorage, System, WriteStorage}; use crate::{ - components::{Fleet, Position, Ship, Velocity}, + components::{Fleet, FleetOwned, Position, Ship, Velocity}, constants::{ SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND, SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X, @@ -22,6 +22,7 @@ pub struct Fleets; pub struct FleetsData<'a> { ship: WriteStorage<'a, Ship>, velocity: WriteStorage<'a, Velocity>, + fleet_owned: ReadStorage<'a, FleetOwned>, position: ReadStorage<'a, Position>, fleet: ReadStorage<'a, Fleet>, global: Read<'a, Global>, @@ -34,15 +35,24 @@ impl<'a> System<'a> for Fleets { let FleetsData { mut ship, mut velocity, + fleet_owned, position, fleet, global, } = data; - (&mut ship, &mut velocity, &position) + (&mut ship, &mut velocity, &fleet_owned, &position) .par_join() - .for_each(|(ship, vel, pos)| { - progress_ship(&position, &fleet, ship, vel, pos, global.delta) + .for_each(|(ship, vel, fleet_owned, pos)| { + progress_ship( + &position, + &fleet, + ship, + vel, + fleet_owned.owner, + pos, + global.delta, + ) }); } } @@ -52,11 +62,12 @@ fn progress_ship<'a>( fleets: &ReadStorage<'a, Fleet>, ship: &mut Ship, velocity: &mut Velocity, + fleet_id: Entity, position: &Position, delta: f32, ) { let (orbit_pos, orbit_min, orbit_max): (Vector2f, f32, f32) = - match (positions.get(ship.fleet), fleets.get(ship.fleet)) { + match (positions.get(fleet_id), fleets.get(fleet_id)) { (Some(position), Some(fleet)) => (position.pos, fleet.orbit_min, fleet.orbit_max), (_, _) => return, };