From: Lizzy Fleckenstein Date: Mon, 6 Feb 2023 18:56:53 +0000 (+0100) Subject: Initial commit X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=be0db6761c344a53a13f569a934b33d01eb54147;p=mt_ser.git Initial commit --- be0db6761c344a53a13f569a934b33d01eb54147 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b2f6f64 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "mt_data" +version = "0.1.0" +edition = "2021" + +[features] +client = [] +random = ["dep:generate-random", "dep:rand"] +serde = ["dep:serde", "dep:serde_arrays", "enumset/serde"] +server = [] + +[dependencies] +enumset = { git = "https://github.com/Lymia/enumset" } +generate-random = { git = "https://github.com/minetest-rust/generate-random", features = ["enumset"], optional = true } +mt_data_derive = { path = "derive" } +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 = "1.0.38" diff --git a/derive/Cargo.lock b/derive/Cargo.lock new file mode 100644 index 0000000..63bbb8c --- /dev/null +++ b/derive/Cargo.lock @@ -0,0 +1,101 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "darling" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "mt_data_derive" +version = "0.1.0" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" diff --git a/derive/Cargo.toml b/derive/Cargo.toml new file mode 100644 index 0000000..5597554 --- /dev/null +++ b/derive/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "mt_data_derive" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "1", features = ["full", "extra-traits", "printing"] } +quote = "1" +proc-macro2 = "1" +darling = "0.14.2" diff --git a/derive/src/lib.rs b/derive/src/lib.rs new file mode 100644 index 0000000..8daabf0 --- /dev/null +++ b/derive/src/lib.rs @@ -0,0 +1,170 @@ +use darling::FromMeta; +use proc_macro::{self, TokenStream}; +use quote::{quote, ToTokens}; +use syn::{parse_macro_input, parse_quote}; + +#[derive(Debug, FromMeta, Copy, Clone, Eq, PartialEq)] +#[darling(rename_all = "snake_case")] +enum To { + Clt, + Srv, +} + +#[derive(Debug, FromMeta)] +struct MacroArgs { + to: To, + repr: Option, + tag: Option, + content: Option, + #[darling(default)] + enumset: bool, +} + +fn wrap_attr(attr: &mut syn::Attribute) { + match attr.path.get_ident().map(|i| i.to_string()).as_deref() { + Some("mt") => { + let path = attr.path.clone(); + let tokens = attr.tokens.clone(); + + *attr = parse_quote! { + #[cfg_attr(any(feature = "client", feature = "server"), #path #tokens)] + }; + } + Some("serde") => { + let path = attr.path.clone(); + let tokens = attr.tokens.clone(); + + *attr = parse_quote! { + #[cfg_attr(feature = "serde", #path #tokens)] + }; + } + _ => {} + } +} + +#[proc_macro_attribute] +pub fn mt_derive(attr: TokenStream, item: TokenStream) -> TokenStream { + let item2 = item.clone(); + + let attr_args = parse_macro_input!(attr as syn::AttributeArgs); + let mut input = parse_macro_input!(item2 as syn::Item); + + let args = match MacroArgs::from_list(&attr_args) { + Ok(v) => v, + Err(e) => { + return TokenStream::from(e.write_errors()); + } + }; + + let (serializer, deserializer) = match args.to { + To::Clt => ("server", "client"), + To::Srv => ("client", "server"), + }; + + let mut out = quote! { + #[derive(Debug)] + #[cfg_attr(feature = "random", derive(GenerateRandom))] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + }; + + macro_rules! iter { + ($t:expr, $f:expr) => { + $t.iter_mut().for_each($f) + }; + } + + match &mut input { + syn::Item::Enum(e) => { + iter!(e.attrs, wrap_attr); + iter!(e.variants, |v| { + iter!(v.attrs, wrap_attr); + iter!(v.fields, |f| iter!(f.attrs, wrap_attr)); + }); + + let repr = args.repr.expect("missing repr for enum"); + + if args.enumset { + let repr_str = repr.to_token_stream().to_string(); + + out.extend(quote! { + #[derive(EnumSetType)] + #[enumset(repr = #repr_str, serialize_as_map)] + }) + } else { + let has_payload = e + .variants + .iter() + .find_map(|v| if v.fields.is_empty() { None } else { Some(()) }) + .is_some(); + + if has_payload { + let tag = args.tag.expect("missing tag for enum with payload"); + + out.extend(quote! { + #[derive(Clone)] + #[cfg_attr(feature = "serde", serde(tag = #tag))] + }); + + if let Some(content) = args.content { + out.extend(quote! { + #[cfg_attr(feature = "serde", serde(content = #content))] + }); + } + } else { + out.extend(quote! { + #[derive(Copy, Clone, PartialEq, Eq)] + }); + } + + out.extend(quote! { + #[repr(#repr)] + #[cfg_attr(feature = #serializer, derive(MtSerialize))] + #[cfg_attr(feature = #deserializer, derive(MtDeserialize))] + }); + } + + out.extend(quote! { + #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] + }); + } + syn::Item::Struct(s) => { + iter!(s.attrs, wrap_attr); + iter!(s.fields, |f| iter!(f.attrs, wrap_attr)); + + out.extend(quote! { + #[derive(Clone)] + #[cfg_attr(feature = #serializer, derive(MtSerialize))] + #[cfg_attr(feature = #deserializer, derive(MtDeserialize))] + }); + } + _ => panic!("only enum and struct supported"), + } + + out.extend(input.to_token_stream()); + out.into() +} + +#[proc_macro_derive(MtSerialize, attributes(mt))] +pub fn derive_serialize(input: TokenStream) -> TokenStream { + let syn::DeriveInput { ident, .. } = parse_macro_input!(input); + let output = quote! { + impl MtSerialize for #ident { + fn mt_serialize(&self, writer: &mut W) -> Result<(), mt_data::SerializeError> { + Err(mt_data::SerializeError::Unimplemented) + } + } + }; + output.into() +} + +#[proc_macro_derive(MtDeserialize, attributes(mt))] +pub fn derive_deserialize(input: TokenStream) -> TokenStream { + let syn::DeriveInput { ident, .. } = parse_macro_input!(input); + quote! { + impl MtDeserialize for #ident { + fn mt_deserialize(reader: &mut R) -> Result { + Err(mt_data::DeserializeError::Unimplemented) + } + } + }.into() +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..143b397 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,52 @@ +pub use enumset; + +#[cfg(feature = "random")] +pub use generate_random; + +#[cfg(feature = "random")] +pub use rand; + +#[cfg(feature = "serde")] +pub use serde; + +use enumset::{EnumSet, EnumSetType}; +use mt_data_derive::mt_derive; +pub use mt_data_derive::{MtDeserialize, MtSerialize}; +use std::{collections::HashMap, fmt, io}; +use thiserror::Error; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "random")] +use generate_random::GenerateRandom; + +#[derive(Error, Debug)] +pub enum SerializeError { + #[error("{0}")] + IoError(#[from] io::Error), + #[error("serialization is not implemented")] + Unimplemented, +} + +#[derive(Error, Debug)] +pub enum DeserializeError { + #[error("{0}")] + IoError(#[from] io::Error), + #[error("deserialization is not implemented")] + Unimplemented, +} + +pub trait MtSerialize: Sized { + fn mt_serialize(&self, writer: &mut W) -> Result<(), SerializeError>; +} + +pub trait MtDeserialize: Sized { + fn mt_deserialize(reader: &mut R) -> Result; +} + +mod to_clt; +mod to_srv; + +pub use to_clt::*; +pub use to_srv::*; diff --git a/src/to_clt.rs b/src/to_clt.rs new file mode 100644 index 0000000..6a4b3c6 --- /dev/null +++ b/src/to_clt.rs @@ -0,0 +1,330 @@ +use crate::*; + +#[mt_derive(to = "clt")] +pub struct ArgbColor { + pub a: u8, + pub r: u8, + pub g: u8, + pub b: u8, +} + +#[mt_derive(to = "clt", repr = "u8")] +pub enum ModChanSig { + JoinOk = 0, + JoinFail, + LeaveOk, + LeaveFail, + NotRegistered, + SetState, +} + +mod chat; +mod env; +mod hud; +mod media; +mod status; + +pub use chat::*; +pub use env::*; +pub use hud::*; +pub use media::*; +pub use status::*; + +#[mt_derive(to = "clt", repr = "u8", tag = "type", content = "data")] +pub enum ToCltPkt { + Hello { + serialize_version: u8, + #[mt(const16 = 1)] // compression + proto_version: u16, + auth_methods: EnumSet, + username: String, + } = 2, + AcceptAuth { + player_pos: [f32; 3], + map_seed: u64, + send_interval: f32, + sudo_auth_methods: EnumSet, + } = 3, + AcceptSudoMode { + sudo_auth_methods: EnumSet, + } = 4, + DenySudoMode = 5, + Kick(KickReason) = 10, + BlockData { + pos: [i16; 3], + #[mt(zstd)] + block: Box, + } = 32, + AddNode { + pos: [i16; 3], + param0: u16, + param1: u8, + param2: u8, + keep_meta: bool, + } = 33, + RemoveNode { + pos: [i16; 3], + } = 34, + Inv { + inv: String, + } = 39, + TimeOfDay { + time: u16, + speed: f32, + } = 41, + CsmRestrictionFlags { + flags: EnumSet, + map_range: u32, + } = 42, + AddPlayerVelocity { + vel: [f32; 3], + } = 43, + MediaPush { + no_len_hash: String, + filename: String, + callback_token: u32, + should_cache: bool, + } = 44, + ChatMsg { + #[mt(const8 = 1)] + msg_type: ChatMsgType, + #[mt(utf16)] + sender: String, + #[mt(utf16)] + text: String, + timestamp: i64, // unix time + } = 47, + ObjRemoveAdd { + remove: Vec, + add: Vec, + } = 49, + ObjMsgs { + msgs: Vec, + } = 50, + Hp { + hp: u16, + #[mt(default)] + damage_effect: bool, + } = 51, + MovePlayer { + pos: [f32; 3], + pitch: f32, + yaw: f32, + } = 52, + LegacyKick { + #[mt(utf16)] + reason: String, + } = 53, + Fov { + fov: f32, + multiplier: bool, + transition_time: f32, + } = 54, + DeathScreen { + point_cam: bool, + point_at: [f32; 3], + } = 55, + Media { + n: u16, + i: u16, + files: Vec, + } = 56, + NodeDefs { + defs: Vec, + } = 58, + AnnounceMedia { + files: Vec, + url: String, + } = 60, + #[mt(size32, zlib)] + ItemDefs { + #[mt(const8 = 0)] // version + defs: Vec, + aliases: HashMap, + } = 61, + PlaySound { + id: u32, + name: String, + gain: f32, + src_type: SoundSrcType, + pos: [f32; 3], + src_obj_id: u16, + #[serde(rename = "loop")] + sound_loop: bool, + fade: f32, + pitch: f32, + ephermeral: bool, + } = 63, + StopSound { + id: u32, + } = 64, + Privs { + privs: Vec, + } = 65, + InvFormspec { + #[mt(size32)] + formspec: String, + } = 66, + DetachedInv { + name: String, + keep: bool, + len: u16, + #[mt(len0)] + inv: String, + } = 67, + ShowFormspec { + #[mt(len32)] + formspec: String, + formname: String, + } = 68, + Movement { + default_accel: f32, + air_accel: f32, + fast_accel: f32, + walk_speed: f32, + crouch_speed: f32, + fast_speed: f32, + climb_speed: f32, + jump_speed: f32, + gravity: f32, + } = 69, + SpawnParticle { + pos: [f32; 3], + vel: [f32; 3], + acc: [f32; 3], + expiration_time: f32, + size: f32, + collide: bool, + #[mt(len32)] + texture: String, + vertical: bool, + collision_rm: bool, + anim_params: TileAnim, + glow: u8, + obj_collision: bool, + node_param0: u16, + node_param2: u8, + node_tile: u8, + } = 70, + AddParticleSpawner { + amount: u16, + duration: f32, + pos: [[f32; 3]; 2], + vel: [[f32; 3]; 2], + acc: [[f32; 3]; 2], + expiration_time: [f32; 2], + size: [f32; 2], + collide: bool, + #[mt(len32)] + texture: String, + id: u32, + vertical: bool, + collision_rm: bool, + attached_obj_id: u16, + anim_params: TileAnim, + glow: u8, + obj_collision: bool, + node_param0: u16, + node_param2: u8, + node_tile: u8, + } = 71, + AddHud { + id: u32, + hud: HudElement, + } = 73, + RemoveHud { + id: u32, + } = 74, + ChangeHud { + id: u32, + change: HudChange, + } = 75, + HudFlags { + flags: EnumSet, + mask: EnumSet, + } = 76, + SetHotbarParam(HotbarParam) = 77, + Breath { + breath: u16, + } = 78, + // TODO + SkyParams = 79, + OverrideDayNightRatio { + #[serde(rename = "override")] + ratio_override: bool, + ratio: u16, + } = 80, + LocalPlayerAnim { + idle: [i32; 2], + walk: [i32; 2], + dig: [i32; 2], + walk_dig: [i32; 2], + speed: f32, + } = 81, + EyeOffset { + first: [f32; 3], + third: [f32; 3], + } = 82, + RemoveParticleSpawner { + id: u32, + } = 83, + CloudParams { + density: f32, + diffuse_color: ArgbColor, + ambient_color: ArgbColor, + height: f32, + thickness: f32, + speed: [f32; 2], + } = 84, + FadeSound { + id: u32, + step: f32, + gain: f32, + } = 85, + UpdatePlayerList { + update_type: PlayerListUpdateType, + players: Vec, + } = 86, + ModChanMsg { + channel: String, + sender: String, + msg: String, + } = 87, + ModChanSig { + signal: ModChanSig, + channel: String, + } = 88, + NodeMetasChanged(#[mt(size32)] HashMap<[i16; 3], NodeMeta>) = 89, + SunParams { + visible: bool, + texture: String, + tone_map: String, + rise: String, + rising: bool, + size: f32, + } = 90, + MoonParams { + visible: bool, + texture: String, + tone_map: String, + size: f32, + } = 91, + StarParams { + visible: bool, + texture: String, + tone_map: String, + size: f32, + } = 92, + SrpBytesSaltB { + salt: Vec, + b: Vec, + } = 96, + FormspecPrepend { + prepend: String, + } = 97, + MinimapModes { + #[mt(len = "modes")] + current: u16, + modes: Vec, + } = 98, +} diff --git a/src/to_clt/chat.rs b/src/to_clt/chat.rs new file mode 100644 index 0000000..4d99853 --- /dev/null +++ b/src/to_clt/chat.rs @@ -0,0 +1,16 @@ +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, +} diff --git a/src/to_clt/env.rs b/src/to_clt/env.rs new file mode 100644 index 0000000..f242298 --- /dev/null +++ b/src/to_clt/env.rs @@ -0,0 +1,44 @@ +use super::*; + +#[mt_derive(to = "clt")] +pub struct ObjAdd; // TODO + +#[mt_derive(to = "clt")] +pub struct ObjMsg; // TODO + +#[mt_derive(to = "clt", repr = "u8", enumset)] +pub enum MapBlockFlag { + IsUnderground = 0, + DayNightDiff, + LightExpired, + NotGenerated, +} + +pub const ALWAYS_LIT_FROM: u16 = 0xf000; + +#[mt_derive(to = "clt")] +pub struct MapBlock { + pub flags: EnumSet, + pub lit_from: u16, + + #[mt(const8 = 2)] + #[serde(skip)] + pub param0_size: (), + + #[mt(const8 = 2)] + #[serde(skip)] + pub param12_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], + + pub node_metas: HashMap, + + #[mt(const8 = 2)] + #[serde(skip)] + pub version: (), +} diff --git a/src/to_clt/hud.rs b/src/to_clt/hud.rs new file mode 100644 index 0000000..c7a206a --- /dev/null +++ b/src/to_clt/hud.rs @@ -0,0 +1,124 @@ +use super::*; + +#[mt_derive(to = "clt", repr = "u32", enumset)] +pub enum HudStyleFlag { + Bold, + Italic, + Mono, +} + +#[mt_derive(to = "clt", repr = "u8", tag = "attribute", content = "value")] +pub enum HudChange { + Pos([f32; 2]) = 0, + Name(String), + Scale([f32; 2]), + Text(String), + Number(u32), + Item(u32), + Dir(u32), + Align([f32; 2]), + Offset([f32; 2]), + WorldPos([f32; 3]), + ZIndex(i32), + Text2(String), + Style(EnumSet), +} + +#[mt_derive(to = "clt", repr = "u8")] +pub enum HudType { + Image = 0, + Text, + Statbar, + Inv, + Waypoint, + ImageWaypoint, +} + +#[mt_derive(to = "clt")] +pub struct HudElement { + pub hud_type: HudType, + pub pos: [f32; 2], + pub name: String, + pub scale: [f32; 2], + pub text: String, + pub number: u32, + pub item: u32, + pub dir: u32, + pub align: [f32; 2], + pub offset: [f32; 2], + pub world_pos: [f32; 3], + pub z_index: i32, + pub text_2: String, + pub style: EnumSet, +} + +impl HudElement { + pub fn apply_change(&mut self, change: HudChange) { + use HudChange::*; + + match change { + Pos(v) => self.pos = v, + Name(v) => self.name = v, + Scale(v) => self.scale = v, + Text(v) => self.text = v, + Number(v) => self.number = v, + Item(v) => self.item = v, + Dir(v) => self.dir = v, + Align(v) => self.align = v, + Offset(v) => self.offset = v, + WorldPos(v) => self.world_pos = v, + ZIndex(v) => self.z_index = v, + Text2(v) => self.text_2 = v, + Style(v) => self.style = v, + } + } +} + +#[mt_derive(to = "clt", repr = "u32", enumset)] +pub enum HudFlag { + Hotbar, + HealthBar, + Crosshair, + WieldedItem, + BreathBar, + Minimap, + RadarMinimap, +} + +#[mt_derive(to = "clt", repr = "u16", tag = "attribute", content = "value")] +pub enum HotbarParam { + Size(#[mt(const16 = 4)] u32) = 0, + Image(String), + SelectionImage(String), +} + +#[mt_derive(to = "clt", repr = "u16")] +pub enum MinimapType { + None = 0, + Surface, + Radar, + Texture, +} + +#[mt_derive(to = "clt")] +pub struct MinimapMode { + pub minimap_type: MinimapType, + pub label: String, + pub size: u16, + pub texture: String, + pub scale: u16, +} + +/* +TODO: rustify + +var DefaultMinimap = []MinimapMode{ + {Type: NoMinimap}, + {Type: SurfaceMinimap, Size: 256}, + {Type: SurfaceMinimap, Size: 128}, + {Type: SurfaceMinimap, Size: 64}, + {Type: RadarMinimap, Size: 512}, + {Type: RadarMinimap, Size: 256}, + {Type: RadarMinimap, Size: 128}, +} +*/ diff --git a/src/to_clt/media.rs b/src/to_clt/media.rs new file mode 100644 index 0000000..0dd1f3d --- /dev/null +++ b/src/to_clt/media.rs @@ -0,0 +1,33 @@ +use super::*; + +#[mt_derive(to = "clt")] +pub struct MediaAnnounce { + pub name: String, + pub base64_sha1: String, +} + +#[mt_derive(to = "clt")] +pub struct MediaPayload { + pub name: String, + #[mt(len32)] + pub data: Vec, +} + +#[mt_derive(to = "clt")] +pub struct TileAnim; // TODO + +#[mt_derive(to = "clt")] +pub struct ItemDef; // TODO + +#[mt_derive(to = "clt")] +pub struct NodeDef; // TODO + +#[mt_derive(to = "clt")] +pub struct NodeMeta; // TODO + +#[mt_derive(to = "clt", repr = "u16")] +pub enum SoundSrcType { + Nowhere = 0, + Pos, + Obj, +} diff --git a/src/to_clt/status.rs b/src/to_clt/status.rs new file mode 100644 index 0000000..54adb45 --- /dev/null +++ b/src/to_clt/status.rs @@ -0,0 +1,80 @@ +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, +} diff --git a/src/to_srv.rs b/src/to_srv.rs new file mode 100644 index 0000000..354bbb4 --- /dev/null +++ b/src/to_srv.rs @@ -0,0 +1,119 @@ +use crate::*; + +#[mt_derive(to = "srv")] +pub struct PlayerPos { + #[mt(const_u16 = 1)] // supported compression + pub pos_100: [i32; 3], + pub vel_100: [i32; 3], + pub pitch_100: i32, + pub yaw_100: i32, + pub fov_80: u8, + pub wanted_range: u8, +} + +#[mt_derive(to = "srv", repr = "u8")] +pub enum Interaction { + Dig = 0, + StopDigging, + Dug, + Place, + Use, + Activate, +} + +#[mt_derive(to = "srv")] +pub struct PointedThing; // TODO + +#[mt_derive(to = "srv", repr = "u16", tag = "type", content = "data")] +pub enum ToSrvPkt { + Nil = 0, + Init { + serialize_version: u8, + #[mt(const_u16 = 1)] // supported compression + min_proto_version: u16, + max_proto_version: u16, + player_name: String, + #[mt(default)] + send_full_item_meta: bool, + } = 2, + Init2 { + lang: String, + } = 17, + JoinModChan { + channel: String, + } = 23, + LeaveModChan { + channel: String, + } = 24, + MsgModChan { + channel: String, + msg: String, + } = 25, + PlayerPos(PlayerPos) = 35, + GotBlocks { + #[mt(len8)] + blocks: Vec<[i16; 3]>, + } = 36, + DeletedBlocks { + #[mt(len8)] + blocks: Vec<[i16; 3]>, + } = 37, + InvAction { + #[mt(len0)] + action: String, + } = 49, + ChatMsg { + #[mt(utf16)] + msg: String, + } = 50, + FallDmg { + amount: u16, + } = 53, + SelectItem { + select_item: u16, + } = 55, + Respawn = 56, + Interact { + action: Interaction, + item_slot: u16, + #[mt(size_u32)] + pointed: PointedThing, + pos: PlayerPos, + } = 57, + RemovedSounds { + ids: Vec, + } = 58, + NodeMetaFields { + pos: [i16; 3], + formname: String, + fields: HashMap, + } = 59, + InvFields { + formname: String, + fields: HashMap, + } = 60, + ReqMedia { + filenames: Vec, + } = 64, + CltReady { + major: u8, + minor: u8, + patch: u8, + reserved: u8, + version: String, + formspec: u16, + } = 67, + FirstSrp { + salt: Vec, + verifier: Vec, + empty_passwd: bool, + } = 80, + SrpBytesA { + a: Vec, + no_sha1: bool, + } = 81, + SrpBytesM { + m: Vec, + } = 82, + Disco = 0xffff, +}