summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-07-14 21:00:54 +0200
committermetamuffin <metamuffin@disroot.org>2024-07-14 21:00:54 +0200
commitf6cc57f29fc65a33219b1266b3508dc40536f3c2 (patch)
tree3a5ee5897f778fd1e0547a3026060e579a4c7c56 /server
parent721b9ecb282f84839eb096de4d269176f8ab389f (diff)
downloadhurrycurry-f6cc57f29fc65a33219b1266b3508dc40536f3c2.tar
hurrycurry-f6cc57f29fc65a33219b1266b3508dc40536f3c2.tar.bz2
hurrycurry-f6cc57f29fc65a33219b1266b3508dc40536f3c2.tar.zst
add binary protocol support
Diffstat (limited to 'server')
-rw-r--r--server/Cargo.toml1
-rw-r--r--server/protocol/Cargo.toml2
-rw-r--r--server/protocol/src/lib.rs50
-rw-r--r--server/src/main.rs92
4 files changed, 98 insertions, 47 deletions
diff --git a/server/Cargo.toml b/server/Cargo.toml
index da084855..39b9ea1c 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -19,5 +19,6 @@ shlex = "1.3.0"
clap = { version = "4.5.8", features = ["derive"] }
fake = "2.9.2"
pollster = "0.3.0"
+bincode = "2.0.0-rc.3"
hurrycurry-protocol = { path = "protocol" }
diff --git a/server/protocol/Cargo.toml b/server/protocol/Cargo.toml
index 8fc63121..6c51c86d 100644
--- a/server/protocol/Cargo.toml
+++ b/server/protocol/Cargo.toml
@@ -6,4 +6,4 @@ edition = "2021"
[dependencies]
serde = { version = "1.0.204", features = ["derive"] }
glam = { version = "0.28.0", features = ["serde"] }
-
+bincode = { version = "2.0.0-rc.3", features = ["serde", "derive"] }
diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs
index 94bebf05..895af376 100644
--- a/server/protocol/src/lib.rs
+++ b/server/protocol/src/lib.rs
@@ -15,6 +15,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+use bincode::{
+ config::{standard, Configuration, Limit, LittleEndian, Varint},
+ Decode, Encode,
+};
use glam::{IVec2, Vec2};
use serde::{Deserialize, Serialize};
use std::{
@@ -26,31 +30,44 @@ pub use glam;
pub const VERSION: (u32, u32) = (1, 0);
-#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub const BINCODE_CONFIG: Configuration<LittleEndian, Varint, Limit<4096>> =
+ standard().with_limit();
+
+#[derive(
+ Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Hash,
+)]
#[serde(transparent)]
pub struct PlayerID(pub i64);
-#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(
+ Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Hash,
+)]
#[serde(transparent)]
pub struct ItemIndex(pub usize);
-#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(
+ Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Hash,
+)]
#[serde(transparent)]
pub struct TileIndex(pub usize);
-#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(
+ Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Hash,
+)]
#[serde(transparent)]
pub struct RecipeIndex(pub usize);
-#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(
+ Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Hash,
+)]
#[serde(transparent)]
pub struct DemandIndex(pub usize);
-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct MapMetadata {
name: String,
players: usize,
difficulty: i32,
}
-#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, Default)]
#[rustfmt::skip]
pub struct ClientGamedata {
pub item_names: Vec<String>,
@@ -61,7 +78,7 @@ pub struct ClientGamedata {
pub maps: HashMap<String, MapMetadata>,
}
-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum PacketS {
Join {
@@ -70,15 +87,18 @@ pub enum PacketS {
},
Leave,
Position {
+ #[bincode(with_serde)]
pos: Vec2,
rot: f32,
boosting: bool,
},
Interact {
+ #[bincode(with_serde)]
pos: Option<IVec2>,
},
Collide {
player: PlayerID,
+ #[bincode(with_serde)]
force: Vec2,
},
Communicate {
@@ -87,6 +107,7 @@ pub enum PacketS {
},
#[serde(skip)]
+ #[bincode(skip)]
/// For internal use only
ReplaceHand {
item: Option<ItemIndex>,
@@ -97,7 +118,7 @@ pub enum PacketS {
},
}
-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
#[serde(rename_all = "snake_case")]
pub enum Message {
Text(String),
@@ -105,12 +126,13 @@ pub enum Message {
Effect(String),
}
-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum PacketC {
Version {
minor: u32,
major: u32,
+ supports_bincode: bool,
},
Init {
id: PlayerID,
@@ -120,6 +142,7 @@ pub enum PacketC {
},
AddPlayer {
id: PlayerID,
+ #[bincode(with_serde)]
position: Vec2,
character: i32,
name: String,
@@ -129,6 +152,7 @@ pub enum PacketC {
},
Position {
player: PlayerID,
+ #[bincode(with_serde)]
pos: Vec2,
rot: f32,
boosting: bool,
@@ -147,12 +171,14 @@ pub enum PacketC {
warn: bool,
},
UpdateMap {
+ #[bincode(with_serde)]
tile: IVec2,
kind: Option<TileIndex>,
neighbors: [Option<TileIndex>; 4],
},
Collide {
player: PlayerID,
+ #[bincode(with_serde)]
force: Vec2,
},
Communicate {
@@ -181,10 +207,10 @@ pub enum PacketC {
ReplayStart,
}
-#[derive(Debug, Clone, Serialize, Deserialize, Copy, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, Copy, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum ItemLocation {
- Tile(IVec2),
+ Tile(#[bincode(with_serde)] IVec2),
Player(PlayerID),
}
diff --git a/server/src/main.rs b/server/src/main.rs
index 90d090d8..6f73851a 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -18,10 +18,19 @@
use anyhow::{anyhow, Result};
use clap::Parser;
use futures_util::{SinkExt, StreamExt};
-use hurrycurry_protocol::{PacketC, PacketS, PlayerID, VERSION};
+use hurrycurry_protocol::{PacketC, PacketS, PlayerID, BINCODE_CONFIG, VERSION};
use hurrycurry_server::{data::DATA_DIR, state::State};
use log::{debug, info, trace, warn, LevelFilter};
-use std::{path::PathBuf, process::exit, str::FromStr, sync::Arc, time::Duration};
+use std::{
+ path::PathBuf,
+ process::exit,
+ str::FromStr,
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+ },
+ time::Duration,
+};
use tokio::{
net::TcpListener,
spawn,
@@ -121,9 +130,14 @@ async fn run() -> anyhow::Result<()> {
PacketC::Version {
major: VERSION.0,
minor: VERSION.1,
+ supports_bincode: true,
},
);
init.insert(1, PacketC::Init { id });
+
+ let supports_binary = Arc::new(AtomicBool::new(false));
+ let supports_binary2 = supports_binary.clone();
+
spawn(async move {
for p in init {
if let Err(e) = write
@@ -154,52 +168,62 @@ async fn run() -> anyhow::Result<()> {
info!("client outbound sender dropped. closing connection");
break;
};
- if let Err(e) = write
- .send(tokio_tungstenite::tungstenite::Message::Text(
- serde_json::to_string(&packet).unwrap(),
- ))
- .await
- {
+ let message = if supports_binary.load(Ordering::Relaxed) {
+ Message::Binary(bincode::encode_to_vec(&packet, BINCODE_CONFIG).unwrap())
+ } else {
+ Message::Text(serde_json::to_string(&packet).unwrap())
+ };
+ if let Err(e) = write.send(message).await {
warn!("ws error: {e}");
break;
}
}
});
+
spawn(async move {
info!("{id:?} joined");
while let Some(Ok(message)) = read.next().await {
- match message {
- Message::Text(line) => {
- let packet = match serde_json::from_str(&line) {
- Ok(p) => p,
- Err(e) => {
- warn!("invalid packet: {e}");
- break;
- }
- };
- if matches!(
- packet,
- PacketS::Position { .. } | PacketS::ReplayTick { .. }
- ) {
- trace!("<- {id:?} {packet:?}");
- } else {
- debug!("<- {id:?} {packet:?}");
+ let packet = match message {
+ Message::Text(line) => match serde_json::from_str(&line) {
+ Ok(p) => p,
+ Err(e) => {
+ warn!("invalid json packet: {e}");
+ break;
}
- let packet_out = match state.write().await.packet_in(id, packet).await {
- Ok(packets) => packets,
+ },
+ Message::Binary(packet) => {
+ supports_binary2.store(true, Ordering::Relaxed);
+ match bincode::decode_from_slice::<PacketS, _>(&packet, BINCODE_CONFIG) {
+ Ok((p, _size)) => p,
Err(e) => {
- warn!("client error: {e}");
- vec![PacketC::Error {
- message: format!("{e}"),
- }]
+ warn!("invalid binary packet: {e}");
+ break;
}
- };
- for packet in packet_out {
- let _ = error_tx.send(packet).await;
}
}
Message::Close(_) => break,
- _ => (),
+ _ => continue,
+ };
+
+ if matches!(
+ packet,
+ PacketS::Position { .. } | PacketS::ReplayTick { .. }
+ ) {
+ trace!("<- {id:?} {packet:?}");
+ } else {
+ debug!("<- {id:?} {packet:?}");
+ }
+ let packet_out = match state.write().await.packet_in(id, packet).await {
+ Ok(packets) => packets,
+ Err(e) => {
+ warn!("client error: {e}");
+ vec![PacketC::Error {
+ message: format!("{e}"),
+ }]
+ }
+ };
+ for packet in packet_out {
+ let _ = error_tx.send(packet).await;
}
}
info!("{id:?} left");