~starkingdoms/starkingdoms

ea69ba5aab7133cd404706ac280f061b89ed7fb2 — core 5 months ago ac4be98
feat: indicators
M Cargo.lock => Cargo.lock +1 -0
@@ 7658,6 7658,7 @@ dependencies = [
 "console_error_panic_hook",
 "getrandom 0.3.3",
 "log",
 "ordered-float 5.0.0",
 "rand 0.9.1",
 "serde",
 "tracing-subscriber",

M crates/unified/Cargo.toml => crates/unified/Cargo.toml +2 -0
@@ 51,6 51,8 @@ aeronet_websocket = { version = "0.14", features = ["client"] }

bevy_enoki = "0.4"

ordered-float = "5"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]

[target.'cfg(target_arch = "wasm32")'.dependencies]

M crates/unified/assets/config/planets.pc.toml => crates/unified/assets/config/planets.pc.toml +3 -0
@@ 22,6 22,7 @@ default_transform = [216_999.6, 0.0, 0.0]
[[planets]]
name = "Earth"
sprite = "textures/earth.png"
indicator_sprite = "textures/earth_icon.png"
radius = 1000.0 # m
mass = 10_000.0 # kg
default_transform = [300_000.0, 0.0, 0.0]


@@ 29,6 30,7 @@ default_transform = [300_000.0, 0.0, 0.0]
[[planets]]
name = "Moon"
sprite = "textures/moon.png"
indicator_sprite = "textures/moon_icon.png"
radius = 272.7 # m
mass = 123.082_143_245 # kg
default_transform = [301_541.4, 0.0, 0.0]


@@ 36,6 38,7 @@ default_transform = [301_541.4, 0.0, 0.0]
[[planets]]
name = "Mars"
sprite = "textures/mars.png"
indicator_sprite = "textures/mars_icon.png"
radius = 531.0 # m
mass = 1_070.519_602 # kg
default_transform = [457_100.0, 0.0, 0.0]

M crates/unified/src/client/mod.rs => crates/unified/src/client/mod.rs +4 -3
@@ 1,15 1,15 @@
mod colors;
mod incoming_particles;
mod incoming_parts;
mod incoming_planets;
mod key_input;
mod net;
mod starfield;
mod ui;
mod planet;

use crate::client::incoming_particles::replicated_particles_plugin;
use crate::client::incoming_parts::incoming_parts_plugin;
use crate::client::incoming_planets::incoming_planets_plugin;
use planet::incoming_planets::incoming_planets_plugin;
use crate::client::key_input::key_input_plugin;
use crate::client::starfield::starfield_plugin;
use crate::client::ui::ui_plugin;


@@ 19,6 19,7 @@ use bevy::core_pipeline::fxaa::Fxaa;
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use bevy_replicon::shared::server_entity_map::ServerEntityMap;
use crate::client::planet::indicators::indicators_plugin;

pub struct ClientPlugin {
    pub server: String,


@@ 41,7 42,7 @@ impl Plugin for ClientPlugin {
            .add_systems(Update, update_cursor_position)
            .add_systems(Update, follow_camera)
            .add_systems(Update, find_me)
            .add_plugins(incoming_planets_plugin)
            .add_plugins((incoming_planets_plugin, indicators_plugin))
            .add_plugins(incoming_parts_plugin)
            .add_plugins(key_input_plugin)
            .add_plugins(starfield_plugin)

R crates/unified/src/client/incoming_planets.rs => crates/unified/src/client/planet/incoming_planets.rs +0 -0
A crates/unified/src/client/planet/indicators.rs => crates/unified/src/client/planet/indicators.rs +65 -0
@@ 0,0 1,65 @@
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use ordered_float::OrderedFloat;
use crate::client::Me;
use crate::config::planet::Planet;

pub fn indicators_plugin(app: &mut App) {
    app.add_systems(PreUpdate, (add_indicators, update_indicators))
        .add_systems(Update, update_indicators_position);
}

#[derive(Component)]
struct PlanetIndicator(String);
#[derive(Component)]
struct HasIndicator(Entity);

fn add_indicators(planets_wo_indicators: Query<(Entity, &Planet), Without<HasIndicator>>, player: Query<Entity, With<Me>>, asset_server: Res<AssetServer>, mut commands: Commands) {
    let Ok(me) = player.single() else { return; };
    for (planet, planet_data) in &planets_wo_indicators {
        let Some(indicator_url) = &planet_data.indicator_sprite else { continue };
        let mut sprite = Sprite::from_image(asset_server.load(indicator_url));
        sprite.custom_size = Some(Vec2::new(50.0, 50.0));
        let indicator = commands.spawn((
            ChildOf(me),
            PlanetIndicator(planet_data.name.clone()),
            sprite,
            Transform::from_xyz(0.0, 0.0, 0.0)
        )).id();
        commands.entity(planet).insert(HasIndicator(indicator));
    }
}
fn update_indicators(changed_planets_w_indicators: Query<(&Planet, &HasIndicator), Changed<Planet>>, asset_server: Res<AssetServer>, mut commands: Commands) {
    for (planet_data, indicator) in changed_planets_w_indicators.iter() {
        let Some(indicator_sprite) = &planet_data.indicator_sprite else { continue; };
        let mut sprite = Sprite::from_image(asset_server.load(indicator_sprite));
        sprite.custom_size = Some(Vec2::new(50.0, 50.0));
        commands.entity(indicator.0)
            .remove::<Sprite>()
            .insert(sprite);
    }
}
fn update_indicators_position(
    planets_w_indicator: Query<(&Transform, &HasIndicator), Without<PlanetIndicator>>,
    player: Query<&Transform, (With<Me>, Without<PlanetIndicator>)>,
    mut indicators: Query<(&mut Transform), (With<PlanetIndicator>, Without<HasIndicator>, Without<Me>)>,
    window: Query<&Window, With<PrimaryWindow>>,
)
{
    let Ok(player_position) = player.single() else { return; };
    let window = window.single().unwrap();

    for (planet_position, indicator_id) in &planets_w_indicator {
        let mut offset = planet_position.translation - player_position.translation;
        let half_window_height = window.height() / 2.0 - 25.0;
        let half_window_width = window.width() / 2.0 - 25.0;
        offset.x = offset.x.clamp(-half_window_width, half_window_width);
        offset.y = offset.y.clamp(-half_window_height, half_window_height);

        let Ok(mut this_indicator) = indicators.get_mut(indicator_id.0) else { continue; };

        let inv_rot = player_position.rotation.inverse();
        this_indicator.translation = inv_rot.mul_vec3(Vec3::new(offset.x, offset.y, 0.0));
        this_indicator.rotation = inv_rot;
    }
}
\ No newline at end of file

A crates/unified/src/client/planet/mod.rs => crates/unified/src/client/planet/mod.rs +2 -0
@@ 0,0 1,2 @@
pub mod incoming_planets;
pub mod indicators;
\ No newline at end of file

M crates/unified/src/config/planet.rs => crates/unified/src/config/planet.rs +1 -0
@@ 8,6 8,7 @@ use serde::{Deserialize, Serialize};
pub struct Planet {
    pub name: String,
    pub sprite: String,
    pub indicator_sprite: Option<String>,
    pub radius: f32,
    pub mass: f32,
    pub default_transform: [f32; 3],

M crates/unified/src/server/player.rs => crates/unified/src/server/player.rs +4 -4
@@ 81,7 81,7 @@ fn handle_new_players(
                (
                    Particles {
                        effect: "particles/ship_thruster.particle.ron".to_string(),
                        active: true
                        active: false
                    },
                    Transform::from_xyz(
                        -wc.part.default_width / 2.0 + 5.0,


@@ 95,7 95,7 @@ fn handle_new_players(
                (
                    Particles {
                        effect: "particles/ship_thruster.particle.ron".to_string(),
                        active: true
                        active: false
                    },
                    Transform::from_xyz(
                        wc.part.default_width / 2.0 - 5.0,


@@ 109,7 109,7 @@ fn handle_new_players(
                (
                    Particles {
                        effect: "particles/ship_thruster.particle.ron".to_string(),
                        active: true
                        active: false
                    },
                    Transform::from_xyz(
                        -wc.part.default_width / 2.0 + 5.0,


@@ 122,7 122,7 @@ fn handle_new_players(
                (
                    Particles {
                        effect: "particles/ship_thruster.particle.ron".to_string(),
                        active: true
                        active: false
                    },
                    Transform::from_xyz(
                        wc.part.default_width / 2.0 - 5.0,