From ccdf03daaf880dd0c89a03b50c11eb083ee1cfb0 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 24 Dec 2014 07:20:17 +0100 Subject: Refactored all player block placing to go through hooks. Fixes #1618. --- src/Entities/Player.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ src/Entities/Player.h | 18 ++++++++++ 2 files changed, 114 insertions(+) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 15920d6cf..7bdd1c6f7 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Player.h" +#include #include "../ChatColor.h" #include "../Server.h" #include "../UI/Window.h" @@ -19,6 +20,10 @@ #include "../WorldStorage/StatSerializer.h" #include "../CompositeChat.h" +#include "../Blocks/BlockHandler.h" +#include "../Blocks/BlockSlab.h" +#include "../Blocks/ChunkInterface.h" + #include "../IniFile.h" #include "json/json.h" @@ -2168,6 +2173,97 @@ void cPlayer::LoadRank(void) +bool cPlayer::PlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +{ + sSetBlockVector blk{{a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta}}; + return PlaceBlocks(blk); +} + + + + + +void cPlayer::SendBlocksAround(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Range) +{ + // Collect the coords of all the blocks to send: + sSetBlockVector blks; + for (int y = a_BlockY - a_Range + 1; y < a_BlockY + a_Range; y++) + { + for (int z = a_BlockZ - a_Range + 1; z < a_BlockZ + a_Range; z++) + { + for (int x = a_BlockX - a_Range + 1; x < a_BlockX + a_Range; x++) + { + blks.emplace_back(x, y, z, E_BLOCK_AIR, 0); // Use fake blocktype, it will get set later on. + }; + }; + } // for y + + // Get the values of all the blocks: + if (!m_World->GetBlocks(blks, false)) + { + LOGD("%s: Cannot query all blocks, not sending an update", __FUNCTION__); + return; + } + + // Divide the block changes by their respective chunks: + std::unordered_map Changes; + for (const auto & blk: blks) + { + Changes[cChunkCoords(blk.m_ChunkX, blk.m_ChunkZ)].push_back(blk); + } // for blk - blks[] + blks.clear(); + + // Send the blocks for each affected chunk: + for (auto itr = Changes.cbegin(), end = Changes.cend(); itr != end; ++itr) + { + m_ClientHandle->SendBlockChanges(itr->first.m_ChunkX, itr->first.m_ChunkZ, itr->second); + } +} + + + + + +bool cPlayer::PlaceBlocks(const sSetBlockVector & a_Blocks) +{ + // Call the "placing" hooks; if any fail, abort: + cPluginManager * pm = cPluginManager::Get(); + for (auto blk: a_Blocks) + { + if (pm->CallHookPlayerPlacingBlock(*this, blk)) + { + // Abort - re-send all the current blocks in the a_Blocks' coords to the client: + for (auto blk2: a_Blocks) + { + m_World->SendBlockTo(blk2.GetX(), blk2.GetY(), blk2.GetZ(), this); + } + return false; + } + } // for blk - a_Blocks[] + + // Set the blocks: + m_World->SetBlocks(a_Blocks); + + // Notify the blockhandlers: + cChunkInterface ChunkInterface(m_World->GetChunkMap()); + for (auto blk: a_Blocks) + { + cBlockHandler * newBlock = BlockHandler(blk.m_BlockType); + newBlock->OnPlacedByPlayer(ChunkInterface, *m_World, this, blk); + } + + // Call the "placed" hooks: + for (auto blk: a_Blocks) + { + pm->CallHookPlayerPlacedBlock(*this, blk); + } + return true; +} + + + + + void cPlayer::Detach() { super::Detach(); diff --git a/src/Entities/Player.h b/src/Entities/Player.h index c643aaa8e..33ab5293c 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -440,8 +440,26 @@ public: Loads the m_Rank, m_Permissions, m_MsgPrefix, m_MsgSuffix and m_MsgNameColorCode members. */ void LoadRank(void); + /** Calls the block-placement hook and places the block in the world, unless refused by the hook. + If the hook prevents the placement, sends the current block at the specified coords back to the client. + Assumes that all the blocks are in currently loaded chunks. */ + bool PlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, 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. + The blocks in range (a_BlockX - a_Range, a_BlockX + a_Range) are sent (NY-metric). */ + void SendBlocksAround(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Range = 1); + // tolua_end + /** Calls the block placement hooks and places the blocks in the world. + First the "placing" hooks for all the blocks are called, then the blocks are placed, and finally + the "placed" hooks are called. + 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); + // cEntity overrides: virtual bool IsCrouched (void) const { return m_IsCrouched; } virtual bool IsSprinting(void) const { return m_IsSprinting; } -- cgit v1.2.3