Using builders ensure that the correct components are added to a new created entity.master
| @@ -74,7 +74,7 @@ impl<'a> System<'a> for Fleets { | |||||
| ), | ), | ||||
| ) | ) | ||||
| .panic("Unable to update text") | .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); | gl::blend_equation(gl::FUNC_ADD); | ||||
| @@ -34,16 +34,16 @@ impl<'a> System<'a> for MeetingPoints { | |||||
| gl::blend_equation(gl::FUNC_ADD); | gl::blend_equation(gl::FUNC_ADD); | ||||
| geometry.render_lines( | geometry.render_lines( | ||||
| Vector4f::new(0.5, 0.5, 0.5, 0.05), | Vector4f::new(0.5, 0.5, 0.5, 0.05), | ||||
| &create_circle(position.pos(), meeting_point.min()), | |||||
| &create_circle(position.get(), meeting_point.min()), | |||||
| ); | ); | ||||
| geometry.render_lines( | geometry.render_lines( | ||||
| Vector4f::new(0.5, 0.5, 0.5, 0.05), | Vector4f::new(0.5, 0.5, 0.5, 0.05), | ||||
| &create_circle(position.pos(), meeting_point.max()), | |||||
| &create_circle(position.get(), meeting_point.max()), | |||||
| ); | ); | ||||
| geometry.render_lines( | geometry.render_lines( | ||||
| Vector4f::new(0.5, 0.5, 0.5, 0.05), | Vector4f::new(0.5, 0.5, 0.5, 0.05), | ||||
| &create_circle( | &create_circle( | ||||
| position.pos(), | |||||
| position.get(), | |||||
| SHIP_ORBIT_DISTANCE_MAX * meeting_point.max(), | SHIP_ORBIT_DISTANCE_MAX * meeting_point.max(), | ||||
| ), | ), | ||||
| ); | ); | ||||
| @@ -33,7 +33,7 @@ impl<'a> System<'a> for Ships { | |||||
| gl::blend_func(gl::SRC_ALPHA, gl::ONE); | gl::blend_func(gl::SRC_ALPHA, gl::ONE); | ||||
| for (position, velocity, ship) in (&positions, &velocities, &ships).join() { | for (position, velocity, ship) in (&positions, &velocities, &ships).join() { | ||||
| let ship_pos = position.pos(); | |||||
| let ship_pos = position.get(); | |||||
| geometry.render_lines( | geometry.render_lines( | ||||
| Vector4f::new(0.0, 0.0, 1.0, 0.2), | 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() { | 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( | geometry.render_lines( | ||||
| Vector4f::new(0.0, 1.0, 0.0, 0.2), | Vector4f::new(0.0, 1.0, 0.0, 0.2), | ||||
| @@ -7,7 +7,7 @@ use glutin::{ | |||||
| }; | }; | ||||
| use glyph_brush::ab_glyph::InvalidFont; | use glyph_brush::ab_glyph::InvalidFont; | ||||
| use serde_json::Error as JsonError; | 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; | use thiserror::Error; | ||||
| #[derive(Debug, Error)] | #[derive(Debug, Error)] | ||||
| @@ -39,6 +39,9 @@ pub enum Error { | |||||
| #[error("{0}")] | #[error("{0}")] | ||||
| CommonError(CommonError), | CommonError(CommonError), | ||||
| #[error("{0}")] | |||||
| BuilderError(BuilderError), | |||||
| #[error("Resource is not registered: {0}!")] | #[error("Resource is not registered: {0}!")] | ||||
| ResourceNotRegistered(&'static str), | ResourceNotRegistered(&'static str), | ||||
| @@ -102,3 +105,9 @@ impl From<CommonError> for Error { | |||||
| Self::CommonError(err) | Self::CommonError(err) | ||||
| } | } | ||||
| } | } | ||||
| impl From<BuilderError> for Error { | |||||
| fn from(err: BuilderError) -> Self { | |||||
| Self::BuilderError(err) | |||||
| } | |||||
| } | |||||
| @@ -1,13 +1,12 @@ | |||||
| use glc::vector::Vector3f; | |||||
| use log::{error, info}; | use log::{error, info}; | ||||
| use rand::random; | use rand::random; | ||||
| use space_crush_app::{App, Error}; | use space_crush_app::{App, Error}; | ||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::Player, | components::Player, | ||||
| misc::{init_logger, Vfs}, | |||||
| misc::{init_logger, Persistence, Vfs, WorldPersistence}, | |||||
| Dispatcher, | Dispatcher, | ||||
| }; | }; | ||||
| use specs::{Builder, Entity, World, WorldExt}; | |||||
| use specs::{Entity, World, WorldExt}; | |||||
| fn main() -> Result<(), Error> { | fn main() -> Result<(), Error> { | ||||
| let vfs = Vfs::new(&["space-crush-app"])?; | let vfs = Vfs::new(&["space-crush-app"])?; | ||||
| @@ -34,12 +33,10 @@ fn run(vfs: Vfs) -> Result<(), Error> { | |||||
| let mut world = World::new(); | let mut world = World::new(); | ||||
| world.insert(vfs); | world.insert(vfs); | ||||
| WorldPersistence::setup(&mut world); | |||||
| let mut common = Dispatcher::new(&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)?; | let mut app = App::new(&mut world, player1)?; | ||||
| create_world(&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) { | 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) | let planets = (0..3) | ||||
| .map(|i| { | .map(|i| { | ||||
| let x = 2000.0 * (i as f32 - 1.0); | let x = 2000.0 * (i as f32 - 1.0); | ||||
| let y = 0.0; | let y = 0.0; | ||||
| world | |||||
| .create_entity() | |||||
| .marked::<<PersistWorld as Persistence>::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::<Vec<_>>(); | .collect::<Vec<_>>(); | ||||
| @@ -93,27 +79,20 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
| let x = 1000.0 * i_x as f32; | let x = 1000.0 * i_x as f32; | ||||
| let y = 1000.0 * i_y as f32; | let y = 1000.0 * i_y as f32; | ||||
| world | |||||
| .create_entity() | |||||
| .marked::<<PersistWorld as Persistence>::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::Metal, | ||||
| 1 => AsteroidType::Crystal, | 1 => AsteroidType::Crystal, | ||||
| _ => unreachable!(), | _ => unreachable!(), | ||||
| })) | |||||
| .build(); | |||||
| }) | |||||
| .build(world) | |||||
| .unwrap(); | |||||
| } | } | ||||
| let fleet_id = world | |||||
| .create_entity() | |||||
| .marked::<<PersistWorld as Persistence>::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 { | for i in 0..9 { | ||||
| let r = 325.0 + 100.0 * random::<f32>(); | let r = 325.0 + 100.0 * random::<f32>(); | ||||
| @@ -122,22 +101,17 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
| let x = r * a.cos(); | let x = r * a.cos(); | ||||
| let y = r * a.sin(); | let y = r * a.sin(); | ||||
| world | |||||
| .create_entity() | |||||
| .marked::<<PersistWorld as Persistence>::Marker>() | |||||
| .with(PlayerOwned::new(player_id)) | |||||
| .with(FleetOwned::new(fleet_id)) | |||||
| .with(Position::dot(Vector2f::new(x, y))) | |||||
| .with(Velocity::new( | |||||
| Vector2f::new(random::<f32>() - 0.5, random::<f32>() - 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, | 0 => ShipType::Fighter, | ||||
| 1 => ShipType::Bomber, | 1 => ShipType::Bomber, | ||||
| 2 => ShipType::Transporter, | 2 => ShipType::Transporter, | ||||
| _ => unreachable!(), | _ => unreachable!(), | ||||
| })) | |||||
| .build(); | |||||
| }) | |||||
| .build(world) | |||||
| .unwrap(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -9,16 +9,13 @@ use glc::{ | |||||
| vertex_array::{DataType, VertexArray}, | vertex_array::{DataType, VertexArray}, | ||||
| }; | }; | ||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{Asteroid, AsteroidType, Player, PlayerOwned, Position}, | |||||
| components::{Asteroid, AsteroidType, Player, PlayerOwned, Position, Shape}, | |||||
| misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, | misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, | ||||
| }; | }; | ||||
| use specs::{prelude::*, ReadStorage, System, World}; | use specs::{prelude::*, ReadStorage, System, World}; | ||||
| use crate::{ | 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, | misc::WorldHelper, | ||||
| Error, | Error, | ||||
| }; | }; | ||||
| @@ -40,6 +37,15 @@ struct VertexData { | |||||
| texture: gl::GLint, | 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 { | impl Asteroids { | ||||
| pub fn new(world: &mut World) -> Result<Self, Error> { | pub fn new(world: &mut World) -> Result<Self, Error> { | ||||
| WriteStorage::<Asteroid>::setup(world); | WriteStorage::<Asteroid>::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 { | impl<'a> System<'a> for Asteroids { | ||||
| type SystemData = AsteroidsData<'a>; | type SystemData = AsteroidsData<'a>; | ||||
| fn run(&mut self, data: Self::SystemData) { | fn run(&mut self, data: Self::SystemData) { | ||||
| let AsteroidsData { | let AsteroidsData { | ||||
| positions, | positions, | ||||
| shapes, | |||||
| asteroids, | asteroids, | ||||
| players, | players, | ||||
| owned, | owned, | ||||
| @@ -141,16 +140,16 @@ impl<'a> System<'a> for Asteroids { | |||||
| ) | ) | ||||
| .panic("Unable to change buffer size for asteroid data"); | .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 | let mut buffer = buffer | ||||
| .map_mut::<VertexData>(true) | .map_mut::<VertexData>(true) | ||||
| .panic("Unable to map buffer for asteroid data"); | .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]; | 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())) { | d.color = match owned.and_then(|owned| players.get(owned.owner())) { | ||||
| Some(pv) => *pv.color(), | Some(pv) => *pv.color(), | ||||
| None => PLAYER_COLOR_DEFAULT, | None => PLAYER_COLOR_DEFAULT, | ||||
| @@ -69,7 +69,7 @@ impl<'a> System<'a> for FleetMove { | |||||
| (&entities, &positions, &meeting_points).join() | (&entities, &positions, &meeting_points).join() | ||||
| { | { | ||||
| let r = meeting_point.max() * meeting_point.max(); | 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); | self.target_meeting_point = Some(id); | ||||
| break; | break; | ||||
| @@ -82,7 +82,12 @@ impl<'a> System<'a> for FleetMove { | |||||
| let Selection { fleet, count } = selection; | let Selection { fleet, count } = selection; | ||||
| let target = continue_if_none!(self.target_meeting_point); | let target = continue_if_none!(self.target_meeting_point); | ||||
| let player = game_state.player_id(); | let player = game_state.player_id(); | ||||
| let event = FleetControlEvent::move_(player, target, fleet, count); | |||||
| let event = FleetControlEvent::MoveToMeetingPoint { | |||||
| player, | |||||
| fleet, | |||||
| count, | |||||
| target, | |||||
| }; | |||||
| fleet_control.single_write(event); | fleet_control.single_write(event); | ||||
| } | } | ||||
| @@ -10,7 +10,7 @@ use glc::{ | |||||
| }; | }; | ||||
| use shrev::{EventChannel, ReaderId}; | use shrev::{EventChannel, ReaderId}; | ||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{Fleet, MeetingPoint, MeetingPointOwned, Position, ShipCount}, | |||||
| components::{Fleet, MeetingPoint, MeetingPointOwned, Position, Shape, ShipCount}, | |||||
| constants::VECTOR_2F_POS_X, | constants::VECTOR_2F_POS_X, | ||||
| continue_if_none, | continue_if_none, | ||||
| misc::{LogResult, WorldHelper as _}, | misc::{LogResult, WorldHelper as _}, | ||||
| @@ -82,6 +82,7 @@ pub struct FleetSelectData<'a> { | |||||
| meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, | meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, | ||||
| positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
| shapes: ReadStorage<'a, Shape>, | |||||
| meeting_points: ReadStorage<'a, MeetingPoint>, | meeting_points: ReadStorage<'a, MeetingPoint>, | ||||
| fleets: ReadStorage<'a, Fleet>, | 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 { | macro_rules! meeting_point_owned { | ||||
| (&$data:expr, $id:expr) => { | (&$data:expr, $id:expr) => { | ||||
| return_if_none!($data.meeting_point_owned.get($id)) | return_if_none!($data.meeting_point_owned.get($id)) | ||||
| @@ -188,7 +195,7 @@ impl FleetSelect { | |||||
| let selection = d.game_state.selection_mut().take(); | let selection = d.game_state.selection_mut().take(); | ||||
| for (position, meeting_point) in (&d.positions, &d.meeting_points).join() { | for (position, meeting_point) in (&d.positions, &d.meeting_points).join() { | ||||
| let r = meeting_point.max() * meeting_point.max(); | 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 player_index = d.game_state.player_index(); | ||||
| let fleet_id = continue_if_none!(meeting_point.fleet(player_index)); | let fleet_id = continue_if_none!(meeting_point.fleet(player_index)); | ||||
| @@ -273,11 +280,12 @@ impl FleetSelect { | |||||
| let selection = selection!(&d); | let selection = selection!(&d); | ||||
| let meeting_point_owned = meeting_point_owned!(&d, selection.fleet); | let meeting_point_owned = meeting_point_owned!(&d, selection.fleet); | ||||
| let position = position!(&d, meeting_point_owned.owner()); | let position = position!(&d, meeting_point_owned.owner()); | ||||
| let shape = shape!(&d, meeting_point_owned.owner()); | |||||
| let fleet = fleet!(&d, selection.fleet); | let fleet = fleet!(&d, selection.fleet); | ||||
| self.marker = d.camera.view_to_world(self.mouse_pos) - position.pos(); | |||||
| self.marker = d.camera.view_to_world(self.mouse_pos) - position.get(); | |||||
| self.zoom = d.camera.view().axis_x.as_vec3().length(); | 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.ring0 = self.shape_size + FLEET_SELECT_OFFSET / self.zoom; | ||||
| self.ring1 = self.ring0 + FLEET_SELECT_WIDTH / self.zoom; | self.ring1 = self.ring0 + FLEET_SELECT_WIDTH / self.zoom; | ||||
| @@ -431,13 +439,12 @@ impl FleetSelect { | |||||
| /* calculate shared values */ | /* calculate shared values */ | ||||
| let size = self.ring1 + 50.0; | let size = self.ring1 + 50.0; | ||||
| let rings = Vector2f::new(self.ring0 / size, self.ring1 / size); | 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( | let m = Matrix4f::new( | ||||
| Vector4f::new(size, 0.0, 0.0, 0.0), | Vector4f::new(size, 0.0, 0.0, 0.0), | ||||
| Vector4f::new(0.0, size, 0.0, 0.0), | Vector4f::new(0.0, size, 0.0, 0.0), | ||||
| Vector4f::new(0.0, 0.0, size, 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 */ | /* update uniforms */ | ||||
| @@ -475,20 +482,20 @@ impl FleetSelect { | |||||
| if is_simple { | if is_simple { | ||||
| self.text_total | self.text_total | ||||
| .color(Vector4f::new(1.0, 1.0, 1.0, alpha)) | .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 { | } else { | ||||
| self.text_total | self.text_total | ||||
| .color(Vector4f::new(1.0, 1.0, 1.0, alpha)) | .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 | self.text_fighter | ||||
| .color(Vector4f::new(1.0, 1.0, 1.0, alpha)) | .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 | self.text_bomber | ||||
| .color(Vector4f::new(1.0, 1.0, 1.0, alpha)) | .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 | self.text_transporter | ||||
| .color(Vector4f::new(1.0, 1.0, 1.0, alpha)) | .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)); | |||||
| } | } | ||||
| } | } | ||||
| @@ -9,16 +9,13 @@ use glc::{ | |||||
| vertex_array::{DataType, VertexArray}, | vertex_array::{DataType, VertexArray}, | ||||
| }; | }; | ||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{Planet, Player, PlayerOwned, Position}, | |||||
| components::{Planet, Player, PlayerOwned, Position, Shape}, | |||||
| misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, | misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, | ||||
| }; | }; | ||||
| use specs::{prelude::*, ReadStorage, System, World}; | use specs::{prelude::*, ReadStorage, System, World}; | ||||
| use crate::{ | 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, | misc::WorldHelper, | ||||
| Error, | Error, | ||||
| }; | }; | ||||
| @@ -88,6 +85,7 @@ impl Planets { | |||||
| #[derive(SystemData)] | #[derive(SystemData)] | ||||
| pub struct PlanetsData<'a> { | pub struct PlanetsData<'a> { | ||||
| positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
| shapes: ReadStorage<'a, Shape>, | |||||
| planets: ReadStorage<'a, Planet>, | planets: ReadStorage<'a, Planet>, | ||||
| players: ReadStorage<'a, Player>, | players: ReadStorage<'a, Player>, | ||||
| owned: ReadStorage<'a, PlayerOwned>, | owned: ReadStorage<'a, PlayerOwned>, | ||||
| @@ -99,6 +97,7 @@ impl<'a> System<'a> for Planets { | |||||
| fn run(&mut self, data: Self::SystemData) { | fn run(&mut self, data: Self::SystemData) { | ||||
| let PlanetsData { | let PlanetsData { | ||||
| positions, | positions, | ||||
| shapes, | |||||
| planets, | planets, | ||||
| players, | players, | ||||
| owned, | owned, | ||||
| @@ -135,16 +134,16 @@ impl<'a> System<'a> for Planets { | |||||
| ) | ) | ||||
| .panic("Unable to change buffer size for planet data"); | .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 | let mut buffer = buffer | ||||
| .map_mut::<VertexData>(true) | .map_mut::<VertexData>(true) | ||||
| .panic("Unable to map buffer for planet data"); | .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]; | 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())) { | d.color = match owned.and_then(|owned| players.get(owned.owner())) { | ||||
| Some(pv) => *pv.color(), | Some(pv) => *pv.color(), | ||||
| None => PLAYER_COLOR_DEFAULT, | None => PLAYER_COLOR_DEFAULT, | ||||
| @@ -225,7 +225,7 @@ impl Ships { | |||||
| let index = self.id_to_index[id as usize]; | let index = self.id_to_index[id as usize]; | ||||
| let mut s = &mut buf_ship[index as usize]; | let mut s = &mut buf_ship[index as usize]; | ||||
| s.pos = *position.pos(); | |||||
| s.pos = *position.get(); | |||||
| s.dir = *velocity.dir(); | s.dir = *velocity.dir(); | ||||
| if self.need_init.contains(id) { | if self.need_init.contains(id) { | ||||
| @@ -239,7 +239,7 @@ impl Ships { | |||||
| ShipType::Transporter => 2, | 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 borrow_tail = self.input.tail_data.borrow_mut(); | ||||
| let mut buf_tail = borrow_tail | let mut buf_tail = borrow_tail | ||||
| .map_mut::<TailData>(true) | .map_mut::<TailData>(true) | ||||
| @@ -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<AsteroidType>, | |||||
| position: Option<Vector2f>, | |||||
| size: Option<f32>, | |||||
| orbit: Option<(f32, f32)>, | |||||
| owner: Option<Entity>, | |||||
| } | |||||
| impl AsteroidBuilder { | |||||
| pub fn build(self, world: &mut World) -> Result<Entity, Error> { | |||||
| 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::<<WorldPersistence as Persistence>::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::<WriteStorage<PlayerOwned>>(); | |||||
| 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<V: Into<Vector2f>>(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 | |||||
| } | |||||
| } | |||||
| @@ -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<Entity>, | |||||
| } | |||||
| impl FleetBuilder { | |||||
| pub fn build(self, world: &mut World) -> Result<Entity, Error> { | |||||
| 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::<<WorldPersistence as Persistence>::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 | |||||
| } | |||||
| } | |||||
| @@ -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<SpecsError> for Error { | |||||
| fn from(err: SpecsError) -> Self { | |||||
| Self::SpecsError(err) | |||||
| } | |||||
| } | |||||
| @@ -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<Vector2f>, | |||||
| size: Option<f32>, | |||||
| orbit: Option<(f32, f32)>, | |||||
| owner: Option<Entity>, | |||||
| } | |||||
| impl PlanetBuilder { | |||||
| pub fn build(self, world: &mut World) -> Result<Entity, Error> { | |||||
| 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::<<WorldPersistence as Persistence>::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::<WriteStorage<PlayerOwned>>(); | |||||
| player_owned.insert(entity, PlayerOwned::new(owner))?; | |||||
| } | |||||
| Ok(entity) | |||||
| } | |||||
| pub fn position<V: Into<Vector2f>>(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 | |||||
| } | |||||
| } | |||||
| @@ -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<Vector3f>, | |||||
| } | |||||
| impl PlayerBuilder { | |||||
| pub fn build(self, world: &mut World) -> Result<Entity, Error> { | |||||
| let color = self.color.ok_or(Error::MissingValue("color"))?; | |||||
| let player = Player::new(color); | |||||
| let entity = world | |||||
| .create_entity() | |||||
| .marked::<<WorldPersistence as Persistence>::Marker>() | |||||
| .with(player) | |||||
| .build(); | |||||
| Ok(entity) | |||||
| } | |||||
| pub fn color<V: Into<Vector3f>>(mut self, value: V) -> Self { | |||||
| self.color = Some(value.into()); | |||||
| self | |||||
| } | |||||
| } | |||||
| @@ -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<Entity>, | |||||
| fleet: Option<Entity>, | |||||
| position: Option<Vector2f>, | |||||
| type_: Option<ShipType>, | |||||
| direction: Vector2f, | |||||
| } | |||||
| impl ShipBuilder { | |||||
| pub fn build(self, world: &mut World) -> Result<Entity, Error> { | |||||
| 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::<<WorldPersistence as Persistence>::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<V: Into<Vector2f>>(mut self, value: V) -> Self { | |||||
| self.position = Some(value.into()); | |||||
| self | |||||
| } | |||||
| pub fn direction<V: Into<Vector2f>>(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::<f32>() - 0.5, random::<f32>() - 0.5).normalize(), | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,7 +1,7 @@ | |||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||
| use specs::{Component, HashMapStorage}; | use specs::{Component, HashMapStorage}; | ||||
| use crate::misc::FlaggedStorage; | |||||
| use crate::{builder::AsteroidBuilder, misc::FlaggedStorage}; | |||||
| #[derive(Clone, Debug, Serialize, Deserialize)] | #[derive(Clone, Debug, Serialize, Deserialize)] | ||||
| pub struct Asteroid { | pub struct Asteroid { | ||||
| @@ -14,10 +14,12 @@ pub enum Type { | |||||
| Crystal, | Crystal, | ||||
| } | } | ||||
| /* Asteroid */ | |||||
| impl Asteroid { | impl Asteroid { | ||||
| #[inline] | #[inline] | ||||
| pub fn new(type_: Type) -> Self { | |||||
| Self { type_ } | |||||
| pub fn builder() -> AsteroidBuilder { | |||||
| AsteroidBuilder::default() | |||||
| } | } | ||||
| #[inline] | #[inline] | ||||
| @@ -26,6 +28,13 @@ impl Asteroid { | |||||
| } | } | ||||
| } | } | ||||
| impl Asteroid { | |||||
| #[inline] | |||||
| pub(crate) fn new(type_: Type) -> Self { | |||||
| Self { type_ } | |||||
| } | |||||
| } | |||||
| impl Component for Asteroid { | impl Component for Asteroid { | ||||
| type Storage = FlaggedStorage<Self, HashMapStorage<Self>>; | type Storage = FlaggedStorage<Self, HashMapStorage<Self>>; | ||||
| } | } | ||||
| @@ -8,10 +8,14 @@ use specs::{ | |||||
| Component, Entity, HashMapStorage, VecStorage, | 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 | /// A fleet is a group of ships that share the same operation | ||||
| #[derive(Default, Debug, Clone)] | |||||
| #[derive(Debug, Clone)] | |||||
| pub struct Fleet { | pub struct Fleet { | ||||
| owned: BitSet, | owned: BitSet, | ||||
| count: ShipCount, | count: ShipCount, | ||||
| @@ -28,25 +32,45 @@ pub struct FleetOwnedData<M> { | |||||
| pub owner: M, | pub owner: M, | ||||
| } | } | ||||
| /* Fleet */ | |||||
| impl Fleet { | impl Fleet { | ||||
| #[inline] | #[inline] | ||||
| pub fn owned(&self) -> &BitSet { | |||||
| &self.owned | |||||
| pub fn builder() -> FleetBuilder { | |||||
| FleetBuilder::default() | |||||
| } | } | ||||
| #[inline] | #[inline] | ||||
| pub(crate) fn owned_mut(&mut self) -> &mut BitSet { | |||||
| &mut self.owned | |||||
| pub fn owned(&self) -> &BitSet { | |||||
| &self.owned | |||||
| } | } | ||||
| #[inline] | #[inline] | ||||
| pub fn count(&self) -> &ShipCount { | pub fn count(&self) -> &ShipCount { | ||||
| &self.count | &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<Self>; | type Storage = HashMapStorage<Self>; | ||||
| } | } | ||||
| /* FleetOwned */ | |||||
| impl FleetOwned { | impl FleetOwned { | ||||
| pub fn new(owner: Entity) -> Self { | pub fn new(owner: Entity) -> Self { | ||||
| Self { owner } | Self { owner } | ||||
| @@ -37,16 +37,9 @@ pub struct MeetingPointOwnedData<M> { | |||||
| type Fleets = SmallVec<[Option<Entity>; 8]>; | type Fleets = SmallVec<[Option<Entity>; 8]>; | ||||
| impl MeetingPoint { | |||||
| #[inline] | |||||
| pub fn new(min: f32, max: f32) -> Self { | |||||
| Self { | |||||
| min, | |||||
| max, | |||||
| fleets: smallvec![], | |||||
| } | |||||
| } | |||||
| /* MeetingPoint */ | |||||
| impl MeetingPoint { | |||||
| #[inline] | #[inline] | ||||
| pub fn min(&self) -> f32 { | pub fn min(&self) -> f32 { | ||||
| self.min | self.min | ||||
| @@ -62,21 +55,20 @@ impl MeetingPoint { | |||||
| &self.fleets | &self.fleets | ||||
| } | } | ||||
| #[inline] | |||||
| pub(crate) fn fleets_mut(&mut self) -> &mut Fleets { | |||||
| &mut self.fleets | |||||
| } | |||||
| #[inline] | #[inline] | ||||
| pub fn fleet(&self, index: usize) -> Option<Entity> { | pub fn fleet(&self, index: usize) -> Option<Entity> { | ||||
| self.fleets.get(index).cloned().flatten() | self.fleets.get(index).cloned().flatten() | ||||
| } | } | ||||
| } | |||||
| impl MeetingPoint { | |||||
| #[inline] | #[inline] | ||||
| pub(crate) fn fleet_mut(&mut self, index: usize) -> &mut Option<Entity> { | |||||
| 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 { | pub fn owner(&self) -> Entity { | ||||
| self.owner | 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 } | |||||
| } | } | ||||
| } | } | ||||
| @@ -5,6 +5,7 @@ mod obstacle; | |||||
| mod planet; | mod planet; | ||||
| mod player; | mod player; | ||||
| mod position; | mod position; | ||||
| mod shape; | |||||
| mod ship; | mod ship; | ||||
| mod velocity; | mod velocity; | ||||
| @@ -14,6 +15,7 @@ pub use meeting_point::{MeetingPoint, MeetingPointOwned}; | |||||
| pub use obstacle::Obstacle; | pub use obstacle::Obstacle; | ||||
| pub use planet::Planet; | pub use planet::Planet; | ||||
| pub use player::{Player, PlayerOwned}; | 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 ship::{Count as ShipCount, Obstacle as ShipObstacle, Ship, Type as ShipType}; | ||||
| pub use velocity::Velocity; | pub use velocity::Velocity; | ||||
| @@ -5,6 +5,8 @@ use specs::{Component, NullStorage}; | |||||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | ||||
| pub struct Obstacle {} | pub struct Obstacle {} | ||||
| /* Obstacle */ | |||||
| impl Component for Obstacle { | impl Component for Obstacle { | ||||
| type Storage = NullStorage<Self>; | type Storage = NullStorage<Self>; | ||||
| } | } | ||||
| @@ -1,11 +1,19 @@ | |||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||
| use specs::{Component, NullStorage}; | use specs::{Component, NullStorage}; | ||||
| use crate::misc::FlaggedStorage; | |||||
| use crate::{builder::PlanetBuilder, misc::FlaggedStorage}; | |||||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | ||||
| pub struct Planet {} | pub struct Planet {} | ||||
| /* Planet */ | |||||
| impl Planet { | |||||
| pub fn builder() -> PlanetBuilder { | |||||
| PlanetBuilder::default() | |||||
| } | |||||
| } | |||||
| impl Component for Planet { | impl Component for Planet { | ||||
| type Storage = FlaggedStorage<Self, NullStorage<Self>>; | type Storage = FlaggedStorage<Self, NullStorage<Self>>; | ||||
| } | } | ||||
| @@ -6,6 +6,8 @@ use specs::{ | |||||
| Component, Entity, HashMapStorage, | Component, Entity, HashMapStorage, | ||||
| }; | }; | ||||
| use crate::builder::PlayerBuilder; | |||||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | ||||
| pub struct Player { | pub struct Player { | ||||
| index: usize, | index: usize, | ||||
| @@ -22,13 +24,12 @@ pub struct PlayerOwnedData<M> { | |||||
| pub owner: M, | pub owner: M, | ||||
| } | } | ||||
| /* Player */ | |||||
| impl Player { | impl Player { | ||||
| #[inline] | #[inline] | ||||
| pub fn new(color: Vector3f) -> Self { | |||||
| Self { | |||||
| index: next_index(), | |||||
| color, | |||||
| } | |||||
| pub fn builder() -> PlayerBuilder { | |||||
| PlayerBuilder::default() | |||||
| } | } | ||||
| #[inline] | #[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 { | impl Component for Player { | ||||
| type Storage = HashMapStorage<Self>; | type Storage = HashMapStorage<Self>; | ||||
| } | } | ||||
| impl PlayerOwned { | |||||
| pub fn new(owner: Entity) -> Self { | |||||
| Self { owner } | |||||
| } | |||||
| /* PlayerOwned */ | |||||
| impl PlayerOwned { | |||||
| pub fn owner(&self) -> Entity { | pub fn owner(&self) -> Entity { | ||||
| self.owner | self.owner | ||||
| } | } | ||||
| } | } | ||||
| impl PlayerOwned { | |||||
| pub(crate) fn new(owner: Entity) -> Self { | |||||
| Self { owner } | |||||
| } | |||||
| } | |||||
| impl Component for PlayerOwned { | impl Component for PlayerOwned { | ||||
| type Storage = HashMapStorage<Self>; | type Storage = HashMapStorage<Self>; | ||||
| } | } | ||||
| @@ -5,39 +5,22 @@ use specs::{Component, VecStorage}; | |||||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | ||||
| pub struct Position { | pub struct Position { | ||||
| pos: Vector2f, | pos: Vector2f, | ||||
| shape: Shape, | |||||
| } | } | ||||
| #[derive(Clone, Debug, Serialize, Deserialize)] | |||||
| pub enum Shape { | |||||
| Dot, | |||||
| Circle(f32), | |||||
| } | |||||
| /* Position */ | |||||
| impl 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 | &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 | &mut self.pos | ||||
| } | } | ||||
| } | } | ||||
| @@ -45,26 +28,3 @@ impl Position { | |||||
| impl Component for Position { | impl Component for Position { | ||||
| type Storage = VecStorage<Self>; | type Storage = VecStorage<Self>; | ||||
| } | } | ||||
| impl Shape { | |||||
| pub fn radius(&self) -> f32 { | |||||
| match self { | |||||
| Self::Dot => 0.0, | |||||
| Self::Circle(r) => *r, | |||||
| } | |||||
| } | |||||
| pub fn circle(&self) -> Option<f32> { | |||||
| if let Self::Circle(r) = &self { | |||||
| Some(*r) | |||||
| } else { | |||||
| None | |||||
| } | |||||
| } | |||||
| } | |||||
| impl Default for Shape { | |||||
| fn default() -> Self { | |||||
| Self::Dot | |||||
| } | |||||
| } | |||||
| @@ -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<Self>; | |||||
| } | |||||
| impl Shape { | |||||
| pub fn radius(&self) -> f32 { | |||||
| match self { | |||||
| Self::Circle(r) => *r, | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -5,7 +5,7 @@ use glc::vector::Vector2f; | |||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||
| use specs::{Component, Entity, VecStorage}; | use specs::{Component, Entity, VecStorage}; | ||||
| use crate::misc::FlaggedStorage; | |||||
| use crate::{builder::ShipBuilder, misc::FlaggedStorage}; | |||||
| #[derive(Clone, Debug, Serialize, Deserialize)] | #[derive(Clone, Debug, Serialize, Deserialize)] | ||||
| pub struct Ship { | pub struct Ship { | ||||
| @@ -42,15 +42,12 @@ pub enum Type { | |||||
| Transporter, | Transporter, | ||||
| } | } | ||||
| /* Ship */ | |||||
| impl Ship { | impl Ship { | ||||
| #[inline] | #[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] | #[inline] | ||||
| @@ -69,14 +66,26 @@ impl Ship { | |||||
| } | } | ||||
| #[inline] | #[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] | #[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] | #[inline] | ||||
| @@ -89,12 +98,16 @@ impl Component for Ship { | |||||
| type Storage = FlaggedStorage<Self, VecStorage<Self>>; | type Storage = FlaggedStorage<Self, VecStorage<Self>>; | ||||
| } | } | ||||
| /* Obstacle */ | |||||
| impl Default for Obstacle { | impl Default for Obstacle { | ||||
| fn default() -> Self { | fn default() -> Self { | ||||
| Self::Search | Self::Search | ||||
| } | } | ||||
| } | } | ||||
| /* Count */ | |||||
| impl Count { | impl Count { | ||||
| pub fn all() -> Self { | pub fn all() -> Self { | ||||
| Self { | Self { | ||||
| @@ -8,24 +8,28 @@ pub struct Velocity { | |||||
| speed: f32, | speed: f32, | ||||
| } | } | ||||
| impl Velocity { | |||||
| pub fn new(dir: Vector2f, speed: f32) -> Self { | |||||
| Self { dir, speed } | |||||
| } | |||||
| /* Velocity */ | |||||
| impl Velocity { | |||||
| pub fn dir(&self) -> &Vector2f { | pub fn dir(&self) -> &Vector2f { | ||||
| &self.dir | &self.dir | ||||
| } | } | ||||
| pub fn dir_mut(&mut self) -> &mut Vector2f { | |||||
| &mut self.dir | |||||
| } | |||||
| pub fn speed(&self) -> f32 { | pub fn speed(&self) -> f32 { | ||||
| self.speed | 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 { | impl Component for Velocity { | ||||
| type Storage = VecStorage<Self>; | type Storage = VecStorage<Self>; | ||||
| } | } | ||||
| @@ -3,7 +3,7 @@ use specs::{Dispatcher as Inner, DispatcherBuilder, World, WorldExt}; | |||||
| use crate::{ | use crate::{ | ||||
| components::Player, | components::Player, | ||||
| resources::Global, | resources::Global, | ||||
| systems::{FleetControl, FleetOwnedUpdate, MeetingPointOwnedUpdate, Movement, Process, Ships}, | |||||
| systems::{FleetControl, FleetOwnedUpdate, Movement, Process, Ships}, | |||||
| Error, | Error, | ||||
| }; | }; | ||||
| @@ -23,11 +23,6 @@ impl<'a, 'b> Dispatcher<'a, 'b> { | |||||
| .with(Ships::new(world), "ships", &[]) | .with(Ships::new(world), "ships", &[]) | ||||
| .with(FleetControl::new(world)?, "fleet_control", &[]) | .with(FleetControl::new(world)?, "fleet_control", &[]) | ||||
| .with(FleetOwnedUpdate::new(world), "fleet_owned_update", &[]) | .with(FleetOwnedUpdate::new(world), "fleet_owned_update", &[]) | ||||
| .with( | |||||
| MeetingPointOwnedUpdate::new(world), | |||||
| "meeting_point_owned_update", | |||||
| &[], | |||||
| ) | |||||
| .build(); | .build(); | ||||
| dispatcher.setup(world); | dispatcher.setup(world); | ||||
| @@ -1,3 +1,4 @@ | |||||
| pub mod builder; | |||||
| pub mod components; | pub mod components; | ||||
| pub mod constants; | pub mod constants; | ||||
| pub mod dispatcher; | pub mod dispatcher; | ||||
| @@ -11,5 +11,5 @@ pub use flagged_storage::{ | |||||
| ComponentEvent, FlaggedStorage, StorageHelper, StorageHelperMut, Tracked, | ComponentEvent, FlaggedStorage, StorageHelper, StorageHelperMut, Tracked, | ||||
| }; | }; | ||||
| pub use log_result::LogResult; | pub use log_result::LogResult; | ||||
| pub use persistence::{PersistWorld, Persistence}; | |||||
| pub use world::WorldHelper; | |||||
| pub use persistence::Persistence; | |||||
| pub use world::{WorldHelper, WorldPersistence}; | |||||
| @@ -1,37 +1,10 @@ | |||||
| use serde::{de::Deserializer, ser::Serializer}; | use serde::{de::Deserializer, ser::Serializer}; | ||||
| use specs::{ | use specs::{ | ||||
| error::NoError, | error::NoError, | ||||
| saveload::{ConvertSaveload, DeserializeComponents, Marker, SerializeComponents, SimpleMarker}, | |||||
| saveload::{ConvertSaveload, DeserializeComponents, Marker, SerializeComponents}, | |||||
| Component, Entities, ReadStorage, World, WorldExt, Write, WriteStorage, | 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<PersistWorldMarker>; | |||||
| type Components = ( | |||||
| Position, | |||||
| Velocity, | |||||
| Player, | |||||
| PlayerOwned, | |||||
| MeetingPoint, | |||||
| MeetingPointOwned, | |||||
| FleetOwned, | |||||
| Ship, | |||||
| Obstacle, | |||||
| Planet, | |||||
| Asteroid, | |||||
| ); | |||||
| } | |||||
| /* Persistence */ | /* Persistence */ | ||||
| pub trait Persistence { | pub trait Persistence { | ||||
| @@ -45,6 +18,8 @@ pub trait Persistence { | |||||
| { | { | ||||
| world.register::<Self::Marker>(); | world.register::<Self::Marker>(); | ||||
| world.insert(<Self::Marker as Marker>::Allocator::default()); | world.insert(<Self::Marker as Marker>::Allocator::default()); | ||||
| Self::Components::setup(world); | |||||
| } | } | ||||
| fn serialize<S>(&self, world: &World, serializer: S) -> Result<(), S::Error> | fn serialize<S>(&self, world: &World, serializer: S) -> Result<(), S::Error> | ||||
| @@ -68,6 +43,8 @@ pub trait PersistenceComponents<M> | |||||
| where | where | ||||
| M: Marker, | M: Marker, | ||||
| { | { | ||||
| fn setup(world: &mut World); | |||||
| fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | ||||
| where | where | ||||
| S: Serializer; | S: Serializer; | ||||
| @@ -85,7 +62,12 @@ macro_rules! define_persistence_components { | |||||
| M: Marker, | M: Marker, | ||||
| M::Allocator: Default, | M::Allocator: Default, | ||||
| $($T: Component + ConvertSaveload<M, Error = NoError>,)+ | $($T: Component + ConvertSaveload<M, Error = NoError>,)+ | ||||
| $($T::Storage: Default,)+ | |||||
| { | { | ||||
| fn setup(world: &mut World) { | |||||
| $( world.register::<$T>(); )* | |||||
| } | |||||
| fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | ||||
| where | where | ||||
| S: Serializer, | S: Serializer, | ||||
| @@ -3,9 +3,15 @@ use std::any::type_name; | |||||
| use serde::{de::Deserializer, ser::Serializer}; | use serde::{de::Deserializer, ser::Serializer}; | ||||
| use shred::{Fetch, FetchMut, Resource}; | use shred::{Fetch, FetchMut, Resource}; | ||||
| use shrev::{Event, EventChannel, ReaderId}; | 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; | use super::Persistence; | ||||
| @@ -75,3 +81,24 @@ impl WorldHelper for World { | |||||
| persistence.deserialize(self, deserializer) | persistence.deserialize(self, deserializer) | ||||
| } | } | ||||
| } | } | ||||
| /* WorldPersistence */ | |||||
| pub struct WorldPersistence; | |||||
| pub struct PersistWorldMarker; | |||||
| impl Persistence for WorldPersistence { | |||||
| type Marker = SimpleMarker<PersistWorldMarker>; | |||||
| type Components = ( | |||||
| Position, | |||||
| Velocity, | |||||
| Player, | |||||
| PlayerOwned, | |||||
| MeetingPoint, | |||||
| MeetingPointOwned, | |||||
| Ship, | |||||
| Obstacle, | |||||
| Planet, | |||||
| Asteroid, | |||||
| ); | |||||
| } | |||||
| @@ -1,16 +1,19 @@ | |||||
| // TODO | |||||
| #![allow(dead_code)] | |||||
| #![allow(unused_mut)] | |||||
| #![allow(unused_imports)] | |||||
| #![allow(unused_variables)] | |||||
| use shrev::{EventChannel, ReaderId}; | use shrev::{EventChannel, ReaderId}; | ||||
| use specs::{ | use specs::{ | ||||
| prelude::*, saveload::MarkedBuilder, Entities, Entity, LazyUpdate, ReadExpect, ReadStorage, | |||||
| System, World, WriteStorage, | |||||
| prelude::*, Entities, Entity, LazyUpdate, ReadExpect, ReadStorage, System, World, WriteStorage, | |||||
| }; | }; | ||||
| use crate::{ | use crate::{ | ||||
| components::{ | components::{ | ||||
| Fleet, FleetOwned, MeetingPoint, MeetingPointOwned, Player, PlayerOwned, Ship, ShipCount, | Fleet, FleetOwned, MeetingPoint, MeetingPointOwned, Player, PlayerOwned, Ship, ShipCount, | ||||
| ShipType, | |||||
| }, | }, | ||||
| continue_if_none, | |||||
| misc::{LogResult, PersistWorld, Persistence, WorldHelper}, | |||||
| misc::WorldHelper, | |||||
| Error, | Error, | ||||
| }; | }; | ||||
| @@ -20,15 +23,12 @@ pub struct FleetControl { | |||||
| #[derive(Debug)] | #[derive(Debug)] | ||||
| pub enum FleetControlEvent { | 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)] | #[derive(SystemData)] | ||||
| @@ -74,6 +74,7 @@ impl<'a> System<'a> for FleetControl { | |||||
| ships, | ships, | ||||
| } = data; | } = data; | ||||
| /* TODO | |||||
| let events = fleet_control_events.read(&mut self.fleet_control_event_id); | let events = fleet_control_events.read(&mut self.fleet_control_event_id); | ||||
| for event in events { | for event in events { | ||||
| match event { | match event { | ||||
| @@ -91,7 +92,7 @@ impl<'a> System<'a> for FleetControl { | |||||
| f @ None => { | f @ None => { | ||||
| let fleet = lazy | let fleet = lazy | ||||
| .create_entity(&entities) | .create_entity(&entities) | ||||
| .marked::<<PersistWorld as Persistence>::Marker>() | |||||
| .marked::<<WorldPersistence as Persistence>::Marker>() | |||||
| .build(); | .build(); | ||||
| player_owned | 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, | |||||
| }) | |||||
| */ | |||||
| } | } | ||||
| } | } | ||||
| @@ -102,17 +102,9 @@ impl<'a> System<'a> for FleetOwnedUpdate { | |||||
| }; | }; | ||||
| if old_match && !new_match { | 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 { | } 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); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -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<Index, Entity>, | |||||
| meeting_point_owned_event_id: ReaderId<crate::misc::ComponentEvent<MeetingPointOwned>>, | |||||
| } | |||||
| impl MeetingPointOwnedUpdate { | |||||
| pub fn new(world: &mut World) -> Self { | |||||
| WriteStorage::<MeetingPointOwned>::setup(world); | |||||
| let meeting_point_ids = BitSet::new(); | |||||
| let meeting_point_owned_ids = BitSet::new(); | |||||
| let old_meeting_point_ids = HashMap::new(); | |||||
| let meeting_point_owned_event_id = world | |||||
| .system_data::<WriteStorage<MeetingPointOwned>>() | |||||
| .register_event_reader(); | |||||
| Self { | |||||
| meeting_point_ids, | |||||
| meeting_point_owned_ids, | |||||
| old_meeting_point_ids, | |||||
| meeting_point_owned_event_id, | |||||
| } | |||||
| } | |||||
| } | |||||
| #[derive(SystemData)] | |||||
| pub struct MeetingPointOwnedUpdateData<'a> { | |||||
| entities: Entities<'a>, | |||||
| meeting_points: WriteStorage<'a, MeetingPoint>, | |||||
| player_owned: ReadStorage<'a, PlayerOwned>, | |||||
| meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, | |||||
| } | |||||
| impl<'a> System<'a> for MeetingPointOwnedUpdate { | |||||
| type SystemData = MeetingPointOwnedUpdateData<'a>; | |||||
| fn run(&mut self, data: Self::SystemData) { | |||||
| let MeetingPointOwnedUpdateData { | |||||
| entities, | |||||
| mut meeting_points, | |||||
| player_owned, | |||||
| meeting_point_owned, | |||||
| } = data; | |||||
| self.meeting_point_ids.clear(); | |||||
| self.meeting_point_owned_ids.clear(); | |||||
| self.old_meeting_point_ids.clear(); | |||||
| /* handle events */ | |||||
| let events = meeting_point_owned | |||||
| .channel() | |||||
| .read(&mut self.meeting_point_owned_event_id); | |||||
| for event in events { | |||||
| match event { | |||||
| ComponentEvent::Inserted(id, meeting_point_owned) => { | |||||
| self.meeting_point_ids.add(meeting_point_owned.owner().id()); | |||||
| self.meeting_point_owned_ids.add(*id); | |||||
| } | |||||
| ComponentEvent::Modified(id, meeting_point_owned) => { | |||||
| self.meeting_point_ids.add(meeting_point_owned.owner().id()); | |||||
| self.meeting_point_owned_ids.add(*id); | |||||
| *self | |||||
| .old_meeting_point_ids | |||||
| .entry(*id) | |||||
| .or_insert_with(|| meeting_point_owned.owner()) = | |||||
| meeting_point_owned.owner(); | |||||
| } | |||||
| ComponentEvent::Removed(id, meeting_point_owned) => { | |||||
| self.meeting_point_ids.add(meeting_point_owned.owner().id()); | |||||
| self.meeting_point_owned_ids.add(*id); | |||||
| *self | |||||
| .old_meeting_point_ids | |||||
| .entry(*id) | |||||
| .or_insert_with(|| meeting_point_owned.owner()) = | |||||
| meeting_point_owned.owner(); | |||||
| } | |||||
| } | |||||
| } | |||||
| /* find new meeting_point ids */ | |||||
| for (meeting_point_owned, _) in (&meeting_point_owned, &self.meeting_point_owned_ids).join() | |||||
| { | |||||
| self.meeting_point_ids.add(meeting_point_owned.owner().id()); | |||||
| } | |||||
| /* update meeting_points */ | |||||
| for (meeting_point_id, meeting_point, _) in | |||||
| (&entities, &mut meeting_points, &self.meeting_point_ids).join() | |||||
| { | |||||
| let data = ( | |||||
| &entities, | |||||
| &meeting_point_owned, | |||||
| &player_owned, | |||||
| &self.meeting_point_owned_ids, | |||||
| ); | |||||
| for (fleet_id, meeting_point_owned, player_owned, _) in data.join() { | |||||
| let new_match = meeting_point_id == meeting_point_owned.owner(); | |||||
| let old_match = match self.old_meeting_point_ids.get(&fleet_id.id()) { | |||||
| Some(old_meeting_point_id) => meeting_point_id == *old_meeting_point_id, | |||||
| None => false, | |||||
| }; | |||||
| let player_id = player_owned.owner().id() as usize; | |||||
| if old_match && !new_match { | |||||
| if let Some(fleet) = meeting_point.fleets_mut().get_mut(player_id) { | |||||
| *fleet = None; | |||||
| } | |||||
| } else if !old_match && new_match { | |||||
| *meeting_point.fleet_mut(player_id) = Some(fleet_id); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,13 +1,11 @@ | |||||
| mod fleet_control; | mod fleet_control; | ||||
| mod fleet_owned_update; | mod fleet_owned_update; | ||||
| mod meeting_point_owned_update; | |||||
| mod movement; | mod movement; | ||||
| mod process; | mod process; | ||||
| mod ships; | mod ships; | ||||
| pub use fleet_control::{FleetControl, FleetControlEvent}; | pub use fleet_control::{FleetControl, FleetControlEvent}; | ||||
| pub use fleet_owned_update::FleetOwnedUpdate; | pub use fleet_owned_update::FleetOwnedUpdate; | ||||
| pub use meeting_point_owned_update::MeetingPointOwnedUpdate; | |||||
| pub use movement::Movement; | pub use movement::Movement; | ||||
| pub use process::Process; | pub use process::Process; | ||||
| pub use ships::Ships; | pub use ships::Ships; | ||||
| @@ -31,8 +31,9 @@ impl<'a> System<'a> for Movement { | |||||
| .par_join() | .par_join() | ||||
| .for_each(|(position, velocity)| { | .for_each(|(position, velocity)| { | ||||
| let delta = global.delta * global.world_speed; | 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; | |||||
| }); | }); | ||||
| } | } | ||||
| } | } | ||||
| @@ -12,7 +12,7 @@ use specs::{ | |||||
| use crate::{ | use crate::{ | ||||
| components::{ | components::{ | ||||
| FleetOwned, MeetingPoint, MeetingPointOwned, Obstacle, Position, Ship, ShipObstacle, | |||||
| FleetOwned, MeetingPoint, MeetingPointOwned, Obstacle, Position, Shape, Ship, ShipObstacle, | |||||
| Velocity, | Velocity, | ||||
| }, | }, | ||||
| constants::{ | constants::{ | ||||
| @@ -38,6 +38,7 @@ pub struct ShipsData<'a> { | |||||
| fleet_owned: ReadStorage<'a, FleetOwned>, | fleet_owned: ReadStorage<'a, FleetOwned>, | ||||
| meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, | meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, | ||||
| positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
| shapes: ReadStorage<'a, Shape>, | |||||
| obstacles: ReadStorage<'a, Obstacle>, | obstacles: ReadStorage<'a, Obstacle>, | ||||
| meeting_points: ReadStorage<'a, MeetingPoint>, | meeting_points: ReadStorage<'a, MeetingPoint>, | ||||
| } | } | ||||
| @@ -46,6 +47,7 @@ struct Processor<'a> { | |||||
| need_update: &'a BitSet, | need_update: &'a BitSet, | ||||
| entities: &'a Entities<'a>, | entities: &'a Entities<'a>, | ||||
| positions: &'a ReadStorage<'a, Position>, | positions: &'a ReadStorage<'a, Position>, | ||||
| shapes: &'a ReadStorage<'a, Shape>, | |||||
| obstacles: &'a ReadStorage<'a, Obstacle>, | obstacles: &'a ReadStorage<'a, Obstacle>, | ||||
| meeting_points: &'a ReadStorage<'a, MeetingPoint>, | meeting_points: &'a ReadStorage<'a, MeetingPoint>, | ||||
| meeting_point_owned: &'a ReadStorage<'a, MeetingPointOwned>, | meeting_point_owned: &'a ReadStorage<'a, MeetingPointOwned>, | ||||
| @@ -94,6 +96,7 @@ impl<'a> System<'a> for Ships { | |||||
| fleet_owned, | fleet_owned, | ||||
| meeting_point_owned, | meeting_point_owned, | ||||
| positions, | positions, | ||||
| shapes, | |||||
| obstacles, | obstacles, | ||||
| meeting_points, | meeting_points, | ||||
| } = data; | } = data; | ||||
| @@ -105,6 +108,7 @@ impl<'a> System<'a> for Ships { | |||||
| need_update: &self.need_update, | need_update: &self.need_update, | ||||
| entities: &entities, | entities: &entities, | ||||
| positions: &positions, | positions: &positions, | ||||
| shapes: &shapes, | |||||
| obstacles: &obstacles, | obstacles: &obstacles, | ||||
| meeting_point_owned: &meeting_point_owned, | meeting_point_owned: &meeting_point_owned, | ||||
| meeting_points: &meeting_points, | 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_owned = return_if_none!(self.meeting_point_owned.get(fleet_id)); | ||||
| let meeting_point_id = meeting_point_owned.owner(); | let meeting_point_id = meeting_point_owned.owner(); | ||||
| let meeting_point = return_if_none!(self.meeting_points.get(meeting_point_id)); | 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_pos = ship.target_pos(); | ||||
| let target_dir = ship.target_dir(); | let target_dir = ship.target_dir(); | ||||
| @@ -213,7 +217,7 @@ impl Processor<'_> { | |||||
| } else if let ShipObstacle::Known(obstacle) = ship.obstacle() { | } else if let ShipObstacle::Known(obstacle) = ship.obstacle() { | ||||
| if let Some(position) = self.positions.get(obstacle) { | if let Some(position) = self.positions.get(obstacle) { | ||||
| let obstacle_meeting_point = self.meeting_points.get(obstacle).unwrap(); | 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 ship_to_obstacle = obstacle_pos - ship_pos; | ||||
| let obstacle_angle = ship_to_target | let obstacle_angle = ship_to_target | ||||
| @@ -237,7 +241,7 @@ impl Processor<'_> { | |||||
| if !ship_in_meeting_point && ship.obstacle() == ShipObstacle::Search { | if !ship_in_meeting_point && ship.obstacle() == ShipObstacle::Search { | ||||
| let mut dist_sqr = f32::MAX; | let mut dist_sqr = f32::MAX; | ||||
| for (e, position, _) in (self.entities, self.positions, self.obstacles).join() { | for (e, position, _) in (self.entities, self.positions, self.obstacles).join() { | ||||
| let obstacle_pos = position.pos(); | |||||
| let obstacle_pos = position.get(); | |||||
| let ship_to_obstacle = obstacle_pos - ship_pos; | let ship_to_obstacle = obstacle_pos - ship_pos; | ||||
| if ship_to_target * ship_to_obstacle < 0.0 { | if ship_to_target * ship_to_obstacle < 0.0 { | ||||
| @@ -262,8 +266,9 @@ impl Processor<'_> { | |||||
| let mut expected_dir = ship_to_target; | let mut expected_dir = ship_to_target; | ||||
| if let ShipObstacle::Known(obstacle) = ship.obstacle() { | if let ShipObstacle::Known(obstacle) = ship.obstacle() { | ||||
| let obstacle_pos = self.positions.get(obstacle).unwrap(); | let obstacle_pos = self.positions.get(obstacle).unwrap(); | ||||
| let obstacle_shape = self.shapes.get(obstacle).unwrap(); | |||||
| let obstacle_meeting_point = self.meeting_points.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_min = obstacle_meeting_point.min(); | ||||
| let meeting_point_max = obstacle_meeting_point.max(); | let meeting_point_max = obstacle_meeting_point.max(); | ||||
| @@ -272,7 +277,7 @@ impl Processor<'_> { | |||||
| if meeting_point < meeting_point_max { | if meeting_point < meeting_point_max { | ||||
| let mut tangent = Vector2f::new(-ship_to_obstacle.y, ship_to_obstacle.x); | let mut tangent = Vector2f::new(-ship_to_obstacle.y, ship_to_obstacle.x); | ||||
| let radius = obstacle_pos.shape().radius(); | |||||
| let radius = obstacle_shape.radius(); | |||||
| let mut adjust_low = linear_step(meeting_point_min, radius, meeting_point); | let mut adjust_low = linear_step(meeting_point_min, radius, meeting_point); | ||||
| let adjust_high = | let adjust_high = | ||||
| 1.0 - linear_step(meeting_point_max, meeting_point_min, meeting_point); | 1.0 - linear_step(meeting_point_max, meeting_point_min, meeting_point); | ||||