--- /dev/null
+/target
+/Cargo.lock
--- /dev/null
+[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"
--- /dev/null
+# 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"
--- /dev/null
+[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"
--- /dev/null
+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<syn::Type>,
+ tag: Option<String>,
+ content: Option<String>,
+ #[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<W: std::io::Write>(&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<R: std::io::Read>(reader: &mut R) -> Result<Self, mt_data::DeserializeError> {
+ Err(mt_data::DeserializeError::Unimplemented)
+ }
+ }
+ }.into()
+}
--- /dev/null
+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<W: io::Write>(&self, writer: &mut W) -> Result<(), SerializeError>;
+}
+
+pub trait MtDeserialize: Sized {
+ fn mt_deserialize<R: io::Read>(reader: &mut R) -> Result<Self, DeserializeError>;
+}
+
+mod to_clt;
+mod to_srv;
+
+pub use to_clt::*;
+pub use to_srv::*;
--- /dev/null
+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<AuthMethod>,
+ username: String,
+ } = 2,
+ AcceptAuth {
+ player_pos: [f32; 3],
+ map_seed: u64,
+ send_interval: f32,
+ sudo_auth_methods: EnumSet<AuthMethod>,
+ } = 3,
+ AcceptSudoMode {
+ sudo_auth_methods: EnumSet<AuthMethod>,
+ } = 4,
+ DenySudoMode = 5,
+ Kick(KickReason) = 10,
+ BlockData {
+ pos: [i16; 3],
+ #[mt(zstd)]
+ block: Box<MapBlock>,
+ } = 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<CsmRestrictionFlag>,
+ 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<u16>,
+ add: Vec<ObjAdd>,
+ } = 49,
+ ObjMsgs {
+ msgs: Vec<ObjMsg>,
+ } = 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<MediaPayload>,
+ } = 56,
+ NodeDefs {
+ defs: Vec<NodeDef>,
+ } = 58,
+ AnnounceMedia {
+ files: Vec<MediaAnnounce>,
+ url: String,
+ } = 60,
+ #[mt(size32, zlib)]
+ ItemDefs {
+ #[mt(const8 = 0)] // version
+ defs: Vec<ItemDef>,
+ aliases: HashMap<String, String>,
+ } = 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<String>,
+ } = 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<HudFlag>,
+ mask: EnumSet<HudFlag>,
+ } = 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<String>,
+ } = 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<u8>,
+ b: Vec<u8>,
+ } = 96,
+ FormspecPrepend {
+ prepend: String,
+ } = 97,
+ MinimapModes {
+ #[mt(len = "modes")]
+ current: u16,
+ modes: Vec<MinimapMode>,
+ } = 98,
+}
--- /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")]
+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<MapBlockFlag>,
+ 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<u16, NodeMeta>,
+
+ #[mt(const8 = 2)]
+ #[serde(skip)]
+ pub version: (),
+}
--- /dev/null
+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<HudStyleFlag>),
+}
+
+#[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<HudStyleFlag>,
+}
+
+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},
+}
+*/
--- /dev/null
+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<u8>,
+}
+
+#[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,
+}
--- /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,
+}
--- /dev/null
+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<i32>,
+ } = 58,
+ NodeMetaFields {
+ pos: [i16; 3],
+ formname: String,
+ fields: HashMap<String, String>,
+ } = 59,
+ InvFields {
+ formname: String,
+ fields: HashMap<String, String>,
+ } = 60,
+ ReqMedia {
+ filenames: Vec<String>,
+ } = 64,
+ CltReady {
+ major: u8,
+ minor: u8,
+ patch: u8,
+ reserved: u8,
+ version: String,
+ formspec: u16,
+ } = 67,
+ FirstSrp {
+ salt: Vec<u8>,
+ verifier: Vec<u8>,
+ empty_passwd: bool,
+ } = 80,
+ SrpBytesA {
+ a: Vec<u8>,
+ no_sha1: bool,
+ } = 81,
+ SrpBytesM {
+ m: Vec<u8>,
+ } = 82,
+ Disco = 0xffff,
+}