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::{ClientId, Hi, SendTargets, ToClients};
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::<f32>() * 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::<PendingPlayer>();
}
#[derive(Component)]
pub struct PendingPlayer;
pub fn handle_new_players(
mut commands: Commands,
q_new_clients: Query<(Entity, &ConnectedGameEntity), Added<ConnectedGameEntity>>,
world_config: Res<WorldConfigResource>,
planets: Query<(&Transform, &LinearVelocity, &Planet)>,
asset_server: Res<AssetServer>,
mut welcome_messages: MessageWriter<ToClients<Hi>>,
time: Res<Time>,
) {
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 {
targets: SendTargets::Single(ClientId::Client(joined_player.1.network_entity)),
message: Hi {
you_are: joined_player.0,
time_offset: time.elapsed_secs_f64(),
},
});
join_player(joined_player.0, commands.reborrow(), wc, planets, &asset_server);
}
}
pub fn handle_pending_players(
mut commands: Commands,
pending_players: Query<Entity, With<PendingPlayer>>,
world_config: Res<WorldConfigResource>,
planets: Query<(&Transform, &LinearVelocity, &Planet)>,
asset_server: Res<AssetServer>,
mut welcome_messages: MessageWriter<ToClients<Hi>>
) {
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,
));
}