M crates/unified/Cargo.toml => crates/unified/Cargo.toml +1 -1
@@ 27,6 27,6 @@ getrandom = { version = "0.3", features = [] }
tokio = { version = "1", features = ["rt-multi-thread"] }
[features]
-default = []
+default = ["native"]
native = ["bevy/file_watcher", "bevy_replicon_renet2/native_transport", "bevy_replicon_renet2/ws_server_transport"]
wasm = ["getrandom/wasm_js", "bevy_replicon_renet2/ws_client_transport"]=
\ No newline at end of file
M crates/unified/src/client/incoming_parts.rs => crates/unified/src/client/incoming_parts.rs +15 -6
@@ 1,19 1,23 @@
+use crate::ecs::Part;
use bevy::prelude::*;
use bevy_rapier2d::dynamics::MassProperties;
use bevy_rapier2d::prelude::{AdditionalMassProperties, ReadMassProperties, RigidBody};
-use crate::config::planet::Planet;
-use crate::ecs::Part;
pub fn incoming_parts_plugin(app: &mut App) {
app.add_systems(Update, (handle_incoming_parts, handle_updated_parts));
}
-fn handle_incoming_parts(mut commands: Commands, mut new_parts: Query<(Entity, &Part), Added<Part>>, asset_server: Res<AssetServer>) {
+fn handle_incoming_parts(
+ mut commands: Commands,
+ new_parts: Query<(Entity, &Part), Added<Part>>,
+ asset_server: Res<AssetServer>,
+) {
for (new_entity, new_part) in new_parts.iter() {
let mut sprite = Sprite::from_image(asset_server.load(&new_part.sprite));
sprite.custom_size = Some(Vec2::new(new_part.width, new_part.height));
- commands.entity(new_entity)
+ commands
+ .entity(new_entity)
.insert(sprite)
.insert(AdditionalMassProperties::MassProperties(MassProperties {
local_center_of_mass: Vec2::ZERO,
@@ 25,12 29,17 @@ fn handle_incoming_parts(mut commands: Commands, mut new_parts: Query<(Entity, &
info!(?new_part, "prepared new part");
}
}
-fn handle_updated_parts(mut commands: Commands, mut updated_parts: Query<(Entity, &Part), Changed<Part>>, asset_server: Res<AssetServer>) {
+fn handle_updated_parts(
+ mut commands: Commands,
+ updated_parts: Query<(Entity, &Part), Changed<Part>>,
+ asset_server: Res<AssetServer>,
+) {
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));
- commands.entity(updated_entity)
+ commands
+ .entity(updated_entity)
.remove::<Sprite>()
.remove::<AdditionalMassProperties>()
.insert(sprite)
M crates/unified/src/client/incoming_planets.rs => crates/unified/src/client/incoming_planets.rs +21 -9
@@ 1,33 1,45 @@
+use crate::config::planet::Planet;
use bevy::prelude::*;
use bevy_rapier2d::prelude::AdditionalMassProperties;
-use crate::config::planet::Planet;
pub fn incoming_planets_plugin(app: &mut App) {
app.add_systems(Update, (handle_incoming_planets, handle_updated_planets));
}
-
-fn handle_incoming_planets(mut commands: Commands, mut new_planets: Query<(Entity, &Planet), Added<Planet>>, asset_server: Res<AssetServer>) {
+fn handle_incoming_planets(
+ mut commands: Commands,
+ new_planets: Query<(Entity, &Planet), Added<Planet>>,
+ asset_server: Res<AssetServer>,
+) {
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));
+ sprite.custom_size = Some(Vec2::new(new_planet.radius * 2.0, new_planet.radius * 2.0));
- commands.entity(new_entity)
+ commands
+ .entity(new_entity)
.insert(sprite)
.insert(AdditionalMassProperties::Mass(new_planet.mass));
info!(?new_planet, "prepared new planet");
}
}
-fn handle_updated_planets(mut commands: Commands, mut updated_planets: Query<(Entity, &Planet), Changed<Planet>>, asset_server: Res<AssetServer>) {
+fn handle_updated_planets(
+ mut commands: Commands,
+ updated_planets: Query<(Entity, &Planet), Changed<Planet>>,
+ asset_server: Res<AssetServer>,
+) {
for (updated_entity, updated_planet) in updated_planets.iter() {
let mut sprite = Sprite::from_image(asset_server.load(&updated_planet.sprite));
- sprite.custom_size = Some(Vec2::new(updated_planet.radius*2.0, updated_planet.radius*2.0));
+ sprite.custom_size = Some(Vec2::new(
+ updated_planet.radius * 2.0,
+ updated_planet.radius * 2.0,
+ ));
- commands.entity(updated_entity)
+ commands
+ .entity(updated_entity)
.remove::<Sprite>()
.remove::<AdditionalMassProperties>()
.insert(sprite)
.insert(AdditionalMassProperties::Mass(updated_planet.mass));
info!(?updated_planet, "updated planet");
}
-}>
\ No newline at end of file
+}
M crates/unified/src/client/key_input.rs => crates/unified/src/client/key_input.rs +5 -1
@@ 1,4 1,8 @@
-use bevy::{app::{App, Update}, ecs::{event::EventWriter, system::Res}, input::{keyboard::KeyCode, ButtonInput}};
+use bevy::{
+ app::{App, Update},
+ ecs::{event::EventWriter, system::Res},
+ input::{ButtonInput, keyboard::KeyCode},
+};
use crate::ecs::ThrustEvent;
M crates/unified/src/client/mod.rs => crates/unified/src/client/mod.rs +101 -76
@@ 1,88 1,105 @@
-mod incoming_planets;
mod incoming_parts;
+mod incoming_planets;
mod key_input;
mod starfield;
-use std::net::{IpAddr, SocketAddr, UdpSocket};
-use std::time::SystemTime;
-use bevy::core_pipeline::bloom::Bloom;
+use crate::client::incoming_parts::incoming_parts_plugin;
+use crate::client::incoming_planets::incoming_planets_plugin;
+use crate::client::key_input::key_input_plugin;
+use crate::client::starfield::starfield_plugin;
+use crate::ecs::{CursorWorldCoordinates, MainCamera, Player};
use bevy::core_pipeline::fxaa::Fxaa;
-use bevy::core_pipeline::tonemapping::Tonemapping;
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
-use bevy_rapier2d::prelude::RigidBody;
-use bevy_replicon::prelude::{ConnectedClient, RepliconChannels};
+use bevy_replicon::prelude::RepliconChannels;
use bevy_replicon::shared::server_entity_map::ServerEntityMap;
-use bevy_replicon_renet2::netcode::{ClientAuthentication, NetcodeClientTransport};
+use bevy_replicon_renet2::RenetChannelsExt;
#[cfg(not(target_arch = "wasm32"))]
use bevy_replicon_renet2::netcode::NativeSocket;
+use bevy_replicon_renet2::netcode::{ClientAuthentication, NetcodeClientTransport};
#[cfg(target_arch = "wasm32")]
-use bevy_replicon_renet2::netcode::{WebSocketClientConfig, WebSocketClient, ClientSocket};
+use bevy_replicon_renet2::netcode::{ClientSocket, WebSocketClient, WebSocketClientConfig};
use bevy_replicon_renet2::renet2::{ConnectionConfig, RenetClient};
-use bevy_replicon_renet2::RenetChannelsExt;
-use crate::client::incoming_parts::incoming_parts_plugin;
-use crate::client::incoming_planets::incoming_planets_plugin;
-use crate::client::key_input::key_input_plugin;
-use crate::client::starfield::starfield_plugin;
-use crate::ecs::{Ball, CursorWorldCoordinates, Ground, MainCamera, Player, SendBallHere};
+use std::net::{IpAddr, SocketAddr, UdpSocket};
+use std::time::SystemTime;
pub struct ClientPlugin {
#[cfg(target_arch = "wasm32")]
pub server: url::Url,
#[cfg(not(target_arch = "wasm32"))]
- pub server: SocketAddr
+ pub server: SocketAddr,
}
impl Plugin for ClientPlugin {
fn build(&self, app: &mut App) {
- let server = self.server.clone();
- app
- .insert_resource(CursorWorldCoordinates(None))
- .add_systems(Startup, move |mut commands: Commands, channels: Res<RepliconChannels>| {
- let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
- let client_id = current_time.as_millis() as u64;
+ let server = self.server;
+ app.insert_resource(CursorWorldCoordinates(None))
+ .add_systems(
+ Startup,
+ move |mut commands: Commands, channels: Res<RepliconChannels>| {
+ let current_time = SystemTime::now()
+ .duration_since(SystemTime::UNIX_EPOCH)
+ .unwrap();
+ let client_id = current_time.as_millis() as u64;
- #[cfg(target_arch = "wasm32")] {
- let socket_config = WebSocketClientConfig {
- server_url: server.clone(),
- };
- let socket = WebSocketClient::new(socket_config).unwrap();
- let client = RenetClient::new(
- ConnectionConfig::from_channels(channels.server_configs(), channels.client_configs()),
- socket.is_reliable()
- );
- let authentication = ClientAuthentication::Unsecure {
- socket_id: 1,
- server_addr: socket.server_address(),
- client_id: current_time.as_millis() as u64,
- user_data: None,
- protocol_id: 0
- };
- let mut transport = NetcodeClientTransport::new(current_time, authentication, socket).unwrap();
- commands.insert_resource(client);
- commands.insert_resource(transport);
- }
- #[cfg(not(target_arch = "wasm32"))] {
- let bind = match server.ip() {
- IpAddr::V4(_) => "127.0.0.1:0",
- IpAddr::V6(_) => "[::1]:0",
- };
- let client_socket = NativeSocket::new(UdpSocket::bind(bind).unwrap()).unwrap();
- let authentication = ClientAuthentication::Unsecure {
- socket_id: 0,
- server_addr: server,
- client_id: current_time.as_millis() as u64,
- user_data: None,
- protocol_id: 0
- };
- let client = RenetClient::new(
- ConnectionConfig::from_channels(channels.server_configs(), channels.client_configs()),
- false
- );
- let mut transport = NetcodeClientTransport::new(current_time, authentication, client_socket).unwrap();
- commands.insert_resource(client);
- commands.insert_resource(transport);
- }
- })
+ #[cfg(target_arch = "wasm32")]
+ {
+ let socket_config = WebSocketClientConfig {
+ server_url: server.clone(),
+ };
+ let socket = WebSocketClient::new(socket_config).unwrap();
+ let client = RenetClient::new(
+ ConnectionConfig::from_channels(
+ channels.server_configs(),
+ channels.client_configs(),
+ ),
+ socket.is_reliable(),
+ );
+ let authentication = ClientAuthentication::Unsecure {
+ socket_id: 1,
+ server_addr: socket.server_address(),
+ client_id: current_time.as_millis() as u64,
+ user_data: None,
+ protocol_id: 0,
+ };
+ let mut transport =
+ NetcodeClientTransport::new(current_time, authentication, socket)
+ .unwrap();
+ commands.insert_resource(client);
+ commands.insert_resource(transport);
+ }
+ #[cfg(not(target_arch = "wasm32"))]
+ {
+ let bind = match server.ip() {
+ IpAddr::V4(_) => "127.0.0.1:0",
+ IpAddr::V6(_) => "[::1]:0",
+ };
+ let client_socket =
+ NativeSocket::new(UdpSocket::bind(bind).unwrap()).unwrap();
+ let authentication = ClientAuthentication::Unsecure {
+ socket_id: 0,
+ server_addr: server,
+ client_id: current_time.as_millis() as u64,
+ user_data: None,
+ protocol_id: 0,
+ };
+ let client = RenetClient::new(
+ ConnectionConfig::from_channels(
+ channels.server_configs(),
+ channels.client_configs(),
+ ),
+ false,
+ );
+ let transport = NetcodeClientTransport::new(
+ current_time,
+ authentication,
+ client_socket,
+ )
+ .unwrap();
+ commands.insert_resource(client);
+ commands.insert_resource(transport);
+ }
+ },
+ )
.add_systems(Startup, setup_graphics)
.add_systems(Update, update_cursor_position)
.add_systems(Update, follow_camera)
@@ 97,8 114,11 @@ impl Plugin for ClientPlugin {
#[derive(Component)]
pub struct Me;
-
-fn find_me(mut commands: Commands, q_clients: Query<(Entity, &Player), Added<Player>>, entity_map: Res<ServerEntityMap>) {
+fn find_me(
+ mut commands: Commands,
+ q_clients: Query<(Entity, &Player), Added<Player>>,
+ entity_map: Res<ServerEntityMap>,
+) {
for (entity, player) in q_clients.iter() {
let this_id_clientside = entity_map.to_client().get(&player.client).unwrap();
if *this_id_clientside == entity {
@@ 107,33 127,38 @@ fn find_me(mut commands: Commands, q_clients: Query<(Entity, &Player), Added<Pla
}
}
-
fn setup_graphics(mut commands: Commands) {
- commands.spawn(Camera2d)
- .insert(Camera {
- ..default()
- })
+ commands
+ .spawn(Camera2d)
+ .insert(Camera { ..default() })
.insert(Fxaa::default())
.insert(MainCamera);
}
-fn follow_camera(mut camera: Query<&mut Transform, (With<MainCamera>, Without<Me>)>, mut player: Query<&Transform, With<Me>>) {
+fn follow_camera(
+ mut camera: Query<&mut Transform, (With<MainCamera>, Without<Me>)>,
+ player: Query<&Transform, With<Me>>,
+) {
let mut camera = camera.single_mut().unwrap();
- let Ok(player) = player.single() else { return; };
+ let Ok(player) = player.single() else {
+ return;
+ };
camera.translation = player.translation;
}
fn update_cursor_position(
q_windows: Query<&Window, With<PrimaryWindow>>,
q_camera: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
- mut coords: ResMut<CursorWorldCoordinates>
+ mut coords: ResMut<CursorWorldCoordinates>,
) {
let (camera, camera_transform) = q_camera.single().unwrap();
let window = q_windows.single().unwrap();
- if let Some(world_position) = window.cursor_position()
+ if let Some(world_position) = window
+ .cursor_position()
.and_then(|cursor| camera.viewport_to_world(camera_transform, cursor).ok())
- .map(|ray| ray.origin.truncate()) {
+ .map(|ray| ray.origin.truncate())
+ {
coords.0 = Some(world_position);
} else {
coords.0 = None;
M crates/unified/src/client/starfield.rs => crates/unified/src/client/starfield.rs +137 -51
@@ 1,14 1,29 @@
-use bevy::{app::{App, Startup, Update}, asset::{AssetEvent, AssetServer, Assets}, color::Color, ecs::{event::EventReader, query::{With, Without}, system::{Commands, Query, Res, ResMut}}, image::Image, math::{Vec2, Vec3}, sprite::{Sprite, SpriteImageMode}, transform::components::Transform, window::{Window, WindowResized}};
+use bevy::{
+ app::{App, Startup, Update},
+ asset::{AssetEvent, AssetServer, Assets},
+ ecs::{
+ event::EventReader,
+ query::{With, Without},
+ system::{Commands, Query, Res},
+ },
+ image::Image,
+ math::{Vec2, Vec3},
+ sprite::{Sprite, SpriteImageMode},
+ transform::components::Transform,
+ window::{Window, WindowResized},
+};
-use crate::{client::Me, ecs::{StarfieldBack, StarfieldFront, StarfieldMid}};
+use crate::{
+ client::Me,
+ ecs::{StarfieldBack, StarfieldFront, StarfieldMid},
+};
const BACK_STARFIELD_SIZE: f32 = 256.0;
const MID_STARFIELD_SIZE: f32 = 384.0;
const FRONT_STARFIELD_SIZE: f32 = 512.0;
pub fn starfield_plugin(app: &mut App) {
- app
- .add_systems(Startup, setup_starfield)
+ app.add_systems(Startup, setup_starfield)
.add_systems(Update, fix_starfield)
.add_systems(Update, resize_starfield)
.add_systems(Update, update_starfield);
@@ 17,53 32,77 @@ pub fn starfield_plugin(app: &mut App) {
pub fn setup_starfield(
mut commands: Commands,
asset_server: Res<AssetServer>,
- window: Query<&Window>
+ window: Query<&Window>,
) {
let starfield_handle = asset_server.load("textures/starfield.png");
let starfield_transp_handle = asset_server.load("textures/starfield_transp.png");
let window = window.iter().next().unwrap();
- commands.spawn(Sprite {
- image: starfield_handle,
- custom_size: Some(window.size() + Vec2::splat(BACK_STARFIELD_SIZE)),
- image_mode: SpriteImageMode::Tiled {
- tile_x: true,
- tile_y: true,
- stretch_value: 1.0,
- },
- ..Default::default()
- })
+ commands
+ .spawn(Sprite {
+ image: starfield_handle,
+ custom_size: Some(window.size() + Vec2::splat(BACK_STARFIELD_SIZE)),
+ image_mode: SpriteImageMode::Tiled {
+ tile_x: true,
+ tile_y: true,
+ stretch_value: 1.0,
+ },
+ ..Default::default()
+ })
.insert(Transform::from_xyz(0.0, 0.0, 5.0))
.insert(StarfieldBack);
- commands.spawn(Sprite {
- image: starfield_transp_handle.clone(),
- custom_size: Some(window.size() + Vec2::splat(MID_STARFIELD_SIZE)),
- image_mode: SpriteImageMode::Tiled {
- tile_x: true,
- tile_y: true,
- stretch_value: 1.0,
- },
- ..Default::default()
- })
+ commands
+ .spawn(Sprite {
+ image: starfield_transp_handle.clone(),
+ custom_size: Some(window.size() + Vec2::splat(MID_STARFIELD_SIZE)),
+ image_mode: SpriteImageMode::Tiled {
+ tile_x: true,
+ tile_y: true,
+ stretch_value: 1.0,
+ },
+ ..Default::default()
+ })
.insert(Transform::from_xyz(0.0, 0.0, 4.5))
.insert(StarfieldMid);
- commands.spawn(Sprite {
- image: starfield_transp_handle,
- custom_size: Some(window.size() + Vec2::splat(FRONT_STARFIELD_SIZE)),
- image_mode: SpriteImageMode::Tiled {
- tile_x: true,
- tile_y: true,
- stretch_value: 1.0,
- },
- ..Default::default()
- })
+ commands
+ .spawn(Sprite {
+ image: starfield_transp_handle,
+ custom_size: Some(window.size() + Vec2::splat(FRONT_STARFIELD_SIZE)),
+ image_mode: SpriteImageMode::Tiled {
+ tile_x: true,
+ tile_y: true,
+ stretch_value: 1.0,
+ },
+ ..Default::default()
+ })
.insert(Transform::from_xyz(0.0, 0.0, 4.0))
.insert(StarfieldFront);
}
pub fn fix_starfield(
- mut starfield_back: Query<&mut Sprite, (With<StarfieldBack>, Without<StarfieldMid>, Without<StarfieldFront>)>,
- mut starfield_mid: Query<&mut Sprite, (With<StarfieldMid>, Without<StarfieldBack>, Without<StarfieldFront>)>,
- mut starfield_front: Query<&mut Sprite, (With<StarfieldFront>, Without<StarfieldBack>, Without<StarfieldMid>)>,
+ mut starfield_back: Query<
+ &mut Sprite,
+ (
+ With<StarfieldBack>,
+ Without<StarfieldMid>,
+ Without<StarfieldFront>,
+ ),
+ >,
+ mut starfield_mid: Query<
+ &mut Sprite,
+ (
+ With<StarfieldMid>,
+ Without<StarfieldBack>,
+ Without<StarfieldFront>,
+ ),
+ >,
+ mut starfield_front: Query<
+ &mut Sprite,
+ (
+ With<StarfieldFront>,
+ Without<StarfieldBack>,
+ Without<StarfieldMid>,
+ ),
+ >,
assets: Res<Assets<Image>>,
mut asset_events: EventReader<AssetEvent<Image>>,
) {
@@ 101,39 140,86 @@ pub fn fix_starfield(
}
pub fn resize_starfield(
- mut starfield_back: Query<&mut Sprite, (With<StarfieldBack>, Without<StarfieldMid>, Without<StarfieldFront>)>,
- mut starfield_mid: Query<&mut Sprite, (With<StarfieldMid>, Without<StarfieldBack>, Without<StarfieldFront>)>,
- mut starfield_front: Query<&mut Sprite, (With<StarfieldFront>, Without<StarfieldBack>, Without<StarfieldMid>)>,
+ mut starfield_back: Query<
+ &mut Sprite,
+ (
+ With<StarfieldBack>,
+ Without<StarfieldMid>,
+ Without<StarfieldFront>,
+ ),
+ >,
+ mut starfield_mid: Query<
+ &mut Sprite,
+ (
+ With<StarfieldMid>,
+ Without<StarfieldBack>,
+ Without<StarfieldFront>,
+ ),
+ >,
+ mut starfield_front: Query<
+ &mut Sprite,
+ (
+ With<StarfieldFront>,
+ Without<StarfieldBack>,
+ Without<StarfieldMid>,
+ ),
+ >,
mut resize_event: EventReader<WindowResized>,
) {
for event in resize_event.read() {
starfield_back.single_mut().unwrap().custom_size =
- Some(Vec2::new(event.width, event.height) + Vec2::splat(BACK_STARFIELD_SIZE*2.0));
+ Some(Vec2::new(event.width, event.height) + Vec2::splat(BACK_STARFIELD_SIZE * 2.0));
starfield_mid.single_mut().unwrap().custom_size =
- Some(Vec2::new(event.width, event.height) + Vec2::splat(MID_STARFIELD_SIZE*2.0));
+ Some(Vec2::new(event.width, event.height) + Vec2::splat(MID_STARFIELD_SIZE * 2.0));
starfield_front.single_mut().unwrap().custom_size =
- Some(Vec2::new(event.width, event.height) + Vec2::splat(FRONT_STARFIELD_SIZE*2.0));
+ Some(Vec2::new(event.width, event.height) + Vec2::splat(FRONT_STARFIELD_SIZE * 2.0));
}
}
pub fn update_starfield(
- mut starfield_back: Query<&mut Transform, (With<StarfieldBack>, Without<Me>, Without<StarfieldMid>, Without<StarfieldFront>)>,
- mut starfield_mid: Query<&mut Transform, (With<StarfieldMid>, Without<Me>, Without<StarfieldBack>, Without<StarfieldFront>)>,
- mut starfield_front: Query<&mut Transform, (With<StarfieldFront>, Without<Me>, Without<StarfieldBack>, Without<StarfieldMid>)>,
+ mut starfield_back: Query<
+ &mut Transform,
+ (
+ With<StarfieldBack>,
+ Without<Me>,
+ Without<StarfieldMid>,
+ Without<StarfieldFront>,
+ ),
+ >,
+ mut starfield_mid: Query<
+ &mut Transform,
+ (
+ With<StarfieldMid>,
+ Without<Me>,
+ Without<StarfieldBack>,
+ Without<StarfieldFront>,
+ ),
+ >,
+ mut starfield_front: Query<
+ &mut Transform,
+ (
+ With<StarfieldFront>,
+ Without<Me>,
+ Without<StarfieldBack>,
+ Without<StarfieldMid>,
+ ),
+ >,
player: Query<&Transform, (With<Me>, Without<StarfieldFront>)>,
) {
- let Some(player) = player.iter().next() else { return };
+ let Some(player) = player.iter().next() else {
+ return;
+ };
let mut starfield_back_pos = starfield_back.single_mut().unwrap();
let mut starfield_mid_pos = starfield_mid.single_mut().unwrap();
let mut starfield_front_pos = starfield_front.single_mut().unwrap();
//starfield_pos.translation = (player.translation / STARFIELD_SIZE).round() * STARFIELD_SIZE;
starfield_back_pos.translation = player.translation
- + (-player.translation/3.0) % BACK_STARFIELD_SIZE
+ + (-player.translation / 3.0) % BACK_STARFIELD_SIZE
- Vec3::new(0.0, 0.0, 5.0);
starfield_mid_pos.translation = player.translation
- + (-player.translation/2.5) % MID_STARFIELD_SIZE
+ + (-player.translation / 2.5) % MID_STARFIELD_SIZE
- Vec3::new(0.0, 0.0, 4.5);
starfield_front_pos.translation = player.translation
- + (-player.translation/2.0) % FRONT_STARFIELD_SIZE
+ + (-player.translation / 2.0) % FRONT_STARFIELD_SIZE
- Vec3::new(0.0, 0.0, 4.0);
}
M crates/unified/src/client_plugins.rs => crates/unified/src/client_plugins.rs +10 -15
@@ 1,31 1,26 @@
-use std::net::SocketAddr;
-use bevy::app::{PluginGroup, PluginGroupBuilder};
+use crate::client::ClientPlugin;
use bevy::DefaultPlugins;
+use bevy::app::{PluginGroup, PluginGroupBuilder};
use bevy::log::LogPlugin;
-use bevy_rapier2d::render::RapierDebugRenderPlugin;
use bevy_replicon::RepliconPlugins;
use bevy_replicon_renet2::RepliconRenetClientPlugin;
-use crate::client::ClientPlugin;
+use std::net::SocketAddr;
pub struct ClientPluginGroup {
#[cfg(target_arch = "wasm32")]
pub server: url::Url,
#[cfg(not(target_arch = "wasm32"))]
- pub server: SocketAddr
+ pub server: SocketAddr,
}
impl PluginGroup for ClientPluginGroup {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<Self>()
- .add_group(
- DefaultPlugins
- .build()
- .disable::<LogPlugin>()
- )
- .add_group(
- RepliconPlugins
- )
+ .add_group(DefaultPlugins.build().disable::<LogPlugin>())
+ .add_group(RepliconPlugins)
.add(RepliconRenetClientPlugin)
- .add(ClientPlugin { server: self.server })
- //.add(RapierDebugRenderPlugin::default())
+ .add(ClientPlugin {
+ server: self.server,
+ })
+ //.add(RapierDebugRenderPlugin::default())
}
}
M crates/unified/src/config/mod.rs => crates/unified/src/config/mod.rs +1 -1
@@ 1,2 1,2 @@
+pub mod planet;
pub mod world;
-pub mod planet;>
\ No newline at end of file
M crates/unified/src/config/planet.rs => crates/unified/src/config/planet.rs +3 -8
@@ 1,20 1,16 @@
use bevy::asset::Asset;
-use bevy::math::Vec3;
use bevy::prelude::{Bundle, Component, Transform, TypePath};
use bevy_rapier2d::prelude::{AdditionalMassProperties, Collider, ReadMassProperties, RigidBody};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Asset, TypePath, Component, Serialize, Clone, Debug)]
-#[require(
- ReadMassProperties,
- RigidBody::Fixed
-)]
+#[require(ReadMassProperties, RigidBody::Fixed)]
pub struct Planet {
pub name: String,
pub sprite: String,
pub radius: f32,
pub mass: f32,
- pub default_transform: [f32; 3]
+ pub default_transform: [f32; 3],
}
#[derive(Bundle)]
@@ 25,8 21,7 @@ pub struct PlanetBundle {
pub additional_mass_properties: AdditionalMassProperties,
}
-
#[derive(Deserialize, Asset, TypePath)]
pub struct PlanetConfigCollection {
pub planets: Vec<Planet>,
-}>
\ No newline at end of file
+}
M crates/unified/src/config/world.rs => crates/unified/src/config/world.rs +2 -2
@@ 11,14 11,14 @@ pub struct GlobalWorldConfig {
#[derive(Deserialize, Asset, TypePath, Clone)]
pub struct WorldConfig {
- pub gravity: f32
+ pub gravity: f32,
}
#[derive(Deserialize, Asset, TypePath, Clone)]
pub struct PartConfig {
pub default_width: f32,
pub default_height: f32,
- pub default_mass: f32
+ pub default_mass: f32,
}
#[derive(Deserialize, Asset, TypePath, Clone)]
M crates/unified/src/ecs.rs => crates/unified/src/ecs.rs +2 -3
@@ 1,7 1,6 @@
use bevy::math::Vec2;
use bevy::prelude::{Bundle, Component, Entity, Event, Resource, Transform};
use bevy_rapier2d::dynamics::AdditionalMassProperties;
-use bevy_replicon::prelude::Replicated;
use bevy_rapier2d::dynamics::RigidBody;
use bevy_rapier2d::geometry::Collider;
use bevy_rapier2d::prelude::*;
@@ 39,7 38,7 @@ pub struct Part {
pub sprite: String,
pub width: f32,
pub height: f32,
- pub mass: f32
+ pub mass: f32,
}
#[derive(Bundle)]
pub struct PartBundle {
@@ 51,7 50,7 @@ pub struct PartBundle {
#[derive(Component, Serialize, Deserialize, Debug)]
pub struct Player {
- pub client: Entity
+ pub client: Entity,
}
#[derive(Component, Default, Serialize, Deserialize, Debug)]
M crates/unified/src/main.rs => crates/unified/src/main.rs +24 -22
@@ 1,22 1,21 @@
-pub mod server_plugins;
-pub mod shared_plugins;
-pub mod server;
pub mod client;
-pub mod ecs;
pub mod client_plugins;
pub mod config;
+pub mod ecs;
+pub mod server;
+pub mod server_plugins;
+pub mod shared_plugins;
+use crate::client_plugins::ClientPluginGroup;
+use crate::server_plugins::ServerPluginGroup;
+use crate::shared_plugins::SharedPluginGroup;
+use bevy::log::{Level, tracing_subscriber};
+use bevy::prelude::*;
+use clap::Parser;
use std::net::SocketAddr;
use std::process::exit;
-use bevy::log::{tracing_subscriber, Level, LogPlugin};
-use clap::Parser;
-use bevy::prelude::*;
use tracing_subscriber::EnvFilter;
-use tracing_subscriber::filter::Directive;
use tracing_subscriber::util::SubscriberInitExt;
-use crate::client_plugins::ClientPluginGroup;
-use crate::server_plugins::ServerPluginGroup;
-use crate::shared_plugins::SharedPluginGroup;
#[derive(Parser, Debug)]
#[command(version, about)]
@@ 27,7 26,7 @@ enum Cli {
server: url::Url,
#[cfg(not(target_arch = "wasm32"))]
#[arg(short, long)]
- server: SocketAddr
+ server: SocketAddr,
},
Server {
#[arg(short = 'w', long)]
@@ 37,8 36,8 @@ enum Cli {
#[arg(short = 'r', long)]
tick_rate: f64,
#[arg(short = 'C', long)]
- max_clients: usize
- }
+ max_clients: usize,
+ },
}
fn main() -> AppExit {
@@ 55,18 54,21 @@ fn main() -> AppExit {
.add_directive("bevy_replicon=warn".parse().unwrap())
.add_directive("bevy_replicon_renet2=warn".parse().unwrap())
.add_directive("naga=warn".parse().unwrap())
- .add_directive("wgpu_hal::vulkan=error".parse().unwrap())
+ .add_directive("wgpu_hal::vulkan=error".parse().unwrap()),
)
.finish()
.init();
match cli {
Cli::Client { server } => {
- app.add_plugins(ClientPluginGroup {
- server
- });
- },
- Cli::Server { bind_ws, bind_native, tick_rate, max_clients } => {
+ app.add_plugins(ClientPluginGroup { server });
+ }
+ Cli::Server {
+ bind_ws,
+ bind_native,
+ tick_rate,
+ max_clients,
+ } => {
if cfg!(target_family = "wasm") {
eprintln!("the server cannot run on webassembly");
exit(1);
@@ 76,7 78,7 @@ fn main() -> AppExit {
bind_ws,
bind_native,
tick_rate,
- max_clients
+ max_clients,
});
}
}
@@ 84,4 86,4 @@ fn main() -> AppExit {
app.add_plugins(SharedPluginGroup);
app.run()
-}>
\ No newline at end of file
+}
M crates/unified/src/server/gravity.rs => crates/unified/src/server/gravity.rs +11 -8
@@ 1,9 1,9 @@
-use bevy::math::FloatPow;
-use bevy::prelude::*;
-use bevy_rapier2d::prelude::*;
use crate::config::planet::Planet;
use crate::ecs::Part;
use crate::server::world_config::WorldConfigResource;
+use bevy::math::FloatPow;
+use bevy::prelude::*;
+use bevy_rapier2d::prelude::*;
pub fn newtonian_gravity_plugin(app: &mut App) {
app.add_systems(Update, update_gravity);
@@ 15,16 15,18 @@ fn update_gravity(
&Transform,
&ReadMassProperties,
&mut ExternalForce,
- &mut ExternalImpulse
+ &mut ExternalImpulse,
),
- With<Part>
+ With<Part>,
>,
planet_query: Query<(&Transform, &ReadMassProperties), With<Planet>>,
world_config: Res<WorldConfigResource>,
) {
- let Some(world_config) = &world_config.config else { return; };
+ let Some(world_config) = &world_config.config else {
+ return;
+ };
- for (part_transform, part_mass, mut forces, mut impulses) in &mut part_query {
+ for (part_transform, part_mass, mut forces, impulses) in &mut part_query {
let part_mass = part_mass.mass;
let part_translation = part_transform.translation;
@@ 34,7 36,8 @@ fn update_gravity(
let distance = planet_translation.distance(part_translation);
- let force = world_config.world.gravity * ((part_mass * planet_mass) / distance.squared());
+ let force =
+ world_config.world.gravity * ((part_mass * planet_mass) / distance.squared());
let direction = (planet_translation - part_translation).normalize() * force;
forces.force += direction.xy();
}
M crates/unified/src/server/mod.rs => crates/unified/src/server/mod.rs +54 -43
@@ 1,25 1,27 @@
+mod gravity;
pub mod planets;
pub mod player;
mod world_config;
-mod gravity;
+use bevy::prelude::*;
+use bevy_replicon::prelude::RepliconChannels;
+use bevy_replicon_renet2::netcode::{
+ BoxedSocket, NetcodeServerTransport, ServerAuthentication, ServerSetupConfig,
+};
use std::net::{SocketAddr, UdpSocket};
use std::time::{SystemTime, UNIX_EPOCH};
-use bevy::prelude::*;
-use bevy_rapier2d::prelude::{Collider, Restitution, RigidBody, Velocity};
-use bevy_replicon::prelude::{FromClient, Replicated, RepliconChannels};
-use bevy_replicon_renet2::netcode::{NetcodeServerTransport, ServerAuthentication, ServerSetupConfig, BoxedSocket};
#[cfg(not(target_arch = "wasm32"))]
-use bevy_replicon_renet2::netcode::{NativeSocket, WebSocketAcceptor, WebSocketServerConfig, WebSocketServer};
+use bevy_replicon_renet2::netcode::{
+ NativeSocket, WebSocketAcceptor, WebSocketServer, WebSocketServerConfig,
+};
-use bevy_replicon_renet2::renet2::{ConnectionConfig, RenetServer};
-use bevy_replicon_renet2::RenetChannelsExt;
-use crate::ecs::{Ball, Ground, SendBallHere};
use crate::server::gravity::newtonian_gravity_plugin;
use crate::server::planets::planets_plugin;
use crate::server::player::player_management_plugin;
use crate::server::world_config::world_config_plugin;
+use bevy_replicon_renet2::RenetChannelsExt;
+use bevy_replicon_renet2::renet2::{ConnectionConfig, RenetServer};
pub struct ServerPlugin {
pub bind_ws: SocketAddr,
@@ 28,48 30,57 @@ pub struct ServerPlugin {
}
impl Plugin for ServerPlugin {
fn build(&self, app: &mut App) {
- let bind_ws = self.bind_ws.clone();
- let bind_native = self.bind_native.clone();
- let max_clients = self.max_clients.clone();
-
- app
- .add_systems(FixedPreUpdate, bevy_replicon::server::increment_tick) // !!important!! do not remove or move
- .add_systems(Startup, move |mut commands: Commands, channels: Res<RepliconChannels>| {
-
- let server = RenetServer::new(ConnectionConfig::from_channels(
- channels.server_configs(),
- channels.client_configs()
- ));
+ let bind_ws = self.bind_ws;
+ let bind_native = self.bind_native;
+ let max_clients = self.max_clients;
- #[cfg(not(target_arch = "wasm32"))] {
- let server_config = ServerSetupConfig {
- current_time: SystemTime::now().duration_since(UNIX_EPOCH).unwrap(),
- max_clients: max_clients,
- protocol_id: 0,
- authentication: ServerAuthentication::Unsecure,
- socket_addresses: vec![vec![bind_native], vec![bind_ws]]
- };
+ app.add_systems(FixedPreUpdate, bevy_replicon::server::increment_tick) // !!important!! do not remove or move
+ .add_systems(
+ Startup,
+ move |mut commands: Commands, channels: Res<RepliconChannels>| {
+ let server = RenetServer::new(ConnectionConfig::from_channels(
+ channels.server_configs(),
+ channels.client_configs(),
+ ));
- let rt = tokio::runtime::Runtime::new().unwrap();
+ #[cfg(not(target_arch = "wasm32"))]
+ {
+ let server_config = ServerSetupConfig {
+ current_time: SystemTime::now().duration_since(UNIX_EPOCH).unwrap(),
+ max_clients,
+ protocol_id: 0,
+ authentication: ServerAuthentication::Unsecure,
+ socket_addresses: vec![vec![bind_native], vec![bind_ws]],
+ };
- let ws_config = WebSocketServerConfig {
- acceptor: WebSocketAcceptor::Plain { has_tls_proxy: true },
- listen: bind_ws,
- max_clients
- };
- let ws_server = WebSocketServer::new(ws_config, rt.handle().clone()).unwrap();
+ let rt = tokio::runtime::Runtime::new().unwrap();
- let native_socket = NativeSocket::new(UdpSocket::bind(bind_native).unwrap()).unwrap();
+ let ws_config = WebSocketServerConfig {
+ acceptor: WebSocketAcceptor::Plain {
+ has_tls_proxy: true,
+ },
+ listen: bind_ws,
+ max_clients,
+ };
+ let ws_server =
+ WebSocketServer::new(ws_config, rt.handle().clone()).unwrap();
- let transport = NetcodeServerTransport::new_with_sockets(server_config, vec![BoxedSocket::new(native_socket), BoxedSocket::new(ws_server)]).unwrap();
+ let native_socket =
+ NativeSocket::new(UdpSocket::bind(bind_native).unwrap()).unwrap();
- commands.insert_resource(server);
- commands.insert_resource(transport);
+ let transport = NetcodeServerTransport::new_with_sockets(
+ server_config,
+ vec![BoxedSocket::new(native_socket), BoxedSocket::new(ws_server)],
+ )
+ .unwrap();
- info!("websocket/native server listening");
+ commands.insert_resource(server);
+ commands.insert_resource(transport);
- }
- })
+ info!("websocket/native server listening");
+ }
+ },
+ )
.add_plugins(planets_plugin)
.add_plugins(world_config_plugin)
.add_plugins(newtonian_gravity_plugin)
M crates/unified/src/server/planets.rs => crates/unified/src/server/planets.rs +58 -30
@@ 1,35 1,40 @@
+use crate::config::planet::{Planet, PlanetBundle, PlanetConfigCollection};
use bevy::asset::Handle;
use bevy::prelude::*;
use bevy_rapier2d::dynamics::AdditionalMassProperties;
use bevy_rapier2d::prelude::Collider;
use bevy_replicon::prelude::Replicated;
-use crate::config::planet::{Planet, PlanetBundle, PlanetConfigCollection};
pub fn planets_plugin(app: &mut App) {
- app
- .init_resource::<PlanetConfigResource>()
+ app.init_resource::<PlanetConfigResource>()
.add_systems(Startup, start_loading_planets)
.add_systems(Update, update_planets);
}
#[derive(Resource, Default)]
pub struct PlanetConfigResource {
- handle: Option<Handle<PlanetConfigCollection>>
+ handle: Option<Handle<PlanetConfigCollection>>,
}
fn start_loading_planets(assets: Res<AssetServer>, mut planets: ResMut<PlanetConfigResource>) {
planets.handle = Some(assets.load("config/planets.pc.toml"));
}
-
pub fn update_planets(
mut commands: Commands,
mut ev_config: EventReader<AssetEvent<PlanetConfigCollection>>,
- mut assets: ResMut<Assets<PlanetConfigCollection>>,
- mut planets: ResMut<PlanetConfigResource>,
- mut q_planets: Query<(Entity, &mut Planet, &mut Transform, &mut AdditionalMassProperties)>
+ assets: ResMut<Assets<PlanetConfigCollection>>,
+ planets: ResMut<PlanetConfigResource>,
+ mut q_planets: Query<(
+ Entity,
+ &mut Planet,
+ &mut Transform,
+ &mut AdditionalMassProperties,
+ )>,
) {
- let Some(handle) = planets.handle.as_ref() else { return; };
+ let Some(handle) = planets.handle.as_ref() else {
+ return;
+ };
let waiting_for_asset_id = handle.id();
@@ 40,47 45,70 @@ pub fn update_planets(
info!("planet config loaded - creating planets");
let planet_config = assets.get(*id).unwrap();
for planet in &planet_config.planets {
- commands.spawn(PlanetBundle {
- planet: planet.clone(),
- transform: Transform::from_xyz(planet.default_transform[0], planet.default_transform[1], planet.default_transform[2]),
- collider: Collider::ball(planet.radius),
- additional_mass_properties: AdditionalMassProperties::Mass(planet.mass),
- }).insert(Replicated);
+ commands
+ .spawn(PlanetBundle {
+ planet: planet.clone(),
+ transform: Transform::from_xyz(
+ planet.default_transform[0],
+ planet.default_transform[1],
+ planet.default_transform[2],
+ ),
+ collider: Collider::ball(planet.radius),
+ additional_mass_properties: AdditionalMassProperties::Mass(
+ planet.mass,
+ ),
+ })
+ .insert(Replicated);
info!(?planet, "new planet spawned");
}
}
- },
+ }
AssetEvent::Modified { id } => {
if *id == waiting_for_asset_id {
info!("planet config modified - reloading planets");
let planet_config = assets.get(*id).unwrap();
for planet in &planet_config.planets {
- let existing_planet = q_planets.iter_mut().find(|(_, p, _, _)| p.name == planet.name);
+ let existing_planet = q_planets
+ .iter_mut()
+ .find(|(_, p, _, _)| p.name == planet.name);
- if let Some((existing, mut e_planet, mut e_transform, mut e_mass)) = existing_planet {
- commands.entity(existing)
+ if let Some((existing, mut e_planet, mut e_transform, mut e_mass)) =
+ existing_planet
+ {
+ commands
+ .entity(existing)
.remove::<Collider>()
.insert(Collider::ball(planet.radius));
*e_planet = planet.clone();
- e_transform.translation = Vec3::new(planet.default_transform[0], planet.default_transform[1], planet.default_transform[2]);
+ e_transform.translation = Vec3::new(
+ planet.default_transform[0],
+ planet.default_transform[1],
+ planet.default_transform[2],
+ );
*e_mass = AdditionalMassProperties::Mass(planet.mass);
info!(?planet, "planet hot-reloaded");
} else {
- commands.spawn(PlanetBundle {
- planet: planet.clone(),
- transform: Transform::from_xyz(planet.default_transform[0], planet.default_transform[1], planet.default_transform[2]),
- collider: Collider::ball(planet.radius),
- additional_mass_properties: AdditionalMassProperties::Mass(planet.mass),
- }).insert(Replicated);
+ commands
+ .spawn(PlanetBundle {
+ planet: planet.clone(),
+ transform: Transform::from_xyz(
+ planet.default_transform[0],
+ planet.default_transform[1],
+ planet.default_transform[2],
+ ),
+ collider: Collider::ball(planet.radius),
+ additional_mass_properties: AdditionalMassProperties::Mass(
+ planet.mass,
+ ),
+ })
+ .insert(Replicated);
info!(?planet, "new planet spawned");
}
-
-
}
}
- },
+ }
_ => {}
}
}
-}>
\ No newline at end of file
+}
M crates/unified/src/server/player.rs => crates/unified/src/server/player.rs +67 -33
@@ 1,21 1,20 @@
use std::f32::consts::PI;
-use bevy::prelude::*;
-use bevy_rapier2d::prelude::{AdditionalMassProperties, Collider, ExternalForce, ExternalImpulse, MassProperties, ReadMassProperties, RigidBody, Sensor};
-use bevy_replicon::prelude::{ConnectedClient, FromClient, Replicated};
use crate::config::planet::Planet;
use crate::ecs::{Part, PartBundle, Player, PlayerThrust, ThrustEvent};
use crate::server::world_config::WorldConfigResource;
+use bevy::prelude::*;
+use bevy_rapier2d::prelude::{
+ AdditionalMassProperties, Collider, ExternalForce, ExternalImpulse, MassProperties,
+};
+use bevy_replicon::prelude::{ConnectedClient, FromClient, Replicated};
pub fn player_management_plugin(app: &mut App) {
- app
- .add_systems(PreUpdate, reset_movement)
+ app.add_systems(PreUpdate, reset_movement)
.add_systems(Update, (handle_new_players, player_thrust));
}
-fn reset_movement(
- mut players: Query<(&mut ExternalForce, &mut ExternalImpulse)>
-) {
+fn reset_movement(mut players: Query<(&mut ExternalForce, &mut ExternalImpulse)>) {
for (mut force, mut impulse) in &mut players {
force.force = Vec2::ZERO;
force.torque = 0.0;
@@ 23,33 22,49 @@ fn reset_movement(
}
}
-fn handle_new_players(mut commands: Commands, q_new_clients: Query<Entity, Added<ConnectedClient>>, world_config: Res<WorldConfigResource>, planets: Query<(&Transform, &Planet)>) {
- let Some(wc) = &world_config.config else { return; };
+fn handle_new_players(
+ mut commands: Commands,
+ q_new_clients: Query<Entity, Added<ConnectedClient>>,
+ world_config: Res<WorldConfigResource>,
+ planets: Query<(&Transform, &Planet)>,
+) {
+ let Some(wc) = &world_config.config else {
+ return;
+ };
for joined_player in &q_new_clients {
// find earth
- let (earth_pos, earth_planet) = planets.iter().find(|p| p.1.name == "Earth").expect("earth is missing? (check that the planet is named 'Earth')");
+ let (earth_pos, earth_planet) = planets
+ .iter()
+ .find(|p| p.1.name == "Earth")
+ .expect("earth is missing? (check that the planet is named 'Earth')");
let angle = rand::random::<f32>() * std::f32::consts::TAU;
let offset = earth_planet.radius + 150.0;
- let mut new_transform = Transform::from_xyz(angle.cos() * offset, angle.sin() * offset, 0.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;
-
- commands.entity(joined_player)
+ commands
+ .entity(joined_player)
.insert(PartBundle {
part: Part {
sprite: "textures/hearty.png".to_string(),
width: wc.part.default_width,
height: wc.part.default_height,
- mass: wc.part.default_mass
+ 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,
- })
+ 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)
.insert(ExternalForce::default())
@@ 67,8 82,13 @@ fn player_thrust(
) {
use ThrustEvent::*;
for event in thrust_event.read() {
- let FromClient { client_entity, event } = event;
- let Ok((_, _, mut thrust)) = players.get_mut(*client_entity) else { continue };
+ let FromClient {
+ client_entity,
+ event,
+ } = event;
+ let Ok((_, _, mut thrust)) = players.get_mut(*client_entity) else {
+ continue;
+ };
match *event {
Up(on) => thrust.up = on,
Down(on) => thrust.down = on,
@@ 77,7 97,9 @@ fn player_thrust(
}
}
for (transform, mut force, thrust) in &mut players {
- let Some(world_config) = &world_config.config else { return; };
+ let Some(world_config) = &world_config.config else {
+ return;
+ };
let forward = (transform.rotation * Vec3::Y).xy();
let mut external_force = ExternalForce::default();
@@ 98,25 120,37 @@ fn player_thrust(
thrusters[1] = 1.0;
thrusters[3] = 1.0;
}
- let half_size = Vec2::new(world_config.part.default_width/2.0, world_config.part.default_height/2.0).length();
+ let half_size = Vec2::new(
+ world_config.part.default_width / 2.0,
+ world_config.part.default_height / 2.0,
+ )
+ .length();
external_force += ExternalForce::at_point(
- -forward*thrusters[0]*world_config.hearty.thrust,
- transform.translation.xy() + half_size*Vec2::new((1.0*PI/4.0).cos(), (1.0*PI/4.0).sin()).rotate(forward),
+ -forward * thrusters[0] * world_config.hearty.thrust,
+ transform.translation.xy()
+ + half_size
+ * Vec2::new((1.0 * PI / 4.0).cos(), (1.0 * PI / 4.0).sin()).rotate(forward),
transform.translation.xy(),
);
external_force += ExternalForce::at_point(
- forward*thrusters[1]*world_config.hearty.thrust,
- transform.translation.xy() + half_size*Vec2::new((3.0*PI/4.0).cos(), (3.0*PI/4.0).sin()).rotate(forward),
+ forward * thrusters[1] * world_config.hearty.thrust,
+ transform.translation.xy()
+ + half_size
+ * Vec2::new((3.0 * PI / 4.0).cos(), (3.0 * PI / 4.0).sin()).rotate(forward),
transform.translation.xy(),
);
external_force += ExternalForce::at_point(
- forward*thrusters[2]*world_config.hearty.thrust,
- transform.translation.xy() + half_size*Vec2::new((5.0*PI/4.0).cos(), (5.0*PI/4.0).sin()).rotate(forward),
+ forward * thrusters[2] * world_config.hearty.thrust,
+ transform.translation.xy()
+ + half_size
+ * Vec2::new((5.0 * PI / 4.0).cos(), (5.0 * PI / 4.0).sin()).rotate(forward),
transform.translation.xy(),
);
external_force += ExternalForce::at_point(
- -forward*thrusters[3]*world_config.hearty.thrust,
- transform.translation.xy() + half_size*Vec2::new((7.0*PI/4.0).cos(), (7.0*PI/4.0).sin()).rotate(forward),
+ -forward * thrusters[3] * world_config.hearty.thrust,
+ transform.translation.xy()
+ + half_size
+ * Vec2::new((7.0 * PI / 4.0).cos(), (7.0 * PI / 4.0).sin()).rotate(forward),
transform.translation.xy(),
);
*force += external_force;
M crates/unified/src/server/world_config.rs => crates/unified/src/server/world_config.rs +11 -15
@@ 1,14 1,9 @@
+use crate::config::world::GlobalWorldConfig;
use bevy::asset::Handle;
use bevy::prelude::*;
-use bevy_rapier2d::dynamics::AdditionalMassProperties;
-use bevy_rapier2d::prelude::Collider;
-use bevy_replicon::prelude::Replicated;
-use crate::config::planet::{Planet, PlanetBundle, PlanetConfigCollection};
-use crate::config::world::{GlobalWorldConfig, WorldConfig};
pub fn world_config_plugin(app: &mut App) {
- app
- .init_resource::<WorldConfigResource>()
+ app.init_resource::<WorldConfigResource>()
.add_systems(Startup, start_loading_planets)
.add_systems(Update, update_planets);
}
@@ 16,21 11,22 @@ pub fn world_config_plugin(app: &mut App) {
#[derive(Resource, Default)]
pub struct WorldConfigResource {
handle: Option<Handle<GlobalWorldConfig>>,
- pub config: Option<GlobalWorldConfig>
+ pub config: Option<GlobalWorldConfig>,
}
fn start_loading_planets(assets: Res<AssetServer>, mut planets: ResMut<WorldConfigResource>) {
planets.handle = Some(assets.load("config/world.wc.toml"));
}
-
pub fn update_planets(
- mut commands: Commands,
+ commands: Commands,
mut ev_config: EventReader<AssetEvent<GlobalWorldConfig>>,
- mut assets: ResMut<Assets<GlobalWorldConfig>>,
+ assets: ResMut<Assets<GlobalWorldConfig>>,
mut resource: ResMut<WorldConfigResource>,
) {
- let Some(handle) = resource.handle.as_ref() else { return; };
+ let Some(handle) = resource.handle.as_ref() else {
+ return;
+ };
let waiting_for_asset_id = handle.id();
@@ 42,15 38,15 @@ pub fn update_planets(
let world_config = assets.get(*id).unwrap();
resource.config = Some(world_config.clone());
}
- },
+ }
AssetEvent::Modified { id } => {
if *id == waiting_for_asset_id {
info!("world config modified - reloading");
let world_config = assets.get(*id).unwrap();
resource.config = Some(world_config.clone());
}
- },
+ }
_ => {}
}
}
-}>
\ No newline at end of file
+}
M crates/unified/src/server_plugins.rs => crates/unified/src/server_plugins.rs +11 -15
@@ 1,5 1,5 @@
-use std::net::SocketAddr;
-use std::time::Duration;
+use crate::config::planet::PlanetConfigCollection;
+use crate::config::world::GlobalWorldConfig;
use bevy::app::{PluginGroup, PluginGroupBuilder, ScheduleRunnerPlugin, TaskPoolPlugin};
use bevy::asset::AssetPlugin;
use bevy::diagnostic::FrameCountPlugin;
@@ 7,14 7,14 @@ use bevy::time::TimePlugin;
use bevy_common_assets::toml::TomlAssetPlugin;
use bevy_replicon::RepliconPlugins;
use bevy_replicon_renet2::RepliconRenetServerPlugin;
-use crate::config::planet::{Planet, PlanetConfigCollection};
-use crate::config::world::{GlobalWorldConfig, WorldConfig};
+use std::net::SocketAddr;
+use std::time::Duration;
pub struct ServerPluginGroup {
pub bind_ws: SocketAddr,
pub bind_native: SocketAddr,
pub tick_rate: f64,
- pub max_clients: usize
+ pub max_clients: usize,
}
impl PluginGroup for ServerPluginGroup {
fn build(self) -> PluginGroupBuilder {
@@ 22,15 22,11 @@ impl PluginGroup for ServerPluginGroup {
.add(TaskPoolPlugin::default())
.add(FrameCountPlugin)
.add(TimePlugin)
- .add(ScheduleRunnerPlugin::run_loop(
- Duration::from_secs_f64(1.0 / self.tick_rate)
- ))
- .add_group(
- RepliconPlugins
- )
- .add(
- RepliconRenetServerPlugin
- )
+ .add(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64(
+ 1.0 / self.tick_rate,
+ )))
+ .add_group(RepliconPlugins)
+ .add(RepliconRenetServerPlugin)
/* Assets */
.add(AssetPlugin::default())
.add(TomlAssetPlugin::<GlobalWorldConfig>::new(&["wc.toml"]))
@@ 41,4 37,4 @@ impl PluginGroup for ServerPluginGroup {
max_clients: self.max_clients,
})
}
-}>
\ No newline at end of file
+}
M crates/unified/src/shared_plugins.rs => crates/unified/src/shared_plugins.rs +7 -13
@@ 1,26 1,23 @@
+use crate::config::planet::Planet;
+use crate::ecs::{Ball, Ground, Part, Player, SendBallHere, ThrustEvent};
use bevy::app::{App, PluginGroup, PluginGroupBuilder};
use bevy::prelude::*;
use bevy_rapier2d::prelude::*;
-use bevy_replicon::prelude::{AppRuleExt, Channel, ClientEventAppExt, FromClient, ServerEventAppExt};
-use crate::config::planet::Planet;
-use crate::ecs::{Ball, Ground, Part, Player, SendBallHere, ThrustEvent};
+use bevy_replicon::prelude::{AppRuleExt, Channel, ClientEventAppExt};
pub struct SharedPluginGroup;
impl PluginGroup for SharedPluginGroup {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<Self>()
- .add(
- RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0)
- )
+ .add(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0))
.add(register_everything)
.add(physics_setup_plugin)
}
}
pub fn register_everything(app: &mut App) {
- app
- .add_client_event::<SendBallHere>(Channel::Ordered)
+ app.add_client_event::<SendBallHere>(Channel::Ordered)
.add_client_event::<ThrustEvent>(Channel::Ordered)
.replicate::<Transform>()
.replicate::<Ball>()
@@ 31,14 28,11 @@ pub fn register_everything(app: &mut App) {
.replicate::<Player>();
}
-fn physics_setup_plugin(mut app: &mut App) {
+fn physics_setup_plugin(app: &mut App) {
app.add_systems(Startup, setup_physics);
}
-
-fn setup_physics(
- mut rapier_config: Query<&mut RapierConfiguration>
-) {
+fn setup_physics(mut rapier_config: Query<&mut RapierConfiguration>) {
let mut cfg = rapier_config.single_mut().unwrap();
cfg.gravity = Vec2::ZERO;
}