Compare commits
11 Commits
4fb37e27c5
...
use-renet-
| Author | SHA1 | Date | |
|---|---|---|---|
| a620f18a55 | |||
| 38f7f5c30a | |||
| e9f53c11e9 | |||
| 12c3cdc87b | |||
| 930753170f | |||
| 2c20b1efea | |||
| 1a632e729e | |||
| 22674822cc | |||
| 0f5a21995a | |||
| 7ea9046414 | |||
|
|
f6fa9ce1e4 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,4 +5,3 @@ 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
|
|
||||||
146
Cargo.lock
generated
146
Cargo.lock
generated
@@ -85,6 +85,16 @@ version = "2.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aead"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.12"
|
version = "0.8.12"
|
||||||
@@ -1508,6 +1518,7 @@ dependencies = [
|
|||||||
"bevy_ecs",
|
"bevy_ecs",
|
||||||
"bevy_time",
|
"bevy_time",
|
||||||
"renet",
|
"renet",
|
||||||
|
"renet_netcode",
|
||||||
"renet_steam",
|
"renet_steam",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2155,6 +2166,41 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20poly1305"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
|
||||||
|
dependencies = [
|
||||||
|
"aead",
|
||||||
|
"chacha20",
|
||||||
|
"cipher",
|
||||||
|
"poly1305",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"inout",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
@@ -2443,6 +2489,15 @@ dependencies = [
|
|||||||
"windows 0.54.0",
|
"windows 0.54.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@@ -2507,6 +2562,17 @@ version = "0.2.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"rand_core 0.6.4",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "csv"
|
name = "csv"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -3197,6 +3263,16 @@ dependencies = [
|
|||||||
"thread_local",
|
"thread_local",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gethostname"
|
name = "gethostname"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -3815,6 +3891,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inventory"
|
name = "inventory"
|
||||||
version = "0.3.21"
|
version = "0.3.21"
|
||||||
@@ -4810,6 +4895,12 @@ version = "1.70.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opener"
|
name = "opener"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
@@ -5054,6 +5145,17 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "poly1305"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
|
||||||
|
dependencies = [
|
||||||
|
"cpufeatures",
|
||||||
|
"opaque-debug",
|
||||||
|
"universal-hash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portable-atomic"
|
name = "portable-atomic"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
@@ -5451,6 +5553,18 @@ dependencies = [
|
|||||||
"octets",
|
"octets",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "renet_netcode"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d73ffa79c2081fe93286acac186a20d49657b93b8cfa4e0e8b79b1f3ee81241"
|
||||||
|
dependencies = [
|
||||||
|
"bevy_ecs",
|
||||||
|
"log",
|
||||||
|
"renet",
|
||||||
|
"renetcode",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "renet_steam"
|
name = "renet_steam"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
@@ -5463,6 +5577,16 @@ dependencies = [
|
|||||||
"steamworks",
|
"steamworks",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "renetcode"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "118d456f815f7fd5bd12713a9e69a0b0f8b45806bd515e05bb60146f1867310d"
|
||||||
|
dependencies = [
|
||||||
|
"chacha20poly1305",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rmp"
|
name = "rmp"
|
||||||
version = "0.8.14"
|
version = "0.8.14"
|
||||||
@@ -5941,6 +6065,12 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "svg_fmt"
|
name = "svg_fmt"
|
||||||
version = "0.4.5"
|
version = "0.4.5"
|
||||||
@@ -6400,6 +6530,16 @@ version = "0.2.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "universal-hash"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.7"
|
version = "2.5.7"
|
||||||
@@ -7470,6 +7610,12 @@ dependencies = [
|
|||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerotrie"
|
name = "zerotrie"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
|||||||
@@ -61,9 +61,8 @@ bevy_pkv = { version = "0.14", default-features = false, features = [
|
|||||||
"redb",
|
"redb",
|
||||||
] }
|
] }
|
||||||
bevy_replicon = "0.37.1"
|
bevy_replicon = "0.37.1"
|
||||||
bevy_replicon_renet = { version = "0.13.0", default-features = false, features = [
|
# TODO: i dont think we need this in dedicated server mode
|
||||||
"renet_steam",
|
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",
|
||||||
@@ -78,6 +77,7 @@ 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."*"]
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ client = [
|
|||||||
"bevy_replicon_renet/client",
|
"bevy_replicon_renet/client",
|
||||||
"bevy_trenchbroom/client",
|
"bevy_trenchbroom/client",
|
||||||
]
|
]
|
||||||
dbg = ["avian3d/debug-plugin", "dep:bevy-inspector-egui"]
|
dbg = ["avian3d/debug-plugin", "bevy/debug", "dep:bevy-inspector-egui"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
avian3d = { workspace = true }
|
avian3d = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState,
|
GameState,
|
||||||
config::NetworkingConfig,
|
config::NetConfig,
|
||||||
protocol::{
|
protocol::{
|
||||||
ClientEnteredPlaying, TbMapEntityId, TbMapEntityMapping, messages::DespawnTbMapEntity,
|
ClientEnteredPlaying, TbMapEntityId, TbMapEntityMapping, messages::DespawnTbMapEntity,
|
||||||
},
|
},
|
||||||
@@ -18,11 +18,9 @@ use bevy_replicon::{
|
|||||||
use bevy_replicon_renet::{
|
use bevy_replicon_renet::{
|
||||||
RenetChannelsExt,
|
RenetChannelsExt,
|
||||||
renet::{ConnectionConfig, RenetClient},
|
renet::{ConnectionConfig, RenetClient},
|
||||||
steam::SteamClientTransport,
|
|
||||||
};
|
};
|
||||||
use bevy_steamworks::Client;
|
use bevy_steamworks::Client;
|
||||||
use bevy_trenchbroom::geometry::Brushes;
|
use bevy_trenchbroom::geometry::Brushes;
|
||||||
use steamworks::SteamId;
|
|
||||||
|
|
||||||
pub mod audio;
|
pub mod audio;
|
||||||
pub mod backpack;
|
pub mod backpack;
|
||||||
@@ -53,7 +51,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<NetworkingConfig>| config.connect_to_host()),
|
connect_to_server.run_if(|config: Res<NetConfig>| config.is_client()),
|
||||||
);
|
);
|
||||||
app.add_systems(Update, despawn_absent_map_entities);
|
app.add_systems(Update, despawn_absent_map_entities);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
@@ -87,9 +85,9 @@ fn on_disconnect() {
|
|||||||
|
|
||||||
fn connect_to_server(
|
fn connect_to_server(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
config: Res<NetworkingConfig>,
|
config: Res<NetConfig>,
|
||||||
channels: Res<RepliconChannels>,
|
channels: Res<RepliconChannels>,
|
||||||
steam_client: Res<Client>,
|
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();
|
||||||
@@ -100,14 +98,44 @@ fn connect_to_server(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
let steam_id: u64 = config.steam_id.clone().unwrap().parse().unwrap();
|
|
||||||
let steam_id = SteamId::from_raw(steam_id);
|
|
||||||
|
|
||||||
info!("attempting connection to {steam_id:?}");
|
|
||||||
let transport = SteamClientTransport::new((**steam_client).clone(), &steam_id)?;
|
|
||||||
|
|
||||||
commands.insert_resource(client);
|
commands.insert_resource(client);
|
||||||
|
|
||||||
|
if let NetConfig::SteamClient(host_steam_id) = &*config {
|
||||||
|
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);
|
commands.insert_resource(transport);
|
||||||
|
} else if let NetConfig::NetcodeClient(host_addr) = &*config {
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
info!("connecting to netcode host: {host_addr:?}");
|
||||||
|
|
||||||
|
let current_time = SystemTime::now()
|
||||||
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.unwrap();
|
||||||
|
let client_id = current_time.as_millis() as u64;
|
||||||
|
let socket = std::net::UdpSocket::bind((std::net::Ipv4Addr::UNSPECIFIED, 0))?;
|
||||||
|
let authentication = bevy_replicon_renet::netcode::ClientAuthentication::Unsecure {
|
||||||
|
client_id,
|
||||||
|
protocol_id: 0,
|
||||||
|
server_addr: host_addr.clone(),
|
||||||
|
user_data: None,
|
||||||
|
};
|
||||||
|
let transport = bevy_replicon_renet::netcode::NetcodeClientTransport::new(
|
||||||
|
current_time,
|
||||||
|
authentication,
|
||||||
|
socket,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
commands.insert_resource(transport);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ 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);
|
app.add_systems(Update, persist_settings.run_if(resource_exists::<PkvStore>));
|
||||||
app.add_systems(Startup, load_settings);
|
app.add_systems(Startup, load_settings.run_if(resource_exists::<PkvStore>));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn persist_settings(
|
fn persist_settings(
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ 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,26 +1,92 @@
|
|||||||
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use steamworks::SteamId;
|
||||||
|
|
||||||
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(Resource, Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
pub struct NetworkingConfig {
|
struct NetworkingConfig {
|
||||||
/// Steam id of the host to connect to
|
/// Steam id of the host to connect to
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub steam_id: Option<String>,
|
pub steam_host_id: Option<String>,
|
||||||
/// Whether or not to open a port when opening the client, for other clients
|
|
||||||
/// to connect. Does nothing if `server` is set.
|
/// Act as steam host
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub host: bool,
|
pub steam_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>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkingConfig {
|
#[derive(Resource, Debug)]
|
||||||
pub fn connect_to_host(&self) -> bool {
|
pub enum NetConfig {
|
||||||
self.steam_id.is_some()
|
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::NetworkingConfig,
|
config::NetConfig,
|
||||||
heads_database::{HeadDatabaseAsset, HeadsDatabase},
|
heads_database::{HeadDatabaseAsset, HeadsDatabase},
|
||||||
protocol::{PlayerId, messages::AssignClientPlayer},
|
protocol::{PlayerIdCounter, messages::AssignClientPlayer},
|
||||||
tb_entities::SpawnPoint,
|
tb_entities::SpawnPoint,
|
||||||
};
|
};
|
||||||
use avian3d::{PhysicsPlugins, prelude::TransformInterpolation};
|
use avian3d::{PhysicsPlugins, prelude::TransformInterpolation};
|
||||||
@@ -47,6 +47,7 @@ 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,
|
||||||
};
|
};
|
||||||
@@ -148,21 +149,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
|
start_solo_client.run_if(|config: Res<NetConfig>| config.is_singleplayer()),
|
||||||
.run_if(|config: Res<NetworkingConfig>| !config.connect_to_host() && !config.host),
|
|
||||||
);
|
);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
OnEnter(GameState::Waiting),
|
OnEnter(GameState::Waiting),
|
||||||
start_listen_server
|
start_listen_server.run_if(|config: Res<NetConfig>| config.is_host()),
|
||||||
.run_if(|config: Res<NetworkingConfig>| config.connect_to_host() && config.host),
|
|
||||||
);
|
);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
OnEnter(GameState::Waiting),
|
OnEnter(GameState::Waiting),
|
||||||
start_client.run_if(|config: Res<NetworkingConfig>| config.connect_to_host()),
|
start_client.run_if(|config: Res<NetConfig>| config.is_client()),
|
||||||
);
|
);
|
||||||
} 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)]
|
||||||
@@ -192,18 +193,33 @@ 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);
|
||||||
|
|
||||||
player::spawn(commands, ClientId::Server, query, heads_db);
|
ids.reset();
|
||||||
|
let id = ids.alloc();
|
||||||
|
|
||||||
assign_player_id.write(AssignClientPlayer(PlayerId { id: 0 }));
|
player::spawn(commands, ClientId::Server, id, query, heads_db);
|
||||||
|
|
||||||
|
assign_player_id.write(AssignClientPlayer(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_listen_server(
|
fn start_listen_server(
|
||||||
@@ -212,12 +228,16 @@ 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);
|
||||||
|
|
||||||
player::spawn(commands, ClientId::Server, query, heads_db);
|
ids.reset();
|
||||||
|
let id = ids.alloc();
|
||||||
|
|
||||||
assign_player_id.write(AssignClientPlayer(PlayerId { id: 0 }));
|
player::spawn(commands, ClientId::Server, id, query, heads_db);
|
||||||
|
|
||||||
|
assign_player_id.write(AssignClientPlayer(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_client(mut next: ResMut<NextState<GameState>>) {
|
fn start_client(mut next: ResMut<NextState<GameState>>) {
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ 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> {
|
||||||
@@ -91,7 +92,7 @@ pub fn spawn(
|
|||||||
transform,
|
transform,
|
||||||
Visibility::default(),
|
Visibility::default(),
|
||||||
PlayerCharacterController,
|
PlayerCharacterController,
|
||||||
PlayerId { id: 0 },
|
id,
|
||||||
),
|
),
|
||||||
Backpack::default(),
|
Backpack::default(),
|
||||||
BackpackUiState::default(),
|
BackpackUiState::default(),
|
||||||
|
|||||||
@@ -76,6 +76,23 @@ 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,6 +74,7 @@ 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,8 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState, global_observer,
|
GameState,
|
||||||
|
config::NetConfig,
|
||||||
|
global_observer,
|
||||||
heads_database::HeadsDatabase,
|
heads_database::HeadsDatabase,
|
||||||
player::ClientPlayerId,
|
player::ClientPlayerId,
|
||||||
protocol::{ClientEnteredPlaying, PlayerId, SetGameTick, messages::AssignClientPlayer},
|
protocol::{ClientEnteredPlaying, PlayerIdCounter, SetGameTick, messages::AssignClientPlayer},
|
||||||
tb_entities::SpawnPoint,
|
tb_entities::SpawnPoint,
|
||||||
tick::GameTick,
|
tick::GameTick,
|
||||||
};
|
};
|
||||||
@@ -34,12 +36,14 @@ 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");
|
||||||
|
|
||||||
crate::player::spawn(commands, trigger.client_id, query, heads_db)
|
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_or("failed to spawn player")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -53,7 +57,8 @@ 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: Res<bevy_steamworks::Client>,
|
steam_client: Option<Res<bevy_steamworks::Client>>,
|
||||||
|
config: Res<NetConfig>,
|
||||||
) -> Result<(), BevyError> {
|
) -> Result<(), BevyError> {
|
||||||
info!("opening server");
|
info!("opening server");
|
||||||
|
|
||||||
@@ -66,6 +71,11 @@ 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 {
|
let steam_config = bevy_replicon_renet::steam::SteamServerConfig {
|
||||||
access_permission: bevy_replicon_renet::steam::AccessPermission::FriendsOnly,
|
access_permission: bevy_replicon_renet::steam::AccessPermission::FriendsOnly,
|
||||||
max_clients: 16,
|
max_clients: 16,
|
||||||
@@ -74,10 +84,35 @@ fn open_renet_server(
|
|||||||
let client = (**steam_client).clone();
|
let client = (**steam_client).clone();
|
||||||
let transport = SteamServerTransport::new(client, steam_config)?;
|
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(server);
|
||||||
commands.insert_resource(transport);
|
commands.insert_resource(transport);
|
||||||
|
|
||||||
info!("hosting a server");
|
info!("hosting server: netcode on port {port}");
|
||||||
|
} else {
|
||||||
|
return Err("Invalid configuration, choose either steam or netcode".into());
|
||||||
|
}
|
||||||
|
|
||||||
next.set(GameState::Playing);
|
next.set(GameState::Playing);
|
||||||
|
|
||||||
@@ -93,16 +128,17 @@ 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 = ClientPlayerId(PlayerId { id: 0 });
|
let id = ids.alloc();
|
||||||
commands.entity(client).insert(id);
|
commands.entity(client).insert(ClientPlayerId(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.0),
|
message: AssignClientPlayer(id),
|
||||||
});
|
});
|
||||||
|
|
||||||
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 }}
|
RUST_BACKTRACE=1 cargo r {{ server_args }} -- --netcode-host
|
||||||
|
|
||||||
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 --check --workspace
|
cargo sort --workspace
|
||||||
|
|
||||||
check:
|
check:
|
||||||
cargo sort --check --workspace
|
cargo sort --check --workspace
|
||||||
|
|||||||
Reference in New Issue
Block a user