Crate unification (#88)

* move client/server/config into shared

* move platforms into shared

* move head drops into shared

* move tb_entities to shared

* reduce server to just a call into shared

* get solo play working

* fix server opening window

* fix fmt

* extracted a few more modules from client

* near completely migrated client

* fixed duplicate CharacterInputEnabled definition

* simplify a few things related to builds

* more simplifications

* fix warnings/check

* ci update

* address comments

* try fixing macos steam build

* address comments

* address comments

* CI tweaks with default client feature

---------

Co-authored-by: PROMETHIA-27 <electriccobras@gmail.com>
This commit is contained in:
extrawurst
2025-12-18 18:31:22 +01:00
committed by GitHub
parent c80129dac1
commit 7cfae285ed
100 changed files with 1099 additions and 1791 deletions

View File

@@ -0,0 +1,123 @@
use crate::{
GameState, global_observer,
heads_database::HeadsDatabase,
player::ClientPlayerId,
protocol::{ClientEnteredPlaying, PlayerId, 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,
netcode::{NetcodeServerTransport, ServerAuthentication},
renet::{ConnectionConfig, RenetServer},
};
use std::{
net::{Ipv4Addr, UdpSocket},
time::SystemTime,
};
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,
query: Query<&Transform, With<SpawnPoint>>,
heads_db: Res<HeadsDatabase>,
) -> Result {
info!("client has entered playing gamestate");
crate::player::spawn(commands, trigger.client_id, 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>>,
) -> 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()
});
let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
let port = 31111;
let socket = UdpSocket::bind((Ipv4Addr::UNSPECIFIED, port))?;
let server_config = bevy_replicon_renet::netcode::ServerConfig {
current_time,
max_clients: 1,
protocol_id: 0,
authentication: ServerAuthentication::Unsecure,
public_addresses: Default::default(),
};
let transport = NetcodeServerTransport::new(server_config, socket)?;
commands.insert_resource(server);
commands.insert_resource(transport);
info!("hosting a server 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>>,
) {
let client = trigger.event_target();
info!("{client} connected to server!");
let id = ClientPlayerId(PlayerId { id: 0 });
commands.entity(client).insert(id);
assign_id.write(ToClients {
mode: SendMode::Direct(ClientId::Client(trigger.entity)),
message: AssignClientPlayer(id.0),
});
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);
}