From f8de67aace4e65ff4c34a1f46f6d8b258b6839aa Mon Sep 17 00:00:00 2001 From: 12xx12 <12xx12100@gmail.com> Date: Thu, 17 Sep 2020 16:16:20 +0200 Subject: [PATCH] Added end portal and enchanting table block entities --- src/BlockEntities/BlockEntity.cpp | 44 +++--- src/BlockEntities/CMakeLists.txt | 4 + src/BlockEntities/EnchantingTableEntity.cpp | 47 ++++++ src/BlockEntities/EnchantingTableEntity.h | 32 ++++ src/BlockEntities/EndPortalEntity.cpp | 43 ++++++ src/BlockEntities/EndPortalEntity.h | 27 ++++ src/Blocks/BlockEnchantingTable.h | 84 ++++++++++ src/Blocks/BlockEnchantmentTable.h | 64 -------- src/Blocks/BlockEndPortalFrame.h | 160 -------------------- src/Blocks/BlockHandler.cpp | 6 +- src/Blocks/CMakeLists.txt | 2 +- src/Items/CMakeLists.txt | 2 + src/Items/ItemEnchantingTable.h | 63 ++++++++ src/Items/ItemEyeOfEnder.h | 144 ++++++++++++++++++ src/Items/ItemHandler.cpp | 2 + src/Protocol/Protocol_1_13.cpp | 26 ++-- src/Protocol/Protocol_1_8.cpp | 40 ++++- src/UI/EnchantingWindow.cpp | 4 +- src/UI/EnchantingWindow.h | 2 +- src/WorldStorage/NBTChunkSerializer.cpp | 66 +++++--- src/WorldStorage/WSSAnvil.cpp | 82 +++++++--- src/WorldStorage/WSSAnvil.h | 34 +++-- 22 files changed, 657 insertions(+), 321 deletions(-) create mode 100644 src/BlockEntities/EnchantingTableEntity.cpp create mode 100644 src/BlockEntities/EnchantingTableEntity.h create mode 100644 src/BlockEntities/EndPortalEntity.cpp create mode 100644 src/BlockEntities/EndPortalEntity.h create mode 100644 src/Blocks/BlockEnchantingTable.h delete mode 100644 src/Blocks/BlockEnchantmentTable.h create mode 100644 src/Items/ItemEnchantingTable.h diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp index b32785e3c..7e7f5eaab 100644 --- a/src/BlockEntities/BlockEntity.cpp +++ b/src/BlockEntities/BlockEntity.cpp @@ -7,12 +7,14 @@ #include "BeaconEntity.h" #include "BedEntity.h" #include "BlockEntity.h" +#include "EnchantingTableEntity.h" #include "BrewingstandEntity.h" #include "ChestEntity.h" #include "CommandBlockEntity.h" #include "DispenserEntity.h" #include "DropperEntity.h" #include "EnderChestEntity.h" +#include "EndPortalEntity.h" #include "FlowerPotEntity.h" #include "FurnaceEntity.h" #include "HopperEntity.h" @@ -47,7 +49,9 @@ bool cBlockEntity::IsBlockEntityBlockType(BLOCKTYPE a_BlockType) case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: + case E_BLOCK_ENCHANTMENT_TABLE: case E_BLOCK_ENDER_CHEST: + case E_BLOCK_END_PORTAL: case E_BLOCK_FLOWER_POT: case E_BLOCK_FURNACE: case E_BLOCK_HEAD: @@ -77,25 +81,27 @@ OwnedBlockEntity cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETY { switch (a_BlockType) { - case E_BLOCK_BEACON: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_BED: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_BREWING_STAND: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_CHEST: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_COMMAND_BLOCK: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_DISPENSER: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_DROPPER: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_ENDER_CHEST: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_FLOWER_POT: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_FURNACE: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_HEAD: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_HOPPER: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_JUKEBOX: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_LIT_FURNACE: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_MOB_SPAWNER: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_NOTE_BLOCK: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_SIGN_POST: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_TRAPPED_CHEST: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); - case E_BLOCK_WALLSIGN: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_BEACON: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_BED: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_BREWING_STAND: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_CHEST: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_COMMAND_BLOCK: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_DISPENSER: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_DROPPER: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_ENCHANTMENT_TABLE: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_ENDER_CHEST: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_END_PORTAL: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_FLOWER_POT: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_FURNACE: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_HEAD: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_HOPPER: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_JUKEBOX: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_LIT_FURNACE: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_MOB_SPAWNER: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_NOTE_BLOCK: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_SIGN_POST: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_TRAPPED_CHEST: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); + case E_BLOCK_WALLSIGN: return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, a_World); default: { LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)", diff --git a/src/BlockEntities/CMakeLists.txt b/src/BlockEntities/CMakeLists.txt index b0e456da3..d8ec1e005 100644 --- a/src/BlockEntities/CMakeLists.txt +++ b/src/BlockEntities/CMakeLists.txt @@ -11,6 +11,8 @@ target_sources( DispenserEntity.cpp DropSpenserEntity.cpp DropperEntity.cpp + EnchantingTableEntity.cpp + EndPortalEntity.cpp EnderChestEntity.cpp FlowerPotEntity.cpp FurnaceEntity.cpp @@ -31,6 +33,8 @@ target_sources( DispenserEntity.h DropSpenserEntity.h DropperEntity.h + EnchantingTableEntity.h + EndPortalEntity.h EnderChestEntity.h FlowerPotEntity.h FurnaceEntity.h diff --git a/src/BlockEntities/EnchantingTableEntity.cpp b/src/BlockEntities/EnchantingTableEntity.cpp new file mode 100644 index 000000000..55124e7d3 --- /dev/null +++ b/src/BlockEntities/EnchantingTableEntity.cpp @@ -0,0 +1,47 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "EnchantingTableEntity.h" +#include "../ClientHandle.h" + + + + + +cEnchantingTableEntity::cEnchantingTableEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World, AString a_CustomName) : + Super(a_BlockType, a_BlockMeta, a_Pos, a_World), + m_CustomName(std::move(a_CustomName)) +{ + ASSERT(a_BlockType == E_BLOCK_ENCHANTMENT_TABLE); +} + + + + + +void cEnchantingTableEntity::CopyFrom(const cBlockEntity & a_Src) +{ + Super::CopyFrom(a_Src); + + auto & Src = static_cast(a_Src); + m_CustomName = Src.m_CustomName; +} + + + + + +bool cEnchantingTableEntity::UsedBy(cPlayer * a_Player) +{ + UNUSED(a_Player); + return true; +} + + + + + +void cEnchantingTableEntity::SendTo(cClientHandle & a_Client) +{ + a_Client.SendUpdateBlockEntity(*this); +} diff --git a/src/BlockEntities/EnchantingTableEntity.h b/src/BlockEntities/EnchantingTableEntity.h new file mode 100644 index 000000000..f10fa3c87 --- /dev/null +++ b/src/BlockEntities/EnchantingTableEntity.h @@ -0,0 +1,32 @@ + +#pragma once + +#include "BlockEntity.h" + + + + + +class cEnchantingTableEntity : + public cBlockEntity +{ + using Super = cBlockEntity; + +public: + + BLOCKENTITY_PROTODEF(cEnchantingTableEntity) + + cEnchantingTableEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World, AString a_CustomName = ""); + + const AString & GetCustomName() const { return m_CustomName; } + void SetCustomName(const AString & a_CustomName) { m_CustomName = a_CustomName; } + +private: + + // cBlockEntity overrides: + virtual void CopyFrom(const cBlockEntity & a_Src) override; + virtual bool UsedBy(cPlayer * a_Player) override; + virtual void SendTo(cClientHandle & a_Client) override; + + AString m_CustomName; +}; diff --git a/src/BlockEntities/EndPortalEntity.cpp b/src/BlockEntities/EndPortalEntity.cpp new file mode 100644 index 000000000..f40e9b20e --- /dev/null +++ b/src/BlockEntities/EndPortalEntity.cpp @@ -0,0 +1,43 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "EndPortalEntity.h" +#include "../ClientHandle.h" + + + + + +cEndPortalEntity::cEndPortalEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World) : + Super(a_BlockType, a_BlockMeta, a_Pos, a_World) +{ + ASSERT(a_BlockType == E_BLOCK_END_PORTAL); +} + + + + + +void cEndPortalEntity::CopyFrom(const cBlockEntity & a_Src) +{ + Super::CopyFrom(a_Src); +} + + + + + +bool cEndPortalEntity::UsedBy(cPlayer * a_Player) +{ + UNUSED(a_Player); + return true; +} + + + + + +void cEndPortalEntity::SendTo(cClientHandle & a_Client) +{ + a_Client.SendUpdateBlockEntity(*this); +} diff --git a/src/BlockEntities/EndPortalEntity.h b/src/BlockEntities/EndPortalEntity.h new file mode 100644 index 000000000..fe5ed4322 --- /dev/null +++ b/src/BlockEntities/EndPortalEntity.h @@ -0,0 +1,27 @@ + +#pragma once + +#include "BlockEntity.h" + + + + + +class cEndPortalEntity : + public cBlockEntity +{ + using Super = cBlockEntity; + +public: + + BLOCKENTITY_PROTODEF(cEndPortalEntity) + + cEndPortalEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World); + +private: + + // cBlockEntity overrides: + virtual void CopyFrom(const cBlockEntity & a_Src) override; + virtual bool UsedBy(cPlayer * a_Player) override; + virtual void SendTo(cClientHandle & a_Client) override; +}; diff --git a/src/Blocks/BlockEnchantingTable.h b/src/Blocks/BlockEnchantingTable.h new file mode 100644 index 000000000..ddd25182b --- /dev/null +++ b/src/Blocks/BlockEnchantingTable.h @@ -0,0 +1,84 @@ + +#pragma once + +#include "BlockHandler.h" +#include "../Item.h" +#include "../UI/EnchantingWindow.h" +#include "../BlockEntities/EnchantingTableEntity.h" +#include "../Entities/Player.h" + + + + + +class cBlockEnchantingTableHandler : + public cBlockHandler +{ + using Super = cBlockHandler; + +public: + + using Super::Super; + +private: + + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override + { + AString WindowName = "Enchant"; + a_WorldInterface.DoWithBlockEntityAt(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, [&WindowName](cBlockEntity & a_Entity) + { + if (a_Entity.GetBlockType() != E_BLOCK_ENCHANTMENT_TABLE) + { + return false; + } + + const auto & EnchantingTable = static_cast(a_Entity); + const auto & CustomName = EnchantingTable.GetCustomName(); + if (!CustomName.empty()) + { + WindowName = CustomName; + } + + return true; + }); + + cWindow * Window = new cEnchantingWindow(a_BlockPos, std::move(WindowName)); + a_Player.OpenWindow(*Window); + + return true; + } + + + virtual bool IsUseable(void) override + { + return true; + } + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override + { + if ((a_BlockEntity == nullptr) || (a_BlockEntity->GetBlockType() != E_BLOCK_ENCHANTMENT_TABLE)) + { + return {}; + } + + auto & EnchantingTable = static_cast(*a_BlockEntity); + cItem Item = cItem(E_BLOCK_ENCHANTMENT_TABLE); + Item.m_CustomName = EnchantingTable.GetCustomName(); + return Item; + } + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override + { + UNUSED(a_Meta); + return 29; + } +}; diff --git a/src/Blocks/BlockEnchantmentTable.h b/src/Blocks/BlockEnchantmentTable.h deleted file mode 100644 index 48560451b..000000000 --- a/src/Blocks/BlockEnchantmentTable.h +++ /dev/null @@ -1,64 +0,0 @@ - -#pragma once - -#include "BlockHandler.h" -#include "../UI/EnchantingWindow.h" -#include "../Entities/Player.h" - - - - - -class cBlockEnchantmentTableHandler: - public cBlockHandler -{ - using Super = cBlockHandler; - -public: - - cBlockEnchantmentTableHandler(BLOCKTYPE a_BlockType): - Super(a_BlockType) - { - } - - - - - - virtual bool OnUse( - cChunkInterface & a_ChunkInterface, - cWorldInterface & a_WorldInterface, - cPlayer & a_Player, - const Vector3i a_BlockPos, - eBlockFace a_BlockFace, - const Vector3i a_CursorPos - ) override - { - cWindow * Window = new cEnchantingWindow(a_BlockPos); - a_Player.OpenWindow(*Window); - return true; - } - - - - - - virtual bool IsUseable(void) override - { - return true; - } - - - - - - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override - { - UNUSED(a_Meta); - return 29; - } -}; - - - - diff --git a/src/Blocks/BlockEndPortalFrame.h b/src/Blocks/BlockEndPortalFrame.h index be67bb4f9..567de8bcc 100644 --- a/src/Blocks/BlockEndPortalFrame.h +++ b/src/Blocks/BlockEndPortalFrame.h @@ -82,166 +82,6 @@ public: - virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override - { - // E_META_END_PORTAL_FRAME_EYE is the bit which signifies the eye of ender is in it. - // LOG("PortalPlaced, meta %d", a_BlockMeta); - if ((a_BlockMeta & E_META_END_PORTAL_FRAME_EYE) == E_META_END_PORTAL_FRAME_EYE) - { - // LOG("Location is %d %d %d", a_BlockX, a_BlockY, a_BlockZ); - // Direction is the first two bits, masked by 0x3 - FindAndSetPortal(a_BlockPos, a_BlockMeta & 3, a_ChunkInterface, a_WorldInterface); - } - } - - - - - - /** Returns false if portal cannot be made, true if portal was made. */ - bool FindAndSetPortal(Vector3i a_FirstFrame, NIBBLETYPE a_Direction, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface) - { - /* - PORTAL FINDING ALGORITH - ======================= - - Get clicked base block - - Check diagonally (clockwise) for another portal block - - if exists, and has eye, Continue. Abort if any are facing the wrong direction. - - if doesn't exist, check horizontally (the block to the left of this block). Abort if there is no horizontal block. - - After a corner has been met, traverse the portal clockwise, ensuring valid portal frames connect the rectangle. - - Track the NorthWest Corner, and the dimensions. - - If dimensions are valid, create the portal. - */ - - static_assert((E_META_END_PORTAL_FRAME_ZM - E_META_END_PORTAL_FRAME_XM) == 1, "Should be going clockwise"); - - const int MIN_PORTAL_WIDTH = 3; - const int MAX_PORTAL_WIDTH = 4; - - // Directions to use for the clockwise traversal. - static const Vector3i Left[] = - { - { 1, 0, 0}, // 0, South, left block is East / XP - { 0, 0, 1}, // 1, West, left block is South / ZP - {-1, 0, 0}, // 2, North, left block is West / XM - { 0, 0, -1}, // 3, East, left block is North / ZM - }; - static const Vector3i LeftForward[] = - { - { 1, 0, 1}, // 0, South, left block is SouthEast / XP ZP - {-1, 0, 1}, // 1, West, left block is SouthWest / XM ZP - {-1, 0, -1}, // 2, North, left block is NorthWest / XM ZM - { 1, 0, -1}, // 3, East, left block is NorthEast / XP ZM - }; - - - int EdgesComplete = -1; // We start search _before_ finding the first edge - Vector3i NorthWestCorner; - int EdgeWidth[4] = { 1, 1, 1, 1 }; - NIBBLETYPE CurrentDirection = a_Direction; - Vector3i CurrentPos = a_FirstFrame; - - // Scan clockwise until we have seen all 4 edges - while (EdgesComplete < 4) - { - // Check if we are at a corner - Vector3i NextPos = CurrentPos + LeftForward[CurrentDirection]; - if (IsPortalFrame(a_ChunkInterface.GetBlock(NextPos))) - { - // We have found the corner, move clockwise to next edge - if (CurrentDirection == E_META_END_PORTAL_FRAME_XP) - { - // We are on the NW (XM, ZM) Corner - // Relative to the previous frame, the portal should appear to the right of this portal frame. - NorthWestCorner = NextPos - Left[CurrentDirection]; - } - - if (EdgesComplete == -1) - { - // Reset current width, we will revisit it last - EdgeWidth[CurrentDirection] = 1; - } - - // Rotate 90 degrees clockwise - CurrentDirection = (CurrentDirection + 1) % 4; - EdgesComplete++; - } - else - { - // We are not at a corner, keep walking the edge - NextPos = CurrentPos + Left[CurrentDirection]; - - EdgeWidth[CurrentDirection]++; - if (EdgeWidth[CurrentDirection] > MAX_PORTAL_WIDTH) - { - // Don't build a portal that is too long. - return false; - } - } - - if (!IsValidFrameAtPos(a_ChunkInterface, NextPos, CurrentDirection)) - { - // Neither the edge nor the corner are valid portal blocks. - return false; - } - - CurrentPos = NextPos; - } - - if ((EdgeWidth[0] != EdgeWidth[2]) || (EdgeWidth[1] != EdgeWidth[3])) - { - // Mismatched Portal Dimensions. - return false; - } - if ((EdgeWidth[0] < MIN_PORTAL_WIDTH) || (EdgeWidth[1] < MIN_PORTAL_WIDTH)) - { - // Portal too small. - return false; - } - - // LOG("NW corner (low corner) %d %d %d", Corner.x, Corner.y, Corner.z); - // LOG("%d by %d", Width[0], Width[1]); - for (int i = 0; i < EdgeWidth[0]; i++) - { - for (int j = 0; j < EdgeWidth[1]; j++) - { - a_ChunkInterface.SetBlock(NorthWestCorner.x + i, NorthWestCorner.y, NorthWestCorner.z + j, E_BLOCK_END_PORTAL, 0); - // TODO: Create block entity so portal doesn't become invisible on relog. - } - } - return true; - } - - - - - - /** Return true if this block is a portal frame, has an eye, and is facing the correct direction. */ - bool IsValidFrameAtPos(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, NIBBLETYPE a_ShouldFace) - { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - - return ( - a_ChunkInterface.GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta) && - (BlockType == E_BLOCK_END_PORTAL_FRAME) && - (BlockMeta == (a_ShouldFace | E_META_END_PORTAL_FRAME_EYE)) - ); - } - - - - - /** Return true if this block is a portal frame. */ - bool IsPortalFrame(BLOCKTYPE BlockType) - { - return (BlockType == E_BLOCK_END_PORTAL_FRAME); - } - - - - - virtual bool IsClickedThrough(void) override { // TODO: Colision diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 7938ec065..20ba6edb5 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -27,7 +27,7 @@ #include "BlockDirt.h" #include "BlockDoor.h" #include "BlockDropSpenser.h" -#include "BlockEnchantmentTable.h" +#include "BlockEnchantingTable.h" #include "BlockEnderchest.h" #include "BlockEndPortalFrame.h" #include "BlockEntity.h" @@ -263,7 +263,7 @@ namespace cBlockDropSpenserHandler BlockDropperHandler (E_BLOCK_DROPPER); cBlockHandler BlockEmeraldBlockHandler (E_BLOCK_EMERALD_BLOCK); cBlockOreHandler BlockEmeraldOreHandler (E_BLOCK_EMERALD_ORE); - cBlockEnchantmentTableHandler BlockEnchantmentTableHandler (E_BLOCK_ENCHANTMENT_TABLE); + cBlockEnchantingTableHandler BlockEnchantingTableHandler (E_BLOCK_ENCHANTMENT_TABLE); cBlockHandler BlockEndBricksHandler (E_BLOCK_END_BRICKS); cBlockHandler BlockEndGatewayHandler (E_BLOCK_END_GATEWAY); cBlockEndPortalFrameHandler BlockEndPortalFrameHandler (E_BLOCK_END_PORTAL_FRAME); @@ -735,7 +735,7 @@ cBlockHandler & cBlockHandler::GetBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_DROPPER: return BlockDropperHandler; case E_BLOCK_EMERALD_BLOCK: return BlockEmeraldBlockHandler; case E_BLOCK_EMERALD_ORE: return BlockEmeraldOreHandler; - case E_BLOCK_ENCHANTMENT_TABLE: return BlockEnchantmentTableHandler; + case E_BLOCK_ENCHANTMENT_TABLE: return BlockEnchantingTableHandler; case E_BLOCK_ENDER_CHEST: return BlockEnderChestHandler; case E_BLOCK_END_BRICKS: return BlockEndBricksHandler; case E_BLOCK_END_GATEWAY: return BlockEndGatewayHandler; diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index 87464bd04..a3d1e5cb2 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -29,7 +29,7 @@ target_sources( BlockDirt.h BlockDoor.h BlockDropSpenser.h - BlockEnchantmentTable.h + BlockEnchantingTable.h BlockEnderchest.h BlockEndPortalFrame.h BlockEntity.h diff --git a/src/Items/CMakeLists.txt b/src/Items/CMakeLists.txt index 2ade4b9df..ddec54e85 100644 --- a/src/Items/CMakeLists.txt +++ b/src/Items/CMakeLists.txt @@ -18,6 +18,8 @@ target_sources( ItemDoor.h ItemDye.h ItemEmptyMap.h + ItemEnchantingTable.h + ItemEyeOfEnder.h ItemFishingRod.h ItemFood.h ItemFoodSeeds.h diff --git a/src/Items/ItemEnchantingTable.h b/src/Items/ItemEnchantingTable.h new file mode 100644 index 000000000..c8eb42cac --- /dev/null +++ b/src/Items/ItemEnchantingTable.h @@ -0,0 +1,63 @@ + +#pragma once + +#include "ItemHandler.h" +#include "../BlockEntities/EnchantingTableEntity.h" +#include "../World.h" + + + + + +class cItemEnchantingTableHandler: + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool IsPlaceable(void) override + { + return true; + } + + + virtual bool OnPlayerPlace( + cWorld & a_World, + cPlayer & a_Player, + const cItem & a_EquippedItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos + ) override + { + if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos)) + { + return false; + } + + if (a_EquippedItem.IsCustomNameEmpty()) + { + return true; + } + + const auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); + a_World.DoWithBlockEntityAt(PlacePos.x, PlacePos.y, PlacePos.z, [&a_EquippedItem](cBlockEntity & a_Entity) + { + if (a_Entity.GetBlockType() != E_BLOCK_ENCHANTMENT_TABLE) + { + return true; + } + + auto & EnchantingTable = static_cast(a_Entity); + EnchantingTable.SetCustomName(a_EquippedItem.m_CustomName); + return true; + }); + + return true; + } +} ; diff --git a/src/Items/ItemEyeOfEnder.h b/src/Items/ItemEyeOfEnder.h index 3849feb00..6a636cb12 100644 --- a/src/Items/ItemEyeOfEnder.h +++ b/src/Items/ItemEyeOfEnder.h @@ -46,6 +46,11 @@ public: { a_Player->GetInventory().RemoveOneEquippedItem(); } + + cChunkInterface ChunkInterface(a_World->GetChunkMap()); + + // Try to spawn portal: + FindAndSetPortal(a_ClickedBlockPos, FacingMeta & 3, ChunkInterface, *a_World); return true; } } @@ -58,6 +63,145 @@ public: return false; } + + + + /** Returns false if portal cannot be made, true if portal was made. */ + static bool FindAndSetPortal(Vector3i a_FirstFrame, NIBBLETYPE a_Direction, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface) + { + /* + PORTAL FINDING ALGORITH + ======================= + - Get clicked base block + - Check diagonally (clockwise) for another portal block + - if exists, and has eye, Continue. Abort if any are facing the wrong direction. + - if doesn't exist, check horizontally (the block to the left of this block). Abort if there is no horizontal block. + - After a corner has been met, traverse the portal clockwise, ensuring valid portal frames connect the rectangle. + - Track the NorthWest Corner, and the dimensions. + - If dimensions are valid, create the portal. + */ + + static_assert((E_META_END_PORTAL_FRAME_ZM - E_META_END_PORTAL_FRAME_XM) == 1, "Should be going clockwise"); + + const int MIN_PORTAL_WIDTH = 3; + const int MAX_PORTAL_WIDTH = 4; + + // Directions to use for the clockwise traversal. + static const Vector3i Left[] = + { + { 1, 0, 0}, // 0, South, left block is East / XP + { 0, 0, 1}, // 1, West, left block is South / ZP + {-1, 0, 0}, // 2, North, left block is West / XM + { 0, 0, -1}, // 3, East, left block is North / ZM + }; + static const Vector3i LeftForward[] = + { + { 1, 0, 1}, // 0, South, left block is SouthEast / XP ZP + {-1, 0, 1}, // 1, West, left block is SouthWest / XM ZP + {-1, 0, -1}, // 2, North, left block is NorthWest / XM ZM + { 1, 0, -1}, // 3, East, left block is NorthEast / XP ZM + }; + + + int EdgesComplete = -1; // We start search _before_ finding the first edge + Vector3i NorthWestCorner; + int EdgeWidth[4] = { 1, 1, 1, 1 }; + NIBBLETYPE CurrentDirection = a_Direction; + Vector3i CurrentPos = a_FirstFrame; + + // Scan clockwise until we have seen all 4 edges + while (EdgesComplete < 4) + { + // Check if we are at a corner + Vector3i NextPos = CurrentPos + LeftForward[CurrentDirection]; + if (IsPortalFrame(a_ChunkInterface.GetBlock(NextPos))) + { + // We have found the corner, move clockwise to next edge + if (CurrentDirection == E_META_END_PORTAL_FRAME_XP) + { + // We are on the NW (XM, ZM) Corner + // Relative to the previous frame, the portal should appear to the right of this portal frame. + NorthWestCorner = NextPos - Left[CurrentDirection]; + } + + if (EdgesComplete == -1) + { + // Reset current width, we will revisit it last + EdgeWidth[CurrentDirection] = 1; + } + + // Rotate 90 degrees clockwise + CurrentDirection = (CurrentDirection + 1) % 4; + EdgesComplete++; + } + else + { + // We are not at a corner, keep walking the edge + NextPos = CurrentPos + Left[CurrentDirection]; + + EdgeWidth[CurrentDirection]++; + if (EdgeWidth[CurrentDirection] > MAX_PORTAL_WIDTH) + { + // Don't build a portal that is too long. + return false; + } + } + + if (!IsValidFrameAtPos(a_ChunkInterface, NextPos, CurrentDirection)) + { + // Neither the edge nor the corner are valid portal blocks. + return false; + } + + CurrentPos = NextPos; + } + + if ((EdgeWidth[0] != EdgeWidth[2]) || (EdgeWidth[1] != EdgeWidth[3])) + { + // Mismatched Portal Dimensions. + return false; + } + if ((EdgeWidth[0] < MIN_PORTAL_WIDTH) || (EdgeWidth[1] < MIN_PORTAL_WIDTH)) + { + // Portal too small. + return false; + } + + for (int i = 0; i < EdgeWidth[0]; i++) + { + for (int j = 0; j < EdgeWidth[1]; j++) + { + a_ChunkInterface.SetBlock(NorthWestCorner.x + i, NorthWestCorner.y, NorthWestCorner.z + j, E_BLOCK_END_PORTAL, 0); + } + } + return true; + } + + + + + + /** Return true if this block is a portal frame, has an eye, and is facing the correct direction. */ + static bool IsValidFrameAtPos(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, NIBBLETYPE a_ShouldFace) + { + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + + return ( + a_ChunkInterface.GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta) && + (BlockType == E_BLOCK_END_PORTAL_FRAME) && + (BlockMeta == (a_ShouldFace | E_META_END_PORTAL_FRAME_EYE)) + ); + } + + + + + /** Return true if this block is a portal frame. */ + static bool IsPortalFrame(BLOCKTYPE BlockType) + { + return (BlockType == E_BLOCK_END_PORTAL_FRAME); + } } ; diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 79a0dbcb9..d9f9c3168 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -23,6 +23,7 @@ #include "ItemDoor.h" #include "ItemDye.h" #include "ItemEmptyMap.h" +#include "ItemEnchantingTable.h" #include "ItemEyeOfEnder.h" #include "ItemFishingRod.h" #include "ItemFood.h" @@ -112,6 +113,7 @@ cItemHandler * cItemHandler::CreateItemHandler(int a_ItemType) // Single item per handler, alphabetically sorted: case E_BLOCK_BIG_FLOWER: return new cItemBigFlowerHandler; case E_BLOCK_CHEST: return new cItemChestHandler(a_ItemType); + case E_BLOCK_ENCHANTMENT_TABLE: return new cItemEnchantingTableHandler(a_ItemType); case E_BLOCK_LEAVES: return new cItemLeavesHandler(a_ItemType); case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType); case E_BLOCK_HEAD: return new cItemMobHeadHandler(a_ItemType); diff --git a/src/Protocol/Protocol_1_13.cpp b/src/Protocol/Protocol_1_13.cpp index 9a7202f02..0259565f5 100644 --- a/src/Protocol/Protocol_1_13.cpp +++ b/src/Protocol/Protocol_1_13.cpp @@ -205,18 +205,22 @@ void cProtocol_1_13::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) Byte Action = 0; 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_CONDUIT: Action = 5; break; // Update Conduit entity + 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_CONDUIT: Action = 5; break; // Update Conduit entity case E_BLOCK_STANDING_BANNER: - case E_BLOCK_WALL_BANNER: Action = 6; break; // Update banner entity - // case Structure Block: Action = 7; break; // Update Structure tile entity - case E_BLOCK_END_GATEWAY: Action = 8; break; // Update destination for a end gateway entity - case E_BLOCK_SIGN_POST: Action = 9; break; // Update sign entity - // 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_WALL_BANNER: Action = 6; break; // Update banner entity + // case Structure Block: Action = 7; break; // Update Structure tile entity + case E_BLOCK_END_GATEWAY: Action = 8; break; // Update destination for a end gateway entity + case E_BLOCK_SIGN_POST: Action = 9; break; // Update sign entity + // 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; } Pkt.WriteBEUInt8(Action); diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index 1c98d83f3..c6b21fc3d 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -43,6 +43,7 @@ Implements the 1.8 protocol classes: #include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/CommandBlockEntity.h" +#include "../BlockEntities/EnchantingTableEntity.h" #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/MobSpawnerEntity.h" #include "../BlockEntities/FlowerPotEntity.h" @@ -1529,12 +1530,16 @@ void cProtocol_1_8_0::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) Byte Action = 0; 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_BED: Action = 11; break; // Update bed color + 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_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; } Pkt.WriteBEUInt8(Action); @@ -3395,6 +3400,29 @@ void cProtocol_1_8_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & 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); diff --git a/src/UI/EnchantingWindow.cpp b/src/UI/EnchantingWindow.cpp index a3abf3a02..4ce4bebb3 100644 --- a/src/UI/EnchantingWindow.cpp +++ b/src/UI/EnchantingWindow.cpp @@ -11,8 +11,8 @@ -cEnchantingWindow::cEnchantingWindow(Vector3i a_BlockPos) : - cWindow(wtEnchantment, "Enchant"), +cEnchantingWindow::cEnchantingWindow(Vector3i a_BlockPos, const AString & a_Title) : + cWindow(wtEnchantment, a_Title), m_SlotArea(), m_BlockPos(a_BlockPos) { diff --git a/src/UI/EnchantingWindow.h b/src/UI/EnchantingWindow.h index 5807d097e..4de5ed00c 100644 --- a/src/UI/EnchantingWindow.h +++ b/src/UI/EnchantingWindow.h @@ -22,7 +22,7 @@ class cEnchantingWindow: public: - cEnchantingWindow(Vector3i a_BlockPos); + cEnchantingWindow(Vector3i a_BlockPos, const AString & a_Title); virtual void SetProperty(short a_Property, short a_Value, cPlayer & a_Player) override; diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 419115ea0..c78b04c66 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -18,7 +18,9 @@ #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" +#include "../BlockEntities/EnchantingTableEntity.h" #include "../BlockEntities/EnderChestEntity.h" +#include "../BlockEntities/EndPortalEntity.h" #include "../BlockEntities/FurnaceEntity.h" #include "../BlockEntities/HopperEntity.h" #include "../BlockEntities/JukeboxEntity.h" @@ -208,25 +210,27 @@ public: // Add tile-entity into NBT: switch (a_Entity->GetBlockType()) { - case E_BLOCK_BEACON: AddBeaconEntity (static_cast (a_Entity)); break; - case E_BLOCK_BED: AddBedEntity (static_cast (a_Entity)); break; - case E_BLOCK_BREWING_STAND: AddBrewingstandEntity(static_cast(a_Entity)); break; - case E_BLOCK_CHEST: AddChestEntity (static_cast (a_Entity), a_Entity->GetBlockType()); break; - case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity(static_cast(a_Entity)); break; - case E_BLOCK_DISPENSER: AddDispenserEntity (static_cast (a_Entity)); break; - case E_BLOCK_DROPPER: AddDropperEntity (static_cast (a_Entity)); break; - case E_BLOCK_ENDER_CHEST: AddEnderchestEntity (static_cast (a_Entity)); break; - case E_BLOCK_FLOWER_POT: AddFlowerPotEntity (static_cast (a_Entity)); break; - case E_BLOCK_FURNACE: AddFurnaceEntity (static_cast (a_Entity)); break; - case E_BLOCK_HEAD: AddMobHeadEntity (static_cast (a_Entity)); break; - case E_BLOCK_HOPPER: AddHopperEntity (static_cast (a_Entity)); break; - case E_BLOCK_JUKEBOX: AddJukeboxEntity (static_cast (a_Entity)); break; - case E_BLOCK_LIT_FURNACE: AddFurnaceEntity (static_cast (a_Entity)); break; - case E_BLOCK_MOB_SPAWNER: AddMobSpawnerEntity (static_cast (a_Entity)); break; - case E_BLOCK_NOTE_BLOCK: AddNoteEntity (static_cast (a_Entity)); break; - case E_BLOCK_SIGN_POST: AddSignEntity (static_cast (a_Entity)); break; - case E_BLOCK_TRAPPED_CHEST: AddChestEntity (static_cast (a_Entity), a_Entity->GetBlockType()); break; - case E_BLOCK_WALLSIGN: AddSignEntity (static_cast (a_Entity)); break; + case E_BLOCK_BEACON: AddBeaconEntity (static_cast (a_Entity)); break; + case E_BLOCK_BED: AddBedEntity (static_cast (a_Entity)); break; + case E_BLOCK_BREWING_STAND: AddBrewingstandEntity (static_cast (a_Entity)); break; + case E_BLOCK_CHEST: AddChestEntity (static_cast (a_Entity), a_Entity->GetBlockType()); break; + case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity (static_cast (a_Entity)); break; + case E_BLOCK_DISPENSER: AddDispenserEntity (static_cast (a_Entity)); break; + case E_BLOCK_DROPPER: AddDropperEntity (static_cast (a_Entity)); break; + case E_BLOCK_ENCHANTMENT_TABLE: AddEnchantingTableEntity(static_cast(a_Entity)); break; + case E_BLOCK_ENDER_CHEST: AddEnderchestEntity (static_cast (a_Entity)); break; + case E_BLOCK_END_PORTAL: AddEndPortalEntity (static_cast (a_Entity)); break; + case E_BLOCK_FLOWER_POT: AddFlowerPotEntity (static_cast (a_Entity)); break; + case E_BLOCK_FURNACE: AddFurnaceEntity (static_cast (a_Entity)); break; + case E_BLOCK_HEAD: AddMobHeadEntity (static_cast (a_Entity)); break; + case E_BLOCK_HOPPER: AddHopperEntity (static_cast (a_Entity)); break; + case E_BLOCK_JUKEBOX: AddJukeboxEntity (static_cast (a_Entity)); break; + case E_BLOCK_LIT_FURNACE: AddFurnaceEntity (static_cast (a_Entity)); break; + case E_BLOCK_MOB_SPAWNER: AddMobSpawnerEntity (static_cast (a_Entity)); break; + case E_BLOCK_NOTE_BLOCK: AddNoteEntity (static_cast (a_Entity)); break; + case E_BLOCK_SIGN_POST: AddSignEntity (static_cast (a_Entity)); break; + case E_BLOCK_TRAPPED_CHEST: AddChestEntity (static_cast (a_Entity), a_Entity->GetBlockType()); break; + case E_BLOCK_WALLSIGN: AddSignEntity (static_cast (a_Entity)); break; default: { @@ -461,6 +465,20 @@ public: + void AddEnchantingTableEntity(cEnchantingTableEntity * a_Entity) + { + mWriter.BeginCompound(""); + AddBasicTileEntity(a_Entity, "EnchantingTable"); + if (!a_Entity->GetCustomName().empty()) + { + mWriter.AddString("CustomName", a_Entity->GetCustomName()); + } + mWriter.EndCompound(); + } + + + + void AddEnderchestEntity(cEnderChestEntity * a_Entity) { mWriter.BeginCompound(""); @@ -471,6 +489,16 @@ public: + void AddEndPortalEntity(cEndPortalEntity * a_Entity) + { + mWriter.BeginCompound(""); + AddBasicTileEntity(a_Entity, "EndPortal"); + mWriter.EndCompound(); + } + + + + void AddFurnaceEntity(cFurnaceEntity * a_Furnace) { diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index a62971e7c..b01bb7fd5 100755 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -25,7 +25,9 @@ #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" +#include "../BlockEntities/EnchantingTableEntity.h" #include "../BlockEntities/EnderChestEntity.h" +#include "../BlockEntities/EndPortalEntity.h" #include "../BlockEntities/FurnaceEntity.h" #include "../BlockEntities/HopperEntity.h" #include "../BlockEntities/JukeboxEntity.h" @@ -639,25 +641,27 @@ OwnedBlockEntity cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int switch (a_BlockType) { // Specific entity loaders: - case E_BLOCK_BEACON: return LoadBeaconFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_BED: return LoadBedFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_BREWING_STAND: return LoadBrewingstandFromNBT(a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_COMMAND_BLOCK: return LoadCommandBlockFromNBT(a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_DISPENSER: return LoadDispenserFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_DROPPER: return LoadDropperFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_ENDER_CHEST: return LoadEnderChestFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_FLOWER_POT: return LoadFlowerPotFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_HEAD: return LoadMobHeadFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_HOPPER: return LoadHopperFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_JUKEBOX: return LoadJukeboxFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_LIT_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_MOB_SPAWNER: return LoadMobSpawnerFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_NOTE_BLOCK: return LoadNoteBlockFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_SIGN_POST: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_TRAPPED_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); - case E_BLOCK_WALLSIGN: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_BEACON: return LoadBeaconFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_BED: return LoadBedFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_BREWING_STAND: return LoadBrewingstandFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_COMMAND_BLOCK: return LoadCommandBlockFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_DISPENSER: return LoadDispenserFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_DROPPER: return LoadDropperFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_ENCHANTMENT_TABLE: return LoadEnchantingTableFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_ENDER_CHEST: return LoadEnderChestFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_END_PORTAL: return LoadEndPortalFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_FLOWER_POT: return LoadFlowerPotFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_HEAD: return LoadMobHeadFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_HOPPER: return LoadHopperFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_JUKEBOX: return LoadJukeboxFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_LIT_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_MOB_SPAWNER: return LoadMobSpawnerFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_NOTE_BLOCK: return LoadNoteBlockFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_SIGN_POST: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_TRAPPED_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); + case E_BLOCK_WALLSIGN: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockType, a_BlockMeta, a_Pos); default: { @@ -1124,6 +1128,31 @@ OwnedBlockEntity cWSSAnvil::LoadDropperFromNBT(const cParsedNBT & a_NBT, int a_T +OwnedBlockEntity cWSSAnvil::LoadEnchantingTableFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos) +{ + // Check if the data has a proper type: + static const AStringVector expectedTypes({ "EnchantingTable", "minecraft:enchanting_table" }); + if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos)) + { + return nullptr; + } + + AString CustomName; + int currentLine = a_NBT.FindChildByName(a_TagIdx, "CustomName"); + if (currentLine >= 0) + { + if (a_NBT.GetType(currentLine) == TAG_String) + { + CustomName = a_NBT.GetString(currentLine); + } + } + return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, m_World, CustomName); +} + + + + + OwnedBlockEntity cWSSAnvil::LoadEnderChestFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos) { // Check if the data has a proper type: @@ -1139,6 +1168,21 @@ OwnedBlockEntity cWSSAnvil::LoadEnderChestFromNBT(const cParsedNBT & a_NBT, int +OwnedBlockEntity cWSSAnvil::LoadEndPortalFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos) +{ + // Check if the data has a proper type: + static const AStringVector expectedTypes({ "EndPortal", "minecraft:end_portal" }); + if (!CheckBlockEntityType(a_NBT, a_TagIdx, expectedTypes, a_Pos)) + { + return nullptr; + } + return std::make_unique(a_BlockType, a_BlockMeta, a_Pos, m_World); +} + + + + + OwnedBlockEntity cWSSAnvil::LoadFlowerPotFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos) { // Check if the data has a proper type: diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 7684fd81b..8baa69c00 100755 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -156,22 +156,24 @@ protected: The coordinates are used only for the log message. */ bool CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, const AStringVector & a_ExpectedTypes, Vector3i a_Pos); - OwnedBlockEntity LoadBeaconFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadBedFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadBrewingstandFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadChestFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadDispenserFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadDropperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadEnderChestFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadFlowerPotFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadFurnaceFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadHopperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadJukeboxFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadMobHeadFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadMobSpawnerFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadNoteBlockFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); - OwnedBlockEntity LoadSignFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadBeaconFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadBedFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadBrewingstandFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadChestFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadCommandBlockFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadDispenserFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadDropperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadEnchantingTableFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadEnderChestFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadEndPortalFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadFlowerPotFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadFurnaceFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadHopperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadJukeboxFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadMobHeadFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadMobSpawnerFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadNoteBlockFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); + OwnedBlockEntity LoadSignFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos); void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength);