[features]
all = ["client", "server", "random", "serde"]
-test = ["client", "server", "random"]
client = []
random = ["dep:generate-random", "dep:rand"]
serde = ["dep:serde", "dep:serde_arrays", "enumset/serde"]
server = []
+test = ["client", "server", "random"]
[dependencies]
-mt_ser = { git = "https://github.com/minetest-rust/mt_ser" }
-#mt_ser = { path = "../mt_ser" }
enumset = { git = "https://github.com/Lymia/enumset" }
generate-random = { git = "https://github.com/minetest-rust/generate-random", features = ["enumset"], optional = true }
+mt_ser = { git = "https://github.com/minetest-rust/mt_ser" }
+#mt_ser = { path = "../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 }
libtest-mimic = "0.6.0"
[[test]]
+harness = false
name = "random"
path = "tests/random.rs"
-harness = false
SetState,
}
-mod chat;
-mod env;
+#[mt_derive(to = "clt", repr = "u32", enumset)]
+pub enum AuthMethod {
+ LegacyPasswd,
+ Srp,
+ FirstSrp,
+}
+
+#[mt_derive(to = "clt", repr = "u64", enumset)]
+pub enum CsmRestrictionFlag {
+ NoCsms,
+ NoChatMsgs,
+ NoItemDefs,
+ NoNodeDefs,
+ LimitMapRange,
+ NoPlayerList,
+}
+
+#[mt_derive(to = "clt", repr = "u8")]
+pub enum ChatMsgType {
+ Raw = 0,
+ Normal,
+ Announce,
+ System,
+}
+
+#[mt_derive(to = "clt", repr = "u8")]
+pub enum PlayerListUpdateType {
+ Init = 0,
+ Add,
+ Remove,
+}
+
mod hud;
+mod inv;
+mod kick;
+mod map;
mod media;
+mod obj;
mod sky;
-mod status;
-pub use chat::*;
-pub use env::*;
pub use hud::*;
+pub use inv::*;
+pub use kick::*;
+pub use map::*;
pub use media::*;
+pub use obj::*;
pub use sky::*;
-pub use status::*;
#[mt_derive(to = "clt", repr = "u16", tag = "type", content = "data")]
pub enum ToCltPkt {
pos: [i16; 3],
} = 34,
Inv {
+ #[mt(len = "()")]
inv: String,
} = 39,
TimeOfDay {
channel: String,
} = 88,
NodeMetasChanged {
- #[mt(size = "u32")]
+ #[mt(size = "u32", zlib)]
+ #[mt(len = "NodeMetasLen")]
changed: HashMap<[i16; 3], NodeMeta>,
} = 89,
SunParams(SunParams) = 90,
+++ /dev/null
-use super::*;
-
-#[mt_derive(to = "clt", repr = "u8")]
-pub enum ChatMsgType {
- Raw = 0,
- Normal,
- Announce,
- System,
-}
-
-#[mt_derive(to = "clt", repr = "u8")]
-pub enum PlayerListUpdateType {
- Init = 0,
- Add,
- Remove,
-}
+++ /dev/null
-use super::*;
-
-#[mt_derive(to = "clt", repr = "str")]
-pub enum ObjVisual {
- Cube,
- Sprite,
- UprightSprite,
- Mesh,
- Wielditem,
- Item,
-}
-
-#[mt_derive(to = "clt")]
-pub struct ObjProps {
- #[mt(const_before = "4u8")] // version
- pub max_hp: u16, // player only
- pub collide_with_nodes: bool,
- pub weight: f32, // deprecated
- pub collision_box: ([f32; 3], [f32; 3]),
- pub selection_box: ([f32; 3], [f32; 3]),
- pub pointable: bool,
- pub visual: ObjVisual,
- pub visual_size: [f32; 3],
- pub textures: Vec<String>,
- pub sprite_sheet_size: [i16; 2], // in sprites
- pub sprite_pos: [i16; 2], // in sprite sheet
- pub visible: bool,
- pub make_footstep_sounds: bool,
- pub rotate_speed: f32, // in radians per second
- pub mesh: String,
- pub colors: Vec<Color>,
- pub collide_with_objs: bool,
- pub step_height: f32,
- pub face_rotate_dir: bool,
- pub face_rotate_dir_off: f32, // in degrees
- pub backface_cull: bool,
- pub nametag: String,
- pub nametag_color: Color,
- pub face_rotate_speed: f32, // in degrees per second
- pub infotext: String,
- pub itemstring: String,
- pub glow: i8,
- pub max_breath: u16, // player only
- pub eye_height: f32, // player only
- pub zoom_fov: f32, // in degrees. player only
- pub use_texture_alpha: bool,
- pub dmg_texture_mod: String, // suffix
- pub shaded: bool,
- pub show_on_minimap: bool,
- pub nametag_bg: Color,
-}
-
-#[mt_derive(to = "clt")]
-pub struct ObjPos {
- pub pos: [f32; 3],
- pub vel: [f32; 3],
- pub acc: [f32; 3],
- pub rot: [f32; 3],
- pub interpolate: bool,
- pub end: bool,
- pub update_interval: f32,
-}
-
-#[mt_derive(to = "clt")]
-pub struct ObjSprite {
- pub frame0: [i16; 2],
- pub frames: u16,
- pub frame_duration: f32,
- pub view_angle_frames: bool,
-}
-
-#[mt_derive(to = "clt")]
-pub struct ObjAnim {
- pub frames: [i32; 2],
- pub speed: f32,
- pub blend: f32,
- pub no_loop: bool,
-}
-
-#[mt_derive(to = "clt")]
-pub struct ObjBonePos {
- pub pos: [f32; 3],
- pub rot: [f32; 3],
-}
-
-#[mt_derive(to = "clt")]
-pub struct ObjAttach {
- pub parent_id: u16,
- pub bone: String,
- pub pos: [f32; 3],
- pub rot: [f32; 3],
- pub force_visible: bool,
-}
-
-#[mt_derive(to = "clt")]
-pub struct ObjPhysicsOverride {
- pub walk: f32,
- pub jump: f32,
- pub gravity: f32,
- // the following are player only
- pub no_sneak: bool,
- pub no_sneak_glitch: bool,
- pub old_sneak: bool,
-}
-
-pub const GENERIC_CAO: u8 = 101;
-
-#[mt_derive(to = "clt", repr = "u8", tag = "type", content = "data")]
-pub enum ObjMsg {
- Props(ObjProps) = 0,
- Pos(ObjPos),
- TextureMod {
- #[serde(rename = "mod")]
- texture_mod: String,
- },
- Sprite(ObjSprite),
- Hp {
- hp: u16,
- },
- ArmorGroups {
- armor: HashMap<String, u16>,
- },
- Anim(ObjAnim),
- BonePos {
- bone: String,
- pos: ObjBonePos,
- },
- Attach(ObjAttach),
- PhysicsOverride(ObjPhysicsOverride),
- SpawnInfant {
- #[mt(const_after = "GENERIC_CAO")]
- id: u16,
- } = 11,
- AnimSpeed {
- speed: f32,
- },
-}
-
-#[mt_derive(to = "clt")]
-pub struct ObjIdMsg {
- pub id: u16,
- #[mt(size = "u16")]
- pub msg: ObjMsg,
-}
-
-#[mt_derive(to = "clt")]
-pub struct ObjInitMsg(#[mt(size = "u32")] pub ObjMsg);
-
-#[mt_derive(to = "clt")]
-pub struct ObjInitData {
- #[mt(const_before = "1u8")] // version
- pub name: String,
- pub is_player: bool,
- pub id: u16,
- pub pos: [f32; 3],
- pub rot: [f32; 3],
- pub hp: u16,
- #[mt(len = "u8")]
- pub msgs: Vec<ObjInitMsg>,
-}
-
-#[mt_derive(to = "clt")]
-pub struct ObjAdd {
- pub id: u16,
- #[mt(const_before = "GENERIC_CAO")]
- #[mt(size = "u32")]
- pub init_data: ObjInitData,
-}
-
-#[mt_derive(to = "clt", repr = "u8", enumset)]
-pub enum MapBlockFlag {
- IsUnderground = 0,
- DayNightDiff,
- LightExpired,
- NotGenerated,
-}
-
-pub const ALWAYS_LIT_FROM: u16 = 0xf000;
-
-pub const CONTENT_UNKNOWN: u16 = 125;
-pub const CONTENT_AIR: u16 = 126;
-pub const CONTENT_IGNORE: u16 = 127;
-
-#[mt_derive(to = "clt")]
-pub struct MapBlock {
- pub flags: EnumSet<MapBlockFlag>,
- pub lit_from: u16,
- #[mt(const_before = "2u8")] // param0 size
- #[mt(const_before = "2u8")] // param1 size + param2 size
- #[serde(with = "serde_arrays")]
- pub param_0: [u16; 4096],
- #[serde(with = "serde_arrays")]
- pub param_1: [u8; 4096],
- #[serde(with = "serde_arrays")]
- pub param_2: [u8; 4096],
- #[mt(const_after = "2u8")] // version
- pub node_metas: HashMap<u16, NodeMeta>,
-}
--- /dev/null
+use super::*;
+use mt_ser::{DeserializeError, SerializeError};
+use std::io::{Read, Write};
+
+#[mt_derive(to = "clt", custom)]
+pub struct Inventory; // TODO
+
+#[cfg(feature = "server")]
+impl MtSerialize for Inventory {
+ fn mt_serialize<C: MtCfg>(&self, writer: &mut impl Write) -> Result<(), SerializeError> {
+ "EndInventory\n".mt_serialize::<()>(writer)
+ }
+}
+
+fn read_line(reader: &mut impl Read) -> Result<String, DeserializeError> {
+ let utf8 = mt_ser::mt_deserialize_seq::<(), u8>(reader)?
+ .map_while(|x| match x {
+ Ok(0x0A) => None,
+ x => Some(x),
+ })
+ .try_collect::<Vec<_>>()?;
+
+ String::from_utf8(utf8)
+ .map_err(|e| DeserializeError::Other(format!("Invalid UTF-8: {e}").into()))
+}
+
+#[cfg(feature = "client")]
+impl MtDeserialize for Inventory {
+ fn mt_deserialize<C: MtCfg>(reader: &mut impl Read) -> Result<Self, DeserializeError> {
+ loop {
+ match read_line(reader)?.as_str() {
+ "EndInventory" => return Ok(Self),
+ _ => {}
+ }
+ }
+ }
+}
--- /dev/null
+use super::*;
+
+#[mt_derive(to = "clt", repr = "u8", tag = "reason")]
+pub enum KickReason {
+ WrongPasswd,
+ UnexpectedData,
+ SrvIsSingleplayer,
+ UnsupportedVersion,
+ BadNameChars,
+ BadName,
+ TooManyClts,
+ EmptyPasswd,
+ AlreadyConnected,
+ SrvErr,
+ Custom { custom: String },
+ Shutdown { custom: String, reconnect: bool },
+ Crash { custom: String, reconnect: bool },
+}
+
+impl KickReason {
+ pub fn reconnect(&self) -> bool {
+ use KickReason::*;
+
+ match self {
+ Shutdown { reconnect, .. } | Crash { reconnect, .. } => *reconnect,
+ _ => false,
+ }
+ }
+}
+
+impl fmt::Display for KickReason {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use KickReason::*;
+
+ match self {
+ WrongPasswd => write!(f, "wrong password"),
+ UnexpectedData => write!(f, "unexpected data"),
+ SrvIsSingleplayer => write!(f, "server is singleplayer"),
+ UnsupportedVersion => write!(f, "unsupported client version"),
+ BadNameChars => write!(f, "disallowed character(s) in player name"),
+ BadName => write!(f, "disallowed player name"),
+ TooManyClts => write!(f, "too many clients"),
+ EmptyPasswd => write!(f, "empty password"),
+ AlreadyConnected => write!(f, "another client is already connected with the same name"),
+ SrvErr => write!(f, "unsupported client version"),
+ Custom { custom } => write!(f, "{custom}"),
+ Shutdown { custom, .. } => {
+ if custom.is_empty() {
+ write!(f, "server shutdown")
+ } else {
+ write!(f, "server shutdown: {custom}")
+ }
+ }
+ Crash { custom, .. } => {
+ if custom.is_empty() {
+ write!(f, "server crash")
+ } else {
+ write!(f, "server crash: {custom}")
+ }
+ }
+ }
+ }
+}
--- /dev/null
+use super::*;
+use mt_ser::{DeserializeError, SerializeError};
+
+#[mt_derive(to = "clt", repr = "u8", enumset)]
+pub enum MapBlockFlag {
+ IsUnderground = 0,
+ DayNightDiff,
+ LightExpired,
+ NotGenerated,
+}
+
+pub const ALWAYS_LIT_FROM: u16 = 0xf000;
+
+pub const CONTENT_UNKNOWN: u16 = 125;
+pub const CONTENT_AIR: u16 = 126;
+pub const CONTENT_IGNORE: u16 = 127;
+
+#[mt_derive(to = "clt")]
+pub struct NodeMetaField {
+ #[mt(len = "u32")]
+ value: String,
+ private: bool,
+}
+
+#[mt_derive(to = "clt")]
+pub struct NodeMeta {
+ #[mt(len = "u32")]
+ fields: HashMap<String, NodeMetaField>,
+ inv: Inventory,
+}
+
+#[derive(Debug)]
+pub struct NodeMetasLen;
+
+impl MtCfg for NodeMetasLen {
+ type Len = <DefCfg as MtCfg>::Len;
+ type Inner = <DefCfg as MtCfg>::Inner;
+
+ fn write_len(len: usize, writer: &mut impl std::io::Write) -> Result<(), SerializeError> {
+ if len == 0 {
+ 0u8.mt_serialize::<DefCfg>(writer)
+ } else {
+ 2u8.mt_serialize::<DefCfg>(writer)?;
+ DefCfg::write_len(len, writer)
+ }
+ }
+
+ fn read_len(reader: &mut impl std::io::Read) -> Result<Self::Len, DeserializeError> {
+ match u8::mt_deserialize::<DefCfg>(reader)? {
+ 0 => Ok(0),
+ 2 => DefCfg::read_len(reader),
+ x => Err(DeserializeError::InvalidEnum("NodeMetasLen", Box::new(x))),
+ }
+ }
+}
+
+#[mt_derive(to = "clt")]
+pub struct MapBlock {
+ pub flags: EnumSet<MapBlockFlag>,
+ pub lit_from: u16,
+ #[mt(const_before = "2u8")] // param0 size
+ #[mt(const_before = "2u8")] // param1 size + param2 size
+ #[serde(with = "serde_arrays")]
+ pub param_0: [u16; 4096],
+ #[serde(with = "serde_arrays")]
+ pub param_1: [u8; 4096],
+ #[serde(with = "serde_arrays")]
+ pub param_2: [u8; 4096],
+ #[mt(len = "NodeMetasLen")]
+ pub metas: HashMap<u16, NodeMeta>,
+}
#[mt_derive(to = "clt")]
pub struct NodeDef; // TODO
-#[mt_derive(to = "clt")]
-pub struct NodeMeta; // TODO
-
#[mt_derive(to = "clt", repr = "u8")]
pub enum SoundSrcType {
Nowhere = 0,
--- /dev/null
+use super::*;
+
+#[mt_derive(to = "clt", repr = "str")]
+pub enum ObjVisual {
+ Cube,
+ Sprite,
+ UprightSprite,
+ Mesh,
+ Wielditem,
+ Item,
+}
+
+#[mt_derive(to = "clt")]
+pub struct ObjProps {
+ #[mt(const_before = "4u8")] // version
+ pub max_hp: u16, // player only
+ pub collide_with_nodes: bool,
+ pub weight: f32, // deprecated
+ pub collision_box: ([f32; 3], [f32; 3]),
+ pub selection_box: ([f32; 3], [f32; 3]),
+ pub pointable: bool,
+ pub visual: ObjVisual,
+ pub visual_size: [f32; 3],
+ pub textures: Vec<String>,
+ pub sprite_sheet_size: [i16; 2], // in sprites
+ pub sprite_pos: [i16; 2], // in sprite sheet
+ pub visible: bool,
+ pub make_footstep_sounds: bool,
+ pub rotate_speed: f32, // in radians per second
+ pub mesh: String,
+ pub colors: Vec<Color>,
+ pub collide_with_objs: bool,
+ pub step_height: f32,
+ pub face_rotate_dir: bool,
+ pub face_rotate_dir_off: f32, // in degrees
+ pub backface_cull: bool,
+ pub nametag: String,
+ pub nametag_color: Color,
+ pub face_rotate_speed: f32, // in degrees per second
+ pub infotext: String,
+ pub itemstring: String,
+ pub glow: i8,
+ pub max_breath: u16, // player only
+ pub eye_height: f32, // player only
+ pub zoom_fov: f32, // in degrees. player only
+ pub use_texture_alpha: bool,
+ pub dmg_texture_mod: String, // suffix
+ pub shaded: bool,
+ pub show_on_minimap: bool,
+ pub nametag_bg: Color,
+}
+
+#[mt_derive(to = "clt")]
+pub struct ObjPos {
+ pub pos: [f32; 3],
+ pub vel: [f32; 3],
+ pub acc: [f32; 3],
+ pub rot: [f32; 3],
+ pub interpolate: bool,
+ pub end: bool,
+ pub update_interval: f32,
+}
+
+#[mt_derive(to = "clt")]
+pub struct ObjSprite {
+ pub frame0: [i16; 2],
+ pub frames: u16,
+ pub frame_duration: f32,
+ pub view_angle_frames: bool,
+}
+
+#[mt_derive(to = "clt")]
+pub struct ObjAnim {
+ pub frames: [i32; 2],
+ pub speed: f32,
+ pub blend: f32,
+ pub no_loop: bool,
+}
+
+#[mt_derive(to = "clt")]
+pub struct ObjBonePos {
+ pub pos: [f32; 3],
+ pub rot: [f32; 3],
+}
+
+#[mt_derive(to = "clt")]
+pub struct ObjAttach {
+ pub parent_id: u16,
+ pub bone: String,
+ pub pos: [f32; 3],
+ pub rot: [f32; 3],
+ pub force_visible: bool,
+}
+
+#[mt_derive(to = "clt")]
+pub struct ObjPhysicsOverride {
+ pub walk: f32,
+ pub jump: f32,
+ pub gravity: f32,
+ // the following are player only
+ pub no_sneak: bool,
+ pub no_sneak_glitch: bool,
+ pub old_sneak: bool,
+}
+
+pub const GENERIC_CAO: u8 = 101;
+
+#[mt_derive(to = "clt", repr = "u8", tag = "type", content = "data")]
+pub enum ObjMsg {
+ Props(Box<ObjProps>) = 0,
+ Pos(ObjPos),
+ TextureMod {
+ #[serde(rename = "mod")]
+ texture_mod: String,
+ },
+ Sprite(ObjSprite),
+ Hp {
+ hp: u16,
+ },
+ ArmorGroups {
+ armor: HashMap<String, u16>,
+ },
+ Anim(ObjAnim),
+ BonePos {
+ bone: String,
+ pos: ObjBonePos,
+ },
+ Attach(ObjAttach),
+ PhysicsOverride(ObjPhysicsOverride),
+ SpawnInfant {
+ #[mt(const_after = "GENERIC_CAO")]
+ id: u16,
+ } = 11,
+ AnimSpeed {
+ speed: f32,
+ },
+}
+
+#[mt_derive(to = "clt")]
+pub struct ObjIdMsg {
+ pub id: u16,
+ #[mt(size = "u16")]
+ pub msg: ObjMsg,
+}
+
+#[mt_derive(to = "clt")]
+pub struct ObjInitMsg(#[mt(size = "u32")] pub ObjMsg);
+
+#[mt_derive(to = "clt")]
+pub struct ObjInitData {
+ #[mt(const_before = "1u8")] // version
+ pub name: String,
+ pub is_player: bool,
+ pub id: u16,
+ pub pos: [f32; 3],
+ pub rot: [f32; 3],
+ pub hp: u16,
+ #[mt(len = "u8")]
+ pub msgs: Vec<ObjInitMsg>,
+}
+
+#[mt_derive(to = "clt")]
+pub struct ObjAdd {
+ pub id: u16,
+ #[mt(const_before = "GENERIC_CAO")]
+ #[mt(size = "u32")]
+ pub init_data: ObjInitData,
+}
+++ /dev/null
-use super::*;
-
-#[mt_derive(to = "clt", repr = "u8", tag = "reason")]
-pub enum KickReason {
- WrongPasswd,
- UnexpectedData,
- SrvIsSingleplayer,
- UnsupportedVersion,
- BadNameChars,
- BadName,
- TooManyClts,
- EmptyPasswd,
- AlreadyConnected,
- SrvErr,
- Custom { custom: String },
- Shutdown { custom: String, reconnect: bool },
- Crash { custom: String, reconnect: bool },
-}
-
-impl KickReason {
- pub fn reconnect(&self) -> bool {
- use KickReason::*;
-
- match self {
- Shutdown { reconnect, .. } | Crash { reconnect, .. } => *reconnect,
- _ => false,
- }
- }
-}
-
-impl fmt::Display for KickReason {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use KickReason::*;
-
- match self {
- WrongPasswd => write!(f, "wrong password"),
- UnexpectedData => write!(f, "unexpected data"),
- SrvIsSingleplayer => write!(f, "server is singleplayer"),
- UnsupportedVersion => write!(f, "unsupported client version"),
- BadNameChars => write!(f, "disallowed character(s) in player name"),
- BadName => write!(f, "disallowed player name"),
- TooManyClts => write!(f, "too many clients"),
- EmptyPasswd => write!(f, "empty password"),
- AlreadyConnected => write!(f, "another client is already connected with the same name"),
- SrvErr => write!(f, "unsupported client version"),
- Custom { custom } => write!(f, "{custom}"),
- Shutdown { custom, .. } => {
- if custom.is_empty() {
- write!(f, "server shutdown")
- } else {
- write!(f, "server shutdown: {custom}")
- }
- }
- Crash { custom, .. } => {
- if custom.is_empty() {
- write!(f, "server crash")
- } else {
- write!(f, "server crash: {custom}")
- }
- }
- }
- }
-}
-
-#[mt_derive(to = "clt", repr = "u32", enumset)]
-pub enum AuthMethod {
- LegacyPasswd,
- Srp,
- FirstSrp,
-}
-
-#[mt_derive(to = "clt", repr = "u64", enumset)]
-pub enum CsmRestrictionFlag {
- NoCsms,
- NoChatMsgs,
- NoItemDefs,
- NoNodeDefs,
- LimitMapRange,
- NoPlayerList,
-}