Переглянути джерело

Use builder to create the different world objects

Using builders ensure that the correct components are added to a new created entity.
master
Bergmann89 4 роки тому
джерело
коміт
7ec1321114
38 змінених файлів з 691 додано та 434 видалено
  1. +1
    -1
      space-crush-app/src/debug/fleets.rs
  2. +3
    -3
      space-crush-app/src/debug/meeting_points.rs
  3. +3
    -2
      space-crush-app/src/debug/ships.rs
  4. +10
    -1
      space-crush-app/src/error.rs
  5. +30
    -56
      space-crush-app/src/main.rs
  6. +16
    -17
      space-crush-app/src/render/asteroids.rs
  7. +7
    -2
      space-crush-app/src/render/fleet_move.rs
  8. +19
    -12
      space-crush-app/src/render/fleet_select.rs
  9. +8
    -9
      space-crush-app/src/render/planets.rs
  10. +2
    -2
      space-crush-app/src/render/ships.rs
  11. +82
    -0
      space-crush-common/src/builder/asteroid.rs
  12. +37
    -0
      space-crush-common/src/builder/fleet.rs
  13. +29
    -0
      space-crush-common/src/builder/mod.rs
  14. +74
    -0
      space-crush-common/src/builder/planet.rs
  15. +37
    -0
      space-crush-common/src/builder/player.rs
  16. +90
    -0
      space-crush-common/src/builder/ship.rs
  17. +12
    -3
      space-crush-common/src/components/asteroid.rs
  18. +35
    -9
      space-crush-common/src/components/fleet.rs
  19. +16
    -24
      space-crush-common/src/components/meeting_point.rs
  20. +3
    -1
      space-crush-common/src/components/mod.rs
  21. +2
    -0
      space-crush-common/src/components/obstacle.rs
  22. +9
    -1
      space-crush-common/src/components/planet.rs
  23. +24
    -9
      space-crush-common/src/components/player.rs
  24. +7
    -47
      space-crush-common/src/components/position.rs
  25. +21
    -0
      space-crush-common/src/components/shape.rs
  26. +26
    -13
      space-crush-common/src/components/ship.rs
  27. +12
    -8
      space-crush-common/src/components/velocity.rs
  28. +1
    -6
      space-crush-common/src/dispatcher.rs
  29. +1
    -0
      space-crush-common/src/lib.rs
  30. +2
    -2
      space-crush-common/src/misc/mod.rs
  31. +10
    -28
      space-crush-common/src/misc/persistence.rs
  32. +29
    -2
      space-crush-common/src/misc/world.rs
  33. +17
    -26
      space-crush-common/src/systems/fleet_control.rs
  34. +2
    -10
      space-crush-common/src/systems/fleet_owned_update.rs
  35. +0
    -130
      space-crush-common/src/systems/meeting_point_owned_update.rs
  36. +0
    -2
      space-crush-common/src/systems/mod.rs
  37. +2
    -1
      space-crush-common/src/systems/movement.rs
  38. +12
    -7
      space-crush-common/src/systems/ships.rs

+ 1
- 1
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);


+ 3
- 3
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(),
),
);


+ 3
- 2
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),


+ 10
- 1
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<CommonError> for Error {
Self::CommonError(err)
}
}

impl From<BuilderError> for Error {
fn from(err: BuilderError) -> Self {
Self::BuilderError(err)
}
}

+ 30
- 56
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::<<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<_>>();

@@ -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::<<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::Crystal,
_ => 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 {
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 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,
1 => ShipType::Bomber,
2 => ShipType::Transporter,
_ => unreachable!(),
}))
.build();
})
.build(world)
.unwrap();
}
}

+ 16
- 17
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<Self, Error> {
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 {
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::<VertexData>(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,


+ 7
- 2
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);
}


+ 19
- 12
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));
}
}



+ 8
- 9
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::<VertexData>(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,


+ 2
- 2
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::<TailData>(true)


+ 82
- 0
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<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
}
}

+ 37
- 0
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<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
}
}

+ 29
- 0
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<SpecsError> for Error {
fn from(err: SpecsError) -> Self {
Self::SpecsError(err)
}
}

+ 74
- 0
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<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
}
}

+ 37
- 0
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<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
}
}

+ 90
- 0
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<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(),
}
}
}

+ 12
- 3
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<Self, HashMapStorage<Self>>;
}

+ 35
- 9
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<M> {
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<Self>;
}

/* FleetOwned */

impl FleetOwned {
pub fn new(owner: Entity) -> Self {
Self { owner }


+ 16
- 24
space-crush-common/src/components/meeting_point.rs Переглянути файл

@@ -37,16 +37,9 @@ pub struct MeetingPointOwnedData<M> {

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]
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<Entity> {
self.fleets.get(index).cloned().flatten()
}
}

impl MeetingPoint {
#[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 {
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 }
}
}



+ 3
- 1
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;

+ 2
- 0
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<Self>;
}

+ 9
- 1
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<Self, NullStorage<Self>>;
}

+ 24
- 9
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<M> {
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<Self>;
}

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


+ 7
- 47
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<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
}
}

+ 21
- 0
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<Self>;
}

impl Shape {
pub fn radius(&self) -> f32 {
match self {
Self::Circle(r) => *r,
}
}
}

+ 26
- 13
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<Self, VecStorage<Self>>;
}

/* Obstacle */

impl Default for Obstacle {
fn default() -> Self {
Self::Search
}
}

/* Count */

impl Count {
pub fn all() -> Self {
Self {


+ 12
- 8
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<Self>;
}

+ 1
- 6
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);



+ 1
- 0
space-crush-common/src/lib.rs Переглянути файл

@@ -1,3 +1,4 @@
pub mod builder;
pub mod components;
pub mod constants;
pub mod dispatcher;


+ 2
- 2
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};

+ 10
- 28
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<PersistWorldMarker>;
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::<Self::Marker>();
world.insert(<Self::Marker as Marker>::Allocator::default());

Self::Components::setup(world);
}

fn serialize<S>(&self, world: &World, serializer: S) -> Result<(), S::Error>
@@ -68,6 +43,8 @@ pub trait PersistenceComponents<M>
where
M: Marker,
{
fn setup(world: &mut World);

fn serialize<S>(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<M, Error = NoError>,)+
$($T::Storage: Default,)+
{
fn setup(world: &mut World) {
$( world.register::<$T>(); )*
}

fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error>
where
S: Serializer,


+ 29
- 2
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<PersistWorldMarker>;
type Components = (
Position,
Velocity,
Player,
PlayerOwned,
MeetingPoint,
MeetingPointOwned,
Ship,
Obstacle,
Planet,
Asteroid,
);
}

+ 17
- 26
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::<<PersistWorld as Persistence>::Marker>()
.marked::<<WorldPersistence as Persistence>::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,
})
*/
}
}

+ 2
- 10
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);
}
}
}


+ 0
- 130
space-crush-common/src/systems/meeting_point_owned_update.rs Переглянути файл

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

+ 0
- 2
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;

+ 2
- 1
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;
});
}
}

+ 12
- 7
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);


Завантаження…
Відмінити
Зберегти