From 55875fb4063a64de25ace0b5013a0f19bc86c19a Mon Sep 17 00:00:00 2001 From: Lizzy Fleckenstein Date: Wed, 15 Feb 2023 02:22:36 +0100 Subject: Implement NodeDefs and ItemDefs --- Cargo.toml | 1 - src/lib.rs | 2 + src/to_clt.rs | 17 +-- src/to_clt/inv.rs | 16 +- src/to_clt/map.rs | 14 +- src/to_clt/media.rs | 411 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/to_clt/obj.rs | 4 +- 7 files changed, 439 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index eb9d99c..afbc3e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ test = ["client", "server", "random"] 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 } diff --git a/src/lib.rs b/src/lib.rs index 36ffec9..77538cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![feature(iterator_try_collect)] +pub use enumset; pub use mt_ser; #[cfg(feature = "random")] @@ -16,6 +17,7 @@ use mt_ser::mt_derive; use std::{ collections::{HashMap, HashSet}, fmt, + ops::RangeInclusive, }; #[cfg(any(feature = "client", feature = "server"))] diff --git a/src/to_clt.rs b/src/to_clt.rs index 9848dae..3792018 100644 --- a/src/to_clt.rs +++ b/src/to_clt.rs @@ -170,10 +170,7 @@ pub enum ToCltPkt { files: HashMap>, // name -> payload } = 56, #[mt(size = "u32", zlib)] - NodeDefs { - #[mt(const_before = "1u8")] // version - defs: Vec, - } = 58, + NodeDefs(#[mt(const_before = "1u8")] NodeDefs) = 58, AnnounceMedia { files: HashMap, // name -> base64 sha1 hash url: String, @@ -188,7 +185,7 @@ pub enum ToCltPkt { id: u32, name: String, gain: f32, - src_type: SoundSrcType, + source: SoundSource, pos: [f32; 3], src_obj_id: u16, #[serde(rename = "loop")] @@ -254,11 +251,11 @@ pub enum ToCltPkt { AddParticleSpawner { amount: u16, duration: f32, - pos: [[f32; 3]; 2], - vel: [[f32; 3]; 2], - acc: [[f32; 3]; 2], - expiration_time: [f32; 2], - size: [f32; 2], + pos: RangeInclusive<[f32; 3]>, + vel: RangeInclusive<[f32; 3]>, + acc: RangeInclusive<[f32; 3]>, + expiration_time: RangeInclusive, + size: RangeInclusive, collide: bool, #[mt(len = "u32")] texture: String, diff --git a/src/to_clt/inv.rs b/src/to_clt/inv.rs index 2ada0a1..01eaa75 100644 --- a/src/to_clt/inv.rs +++ b/src/to_clt/inv.rs @@ -1,18 +1,20 @@ 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(&self, writer: &mut impl Write) -> Result<(), SerializeError> { + fn mt_serialize( + &self, + writer: &mut impl std::io::Write, + ) -> Result<(), mt_ser::SerializeError> { "EndInventory\n".mt_serialize::<()>(writer) } } -fn read_line(reader: &mut impl Read) -> Result { +#[cfg(feature = "client")] +fn read_line(reader: &mut impl std::io::Read) -> Result { let utf8 = mt_ser::mt_deserialize_seq::<(), u8>(reader)? .map_while(|x| match x { Ok(0x0A) => None, @@ -21,12 +23,14 @@ fn read_line(reader: &mut impl Read) -> Result { .try_collect::>()?; String::from_utf8(utf8) - .map_err(|e| DeserializeError::Other(format!("Invalid UTF-8: {e}").into())) + .map_err(|e| mt_ser::DeserializeError::Other(format!("Invalid UTF-8: {e}").into())) } #[cfg(feature = "client")] impl MtDeserialize for Inventory { - fn mt_deserialize(reader: &mut impl Read) -> Result { + fn mt_deserialize( + reader: &mut impl std::io::Read, + ) -> Result { loop { match read_line(reader)?.as_str() { "EndInventory" => return Ok(Self), diff --git a/src/to_clt/map.rs b/src/to_clt/map.rs index 296a23f..b35f2cd 100644 --- a/src/to_clt/map.rs +++ b/src/to_clt/map.rs @@ -1,5 +1,4 @@ use super::*; -use mt_ser::{DeserializeError, SerializeError}; #[mt_derive(to = "clt", repr = "u8", enumset)] pub enum MapBlockFlag { @@ -32,11 +31,15 @@ pub struct NodeMeta { #[derive(Debug)] pub struct NodeMetasLen; +#[cfg(any(feature = "client", feature = "server"))] impl MtCfg for NodeMetasLen { type Len = ::Len; type Inner = ::Inner; - fn write_len(len: usize, writer: &mut impl std::io::Write) -> Result<(), SerializeError> { + fn write_len( + len: usize, + writer: &mut impl std::io::Write, + ) -> Result<(), mt_ser::SerializeError> { if len == 0 { 0u8.mt_serialize::(writer) } else { @@ -45,11 +48,14 @@ impl MtCfg for NodeMetasLen { } } - fn read_len(reader: &mut impl std::io::Read) -> Result { + fn read_len(reader: &mut impl std::io::Read) -> Result { match u8::mt_deserialize::(reader)? { 0 => Ok(0), 2 => DefCfg::read_len(reader), - x => Err(DeserializeError::InvalidEnum("NodeMetasLen", Box::new(x))), + x => Err(mt_ser::DeserializeError::InvalidEnum( + "NodeMetasLen", + Box::new(x), + )), } } } diff --git a/src/to_clt/media.rs b/src/to_clt/media.rs index 1ec1fd6..7176773 100644 --- a/src/to_clt/media.rs +++ b/src/to_clt/media.rs @@ -1,5 +1,73 @@ use super::*; +#[mt_derive(to = "clt", repr = "u8")] +pub enum Param1Type { + None = 0, + Light, +} + +#[mt_derive(to = "clt", repr = "u8")] +pub enum Param2Type { + Nibble = 0, + Byte, + Flowing, + FaceDir, + Mounted, + Leveled, + Rotation, + Mesh, + Color, + ColorFaceDir, + ColorMounted, + GrassLikeLevel, + ColorRotation, +} + +#[mt_derive(to = "clt", repr = "u8")] +pub enum DrawType { + Cube = 0, + None, + Liquid, + Flowing, + GlassLike, + AllFaces, + AllFacesOpt, + Torch, + Sign, + Plant, + Fence, + Rail, + NodeBox, + GlassFrame, + Fire, + GlassFrameOpt, + Mesh, + RootedPlant, +} + +#[mt_derive(to = "clt", repr = "u8")] +pub enum Waving { + None = 0, + Plant, + Leaf, + Liquid, +} + +#[mt_derive(to = "clt", repr = "u8")] +pub enum Liquid { + None = 0, + Flowing, + Source, +} + +#[mt_derive(to = "clt", repr = "u8")] +pub enum Alpha { + Blend = 0, + Mask, // either fully opaque or transparent + Opaque, + Legacy, +} + #[mt_derive(to = "clt", repr = "u8", tag = "type")] pub enum TileAnim { None = 0, @@ -13,15 +81,352 @@ pub enum TileAnim { }, } +#[mt_derive(to = "clt", repr = "u8")] +pub enum TileAlign { + None = 0, + World, + User, +} + +#[mt_derive(to = "clt", enumset, custom)] +pub enum TileFlag { + BackfaceCull, + TileHorizontal, + TileVertical, +} + +#[mt_derive(to = "clt", repr = "u16", enumset)] +enum TileFlagInternal { + BackfaceCull, + TileHorizontal, + TileVertical, + Color, + Scale, + Align, +} + +#[mt_derive(to = "clt", custom)] +pub struct TileDef { + // #[mt(const_before = "6u8")] + pub texture: String, + pub animation: TileAnim, + pub flags: EnumSet, + pub color: Option<[u8; 3]>, + pub scale: Option, + pub align: Option, +} + +#[cfg(feature = "server")] +impl MtSerialize for TileDef { + fn mt_serialize( + &self, + writer: &mut impl std::io::Write, + ) -> Result<(), mt_ser::SerializeError> { + 6u8.mt_serialize::(writer)?; + self.texture.mt_serialize::(writer)?; + self.animation.mt_serialize::(writer)?; + + let mut flags: EnumSet = self + .flags + .iter() + .map(|f| match f { + TileFlag::BackfaceCull => TileFlagInternal::BackfaceCull, + TileFlag::TileHorizontal => TileFlagInternal::TileHorizontal, + TileFlag::TileVertical => TileFlagInternal::TileVertical, + }) + .collect(); + + if self.color.is_some() { + flags.insert(TileFlagInternal::Color); + } + + if self.scale.is_some() { + flags.insert(TileFlagInternal::Scale); + } + + if self.align.is_some() { + flags.insert(TileFlagInternal::Align); + } + + flags.mt_serialize::(writer)?; + self.color.mt_serialize::(writer)?; + self.scale.mt_serialize::(writer)?; + self.align.mt_serialize::(writer)?; + + Ok(()) + } +} + +#[cfg(feature = "client")] +impl MtDeserialize for TileDef { + fn mt_deserialize( + reader: &mut impl std::io::Read, + ) -> Result { + let const6u8 = MtDeserialize::mt_deserialize::(reader)?; + if 6u8 != const6u8 { + return Err(mt_ser::DeserializeError::InvalidConst( + Box::new(const6u8), + Box::new(6u8), + )); + } + + let texture = MtDeserialize::mt_deserialize::(reader)?; + let animation = MtDeserialize::mt_deserialize::(reader)?; + + let flags_internal = EnumSet::::mt_deserialize::(reader)?; + + let color = if flags_internal.contains(TileFlagInternal::Color) { + Some(MtDeserialize::mt_deserialize::(reader)?) + } else { + None + }; + + let scale = if flags_internal.contains(TileFlagInternal::Scale) { + Some(MtDeserialize::mt_deserialize::(reader)?) + } else { + None + }; + + let align = if flags_internal.contains(TileFlagInternal::Align) { + Some(MtDeserialize::mt_deserialize::(reader)?) + } else { + None + }; + + let flags = flags_internal + .iter() + .flat_map(|f| match f { + TileFlagInternal::BackfaceCull => Some(TileFlag::BackfaceCull), + TileFlagInternal::TileHorizontal => Some(TileFlag::TileHorizontal), + TileFlagInternal::TileVertical => Some(TileFlag::TileVertical), + _ => None, + }) + .collect(); + + Ok(Self { + texture, + animation, + flags, + color, + scale, + align, + }) + } +} + +#[mt_derive(to = "clt", repr = "u8", tag = "type")] +#[mt(const_before = "6u8")] +pub enum NodeBox { + Cube = 0, + Fixed { + fixed: Vec>, + }, + Mounted { + wall_top: RangeInclusive<[f32; 3]>, + wall_bottom: RangeInclusive<[f32; 3]>, + wall_sides: RangeInclusive<[f32; 3]>, + }, + Leveled { + fixed: Vec>, + }, + Connected { + fixed: Vec>, + connect_dirs: [Vec>; 6], + disconnect_dirs: [Vec>; 6], + disconnect_all: Vec>, + disconnect_sides: Vec>, + }, +} + #[mt_derive(to = "clt")] -pub struct ItemDef; // TODO +#[mt(size = "u16")] +pub struct NodeDef { + // TODO: impl Default + #[mt(const_before = "13u8")] + pub name: String, + pub groups: HashMap, + pub param1_type: Param1Type, + pub param2_type: Param2Type, + pub draw_type: DrawType, + pub mesh: String, + pub scale: f32, + #[mt(const_before = "6u8")] + pub tiles: [TileDef; 6], + pub overlay_tiles: [TileDef; 6], + #[mt(const_before = "6u8")] + pub special_tiles: [TileDef; 6], + pub color: Color, + pub palette: String, + pub waving: Waving, + pub connect_sides: u8, + pub connect_to: Vec, + pub inside_tint: Color, + pub level: u8, // FIXME: must be below 128 + pub translucent: bool, // sunlight scattering + pub transparent: bool, + pub light_source: u8, // FIXME: max: 14 (?) + pub ground_content: bool, + pub collision: bool, + pub pointable: bool, + pub diggable: bool, + pub climbable: bool, + pub replaceable: bool, + pub has_on_right_click: bool, + pub damage_per_second: i32, + pub liquid: Liquid, + pub flowing_alt: String, + pub source_alt: String, + pub viscosity: u8, // FIXME: 0-7 + pub liquid_renewable: bool, + pub flow_range: u8, + pub drown_damage: u8, + pub floodable: bool, + pub draw_box: NodeBox, + pub collision_box: NodeBox, + pub selection_box: NodeBox, + pub footstep_sound: SoundDef, + pub digging_sound: SoundDef, + pub dug_sound: SoundDef, + pub legacy_face_dir: bool, + pub legacy_mounted: bool, + pub dig_predict: String, + pub max_level: u8, + pub alpha: Alpha, + pub move_resistance: u8, + pub liquid_move_physics: bool, +} + +#[mt_derive(to = "clt", custom)] +pub struct NodeDefs(pub HashMap); + +// stupid bullshit ahead + +#[cfg(feature = "server")] +impl MtSerialize for NodeDefs { + fn mt_serialize( + &self, + writer: &mut impl std::io::Write, + ) -> Result<(), mt_ser::SerializeError> { + DefCfg::write_len(self.0.len(), writer)?; + + let mut buf = Vec::new(); + self.0.mt_serialize::<()>(&mut buf)?; + buf.mt_serialize::(writer)?; + + Ok(()) + } +} + +#[cfg(feature = "client")] +impl MtDeserialize for NodeDefs { + fn mt_deserialize( + reader: &mut impl std::io::Read, + ) -> Result { + use mt_ser::MtLen; + + let len = DefCfg::read_len(reader)?; + let mut reader = u32::read_len(reader)?.take(mt_ser::WrapRead(reader)); + let inner = + mt_ser::mt_deserialize_sized_seq::(&len, &mut reader)?.try_collect()?; + + Ok(Self(inner)) + } +} + +/* TODO: Rustify this + +func BuiltinNodeDefs(n int) map[Content]NodeDef { + defs := make(map[Content]NodeDef, 3+n) + defs[Unknown] = NodeDef{ + Name: "unknown", + } + defs[Air] = NodeDef{ + Name: "air", + DrawType: DrawNothing, + P1Type: P1Light, + Translucent: true, + Transparent: true, + Replaceable: true, + Floodable: true, + GndContent: true, + } + defs[Ignore] = NodeDef{ + Name: "ignore", + DrawType: DrawNothing, + Replaceable: true, + GndContent: true, + } + return defs +} +*/ + +#[mt_derive(to = "clt")] +pub struct ToolGroupCap { + pub uses: i16, // 32to16 + pub max_level: i16, + #[mt(len = "u32")] + pub times: HashMap, +} #[mt_derive(to = "clt")] -pub struct NodeDef; // TODO +pub struct ToolCaps { + #[mt(const_before = "5u8")] + pub attack_cooldown: f32, + pub max_drop_level: i16, + #[mt(len = "u32")] + pub group_caps: HashMap, + #[mt(len = "u32")] + pub dmg_groups: HashMap, + pub punch_uses: u16, // 32tou16 +} #[mt_derive(to = "clt", repr = "u8")] -pub enum SoundSrcType { +pub enum ItemType { + Node = 1, + Craft, + Tool, +} + +#[mt_derive(to = "clt", repr = "u8")] +pub enum SoundSource { Nowhere = 0, Pos, Obj, } + +#[mt_derive(to = "clt")] +pub struct SoundDef { + pub name: String, + pub gain: f32, + pub pitch: f32, + pub fade: f32, +} + +#[mt_derive(to = "clt")] +#[mt(size = "u16")] +pub struct ItemDef { + #[mt(const_before = "6u8")] + #[serde(rename = "type")] + pub item_type: ItemType, + pub name: String, + pub description: String, + pub inventory_image: String, + pub wield_image: String, + pub wield_scale: [f32; 3], + pub stack_max: u16, + pub usable: bool, + pub can_point_liquids: bool, + #[mt(size = "u16")] + pub tool_caps: Option, + pub groups: HashMap, + pub place_predict: String, + pub place_sound: SoundDef, + pub place_fail_sound: SoundDef, + pub point_range: f32, + pub palette: String, + pub color: Color, + pub inventory_overlay: String, + pub wield_overlay: String, + pub short_description: String, + pub place_param2: u8, +} diff --git a/src/to_clt/obj.rs b/src/to_clt/obj.rs index 9e88fff..1b605cc 100644 --- a/src/to_clt/obj.rs +++ b/src/to_clt/obj.rs @@ -16,8 +16,8 @@ pub struct ObjProps { 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 collision_box: RangeInclusive<[f32; 3]>, + pub selection_box: RangeInclusive<[f32; 3]>, pub pointable: bool, pub visual: ObjVisual, pub visual_size: [f32; 3], -- cgit v1.2.3