Browse Source

Implemented FleetInfo component to count the player controlled ships

raster
Bergmann89 3 years ago
parent
commit
f98d2cbed9
25 changed files with 498 additions and 201 deletions
  1. +2
    -1
      Cargo.lock
  2. +1
    -1
      space-crush-app/Cargo.toml
  3. +11
    -0
      space-crush-app/src/components/fleet_info.rs
  4. +3
    -0
      space-crush-app/src/components/mod.rs
  5. +3
    -3
      space-crush-app/src/debug/fleets.rs
  6. +15
    -11
      space-crush-app/src/lib.rs
  7. +27
    -54
      space-crush-app/src/main.rs
  8. +0
    -1
      space-crush-app/src/misc/window.rs
  9. +2
    -2
      space-crush-app/src/render/asteroids.rs
  10. +2
    -2
      space-crush-app/src/render/planets.rs
  11. +2
    -2
      space-crush-app/src/render/ships.rs
  12. +2
    -0
      space-crush-app/src/resources/mod.rs
  13. +13
    -0
      space-crush-app/src/resources/player_state.rs
  14. +165
    -0
      space-crush-app/src/systems/fleet_info_update.rs
  15. +2
    -0
      space-crush-app/src/systems/mod.rs
  16. +2
    -1
      space-crush-common/Cargo.toml
  17. +47
    -1
      space-crush-common/src/components/fleet.rs
  18. +3
    -5
      space-crush-common/src/components/mod.rs
  19. +0
    -46
      space-crush-common/src/components/owned.rs
  20. +47
    -1
      space-crush-common/src/components/player.rs
  21. +28
    -63
      space-crush-common/src/components/ship.rs
  22. +92
    -0
      space-crush-common/src/misc/flagged_storage.rs
  23. +2
    -0
      space-crush-common/src/misc/mod.rs
  24. +11
    -2
      space-crush-common/src/misc/persistence.rs
  25. +16
    -5
      space-crush-common/src/systems/fleets.rs

+ 2
- 1
Cargo.lock View File

@@ -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",
]


+ 1
- 1
space-crush-app/Cargo.toml View File

@@ -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"

+ 11
- 0
space-crush-app/src/components/fleet_info.rs View File

@@ -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<Self>;
}

+ 3
- 0
space-crush-app/src/components/mod.rs View File

@@ -0,0 +1,3 @@
mod fleet_info;

pub use fleet_info::FleetInfo;

+ 3
- 3
space-crush-app/src/debug/fleets.rs View File

@@ -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),
);
}


+ 15
- 11
space-crush-app/src/lib.rs View File

@@ -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<Self, Error> {
pub fn new(world: &mut World, player_id: Entity) -> Result<Self, Error> {
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)?)


+ 27
- 54
space-crush-app/src/main.rs View File

@@ -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::<WriteStorage<Player>>()
.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::<<PersistWorld as Persistence>::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::<<PersistWorld as Persistence>::Marker>()
.with(Owned { owner: player1 })
.with(PlayerOwned { owner: player_id })
.with(Position {
pos: Vector2f::new(
500.0 * random::<f32>() - 250.0,
@@ -138,6 +145,7 @@ fn create_world(world: &mut World) {
dir: Vector2f::new(random::<f32>() - 0.5, random::<f32>() - 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<bool, Error> {
use serde_json::de::{Deserializer, IoRead};
use space_crush_common::misc::{PersistWorld, Persistence, WorldHelper};

PersistWorld::setup(world);

let vfs = world.resource::<Vfs>()?;
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::<Vfs>()?;
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";

+ 0
- 1
space-crush-app/src/misc/window.rs View File

@@ -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));


+ 2
- 2
space-crush-app/src/render/asteroids.rs View File

@@ -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>,
}



+ 2
- 2
space-crush-app/src/render/planets.rs View File

@@ -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>,
}



+ 2
- 2
space-crush-app/src/render/ships.rs View File

@@ -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>,
}



+ 2
- 0
space-crush-app/src/resources/mod.rs View File

@@ -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;

+ 13
- 0
space-crush-app/src/resources/player_state.rs View File

@@ -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 }
}
}

+ 165
- 0
space-crush-app/src/systems/fleet_info_update.rs View File

@@ -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<Index, Modified>,
need_update: BitSet,
fleet_owned_id: ReaderId<ComponentEvent<FleetOwned>>,
player_owned_id: ReaderId<ComponentEvent<PlayerOwned>>,
}

#[derive(Default)]
struct Modified {
old_fleet_id: Option<Entity>,
old_player_id: Option<Entity>,
}

impl FleetInfoUpdate {
pub fn new(world: &mut World) -> Result<Self, Error> {
let modified = HashMap::new();
let need_update = BitSet::new();

let fleet_owned_id = unsafe {
WriteStorage::<FleetOwned>::setup(world);

let mut fleet_owned = world.system_data::<WriteStorage<FleetOwned>>();
fleet_owned
.unprotected_storage_mut()
.channel_mut()
.register_reader()
};

let player_owned_id = unsafe {
WriteStorage::<PlayerOwned>::setup(world);

let mut player_owned = world.system_data::<WriteStorage<PlayerOwned>>();
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;
}
}
}
}
}

+ 2
- 0
space-crush-app/src/systems/mod.rs View File

@@ -1,3 +1,5 @@
mod fleet_info_update;
mod state_update;

pub use fleet_info_update::FleetInfoUpdate;
pub use state_update::StateUpdate;

+ 2
- 1
space-crush-common/Cargo.toml View File

@@ -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"

+ 47
- 1
space-crush-common/src/components/fleet.rs View File

@@ -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<M> {
pub owner: M,
}

impl Component for Fleet {
type Storage = HashMapStorage<Self>;
}

impl Component for Owned {
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
}

impl<M> ConvertSaveload<M> for Owned
where
for<'de> M: Marker + Serialize + Deserialize<'de>,
{
type Data = OwnedData<M>;
type Error = NoError;

fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error>
where
F: FnMut(Entity) -> Option<M>,
{
let owner = ids(self.owner).unwrap();

Ok(OwnedData { owner })
}

fn convert_from<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error>
where
F: FnMut(M) -> Option<Entity>,
{
let owner = ids(data.owner).unwrap();

Ok(Owned { owner })
}
}

+ 3
- 5
space-crush-common/src/components/mod.rs View File

@@ -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;

+ 0
- 46
space-crush-common/src/components/owned.rs View File

@@ -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<M> {
pub owner: M,
}

impl Component for Owned {
type Storage = VecStorage<Self>;
}

impl<M> ConvertSaveload<M> for Owned
where
for<'de> M: Marker + Serialize + Deserialize<'de>,
{
type Data = OwnedData<M>;
type Error = NoError;

fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error>
where
F: FnMut(Entity) -> Option<M>,
{
let owner = ids(self.owner).unwrap();

Ok(OwnedData { owner })
}

fn convert_from<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error>
where
F: FnMut(M) -> Option<Entity>,
{
let owner = ids(data.owner).unwrap();

Ok(Owned { owner })
}
}

+ 47
- 1
space-crush-common/src/components/player.rs View File

@@ -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<M> {
pub owner: M,
}

impl Component for Player {
type Storage = HashMapStorage<Self>;
}

impl Component for Owned {
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
}

impl<M> ConvertSaveload<M> for Owned
where
for<'de> M: Marker + Serialize + Deserialize<'de>,
{
type Data = OwnedData<M>;
type Error = NoError;

fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error>
where
F: FnMut(Entity) -> Option<M>,
{
let owner = ids(self.owner).unwrap();

Ok(OwnedData { owner })
}

fn convert_from<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error>
where
F: FnMut(M) -> Option<Entity>,
{
let owner = ids(data.owner).unwrap();

Ok(Owned { owner })
}
}

+ 28
- 63
space-crush-common/src/components/ship.rs View File

@@ -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<f32>,
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<M> {
pub type_: Type,
pub fleet: M,
pub agility: Angle<f32>,
pub target_pos: Vector2f,
pub target_dir: Vector2f,
}

impl Component for Ship {
type Storage = VecStorage<Self>;
}

impl<M> ConvertSaveload<M> for Ship
where
for<'de> M: Marker + Serialize + Deserialize<'de>,
{
type Data = ShipData<M>;
type Error = NoError;
impl Index<Type> for Count {
type Output = usize;

fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error>
where
F: FnMut(Entity) -> Option<M>,
{
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<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error>
where
F: FnMut(M) -> Option<Entity>,
{
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<Type> 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,
}
}
}

+ 92
- 0
space-crush-common/src/misc/flagged_storage.rs View File

@@ -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<C, T = DenseVecStorage<C>>
where
C: Send + Sync + 'static,
{
channel: EventChannel<ComponentEvent<C>>,
storage: T,
}

pub enum ComponentEvent<C>
where
C: Send + Sync + 'static,
{
Inserted(Index),
Modified(Index, C),
Removed(Index, C),
}

impl<C, T> FlaggedStorage<C, T>
where
C: Send + Sync + 'static,
{
pub fn channel(&self) -> &EventChannel<ComponentEvent<C>> {
&self.channel
}

pub fn channel_mut(&mut self) -> &mut EventChannel<ComponentEvent<C>> {
&mut self.channel
}
}

impl<C, T> Default for FlaggedStorage<C, T>
where
C: Send + Sync + 'static,
T: TryDefault,
{
fn default() -> Self {
FlaggedStorage {
channel: EventChannel::new(),
storage: T::unwrap_default(),
}
}
}

impl<C: Component + Clone, T: UnprotectedStorage<C>> UnprotectedStorage<C> for FlaggedStorage<C, T>
where
C: Send + Sync + 'static,
{
unsafe fn clean<B>(&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
}
}

+ 2
- 0
space-crush-common/src/misc/mod.rs View File

@@ -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;

+ 11
- 2
space-crush-common/src/misc/persistence.rs View File

@@ -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<PersistWorldMarker>;
type Components = (Position, Velocity, Planet, Ship, Owned, Player, Fleet);
type Components = (
Position,
Velocity,
Planet,
Ship,
Player,
PlayerOwned,
Fleet,
FleetOwned,
);
}

/* Persistence */


+ 16
- 5
space-crush-common/src/systems/fleets.rs View File

@@ -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,
};


Loading…
Cancel
Save