From 68441320e8fcb6c0cfe2b8337e831d6692ab0c43 Mon Sep 17 00:00:00 2001 From: iceiix <43691553+iceiix@users.noreply.github.com> Date: Fri, 28 Dec 2018 21:11:42 -0800 Subject: [PATCH] 1.13.2 (404) multiprotocol support (#67) Adds support for 1.13.2 protocol (404) Expands https://github.com/iceiix/steven/issues/18 Enhance protocol support Metadata: * Support 1.13.2 slot data format, bool and varint item id, optional damage (moved to NBT) https://wiki.vg/index.php?title=Slot_Data&type=revision&diff=14363&oldid=7835 Packets: * Add 1.13.2 packets, and implement all the command data parsers https://wiki.vg/Command_Data#Parsers * Send new plugin channel minecraft:brand https://wiki.vg/Plugin_channels#minecraft:brand * Add 1.13.2 metadata format, with shifted IDs https://wiki.vg/Entity_metadata#Entity_Metadata_Format * Implement particle entity metadata * Add structures for 16 new packets Blocks: The Flattening: * Assign flattened IDs in correct order using new 'offset' macro token * Assign hierarchical (pre-flattening) block IDs sequentially by counting Some data * Split VANILLA_ID_MAP into flat/hier struct, to support before and after the flattening * Extend travis build time to 20 minutes because the blocks macro takes a long time * Support both flat/hier blocks by passing protocol_version to by_vanilla_id Add block states and offsets for all blocks, replacing metadata for 1.13+: * Add stripped logs and what was Log2 to Log * Add the Wood blocks, should be called bark, previously Axis::None Log * Add leaves distance and offset * Add jungle/acacia to Leaves moved from Leaves2 * Add dispenser offsets, direction * Add note block states * Add offset None to Missing253 and Missing254, no holes in block states of 1.13.2 * Add bed colors * Add seagrass, tall seagrass, remove redundant deadgrass, and piston offset * Add torch, TNT, fire offsets, remove slabs * Add furnance offset, merges lit into a property * Add pressure plate offsets, new pressure plates, redstone ore/lit merged * Add lever offsets, new directions from ceiling/floor, rename LeverDirections * Add redstone torch offsets, new blocks since lit/unlit is now merged, and standing/wall is split * Change lever to split face/facing, rm LeverDirection, add AttachedFace * Add stone button offsets, face/facing similar to lever * Move face/facing data and variant to AttachedFace, reuse for lever/stonebutton * Add data_with_facing_and_powered() to AttachedFace, for lever/stonebutton * Add wooden button offsets each wood * Add pumpkin without a face * Add carved pumpkin, portal offsets * Add lit pumpkin (as jack-o-lantern) offsets after carved pumpkin * Add repeater offsets, merged into Repeater * Change brown mushroom block to booleans instead of MushroomVariant * Add mushroom block offsets, red/brown mushroom blocks, and a new mushroom stem block * Add command block, cobblestone walls, and flower pot offsets Empty flower pot, and potted plants including saplings. Rename variant DarkOak to DarkOakSaplings because it is a sapling, and remove the duplicate Dandelion variant which causes duplicate blocks. * Increase recursion limit in steven_blocks * Add colored banner offsets * Add wooden slab including double slab, in a different position for pre-1.13 and 1.13 * StoneSlabVariant::Wood -> StoneSlabVariant::PetrifiedWood * Add fence_gate_offset() for wooden fence gates * Add frosted ice age, offset * Add new blocks: kelp, turtle egg, coral, coral fans, sea pickle, blue ice, smooth stone * Add new blocks: conduit, void air, cave aid, bubble column, last of the 1.13 blocks --- protocol/src/item.rs | 32 +++- protocol/src/types/metadata.rs | 299 ++++++++++++++++++++++++++++++++- 2 files changed, 322 insertions(+), 9 deletions(-) diff --git a/protocol/src/item.rs b/protocol/src/item.rs index 7ed18d6..9d791e9 100644 --- a/protocol/src/item.rs +++ b/protocol/src/item.rs @@ -21,7 +21,7 @@ use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; pub struct Stack { id: isize, count: isize, - damage: isize, + damage: Option, tag: Option, } @@ -31,7 +31,7 @@ impl Default for Stack { Stack { id: -1, count: 0, - damage: 0, + damage: None, tag: None, } } @@ -39,14 +39,31 @@ impl Default for Stack { impl Serializable for Option { fn read_from(buf: &mut R) -> Result, protocol::Error> { - let id = buf.read_i16::()?; + let protocol_version = unsafe { protocol::CURRENT_PROTOCOL_VERSION }; + + if protocol_version >= 404 { + let present = buf.read_u8()? != 0; + if !present { + return Ok(None) + } + } + + let id = if protocol_version >= 404 { + protocol::VarInt::read_from(buf)?.0 as isize + } else { + buf.read_i16::()? as isize + }; + if id == -1 { return Ok(None); } let count = buf.read_u8()? as isize; - let damage = buf.read_i16::()? as isize; - - let protocol_version = unsafe { protocol::CURRENT_PROTOCOL_VERSION }; + let damage = if protocol_version >= 404 { + // 1.13.2+ stores damage in the NBT + None + } else { + Some(buf.read_i16::()? as isize) + }; let tag: Option = if protocol_version >= 47 { Serializable::read_from(buf)? @@ -74,9 +91,10 @@ impl Serializable for Option { fn write_to(&self, buf: &mut W) -> Result<(), protocol::Error> { match *self { Some(ref val) => { + // TODO: if protocol_version >= 404, send present and id varint, no damage, for 1.13.2 buf.write_i16::(val.id as i16)?; buf.write_u8(val.count as u8)?; - buf.write_i16::(val.damage as i16)?; + buf.write_i16::(val.damage.unwrap_or(0) as i16)?; // TODO: compress zlib NBT if 1.7 val.tag.write_to(buf)?; } diff --git a/protocol/src/types/metadata.rs b/protocol/src/types/metadata.rs index 44ee0a7..a5e8a3e 100644 --- a/protocol/src/types/metadata.rs +++ b/protocol/src/types/metadata.rs @@ -18,6 +18,7 @@ use std::io; use std::fmt; use crate::protocol; use crate::protocol::Serializable; +use crate::protocol::LenPrefixed; use crate::format; use crate::item; use crate::shared::Position; @@ -271,13 +272,151 @@ impl Metadata { u8::write_to(&0xFF, buf)?; Ok(()) } + + fn read_from113(buf: &mut R) -> Result { + let mut m = Self::new(); + loop { + let index = u8::read_from(buf)? as i32; + if index == 0xFF { + break; + } + let ty = protocol::VarInt::read_from(buf)?.0; + match ty { + 0 => m.put_raw(index, i8::read_from(buf)?), + 1 => m.put_raw(index, protocol::VarInt::read_from(buf)?.0), + 2 => m.put_raw(index, f32::read_from(buf)?), + 3 => m.put_raw(index, String::read_from(buf)?), + 4 => m.put_raw(index, format::Component::read_from(buf)?), + 5 => m.put_raw(index, LenPrefixed::::read_from(buf)?), + 6 => m.put_raw(index, Option::::read_from(buf)?), + 7 => m.put_raw(index, bool::read_from(buf)?), + 8 => m.put_raw(index, + [f32::read_from(buf)?, + f32::read_from(buf)?, + f32::read_from(buf)?]), + 9 => m.put_raw(index, Position::read_from(buf)?), + 10 => { + if bool::read_from(buf)? { + m.put_raw(index, Option::::read_from(buf)?); + } else { + m.put_raw::>(index, None); + } + } + 11 => m.put_raw(index, protocol::VarInt::read_from(buf)?), + 12 => { + if bool::read_from(buf)? { + m.put_raw(index, Option::::read_from(buf)?); + } else { + m.put_raw::>(index, None); + } + } + 13 => m.put_raw(index, protocol::VarInt::read_from(buf)?.0 as u16), + 14 => { + let ty = u8::read_from(buf)?; + if ty != 0 { + let name = nbt::read_string(buf)?; + let tag = nbt::Tag::read_from(buf)?; + + m.put_raw(index, nbt::NamedTag(name, tag)); + } + } + 15 => panic!("TODO: particle"), + _ => return Err(protocol::Error::Err("unknown metadata type".to_owned())), + } + } + Ok(m) + } + + fn write_to113(&self, buf: &mut W) -> Result<(), protocol::Error> { + for (k, v) in &self.map { + (*k as u8).write_to(buf)?; + match *v { + Value::Byte(ref val) => { + u8::write_to(&0, buf)?; + val.write_to(buf)?; + } + Value::Int(ref val) => { + u8::write_to(&1, buf)?; + protocol::VarInt(*val).write_to(buf)?; + } + Value::Float(ref val) => { + u8::write_to(&2, buf)?; + val.write_to(buf)?; + } + Value::String(ref val) => { + u8::write_to(&3, buf)?; + val.write_to(buf)?; + } + Value::FormatComponent(ref val) => { + u8::write_to(&4, buf)?; + val.write_to(buf)?; + } + Value::OptionalFormatComponent(ref val) => { + u8::write_to(&5, buf)?; + val.write_to(buf)?; + } + Value::OptionalItemStack(ref val) => { + u8::write_to(&6, buf)?; + val.write_to(buf)?; + } + Value::Bool(ref val) => { + u8::write_to(&7, buf)?; + val.write_to(buf)?; + } + Value::Vector(ref val) => { + u8::write_to(&8, buf)?; + val[0].write_to(buf)?; + val[1].write_to(buf)?; + val[2].write_to(buf)?; + } + Value::Position(ref val) => { + u8::write_to(&9, buf)?; + val.write_to(buf)?; + } + Value::OptionalPosition(ref val) => { + u8::write_to(&10, buf)?; + val.is_some().write_to(buf)?; + val.write_to(buf)?; + } + Value::Direction(ref val) => { + u8::write_to(&11, buf)?; + val.write_to(buf)?; + } + Value::OptionalUUID(ref val) => { + u8::write_to(&12, buf)?; + val.is_some().write_to(buf)?; + val.write_to(buf)?; + } + Value::Block(ref val) => { + u8::write_to(&13, buf)?; + protocol::VarInt(*val as i32).write_to(buf)?; + } + Value::NBTTag(ref _val) => { + u8::write_to(&14, buf)?; + // TODO: write NBT tags metadata + //nbt::Tag(*val).write_to(buf)?; + } + Value::Particle(ref val) => { + u8::write_to(&15, buf)?; + val.write_to(buf)?; + } + _ => panic!("unexpected metadata"), + } + } + u8::write_to(&0xFF, buf)?; + Ok(()) + } + + } impl Serializable for Metadata { fn read_from(buf: &mut R) -> Result { let protocol_version = unsafe { protocol::CURRENT_PROTOCOL_VERSION }; - if protocol_version >= 74 { + if protocol_version >= 404 { + Metadata::read_from113(buf) + } else if protocol_version >= 74 { Metadata::read_from19(buf) } else { Metadata::read_from18(buf) @@ -287,7 +426,9 @@ impl Serializable for Metadata { fn write_to(&self, buf: &mut W) -> Result<(), protocol::Error> { let protocol_version = unsafe { protocol::CURRENT_PROTOCOL_VERSION }; - if protocol_version >= 74 { + if protocol_version >= 404 { + self.write_to113(buf) + } else if protocol_version >= 74 { self.write_to19(buf) } else { self.write_to18(buf) @@ -319,6 +460,7 @@ pub enum Value { Float(f32), String(String), FormatComponent(format::Component), + OptionalFormatComponent(LenPrefixed), OptionalItemStack(Option), Bool(bool), Vector([f32; 3]), @@ -329,6 +471,146 @@ pub enum Value { OptionalUUID(Option), Block(u16), // TODO: Proper type NBTTag(nbt::NamedTag), + Particle(ParticleData), +} + +#[derive(Debug)] +pub enum ParticleData { + AmbientEntityEffect, + AngryVillager, + Barrier, + Block { + block_state: protocol::VarInt, + }, + Bubble, + Cloud, + Crit, + DamageIndicator, + DragonBreath, + DrippingLava, + DrippingWater, + Dust { + red: f32, + green: f32, + blue: f32, + scale: f32, + }, + Effect, + ElderGuardian, + EnchantedHit, + Enchant, + EndRod, + EntityEffect, + ExplosionEmitter, + Explosion, + FallingDust { + block_state: protocol::VarInt, + }, + Firework, + Fishing, + Flame, + HappyVillager, + Heart, + InstantEffect, + Item { + item: Option, + }, + ItemSlime, + ItemSnowball, + LargeSmoke, + Lava, + Mycelium, + Note, + Poof, + Portal, + Rain, + Smoke, + Spit, + SquidInk, + SweepAttack, + TotemOfUndying, + Underwater, + Splash, + Witch, + BubblePop, + CurrentDown, + BubbleColumnUp, + Nautilus, + Dolphin, +} + +impl Serializable for ParticleData { + fn read_from(buf: &mut R) -> Result { + let id = protocol::VarInt::read_from(buf)?.0; + Ok(match id { + 0 => ParticleData::AmbientEntityEffect, + 1 => ParticleData::AngryVillager, + 2 => ParticleData::Barrier, + 3 => ParticleData::Block { + block_state: Serializable::read_from(buf)? + }, + 4 => ParticleData::Bubble, + 5 => ParticleData::Cloud, + 6 => ParticleData::Crit, + 7 => ParticleData::DamageIndicator, + 8 => ParticleData::DragonBreath, + 9 => ParticleData::DrippingLava, + 10 => ParticleData::DrippingWater, + 11 => ParticleData::Dust { + red: Serializable::read_from(buf)?, + green: Serializable::read_from(buf)?, + blue: Serializable::read_from(buf)?, + scale: Serializable::read_from(buf)?, + }, + 12 => ParticleData::Effect, + 13 => ParticleData::ElderGuardian, + 14 => ParticleData::EnchantedHit, + 15 => ParticleData::Enchant, + 16 => ParticleData::EndRod, + 17 => ParticleData::EntityEffect, + 18 => ParticleData::ExplosionEmitter, + 19 => ParticleData::Explosion, + 20 => ParticleData::FallingDust { + block_state: Serializable::read_from(buf)?, + }, + 21 => ParticleData::Firework, + 22 => ParticleData::Fishing, + 23 => ParticleData::Flame, + 24 => ParticleData::HappyVillager, + 25 => ParticleData::Heart, + 26 => ParticleData::InstantEffect, + 27 => ParticleData::Item { + item: Serializable::read_from(buf)?, + }, + 28 => ParticleData::ItemSlime, + 29 => ParticleData::ItemSnowball, + 30 => ParticleData::LargeSmoke, + 31 => ParticleData::Lava, + 32 => ParticleData::Mycelium, + 33 => ParticleData::Note, + 34 => ParticleData::Poof, + 35 => ParticleData::Portal, + 36 => ParticleData::Rain, + 37 => ParticleData::Smoke, + 38 => ParticleData::Spit, + 39 => ParticleData::SquidInk, + 40 => ParticleData::SweepAttack, + 41 => ParticleData::TotemOfUndying, + 42 => ParticleData::Underwater, + 43 => ParticleData::Splash, + 44 => ParticleData::Witch, + 45 => ParticleData::BubblePop, + 46 => ParticleData::CurrentDown, + 47 => ParticleData::BubbleColumnUp, + 48 => ParticleData::Nautilus, + 49 => ParticleData::Dolphin, + _ => panic!("unrecognized particle data id {}", id), + }) + } + + fn write_to(&self, _buf: &mut W) -> Result<(), protocol::Error> { + unimplemented!() + } } pub trait MetaValue { @@ -408,6 +690,19 @@ impl MetaValue for format::Component { } } +impl MetaValue for LenPrefixed { + fn unwrap(value: &Value) -> &Self { + match *value { + Value::OptionalFormatComponent(ref val) => val, + _ => panic!("incorrect key"), + } + } + fn wrap(self) -> Value { + Value::OptionalFormatComponent(self) + } +} + + impl MetaValue for Option { fn unwrap(value: &Value) -> &Self { match *value {