From d18ffeae50e20652e18195ae14a3097653a96124 Mon Sep 17 00:00:00 2001 From: core Date: Tue, 8 Jul 2025 21:56:54 -0400 Subject: [PATCH] feat: basic part functionality --- crates/unified/src/client/mod.rs | 2 +- crates/unified/src/client/parts.rs | 17 +++++------- crates/unified/src/config/world.rs | 6 ++--- crates/unified/src/ecs.rs | 19 ++++--------- crates/unified/src/server/part.rs | 43 ++++++++++++++++++++++++++++-- 5 files changed, 56 insertions(+), 31 deletions(-) diff --git a/crates/unified/src/client/mod.rs b/crates/unified/src/client/mod.rs index 91fbea2caa0c6fd51242bfb6dccca1155dc477f4..b0159f71414434f501d2c4fd5359c58400487daf 100644 --- a/crates/unified/src/client/mod.rs +++ b/crates/unified/src/client/mod.rs @@ -70,7 +70,7 @@ fn find_me( commands.entity(entity).insert(Me); let mut heart_sprite = Sprite::from_image(asset_server.load("sprites/hearty_heart.png")); - heart_sprite.custom_size = Some(Vec2::new(part.width, part.height)); + heart_sprite.custom_size = Some(Vec2::new(part.strong_config.physics.width, part.strong_config.physics.height)); heart_sprite.color = Color::srgb(20.0, 0.0, 0.0); commands.spawn(( diff --git a/crates/unified/src/client/parts.rs b/crates/unified/src/client/parts.rs index 9ba845db05b4f40e7138a5f75b7235ec2e9c8a6b..a5c0a4de045b6d3fe8aa128b18d72021b2d107d7 100644 --- a/crates/unified/src/client/parts.rs +++ b/crates/unified/src/client/parts.rs @@ -17,23 +17,19 @@ fn handle_incoming_parts( ) { for (new_entity, new_part) in new_parts.iter() { trace!(?new_entity, ?new_part, "new part"); - let mut sprite = Sprite::from_image(asset_server.load(&new_part.sprite)); - sprite.custom_size = Some(Vec2::new(new_part.width, new_part.height)); + let mut sprite = Sprite::from_image(asset_server.load(&new_part.strong_config.part.sprite_disconnected)); + sprite.custom_size = Some(Vec2::new(new_part.strong_config.physics.width, new_part.strong_config.physics.height)); commands .entity(new_entity) .insert(sprite) .insert(AdditionalMassProperties::MassProperties(MassProperties { local_center_of_mass: Vec2::ZERO, - mass: new_part.mass, + mass: new_part.strong_config.physics.mass, principal_inertia: 7.5, })) - .insert(ReadMassProperties::default()) - .insert(RigidBody::Dynamic) .insert(Pickable::default()) .observe(on_part_click); - - trace!(?new_part, ?new_entity, "prepared new part"); } } fn handle_updated_parts( @@ -42,8 +38,8 @@ fn handle_updated_parts( asset_server: Res, ) { for (updated_entity, updated_part) in updated_parts.iter() { - let mut sprite = Sprite::from_image(asset_server.load(&updated_part.sprite)); - sprite.custom_size = Some(Vec2::new(updated_part.width, updated_part.height)); + let mut sprite = Sprite::from_image(asset_server.load(&updated_part.strong_config.part.sprite_disconnected)); + sprite.custom_size = Some(Vec2::new(updated_part.strong_config.physics.width, updated_part.strong_config.physics.height)); commands .entity(updated_entity) @@ -52,10 +48,9 @@ fn handle_updated_parts( .insert(sprite) .insert(AdditionalMassProperties::MassProperties(MassProperties { local_center_of_mass: Vec2::ZERO, - mass: updated_part.mass, + mass: updated_part.strong_config.physics.mass, principal_inertia: 7.5, })); - trace!(?updated_part, ?updated_entity, "updated part"); } } diff --git a/crates/unified/src/config/world.rs b/crates/unified/src/config/world.rs index d503345c743e36729f4931b0d81d03cf5c5b4d8f..840c39ea16006731a5267f4e8a74c18d9791b235 100644 --- a/crates/unified/src/config/world.rs +++ b/crates/unified/src/config/world.rs @@ -5,7 +5,7 @@ use serde::Deserialize; #[derive(Deserialize, Asset, TypePath, Clone)] pub struct GlobalWorldConfig { pub world: WorldConfig, - pub part: PartConfig, + pub part: WPartConfig, pub hearty: HeartyConfig, } @@ -16,8 +16,8 @@ pub struct WorldConfig { pub spawn_parts_interval_secs: f32, } -#[derive(Deserialize, Asset, TypePath, Clone)] -pub struct PartConfig { +#[derive(Deserialize, Asset, TypePath, Clone, Debug)] +pub struct WPartConfig { pub default_width: f32, pub default_height: f32, pub default_mass: f32, diff --git a/crates/unified/src/ecs.rs b/crates/unified/src/ecs.rs index 09aa73693601bc62d5e3fca927125570985aee8d..483ce1d561c146b7b152ce29119e63c5eeb2e6c2 100644 --- a/crates/unified/src/ecs.rs +++ b/crates/unified/src/ecs.rs @@ -1,12 +1,11 @@ use bevy::ecs::entity::MapEntities; use bevy::math::Vec2; -use bevy::prelude::{Bundle, Component, Entity, Event, Resource, Transform}; -use bevy_rapier2d::dynamics::AdditionalMassProperties; +use bevy::prelude::{Component, Entity, Event, Handle, Resource}; use bevy_rapier2d::dynamics::RigidBody; -use bevy_rapier2d::geometry::Collider; use bevy_rapier2d::prelude::*; use bevy_replicon::prelude::Replicated; use serde::{Deserialize, Serialize}; +use crate::config::part::PartConfig; #[derive(Component)] pub struct MainCamera; @@ -38,18 +37,10 @@ pub enum ThrustEvent { Replicated )] pub struct Part { - pub sprite: String, - pub width: f32, - pub height: f32, - pub mass: f32, -} -#[derive(Bundle)] -pub struct PartBundle { - pub part: Part, - pub transform: Transform, - pub collider: Collider, - pub additional_mass_properties: AdditionalMassProperties, + pub strong_config: PartConfig } +#[derive(Component, Debug)] +pub struct PartHandle(pub Handle); #[derive(Component, Serialize, Deserialize, Debug)] pub struct Player { diff --git a/crates/unified/src/server/part.rs b/crates/unified/src/server/part.rs index 274552578d2a57d2d560bf43f36f135a866558d3..498a7c3ac4ffc5f4a0ec62662517d62f4429e811 100644 --- a/crates/unified/src/server/part.rs +++ b/crates/unified/src/server/part.rs @@ -1,8 +1,47 @@ -use crate::config::world::PartConfig; +use bevy::ecs::system::entity_command::remove; use bevy::prelude::Component; use bevy::prelude::*; +use bevy_rapier2d::prelude::{AdditionalMassProperties, Collider}; +use crate::config::part::PartConfig; +use crate::ecs::{Part, PartHandle}; -pub fn part_management_plugin(_app: &mut App) {} +pub fn part_management_plugin(app: &mut App) { + app.add_systems(PreUpdate, handle_ready_parts); +} + +#[derive(Bundle)] +pub struct SpawnPartBundle { + pub req: SpawnPartRequest, + pub transform: Transform, +} #[derive(Component)] pub struct SpawnPartRequest(pub Handle); + +// wait for parts assets to be ready, then spawn the full part +pub fn handle_ready_parts(loading_parts: Query<(Entity, &SpawnPartRequest)>, mut commands: Commands, assets: Res>) { + for (entity, loading_part) in &loading_parts { + if let Some(strong_config) = assets.get(&loading_part.0) { + // config is strong; spawn 'er in! + commands.entity(entity) + .insert(calculate_bundle(strong_config, &loading_part.0)) + .remove::(); + } + } +} + +fn calculate_bundle(config: &PartConfig, handle: &Handle) -> impl Bundle { + let part = Part { + strong_config: config.clone(), + }; + let part_handle = PartHandle(handle.clone()); + let collider = Collider::cuboid(config.physics.width / 2.0, config.physics.height / 2.0); + let additional_mass_properties = AdditionalMassProperties::Mass(config.physics.mass); + + ( + part, + part_handle, + collider, + additional_mass_properties, + ) +} \ No newline at end of file