Browse Source

Merged 'Fleet' and 'FleetInfo' and added 'Orbit' component

Hint: The 'FleetControl' system is broken now, but will be refactored in the future anyway.
master
Bergmann89 3 years ago
parent
commit
8d7e4dc021
24 changed files with 513 additions and 301 deletions
  1. +1
    -0
      Cargo.lock
  2. +0
    -1
      ToDo
  3. +0
    -12
      space-crush-app/src/components/fleet_info.rs
  4. +0
    -3
      space-crush-app/src/components/mod.rs
  5. +22
    -13
      space-crush-app/src/debug/fleets.rs
  6. +1
    -3
      space-crush-app/src/lib.rs
  7. +22
    -13
      space-crush-app/src/main.rs
  8. +46
    -25
      space-crush-app/src/render/fleet_select.rs
  9. +19
    -17
      space-crush-app/src/systems/fleet_control.rs
  10. +0
    -167
      space-crush-app/src/systems/fleet_info_update.rs
  11. +0
    -2
      space-crush-app/src/systems/mod.rs
  12. +1
    -0
      space-crush-common/Cargo.toml
  13. +5
    -4
      space-crush-common/src/components/fleet.rs
  14. +2
    -0
      space-crush-common/src/components/mod.rs
  15. +102
    -0
      space-crush-common/src/components/orbit.rs
  16. +3
    -4
      space-crush-common/src/components/player.rs
  17. +3
    -1
      space-crush-common/src/dispatcher.rs
  18. +11
    -10
      space-crush-common/src/misc/flagged_storage.rs
  19. +10
    -4
      space-crush-common/src/misc/persistence.rs
  20. +111
    -0
      space-crush-common/src/systems/fleet_owned_update.rs
  21. +4
    -0
      space-crush-common/src/systems/mod.rs
  22. +121
    -0
      space-crush-common/src/systems/orbit_owned_update.rs
  23. +4
    -0
      space-crush-common/src/systems/process.rs
  24. +25
    -22
      space-crush-common/src/systems/ships.rs

+ 1
- 0
Cargo.lock View File

@@ -1537,6 +1537,7 @@ dependencies = [
"serde_yaml",
"shred",
"shrev",
"smallvec",
"specs",
"thiserror",
"vfs",


+ 0
- 1
ToDo View File

@@ -1 +0,0 @@
- De-/Serialize World

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

@@ -1,12 +0,0 @@
use space_crush_common::components::ShipCount;
use specs::{hibitset::BitSet, Component, HashMapStorage};

#[derive(Default, Debug)]
pub struct FleetInfo {
pub owned: BitSet,
pub count: ShipCount,
}

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

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

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

pub use fleet_info::FleetInfo;

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

@@ -1,15 +1,16 @@
use glc::vector::{Angle, Vector2f, Vector4f};
use space_crush_common::{
components::{Fleet, Position},
components::{Fleet, Orbit, Player, Position},
constants::SHIP_ORBIT_DISTANCE_MAX,
continue_if_none,
misc::LogResult,
return_if_none,
};
use specs::{prelude::*, ReadStorage, System, World, WriteExpect};
use specs::{prelude::*, ReadExpect, ReadStorage, System, World, WriteExpect};

use crate::{
components::FleetInfo,
misc::{HorizontalAlign, Text, TextManager, VerticalAlign},
resources::{Camera, Geometry},
resources::{Camera, Geometry, PlayerState},
Error,
};

@@ -19,11 +20,13 @@ pub struct Fleets {

#[derive(SystemData)]
pub struct FleetData<'a> {
player_state: ReadExpect<'a, PlayerState>,
geometry: WriteExpect<'a, Geometry>,
camera: ReadExpect<'a, Camera>,
positions: ReadStorage<'a, Position>,
players: ReadStorage<'a, Player>,
orbits: ReadStorage<'a, Orbit>,
fleets: ReadStorage<'a, Fleet>,
fleet_infos: ReadStorage<'a, FleetInfo>,
}

impl Fleets {
@@ -48,29 +51,37 @@ impl<'a> System<'a> for Fleets {

fn run(&mut self, data: Self::SystemData) {
let FleetData {
player_state,
mut geometry,
camera,
positions,
players,
orbits,
fleets,
fleet_infos,
} = data;

let player = return_if_none!(players.get(player_state.player_id));

gl::enable(gl::BLEND);

for (position, fleet, fleet_info) in (&positions, &fleets, &fleet_infos).join() {
for (position, orbit) in (&positions, &orbits).join() {
let fleet_id = continue_if_none!(orbit.fleets.get(player.index));
let fleet_id = continue_if_none!(fleet_id);
let fleet = continue_if_none!(fleets.get(*fleet_id));

gl::blend_func(gl::SRC_ALPHA, gl::ONE);
gl::blend_equation(gl::FUNC_ADD);
geometry.render_lines(
Vector4f::new(0.5, 0.5, 0.5, 0.05),
&create_circle(position.pos, fleet.orbit_min),
&create_circle(position.pos, orbit.min),
);
geometry.render_lines(
Vector4f::new(0.5, 0.5, 0.5, 0.05),
&create_circle(position.pos, fleet.orbit_max),
&create_circle(position.pos, orbit.max),
);
geometry.render_lines(
Vector4f::new(0.5, 0.5, 0.5, 0.05),
&create_circle(position.pos, SHIP_ORBIT_DISTANCE_MAX * fleet.orbit_max),
&create_circle(position.pos, SHIP_ORBIT_DISTANCE_MAX * orbit.max),
);

gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
@@ -80,9 +91,7 @@ impl<'a> System<'a> for Fleets {
0,
format!(
"F:{}\nB:{}\nT:{}",
fleet_info.count.fighter,
fleet_info.count.bomber,
fleet_info.count.transporter
fleet.count.fighter, fleet.count.bomber, fleet.count.transporter
),
)
.panic("Unable to update text")


+ 1
- 3
space-crush-app/src/lib.rs View File

@@ -1,4 +1,3 @@
pub mod components;
pub mod constants;
pub mod debug;
pub mod error;
@@ -16,7 +15,7 @@ use debug::{Fleets as DebugFleets, Ships as DebugShips, Summary as DebugSummary}
use misc::{Events, TextManager, Window};
use render::{Asteroids, FleetSelect, Init, Planets, Ships};
use resources::{Camera, Config, Geometry, InputState, PlayerState, Uniform};
use systems::{FleetControl, FleetInfoUpdate, StateUpdate};
use systems::{FleetControl, StateUpdate};

pub struct App<'a, 'b> {
is_running: bool,
@@ -50,7 +49,6 @@ impl<'a, 'b> App<'a, 'b> {

let mut dispatcher = DispatcherBuilder::new()
.with(StateUpdate::new(world)?, "state_update", &[])
.with(FleetInfoUpdate::new(world), "fleet_info_update", &[])
.with(FleetControl::new(world)?, "fleet_control", &[])
.with_thread_local(Init::new(world)?)
.with_thread_local(Planets::new(world)?)


+ 22
- 13
space-crush-app/src/main.rs View File

@@ -57,11 +57,11 @@ fn create_world(world: &mut World, player_id: Entity) {
matrix::Angle,
vector::{Vector2f, Vector4f},
};
use space_crush_app::components::FleetInfo;
use smallvec::smallvec;
use space_crush_common::{
components::{
Asteroid, AsteroidType, Fleet, FleetOwned, Obstacle, Planet, Player, PlayerOwned,
Position, Shape, Ship, ShipType, Velocity,
Asteroid, AsteroidType, Fleet, FleetOwned, Obstacle, Orbit, OrbitOwned, Planet, Player,
PlayerOwned, Position, Shape, Ship, ShipType, Velocity,
},
misc::{PersistWorld, Persistence},
};
@@ -74,6 +74,7 @@ fn create_world(world: &mut World, player_id: Entity) {
.insert(
player_id,
Player {
index: 0,
color: Vector4f::new(0.0, 0.5, 1.0, 0.1),
},
)
@@ -92,11 +93,11 @@ fn create_world(world: &mut World, player_id: Entity) {
pos: Vector2f::new(x, y),
shape: Shape::Circle(250.0),
})
.with(Fleet {
orbit_min: 325.0,
orbit_max: 425.0,
.with(Orbit {
min: 325.0,
max: 425.0,
fleets: smallvec![],
})
.with(FleetInfo::default())
.with(Obstacle {})
.with(Planet {})
.build()
@@ -117,11 +118,11 @@ fn create_world(world: &mut World, player_id: Entity) {
pos: Vector2f::new(x, y),
shape: Shape::Circle(100.0),
})
.with(Fleet {
orbit_min: 125.0,
orbit_max: 175.0,
.with(Orbit {
min: 125.0,
max: 175.0,
fleets: smallvec![],
})
.with(FleetInfo::default())
.with(Obstacle {})
.with(Asteroid {
type_: match i_x * i_y {
@@ -133,7 +134,15 @@ fn create_world(world: &mut World, player_id: Entity) {
.build();
}

for i in 0..999 {
let fleet_id = world
.create_entity()
.marked::<<PersistWorld as Persistence>::Marker>()
.with(PlayerOwned { owner: player_id })
.with(OrbitOwned { owner: planets[1] })
.with(Fleet::default())
.build();

for i in 0..9 {
let r = 325.0 + 100.0 * random::<f32>();
let a = Angle::Deg(360.0 * random::<f32>());

@@ -144,6 +153,7 @@ fn create_world(world: &mut World, player_id: Entity) {
.create_entity()
.marked::<<PersistWorld as Persistence>::Marker>()
.with(PlayerOwned { owner: player_id })
.with(FleetOwned { owner: fleet_id })
.with(Position {
pos: Vector2f::new(x, y),
shape: Shape::Dot,
@@ -152,7 +162,6 @@ fn create_world(world: &mut World, player_id: Entity) {
dir: Vector2f::new(random::<f32>() - 0.5, random::<f32>() - 0.5).normalize(),
speed: 100.0,
})
.with(FleetOwned { owner: planets[1] })
.with(Ship {
type_: match i % 3 {
0 => ShipType::Fighter,


+ 46
- 25
space-crush-app/src/render/fleet_select.rs View File

@@ -10,16 +10,16 @@ use glc::{
};
use shrev::{EventChannel, ReaderId};
use space_crush_common::{
components::{Fleet, Position, ShipCount},
components::{Fleet, Orbit, OrbitOwned, Player, Position, ShipCount},
constants::VECTOR_2F_POS_X,
continue_if_none,
misc::{LogResult, WorldHelper as _},
resources::Global,
return_if_none,
};
use specs::{prelude::*, Entities, ReadExpect, ReadStorage, System, World};
use specs::{prelude::*, ReadExpect, ReadStorage, System, World};

use crate::{
components::FleetInfo,
constants::{
FLEET_SELECT_ANIMATION_TIME, FLEET_SELECT_DETAIL_TIMEOUT, FLEET_SELECT_OFFSET,
FLEET_SELECT_TEXT_OFFSET, FLEET_SELECT_TEXT_SIZE, FLEET_SELECT_WIDTH,
@@ -74,15 +74,16 @@ pub struct FleetSelectData<'a> {
player_state: WriteExpect<'a, PlayerState>,
camera: ReadExpect<'a, Camera>,

entities: Entities<'a>,
mouse_events: ReadExpect<'a, EventChannel<MouseEvent>>,
input_state: ReadExpect<'a, InputState>,
geometry: ReadExpect<'a, Geometry>,
global: ReadExpect<'a, Global>,
config: ReadExpect<'a, Config>,

fleet_infos: ReadStorage<'a, FleetInfo>,
orbit_owned: ReadStorage<'a, OrbitOwned>,
positions: ReadStorage<'a, Position>,
players: ReadStorage<'a, Player>,
orbits: ReadStorage<'a, Orbit>,
fleets: ReadStorage<'a, Fleet>,
}

@@ -95,9 +96,15 @@ macro_rules! selection {
};
}

macro_rules! fleet_info {
macro_rules! player {
(&$data:expr, $id:expr) => {
return_if_none!($data.fleet_infos.get($id))
return_if_none!($data.players.get($id))
};
}

macro_rules! fleet {
(&$data:expr, $id:expr) => {
return_if_none!($data.fleets.get($id))
};
}

@@ -107,6 +114,12 @@ macro_rules! position {
};
}

macro_rules! orbit_owned {
(&$data:expr, $id:expr) => {
return_if_none!($data.orbit_owned.get($id))
};
}

impl FleetSelect {
pub fn new(world: &World, text_manager: &TextManager) -> Result<Self, Error> {
let program_simple = world.load_program(vec![
@@ -180,11 +193,17 @@ impl FleetSelect {
MouseEvent::ButtonDown(button) if button == &d.config.input.fleet_select_button => {
let pos = d.camera.view_to_world(d.input_state.mouse_pos);
let selection = d.player_state.selection.take();
for (id, position, fleet) in (&d.entities, &d.positions, &d.fleets).join() {
let r = fleet.orbit_max * fleet.orbit_max;
for (position, orbit) in (&d.positions, &d.orbits).join() {
let r = orbit.max * orbit.max;
if (position.pos - pos).length_sqr() <= r {
let player_id = d.player_state.player_id;
let player = player!(&d, player_id);
let player_index = player.index;
let fleet_id = continue_if_none!(orbit.fleets.get(player_index));
let fleet_id = *continue_if_none!(fleet_id);

d.player_state.selection = match selection {
Some(s) if s.fleet == id => {
Some(s) if s.fleet == fleet_id => {
self.is_new_selection = false;

Some(s)
@@ -193,20 +212,20 @@ impl FleetSelect {
self.is_new_selection = true;

Some(Selection {
fleet: id,
fleet: fleet_id,
count: ShipCount::none(),
})
}
};

let selection = selection!(&d);
let fleet_info = fleet_info!(&d, selection.fleet);
let fleet = fleet!(&d, selection.fleet);
let timeout = Instant::now() + FLEET_SELECT_DETAIL_TIMEOUT;

self.mouse_pos = d.input_state.mouse_pos;
self.select_mode = SelectMode::Init(timeout);
self.values_changed_once = false;
self.set_count(selection.count, &fleet_info.count);
self.set_count(selection.count, &fleet.count);

break;
}
@@ -262,8 +281,9 @@ impl FleetSelect {

/* calculate values */
let selection = selection!(&d);
let position = position!(&d, selection.fleet);
let fleet_info = fleet_info!(&d, selection.fleet);
let orbit_owned = orbit_owned!(&d, selection.fleet);
let position = position!(&d, orbit_owned.owner);
let fleet = fleet!(&d, selection.fleet);

self.marker = d.camera.view_to_world(self.mouse_pos) - position.pos;
self.zoom = d.camera.view().axis_x.as_vec3().length();
@@ -294,10 +314,10 @@ impl FleetSelect {
x @ 0..=2 => {
let mut count = selection.count;
count[x] = usize::MAX;
self.set_count(count, &fleet_info.count);
self.set_count(count, &fleet.count);

self.values[x] = 1.0;
self.update_values(&fleet_info.count);
self.update_values(&fleet.count);
}
_ => {
self.count = ShipCount::all();
@@ -312,14 +332,14 @@ impl FleetSelect {
match sector {
x @ 0..=2 => {
let mut count = selection.count;
count[x] = (fleet_info.count[x] as f32 * value).round() as usize;
self.set_count(count, &fleet_info.count);
count[x] = (fleet.count[x] as f32 * value).round() as usize;
self.set_count(count, &fleet.count);

self.values[x] = value;
self.update_values(&fleet_info.count);
self.update_values(&fleet.count);
}
_ => {
self.count = fleet_info.count * value;
self.count = fleet.count * value;
self.values = value.into();
}
}
@@ -328,10 +348,10 @@ impl FleetSelect {
x @ 0..=2 => {
let mut count = selection.count;
count[x] = 0;
self.set_count(count, &fleet_info.count);
self.set_count(count, &fleet.count);

self.values[x] = 0.0;
self.update_values(&fleet_info.count);
self.update_values(&fleet.count);
}
_ => {
self.count = Default::default();
@@ -341,7 +361,7 @@ impl FleetSelect {
}

/* update texts */
let c = self.count.merge(&fleet_info.count);
let c = self.count.merge(&fleet.count);
let _guard = self.cache.begin_update();
self.text_total
.update(0, c.total().to_string())
@@ -415,7 +435,8 @@ impl FleetSelect {

/* extract system data */
let selection = selection!(&d);
let position = position!(&d, selection.fleet);
let orbit_owned = orbit_owned!(&d, selection.fleet);
let position = position!(&d, orbit_owned.owner);

/* calculate shared values */
let size = self.ring1 + 50.0;


+ 19
- 17
space-crush-app/src/systems/fleet_control.rs View File

@@ -1,13 +1,12 @@
use shrev::{EventChannel, ReaderId};
use space_crush_common::{
components::{Fleet, FleetOwned, Position, Ship, ShipType},
components::{Fleet, FleetOwned, Orbit, Player, Position, Ship, ShipType},
continue_if_none,
misc::WorldHelper,
return_if_none,
};
use specs::{prelude::*, Entities, Entity, ReadStorage, System, World, WriteStorage};
use specs::{prelude::*, Entity, ReadStorage, System, World, WriteStorage};

use crate::{
components::FleetInfo,
misc::MouseEvent,
resources::{Camera, Config, InputState, PlayerState},
Error,
@@ -26,11 +25,11 @@ pub struct FleetControlData<'a> {
camera: ReadExpect<'a, Camera>,
config: ReadExpect<'a, Config>,

entities: Entities<'a>,
ships: ReadStorage<'a, Ship>,
fleet_owned: WriteStorage<'a, FleetOwned>,
positions: ReadStorage<'a, Position>,
fleet_infos: ReadStorage<'a, FleetInfo>,
players: ReadStorage<'a, Player>,
orbits: ReadStorage<'a, Orbit>,
fleets: ReadStorage<'a, Fleet>,
}

@@ -56,11 +55,11 @@ impl<'a> System<'a> for FleetControl {
input_state,
camera,
config,
entities,
ships,
mut fleet_owned,
positions,
fleet_infos,
players,
orbits,
fleets,
} = data;

@@ -69,10 +68,15 @@ impl<'a> System<'a> for FleetControl {
match event {
MouseEvent::ButtonDown(button) if button == &config.input.fleet_move_button => {
let pos = camera.view_to_world(input_state.mouse_pos);
for (id, position, fleet) in (&entities, &positions, &fleets).join() {
let r = fleet.orbit_max * fleet.orbit_max;
for (position, orbit) in (&positions, &orbits).join() {
let r = orbit.max * orbit.max;
if (position.pos - pos).length_sqr() <= r {
self.target_fleet = Some(id);
let player_id = player_state.player_id;
let player = continue_if_none!(players.get(player_id));
let fleet_id = continue_if_none!(orbit.fleets.get(player.index));
let fleet_id = *continue_if_none!(fleet_id);

self.target_fleet = Some(fleet_id);

break;
}
@@ -80,12 +84,10 @@ impl<'a> System<'a> for FleetControl {
}
MouseEvent::ButtonUp(button) if button == &config.input.fleet_move_button => {
let selection = player_state.selection.take();
let target_fleet = return_if_none!(self.target_fleet.take());
let mut selection = return_if_none!(selection);
let fleet_info = return_if_none!(fleet_infos.get(selection.fleet));
for (ship, fleet_owned, _) in
(&ships, &mut fleet_owned, &fleet_info.owned).join()
{
let target_fleet = continue_if_none!(self.target_fleet.take());
let mut selection = continue_if_none!(selection);
let fleet = continue_if_none!(fleets.get(selection.fleet));
for (ship, fleet_owned, _) in (&ships, &mut fleet_owned, &fleet.owned).join() {
match &ship.type_ {
ShipType::Fighter if selection.count.fighter > 0 => {
fleet_owned.owner = target_fleet;


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

@@ -1,167 +0,0 @@
use std::collections::HashMap;

use shrev::ReaderId;
use space_crush_common::{
components::{FleetOwned, PlayerOwned, Ship},
misc::ComponentEvent,
};
use specs::{
hibitset::BitSetLike, prelude::*, world::Index, Entities, ReadExpect, ReadStorage, System,
World, WriteStorage,
};

use crate::{components::FleetInfo, resources::PlayerState};

pub struct FleetInfoUpdate {
modified: HashMap<Index, Modified>,
need_update: BitSet,
fleet_owned_id: ReaderId<ComponentEvent<FleetOwned>>,
player_owned_id: ReaderId<ComponentEvent<PlayerOwned>>,
}

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

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

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

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

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

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

Self {
modified,
need_update,
fleet_owned_id,
player_owned_id,
}
}
}

#[derive(SystemData)]
pub struct FleetInfoUpdateData<'a> {
entities: Entities<'a>,
player_state: ReadExpect<'a, PlayerState>,
ships: ReadStorage<'a, Ship>,
fleet_infos: WriteStorage<'a, FleetInfo>,
fleet_owned: ReadStorage<'a, FleetOwned>,
player_owned: ReadStorage<'a, PlayerOwned>,
}

impl<'a> System<'a> for FleetInfoUpdate {
type SystemData = FleetInfoUpdateData<'a>;

fn run(&mut self, data: Self::SystemData) {
let FleetInfoUpdateData {
entities,
player_state,
ships,
mut fleet_infos,
fleet_owned,
player_owned,
} = data;

self.modified.clear();
self.need_update.clear();

/* player owned events */
let events = player_owned
.unprotected_storage()
.channel()
.read(&mut self.player_owned_id);
for event in events {
match event {
ComponentEvent::Inserted(id) => {
self.need_update.add(*id);
}
ComponentEvent::Modified(id, player_owned)
| ComponentEvent::Removed(id, player_owned) => {
self.need_update.add(*id);
self.modified.entry(*id).or_default().old_player_id = Some(player_owned.owner);
}
}
}

/* fleet owned events */
let events = fleet_owned
.unprotected_storage()
.channel()
.read(&mut self.fleet_owned_id);
for event in events {
match event {
ComponentEvent::Inserted(id) => {
self.need_update.add(*id);
}
ComponentEvent::Modified(id, fleet_owned)
| ComponentEvent::Removed(id, fleet_owned) => {
self.need_update.add(*id);
self.modified.entry(*id).or_default().old_fleet_id = Some(fleet_owned.owner);
}
}
}

if self.need_update.is_empty() {
return;
}

/* update fleets */
let player_id = player_state.player_id;
for (fleet_id, fleet_info) in (&entities, &mut fleet_infos).join() {
for (ship_id, ship, fleet_owned, player_owned, _) in (
&entities,
&ships,
&fleet_owned,
&player_owned,
&self.need_update,
)
.join()
{
let new_match = fleet_owned.owner == fleet_id && player_owned.owner == player_id;
let old_match = match self.modified.get(&ship_id.id()) {
None => false,
Some(modified) => match (modified.old_fleet_id, modified.old_player_id) {
(Some(old_fleet_id), Some(old_player_id)) => {
old_fleet_id == fleet_id && old_player_id == player_id
}
(Some(old_fleet_id), None) => {
old_fleet_id == fleet_id && player_owned.owner == player_id
}
(None, Some(old_player_id)) => {
fleet_owned.owner == fleet_id && old_player_id == player_id
}
(None, None) => unreachable!(),
},
};

if old_match && !new_match {
fleet_info.owned.remove(ship_id.id());
fleet_info.count[ship.type_] = fleet_info.count[ship.type_].saturating_sub(1);
} else if !old_match && new_match {
fleet_info.owned.add(ship_id.id());
fleet_info.count[ship.type_] += 1;
}
}
}
}
}

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

@@ -1,7 +1,5 @@
mod fleet_control;
mod fleet_info_update;
mod state_update;

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

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

@@ -14,6 +14,7 @@ serde = "1.0"
serde_yaml = "0.8"
shred = { version = "0.10", features = [ "shred-derive" ] }
shrev = "1.1"
smallvec = { version = "1.5", features = [ "serde" ] }
specs = { version = "*", features = [ "serde" ] }
thiserror = "1.0"
vfs = "0.4"


+ 5
- 4
space-crush-common/src/components/fleet.rs View File

@@ -1,16 +1,17 @@
use serde::{Deserialize, Serialize};
use specs::{
error::NoError,
hibitset::BitSet,
saveload::{ConvertSaveload, Marker},
Component, Entity, HashMapStorage, VecStorage,
};

use crate::misc::FlaggedStorage;
use crate::{components::ShipCount, misc::FlaggedStorage};

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[derive(Default, Debug, Clone)]
pub struct Fleet {
pub orbit_min: f32,
pub orbit_max: f32,
pub owned: BitSet,
pub count: ShipCount,
}

#[derive(Copy, Clone, Debug)]


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

@@ -1,6 +1,7 @@
mod asteroid;
mod fleet;
mod obstacle;
mod orbit;
mod planet;
mod player;
mod position;
@@ -10,6 +11,7 @@ mod velocity;
pub use asteroid::{Asteroid, Type as AsteroidType};
pub use fleet::{Fleet, Owned as FleetOwned};
pub use obstacle::Obstacle;
pub use orbit::{Orbit, Owned as OrbitOwned};
pub use planet::Planet;
pub use player::{Owned as PlayerOwned, Player};
pub use position::{Position, Shape};


+ 102
- 0
space-crush-common/src/components/orbit.rs View File

@@ -0,0 +1,102 @@
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use specs::{
error::NoError,
saveload::{ConvertSaveload, Marker},
Component, Entity, HashMapStorage,
};

use crate::misc::FlaggedStorage;

#[derive(Clone, Debug, Default)]
pub struct Orbit {
pub min: f32,
pub max: f32,
pub fleets: SmallVec<[Option<Entity>; 8]>,
}

#[derive(Serialize, Deserialize)]
pub struct OrbitData<M> {
pub min: f32,
pub max: f32,
pub fleets: Vec<Option<M>>,
}

#[derive(Copy, Clone, Debug)]
pub struct Owned {
pub owner: Entity,
}

#[derive(Serialize, Deserialize)]
pub struct OwnedData<M> {
pub owner: M,
}

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

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

fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error>
where
F: FnMut(Entity) -> Option<M>,
{
let Orbit { min, max, fleets } = self;

let min = *min;
let max = *max;
let fleets = fleets
.iter()
.cloned()
.map(|e| e.and_then(|e| ids(e)))
.collect();

Ok(OrbitData { min, max, fleets })
}

fn convert_from<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error>
where
F: FnMut(M) -> Option<Entity>,
{
let OrbitData { min, max, fleets } = data;
let fleets = fleets.into_iter().map(|e| e.and_then(|e| ids(e))).collect();

Ok(Orbit { min, max, fleets })
}
}

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

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

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

Ok(OwnedData { owner })
}

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

Ok(Owned { owner })
}
}

+ 3
- 4
space-crush-common/src/components/player.rs View File

@@ -3,13 +3,12 @@ use serde::{Deserialize, Serialize};
use specs::{
error::NoError,
saveload::{ConvertSaveload, Marker},
Component, Entity, HashMapStorage, VecStorage,
Component, Entity, HashMapStorage,
};

use crate::misc::FlaggedStorage;

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Player {
pub index: usize,
pub color: Vector4f,
}

@@ -28,7 +27,7 @@ impl Component for Player {
}

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

impl<M> ConvertSaveload<M> for Owned


+ 3
- 1
space-crush-common/src/dispatcher.rs View File

@@ -3,7 +3,7 @@ use specs::{Dispatcher as Inner, DispatcherBuilder, World, WorldExt};
use crate::{
components::Player,
resources::Global,
systems::{Movement, Process, Ships},
systems::{FleetOwnedUpdate, Movement, OrbitOwnedUpdate, Process, Ships},
};

pub struct Dispatcher<'a, 'b> {
@@ -20,6 +20,8 @@ impl<'a, 'b> Dispatcher<'a, 'b> {
.with(Process::default(), "process", &[])
.with(Movement::default(), "movement", &[])
.with(Ships::new(world), "ships", &[])
.with(FleetOwnedUpdate::new(world), "fleet_owned_update", &[])
.with(OrbitOwnedUpdate::new(world), "orbit_owned_update", &[])
.build();
dispatcher.setup(world);



+ 11
- 10
space-crush-common/src/misc/flagged_storage.rs View File

@@ -20,7 +20,7 @@ pub enum ComponentEvent<C>
where
C: Send + Sync + 'static,
{
Inserted(Index),
Inserted(Index, C),
Modified(Index, C),
Removed(Index, C),
}
@@ -67,26 +67,27 @@ where
}

unsafe fn get_mut(&mut self, id: Index) -> &mut C {
let ret = self.storage.get_mut(id);
let component = self.storage.get_mut(id);

self.channel
.single_write(ComponentEvent::Modified(id, ret.clone()));
.single_write(ComponentEvent::Modified(id, component.clone()));

ret
component
}

unsafe fn insert(&mut self, id: Index, comp: C) {
self.storage.insert(id, comp);
unsafe fn insert(&mut self, id: Index, component: C) {
self.storage.insert(id, component.clone());

self.channel.single_write(ComponentEvent::Inserted(id));
self.channel
.single_write(ComponentEvent::Inserted(id, component));
}

unsafe fn remove(&mut self, id: Index) -> C {
let c = self.storage.remove(id);
let component = self.storage.remove(id);

self.channel
.single_write(ComponentEvent::Removed(id, c.clone()));
.single_write(ComponentEvent::Removed(id, component.clone()));

c
component
}
}

+ 10
- 4
space-crush-common/src/misc/persistence.rs View File

@@ -5,7 +5,10 @@ use specs::{
Component, Entities, ReadStorage, World, WorldExt, Write, WriteStorage,
};

use crate::components::{Fleet, FleetOwned, Planet, Player, PlayerOwned, Position, Ship, Velocity};
use crate::components::{
Asteroid, FleetOwned, Obstacle, Orbit, OrbitOwned, Planet, Player, PlayerOwned, Position, Ship,
Velocity,
};

/* PersistWorld */

@@ -17,12 +20,15 @@ impl Persistence for PersistWorld {
type Components = (
Position,
Velocity,
Planet,
Ship,
Player,
PlayerOwned,
Fleet,
Orbit,
OrbitOwned,
FleetOwned,
Ship,
Obstacle,
Planet,
Asteroid,
);
}



+ 111
- 0
space-crush-common/src/systems/fleet_owned_update.rs View File

@@ -0,0 +1,111 @@
use std::collections::HashMap;

use shrev::ReaderId;
use specs::{prelude::*, world::Index, Entities, ReadStorage, System, World, WriteStorage};

use crate::{
components::{Fleet, FleetOwned, Ship},
misc::ComponentEvent,
};

pub struct FleetOwnedUpdate {
fleet_ids: BitSet,
fleet_owned_ids: BitSet,
old_fleet_ids: HashMap<Index, Entity>,
fleet_owned_event_id: ReaderId<ComponentEvent<FleetOwned>>,
}

impl FleetOwnedUpdate {
pub fn new(world: &mut World) -> Self {
let fleet_ids = BitSet::new();
let fleet_owned_ids = BitSet::new();
let old_fleet_ids = HashMap::new();

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

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

Self {
fleet_ids,
fleet_owned_ids,
old_fleet_ids,
fleet_owned_event_id,
}
}
}

#[derive(SystemData)]
pub struct FleetOwnedUpdateData<'a> {
entities: Entities<'a>,
ships: ReadStorage<'a, Ship>,
fleets: WriteStorage<'a, Fleet>,
fleet_owned: ReadStorage<'a, FleetOwned>,
}

impl<'a> System<'a> for FleetOwnedUpdate {
type SystemData = FleetOwnedUpdateData<'a>;

fn run(&mut self, data: Self::SystemData) {
let FleetOwnedUpdateData {
entities,
ships,
mut fleets,
fleet_owned,
} = data;

self.fleet_ids.clear();
self.fleet_owned_ids.clear();
self.old_fleet_ids.clear();

/* handle events */
let events = fleet_owned
.unprotected_storage()
.channel()
.read(&mut self.fleet_owned_event_id);
for event in events {
match event {
ComponentEvent::Inserted(id, fleet_owned) => {
self.fleet_ids.add(fleet_owned.owner.id());
self.fleet_owned_ids.add(*id);
}
ComponentEvent::Modified(id, fleet_owned) => {
self.fleet_ids.add(fleet_owned.owner.id());
self.fleet_owned_ids.add(*id);
*self.old_fleet_ids.entry(*id).or_insert(fleet_owned.owner) = fleet_owned.owner;
}
ComponentEvent::Removed(id, fleet_owned) => {
self.fleet_ids.add(fleet_owned.owner.id());
self.fleet_owned_ids.add(*id);
*self.old_fleet_ids.entry(*id).or_insert(fleet_owned.owner) = fleet_owned.owner;
}
}
}

/* update fleets */
for (fleet_id, fleet_info, _) in (&entities, &mut fleets, &self.fleet_ids).join() {
let data = (&entities, &ships, &fleet_owned, &self.fleet_owned_ids);

for (ship_id, ship, fleet_owned, _) in data.join() {
let new_match = fleet_id == fleet_owned.owner;
let old_match = match self.old_fleet_ids.get(&ship_id.id()) {
Some(old_fleet_id) => fleet_id == *old_fleet_id,
None => false,
};

if old_match && !new_match {
fleet_info.owned.remove(ship_id.id());
fleet_info.count[ship.type_] = fleet_info.count[ship.type_].saturating_sub(1);
} else if !old_match && new_match {
fleet_info.owned.add(ship_id.id());
fleet_info.count[ship.type_] += 1;
}
}
}
}
}

+ 4
- 0
space-crush-common/src/systems/mod.rs View File

@@ -1,7 +1,11 @@
mod fleet_owned_update;
mod movement;
mod orbit_owned_update;
mod process;
mod ships;

pub use fleet_owned_update::FleetOwnedUpdate;
pub use movement::Movement;
pub use orbit_owned_update::OrbitOwnedUpdate;
pub use process::Process;
pub use ships::Ships;

+ 121
- 0
space-crush-common/src/systems/orbit_owned_update.rs View File

@@ -0,0 +1,121 @@
use std::collections::HashMap;

use shrev::ReaderId;
use specs::{
hibitset::BitSet, prelude::*, world::Index, Entities, Entity, ReadStorage, System, World,
WriteStorage,
};

use crate::{
components::{Orbit, OrbitOwned, PlayerOwned},
misc::ComponentEvent,
};

pub struct OrbitOwnedUpdate {
orbit_ids: BitSet,
orbit_owned_ids: BitSet,
old_orbit_ids: HashMap<Index, Entity>,
orbit_owned_event_id: ReaderId<crate::misc::ComponentEvent<OrbitOwned>>,
}

impl OrbitOwnedUpdate {
pub fn new(world: &mut World) -> Self {
let orbit_ids = BitSet::new();
let orbit_owned_ids = BitSet::new();
let old_orbit_ids = HashMap::new();

let orbit_owned_event_id = unsafe {
WriteStorage::<OrbitOwned>::setup(world);

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

Self {
orbit_ids,
orbit_owned_ids,
old_orbit_ids,
orbit_owned_event_id,
}
}
}

#[derive(SystemData)]
pub struct OrbitOwnedUpdateData<'a> {
entities: Entities<'a>,
orbits: WriteStorage<'a, Orbit>,
player_owned: ReadStorage<'a, PlayerOwned>,
orbit_owned: ReadStorage<'a, OrbitOwned>,
}

impl<'a> System<'a> for OrbitOwnedUpdate {
type SystemData = OrbitOwnedUpdateData<'a>;

fn run(&mut self, data: Self::SystemData) {
let OrbitOwnedUpdateData {
entities,
mut orbits,
player_owned,
orbit_owned,
} = data;

self.orbit_ids.clear();
self.orbit_owned_ids.clear();
self.old_orbit_ids.clear();

/* handle events */
let events = orbit_owned
.unprotected_storage()
.channel()
.read(&mut self.orbit_owned_event_id);
for event in events {
match event {
ComponentEvent::Inserted(id, orbit_owned) => {
self.orbit_ids.add(orbit_owned.owner.id());
self.orbit_owned_ids.add(*id);
}
ComponentEvent::Modified(id, orbit_owned) => {
self.orbit_ids.add(orbit_owned.owner.id());
self.orbit_owned_ids.add(*id);
*self.old_orbit_ids.entry(*id).or_insert(orbit_owned.owner) = orbit_owned.owner;
}
ComponentEvent::Removed(id, orbit_owned) => {
self.orbit_ids.add(orbit_owned.owner.id());
self.orbit_owned_ids.add(*id);
*self.old_orbit_ids.entry(*id).or_insert(orbit_owned.owner) = orbit_owned.owner;
}
}
}

/* update orbits */
for (orbit_id, orbit, _) in (&entities, &mut orbits, &self.orbit_ids).join() {
let data = (
&entities,
&orbit_owned,
&player_owned,
&self.orbit_owned_ids,
);

for (fleet_id, orbit_owned, player_owned, _) in data.join() {
let new_match = orbit_id == orbit_owned.owner;
let old_match = match self.old_orbit_ids.get(&fleet_id.id()) {
Some(old_orbit_id) => orbit_id == *old_orbit_id,
None => false,
};

let player_id = player_owned.owner.id() as usize;
if old_match && !new_match {
if let Some(fleet) = orbit.fleets.get_mut(player_id) {
*fleet = None;
}
} else if !old_match && new_match {
orbit.fleets.resize_with(player_id + 1, Default::default);
orbit.fleets[player_id] = Some(fleet_id);
}
}
}
}
}

+ 4
- 0
space-crush-common/src/systems/process.rs View File

@@ -34,6 +34,10 @@ impl<'a> System<'a> for Process {
self.time += global.delta;
self.count += 1;

if global.delta > 1.0 {
global.delta = 1.0;
}

if self.time >= 2.0 {
self.time = 0.0;
self.count = 0;


+ 25
- 22
space-crush-common/src/systems/ships.rs View File

@@ -11,7 +11,7 @@ use specs::{
};

use crate::{
components::{Fleet, FleetOwned, Obstacle, Position, Ship, ShipObstacle, Velocity},
components::{FleetOwned, Obstacle, Orbit, OrbitOwned, Position, Ship, ShipObstacle, Velocity},
constants::{
SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND,
SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X,
@@ -33,9 +33,10 @@ pub struct ShipsData<'a> {
ships: WriteStorage<'a, Ship>,
velocities: WriteStorage<'a, Velocity>,
fleet_owned: ReadStorage<'a, FleetOwned>,
orbit_owned: ReadStorage<'a, OrbitOwned>,
positions: ReadStorage<'a, Position>,
obstacles: ReadStorage<'a, Obstacle>,
fleets: ReadStorage<'a, Fleet>,
orbits: ReadStorage<'a, Orbit>,
}

struct Processor<'a> {
@@ -43,7 +44,8 @@ struct Processor<'a> {
entities: &'a Entities<'a>,
positions: &'a ReadStorage<'a, Position>,
obstacles: &'a ReadStorage<'a, Obstacle>,
fleets: &'a ReadStorage<'a, Fleet>,
orbits: &'a ReadStorage<'a, Orbit>,
orbit_owned: &'a ReadStorage<'a, OrbitOwned>,
delta: f32,
}

@@ -74,7 +76,7 @@ impl Ships {
.read(&mut self.fleet_owned_id);
for event in events {
let id = match event {
ComponentEvent::Inserted(id) => id,
ComponentEvent::Inserted(id, _) => id,
ComponentEvent::Modified(id, _) => id,
ComponentEvent::Removed(id, _) => id,
};
@@ -94,9 +96,10 @@ impl<'a> System<'a> for Ships {
mut ships,
mut velocities,
fleet_owned,
orbit_owned,
positions,
obstacles,
fleets,
orbits,
} = data;

self.progress_events(&fleet_owned);
@@ -107,7 +110,8 @@ impl<'a> System<'a> for Ships {
entities: &entities,
positions: &positions,
obstacles: &obstacles,
fleets: &fleets,
orbit_owned: &orbit_owned,
orbits: &orbits,
delta: global.delta * global.world_speed,
};

@@ -136,8 +140,10 @@ impl Processor<'_> {
fleet_owned: &FleetOwned,
) {
let fleet_id = fleet_owned.owner;
let fleet = return_if_none!(self.fleets.get(fleet_id));
let orbit_pos = return_if_none!(self.positions.get(fleet_id)).pos;
let orbit_owned = return_if_none!(self.orbit_owned.get(fleet_id));
let orbit_id = orbit_owned.owner;
let orbit = return_if_none!(self.orbits.get(orbit_id));
let orbit_pos = return_if_none!(self.positions.get(orbit_id)).pos;
let ship_pos = position.pos;
let target_pos = ship.target_pos;
let target_dir = ship.target_dir;
@@ -149,11 +155,8 @@ impl Processor<'_> {
let r_ship = orbit_to_ship.length_sqr();
let r_target = orbit_to_target.length_sqr();

let orbit_min = fleet.orbit_min;
let orbit_max = fleet.orbit_max;

let target_in_orbit = (r_target <= sqr(fleet.orbit_max)) && (r_target >= sqr(orbit_min));
let ship_in_orbit = r_ship < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit_max);
let target_in_orbit = (r_target <= sqr(orbit.max)) && (r_target >= sqr(orbit.min));
let ship_in_orbit = r_ship < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit.max);

let need_update = self.need_update.contains(id);
let has_target = target_dir.length_sqr() != 0.0;
@@ -161,7 +164,7 @@ impl Processor<'_> {

/* check and update target posistion */
if need_update || !has_target || passed_target || ship_in_orbit != target_in_orbit {
let target_pos = if ship_in_orbit && fleet.orbit_max > 0.0 {
let target_pos = if ship_in_orbit && orbit.max > 0.0 {
let orbit_to_ship_vec3 = Vector3f::new(orbit_to_ship.x, orbit_to_ship.y, 0.0);
let ship_dir_vec3 = Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0);

@@ -173,8 +176,8 @@ impl Processor<'_> {

let add = SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random();
let angle = orbit_to_ship.angle2(&VECTOR_2F_POS_X);
let angle = angle + add * dir / orbit_max;
let radius = orbit_min + (orbit_max - orbit_min) * random::<f32>();
let angle = angle + add * dir / orbit.max;
let radius = orbit.min + (orbit.max - orbit.min) * random::<f32>();

Vector2f::new(
orbit_pos.x + radius * angle.cos(),
@@ -197,7 +200,7 @@ impl Processor<'_> {
ship.obstacle = ShipObstacle::Done;
} else if let ShipObstacle::Known(obstacle) = ship.obstacle {
if let Some(position) = self.positions.get(obstacle) {
let obstacle_fleet = self.fleets.get(obstacle).unwrap();
let obstacle_orbit = self.orbits.get(obstacle).unwrap();
let obstacle_pos = position.pos;
let ship_to_obstacle = obstacle_pos - ship_pos;

@@ -207,7 +210,7 @@ impl Processor<'_> {
.into_inner()
.abs();

let orbit_sqr = obstacle_fleet.orbit_max * obstacle_fleet.orbit_max;
let orbit_sqr = obstacle_orbit.max * obstacle_orbit.max;
if (obstacle_angle > 90.0 && ship_to_obstacle.length_sqr() > orbit_sqr)
|| obstacle_angle > 170.0
{
@@ -247,13 +250,13 @@ 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_fleet = self.fleets.get(obstacle).unwrap();
let obstacle_orbit = self.orbits.get(obstacle).unwrap();
let ship_to_obstacle = obstacle_pos.pos - ship_pos;

let orbit = ship_to_obstacle.length();
if orbit < obstacle_fleet.orbit_max {
let orbit_min = obstacle_fleet.orbit_min;
let orbit_max = obstacle_fleet.orbit_max;
if orbit < obstacle_orbit.max {
let orbit_min = obstacle_orbit.min;
let orbit_max = obstacle_orbit.max;
let mut tangent = Vector2f::new(-ship_to_obstacle.y, ship_to_obstacle.x);

let radius = obstacle_pos.shape.radius();


Loading…
Cancel
Save