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 {