~starkingdoms/starkingdoms

8862b7da90a15e913d6a931a6c6aed8f04dc76f7 — core 5 months ago ea69ba5
feat: bloom!
M Cargo.lock => Cargo.lock +0 -4
@@ 7647,7 7647,6 @@ version = "0.1.0"
dependencies = [
 "aeronet",
 "aeronet_replicon",
 "aeronet_transport",
 "aeronet_websocket",
 "bevy 0.16.1",
 "bevy_common_assets",


@@ 7657,15 7656,12 @@ dependencies = [
 "clap",
 "console_error_panic_hook",
 "getrandom 0.3.3",
 "log",
 "ordered-float 5.0.0",
 "rand 0.9.1",
 "serde",
 "tracing-subscriber",
 "tracing-wasm",
 "url",
 "wasm-bindgen",
 "web-time 1.1.0",
]

[[package]]

M crates/unified/Cargo.toml => crates/unified/Cargo.toml +0 -6
@@ 35,24 35,18 @@ clap = { version = "4", features = ["derive", "cargo"] }
url = "2"

tracing-subscriber = "0.3"
log = { version = "*", features = ["max_level_debug", "release_max_level_warn"] }

serde = { version = "1", features = ["derive"] }

rand = "0.9"
getrandom = { version = "0.3", features = [] }

web-time = "1"

aeronet = "0.14"
aeronet_replicon = { version = "0.15", features = ["client"] }
aeronet_transport = "0.14"
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 +1 -0
@@ 4,6 4,7 @@ sprite = "textures/sun.png"
radius = 20_000.0 # m
mass = 16_000_000.0 # kg
default_transform = [0.0, 0.0, 0.0]
special_sprite_properties = { DrawAsCircle = { Oklcha = { lightness = 10.0, chroma = 0.058, hue = 104.26, alpha = 1.0 } } }

[[planets]]
name = "Mercury"

M crates/unified/assets/config/world.wc.toml => crates/unified/assets/config/world.wc.toml +1 -0
@@ 8,3 8,4 @@ default_mass = 100

[hearty]
thrust = 50000
spawn_at = "Earth"
\ No newline at end of file

A crates/unified/assets/textures/hearty_heart.png => crates/unified/assets/textures/hearty_heart.png +0 -0
A crates/unified/assets/vector_textures/hearty_heart.svg => crates/unified/assets/vector_textures/hearty_heart.svg +246 -0
@@ 0,0 1,246 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   width="512"
   height="512"
   viewBox="0 0 135.46666 135.46667"
   version="1.1"
   id="svg5"
   inkscape:export-filename="/home/tm85/prj/stk_sprites/hearty.png"
   inkscape:export-xdpi="96"
   inkscape:export-ydpi="96"
   inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
   sodipodi:docname="hearty_heart.svg"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <sodipodi:namedview
     id="namedview7"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageshadow="2"
     inkscape:pageopacity="0.0"
     inkscape:pagecheckerboard="0"
     inkscape:document-units="mm"
     showgrid="false"
     units="px"
     width="512px"
     showguides="true"
     inkscape:snap-object-midpoints="true"
     inkscape:snap-global="true"
     inkscape:guide-bbox="true"
     inkscape:zoom="1"
     inkscape:cx="309.5"
     inkscape:cy="245"
     inkscape:window-width="1920"
     inkscape:window-height="1055"
     inkscape:window-x="1920"
     inkscape:window-y="25"
     inkscape:window-maximized="1"
     inkscape:current-layer="layer2"
     inkscape:showpageshadow="2"
     inkscape:deskcolor="#d1d1d1" />
  <defs
     id="defs2">
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect17083"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="8"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false"
       nodesatellites_param="F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect16803"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="8"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false"
       nodesatellites_param="F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect15774"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,4.2333333,0,1 @ F,0,0,1,0,4.2333333,0,1 @ F,0,0,1,0,4.2333333,0,1 @ F,0,0,1,0,4.2333333,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="16"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false"
       nodesatellites_param="F,0,0,1,0,4.2333333,0,1 @ F,0,0,1,0,4.2333333,0,1 @ F,0,0,1,0,4.2333333,0,1 @ F,0,0,1,0,4.2333333,0,1" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect15612"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="16"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false"
       nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect15006"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="16"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false"
       nodesatellites_param="F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect12397"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5 | F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5"
       unit="px"
       method="auto"
       mode="F"
       radius="10"
       chamfer_steps="5"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false"
       nodesatellites_param="F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5 | F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect12289"
       is_visible="true"
       lpeversion="1"
       satellites_param="C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5 | C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5"
       unit="px"
       method="auto"
       mode="F"
       radius="10"
       chamfer_steps="5"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false"
       nodesatellites_param="C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5 | C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect12074"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="0"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false"
       nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1" />
    <filter
       inkscape:menu-tooltip="In and out glow with a possible offset and colorizable flood"
       inkscape:menu="Shadows and Glows"
       inkscape:label="Cutout Glow"
       style="color-interpolation-filters:sRGB;"
       id="filter13281"
       x="-0.23629366"
       y="-0.23629366"
       width="1.4725873"
       height="1.4725873">
      <feGaussianBlur
         stdDeviation="29.536707281068317"
         result="blur"
         id="feGaussianBlur13273" />
      <feComposite
         in="flood"
         in2="SourceGraphic"
         operator="in"
         result="composite"
         id="feComposite13277" />
      <feBlend
         in="blur"
         in2="composite"
         mode="normal"
         id="feBlend13279" />
    </filter>
  </defs>
  <g
     inkscape:groupmode="layer"
     id="layer2"
     inkscape:label="Thrusters"
     style="display:inline" />
  <g
     inkscape:label="Body"
     inkscape:groupmode="layer"
     id="layer1"
     style="display:inline">
    <g
       id="use12910"
       transform="matrix(-0.14028033,-0.14028033,0.14028033,-0.14028033,67.733335,98.694702)"
       style="fill:#ff0000;stroke:none;stroke-width:0">
      <path
         d="M 0,200 V 0 h 200 a 100,100 90 0 1 0,200 100,100 90 0 1 -200,0 z"
         id="path13158" />
    </g>
    <g
       id="use12910-2"
       transform="matrix(-0.14028033,-0.14028033,0.14028033,-0.14028033,67.733335,98.694702)"
       style="display:inline;fill:#ff0000;stroke:none;stroke-width:0;filter:url(#filter13281)">
      <path
         d="M 0,200 V 0 h 200 a 100,100 90 0 1 0,200 100,100 90 0 1 -200,0 z"
         id="path13158-7" />
    </g>
  </g>
</svg>

M crates/unified/src/client/key_input.rs => crates/unified/src/client/key_input.rs +15 -3
@@ 3,14 3,26 @@ use bevy::{
    ecs::{event::EventWriter, system::Res},
    input::{ButtonInput, keyboard::KeyCode},
};

use bevy::prelude::ResMut;
use bevy_rapier2d::render::DebugRenderContext;
use crate::ecs::ThrustEvent;

pub fn key_input_plugin(app: &mut App) {
    app.add_systems(Update, directional_keys);
    app.add_systems(Update, directional_keys)
        .add_systems(Update, debug_render_keybind);
}

pub fn directional_keys(
fn debug_render_keybind(
    keys: Res<ButtonInput<KeyCode>>,
    mut debug_render: ResMut<DebugRenderContext>
) {
    if keys.just_pressed(KeyCode::F3) {
        debug_render.enabled = !debug_render.enabled;
    }
}


fn directional_keys(
    keys: Res<ButtonInput<KeyCode>>,
    mut thrust_event: EventWriter<ThrustEvent>,
) {

M crates/unified/src/client/mod.rs => crates/unified/src/client/mod.rs +22 -4
@@ 13,9 13,11 @@ 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;
use crate::ecs::{CursorWorldCoordinates, MainCamera, Player};
use crate::ecs::{CursorWorldCoordinates, MainCamera, Part, Player};
use aeronet_websocket::client::WebSocketClient;
use bevy::core_pipeline::bloom::Bloom;
use bevy::core_pipeline::fxaa::Fxaa;
use bevy::core_pipeline::tonemapping::DebandDither;
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use bevy_replicon::shared::server_entity_map::ServerEntityMap;


@@ 56,14 58,24 @@ pub struct Me;

fn find_me(
    mut commands: Commands,
    q_clients: Query<(Entity, &Player), Added<Player>>,
    q_clients: Query<(Entity, &Player, &Part), Added<Player>>,
    entity_map: Res<ServerEntityMap>,
    asset_server: Res<AssetServer>,
) {
    for (entity, player) in q_clients.iter() {
    for (entity, player, part) in q_clients.iter() {
        let this_id_clientside = entity_map.to_client().get(&player.client).unwrap();
        if *this_id_clientside == entity {
            info!("hi! i've been found!");
            commands.entity(entity).insert(Me);
            let mut heart_sprite = Sprite::from_image(asset_server.load("sprites/heart_sprite.png"));
            heart_sprite.custom_size = Some(Vec2::new(part.width, part.height));
            heart_sprite.color = Color::srgb(20.0, 0.0, 0.0);

            commands.spawn((
                    ChildOf(entity),
                    heart_sprite,
                    Transform::from_xyz(0.0, 0.0, 10.0)
                ));
        }
    }
}


@@ 71,7 83,13 @@ fn find_me(
fn setup_graphics(mut commands: Commands) {
    commands
        .spawn(Camera2d)
        .insert(Camera { ..default() })
        .insert(Camera {
            hdr: true,
            clear_color: ClearColorConfig::Custom(Color::BLACK),
            ..default()
        })
        .insert(Bloom::default())
        .insert(DebandDither::Enabled)
        .insert(Fxaa::default())
        .insert(MainCamera);
}

M crates/unified/src/client/planet/incoming_planets.rs => crates/unified/src/client/planet/incoming_planets.rs +32 -10
@@ 1,4 1,4 @@
use crate::config::planet::Planet;
use crate::config::planet::{Planet, SpecialSpriteProperties};
use bevy::prelude::*;
use bevy_rapier2d::prelude::AdditionalMassProperties;



@@ 10,15 10,26 @@ fn handle_incoming_planets(
    mut commands: Commands,
    new_planets: Query<(Entity, &Planet), Added<Planet>>,
    asset_server: Res<AssetServer>,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>
) {
    for (new_entity, new_planet) in new_planets.iter() {
        let mut sprite = Sprite::from_image(asset_server.load(&new_planet.sprite));
        sprite.custom_size = Some(Vec2::new(new_planet.radius * 2.0, new_planet.radius * 2.0));

        commands
            .entity(new_entity)
            .insert(sprite)
            .insert(AdditionalMassProperties::Mass(new_planet.mass));
        match new_planet.special_sprite_properties {
            Some(SpecialSpriteProperties::ForceColor(c)) => {
                sprite.color = c;
            },
            _ => {}
        }

        let mut commands = commands
            .entity(new_entity);

    commands.insert(AdditionalMassProperties::Mass(new_planet.mass))
    .insert(sprite);

        info!(?new_planet, "prepared new planet");
    }
}


@@ 26,6 37,8 @@ fn handle_updated_planets(
    mut commands: Commands,
    updated_planets: Query<(Entity, &Planet), Changed<Planet>>,
    asset_server: Res<AssetServer>,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>
) {
    for (updated_entity, updated_planet) in updated_planets.iter() {
        let mut sprite = Sprite::from_image(asset_server.load(&updated_planet.sprite));


@@ 34,12 47,21 @@ fn handle_updated_planets(
            updated_planet.radius * 2.0,
        ));

        commands
            .entity(updated_entity)
        match updated_planet.special_sprite_properties {
            Some(SpecialSpriteProperties::ForceColor(c)) => {
                sprite.color = c;
            },
            _ => {}
        }

        let mut commands = commands.entity(updated_entity);
            commands.remove::<AdditionalMassProperties>()
            .insert(AdditionalMassProperties::Mass(updated_planet.mass))
            .remove::<Sprite>()
            .remove::<AdditionalMassProperties>()
            .insert(sprite)
            .insert(AdditionalMassProperties::Mass(updated_planet.mass));
            .insert(sprite);



        info!(?updated_planet, "updated planet");
    }
}

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


M crates/unified/src/client_plugins.rs => crates/unified/src/client_plugins.rs +2 -1
@@ 5,6 5,7 @@ use bevy::DefaultPlugins;
use bevy::app::{PluginGroup, PluginGroupBuilder};
use bevy::log::LogPlugin;
use bevy_enoki::EnokiPlugin;
use bevy_rapier2d::prelude::RapierDebugRenderPlugin;
use bevy_replicon::RepliconPlugins;

pub struct ClientPluginGroup {


@@ 21,6 22,6 @@ impl PluginGroup for ClientPluginGroup {
            .add(ClientPlugin {
                server: self.server,
            })
        //.add(RapierDebugRenderPlugin::default())
            .add(RapierDebugRenderPlugin::default().disabled())
    }
}

M crates/unified/src/config/planet.rs => crates/unified/src/config/planet.rs +8 -0
@@ 1,4 1,5 @@
use bevy::asset::Asset;
use bevy::color::Color;
use bevy::prelude::{Bundle, Component, Transform, TypePath};
use bevy_rapier2d::prelude::{AdditionalMassProperties, Collider, ReadMassProperties, RigidBody};
use serde::{Deserialize, Serialize};


@@ 12,8 13,15 @@ pub struct Planet {
    pub radius: f32,
    pub mass: f32,
    pub default_transform: [f32; 3],
    pub special_sprite_properties: Option<SpecialSpriteProperties>,
}

#[derive(Deserialize, TypePath, Serialize, Clone, Debug)]
pub enum SpecialSpriteProperties {
    ForceColor(Color)
}


#[derive(Bundle)]
pub struct PlanetBundle {
    pub planet: Planet,

M crates/unified/src/config/world.rs => crates/unified/src/config/world.rs +1 -0
@@ 24,4 24,5 @@ pub struct PartConfig {
#[derive(Deserialize, Asset, TypePath, Clone)]
pub struct HeartyConfig {
    pub thrust: f32,
    pub spawn_at: String,
}

M crates/unified/src/server/player.rs => crates/unified/src/server/player.rs +5 -5
@@ 35,16 35,16 @@ fn handle_new_players(
    for joined_player in &q_new_clients {
        info!(?joined_player, "detected joined player!");
        // find earth
        let (earth_pos, earth_planet) = planets
        let (spawn_planet_pos, spawn_planet) = planets
            .iter()
            .find(|p| p.1.name == "Earth")
            .expect("earth is missing? (check that the planet is named 'Earth')");
            .find(|p| p.1.name == wc.hearty.spawn_at)
            .expect(format!("spawn planet {} is missing? (check that the planet is named exactly '{}')", wc.hearty.spawn_at, wc.hearty.spawn_at).as_str());
        let angle = rand::random::<f32>() * std::f32::consts::TAU;
        let offset = earth_planet.radius + 150.0;
        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 += earth_pos.translation;
        new_transform.translation += spawn_planet_pos.translation;

        info!(?new_transform, "set player's position!");