diff --git a/src/actor.rs b/src/actor.rs index 2d275fd..4292bb0 100644 --- a/src/actor.rs +++ b/src/actor.rs @@ -3,6 +3,7 @@ use bevy_xpbd_3d::prelude::*; use bevy::scene::SceneInstance; use bevy::math::DVec3; use crate::{actor, audio, camera, chat, commands, effects, hud, nature, var, world}; +use std::collections::HashMap; pub const ENGINE_SPEED_FACTOR: f32 = 30.0; const MAX_TRANSMISSION_DISTANCE: f32 = 100.0; @@ -27,9 +28,11 @@ impl Plugin for ActorPlugin { )); app.add_systems(PostUpdate, ( handle_vehicle_enter_exit, + update_id2pos, )); app.add_event::(); app.add_event::(); + app.insert_resource(Id2Pos(HashMap::new())); } } @@ -115,6 +118,8 @@ impl Default for ExperiencesGForce { fn default() -> Self { Self { #[derive(Component)] pub struct ActorVehicleBeingEntered; #[derive(Component)] pub struct WantsMaxRotation(pub f64); #[derive(Component)] pub struct WantsMaxVelocity(pub f64); +#[derive(Component)] pub struct Identifier(pub String); +#[derive(Resource)] pub struct Id2Pos(pub HashMap); #[derive(Component)] pub struct LifeForm { @@ -521,3 +526,13 @@ fn handle_gforce( } } } + +fn update_id2pos( + mut id2pos: ResMut, + q_id: Query<(&Position, &Identifier)>, +) { + id2pos.0.clear(); + for (pos, id) in &q_id { + id2pos.0.insert(id.0.clone(), pos.0); + } +} diff --git a/src/commands.rs b/src/commands.rs index 5ffcb8e..63f8c91 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -7,7 +7,6 @@ use crate::{actor, chat, hud, nature, shading, world}; use regex::Regex; use std::f32::consts::PI; use std::f64::consts::PI as PI64; -use std::collections::HashMap; pub struct CommandsPlugin; impl Plugin for CommandsPlugin { @@ -39,6 +38,7 @@ struct ParserState { // Actor fields id: String, pos: DVec3, + relative_to: Option, model: Option, model_scale: f32, rotation: Quat, @@ -86,6 +86,7 @@ impl Default for ParserState { id: "".to_string(), pos: DVec3::new(0.0, 0.0, 0.0), + relative_to: None, model: None, model_scale: 1.0, rotation: Quat::IDENTITY, @@ -135,7 +136,6 @@ pub fn load_defs( let mut state = ParserState::default(); let mut command; let mut parameters; - let mut id2pos: HashMap = HashMap::new(); let mut line_nr = -1; while let Some(line) = lines.next() { @@ -207,18 +207,7 @@ pub fn load_defs( } } ["relativeto", id] => { - // NOTE: call this command before "id", otherwise actors that - // set their position relative to this actor will get the wrong offset - // TODO: fix the above - match id2pos.get(&id.to_string()) { - Some(pos) => { - state.pos += *pos; - } - None => { - error!("Specified `relativeto` command but could not find id `{id}`"); - continue; - } - } + state.relative_to = Some(id.to_string()); } ["orbit", radius_str, phase_str] => { if let (Ok(r), Ok(phase)) = (radius_str.parse::(), phase_str.parse::()) { @@ -239,7 +228,6 @@ pub fn load_defs( } ["id", id] => { state.id = id.to_string(); - id2pos.insert(state.id.clone(), state.pos.clone()); } ["alive", "yes"] => { state.is_alive = true; @@ -468,10 +456,25 @@ fn spawn_entities( mut meshes: ResMut>, mut materials: ResMut>, mut materials_jupiter: ResMut>, + mut id2pos: ResMut, ) { for state_wrapper in er_spawn.read() { let state = &state_wrapper.0; if state.class == DefClass::Actor { + let relative_pos = if let Some(id) = &state.relative_to { + match id2pos.0.get(&id.to_string()) { + Some(pos) => { + state.pos + *pos + } + None => { + error!("Specified `relativeto` command but could not find id `{id}`"); + continue; + } + } + } else { + state.pos + }; + let actor_entity; { let mut actor = commands.spawn_empty(); @@ -484,7 +487,7 @@ fn spawn_entities( actor.insert(SleepingDisabled); actor.insert(world::DespawnOnPlayerDeath); actor.insert(actor::HitPoints::default()); - actor.insert(Position::from(state.pos)); + actor.insert(Position::from(relative_pos)); actor.insert(Rotation::from(state.rotation)); if state.is_sphere { let sphere_texture_handle = if let Some(model) = &state.model { @@ -603,6 +606,10 @@ fn spawn_entities( ..default() }); } + if !state.id.is_empty() { + actor.insert(actor::Identifier(state.id.clone())); + id2pos.0.insert(state.id.clone(), relative_pos); + } if !state.chat.is_empty() { actor.insert(chat::Talker { actor_id: state.id.clone(), @@ -661,10 +668,10 @@ fn spawn_entities( ring_radius: nature::JUPITER_RING_RADIUS as f32, jupiter_radius: nature::JUPITER_RADIUS as f32, }), - transform: Transform::from_translation(state.pos.as_vec3()), + transform: Transform::from_translation(relative_pos.as_vec3()), ..default() }, - Position::new(state.pos), + Position::new(relative_pos), Rotation::from(Quat::IDENTITY), //Rotation::from(Quat::from_rotation_x(-0.3f32.to_radians())), ));