From 7ec1321114424e0db647d8e7bc4bd03fe89fcac4 Mon Sep 17 00:00:00 2001 From: Bergmann89 Date: Thu, 7 Jan 2021 11:09:15 +0100 Subject: [PATCH] Use builder to create the different world objects Using builders ensure that the correct components are added to a new created entity. --- space-crush-app/src/debug/fleets.rs | 2 +- space-crush-app/src/debug/meeting_points.rs | 6 +- space-crush-app/src/debug/ships.rs | 5 +- space-crush-app/src/error.rs | 11 +- space-crush-app/src/main.rs | 86 ++++-------- space-crush-app/src/render/asteroids.rs | 33 +++-- space-crush-app/src/render/fleet_move.rs | 9 +- space-crush-app/src/render/fleet_select.rs | 31 +++-- space-crush-app/src/render/planets.rs | 17 ++- space-crush-app/src/render/ships.rs | 4 +- space-crush-common/src/builder/asteroid.rs | 82 +++++++++++ space-crush-common/src/builder/fleet.rs | 37 +++++ space-crush-common/src/builder/mod.rs | 29 ++++ space-crush-common/src/builder/planet.rs | 74 ++++++++++ space-crush-common/src/builder/player.rs | 37 +++++ space-crush-common/src/builder/ship.rs | 90 ++++++++++++ space-crush-common/src/components/asteroid.rs | 15 +- space-crush-common/src/components/fleet.rs | 44 ++++-- .../src/components/meeting_point.rs | 40 +++--- space-crush-common/src/components/mod.rs | 4 +- space-crush-common/src/components/obstacle.rs | 2 + space-crush-common/src/components/planet.rs | 10 +- space-crush-common/src/components/player.rs | 33 +++-- space-crush-common/src/components/position.rs | 54 +------- space-crush-common/src/components/shape.rs | 21 +++ space-crush-common/src/components/ship.rs | 39 ++++-- space-crush-common/src/components/velocity.rs | 20 +-- space-crush-common/src/dispatcher.rs | 7 +- space-crush-common/src/lib.rs | 1 + space-crush-common/src/misc/mod.rs | 4 +- space-crush-common/src/misc/persistence.rs | 38 ++--- space-crush-common/src/misc/world.rs | 31 ++++- .../src/systems/fleet_control.rs | 43 +++--- .../src/systems/fleet_owned_update.rs | 12 +- .../src/systems/meeting_point_owned_update.rs | 130 ------------------ space-crush-common/src/systems/mod.rs | 2 - space-crush-common/src/systems/movement.rs | 3 +- space-crush-common/src/systems/ships.rs | 19 ++- 38 files changed, 691 insertions(+), 434 deletions(-) create mode 100644 space-crush-common/src/builder/asteroid.rs create mode 100644 space-crush-common/src/builder/fleet.rs create mode 100644 space-crush-common/src/builder/mod.rs create mode 100644 space-crush-common/src/builder/planet.rs create mode 100644 space-crush-common/src/builder/player.rs create mode 100644 space-crush-common/src/builder/ship.rs create mode 100644 space-crush-common/src/components/shape.rs delete mode 100644 space-crush-common/src/systems/meeting_point_owned_update.rs diff --git a/space-crush-app/src/debug/fleets.rs b/space-crush-app/src/debug/fleets.rs index 269aadb..df31ae6 100644 --- a/space-crush-app/src/debug/fleets.rs +++ b/space-crush-app/src/debug/fleets.rs @@ -74,7 +74,7 @@ impl<'a> System<'a> for Fleets { ), ) .panic("Unable to update text") - .render_offset(&camera.world_to_window(*position.pos())); + .render_offset(&camera.world_to_window(*position.get())); } gl::blend_equation(gl::FUNC_ADD); diff --git a/space-crush-app/src/debug/meeting_points.rs b/space-crush-app/src/debug/meeting_points.rs index 691bf49..03ef957 100644 --- a/space-crush-app/src/debug/meeting_points.rs +++ b/space-crush-app/src/debug/meeting_points.rs @@ -34,16 +34,16 @@ impl<'a> System<'a> for MeetingPoints { gl::blend_equation(gl::FUNC_ADD); geometry.render_lines( Vector4f::new(0.5, 0.5, 0.5, 0.05), - &create_circle(position.pos(), meeting_point.min()), + &create_circle(position.get(), meeting_point.min()), ); geometry.render_lines( Vector4f::new(0.5, 0.5, 0.5, 0.05), - &create_circle(position.pos(), meeting_point.max()), + &create_circle(position.get(), meeting_point.max()), ); geometry.render_lines( Vector4f::new(0.5, 0.5, 0.5, 0.05), &create_circle( - position.pos(), + position.get(), SHIP_ORBIT_DISTANCE_MAX * meeting_point.max(), ), ); diff --git a/space-crush-app/src/debug/ships.rs b/space-crush-app/src/debug/ships.rs index 8a78881..eba79fe 100644 --- a/space-crush-app/src/debug/ships.rs +++ b/space-crush-app/src/debug/ships.rs @@ -33,7 +33,7 @@ impl<'a> System<'a> for Ships { gl::blend_func(gl::SRC_ALPHA, gl::ONE); for (position, velocity, ship) in (&positions, &velocities, &ships).join() { - let ship_pos = position.pos(); + let ship_pos = position.get(); geometry.render_lines( Vector4f::new(0.0, 0.0, 1.0, 0.2), @@ -49,7 +49,8 @@ impl<'a> System<'a> for Ships { ); if let ShipObstacle::Known(obstacle) = ship.obstacle() { - let obstacle_pos = continue_if_none!(positions.get(obstacle)).pos(); + let obstacle_pos = continue_if_none!(positions.get(obstacle)); + let obstacle_pos = obstacle_pos.get(); geometry.render_lines( Vector4f::new(0.0, 1.0, 0.0, 0.2), diff --git a/space-crush-app/src/error.rs b/space-crush-app/src/error.rs index 51f2f36..e94d504 100644 --- a/space-crush-app/src/error.rs +++ b/space-crush-app/src/error.rs @@ -7,7 +7,7 @@ use glutin::{ }; use glyph_brush::ab_glyph::InvalidFont; use serde_json::Error as JsonError; -use space_crush_common::{misc::VfsError, Error as CommonError}; +use space_crush_common::{builder::Error as BuilderError, misc::VfsError, Error as CommonError}; use thiserror::Error; #[derive(Debug, Error)] @@ -39,6 +39,9 @@ pub enum Error { #[error("{0}")] CommonError(CommonError), + #[error("{0}")] + BuilderError(BuilderError), + #[error("Resource is not registered: {0}!")] ResourceNotRegistered(&'static str), @@ -102,3 +105,9 @@ impl From for Error { Self::CommonError(err) } } + +impl From for Error { + fn from(err: BuilderError) -> Self { + Self::BuilderError(err) + } +} diff --git a/space-crush-app/src/main.rs b/space-crush-app/src/main.rs index 6cf8cfb..ef80313 100644 --- a/space-crush-app/src/main.rs +++ b/space-crush-app/src/main.rs @@ -1,13 +1,12 @@ -use glc::vector::Vector3f; use log::{error, info}; use rand::random; use space_crush_app::{App, Error}; use space_crush_common::{ components::Player, - misc::{init_logger, Vfs}, + misc::{init_logger, Persistence, Vfs, WorldPersistence}, Dispatcher, }; -use specs::{Builder, Entity, World, WorldExt}; +use specs::{Entity, World, WorldExt}; fn main() -> Result<(), Error> { let vfs = Vfs::new(&["space-crush-app"])?; @@ -34,12 +33,10 @@ fn run(vfs: Vfs) -> Result<(), Error> { let mut world = World::new(); world.insert(vfs); + WorldPersistence::setup(&mut world); let mut common = Dispatcher::new(&mut world)?; - let player1 = world - .create_entity() - .with(Player::new(Vector3f::new(0.0, 0.5, 1.0))) - .build(); + let player1 = Player::builder().color((0.0, 0.5, 1.0)).build(&mut world)?; let mut app = App::new(&mut world, player1)?; create_world(&mut world, player1); @@ -57,32 +54,21 @@ fn run(vfs: Vfs) -> Result<(), Error> { } fn create_world(world: &mut World, player_id: Entity) { - use glc::{matrix::Angle, vector::Vector2f}; - use space_crush_common::{ - components::{ - Asteroid, AsteroidType, Fleet, FleetOwned, MeetingPoint, MeetingPointOwned, Obstacle, - Planet, PlayerOwned, Position, Ship, ShipType, Velocity, - }, - misc::{PersistWorld, Persistence}, - }; - use specs::saveload::MarkedBuilder; - - PersistWorld::setup(world); + use glc::matrix::Angle; + use space_crush_common::components::{Asteroid, AsteroidType, Fleet, Planet, Ship, ShipType}; let planets = (0..3) .map(|i| { let x = 2000.0 * (i as f32 - 1.0); let y = 0.0; - world - .create_entity() - .marked::<::Marker>() - .with(PlayerOwned::new(player_id)) - .with(Position::circle(Vector2f::new(x, y), 250.0)) - .with(MeetingPoint::new(325.0, 425.0)) - .with(Obstacle {}) - .with(Planet {}) - .build() + Planet::builder() + .position((x, y)) + .size(250.0) + .orbit(325.0, 425.0) + .owner(player_id) + .build(world) + .unwrap() }) .collect::>(); @@ -93,27 +79,20 @@ fn create_world(world: &mut World, player_id: Entity) { let x = 1000.0 * i_x as f32; let y = 1000.0 * i_y as f32; - world - .create_entity() - .marked::<::Marker>() - .with(Position::circle(Vector2f::new(x, y), 100.0)) - .with(MeetingPoint::new(125.0, 175.0)) - .with(Obstacle {}) - .with(Asteroid::new(match i_x * i_y { + Asteroid::builder() + .position((x, y)) + .size(100.0) + .orbit(125.0, 175.0) + .type_(match i_x * i_y { -1 => AsteroidType::Metal, 1 => AsteroidType::Crystal, _ => unreachable!(), - })) - .build(); + }) + .build(world) + .unwrap(); } - let fleet_id = world - .create_entity() - .marked::<::Marker>() - .with(PlayerOwned::new(player_id)) - .with(MeetingPointOwned::new(planets[1])) - .with(Fleet::default()) - .build(); + let fleet_id = Fleet::builder().owner(planets[1]).build(world).unwrap(); for i in 0..9 { let r = 325.0 + 100.0 * random::(); @@ -122,22 +101,17 @@ fn create_world(world: &mut World, player_id: Entity) { let x = r * a.cos(); let y = r * a.sin(); - world - .create_entity() - .marked::<::Marker>() - .with(PlayerOwned::new(player_id)) - .with(FleetOwned::new(fleet_id)) - .with(Position::dot(Vector2f::new(x, y))) - .with(Velocity::new( - Vector2f::new(random::() - 0.5, random::() - 0.5).normalize(), - 100.0, - )) - .with(Ship::new(match i % 3 { + Ship::builder() + .player(player_id) + .fleet(fleet_id) + .position((x, y)) + .type_(match i % 3 { 0 => ShipType::Fighter, 1 => ShipType::Bomber, 2 => ShipType::Transporter, _ => unreachable!(), - })) - .build(); + }) + .build(world) + .unwrap(); } } diff --git a/space-crush-app/src/render/asteroids.rs b/space-crush-app/src/render/asteroids.rs index 82bdcf1..7027263 100644 --- a/space-crush-app/src/render/asteroids.rs +++ b/space-crush-app/src/render/asteroids.rs @@ -9,16 +9,13 @@ use glc::{ vertex_array::{DataType, VertexArray}, }; use space_crush_common::{ - components::{Asteroid, AsteroidType, Player, PlayerOwned, Position}, + components::{Asteroid, AsteroidType, Player, PlayerOwned, Position, Shape}, misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, }; use specs::{prelude::*, ReadStorage, System, World}; use crate::{ - constants::{ - ASTEROID_SIZE, PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, - UNIFORM_BUFFER_INDEX_UNIFORM, - }, + constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, misc::WorldHelper, Error, }; @@ -40,6 +37,15 @@ struct VertexData { texture: gl::GLint, } +#[derive(SystemData)] +pub struct AsteroidsData<'a> { + positions: ReadStorage<'a, Position>, + shapes: ReadStorage<'a, Shape>, + asteroids: ReadStorage<'a, Asteroid>, + players: ReadStorage<'a, Player>, + owned: ReadStorage<'a, PlayerOwned>, +} + impl Asteroids { pub fn new(world: &mut World) -> Result { WriteStorage::::setup(world); @@ -91,20 +97,13 @@ impl Asteroids { } } -#[derive(SystemData)] -pub struct AsteroidsData<'a> { - positions: ReadStorage<'a, Position>, - asteroids: ReadStorage<'a, Asteroid>, - players: ReadStorage<'a, Player>, - owned: ReadStorage<'a, PlayerOwned>, -} - impl<'a> System<'a> for Asteroids { type SystemData = AsteroidsData<'a>; fn run(&mut self, data: Self::SystemData) { let AsteroidsData { positions, + shapes, asteroids, players, owned, @@ -141,16 +140,16 @@ impl<'a> System<'a> for Asteroids { ) .panic("Unable to change buffer size for asteroid data"); - let data = (&positions, &asteroids, owned.maybe()); + let data = (&positions, &shapes, &asteroids, owned.maybe()); let mut buffer = buffer .map_mut::(true) .panic("Unable to map buffer for asteroid data"); - for (i, (position, asteroid, owned)) in data.join().enumerate() { + for (i, (position, shape, asteroid, owned)) in data.join().enumerate() { let mut d = &mut buffer[i]; - d.pos = *position.pos(); - d.size = position.shape().circle().unwrap_or(ASTEROID_SIZE); + d.pos = *position.get(); + d.size = shape.radius(); d.color = match owned.and_then(|owned| players.get(owned.owner())) { Some(pv) => *pv.color(), None => PLAYER_COLOR_DEFAULT, diff --git a/space-crush-app/src/render/fleet_move.rs b/space-crush-app/src/render/fleet_move.rs index 0c7e0bf..8a6508c 100644 --- a/space-crush-app/src/render/fleet_move.rs +++ b/space-crush-app/src/render/fleet_move.rs @@ -69,7 +69,7 @@ impl<'a> System<'a> for FleetMove { (&entities, &positions, &meeting_points).join() { let r = meeting_point.max() * meeting_point.max(); - if (position.pos() - pos).length_sqr() <= r { + if (position.get() - pos).length_sqr() <= r { self.target_meeting_point = Some(id); break; @@ -82,7 +82,12 @@ impl<'a> System<'a> for FleetMove { let Selection { fleet, count } = selection; let target = continue_if_none!(self.target_meeting_point); let player = game_state.player_id(); - let event = FleetControlEvent::move_(player, target, fleet, count); + let event = FleetControlEvent::MoveToMeetingPoint { + player, + fleet, + count, + target, + }; fleet_control.single_write(event); } diff --git a/space-crush-app/src/render/fleet_select.rs b/space-crush-app/src/render/fleet_select.rs index cc3a0ca..0262e7b 100644 --- a/space-crush-app/src/render/fleet_select.rs +++ b/space-crush-app/src/render/fleet_select.rs @@ -10,7 +10,7 @@ use glc::{ }; use shrev::{EventChannel, ReaderId}; use space_crush_common::{ - components::{Fleet, MeetingPoint, MeetingPointOwned, Position, ShipCount}, + components::{Fleet, MeetingPoint, MeetingPointOwned, Position, Shape, ShipCount}, constants::VECTOR_2F_POS_X, continue_if_none, misc::{LogResult, WorldHelper as _}, @@ -82,6 +82,7 @@ pub struct FleetSelectData<'a> { meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, positions: ReadStorage<'a, Position>, + shapes: ReadStorage<'a, Shape>, meeting_points: ReadStorage<'a, MeetingPoint>, fleets: ReadStorage<'a, Fleet>, } @@ -107,6 +108,12 @@ macro_rules! position { }; } +macro_rules! shape { + (&$data:expr, $id:expr) => { + return_if_none!($data.shapes.get($id)) + }; +} + macro_rules! meeting_point_owned { (&$data:expr, $id:expr) => { return_if_none!($data.meeting_point_owned.get($id)) @@ -188,7 +195,7 @@ impl FleetSelect { let selection = d.game_state.selection_mut().take(); 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.get() - pos).length_sqr() <= r { let player_index = d.game_state.player_index(); let fleet_id = continue_if_none!(meeting_point.fleet(player_index)); @@ -273,11 +280,12 @@ impl FleetSelect { let selection = selection!(&d); let meeting_point_owned = meeting_point_owned!(&d, selection.fleet); let position = position!(&d, meeting_point_owned.owner()); + let shape = shape!(&d, meeting_point_owned.owner()); 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.get(); self.zoom = d.camera.view().axis_x.as_vec3().length(); - self.shape_size = position.shape().radius(); + self.shape_size = shape.radius(); self.ring0 = self.shape_size + FLEET_SELECT_OFFSET / self.zoom; self.ring1 = self.ring0 + FLEET_SELECT_WIDTH / self.zoom; @@ -431,13 +439,12 @@ impl FleetSelect { /* calculate shared values */ let size = self.ring1 + 50.0; let rings = Vector2f::new(self.ring0 / size, self.ring1 / size); - let px = position.pos().x; - let py = position.pos().y; + let p = position.get(); let m = Matrix4f::new( Vector4f::new(size, 0.0, 0.0, 0.0), Vector4f::new(0.0, size, 0.0, 0.0), Vector4f::new(0.0, 0.0, size, 0.0), - Vector4f::new(px, py, 0.0, 1.0), + Vector4f::new(p.x, p.y, 0.0, 1.0), ); /* update uniforms */ @@ -475,20 +482,20 @@ impl FleetSelect { if is_simple { self.text_total .color(Vector4f::new(1.0, 1.0, 1.0, alpha)) - .render_offset(&self.text_pos(self.marker, *position.pos(), d)); + .render_offset(&self.text_pos(self.marker, *position.get(), d)); } else { self.text_total .color(Vector4f::new(1.0, 1.0, 1.0, alpha)) - .render_offset(&self.text_pos((0.0, 1.0), *position.pos(), d)); + .render_offset(&self.text_pos((0.0, 1.0), *position.get(), d)); self.text_fighter .color(Vector4f::new(1.0, 1.0, 1.0, alpha)) - .render_offset(&self.text_pos((1.0, 0.0), *position.pos(), d)); + .render_offset(&self.text_pos((1.0, 0.0), *position.get(), d)); self.text_bomber .color(Vector4f::new(1.0, 1.0, 1.0, alpha)) - .render_offset(&self.text_pos((0.0, -1.0), *position.pos(), d)); + .render_offset(&self.text_pos((0.0, -1.0), *position.get(), d)); self.text_transporter .color(Vector4f::new(1.0, 1.0, 1.0, alpha)) - .render_offset(&self.text_pos((-1.0, 0.0), *position.pos(), d)); + .render_offset(&self.text_pos((-1.0, 0.0), *position.get(), d)); } } diff --git a/space-crush-app/src/render/planets.rs b/space-crush-app/src/render/planets.rs index eee1454..44d282d 100644 --- a/space-crush-app/src/render/planets.rs +++ b/space-crush-app/src/render/planets.rs @@ -9,16 +9,13 @@ use glc::{ vertex_array::{DataType, VertexArray}, }; use space_crush_common::{ - components::{Planet, Player, PlayerOwned, Position}, + components::{Planet, Player, PlayerOwned, Position, Shape}, misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, }; use specs::{prelude::*, ReadStorage, System, World}; use crate::{ - constants::{ - PLANET_SIZE, PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, - UNIFORM_BUFFER_INDEX_UNIFORM, - }, + constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, misc::WorldHelper, Error, }; @@ -88,6 +85,7 @@ impl Planets { #[derive(SystemData)] pub struct PlanetsData<'a> { positions: ReadStorage<'a, Position>, + shapes: ReadStorage<'a, Shape>, planets: ReadStorage<'a, Planet>, players: ReadStorage<'a, Player>, owned: ReadStorage<'a, PlayerOwned>, @@ -99,6 +97,7 @@ impl<'a> System<'a> for Planets { fn run(&mut self, data: Self::SystemData) { let PlanetsData { positions, + shapes, planets, players, owned, @@ -135,16 +134,16 @@ impl<'a> System<'a> for Planets { ) .panic("Unable to change buffer size for planet data"); - let data = (&positions, &planets, owned.maybe()); + let data = (&positions, &shapes, &planets, owned.maybe()); let mut buffer = buffer .map_mut::(true) .panic("Unable to map buffer for planet data"); - for (i, (position, _, owned)) in data.join().enumerate() { + for (i, (position, shape, _, owned)) in data.join().enumerate() { let mut d = &mut buffer[i]; - d.pos = *position.pos(); - d.size = position.shape().circle().unwrap_or(PLANET_SIZE); + d.pos = *position.get(); + d.size = shape.radius(); d.color = match owned.and_then(|owned| players.get(owned.owner())) { Some(pv) => *pv.color(), None => PLAYER_COLOR_DEFAULT, diff --git a/space-crush-app/src/render/ships.rs b/space-crush-app/src/render/ships.rs index 2d4e69c..48bc4af 100644 --- a/space-crush-app/src/render/ships.rs +++ b/space-crush-app/src/render/ships.rs @@ -225,7 +225,7 @@ impl Ships { let index = self.id_to_index[id as usize]; let mut s = &mut buf_ship[index as usize]; - s.pos = *position.pos(); + s.pos = *position.get(); s.dir = *velocity.dir(); if self.need_init.contains(id) { @@ -239,7 +239,7 @@ impl Ships { ShipType::Transporter => 2, }; - let mut pos = *position.pos(); + let mut pos = *position.get(); let mut borrow_tail = self.input.tail_data.borrow_mut(); let mut buf_tail = borrow_tail .map_mut::(true) diff --git a/space-crush-common/src/builder/asteroid.rs b/space-crush-common/src/builder/asteroid.rs new file mode 100644 index 0000000..32dd665 --- /dev/null +++ b/space-crush-common/src/builder/asteroid.rs @@ -0,0 +1,82 @@ +use specs::{saveload::MarkedBuilder, Builder, Entity, World, WorldExt, WriteStorage}; + +use glc::vector::Vector2f; + +use crate::{ + components::{Asteroid, AsteroidType, MeetingPoint, Obstacle, PlayerOwned, Position, Shape}, + misc::{Persistence, WorldPersistence}, +}; + +use super::Error; + +#[derive(Default, Clone)] +pub struct AsteroidBuilder { + type_: Option, + position: Option, + size: Option, + orbit: Option<(f32, f32)>, + owner: Option, +} + +impl AsteroidBuilder { + pub fn build(self, world: &mut World) -> Result { + let type_ = self.type_.ok_or(Error::MissingValue("type"))?; + let position = self.position.ok_or(Error::MissingValue("position"))?; + let size = self.size.ok_or(Error::MissingValue("size"))?; + let (orbit_min, orbit_max) = self.orbit.ok_or(Error::MissingValue("orbit"))?; + + let position = Position::new(position); + let shape = Shape::Circle(size); + let meeting_point = MeetingPoint::new(orbit_min, orbit_max); + let obstacle = Obstacle::default(); + let asteroid = Asteroid::new(type_); + + let entity = world + .create_entity() + .marked::<::Marker>() + .with(position) + .with(shape) + .with(meeting_point) + .with(obstacle) + .with(asteroid) + .build(); + + if let Some(owner) = self.owner { + let mut player_owned = world.system_data::>(); + + player_owned.insert(entity, PlayerOwned::new(owner))?; + } + + Ok(entity) + } + + pub fn type_(mut self, value: AsteroidType) -> Self { + self.type_ = Some(value); + + self + } + + pub fn position>(mut self, value: V) -> Self { + self.position = Some(value.into()); + + self + } + + pub fn size(mut self, value: f32) -> Self { + self.size = Some(value); + + self + } + + pub fn orbit(mut self, min: f32, max: f32) -> Self { + self.orbit = Some((min, max)); + + self + } + + pub fn owner(mut self, player: Entity) -> Self { + self.owner = Some(player); + + self + } +} diff --git a/space-crush-common/src/builder/fleet.rs b/space-crush-common/src/builder/fleet.rs new file mode 100644 index 0000000..9e85446 --- /dev/null +++ b/space-crush-common/src/builder/fleet.rs @@ -0,0 +1,37 @@ +use specs::{saveload::MarkedBuilder, Builder, Entity, World, WorldExt}; + +use crate::{ + components::{Fleet, MeetingPointOwned}, + misc::{Persistence, WorldPersistence}, +}; + +use super::Error; + +#[derive(Default, Clone)] +pub struct FleetBuilder { + owner: Option, +} + +impl FleetBuilder { + pub fn build(self, world: &mut World) -> Result { + let owner = self.owner.ok_or(Error::MissingValue("owner"))?; + + let meeting_point_owned = MeetingPointOwned::new(owner); + let fleet = Fleet::new(); + + let entity = world + .create_entity() + .marked::<::Marker>() + .with(meeting_point_owned) + .with(fleet) + .build(); + + Ok(entity) + } + + pub fn owner(mut self, meeting_point: Entity) -> Self { + self.owner = Some(meeting_point); + + self + } +} diff --git a/space-crush-common/src/builder/mod.rs b/space-crush-common/src/builder/mod.rs new file mode 100644 index 0000000..9ff845f --- /dev/null +++ b/space-crush-common/src/builder/mod.rs @@ -0,0 +1,29 @@ +mod asteroid; +mod fleet; +mod planet; +mod player; +mod ship; + +pub use asteroid::AsteroidBuilder; +pub use fleet::FleetBuilder; +pub use planet::PlanetBuilder; +pub use player::PlayerBuilder; +pub use ship::ShipBuilder; + +use specs::error::Error as SpecsError; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum Error { + #[error("Specs Error: {0}")] + SpecsError(SpecsError), + + #[error("Builder is missing the value '{0}'")] + MissingValue(&'static str), +} + +impl From for Error { + fn from(err: SpecsError) -> Self { + Self::SpecsError(err) + } +} diff --git a/space-crush-common/src/builder/planet.rs b/space-crush-common/src/builder/planet.rs new file mode 100644 index 0000000..a2ce679 --- /dev/null +++ b/space-crush-common/src/builder/planet.rs @@ -0,0 +1,74 @@ +use specs::{saveload::MarkedBuilder, Builder, Entity, World, WorldExt, WriteStorage}; + +use glc::vector::Vector2f; + +use crate::{ + components::{MeetingPoint, Obstacle, Planet, PlayerOwned, Position, Shape}, + misc::{Persistence, WorldPersistence}, +}; + +use super::Error; + +#[derive(Default, Clone)] +pub struct PlanetBuilder { + position: Option, + size: Option, + orbit: Option<(f32, f32)>, + owner: Option, +} + +impl PlanetBuilder { + pub fn build(self, world: &mut World) -> Result { + let position = self.position.ok_or(Error::MissingValue("position"))?; + let size = self.size.ok_or(Error::MissingValue("size"))?; + let (orbit_min, orbit_max) = self.orbit.ok_or(Error::MissingValue("orbit"))?; + + let position = Position::new(position); + let shape = Shape::Circle(size); + let meeting_point = MeetingPoint::new(orbit_min, orbit_max); + let obstacle = Obstacle::default(); + let planet = Planet::default(); + + let entity = world + .create_entity() + .marked::<::Marker>() + .with(position) + .with(shape) + .with(meeting_point) + .with(obstacle) + .with(planet) + .build(); + + if let Some(owner) = self.owner { + let mut player_owned = world.system_data::>(); + + player_owned.insert(entity, PlayerOwned::new(owner))?; + } + + Ok(entity) + } + + pub fn position>(mut self, value: V) -> Self { + self.position = Some(value.into()); + + self + } + + pub fn size(mut self, value: f32) -> Self { + self.size = Some(value); + + self + } + + pub fn orbit(mut self, min: f32, max: f32) -> Self { + self.orbit = Some((min, max)); + + self + } + + pub fn owner(mut self, player: Entity) -> Self { + self.owner = Some(player); + + self + } +} diff --git a/space-crush-common/src/builder/player.rs b/space-crush-common/src/builder/player.rs new file mode 100644 index 0000000..82783b7 --- /dev/null +++ b/space-crush-common/src/builder/player.rs @@ -0,0 +1,37 @@ +use specs::{saveload::MarkedBuilder, Builder, Entity, World, WorldExt}; + +use glc::vector::Vector3f; + +use crate::{ + components::Player, + misc::{Persistence, WorldPersistence}, +}; + +use super::Error; + +#[derive(Default, Clone)] +pub struct PlayerBuilder { + color: Option, +} + +impl PlayerBuilder { + pub fn build(self, world: &mut World) -> Result { + let color = self.color.ok_or(Error::MissingValue("color"))?; + + let player = Player::new(color); + + let entity = world + .create_entity() + .marked::<::Marker>() + .with(player) + .build(); + + Ok(entity) + } + + pub fn color>(mut self, value: V) -> Self { + self.color = Some(value.into()); + + self + } +} diff --git a/space-crush-common/src/builder/ship.rs b/space-crush-common/src/builder/ship.rs new file mode 100644 index 0000000..a835b5a --- /dev/null +++ b/space-crush-common/src/builder/ship.rs @@ -0,0 +1,90 @@ +use glc::vector::Vector2f; +use rand::random; +use specs::{saveload::MarkedBuilder, Builder, Entity, World, WorldExt}; + +use crate::{ + components::{FleetOwned, PlayerOwned, Position, Ship, ShipType, Velocity}, + misc::{Persistence, WorldPersistence}, +}; + +use super::Error; + +#[derive(Clone)] +pub struct ShipBuilder { + player: Option, + fleet: Option, + position: Option, + type_: Option, + direction: Vector2f, +} + +impl ShipBuilder { + pub fn build(self, world: &mut World) -> Result { + let player = self.player.ok_or(Error::MissingValue("player"))?; + let fleet = self.fleet.ok_or(Error::MissingValue("fleet"))?; + let position = self.position.ok_or(Error::MissingValue("position"))?; + let type_ = self.type_.ok_or(Error::MissingValue("type"))?; + let direction = self.direction; + let speed = 100.0; + + let player_owned = PlayerOwned::new(player); + let fleet_owned = FleetOwned::new(fleet); + let position = Position::new(position); + let velocity = Velocity::new(direction, speed); + let ship = Ship::new(type_); + + let entity = world + .create_entity() + .marked::<::Marker>() + .with(player_owned) + .with(fleet_owned) + .with(position) + .with(velocity) + .with(ship) + .build(); + + Ok(entity) + } + + pub fn player(mut self, value: Entity) -> Self { + self.player = Some(value); + + self + } + + pub fn fleet(mut self, value: Entity) -> Self { + self.fleet = Some(value); + + self + } + + pub fn position>(mut self, value: V) -> Self { + self.position = Some(value.into()); + + self + } + + pub fn direction>(mut self, value: V) -> Self { + self.position = Some(value.into()); + + self + } + + pub fn type_(mut self, value: ShipType) -> Self { + self.type_ = Some(value); + + self + } +} + +impl Default for ShipBuilder { + fn default() -> Self { + Self { + player: None, + fleet: None, + position: None, + type_: None, + direction: Vector2f::new(random::() - 0.5, random::() - 0.5).normalize(), + } + } +} diff --git a/space-crush-common/src/components/asteroid.rs b/space-crush-common/src/components/asteroid.rs index 6adbd38..5ad69a1 100644 --- a/space-crush-common/src/components/asteroid.rs +++ b/space-crush-common/src/components/asteroid.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use specs::{Component, HashMapStorage}; -use crate::misc::FlaggedStorage; +use crate::{builder::AsteroidBuilder, misc::FlaggedStorage}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Asteroid { @@ -14,10 +14,12 @@ pub enum Type { Crystal, } +/* Asteroid */ + impl Asteroid { #[inline] - pub fn new(type_: Type) -> Self { - Self { type_ } + pub fn builder() -> AsteroidBuilder { + AsteroidBuilder::default() } #[inline] @@ -26,6 +28,13 @@ impl Asteroid { } } +impl Asteroid { + #[inline] + pub(crate) fn new(type_: Type) -> Self { + Self { type_ } + } +} + impl Component for Asteroid { type Storage = FlaggedStorage>; } diff --git a/space-crush-common/src/components/fleet.rs b/space-crush-common/src/components/fleet.rs index 120068f..6cde4f9 100644 --- a/space-crush-common/src/components/fleet.rs +++ b/space-crush-common/src/components/fleet.rs @@ -8,10 +8,14 @@ use specs::{ Component, Entity, HashMapStorage, VecStorage, }; -use crate::{components::ShipCount, misc::FlaggedStorage}; +use crate::{ + builder::FleetBuilder, + components::{Ship, ShipCount}, + misc::FlaggedStorage, +}; /// A fleet is a group of ships that share the same operation -#[derive(Default, Debug, Clone)] +#[derive(Debug, Clone)] pub struct Fleet { owned: BitSet, count: ShipCount, @@ -28,25 +32,45 @@ pub struct FleetOwnedData { pub owner: M, } +/* Fleet */ + impl Fleet { #[inline] - pub fn owned(&self) -> &BitSet { - &self.owned + pub fn builder() -> FleetBuilder { + FleetBuilder::default() } #[inline] - pub(crate) fn owned_mut(&mut self) -> &mut BitSet { - &mut self.owned + pub fn owned(&self) -> &BitSet { + &self.owned } #[inline] pub fn count(&self) -> &ShipCount { &self.count } +} - #[inline] - pub(crate) fn count_mut(&mut self) -> &mut ShipCount { - &mut self.count +impl Fleet { + pub(crate) fn new() -> Self { + Self { + owned: BitSet::new(), + count: ShipCount::none(), + } + } + + pub(crate) fn add_ship(&mut self, ship_id: Entity, ship: &Ship) { + let type_ = ship.type_(); + + self.count[type_] += 1; + self.owned.add(ship_id.id()); + } + + pub(crate) fn remove_ship(&mut self, ship_id: Entity, ship: &Ship) { + let type_ = ship.type_(); + + self.count[type_] -= 1; + self.owned.remove(ship_id.id()); } } @@ -54,6 +78,8 @@ impl Component for Fleet { type Storage = HashMapStorage; } +/* FleetOwned */ + impl FleetOwned { pub fn new(owner: Entity) -> Self { Self { owner } diff --git a/space-crush-common/src/components/meeting_point.rs b/space-crush-common/src/components/meeting_point.rs index c5d350a..cc589dd 100644 --- a/space-crush-common/src/components/meeting_point.rs +++ b/space-crush-common/src/components/meeting_point.rs @@ -37,16 +37,9 @@ pub struct MeetingPointOwnedData { type Fleets = SmallVec<[Option; 8]>; -impl MeetingPoint { - #[inline] - pub fn new(min: f32, max: f32) -> Self { - Self { - min, - max, - fleets: smallvec![], - } - } +/* MeetingPoint */ +impl MeetingPoint { #[inline] pub fn min(&self) -> f32 { self.min @@ -62,21 +55,20 @@ impl MeetingPoint { &self.fleets } - #[inline] - pub(crate) fn fleets_mut(&mut self) -> &mut Fleets { - &mut self.fleets - } - #[inline] pub fn fleet(&self, index: usize) -> Option { self.fleets.get(index).cloned().flatten() } +} +impl MeetingPoint { #[inline] - pub(crate) fn fleet_mut(&mut self, index: usize) -> &mut Option { - self.fleets.resize_with(index + 1, Default::default); - - &mut self.fleets[index] + pub(crate) fn new(min: f32, max: f32) -> Self { + Self { + min, + max, + fleets: smallvec![], + } } } @@ -119,17 +111,17 @@ where } } -impl MeetingPointOwned { - pub fn new(owner: Entity) -> Self { - Self { owner } - } +/* MeetingPointOwned */ +impl MeetingPointOwned { pub fn owner(&self) -> Entity { self.owner } +} - pub(crate) fn set_owner(&mut self, value: Entity) { - self.owner = value; +impl MeetingPointOwned { + pub(crate) fn new(owner: Entity) -> Self { + Self { owner } } } diff --git a/space-crush-common/src/components/mod.rs b/space-crush-common/src/components/mod.rs index d28c483..2ddd174 100644 --- a/space-crush-common/src/components/mod.rs +++ b/space-crush-common/src/components/mod.rs @@ -5,6 +5,7 @@ mod obstacle; mod planet; mod player; mod position; +mod shape; mod ship; mod velocity; @@ -14,6 +15,7 @@ pub use meeting_point::{MeetingPoint, MeetingPointOwned}; pub use obstacle::Obstacle; pub use planet::Planet; pub use player::{Player, PlayerOwned}; -pub use position::{Position, Shape}; +pub use position::Position; +pub use shape::Shape; pub use ship::{Count as ShipCount, Obstacle as ShipObstacle, Ship, Type as ShipType}; pub use velocity::Velocity; diff --git a/space-crush-common/src/components/obstacle.rs b/space-crush-common/src/components/obstacle.rs index 761f306..2b0dd87 100644 --- a/space-crush-common/src/components/obstacle.rs +++ b/space-crush-common/src/components/obstacle.rs @@ -5,6 +5,8 @@ use specs::{Component, NullStorage}; #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct Obstacle {} +/* Obstacle */ + impl Component for Obstacle { type Storage = NullStorage; } diff --git a/space-crush-common/src/components/planet.rs b/space-crush-common/src/components/planet.rs index 1fd59ad..c11c70c 100644 --- a/space-crush-common/src/components/planet.rs +++ b/space-crush-common/src/components/planet.rs @@ -1,11 +1,19 @@ use serde::{Deserialize, Serialize}; use specs::{Component, NullStorage}; -use crate::misc::FlaggedStorage; +use crate::{builder::PlanetBuilder, misc::FlaggedStorage}; #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct Planet {} +/* Planet */ + +impl Planet { + pub fn builder() -> PlanetBuilder { + PlanetBuilder::default() + } +} + impl Component for Planet { type Storage = FlaggedStorage>; } diff --git a/space-crush-common/src/components/player.rs b/space-crush-common/src/components/player.rs index c9af4d9..3c6e14f 100644 --- a/space-crush-common/src/components/player.rs +++ b/space-crush-common/src/components/player.rs @@ -6,6 +6,8 @@ use specs::{ Component, Entity, HashMapStorage, }; +use crate::builder::PlayerBuilder; + #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct Player { index: usize, @@ -22,13 +24,12 @@ pub struct PlayerOwnedData { pub owner: M, } +/* Player */ + impl Player { #[inline] - pub fn new(color: Vector3f) -> Self { - Self { - index: next_index(), - color, - } + pub fn builder() -> PlayerBuilder { + PlayerBuilder::default() } #[inline] @@ -42,20 +43,34 @@ impl Player { } } +impl Player { + #[inline] + pub(crate) fn new(color: Vector3f) -> Self { + Self { + index: next_index(), + color, + } + } +} + impl Component for Player { type Storage = HashMapStorage; } -impl PlayerOwned { - pub fn new(owner: Entity) -> Self { - Self { owner } - } +/* PlayerOwned */ +impl PlayerOwned { pub fn owner(&self) -> Entity { self.owner } } +impl PlayerOwned { + pub(crate) fn new(owner: Entity) -> Self { + Self { owner } + } +} + impl Component for PlayerOwned { type Storage = HashMapStorage; } diff --git a/space-crush-common/src/components/position.rs b/space-crush-common/src/components/position.rs index 4e822ba..bdf6aea 100644 --- a/space-crush-common/src/components/position.rs +++ b/space-crush-common/src/components/position.rs @@ -5,39 +5,22 @@ use specs::{Component, VecStorage}; #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct Position { pos: Vector2f, - shape: Shape, } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum Shape { - Dot, - Circle(f32), -} +/* Position */ impl Position { - pub fn dot(pos: Vector2f) -> Self { - Self { - pos, - shape: Shape::Dot, - } - } - - pub fn circle(pos: Vector2f, radius: f32) -> Self { - Self { - pos, - shape: Shape::Circle(radius), - } - } - - pub fn pos(&self) -> &Vector2f { + pub fn get(&self) -> &Vector2f { &self.pos } +} - pub fn shape(&self) -> &Shape { - &self.shape +impl Position { + pub(crate) fn new(pos: Vector2f) -> Self { + Self { pos } } - pub(crate) fn pos_mut(&mut self) -> &mut Vector2f { + pub(crate) fn get_mut(&mut self) -> &mut Vector2f { &mut self.pos } } @@ -45,26 +28,3 @@ impl Position { impl Component for Position { type Storage = VecStorage; } - -impl Shape { - pub fn radius(&self) -> f32 { - match self { - Self::Dot => 0.0, - Self::Circle(r) => *r, - } - } - - pub fn circle(&self) -> Option { - if let Self::Circle(r) = &self { - Some(*r) - } else { - None - } - } -} - -impl Default for Shape { - fn default() -> Self { - Self::Dot - } -} diff --git a/space-crush-common/src/components/shape.rs b/space-crush-common/src/components/shape.rs new file mode 100644 index 0000000..fb57161 --- /dev/null +++ b/space-crush-common/src/components/shape.rs @@ -0,0 +1,21 @@ +use serde::{Deserialize, Serialize}; +use specs::{Component, HashMapStorage}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Shape { + Circle(f32), +} + +/* Shape */ + +impl Component for Shape { + type Storage = HashMapStorage; +} + +impl Shape { + pub fn radius(&self) -> f32 { + match self { + Self::Circle(r) => *r, + } + } +} diff --git a/space-crush-common/src/components/ship.rs b/space-crush-common/src/components/ship.rs index 83eaca1..fd3c674 100644 --- a/space-crush-common/src/components/ship.rs +++ b/space-crush-common/src/components/ship.rs @@ -5,7 +5,7 @@ use glc::vector::Vector2f; use serde::{Deserialize, Serialize}; use specs::{Component, Entity, VecStorage}; -use crate::misc::FlaggedStorage; +use crate::{builder::ShipBuilder, misc::FlaggedStorage}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Ship { @@ -42,15 +42,12 @@ pub enum Type { Transporter, } +/* Ship */ + impl Ship { #[inline] - pub fn new(type_: Type) -> Self { - Self { - type_, - obstacle: Default::default(), - target_pos: Default::default(), - target_dir: Default::default(), - } + pub fn builder() -> ShipBuilder { + ShipBuilder::default() } #[inline] @@ -69,14 +66,26 @@ impl Ship { } #[inline] - pub(crate) fn set_target(&mut self, pos: Vector2f, dir: Vector2f) { - self.target_pos = pos; - self.target_dir = dir; + pub fn obstacle(&self) -> Obstacle { + self.obstacle } +} +impl Ship { #[inline] - pub fn obstacle(&self) -> Obstacle { - self.obstacle + pub(crate) fn new(type_: Type) -> Self { + Self { + type_, + obstacle: Default::default(), + target_pos: Default::default(), + target_dir: Default::default(), + } + } + + #[inline] + pub(crate) fn set_target(&mut self, pos: Vector2f, dir: Vector2f) { + self.target_pos = pos; + self.target_dir = dir; } #[inline] @@ -89,12 +98,16 @@ impl Component for Ship { type Storage = FlaggedStorage>; } +/* Obstacle */ + impl Default for Obstacle { fn default() -> Self { Self::Search } } +/* Count */ + impl Count { pub fn all() -> Self { Self { diff --git a/space-crush-common/src/components/velocity.rs b/space-crush-common/src/components/velocity.rs index 34cbadd..d6db248 100644 --- a/space-crush-common/src/components/velocity.rs +++ b/space-crush-common/src/components/velocity.rs @@ -8,24 +8,28 @@ pub struct Velocity { speed: f32, } -impl Velocity { - pub fn new(dir: Vector2f, speed: f32) -> Self { - Self { dir, speed } - } +/* Velocity */ +impl Velocity { pub fn dir(&self) -> &Vector2f { &self.dir } - pub fn dir_mut(&mut self) -> &mut Vector2f { - &mut self.dir - } - pub fn speed(&self) -> f32 { self.speed } } +impl Velocity { + pub(crate) fn new(dir: Vector2f, speed: f32) -> Self { + Self { dir, speed } + } + + pub(crate) fn dir_mut(&mut self) -> &mut Vector2f { + &mut self.dir + } +} + impl Component for Velocity { type Storage = VecStorage; } diff --git a/space-crush-common/src/dispatcher.rs b/space-crush-common/src/dispatcher.rs index d043797..6a8fa78 100644 --- a/space-crush-common/src/dispatcher.rs +++ b/space-crush-common/src/dispatcher.rs @@ -3,7 +3,7 @@ use specs::{Dispatcher as Inner, DispatcherBuilder, World, WorldExt}; use crate::{ components::Player, resources::Global, - systems::{FleetControl, FleetOwnedUpdate, MeetingPointOwnedUpdate, Movement, Process, Ships}, + systems::{FleetControl, FleetOwnedUpdate, Movement, Process, Ships}, Error, }; @@ -23,11 +23,6 @@ impl<'a, 'b> Dispatcher<'a, 'b> { .with(Ships::new(world), "ships", &[]) .with(FleetControl::new(world)?, "fleet_control", &[]) .with(FleetOwnedUpdate::new(world), "fleet_owned_update", &[]) - .with( - MeetingPointOwnedUpdate::new(world), - "meeting_point_owned_update", - &[], - ) .build(); dispatcher.setup(world); diff --git a/space-crush-common/src/lib.rs b/space-crush-common/src/lib.rs index 232c20c..0cdd993 100644 --- a/space-crush-common/src/lib.rs +++ b/space-crush-common/src/lib.rs @@ -1,3 +1,4 @@ +pub mod builder; pub mod components; pub mod constants; pub mod dispatcher; diff --git a/space-crush-common/src/misc/mod.rs b/space-crush-common/src/misc/mod.rs index 7898d40..f78fe3f 100644 --- a/space-crush-common/src/misc/mod.rs +++ b/space-crush-common/src/misc/mod.rs @@ -11,5 +11,5 @@ pub use flagged_storage::{ ComponentEvent, FlaggedStorage, StorageHelper, StorageHelperMut, Tracked, }; pub use log_result::LogResult; -pub use persistence::{PersistWorld, Persistence}; -pub use world::WorldHelper; +pub use persistence::Persistence; +pub use world::{WorldHelper, WorldPersistence}; diff --git a/space-crush-common/src/misc/persistence.rs b/space-crush-common/src/misc/persistence.rs index f796f45..deeaaf1 100644 --- a/space-crush-common/src/misc/persistence.rs +++ b/space-crush-common/src/misc/persistence.rs @@ -1,37 +1,10 @@ use serde::{de::Deserializer, ser::Serializer}; use specs::{ error::NoError, - saveload::{ConvertSaveload, DeserializeComponents, Marker, SerializeComponents, SimpleMarker}, + saveload::{ConvertSaveload, DeserializeComponents, Marker, SerializeComponents}, Component, Entities, ReadStorage, World, WorldExt, Write, WriteStorage, }; -use crate::components::{ - Asteroid, FleetOwned, MeetingPoint, MeetingPointOwned, Obstacle, Planet, Player, PlayerOwned, - Position, Ship, Velocity, -}; - -/* PersistWorld */ - -pub struct PersistWorld; -pub struct PersistWorldMarker; - -impl Persistence for PersistWorld { - type Marker = SimpleMarker; - type Components = ( - Position, - Velocity, - Player, - PlayerOwned, - MeetingPoint, - MeetingPointOwned, - FleetOwned, - Ship, - Obstacle, - Planet, - Asteroid, - ); -} - /* Persistence */ pub trait Persistence { @@ -45,6 +18,8 @@ pub trait Persistence { { world.register::(); world.insert(::Allocator::default()); + + Self::Components::setup(world); } fn serialize(&self, world: &World, serializer: S) -> Result<(), S::Error> @@ -68,6 +43,8 @@ pub trait PersistenceComponents where M: Marker, { + fn setup(world: &mut World); + fn serialize(world: &World, serializer: S) -> Result<(), S::Error> where S: Serializer; @@ -85,7 +62,12 @@ macro_rules! define_persistence_components { M: Marker, M::Allocator: Default, $($T: Component + ConvertSaveload,)+ + $($T::Storage: Default,)+ { + fn setup(world: &mut World) { + $( world.register::<$T>(); )* + } + fn serialize(world: &World, serializer: S) -> Result<(), S::Error> where S: Serializer, diff --git a/space-crush-common/src/misc/world.rs b/space-crush-common/src/misc/world.rs index e42cae9..b57147c 100644 --- a/space-crush-common/src/misc/world.rs +++ b/space-crush-common/src/misc/world.rs @@ -3,9 +3,15 @@ use std::any::type_name; use serde::{de::Deserializer, ser::Serializer}; use shred::{Fetch, FetchMut, Resource}; use shrev::{Event, EventChannel, ReaderId}; -use specs::World; +use specs::{saveload::SimpleMarker, World}; -use crate::Error; +use crate::{ + components::{ + Asteroid, MeetingPoint, MeetingPointOwned, Obstacle, Planet, Player, PlayerOwned, Position, + Ship, Velocity, + }, + Error, +}; use super::Persistence; @@ -75,3 +81,24 @@ impl WorldHelper for World { persistence.deserialize(self, deserializer) } } + +/* WorldPersistence */ + +pub struct WorldPersistence; +pub struct PersistWorldMarker; + +impl Persistence for WorldPersistence { + type Marker = SimpleMarker; + type Components = ( + Position, + Velocity, + Player, + PlayerOwned, + MeetingPoint, + MeetingPointOwned, + Ship, + Obstacle, + Planet, + Asteroid, + ); +} diff --git a/space-crush-common/src/systems/fleet_control.rs b/space-crush-common/src/systems/fleet_control.rs index e8d072e..0d7e64a 100644 --- a/space-crush-common/src/systems/fleet_control.rs +++ b/space-crush-common/src/systems/fleet_control.rs @@ -1,16 +1,19 @@ +// TODO +#![allow(dead_code)] +#![allow(unused_mut)] +#![allow(unused_imports)] +#![allow(unused_variables)] + use shrev::{EventChannel, ReaderId}; use specs::{ - prelude::*, saveload::MarkedBuilder, Entities, Entity, LazyUpdate, ReadExpect, ReadStorage, - System, World, WriteStorage, + prelude::*, Entities, Entity, LazyUpdate, ReadExpect, ReadStorage, System, World, WriteStorage, }; use crate::{ components::{ Fleet, FleetOwned, MeetingPoint, MeetingPointOwned, Player, PlayerOwned, Ship, ShipCount, - ShipType, }, - continue_if_none, - misc::{LogResult, PersistWorld, Persistence, WorldHelper}, + misc::WorldHelper, Error, }; @@ -20,15 +23,12 @@ pub struct FleetControl { #[derive(Debug)] pub enum FleetControlEvent { - Move(MoveArgs), -} - -#[derive(Debug)] -pub struct MoveArgs { - player: Entity, - target: Entity, - fleet: Entity, - count: ShipCount, + MoveToMeetingPoint { + player: Entity, + fleet: Entity, + count: ShipCount, + target: Entity, + }, } #[derive(SystemData)] @@ -74,6 +74,7 @@ impl<'a> System<'a> for FleetControl { ships, } = data; + /* TODO let events = fleet_control_events.read(&mut self.fleet_control_event_id); for event in events { match event { @@ -91,7 +92,7 @@ impl<'a> System<'a> for FleetControl { f @ None => { let fleet = lazy .create_entity(&entities) - .marked::<::Marker>() + .marked::<::Marker>() .build(); player_owned @@ -132,16 +133,6 @@ impl<'a> System<'a> for FleetControl { } } } - } -} - -impl FleetControlEvent { - pub fn move_(player: Entity, target: Entity, fleet: Entity, count: ShipCount) -> Self { - Self::Move(MoveArgs { - player, - target, - fleet, - count, - }) + */ } } diff --git a/space-crush-common/src/systems/fleet_owned_update.rs b/space-crush-common/src/systems/fleet_owned_update.rs index ff607ba..c75d819 100644 --- a/space-crush-common/src/systems/fleet_owned_update.rs +++ b/space-crush-common/src/systems/fleet_owned_update.rs @@ -102,17 +102,9 @@ impl<'a> System<'a> for FleetOwnedUpdate { }; if old_match && !new_match { - let count = fleet.count_mut(); - let count = &mut count[ship.type_()]; - *count = count.saturating_sub(1); - - fleet.owned_mut().remove(ship_id.id()); + fleet.remove_ship(ship_id, ship); } else if !old_match && new_match { - let count = fleet.count_mut(); - let count = &mut count[ship.type_()]; - *count += 1; - - fleet.owned_mut().add(ship_id.id()); + fleet.add_ship(ship_id, ship); } } } diff --git a/space-crush-common/src/systems/meeting_point_owned_update.rs b/space-crush-common/src/systems/meeting_point_owned_update.rs deleted file mode 100644 index d811b08..0000000 --- a/space-crush-common/src/systems/meeting_point_owned_update.rs +++ /dev/null @@ -1,130 +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::{MeetingPoint, MeetingPointOwned, PlayerOwned}, - misc::{ComponentEvent, StorageHelper, StorageHelperMut}, -}; - -pub struct MeetingPointOwnedUpdate { - meeting_point_ids: BitSet, - meeting_point_owned_ids: BitSet, - old_meeting_point_ids: HashMap, - meeting_point_owned_event_id: ReaderId>, -} - -impl MeetingPointOwnedUpdate { - pub fn new(world: &mut World) -> Self { - WriteStorage::::setup(world); - - let meeting_point_ids = BitSet::new(); - let meeting_point_owned_ids = BitSet::new(); - let old_meeting_point_ids = HashMap::new(); - let meeting_point_owned_event_id = world - .system_data::>() - .register_event_reader(); - - Self { - meeting_point_ids, - meeting_point_owned_ids, - old_meeting_point_ids, - meeting_point_owned_event_id, - } - } -} - -#[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); - } - } - } - } -} diff --git a/space-crush-common/src/systems/mod.rs b/space-crush-common/src/systems/mod.rs index 196af74..91af7d4 100644 --- a/space-crush-common/src/systems/mod.rs +++ b/space-crush-common/src/systems/mod.rs @@ -1,13 +1,11 @@ mod fleet_control; mod fleet_owned_update; -mod meeting_point_owned_update; mod movement; mod process; mod ships; pub use fleet_control::{FleetControl, FleetControlEvent}; pub use fleet_owned_update::FleetOwnedUpdate; -pub use meeting_point_owned_update::MeetingPointOwnedUpdate; pub use movement::Movement; pub use process::Process; pub use ships::Ships; diff --git a/space-crush-common/src/systems/movement.rs b/space-crush-common/src/systems/movement.rs index 5f8a8fe..4cfd316 100644 --- a/space-crush-common/src/systems/movement.rs +++ b/space-crush-common/src/systems/movement.rs @@ -31,8 +31,9 @@ impl<'a> System<'a> for Movement { .par_join() .for_each(|(position, velocity)| { let delta = global.delta * global.world_speed; + let position = position.get_mut(); - *position.pos_mut() += velocity.dir() * velocity.speed() * delta; + *position += velocity.dir() * velocity.speed() * delta; }); } } diff --git a/space-crush-common/src/systems/ships.rs b/space-crush-common/src/systems/ships.rs index 45e5dd4..0022f57 100644 --- a/space-crush-common/src/systems/ships.rs +++ b/space-crush-common/src/systems/ships.rs @@ -12,7 +12,7 @@ use specs::{ use crate::{ components::{ - FleetOwned, MeetingPoint, MeetingPointOwned, Obstacle, Position, Ship, ShipObstacle, + FleetOwned, MeetingPoint, MeetingPointOwned, Obstacle, Position, Shape, Ship, ShipObstacle, Velocity, }, constants::{ @@ -38,6 +38,7 @@ pub struct ShipsData<'a> { fleet_owned: ReadStorage<'a, FleetOwned>, meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, positions: ReadStorage<'a, Position>, + shapes: ReadStorage<'a, Shape>, obstacles: ReadStorage<'a, Obstacle>, meeting_points: ReadStorage<'a, MeetingPoint>, } @@ -46,6 +47,7 @@ struct Processor<'a> { need_update: &'a BitSet, entities: &'a Entities<'a>, positions: &'a ReadStorage<'a, Position>, + shapes: &'a ReadStorage<'a, Shape>, obstacles: &'a ReadStorage<'a, Obstacle>, meeting_points: &'a ReadStorage<'a, MeetingPoint>, meeting_point_owned: &'a ReadStorage<'a, MeetingPointOwned>, @@ -94,6 +96,7 @@ impl<'a> System<'a> for Ships { fleet_owned, meeting_point_owned, positions, + shapes, obstacles, meeting_points, } = data; @@ -105,6 +108,7 @@ impl<'a> System<'a> for Ships { need_update: &self.need_update, entities: &entities, positions: &positions, + shapes: &shapes, obstacles: &obstacles, meeting_point_owned: &meeting_point_owned, meeting_points: &meeting_points, @@ -143,8 +147,8 @@ impl Processor<'_> { 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 meeting_point_pos = return_if_none!(self.positions.get(meeting_point_id)).get(); + let ship_pos = position.get(); let target_pos = ship.target_pos(); let target_dir = ship.target_dir(); @@ -213,7 +217,7 @@ impl Processor<'_> { } else if let ShipObstacle::Known(obstacle) = ship.obstacle() { if let Some(position) = self.positions.get(obstacle) { let obstacle_meeting_point = self.meeting_points.get(obstacle).unwrap(); - let obstacle_pos = position.pos(); + let obstacle_pos = position.get(); let ship_to_obstacle = obstacle_pos - ship_pos; let obstacle_angle = ship_to_target @@ -237,7 +241,7 @@ impl Processor<'_> { if !ship_in_meeting_point && ship.obstacle() == ShipObstacle::Search { let mut dist_sqr = f32::MAX; for (e, position, _) in (self.entities, self.positions, self.obstacles).join() { - let obstacle_pos = position.pos(); + let obstacle_pos = position.get(); let ship_to_obstacle = obstacle_pos - ship_pos; if ship_to_target * ship_to_obstacle < 0.0 { @@ -262,8 +266,9 @@ impl Processor<'_> { let mut expected_dir = ship_to_target; if let ShipObstacle::Known(obstacle) = ship.obstacle() { let obstacle_pos = self.positions.get(obstacle).unwrap(); + let obstacle_shape = self.shapes.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.get() - ship_pos; let meeting_point_min = obstacle_meeting_point.min(); let meeting_point_max = obstacle_meeting_point.max(); @@ -272,7 +277,7 @@ impl Processor<'_> { if meeting_point < meeting_point_max { let mut tangent = Vector2f::new(-ship_to_obstacle.y, ship_to_obstacle.x); - let radius = obstacle_pos.shape().radius(); + let radius = obstacle_shape.radius(); 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);