~starkingdoms/starkingdoms

56611596a79075bf62c8ec3fa4f3607b79bb7045 — core 5 months ago 82e5a5f
feat: mod spawning
M Cargo.lock => Cargo.lock +1 -0
@@ 7647,6 7647,7 @@ version = "0.1.0"
dependencies = [
 "aeronet",
 "aeronet_replicon",
 "aeronet_transport",
 "aeronet_websocket",
 "bevy 0.16.1",
 "bevy_common_assets",

M crates/unified/Cargo.toml => crates/unified/Cargo.toml +1 -0
@@ 44,6 44,7 @@ getrandom = { version = "0.3", features = [] }
aeronet = "0.14"
aeronet_replicon = { version = "0.15", features = ["client"] }
aeronet_websocket = { version = "0.14", features = ["client"] }
aeronet_transport = "0.14"

bevy_enoki = "0.4"


M crates/unified/assets/config/world.wc.toml => crates/unified/assets/config/world.wc.toml +2 -0
@@ 1,5 1,7 @@
[world]
gravity = 2
spawn_parts_at = "Earth"
spawn_parts_interval_secs = 10

[part]
default_height = 50

M crates/unified/src/client/incoming_parts.rs => crates/unified/src/client/incoming_parts.rs +2 -2
@@ 26,7 26,7 @@ fn handle_incoming_parts(
            }))
            .insert(ReadMassProperties::default())
            .insert(RigidBody::Dynamic);
        info!(?new_part, "prepared new part");
        info!(?new_part, ?new_entity, "prepared new part");
    }
}
fn handle_updated_parts(


@@ 48,6 48,6 @@ fn handle_updated_parts(
                mass: updated_part.mass,
                principal_inertia: 7.5,
            }));
        info!(?updated_part, "updated part");
        info!(?updated_part, ?updated_entity, "updated part");
    }
}

M crates/unified/src/client/mod.rs => crates/unified/src/client/mod.rs +2 -0
@@ 23,6 23,7 @@ use bevy::core_pipeline::tonemapping::DebandDither;
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use bevy_replicon::shared::server_entity_map::ServerEntityMap;
use crate::client::net::set_config;
use crate::client::planet::indicators::indicators_plugin;

pub struct ClientPlugin {


@@ 46,6 47,7 @@ impl Plugin for ClientPlugin {
            .add_systems(Update, update_cursor_position)
            .add_systems(Update, follow_camera)
            .add_systems(Update, find_me)
            .add_systems(Update, set_config)
            .add_plugins((incoming_planets_plugin, indicators_plugin))
            .add_plugins(incoming_parts_plugin)
            .add_plugins(key_input_plugin)

M crates/unified/src/client/net.rs => crates/unified/src/client/net.rs +8 -0
@@ 1,8 1,16 @@
use aeronet::io::connection::Disconnected;
use aeronet::io::{Session, SessionEndpoint};
use aeronet_replicon::client::AeronetRepliconClient;
use aeronet_transport::TransportConfig;
use bevy::prelude::*;

pub fn set_config(mut q: Query<&mut TransportConfig, Added<TransportConfig>>) {
    for mut q in q.iter_mut() {
        q.max_memory_usage = 8388608; // 8 MiB
    }
}


pub fn on_connecting(
    trigger: Trigger<OnAdd, SessionEndpoint>,
    names: Query<&Name>,

M crates/unified/src/client/planet/indicators.rs => crates/unified/src/client/planet/indicators.rs +14 -7
@@ 2,10 2,11 @@ use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use crate::client::Me;
use crate::config::planet::Planet;
use crate::ecs::{MainCamera, StarfieldBack, StarfieldFront, StarfieldMid};

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

#[derive(Component)]


@@ 18,7 19,7 @@ fn add_indicators(planets_wo_indicators: Query<(Entity, &Planet), Without<HasInd
    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));
        sprite.custom_size = Some(Vec2::new(25.0, 25.0));
        let indicator = commands.spawn((
            ChildOf(me),
            PlanetIndicator(planet_data.name.clone()),


@@ 41,21 42,27 @@ fn update_indicators(changed_planets_w_indicators: Query<(&Planet, &HasIndicator
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>)>,
    mut indicators: Query<(&mut Transform, &mut Sprite), (With<PlanetIndicator>, Without<HasIndicator>, Without<Me>, Without<MainCamera>)>,
    window: Query<&Window, With<PrimaryWindow>>,
    camera: Single<&Transform, (With<MainCamera>, Without<PlanetIndicator>)>,
)
{
    let Ok(player_position) = player.single() else { return; };
    let window = window.single().unwrap();
    let Ok(window) = window.single() else { return };

    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;

        let sprite_size = 25.0 * camera.scale.z;

        let half_window_height = window.height() * camera.scale.z / 2.0 - (sprite_size / 2.0);
        let half_window_width = window.width() * camera.scale.z / 2.0 - (sprite_size / 2.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 Ok((mut this_indicator, mut this_sprite)) = indicators.get_mut(indicator_id.0) else { continue; };

        this_sprite.custom_size = Some(Vec2::splat(sprite_size));

        let inv_rot = player_position.rotation.inverse();
        this_indicator.translation = inv_rot.mul_vec3(Vec3::new(offset.x, offset.y, 0.0));

M crates/unified/src/config/world.rs => crates/unified/src/config/world.rs +2 -0
@@ 12,6 12,8 @@ pub struct GlobalWorldConfig {
#[derive(Deserialize, Asset, TypePath, Clone)]
pub struct WorldConfig {
    pub gravity: f32,
    pub spawn_parts_at: String,
    pub spawn_parts_interval_secs: f32
}

#[derive(Deserialize, Asset, TypePath, Clone)]

M crates/unified/src/particle/mod.rs => crates/unified/src/particle/mod.rs +7 -5
@@ 1,4 1,4 @@
use bevy::color::{Color, ColorCurve};
use bevy::color::{Color, ColorCurve, LinearRgba};
use bevy::math::cubic_splines::LinearSpline;
use bevy::math::Vec2;
use rand::Rng;


@@ 24,15 24,16 @@ pub struct ParticleEffect {

    // -- scale -- //

    /// Scale curve over the lifetime of the particle
    pub scale: LinearSpline<f32>,
    // Scale curve over the lifetime of the particle
    //pub scale: LinearSpline<f32>,

    // -- color -- //

    /// Color curve over the lifetime of the particle
    pub color: LinearSpline<Color>,
    // Color curve over the lifetime of the particle
    //pub color: LinearSpline<LinearRgba>,
}

#[derive(Deserialize, Serialize)]
pub struct RandF32 {
    pub value: f32,
    pub randomness: f32


@@ 43,6 44,7 @@ impl RandF32 {
    }
}

#[derive(Deserialize, Serialize)]
pub struct RandVec2 {
    pub x: RandF32,
    pub y: RandF32,

A crates/unified/src/server/earth_parts.rs => crates/unified/src/server/earth_parts.rs +76 -0
@@ 0,0 1,76 @@
use std::time::Duration;
use bevy::app::App;
use bevy::math::Vec2;
use bevy::prelude::{Commands, Query, Res, Transform};
use bevy::time::{Real, Time};
use bevy_rapier2d::dynamics::{AdditionalMassProperties, ExternalForce, MassProperties};
use bevy_rapier2d::geometry::Collider;
use bevy_replicon::prelude::Replicated;
use crate::config::planet::Planet;
use crate::ecs::{Part, PartBundle, Player, PlayerThrust};
use crate::server::world_config::WorldConfigResource;
use bevy::prelude::*;

#[derive(Resource, Default)]
struct PartTimerRes {
    timer: Timer
}


pub fn spawn_parts_plugin(app: &mut App) {
    app.init_resource::<PartTimerRes>()
        .add_systems(Update, spawn_parts_on_earth);
}


pub fn spawn_parts_on_earth(
    mut commands: Commands,
    world_config: Res<WorldConfigResource>,
    planets: Query<(&Transform, &Planet)>,
    mut timer: ResMut<PartTimerRes>,
    time: Res<Time>
) {
    let Some(wc) = &world_config.config else {
        return;
    };
    timer.timer.tick(time.delta());

    if !timer.timer.just_finished() {
        return;
    }
    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) else { return; };
    let angle = rand::random::<f32>() * std::f32::consts::TAU;
    let offset = spawn_planet.radius + 150.0;
    let mut new_transform =
        Transform::from_xyz(angle.cos() * offset, angle.sin() * offset, 0.0);
    new_transform.rotate_z(angle);
    new_transform.translation += spawn_planet_pos.translation;

    commands
        .spawn(PartBundle {
            part: Part {
                sprite: "textures/chassis.png".to_string(),
                width: wc.part.default_width,
                height: wc.part.default_height,
                mass: wc.part.default_mass,
            },
            transform: new_transform,
            collider: Collider::cuboid(
                wc.part.default_width / 2.0,
                wc.part.default_height / 2.0,
            ),
            additional_mass_properties: AdditionalMassProperties::MassProperties(
                MassProperties {
                    local_center_of_mass: Vec2::ZERO,
                    mass: wc.part.default_mass,
                    principal_inertia: 7.5,
                },
            ),
        })
        .insert(Replicated);
}
\ No newline at end of file

M crates/unified/src/server/mod.rs => crates/unified/src/server/mod.rs +4 -1
@@ 2,6 2,7 @@ mod gravity;
pub mod planets;
pub mod player;
mod world_config;
mod earth_parts;

use crate::server::gravity::newtonian_gravity_plugin;
use crate::server::planets::planets_plugin;


@@ 15,6 16,7 @@ use aeronet_websocket::server::WebSocketServer;
use bevy::prelude::*;
use bevy_replicon::prelude::Replicated;
use std::net::SocketAddr;
use crate::server::earth_parts::{spawn_parts_on_earth, spawn_parts_plugin};

pub struct ServerPlugin {
    pub bind: SocketAddr,


@@ 41,7 43,8 @@ impl Plugin for ServerPlugin {
            .add_plugins(planets_plugin)
            .add_plugins(world_config_plugin)
            .add_plugins(newtonian_gravity_plugin)
            .add_plugins(player_management_plugin);
            .add_plugins(player_management_plugin)
            .add_plugins(spawn_parts_plugin);
    }
}
impl ServerPlugin {