From 54589315a90d94a48978d94420ff0a656d81a2df Mon Sep 17 00:00:00 2001 From: core Date: Sat, 22 Nov 2025 11:36:30 -0500 Subject: [PATCH] feat: thruster metadata --- .../assets/config/parts/chassis.part.toml | 8 ++-- .../assets/config/parts/hearty.part.toml | 15 ++++--- .../assets/config/parts/housing.part.toml | 8 ++-- crates/unified/src/config/part.rs | 18 +++++--- crates/unified/src/ecs.rs | 2 + crates/unified/src/ecs/thruster.rs | 44 +++++++++++++++++++ crates/unified/src/server/mod.rs | 1 + crates/unified/src/server/part.rs | 26 ++++++++++- crates/unified/src/server/thruster/mod.rs | 3 ++ 9 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 crates/unified/src/ecs/thruster.rs create mode 100644 crates/unified/src/server/thruster/mod.rs diff --git a/crates/unified/assets/config/parts/chassis.part.toml b/crates/unified/assets/config/parts/chassis.part.toml index bfec3c4151df1b562f197ab641b9954acaed6b6e..ee79df9895f780a769efc40d27ba9634921f31e8 100644 --- a/crates/unified/assets/config/parts/chassis.part.toml +++ b/crates/unified/assets/config/parts/chassis.part.toml @@ -8,23 +8,23 @@ width = 50 height = 50 mass = 100 -[[joints]] +[[joint]] id = "Top" target = { translation = [ 0.0, 50.0, 0.0 ], rotation = 0.0 } snap = { translation = [ 0.0, 25.0, 0.0 ], rotation = 0.0 } -[[joints]] +[[joint]] id = "Right" target = { translation = [ 50.0, 0.0, 0.0 ], rotation = -90.0 } snap = { translation = [ 25.0, 0.0, 0.0 ], rotation = 0.0 } -[[joints]] +[[joint]] id = "Bottom" target = { translation = [ 0.0, -50.0, 0.0 ], rotation = -180.0 } snap = { translation = [ 0.0, -25.0, 0.0 ], rotation = 0.0 } -[[joints]] +[[joint]] id = "Left" target = { translation = [ -50.0, 0.0, 0.0 ], rotation = -270.0 } snap = { translation = [ -25.0, 0.0, 0.0 ], rotation = 0.0 } \ No newline at end of file diff --git a/crates/unified/assets/config/parts/hearty.part.toml b/crates/unified/assets/config/parts/hearty.part.toml index 96cb585d661679832fafea90eddbb33380d345c9..aa52e9d2b136eb4a6d164294580e8d56b3ef4e0a 100644 --- a/crates/unified/assets/config/parts/hearty.part.toml +++ b/crates/unified/assets/config/parts/hearty.part.toml @@ -8,27 +8,28 @@ width = 50 height = 50 mass = 100 -[thruster] -flow_rate = 0.1 -exhaust_speed = 250 +[[thruster]] +id = "bottom left" +apply_force_at_local = [ -50.0, -50.0 ] +thrust_vector = [ 0.0, 25.0 ] -[[joints]] +[[joint]] id = "Top" target = { translation = [ 0.0, 55.0, 0.0 ], rotation = 0.0 } snap = { translation = [ 0.0, 25.0, 0.0 ], rotation = 0.0 } -[[joints]] +[[joint]] id = "Right" target = { translation = [ 55.0, 0.0, 0.0 ], rotation = -90.0 } snap = { translation = [ 25.0, 0.0, 0.0 ], rotation = 0.0 } -[[joints]] +[[joint]] id = "Bottom" target = { translation = [ 0.0, -55.0, 0.0 ], rotation = -180.0 } snap = { translation = [ 0.0, -25.0, 0.0 ], rotation = 0.0 } -[[joints]] +[[joint]] id = "Left" target = { translation = [ -55.0, 0.0, 0.0 ], rotation = -270.0 } snap = { translation = [ -25.0, 0.0, 0.0 ], rotation = 0.0 } \ No newline at end of file diff --git a/crates/unified/assets/config/parts/housing.part.toml b/crates/unified/assets/config/parts/housing.part.toml index 5a732578e1f720fe5eacdfa78a8a5ab65705eed5..d724dcb93556382169d9c2c27ea00a653a5d4773 100644 --- a/crates/unified/assets/config/parts/housing.part.toml +++ b/crates/unified/assets/config/parts/housing.part.toml @@ -8,23 +8,23 @@ width = 50 height = 50 mass = 50 -[[joints]] +[[joint]] id = "Top" target = { translation = [ 0.0, 55.0, 0.0 ], rotation = 0.0 } snap = { translation = [ 0.0, 25.0, 0.0 ], rotation = 0.0 } -[[joints]] +[[joint]] id = "Right" target = { translation = [ 55.0, 0.0, 0.0 ], rotation = -90.0 } snap = { translation = [ 25.0, 0.0, 0.0 ], rotation = 0.0 } -[[joints]] +[[joint]] id = "Bottom" target = { translation = [ 0.0, -55.0, 0.0 ], rotation = -180.0 } snap = { translation = [ 0.0, -25.0, 0.0 ], rotation = 0.0 } -[[joints]] +[[joint]] id = "Left" target = { translation = [ -55.0, 0.0, 0.0 ], rotation = -270.0 } snap = { translation = [ -25.0, 0.0, 0.0 ], rotation = 0.0 } diff --git a/crates/unified/src/config/part.rs b/crates/unified/src/config/part.rs index f80c4b28cfa470d7b8576c4c0dbcf556ba8e6dfb..75f03c16904f1ab623b59961a757d19157fbe913 100644 --- a/crates/unified/src/config/part.rs +++ b/crates/unified/src/config/part.rs @@ -7,7 +7,11 @@ use serde::{Deserialize, Serialize}; pub struct PartConfig { pub part: PartPartConfig, pub physics: PartPhysicsConfig, - pub thruster: Option, + #[serde(rename = "thruster")] + #[serde(default)] + pub thrusters: Vec, + #[serde(default)] + #[serde(rename = "joint")] pub joints: Vec, } #[derive(Deserialize, TypePath, Serialize, Clone, Debug, PartialEq)] @@ -23,16 +27,18 @@ pub struct PartPhysicsConfig { pub mass: f32, } #[derive(Deserialize, TypePath, Serialize, Clone, Debug, PartialEq)] -pub struct PartThrusterConfig { - pub flow_rate: f32, // kg/s - pub exhaust_speed: f32, // m/s -} -#[derive(Deserialize, TypePath, Serialize, Clone, Debug, PartialEq)] pub struct JointConfig { pub id: String, pub target: JointOffset, pub snap: JointOffset, } +#[derive(Deserialize, TypePath, Serialize, Clone, Debug, PartialEq)] +pub struct ThrusterConfig { + pub id: String, + #[serde(default)] + pub apply_force_at_local: Vec2, + pub thrust_vector: Vec2, +} #[derive(Deserialize, Serialize, Clone, Debug, TypePath, PartialEq, Copy)] pub struct JointOffset { pub translation: Vec3, diff --git a/crates/unified/src/ecs.rs b/crates/unified/src/ecs.rs index 6468ac6c9828092b214e3566337dee95bdca3a6b..fffffa662ea4af938646fced8d8c6b8800f11f8a 100644 --- a/crates/unified/src/ecs.rs +++ b/crates/unified/src/ecs.rs @@ -1,3 +1,5 @@ +pub mod thruster; + use crate::config::part::PartConfig; use bevy::ecs::entity::MapEntities; use bevy::math::{Quat, Vec2}; diff --git a/crates/unified/src/ecs/thruster.rs b/crates/unified/src/ecs/thruster.rs new file mode 100644 index 0000000000000000000000000000000000000000..59424c6c3df4c17dea3af7dd7f368a12e4426a10 --- /dev/null +++ b/crates/unified/src/ecs/thruster.rs @@ -0,0 +1,44 @@ +use std::ops::Deref; +use bevy::ecs::entity::MapEntities; +use bevy::math::Vec2; +use bevy::prelude::Bundle; +use serde::{Deserialize, Serialize}; +use crate::prelude::{ChildOf, Component, Entity, Transform}; + +#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] +pub struct ThrusterId(pub String); +impl ThrusterId { + #[must_use] + pub fn from_part_and_thruster_id(part: impl AsRef, thruster: impl AsRef) -> Self { + Self(format!("{}:{}", part.as_ref(), thruster.as_ref())) + } +} + +#[derive(Component, Serialize, Deserialize, MapEntities)] +#[relationship_target(relationship = ThrusterOfPart, linked_spawn)] +pub struct PartThrusters(#[entities] Vec); +impl Deref for PartThrusters { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Component, Serialize, Deserialize, MapEntities)] +#[relationship(relationship_target = PartThrusters)] +pub struct ThrusterOfPart(#[entities] pub Entity); + +#[derive(Component, Serialize, Deserialize)] +pub struct Thruster { + pub id: ThrusterId, + pub thrust_vector: Vec2 +} + +#[derive(Bundle)] +pub struct ThrusterBundle { + pub thruster: Thruster, + pub transform: Transform, + pub child_of: ChildOf, + pub thruster_of_part: ThrusterOfPart, +} \ No newline at end of file diff --git a/crates/unified/src/server/mod.rs b/crates/unified/src/server/mod.rs index 827e622ee6ee3ee68a1d49596caf13a596e430ec..8183ebe829b177db65308a19060bffb7ff17f750 100644 --- a/crates/unified/src/server/mod.rs +++ b/crates/unified/src/server/mod.rs @@ -5,6 +5,7 @@ pub mod planets; pub mod player; mod system_sets; mod world_config; +mod thruster; use crate::server::earth_parts::spawn_parts_plugin; use crate::server::gravity::newtonian_gravity_plugin; diff --git a/crates/unified/src/server/part.rs b/crates/unified/src/server/part.rs index 1f6077364888957fb68cc11a16268bfb14b75b2e..5af6048f422d4c9b59cd1303cc25fc73b7c811d1 100644 --- a/crates/unified/src/server/part.rs +++ b/crates/unified/src/server/part.rs @@ -3,6 +3,7 @@ use crate::config::part::{JointConfig, PartConfig}; use crate::ecs::{Part, PartHandle}; use crate::prelude::*; use bevy_replicon::prelude::Replicated; +use crate::ecs::thruster::{PartThrusters, Thruster, ThrusterBundle, ThrusterId, ThrusterOfPart}; pub fn part_management_plugin(app: &mut App) { app.add_systems(PreUpdate, (handle_ready_parts, handle_part_reloading)); @@ -31,12 +32,13 @@ fn handle_ready_parts( .insert(calculate_bundle(strong_config, &loading_part.0)) .remove::(); spawn_joints(strong_config, entity, commands.reborrow()); + spawn_thrusters(strong_config, entity, commands.reborrow()); } } } fn handle_part_reloading( - existing_parts: Query<(Entity, &PartHandle, &Joints)>, + existing_parts: Query<(Entity, &PartHandle, &Joints, &PartThrusters)>, joints: Query<(&mut Joint, Option<&Peer>, Entity)>, snaps: Query<(Entity, &SnapOfJoint)>, assets: Res>, @@ -51,6 +53,13 @@ fn handle_part_reloading( commands .entity(existing_part.0) .insert(calculate_bundle(config, &existing_part.1.0)); + + // vaporize all thrusters, then respawn + for thruster in &**existing_part.3 { + commands.entity(*thruster).despawn(); + } + spawn_thrusters(config, existing_part.0, commands.reborrow()); + // update all joints let mut used_joints = vec![]; for joint_id in &**existing_part.2 { @@ -144,3 +153,18 @@ fn spawn_joints(config: &PartConfig, parent: Entity, mut commands: Commands) { commands.spawn(spawn_snap_bundle(joint, &parent, &joint_id)); } } + +fn spawn_thrusters(config: &PartConfig, part: Entity, mut commands: Commands) { + for thruster in &config.thrusters { + commands + .spawn(ThrusterBundle { + thruster: Thruster { + id: ThrusterId::from_part_and_thruster_id(&config.part.name, &thruster.id), + thrust_vector: thruster.thrust_vector, + }, + transform: Transform::from_translation(Vec3::new(thruster.apply_force_at_local.x, thruster.apply_force_at_local.y, 0.0)), + child_of: ChildOf(part), + thruster_of_part: ThrusterOfPart(part), + }); + } +} diff --git a/crates/unified/src/server/thruster/mod.rs b/crates/unified/src/server/thruster/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..212f0965ef35816c229242b610b8ab4a2eeb05ea --- /dev/null +++ b/crates/unified/src/server/thruster/mod.rs @@ -0,0 +1,3 @@ +//! # Thruster solver +//! Given a ship and the desired target vector, solve for the combination of thrusters +//! that will produce as close to the desired target as possible. \ No newline at end of file