From 221cc4ec5cb6301743e947eaabed3fecedba796f Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 16 Oct 2019 10:06:34 +0200 Subject: Refactored block-to-pickup conversion. (#4417) --- src/Bindings/Plugin.h | 2 +- src/Bindings/PluginLua.cpp | 19 ++- src/Bindings/PluginLua.h | 2 +- src/Bindings/PluginManager.cpp | 10 +- src/Bindings/PluginManager.h | 2 +- src/BlockArea.cpp | 30 +++++ src/BlockArea.h | 7 + src/BlockInServerPluginInterface.h | 5 - src/Blocks/BlockAnvil.h | 12 +- src/Blocks/BlockBed.cpp | 40 +++--- src/Blocks/BlockBed.h | 44 ++++--- src/Blocks/BlockBigFlower.h | 128 ++++++------------- src/Blocks/BlockBrewingStand.h | 23 ++-- src/Blocks/BlockButton.h | 21 +-- src/Blocks/BlockCactus.h | 24 +++- src/Blocks/BlockCake.h | 11 +- src/Blocks/BlockCarpet.h | 20 ++- src/Blocks/BlockCauldron.h | 12 +- src/Blocks/BlockChest.h | 40 ++++-- src/Blocks/BlockCobWeb.h | 20 ++- src/Blocks/BlockCocoaPod.h | 15 ++- src/Blocks/BlockCommandBlock.h | 20 ++- src/Blocks/BlockComparator.h | 17 +-- src/Blocks/BlockConcretePowder.h | 21 ++- src/Blocks/BlockCrops.h | 48 +++---- src/Blocks/BlockDeadBush.h | 61 +++------ src/Blocks/BlockDirt.h | 14 +- src/Blocks/BlockDoor.cpp | 18 ++- src/Blocks/BlockDoor.h | 68 ++++------ src/Blocks/BlockDropSpenser.h | 42 ++++-- src/Blocks/BlockEndPortalFrame.h | 4 +- src/Blocks/BlockEnderchest.h | 37 +++++- src/Blocks/BlockEntity.h | 55 +++++++- src/Blocks/BlockFarmland.h | 32 +++-- src/Blocks/BlockFence.h | 18 ++- src/Blocks/BlockFenceGate.h | 14 +- src/Blocks/BlockFire.h | 26 +++- src/Blocks/BlockFlower.h | 15 ++- src/Blocks/BlockFlowerPot.h | 16 ++- src/Blocks/BlockFluid.h | 31 ++++- src/Blocks/BlockFurnace.h | 22 ++-- src/Blocks/BlockGlass.h | 16 ++- src/Blocks/BlockGlowstone.h | 22 +++- src/Blocks/BlockGravel.h | 15 ++- src/Blocks/BlockHandler.cpp | 212 ++++++++----------------------- src/Blocks/BlockHandler.h | 94 ++++++++++---- src/Blocks/BlockHopper.h | 27 ++-- src/Blocks/BlockIce.h | 53 +++++--- src/Blocks/BlockLadder.h | 41 ++++-- src/Blocks/BlockLeaves.h | 56 +++++--- src/Blocks/BlockLever.h | 55 +++++++- src/Blocks/BlockMelon.h | 19 ++- src/Blocks/BlockMobHead.h | 51 +++----- src/Blocks/BlockMobSpawner.h | 26 +++- src/Blocks/BlockMushroom.h | 17 +-- src/Blocks/BlockMycelium.h | 18 ++- src/Blocks/BlockNetherWart.h | 37 ++++-- src/Blocks/BlockOre.h | 95 ++++++-------- src/Blocks/BlockPiston.cpp | 75 ++++------- src/Blocks/BlockPiston.h | 41 ++++-- src/Blocks/BlockPlant.h | 80 +++++++----- src/Blocks/BlockPluginInterface.h | 1 - src/Blocks/BlockPortal.h | 11 +- src/Blocks/BlockPressurePlate.h | 13 +- src/Blocks/BlockPumpkin.h | 2 +- src/Blocks/BlockRail.h | 95 ++++++++------ src/Blocks/BlockRedstone.h | 15 +-- src/Blocks/BlockRedstoneLamp.h | 19 ++- src/Blocks/BlockRedstoneRepeater.h | 21 ++- src/Blocks/BlockRedstoneTorch.h | 19 ++- src/Blocks/BlockSapling.h | 21 ++- src/Blocks/BlockSeaLantern.h | 15 ++- src/Blocks/BlockSideways.h | 27 +++- src/Blocks/BlockSignPost.h | 18 ++- src/Blocks/BlockSlab.h | 73 +++++++++-- src/Blocks/BlockSlime.h | 18 +-- src/Blocks/BlockSnow.h | 26 +++- src/Blocks/BlockSponge.h | 17 ++- src/Blocks/BlockStairs.h | 17 +-- src/Blocks/BlockStems.h | 24 +++- src/Blocks/BlockStone.h | 30 +++-- src/Blocks/BlockSugarcane.h | 25 +++- src/Blocks/BlockTallGrass.h | 69 +++++----- src/Blocks/BlockTorch.h | 17 +-- src/Blocks/BlockTrapdoor.h | 22 ++-- src/Blocks/BlockTripwire.h | 19 ++- src/Blocks/BlockTripwireHook.h | 35 +++-- src/Blocks/BlockVine.h | 113 ++++++++++++---- src/Blocks/BlockWallSign.h | 41 ++++-- src/Blocks/CMakeLists.txt | 3 +- src/Blocks/ChunkInterface.cpp | 34 +++-- src/Blocks/ChunkInterface.h | 19 ++- src/Blocks/ClearMetaOnDrop.h | 24 ---- src/Blocks/MetaRotator.h | 120 ----------------- src/Blocks/Mixins.h | 166 ++++++++++++++++++++++++ src/Blocks/WorldInterface.h | 2 +- src/Chunk.cpp | 118 ++++++++--------- src/Chunk.h | 35 ++++- src/ChunkMap.cpp | 201 +++++++++-------------------- src/ChunkMap.h | 31 ++--- src/ClientHandle.cpp | 24 ++-- src/Item.cpp | 21 +++ src/Item.h | 13 ++ src/Items/ItemBucket.h | 12 +- src/Items/ItemChest.h | 14 +- src/Items/ItemHandler.cpp | 28 +--- src/Items/ItemHandler.h | 5 +- src/Items/ItemShears.h | 8 -- src/Items/ItemShovel.h | 26 ++-- src/Mobs/Villager.cpp | 6 +- src/Simulator/FireSimulator.cpp | 12 +- src/Simulator/FloodyFluidSimulator.cpp | 30 ++--- src/Simulator/SandSimulator.cpp | 4 +- src/Simulator/VaporizeFluidSimulator.cpp | 11 +- src/World.cpp | 70 ++++++++-- src/World.h | 75 +++++++++-- 116 files changed, 2384 insertions(+), 1667 deletions(-) delete mode 100644 src/Blocks/ClearMetaOnDrop.h delete mode 100644 src/Blocks/MetaRotator.h create mode 100644 src/Blocks/Mixins.h (limited to 'src') diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 4214706dd..737ed8465 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -44,7 +44,7 @@ public: /** Calls the specified hook with the params given. Returns the bool that the hook callback returns. */ virtual bool OnBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0; - virtual bool OnBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0; + virtual bool OnBlockToPickups (cWorld & a_World, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, const cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool, cItems & a_Pickups) = 0; virtual bool OnBrewingCompleting (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) = 0; virtual bool OnBrewingCompleted (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) = 0; virtual bool OnChat (cPlayer & a_Player, AString & a_Message) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index ba09b9752..e2062117a 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -227,9 +227,24 @@ bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int -bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) +bool cPluginLua::OnBlockToPickups( + cWorld & a_World, + Vector3i a_BlockPos, + BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, + const cBlockEntity * a_BlockEntity, + const cEntity * a_Digger, + const cItem * a_Tool, + cItems & a_Pickups +) { - return CallSimpleHooks(cPluginManager::HOOK_BLOCK_TO_PICKUPS, &a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, &a_Pickups); + // TODO: Change the hook signature to reflect the real parameters to this function, once we are allowed to make breaking API changes + return CallSimpleHooks( + cPluginManager::HOOK_BLOCK_TO_PICKUPS, + &a_World, + a_Digger, + a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, + a_BlockType, a_BlockMeta, &a_Pickups + ); } diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index 7904fe115..50ab328d6 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -66,7 +66,7 @@ public: virtual void Tick(float a_Dt) override; virtual bool OnBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) override; - virtual bool OnBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) override; + virtual bool OnBlockToPickups (cWorld & a_World, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, const cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool, cItems & a_Pickups) override; virtual bool OnBrewingCompleting (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) override; virtual bool OnBrewingCompleted (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) override; virtual bool OnChat (cPlayer & a_Player, AString & a_Message) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 257ad7c07..987b6a7cf 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -248,14 +248,18 @@ bool cPluginManager::CallHookBlockSpread(cWorld & a_World, int a_BlockX, int a_B bool cPluginManager::CallHookBlockToPickups( - cWorld & a_World, cEntity * a_Digger, - int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, + cWorld & a_World, + Vector3i a_BlockPos, + BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, + const cBlockEntity * a_BlockEntity, + const cEntity * a_Digger, + const cItem * a_Tool, cItems & a_Pickups ) { return GenericCallHook(HOOK_BLOCK_TO_PICKUPS, [&](cPlugin * a_Plugin) { - return a_Plugin->OnBlockToPickups(a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_Pickups); + return a_Plugin->OnBlockToPickups(a_World, a_BlockPos, a_BlockType, a_BlockMeta, a_BlockEntity, a_Digger, a_Tool, a_Pickups); } ); } diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index f68a21065..7ce4b0f3f 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -225,7 +225,7 @@ public: // Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort bool CallHookBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source); - bool CallHookBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups); + bool CallHookBlockToPickups (cWorld & a_World, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, const cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool, cItems & a_Pickups); bool CallHookBrewingCompleting (cWorld & a_World, cBrewingstandEntity & a_Brewingstand); bool CallHookBrewingCompleted (cWorld & a_World, cBrewingstandEntity & a_Brewingstand); bool CallHookChat (cPlayer & a_Player, AString & a_Message); diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index 417325c8a..4a07db39b 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -14,6 +14,7 @@ #include "Blocks/BlockHandler.h" #include "ChunkData.h" #include "BlockEntities/BlockEntity.h" +#include "Item.h" @@ -2215,6 +2216,21 @@ bool cBlockArea::ForEachBlockEntity(cBlockEntityCallback a_Callback) +cItems cBlockArea::PickupsFromBlock(Vector3i a_AbsPos, const cEntity * a_Digger, const cItem * a_Tool) +{ + auto relPos = a_AbsPos - m_Origin; + BLOCKTYPE blockType; + NIBBLETYPE blockMeta; + GetRelBlockTypeMeta(relPos.x, relPos.y, relPos.z, blockType, blockMeta); + auto blockEntity = GetBlockEntityRel(relPos); + auto handler = BlockHandler(blockType); + return handler->ConvertToPickups(blockMeta, blockEntity, a_Digger, a_Tool); +} + + + + + void cBlockArea::SetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array) { if (a_Array == nullptr) @@ -2710,6 +2726,20 @@ void cBlockArea::RemoveNonMatchingBlockEntities(void) +cBlockEntity * cBlockArea::GetBlockEntityRel(Vector3i a_RelPos) +{ + if (!HasBlockEntities()) + { + return nullptr; + } + auto itr = m_BlockEntities->find(MakeIndex(a_RelPos)); + return (itr == m_BlockEntities->end()) ? nullptr : itr->second; +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cBlockArea::sBlockEntityDeleter: diff --git a/src/BlockArea.h b/src/BlockArea.h index 8f57c8e5e..b7bfded9a 100644 --- a/src/BlockArea.h +++ b/src/BlockArea.h @@ -24,6 +24,7 @@ // fwd: class cCuboid; +class cItems; using cBlockEntityCallback = cFunctionRef; @@ -421,6 +422,9 @@ public: /** Direct read-only access to block entities. */ const cBlockEntities & GetBlockEntities(void) const { ASSERT(HasBlockEntities()); return *m_BlockEntities; } + /** Returns the pickups that would result if the block at the specified position was mined by a_Digger, using a_Tool. */ + cItems PickupsFromBlock(Vector3i a_AbsPos, const cEntity * a_Digger = nullptr, const cItem * a_Tool = nullptr); + protected: @@ -520,6 +524,9 @@ protected: /** Removes from m_BlockEntities those BEs that no longer match the blocktype at their coords. */ void RemoveNonMatchingBlockEntities(void); + /** Returns the cBlockEntity at the specified coords, or nullptr if none. */ + cBlockEntity * GetBlockEntityRel(Vector3i a_RelPos); + // tolua_begin } ; // tolua_end diff --git a/src/BlockInServerPluginInterface.h b/src/BlockInServerPluginInterface.h index b3a71577f..f3ed774f7 100644 --- a/src/BlockInServerPluginInterface.h +++ b/src/BlockInServerPluginInterface.h @@ -27,11 +27,6 @@ public: return cPluginManager::Get()->CallHookBlockSpread(m_World, a_BlockX, a_BlockY, a_BlockZ, a_Source); } - virtual bool CallHookBlockToPickups(cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) override - { - return cPluginManager::Get()->CallHookBlockToPickups(m_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_Pickups); - } - virtual bool CallHookPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override { return cPluginManager::Get()->CallHookPlayerBreakingBlock(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta); diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index 5b1fea134..2252c7ded 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -18,11 +18,19 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2)); + return cItem(m_BlockType, 1, a_BlockMeta >> 2); } + + + + virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override { cWindow * Window = new cAnvilWindow(a_BlockX, a_BlockY, a_BlockZ); diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp index 6a5a9ec02..3f10a2e88 100644 --- a/src/Blocks/BlockBed.cpp +++ b/src/Blocks/BlockBed.cpp @@ -15,35 +15,33 @@ -void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockBedHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) { - Vector3i ThisPos(a_BlockX, a_BlockY, a_BlockZ); - NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(ThisPos); - Vector3i Direction = MetaDataToDirection(OldMeta & 0x3); - if (OldMeta & 0x8) + auto Direction = MetaDataToDirection(a_OldBlockMeta & 0x03); + if ((a_OldBlockMeta & 0x08) != 0) { // Was pillow - if (a_ChunkInterface.GetBlock(ThisPos - Direction) == E_BLOCK_BED) + if (a_ChunkInterface.GetBlock(a_BlockPos - Direction) == E_BLOCK_BED) { // First replace the bed with air - a_ChunkInterface.FastSetBlock(ThisPos - Direction, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockPos - Direction, E_BLOCK_AIR, 0); // Then destroy the bed entity - Vector3i PillowPos(ThisPos - Direction); - a_ChunkInterface.SetBlock(PillowPos.x, PillowPos.y, PillowPos.z, E_BLOCK_AIR, 0); + Vector3i PillowPos(a_BlockPos - Direction); + a_ChunkInterface.SetBlock(PillowPos, E_BLOCK_AIR, 0); } } else { // Was foot end - if (a_ChunkInterface.GetBlock(ThisPos + Direction) == E_BLOCK_BED) + if (a_ChunkInterface.GetBlock(a_BlockPos + Direction) == E_BLOCK_BED) { // First replace the bed with air - a_ChunkInterface.FastSetBlock(ThisPos + Direction, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockPos + Direction, E_BLOCK_AIR, 0); // Then destroy the bed entity - Vector3i FootPos(ThisPos + Direction); - a_ChunkInterface.SetBlock(FootPos.x, FootPos.y, FootPos.z, E_BLOCK_AIR, 0); + Vector3i FootPos(a_BlockPos + Direction); + a_ChunkInterface.SetBlock(FootPos, E_BLOCK_AIR, 0); } } } @@ -155,14 +153,12 @@ void cBlockBedHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWor -void cBlockBedHandler::ConvertToPickups(cWorldInterface & a_WorldInterface, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ) +cItems cBlockBedHandler::ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) { - short Color = E_META_WOOL_RED; - a_WorldInterface.DoWithBedAt(a_BlockX, a_BlockY, a_BlockZ, [&](cBedEntity & a_Bed) - { - Color = a_Bed.GetColor(); - return true; - } - ); - a_Pickups.Add(cItem(E_ITEM_BED, 1, Color)); + short color = E_META_WOOL_RED; + if (a_BlockEntity != nullptr) + { + color = reinterpret_cast(a_BlockEntity)->GetColor(); + } + return cItem(E_ITEM_BED, 1, color); } diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index c66542e7d..585067ce2 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -4,7 +4,7 @@ #pragma once #include "BlockEntity.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "ChunkInterface.h" @@ -18,24 +18,28 @@ class cWorldInterface; class cBlockBedHandler : public cMetaRotator { + using super = cMetaRotator; + public: - cBlockBedHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) + + cBlockBedHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override; + + + + // Overrides: + virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override; virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override; + virtual void OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) override; + - virtual bool IsUseable(void) override - { - return true; - } - virtual void ConvertToPickups(cItems & Pickups, NIBBLETYPE Meta) override {} - virtual void ConvertToPickups(cWorldInterface & a_WorldInterface, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ) override; // Bed specific helper functions static NIBBLETYPE RotationToMetaData(double a_Rotation) @@ -51,18 +55,26 @@ public: return (static_cast(a_Rotation + 2)) % 4; } + + + + static Vector3i MetaDataToDirection(NIBBLETYPE a_MetaData) { switch (a_MetaData) { - case 0: return Vector3i(0, 0, 1); - case 1: return Vector3i(-1, 0, 0); - case 2: return Vector3i(0, 0, -1); - case 3: return Vector3i(1, 0, 0); + case 0: return Vector3i( 0, 0, 1); + case 1: return Vector3i(-1, 0, 0); + case 2: return Vector3i( 0, 0, -1); + case 3: return Vector3i( 1, 0, 0); } return Vector3i(); } + + + + static void SetBedOccupationState(cChunkInterface & a_ChunkInterface, const Vector3i & a_BedPosition, bool a_IsOccupied) { auto Meta = a_ChunkInterface.GetBlockMeta(a_BedPosition); @@ -78,7 +90,9 @@ public: a_ChunkInterface.SetBlockMeta(a_BedPosition.x, a_BedPosition.y, a_BedPosition.z, Meta); } - virtual void OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) override; + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h index defe57d99..ae4b2500a 100644 --- a/src/Blocks/BlockBigFlower.h +++ b/src/Blocks/BlockBigFlower.h @@ -42,106 +42,53 @@ public: ); } - virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override - { - Vector3i Pos(a_BlockX, a_BlockY, a_BlockZ); - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(Pos); - int AlternateY = a_BlockY; - int BottomY = a_BlockY; - if (Meta & 0x8) - { - --AlternateY; - --BottomY; - } - else - { - ++AlternateY; - } - // also destroy the other block if it has a valid height and is a big flower - if (cChunkDef::IsValidHeight(AlternateY) && a_ChunkInterface.GetBlock({Pos.x, AlternateY, Pos.z}) == E_BLOCK_BIG_FLOWER) - { - super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, BottomY, a_BlockZ, a_CanDrop); - a_ChunkInterface.FastSetBlock(a_BlockX, AlternateY, a_BlockZ, E_BLOCK_AIR, 0); - } - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { if (IsMetaTopPart(a_BlockMeta)) { - return; // No way to tell flower type + return {}; // No drops from the top part } - NIBBLETYPE Meta = a_BlockMeta & 0x7; - if (Meta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) + // With shears, drop self (even tall grass and fern): + if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS)) + { + // Bit 0x08 specifies whether this is a top part or bottom; cut it off from the pickup: + return cItem(m_BlockType, 1, a_BlockMeta & 0x07); + } + + // Tall grass drops seeds, large fern drops nothing, others drop self: + auto flowerType = a_BlockMeta & 0x07; + if (flowerType == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) { if (GetRandomProvider().RandBool(1.0 / 24.0)) { - a_Pickups.push_back(cItem(E_ITEM_SEEDS)); + return cItem(E_ITEM_SEEDS); } } - else if (Meta != E_META_BIG_FLOWER_LARGE_FERN) + else if (flowerType != E_META_BIG_FLOWER_LARGE_FERN) { - a_Pickups.push_back(cItem(E_BLOCK_BIG_FLOWER, 1, Meta)); + return cItem(m_BlockType, 1, static_cast(flowerType)); } + return {}; } - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - Vector3i BlockPos(a_BlockX, a_BlockY, a_BlockZ); - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(BlockPos); - if (Meta & 0x8) - { - Meta = a_ChunkInterface.GetBlockMeta(BlockPos - Vector3i(0, 1, 0)); - } - NIBBLETYPE FlowerMeta = Meta & 0x7; - if (!a_Player.IsGameModeCreative()) - { - if ( - (a_Player.GetEquippedItem().m_ItemType == E_ITEM_SHEARS) && - ( - (FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) || - (FlowerMeta == E_META_BIG_FLOWER_LARGE_FERN) - ) - ) - { - if (GetRandomProvider().RandBool(0.10)) - { - cItems Pickups; - if (FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) - { - Pickups.Add(E_BLOCK_TALL_GRASS, 2, 1); - } - else if (FlowerMeta == E_META_BIG_FLOWER_LARGE_FERN) - { - Pickups.Add(E_BLOCK_TALL_GRASS, 2, 2); - } - a_WorldInterface.SpawnItemPickups(Pickups, BlockPos.x, BlockPos.y, BlockPos.z); - } - a_Player.UseEquippedItem(); - } - } - if ( - (a_Player.GetEquippedItem().m_ItemType != E_ITEM_SHEARS) && - ( - (FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) || - (FlowerMeta == E_META_BIG_FLOWER_LARGE_FERN) - ) - ) - { - a_ChunkInterface.SetBlock(BlockPos.x, BlockPos.y, BlockPos.z, 0, 0); - a_Player.UseEquippedItem(cItemHandler::dlaBreakBlockInstant); - } - } + bool IsMetaTopPart(NIBBLETYPE a_Meta) { - return (a_Meta & 0x08) != 0; + return ((a_Meta & 0x08) != 0); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) @@ -155,31 +102,36 @@ public: return IsBlockTypeOfDirt(BlockType) || ((BlockType == E_BLOCK_BIG_FLOWER) && !IsMetaTopPart(BlockMeta)); } - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - Vector3i BlockPos(a_BlockX, a_BlockY, a_BlockZ); - NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(BlockPos); - if (OldMeta & 0x8) + + + + virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override + { + if ((a_OldBlockMeta & 0x8) != 0) { // Was upper part of flower - Vector3i LowerPart = BlockPos - Vector3i(0, 1, 0); - if (a_ChunkInterface.GetBlock(LowerPart) == m_BlockType) + auto lowerPartPos = a_BlockPos - Vector3i(0, 1, 0); + if (a_ChunkInterface.GetBlock(lowerPartPos) == a_OldBlockType) { - a_ChunkInterface.FastSetBlock(LowerPart, E_BLOCK_AIR, 0); + a_ChunkInterface.DropBlockAsPickups(lowerPartPos); } } else { // Was lower part - Vector3i UpperPart = BlockPos + Vector3i(0, 1, 0); - if (a_ChunkInterface.GetBlock(UpperPart) == m_BlockType) + auto upperPartPos = a_BlockPos + Vector3i(0, 1, 0); + if (a_ChunkInterface.GetBlock(upperPartPos) == a_OldBlockType) { - a_ChunkInterface.FastSetBlock(UpperPart, E_BLOCK_AIR, 0); + a_ChunkInterface.DropBlockAsPickups(upperPartPos); } } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockBrewingStand.h b/src/Blocks/BlockBrewingStand.h index 3445a0f5a..48158ef73 100644 --- a/src/Blocks/BlockBrewingStand.h +++ b/src/Blocks/BlockBrewingStand.h @@ -2,28 +2,27 @@ #pragma once #include "BlockEntity.h" -#include "MetaRotator.h" +#include "Mixins.h" + + class cBlockBrewingStandHandler : - public cMetaRotator + public cClearMetaOnDrop> { + using super = cClearMetaOnDrop>; + public: - cBlockBrewingStandHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockBrewingStandHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.push_back(cItem(E_ITEM_BREWING_STAND, 1, 0)); } - virtual bool IsUseable() override - { - return true; - } + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index f81220b36..86c7cb2c5 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -2,20 +2,27 @@ #include "BlockHandler.h" #include "../Chunk.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockButtonHandler : - public cMetaRotator + public cClearMetaOnDrop> { + using super = cClearMetaOnDrop>; + public: - cBlockButtonHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) + + cBlockButtonHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override { Vector3i Pos(a_BlockX, a_BlockY, a_BlockZ); @@ -53,12 +60,6 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to 0 - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } - virtual bool IsUseable(void) override { return true; diff --git a/src/Blocks/BlockCactus.h b/src/Blocks/BlockCactus.h index 371402423..f33c17153 100644 --- a/src/Blocks/BlockCactus.h +++ b/src/Blocks/BlockCactus.h @@ -8,21 +8,31 @@ class cBlockCactusHandler : - public cBlockPlant + public cBlockPlant { - typedef cBlockPlant Super; + using super = cBlockPlant; + public: - cBlockCactusHandler(BLOCKTYPE a_BlockType) - : Super(a_BlockType, false) + + cBlockCactusHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // Reset meta to 0 - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); + return cItem(m_BlockType, 1, 0); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) @@ -88,7 +98,7 @@ protected: auto Action = paStay; if (((a_RelY + 1) < cChunkDef::Height) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR)) { - Action = Super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); + Action = super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); } return Action; diff --git a/src/Blocks/BlockCake.h b/src/Blocks/BlockCake.h index 88125c56b..4767a5148 100644 --- a/src/Blocks/BlockCake.h +++ b/src/Blocks/BlockCake.h @@ -35,11 +35,20 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // Give nothing + return {}; } + + + + virtual bool IsUseable(void) override { return true; diff --git a/src/Blocks/BlockCarpet.h b/src/Blocks/BlockCarpet.h index aee36d271..2b2ae2434 100644 --- a/src/Blocks/BlockCarpet.h +++ b/src/Blocks/BlockCarpet.h @@ -17,12 +17,19 @@ class cBlockCarpetHandler : public cBlockHandler { + using super = cBlockHandler; + public: + cBlockCarpetHandler(BLOCKTYPE a_BlockType) : - cBlockHandler(a_BlockType) + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -35,16 +42,19 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - a_Pickups.push_back(cItem(E_BLOCK_CARPET, 1, a_BlockMeta)); - } + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { return (a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { switch (a_Meta) diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h index 466eb6bcc..40eab2be9 100644 --- a/src/Blocks/BlockCauldron.h +++ b/src/Blocks/BlockCauldron.h @@ -8,17 +8,15 @@ class cBlockCauldronHandler : - public cBlockHandler + public cClearMetaOnDrop { + using super = cClearMetaOnDrop; + public: - cBlockCauldronHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockCauldronHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.push_back(cItem(E_ITEM_CAULDRON, 1, 0)); } virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h index 804c3d34a..0e277532e 100644 --- a/src/Blocks/BlockChest.h +++ b/src/Blocks/BlockChest.h @@ -1,24 +1,31 @@ #pragma once -#include "BlockEntity.h" +#include "../BlockEntities/ChestEntity.h" #include "../BlockArea.h" #include "../Entities/Player.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockChestHandler : - public cMetaRotator + public cMetaRotator, 0x07, 0x02, 0x05, 0x03, 0x04> { + using super = cMetaRotator, 0x07, 0x02, 0x05, 0x03, 0x04>; + public: - cBlockChestHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) + + cBlockChestHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -65,6 +72,10 @@ public: return true; } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; @@ -72,6 +83,10 @@ public: return CanBeAt(a_ChunkInterface, BlockX, a_RelY, BlockZ); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) { cBlockArea Area; @@ -137,6 +152,10 @@ public: return (NumChestNeighbors < 2); } + + + + /** Translates player yaw when placing a chest into the chest block metadata. Valid for single chests only */ static NIBBLETYPE PlayerYawToMetaData(double a_Yaw) { @@ -164,6 +183,10 @@ public: } } + + + + /** If there's a chest in the a_Area in the specified coords, modifies its meta to a_NewMeta and returns true. */ bool CheckAndAdjustNeighbor(cChunkInterface & a_ChunkInterface, const cBlockArea & a_Area, int a_RelX, int a_RelZ, NIBBLETYPE a_NewMeta) { @@ -175,10 +198,9 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { diff --git a/src/Blocks/BlockCobWeb.h b/src/Blocks/BlockCobWeb.h index e7dd70af4..0c80edd2d 100644 --- a/src/Blocks/BlockCobWeb.h +++ b/src/Blocks/BlockCobWeb.h @@ -18,11 +18,27 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_STRING, 1, 0)); + // Silk touch gives cobweb, anything else gives just string: + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(m_BlockType, 1, 0); + } + else + { + return cItem(E_ITEM_STRING, 1, 0); + } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockCocoaPod.h b/src/Blocks/BlockCocoaPod.h index 4a1fb8c10..2d5243995 100644 --- a/src/Blocks/BlockCocoaPod.h +++ b/src/Blocks/BlockCocoaPod.h @@ -44,12 +44,21 @@ public: } } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - int GrowState = a_BlockMeta >> 2; - a_Pickups.Add(E_ITEM_DYE, ((GrowState >= 2) ? 3 : 1), E_META_DYE_BROWN); + // If fully grown, give 3 items, otherwise just one: + auto growState = a_BlockMeta >> 2; + return cItem(E_ITEM_DYE, ((growState >= 2) ? 3 : 1), E_META_DYE_BROWN); } + + + + static eBlockFace MetaToBlockFace(NIBBLETYPE a_Meta) { switch (a_Meta & 0x3) diff --git a/src/Blocks/BlockCommandBlock.h b/src/Blocks/BlockCommandBlock.h index d1b81185f..70b98baf0 100644 --- a/src/Blocks/BlockCommandBlock.h +++ b/src/Blocks/BlockCommandBlock.h @@ -10,17 +10,29 @@ class cBlockCommandBlockHandler : public cBlockEntityHandler { + using super = cBlockEntityHandler; + public: - cBlockCommandBlockHandler(BLOCKTYPE a_BlockType) - : cBlockEntityHandler(a_BlockType) + + cBlockCommandBlockHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_BLOCK_AIR, 8, 0)); + // Don't allow as a pickup: + return {}; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h index ddbcaa0c2..4103c805e 100644 --- a/src/Blocks/BlockComparator.h +++ b/src/Blocks/BlockComparator.h @@ -3,18 +3,21 @@ #include "BlockHandler.h" #include "BlockRedstoneRepeater.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockComparatorHandler : - public cMetaRotator + public cClearMetaOnDrop> { + using super = cClearMetaOnDrop>; + public: - cBlockComparatorHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) + + cBlockComparatorHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -32,12 +35,6 @@ public: a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to 0 - a_Pickups.push_back(cItem(E_ITEM_COMPARATOR, 1, 0)); - } - virtual bool IsUseable(void) override { return true; diff --git a/src/Blocks/BlockConcretePowder.h b/src/Blocks/BlockConcretePowder.h index 4b2a81b2a..58dfade99 100644 --- a/src/Blocks/BlockConcretePowder.h +++ b/src/Blocks/BlockConcretePowder.h @@ -10,9 +10,12 @@ class cBlockConcretePowderHandler : public cBlockHandler { + using super = cBlockHandler; + public: + cBlockConcretePowderHandler(BLOCKTYPE a_BlockType): - cBlockHandler(a_BlockType) + super(a_BlockType) { } @@ -20,21 +23,25 @@ public: - virtual void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override + virtual void Check( + cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk + ) override { - if (GetSoaked(Vector3i(a_RelX, a_RelY, a_RelZ), a_Chunk)) + if (GetSoaked(a_RelPos, a_Chunk)) { return; } - cBlockHandler::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk); + super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk); } - /** Check blocks above and around to see if they are water. If one is, convert this into concrete block. - Returns TRUE if the block was changed. */ + /** Check blocks above and around to see if they are water. If one is, converts this into concrete block. + Returns true if the block was changed. */ bool GetSoaked(Vector3i a_Rel, cChunk & a_Chunk) { static const std::array WaterCheck @@ -62,7 +69,7 @@ public: { NIBBLETYPE BlockMeta; BlockMeta = a_Chunk.GetMeta(a_Rel.x, a_Rel.y, a_Rel.z); - a_Chunk.SetBlock(a_Rel.x, a_Rel.y, a_Rel.z, E_BLOCK_CONCRETE, BlockMeta); + a_Chunk.SetBlock(a_Rel, E_BLOCK_CONCRETE, BlockMeta); return true; } return false; diff --git a/src/Blocks/BlockCrops.h b/src/Blocks/BlockCrops.h index 378505430..0d6296a33 100644 --- a/src/Blocks/BlockCrops.h +++ b/src/Blocks/BlockCrops.h @@ -10,71 +10,70 @@ /** Common class that takes care of beetroots, carrots, potatoes and wheat */ template -class cBlockCropsHandler : - public cBlockPlant +class cBlockCropsHandler: + public cBlockPlant { - typedef cBlockPlant Super; + using super = cBlockPlant; public: cBlockCropsHandler(BLOCKTYPE a_BlockType): - Super(a_BlockType, true) + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { auto & rand = GetRandomProvider(); // If not fully grown, drop the "seed" of whatever is growing: - if (a_Meta < RipeMeta) + if (a_BlockMeta < RipeMeta) { switch (m_BlockType) { - case E_BLOCK_BEETROOTS: a_Pickups.push_back(cItem(E_ITEM_BEETROOT_SEEDS, 1, 0)); break; - case E_BLOCK_CROPS: a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1, 0)); break; - case E_BLOCK_CARROTS: a_Pickups.push_back(cItem(E_ITEM_CARROT, 1, 0)); break; - case E_BLOCK_POTATOES: a_Pickups.push_back(cItem(E_ITEM_POTATO, 1, 0)); break; - default: - { - ASSERT(!"Unhandled block type"); - break; - } + case E_BLOCK_BEETROOTS: return cItem(E_ITEM_BEETROOT_SEEDS, 1, 0); break; + case E_BLOCK_CROPS: return cItem(E_ITEM_SEEDS, 1, 0); break; + case E_BLOCK_CARROTS: return cItem(E_ITEM_CARROT, 1, 0); break; + case E_BLOCK_POTATOES: return cItem(E_ITEM_POTATO, 1, 0); break; } - return; + ASSERT(!"Unhandled block type"); + return {}; } // Fully grown, drop the crop's produce: + cItems res; switch (m_BlockType) { case E_BLOCK_BEETROOTS: { char SeedCount = 1 + ((rand.RandInt(2) + rand.RandInt(2)) / 2); // [1 .. 3] with high preference of 2 - a_Pickups.emplace_back(E_ITEM_BEETROOT_SEEDS, SeedCount, 0); + res.Add(E_ITEM_BEETROOT_SEEDS, SeedCount, 0); char BeetrootCount = 1 + ((rand.RandInt(2) + rand.RandInt(2)) / 2); // [1 .. 3] with high preference of 2 - a_Pickups.emplace_back(E_ITEM_BEETROOT, BeetrootCount, 0); + res.Add(E_ITEM_BEETROOT, BeetrootCount, 0); break; } case E_BLOCK_CROPS: { - a_Pickups.emplace_back(E_ITEM_WHEAT, 1, 0); - a_Pickups.emplace_back(E_ITEM_SEEDS, 1 + ((rand.RandInt(2) + rand.RandInt(2)) / 2), 0); // [1 .. 3] with high preference of 2 + res.Add(E_ITEM_WHEAT, 1, 0); + res.Add(E_ITEM_SEEDS, 1 + ((rand.RandInt(2) + rand.RandInt(2)) / 2), 0); // [1 .. 3] with high preference of 2 break; } case E_BLOCK_CARROTS: { - a_Pickups.emplace_back(E_ITEM_CARROT, 1 + ((rand.RandInt(2) + rand.RandInt(2)) / 2), 0); // [1 .. 3] with high preference of 2 + res.Add(E_ITEM_CARROT, 1 + ((rand.RandInt(2) + rand.RandInt(2)) / 2), 0); // [1 .. 3] with high preference of 2 break; } case E_BLOCK_POTATOES: { - a_Pickups.emplace_back(E_ITEM_POTATO, 1 + ((rand.RandInt(2) + rand.RandInt(2)) / 2), 0); // [1 .. 3] with high preference of 2 + res.Add(E_ITEM_POTATO, 1 + ((rand.RandInt(2) + rand.RandInt(2)) / 2), 0); // [1 .. 3] with high preference of 2 if (rand.RandBool(0.05)) { // With a 5% chance, drop a poisonous potato as well - a_Pickups.emplace_back(E_ITEM_POISONOUS_POTATO, 1, 0); + res.emplace_back(E_ITEM_POISONOUS_POTATO, 1, 0); } break; } @@ -84,10 +83,13 @@ public: break; } } // switch (m_BlockType) + return res; } + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); diff --git a/src/Blocks/BlockDeadBush.h b/src/Blocks/BlockDeadBush.h index 68846ff46..0b7d27e8b 100644 --- a/src/Blocks/BlockDeadBush.h +++ b/src/Blocks/BlockDeadBush.h @@ -43,57 +43,34 @@ public: } } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Drop 0-3 sticks - char chance = GetRandomProvider().RandInt(3); - if (chance != 0) - { - a_Pickups.emplace_back(E_ITEM_STICK, chance, 0); - } - } - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override - { - UNUSED(a_Meta); - return 0; - } - virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - if (a_CanDrop && (a_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_ItemType == E_ITEM_SHEARS)) + // If cutting down with shears, drop self: + if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS)) { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); - cItems Drops; - Drops.Add(m_BlockType, 1, Meta); + return cItem(m_BlockType, 1, a_BlockMeta); + } - // Allow plugins to modify the pickups: - a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Drops); + // Drop 0-3 sticks: + auto chance = GetRandomProvider().RandInt(3); + if (chance > 0) + { + return cItem(E_ITEM_STICK, chance, 0); + } + return {}; + } - // Spawn the pickups: - if (!Drops.empty()) - { - auto & r1 = GetRandomProvider(); - // Mid-block position first - double MicroX, MicroY, MicroZ; - MicroX = a_BlockX + 0.5; - MicroY = a_BlockY + 0.5; - MicroZ = a_BlockZ + 0.5; - // Add random offset second - MicroX += r1.RandReal(-0.5, 0.5); - MicroZ += r1.RandReal(-0.5, 0.5); - a_WorldInterface.SpawnItemPickups(Drops, MicroX, MicroY, MicroZ); - } - return; - } - super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop); + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override + { + UNUSED(a_Meta); + return 0; } } ; - - - - diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h index 43cadf767..0d4f73212 100644 --- a/src/Blocks/BlockDirt.h +++ b/src/Blocks/BlockDirt.h @@ -20,19 +20,27 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { if (a_BlockMeta == E_META_DIRT_COARSE) { // Drop the coarse block (dirt, meta 1) - a_Pickups.Add(E_BLOCK_DIRT, 1, E_META_DIRT_COARSE); + return cItem(E_BLOCK_DIRT, 1, E_META_DIRT_COARSE); } else { - a_Pickups.Add(E_BLOCK_DIRT, 1, E_META_DIRT_NORMAL); + return cItem(E_BLOCK_DIRT, 1, E_META_DIRT_NORMAL); } } + + + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { if (m_BlockType != E_BLOCK_GRASS) diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp index fe0db26ec..d9a4f12ec 100644 --- a/src/Blocks/BlockDoor.cpp +++ b/src/Blocks/BlockDoor.cpp @@ -7,8 +7,8 @@ -cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType) - : super(a_BlockType) +cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -16,24 +16,22 @@ cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType) -void cBlockDoorHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockDoorHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) { - NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); - - if (OldMeta & 8) + if ((a_OldBlockMeta & 0x08) != 0) { // Was upper part of door - if (IsDoorBlockType(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY - 1, a_BlockZ}))) + if ((a_BlockPos.y > 0) && IsDoorBlockType(a_ChunkInterface.GetBlock(a_BlockPos.addedY(-1)))) { - a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.DropBlockAsPickups(a_BlockPos.addedY(-1)); } } else { // Was lower part - if (IsDoorBlockType(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY + 1, a_BlockZ}))) + if ((a_BlockPos.y < cChunkDef::Height - 1) && IsDoorBlockType(a_ChunkInterface.GetBlock(a_BlockPos.addedY(1)))) { - a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.DropBlockAsPickups(a_BlockPos.addedY(1)); } } } diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h index 04d63141d..b1a606f67 100644 --- a/src/Blocks/BlockDoor.h +++ b/src/Blocks/BlockDoor.h @@ -4,7 +4,7 @@ #include "BlockHandler.h" #include "../Entities/Player.h" #include "../Chunk.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "ChunkInterface.h" #include "BlockSlab.h" @@ -13,11 +13,13 @@ class cBlockDoorHandler : public cMetaRotator { - typedef cMetaRotator super; + using super = cMetaRotator; + public: + cBlockDoorHandler(BLOCKTYPE a_BlockType); - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override; virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override; @@ -54,57 +56,39 @@ public: virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) override; - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - if ((a_BlockMeta & 0x08) != 0) // is top part of door + // Top part of a door doesn't drop anything: + if ((a_BlockMeta & 0x08) != 0) { - return; + return {}; } + switch (m_BlockType) { - case E_BLOCK_OAK_DOOR: - { - a_Pickups.Add(E_ITEM_WOODEN_DOOR); - break; - } - case E_BLOCK_ACACIA_DOOR: - { - a_Pickups.Add(E_ITEM_ACACIA_DOOR); - break; - } - case E_BLOCK_BIRCH_DOOR: - { - a_Pickups.Add(E_ITEM_BIRCH_DOOR); - break; - } - case E_BLOCK_DARK_OAK_DOOR: - { - a_Pickups.Add(E_ITEM_DARK_OAK_DOOR); - break; - } - case E_BLOCK_JUNGLE_DOOR: - { - a_Pickups.Add(E_ITEM_JUNGLE_DOOR); - break; - } - case E_BLOCK_SPRUCE_DOOR: - { - a_Pickups.Add(E_ITEM_SPRUCE_DOOR); - break; - } - case E_BLOCK_IRON_DOOR: - { - a_Pickups.Add(E_ITEM_IRON_DOOR); - break; - } + case E_BLOCK_OAK_DOOR: return cItem(E_ITEM_WOODEN_DOOR); + case E_BLOCK_ACACIA_DOOR: return cItem(E_ITEM_ACACIA_DOOR); + case E_BLOCK_BIRCH_DOOR: return cItem(E_ITEM_BIRCH_DOOR); + case E_BLOCK_DARK_OAK_DOOR: return cItem(E_ITEM_DARK_OAK_DOOR); + case E_BLOCK_JUNGLE_DOOR: return cItem(E_ITEM_JUNGLE_DOOR); + case E_BLOCK_SPRUCE_DOOR: return cItem(E_ITEM_SPRUCE_DOOR); + case E_BLOCK_IRON_DOOR: return cItem(E_ITEM_IRON_DOOR); default: { ASSERT(!"Unhandled door type!"); - break; + return {}; } } } + + + + virtual bool IsUseable(void) override { return true; diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h index 2700b416c..ce98940d2 100644 --- a/src/Blocks/BlockDropSpenser.h +++ b/src/Blocks/BlockDropSpenser.h @@ -6,7 +6,8 @@ #pragma once #include "../Blocks/BlockPiston.h" -#include "MetaRotator.h" +#include "../BlockEntities/DropSpenserEntity.h" +#include "Mixins.h" @@ -15,12 +16,19 @@ class cBlockDropSpenserHandler : public cMetaRotator { + using super = cMetaRotator; + public: - cBlockDropSpenserHandler(BLOCKTYPE a_BlockType) : - cMetaRotator(a_BlockType) + + cBlockDropSpenserHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -35,18 +43,30 @@ public: return true; } - /** Called when the drop / dispenser is convert into pickup, ignore meta data */ - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - UNUSED(a_BlockMeta); - a_Pickups.push_back(cItem(m_BlockType, 1)); + cItems res(cItem(m_BlockType, 1)); + if (a_BlockEntity != nullptr) + { + auto be = static_cast(a_BlockEntity); + res.AddItemGrid(be->GetContents()); + } + return res; } + + + + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override { - // Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000 + // Bit 0x08 is a flag. Lowest three bits are position. NIBBLETYPE OtherMeta = a_Meta & 0x08; - // Mirrors defined by by a table. (Source, mincraft.gamepedia.com) 0x07 == 0111 + // Mirrors defined by a table. (Source, minecraft.gamepedia.com) switch (a_Meta & 0x07) { case 0x00: return 0x01 + OtherMeta; // Down -> Up @@ -56,6 +76,10 @@ public: return a_Meta; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockEndPortalFrame.h b/src/Blocks/BlockEndPortalFrame.h index e1741f5f6..c35d13929 100644 --- a/src/Blocks/BlockEndPortalFrame.h +++ b/src/Blocks/BlockEndPortalFrame.h @@ -76,7 +76,7 @@ public: - virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + 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); @@ -84,7 +84,7 @@ public: { // LOG("Location is %d %d %d", a_BlockX, a_BlockY, a_BlockZ); // Direction is the first two bits, masked by 0x3 - FindAndSetPortal(Vector3i(a_BlockX, a_BlockY, a_BlockZ), a_BlockMeta & 3, a_ChunkInterface, a_WorldInterface); + FindAndSetPortal(a_BlockPos, a_BlockMeta & 3, a_ChunkInterface, a_WorldInterface); } } diff --git a/src/Blocks/BlockEnderchest.h b/src/Blocks/BlockEnderchest.h index 8fd5c2a89..f233468f4 100644 --- a/src/Blocks/BlockEnderchest.h +++ b/src/Blocks/BlockEnderchest.h @@ -2,7 +2,7 @@ #pragma once #include "BlockEntity.h" -#include "MetaRotator.h" +#include "Mixins.h" @@ -10,17 +10,44 @@ class cBlockEnderchestHandler : public cMetaRotator { + using super = cMetaRotator; + public: - cBlockEnderchestHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) + + cBlockEnderchestHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_BLOCK_OBSIDIAN, 8, 0)); + // Only drop something when mined with a pickaxe: + if ( + (a_Tool != nullptr) && + ItemCategory::IsPickaxe(a_Tool->m_ItemType) + ) + { + // Only drop self when mined with a silk-touch pickaxe: + if (a_Tool->m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) + { + return cItem(E_BLOCK_ENDER_CHEST, 1, 0); + } + else + { + return cItem(E_BLOCK_OBSIDIAN, 8, 0); + } + } + return {}; } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, diff --git a/src/Blocks/BlockEntity.h b/src/Blocks/BlockEntity.h index 77d6a7f1e..f592dbd83 100644 --- a/src/Blocks/BlockEntity.h +++ b/src/Blocks/BlockEntity.h @@ -3,23 +3,40 @@ #include "BlockHandler.h" #include "ChunkInterface.h" +#include "../Item.h" +#include "../BlockEntities/BlockEntityWithItems.h" -class cBlockEntityHandler : public cBlockHandler + +/** Wrapper for blocks that have a cBlockEntity descendant attached to them and can be "used" by the player. +Forwards the "use" event to the block entity. */ +class cBlockEntityHandler: + public cBlockHandler { + using super = cBlockHandler; + public: - cBlockEntityHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockEntityHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override { return a_ChunkInterface.UseBlockEntity(&a_Player, a_BlockX, a_BlockY, a_BlockZ); } + + + + virtual bool IsUseable() override { return true; @@ -29,3 +46,35 @@ public: + +/** Wrapper for blocks that have a cBlockEntityWithItems descendant attached to them. +When converting to pickups, drops self with meta reset to zero, and adds the container contents. */ +template +class cContainerEntityHandler: + public Base +{ +public: + + cContainerEntityHandler(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override + { + // Reset meta to 0 + cItems res(cItem(Base::m_BlockType, 1, 0)); + + // Drop the contents: + if (a_BlockEntity != nullptr) + { + auto container = static_cast(a_BlockEntity); + res.AddItemGrid(container->GetContents()); + } + return res; + } +}; diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h index 09982cd5e..219f9a654 100644 --- a/src/Blocks/BlockFarmland.h +++ b/src/Blocks/BlockFarmland.h @@ -17,15 +17,21 @@ class cBlockFarmlandHandler : - public cBlockHandler + public cClearMetaOnDrop { + using super = cClearMetaOnDrop; public: - cBlockFarmlandHandler(BLOCKTYPE a_BlockType) : - cBlockHandler(a_BlockType) + + cBlockFarmlandHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { NIBBLETYPE BlockMeta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); @@ -60,14 +66,17 @@ public: } default: { - a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, 0); + a_Chunk.SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_DIRT, 0); break; } } } - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override + + + + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override { // Don't care about any neighbor but the one above us (fix recursion loop in #2213): if (a_WhichNeighbor != BLOCK_FACE_YP) @@ -76,24 +85,21 @@ public: } // Don't care about anything if we're at the top of the world: - if (a_BlockY >= cChunkDef::Height) + if (a_BlockPos.y >= cChunkDef::Height) { return; } // Check whether we should revert to dirt: - BLOCKTYPE UpperBlock = a_ChunkInterface.GetBlock({a_BlockX, a_BlockY + 1, a_BlockZ}); - if (cBlockInfo::FullyOccupiesVoxel(UpperBlock)) + auto upperBlock = a_ChunkInterface.GetBlock(a_BlockPos.addedY(1)); + if (cBlockInfo::FullyOccupiesVoxel(upperBlock)) { - a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DIRT, 0); + a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_DIRT, 0); } } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - a_Pickups.Add(E_BLOCK_DIRT, 1, 0); // Reset meta - } + bool IsWaterInNear(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) diff --git a/src/Blocks/BlockFence.h b/src/Blocks/BlockFence.h index 6c38b7c72..96a3d8d96 100644 --- a/src/Blocks/BlockFence.h +++ b/src/Blocks/BlockFence.h @@ -122,13 +122,21 @@ public: return true; } - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - auto LeashKnot = cLeashKnot::FindKnotAtPos(a_WorldInterface, { a_BlockX, a_BlockY, a_BlockZ }); - if (LeashKnot != nullptr) + + + + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override + { + // Destroy any leash knot tied to the fence: + auto leashKnot = cLeashKnot::FindKnotAtPos(a_WorldInterface, a_BlockPos); + if (leashKnot != nullptr) { - LeashKnot->SetShouldSelfDestroy(); + leashKnot->SetShouldSelfDestroy(); } } diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h index c8fca21af..c56925633 100644 --- a/src/Blocks/BlockFenceGate.h +++ b/src/Blocks/BlockFenceGate.h @@ -2,24 +2,22 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "../EffectID.h" class cBlockFenceGateHandler : - public cMetaRotator + public cClearMetaOnDrop> { + using super = cClearMetaOnDrop>; + public: - cBlockFenceGateHandler(BLOCKTYPE a_BlockType) : - cMetaRotator(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockFenceGateHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.Add(m_BlockType, 1, 0); // Reset meta to zero } virtual bool GetPlacementBlockTypeMeta( diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h index ae0df0727..a4b3d3a05 100644 --- a/src/Blocks/BlockFire.h +++ b/src/Blocks/BlockFire.h @@ -18,11 +18,16 @@ public: } /** Portal boundary and direction variables */ - // 2014_03_30 _X: What are these used for? Why do we need extra variables? + // TODO: These need to be removed, BlockHandler instances are shared for all blocks in all worlds on the server + // and are not supposed to have any data in them. int XZP, XZM; NIBBLETYPE Dir; - virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + + + + + virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override { /* PORTAL FINDING ALGORITH @@ -38,14 +43,23 @@ public: */ // a_BlockY - 1: Because we want the block below the fire - FindAndSetPortalFrame(a_BlockX, a_BlockY - 1, a_BlockZ, a_ChunkInterface, a_WorldInterface); + FindAndSetPortalFrame(a_BlockPos.x, a_BlockPos.y - 1, a_BlockPos.z, a_ChunkInterface, a_WorldInterface); } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // No pickups from this block + return {}; } + + + + virtual bool IsClickedThrough(void) override { return true; @@ -102,6 +116,10 @@ public: return true; } + + + + /** Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE) */ void FindAndSetPortalFrame(int X, int Y, int Z, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface) { diff --git a/src/Blocks/BlockFlower.h b/src/Blocks/BlockFlower.h index 3340b701f..d88891d75 100644 --- a/src/Blocks/BlockFlower.h +++ b/src/Blocks/BlockFlower.h @@ -16,13 +16,20 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - NIBBLETYPE Meta = a_BlockMeta & 0x7; - a_Pickups.push_back(cItem(m_BlockType, 1, Meta)); + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override + { + NIBBLETYPE meta = a_BlockMeta & 0x7; + return cItem(m_BlockType, 1, meta); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)); diff --git a/src/Blocks/BlockFlowerPot.h b/src/Blocks/BlockFlowerPot.h index 40bad534f..36c71df5b 100644 --- a/src/Blocks/BlockFlowerPot.h +++ b/src/Blocks/BlockFlowerPot.h @@ -8,19 +8,21 @@ class cBlockFlowerPotHandler : - public cBlockEntityHandler + public cClearMetaOnDrop { + using super = cClearMetaOnDrop; + public: - cBlockFlowerPotHandler(BLOCKTYPE a_BlockType) : - cBlockEntityHandler(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockFlowerPotHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.push_back(cItem(E_ITEM_FLOWER_POT, 1, 0)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h index c33427739..430940df0 100644 --- a/src/Blocks/BlockFluid.h +++ b/src/Blocks/BlockFluid.h @@ -19,34 +19,55 @@ public: } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // No pickups + return {}; } + + + + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { return true; } - virtual void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override + + + + + virtual void Check( + cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk + ) override { switch (m_BlockType) { case E_BLOCK_STATIONARY_LAVA: { - a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_LAVA, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); + a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_LAVA, a_Chunk.GetMeta(a_RelPos)); break; } case E_BLOCK_STATIONARY_WATER: { - a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_WATER, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); + a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_WATER, a_Chunk.GetMeta(a_RelPos)); break; } } - super::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk); + super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h index ea1779c41..4a0459bf0 100644 --- a/src/Blocks/BlockFurnace.h +++ b/src/Blocks/BlockFurnace.h @@ -3,25 +3,27 @@ #include "BlockEntity.h" #include "../Blocks/BlockPiston.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockFurnaceHandler : - public cMetaRotator + public cClearMetaOnDrop> { + using super = cClearMetaOnDrop>; + public: - cBlockFurnaceHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockFurnaceHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.push_back(cItem(E_BLOCK_FURNACE, 1, 0)); } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -37,6 +39,10 @@ public: return true; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockGlass.h b/src/Blocks/BlockGlass.h index 5b797be31..8d082a2bf 100644 --- a/src/Blocks/BlockGlass.h +++ b/src/Blocks/BlockGlass.h @@ -16,10 +16,24 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { + // Only drop self when mined with silk-touch: + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(m_BlockType, 1, a_BlockMeta); + } + return {}; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockGlowstone.h b/src/Blocks/BlockGlowstone.h index 4b0d72a93..eddbf30d9 100644 --- a/src/Blocks/BlockGlowstone.h +++ b/src/Blocks/BlockGlowstone.h @@ -16,12 +16,28 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // Add more than one dust - a_Pickups.emplace_back(E_ITEM_GLOWSTONE_DUST, GetRandomProvider().RandInt(2, 4), 0); + // Drop self only when using silk-touch: + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(E_BLOCK_GLOWSTONE, 1, 0); + } + else + { + // TODO: Handle the Fortune enchantment here + return cItem(E_ITEM_GLOWSTONE_DUST, GetRandomProvider().RandInt(2, 4), 0); + } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockGravel.h b/src/Blocks/BlockGravel.h index 6229d1d75..fe93dc96b 100644 --- a/src/Blocks/BlockGravel.h +++ b/src/Blocks/BlockGravel.h @@ -16,18 +16,27 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { + // TODO: Handle the Fortune and Silk touch enchantments here if (GetRandomProvider().RandBool(0.10)) { - a_Pickups.Add(E_ITEM_FLINT, 1, 0); + return cItem(E_ITEM_FLINT, 1, 0); } else { - a_Pickups.Add(E_BLOCK_GRAVEL, 1, 0); + return cItem(E_BLOCK_GRAVEL, 1, 0); } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 928fca1e9..58096f038 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -189,6 +189,7 @@ static cBlockHandler * CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_ACACIA_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType); case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType); + case E_BLOCK_AIR: return new cBlockWithNoDrops<> (a_BlockType); case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType); case E_BLOCK_BEACON: return new cBlockEntityHandler (a_BlockType); case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType); @@ -401,185 +402,72 @@ void cBlockHandler::OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface void cBlockHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) { - OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(), a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta); + OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockChange.GetPos(), a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta); } -void cBlockHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) -{ -} - - - - - -void cBlockHandler::OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +void cBlockHandler::OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { // Notify the neighbors - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ, BLOCK_FACE_XP); - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ, BLOCK_FACE_XM); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_YP); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_YM); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1, BLOCK_FACE_ZP); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ + 1, BLOCK_FACE_ZM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedX(-1), BLOCK_FACE_XP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedX( 1), BLOCK_FACE_XM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedY(-1), BLOCK_FACE_YP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedY( 1), BLOCK_FACE_YM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ(-1), BLOCK_FACE_ZP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ( 1), BLOCK_FACE_ZM); } -void cBlockHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) { // Notify the neighbors - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ, BLOCK_FACE_XP); - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ, BLOCK_FACE_XM); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_YP); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_YM); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1, BLOCK_FACE_ZP); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ + 1, BLOCK_FACE_ZM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedX(-1), BLOCK_FACE_XP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedX( 1), BLOCK_FACE_XM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedY(-1), BLOCK_FACE_YP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedY( 1), BLOCK_FACE_YM); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ(-1), BLOCK_FACE_ZP); + NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ( 1), BLOCK_FACE_ZM); } -void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_NeighborX, int a_NeighborY, int a_NeighborZ, eBlockFace a_WhichNeighbor) +void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_NeighborPos, eBlockFace a_WhichNeighbor) { - if ((a_NeighborY >= 0) && (a_NeighborY < cChunkDef::Height)) + if (!cChunkDef::IsValidHeight(a_NeighborPos.y)) { - cBlockInfo::GetHandler(a_ChunkInterface.GetBlock({a_NeighborX, a_NeighborY, a_NeighborZ}))->OnNeighborChanged(a_ChunkInterface, a_NeighborX, a_NeighborY, a_NeighborZ, a_WhichNeighbor); + return; } -} - - - - -void cBlockHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) -{ - // Setting the meta to a_BlockMeta keeps most textures. The few other blocks have to override this. - a_Pickups.push_back(cItem(m_BlockType, 1, a_BlockMeta)); + cBlockInfo::GetHandler(a_ChunkInterface.GetBlock(a_NeighborPos))->OnNeighborChanged(a_ChunkInterface, a_NeighborPos, a_WhichNeighbor); } -void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) +cItems cBlockHandler::ConvertToPickups( + NIBBLETYPE a_BlockMeta, + cBlockEntity * a_BlockEntity, + const cEntity * a_Digger, + const cItem * a_Tool +) { - cItems Pickups; - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); - - if (a_CanDrop) - { - if ((a_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0)) - { - switch (m_BlockType) - { - case E_BLOCK_ACACIA_DOOR: - case E_BLOCK_ACTIVE_COMPARATOR: - case E_BLOCK_BEETROOTS: - case E_BLOCK_BIRCH_DOOR: - case E_BLOCK_BREWING_STAND: - case E_BLOCK_CAKE: - case E_BLOCK_CARROTS: - case E_BLOCK_CAULDRON: - case E_BLOCK_COCOA_POD: - case E_BLOCK_CROPS: - case E_BLOCK_DARK_OAK_DOOR: - case E_BLOCK_DEAD_BUSH: - case E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB: - case E_BLOCK_DOUBLE_STONE_SLAB: - case E_BLOCK_DOUBLE_WOODEN_SLAB: - case E_BLOCK_FIRE: - case E_BLOCK_FARMLAND: - case E_BLOCK_FLOWER_POT: - case E_BLOCK_HEAD: - case E_BLOCK_INACTIVE_COMPARATOR: - case E_BLOCK_INVERTED_DAYLIGHT_SENSOR: - case E_BLOCK_IRON_DOOR: - case E_BLOCK_JUNGLE_DOOR: - case E_BLOCK_MELON_STEM: - case E_BLOCK_MOB_SPAWNER: - case E_BLOCK_NETHER_WART: - case E_BLOCK_OAK_DOOR: - case E_BLOCK_PISTON_EXTENSION: - case E_BLOCK_POTATOES: - case E_BLOCK_PUMPKIN_STEM: - case E_BLOCK_PURPUR_DOUBLE_SLAB: - case E_BLOCK_REDSTONE_ORE_GLOWING: - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_WIRE: - case E_BLOCK_SIGN_POST: - case E_BLOCK_SNOW: - case E_BLOCK_SPRUCE_DOOR: - case E_BLOCK_STANDING_BANNER: - case E_BLOCK_SUGARCANE: - case E_BLOCK_TALL_GRASS: - case E_BLOCK_TRIPWIRE: - case E_BLOCK_WALL_BANNER: - case E_BLOCK_WALLSIGN: - { - // Silktouch can't be used for these blocks - ConvertToPickups(Pickups, Meta); - break; - } - case E_BLOCK_BED: - { - // Need to access the bed entity to get the color for the item damage - ConvertToPickups(a_WorldInterface, Pickups, Meta, a_BlockX, a_BlockY, a_BlockZ); - break; - } - case E_BLOCK_ENDER_CHEST: - { - // Reset meta to 0 - Pickups.Add(m_BlockType, 1, 0); - break; - } - case E_BLOCK_LEAVES: - case E_BLOCK_NEW_LEAVES: - { - Pickups.Add(m_BlockType, 1, Meta & 0x03); - break; - } - default: Pickups.Add(m_BlockType, 1, Meta); break; - } - } - else if (m_BlockType == E_BLOCK_BED) - { - // Need to access the bed entity to get the color for the item damage - ConvertToPickups(a_WorldInterface, Pickups, Meta, a_BlockX, a_BlockY, a_BlockZ); - } - else - { - ConvertToPickups(Pickups, Meta); - } - } - - // Allow plugins to modify the pickups: - a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Pickups); - - if (!Pickups.empty()) - { - auto & r1 = GetRandomProvider(); - - // Mid-block position first - double MicroX, MicroY, MicroZ; - MicroX = a_BlockX + 0.5; - MicroY = a_BlockY + 0.5; - MicroZ = a_BlockZ + 0.5; - - // Add random offset second - MicroX += r1.RandReal(-0.5, 0.5); - MicroZ += r1.RandReal(-0.5, 0.5); - - a_WorldInterface.SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ); - } + UNUSED(a_BlockEntity); + UNUSED(a_Digger); + UNUSED(a_Tool); + + // Add self: + cItems res; + res.push_back(cItem(m_BlockType, 1, a_BlockMeta)); + return res; } @@ -655,25 +543,28 @@ cBoundingBox cBlockHandler::GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a -void cBlockHandler::Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) +void cBlockHandler::Check( + cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk +) { - if (!CanBeAt(a_ChunkInterface, a_RelX, a_RelY, a_RelZ, a_Chunk)) + if (!CanBeAt(a_ChunkInterface, a_RelPos.x, a_RelPos.y, a_RelPos.z, a_Chunk)) { if (DoesDropOnUnsuitable()) { - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ); + a_ChunkInterface.DropBlockAsPickups(a_Chunk.RelativeToAbsolute(a_RelPos)); + } + else + { + a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0); } - - a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); } else { // Wake up the simulators for this block: - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, &a_Chunk); + auto absPos = a_Chunk.RelativeToAbsolute(a_RelPos); + a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(absPos, &a_Chunk); } } @@ -691,6 +582,15 @@ ColourID cBlockHandler::GetMapBaseColourID(NIBBLETYPE a_Meta) +bool cBlockHandler::ToolHasSilkTouch(const cItem * a_Tool) +{ + return ((a_Tool != nullptr) && (a_Tool->m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0)); +} + + + + + cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE aBlockType) { return ::CreateBlockHandler(aBlockType); diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index d077442c9..c0a11186e 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -50,30 +50,62 @@ public: ); /** Called by cWorld::SetBlock() after the block has been set */ - virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); /** Called by cPlayer::PlaceBlocks() for each block after it has been set to the world. Called after OnPlaced(). */ virtual void OnPlacedByPlayer( cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange ); - /** Called before the player has destroyed a block */ - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ); - - /** Called before a block gets destroyed / replaced with air */ - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ); + /** Called just before the player breaks the block. + The block is still valid in the world. + By default does nothing special; descendants may provide further behavior. */ + virtual void OnPlayerBreakingBlock( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + Vector3i a_BlockPos + ) {} + + /** Called just after the player breaks the block. + The block is already dug up in the world, the original block type and meta is passed in a_OldBlockType and a_OldBlockMeta. + By default does nothing special, descendants may provide further behavior. */ + virtual void OnPlayerBrokeBlock( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) {} + + /** Called before a block gets broken (replaced with air), either by player or by natural means. + If by player, it is called after the OnPlayerBreakingBlock() callback. + By default does nothing. */ + virtual void OnBreaking( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos + ) {} + + /** Called after a block gets broken (replaced with air), either by player or by natural means. + If by player, it is called before the OnPlayerBrokeBlock() callback. + The block is already dug up in the world, the original block type and meta is passed in a_OldBlockType and a_OldBlockMeta. + By default notifies all direct neighbors via their OnNeighborChanged() callbacks. */ + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ); - /** Called when a direct neighbor of this block has been changed (The position is the block's own position, not the changing neighbor's position) + /** Called when a direct neighbor of this block has been changed. + The position is the block's own position, NOT the changed neighbor's position. a_WhichNeighbor indicates which neighbor has changed. For example, BLOCK_FACE_YP meant the neighbor above has changed. BLOCK_FACE_NONE means that it is a neighbor not directly adjacent (diagonal, etc.) */ - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) {} + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) {} /** Notifies the specified neighbor that the current block has changed. - a_NeighborXYZ coords are the coords of the neighbor - a_WhichNeighbor specifies which neighbor (relative to a_NeighborXYZ) has changed. + a_NeighborPos are the coords of the neighbor to be notified + a_WhichNeighbor specifies which neighbor (relative to a_NeighborPos) has changed. For example BLOCK_FACE_YP means that the block at {a_NeighborX, a_NeighborY + 1, a_NeighborZ} has changed. BLOCK_FACE_NONE means that it is a neighbor not directly adjacent (diagonal, etc.) */ - static void NeighborChanged(cChunkInterface & a_ChunkInterface, int a_NeighborX, int a_NeighborY, int a_NeighborZ, eBlockFace a_WhichNeighbor); + static void NeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_NeighborPos, eBlockFace a_WhichNeighbor); /** Called when the player starts digging the block. */ virtual void OnDigging(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {} @@ -86,19 +118,18 @@ public: It forces the server to send the real state of a block to the client to prevent client assuming the operation is successfull */ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) {} - /** Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents */ - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta); - - /** Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents. - Overloaded method with coords and world interface for blocks that needs to access the block entity, e.g. a bed. */ - virtual void ConvertToPickups(cWorldInterface & a_WorldInterface, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ) {} - - /** Handles the dropping, but not destruction, of a block based on what ConvertTo(Verbatim)Pickups() returns, including the spawning of pickups and alertion of plugins - @param a_Digger The entity causing the drop; it may be nullptr - @param a_CanDrop Informs the handler whether the block should be dropped at all. One example when this is false is when stone is destroyed by hand - @param a_DropVerbatim Calls ConvertToVerbatimPickups() instead of its counterpart, meaning the block itself is dropped by default (due to a speical tool or enchantment) - */ - virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop = true); + /** Returns the pickups that would result if the block was mined by a_Digger using a_Tool. + Doesn't do any actual block change / mining, only calculates the pickups. + a_BlockEntity is the block entity present at the block, if any, nullptr if none. + a_Digger is the entity that caused the conversion, usually the player digging. + a_Tool is the tool used for the digging. + The default implementation drops a single item created from m_BlockType and the current meta. */ + virtual cItems ConvertToPickups( + NIBBLETYPE a_BlockMeta, + cBlockEntity * a_BlockEntity, + const cEntity * a_Digger = nullptr, + const cItem * a_Tool = nullptr + ); /** Checks if the block can stay at the specified relative coords in the chunk */ virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk); @@ -138,9 +169,13 @@ public: virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta); /** Called when one of the neighbors gets set; equivalent to MC block update. - By default drops if position no more suitable (CanBeAt(), DoesDropOnUnsuitable(), Drop()), - and wakes up all simulators on the block. */ - virtual void Check(cChunkInterface & ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk); + By default drops (DropBlockAsPickup() / SetBlock()) if the position is no longer suitable (CanBeAt(), DoesDropOnUnsuitable()), + otherwise wakes up all simulators on the block. */ + virtual void Check( + cChunkInterface & ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk + ); /** Returns the base colour ID of the block, as will be represented on a map, as per documentation: https://minecraft.gamepedia.com/Map_item_format */ virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta); @@ -165,6 +200,11 @@ public: Returns block meta following rotation */ virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) { return a_Meta; } + /** Returns true if the specified tool is valid and has a non-zero silk-touch enchantment. + Helper used in many ConvertToPickups() implementations. */ + static bool ToolHasSilkTouch(const cItem * a_Tool); + + protected: BLOCKTYPE m_BlockType; diff --git a/src/Blocks/BlockHopper.h b/src/Blocks/BlockHopper.h index d855ed0a4..da2f7c6e1 100644 --- a/src/Blocks/BlockHopper.h +++ b/src/Blocks/BlockHopper.h @@ -3,19 +3,26 @@ // Declares the cBlockHopperHandler class representing the handler for the Hopper block -#include "MetaRotator.h" +#include "Mixins.h" class cBlockHopperHandler : - public cMetaRotator + public cMetaRotator, 0x07, 0x02, 0x05, 0x03, 0x04> { + using super = cMetaRotator, 0x07, 0x02, 0x05, 0x03, 0x04>; + public: - cBlockHopperHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) + + cBlockHopperHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -39,6 +46,10 @@ public: return true; } + + + + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override { // Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000 @@ -53,11 +64,9 @@ public: return a_Meta; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to 0 - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { diff --git a/src/Blocks/BlockIce.h b/src/Blocks/BlockIce.h index 845bb423b..672288ca3 100644 --- a/src/Blocks/BlockIce.h +++ b/src/Blocks/BlockIce.h @@ -10,37 +10,58 @@ class cBlockIceHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockIceHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockIceHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // No pickups + // Only drop self when using silk-touch: + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(m_BlockType); + } + else + { + return {}; + } } - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override + + + + + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override { - if (a_Player.IsGameModeCreative() || (a_BlockY <= 0)) + // If there's a solid block or a liquid underneath, convert to water, rather than air + if (a_BlockPos.y <= 0) { return; } - - cEnchantments Enchantments = a_Player.GetInventory().GetEquippedItem().m_Enchantments; - if (Enchantments.GetLevel(cEnchantments::enchSilkTouch) == 0) + auto blockTypeBelow = a_ChunkInterface.GetBlock(a_BlockPos.addedY(-1)); + if (cBlockInfo::FullyOccupiesVoxel(blockTypeBelow) || IsBlockLiquid(blockTypeBelow)) { - BLOCKTYPE BlockBelow = a_ChunkInterface.GetBlock({a_BlockX, a_BlockY - 1, a_BlockZ}); - if (!cBlockInfo::FullyOccupiesVoxel(BlockBelow) && !IsBlockLiquid(BlockBelow)) - { - return; - } - - a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WATER, 0); + a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_WATER, 0); } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockLadder.h b/src/Blocks/BlockLadder.h index 29c0cf2b7..90e2d8304 100644 --- a/src/Blocks/BlockLadder.h +++ b/src/Blocks/BlockLadder.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "ClearMetaOnDrop.h" +#include "Mixins.h" @@ -11,13 +11,19 @@ class cBlockLadderHandler : public cClearMetaOnDrop > { - typedef cClearMetaOnDrop > super; + using super = cClearMetaOnDrop>; + public: - cBlockLadderHandler(BLOCKTYPE a_BlockType) - : super(a_BlockType) + + cBlockLadderHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -40,10 +46,9 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - a_Pickups.Add(m_BlockType, 1, 0); // Reset meta - } + + + static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction) { @@ -63,6 +68,10 @@ public: UNREACHABLE("Unsupported block face"); } + + + + static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData) { switch (a_MetaData) @@ -75,6 +84,10 @@ public: } } + + + + /** Finds a suitable Direction for the Ladder. Returns BLOCK_FACE_BOTTOM on failure */ static eBlockFace FindSuitableBlockFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) { @@ -89,6 +102,10 @@ public: return BLOCK_FACE_BOTTOM; } + + + + static bool LadderCanBePlacedAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) { if ((a_BlockFace == BLOCK_FACE_BOTTOM) || (a_BlockFace == BLOCK_FACE_TOP)) @@ -101,6 +118,10 @@ public: return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ})); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { // TODO: Use AdjustCoordsByMeta(), then cChunk::UnboundedRelGetBlock() and finally some comparison @@ -110,6 +131,10 @@ public: return LadderCanBePlacedAt(a_ChunkInterface, BlockX, a_RelY, BlockZ, BlockFace); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index c1840c474..065c5ec19 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -36,13 +36,25 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - auto & rand = GetRandomProvider(); + // If breaking with shears, drop self: + if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS)) + { + return cItem(m_BlockType, a_BlockMeta & 0x03); + } + // There is a chance to drop a sapling that varies depending on the type of leaf broken. + // Note: It is possible (though very rare) for a single leaves block to drop both a sapling and an apple // TODO: Take into account fortune for sapling drops. double chance = 0.0; + auto & rand = GetRandomProvider(); + cItems res; if ((m_BlockType == E_BLOCK_LEAVES) && ((a_BlockMeta & 0x03) == E_META_LEAVES_JUNGLE)) { // Jungle leaves have a 2.5% chance of dropping a sapling. @@ -55,12 +67,10 @@ public: } if (rand.RandBool(chance)) { - a_Pickups.push_back( - cItem( - E_BLOCK_SAPLING, - 1, - (m_BlockType == E_BLOCK_LEAVES) ? (a_BlockMeta & 0x03) : static_cast(4 + (a_BlockMeta & 0x01)) - ) + res.Add( + E_BLOCK_SAPLING, + 1, + (m_BlockType == E_BLOCK_LEAVES) ? (a_BlockMeta & 0x03) : static_cast(4 + (a_BlockMeta & 0x01)) ); } @@ -69,22 +79,31 @@ public: { if (rand.RandBool(0.005)) { - a_Pickups.push_back(cItem(E_ITEM_RED_APPLE, 1, 0)); + res.Add(E_ITEM_RED_APPLE, 1, 0); } } + return res; } - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override + + + + + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); + auto meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); - // Set 0x8 bit so this block gets checked for decay: - if ((Meta & 0x08) == 0) + // Set bit 0x08, so this block gets checked for decay: + if ((meta & 0x08) == 0) { - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x8, true, false); + a_ChunkInterface.SetBlockMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, meta | 0x8, true, false); } } + + + + virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); @@ -119,15 +138,18 @@ public: if (HasNearLog(Area, BlockX, a_RelY, BlockZ)) { // Wood found, the leaves stay; unset the check bit - a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta ^ 0x8, true, false); + a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta ^ 0x08, true, false); return; } // Decay the leaves: - DropBlock(a_ChunkInterface, a_WorldInterface, a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ); - a_ChunkInterface.DigBlock(a_WorldInterface, BlockX, a_RelY, BlockZ); + a_ChunkInterface.DropBlockAsPickups({BlockX, a_RelY, BlockZ}); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 6cb80222e..e4b181a24 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -2,21 +2,26 @@ #include "BlockHandler.h" #include "../Chunk.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "BlockSlab.h" class cBlockLeverHandler : public cMetaRotator { - typedef cMetaRotator super; + using super = cMetaRotator; public: + cBlockLeverHandler(BLOCKTYPE a_BlockType) : super(a_BlockType) { } + + + + virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override { Vector3i Coords(a_BlockX, a_BlockY, a_BlockZ); @@ -29,17 +34,29 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // Reset meta to 0 - a_Pickups.push_back(cItem(E_BLOCK_LEVER, 1, 0)); + // Reset meta to zero: + return cItem(E_BLOCK_LEVER, 1, 0); } + + + + virtual bool IsUseable(void) override { return true; } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -52,6 +69,10 @@ public: return true; } + + + + inline static NIBBLETYPE LeverDirectionToMetaData(eBlockFace a_Dir) { // Determine lever direction: @@ -68,6 +89,10 @@ public: UNREACHABLE("Unsupported block face"); } + + + + inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) { switch (a_Meta & 0x7) @@ -88,6 +113,10 @@ public: } } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); @@ -121,6 +150,10 @@ public: return false; } + + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override { switch (a_Meta) @@ -135,6 +168,10 @@ public: } } + + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override { switch (a_Meta) @@ -149,12 +186,20 @@ public: } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); return 0; } + + + + /** Extracts the ON bit from metadata and returns if true if it is set */ static bool IsLeverOn(NIBBLETYPE a_BlockMeta) { diff --git a/src/Blocks/BlockMelon.h b/src/Blocks/BlockMelon.h index baf3053e1..3a25a0e2d 100644 --- a/src/Blocks/BlockMelon.h +++ b/src/Blocks/BlockMelon.h @@ -10,17 +10,28 @@ class cBlockMelonHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockMelonHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockMelonHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.emplace_back(E_ITEM_MELON_SLICE, GetRandomProvider().RandInt(3, 7), 0); + return cItem(E_ITEM_MELON_SLICE, GetRandomProvider().RandInt(3, 7), 0); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h index 764cd7f65..cdee5c297 100644 --- a/src/Blocks/BlockMobHead.h +++ b/src/Blocks/BlockMobHead.h @@ -11,53 +11,32 @@ class cBlockMobHeadHandler : public cBlockEntityHandler { + using super = cBlockEntityHandler; + public: cBlockMobHeadHandler(BLOCKTYPE a_BlockType): - cBlockEntityHandler(a_BlockType) + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // The drop spawn is in the OnDestroyedByPlayer method - } - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - if (a_Player.IsGameModeCreative()) + if ((a_BlockEntity == nullptr) || (a_BlockEntity->GetBlockType() != E_BLOCK_HEAD)) { - // No drops in creative mode - return; + return {}; } - - a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, [](cBlockEntity & a_BlockEntity) - { - if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD) - { - return false; - } - auto & MobHeadEntity = static_cast(a_BlockEntity); - - cItems Pickups; - Pickups.Add(E_ITEM_HEAD, 1, static_cast(MobHeadEntity.GetType())); - auto & r1 = GetRandomProvider(); - - // Mid-block position first - double MicroX, MicroY, MicroZ; - MicroX = MobHeadEntity.GetPosX() + 0.5; - MicroY = MobHeadEntity.GetPosY() + 0.5; - MicroZ = MobHeadEntity.GetPosZ() + 0.5; - - // Add random offset second - MicroX += r1.RandReal(-0.5, 0.5); - MicroZ += r1.RandReal(-0.5, 0.5); - - MobHeadEntity.GetWorld()->SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ); - return false; - } - ); + auto mobHeadEntity = static_cast(a_BlockEntity); + return cItem(E_ITEM_HEAD, 1, static_cast(mobHeadEntity->GetType())); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockMobSpawner.h b/src/Blocks/BlockMobSpawner.h index 7911d3398..c8a1c5696 100644 --- a/src/Blocks/BlockMobSpawner.h +++ b/src/Blocks/BlockMobSpawner.h @@ -30,22 +30,34 @@ public: } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // No pickups + return {}; } - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override + + + + virtual void OnPlayerBrokeBlock( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override { - cItemHandler * Handler = a_Player.GetEquippedItem().GetHandler(); - if (a_Player.IsGameModeCreative() || !Handler->CanHarvestBlock(E_BLOCK_MOB_SPAWNER)) + auto handler = a_Player.GetEquippedItem().GetHandler(); + if (!a_Player.IsGameModeSurvival() || !handler->CanHarvestBlock(E_BLOCK_MOB_SPAWNER)) { return; } - auto & Random = GetRandomProvider(); - int Reward = 15 + Random.RandInt(14) + Random.RandInt(14); - a_WorldInterface.SpawnSplitExperienceOrbs(static_cast(a_BlockX), static_cast(a_BlockY + 1), static_cast(a_BlockZ), Reward); + auto & random = GetRandomProvider(); + int reward = 15 + random.RandInt(14) + random.RandInt(14); + a_WorldInterface.SpawnSplitExperienceOrbs(Vector3d(0.5, 0.5, 0.5) + a_BlockPos, reward); } } ; diff --git a/src/Blocks/BlockMushroom.h b/src/Blocks/BlockMushroom.h index d6b726b57..7fb397420 100644 --- a/src/Blocks/BlockMushroom.h +++ b/src/Blocks/BlockMushroom.h @@ -7,23 +7,20 @@ -class cBlockMushroomHandler : - public cBlockHandler +class cBlockMushroomHandler: + public cClearMetaOnDrop { + using super = cClearMetaOnDrop; + public: - cBlockMushroomHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockMushroomHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } // TODO: Add Mushroom Spread - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to 0 - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) diff --git a/src/Blocks/BlockMycelium.h b/src/Blocks/BlockMycelium.h index 1c365caa8..e91d45b98 100644 --- a/src/Blocks/BlockMycelium.h +++ b/src/Blocks/BlockMycelium.h @@ -7,22 +7,30 @@ -class cBlockMyceliumHandler : +class cBlockMyceliumHandler: public cBlockHandler { public: - cBlockMyceliumHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + cBlockMyceliumHandler(BLOCKTYPE a_BlockType): + cBlockHandler(a_BlockType) { } // TODO: Add Mycel Spread - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_BLOCK_DIRT, 1, 0)); + return cItem(E_BLOCK_DIRT, 1, 0); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockNetherWart.h b/src/Blocks/BlockNetherWart.h index 5732259db..6b0b394b5 100644 --- a/src/Blocks/BlockNetherWart.h +++ b/src/Blocks/BlockNetherWart.h @@ -9,30 +9,39 @@ class cBlockNetherWartHandler : - public cBlockPlant + public cBlockPlant { - typedef cBlockPlant Super; + using super = cBlockPlant; + public: - cBlockNetherWartHandler(BLOCKTYPE a_BlockType) - : Super(a_BlockType, false) + + cBlockNetherWartHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override - { - auto & rand = GetRandomProvider(); - if (a_Meta == 0x3) + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override + { + if (a_BlockMeta == 0x03) { // Fully grown, drop the entire produce: - a_Pickups.emplace_back(E_ITEM_NETHER_WART, 1 + (rand.RandInt(2) + rand.RandInt(2)) / 2, 0); + auto & rand = GetRandomProvider(); + return cItem(E_ITEM_NETHER_WART, 1 + (rand.RandInt(2) + rand.RandInt(2)) / 2, 0); } else { - a_Pickups.push_back(cItem(E_ITEM_NETHER_WART)); + return cItem(E_ITEM_NETHER_WART); } } + + + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); @@ -46,12 +55,20 @@ public: } } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { // Needs to be placed on top of a Soulsand block: return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SOULSAND)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockOre.h b/src/Blocks/BlockOre.h index 0a52de3d6..70bb0515d 100644 --- a/src/Blocks/BlockOre.h +++ b/src/Blocks/BlockOre.h @@ -17,63 +17,50 @@ public: { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - auto & Random = GetRandomProvider(); + // If using silk-touch, drop self rather than the resource: + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(m_BlockType); + } + // TODO: Handle the Fortune enchantment here + auto & random = GetRandomProvider(); switch (m_BlockType) { - case E_BLOCK_LAPIS_ORE: - { - a_Pickups.emplace_back(E_ITEM_DYE, Random.RandInt(4, 8), 4); - break; - } - case E_BLOCK_REDSTONE_ORE: - case E_BLOCK_REDSTONE_ORE_GLOWING: - { - a_Pickups.emplace_back(E_ITEM_REDSTONE_DUST, Random.RandInt(4, 5), 0); - break; - } - case E_BLOCK_DIAMOND_ORE: - { - a_Pickups.push_back(cItem(E_ITEM_DIAMOND)); - break; - } - case E_BLOCK_EMERALD_ORE: - { - a_Pickups.push_back(cItem(E_ITEM_EMERALD)); - break; - } - case E_BLOCK_COAL_ORE: - { - a_Pickups.push_back(cItem(E_ITEM_COAL)); - break; - } - case E_BLOCK_NETHER_QUARTZ_ORE: - { - a_Pickups.push_back(cItem(E_ITEM_NETHER_QUARTZ)); - break; - } - case E_BLOCK_CLAY: - { - a_Pickups.push_back(cItem(E_ITEM_CLAY, 4)); - break; - } + case E_BLOCK_LAPIS_ORE: return cItem(E_ITEM_DYE, random.RandInt(4, 8), 4); + case E_BLOCK_REDSTONE_ORE: return cItem(E_ITEM_REDSTONE_DUST, random.RandInt(4, 5), 0); + case E_BLOCK_REDSTONE_ORE_GLOWING: return cItem(E_ITEM_REDSTONE_DUST, random.RandInt(4, 5), 0); + case E_BLOCK_DIAMOND_ORE: return cItem(E_ITEM_DIAMOND); + case E_BLOCK_EMERALD_ORE: return cItem(E_ITEM_EMERALD); + case E_BLOCK_COAL_ORE: return cItem(E_ITEM_COAL); + case E_BLOCK_NETHER_QUARTZ_ORE: return cItem(E_ITEM_NETHER_QUARTZ); + case E_BLOCK_CLAY: return cItem(E_ITEM_CLAY, 4); default: { - a_Pickups.push_back(cItem(m_BlockType)); - break; + return cItem(m_BlockType); } } } - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - super::OnDestroyedByPlayer(a_ChunkInterface, a_WorldInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ); - if (a_Player.IsGameModeCreative()) + + + + virtual void OnPlayerBrokeBlock( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + cPlayer & a_Player, Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override + { + if (!a_Player.IsGameModeSurvival()) { - // Don't drop XP when the player is in creative mode. + // Don't drop XP unless the player is in survival mode. return; } @@ -83,45 +70,45 @@ public: return; } - auto & Random = GetRandomProvider(); - int Reward = 0; + auto & random = GetRandomProvider(); + int reward = 0; - switch (m_BlockType) + switch (a_OldBlockType) { case E_BLOCK_NETHER_QUARTZ_ORE: case E_BLOCK_LAPIS_ORE: { // Lapis and nether quartz get 2 - 5 experience - Reward = Random.RandInt(2, 5); + reward = random.RandInt(2, 5); break; } case E_BLOCK_REDSTONE_ORE: case E_BLOCK_REDSTONE_ORE_GLOWING: { // Redstone gets 1 - 5 experience - Reward = Random.RandInt(1, 5); + reward = random.RandInt(1, 5); break; } case E_BLOCK_DIAMOND_ORE: case E_BLOCK_EMERALD_ORE: { // Diamond and emerald get 3 - 7 experience - Reward = Random.RandInt(3, 7); + reward = random.RandInt(3, 7); break; } case E_BLOCK_COAL_ORE: { // Coal gets 0 - 2 experience - Reward = Random.RandInt(2); + reward = random.RandInt(2); break; } default: break; } - if (Reward != 0) + if (reward > 0) { - a_WorldInterface.SpawnSplitExperienceOrbs(a_BlockX, a_BlockY, a_BlockZ, Reward); + a_WorldInterface.SpawnSplitExperienceOrbs(Vector3d(0.5, 0.5, 0.5) + a_BlockPos, reward); } } } ; diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index c3a90c8a5..6ebbd784d 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -16,8 +16,8 @@ -cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) +cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -25,20 +25,19 @@ cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockType) -void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockPistonHandler::OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta +) { - Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ); - - NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(blockPos); // If the piston is extended, destroy the extension as well - if (IsExtended(OldMeta)) + if (IsExtended(a_OldBlockMeta)) { - // Get the position of the extension - blockPos += MetadataToOffset(OldMeta); - - if (a_ChunkInterface.GetBlock(blockPos) == E_BLOCK_PISTON_EXTENSION) + auto extPos = a_BlockPos + MetadataToOffset(a_OldBlockMeta); + if (a_ChunkInterface.GetBlock(extPos) == E_BLOCK_PISTON_EXTENSION) { - a_ChunkInterface.SetBlock(blockPos.x, blockPos.y, blockPos.z, E_BLOCK_AIR, 0); + a_ChunkInterface.DropBlockAsPickups(extPos); } } } @@ -47,16 +46,6 @@ void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorld -void cBlockPistonHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) -{ - // Returning Piston Item without Direction-Metavalue - a_Pickups.push_back(cItem(m_BlockType, 1)); -} - - - - - bool cBlockPistonHandler::GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -106,7 +95,7 @@ void cBlockPistonHandler::PushBlocks( std::vector sortedBlocks(a_BlocksToPush.begin(), a_BlocksToPush.end()); std::sort(sortedBlocks.begin(), sortedBlocks.end(), [a_PushDir](const Vector3i & a, const Vector3i & b) { - return a.Dot(a_PushDir) > b.Dot(a_PushDir); + return (a.Dot(a_PushDir) > b.Dot(a_PushDir)); }); // Move every block @@ -118,17 +107,8 @@ void cBlockPistonHandler::PushBlocks( if (cBlockInfo::IsPistonBreakable(moveBlock)) { - // Block is breakable, drop it - cBlockHandler * Handler = BlockHandler(moveBlock); - if (Handler->DoesDropOnUnsuitable()) - { - cChunkInterface ChunkInterface(a_World.GetChunkMap()); - cBlockInServerPluginInterface PluginInterface(a_World); - Handler->DropBlock(ChunkInterface, a_World, PluginInterface, nullptr, - moveBlockPos.x, moveBlockPos.y, moveBlockPos.z - ); - } - a_World.SetBlock(moveBlockPos.x, moveBlockPos.y, moveBlockPos.z, E_BLOCK_AIR, 0); + // Block is breakable, drop it: + a_World.DropBlockAsPickups(moveBlockPos, nullptr, nullptr); } else { @@ -357,26 +337,17 @@ cBlockPistonHeadHandler::cBlockPistonHeadHandler(void) : -void cBlockPistonHeadHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockPistonHeadHandler::OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta +) { - Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ); - - // Get the base of the piston - NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(blockPos); - blockPos -= cBlockPistonHandler::MetadataToOffset(OldMeta); - - BLOCKTYPE Block = a_ChunkInterface.GetBlock(blockPos); - if ((Block == E_BLOCK_STICKY_PISTON) || (Block == E_BLOCK_PISTON)) + // Drop the base of the piston: + auto basePos = a_BlockPos - cBlockPistonHandler::MetadataToOffset(a_OldBlockMeta); + if (cChunkDef::IsValidHeight(basePos.y)) { - a_ChunkInterface.DigBlock(a_WorldInterface, blockPos.x, blockPos.y, blockPos.z); - if (a_Player.IsGameModeCreative()) - { - return; // No pickups if creative - } - - cItems Pickups; - Pickups.push_back(cItem(Block, 1)); - a_WorldInterface.SpawnItemPickups(Pickups, blockPos.x + 0.5, blockPos.y + 0.5, blockPos.z + 0.5); + a_ChunkInterface.DropBlockAsPickups(basePos); } } diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h index e604cd38e..c9e920f5b 100644 --- a/src/Blocks/BlockPiston.h +++ b/src/Blocks/BlockPiston.h @@ -2,22 +2,34 @@ #pragma once #include "BlockHandler.h" - #include +#include "Mixins.h" +#include "../Item.h" + + +// fwd: class cWorld; -class cBlockPistonHandler : - public cBlockHandler + + + +class cBlockPistonHandler: + public cClearMetaOnDrop { + using super = cClearMetaOnDrop; + public: - cBlockPistonHandler(BLOCKTYPE a_BlockType); - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override; + cBlockPistonHandler(BLOCKTYPE a_BlockType); - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override; + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override; virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, @@ -174,23 +186,24 @@ private: -class cBlockPistonHeadHandler : +class cBlockPistonHeadHandler: public cBlockHandler { - typedef cBlockHandler super; + using super = cBlockHandler; public: cBlockPistonHeadHandler(void); - virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override; - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // No pickups // Also with 1.7, the item forms of these technical blocks have been removed, so giving someone this will crash their client... + return {}; } } ; - - - - diff --git a/src/Blocks/BlockPlant.h b/src/Blocks/BlockPlant.h index bab34f798..02092fc38 100644 --- a/src/Blocks/BlockPlant.h +++ b/src/Blocks/BlockPlant.h @@ -1,25 +1,30 @@ -// BlockPlant.h - -// Base class for any growing block - +#pragma once +#include "BlockHandler.h" -#pragma once -#include "BlockHandler.h" -class cBlockPlant : public cBlockHandler +/** Base class for plants that use light values to decide whether to grow or not. */ +template +class cBlockPlant: + public cBlockHandler { - typedef cBlockHandler Super; - bool m_NeedLightToGrow; + using super = cBlockHandler; + public: - cBlockPlant(BLOCKTYPE a_BlockType, bool a_LightToGrow) - : Super(a_BlockType), m_NeedLightToGrow(a_LightToGrow){} + + cBlockPlant(BLOCKTYPE a_BlockType): + super(a_BlockType) + { + } + protected: + + /** The action the plant can take on an update. */ enum PlantAction { paDeath, @@ -27,6 +32,10 @@ protected: paStay }; + + + + /** Checks whether there is enough light for the plant to grow. If the plant doesn't require light to grow, then it returns paGrowth. If the plant requires light to grow and there is enough light, it returns paGrowth. @@ -37,34 +46,37 @@ protected: { // If the plant requires light to grow, check to see if there is enough light // Otherwise, return true - if (m_NeedLightToGrow) + if (!NeedsLightToGrow) { - NIBBLETYPE Blocklight = a_Chunk.GetBlockLight(a_RelX, a_RelY, a_RelZ); - NIBBLETYPE SkyLight = a_Chunk.GetSkyLight (a_RelX, a_RelY, a_RelZ); - NIBBLETYPE Light = a_Chunk.GetTimeAlteredLight(SkyLight); - - // If the amount of light provided by blocks is greater than the sky light, use it instead - if (Blocklight > Light) - { - Light = Blocklight; - } + return paGrowth; + } + NIBBLETYPE Blocklight = a_Chunk.GetBlockLight(a_RelX, a_RelY, a_RelZ); + NIBBLETYPE SkyLight = a_Chunk.GetSkyLight (a_RelX, a_RelY, a_RelZ); + NIBBLETYPE Light = a_Chunk.GetTimeAlteredLight(SkyLight); - // Based on light levels, decide between growth, stay and death: - if (Light > 8) - { - return paGrowth; - } - else if ((Blocklight < 9) && (SkyLight < 9)) - { - return paDeath; - } + // If the amount of light provided by blocks is greater than the sky light, use it instead + if (Blocklight > Light) + { + Light = Blocklight; + } - return paStay; + // Based on light levels, decide between growth, stay and death: + if (Light > 8) + { + return paGrowth; + } + else if ((Blocklight < 9) && (SkyLight < 9)) + { + return paDeath; } - return paGrowth; + return paStay; } + + + + /** Checks whether a plant can grow grow, based on what is returned from cBlockPlant::HasEnoughLight and a random check based on what is returned from cBlockPlant::GetGrowthChance. Can return three values. @@ -84,6 +96,10 @@ protected: return Action; } + + + + /** Generates a int value between 4 and 25 based on surrounding blocks that affect how quickly the plant grows. The higher the value, the less likely the plant is to grow */ virtual int GetGrowthChance(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) diff --git a/src/Blocks/BlockPluginInterface.h b/src/Blocks/BlockPluginInterface.h index d97927b36..087e86412 100644 --- a/src/Blocks/BlockPluginInterface.h +++ b/src/Blocks/BlockPluginInterface.h @@ -30,7 +30,6 @@ public: virtual ~cBlockPluginInterface() {} virtual bool CallHookBlockSpread(int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0; - virtual bool CallHookBlockToPickups(cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0; virtual bool CallHookPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual bool CallHookPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; }; diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 6cebcbd37..852a231b6 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -32,11 +32,20 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // No pickups + return {}; } + + + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { if (GetRandomProvider().RandBool(0.9995)) diff --git a/src/Blocks/BlockPressurePlate.h b/src/Blocks/BlockPressurePlate.h index 7fb7585f1..7067bd2e5 100644 --- a/src/Blocks/BlockPressurePlate.h +++ b/src/Blocks/BlockPressurePlate.h @@ -7,18 +7,15 @@ class cBlockPressurePlateHandler : - public cBlockHandler + public cClearMetaOnDrop { + using super = cClearMetaOnDrop; + public: - cBlockPressurePlateHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockPressurePlateHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - // Reset meta to zero - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override diff --git a/src/Blocks/BlockPumpkin.h b/src/Blocks/BlockPumpkin.h index 9cf3c895c..29834900f 100644 --- a/src/Blocks/BlockPumpkin.h +++ b/src/Blocks/BlockPumpkin.h @@ -1,7 +1,7 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index d9bb15913..6b9ddcdd5 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -17,13 +17,14 @@ enum ENUM_PURE class cBlockRailHandler : - public cBlockHandler + public cClearMetaOnDrop { - typedef cBlockHandler super; + using super = cClearMetaOnDrop; public: - cBlockRailHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockRailHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -46,51 +47,69 @@ public: ); } - virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + + + + + virtual void OnPlaced( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta + ) override { - super::OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); - - // Alert diagonal rails - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ + 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ - 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ + 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ - 1, BLOCK_FACE_NONE); + super::OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_BlockType, a_BlockMeta); + + // Alert diagonal rails: + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE); } - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override + + + + + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override { - super::OnDestroyed(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ); - - // Alert diagonal rails - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ + 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ - 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ + 1, BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ - 1, BLOCK_FACE_NONE); + super::OnBroken(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_OldBlockType, a_OldBlockMeta); + + // Alert diagonal rails: + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE); } - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override + + + + + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override { - Vector3i Pos(a_BlockX, a_BlockY, a_BlockZ); - auto Meta = a_ChunkInterface.GetBlockMeta(Pos); - auto NewMeta = FindMeta(a_ChunkInterface, Pos); - if (IsUnstable(a_ChunkInterface, Pos) && (Meta != NewMeta)) + auto meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); + auto newMeta = FindMeta(a_ChunkInterface, a_BlockPos); + if (IsUnstable(a_ChunkInterface, a_BlockPos) && (meta != newMeta)) { - a_ChunkInterface.FastSetBlock(Pos, m_BlockType, (m_BlockType == E_BLOCK_RAIL) ? NewMeta : NewMeta | (Meta & 0x08)); + a_ChunkInterface.FastSetBlock(a_BlockPos, m_BlockType, (m_BlockType == E_BLOCK_RAIL) ? newMeta : newMeta | (meta & 0x08)); } } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - super::ConvertToPickups(a_Pickups, 0); - } + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { diff --git a/src/Blocks/BlockRedstone.h b/src/Blocks/BlockRedstone.h index 225f1cc75..d01a40631 100644 --- a/src/Blocks/BlockRedstone.h +++ b/src/Blocks/BlockRedstone.h @@ -9,11 +9,14 @@ class cBlockRedstoneHandler : - public cBlockHandler + public cClearMetaOnDrop { + using super = cClearMetaOnDrop; + public: - cBlockRedstoneHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockRedstoneHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -43,12 +46,6 @@ public: return false; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to zero - a_Pickups.push_back(cItem(E_ITEM_REDSTONE_DUST, 1, 0)); - } - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockRedstoneLamp.h b/src/Blocks/BlockRedstoneLamp.h index 5ac98de87..576467c12 100644 --- a/src/Blocks/BlockRedstoneLamp.h +++ b/src/Blocks/BlockRedstoneLamp.h @@ -7,20 +7,29 @@ -class cBlockRedstoneLampHandler : +class cBlockRedstoneLampHandler: public cBlockHandler { public: - cBlockRedstoneLampHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + cBlockRedstoneLampHandler(BLOCKTYPE a_BlockType): + cBlockHandler(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_BLOCK_REDSTONE_LAMP_OFF, 1, 0)); + // Always drop the Off variant: + return(cItem(E_BLOCK_REDSTONE_LAMP_OFF, 1, 0)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 455ef1171..6e749bd57 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -2,19 +2,24 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "ChunkInterface.h" #include "BlockSlab.h" #include "../Chunk.h" -class cBlockRedstoneRepeaterHandler : - public cMetaRotator + + +class cBlockRedstoneRepeaterHandler: + public cClearMetaOnDrop> { + using super = cClearMetaOnDrop>; + public: - cBlockRedstoneRepeaterHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) + + cBlockRedstoneRepeaterHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -42,12 +47,6 @@ public: a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to zero - a_Pickups.push_back(cItem(E_ITEM_REDSTONE_REPEATER, 1, 0)); - } - virtual bool IsUseable(void) override { return true; diff --git a/src/Blocks/BlockRedstoneTorch.h b/src/Blocks/BlockRedstoneTorch.h index 11a42bf9f..3f065b1cb 100644 --- a/src/Blocks/BlockRedstoneTorch.h +++ b/src/Blocks/BlockRedstoneTorch.h @@ -10,18 +10,29 @@ class cBlockRedstoneTorchHandler : public cBlockTorchHandler { + using super = cBlockTorchHandler; + public: - cBlockRedstoneTorchHandler(BLOCKTYPE a_BlockType) - : cBlockTorchHandler(a_BlockType) + + cBlockRedstoneTorchHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // Always drop the ON torch, meta 0 - a_Pickups.push_back(cItem(E_BLOCK_REDSTONE_TORCH_ON, 1, 0)); + return cItem(E_BLOCK_REDSTONE_TORCH_ON, 1, 0); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockSapling.h b/src/Blocks/BlockSapling.h index 4133c5b80..f3cefd722 100644 --- a/src/Blocks/BlockSapling.h +++ b/src/Blocks/BlockSapling.h @@ -11,18 +11,29 @@ class cBlockSaplingHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockSaplingHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockSaplingHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // Only the first 2 bits contain the display information and the 4th bit is for the growth indicator, but, we use 0x07 for forward compatibility - a_Pickups.push_back(cItem(E_BLOCK_SAPLING, 1, a_BlockMeta & 0x07)); + // The low 3 bits store the sapling type; bit 0x08 is the growth timer (not used in pickups) + return cItem(m_BlockType, 1, a_BlockMeta & 0x07); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)); diff --git a/src/Blocks/BlockSeaLantern.h b/src/Blocks/BlockSeaLantern.h index 691e7de10..0d7c62b94 100644 --- a/src/Blocks/BlockSeaLantern.h +++ b/src/Blocks/BlockSeaLantern.h @@ -10,17 +10,24 @@ class cBlockSeaLanternHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockSeaLanternHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockSeaLanternHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { // Reset meta to 0 - a_Pickups.emplace_back(E_ITEM_PRISMARINE_CRYSTALS, GetRandomProvider().RandInt(2, 3), 0); + // TODO: Handle the Fortune enchantment + return cItem(E_ITEM_PRISMARINE_CRYSTALS, GetRandomProvider().RandInt(2, 3), 0); } } ; diff --git a/src/Blocks/BlockSideways.h b/src/Blocks/BlockSideways.h index 5bc7874b4..017dc30e0 100644 --- a/src/Blocks/BlockSideways.h +++ b/src/Blocks/BlockSideways.h @@ -7,15 +7,25 @@ -class cBlockSidewaysHandler : public cBlockHandler +/** Handler for blocks that have 3 orientations (hay bale, log), specified by the upper 2 bits in meta. +Handles setting the correct orientation on placement. +Additionally supports the metadata specifying block sub-type in its lower 2 bits. */ +class cBlockSidewaysHandler: + public cBlockHandler { + using super = cBlockHandler; + public: - cBlockSidewaysHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockSidewaysHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -30,12 +40,19 @@ public: } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.Add(m_BlockType, 1, a_BlockMeta & 0x3); // Reset meta + // Reset the orientation part of meta, keep the sub-type part of meta + return cItem(m_BlockType, 1, a_BlockMeta & 0x03); } + + + inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_Meta) { switch (a_BlockFace) diff --git a/src/Blocks/BlockSignPost.h b/src/Blocks/BlockSignPost.h index fe170a675..b5ccfe5d7 100644 --- a/src/Blocks/BlockSignPost.h +++ b/src/Blocks/BlockSignPost.h @@ -8,22 +8,30 @@ -class cBlockSignPostHandler : +class cBlockSignPostHandler: public cBlockHandler { - typedef cBlockHandler super; + using super = cBlockHandler; public: - cBlockSignPostHandler(BLOCKTYPE a_BlockType) : + + cBlockSignPostHandler(BLOCKTYPE a_BlockType): super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_SIGN, 1, 0)); + return cItem(E_ITEM_SIGN, 1, 0); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index 46e0a8244..a136cd6e0 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -18,17 +18,29 @@ class cBlockSlabHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockSlabHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockSlabHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(m_BlockType, 1, a_BlockMeta & 0x7)); + // Reset the "top half" flag: + return cItem(m_BlockType, 1, a_BlockMeta & 0x07); } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -84,6 +96,10 @@ public: return true; } + + + + /** Returns true if the specified blocktype is one of the slabs handled by this handler */ static bool IsAnySlabType(BLOCKTYPE a_BlockType) { @@ -95,6 +111,10 @@ public: ); } + + + + virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override { if ((a_BlockFace == BLOCK_FACE_NONE) || (a_Player.GetEquippedItem().m_ItemType != static_cast(m_BlockType))) @@ -106,6 +126,10 @@ public: a_Player.GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); } + + + + /** Converts the single-slab blocktype to its equivalent double-slab blocktype */ static BLOCKTYPE GetDoubleSlabType(BLOCKTYPE a_SingleSlabBlockType) { @@ -120,12 +144,20 @@ public: return E_BLOCK_AIR; } + + + + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override { // Toggle the 4th bit - up / down: return (a_Meta ^ 0x08); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { a_Meta &= 0x7; @@ -184,6 +216,10 @@ public: } } + + + + virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) override { if (a_BlockMeta & 0x8) // top half @@ -201,31 +237,46 @@ public: class cBlockDoubleSlabHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockDoubleSlabHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockDoubleSlabHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { BLOCKTYPE Block = GetSingleSlabType(m_BlockType); - a_Pickups.push_back(cItem(Block, 2, a_BlockMeta & 0x7)); + return cItem(Block, 2, a_BlockMeta & 0x7); } + + + + inline static BLOCKTYPE GetSingleSlabType(BLOCKTYPE a_BlockType) { switch (a_BlockType) { - case E_BLOCK_DOUBLE_STONE_SLAB: return E_BLOCK_STONE_SLAB; - case E_BLOCK_DOUBLE_WOODEN_SLAB: return E_BLOCK_WOODEN_SLAB; + case E_BLOCK_DOUBLE_STONE_SLAB: return E_BLOCK_STONE_SLAB; + case E_BLOCK_DOUBLE_WOODEN_SLAB: return E_BLOCK_WOODEN_SLAB; case E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB: return E_BLOCK_RED_SANDSTONE_SLAB; - case E_BLOCK_PURPUR_DOUBLE_SLAB: return E_BLOCK_PURPUR_SLAB; + case E_BLOCK_PURPUR_DOUBLE_SLAB: return E_BLOCK_PURPUR_SLAB; } ASSERT(!"Unhandled double slab type!"); return a_BlockType; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { // For doule slabs, the meta values are the same. Only the meaning of the 4th bit changes, but that's ignored in the below handler diff --git a/src/Blocks/BlockSlime.h b/src/Blocks/BlockSlime.h index 8302c0bf4..bbf28fa16 100644 --- a/src/Blocks/BlockSlime.h +++ b/src/Blocks/BlockSlime.h @@ -6,20 +6,22 @@ -class cBlockSlimeHandler : - public cBlockHandler +class cBlockSlimeHandler: + public cClearMetaOnDrop { + using super = cClearMetaOnDrop; + public: - cBlockSlimeHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockSlimeHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockSnow.h b/src/Blocks/BlockSnow.h index 8e4083b0e..4972e61fe 100644 --- a/src/Blocks/BlockSnow.h +++ b/src/Blocks/BlockSnow.h @@ -70,11 +70,33 @@ public: return false; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_SNOWBALL, 1, 0)); + // No drop unless dug up with a shovel + if ((a_Tool == nullptr) || !ItemCategory::IsShovel(a_Tool->m_ItemType)) + { + return {}; + } + + if (ToolHasSilkTouch(a_Tool)) + { + return cItem(m_BlockType, 1, 0); + } + else + { + // Drop as many snowballs as there were "layers" of snow: + return cItem(E_ITEM_SNOWBALL, 1 + (a_BlockMeta & 0x07), 0); + } } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY > 0) diff --git a/src/Blocks/BlockSponge.h b/src/Blocks/BlockSponge.h index 24bc25388..7df5d69ff 100644 --- a/src/Blocks/BlockSponge.h +++ b/src/Blocks/BlockSponge.h @@ -10,9 +10,12 @@ class cBlockSpongeHandler : public cBlockHandler { + using super = cBlockHandler; + public: + cBlockSpongeHandler(BLOCKTYPE a_BlockType): - cBlockHandler(a_BlockType) + super(a_BlockType) { } @@ -20,13 +23,17 @@ public: - virtual void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override + virtual void Check( + cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk + ) override { - if (GetSoaked(Vector3i(a_RelX, a_RelY, a_RelZ), a_Chunk)) + if (GetSoaked(a_RelPos, a_Chunk)) { return; } - cBlockHandler::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk); + super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk); } @@ -115,7 +122,7 @@ public: } Seeds.pop(); } - a_Chunk.SetBlock(a_Rel.x, a_Rel.y, a_Rel.z, E_BLOCK_SPONGE, E_META_SPONGE_WET); + a_Chunk.SetBlock(a_Rel, E_BLOCK_SPONGE, E_META_SPONGE_WET); return true; } diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index 6cd05df19..4263a5b13 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -2,17 +2,20 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockStairsHandler : - public cMetaRotator + public cClearMetaOnDrop> { + using super = cClearMetaOnDrop>; + public: - cBlockStairsHandler(BLOCKTYPE a_BlockType) : - cMetaRotator(a_BlockType) + + cBlockStairsHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -53,12 +56,6 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to zero - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } - static NIBBLETYPE RotationToMetaData(double a_Rotation) { a_Rotation += 90 + 45; // So its not aligned with axis diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h index 659df558f..132526b93 100644 --- a/src/Blocks/BlockStems.h +++ b/src/Blocks/BlockStems.h @@ -8,21 +8,31 @@ class cBlockStemsHandler : - public cBlockPlant + public cBlockPlant { - typedef cBlockPlant Super; + using super = cBlockPlant; + public: - cBlockStemsHandler(BLOCKTYPE a_BlockType) - : Super(a_BlockType, true) + + cBlockStemsHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - short ItemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS; - a_Pickups.push_back(cItem(ItemType, 1, 0)); + auto itemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS; + return cItem(itemType, 1, 0); } + + + + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { auto Action = CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); diff --git a/src/Blocks/BlockStone.h b/src/Blocks/BlockStone.h index e1522a2a2..f691d4452 100644 --- a/src/Blocks/BlockStone.h +++ b/src/Blocks/BlockStone.h @@ -6,25 +6,39 @@ -class cBlockStoneHandler : +class cBlockStoneHandler: public cBlockHandler { + using super = cBlockHandler; + public: - cBlockStoneHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockStoneHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - if (a_BlockMeta == E_META_STONE_STONE) + // Convert stone to cobblestone, unless using silk-touch: + if ( + (a_BlockMeta == E_META_STONE_STONE) && + !ToolHasSilkTouch(a_Tool) + ) { - a_Pickups.push_back(cItem(E_BLOCK_COBBLESTONE, 1, 0)); - return; + return cItem(E_BLOCK_COBBLESTONE, 1, 0); } - a_Pickups.push_back(cItem(E_BLOCK_STONE, 1, a_BlockMeta)); + return cItem(m_BlockType, 1, a_BlockMeta); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockSugarcane.h b/src/Blocks/BlockSugarcane.h index 1322987f5..622f82138 100644 --- a/src/Blocks/BlockSugarcane.h +++ b/src/Blocks/BlockSugarcane.h @@ -8,20 +8,30 @@ class cBlockSugarcaneHandler : - public cBlockPlant + public cBlockPlant { - typedef cBlockPlant Super; + using super = cBlockPlant; + public: - cBlockSugarcaneHandler(BLOCKTYPE a_BlockType) - : Super(a_BlockType, false) + + cBlockSugarcaneHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_SUGARCANE, 1, 0)); + return cItem(E_ITEM_SUGARCANE, 1, 0); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) @@ -86,6 +96,7 @@ public: return 7; } + protected: virtual PlantAction CanGrow(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override @@ -93,7 +104,7 @@ protected: auto Action = paStay; if (((a_RelY + 1) < cChunkDef::Height) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR)) { - Action = Super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); + Action = super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); } return Action; diff --git a/src/Blocks/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h index aa369f0cf..c4b7194b5 100644 --- a/src/Blocks/BlockTallGrass.h +++ b/src/Blocks/BlockTallGrass.h @@ -8,64 +8,51 @@ -class cBlockTallGrassHandler : +class cBlockTallGrassHandler: public cBlockHandler { - typedef cBlockHandler super; + using super = cBlockHandler; + public: - cBlockTallGrassHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockTallGrassHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // Drop seeds, sometimes - if (GetRandomProvider().RandBool(0.125)) + // If using shears, drop self: + if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS)) { - a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1, 0)); + return cItem(m_BlockType, 1, a_BlockMeta); } - } - virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override - { - if (a_CanDrop && (a_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_ItemType == E_ITEM_SHEARS)) + // Drop seeds, sometimes: + if (GetRandomProvider().RandBool(0.125)) { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); - cItems Drops; - Drops.Add(m_BlockType, 1, Meta); - - // Allow plugins to modify the pickups: - a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Drops); - - // Spawn the pickups: - if (!Drops.empty()) - { - auto & r1 = GetRandomProvider(); - - // Mid-block position first - double MicroX, MicroY, MicroZ; - MicroX = a_BlockX + 0.5; - MicroY = a_BlockY + 0.5; - MicroZ = a_BlockZ + 0.5; - - // Add random offset second - MicroX += r1.RandReal(-0.5, 0.5); - MicroZ += r1.RandReal(-0.5, 0.5); - - a_WorldInterface.SpawnItemPickups(Drops, MicroX, MicroY, MicroZ); - } - return; + return cItem(E_ITEM_SEEDS); } - - super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop); + return {}; } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { if (a_RelY <= 0) @@ -77,6 +64,10 @@ public: return IsBlockTypeOfDirt(BelowBlock); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index 8f95fa344..c5b06b18a 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -3,17 +3,20 @@ #include "BlockHandler.h" #include "../Chunk.h" #include "ChunkInterface.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockTorchHandler : - public cMetaRotator + public cClearMetaOnDrop> { + using super = cClearMetaOnDrop>; + public: - cBlockTorchHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) + + cBlockTorchHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } @@ -182,12 +185,6 @@ public: return CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face); } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Always drop meta = 0 - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); - } - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h index 8fdae6028..e5361706c 100644 --- a/src/Blocks/BlockTrapdoor.h +++ b/src/Blocks/BlockTrapdoor.h @@ -2,32 +2,36 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" #include "../EffectID.h" class cBlockTrapdoorHandler : - public cMetaRotator + public cClearMetaOnDrop> { + using super = cClearMetaOnDrop>; + public: - cBlockTrapdoorHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) - { - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + cBlockTrapdoorHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { - // Reset meta to zero - a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } + + + virtual bool IsUseable(void) override { return true; } + + + + virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override { if (m_BlockType == E_BLOCK_IRON_TRAPDOOR) diff --git a/src/Blocks/BlockTripwire.h b/src/Blocks/BlockTripwire.h index 19a9c4384..dbf21e318 100644 --- a/src/Blocks/BlockTripwire.h +++ b/src/Blocks/BlockTripwire.h @@ -10,17 +10,28 @@ class cBlockTripwireHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockTripwireHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockTripwireHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_STRING, 1, 0)); + return cItem(E_ITEM_STRING, 1, 0); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockTripwireHook.h b/src/Blocks/BlockTripwireHook.h index d544fff86..8537f99ce 100644 --- a/src/Blocks/BlockTripwireHook.h +++ b/src/Blocks/BlockTripwireHook.h @@ -1,21 +1,28 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotator.h" +#include "Mixins.h" class cBlockTripwireHookHandler : - public cMetaRotator + public cMetaRotator, 0x03, 0x02, 0x03, 0x00, 0x01> { + using super = cMetaRotator, 0x03, 0x02, 0x03, 0x00, 0x01>; + public: - cBlockTripwireHookHandler(BLOCKTYPE a_BlockType) - : cMetaRotator(a_BlockType) + + cBlockTripwireHookHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -29,6 +36,10 @@ public: return true; } + + + + inline static NIBBLETYPE DirectionToMetadata(eBlockFace a_Direction) { switch (a_Direction) @@ -48,6 +59,10 @@ public: UNREACHABLE("Unsupported block face"); } + + + + inline static eBlockFace MetadataToDirection(NIBBLETYPE a_Meta) { switch (a_Meta & 0x03) @@ -60,11 +75,9 @@ public: } } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - // Reset meta to zero - a_Pickups.push_back(cItem(E_BLOCK_TRIPWIRE_HOOK, 1, 0)); - } + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { @@ -78,6 +91,10 @@ public: return ((a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index f5716c58a..53224a5db 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -9,12 +9,19 @@ class cBlockVineHandler : public cBlockHandler { + using super = cBlockHandler; + public: - cBlockVineHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockVineHandler(BLOCKTYPE a_BlockType): + super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -38,12 +45,24 @@ public: return true; } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - // Reset meta to zero - a_Pickups.push_back(cItem(E_BLOCK_VINES, 1, 0)); + // Only drops self when using shears, otherwise drops nothing: + if ((a_Tool == nullptr) || (a_Tool->m_ItemType != E_ITEM_SHEARS)) + { + return {}; + } + return cItem(E_BLOCK_VINES, 1, 0); } + + + + static NIBBLETYPE DirectionToMetaData(char a_BlockFace) { switch (a_BlockFace) @@ -56,6 +75,10 @@ public: } } + + + + static char MetaDataToDirection(NIBBLETYPE a_MetaData) { switch (a_MetaData) @@ -68,6 +91,10 @@ public: } } + + + + /** Returns true if the specified block type is good for vines to attach to */ static bool IsBlockAttachable(BLOCKTYPE a_BlockType) { @@ -94,8 +121,12 @@ public: } } + + + + /** Returns the meta that has the maximum allowable sides of the vine, given the surroundings */ - NIBBLETYPE GetMaxMeta(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) + NIBBLETYPE GetMaxMeta(cChunk & a_Chunk, Vector3i a_RelPos) { static const struct { @@ -113,8 +144,9 @@ public: { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; + auto checkPos = a_RelPos.addedXZ(Coord.x, Coord.z); if ( - a_Chunk.UnboundedRelGetBlock(a_RelX + Coord.x, a_RelY, a_RelZ + Coord.z, BlockType, BlockMeta) && + a_Chunk.UnboundedRelGetBlock(checkPos.x, checkPos.y, checkPos.z, BlockType, BlockMeta) && IsBlockAttachable(BlockType) ) { @@ -124,55 +156,71 @@ public: return res; } - void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override + + + + + virtual void Check( + cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, + Vector3i a_RelPos, + cChunk & a_Chunk + ) override { - NIBBLETYPE CurMeta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); - NIBBLETYPE MaxMeta = GetMaxMeta(a_Chunk, a_RelX, a_RelY, a_RelZ); + NIBBLETYPE CurMeta = a_Chunk.GetMeta(a_RelPos); + NIBBLETYPE MaxMeta = GetMaxMeta(a_Chunk, a_RelPos); // Check if vine above us, add its meta to MaxMeta - if ((a_RelY < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == m_BlockType)) + if ((a_RelPos.y < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_RelPos.addedY(1)) == m_BlockType)) { - MaxMeta |= a_Chunk.GetMeta(a_RelX, a_RelY + 1, a_RelZ); + MaxMeta |= a_Chunk.GetMeta(a_RelPos.addedY(1)); } NIBBLETYPE Common = CurMeta & MaxMeta; // Neighbors that we have and are legal if (Common != CurMeta) { // There is a neighbor missing, need to update the meta or even destroy the block - bool HasTop = (a_RelY < cChunkDef::Height - 1) && IsBlockAttachable(a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ)); + bool HasTop = (a_RelPos.y < cChunkDef::Height - 1) && IsBlockAttachable(a_Chunk.GetBlock(a_RelPos.addedY(1))); if ((Common == 0) && !HasTop) { // The vine just lost all its support, destroy the block: if (DoesDropOnUnsuitable()) { - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ); + a_ChunkInterface.DropBlockAsPickups(a_Chunk.RelativeToAbsolute(a_RelPos)); } - a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); + a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0); return; } - a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, Common); + a_Chunk.SetBlock(a_RelPos, m_BlockType, Common); } else { - // Wake up the simulators for this block: - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, &a_Chunk); + auto absPos = a_Chunk.RelativeToAbsolute(a_RelPos); + a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(absPos, &a_Chunk); } } + + + + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { return true; } + + + + virtual bool DoesDropOnUnsuitable(void) override { return false; } + + + + virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { UNUSED(a_ChunkInterface); @@ -196,34 +244,53 @@ public: } } + + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override { return ((a_Meta >> 1) | (a_Meta << 3)) & 0x0f; // Rotate bits to the right } + + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override { return ((a_Meta << 1) | (a_Meta >> 3)) & 0x0f; // Rotate bits to the left } + + + + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override { // Bits 2 and 4 stay, bits 1 and 3 swap return static_cast((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2)); } + + + + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override { // Bits 1 and 3 stay, bits 2 and 4 swap return static_cast((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2)); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); return 7; } - } ; diff --git a/src/Blocks/BlockWallSign.h b/src/Blocks/BlockWallSign.h index 37ca2afae..3759b4db6 100644 --- a/src/Blocks/BlockWallSign.h +++ b/src/Blocks/BlockWallSign.h @@ -8,22 +8,31 @@ -class cBlockWallSignHandler : +class cBlockWallSignHandler: public cBlockHandler { - typedef cBlockHandler super; + using super = cBlockHandler; public: - cBlockWallSignHandler(BLOCKTYPE a_BlockType) : + + cBlockWallSignHandler(BLOCKTYPE a_BlockType): super(a_BlockType) { } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - a_Pickups.push_back(cItem(E_ITEM_SIGN, 1, 0)); + return cItem(E_ITEM_SIGN, 1, 0); } + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { int BlockX = (a_Chunk.GetPosX() * cChunkDef::Width) + a_RelX; @@ -34,6 +43,10 @@ public: return ((Type == E_BLOCK_WALLSIGN) || (Type == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(Type)); } + + + + static void GetBlockCoordsBehindTheSign(NIBBLETYPE a_BlockMeta, int & a_BlockX, int & a_BlockZ) { switch (a_BlockMeta) @@ -46,14 +59,18 @@ public: } } + + + + static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction) { switch (a_Direction) { - case BLOCK_FACE_ZM: return 0x2; - case BLOCK_FACE_ZP: return 0x3; - case BLOCK_FACE_XM: return 0x4; - case BLOCK_FACE_XP: return 0x5; + case BLOCK_FACE_ZM: return 0x02; + case BLOCK_FACE_ZP: return 0x03; + case BLOCK_FACE_XM: return 0x04; + case BLOCK_FACE_XP: return 0x05; case BLOCK_FACE_NONE: case BLOCK_FACE_YP: case BLOCK_FACE_YM: @@ -61,9 +78,13 @@ public: break; } } - return 0x2; + return 0x02; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index 4420871ae..5a637f69c 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -97,9 +97,8 @@ SET (HDRS BlockWorkbench.h BroadcastInterface.h ChunkInterface.h - ClearMetaOnDrop.h GetHandlerCompileTimeTemplate.h - MetaRotator.h + Mixins.h WorldInterface.h ) diff --git a/src/Blocks/ChunkInterface.cpp b/src/Blocks/ChunkInterface.cpp index 28dd1ac36..4d6301925 100644 --- a/src/Blocks/ChunkInterface.cpp +++ b/src/Blocks/ChunkInterface.cpp @@ -5,6 +5,7 @@ #include "BlockHandler.h" #include "WorldInterface.h" #include "../ChunkMap.h" +#include "../World.h" @@ -30,19 +31,16 @@ NIBBLETYPE cChunkInterface::GetBlockMeta(Vector3i a_Pos) bool cChunkInterface::GetBlockTypeMeta(Vector3i a_Pos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) { - return m_ChunkMap->GetBlockTypeMeta(a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta); + return m_ChunkMap->GetBlockTypeMeta(a_Pos, a_BlockType, a_BlockMeta); } -/** Sets the block at the specified coords to the specified value. -Full processing, incl. updating neighbors, is performed. -*/ -void cChunkInterface::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +void cChunkInterface::SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - m_ChunkMap->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); + m_ChunkMap->SetBlock(a_BlockPos, a_BlockType, a_BlockMeta); } @@ -106,10 +104,26 @@ bool cChunkInterface::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a -bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, int a_X, int a_Y, int a_Z) +bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos) { - cBlockHandler * Handler = cBlockInfo::GetHandler(GetBlock({a_X, a_Y, a_Z})); - Handler->OnDestroyed(*this, a_WorldInterface, a_X, a_Y, a_Z); - return m_ChunkMap->DigBlock(a_X, a_Y, a_Z); + BLOCKTYPE blockType; + NIBBLETYPE blockMeta; + GetBlockTypeMeta(a_BlockPos, blockType, blockMeta); + auto handler = cBlockInfo::GetHandler(blockType); + handler->OnBreaking(*this, a_WorldInterface, a_BlockPos); + if (!m_ChunkMap->DigBlock(a_BlockPos)) + { + return false; + } + handler->OnBroken(*this, a_WorldInterface, a_BlockPos, blockType, blockMeta); + return true; } + + + + +void cChunkInterface::DropBlockAsPickups(Vector3i a_BlockPos, const cEntity * a_Digger, const cItem * a_Tool) +{ + m_ChunkMap->GetWorld()->DropBlockAsPickups(a_BlockPos, a_Digger, a_Tool); +} diff --git a/src/Blocks/ChunkInterface.h b/src/Blocks/ChunkInterface.h index 120ccf455..6bf450748 100644 --- a/src/Blocks/ChunkInterface.h +++ b/src/Blocks/ChunkInterface.h @@ -22,9 +22,16 @@ public: bool GetBlockTypeMeta(Vector3i a_Pos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); /** Sets the block at the specified coords to the specified value. - Full processing, incl. updating neighbors, is performed. - */ - void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + Full processing, incl. updating neighbors, is performed. */ + void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + + /** OBSOLETE, use the Vector3i-based overload instead. + Sets the block at the specified coords to the specified value. + Full processing, incl. updating neighbors, is performed. */ + void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) + { + return SetBlock({a_BlockX, a_BlockY, a_BlockZ}, a_BlockType, a_BlockMeta); + } void SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData, bool a_ShouldMarkDirty = true, bool a_ShouldInformClient = true); @@ -44,7 +51,11 @@ public: virtual bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes) override; - bool DigBlock(cWorldInterface & a_WorldInterface, int a_X, int a_Y, int a_Z); + bool DigBlock(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos); + + /** Digs the block and spawns the relevant pickups, as if a_Digger used a_Tool to dig the block. */ + void DropBlockAsPickups(Vector3i a_BlockPos, const cEntity * a_Digger = nullptr, const cItem * a_Tool = nullptr); + private: cChunkMap * m_ChunkMap; diff --git a/src/Blocks/ClearMetaOnDrop.h b/src/Blocks/ClearMetaOnDrop.h deleted file mode 100644 index 3a375e121..000000000 --- a/src/Blocks/ClearMetaOnDrop.h +++ /dev/null @@ -1,24 +0,0 @@ - -#pragma once - -// mixin for use to clear meta values when the block is converted to a pickup - -// Usage: inherit from this class, passing the parent class as the parameter Base -// For example to use in class Foo which should inherit Bar use -// class Foo : public cClearMetaOnDrop; - -template -class cClearMetaOnDrop : public Base -{ -public: - - cClearMetaOnDrop(BLOCKTYPE a_BlockType) : - Base(a_BlockType) - {} - - virtual ~cClearMetaOnDrop() override {} - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - a_Pickups.push_back(cItem(this->m_BlockType)); - } -}; diff --git a/src/Blocks/MetaRotator.h b/src/Blocks/MetaRotator.h deleted file mode 100644 index 61cd81ddc..000000000 --- a/src/Blocks/MetaRotator.h +++ /dev/null @@ -1,120 +0,0 @@ -// MetaRotator.h - -// Provides a mixin for rotations and reflections - -#pragma once - -// MSVC generates warnings for the templated AssertIfNotMatched parameter conditions, so disable it: -#ifdef _MSC_VER - #pragma warning(disable: 4127) // Conditional expression is constant -#endif - - - - - -/* -Provides a mixin for rotations and reflections following the standard pattern of apply mask then use case. - -Usage: -Inherit from this class providing your base class as Base, the BitMask for the direction bits in bitmask and the masked value for the directions in North, East, South, West. There is also an aptional parameter AssertIfNotMatched. Set this if it is invalid for a block to exist in any other state. -*/ - -template -class cMetaRotator : public Base -{ -public: - - cMetaRotator(BLOCKTYPE a_BlockType) : - Base(a_BlockType) - {} - - virtual ~cMetaRotator() override {} - - virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override; - virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override; - virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override; - virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override; -}; - - - - - -template -NIBBLETYPE cMetaRotator::MetaRotateCW(NIBBLETYPE a_Meta) -{ - NIBBLETYPE OtherMeta = a_Meta & (~BitMask); - switch (a_Meta & BitMask) - { - case South: return West | OtherMeta; - case West: return North | OtherMeta; - case North: return East | OtherMeta; - case East: return South | OtherMeta; - } - if (AssertIfNotMatched) - { - ASSERT(!"Invalid Meta value"); - } - return a_Meta; -} - - - - - -template -NIBBLETYPE cMetaRotator::MetaRotateCCW(NIBBLETYPE a_Meta) -{ - NIBBLETYPE OtherMeta = a_Meta & (~BitMask); - switch (a_Meta & BitMask) - { - case South: return East | OtherMeta; - case East: return North | OtherMeta; - case North: return West | OtherMeta; - case West: return South | OtherMeta; - } - if (AssertIfNotMatched) - { - ASSERT(!"Invalid Meta value"); - } - return a_Meta; -} - - - - - -template -NIBBLETYPE cMetaRotator::MetaMirrorXY(NIBBLETYPE a_Meta) -{ - NIBBLETYPE OtherMeta = a_Meta & (~BitMask); - switch (a_Meta & BitMask) - { - case South: return North | OtherMeta; - case North: return South | OtherMeta; - } - // Not Facing North or South; No change. - return a_Meta; -} - - - - - -template -NIBBLETYPE cMetaRotator::MetaMirrorYZ(NIBBLETYPE a_Meta) -{ - NIBBLETYPE OtherMeta = a_Meta & (~BitMask); - switch (a_Meta & BitMask) - { - case West: return East | OtherMeta; - case East: return West | OtherMeta; - } - // Not Facing East or West; No change. - return a_Meta; -} - - - - diff --git a/src/Blocks/Mixins.h b/src/Blocks/Mixins.h new file mode 100644 index 000000000..a65fe7b06 --- /dev/null +++ b/src/Blocks/Mixins.h @@ -0,0 +1,166 @@ +// Mixins.h + +// Provides various mixins for easier cBlockHandler descendant implementations + +/* The general use case is to derive a handler from these mixins, providing a suitable base to them: +class cBlockAir: public cBlockWithNoDrops; +class cBlockLadder: public cMetaRotator +*/ + +#pragma once + +#include "../Item.h" + + + + + +// MSVC generates warnings for the templated AssertIfNotMatched parameter conditions, so disable it: +#ifdef _MSC_VER + #pragma warning(disable: 4127) // Conditional expression is constant +#endif + + + + + +template +class cBlockWithNoDrops: + public Base +{ +public: + + cBlockWithNoDrops(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override + { + // Don't drop anything: + return {}; + } +}; + + + + + +/** Mixin to clear the block's meta value when converting to a pickup. */ +template +class cClearMetaOnDrop: + public Base +{ +public: + + cClearMetaOnDrop(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + + + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override + { + // Reset the meta to zero: + return cItem(this->m_BlockType); + } +}; + + + + + +/** Mixin for rotations and reflections following the standard pattern of "apply mask, then use a switch". +Inherit from this class providing your base class as Base, the BitMask for the direction bits in bitmask and the masked value for the directions in North, East, South, West. +There is also an aptional parameter AssertIfNotMatched, set this if it is invalid for a block to exist in any other state. */ +template +class cMetaRotator: + public Base +{ +public: + + cMetaRotator(BLOCKTYPE a_BlockType): + Base(a_BlockType) + {} + + + + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override + { + NIBBLETYPE OtherMeta = a_Meta & (~BitMask); + switch (a_Meta & BitMask) + { + case South: return East | OtherMeta; + case East: return North | OtherMeta; + case North: return West | OtherMeta; + case West: return South | OtherMeta; + } + if (AssertIfNotMatched) + { + ASSERT(!"Invalid Meta value"); + } + return a_Meta; + } + + + + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override + { + NIBBLETYPE OtherMeta = a_Meta & (~BitMask); + switch (a_Meta & BitMask) + { + case South: return West | OtherMeta; + case West: return North | OtherMeta; + case North: return East | OtherMeta; + case East: return South | OtherMeta; + } + if (AssertIfNotMatched) + { + ASSERT(!"Invalid Meta value"); + } + return a_Meta; + } + + + + + + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override + { + NIBBLETYPE OtherMeta = a_Meta & (~BitMask); + switch (a_Meta & BitMask) + { + case South: return North | OtherMeta; + case North: return South | OtherMeta; + } + // Not Facing North or South; No change. + return a_Meta; + } + + + + + + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override + { + NIBBLETYPE OtherMeta = a_Meta & (~BitMask); + switch (a_Meta & BitMask) + { + case West: return East | OtherMeta; + case East: return West | OtherMeta; + } + // Not Facing East or West; No change. + return a_Meta; + } +}; diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index da9075fb4..b4dcfa4a9 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -55,7 +55,7 @@ public: /** Spawns experience orbs of the specified total value at the given location. The orbs' values are split according to regular Minecraft rules. Returns an vector of UniqueID of all the orbs. */ - virtual std::vector SpawnSplitExperienceOrbs(double a_X, double a_Y, double a_Z, int a_Reward) = 0; + virtual std::vector SpawnSplitExperienceOrbs(Vector3d a_Pos, int a_Reward) = 0; /** Sends the block on those coords to the player */ virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer & a_Player) = 0; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 34ec80b34..a84bbd9b7 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -821,7 +821,7 @@ void cChunk::CheckBlocks() Vector3i Pos = (*itr); cBlockHandler * Handler = BlockHandler(GetBlock(Pos)); - Handler->Check(ChunkInterface, PluginInterface, Pos.x, Pos.y, Pos.z, *this); + Handler->Check(ChunkInterface, PluginInterface, Pos, *this); } // for itr - ToTickBlocks[] } @@ -943,11 +943,11 @@ void cChunk::ApplyWeatherToTop() } else if (cBlockInfo::IsSnowable(TopBlock) && (Height < cChunkDef::Height - 1)) { - SetBlock(X, Height + 1, Z, E_BLOCK_SNOW, 0); + SetBlock({X, Height + 1, Z}, E_BLOCK_SNOW, 0); } else if (IsBlockWater(TopBlock) && (TopMeta == 0)) { - SetBlock(X, Height, Z, E_BLOCK_ICE, 0); + SetBlock({X, Height, Z}, E_BLOCK_ICE, 0); } else if ( (m_World->IsDeepSnowEnabled()) && @@ -959,7 +959,7 @@ void cChunk::ApplyWeatherToTop() ) ) { - SetBlock(X, Height, Z, E_BLOCK_SNOW, 0); + SetBlock({X, Height, Z}, E_BLOCK_SNOW, 0); } } @@ -967,6 +967,23 @@ void cChunk::ApplyWeatherToTop() +cItems cChunk::PickupsFromBlock(Vector3i a_RelPos, const cEntity * a_Digger, const cItem * a_Tool) +{ + BLOCKTYPE blockType; + NIBBLETYPE blockMeta; + GetBlockTypeMeta(a_RelPos, blockType, blockMeta); + auto blockHandler = cBlockInfo::GetHandler(blockType); + auto blockEntity = GetBlockEntityRel(a_RelPos); + auto pickups = blockHandler->ConvertToPickups(blockMeta, blockEntity, a_Digger, a_Tool); + auto absPos = RelativeToAbsolute(a_RelPos); + cRoot::Get()->GetPluginManager()->CallHookBlockToPickups(*m_World, absPos, blockType, blockMeta, blockEntity, a_Digger, a_Tool, pickups); + return pickups; +} + + + + + bool cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType) { auto & Random = GetRandomProvider(); @@ -1047,9 +1064,9 @@ bool cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl Meta ); VERIFY(UnboundedRelFastSetBlock(a_RelX + x, a_RelY, a_RelZ + z, ProduceType, Meta)); - auto Absolute = RelativeToAbsolute(Vector3i{a_RelX + x, a_RelY, a_RelZ + z}); + auto absolute = RelativeToAbsolute(Vector3i{a_RelX + x, a_RelY, a_RelZ + z}); cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap()); - cBlockHandler::NeighborChanged(ChunkInterface, Absolute.x, Absolute.y - 1, Absolute.z, BLOCK_FACE_YP); + cBlockHandler::NeighborChanged(ChunkInterface, absolute.addedY(-1), BLOCK_FACE_YP); break; } } @@ -1154,21 +1171,7 @@ int cChunk::GrowCactus(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks) ) { // Remove the cactus - GetWorld()->DigBlock(a_RelX + GetPosX() * cChunkDef::Width, Top + i, a_RelZ + GetPosZ() * cChunkDef::Width); - - // Drop the cactus on the other side of the blocking block - cBlockHandler * Handler = BlockHandler(E_BLOCK_CACTUS); - cChunkInterface ChunkInterface(GetWorld()->GetChunkMap()); - cBlockInServerPluginInterface PluginInterface(*GetWorld()); - Handler->DropBlock( - ChunkInterface, - *GetWorld(), - PluginInterface, - nullptr, - a_RelX + GetPosX() * cChunkDef::Width - Coord.x, - Top + i, - a_RelZ + GetPosZ() * cChunkDef::Width - Coord.z - ); + GetWorld()->DropBlockAsPickups(RelativeToAbsolute({a_RelX, a_RelY, a_RelZ}), nullptr, nullptr); return false; } } // for i - Coords[] @@ -1356,7 +1359,7 @@ bool cChunk::UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE // The chunk is not available, bail out return false; } - Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); + Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, a_BlockType, a_BlockMeta); return true; } @@ -1385,17 +1388,17 @@ bool cChunk::UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKT -void cChunk::UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ) +void cChunk::UnboundedQueueTickBlock(Vector3i a_RelPos) { - if (!cChunkDef::IsValidHeight(a_RelY)) + if (!cChunkDef::IsValidHeight(a_RelPos.y)) { // Outside of chunkmap return; } - cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - if ((Chunk != nullptr) && Chunk->IsValid()) + auto chunk = GetRelNeighborChunkAdjustCoords(a_RelPos.x, a_RelPos.z); + if ((chunk != nullptr) && chunk->IsValid()) { - Chunk->QueueTickBlock(a_RelX, a_RelY, a_RelZ); + chunk->QueueTickBlock(a_RelPos); } } @@ -1533,17 +1536,16 @@ void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes) -void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients) +void cChunk::SetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta, a_SendToClients); + FastSetBlock(a_RelPos, a_BlockType, a_BlockMeta); // Tick this block and its neighbors: - m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ)); - QueueTickBlockNeighbors(a_RelX, a_RelY, a_RelZ); + m_ToTickBlocks.push_back(a_RelPos); + QueueTickBlockNeighbors(a_RelPos); // If there was a block entity, remove it: - Vector3i WorldPos = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ); - cBlockEntity * BlockEntity = GetBlockEntity(WorldPos); + cBlockEntity * BlockEntity = GetBlockEntityRel(a_RelPos); if (BlockEntity != nullptr) { BlockEntity->Destroy(); @@ -1576,7 +1578,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, case E_BLOCK_BREWING_STAND: { // Fast set block has already marked dirty - AddBlockEntityClean(cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, WorldPos, m_World)); + AddBlockEntityClean(cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, RelativeToAbsolute(a_RelPos), m_World)); break; } } // switch (a_BlockType) @@ -1586,33 +1588,25 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, -void cChunk::QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ) +void cChunk::QueueTickBlock(Vector3i a_RelPos) { - ASSERT ( - (a_RelX >= 0) && (a_RelX < Width) && - (a_RelY >= 0) && (a_RelY < Height) && - (a_RelZ >= 0) && (a_RelZ < Width) - ); // Coords need to be valid + ASSERT (IsValidRelPos(a_RelPos)); if (!IsValid()) { return; } - m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ)); + m_ToTickBlocks.push_back(a_RelPos); } -void cChunk::QueueTickBlockNeighbors(int a_RelX, int a_RelY, int a_RelZ) +void cChunk::QueueTickBlockNeighbors(Vector3i a_RelPos) { - struct - { - int x, y, z; - } - Coords[] = + static const Vector3i neighborCoords[] = { { 1, 0, 0}, {-1, 0, 0}, @@ -1621,9 +1615,9 @@ void cChunk::QueueTickBlockNeighbors(int a_RelX, int a_RelY, int a_RelZ) { 0, 0, 1}, { 0, 0, -1}, } ; - for (size_t i = 0; i < ARRAYCOUNT(Coords); i++) + for (const auto & neighbor: neighborCoords) { - UnboundedQueueTickBlock(a_RelX + Coords[i].x, a_RelY + Coords[i].y, a_RelZ + Coords[i].z); + UnboundedQueueTickBlock(a_RelPos + neighbor); } // for i - Coords[] } @@ -1759,22 +1753,28 @@ void cChunk::AddBlockEntityClean(cBlockEntity * a_BlockEntity) -cBlockEntity * cChunk::GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ) +cBlockEntity * cChunk::GetBlockEntity(Vector3i a_AbsPos) { - int RelX = a_BlockX - m_PosX * cChunkDef::Width; - int RelZ = a_BlockZ - m_PosZ * cChunkDef::Width; + auto relPos = AbsoluteToRelative(a_AbsPos); - if ( - !IsValidWidth (RelX) || - !IsValidHeight(a_BlockY) || - !IsValidWidth (RelZ) - ) + if (!IsValidRelPos(relPos)) { - // Coordinates are outside outside the world, no block entities here + // Coordinates are outside outside this chunk, no block entities here return nullptr; } - auto itr = m_BlockEntities.find(static_cast(MakeIndexNoCheck(RelX, a_BlockY, RelZ))); + auto itr = m_BlockEntities.find(static_cast(MakeIndexNoCheck(relPos))); + return (itr == m_BlockEntities.end()) ? nullptr : itr->second; +} + + + + + +cBlockEntity * cChunk::GetBlockEntityRel(Vector3i a_RelPos) +{ + ASSERT(IsValidRelPos(a_RelPos)); + auto itr = m_BlockEntities.find(static_cast(MakeIndexNoCheck(a_RelPos))); return (itr == m_BlockEntities.end()) ? nullptr : itr->second; } diff --git a/src/Chunk.h b/src/Chunk.h index 13ef1a5a9..d153a44ea 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -152,15 +152,21 @@ public: cWorld * GetWorld(void) const { return m_World; } - void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true); + void SetBlock(Vector3i a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); // SetBlock() does a lot of work (heightmap, tickblocks, blockentities) so a BlockIdx version doesn't make sense - void SetBlock(Vector3i a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { SetBlock( a_RelBlockPos.x, a_RelBlockPos.y, a_RelBlockPos.z, a_BlockType, a_BlockMeta); } /** Queues block for ticking (m_ToTickQueue) */ - void QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ); + void QueueTickBlock(Vector3i a_RelPos); + + /** OBSOLETE, use the Vector3i-based overload instead. + Queues block for ticking (m_ToTickQueue) */ + void QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ) + { + return QueueTickBlock({a_RelX, a_RelY, a_RelZ}); + } /** Queues all 6 neighbors of the specified block for ticking (m_ToTickQueue). If any are outside the chunk, relays the checking to the proper neighboring chunk */ - void QueueTickBlockNeighbors(int a_RelX, int a_RelY, int a_RelZ); + void QueueTickBlockNeighbors(Vector3i a_RelPos); void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc. void FastSetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true) @@ -447,7 +453,7 @@ public: bool UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); /** Same as QueueTickBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s in such a case), ignores unsuccessful attempts */ - void UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ); + void UnboundedQueueTickBlock(Vector3i a_RelPos); @@ -460,8 +466,19 @@ public: cRedstoneSimulatorChunkData * GetRedstoneSimulatorData(void) { return m_RedstoneSimulatorData; } void SetRedstoneSimulatorData(cRedstoneSimulatorChunkData * a_Data) { m_RedstoneSimulatorData = a_Data; } - cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ); - cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); } + /** OBSOLETE, use the Vector3i-based overload isntead. + Returns the block entity at the specified (absolute) coords. + Returns nullptr if no such BE or outside this chunk. */ + cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ) { return GetBlockEntity({a_BlockX, a_BlockY, a_BlockZ}); } + + /** Returns the block entity at the specified (absolute) coords. + Returns nullptr if no such BE or outside this chunk. */ + cBlockEntity * GetBlockEntity(Vector3i a_AbsPos); + + /** Returns the block entity at the specified (relative) coords. + Returns nullptr if no such BE. + Asserts that the position is a valid relative position. */ + cBlockEntity * GetBlockEntityRel(Vector3i a_RelPos); /** Returns true if the chunk should be ticked in the tick-thread. Checks if there are any clients and if the always-tick flag is set */ @@ -587,6 +604,10 @@ private: /** Adds snow to the top of snowy biomes and hydrates farmland / fills cauldrons in rainy biomes */ void ApplyWeatherToTop(void); + /** Returns the pickups that would be produced, if the specified block was dug up by a_Digger using a_Tool. + Doesn't dig the block, only queries the block handlers and then plugins for the pickups. */ + cItems PickupsFromBlock(Vector3i a_RelPos, const cEntity * a_Digger, const cItem * a_Tool); + /** Grows sugarcane by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking); returns the amount of blocks the sugarcane grew inside this call */ int GrowSugarcane (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks); diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index a859deca5..ec6b74192 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -145,108 +145,6 @@ cChunkPtr cChunkMap::GetChunkNoLoad(int a_ChunkX, int a_ChunkZ) -bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) -{ - // We already have m_CSChunks locked since this can be called only from within the tick thread - ASSERT(m_CSChunks.IsLockedByCurrentThread()); - - int ChunkX, ChunkZ; - cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk == nullptr) - { - return false; - } - - a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ); - return true; -} - - - - - -bool cChunkMap::LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType) -{ - // We already have m_CSChunks locked since this can be called only from within the tick thread - ASSERT(m_CSChunks.IsLockedByCurrentThread()); - - int ChunkX, ChunkZ; - cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk == nullptr) - { - return false; - } - - a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - return true; -} - - - - - -bool cChunkMap::LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE & a_BlockMeta) -{ - // We already have m_CSChunks locked since this can be called only from within the tick thread - ASSERT(m_CSChunks.IsLockedByCurrentThread()); - - int ChunkX, ChunkZ; - cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk == nullptr) - { - return false; - } - - a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ); - return true; -} - - - - - -bool cChunkMap::LockedSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) -{ - // We already have m_CSChunks locked since this can be called only from within the tick thread - int ChunkX, ChunkZ; - cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk == nullptr) - { - return false; - } - - Chunk->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); - return true; -} - - - - - -bool cChunkMap::LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) -{ - // We already have m_CSChunks locked since this can be called only from within the tick thread - int ChunkX, ChunkZ; - cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); - if (Chunk == nullptr) - { - return false; - } - - Chunk->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); - return true; -} - - - - - cChunk * cChunkMap::FindChunk(int a_ChunkX, int a_ChunkZ) { ASSERT(m_CSChunks.IsLockedByCurrentThread()); @@ -581,7 +479,7 @@ void cChunkMap::SetBlocks(const sSetBlockVector & a_Blocks) // If the chunk is valid, set the block: if (chunk != nullptr) { - chunk->SetBlock(block.m_RelX, block.m_RelY, block.m_RelZ, block.m_BlockType, block.m_BlockMeta); + chunk->SetBlock({block.m_RelX, block.m_RelY, block.m_RelZ}, block.m_BlockType, block.m_BlockMeta); } } // for block - a_Blocks[] } @@ -711,38 +609,40 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP -void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients) +void cChunkMap::SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - cChunkInterface ChunkInterface(this); - BlockHandler(GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnDestroyed(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ); - - int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; - cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); + auto chunkCoord = cChunkDef::BlockToChunk(a_BlockPos); + auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkCoord); cCSLock Lock(m_CSChunks); - cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); - if ((Chunk != nullptr) && Chunk->IsValid()) + auto chunk = GetChunk(chunkCoord.m_ChunkX, chunkCoord.m_ChunkZ); + if ((chunk != nullptr) && chunk->IsValid()) { - Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_SendToClients); - m_World->GetSimulatorManager()->WakeUp({a_BlockX, a_BlockY, a_BlockZ}, Chunk); + BLOCKTYPE blockType; + NIBBLETYPE blockMeta; + GetBlockTypeMeta(a_BlockPos, blockType, blockMeta); + cChunkInterface ChunkInterface(this); + BlockHandler(blockType)->OnBroken(ChunkInterface, *m_World, a_BlockPos, blockType, blockMeta); + chunk->SetBlock(relPos, a_BlockType, a_BlockMeta); + m_World->GetSimulatorManager()->WakeUp(a_BlockPos, chunk); + BlockHandler(a_BlockType)->OnPlaced(ChunkInterface, *m_World, a_BlockPos, a_BlockType, a_BlockMeta); } - BlockHandler(a_BlockType)->OnPlaced(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); } -bool cChunkMap::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) +bool cChunkMap::GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) { - int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; - cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); + auto chunkCoord = cChunkDef::BlockToChunk(a_BlockPos); + auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkCoord); cCSLock Lock(m_CSChunks); - cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); - if ((Chunk != nullptr) && Chunk->IsValid()) + auto chunk = GetChunk(chunkCoord.m_ChunkX, chunkCoord.m_ChunkZ); + if ((chunk != nullptr) && chunk->IsValid()) { - Chunk->GetBlockTypeMeta(X, Y, Z, a_BlockType, a_BlockMeta); + chunk->GetBlockTypeMeta(relPos, a_BlockType, a_BlockMeta); return true; } return false; @@ -776,14 +676,15 @@ void cChunkMap::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_Filt cCSLock Lock(m_CSChunks); for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { - cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) + auto chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ); + if ((chunk == nullptr) || !chunk->IsValid()) { continue; } - if (Chunk->GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ) == a_FilterBlockType) + Vector3i relPos(itr->m_RelX, itr->m_RelY, itr->m_RelZ); + if (chunk->GetBlock(relPos) == a_FilterBlockType) { - Chunk->SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta); + chunk->SetBlock(relPos, itr->m_BlockType, itr->m_BlockMeta); } } } @@ -797,16 +698,17 @@ void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks) cCSLock Lock(m_CSChunks); for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { - cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) + auto chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ); + if ((chunk == nullptr) || !chunk->IsValid()) { continue; } - switch (Chunk->GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ)) + Vector3i relPos(itr->m_RelX, itr->m_RelY, itr->m_RelZ); + switch (chunk->GetBlock(relPos)) { CASE_TREE_OVERWRITTEN_BLOCKS: { - Chunk->SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta); + chunk->SetBlock(relPos, itr->m_BlockType, itr->m_BlockMeta); break; } case E_BLOCK_LEAVES: @@ -814,7 +716,7 @@ void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks) { if ((itr->m_BlockType == E_BLOCK_LOG) || (itr->m_BlockType == E_BLOCK_NEW_LOG)) { - Chunk->SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta); + chunk->SetBlock(relPos, itr->m_BlockType, itr->m_BlockMeta); } break; } @@ -930,24 +832,22 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure) -bool cChunkMap::DigBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +bool cChunkMap::DigBlock(Vector3i a_BlockPos) { - int PosX = a_BlockX, PosY = a_BlockY, PosZ = a_BlockZ, ChunkX, ChunkZ; - - cChunkDef::AbsoluteToRelative(PosX, PosY, PosZ, ChunkX, ChunkZ); + auto chunkCoords = cChunkDef::BlockToChunk(a_BlockPos); + auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkCoords); { cCSLock Lock(m_CSChunks); - cChunkPtr DestChunk = GetChunk( ChunkX, ChunkZ); - if ((DestChunk == nullptr) || !DestChunk->IsValid()) + auto destChunk = GetChunk(chunkCoords.m_ChunkX, chunkCoords.m_ChunkZ); + if ((destChunk == nullptr) || !destChunk->IsValid()) { return false; } - DestChunk->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, 0); - m_World->GetSimulatorManager()->WakeUp({a_BlockX, a_BlockY, a_BlockZ}, DestChunk); + destChunk->SetBlock(relPos, E_BLOCK_AIR, 0); + m_World->GetSimulatorManager()->WakeUp(a_BlockPos, destChunk); } - return true; } @@ -955,6 +855,24 @@ bool cChunkMap::DigBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +cItems cChunkMap::PickupsFromBlock(Vector3i a_BlockPos, const cEntity * a_Digger, const cItem * a_Tool) +{ + auto chunkCoords = cChunkDef::BlockToChunk(a_BlockPos); + auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkCoords); + + cCSLock Lock(m_CSChunks); + auto destChunk = GetChunk(chunkCoords.m_ChunkX, chunkCoords.m_ChunkZ); + if ((destChunk == nullptr) || !destChunk->IsValid()) + { + return {}; + } + return destChunk->PickupsFromBlock(relPos, a_Digger, a_Tool); +} + + + + + void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer & a_Player) { int ChunkX, ChunkZ; @@ -1305,11 +1223,8 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ auto & Random = GetRandomProvider(); if (Random.RandBool(0.25)) // 25% chance of pickups { - cItems Drops; - cBlockHandler * Handler = BlockHandler(Block); - - Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); // Stone becomes cobblestone, coal ore becomes coal, etc. - m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z); + auto pickups = area.PickupsFromBlock({bx + x, by + y, bz + z}); + m_World->SpawnItemPickups(pickups, bx + x, by + y, bz + z); } else if ((m_World->GetTNTShrapnelLevel() > slNone) && Random.RandBool(0.20)) // 20% chance of flinging stuff around { diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 4a3dd2dfd..771eed2e7 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -17,6 +17,7 @@ class cWorld; class cItem; +class cItems; class cChunkStay; class cChunk; class cPlayer; @@ -136,8 +137,8 @@ public: NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ); NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ); void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta, bool a_ShouldMarkDirty, bool a_ShouldInformClients); - void SetBlock (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true); - bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); + void SetBlock (Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + bool GetBlockTypeMeta (Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); /** Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType */ @@ -165,7 +166,14 @@ public: /** Removes the block at the specified coords and wakes up simulators. Returns false if the chunk is not loaded (and the block is not dug). Returns true if successful. */ - bool DigBlock(int a_BlockX, int a_BlockY, int a_BlockZ); + bool DigBlock(Vector3i a_BlockPos); + + /** Returns all the pickups that would result if the a_Digger dug up the block at a_BlockPos using a_Tool. + a_Digger is usually a player, but can be nullptr for natural causes. + a_Tool is an optional item used to dig up the block, used by the handlers (empty hand vs shears produce different pickups from leaves). + An empty hand is assumed if a_Tool is nullptr. + Returns an empty cItems object if the chunk is not present. */ + cItems PickupsFromBlock(Vector3i a_BlockPos, const cEntity * a_Digger, const cItem * a_Tool); /** Sends the block at the specified coords to the specified player. Uses a blockchange packet to send the block. @@ -401,7 +409,7 @@ public: private: - // The chunks can manipulate neighbors while in their Tick() method, using LockedGetBlock() and LockedSetBlock() + // Chunks query their neighbors using GetChunk(), while being ticked friend class cChunk; // The chunkstay can (de-)register itself using AddChunkStay() and DelChunkStay() @@ -476,21 +484,6 @@ private: /** Constructs a chunk, returning it. Doesn't load, doesn't generate */ cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkZ); - /** Gets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */ - bool LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); - - /** Gets a block type in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */ - bool LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType); - - /** Gets a block meta in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */ - bool LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE & a_BlockMeta); - - /** Sets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */ - bool LockedSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); - - /** Fast-sets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */ - bool LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); - /** Locates a chunk ptr in the chunkmap; doesn't create it when not found; assumes m_CSChunks is locked. To be called only from cChunkMap. */ cChunk * FindChunk(int a_ChunkX, int a_ChunkZ); diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 79698ad64..16f323cc3 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1339,7 +1339,6 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo } cWorld * World = m_Player->GetWorld(); - cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem()); if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta)) { @@ -1352,22 +1351,29 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo if (a_OldBlock == E_BLOCK_AIR) { - LOGD("Dug air - what the function?"); return; } m_Player->AddFoodExhaustion(0.025); - ItemHandler->OnBlockDestroyed(World, m_Player, m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ); - // The ItemHandler is also responsible for spawning the pickups cChunkInterface ChunkInterface(World->GetChunkMap()); - BlockHandler(a_OldBlock)->OnDestroyedByPlayer(ChunkInterface, *World, *m_Player, a_BlockX, a_BlockY, a_BlockZ); - World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, {a_BlockX, a_BlockY, a_BlockZ}, a_OldBlock, this); - // This call would remove the water, placed from the ice block handler - if (!((a_OldBlock == E_BLOCK_ICE) && (ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ}) == E_BLOCK_WATER))) + auto blockHandler = BlockHandler(a_OldBlock); + Vector3i absPos(a_BlockX, a_BlockY, a_BlockZ); + blockHandler->OnPlayerBreakingBlock(ChunkInterface, *World, *m_Player, absPos); + if (m_Player->IsGameModeSurvival()) { - World->DigBlock(a_BlockX, a_BlockY, a_BlockZ); + World->DropBlockAsPickups(absPos, m_Player, &m_Player->GetEquippedItem()); } + else + { + World->DigBlock(absPos); + } + + // Damage the tool: + auto dlAction = (cBlockInfo::IsOneHitDig(a_OldBlock) ? cItemHandler::dlaBreakBlockInstant : cItemHandler::dlaBreakBlock); + m_Player->UseEquippedItem(dlAction); + World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, absPos, a_OldBlock, this); + blockHandler->OnPlayerBrokeBlock(ChunkInterface, *World, *m_Player, absPos, a_OldBlock, a_OldMeta); cRoot::Get()->GetPluginManager()->CallHookPlayerBrokenBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta); } diff --git a/src/Item.cpp b/src/Item.cpp index 5d486fdab..16aa22b50 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Item.h" +#include "ItemGrid.h" #include "json/json.h" #include "Items/ItemHandler.h" @@ -626,6 +627,15 @@ int cItem::AddEnchantmentsFromItem(const cItem & a_Other) //////////////////////////////////////////////////////////////////////////////// // cItems: +cItems::cItems(cItem && a_InitialItem) +{ + push_back(std::move(a_InitialItem)); +} + + + + + cItem * cItems::Get(int a_Idx) { if ((a_Idx < 0) || (a_Idx >= static_cast(size()))) @@ -711,3 +721,14 @@ bool cItems::ContainsType(const cItem & a_Item) } + + + +void cItems::AddItemGrid(const cItemGrid & a_ItemGrid) +{ + auto numSlots = a_ItemGrid.GetNumSlots(); + for (int i = 0; i < numSlots; ++i) + { + Add(a_ItemGrid.GetSlot(i)); + } +} diff --git a/src/Item.h b/src/Item.h index a94f35176..306e36b0a 100644 --- a/src/Item.h +++ b/src/Item.h @@ -20,6 +20,7 @@ // fwd: class cItemHandler; +class cItemGrid; class cColor; namespace Json @@ -234,6 +235,15 @@ class cItems // tolua_export : public std::vector { // tolua_export public: + + cItems(const cItems &) = default; + cItems(cItems &&) = default; + cItems & operator = (const cItems &) = default; + cItems & operator = (cItems &&) = default; + + /** Constructs a new instance containing the specified item. */ + cItems(cItem && a_InitialItem); + // tolua_begin /** Need a Lua-accessible constructor */ @@ -254,6 +264,9 @@ public: push_back(cItem(a_ItemType, a_ItemCount, a_ItemDamage)); } + /** Adds a copy of all items in a_ItemGrid. */ + void AddItemGrid(const cItemGrid & a_ItemGrid); + // tolua_end } ; // tolua_export diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h index f5acb25b3..36caf667b 100644 --- a/src/Items/ItemBucket.h +++ b/src/Items/ItemBucket.h @@ -114,6 +114,8 @@ public: + + bool PlaceFluid( cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock @@ -164,13 +166,7 @@ public: // Plugin disagrees with the washing-away return false; } - - cBlockHandler * Handler = BlockHandler(CurrentBlockType); - if (Handler->DoesDropOnUnsuitable()) - { - cChunkInterface ChunkInterface(a_World->GetChunkMap()); - Handler->DropBlock(ChunkInterface, *a_World, a_PluginInterface, a_Player, BlockPos.x, BlockPos.y, BlockPos.z); - } + a_World->DropBlockAsPickups(BlockPos, a_Player, nullptr); a_PluginInterface.CallHookPlayerBrokenBlock(*a_Player, BlockPos.x, BlockPos.y, BlockPos.z, EntryFace, CurrentBlockType, CurrentBlockMeta); } @@ -180,6 +176,8 @@ public: + + bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos) { class cCallbacks : diff --git a/src/Items/ItemChest.h b/src/Items/ItemChest.h index 58f6fbc6e..817020a25 100644 --- a/src/Items/ItemChest.h +++ b/src/Items/ItemChest.h @@ -40,13 +40,15 @@ public: } // Check if the block ignores build collision (water, grass etc.): - BLOCKTYPE ClickedBlock; - NIBBLETYPE ClickedBlockMeta; - a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta); + BLOCKTYPE clickedBlock; + NIBBLETYPE clickedBlockMeta; + Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ); + a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, clickedBlock, clickedBlockMeta); cChunkInterface ChunkInterface(a_World.GetChunkMap()); - if (BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, ClickedBlockMeta)) + auto blockHandler = BlockHandler(clickedBlock); + if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta)) { - BlockHandler(ClickedBlock)->OnDestroyedByPlayer(ChunkInterface, a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ); + blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, blockPos); } else { @@ -64,7 +66,7 @@ public: // Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed. // No need to do combinability (dblslab) checks, client will do that here. - if (BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, ClickedBlockMeta)) + if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta)) { // Tried to place a block into another? // Happens when you place a block aiming at side of block with a torch on it or stem beside it diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 489ef4f28..ecc4a9ace 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -361,9 +361,11 @@ bool cItemHandler::OnPlayerPlace( cChunkInterface ChunkInterface(a_World.GetChunkMap()); // Check if the block ignores build collision (water, grass etc.): - if (BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, ClickedBlockMeta)) + auto blockHandler = BlockHandler(ClickedBlock); + Vector3i absPos(a_BlockX, a_BlockY, a_BlockZ); + if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, absPos, a_Player, ClickedBlockMeta)) { - BlockHandler(ClickedBlock)->OnDestroyedByPlayer(ChunkInterface, a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ); + a_World.DropBlockAsPickups(absPos, &a_Player, nullptr); } else { @@ -482,28 +484,6 @@ bool cItemHandler::OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cI -void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ) -{ - UNUSED(a_Item); - - BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - cBlockHandler * Handler = cBlockInfo::GetHandler(Block); - - if (a_Player->IsGameModeSurvival()) - { - cChunkInterface ChunkInterface(a_World->GetChunkMap()); - cBlockInServerPluginInterface PluginInterface(*a_World); - Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, CanHarvestBlock(Block)); - } - - auto Action = (cBlockInfo::IsOneHitDig(Block) ? dlaBreakBlockInstant : dlaBreakBlock); - a_Player->UseEquippedItem(Action); -} - - - - - void cItemHandler::OnEntityAttack(cPlayer * a_Attacker, cEntity * a_AttackedEntity) { UNUSED(a_AttackedEntity); diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index 26703f573..ea0684dd1 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -99,12 +99,9 @@ public: UNUSED(a_Item); } - /** Called while the player diggs a block using this item */ + /** Called while the player digs a block using this item */ virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace); - /** Called when the player destroys a block using this item. This also calls the drop function for the destroyed block */ - virtual void OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ); - /** Called when a player attacks a other entity. */ virtual void OnEntityAttack(cPlayer * a_Attacker, cEntity * a_AttackedEntity); diff --git a/src/Items/ItemShears.h b/src/Items/ItemShears.h index 6cbb37b2a..9a6baa5e1 100644 --- a/src/Items/ItemShears.h +++ b/src/Items/ItemShears.h @@ -73,14 +73,6 @@ public: } - virtual void OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - BLOCKTYPE Block; - NIBBLETYPE BlockMeta; - a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, BlockMeta); - - super::OnBlockDestroyed(a_World, a_Player, a_Item, a_BlockX, a_BlockY, a_BlockZ); - } diff --git a/src/Items/ItemShovel.h b/src/Items/ItemShovel.h index 49ecf3348..0715f8d99 100644 --- a/src/Items/ItemShovel.h +++ b/src/Items/ItemShovel.h @@ -36,21 +36,7 @@ public: - virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override - { - BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - if (Block == E_BLOCK_SNOW) - { - cChunkInterface ChunkInterface(a_World->GetChunkMap()); - cBlockInServerPluginInterface PluginInterface(*a_World); - BlockHandler(Block)->DropBlock(ChunkInterface, *a_World, PluginInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ); - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); - a_Player->UseEquippedItem(cItemHandler::dlaBreakBlock); - return true; - } - return false; - } virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override { @@ -61,6 +47,10 @@ public: return super::CanHarvestBlock(a_BlockType); } + + + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override { switch (m_ItemType) @@ -74,6 +64,10 @@ public: return false; } + + + + virtual float GetBlockBreakingStrength(BLOCKTYPE a_Block) override { switch (a_Block) @@ -101,9 +95,7 @@ public: } break; } - default: return super::GetBlockBreakingStrength(a_Block); } - ASSERT(!"Something is wrong here... Maybe they are shovels out of a new material?"); - return 1.0f; + return super::GetBlockBreakingStrength(a_Block); } }; diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp index 9c5ec8c39..fca72ab97 100644 --- a/src/Mobs/Villager.cpp +++ b/src/Mobs/Villager.cpp @@ -169,11 +169,7 @@ void cVillager::HandleFarmerTryHarvestCrops() BLOCKTYPE CropBlock = m_World->GetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z); if (IsBlockFarmable(CropBlock) && m_World->GetBlockMeta(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z) == 0x7) { - cBlockHandler * Handler = cBlockInfo::GetHandler(CropBlock); - cChunkInterface ChunkInterface(m_World->GetChunkMap()); - cBlockInServerPluginInterface PluginInterface(*m_World); - Handler->DropBlock(ChunkInterface, *m_World, PluginInterface, this, m_CropsPos.x, m_CropsPos.y, m_CropsPos.z); - m_World->SetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z, E_BLOCK_AIR, 0); + m_World->DropBlockAsPickups(m_CropsPos, this, nullptr); m_ActionCountDown = 20; } } diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index 9a00d00a8..7862ed335 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -129,7 +129,7 @@ void cFireSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, // Randomly burn out the fire if it is raining: if (!BurnsForever && Raining && GetRandomProvider().RandBool(CHANCE_BASE_RAIN_EXTINGUISH + (BlockMeta * CHANCE_AGE_M_RAIN_EXTINGUISH))) { - a_Chunk->SetBlock(x, y, z, E_BLOCK_AIR, 0); + a_Chunk->SetBlock({x, y, z}, E_BLOCK_AIR, 0); itr = Data.erase(itr); continue; } @@ -157,7 +157,7 @@ void cFireSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, FIRE_FLOG("FS: Fire at {0} burnt out, removing the fire block", a_Chunk->PositionToWorldPosition({itr->x, itr->y, itr->z}) ); - a_Chunk->SetBlock(x, y, z, E_BLOCK_AIR, 0); + a_Chunk->SetBlock({x, y, z}, E_BLOCK_AIR, 0); RemoveFuelNeighbors(a_Chunk, x, y, z); itr = Data.erase(itr); continue; @@ -314,7 +314,7 @@ int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, in // Checked through everything, nothing was flammable // If block below isn't solid, we can't have fire, it would be a non-fueled fire // SetBlock just to make sure fire doesn't spawn - a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); + a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_AIR, 0); return 0; } return static_cast(m_BurnStepTimeNonfuel); @@ -403,18 +403,18 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel if (BlockType == E_BLOCK_TNT) { m_World.SpawnPrimedTNT({static_cast(AbsX), static_cast(Y), static_cast(AbsZ)}, 0); - Neighbour->SetBlock(X, Y, Z, E_BLOCK_AIR, 0); + Neighbour->SetBlock({X, Y, Z}, E_BLOCK_AIR, 0); return; } bool ShouldReplaceFuel = (GetRandomProvider().RandBool(m_ReplaceFuelChance * (1.0 / MAX_CHANCE_REPLACE_FUEL))); if (ShouldReplaceFuel && !cRoot::Get()->GetPluginManager()->CallHookBlockSpread(m_World, AbsX, Y, AbsZ, ssFireSpread)) { - Neighbour->SetBlock(X, Y, Z, E_BLOCK_FIRE, 0); + Neighbour->SetBlock({X, Y, Z}, E_BLOCK_FIRE, 0); } else { - Neighbour->SetBlock(X, Y, Z, E_BLOCK_AIR, 0); + Neighbour->SetBlock({X, Y, Z}, E_BLOCK_AIR, 0); } } // for i - Coords[] } diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index 7066dc016..f00dd3bfd 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -193,7 +193,7 @@ bool cFloodyFluidSimulator::CheckTributaries(cChunk * a_Chunk, int a_RelX, int a if (a_MyMeta >= 8) { FLUID_FLOG(" Not fed and downwards, turning into non-downwards meta {0}", m_Falloff); - a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, m_StationaryFluidBlock, m_Falloff); + a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, m_StationaryFluidBlock, m_Falloff); } else { @@ -201,12 +201,12 @@ bool cFloodyFluidSimulator::CheckTributaries(cChunk * a_Chunk, int a_RelX, int a if (a_MyMeta < 8) { FLUID_FLOG(" Not fed, decreasing from {0} to {1}", a_MyMeta - m_Falloff, a_MyMeta); - a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, m_StationaryFluidBlock, a_MyMeta); + a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, m_StationaryFluidBlock, a_MyMeta); } else { FLUID_FLOG(" Not fed, meta {0}, erasing altogether", a_MyMeta); - a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); + a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_AIR, 0); } } return true; @@ -254,7 +254,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i FLUID_FLOG(" Lava flowing into water, turning water at rel {0} into {1}", Vector3i{a_RelX, a_RelY, a_RelZ}, ItemTypeToString(NewBlock) ); - a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); + a_NearChunk->SetBlock({a_RelX, a_RelY, a_RelZ}, NewBlock, 0); m_World.BroadcastSoundEffect( "block.lava.extinguish", @@ -274,7 +274,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i FLUID_FLOG(" Water flowing into lava, turning lava at rel {0} into {1}", Vector3i{a_RelX, a_RelY, a_RelZ}, ItemTypeToString(NewBlock) ); - a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); + a_NearChunk->SetBlock({a_RelX, a_RelY, a_RelZ}, NewBlock, 0); m_World.BroadcastSoundEffect( "block.lava.extinguish", @@ -302,23 +302,13 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i cBlockHandler * Handler = BlockHandler(BlockType); if (Handler->DoesDropOnUnsuitable()) { - cChunkInterface ChunkInterface(m_World.GetChunkMap()); - cBlockInServerPluginInterface PluginInterface(m_World); - Handler->DropBlock( - ChunkInterface, - m_World, - PluginInterface, - nullptr, - BlockX, - a_RelY, - BlockZ - ); + m_World.DropBlockAsPickups({BlockX, a_RelY, BlockZ}, nullptr, nullptr); } } // if (CanWashAway) // Spread: FLUID_FLOG(" Spreading to {0} with meta {1}", Vector3i{BlockX, a_RelY, BlockZ}, a_NewMeta); - a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); + a_NearChunk->SetBlock({a_RelX, a_RelY, a_RelZ}, m_FluidBlock, a_NewMeta); m_World.GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, a_NearChunk); HardenBlock(a_NearChunk, a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); @@ -362,7 +352,7 @@ bool cFloodyFluidSimulator::CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX { // Found enough, turn into a source and bail out // FLUID_FLOG(" Found enough neighbor sources, turning into a source"); - a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, 0); + a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, m_FluidBlock, 0); return true; } } @@ -411,13 +401,13 @@ bool cFloodyFluidSimulator::HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY if (a_Meta == 0) { // Source lava block - a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_OBSIDIAN, 0); + a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_OBSIDIAN, 0); return true; } // Ignore last lava level else if (a_Meta <= 4) { - a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_COBBLESTONE, 0); + a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_COBBLESTONE, 0); return true; } } diff --git a/src/Simulator/SandSimulator.cpp b/src/Simulator/SandSimulator.cpp index a75ea2d11..5f0595d48 100644 --- a/src/Simulator/SandSimulator.cpp +++ b/src/Simulator/SandSimulator.cpp @@ -67,7 +67,7 @@ void cSandSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, { continue; } - a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0); + a_Chunk->SetBlock({itr->x, itr->y, itr->z}, E_BLOCK_AIR, 0); } } m_TotalBlocks -= static_cast(ChunkData.size()); @@ -302,7 +302,7 @@ void cSandSimulator::DoInstantFall(cChunk * a_Chunk, int a_RelX, int a_RelY, int BLOCKTYPE FallingBlockType; NIBBLETYPE FallingBlockMeta; a_Chunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, FallingBlockType, FallingBlockMeta); - a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); + a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_AIR, 0); // Search for a place to put it: for (int y = a_RelY - 1; y >= 0; y--) diff --git a/src/Simulator/VaporizeFluidSimulator.cpp b/src/Simulator/VaporizeFluidSimulator.cpp index 32a55794d..441c0bb6c 100644 --- a/src/Simulator/VaporizeFluidSimulator.cpp +++ b/src/Simulator/VaporizeFluidSimulator.cpp @@ -28,15 +28,14 @@ void cVaporizeFluidSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk) { return; } - int RelX = a_Block.x - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_Block.z - a_Chunk->GetPosZ() * cChunkDef::Width; - BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_Block.y, RelZ); + auto relPos = cChunkDef::AbsoluteToRelative(a_Block); + auto blockType = a_Chunk->GetBlock(relPos); if ( - (BlockType == m_FluidBlock) || - (BlockType == m_StationaryFluidBlock) + (blockType == m_FluidBlock) || + (blockType == m_StationaryFluidBlock) ) { - a_Chunk->SetBlock(RelX, a_Block.y, RelZ, E_BLOCK_AIR, 0); + a_Chunk->SetBlock(relPos, E_BLOCK_AIR, 0); World::GetBroadcastInterface(m_World).BroadcastSoundEffect( "block.fire.extinguish", Vector3d(a_Block), diff --git a/src/World.cpp b/src/World.cpp index 59292950d..995ba12a4 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2173,9 +2173,9 @@ void cWorld::SetMaxViewDistance(int a_MaxViewDistance) -void cWorld::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients) +void cWorld::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - m_ChunkMap->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_SendToClients); + m_ChunkMap->SetBlock({a_BlockX, a_BlockY, a_BlockZ}, a_BlockType, a_BlockMeta); } @@ -2209,9 +2209,9 @@ NIBBLETYPE cWorld::GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ) -bool cWorld::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) +bool cWorld::GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) { - return m_ChunkMap->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); + return m_ChunkMap->GetBlockTypeMeta(a_BlockPos, a_BlockType, a_BlockMeta); } @@ -2236,7 +2236,19 @@ bool cWorld::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock -void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3d a_Pos, double a_FlyAwaySpeed, bool IsPlayerCreated) +void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3i a_BlockPos, double a_FlyAwaySpeed, bool a_IsPlayerCreated) +{ + auto & random = GetRandomProvider(); + auto microX = random.RandReal(0, 1); + auto microZ = random.RandReal(0, 1); + return SpawnItemPickups(a_Pickups, Vector3d(microX, 0, microZ) + a_BlockPos, a_FlyAwaySpeed, a_IsPlayerCreated); +} + + + + + +void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3d a_Pos, double a_FlyAwaySpeed, bool a_IsPlayerCreated) { auto & Random = GetRandomProvider(); a_FlyAwaySpeed /= 100; // Pre-divide, so that we don't have to divide each time inside the loop @@ -2252,7 +2264,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3d a_Pos, double a float SpeedY = static_cast(a_FlyAwaySpeed * Random.RandInt(50)); float SpeedZ = static_cast(a_FlyAwaySpeed * Random.RandInt(-5, 5)); - auto Pickup = cpp14::make_unique(a_Pos, *itr, IsPlayerCreated, Vector3f{SpeedX, SpeedY, SpeedZ}); + auto Pickup = cpp14::make_unique(a_Pos, *itr, a_IsPlayerCreated, Vector3f{SpeedX, SpeedY, SpeedZ}); auto PickupPtr = Pickup.get(); PickupPtr->Initialize(std::move(Pickup), *this); } @@ -2262,7 +2274,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3d a_Pos, double a -void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3d a_Pos, Vector3d a_Speed, bool IsPlayerCreated) +void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3d a_Pos, Vector3d a_Speed, bool a_IsPlayerCreated) { for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr) { @@ -2271,7 +2283,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3d a_Pos, Vector3d continue; } - auto pickup = cpp14::make_unique(a_Pos, *itr, IsPlayerCreated, a_Speed); + auto pickup = cpp14::make_unique(a_Pos, *itr, a_IsPlayerCreated, a_Speed); auto pickupPtr = pickup.get(); pickupPtr->Initialize(std::move(pickup), *this); } @@ -2468,12 +2480,44 @@ bool cWorld::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure) -bool cWorld::DigBlock(int a_X, int a_Y, int a_Z) +bool cWorld::DigBlock(Vector3i a_BlockPos) +{ + BLOCKTYPE blockType; + NIBBLETYPE blockMeta; + GetBlockTypeMeta(a_BlockPos, blockType, blockMeta); + cChunkInterface chunkInterface(GetChunkMap()); + auto blockHandler = cBlockInfo::GetHandler(blockType); + blockHandler->OnBreaking(chunkInterface, *this, a_BlockPos); + if (!m_ChunkMap->DigBlock(a_BlockPos)) + { + return false; + } + blockHandler->OnBroken(chunkInterface, *this, a_BlockPos, blockType, blockMeta); + return true; +} + + + + + +bool cWorld::DropBlockAsPickups(Vector3i a_BlockPos, const cEntity * a_Digger, const cItem * a_Tool) +{ + auto pickups = PickupsFromBlock(a_BlockPos, a_Digger, a_Tool); + if (!DigBlock(a_BlockPos)) + { + return false; + } + SpawnItemPickups(pickups, Vector3d(0.5, 0.5, 0.5) + a_BlockPos); + return true; +} + + + + + +cItems cWorld::PickupsFromBlock(Vector3i a_BlockPos, const cEntity * a_Digger, const cItem * a_Tool) { - cBlockHandler * Handler = cBlockInfo::GetHandler(GetBlock(a_X, a_Y, a_Z)); - cChunkInterface ChunkInterface(GetChunkMap()); - Handler->OnDestroyed(ChunkInterface, *this, a_X, a_Y, a_Z); - return m_ChunkMap->DigBlock(a_X, a_Y, a_Z); + return m_ChunkMap->PickupsFromBlock(a_BlockPos, a_Digger, a_Tool); } diff --git a/src/World.h b/src/World.h index 00f9f8b01..742c1795e 100644 --- a/src/World.h +++ b/src/World.h @@ -383,14 +383,12 @@ public: // tolua_begin /** Sets the block at the specified coords to the specified value. - Full processing, incl. updating neighbors, is performed. - */ - void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true); + Full processing, incl. updating neighbors, is performed. */ + void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); /** Sets the block at the specified coords to the specified value. The replacement doesn't trigger block updates. - The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block) - */ + The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block). */ void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { m_ChunkMap->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); @@ -412,8 +410,22 @@ public: // tolua_end - bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); // TODO: Exported in ManualBindings.cpp - bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); // TODO: Exported in ManualBindings.cpp + /** Retrieves the block type and meta at the specified coords. + Stores the result into a_BlockType and a_BlockMeta. + Returns true if successful, false if chunk not present. */ + bool GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); // TODO: Export in ManualBindings_World.cpp + + /** OBSOLETE, use the Vector3i-based overload instead. + Retrieves the block type and meta at the specified coords. + Stores the result into a_BlockType and a_BlockMeta. + Returns true if successful, false if chunk not present. */ + bool GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) // Exported in ManualBindings_World.cpp + { + return GetBlockTypeMeta({a_BlockX, a_BlockY, a_BlockZ}, a_BlockType, a_BlockMeta); + } + + bool GetBlockInfo(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); // Exported in ManualBindings.cpp + // TODO: NIBBLETYPE GetBlockActualLight(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_begin @@ -435,14 +447,21 @@ public: // tolua_begin - /** Spawns item pickups for each item in the list. May compress pickups if too many entities: */ + /** Spawns item pickups for each item in the list. + The initial position of the pickups is at the center of the specified block, with a small random offset. + May compress pickups if too many entities. */ + void SpawnItemPickups(const cItems & a_Pickups, Vector3i a_BlockPos, double a_FlyAwaySpeed = 1.0, bool a_IsPlayerCreated = false); + + /** Spawns item pickups for each item in the list. + May compress pickups if too many entities. */ void SpawnItemPickups(const cItems & a_Pickups, Vector3d a_Pos, double a_FlyAwaySpeed = 1.0, bool a_IsPlayerCreated = false); /** OBSOLETE, use the Vector3d-based overload instead. - Spawns item pickups for each item in the list. May compress pickups if too many entities: */ + Spawns item pickups for each item in the list. + May compress pickups if too many entities. */ virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool a_IsPlayerCreated = false) override { - return SpawnItemPickups(a_Pickups, {a_BlockX, a_BlockY, a_BlockZ}, a_FlyAwaySpeed, a_IsPlayerCreated); + return SpawnItemPickups(a_Pickups, Vector3d{a_BlockX, a_BlockY, a_BlockZ}, a_FlyAwaySpeed, a_IsPlayerCreated); } /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified. */ @@ -516,12 +535,12 @@ public: /** Spawns experience orbs of the specified total value at the given location. The orbs' values are split according to regular Minecraft rules. Returns an vector of UniqueID of all the orbs. */ - std::vector SpawnSplitExperienceOrbs(Vector3d a_Pos, int a_Reward); // Exported in ManualBindings_World.cpp + virtual std::vector SpawnSplitExperienceOrbs(Vector3d a_Pos, int a_Reward) override; // Exported in ManualBindings_World.cpp /** OBSOLETE, use the Vector3d-based overload instead. Spawns experience orbs of the specified total value at the given location. The orbs' values are split according to regular Minecraft rules. Returns an vector of UniqueID of all the orbs. */ - virtual std::vector SpawnSplitExperienceOrbs(double a_X, double a_Y, double a_Z, int a_Reward) override + std::vector SpawnSplitExperienceOrbs(double a_X, double a_Y, double a_Z, int a_Reward) { return SpawnSplitExperienceOrbs({a_X, a_Y, a_Z}, a_Reward); } @@ -554,7 +573,37 @@ public: bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure); // tolua_begin - bool DigBlock (int a_X, int a_Y, int a_Z); + + /** Replaces the specified block with air, and calls the apropriate block handlers (OnBreaking(), OnBroken()). + Wakes up the simulators. + Doesn't produce pickups, use DropBlockAsPickups() for that instead. + Returns true on success, false if the chunk is not loaded. */ + bool DigBlock(Vector3i a_BlockPos); + + /** OBSOLETE, use the Vector3-based overload instead. + Replaces the specified block with air, and calls the apropriate block handlers (OnBreaking(), OnBroken()). + Wakes up the simulators. + Doesn't produce pickups, use DropBlockAsPickups() for that instead. + Returns true on success, false if the chunk is not loaded. */ + bool DigBlock(int a_X, int a_Y, int a_Z) + { + return DigBlock({a_X, a_Y, a_Z}); + } + + /** Digs the specified block, and spawns the appropriate pickups for it. + a_Digger is an optional entity causing the digging, usually the player. + a_Tool is an optional item used to dig up the block, used by the handlers (empty hand vs shears produce different pickups from leaves). + An empty hand is assumed if a_Tool is nullptr. + Returns true on success, false if the chunk is not loaded. */ + bool DropBlockAsPickups(Vector3i a_BlockPos, const cEntity * a_Digger = nullptr, const cItem * a_Tool = nullptr); + + /** Returns all the pickups that would result if the a_Digger dug up the block at a_BlockPos using a_Tool + a_Digger is usually a player, but can be nullptr for natural causes. + a_Tool is an optional item used to dig up the block, used by the handlers (empty hand vs shears produce different pickups from leaves). + An empty hand is assumed if a_Tool is nullptr. + Returns an empty cItems object if the chunk is not present. */ + cItems PickupsFromBlock(Vector3i a_BlockPos, const cEntity * a_Digger = nullptr, const cItem * a_Tool = nullptr); + virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer & a_Player) override; /** Set default spawn at the given coordinates. -- cgit v1.2.3