diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 3fcc23d..d78ac15 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -39,6 +39,8 @@ use crate::shared::Position; pub const SUPPORTED_PROTOCOLS: [i32; 8] = [340, 316, 315, 210, 109, 107, 74, 47]; +// TODO: switch to using thread_local storage?, see https://doc.rust-lang.org/std/macro.thread_local.html +pub static mut CURRENT_PROTOCOL_VERSION: i32 = SUPPORTED_PROTOCOLS[0]; /// Helper macro for defining packets #[macro_export] @@ -805,6 +807,10 @@ pub struct Conn { impl Conn { pub fn new(target: &str, protocol_version: i32) -> Result { + unsafe { + CURRENT_PROTOCOL_VERSION = protocol_version; + } + // TODO SRV record support let mut parts = target.split(':').collect::>(); let address = if parts.len() == 1 { diff --git a/src/protocol/packet.rs b/src/protocol/packet.rs index bf87440..5006d13 100644 --- a/src/protocol/packet.rs +++ b/src/protocol/packet.rs @@ -417,7 +417,7 @@ state_packets!( field velocity_x: i16 =, field velocity_y: i16 =, field velocity_z: i16 =, - field metadata: types::Metadata19 =, + field metadata: types::Metadata =, } packet SpawnMob_u8 { field entity_id: VarInt =, @@ -432,7 +432,7 @@ state_packets!( field velocity_x: i16 =, field velocity_y: i16 =, field velocity_z: i16 =, - field metadata: types::Metadata19 =, + field metadata: types::Metadata =, } packet SpawnMob_u8_i32 { field entity_id: VarInt =, @@ -447,9 +447,9 @@ state_packets!( field velocity_x: i16 =, field velocity_y: i16 =, field velocity_z: i16 =, - field metadata: types::Metadata19 =, + field metadata: types::Metadata =, } - packet SpawnMob_u8_i32_NoUUID_18 { + packet SpawnMob_u8_i32_NoUUID { field entity_id: VarInt =, field ty: u8 =, field x: i32 =, @@ -461,7 +461,7 @@ state_packets!( field velocity_x: i16 =, field velocity_y: i16 =, field velocity_z: i16 =, - field metadata: types::Metadata18 =, + field metadata: types::Metadata =, } /// SpawnPainting spawns a painting into the world when it is in range of /// the client. The title effects the size and the texture of the painting. @@ -489,7 +489,7 @@ state_packets!( field z: f64 =, field yaw: i8 =, field pitch: i8 =, - field metadata: types::Metadata19 =, + field metadata: types::Metadata =, } packet SpawnPlayer_i32 { field entity_id: VarInt =, @@ -499,9 +499,9 @@ state_packets!( field z: i32 =, field yaw: i8 =, field pitch: i8 =, - field metadata: types::Metadata19 =, + field metadata: types::Metadata =, } - packet SpawnPlayer_i32_HeldItem_18 { + packet SpawnPlayer_i32_HeldItem { field entity_id: VarInt =, field uuid: UUID =, field x: i32 =, @@ -510,7 +510,7 @@ state_packets!( field yaw: i8 =, field pitch: i8 =, field current_item: u16 =, - field metadata: types::Metadata18 =, + field metadata: types::Metadata =, } /// Animation is sent by the server to play an animation on a specific entity. packet Animation { @@ -1010,11 +1010,7 @@ state_packets!( /// EntityMetadata updates the metadata for an entity. packet EntityMetadata { field entity_id: VarInt =, - field metadata: types::Metadata19 =, - } - packet EntityMetadata_18 { - field entity_id: VarInt =, - field metadata: types::Metadata18 =, + field metadata: types::Metadata =, } /// EntityAttach attaches to entities together, either by mounting or leashing. /// -1 can be used at the EntityID to deattach. diff --git a/src/protocol/versions/v1_8_9.rs b/src/protocol/versions/v1_8_9.rs index 72d55ff..362b93c 100644 --- a/src/protocol/versions/v1_8_9.rs +++ b/src/protocol/versions/v1_8_9.rs @@ -48,10 +48,10 @@ protocol_packet_ids!( 0x09 => SetCurrentHotbarSlot 0x0a => EntityUsedBed 0x0b => Animation - 0x0c => SpawnPlayer_i32_HeldItem_18 + 0x0c => SpawnPlayer_i32_HeldItem 0x0d => CollectItem_nocount 0x0e => SpawnObject_i32_NoUUID - 0x0f => SpawnMob_u8_i32_NoUUID_18 + 0x0f => SpawnMob_u8_i32_NoUUID 0x10 => SpawnPainting_NoUUID 0x11 => SpawnExperienceOrb_i32 0x12 => EntityVelocity @@ -64,7 +64,7 @@ protocol_packet_ids!( 0x19 => EntityHeadLook 0x1a => EntityStatus 0x1b => EntityAttach_leashed - 0x1c => EntityMetadata_18 + 0x1c => EntityMetadata 0x1d => EntityEffect 0x1e => EntityRemoveEffect 0x1f => SetExperience diff --git a/src/server/mod.rs b/src/server/mod.rs index f6d4f28..ca147e8 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -399,7 +399,7 @@ impl Server { EntityDestroy => on_entity_destroy, SpawnPlayer_f64 => on_player_spawn_f64, SpawnPlayer_i32 => on_player_spawn_i32, - SpawnPlayer_i32_HeldItem_18 => on_player_spawn_i32_helditem_18, + SpawnPlayer_i32_HeldItem => on_player_spawn_i32_helditem, EntityTeleport_f64 => on_entity_teleport_f64, EntityTeleport_i32 => on_entity_teleport_i32, EntityMove_i16 => on_entity_move_i16, @@ -752,7 +752,7 @@ impl Server { self.on_player_spawn(spawn.entity_id.0, spawn.uuid, spawn.x as f64, spawn.y as f64, spawn.z as f64, spawn.yaw as f64, spawn.pitch as f64) } - fn on_player_spawn_i32_helditem_18(&mut self, spawn: packet::play::clientbound::SpawnPlayer_i32_HeldItem_18) { + fn on_player_spawn_i32_helditem(&mut self, spawn: packet::play::clientbound::SpawnPlayer_i32_HeldItem) { self.on_player_spawn(spawn.entity_id.0, spawn.uuid, spawn.x as f64, spawn.y as f64, spawn.z as f64, spawn.yaw as f64, spawn.pitch as f64) } diff --git a/src/types/metadata.rs b/src/types/metadata.rs index 498cd01..44ee0a7 100644 --- a/src/types/metadata.rs +++ b/src/types/metadata.rs @@ -38,66 +38,28 @@ impl MetadataKey { } } -pub struct Metadata18 { +pub struct Metadata { map: HashMap, } -pub struct Metadata19 { - map: HashMap, -} - -trait MetadataBase: fmt::Debug + Default { - fn map(&self) -> &HashMap; - fn map_mut(&mut self) -> &mut HashMap; - - fn get(&self, key: &MetadataKey) -> Option<&T> { - self.map().get(&key.index).map(T::unwrap) +impl Metadata { + pub fn new() -> Metadata { + Metadata { map: HashMap::new() } } - fn put(&mut self, key: &MetadataKey, val: T) { - self.map_mut().insert(key.index, val.wrap()); + pub fn get(&self, key: &MetadataKey) -> Option<&T> { + self.map.get(&key.index).map(T::unwrap) + } + + pub fn put(&mut self, key: &MetadataKey, val: T) { + self.map.insert(key.index, val.wrap()); } fn put_raw(&mut self, index: i32, val: T) { - self.map_mut().insert(index, val.wrap()); + self.map.insert(index, val.wrap()); } - fn fmt2(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Metadata[ ")?; - for (k, v) in self.map() { - write!(f, "{:?}={:?}, ", k, v)?; - } - write!(f, "]") - } -} - -impl MetadataBase for Metadata18 { - fn map(&self) -> &HashMap { &self.map } - fn map_mut(&mut self) -> &mut HashMap { &mut self.map } -} - -impl MetadataBase for Metadata19 { - fn map(&self) -> &HashMap { &self.map } - fn map_mut(&mut self) -> &mut HashMap { &mut self.map } -} - -impl Metadata18 { - pub fn new() -> Self { - Self { map: HashMap::new() } - } -} - -impl Metadata19 { - pub fn new() -> Self { - Self { map: HashMap::new() } - } -} - - - -impl Serializable for Metadata18 { - - fn read_from(buf: &mut R) -> Result { + fn read_from18(buf: &mut R) -> Result { let mut m = Self::new(); loop { let ty_index = u8::read_from(buf)? as i32; @@ -128,7 +90,7 @@ impl Serializable for Metadata18 { Ok(m) } - fn write_to(&self, buf: &mut W) -> Result<(), protocol::Error> { + fn write_to18(&self, buf: &mut W) -> Result<(), protocol::Error> { for (k, v) in &self.map { if (*k as u8) > 0x1f { panic!("write metadata index {:x} > 0x1f", *k as u8); @@ -177,9 +139,7 @@ impl Serializable for Metadata18 { val[2].write_to(buf)?; } - Value::FormatComponent(_) | Value::Bool(_) | Value::Position(_) | - Value::OptionalPosition(_) | Value::Direction(_) | Value::OptionalUUID(_) | - Value::Block(_) | Value::NBTTag(_) => { + _ => { panic!("attempted to write 1.9+ metadata to 1.8"); } } @@ -187,11 +147,8 @@ impl Serializable for Metadata18 { u8::write_to(&0x7f, buf)?; Ok(()) } -} -impl Serializable for Metadata19 { - - fn read_from(buf: &mut R) -> Result { + fn read_from19(buf: &mut R) -> Result { let mut m = Self::new(); loop { let index = u8::read_from(buf)? as i32; @@ -243,7 +200,7 @@ impl Serializable for Metadata19 { Ok(m) } - fn write_to(&self, buf: &mut W) -> Result<(), protocol::Error> { + fn write_to19(&self, buf: &mut W) -> Result<(), protocol::Error> { for (k, v) in &self.map { (*k as u8).write_to(buf)?; match *v { @@ -316,18 +273,41 @@ impl Serializable for Metadata19 { } } -// TODO: is it possible to implement these traits on MetadataBase instead? -impl fmt::Debug for Metadata19 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt2(f) } } -impl fmt::Debug for Metadata18 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt2(f) } } +impl Serializable for Metadata { + fn read_from(buf: &mut R) -> Result { + let protocol_version = unsafe { protocol::CURRENT_PROTOCOL_VERSION }; -impl Default for Metadata19 { - fn default() -> Self { - Self::new() + if protocol_version >= 74 { + Metadata::read_from19(buf) + } else { + Metadata::read_from18(buf) + } + } + + fn write_to(&self, buf: &mut W) -> Result<(), protocol::Error> { + let protocol_version = unsafe { protocol::CURRENT_PROTOCOL_VERSION }; + + if protocol_version >= 74 { + self.write_to19(buf) + } else { + self.write_to18(buf) + } } } -impl Default for Metadata18 { - fn default() -> Self { - Self::new() + +impl fmt::Debug for Metadata { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Metadata[ ")?; + for (k, v) in &self.map { + write!(f, "{:?}={:?}, ", k, v)?; + } + write!(f, "]") + } +} + +impl Default for Metadata { + fn default() -> Metadata { + Metadata::new() } } @@ -561,7 +541,7 @@ mod test { #[test] fn basic() { - let mut m = Metadata19::new(); + let mut m = Metadata::new(); m.put(&TEST, "Hello world".to_owned());