~starkingdoms/starkingdoms

89c38c327e6eca6da0ab6d0d2b03d6af21b9f244 — ghostly_zsh 23 days ago 49175fb
fix: parts have initial velocity matching parent planet, and orbit indicator uses relative velocity
M crates/unified/assets/config/planets.pc.toml => crates/unified/assets/config/planets.pc.toml +11 -11
@@ 1,5 1,5 @@
[orbit]
planet_spring_compliance = 0
planet_spring_compliance = 0.0

[[planets]]
name = "Sun"


@@ 17,7 17,7 @@ radius = 666.66 # m
mass = 205_000_000.0 # kg
default_transform = [116_129.4, 0.0, 0.0]
planet_resource = { name = "Composite", color = { LinearRgba = { red = 0.7, green = 0.7, blue = 0.7, alpha = 1.0 } }, mining_speed = 5.0 }
orbit = { orbiting = "Sun", eccentricity = 0.2056, period = 299.0 }
orbit = { orbiting = "Sun", eccentricity = 0.2056 }

[[planets]]
name = "Venus"


@@ 26,7 26,7 @@ radius = 1899.8 # m
mass = 806_166_000.0 # kg
default_transform = [216_999.6, 0.0, 0.0]
planet_resource = { name = "Sulfur", color = { LinearRgba = { red = 0.7, green = 0.7, blue = 0.7, alpha = 1.0 } }, mining_speed = 5.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0068, period = 546.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0068 }

[[planets]]
name = "Earth"


@@ 36,7 36,7 @@ radius = 2000.0 # m
mass = 16_900_000_000.0 # kg
planet_resource = { name = "Carbon", color = { LinearRgba = { red = 1.0, green = 0.7, blue = 0.7, alpha = 1.0 } }, mining_speed = 2.0 }
default_transform = [300_000.0, 0.0, 0.0]
orbit = { orbiting = "Sun", eccentricity = 0.0167, period = 900.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0167 }

[[planets]]
name = "Moon"


@@ 46,7 46,7 @@ radius = 545.4 # m
mass = 360_236_000.0 # kg
default_transform = [312_700.0, 0.0, 0.0]
planet_resource = { name = "Silicon", color = { LinearRgba = { red = 0.7, green = 0.7, blue = 0.7, alpha = 1.0 } }, mining_speed = 5.0 }
orbit = { orbiting = "Earth", eccentricity = 0.0549, period = 256.0 }
orbit = { orbiting = "Earth", eccentricity = 0.0549 }

[[planets]]
name = "Mars"


@@ 56,7 56,7 @@ radius = 1062.0 # m
mass = 525_857_000.0 # kg
default_transform = [430_000.0, 0.0, 0.0]
planet_resource = { name = "Iron", color = { LinearRgba = { red = 0.7, green = 0.7, blue = 0.7, alpha = 1.0 } }, mining_speed = 5.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0934, period = 1745.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0934 }

[[planets]]
name = "Jupiter"


@@ 65,7 65,7 @@ radius = 21946.0 # m
mass = 1_131_221_218_000.0 # kg
default_transform = [1_561_140.0, 0.0, 0.0]
planet_resource = { name = "Hydrogen", color = { LinearRgba = { red = 0.7, green = 0.7, blue = 0.7, alpha = 1.0 } }, mining_speed = 5.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0484, period = 11218.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0484 }

[[planets]]
name = "Saturn"


@@ 74,7 74,7 @@ radius = 18_280.4 # m
mass = 561_386_112_000.0 # kg
default_transform = [2_874_780.0, 0.0, 0.0]
planet_resource = { name = "Helium", color = { LinearRgba = { red = 0.7, green = 0.7, blue = 0.7, alpha = 1.0 } }, mining_speed = 5.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0541, period = 28297.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0541 }

[[planets]]
name = "Uranus"


@@ 83,7 83,7 @@ radius = 8014.0 # m
mass = 69_763_532_000.0 # kg
default_transform = [4_050_000.0, 0.0, 0.0]
planet_resource = { name = "Rubber", color = { LinearRgba = { red = 0.7, green = 0.7, blue = 0.7, alpha = 1.0 } }, mining_speed = 5.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0472, period = 46791.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0472 }

[[planets]]
name = "Neptune"


@@ 92,7 92,7 @@ radius = 7_766.0 # m
mass = 106_674_649_000.0 # kg
default_transform = [5_000_000.0, 0.0, 0.0]
planet_resource = { name = "Methane", color = { LinearRgba = { red = 0.7, green = 0.7, blue = 0.7, alpha = 1.0 } }, mining_speed = 5.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0086, period = 60454.0 }
orbit = { orbiting = "Sun", eccentricity = 0.0086 }

[[planets]]
name = "Pluto"


@@ 101,4 101,4 @@ radius = 373.6 # m
mass = 10_817_000.0 # kg
default_transform = [5_922_300.0, 0.0, 0.0]
planet_resource = { name = "Ice", color = { LinearRgba = { red = 0.7, green = 0.7, blue = 0.7, alpha = 1.0 } }, mining_speed = 5.0 }
orbit = { orbiting = "Sun", eccentricity = 0.2488, period = 118234.0 }
orbit = { orbiting = "Sun", eccentricity = 0.2488 }

M crates/unified/src/client/starguide/orbit.rs => crates/unified/src/client/starguide/orbit.rs +13 -8
@@ 13,7 13,7 @@ fn update_orbits(
    me: Single<(&Transform, &LinearVelocity), (With<Me>, Without<StarguideCamera>)>,
    mut gizmos: Gizmos<StarguideGizmos>,
    world_config: Res<WorldConfigResource>,
    planets: Query<(&Mass, &Planet, &Transform)>,
    planets: Query<(&Mass, &Planet, &Transform, &LinearVelocity)>,
) {
    let Some(world_config) = &world_config.config else {
        return;


@@ 22,12 22,13 @@ fn update_orbits(

    let mut p_mass = None;
    let mut p_transform = None;
    let (sun_mass, _, sun_transform) = planets.iter().find(|planet| planet.1.name == "Sun").unwrap();
    let mut p_velocity = None;
    let (sun_mass, _, sun_transform, sun_velocity) = planets.iter().find(|planet| planet.1.name == "Sun").unwrap();
    let mut closest = f32::INFINITY;
    for (mass, planet, transform) in planets {
    for (mass, planet, transform, velocity) in planets {
        if planet.name == "Sun" { continue }

        let (other_mass, _, other_transform) = planets.iter().find(|f_planet| f_planet.1.name == planet.orbit.clone().unwrap().orbiting).unwrap();
        let (other_mass, _, other_transform, other_velocity) = planets.iter().find(|f_planet| f_planet.1.name == planet.orbit.clone().unwrap().orbiting).unwrap();
        let a = other_transform.translation - transform.translation;
        let hill_sphere = a.length()*(mass.0/(3.0*(other_mass.0+mass.0))).powf(1.0/3.0);



@@ 37,24 38,28 @@ fn update_orbits(
        if rel_dist < closest && hill_sphere > rel_dist {
            p_mass = Some(mass.0);
            p_transform = Some(*transform);
            p_velocity = Some(*velocity);
            closest = rel_dist;
        }
    }
    if p_mass.is_none()  {
        p_mass = Some(sun_mass.0);
        p_transform = Some(*sun_transform);
        p_velocity = Some(*sun_velocity);
    }
    let p_mass = p_mass.unwrap();
    let p_transform = p_transform.unwrap();
    let p_velocity = p_velocity.unwrap();

    // orbit magic
    let rel_pos = me.0.translation - p_transform.translation;
    let rel_vel = me.1.0 - p_velocity.0;
    let u = world_config.world.gravity*p_mass;
    let h = rel_pos.x*me.1.y - rel_pos.y*me.1.x;
    let h = rel_pos.x*rel_vel.y - rel_pos.y*rel_vel.x;
    let r = rel_pos.length();
    let a = (u*r) / (2.0*u - r*(me.1.x*me.1.x + me.1.y*me.1.y));
    let e_x = rel_pos.x/r - (h*me.1.y)/u;
    let e_y = rel_pos.y/r + (h*me.1.x)/u;
    let a = (u*r) / (2.0*u - r*(rel_vel.x*rel_vel.x + rel_vel.y*rel_vel.y));
    let e_x = rel_pos.x/r - (h*rel_vel.y)/u;
    let e_y = rel_pos.y/r + (h*rel_vel.x)/u;
    let f_x = -2.0*a*e_x;
    let f_y = -2.0*a*e_y;


M crates/unified/src/config/planet.rs => crates/unified/src/config/planet.rs +0 -1
@@ 49,7 49,6 @@ pub struct PlanetResource {
pub struct OrbitData {
    pub orbiting: String,
    pub eccentricity: f32,
    pub period: f32
}

#[derive(Deserialize, TypePath, Serialize, Clone, Debug)]

M crates/unified/src/server/craft.rs => crates/unified/src/server/craft.rs +7 -6
@@ 8,8 8,8 @@ pub fn craft_plugin(app: &mut App) {

fn receive_crafting_request(
    mut craft_part_request: MessageReader<FromClient<CraftPartRequest>>,
    part_query: Query<(&Transform, &Part, &PartInShip)>,
    player_query: Query<(Entity, &Transform, &Part), With<Player>>,
    part_query: Query<(&Transform, &LinearVelocity, &Part, &PartInShip)>,
    player_query: Query<(Entity, &Transform, &LinearVelocity, &Part), With<Player>>,
    parts_query: Query<&Parts>,
    mut single_storage_query: Query<(&mut SingleStorage)>,
    mut variable_storage_query: Query<(&mut VariableStorage)>,


@@ 18,15 18,15 @@ fn receive_crafting_request(
) {
    'request: for request in craft_part_request.read() {
        // TODO: make crafting take time
        let (transform, part, parts_list) = if let Ok((transform, part, part_in_ship)) = part_query.get(request.crafting_part) {
        let (transform, vel, part, parts_list) = if let Ok((transform, vel, part, part_in_ship)) = part_query.get(request.crafting_part) {
            // this is a normal part
            let Ok(parts_list) = parts_query.get(part_in_ship.0) else {
                warn!("Couldn't find parts list in part in ship");
                continue;
            };
            let parts_list = parts_list.iter().collect::<Vec<_>>();
            (transform, part, parts_list)
        } else if let Ok((entity, transform, part)) = player_query.get(request.crafting_part) {
            (transform, vel, part, parts_list)
        } else if let Ok((entity, transform, vel, part)) = player_query.get(request.crafting_part) {
            // this is a player
            let parts_list = if let Ok(parts_list) = parts_query.get(entity) {
                let mut parts_list = parts_list.iter().collect::<Vec<_>>();


@@ 35,7 35,7 @@ fn receive_crafting_request(
            } else {
                vec![entity]
            };
            (transform, part, parts_list)
            (transform, vel, part, parts_list)
        } else {
            warn!("When receiving a crafting request, the crafting part didn't exist.");
            continue;


@@ 113,6 113,7 @@ fn receive_crafting_request(
            req: SpawnPartRequest(asset_server.load(
                         format!("config/parts/{}.part.toml", request.crafted_part.to_lowercase()))),
            transform: transform.with_translation(transform.translation + vec3(50.0, 0.0, 0.0)),
            vel: *vel,
        });
    }
}

M crates/unified/src/server/earth_parts.rs => crates/unified/src/server/earth_parts.rs +5 -4
@@ 18,7 18,7 @@ pub fn spawn_parts_plugin(app: &mut App) {
fn spawn_parts_on_earth(
    mut commands: Commands,
    world_config: Res<WorldConfigResource>,
    planets: Query<(&Transform, &Planet)>,
    planets: Query<(&Transform, &LinearVelocity, &Planet)>,
    mut timer: ResMut<PartTimerRes>,
    asset_server: Res<AssetServer>,
    time: Res<Time>,


@@ 34,8 34,8 @@ fn spawn_parts_on_earth(
    timer.timer = Timer::from_seconds(wc.world.spawn_parts_interval_secs, TimerMode::Once);

    // find earth
    let Some((spawn_planet_pos, spawn_planet)) =
        planets.iter().find(|p| p.1.name == wc.hearty.spawn_at)
    let Some((spawn_planet_pos, spawn_planet_vel, spawn_planet)) =
        planets.iter().find(|p| p.2.name == wc.hearty.spawn_at)
    else {
        return;
    };


@@ 48,6 48,7 @@ fn spawn_parts_on_earth(
    commands
        .spawn(SpawnPartBundle {
            req: SpawnPartRequest(asset_server.load("config/parts/housing.part.toml")),
            transform: new_transform
            transform: new_transform,
            vel: *spawn_planet_vel,
        });
}

M crates/unified/src/server/orbit/mod.rs => crates/unified/src/server/orbit/mod.rs +10 -4
@@ 1,6 1,7 @@
use std::collections::HashMap;
use std::f32::consts::PI;
use avian2d::math::TAU;
use avian2d::prelude::LinearVelocity;
use avian2d::prelude::{LinearVelocity, Mass};
use bevy::log::debug;
use bevy::math::ops::atan2;
use bevy::prelude::{Component, Plugin, Transform};


@@ 8,6 9,7 @@ use bevy::time::Time;
use serde::{Deserialize, Serialize};
use crate::config::planet::{Planet, PlanetSpring, PlanetSpringJoint};
use crate::prelude::{App, Query, Res, Update, Without};
use crate::world_config::WorldConfigResource;

pub struct OrbitPlugin;
impl Plugin for OrbitPlugin {


@@ 18,10 20,14 @@ impl Plugin for OrbitPlugin {

fn update_orbits(
    mut planets: Query<(&Planet, &Transform, &mut LinearVelocity), Without<PlanetSpring>>,
    planets_2: Query<(&Planet, &Transform), Without<PlanetSpring>>,
    planets_2: Query<(&Planet, &Transform, &Mass), Without<PlanetSpring>>,
    mut planet_springs: Query<(&PlanetSpring, &mut Transform), Without<Planet>>,
    world_config: Res<WorldConfigResource>,
    time: Res<Time>
) {
    let Some(ref world_config) = world_config.config else {
        return;
    };
    let parent_velocities = planets.iter().map(|u| (u.0.name.clone(), u.2.clone())).collect::<HashMap<String, LinearVelocity>>();
    for (planet, _, mut vel) in planets.iter_mut() {
        let Some(orbit_data) = &planet.orbit else { continue; };


@@ 30,7 36,7 @@ fn update_orbits(

        let a = (planet.default_transform[0] - parent.0.default_transform[0]) / (1.0 - orbit_data.eccentricity);
        let e = orbit_data.eccentricity;
        let t = orbit_data.period;
        let t = 2.0*PI*((a*a*a)/(world_config.world.gravity*(**parent.2))).sqrt();

        let time = time.elapsed_secs();



@@ 71,4 77,4 @@ fn iterative_kepler(m: f32, e: f32) -> f32 {
        }
    }
    output
}
\ No newline at end of file
}

M crates/unified/src/server/part.rs => crates/unified/src/server/part.rs +1 -0
@@ 15,6 15,7 @@ pub fn part_management_plugin(app: &mut App) {
pub struct SpawnPartBundle {
    pub req: SpawnPartRequest,
    pub transform: Transform,
    pub vel: LinearVelocity,
}

#[derive(Component)]

M crates/unified/src/server/planets.rs => crates/unified/src/server/planets.rs +5 -3
@@ 46,7 46,7 @@ pub fn update_planets(
                    let planet_config = assets.get(*id).unwrap();
                    for planet in &planet_config.planets {
                        let mut planet_entity = commands
                            .spawn(PlanetBundle {
                            .spawn((PlanetBundle {
                                planet: planet.clone(),
                                transform: Transform::from_xyz(
                                    planet.default_transform[0],


@@ 55,7 55,9 @@ pub fn update_planets(
                                ),
                                collider: Collider::circle(planet.radius),
                                mass: Mass(planet.mass)
                            }).with_child((
                            },
                            SleepingDisabled
                            )).with_child((
                                Collider::circle(planet.radius+2.0),
                                Sensor,
                                PlanetSensor(planet.name.clone()),


@@ 76,7 78,7 @@ pub fn update_planets(
                                PlanetSpringJoint {
                                    name: planet.name.clone()
                                },
                                FixedJoint::new(planet_entity, spring).with_point_compliance(planet_config.orbit.planet_spring_compliance)
                                FixedJoint::new(planet_entity, spring).with_point_compliance(planet_config.orbit.planet_spring_compliance),
                            ));
                        }


M crates/unified/src/server/player/join.rs => crates/unified/src/server/player/join.rs +8 -5
@@ 7,7 7,9 @@ use crate::server::ConnectedGameEntity;
use crate::server::part::SpawnPartRequest;
use crate::world_config::WorldConfigResource;

fn join_player(joined_player: Entity, mut commands: Commands, wc: &GlobalWorldConfig, planets: Query<(&Transform, &Planet)>, asset_server: &AssetServer) {
fn join_player(joined_player: Entity, mut commands: Commands, wc: &GlobalWorldConfig,
    planets: Query<(&Transform, &LinearVelocity, &Planet)>, asset_server: &AssetServer
) {
    trace!(?joined_player, "detected joined player!");
    // find earth
    if planets.is_empty() {


@@ 15,9 17,9 @@ fn join_player(joined_player: Entity, mut commands: Commands, wc: &GlobalWorldCo
        commands.entity(joined_player).insert(PendingPlayer);
        return;
    }
    let (spawn_planet_pos, spawn_planet) = planets
    let (spawn_planet_pos, spawn_planet_vel, spawn_planet) = planets
        .iter()
        .find(|p| p.1.name == wc.hearty.spawn_at)
        .find(|p| p.2.name == wc.hearty.spawn_at)
        .unwrap_or_else(|| {
            panic!(
                "spawn planet {} is missing? (check that the planet is named exactly '{}')",


@@ 48,6 50,7 @@ fn join_player(joined_player: Entity, mut commands: Commands, wc: &GlobalWorldCo
        .insert(Player {
            client: joined_player,
        })
        .insert(*spawn_planet_vel)
        .remove::<PendingPlayer>();
}



@@ 59,7 62,7 @@ pub fn handle_new_players(
    mut commands: Commands,
    q_new_clients: Query<(Entity, &ConnectedGameEntity), Added<ConnectedGameEntity>>,
    world_config: Res<WorldConfigResource>,
    planets: Query<(&Transform, &Planet)>,
    planets: Query<(&Transform, &LinearVelocity, &Planet)>,
    mut hi_writer: MessageWriter<ToClients<Hi>>,
    asset_server: Res<AssetServer>,
) {


@@ 87,7 90,7 @@ pub fn handle_pending_players(
    mut commands: Commands,
    pending_players: Query<Entity, With<PendingPlayer>>,
    world_config: Res<WorldConfigResource>,
    planets: Query<(&Transform, &Planet)>,
    planets: Query<(&Transform, &LinearVelocity, &Planet)>,
    asset_server: Res<AssetServer>,
) {
    let Some(wc) = &world_config.config else {