Hint: The 'FleetControl' system is broken now, but will be refactored in the future anyway.master
@@ -1537,6 +1537,7 @@ dependencies = [ | |||
"serde_yaml", | |||
"shred", | |||
"shrev", | |||
"smallvec", | |||
"specs", | |||
"thiserror", | |||
"vfs", | |||
@@ -1 +0,0 @@ | |||
- De-/Serialize World |
@@ -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>; | |||
} |
@@ -1,3 +0,0 @@ | |||
mod fleet_info; | |||
pub use fleet_info::FleetInfo; |
@@ -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,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)?) | |||
@@ -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, | |||
@@ -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; | |||
@@ -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; | |||
@@ -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; | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -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; |
@@ -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" | |||
@@ -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)] | |||
@@ -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}; | |||
@@ -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,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,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); | |||
@@ -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 | |||
} | |||
} |
@@ -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, | |||
); | |||
} | |||
@@ -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; | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -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; |
@@ -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); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -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; | |||
@@ -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(); | |||