From a62b2b1be2103d7de2fd66c7304b7473e369be3c Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 5 May 2021 14:25:10 +0100 Subject: Move item placement into item handlers (#5184) * Move item placement into item handlers + Add appropriate CanBeAt checks in cPlayer::PlaceBlocks, into which all placement handlers call. * Partly addresses #5157 * Fixes #4878 * Fixes #2919 * Fixes #4629 * Fixes #4239 * Fixes #4849 Co-authored-by: changyong guo Co-authored-by: Xotheus Co-authored-by: Krist Pregracke * Review fixes * Update APIDesc.lua * Rename Co-authored-by: changyong guo Co-authored-by: Xotheus Co-authored-by: Krist Pregracke --- src/Entities/Player.cpp | 45 ++++++++++++++++++++++++++------------------- src/Entities/Player.h | 6 +++--- 2 files changed, 29 insertions(+), 22 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 08adb1096..235433cf8 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -2391,10 +2391,9 @@ void cPlayer::LoadRank(void) -bool cPlayer::PlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +bool cPlayer::PlaceBlock(const Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - sSetBlockVector blk{{a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta}}; - return PlaceBlocks(blk); + return PlaceBlocks({ { a_Position, a_BlockType, a_BlockMeta } }); } @@ -2442,7 +2441,7 @@ void cPlayer::SendBlocksAround(int a_BlockX, int a_BlockY, int a_BlockZ, int a_R -bool cPlayer::DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks) +bool cPlayer::DoesPlacingBlocksIntersectEntity(const std::initializer_list a_Blocks) const { // Compute the bounding box for each block to be placed std::vector PlacementBoxes; @@ -2516,44 +2515,52 @@ const cUUID & cPlayer::GetUUID(void) const -bool cPlayer::PlaceBlocks(const sSetBlockVector & a_Blocks) +bool cPlayer::PlaceBlocks(const std::initializer_list a_Blocks) { if (DoesPlacingBlocksIntersectEntity(a_Blocks)) { // Abort - re-send all the current blocks in the a_Blocks' coords to the client: - for (auto blk2: a_Blocks) + for (const auto & ResendBlock : a_Blocks) { - m_World->SendBlockTo(blk2.GetX(), blk2.GetY(), blk2.GetZ(), *this); + m_World->SendBlockTo(ResendBlock.GetX(), ResendBlock.GetY(), ResendBlock.GetZ(), *this); } return false; } - // Call the "placing" hooks; if any fail, abort: cPluginManager * pm = cPluginManager::Get(); - for (auto blk: a_Blocks) + + // Check the blocks CanBeAt, and call the "placing" hooks; if any fail, abort: + for (const auto & Block : a_Blocks) { - if (pm->CallHookPlayerPlacingBlock(*this, blk)) + if ( + !m_World->DoWithChunkAt(Block.GetAbsolutePos(), [&Block](cChunk & a_Chunk) + { + return cBlockHandler::For(Block.m_BlockType).CanBeAt(a_Chunk, Block.GetRelativePos(), Block.m_BlockMeta); + }) + ) + { + return false; + } + + if (pm->CallHookPlayerPlacingBlock(*this, Block)) { // Abort - re-send all the current blocks in the a_Blocks' coords to the client: - for (auto blk2: a_Blocks) + for (const auto & ResendBlock : a_Blocks) { - m_World->SendBlockTo(blk2.GetX(), blk2.GetY(), blk2.GetZ(), *this); + m_World->SendBlockTo(ResendBlock.GetX(), ResendBlock.GetY(), ResendBlock.GetZ(), *this); } return false; } - } // for blk - a_Blocks[] + } cChunkInterface ChunkInterface(m_World->GetChunkMap()); - for (auto blk: a_Blocks) + for (const auto & Block : a_Blocks) { // Set the blocks: - m_World->PlaceBlock(blk.GetAbsolutePos(), blk.m_BlockType, blk.m_BlockMeta); - - // Notify the blockhandlers: - cBlockHandler::For(blk.m_BlockType).OnPlacedByPlayer(ChunkInterface, *m_World, *this, blk); + m_World->PlaceBlock(Block.GetAbsolutePos(), Block.m_BlockType, Block.m_BlockMeta); // Call the "placed" hooks: - pm->CallHookPlayerPlacedBlock(*this, blk); + pm->CallHookPlayerPlacedBlock(*this, Block); } return true; diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 987bccbe5..f4ce76f21 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -534,7 +534,7 @@ public: void UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIsOnGround); /** Whether placing the given blocks would intersect any entitiy */ - bool DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks); + bool DoesPlacingBlocksIntersectEntity(std::initializer_list a_Blocks) const; /** Returns the UUID that has been read from the client, or nil if not available. */ const cUUID & GetUUID(void) const; // Exported in ManualBindings.cpp @@ -552,7 +552,7 @@ public: If the hook prevents the placement, sends the current block at the specified coords back to the client. Assumes that the block is in a currently loaded chunk. Returns true if the block is successfully placed. */ - bool PlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + bool PlaceBlock(Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); /** Sends the block in the specified range around the specified coord to the client as a block change packet. @@ -571,7 +571,7 @@ public: If the any of the "placing" hooks aborts, none of the blocks are placed and the function returns false. Returns true if all the blocks are placed. Assumes that all the blocks are in currently loaded chunks. */ - bool PlaceBlocks(const sSetBlockVector & a_Blocks); + bool PlaceBlocks(std::initializer_list a_Blocks); /** Notify nearby wolves that the player or one of the player's wolves took damage or did damage to an entity @param a_Opponent the opponent we're fighting. -- cgit v1.2.3