use bevy_replicon::prelude::{ClientId, SendMode, ToClients}; use crate::client::components::Me; use crate::shared::config::planet::Planet; use crate::shared::config::world::GlobalWorldConfig; use crate::shared::ecs::{Player, PlayerStorage}; use crate::prelude::*; use crate::server::ConnectedGameEntity; use crate::server::part::SpawnPartRequest; use crate::shared::net::Hi; use crate::shared::world_config::WorldConfigResource; const SPAWN_ORBIT_OFFSET: f64 = 150.0; const INITIAL_FUEL_CAPACITY: f32 = 25.0; const INITIAL_POWER_CAPACITY: f32 = 25.0; fn join_player(joined_player: Entity, mut commands: Commands, wc: &GlobalWorldConfig, planets: Query<(&Transform, &LinearVelocity, &Planet)>, asset_server: &AssetServer ) { trace!(?joined_player, "detected joined player!"); // find earth if planets.is_empty() { warn!("planets have not loaded yet, setting this player to pending until they do!"); commands.entity(joined_player).insert(PendingPlayer); return; } let (spawn_planet_pos, spawn_planet_vel, spawn_planet) = planets .iter() .find(|p| p.2.name == wc.hearty.spawn_at) .unwrap_or_else(|| { panic!( "spawn planet {} is missing? (check that the planet is named exactly '{}')", wc.hearty.spawn_at, wc.hearty.spawn_at ) }); let angle = rand::random::() * std::f32::consts::TAU; let offset = spawn_planet.radius + SPAWN_ORBIT_OFFSET; let mut new_transform = Transform::from_xyz(angle.cos() * offset as f32, angle.sin() * offset as f32, 0.0); new_transform.rotate_z(angle); new_transform.translation += spawn_planet_pos.translation; info!(?new_transform, ?joined_player, "set player's position!"); commands .entity(joined_player) .insert(new_transform) .insert(SpawnPartRequest( asset_server.load("config/parts/hearty.part.toml"), )) .insert(PlayerStorage { fuel_capacity: INITIAL_FUEL_CAPACITY, fuel: INITIAL_FUEL_CAPACITY, power_capacity: INITIAL_POWER_CAPACITY, power: INITIAL_POWER_CAPACITY, }) .insert(Player { client: joined_player, }) .insert(*spawn_planet_vel) .remove::(); } #[derive(Component)] pub struct PendingPlayer; pub fn handle_new_players( mut commands: Commands, q_new_clients: Query<(Entity, &ConnectedGameEntity), Added>, world_config: Res, planets: Query<(&Transform, &LinearVelocity, &Planet)>, asset_server: Res, mut welcome_messages: MessageWriter> ) { if q_new_clients.is_empty() { return } let Some(wc) = &world_config.config else { warn!("got a joined player, but world config is not loaded! waiting until it is..."); for joined_player in &q_new_clients { commands.entity(joined_player.0).insert(PendingPlayer); } return; }; for joined_player in &q_new_clients { debug!(?joined_player, "new player!"); welcome_messages.write(ToClients { mode: SendMode::Direct(ClientId::Client(joined_player.1.network_entity)), message: Hi { you_are: joined_player.0 }, }); join_player(joined_player.0, commands.reborrow(), wc, planets, &asset_server); } } pub fn handle_pending_players( mut commands: Commands, pending_players: Query>, world_config: Res, planets: Query<(&Transform, &LinearVelocity, &Planet)>, asset_server: Res, mut welcome_messages: MessageWriter> ) { if pending_players.is_empty() { return }; let Some(wc) = &world_config.config else { warn!("there are pending players, but world config is not loaded! waiting until it is..."); return; }; for pending_player in &pending_players { warn!(?pending_player, "reprocessing pending player"); join_player(pending_player, commands.reborrow(), wc, planets, &asset_server); } } pub fn spawn_singleplayer_player(mut commands: Commands) { commands.spawn(( ConnectedGameEntity { network_entity: Entity::PLACEHOLDER }, Me, )); }