From e3fe9e5e93fbf8ce26a61719fdb4ccd9a627d37a Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 15 Mar 2021 17:06:58 +0000 Subject: Deduplicate WriteBlockEntity --- src/Protocol/Protocol_1_10.cpp | 118 ----------------- src/Protocol/Protocol_1_10.h | 1 - src/Protocol/Protocol_1_11.cpp | 192 ++++++++++------------------ src/Protocol/Protocol_1_11.h | 13 +- src/Protocol/Protocol_1_13.cpp | 24 ++-- src/Protocol/Protocol_1_8.cpp | 279 ++++++++++++++++++----------------------- src/Protocol/Protocol_1_8.h | 6 +- src/Protocol/Protocol_1_9.cpp | 146 +++++---------------- src/Protocol/Protocol_1_9.h | 6 +- 9 files changed, 247 insertions(+), 538 deletions(-) diff --git a/src/Protocol/Protocol_1_10.cpp b/src/Protocol/Protocol_1_10.cpp index 6b88fbe2a..6db08c916 100644 --- a/src/Protocol/Protocol_1_10.cpp +++ b/src/Protocol/Protocol_1_10.cpp @@ -581,124 +581,6 @@ void cProtocol_1_10_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & -void cProtocol_1_10_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity) -{ - cFastNBTWriter Writer; - - switch (a_BlockEntity.GetBlockType()) - { - case E_BLOCK_WALL_BANNER: - case E_BLOCK_STANDING_BANNER: - { - auto & BannerEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", BannerEntity.GetPosX()); - Writer.AddInt("y", BannerEntity.GetPosY()); - Writer.AddInt("z", BannerEntity.GetPosZ()); - Writer.AddString("id", "Banner"); - Writer.AddInt("Base", static_cast(BannerEntity.GetBaseColor())); - break; - } - - case E_BLOCK_BEACON: - { - auto & BeaconEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", BeaconEntity.GetPosX()); - Writer.AddInt("y", BeaconEntity.GetPosY()); - Writer.AddInt("z", BeaconEntity.GetPosZ()); - Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect()); - Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect()); - Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); - Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - break; - } - - case E_BLOCK_COMMAND_BLOCK: - { - auto & CommandBlockEntity = static_cast(a_BlockEntity); - Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this - Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult()); - Writer.AddInt("x", CommandBlockEntity.GetPosX()); - Writer.AddInt("y", CommandBlockEntity.GetPosY()); - Writer.AddInt("z", CommandBlockEntity.GetPosZ()); - Writer.AddString("Command", CommandBlockEntity.GetCommand()); - // You can set custom names for windows in Vanilla - // For a command block, this would be the 'name' prepended to anything it outputs into global chat - // MCS doesn't have this, so just leave it @ '@'. (geddit?) - Writer.AddString("CustomName", "@"); - Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - if (!CommandBlockEntity.GetLastOutput().empty()) - { - Writer.AddString("LastOutput", Printf("{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str())); - } - break; - } - - case E_BLOCK_HEAD: - { - auto & MobHeadEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", MobHeadEntity.GetPosX()); - Writer.AddInt("y", MobHeadEntity.GetPosY()); - Writer.AddInt("z", MobHeadEntity.GetPosZ()); - Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF); - Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF); - Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - - // The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity - Writer.BeginCompound("Owner"); - Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString()); - Writer.AddString("Name", MobHeadEntity.GetOwnerName()); - Writer.BeginCompound("Properties"); - Writer.BeginList("textures", TAG_Compound); - Writer.BeginCompound(""); - Writer.AddString("Signature", MobHeadEntity.GetOwnerTextureSignature()); - Writer.AddString("Value", MobHeadEntity.GetOwnerTexture()); - Writer.EndCompound(); - Writer.EndList(); - Writer.EndCompound(); - Writer.EndCompound(); - break; - } - - case E_BLOCK_FLOWER_POT: - { - auto & FlowerPotEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", FlowerPotEntity.GetPosX()); - Writer.AddInt("y", FlowerPotEntity.GetPosY()); - Writer.AddInt("z", FlowerPotEntity.GetPosZ()); - Writer.AddInt("Item", static_cast(FlowerPotEntity.GetItem().m_ItemType)); - Writer.AddInt("Data", static_cast(FlowerPotEntity.GetItem().m_ItemDamage)); - Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - break; - } - - case E_BLOCK_MOB_SPAWNER: - { - auto & MobSpawnerEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", MobSpawnerEntity.GetPosX()); - Writer.AddInt("y", MobSpawnerEntity.GetPosY()); - Writer.AddInt("z", MobSpawnerEntity.GetPosZ()); - Writer.BeginCompound("SpawnData"); - Writer.AddString("id", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity())); - Writer.EndCompound(); - Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay()); - Writer.AddString("id", "MobSpawner"); - break; - } - - default: - { - break; - } - } - - Writer.Finish(); - a_Pkt.WriteBuf(Writer.GetResult()); -} - - - - - void cProtocol_1_10_0::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) { using namespace Metadata; diff --git a/src/Protocol/Protocol_1_10.h b/src/Protocol/Protocol_1_10.h index 6c27b25b5..639658eb8 100644 --- a/src/Protocol/Protocol_1_10.h +++ b/src/Protocol/Protocol_1_10.h @@ -37,5 +37,4 @@ protected: virtual void HandlePacketResourcePackStatus(cByteBuffer & a_ByteBuffer) override; virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) override; virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) override; - virtual void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity) override; }; diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp index 424116b94..15197ad07 100644 --- a/src/Protocol/Protocol_1_11.cpp +++ b/src/Protocol/Protocol_1_11.cpp @@ -411,144 +411,51 @@ void cProtocol_1_11_0::SendSpawnMob(const cMonster & a_Mob) -void cProtocol_1_11_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity) +void cProtocol_1_11_0::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) { - cFastNBTWriter Writer; + ASSERT(m_State == 3); // In game mode? - switch (a_BlockEntity.GetBlockType()) - { - case E_BLOCK_WALL_BANNER: - case E_BLOCK_STANDING_BANNER: - { - auto & BannerEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", BannerEntity.GetPosX()); - Writer.AddInt("y", BannerEntity.GetPosY()); - Writer.AddInt("z", BannerEntity.GetPosZ()); - Writer.AddString("id", "Banner"); - Writer.AddInt("Base", static_cast(BannerEntity.GetBaseColor())); - break; - } + cPacketizer Pkt(*this, pktTitle); + Pkt.WriteVarInt32(3); // Set title display times + Pkt.WriteBEInt32(a_FadeInTicks); + Pkt.WriteBEInt32(a_DisplayTicks); + Pkt.WriteBEInt32(a_FadeOutTicks); +} - case E_BLOCK_BEACON: - { - auto & BeaconEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", BeaconEntity.GetPosX()); - Writer.AddInt("y", BeaconEntity.GetPosY()); - Writer.AddInt("z", BeaconEntity.GetPosZ()); - Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect()); - Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect()); - Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); - Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - break; - } - case E_BLOCK_BED: - { - auto & BedEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", BedEntity.GetPosX()); - Writer.AddInt("y", BedEntity.GetPosY()); - Writer.AddInt("z", BedEntity.GetPosZ()); - Writer.AddInt("color", BedEntity.GetColor()); - Writer.AddString("id", "Bed"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - break; - } - case E_BLOCK_COMMAND_BLOCK: - { - auto & CommandBlockEntity = static_cast(a_BlockEntity); - Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this - Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult()); - Writer.AddInt("x", CommandBlockEntity.GetPosX()); - Writer.AddInt("y", CommandBlockEntity.GetPosY()); - Writer.AddInt("z", CommandBlockEntity.GetPosZ()); - Writer.AddString("Command", CommandBlockEntity.GetCommand()); - // You can set custom names for windows in Vanilla - // For a command block, this would be the 'name' prepended to anything it outputs into global chat - // MCS doesn't have this, so just leave it @ '@'. (geddit?) - Writer.AddString("CustomName", "@"); - Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - if (!CommandBlockEntity.GetLastOutput().empty()) - { - Writer.AddString("LastOutput", Printf("{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str())); - } - break; - } - case E_BLOCK_HEAD: - { - auto & MobHeadEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", MobHeadEntity.GetPosX()); - Writer.AddInt("y", MobHeadEntity.GetPosY()); - Writer.AddInt("z", MobHeadEntity.GetPosZ()); - Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF); - Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF); - Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - - // The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity - Writer.BeginCompound("Owner"); - Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString()); - Writer.AddString("Name", MobHeadEntity.GetOwnerName()); - Writer.BeginCompound("Properties"); - Writer.BeginList("textures", TAG_Compound); - Writer.BeginCompound(""); - Writer.AddString("Signature", MobHeadEntity.GetOwnerTextureSignature()); - Writer.AddString("Value", MobHeadEntity.GetOwnerTexture()); - Writer.EndCompound(); - Writer.EndList(); - Writer.EndCompound(); - Writer.EndCompound(); - break; - } - case E_BLOCK_FLOWER_POT: - { - auto & FlowerPotEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", FlowerPotEntity.GetPosX()); - Writer.AddInt("y", FlowerPotEntity.GetPosY()); - Writer.AddInt("z", FlowerPotEntity.GetPosZ()); - Writer.AddInt("Item", static_cast(FlowerPotEntity.GetItem().m_ItemType)); - Writer.AddInt("Data", static_cast(FlowerPotEntity.GetItem().m_ItemDamage)); - Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - break; - } +void cProtocol_1_11_0::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) +{ + ASSERT(m_State == 3); // In game mode? - case E_BLOCK_MOB_SPAWNER: - { - auto & MobSpawnerEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", MobSpawnerEntity.GetPosX()); - Writer.AddInt("y", MobSpawnerEntity.GetPosY()); - Writer.AddInt("z", MobSpawnerEntity.GetPosZ()); - Writer.BeginCompound("SpawnData"); - Writer.AddString("id", "minecraft:" + cMonster::MobTypeToVanillaNBT(MobSpawnerEntity.GetEntity())); - Writer.EndCompound(); - Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay()); - Writer.AddString("id", "MobSpawner"); - break; - } + Byte Action; + switch (a_BlockEntity.GetBlockType()) + { + case E_BLOCK_ENCHANTMENT_TABLE: Action = 0; break; // The ones with a action of 0 is just a workaround to send the block entities to a client. + case E_BLOCK_END_PORTAL: Action = 0; break; // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12 + + case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing + case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text + case E_BLOCK_BEACON: Action = 3; break; // Update beacon entity + case E_BLOCK_HEAD: Action = 4; break; // Update mobhead entity + case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot + case E_BLOCK_WALL_BANNER: + case E_BLOCK_STANDING_BANNER: Action = 6; break; // Update banner + case E_BLOCK_BED: Action = 11; break; // Update bed color (new!) - default: - { - break; - } + default: return; // Block entities change between versions } - Writer.Finish(); - a_Pkt.WriteBuf(Writer.GetResult()); -} - - - - - -void cProtocol_1_11_0::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) -{ - ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, pktUpdateBlockEntity); + Pkt.WriteXYZPosition64(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ()); + Pkt.WriteBEUInt8(Action); - cPacketizer Pkt(*this, pktTitle); - Pkt.WriteVarInt32(3); // Set title display times - Pkt.WriteBEInt32(a_FadeInTicks); - Pkt.WriteBEInt32(a_DisplayTicks); - Pkt.WriteBEInt32(a_FadeOutTicks); + cFastNBTWriter Writer; + WriteBlockEntity(Writer, a_BlockEntity); + Writer.Finish(); + Pkt.WriteBuf(Writer.GetResult()); } @@ -644,6 +551,39 @@ void cProtocol_1_11_0::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer) +void cProtocol_1_11_0::WriteBlockEntity(cFastNBTWriter & a_Writer, const cBlockEntity & a_BlockEntity) +{ + a_Writer.AddInt("x", a_BlockEntity.GetPosX()); + a_Writer.AddInt("y", a_BlockEntity.GetPosY()); + a_Writer.AddInt("z", a_BlockEntity.GetPosZ()); + + switch (a_BlockEntity.GetBlockType()) + { + case E_BLOCK_BED: + { + auto & BedEntity = static_cast(a_BlockEntity); + a_Writer.AddInt("color", BedEntity.GetColor()); // New: multicoloured beds + break; + } + + case E_BLOCK_MOB_SPAWNER: + { + auto & MobSpawnerEntity = static_cast(a_BlockEntity); + a_Writer.BeginCompound("SpawnData"); + a_Writer.AddString("id", cMonster::MobTypeToVanillaNBT(MobSpawnerEntity.GetEntity())); // New: uses namespaced ID + a_Writer.EndCompound(); + a_Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay()); + break; + } + + default: Super::WriteBlockEntity(a_Writer, a_BlockEntity); + } +} + + + + + void cProtocol_1_11_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) { using namespace Metadata_1_11; diff --git a/src/Protocol/Protocol_1_11.h b/src/Protocol/Protocol_1_11.h index 731426396..6cd4d7607 100644 --- a/src/Protocol/Protocol_1_11.h +++ b/src/Protocol/Protocol_1_11.h @@ -32,11 +32,12 @@ public: protected: - virtual void SendCollectEntity(const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) override; - virtual void SendHideTitle (void) override; - virtual void SendResetTitle (void) override; - virtual void SendSpawnMob (const cMonster & a_Mob) override; - virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override; + virtual void SendCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) override; + virtual void SendHideTitle (void) override; + virtual void SendResetTitle (void) override; + virtual void SendSpawnMob (const cMonster & a_Mob) override; + virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override; + virtual void SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) override; /** Returns 1.11. */ virtual Version GetProtocolVersion() override; @@ -46,9 +47,9 @@ protected: virtual void HandlePacketBlockPlace (cByteBuffer & a_ByteBuffer) override; + virtual void WriteBlockEntity(cFastNBTWriter & a_Writer, const cBlockEntity & a_BlockEntity) override; virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) override; virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) override; - virtual void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity) override; }; diff --git a/src/Protocol/Protocol_1_13.cpp b/src/Protocol/Protocol_1_13.cpp index 77cf86333..b892e8433 100644 --- a/src/Protocol/Protocol_1_13.cpp +++ b/src/Protocol/Protocol_1_13.cpp @@ -29,6 +29,7 @@ Implements the 1.13 protocol classes: #include "../Server.h" #include "../World.h" #include "../JsonUtils.h" +#include "../WorldStorage/FastNBT.h" #include "../Bindings/PluginManager.h" @@ -200,13 +201,13 @@ void cProtocol_1_13::SendTabCompletionResults(const AStringVector & a_Results) void cProtocol_1_13::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktUpdateBlockEntity); - - Pkt.WriteXYZPosition64(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ()); - Byte Action = 0; + Byte Action; switch (a_BlockEntity.GetBlockType()) { + case E_BLOCK_ENCHANTMENT_TABLE: Action = 0; break; // The ones with a action of 0 is just a workaround to send the block entities to a client. + case E_BLOCK_END_PORTAL: Action = 0; break; // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12 + case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text case E_BLOCK_BEACON: Action = 3; break; // Update beacon entity @@ -220,14 +221,17 @@ void cProtocol_1_13::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) // case E_BLOCK_SHULKER_BOX: Action = 10; break; // sets shulker box - not used just here if anyone is confused from reading the protocol wiki case E_BLOCK_BED: Action = 11; break; // Update bed color - case E_BLOCK_ENCHANTMENT_TABLE: Action = 0; break; // The ones with a action of 0 is just a workaround to send the block entities to a client. - case E_BLOCK_END_PORTAL: Action = 0; break; // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12 - - default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break; + default: return; // Block entities change between versions } + + cPacketizer Pkt(*this, pktUpdateBlockEntity); + Pkt.WriteXYZPosition64(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ()); Pkt.WriteBEUInt8(Action); - WriteBlockEntity(Pkt, a_BlockEntity); + cFastNBTWriter Writer; + WriteBlockEntity(Writer, a_BlockEntity); + Writer.Finish(); + Pkt.WriteBuf(Writer.GetResult()); } @@ -1361,6 +1365,7 @@ void cProtocol_1_13_1::SendBossBarAdd(UInt32 a_UniqueID, const cCompositeChat & case BossBarColor::Purple: return 5U; case BossBarColor::White: return 6U; } + UNREACHABLE("Unsupported boss bar property"); }()); Pkt.WriteVarInt32([a_DivisionType] { @@ -1372,6 +1377,7 @@ void cProtocol_1_13_1::SendBossBarAdd(UInt32 a_UniqueID, const cCompositeChat & case BossBarDivisionType::TwelveNotches: return 3U; case BossBarDivisionType::TwentyNotches: return 4U; } + UNREACHABLE("Unsupported boss bar property"); }()); { UInt8 Flags = 0x00; diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index 1a1229f05..654146e14 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -1598,28 +1598,31 @@ void cProtocol_1_8_0::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktUpdateBlockEntity); - Pkt.WriteXYZPosition64(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ()); - - Byte Action = 0; + Byte Action; switch (a_BlockEntity.GetBlockType()) { - case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing - case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text - case E_BLOCK_BEACON: Action = 3; break; // Update beacon entity - case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity - case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot + case E_BLOCK_ENCHANTMENT_TABLE: Action = 0; break; // The ones with a action of 0 is just a workaround to send the block entities to a client. + case E_BLOCK_END_PORTAL: Action = 0; break; // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12 + + case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing + case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text + case E_BLOCK_BEACON: Action = 3; break; // Update beacon entity + case E_BLOCK_HEAD: Action = 4; break; // Update mobhead entity + case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot case E_BLOCK_WALL_BANNER: - case E_BLOCK_STANDING_BANNER: Action = 6; break; // Update Banner - case E_BLOCK_BED: Action = 11; break; // Update bed color - case E_BLOCK_ENCHANTMENT_TABLE: Action = 0; break; // The ones with a action of 0 is just a workaround to send the block entities to a client. - case E_BLOCK_END_PORTAL: Action = 0; break; // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12 + case E_BLOCK_STANDING_BANNER: Action = 6; break; // Update banner - default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break; + default: return; // Block entities change between versions } + + cPacketizer Pkt(*this, pktUpdateBlockEntity); + Pkt.WriteXYZPosition64(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ()); Pkt.WriteBEUInt8(Action); - WriteBlockEntity(Pkt, a_BlockEntity); + cFastNBTWriter Writer; + WriteBlockEntity(Writer, a_BlockEntity); + Writer.Finish(); + Pkt.WriteBuf(Writer.GetResult()); } @@ -3131,6 +3134,113 @@ void cProtocol_1_8_0::SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_Ob +void cProtocol_1_8_0::WriteBlockEntity(cFastNBTWriter & a_Writer, const cBlockEntity & a_BlockEntity) +{ + a_Writer.AddInt("x", a_BlockEntity.GetPosX()); + a_Writer.AddInt("y", a_BlockEntity.GetPosY()); + a_Writer.AddInt("z", a_BlockEntity.GetPosZ()); + + switch (a_BlockEntity.GetBlockType()) + { + case E_BLOCK_WALL_BANNER: + case E_BLOCK_STANDING_BANNER: + { + auto & BannerEntity = static_cast(a_BlockEntity); + a_Writer.AddInt("Base", static_cast(BannerEntity.GetBaseColor())); + break; + } + + case E_BLOCK_BEACON: + { + auto & BeaconEntity = static_cast(a_BlockEntity); + a_Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect()); + a_Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect()); + a_Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); + break; + } + + case E_BLOCK_COMMAND_BLOCK: + { + auto & CommandBlockEntity = static_cast(a_BlockEntity); + a_Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this + a_Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult()); + a_Writer.AddString("Command", CommandBlockEntity.GetCommand()); + // You can set custom names for windows in Vanilla + // For a command block, this would be the 'name' prepended to anything it outputs into global chat + // MCS doesn't have this, so just leave it @ '@'. (geddit?) + a_Writer.AddString("CustomName", "@"); + if (!CommandBlockEntity.GetLastOutput().empty()) + { + a_Writer.AddString("LastOutput", Printf("{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str())); + } + break; + } + + case E_BLOCK_ENCHANTMENT_TABLE: + { + auto & EnchantingTableEntity = static_cast(a_BlockEntity); + if (!EnchantingTableEntity.GetCustomName().empty()) + { + a_Writer.AddString("CustomName", EnchantingTableEntity.GetCustomName()); + } + break; + } + + case E_BLOCK_END_PORTAL: + { + // Nothing! + break; + } + + case E_BLOCK_HEAD: + { + auto & MobHeadEntity = static_cast(a_BlockEntity); + a_Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF); + a_Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF); + + // The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity + a_Writer.BeginCompound("Owner"); + a_Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString()); + a_Writer.AddString("Name", MobHeadEntity.GetOwnerName()); + a_Writer.BeginCompound("Properties"); + a_Writer.BeginList("textures", TAG_Compound); + a_Writer.BeginCompound(""); + a_Writer.AddString("Signature", MobHeadEntity.GetOwnerTextureSignature()); + a_Writer.AddString("Value", MobHeadEntity.GetOwnerTexture()); + a_Writer.EndCompound(); + a_Writer.EndList(); + a_Writer.EndCompound(); + a_Writer.EndCompound(); + break; + } + + case E_BLOCK_FLOWER_POT: + { + auto & FlowerPotEntity = static_cast(a_BlockEntity); + a_Writer.AddInt("Item", static_cast(FlowerPotEntity.GetItem().m_ItemType)); + a_Writer.AddInt("Data", static_cast(FlowerPotEntity.GetItem().m_ItemDamage)); + break; + } + + case E_BLOCK_MOB_SPAWNER: + { + auto & MobSpawnerEntity = static_cast(a_BlockEntity); + a_Writer.AddString("EntityId", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity())); + a_Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay()); + break; + } + + default: + { + break; + } + } +} + + + + + void cProtocol_1_8_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) { short ItemType = a_Item.m_ItemType; @@ -3213,145 +3323,6 @@ void cProtocol_1_8_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) -void cProtocol_1_8_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity) -{ - cFastNBTWriter Writer; - - switch (a_BlockEntity.GetBlockType()) - { - case E_BLOCK_WALL_BANNER: - case E_BLOCK_STANDING_BANNER: - { - auto & BannerEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", BannerEntity.GetPosX()); - Writer.AddInt("y", BannerEntity.GetPosY()); - Writer.AddInt("z", BannerEntity.GetPosZ()); - Writer.AddString("id", "Banner"); - Writer.AddInt("Base", static_cast(BannerEntity.GetBaseColor())); - break; - } - - case E_BLOCK_BEACON: - { - auto & BeaconEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", BeaconEntity.GetPosX()); - Writer.AddInt("y", BeaconEntity.GetPosY()); - Writer.AddInt("z", BeaconEntity.GetPosZ()); - Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect()); - Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect()); - Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); - Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - break; - } - - case E_BLOCK_COMMAND_BLOCK: - { - auto & CommandBlockEntity = static_cast(a_BlockEntity); - Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this - Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult()); - Writer.AddInt("x", CommandBlockEntity.GetPosX()); - Writer.AddInt("y", CommandBlockEntity.GetPosY()); - Writer.AddInt("z", CommandBlockEntity.GetPosZ()); - Writer.AddString("Command", CommandBlockEntity.GetCommand()); - // You can set custom names for windows in Vanilla - // For a command block, this would be the 'name' prepended to anything it outputs into global chat - // MCS doesn't have this, so just leave it @ '@'. (geddit?) - Writer.AddString("CustomName", "@"); - Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - if (!CommandBlockEntity.GetLastOutput().empty()) - { - Writer.AddString("LastOutput", Printf("{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str())); - } - break; - } - - case E_BLOCK_ENCHANTMENT_TABLE: - { - auto & EnchantingTableEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", EnchantingTableEntity.GetPosX()); - Writer.AddInt("y", EnchantingTableEntity.GetPosY()); - Writer.AddInt("z", EnchantingTableEntity.GetPosZ()); - if (!EnchantingTableEntity.GetCustomName().empty()) - { - Writer.AddString("CustomName", EnchantingTableEntity.GetCustomName()); - } - Writer.AddString("id", "EnchantingTable"); - break; - } - - case E_BLOCK_END_PORTAL: - { - Writer.AddInt("x", a_BlockEntity.GetPosX()); - Writer.AddInt("y", a_BlockEntity.GetPosY()); - Writer.AddInt("z", a_BlockEntity.GetPosZ()); - Writer.AddString("id", "EndPortal"); - break; - } - - case E_BLOCK_HEAD: - { - auto & MobHeadEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", MobHeadEntity.GetPosX()); - Writer.AddInt("y", MobHeadEntity.GetPosY()); - Writer.AddInt("z", MobHeadEntity.GetPosZ()); - Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF); - Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF); - Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - - // The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity - Writer.BeginCompound("Owner"); - Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString()); - Writer.AddString("Name", MobHeadEntity.GetOwnerName()); - Writer.BeginCompound("Properties"); - Writer.BeginList("textures", TAG_Compound); - Writer.BeginCompound(""); - Writer.AddString("Signature", MobHeadEntity.GetOwnerTextureSignature()); - Writer.AddString("Value", MobHeadEntity.GetOwnerTexture()); - Writer.EndCompound(); - Writer.EndList(); - Writer.EndCompound(); - Writer.EndCompound(); - break; - } - - case E_BLOCK_FLOWER_POT: - { - auto & FlowerPotEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", FlowerPotEntity.GetPosX()); - Writer.AddInt("y", FlowerPotEntity.GetPosY()); - Writer.AddInt("z", FlowerPotEntity.GetPosZ()); - Writer.AddInt("Item", static_cast(FlowerPotEntity.GetItem().m_ItemType)); - Writer.AddInt("Data", static_cast(FlowerPotEntity.GetItem().m_ItemDamage)); - Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - break; - } - - case E_BLOCK_MOB_SPAWNER: - { - auto & MobSpawnerEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", MobSpawnerEntity.GetPosX()); - Writer.AddInt("y", MobSpawnerEntity.GetPosY()); - Writer.AddInt("z", MobSpawnerEntity.GetPosZ()); - Writer.AddString("EntityId", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity())); - Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay()); - Writer.AddString("id", "MobSpawner"); - break; - } - - default: - { - break; - } - } - - Writer.Finish(); - a_Pkt.WriteBuf(Writer.GetResult()); -} - - - - - void cProtocol_1_8_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) { // Common metadata: diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h index 29bc7420c..9a849e82e 100644 --- a/src/Protocol/Protocol_1_8.h +++ b/src/Protocol/Protocol_1_8.h @@ -223,6 +223,9 @@ protected: /** Sends the entity type and entity-dependent data required for the entity to initially spawn. */ virtual void SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData); + /** Writes the block entity data for the specified block entity into the packet. */ + virtual void WriteBlockEntity(cFastNBTWriter & a_Writer, const cBlockEntity & a_BlockEntity); + /** Writes the item data into a packet. */ virtual void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item); @@ -235,9 +238,6 @@ protected: /** Writes the entity properties for the specified entity, including the Count field. */ virtual void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity); - /** Writes the block entity data for the specified block entity into the packet. */ - virtual void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity); - private: AString m_ServerAddress; diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index 916d3c206..4ebf826bf 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -128,6 +128,7 @@ void cProtocol_1_9_0::SendBossBarAdd(UInt32 a_UniqueID, const cCompositeChat & a case BossBarColor::Purple: return 5U; case BossBarColor::White: return 6U; } + UNREACHABLE("Unsupported boss bar property"); }()); Pkt.WriteVarInt32([a_DivisionType] { @@ -139,6 +140,7 @@ void cProtocol_1_9_0::SendBossBarAdd(UInt32 a_UniqueID, const cCompositeChat & a case BossBarDivisionType::TwelveNotches: return 3U; case BossBarDivisionType::TwentyNotches: return 4U; } + UNREACHABLE("Unsupported boss bar property"); }()); { UInt8 Flags = 0x00; @@ -237,6 +239,7 @@ void cProtocol_1_9_0::SendBossBarUpdateStyle(UInt32 a_UniqueID, BossBarColor a_C case BossBarColor::Purple: return 5U; case BossBarColor::White: return 6U; } + UNREACHABLE("Unsupported boss bar property"); }()); Pkt.WriteVarInt32([a_DivisionType] { @@ -248,6 +251,7 @@ void cProtocol_1_9_0::SendBossBarUpdateStyle(UInt32 a_UniqueID, BossBarColor a_C case BossBarDivisionType::TwelveNotches: return 3U; case BossBarDivisionType::TwentyNotches: return 4U; } + UNREACHABLE("Unsupported boss bar property"); }()); } @@ -1450,6 +1454,30 @@ void cProtocol_1_9_0::SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_Ob +void cProtocol_1_9_0::WriteBlockEntity(cFastNBTWriter & a_Writer, const cBlockEntity & a_BlockEntity) +{ + a_Writer.AddInt("x", a_BlockEntity.GetPosX()); + a_Writer.AddInt("y", a_BlockEntity.GetPosY()); + a_Writer.AddInt("z", a_BlockEntity.GetPosZ()); + + if (a_BlockEntity.GetBlockType() == E_BLOCK_MOB_SPAWNER) + { + auto & MobSpawnerEntity = static_cast(a_BlockEntity); + a_Writer.BeginCompound("SpawnData"); // New: SpawnData compound + a_Writer.AddString("id", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity())); + a_Writer.EndCompound(); + a_Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay()); + } + else + { + Super::WriteBlockEntity(a_Writer, a_BlockEntity); + } +} + + + + + void cProtocol_1_9_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) { short ItemType = a_Item.m_ItemType; @@ -1620,124 +1648,6 @@ void cProtocol_1_9_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) -void cProtocol_1_9_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity) -{ - cFastNBTWriter Writer; - - switch (a_BlockEntity.GetBlockType()) - { - case E_BLOCK_WALL_BANNER: - case E_BLOCK_STANDING_BANNER: - { - auto & BannerEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", BannerEntity.GetPosX()); - Writer.AddInt("y", BannerEntity.GetPosY()); - Writer.AddInt("z", BannerEntity.GetPosZ()); - Writer.AddString("id", "Banner"); - Writer.AddInt("Base", static_cast(BannerEntity.GetBaseColor())); - break; - } - - case E_BLOCK_BEACON: - { - auto & BeaconEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", BeaconEntity.GetPosX()); - Writer.AddInt("y", BeaconEntity.GetPosY()); - Writer.AddInt("z", BeaconEntity.GetPosZ()); - Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect()); - Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect()); - Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); - Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - break; - } - - case E_BLOCK_COMMAND_BLOCK: - { - auto & CommandBlockEntity = static_cast(a_BlockEntity); - Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this - Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult()); - Writer.AddInt("x", CommandBlockEntity.GetPosX()); - Writer.AddInt("y", CommandBlockEntity.GetPosY()); - Writer.AddInt("z", CommandBlockEntity.GetPosZ()); - Writer.AddString("Command", CommandBlockEntity.GetCommand()); - // You can set custom names for windows in Vanilla - // For a command block, this would be the 'name' prepended to anything it outputs into global chat - // MCS doesn't have this, so just leave it @ '@'. (geddit?) - Writer.AddString("CustomName", "@"); - Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - if (!CommandBlockEntity.GetLastOutput().empty()) - { - Writer.AddString("LastOutput", Printf("{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str())); - } - break; - } - - case E_BLOCK_HEAD: - { - auto & MobHeadEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", MobHeadEntity.GetPosX()); - Writer.AddInt("y", MobHeadEntity.GetPosY()); - Writer.AddInt("z", MobHeadEntity.GetPosZ()); - Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF); - Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF); - Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - - // The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity - Writer.BeginCompound("Owner"); - Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString()); - Writer.AddString("Name", MobHeadEntity.GetOwnerName()); - Writer.BeginCompound("Properties"); - Writer.BeginList("textures", TAG_Compound); - Writer.BeginCompound(""); - Writer.AddString("Signature", MobHeadEntity.GetOwnerTextureSignature()); - Writer.AddString("Value", MobHeadEntity.GetOwnerTexture()); - Writer.EndCompound(); - Writer.EndList(); - Writer.EndCompound(); - Writer.EndCompound(); - break; - } - - case E_BLOCK_FLOWER_POT: - { - auto & FlowerPotEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", FlowerPotEntity.GetPosX()); - Writer.AddInt("y", FlowerPotEntity.GetPosY()); - Writer.AddInt("z", FlowerPotEntity.GetPosZ()); - Writer.AddInt("Item", static_cast(FlowerPotEntity.GetItem().m_ItemType)); - Writer.AddInt("Data", static_cast(FlowerPotEntity.GetItem().m_ItemDamage)); - Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though - break; - } - - case E_BLOCK_MOB_SPAWNER: - { - auto & MobSpawnerEntity = static_cast(a_BlockEntity); - Writer.AddInt("x", MobSpawnerEntity.GetPosX()); - Writer.AddInt("y", MobSpawnerEntity.GetPosY()); - Writer.AddInt("z", MobSpawnerEntity.GetPosZ()); - Writer.BeginCompound("SpawnData"); - Writer.AddString("id", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity())); - Writer.EndCompound(); - Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay()); - Writer.AddString("id", "MobSpawner"); - break; - } - - default: - { - break; - } - } - - Writer.Finish(); - a_Pkt.WriteBuf(Writer.GetResult()); -} - - - - - void cProtocol_1_9_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) { // Common metadata: diff --git a/src/Protocol/Protocol_1_9.h b/src/Protocol/Protocol_1_9.h index cdaeaeed9..be2af147c 100644 --- a/src/Protocol/Protocol_1_9.h +++ b/src/Protocol/Protocol_1_9.h @@ -113,6 +113,9 @@ protected: /** Sends the entity type and entity-dependent data required for the entity to initially spawn. */ virtual void SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData) override; + /** Writes the block entity data for the specified block entity into the packet. */ + virtual void WriteBlockEntity(cFastNBTWriter & a_Writer, const cBlockEntity & a_BlockEntity) override; + /** Writes the item data into a packet. */ virtual void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) override; @@ -125,9 +128,6 @@ protected: /** Writes the entity properties for the specified entity, including the Count field. */ virtual void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity) override; - /** Writes the block entity data for the specified block entity into the packet. */ - virtual void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity) override; - /** Types used within metadata */ enum eMetadataType { -- cgit v1.2.3