From 2daca512b0882c10c078a1a192909634e57d5fa1 Mon Sep 17 00:00:00 2001 From: ice_iix Date: Sun, 29 Dec 2019 15:55:19 -0800 Subject: [PATCH] 1.15.1 protocol support (575) (#252) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add v1_15_1 for protocol 575 * Update for shifted packet IDs https://wiki.vg/index.php?title=Pre-release_protocol&oldid=15213#Packets https://wiki.vg/Pre-release_protocol * Add SpawnMob packet variant, no metadata * Add SpawnPlayer packet variant, no metadata * Add block update actions comments, including beehive * Add particle packet variant with 64-bit floats * Add and handle join game and respawn packet variants, with hashed seeds * Add chunk data packet variant with 3D biomes https://wiki.vg/index.php?title=Pre-release_protocol&oldid=15213#Chunk_Data "1024 biome IDs, ordered by x then z then d, in 4×4×4 blocks. Not present if full chunk is false." This is a fixed-size array of integers, but Rust doesn't yet support generics over integers, so the 1024-element array doesn't support fmt::Debug, hence we wrap it and implement fmt::Debug ourselves. * Add load_chunk115 to not read chunk data structure biomes https://wiki.vg/index.php?title=Pre-release_protocol&oldid=15213#Data_structure --- README.md | 1 + src/protocol/mod.rs | 39 ++++++- src/protocol/packet.rs | 81 +++++++++++++- src/protocol/versions.rs | 3 + src/protocol/versions/v18w50a.rs | 2 +- src/protocol/versions/v19w02a.rs | 2 +- src/protocol/versions/v1_11_2.rs | 2 +- src/protocol/versions/v1_12_2.rs | 2 +- src/protocol/versions/v1_13_2.rs | 2 +- src/protocol/versions/v1_14.rs | 2 +- src/protocol/versions/v1_14_1.rs | 2 +- src/protocol/versions/v1_14_2.rs | 2 +- src/protocol/versions/v1_14_3.rs | 2 +- src/protocol/versions/v1_14_4.rs | 2 +- src/protocol/versions/v1_15_1.rs | 180 +++++++++++++++++++++++++++++++ src/server/mod.rs | 49 ++++++++- src/world/mod.rs | 10 +- 17 files changed, 368 insertions(+), 15 deletions(-) create mode 100644 src/protocol/versions/v1_15_1.rs diff --git a/README.md b/README.md index ff97f99..c13a336 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Join with your favorite IRC client or [Matrix](https://matrix.to/#/#_espernet_#s | Game version | Protocol version | Supported? | | ------ | --- | --- | +| 1.15.1 | 575 | ✓ | | 1.14.4 | 498 | ✓ | | 1.14.3 | 490 | ✓ | | 1.14.2 | 485 | ✓ | diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index a879066..1187c18 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -42,7 +42,7 @@ use std::time::{Instant, Duration}; use crate::shared::Position; use log::debug; -pub const SUPPORTED_PROTOCOLS: [i32; 17] = [498, 490, 485, 480, 477, 452, 451, 404, 340, 316, 315, 210, 109, 107, 74, 47, 5]; +pub const SUPPORTED_PROTOCOLS: [i32; 18] = [575, 498, 490, 485, 480, 477, 452, 451, 404, 340, 316, 315, 210, 109, 107, 74, 47, 5]; // 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]; @@ -447,6 +447,43 @@ impl Serializable for UUID { } } +pub struct Biomes3D { + pub data: [i32; 1024], +} + +impl fmt::Debug for Biomes3D { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Biomes3D(")?; + for i in 0..1024 { + write!(f, "{}, ", self.data[i])?; + } + write!(f, ")") + } +} + +impl Default for Biomes3D { + fn default() -> Self { + Biomes3D { data: [0; 1024] } + } +} + +impl Serializable for Biomes3D { + fn read_from(buf: &mut R) -> Result { + let mut data: [i32; 1024] = [0; 1024]; + + // Non-length-prefixed three-dimensional biome data + for i in 0..1024 { + let b: i32 = Serializable::read_from(buf)?; + data[i] = b; + } + + Result::Ok(Biomes3D { data }) + } + fn write_to(&self, _buf: &mut W) -> Result<(), Error> { + unimplemented!() + } +} + pub trait Lengthable : Serializable + Copy + Default { fn into_len(self) -> usize; diff --git a/src/protocol/packet.rs b/src/protocol/packet.rs index a25c865..535f65c 100644 --- a/src/protocol/packet.rs +++ b/src/protocol/packet.rs @@ -558,7 +558,21 @@ state_packets!( } /// SpawnMob is used to spawn a living entity into the world when it is in /// range of the client. - packet SpawnMob { + packet SpawnMob_NoMeta { + field entity_id: VarInt =, + field uuid: UUID =, + field ty: VarInt =, + field x: f64 =, + field y: f64 =, + field z: f64 =, + field yaw: i8 =, + field pitch: i8 =, + field head_pitch: i8 =, + field velocity_x: i16 =, + field velocity_y: i16 =, + field velocity_z: i16 =, + } + packet SpawnMob_WithMeta { field entity_id: VarInt =, field uuid: UUID =, field ty: VarInt =, @@ -650,6 +664,15 @@ state_packets!( /// SpawnPlayer is used to spawn a player when they are in range of the client. /// This packet alone isn't enough to display the player as the skin and username /// information is in the player information packet. + packet SpawnPlayer_f64_NoMeta { + field entity_id: VarInt =, + field uuid: UUID =, + field x: f64 =, + field y: f64 =, + field z: f64 =, + field yaw: i8 =, + field pitch: i8 =, + } packet SpawnPlayer_f64 { field entity_id: VarInt =, field uuid: UUID =, @@ -969,6 +992,16 @@ state_packets!( } /// ChunkData sends or updates a single chunk on the client. If New is set /// then biome data should be sent too. + packet ChunkData_Biomes3D { + field chunk_x: i32 =, + field chunk_z: i32 =, + field new: bool =, + field bitmask: VarInt =, + field heightmaps: Option =, + field biomes: Biomes3D = when(|p: &ChunkData_Biomes3D| p.new), + field data: LenPrefixedBytes =, + field block_entities: LenPrefixed> =, + } packet ChunkData_HeightMap { field chunk_x: i32 =, field chunk_z: i32 =, @@ -1038,6 +1071,24 @@ state_packets!( } /// Particle spawns particles at the target location with the various /// modifiers. + packet Particle_f64 { + field particle_id: i32 =, + field long_distance: bool =, + field x: f64 =, + field y: f64=, + field z: f64 =, + field offset_x: f32 =, + field offset_y: f32 =, + field offset_z: f32 =, + field speed: f32 =, + field count: i32 =, + field block_state: VarInt = when(|p: &Particle_f64| p.particle_id == 3 || p.particle_id == 20), + field red: f32 = when(|p: &Particle_f64| p.particle_id == 11), + field green: f32 = when(|p: &Particle_f64| p.particle_id == 11), + field blue: f32 = when(|p: &Particle_f64| p.particle_id == 11), + field scale: f32 = when(|p: &Particle_f64| p.particle_id == 11), + field item: Option = when(|p: &Particle_f64| p.particle_id == 27), + } packet Particle_Data { field particle_id: i32 =, field long_distance: bool =, @@ -1083,6 +1134,27 @@ state_packets!( } /// JoinGame is sent after completing the login process. This /// sets the initial state for the client. + packet JoinGame_HashedSeed_Respawn { + /// The entity id the client will be referenced by + field entity_id: i32 =, + /// The starting gamemode of the client + field gamemode: u8 =, + /// The dimension the client is starting in + field dimension: i32 =, + /// Truncated SHA-256 hash of world's seed + field hashed_seed: i64 =, + /// The max number of players on the server + field max_players: u8 =, + /// The level type of the server + field level_type: String =, + /// The render distance (2-32) + field view_distance: VarInt =, + /// Whether the client should reduce the amount of debug + /// information it displays in F3 mode + field reduced_debug_info: bool =, + /// Whether to prompt or immediately respawn + field enable_respawn_screen: bool =, + } packet JoinGame_i32_ViewDistance { /// The entity id the client will be referenced by field entity_id: i32 =, @@ -1387,6 +1459,13 @@ state_packets!( field gamemode: u8 =, field level_type: String =, } + packet Respawn_HashedSeed { + field dimension: i32 =, + field hashed_seed: i64 =, + field difficulty: u8 =, + field gamemode: u8 =, + field level_type: String =, + } /// EntityHeadLook rotates an entity's head to the new angle. packet EntityHeadLook { field entity_id: VarInt =, diff --git a/src/protocol/versions.rs b/src/protocol/versions.rs index 9912bb1..461bca1 100644 --- a/src/protocol/versions.rs +++ b/src/protocol/versions.rs @@ -1,5 +1,6 @@ use super::*; +mod v1_15_1; mod v1_14_4; mod v1_14_3; mod v1_14_2; @@ -23,6 +24,7 @@ mod v1_7_10; pub fn protocol_name_to_protocol_version(s: String) -> i32 { match s.as_ref() { "" => SUPPORTED_PROTOCOLS[0], + "1.15.1" => 575, "1.14.4" => 498, "1.14.3" => 490, "1.14.2" => 485, @@ -52,6 +54,7 @@ pub fn protocol_name_to_protocol_version(s: String) -> i32 { pub fn translate_internal_packet_id_for_version(version: i32, state: State, dir: Direction, id: i32, to_internal: bool) -> i32 { match version { + 575 => v1_15_1::translate_internal_packet_id(state, dir, id, to_internal), 498 => v1_14_4::translate_internal_packet_id(state, dir, id, to_internal), 490 => v1_14_3::translate_internal_packet_id(state, dir, id, to_internal), 485 => v1_14_2::translate_internal_packet_id(state, dir, id, to_internal), diff --git a/src/protocol/versions/v18w50a.rs b/src/protocol/versions/v18w50a.rs index 8eafbd9..0a9d6a9 100644 --- a/src/protocol/versions/v18w50a.rs +++ b/src/protocol/versions/v18w50a.rs @@ -56,7 +56,7 @@ protocol_packet_ids!( 0x00 => SpawnObject 0x01 => SpawnExperienceOrb 0x02 => SpawnGlobalEntity - 0x03 => SpawnMob + 0x03 => SpawnMob_WithMeta 0x04 => SpawnPainting_String 0x05 => SpawnPlayer_f64 0x06 => Animation diff --git a/src/protocol/versions/v19w02a.rs b/src/protocol/versions/v19w02a.rs index 0014b0e..9a2af5c 100644 --- a/src/protocol/versions/v19w02a.rs +++ b/src/protocol/versions/v19w02a.rs @@ -56,7 +56,7 @@ protocol_packet_ids!( 0x00 => SpawnObject 0x01 => SpawnExperienceOrb 0x02 => SpawnGlobalEntity - 0x03 => SpawnMob + 0x03 => SpawnMob_WithMeta 0x04 => SpawnPainting_String 0x05 => SpawnPlayer_f64 0x06 => Animation diff --git a/src/protocol/versions/v1_11_2.rs b/src/protocol/versions/v1_11_2.rs index 4619ba5..aa82c97 100644 --- a/src/protocol/versions/v1_11_2.rs +++ b/src/protocol/versions/v1_11_2.rs @@ -43,7 +43,7 @@ protocol_packet_ids!( 0x00 => SpawnObject 0x01 => SpawnExperienceOrb 0x02 => SpawnGlobalEntity - 0x03 => SpawnMob + 0x03 => SpawnMob_WithMeta 0x04 => SpawnPainting_String 0x05 => SpawnPlayer_f64 0x06 => Animation diff --git a/src/protocol/versions/v1_12_2.rs b/src/protocol/versions/v1_12_2.rs index 338b5fa..1e3b909 100644 --- a/src/protocol/versions/v1_12_2.rs +++ b/src/protocol/versions/v1_12_2.rs @@ -46,7 +46,7 @@ protocol_packet_ids!( 0x00 => SpawnObject 0x01 => SpawnExperienceOrb 0x02 => SpawnGlobalEntity - 0x03 => SpawnMob + 0x03 => SpawnMob_WithMeta 0x04 => SpawnPainting_VarInt 0x05 => SpawnPlayer_f64 0x06 => Animation diff --git a/src/protocol/versions/v1_13_2.rs b/src/protocol/versions/v1_13_2.rs index 874cca7..04871b1 100644 --- a/src/protocol/versions/v1_13_2.rs +++ b/src/protocol/versions/v1_13_2.rs @@ -56,7 +56,7 @@ protocol_packet_ids!( 0x00 => SpawnObject 0x01 => SpawnExperienceOrb 0x02 => SpawnGlobalEntity - 0x03 => SpawnMob + 0x03 => SpawnMob_WithMeta 0x04 => SpawnPainting_VarInt 0x05 => SpawnPlayer_f64 0x06 => Animation diff --git a/src/protocol/versions/v1_14.rs b/src/protocol/versions/v1_14.rs index 0107cce..b5c9a9a 100644 --- a/src/protocol/versions/v1_14.rs +++ b/src/protocol/versions/v1_14.rs @@ -59,7 +59,7 @@ protocol_packet_ids!( 0x00 => SpawnObject 0x01 => SpawnExperienceOrb 0x02 => SpawnGlobalEntity - 0x03 => SpawnMob + 0x03 => SpawnMob_WithMeta 0x04 => SpawnPainting_VarInt 0x05 => SpawnPlayer_f64 0x06 => Animation diff --git a/src/protocol/versions/v1_14_1.rs b/src/protocol/versions/v1_14_1.rs index 0107cce..b5c9a9a 100644 --- a/src/protocol/versions/v1_14_1.rs +++ b/src/protocol/versions/v1_14_1.rs @@ -59,7 +59,7 @@ protocol_packet_ids!( 0x00 => SpawnObject 0x01 => SpawnExperienceOrb 0x02 => SpawnGlobalEntity - 0x03 => SpawnMob + 0x03 => SpawnMob_WithMeta 0x04 => SpawnPainting_VarInt 0x05 => SpawnPlayer_f64 0x06 => Animation diff --git a/src/protocol/versions/v1_14_2.rs b/src/protocol/versions/v1_14_2.rs index 0107cce..b5c9a9a 100644 --- a/src/protocol/versions/v1_14_2.rs +++ b/src/protocol/versions/v1_14_2.rs @@ -59,7 +59,7 @@ protocol_packet_ids!( 0x00 => SpawnObject 0x01 => SpawnExperienceOrb 0x02 => SpawnGlobalEntity - 0x03 => SpawnMob + 0x03 => SpawnMob_WithMeta 0x04 => SpawnPainting_VarInt 0x05 => SpawnPlayer_f64 0x06 => Animation diff --git a/src/protocol/versions/v1_14_3.rs b/src/protocol/versions/v1_14_3.rs index 75ab579..a5eebf2 100644 --- a/src/protocol/versions/v1_14_3.rs +++ b/src/protocol/versions/v1_14_3.rs @@ -59,7 +59,7 @@ protocol_packet_ids!( 0x00 => SpawnObject 0x01 => SpawnExperienceOrb 0x02 => SpawnGlobalEntity - 0x03 => SpawnMob + 0x03 => SpawnMob_WithMeta 0x04 => SpawnPainting_VarInt 0x05 => SpawnPlayer_f64 0x06 => Animation diff --git a/src/protocol/versions/v1_14_4.rs b/src/protocol/versions/v1_14_4.rs index 941dce1..60be91a 100644 --- a/src/protocol/versions/v1_14_4.rs +++ b/src/protocol/versions/v1_14_4.rs @@ -59,7 +59,7 @@ protocol_packet_ids!( 0x00 => SpawnObject 0x01 => SpawnExperienceOrb 0x02 => SpawnGlobalEntity - 0x03 => SpawnMob + 0x03 => SpawnMob_WithMeta 0x04 => SpawnPainting_VarInt 0x05 => SpawnPlayer_f64 0x06 => Animation diff --git a/src/protocol/versions/v1_15_1.rs b/src/protocol/versions/v1_15_1.rs new file mode 100644 index 0000000..6c3386c --- /dev/null +++ b/src/protocol/versions/v1_15_1.rs @@ -0,0 +1,180 @@ +protocol_packet_ids!( + handshake Handshaking { + serverbound Serverbound { + 0x00 => Handshake + } + clientbound Clientbound { + } + } + play Play { + serverbound Serverbound { + 0x00 => TeleportConfirm + 0x01 => QueryBlockNBT + 0x02 => SetDifficulty + 0x03 => ChatMessage + 0x04 => ClientStatus + 0x05 => ClientSettings + 0x06 => TabComplete + 0x07 => ConfirmTransactionServerbound + 0x08 => ClickWindowButton + 0x09 => ClickWindow + 0x0a => CloseWindow + 0x0b => PluginMessageServerbound + 0x0c => EditBook + 0x0d => QueryEntityNBT + 0x0e => UseEntity + 0x0f => KeepAliveServerbound_i64 + 0x10 => LockDifficulty + 0x11 => PlayerPosition + 0x12 => PlayerPositionLook + 0x13 => PlayerLook + 0x14 => Player + 0x15 => VehicleMove + 0x16 => SteerBoat + 0x17 => PickItem + 0x18 => CraftRecipeRequest + 0x19 => ClientAbilities + 0x1a => PlayerDigging + 0x1b => PlayerAction + 0x1c => SteerVehicle + 0x1d => CraftingBookData + 0x1e => NameItem + 0x1f => ResourcePackStatus + 0x20 => AdvancementTab + 0x21 => SelectTrade + 0x22 => SetBeaconEffect + 0x23 => HeldItemChange + 0x24 => UpdateCommandBlock + 0x25 => UpdateCommandBlockMinecart + 0x26 => CreativeInventoryAction + 0x27 => UpdateJigsawBlock + 0x28 => UpdateStructureBlock + 0x29 => SetSign + 0x2a => ArmSwing + 0x2b => SpectateTeleport + 0x2c => PlayerBlockPlacement_f32 + 0x2d => UseItem + } + clientbound Clientbound { + 0x00 => SpawnObject + 0x01 => SpawnExperienceOrb + 0x02 => SpawnGlobalEntity + 0x03 => SpawnMob_NoMeta + 0x04 => SpawnPainting_VarInt + 0x05 => SpawnPlayer_f64_NoMeta + 0x06 => Animation + 0x07 => Statistics + 0x08 => AcknowledgePlayerDigging + 0x09 => BlockBreakAnimation + 0x0a => UpdateBlockEntity + 0x0b => BlockAction + 0x0c => BlockChange_VarInt + 0x0d => BossBar + 0x0e => ServerDifficulty_Locked + 0x0f => ServerMessage + 0x10 => MultiBlockChange_VarInt + 0x11 => TabCompleteReply + 0x12 => DeclareCommands + 0x13 => ConfirmTransaction + 0x14 => WindowClose + 0x15 => WindowItems + 0x16 => WindowProperty + 0x17 => WindowSetSlot + 0x18 => SetCooldown + 0x19 => PluginMessageClientbound + 0x1a => NamedSoundEffect + 0x1b => Disconnect + 0x1c => EntityAction + 0x1d => Explosion + 0x1e => ChunkUnload + 0x1f => ChangeGameState + 0x20 => WindowOpenHorse + 0x21 => KeepAliveClientbound_i64 + 0x22 => ChunkData_Biomes3D + 0x23 => Effect + 0x24 => Particle_f64 + 0x25 => UpdateLight + 0x26 => JoinGame_HashedSeed_Respawn + 0x27 => Maps + 0x28 => TradeList_WithRestock + 0x29 => EntityMove_i16 + 0x2a => EntityLookAndMove_i16 + 0x2b => EntityLook_VarInt + 0x2c => Entity + 0x2d => VehicleTeleport + 0x2e => OpenBook + 0x2f => WindowOpen_VarInt + 0x30 => SignEditorOpen + 0x31 => CraftRecipeResponse + 0x32 => PlayerAbilities + 0x33 => CombatEvent + 0x34 => PlayerInfo + 0x35 => FacePlayer + 0x36 => TeleportPlayer_WithConfirm + 0x37 => UnlockRecipes_WithSmelting + 0x38 => EntityDestroy + 0x39 => EntityRemoveEffect + 0x3a => ResourcePackSend + 0x3b => Respawn_HashedSeed + 0x3c => EntityHeadLook + 0x3d => SelectAdvancementTab + 0x3e => WorldBorder + 0x3f => Camera + 0x40 => SetCurrentHotbarSlot + 0x41 => UpdateViewPosition + 0x42 => UpdateViewDistance + 0x43 => ScoreboardDisplay + 0x44 => EntityMetadata + 0x45 => EntityAttach + 0x46 => EntityVelocity + 0x47 => EntityEquipment + 0x48 => SetExperience + 0x49 => UpdateHealth + 0x4a => ScoreboardObjective + 0x4b => SetPassengers + 0x4c => Teams_VarInt + 0x4d => UpdateScore + 0x4e => SpawnPosition + 0x4f => TimeUpdate + 0x50 => Title + 0x51 => EntitySoundEffect + 0x52 => SoundEffect + 0x53 => StopSound + 0x54 => PlayerListHeaderFooter + 0x55 => NBTQueryResponse + 0x56 => CollectItem + 0x57 => EntityTeleport_f64 + 0x58 => Advancements + 0x59 => EntityProperties + 0x5a => EntityEffect + 0x5b => DeclareRecipes + 0x5c => TagsWithEntities + } + } + login Login { + serverbound Serverbound { + 0x00 => LoginStart + 0x01 => EncryptionResponse + 0x02 => LoginPluginResponse + } + clientbound Clientbound { + 0x00 => LoginDisconnect + 0x01 => EncryptionRequest + 0x02 => LoginSuccess + 0x03 => SetInitialCompression + 0x04 => LoginPluginRequest + } + } + status Status { + serverbound Serverbound { + 0x00 => StatusRequest + 0x01 => StatusPing + } + clientbound Clientbound { + 0x00 => StatusResponse + 0x01 => StatusPong + } + } +); + + diff --git a/src/server/mod.rs b/src/server/mod.rs index 9c4fc7d..77288ea 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -396,15 +396,18 @@ impl Server { self pck { PluginMessageClientbound_i16 => on_plugin_message_clientbound_i16, PluginMessageClientbound => on_plugin_message_clientbound_1, + JoinGame_HashedSeed_Respawn => on_game_join_hashedseed_respawn, JoinGame_i32_ViewDistance => on_game_join_i32_viewdistance, JoinGame_i32 => on_game_join_i32, JoinGame_i8 => on_game_join_i8, JoinGame_i8_NoDebug => on_game_join_i8_nodebug, Respawn => on_respawn, + Respawn_HashedSeed => on_respawn_hashedseed, KeepAliveClientbound_i64 => on_keep_alive_i64, KeepAliveClientbound_VarInt => on_keep_alive_varint, KeepAliveClientbound_i32 => on_keep_alive_i32, ChunkData => on_chunk_data, + ChunkData_Biomes3D => on_chunk_data_biomes3d, ChunkData_HeightMap => on_chunk_data_heightmap, ChunkData_NoEntities => on_chunk_data_no_entities, ChunkData_NoEntities_u16 => on_chunk_data_no_entities_u16, @@ -778,6 +781,10 @@ impl Server { } } + fn on_game_join_hashedseed_respawn(&mut self, join: packet::play::clientbound::JoinGame_HashedSeed_Respawn) { + self.on_game_join(join.gamemode, join.entity_id) + } + fn on_game_join_i32_viewdistance(&mut self, join: packet::play::clientbound::JoinGame_i32_ViewDistance) { self.on_game_join(join.gamemode, join.entity_id) } @@ -821,9 +828,17 @@ impl Server { } } + fn on_respawn_hashedseed(&mut self, respawn: packet::play::clientbound::Respawn_HashedSeed) { + self.respawn(respawn.gamemode) + } + fn on_respawn(&mut self, respawn: packet::play::clientbound::Respawn) { + self.respawn(respawn.gamemode) + } + + fn respawn(&mut self, gamemode_u8: u8) { self.world = world::World::new(self.protocol_version); - let gamemode = Gamemode::from_int((respawn.gamemode & 0x7) as i32); + let gamemode = Gamemode::from_int((gamemode_u8 & 0x7) as i32); if let Some(player) = self.player { *self.entities.get_component_mut(player, self.gamemode).unwrap() = gamemode; @@ -1073,7 +1088,17 @@ impl Server { )); }, Some(nbt) => { - if block_update.action == 9 { + match block_update.action { + // TODO: support more block update actions + //1 => // Mob spawner + //2 => // Command block text + //3 => // Beacon + //4 => // Mob head + //5 => // Conduit + //6 => // Banner + //7 => // Structure + //8 => // Gateway + 9 => { // Sign let line1 = format::Component::from_string(nbt.1.get("Text1").unwrap().as_str().unwrap()); let line2 = format::Component::from_string(nbt.1.get("Text2").unwrap().as_str().unwrap()); let line3 = format::Component::from_string(nbt.1.get("Text3").unwrap().as_str().unwrap()); @@ -1085,6 +1110,14 @@ impl Server { line3, line4, )); + }, + //10 => // Unused + //11 => // Jigsaw + //12 => // Campfire + //14 => // Beehive + _ => { + debug!("Unsupported block entity action: {}", block_update.action); + }, } } } @@ -1231,6 +1264,18 @@ impl Server { } } + fn on_chunk_data_biomes3d(&mut self, chunk_data: packet::play::clientbound::ChunkData_Biomes3D) { + self.world.load_chunk115( + chunk_data.chunk_x, + chunk_data.chunk_z, + chunk_data.new, + chunk_data.bitmask.0 as u16, + chunk_data.data.data + ).unwrap(); + self.load_block_entities(chunk_data.block_entities.data); + } + + fn on_chunk_data(&mut self, chunk_data: packet::play::clientbound::ChunkData) { self.world.load_chunk19( chunk_data.chunk_x, diff --git a/src/world/mod.rs b/src/world/mod.rs index 5078630..09871c6 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -830,6 +830,14 @@ impl World { } pub fn load_chunk19(&mut self, x: i32, z: i32, new: bool, mask: u16, data: Vec) -> Result<(), protocol::Error> { + self.load_chunk19_or_115(true, x, z, new, mask, data) + } + + pub fn load_chunk115(&mut self, x: i32, z: i32, new: bool, mask: u16, data: Vec) -> Result<(), protocol::Error> { + self.load_chunk19_or_115(false, x, z, new, mask, data) + } + + fn load_chunk19_or_115(&mut self, read_biomes: bool, x: i32, z: i32, new: bool, mask: u16, data: Vec) -> Result<(), protocol::Error> { use std::io::Cursor; use byteorder::ReadBytesExt; use crate::protocol::{VarInt, Serializable, LenPrefixed}; @@ -911,7 +919,7 @@ impl World { } } - if new { + if read_biomes && new { data.read_exact(&mut chunk.biomes)?; }