From 7f5894f9f7a31a7df8eebaf7165b290c37ba1e07 Mon Sep 17 00:00:00 2001 From: hut Date: Tue, 30 Apr 2024 00:29:37 +0200 Subject: [PATCH] set moon orbit phases according to real time clock --- src/commands.rs | 59 ++++++++++++++++++++++++++++++++++++++--------- src/data/defs.txt | 16 ++++++------- src/nature.rs | 17 ++++++++++++++ 3 files changed, 73 insertions(+), 19 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 2d49cc7..fff7723 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -19,6 +19,7 @@ use crate::{actor, camera, chat, hud, nature, shading, skeleton, var, world}; use regex::Regex; use std::f32::consts::PI; use std::f64::consts::PI as PI64; +use std::time::SystemTime; pub struct CommandsPlugin; impl Plugin for CommandsPlugin { @@ -68,6 +69,9 @@ struct ParserState { is_sun: bool, is_moon: bool, is_point_of_interest: bool, + orbit_distance: Option, + orbit_object_id: Option, + orbit_phase: Option, has_physics: bool, has_ring: bool, wants_maxrotation: Option, @@ -119,6 +123,9 @@ impl Default for ParserState { is_sun: false, is_moon: false, is_point_of_interest: false, + orbit_distance: None, + orbit_object_id: None, + orbit_phase: None, has_physics: true, has_ring: false, wants_maxrotation: None, @@ -227,14 +234,20 @@ pub fn load_defs( ["relativeto", id] => { state.relative_to = Some(id.to_string()); } + ["orbitaround", object_id, radius_str] => { + if let Ok(r) = radius_str.parse::() { + state.orbit_distance = Some(r); + state.orbit_object_id = Some(object_id.to_string()); + } + else { + error!("Can't parse float: {line}"); + continue; + } + } ["orbit", radius_str, phase_str] => { if let (Ok(r), Ok(phase)) = (radius_str.parse::(), phase_str.parse::()) { - let phase_deg = phase * PI64 * 2.0; - state.pos = DVec3::new( - state.pos.x + r * phase_deg.cos(), - state.pos.y, - state.pos.z + r * phase_deg.sin(), - ); + state.orbit_distance = Some(r); + state.orbit_phase = Some(phase * PI64 * 2.0); } else { error!("Can't parse float: {line}"); @@ -492,7 +505,7 @@ fn spawn_entities( let state = &state_wrapper.0; if state.class == DefClass::Actor { // Preprocessing - let relative_pos = if let Some(id) = &state.relative_to { + let mut absolute_pos = if let Some(id) = &state.relative_to { match id2pos.0.get(&id.to_string()) { Some(pos) => { state.pos + *pos @@ -505,6 +518,30 @@ fn spawn_entities( } else { state.pos }; + if let Some(r) = state.orbit_distance { + let phase_radians: f64 = if let Some(phase_radians) = state.orbit_phase { + phase_radians + } else if let Some(id) = &state.orbit_object_id { + let mass = match id.as_str() { + "jupiter" => nature::JUPITER_MASS, + _ => { + error!("Found no mass for object `{id}`"); + continue; + } + }; + let orbital_period = nature::simple_orbital_period(mass, r); + if let Ok(epoch) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { + PI64 * 2.0 * (epoch.as_secs_f64() % orbital_period) / orbital_period + } else { + error!("Can't determine current time `{id}`"); + 0.0 + } + } else { + error!("if state.orbit_distance is set, then either state.orbit_object_id or state.orbit_phase must be set as well."); + continue; + }; + absolute_pos += nature::phase_dist_to_coords(phase_radians, r); + } let scale = Vec3::splat(if state.is_sun { 5.0 } else if state.is_moon && settings.large_moons { @@ -526,7 +563,7 @@ fn spawn_entities( actor.insert(SleepingDisabled); actor.insert(world::DespawnOnPlayerDeath); actor.insert(actor::HitPoints::default()); - actor.insert(Position::from(relative_pos)); + actor.insert(Position::from(absolute_pos)); actor.insert(Rotation::from(state.rotation)); if state.is_sphere { let sphere_texture_handle = if let Some(model) = &state.model { @@ -653,7 +690,7 @@ fn spawn_entities( } if !state.id.is_empty() { actor.insert(actor::Identifier(state.id.clone())); - id2pos.0.insert(state.id.clone(), relative_pos); + id2pos.0.insert(state.id.clone(), absolute_pos); } if !state.chat.is_empty() { actor.insert(chat::Talker { @@ -730,10 +767,10 @@ fn spawn_entities( ring_radius: nature::JUPITER_RING_RADIUS as f32, jupiter_radius: nature::JUPITER_RADIUS as f32, }), - transform: Transform::from_translation(relative_pos.as_vec3()), + transform: Transform::from_translation(absolute_pos.as_vec3()), ..default() }, - Position::new(relative_pos), + Position::new(absolute_pos), Rotation::from(Quat::IDENTITY), //Rotation::from(Quat::from_rotation_x(-0.3f32.to_radians())), NotShadowCaster, diff --git a/src/data/defs.txt b/src/data/defs.txt index b2d94f5..23a8900 100644 --- a/src/data/defs.txt +++ b/src/data/defs.txt @@ -152,7 +152,7 @@ actor 0 0 0 io name Io id io relativeto jupiter - orbit 421700e3 0.65 + orbitaround jupiter 421700e3 scale 1822e3 rotationy -0.40 rotationx -0.50 @@ -165,7 +165,7 @@ actor 0 0 0 europa name Europa id europa relativeto jupiter - orbit 670900e3 0.35 + orbitaround jupiter 670900e3 scale 1561e3 rotationy 0.20 rotationx -0.50 @@ -178,7 +178,7 @@ actor 0 0 0 ganymede name Ganymede id ganymede relativeto jupiter - orbit 1070400e3 0.93 + orbitaround jupiter 1070400e3 scale 2634e3 rotationy -0.40 rotationx -0.50 @@ -191,7 +191,7 @@ actor 0 0 0 callisto name Callisto id callisto relativeto jupiter - orbit 1882700e3 0.45 + orbitaround jupiter 1882700e3 scale 2410e3 rotationy -0.40 rotationx -0.50 @@ -204,7 +204,7 @@ actor 0 0 0 moonlet name Thebe relativeto jupiter id thebe - orbit 221900e3 0.66 + orbitaround jupiter 221900e3 scale 50e3 angularmomentum 0 0.025 0 actor -55e3 44e3 0 suitv2 @@ -226,7 +226,7 @@ actor 0 0 0 moonlet name Metis relativeto jupiter id metis - orbit 128000e3 0.8 + orbitaround jupiter 128000e3 scale 21.5e3 angularmomentum 0 0.025 0 @@ -234,7 +234,7 @@ actor 0 0 0 moonlet name Adrastea relativeto jupiter id adrastea - orbit 129000e3 0.5 + orbitaround jupiter 129000e3 scale 8.2e3 angularmomentum 0 0.025 0 @@ -242,7 +242,7 @@ actor 0 0 0 moonlet name Amalthea relativeto jupiter id amalthea - orbit 181365.84e3 0.2 + orbitaround jupiter 181365.84e3 scale 83.5e3 angularmomentum 0 0.025 0 diff --git a/src/nature.rs b/src/nature.rs index fdc9f21..dedfbb5 100644 --- a/src/nature.rs +++ b/src/nature.rs @@ -10,6 +10,9 @@ // // This module manages the messy, impure parts of our universe. +use bevy::math::DVec3; +use std::f64::consts::PI as PI64; + pub const OXYGEN_USE_KG_PER_S: f32 = 1e-5; pub const OXY_S: f32 = OXYGEN_USE_KG_PER_S; pub const OXY_M: f32 = OXYGEN_USE_KG_PER_S * 60.0; @@ -20,10 +23,12 @@ pub const PARSEC2METER: f64 = 3.0857e16; pub const DIST_JUPTER_SUN: f64 = 778479.0e6; pub const EARTH_GRAVITY: f32 = 9.81; pub const C: f64 = 299792458.0; // m/s +pub const G: f64 = 6.6743015e-11; // Gravitational constant in Nm²/kg² pub const SOL_RADIUS: f64 = 696_300_000.0; pub const JUPITER_RADIUS: f64 = 71_492_000.0; pub const JUPITER_RING_RADIUS: f64 = 229_000_000.0; +pub const JUPITER_MASS: f64 = 1.8982e27; // Each star's values: (x, y, z, magnitude, color index, distance, name) pub const STARS: &[(f32, f32, f32, f32, f32, f32, &str)] = &include!("data/stars.in"); @@ -139,3 +144,15 @@ pub fn lorenz_factor(speed: f64) -> f64 { pub fn lorenz_factor_custom_c(speed: f64, c: f64) -> f64 { (1.0 - (speed.powf(2.0) / c.powf(2.0))).sqrt() } + +pub fn simple_orbital_period(mass: f64, distance: f64) -> f64 { + return 2.0 * PI64 * (distance.powf(3.0) / (G * mass)).sqrt(); +} + +pub fn phase_dist_to_coords(phase_radians: f64, distance: f64) -> DVec3 { + return DVec3::new( + distance * phase_radians.cos(), + 0.0, + distance * phase_radians.sin(), + ); +}