* fix crashing when steam client not available * allow more than 1 connected player * disable settings persistence when in dbg
151 lines
4.3 KiB
Rust
151 lines
4.3 KiB
Rust
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<FromClient<ClientEnteredPlaying>>,
|
|
commands: Commands,
|
|
clients: Query<&ClientPlayerId>,
|
|
query: Query<&Transform, With<SpawnPoint>>,
|
|
heads_db: Res<HeadsDatabase>,
|
|
) -> 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<RepliconChannels>,
|
|
mut next: ResMut<NextState<GameState>>,
|
|
steam_client: Option<Res<bevy_steamworks::Client>>,
|
|
config: Res<NetConfig>,
|
|
) -> 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<Add, AuthorizedClient>,
|
|
game_tick: Res<GameTick>,
|
|
mut commands: Commands,
|
|
mut assign_id: MessageWriter<ToClients<AssignClientPlayer>>,
|
|
mut ids: ResMut<PlayerIdCounter>,
|
|
) {
|
|
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<Remove, ConnectedClient>) {
|
|
info!("client {} disconnected", on.entity);
|
|
}
|