mod earth_parts; mod gravity; mod part; mod heat; mod drill; mod craft; mod damping; mod management; pub mod planets; pub mod player; mod system_sets; mod priority; pub mod orbit; pub mod plugins; pub mod components; pub mod visibility; use std::net::{SocketAddr, UdpSocket}; use bevy_replicon::prelude::{ConnectedClient, Replicated, RepliconChannels}; use bevy_replicon::server::AuthorizedClient; use bevy_replicon_renet2::RenetChannelsExt; use bevy_replicon_renet2::netcode::{ BoxedSocket, NativeSocket, NetcodeServerTransport, ServerAuthentication, ServerSetupConfig, WebTransportServer, WebTransportServerConfig, }; use bevy_replicon_renet2::renet2::{ConnectionConfig, RenetServer}; use web_time::SystemTime; use crate::server::craft::craft_plugin; use crate::server::damping::damping_plugin; use crate::server::drill::drill_plugin; use crate::server::earth_parts::spawn_parts_plugin; use crate::server::gravity::newtonian_gravity_plugin; use crate::server::management::spawn_management_server; use crate::server::part::part_management_plugin; use crate::server::priority::replication_priority_plugin; use crate::server::planets::planets_plugin; use crate::server::player::player_management_plugin; use crate::server::system_sets::{PlayerInputSet, WorldUpdateSet}; use crate::prelude::*; use crate::server::orbit::OrbitPlugin; use crate::server::player::thrust::server_thrust_plugin; use crate::shared::net::{encode_cert_hash, ManagementInfo, STARKINGDOMS_PROTOCOL_MAGIC}; const MAX_CLIENTS: usize = 32; pub struct ServerPlugin { pub management_bind: SocketAddr, pub native_bind: SocketAddr, pub wt_bind: SocketAddr, } impl Plugin for ServerPlugin { fn build(&self, app: &mut App) { app .add_plugins(planets_plugin) .add_plugins(newtonian_gravity_plugin) .add_plugins(player_management_plugin) .add_plugins(spawn_parts_plugin) .add_plugins(part_management_plugin) .add_plugins(server_thrust_plugin) /*.add_plugins(heat_cooling_plugin) .add_plugins(heat_radiation_plugin) .add_plugins(heat_conduction_plugin)*/ .add_plugins(drill_plugin) .add_plugins(craft_plugin) .add_plugins(OrbitPlugin) .add_plugins(damping_plugin) .add_plugins(replication_priority_plugin) .configure_sets(Update, WorldUpdateSet.before(PlayerInputSet)) .add_systems(Update, handle_authorized) .add_observer(on_client_disconnected); let management_bind = self.management_bind; let native_bind = self.native_bind; let wt_bind = self.wt_bind; app.add_systems(Startup, move |mut commands: Commands, channels: Res| { let connection_config = ConnectionConfig::from_channels(channels.server_configs(), channels.client_configs()); let server = RenetServer::new(connection_config); let native_socket = NativeSocket::new(UdpSocket::bind(native_bind).expect("failed to bind server UDP socket")) .expect("failed to create native socket"); let (wt_config, cert_hash) = WebTransportServerConfig::new_selfsigned(wt_bind, MAX_CLIENTS) .expect("failed to create self-signed WebTransport server config"); let runtime = tokio::runtime::Runtime::new().expect("failed to create tokio runtime"); let wt_socket = WebTransportServer::new(wt_config, runtime.handle().clone()) .expect("failed to create WebTransport server socket"); let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); let server_config = ServerSetupConfig { current_time, max_clients: MAX_CLIENTS, protocol_id: STARKINGDOMS_PROTOCOL_MAGIC, socket_addresses: vec![vec![native_bind], vec![wt_bind]], authentication: ServerAuthentication::Unsecure, }; let transport = NetcodeServerTransport::new_with_sockets(server_config, vec![ BoxedSocket::new(native_socket), BoxedSocket::new(wt_socket), ]).expect("failed to create server transport"); spawn_management_server(management_bind, ManagementInfo { native_port: native_bind.port(), wt_port: wt_bind.port(), cert_hash: encode_cert_hash(&cert_hash.hash), }); commands.insert_resource(server); commands.insert_resource(transport); commands.insert_resource(TokioRuntime(runtime)); }); } } #[derive(Resource)] struct TokioRuntime(tokio::runtime::Runtime); #[derive(Component, Debug)] pub struct ConnectedGameEntity { pub network_entity: Entity, } #[derive(Component)] pub struct ConnectedNetworkEntity { pub game_entity: Entity, } fn handle_authorized( newly_authorized_clients: Query>, mut commands: Commands ) { for client in newly_authorized_clients.iter() { let player = commands .spawn((Replicated, ConnectedGameEntity { network_entity: client, })) .id(); commands.entity(client).insert(( Replicated, ConnectedNetworkEntity { game_entity: player, }, )); } } fn on_client_disconnected( trigger: On, network_entities: Query<&ConnectedNetworkEntity>, mut commands: Commands, ) { let client = trigger.event_target(); let Ok(connected) = network_entities.get(client) else { return; }; if let Ok(mut entity) = commands.get_entity(connected.game_entity) { entity.despawn(); } }