diff options
-rw-r--r-- | Cargo.toml | 6 | ||||
-rw-r--r-- | src/conn.rs | 104 | ||||
-rw-r--r-- | src/lib.rs | 10 | ||||
-rw-r--r-- | src/to_clt.rs | 18 | ||||
-rw-r--r-- | src/to_srv.rs | 27 |
5 files changed, 162 insertions, 3 deletions
@@ -4,20 +4,24 @@ version = "0.1.0" edition = "2021" [features] -all = ["client", "server", "random", "serde"] +all = ["client", "server", "random", "serde", "conn"] client = [] +conn = ["dep:mt_rudp", "dep:thiserror"] random = ["dep:generate-random", "dep:rand"] serde = ["dep:serde", "dep:serde_arrays", "enumset/serde"] server = [] test = ["client", "server", "random"] [dependencies] +delegate = "0.9.0" enumset = { git = "https://github.com/Lymia/enumset" } generate-random = { git = "https://github.com/minetest-rust/generate-random", features = ["enumset"], optional = true } +mt_rudp = { git = "https://github.com/minetest-rust/mt_rudp", optional = true } mt_ser = { git = "https://github.com/minetest-rust/mt_ser" } rand = { version = "0.8.5", optional = true } serde = { version = "1.0.152", features = ["derive"], optional = true } serde_arrays = { version = "0.1.0", optional = true } +thiserror = { version = "1.0.38", optional = true } [dev-dependencies] libtest-mimic = "0.6.0" diff --git a/src/conn.rs b/src/conn.rs new file mode 100644 index 0000000..3fc0e55 --- /dev/null +++ b/src/conn.rs @@ -0,0 +1,104 @@ +use super::PktInfo; +use delegate::delegate; +use mt_ser::{DefCfg, MtDeserialize, MtSerialize}; +use std::{borrow::Cow, io}; +use thiserror::Error; + +pub trait Remote { + type UdpSender: mt_rudp::UdpSender; + type PktFrom: MtDeserialize; + type PktTo: MtSerialize + PktInfo; +} + +#[cfg(feature = "client")] +pub struct RemoteSrv; + +#[cfg(feature = "client")] +impl Remote for RemoteSrv { + type UdpSender = mt_rudp::ToSrv; + type PktTo = crate::ToSrvPkt; + type PktFrom = crate::ToCltPkt; +} + +#[cfg(feature = "client")] +pub async fn connect(addr: &str) -> io::Result<(MtSender<RemoteSrv>, MtReceiver<RemoteSrv>)> { + let (tx, rx) = mt_rudp::connect(addr).await?; + Ok((MtSender(tx), MtReceiver(rx))) +} + +/* + +pub struct RemoteClt; +impl Remote for RemoteClt { + type Sender = mt_rudp::ToClt; + type To = crate::ToCltPkt; + type From = crate::ToSrvPkt; +} + +*/ + +pub struct MtSender<R: Remote>(pub mt_rudp::RudpSender<R::UdpSender>); +pub struct MtReceiver<R: Remote>(pub mt_rudp::RudpReceiver<R::UdpSender>); + +#[derive(Error, Debug)] +pub enum RecvError { + #[error("connection error: {0}")] + ConnError(#[from] mt_rudp::Error), + #[error("deserialize error: {0}")] + DeserializeError(#[from] mt_ser::DeserializeError), +} + +#[derive(Error, Debug)] +pub enum SendError { + #[error("connection error: {0}")] + ConnError(#[from] io::Error), + #[error("serialize error: {0}")] + SerializeError(#[from] mt_ser::SerializeError), +} + +macro_rules! impl_delegate { + ($T:ident) => { + impl<R: Remote> $T<R> { + delegate! { + to self.0 { + pub async fn peer_id(&self) -> u16; + pub async fn is_server(&self) -> bool; + pub async fn close(self); + } + } + } + }; +} + +impl_delegate!(MtSender); +impl_delegate!(MtReceiver); + +impl<R: Remote> MtReceiver<R> { + pub async fn recv(&mut self) -> Option<Result<R::PktFrom, RecvError>> { + self.0.recv().await.map(|res| { + res.map_err(RecvError::from).and_then(|pkt| { + // TODO: warn on trailing data + R::PktFrom::mt_deserialize::<DefCfg>(&mut io::Cursor::new(pkt.data)) + .map_err(RecvError::from) + }) + }) + } +} + +impl<R: Remote> MtSender<R> { + pub async fn send(&self, pkt: &R::PktTo) -> Result<(), SendError> { + let mut writer = Vec::new(); + pkt.mt_serialize::<DefCfg>(&mut writer)?; + + let (chan, unrel) = pkt.pkt_info(); + self.0 + .send(mt_rudp::Pkt { + chan, + unrel, + data: Cow::Borrowed(&writer), + }) + .await?; + + Ok(()) + } +} @@ -29,8 +29,18 @@ use generate_random::GenerateRandom; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +#[cfg(feature = "conn")] +mod conn; + +#[cfg(feature = "conn")] +pub use conn::*; + mod to_clt; mod to_srv; pub use to_clt::*; pub use to_srv::*; + +pub trait PktInfo { + fn pkt_info(&self) -> (u8, bool); +} diff --git a/src/to_clt.rs b/src/to_clt.rs index 3792018..5f99be3 100644 --- a/src/to_clt.rs +++ b/src/to_clt.rs @@ -285,7 +285,7 @@ pub enum ToCltPkt { flags: EnumSet<HudFlag>, mask: EnumSet<HudFlag>, } = 76, - SetHotbarParam(HotbarParam) = 77, + HotbarParam(HotbarParam) = 77, Breath { breath: u16, } = 78, @@ -345,3 +345,19 @@ pub enum ToCltPkt { } = 97, MinimapModes(MinimapModesPkt) = 98, } + +impl PktInfo for ToCltPkt { + fn pkt_info(&self) -> (u8, bool) { + use ToCltPkt::*; + + match self { + BlockData { .. } | Media { .. } => (2, true), + AddHud { .. } + | ChangeHud { .. } + | RemoveHud { .. } + | HudFlags { .. } + | HotbarParam(_) => (1, true), + _ => (0, true), + } + } +} diff --git a/src/to_srv.rs b/src/to_srv.rs index 704acdb..dc9a342 100644 --- a/src/to_srv.rs +++ b/src/to_srv.rs @@ -77,6 +77,10 @@ pub enum ToSrvPkt { #[mt(len = "u8")] blocks: Vec<[i16; 3]>, } = 37, + HaveMedia { + #[mt(len = "u8")] + tokens: Vec<u32>, + } = 41, InvAction { #[mt(len = "()")] action: String, @@ -113,7 +117,7 @@ pub enum ToSrvPkt { #[mt(len = "(DefCfg, (DefCfg, u32))")] fields: HashMap<String, String>, } = 60, - ReqMedia { + RequestMedia { filenames: Vec<String>, } = 64, CltReady { @@ -138,3 +142,24 @@ pub enum ToSrvPkt { } = 82, Disco = 0xffff, } + +impl PktInfo for ToSrvPkt { + fn pkt_info(&self) -> (u8, bool) { + use ToSrvPkt::*; + + match self { + Init { .. } => (1, false), + Init2 { .. } + | RequestMedia { .. } + | CltReady { .. } + | FirstSrp { .. } + | SrpBytesA { .. } + | SrpBytesM { .. } => (1, true), + PlayerPos { .. } => (0, false), + GotBlocks { .. } | HaveMedia { .. } | DeletedBlocks { .. } | RemovedSounds { .. } => { + (2, true) + } + _ => (0, true), + } + } +} |