use crate::{ GameState, config::NetConfig, global_observer, heads_database::HeadsDatabase, player::ClientPlayerId, protocol::{ClientEnteredPlaying, PlayerIdCounter, SetGameTick, messages::AssignClientPlayer}, tb_entities::SpawnPoint, tick::GameTick, }; use bevy::prelude::*; use bevy_replicon::{ prelude::{ ClientId, ConnectedClient, FromClient, RepliconChannels, SendMode, ServerTriggerExt, ToClients, }, server::AuthorizedClient, }; use bevy_replicon_renet::{ RenetChannelsExt, renet::{ConnectionConfig, RenetServer}, steam::SteamServerTransport, }; pub fn plugin(app: &mut App) { app.add_systems(OnEnter(GameState::Hosting), open_renet_server); // Replicon global_observer!(app, on_connected); global_observer!(app, on_disconnected); // Server logic global_observer!(app, on_client_playing); } fn on_client_playing( trigger: On>, commands: Commands, clients: Query<&ClientPlayerId>, query: Query<&Transform, With>, heads_db: Res, ) -> Result { info!("client has entered playing gamestate"); let id = clients.get(trigger.client_id.entity().unwrap()).unwrap(); crate::player::spawn(commands, trigger.client_id, id.0, query, heads_db) .ok_or("failed to spawn player")?; Ok(()) } // // Renet // fn open_renet_server( mut commands: Commands, channels: Res, mut next: ResMut>, steam_client: Option>, config: Res, ) -> Result<(), BevyError> { info!("opening server"); let server_channels_config = channels.server_configs(); let client_channels_config = channels.client_configs(); let server = RenetServer::new(ConnectionConfig { server_channels_config, client_channels_config, ..Default::default() }); if let NetConfig::SteamHost = *config { let Some(steam_client) = steam_client else { return Err("Steam client not found".into()); }; let steam_config = bevy_replicon_renet::steam::SteamServerConfig { access_permission: bevy_replicon_renet::steam::AccessPermission::FriendsOnly, max_clients: 16, }; let client = (**steam_client).clone(); let transport = SteamServerTransport::new(client, steam_config)?; commands.queue(|w: &mut World| { w.insert_resource(server); w.insert_non_send_resource(transport); }); info!("hosting server: steam"); } else if let NetConfig::NetcodeHost { port } = *config { use std::time::SystemTime; let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?; let socket = std::net::UdpSocket::bind((std::net::Ipv4Addr::UNSPECIFIED, port))?; let server_config = bevy_replicon_renet::netcode::ServerConfig { current_time, max_clients: 8, protocol_id: 0, authentication: bevy_replicon_renet::netcode::ServerAuthentication::Unsecure, public_addresses: Default::default(), }; let transport = bevy_replicon_renet::netcode::NetcodeServerTransport::new(server_config, socket)?; commands.insert_resource(server); commands.insert_resource(transport); info!("hosting server: netcode on port {port}"); } next.set(GameState::Playing); Ok(()) } // // server logic // fn on_connected( trigger: On, game_tick: Res, mut commands: Commands, mut assign_id: MessageWriter>, mut ids: ResMut, ) { let client = trigger.event_target(); info!("{client} connected to server!"); let id = ids.alloc(); commands.entity(client).insert(ClientPlayerId(id)); assign_id.write(ToClients { mode: SendMode::Direct(ClientId::Client(trigger.entity)), message: AssignClientPlayer(id), }); commands.server_trigger(ToClients { mode: SendMode::Direct(ClientId::Client(trigger.entity)), message: SetGameTick(game_tick.0), }); } fn on_disconnected(on: On) { info!("client {} disconnected", on.entity); }