Compare commits
7 Commits
a620f18a55
...
use-remade
| Author | SHA1 | Date | |
|---|---|---|---|
| 87d89c9885 | |||
| 3cec532fcd | |||
| b4db8eea0e | |||
| 7086338255 | |||
| 10702d46b4 | |||
| a647edfa13 | |||
| da0d335c09 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ build/steamos/hedz_reloaded
|
|||||||
build/steamos/.env
|
build/steamos/.env
|
||||||
build/macos/src/HEDZReloaded.app/Contents/MacOS
|
build/macos/src/HEDZReloaded.app/Contents/MacOS
|
||||||
build/macos/src/Applications
|
build/macos/src/Applications
|
||||||
|
server.log
|
||||||
13
Cargo.lock
generated
13
Cargo.lock
generated
@@ -1519,7 +1519,6 @@ dependencies = [
|
|||||||
"bevy_time",
|
"bevy_time",
|
||||||
"renet",
|
"renet",
|
||||||
"renet_netcode",
|
"renet_netcode",
|
||||||
"renet_steam",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5565,18 +5564,6 @@ dependencies = [
|
|||||||
"renetcode",
|
"renetcode",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "renet_steam"
|
|
||||||
version = "2.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1f6018afe469d3d2d49fab8fd1cecc46c588ac61498cad879d5781c44b277421"
|
|
||||||
dependencies = [
|
|
||||||
"bevy_ecs",
|
|
||||||
"log",
|
|
||||||
"renet",
|
|
||||||
"steamworks",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "renetcode"
|
name = "renetcode"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|||||||
@@ -61,8 +61,7 @@ bevy_pkv = { version = "0.14", default-features = false, features = [
|
|||||||
"redb",
|
"redb",
|
||||||
] }
|
] }
|
||||||
bevy_replicon = "0.37.1"
|
bevy_replicon = "0.37.1"
|
||||||
# TODO: i dont think we need this in dedicated server mode
|
bevy_replicon_renet = "0.13.0"
|
||||||
bevy_replicon_renet = { version = "0.13.0", features = ["renet_steam"] }
|
|
||||||
bevy_sprite3d = "7.0.0"
|
bevy_sprite3d = "7.0.0"
|
||||||
bevy_trenchbroom = { version = "0.10", default-features = false, features = [
|
bevy_trenchbroom = { version = "0.10", default-features = false, features = [
|
||||||
"physics-integration",
|
"physics-integration",
|
||||||
@@ -77,7 +76,6 @@ rand = "=0.8.5"
|
|||||||
ron = "0.8"
|
ron = "0.8"
|
||||||
serde = { version = "1.0.219", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
shared = { path = "crates/shared" }
|
shared = { path = "crates/shared" }
|
||||||
# TODO: i dont think we need this in dedicated server mode
|
|
||||||
steamworks = "0.12"
|
steamworks = "0.12"
|
||||||
|
|
||||||
[profile.dev.package."*"]
|
[profile.dev.package."*"]
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -20,7 +20,7 @@ client = [
|
|||||||
"bevy_replicon_renet/client",
|
"bevy_replicon_renet/client",
|
||||||
"bevy_trenchbroom/client",
|
"bevy_trenchbroom/client",
|
||||||
]
|
]
|
||||||
dbg = ["avian3d/debug-plugin", "bevy/debug", "dep:bevy-inspector-egui"]
|
dbg = ["avian3d/debug-plugin", "dep:bevy-inspector-egui"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
avian3d = { workspace = true }
|
avian3d = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState,
|
GameState,
|
||||||
config::NetConfig,
|
config::NetworkingConfig,
|
||||||
protocol::{
|
protocol::{
|
||||||
ClientEnteredPlaying, TbMapEntityId, TbMapEntityMapping, messages::DespawnTbMapEntity,
|
ClientEnteredPlaying, TbMapEntityId, TbMapEntityMapping, messages::DespawnTbMapEntity,
|
||||||
},
|
},
|
||||||
@@ -17,10 +17,14 @@ use bevy_replicon::{
|
|||||||
};
|
};
|
||||||
use bevy_replicon_renet::{
|
use bevy_replicon_renet::{
|
||||||
RenetChannelsExt,
|
RenetChannelsExt,
|
||||||
|
netcode::{ClientAuthentication, NetcodeClientTransport, NetcodeError},
|
||||||
renet::{ConnectionConfig, RenetClient},
|
renet::{ConnectionConfig, RenetClient},
|
||||||
};
|
};
|
||||||
use bevy_steamworks::Client;
|
|
||||||
use bevy_trenchbroom::geometry::Brushes;
|
use bevy_trenchbroom::geometry::Brushes;
|
||||||
|
use std::{
|
||||||
|
net::{Ipv4Addr, UdpSocket},
|
||||||
|
time::SystemTime,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod audio;
|
pub mod audio;
|
||||||
pub mod backpack;
|
pub mod backpack;
|
||||||
@@ -51,7 +55,7 @@ pub fn plugin(app: &mut App) {
|
|||||||
|
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
OnEnter(GameState::Connecting),
|
OnEnter(GameState::Connecting),
|
||||||
connect_to_server.run_if(|config: Res<NetConfig>| config.is_client()),
|
connect_to_server.run_if(|config: Res<NetworkingConfig>| config.server.is_some()),
|
||||||
);
|
);
|
||||||
app.add_systems(Update, despawn_absent_map_entities);
|
app.add_systems(Update, despawn_absent_map_entities);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
@@ -85,9 +89,8 @@ fn on_disconnect() {
|
|||||||
|
|
||||||
fn connect_to_server(
|
fn connect_to_server(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
config: Res<NetConfig>,
|
config: Res<NetworkingConfig>,
|
||||||
channels: Res<RepliconChannels>,
|
channels: Res<RepliconChannels>,
|
||||||
steam_client: Option<Res<Client>>,
|
|
||||||
) -> Result {
|
) -> Result {
|
||||||
let server_channels_config = channels.server_configs();
|
let server_channels_config = channels.server_configs();
|
||||||
let client_channels_config = channels.client_configs();
|
let client_channels_config = channels.client_configs();
|
||||||
@@ -99,45 +102,30 @@ fn connect_to_server(
|
|||||||
});
|
});
|
||||||
|
|
||||||
commands.insert_resource(client);
|
commands.insert_resource(client);
|
||||||
|
commands.insert_resource(client_transport(&config)?);
|
||||||
|
|
||||||
if let NetConfig::SteamClient(host_steam_id) = &*config {
|
Ok(())
|
||||||
let Some(steam_client) = steam_client else {
|
}
|
||||||
return Err("Steam client not found".into());
|
|
||||||
};
|
|
||||||
|
|
||||||
info!("connecting to steam host: {host_steam_id:?}");
|
|
||||||
let transport = bevy_replicon_renet::steam::SteamClientTransport::new(
|
|
||||||
(**steam_client).clone(),
|
|
||||||
host_steam_id,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
commands.insert_resource(transport);
|
|
||||||
} else if let NetConfig::NetcodeClient(host_addr) = &*config {
|
|
||||||
use std::time::SystemTime;
|
|
||||||
|
|
||||||
info!("connecting to netcode host: {host_addr:?}");
|
|
||||||
|
|
||||||
|
fn client_transport(config: &NetworkingConfig) -> Result<NetcodeClientTransport, NetcodeError> {
|
||||||
let current_time = SystemTime::now()
|
let current_time = SystemTime::now()
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let client_id = current_time.as_millis() as u64;
|
let client_id = current_time.as_millis() as u64;
|
||||||
let socket = std::net::UdpSocket::bind((std::net::Ipv4Addr::UNSPECIFIED, 0))?;
|
let socket = UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0))?;
|
||||||
let authentication = bevy_replicon_renet::netcode::ClientAuthentication::Unsecure {
|
let server_addr = config
|
||||||
|
.server
|
||||||
|
.flatten()
|
||||||
|
.unwrap_or_else(|| "127.0.0.1:31111".parse().unwrap());
|
||||||
|
let authentication = ClientAuthentication::Unsecure {
|
||||||
client_id,
|
client_id,
|
||||||
protocol_id: 0,
|
protocol_id: 0,
|
||||||
server_addr: host_addr.clone(),
|
server_addr,
|
||||||
user_data: None,
|
user_data: None,
|
||||||
};
|
};
|
||||||
let transport = bevy_replicon_renet::netcode::NetcodeClientTransport::new(
|
|
||||||
current_time,
|
|
||||||
authentication,
|
|
||||||
socket,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
commands.insert_resource(transport);
|
info!("attempting connection to {server_addr}");
|
||||||
}
|
NetcodeClientTransport::new(current_time, authentication, socket)
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ use bevy_pkv::prelude::*;
|
|||||||
use crate::{client::audio::SoundSettings, utils::Debounce};
|
use crate::{client::audio::SoundSettings, utils::Debounce};
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
#[cfg(not(feature = "dbg"))]
|
|
||||||
app.insert_resource(PkvStore::new("Rustunit", "HEDZ"));
|
app.insert_resource(PkvStore::new("Rustunit", "HEDZ"));
|
||||||
|
|
||||||
app.add_systems(Update, persist_settings.run_if(resource_exists::<PkvStore>));
|
app.add_systems(Update, persist_settings);
|
||||||
app.add_systems(Startup, load_settings.run_if(resource_exists::<PkvStore>));
|
app.add_systems(Startup, load_settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn persist_settings(
|
fn persist_settings(
|
||||||
|
|||||||
@@ -61,14 +61,6 @@ fn test_steam_system(steam_client: Res<Client>) {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let id = steam_client.user().steam_id();
|
|
||||||
|
|
||||||
info!("Steam ID: {:?}", id);
|
|
||||||
|
|
||||||
steam_client
|
|
||||||
.friends()
|
|
||||||
.set_rich_presence("connect", Some(id.raw().to_string().as_str()));
|
|
||||||
|
|
||||||
for friend in steam_client.friends().get_friends(FriendFlags::IMMEDIATE) {
|
for friend in steam_client.friends().get_friends(FriendFlags::IMMEDIATE) {
|
||||||
info!(
|
info!(
|
||||||
"Steam Friend: {:?} - {}({:?})",
|
"Steam Friend: {:?} - {}({:?})",
|
||||||
|
|||||||
@@ -1,92 +1,25 @@
|
|||||||
use std::net::SocketAddr;
|
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use steamworks::SteamId;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
let config = NetworkingConfig::parse();
|
let config = NetworkingConfig::parse();
|
||||||
|
|
||||||
let config: NetConfig = config.into();
|
|
||||||
|
|
||||||
info!("net config: {:?}", config);
|
|
||||||
|
|
||||||
app.insert_resource(config);
|
app.insert_resource(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Resource, Parser, Debug)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
struct NetworkingConfig {
|
pub struct NetworkingConfig {
|
||||||
/// Steam id of the host to connect to
|
/// The IP/port to connect to.
|
||||||
|
/// If `None`, host a local server.
|
||||||
|
/// If Some(None), connect to the default server (`127.0.0.1:31111`)
|
||||||
|
/// Otherwise, connect to the given server.
|
||||||
|
/// Does nothing on the server.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub steam_host_id: Option<String>,
|
pub server: Option<Option<SocketAddr>>,
|
||||||
|
/// Whether or not to open a port when opening the client, for other clients
|
||||||
/// Act as steam host
|
/// to connect. Does nothing if `server` is set.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub steam_host: bool,
|
pub host: bool,
|
||||||
|
|
||||||
/// Act as host using netcode, so we have to define our port
|
|
||||||
#[arg(long)]
|
|
||||||
pub netcode_host: Option<Option<u16>>,
|
|
||||||
|
|
||||||
/// Host address we connect to as a client
|
|
||||||
#[arg(long)]
|
|
||||||
pub netcode_client: Option<Option<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Resource, Debug)]
|
|
||||||
pub enum NetConfig {
|
|
||||||
Singleplayer,
|
|
||||||
SteamHost,
|
|
||||||
NetcodeHost { port: u16 },
|
|
||||||
SteamClient(SteamId),
|
|
||||||
NetcodeClient(SocketAddr),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NetConfig {
|
|
||||||
pub fn is_client(&self) -> bool {
|
|
||||||
matches!(
|
|
||||||
self,
|
|
||||||
NetConfig::SteamClient(_) | NetConfig::NetcodeClient(_)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_host(&self) -> bool {
|
|
||||||
matches!(self, NetConfig::SteamHost | NetConfig::NetcodeHost { .. })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_singleplayer(&self) -> bool {
|
|
||||||
!self.is_client() && !self.is_host()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<NetworkingConfig> for NetConfig {
|
|
||||||
fn from(config: NetworkingConfig) -> Self {
|
|
||||||
match (
|
|
||||||
config.steam_host,
|
|
||||||
config.steam_host_id,
|
|
||||||
config.netcode_host,
|
|
||||||
config.netcode_client,
|
|
||||||
) {
|
|
||||||
(false, None, None, None) => Self::Singleplayer,
|
|
||||||
(true, None, None, None) => Self::SteamHost,
|
|
||||||
(false, Some(id), None, None) => Self::SteamClient(parse_steam_id(id)),
|
|
||||||
(false, None, Some(port), None) => Self::NetcodeHost {
|
|
||||||
port: port.unwrap_or(31111),
|
|
||||||
},
|
|
||||||
(false, None, None, Some(addr)) => Self::NetcodeClient(parse_addr(addr)),
|
|
||||||
_ => panic!("Invalid configuration"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_addr(addr: Option<String>) -> SocketAddr {
|
|
||||||
addr.map(|addr| addr.parse().ok())
|
|
||||||
.flatten()
|
|
||||||
.unwrap_or_else(|| "127.0.0.1:31111".parse().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_steam_id(id: String) -> SteamId {
|
|
||||||
let id: u64 = id.parse().unwrap();
|
|
||||||
SteamId::from_raw(id)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ pub mod utils;
|
|||||||
pub mod water;
|
pub mod water;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::NetConfig,
|
config::NetworkingConfig,
|
||||||
heads_database::{HeadDatabaseAsset, HeadsDatabase},
|
heads_database::{HeadDatabaseAsset, HeadsDatabase},
|
||||||
protocol::{PlayerIdCounter, messages::AssignClientPlayer},
|
protocol::{PlayerId, messages::AssignClientPlayer},
|
||||||
tb_entities::SpawnPoint,
|
tb_entities::SpawnPoint,
|
||||||
};
|
};
|
||||||
use avian3d::{PhysicsPlugins, prelude::TransformInterpolation};
|
use avian3d::{PhysicsPlugins, prelude::TransformInterpolation};
|
||||||
@@ -47,7 +47,6 @@ use bevy_common_assets::ron::RonAssetPlugin;
|
|||||||
use bevy_replicon::{RepliconPlugins, prelude::ClientId};
|
use bevy_replicon::{RepliconPlugins, prelude::ClientId};
|
||||||
use bevy_replicon_renet::RepliconRenetPlugins;
|
use bevy_replicon_renet::RepliconRenetPlugins;
|
||||||
use bevy_sprite3d::Sprite3dPlugin;
|
use bevy_sprite3d::Sprite3dPlugin;
|
||||||
use bevy_steamworks::SteamworksEvent;
|
|
||||||
use bevy_trenchbroom::{
|
use bevy_trenchbroom::{
|
||||||
TrenchBroomPlugins, config::TrenchBroomConfig, prelude::TrenchBroomPhysicsPlugin,
|
TrenchBroomPlugins, config::TrenchBroomConfig, prelude::TrenchBroomPhysicsPlugin,
|
||||||
};
|
};
|
||||||
@@ -149,21 +148,21 @@ pub fn plugin(app: &mut App) {
|
|||||||
if cfg!(feature = "client") {
|
if cfg!(feature = "client") {
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
OnEnter(GameState::Waiting),
|
OnEnter(GameState::Waiting),
|
||||||
start_solo_client.run_if(|config: Res<NetConfig>| config.is_singleplayer()),
|
start_solo_client
|
||||||
|
.run_if(|config: Res<NetworkingConfig>| config.server.is_none() && !config.host),
|
||||||
);
|
);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
OnEnter(GameState::Waiting),
|
OnEnter(GameState::Waiting),
|
||||||
start_listen_server.run_if(|config: Res<NetConfig>| config.is_host()),
|
start_listen_server
|
||||||
|
.run_if(|config: Res<NetworkingConfig>| config.server.is_none() && config.host),
|
||||||
);
|
);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
OnEnter(GameState::Waiting),
|
OnEnter(GameState::Waiting),
|
||||||
start_client.run_if(|config: Res<NetConfig>| config.is_client()),
|
start_client.run_if(|config: Res<NetworkingConfig>| config.server.is_some()),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
app.add_systems(OnEnter(GameState::Waiting), start_dedicated_server);
|
app.add_systems(OnEnter(GameState::Waiting), start_dedicated_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.add_systems(Update, log_steam_events);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource, Reflect, Debug)]
|
#[derive(Resource, Reflect, Debug)]
|
||||||
@@ -193,33 +192,18 @@ pub enum GameState {
|
|||||||
Playing,
|
Playing,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log_steam_events(events: Option<MessageReader<SteamworksEvent>>) {
|
|
||||||
let Some(mut events) = events else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
for event in events.read() {
|
|
||||||
let SteamworksEvent::CallbackResult(result) = event;
|
|
||||||
info!("steam: {:?}", result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_solo_client(
|
fn start_solo_client(
|
||||||
commands: Commands,
|
commands: Commands,
|
||||||
mut next: ResMut<NextState<GameState>>,
|
mut next: ResMut<NextState<GameState>>,
|
||||||
query: Query<&Transform, With<SpawnPoint>>,
|
query: Query<&Transform, With<SpawnPoint>>,
|
||||||
heads_db: Res<HeadsDatabase>,
|
heads_db: Res<HeadsDatabase>,
|
||||||
mut assign_player_id: MessageWriter<AssignClientPlayer>,
|
mut assign_player_id: MessageWriter<AssignClientPlayer>,
|
||||||
mut ids: ResMut<PlayerIdCounter>,
|
|
||||||
) {
|
) {
|
||||||
next.set(GameState::Playing);
|
next.set(GameState::Playing);
|
||||||
|
|
||||||
ids.reset();
|
player::spawn(commands, ClientId::Server, query, heads_db);
|
||||||
let id = ids.alloc();
|
|
||||||
|
|
||||||
player::spawn(commands, ClientId::Server, id, query, heads_db);
|
assign_player_id.write(AssignClientPlayer(PlayerId { id: 0 }));
|
||||||
|
|
||||||
assign_player_id.write(AssignClientPlayer(id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_listen_server(
|
fn start_listen_server(
|
||||||
@@ -228,16 +212,12 @@ fn start_listen_server(
|
|||||||
query: Query<&Transform, With<SpawnPoint>>,
|
query: Query<&Transform, With<SpawnPoint>>,
|
||||||
heads_db: Res<HeadsDatabase>,
|
heads_db: Res<HeadsDatabase>,
|
||||||
mut assign_player_id: MessageWriter<AssignClientPlayer>,
|
mut assign_player_id: MessageWriter<AssignClientPlayer>,
|
||||||
mut ids: ResMut<PlayerIdCounter>,
|
|
||||||
) {
|
) {
|
||||||
next.set(GameState::Hosting);
|
next.set(GameState::Hosting);
|
||||||
|
|
||||||
ids.reset();
|
player::spawn(commands, ClientId::Server, query, heads_db);
|
||||||
let id = ids.alloc();
|
|
||||||
|
|
||||||
player::spawn(commands, ClientId::Server, id, query, heads_db);
|
assign_player_id.write(AssignClientPlayer(PlayerId { id: 0 }));
|
||||||
|
|
||||||
assign_player_id.write(AssignClientPlayer(id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_client(mut next: ResMut<NextState<GameState>>) {
|
fn start_client(mut next: ResMut<NextState<GameState>>) {
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ pub fn plugin(app: &mut App) {
|
|||||||
pub fn spawn(
|
pub fn spawn(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
owner: ClientId,
|
owner: ClientId,
|
||||||
id: PlayerId,
|
|
||||||
query: Query<&Transform, With<SpawnPoint>>,
|
query: Query<&Transform, With<SpawnPoint>>,
|
||||||
heads_db: Res<HeadsDatabase>,
|
heads_db: Res<HeadsDatabase>,
|
||||||
) -> Option<Entity> {
|
) -> Option<Entity> {
|
||||||
@@ -92,7 +91,7 @@ pub fn spawn(
|
|||||||
transform,
|
transform,
|
||||||
Visibility::default(),
|
Visibility::default(),
|
||||||
PlayerCharacterController,
|
PlayerCharacterController,
|
||||||
id,
|
PlayerId { id: 0 },
|
||||||
),
|
),
|
||||||
Backpack::default(),
|
Backpack::default(),
|
||||||
BackpackUiState::default(),
|
BackpackUiState::default(),
|
||||||
|
|||||||
@@ -76,23 +76,6 @@ impl From<NetworkedCollider> for Collider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
|
||||||
pub struct PlayerIdCounter {
|
|
||||||
next: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PlayerIdCounter {
|
|
||||||
pub fn reset(&mut self) {
|
|
||||||
self.next = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc(&mut self) -> PlayerId {
|
|
||||||
let id = PlayerId { id: self.next };
|
|
||||||
self.next += 1;
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An ID, unique per player, inserted on the character controller. The `PlayerIdMap` maintains a mapping of ID -> controller entity
|
/// An ID, unique per player, inserted on the character controller. The `PlayerIdMap` maintains a mapping of ID -> controller entity
|
||||||
/// on the server
|
/// on the server
|
||||||
#[derive(Clone, Copy, Component, Hash, Reflect, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Clone, Copy, Component, Hash, Reflect, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ pub fn plugin(app: &mut App) {
|
|||||||
app.register_type::<TbMapIdCounter>();
|
app.register_type::<TbMapIdCounter>();
|
||||||
app.register_type::<TbMapEntityMapping>();
|
app.register_type::<TbMapEntityMapping>();
|
||||||
|
|
||||||
app.init_resource::<PlayerIdCounter>();
|
|
||||||
app.init_resource::<PlayerIdMap>();
|
app.init_resource::<PlayerIdMap>();
|
||||||
app.init_resource::<TbMapIdCounter>();
|
app.init_resource::<TbMapIdCounter>();
|
||||||
app.init_resource::<TbMapEntityMapping>();
|
app.init_resource::<TbMapEntityMapping>();
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState,
|
GameState, global_observer,
|
||||||
config::NetConfig,
|
|
||||||
global_observer,
|
|
||||||
heads_database::HeadsDatabase,
|
heads_database::HeadsDatabase,
|
||||||
player::ClientPlayerId,
|
player::ClientPlayerId,
|
||||||
protocol::{ClientEnteredPlaying, PlayerIdCounter, SetGameTick, messages::AssignClientPlayer},
|
protocol::{ClientEnteredPlaying, PlayerId, SetGameTick, messages::AssignClientPlayer},
|
||||||
tb_entities::SpawnPoint,
|
tb_entities::SpawnPoint,
|
||||||
tick::GameTick,
|
tick::GameTick,
|
||||||
};
|
};
|
||||||
@@ -18,8 +16,12 @@ use bevy_replicon::{
|
|||||||
};
|
};
|
||||||
use bevy_replicon_renet::{
|
use bevy_replicon_renet::{
|
||||||
RenetChannelsExt,
|
RenetChannelsExt,
|
||||||
|
netcode::{NetcodeServerTransport, ServerAuthentication},
|
||||||
renet::{ConnectionConfig, RenetServer},
|
renet::{ConnectionConfig, RenetServer},
|
||||||
steam::SteamServerTransport,
|
};
|
||||||
|
use std::{
|
||||||
|
net::{Ipv4Addr, UdpSocket},
|
||||||
|
time::SystemTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
@@ -36,14 +38,12 @@ pub fn plugin(app: &mut App) {
|
|||||||
fn on_client_playing(
|
fn on_client_playing(
|
||||||
trigger: On<FromClient<ClientEnteredPlaying>>,
|
trigger: On<FromClient<ClientEnteredPlaying>>,
|
||||||
commands: Commands,
|
commands: Commands,
|
||||||
clients: Query<&ClientPlayerId>,
|
|
||||||
query: Query<&Transform, With<SpawnPoint>>,
|
query: Query<&Transform, With<SpawnPoint>>,
|
||||||
heads_db: Res<HeadsDatabase>,
|
heads_db: Res<HeadsDatabase>,
|
||||||
) -> Result {
|
) -> Result {
|
||||||
info!("client has entered playing gamestate");
|
info!("client has entered playing gamestate");
|
||||||
|
|
||||||
let id = clients.get(trigger.client_id.entity().unwrap()).unwrap();
|
crate::player::spawn(commands, trigger.client_id, query, heads_db)
|
||||||
crate::player::spawn(commands, trigger.client_id, id.0, query, heads_db)
|
|
||||||
.ok_or("failed to spawn player")?;
|
.ok_or("failed to spawn player")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -57,8 +57,6 @@ fn open_renet_server(
|
|||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
channels: Res<RepliconChannels>,
|
channels: Res<RepliconChannels>,
|
||||||
mut next: ResMut<NextState<GameState>>,
|
mut next: ResMut<NextState<GameState>>,
|
||||||
steam_client: Option<Res<bevy_steamworks::Client>>,
|
|
||||||
config: Res<NetConfig>,
|
|
||||||
) -> Result<(), BevyError> {
|
) -> Result<(), BevyError> {
|
||||||
info!("opening server");
|
info!("opening server");
|
||||||
|
|
||||||
@@ -71,48 +69,22 @@ fn open_renet_server(
|
|||||||
..Default::default()
|
..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 current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
|
||||||
let socket = std::net::UdpSocket::bind((std::net::Ipv4Addr::UNSPECIFIED, port))?;
|
let port = 31111;
|
||||||
|
let socket = UdpSocket::bind((Ipv4Addr::UNSPECIFIED, port))?;
|
||||||
let server_config = bevy_replicon_renet::netcode::ServerConfig {
|
let server_config = bevy_replicon_renet::netcode::ServerConfig {
|
||||||
current_time,
|
current_time,
|
||||||
max_clients: 8,
|
max_clients: 1,
|
||||||
protocol_id: 0,
|
protocol_id: 0,
|
||||||
authentication: bevy_replicon_renet::netcode::ServerAuthentication::Unsecure,
|
authentication: ServerAuthentication::Unsecure,
|
||||||
public_addresses: Default::default(),
|
public_addresses: Default::default(),
|
||||||
};
|
};
|
||||||
let transport =
|
let transport = NetcodeServerTransport::new(server_config, socket)?;
|
||||||
bevy_replicon_renet::netcode::NetcodeServerTransport::new(server_config, socket)?;
|
|
||||||
|
|
||||||
commands.insert_resource(server);
|
commands.insert_resource(server);
|
||||||
commands.insert_resource(transport);
|
commands.insert_resource(transport);
|
||||||
|
|
||||||
info!("hosting server: netcode on port {port}");
|
info!("hosting a server on port {port}");
|
||||||
} else {
|
|
||||||
return Err("Invalid configuration, choose either steam or netcode".into());
|
|
||||||
}
|
|
||||||
|
|
||||||
next.set(GameState::Playing);
|
next.set(GameState::Playing);
|
||||||
|
|
||||||
@@ -128,17 +100,16 @@ fn on_connected(
|
|||||||
game_tick: Res<GameTick>,
|
game_tick: Res<GameTick>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut assign_id: MessageWriter<ToClients<AssignClientPlayer>>,
|
mut assign_id: MessageWriter<ToClients<AssignClientPlayer>>,
|
||||||
mut ids: ResMut<PlayerIdCounter>,
|
|
||||||
) {
|
) {
|
||||||
let client = trigger.event_target();
|
let client = trigger.event_target();
|
||||||
info!("{client} connected to server!");
|
info!("{client} connected to server!");
|
||||||
|
|
||||||
let id = ids.alloc();
|
let id = ClientPlayerId(PlayerId { id: 0 });
|
||||||
commands.entity(client).insert(ClientPlayerId(id));
|
commands.entity(client).insert(id);
|
||||||
|
|
||||||
assign_id.write(ToClients {
|
assign_id.write(ToClients {
|
||||||
mode: SendMode::Direct(ClientId::Client(trigger.entity)),
|
mode: SendMode::Direct(ClientId::Client(trigger.entity)),
|
||||||
message: AssignClientPlayer(id),
|
message: AssignClientPlayer(id.0),
|
||||||
});
|
});
|
||||||
|
|
||||||
commands.server_trigger(ToClients {
|
commands.server_trigger(ToClients {
|
||||||
|
|||||||
4
justfile
4
justfile
@@ -13,7 +13,7 @@ run *args:
|
|||||||
RUST_BACKTRACE=1 cargo r {{ client_args }} -- {{ args }}
|
RUST_BACKTRACE=1 cargo r {{ client_args }} -- {{ args }}
|
||||||
|
|
||||||
server:
|
server:
|
||||||
RUST_BACKTRACE=1 cargo r {{ server_args }} -- --netcode-host
|
RUST_BACKTRACE=1 cargo r {{ server_args }}
|
||||||
|
|
||||||
dbg *args:
|
dbg *args:
|
||||||
RUST_BACKTRACE=1 cargo r {{ client_args }} --features dbg -- {{ args }}
|
RUST_BACKTRACE=1 cargo r {{ client_args }} --features dbg -- {{ args }}
|
||||||
@@ -22,7 +22,7 @@ dbg-server:
|
|||||||
RUST_BACKTRACE=1 cargo r {{ server_args }} --features dbg
|
RUST_BACKTRACE=1 cargo r {{ server_args }} --features dbg
|
||||||
|
|
||||||
sort:
|
sort:
|
||||||
cargo sort --workspace
|
cargo sort --check --workspace
|
||||||
|
|
||||||
check:
|
check:
|
||||||
cargo sort --check --workspace
|
cargo sort --check --workspace
|
||||||
|
|||||||
Reference in New Issue
Block a user