diff options
author | Tiger Wang <ziwei.tiger@outlook.com> | 2021-03-28 15:40:57 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-28 15:40:57 +0200 |
commit | 748b121703fa28b10933f4432c09391e66179118 (patch) | |
tree | 58a39b6a75c3e9127507bf3c185a99e546147276 | |
parent | Fix Windows XP to 7 compatibility (#5167) (diff) | |
download | cuberite-748b121703fa28b10933f4432c09391e66179118.tar cuberite-748b121703fa28b10933f4432c09391e66179118.tar.gz cuberite-748b121703fa28b10933f4432c09391e66179118.tar.bz2 cuberite-748b121703fa28b10933f4432c09391e66179118.tar.lz cuberite-748b121703fa28b10933f4432c09391e66179118.tar.xz cuberite-748b121703fa28b10933f4432c09391e66179118.tar.zst cuberite-748b121703fa28b10933f4432c09391e66179118.zip |
Diffstat (limited to '')
37 files changed, 546 insertions, 1592 deletions
diff --git a/src/Bindings/ManualBindings.h b/src/Bindings/ManualBindings.h index a23c5d2e4..780c6ce41 100644 --- a/src/Bindings/ManualBindings.h +++ b/src/Bindings/ManualBindings.h @@ -211,228 +211,6 @@ public: - /** Template for the bindings for the DoWithXYZAt(X, Y, Z) functions that don't need to check their coords. */ - template < - class SELF, - class ITEM, - bool (SELF::*DoWithFn)(int, int, int, cFunctionRef<bool(ITEM &)>) - > - static int DoWithXYZ(lua_State * tolua_S) - { - // Check params: - cLuaState L(tolua_S); - if ( - !L.CheckParamNumber(2, 4) || - !L.CheckParamFunction(5) || - !L.CheckParamEnd(6) - ) - { - return 0; - } - - // Get parameters: - SELF * Self = nullptr; - int BlockX = 0; - int BlockY = 0; - int BlockZ = 0; - cLuaState::cRef FnRef; - L.GetStackValues(1, Self, BlockX, BlockY, BlockZ, FnRef); - if (Self == nullptr) - { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); - } - if (!FnRef.IsValid()) - { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #5"); - } - - // Call the DoWith function: - bool res = (Self->*DoWithFn)(BlockX, BlockY, BlockZ, [&](ITEM & a_Item) - { - bool ret = false; - L.Call(FnRef, &a_Item, cLuaState::Return, ret); - return ret; - } - ); - - // Push the result as the return value: - L.Push(res); - return 1; - } - - - - - - /** Template for the bindings for the DoWithXYZAt(X, Y, Z) functions that need to check their coords. */ - template < - class SELF, - class ITEM, - bool (SELF::*DoWithFn)(int, int, int, cFunctionRef<bool(ITEM &)>), - bool (SELF::*CoordCheckFn)(int, int, int) const - > - static int DoWithXYZ(lua_State * tolua_S) - { - // Check params: - cLuaState L(tolua_S); - if ( - !L.CheckParamNumber(2, 4) || - !L.CheckParamFunction(5) || - !L.CheckParamEnd(6) - ) - { - return 0; - } - - // Get parameters: - SELF * Self = nullptr; - int BlockX = 0; - int BlockY = 0; - int BlockZ = 0; - cLuaState::cRef FnRef; - L.GetStackValues(1, Self, BlockX, BlockY, BlockZ, FnRef); - if (Self == nullptr) - { - return L.ApiParamError("Invalid 'self'"); - } - if (!FnRef.IsValid()) - { - return L.ApiParamError("Expected a valid callback function for parameter #5"); - } - if (!(Self->*CoordCheckFn)(BlockX, BlockY, BlockZ)) - { - return L.FApiParamError("The provided coordinates ({0}) are not valid", - Vector3i{BlockX, BlockY, BlockZ} - ); - } - - // Call the DoWith function: - bool res = (Self->*DoWithFn)(BlockX, BlockY, BlockZ, [&](ITEM & a_Item) - { - bool ret = false; - L.Call(FnRef, &a_Item, cLuaState::Return, ret); - return ret; - } - ); - - // Push the result as the return value: - L.Push(res); - return 1; - } - - - - - - template < - class Ty1, - class Ty2, - bool (Ty1::*ForEachFn)(int, int, cFunctionRef<bool(Ty2 &)>) - > - static int ForEachInChunk(lua_State * tolua_S) - { - // Check params: - cLuaState L(tolua_S); - if ( - !L.CheckParamNumber(2, 3) || - !L.CheckParamFunction(4) || - !L.CheckParamEnd(5) - ) - { - return 0; - } - - // Get parameters: - Ty1 * Self = nullptr; - int ChunkX = 0; - int ChunkZ = 0; - cLuaState::cRef FnRef; - L.GetStackValues(1, Self, ChunkX, ChunkZ, FnRef); - if (Self == nullptr) - { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); - } - if (!FnRef.IsValid()) - { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #4"); - } - - // Call the DoWith function: - bool res = (Self->*ForEachFn)(ChunkX, ChunkZ, [&](Ty2 & a_Item) - { - bool ret = false; - L.Call(FnRef, &a_Item, cLuaState::Return, ret); - return ret; - } - ); - - // Push the result as the return value: - L.Push(res); - return 1; - } - - - - - - template < - class Ty1, - class Ty2, - bool (Ty1::*ForEachFn)(const cBoundingBox &, cFunctionRef<bool(Ty2 &)>) - > - static int ForEachInBox(lua_State * tolua_S) - { - // Check params: - cLuaState L(tolua_S); - if ( - !L.CheckParamUserType(1, "cWorld") || - !L.CheckParamUserType(2, "cBoundingBox") || - !L.CheckParamFunction(3) || - !L.CheckParamEnd(4) - ) - { - return 0; - } - - // Get the params: - Ty1 * Self = nullptr; - cBoundingBox * Box = nullptr; - cLuaState::cRef FnRef; - L.GetStackValues(1, Self, Box, FnRef); - if ((Self == nullptr) || (Box == nullptr)) - { - LOGWARNING("Invalid world (%p) or boundingbox (%p)", static_cast<void *>(Self), static_cast<void *>(Box)); - L.LogStackTrace(); - return 0; - } - if (!FnRef.IsValid()) - { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2"); - } - - bool res = (Self->*ForEachFn)(*Box, [&](Ty2 & a_Item) - { - bool ret = false; - if (!L.Call(FnRef, &a_Item, cLuaState::Return, ret)) - { - LOGWARNING("Failed to call Lua callback"); - L.LogStackTrace(); - return true; // Abort enumeration - } - - return ret; - } - ); - - // Push the result as the return value: - L.Push(res); - return 1; - } - - - - - template < class Ty1, class Ty2, diff --git a/src/Bindings/ManualBindings_BlockArea.cpp b/src/Bindings/ManualBindings_BlockArea.cpp index 5f281fadc..a53a7bebf 100644 --- a/src/Bindings/ManualBindings_BlockArea.cpp +++ b/src/Bindings/ManualBindings_BlockArea.cpp @@ -15,6 +15,66 @@ +/** Template for the bindings for the DoWithXYZAt(X, Y, Z) functions that need to check their coords. */ +template < + class SELF, + class ITEM, + bool (SELF::*DoWithFn)(int, int, int, cFunctionRef<bool(ITEM &)>), + bool (SELF::*CoordCheckFn)(int, int, int) const +> +static int DoWithXYZ(lua_State * tolua_S) +{ + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamNumber(2, 4) || + !L.CheckParamFunction(5) || + !L.CheckParamEnd(6) + ) + { + return 0; + } + + // Get parameters: + SELF * Self = nullptr; + int BlockX = 0; + int BlockY = 0; + int BlockZ = 0; + cLuaState::cRef FnRef; + L.GetStackValues(1, Self, BlockX, BlockY, BlockZ, FnRef); + if (Self == nullptr) + { + return L.ApiParamError("Invalid 'self'"); + } + if (!FnRef.IsValid()) + { + return L.ApiParamError("Expected a valid callback function for parameter #5"); + } + if (!(Self->*CoordCheckFn)(BlockX, BlockY, BlockZ)) + { + return L.FApiParamError("The provided coordinates ({0}) are not valid", + Vector3i{BlockX, BlockY, BlockZ} + ); + } + + // Call the DoWith function: + bool res = (Self->*DoWithFn)(BlockX, BlockY, BlockZ, [&](ITEM & a_Item) + { + bool ret = false; + L.Call(FnRef, &a_Item, cLuaState::Return, ret); + return ret; + } + ); + + // Push the result as the return value: + L.Push(res); + return 1; +} + + + + + /** Reads params that together form a Cuboid. These can be: - 6 numbers (MinX, MaxX, MinY, MaxY, MinZ, MaxZ) diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp index 0a748c55d..db797483d 100644 --- a/src/Bindings/ManualBindings_World.cpp +++ b/src/Bindings/ManualBindings_World.cpp @@ -12,6 +12,23 @@ #include "PluginLua.h" #include "LuaChunkStay.h" +#include "BlockEntities/BeaconEntity.h" +#include "BlockEntities/BedEntity.h" +#include "BlockEntities/BrewingstandEntity.h" +#include "BlockEntities/ChestEntity.h" +#include "BlockEntities/CommandBlockEntity.h" +#include "BlockEntities/DispenserEntity.h" +#include "BlockEntities/DropSpenserEntity.h" +#include "BlockEntities/DropperEntity.h" +#include "BlockEntities/FlowerPotEntity.h" +#include "BlockEntities/FurnaceEntity.h" +#include "BlockEntities/HopperEntity.h" +#include "BlockEntities/MobHeadEntity.h" +#include "BlockEntities/NoteEntity.h" + + + + /** Check that a Lua parameter is either a vector or 3 numbers in sequence \param L The Lua state @@ -50,6 +67,183 @@ static bool GetStackVectorOr3Numbers(cLuaState & L, int a_Index, Vector3<T> & a_ +/** Template for the bindings for the DoWithXYZAt(X, Y, Z) functions that don't need to check their coords. */ +template <class BlockEntityType, BLOCKTYPE... BlockTypes> +static int DoWithBlockEntityAt(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + int OffsetIndex; + + // Check params: + if ( + !L.CheckParamSelf("cWorld") || + !CheckParamVectorOr3Numbers(L, "Vector3<int>", 2, OffsetIndex) || + !L.CheckParamFunction(OffsetIndex) || + !L.CheckParamEnd(OffsetIndex + 1) + ) + { + return 0; + } + + cWorld * Self = nullptr; + Vector3i Position; + cLuaState::cRef FnRef; + + // Get parameters: + if ( + !L.GetStackValues(1, Self) || + !GetStackVectorOr3Numbers(L, 2, Position) || + !L.GetStackValues(OffsetIndex, FnRef) + ) + { + return 0; + } + + if (Self == nullptr) + { + return L.ApiParamError("Invalid 'self'"); + } + if (!FnRef.IsValid()) + { + return L.ApiParamError("Expected a valid callback function for parameter %i", OffsetIndex); + } + + // Call the DoWith function: + bool res = Self->DoWithBlockEntityAt(Position, [&L, &FnRef](cBlockEntity & a_BlockEntity) + { + if constexpr (sizeof...(BlockTypes) != 0) + { + if (((a_BlockEntity.GetBlockType() != BlockTypes) && ...)) + { + return false; + } + } + + bool ret = false; + L.Call(FnRef, static_cast<BlockEntityType *>(&a_BlockEntity), cLuaState::Return, ret); + return ret; + }); + + // Push the result as the return value: + L.Push(res); + return 1; +} + + + + + +template < + class Ty1, + class Ty2, + bool (Ty1::*ForEachFn)(const cBoundingBox &, cFunctionRef<bool(Ty2 &)>) +> +static int ForEachInBox(lua_State * tolua_S) +{ + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamUserType(2, "cBoundingBox") || + !L.CheckParamFunction(3) || + !L.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + Ty1 * Self = nullptr; + cBoundingBox * Box = nullptr; + cLuaState::cRef FnRef; + L.GetStackValues(1, Self, Box, FnRef); + if ((Self == nullptr) || (Box == nullptr)) + { + return L.ApiParamError("Invalid world (%p) or boundingbox (%p)", static_cast<void *>(Self), static_cast<void *>(Box)); + } + if (!FnRef.IsValid()) + { + return L.ApiParamError("Expected a valid callback function for parameter #2"); + } + + bool res = (Self->*ForEachFn)(*Box, [&](Ty2 & a_Item) + { + bool ret = false; + if (!L.Call(FnRef, &a_Item, cLuaState::Return, ret)) + { + LOGWARNING("Failed to call Lua callback"); + L.LogStackTrace(); + return true; // Abort enumeration + } + + return ret; + } + ); + + // Push the result as the return value: + L.Push(res); + return 1; +} + + + + + +template <class BlockEntityType, BLOCKTYPE... BlockTypes> +static int ForEachBlockEntityInChunk(lua_State * tolua_S) +{ + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamSelf("cWorld") || + !L.CheckParamNumber(2, 3) || + !L.CheckParamFunction(4) || + !L.CheckParamEnd(5) + ) + { + return 0; + } + + // Get parameters: + cWorld * Self = nullptr; + int ChunkX = 0; + int ChunkZ = 0; + cLuaState::cRef FnRef; + L.GetStackValues(1, Self, ChunkX, ChunkZ, FnRef); + if (Self == nullptr) + { + return L.ApiParamError("Error in function call '#funcname#': Invalid 'self'"); + } + if (!FnRef.IsValid()) + { + return L.ApiParamError("Expected a valid callback function for parameter #4"); + } + + // Call the ForEach function: + bool res = Self->ForEachBlockEntityInChunk(ChunkX, ChunkZ, [&L, &FnRef](cBlockEntity & a_BlockEntity) + { + if constexpr (sizeof...(BlockTypes) != 0) + { + if (((a_BlockEntity.GetBlockType() != BlockTypes) && ...)) + { + return false; + } + } + + bool ret = false; + L.Call(FnRef, static_cast<BlockEntityType *>(&a_BlockEntity), cLuaState::Return, ret); + return ret; + }); + + // Push the result as the return value: + L.Push(res); + return 1; +} + + + + + static int tolua_cWorld_BroadcastBlockAction(lua_State * tolua_S) { /* Function signature: @@ -566,6 +760,53 @@ static int tolua_cWorld_FastSetBlock(lua_State * tolua_S) +static int tolua_cWorld_ForEachEntityInChunk(lua_State * tolua_S) +{ + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamNumber(2, 3) || + !L.CheckParamFunction(4) || + !L.CheckParamEnd(5) + ) + { + return 0; + } + + // Get parameters: + cWorld * Self = nullptr; + int ChunkX = 0; + int ChunkZ = 0; + cLuaState::cRef FnRef; + L.GetStackValues(1, Self, ChunkX, ChunkZ, FnRef); + if (Self == nullptr) + { + return L.ApiParamError("Invalid 'self'"); + } + if (!FnRef.IsValid()) + { + return L.ApiParamError("Expected a valid callback function for parameter #4"); + } + + // Call the DoWith function: + bool res = Self->ForEachEntityInChunk(ChunkX, ChunkZ, [&](cEntity & a_Item) + { + bool ret = false; + L.Call(FnRef, &a_Item, cLuaState::Return, ret); + return ret; + } + ); + + // Push the result as the return value: + L.Push(res); + return 1; +} + + + + + static int tolua_cWorld_ForEachLoadedChunk(lua_State * tolua_S) { // Exported manually, because tolua doesn't support converting functions to functor types. @@ -1347,35 +1588,35 @@ void cManualBindings::BindWorld(lua_State * tolua_S) tolua_function(tolua_S, "BroadcastParticleEffect", tolua_cWorld_BroadcastParticleEffect); tolua_function(tolua_S, "ChunkStay", tolua_cWorld_ChunkStay); tolua_function(tolua_S, "DoExplosionAt", tolua_cWorld_DoExplosionAt); - tolua_function(tolua_S, "DoWithBeaconAt", DoWithXYZ<cWorld, cBeaconEntity, &cWorld::DoWithBeaconAt>); - tolua_function(tolua_S, "DoWithBedAt", DoWithXYZ<cWorld, cBedEntity, &cWorld::DoWithBedAt>); - tolua_function(tolua_S, "DoWithBlockEntityAt", DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>); - tolua_function(tolua_S, "DoWithBrewingstandAt", DoWithXYZ<cWorld, cBrewingstandEntity, &cWorld::DoWithBrewingstandAt>); - tolua_function(tolua_S, "DoWithChestAt", DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); - tolua_function(tolua_S, "DoWithCommandBlockAt", DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>); - tolua_function(tolua_S, "DoWithDispenserAt", DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>); - tolua_function(tolua_S, "DoWithDropSpenserAt", DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>); - tolua_function(tolua_S, "DoWithDropperAt", DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); - tolua_function(tolua_S, "DoWithEntityByID", DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); - tolua_function(tolua_S, "DoWithFlowerPotAt", DoWithXYZ<cWorld, cFlowerPotEntity, &cWorld::DoWithFlowerPotAt>); - tolua_function(tolua_S, "DoWithFurnaceAt", DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); - tolua_function(tolua_S, "DoWithHopperAt", DoWithXYZ<cWorld, cHopperEntity, &cWorld::DoWithHopperAt>); - tolua_function(tolua_S, "DoWithMobHeadAt", DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadAt>); + tolua_function(tolua_S, "DoWithBeaconAt", DoWithBlockEntityAt<cBeaconEntity, E_BLOCK_BEACON>); + tolua_function(tolua_S, "DoWithBedAt", DoWithBlockEntityAt<cBedEntity, E_BLOCK_BED>); + tolua_function(tolua_S, "DoWithBlockEntityAt", DoWithBlockEntityAt<cBlockEntity>); + tolua_function(tolua_S, "DoWithBrewingstandAt", DoWithBlockEntityAt<cBrewingstandEntity, E_BLOCK_BREWING_STAND>); + tolua_function(tolua_S, "DoWithChestAt", DoWithBlockEntityAt<cChestEntity, E_BLOCK_CHEST, E_BLOCK_TRAPPED_CHEST>); + tolua_function(tolua_S, "DoWithCommandBlockAt", DoWithBlockEntityAt<cCommandBlockEntity, E_BLOCK_COMMAND_BLOCK>); + tolua_function(tolua_S, "DoWithDispenserAt", DoWithBlockEntityAt<cDispenserEntity, E_BLOCK_DISPENSER>); + tolua_function(tolua_S, "DoWithDropSpenserAt", DoWithBlockEntityAt<cDropSpenserEntity, E_BLOCK_DISPENSER, E_BLOCK_DROPPER>); + tolua_function(tolua_S, "DoWithDropperAt", DoWithBlockEntityAt<cDropperEntity, E_BLOCK_DROPPER>); + tolua_function(tolua_S, "DoWithEntityByID", DoWithID<cWorld, cEntity, &cWorld::DoWithEntityByID>); + tolua_function(tolua_S, "DoWithFlowerPotAt", DoWithBlockEntityAt<cFlowerPotEntity, E_BLOCK_FLOWER_POT>); + tolua_function(tolua_S, "DoWithFurnaceAt", DoWithBlockEntityAt<cFurnaceEntity, E_BLOCK_FURNACE, E_BLOCK_LIT_FURNACE>); + tolua_function(tolua_S, "DoWithHopperAt", DoWithBlockEntityAt<cHopperEntity, E_BLOCK_HOPPER>); + tolua_function(tolua_S, "DoWithMobHeadAt", DoWithBlockEntityAt<cMobHeadEntity, E_BLOCK_HEAD>); tolua_function(tolua_S, "DoWithNearestPlayer", tolua_cWorld_DoWithNearestPlayer); - tolua_function(tolua_S, "DoWithNoteBlockAt", DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>); - tolua_function(tolua_S, "DoWithPlayer", DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); + tolua_function(tolua_S, "DoWithNoteBlockAt", DoWithBlockEntityAt<cNoteEntity, E_BLOCK_NOTE_BLOCK>); + tolua_function(tolua_S, "DoWithPlayer", DoWith<cWorld, cPlayer, &cWorld::DoWithPlayer>); tolua_function(tolua_S, "DoWithPlayerByUUID", tolua_cWorld_DoWithPlayerByUUID); tolua_function(tolua_S, "FastSetBlock", tolua_cWorld_FastSetBlock); - tolua_function(tolua_S, "FindAndDoWithPlayer", DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); - tolua_function(tolua_S, "ForEachBlockEntityInChunk", ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>); - tolua_function(tolua_S, "ForEachBrewingstandInChunk", ForEachInChunk<cWorld, cBrewingstandEntity, &cWorld::ForEachBrewingstandInChunk>); - tolua_function(tolua_S, "ForEachChestInChunk", ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); - tolua_function(tolua_S, "ForEachEntity", ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); - tolua_function(tolua_S, "ForEachEntityInBox", ForEachInBox< cWorld, cEntity, &cWorld::ForEachEntityInBox>); - tolua_function(tolua_S, "ForEachEntityInChunk", ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>); - tolua_function(tolua_S, "ForEachFurnaceInChunk", ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>); + tolua_function(tolua_S, "FindAndDoWithPlayer", DoWith<cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); + tolua_function(tolua_S, "ForEachBlockEntityInChunk", ForEachBlockEntityInChunk<cBlockEntity>); + tolua_function(tolua_S, "ForEachBrewingstandInChunk", ForEachBlockEntityInChunk<cBrewingstandEntity, E_BLOCK_BREWING_STAND>); + tolua_function(tolua_S, "ForEachChestInChunk", ForEachBlockEntityInChunk<cChestEntity, E_BLOCK_CHEST, E_BLOCK_TRAPPED_CHEST>); + tolua_function(tolua_S, "ForEachEntity", ForEach<cWorld, cEntity, &cWorld::ForEachEntity>); + tolua_function(tolua_S, "ForEachEntityInBox", ForEachInBox<cWorld, cEntity, &cWorld::ForEachEntityInBox>); + tolua_function(tolua_S, "ForEachEntityInChunk", tolua_cWorld_ForEachEntityInChunk); + tolua_function(tolua_S, "ForEachFurnaceInChunk", ForEachBlockEntityInChunk<cFurnaceEntity, E_BLOCK_FURNACE, E_BLOCK_LIT_FURNACE>); tolua_function(tolua_S, "ForEachLoadedChunk", tolua_cWorld_ForEachLoadedChunk); - tolua_function(tolua_S, "ForEachPlayer", ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>); + tolua_function(tolua_S, "ForEachPlayer", ForEach<cWorld, cPlayer, &cWorld::ForEachPlayer>); tolua_function(tolua_S, "GetBlock", tolua_cWorld_GetBlock); tolua_function(tolua_S, "GetBlockBlockLight", tolua_cWorld_GetBlockBlockLight); tolua_function(tolua_S, "GetBlockInfo", tolua_cWorld_GetBlockInfo); diff --git a/src/BlockEntities/BedEntity.cpp b/src/BlockEntities/BedEntity.cpp index 3d7005b12..7f5f90639 100644 --- a/src/BlockEntities/BedEntity.cpp +++ b/src/BlockEntities/BedEntity.cpp @@ -56,12 +56,4 @@ void cBedEntity::SendTo(cClientHandle & a_Client) void cBedEntity::SetColor(short a_Color) { m_Color = a_Color; - auto Pos = GetPos(); - - // If the bed entity is send immediately, the client (maybe) still has not the bed. - // Fix that by delaying the broadcast of the bed entity by a tick: - m_World->ScheduleTask(1, [Pos](cWorld & a_World) - { - a_World.BroadcastBlockEntity(Pos); - }); } diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp index 039d62287..9ede18759 100644 --- a/src/BlockEntities/ChestEntity.cpp +++ b/src/BlockEntities/ChestEntity.cpp @@ -146,24 +146,25 @@ bool cChestEntity::UsedBy(cPlayer * a_Player) void cChestEntity::ScanNeighbours() { - // Callback for finding neighbouring chest: - auto FindNeighbour = [this](cChestEntity & a_Chest) + // Callback for finding neighbouring chest. + auto FindNeighbour = [this](cBlockEntity & a_BlockEntity) { - if (a_Chest.GetBlockType() != m_BlockType) + if (a_BlockEntity.GetBlockType() != m_BlockType) { // Neighboring block is not the same type of chest - return true; + return false; } - m_Neighbour = &a_Chest; - return false; + + m_Neighbour = static_cast<cChestEntity *>(&a_BlockEntity); + return true; }; // Scan horizontally adjacent blocks for any neighbouring chest of the same type: if ( - m_World->DoWithChestAt(m_Pos.x - 1, m_Pos.y, m_Pos.z, FindNeighbour) || - m_World->DoWithChestAt(m_Pos.x + 1, m_Pos.y, m_Pos.z, FindNeighbour) || - m_World->DoWithChestAt(m_Pos.x, m_Pos.y, m_Pos.z - 1, FindNeighbour) || - m_World->DoWithChestAt(m_Pos.x, m_Pos.y, m_Pos.z + 1, FindNeighbour) + m_World->DoWithBlockEntityAt(m_Pos.addedX(-1), FindNeighbour) || + m_World->DoWithBlockEntityAt(m_Pos.addedX(+1), FindNeighbour) || + m_World->DoWithBlockEntityAt(m_Pos.addedZ(-1), FindNeighbour) || + m_World->DoWithBlockEntityAt(m_Pos.addedX(+1), FindNeighbour) ) { m_Neighbour->m_Neighbour = this; diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index c1e2cd430..34b0fd5f5 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -43,15 +43,6 @@ bool cCommandBlockEntity::UsedBy(cPlayer * a_Player) void cCommandBlockEntity::SetCommand(const AString & a_Cmd) { m_Command = a_Cmd; - - /* - Vanilla requires that the server send a Block Entity Update after a command has been set - Therefore, command blocks don't support on-the-fly (when window is open) updating of a command and therefore... - ...the following code can't be put in UsedBy just before the window opens - - Just documenting my experience in getting this to work :P - */ - m_World->BroadcastBlockEntity(GetPos()); } @@ -60,7 +51,6 @@ void cCommandBlockEntity::SetCommand(const AString & a_Cmd) void cCommandBlockEntity::SetLastOutput(const AString & a_LastOut) { - m_World->BroadcastBlockEntity(GetPos()); m_LastOutput = a_LastOut; } @@ -180,7 +170,6 @@ void cCommandBlockEntity::Execute() { // Overwrite field m_CmdBlock->SetLastOutput(cClientHandle::FormatChatPrefix(m_CmdBlock->GetWorld()->ShouldUseChatPrefixes(), "SUCCESS", cChatColor::Green, cChatColor::White) + a_Text); - m_CmdBlock->GetWorld()->BroadcastBlockEntity(m_CmdBlock->GetPos()); } }; diff --git a/src/BlockEntities/MobHeadEntity.cpp b/src/BlockEntities/MobHeadEntity.cpp index 14773a0f1..72d039e7e 100644 --- a/src/BlockEntities/MobHeadEntity.cpp +++ b/src/BlockEntities/MobHeadEntity.cpp @@ -33,7 +33,6 @@ void cMobHeadEntity::SetType(const eMobHeadType & a_Type) m_OwnerUUID = cUUID{}; } m_Type = a_Type; - m_World->BroadcastBlockEntity(GetPos()); } @@ -43,7 +42,6 @@ void cMobHeadEntity::SetType(const eMobHeadType & a_Type) void cMobHeadEntity::SetRotation(eMobHeadRotation a_Rotation) { m_Rotation = a_Rotation; - m_World->BroadcastBlockEntity(GetPos()); } @@ -70,8 +68,6 @@ void cMobHeadEntity::SetOwner(const cPlayer & a_Owner) break; } } - - m_World->BroadcastBlockEntity(GetPos()); } @@ -89,7 +85,6 @@ void cMobHeadEntity::SetOwner(const cUUID & a_OwnerUUID, const AString & a_Owner m_OwnerName = a_OwnerName; m_OwnerTexture = a_OwnerTexture; m_OwnerTextureSignature = a_OwnerTextureSignature; - m_World->BroadcastBlockEntity(GetPos()); } diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp index 78312edb1..8e5585b89 100644 --- a/src/BlockEntities/MobSpawnerEntity.cpp +++ b/src/BlockEntities/MobSpawnerEntity.cpp @@ -70,6 +70,7 @@ bool cMobSpawnerEntity::UsedBy(cPlayer * a_Player) { a_Player->GetInventory().RemoveOneEquippedItem(); } + m_World->BroadcastBlockEntity(GetPos()); FLOGD("Changed monster spawner at {0} to type {1}.", GetPos(), cMonster::MobTypeToString(MonsterType)); return true; } @@ -105,6 +106,7 @@ bool cMobSpawnerEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) if (m_SpawnDelay <= 0) { SpawnEntity(); + m_World->BroadcastBlockEntity(GetPos()); return true; } else @@ -121,7 +123,6 @@ bool cMobSpawnerEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) void cMobSpawnerEntity::ResetTimer(void) { m_SpawnDelay = GetRandomProvider().RandInt<short>(m_MinSpawnDelay, m_MaxSpawnDelay); - m_World->BroadcastBlockEntity(GetPos()); } diff --git a/src/BlockType.h b/src/BlockType.h index f98d9db82..4814c5a68 100644 --- a/src/BlockType.h +++ b/src/BlockType.h @@ -1181,36 +1181,3 @@ extern AString ItemToFullString(const cItem & a_Item); extern cItem GetIniItemSet(cIniFile & a_IniFile, const char * a_Section, const char * a_Key, const char * a_Default); // tolua_end - - - - - -/** Base case for IsOneOf to handle empty template aguments. */ -template <class = void> -bool IsOneOf(BLOCKTYPE a_BlockType) -{ - return false; -} - - -/** Returns true if a_BlockType is equal to any of the variadic template arguments. -Some example usage: -\code - IsOneOf<>(E_BLOCK_AIR) == false - IsOneOf<E_BLOCK_AIR>(E_BLOCK_DIRT) == false - IsOneOf<E_BLOCK_AIR, E_BLOCK_DIRT>(E_BLOCK_DIRT) == true -\endcode -The implementation is ugly but it is equivalent to this C++17 fold expression: -\code - ((a_BlockType == Types) || ...) -\endcode -Just written to be valid without fold expressions or SFINAE. */ -template <BLOCKTYPE Head, BLOCKTYPE ... Tail> -bool IsOneOf(BLOCKTYPE a_BlockType) -{ - return ((a_BlockType == Head) || (IsOneOf<Tail...>(a_BlockType))); -} - - - diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp index 58ff720c8..4fd3eba54 100644 --- a/src/Blocks/BlockBed.cpp +++ b/src/Blocks/BlockBed.cpp @@ -158,12 +158,12 @@ bool cBlockBedHandler::OnUse( void cBlockBedHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) const { - a_Player.GetWorld()->DoWithBedAt(a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(), [&](cBedEntity & a_Bed) - { - a_Bed.SetColor(a_Player.GetEquippedItem().m_ItemDamage); - return true; - } - ); + a_Player.GetWorld()->DoWithBlockEntityAt(a_BlockChange.GetAbsolutePos(), [&a_Player](cBlockEntity & a_BlockEntity) + { + ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_BED); + static_cast<cBedEntity &>(a_BlockEntity).SetColor(a_Player.GetEquippedItem().m_ItemDamage); + return false; + }); } diff --git a/src/Blocks/BlockEnchantingTable.h b/src/Blocks/BlockEnchantingTable.h index c921d8f27..33d7092e3 100644 --- a/src/Blocks/BlockEnchantingTable.h +++ b/src/Blocks/BlockEnchantingTable.h @@ -32,7 +32,7 @@ private: ) const override { AString WindowName = "Enchant"; - a_WorldInterface.DoWithBlockEntityAt(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, [&WindowName](cBlockEntity & a_Entity) + a_WorldInterface.DoWithBlockEntityAt(a_BlockPos, [&WindowName](cBlockEntity & a_Entity) { if (a_Entity.GetBlockType() != E_BLOCK_ENCHANTMENT_TABLE) { @@ -46,7 +46,7 @@ private: WindowName = CustomName; } - return true; + return false; }); cWindow * Window = new cEnchantingWindow(a_BlockPos, std::move(WindowName)); diff --git a/src/Blocks/BlockNoteBlock.h b/src/Blocks/BlockNoteBlock.h index ac1ab7238..566b9bef5 100644 --- a/src/Blocks/BlockNoteBlock.h +++ b/src/Blocks/BlockNoteBlock.h @@ -26,18 +26,15 @@ private: const Vector3i a_BlockPos ) const override { - a_WorldInterface.DoWithBlockEntityAt(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, [](cBlockEntity & a_BlockEntity) + a_WorldInterface.DoWithBlockEntityAt(a_BlockPos, [](cBlockEntity & a_BlockEntity) { if (a_BlockEntity.GetBlockType() != E_BLOCK_NOTE_BLOCK) { return false; } - auto & NoteEntity = static_cast<cNoteEntity &>(a_BlockEntity); - - NoteEntity.MakeSound(); - - return true; + static_cast<cNoteEntity &>(a_BlockEntity).MakeSound(); + return false; }); } }; diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index 2a39ffbc2..4ae3f33c9 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -4,13 +4,11 @@ #include "../FunctionRef.h" #include "../Mobs/MonsterTypes.h" -class cBedEntity; class cBlockEntity; class cBroadcastInterface; class cItems; class cPlayer; -using cBedCallback = cFunctionRef<bool(cBedEntity &)>; using cBlockEntityCallback = cFunctionRef<bool(cBlockEntity &)>; using cPlayerListCallback = cFunctionRef<bool(cPlayer &)>; using cEntityCallback = cFunctionRef<bool(cEntity &)>; @@ -32,10 +30,8 @@ public: virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) = 0; - virtual bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback a_Callback) = 0; - /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ - virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback a_Callback) = 0; + virtual bool DoWithBlockEntityAt(Vector3i a_Position, cBlockEntityCallback a_Callback) = 0; /** 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 IsPlayerCreated = false) = 0; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 161a42512..09b0f0f99 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -12,21 +12,6 @@ #include "ClientHandle.h" #include "Server.h" #include "Defines.h" -#include "BlockEntities/BeaconEntity.h" -#include "BlockEntities/BedEntity.h" -#include "BlockEntities/BrewingstandEntity.h" -#include "BlockEntities/ChestEntity.h" -#include "BlockEntities/CommandBlockEntity.h" -#include "BlockEntities/DispenserEntity.h" -#include "BlockEntities/DropperEntity.h" -#include "BlockEntities/FlowerPotEntity.h" -#include "BlockEntities/FurnaceEntity.h" -#include "BlockEntities/HopperEntity.h" -#include "BlockEntities/JukeboxEntity.h" -#include "BlockEntities/MobHeadEntity.h" -#include "BlockEntities/MobSpawnerEntity.h" -#include "BlockEntities/NoteEntity.h" -#include "BlockEntities/SignEntity.h" #include "Entities/Pickup.h" #include "Item.h" #include "Noise/Noise.h" @@ -468,7 +453,6 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock auto clone = be->Clone({posX, posY, posZ}); clone->SetWorld(m_World); AddBlockEntity(std::move(clone)); - m_World->BroadcastBlockEntity({posX, posY, posZ}); } } } @@ -789,28 +773,34 @@ void cChunk::MoveEntityToNewChunk(OwnedEntity a_Entity) void cChunk::BroadcastPendingBlockChanges(void) { - if (m_PendingSendBlocks.empty()) + if (const auto PendingBlocksCount = m_PendingSendBlocks.size(); PendingBlocksCount >= 10240) { - return; - } - - if (m_PendingSendBlocks.size() >= 10240) - { - // Resend the full chunk - for (auto ClientHandle : m_LoadedByClient) + // Resend the full chunk: + for (const auto ClientHandle : m_LoadedByClient) { m_World->ForceSendChunkTo(m_PosX, m_PosZ, cChunkSender::Priority::Medium, ClientHandle); } } - else + else if (PendingBlocksCount != 0) { - // Only send block changes - for (auto ClientHandle : m_LoadedByClient) + // Send block changes: + for (const auto ClientHandle : m_LoadedByClient) { ClientHandle->SendBlockChanges(m_PosX, m_PosZ, m_PendingSendBlocks); } } + + // Send block entity changes: + for (const auto Entity : m_PendingSendBlockEntities) + { + for (const auto ClientHandle : m_LoadedByClient) + { + Entity->SendTo(*ClientHandle); + } + } + m_PendingSendBlocks.clear(); + m_PendingSendBlockEntities.clear(); } @@ -823,12 +813,12 @@ void cChunk::CheckBlocks() cBlockInServerPluginInterface PluginInterface(*m_World); // Process a limited number of blocks since cBlockHandler::Check may queue more to tick - auto Count = m_ToTickBlocks.size(); + auto Count = m_BlocksToCheck.size(); while (Count != 0) { - const auto Pos = m_ToTickBlocks.front(); - m_ToTickBlocks.pop(); + const auto Pos = m_BlocksToCheck.front(); + m_BlocksToCheck.pop(); Count--; cBlockHandler::For(GetBlock(Pos)).Check(ChunkInterface, PluginInterface, Pos, *this); @@ -1265,8 +1255,8 @@ void cChunk::SetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_Blo { FastSetBlock(a_RelPos, a_BlockType, a_BlockMeta); - // Tick this block's neighbors via cBlockHandler::Check: - m_ToTickBlocks.push(a_RelPos); + // Queue a check of this block's neighbors: + m_BlocksToCheck.push(a_RelPos); // Wake up the simulators for this block: GetWorld()->GetSimulatorManager()->WakeUp(*this, a_RelPos); @@ -1370,22 +1360,26 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client) { + const auto BlockEntity = GetBlockEntityRel({ a_RelX, a_RelY, a_RelZ }); if (a_Client == nullptr) { - // Queue the block for all clients in the chunk (will be sent in Tick()) + // Queue the block (entity) for all clients in the chunk (will be sent in BroadcastPendingBlockChanges()): m_PendingSendBlocks.emplace_back(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ)); + if (BlockEntity != nullptr) + { + m_PendingSendBlockEntities.push_back(BlockEntity); + } return; } - Vector3i wp = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ); - a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ)); + const auto Position = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ); + a_Client->SendBlockChange(Position.x, Position.y, Position.z, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ)); // FS #268 - if a BlockEntity digging is cancelled by a plugin, the entire block entity must be re-sent to the client: - cBlockEntity * Block = GetBlockEntity(wp.x, wp.y, wp.z); - if (Block != nullptr) + if (BlockEntity != nullptr) { - Block->SendTo(*a_Client); + BlockEntity->SendTo(*a_Client); } } @@ -1508,39 +1502,12 @@ void cChunk::SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_Max -bool cChunk::SetSignLines(int a_PosX, int a_PosY, int a_PosZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) -{ - // Also sends update packets to all clients in the chunk - auto Entity = GetBlockEntity(a_PosX, a_PosY, a_PosZ); - if (Entity == nullptr) - { - return false; // Not a block entity - } - if ( - (Entity->GetBlockType() != E_BLOCK_WALLSIGN) && - (Entity->GetBlockType() != E_BLOCK_SIGN_POST) - ) - { - return false; // Not a sign - } - - MarkDirty(); - auto Sign = static_cast<cSignEntity *>(Entity); - Sign->SetLines(a_Line1, a_Line2, a_Line3, a_Line4); - m_World->BroadcastBlockEntity({a_PosX, a_PosY, a_PosZ}); - return true; -} - - - - - void cChunk::RemoveBlockEntity(cBlockEntity * a_BlockEntity) { MarkDirty(); ASSERT(a_BlockEntity != nullptr); - auto idx = static_cast<size_t>(cChunkDef::MakeIndex(a_BlockEntity->GetRelX(), a_BlockEntity->GetPosY(), a_BlockEntity->GetRelZ())); - m_BlockEntities.erase(idx); + m_BlockEntities.erase(static_cast<size_t>(cChunkDef::MakeIndex(a_BlockEntity->GetRelX(), a_BlockEntity->GetPosY(), a_BlockEntity->GetRelZ()))); + m_PendingSendBlockEntities.erase(std::remove(m_PendingSendBlockEntities.begin(), m_PendingSendBlockEntities.end(), a_BlockEntity), m_PendingSendBlockEntities.end()); } @@ -1745,308 +1712,39 @@ bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback a_Callback, boo -template <class tyEntity, BLOCKTYPE... tBlocktype> -bool cChunk::GenericForEachBlockEntity(cFunctionRef<bool(tyEntity &)> a_Callback) +bool cChunk::ForEachBlockEntity(cBlockEntityCallback a_Callback) { // The blockentity list is locked by the parent chunkmap's CS + for (auto & KeyPair : m_BlockEntities) { - cBlockEntity * Block = KeyPair.second.get(); - if ( - (sizeof...(tBlocktype) == 0) || // Let empty list mean all block entities - (IsOneOf<tBlocktype...>(Block->GetBlockType())) - ) + if (a_Callback(*KeyPair.second)) { - if (a_Callback(*static_cast<tyEntity *>(Block))) - { - return false; - } + return false; } - } // for KeyPair - m_BlockEntitites[] - return true; -} - - - - - -bool cChunk::ForEachBlockEntity(cBlockEntityCallback a_Callback) -{ - return GenericForEachBlockEntity<cBlockEntity>(a_Callback); -} - - - - - -bool cChunk::ForEachBrewingstand(cBrewingstandCallback a_Callback) -{ - return GenericForEachBlockEntity<cBrewingstandEntity, - E_BLOCK_BREWING_STAND - >(a_Callback); -} - - - - - -bool cChunk::ForEachChest(cChestCallback a_Callback) -{ - return GenericForEachBlockEntity<cChestEntity, - E_BLOCK_CHEST - >(a_Callback); -} - - - - - -bool cChunk::ForEachDispenser(cDispenserCallback a_Callback) -{ - return GenericForEachBlockEntity<cDispenserEntity, - E_BLOCK_DISPENSER - >(a_Callback); -} - - - - - -bool cChunk::ForEachDropper(cDropperCallback a_Callback) -{ - return GenericForEachBlockEntity<cDropperEntity, - E_BLOCK_DROPPER - >(a_Callback); -} - - - - - -bool cChunk::ForEachDropSpenser(cDropSpenserCallback a_Callback) -{ - return GenericForEachBlockEntity<cDropSpenserEntity, - E_BLOCK_DISPENSER, - E_BLOCK_DROPPER - >(a_Callback); -} - - - - - -bool cChunk::ForEachFurnace(cFurnaceCallback a_Callback) -{ - return GenericForEachBlockEntity<cFurnaceEntity, - E_BLOCK_FURNACE, - E_BLOCK_LIT_FURNACE - >(a_Callback); -} - - - - - -template <class tyEntity, BLOCKTYPE... tBlocktype> -bool cChunk::GenericDoWithBlockEntityAt(Vector3i a_Position, cFunctionRef<bool(tyEntity &)> a_Callback) -{ - // The blockentity list is locked by the parent chunkmap's CS - cBlockEntity * Block = GetBlockEntityRel(a_Position); - if (Block == nullptr) - { - return false; // No block entity here } - if ( - (sizeof...(tBlocktype) != 0) && // Let empty list mean all block entities - (!IsOneOf<tBlocktype...>(Block->GetBlockType())) - ) - { - return false; // Not any of the given tBlocktypes - } - return !a_Callback(*static_cast<tyEntity *>(Block)); -} - - - - -bool cChunk::DoWithBlockEntityAt(Vector3i a_Position, cBlockEntityCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cBlockEntity>(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithBeaconAt(Vector3i a_Position, cBeaconCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cBeaconEntity, - E_BLOCK_BEACON - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithBedAt(Vector3i a_Position, cBedCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cBedEntity, - E_BLOCK_BED - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithBrewingstandAt(Vector3i a_Position, cBrewingstandCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cBrewingstandEntity, - E_BLOCK_BREWING_STAND - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithChestAt(Vector3i a_Position, cChestCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cChestEntity, - E_BLOCK_CHEST, - E_BLOCK_TRAPPED_CHEST - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithDispenserAt(Vector3i a_Position, cDispenserCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cDispenserEntity, - E_BLOCK_DISPENSER - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithDropperAt(Vector3i a_Position, cDropperCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cDropperEntity, - E_BLOCK_DROPPER - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithDropSpenserAt(Vector3i a_Position, cDropSpenserCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cDropSpenserEntity, - E_BLOCK_DISPENSER, - E_BLOCK_DROPPER - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithFurnaceAt(Vector3i a_Position, cFurnaceCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cFurnaceEntity, - E_BLOCK_FURNACE, - E_BLOCK_LIT_FURNACE - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithHopperAt(Vector3i a_Position, cHopperCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cHopperEntity, - E_BLOCK_HOPPER - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithNoteBlockAt(Vector3i a_Position, cNoteBlockCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cNoteEntity, - E_BLOCK_NOTE_BLOCK - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithCommandBlockAt(Vector3i a_Position, cCommandBlockCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cCommandBlockEntity, - E_BLOCK_COMMAND_BLOCK - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithMobHeadAt(Vector3i a_Position, cMobHeadCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cMobHeadEntity, - E_BLOCK_HEAD - >(a_Position, a_Callback); -} - - - - - -bool cChunk::DoWithFlowerPotAt(Vector3i a_Position, cFlowerPotCallback a_Callback) -{ - return GenericDoWithBlockEntityAt<cFlowerPotEntity, - E_BLOCK_FLOWER_POT - >(a_Position, a_Callback); + return true; } -bool cChunk::GetSignLines(Vector3i a_Position, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) +bool cChunk::DoWithBlockEntityAt(Vector3i a_Position, cBlockEntityCallback a_Callback) { // The blockentity list is locked by the parent chunkmap's CS - auto Entity = GetBlockEntity(a_Position); - if (Entity == nullptr) - { - return false; // Not a block entity - } - if ( - (Entity->GetBlockType() != E_BLOCK_WALLSIGN) && - (Entity->GetBlockType() != E_BLOCK_SIGN_POST) - ) + + const auto BlockEntity = GetBlockEntityRel(a_Position); + if (BlockEntity == nullptr) { - return false; // Not a sign + return false; // No block entity here } - auto Sign = static_cast<cSignEntity *>(Entity); - a_Line1 = Sign->GetLine(0); - a_Line2 = Sign->GetLine(1); - a_Line3 = Sign->GetLine(2); - a_Line4 = Sign->GetLine(3); - return true; + const bool Result = a_Callback(*BlockEntity); + m_PendingSendBlockEntities.push_back(BlockEntity); + MarkDirty(); + return Result; } diff --git a/src/Chunk.h b/src/Chunk.h index ce735df8e..c51794d24 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -2,7 +2,6 @@ #pragma once #include "BlockEntities/BlockEntity.h" -#include "Entities/Entity.h" #include "ChunkData.h" #include "Simulator/FireSimulator.h" @@ -19,19 +18,8 @@ class cWorld; class cClientHandle; class cPlayer; class cChunkMap; -class cBeaconEntity; -class cBedEntity; -class cBrewingstandEntity; class cBoundingBox; -class cChestEntity; class cChunkDataCallback; -class cCommandBlockEntity; -class cDispenserEntity; -class cFurnaceEntity; -class cHopperEntity; -class cNoteEntity; -class cMobHeadEntity; -class cFlowerPotEntity; class cBlockArea; class cBlockArea; class cFluidSimulatorData; @@ -212,9 +200,6 @@ public: Sends the chunk to all relevant clients. */ void SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_MaxRelZ, EMCSBiome a_Biome); - /** Sets the sign text. Returns true if successful. Also sends update packets to all clients in the chunk */ - bool SetSignLines(int a_RelX, int a_RelY, int a_RelZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); - int GetHeight( int a_X, int a_Z) const; /** Returns true if it is sunny at the specified location. This takes into account biomes. */ @@ -259,84 +244,12 @@ public: /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. */ bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback a_Callback, bool & a_CallbackResult) const; // Lua-accessible - /** Calls the callback for each tyEntity; returns true if all block entities processed, false if the callback aborted by returning true - tBlocktypes are all blocktypes convertible to tyEntity which are to be called. If no block type is given the callback is called for every block entity - Accessible only from within Chunk.cpp */ - template <class tyEntity, BLOCKTYPE... tBlocktype> - bool GenericForEachBlockEntity(cFunctionRef<bool(tyEntity &)> a_Callback); - /** Calls the callback for each block entity; returns true if all block entities processed, false if the callback aborted by returning true */ bool ForEachBlockEntity(cBlockEntityCallback a_Callback); // Lua-accessible - /** Calls the callback for each brewingstand; returns true if all brewingstands processed, false if the callback aborted by returning true */ - bool ForEachBrewingstand(cBrewingstandCallback a_Callback); // Lua-accessible - - /** Calls the callback for each chest; returns true if all chests processed, false if the callback aborted by returning true */ - bool ForEachChest(cChestCallback a_Callback); // Lua-accessible - - /** Calls the callback for each dispenser; returns true if all dispensers processed, false if the callback aborted by returning true */ - bool ForEachDispenser(cDispenserCallback a_Callback); - - /** Calls the callback for each dropper; returns true if all droppers processed, false if the callback aborted by returning true */ - bool ForEachDropper(cDropperCallback a_Callback); - - /** Calls the callback for each dropspenser; returns true if all dropspensers processed, false if the callback aborted by returning true */ - bool ForEachDropSpenser(cDropSpenserCallback a_Callback); - - /** Calls the callback for each furnace; returns true if all furnaces processed, false if the callback aborted by returning true */ - bool ForEachFurnace(cFurnaceCallback a_Callback); // Lua-accessible - - /** Calls the callback for the tyEntity at the specified coords; returns false if there's no such block entity at those coords, true if found - tBlocktype is a list of the blocktypes to be called. If no BLOCKTYPE template arguments are given the callback is called for any block entity - Accessible only from within Chunk.cpp */ - template <class tyEntity, BLOCKTYPE... tBlocktype> - bool GenericDoWithBlockEntityAt(Vector3i a_Position, cFunctionRef<bool(tyEntity &)> a_Callback); - - /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ + /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, and whatever the callback returns if found. */ bool DoWithBlockEntityAt(Vector3i a_Position, cBlockEntityCallback a_Callback); // Lua-acessible - /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ - bool DoWithBeaconAt(Vector3i a_Position, cBeaconCallback a_Callback); // Lua-acessible - - /** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */ - bool DoWithBrewingstandAt(Vector3i a_Position, cBrewingstandCallback a_Callback); // Lua-acessible - - /** Calls the callback for the bed at the specified coords; returns false if there's no bed at those coords, true if found */ - bool DoWithBedAt(Vector3i a_Position, cBedCallback a_Callback); // Lua-acessible - - /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ - bool DoWithChestAt(Vector3i a_Position, cChestCallback a_Callback); // Lua-acessible - - /** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */ - bool DoWithDispenserAt(Vector3i a_Position, cDispenserCallback a_Callback); - - /** Calls the callback for the dispenser at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */ - bool DoWithDropperAt(Vector3i a_Position, cDropperCallback a_Callback); - - /** Calls the callback for the dispenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */ - bool DoWithDropSpenserAt(Vector3i a_Position, cDropSpenserCallback a_Callback); - - /** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */ - bool DoWithFurnaceAt(Vector3i a_Position, cFurnaceCallback a_Callback); // Lua-accessible - - /** Calls the callback for the hopper at the specified coords; returns false if there's no hopper at those coords or callback returns true, returns true if found */ - bool DoWithHopperAt(Vector3i a_Position, cHopperCallback a_Callback); // Lua-accessible - - /** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */ - bool DoWithNoteBlockAt(Vector3i a_Position, cNoteBlockCallback a_Callback); - - /** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */ - bool DoWithCommandBlockAt(Vector3i a_Position, cCommandBlockCallback a_Callback); - - /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */ - bool DoWithMobHeadAt(Vector3i a_Position, cMobHeadCallback a_Callback); - - /** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */ - bool DoWithFlowerPotAt(Vector3i a_Position, cFlowerPotCallback a_Callback); - - /** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */ - bool GetSignLines (Vector3i a_Position, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible - /** Use block entity on coordinate. returns true if the use was successful, return false to use the block as a "normal" block */ bool UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // [x, y, z] in world block coords @@ -529,9 +442,9 @@ public: as at least one requests is active the chunk will be ticked). */ void SetAlwaysTicked(bool a_AlwaysTicked); - cChunkClientHandles GetAllClients(void) const + const auto & GetAllClients(void) const { - return cChunkClientHandles(m_LoadedByClient); + return m_LoadedByClient; } /** Converts the coord relative to this chunk into an absolute coord. @@ -570,8 +483,19 @@ private: bool m_IsDirty; // True if the chunk has changed since it was last saved bool m_IsSaving; // True if the chunk is being saved - std::queue<Vector3i> m_ToTickBlocks; - sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients + /** Blocks that have changed and need to be sent to all clients. + The protocol has a provision for coalescing block changes, and this is the buffer. + It will collect the block changes that occur in a tick, before being flushed in BroadcastPendingSendBlocks. */ + sSetBlockVector m_PendingSendBlocks; + + /** Block entities that have been touched and need to be sent to all clients. + Because block changes are buffered and we need to happen after them, this buffer exists too. + Pointers to block entities that were destroyed are guaranteed to be removed from this array by RemoveBlockEntity. */ + std::vector<cBlockEntity *> m_PendingSendBlockEntities; + + /** A queue of relative positions to call cBlockHandler::Check on. + Processed at the end of each tick by CheckBlocks. */ + std::queue<Vector3i> m_BlocksToCheck; // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers std::vector<cClientHandle *> m_LoadedByClient; diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 9e97d53fc..673ae347a 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -98,33 +98,6 @@ public: -/** Non-owning view of a chunk's client handles. */ -class cChunkClientHandles -{ -public: - using const_iterator = std::vector<cClientHandle *>::const_iterator; - using iterator = const_iterator; - - explicit cChunkClientHandles(const std::vector<cClientHandle *> & a_Container): - m_Begin(a_Container.cbegin()), - m_End(a_Container.cend()) - { - } - - const_iterator begin() const { return m_Begin; } - const_iterator cbegin() const { return m_Begin; } - - const_iterator end() const { return m_End; } - const_iterator cend() const { return m_End; } - -private: - const_iterator m_Begin, m_End; -}; - - - - - /** Constants used throughout the code, useful typedefs and utility functions */ class cChunkDef { diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index dbd6f8cf3..7bdd1c649 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -11,7 +11,6 @@ #include "Generating/Trees.h" // used in cChunkMap::ReplaceTreeBlocks() for tree block discrimination #include "BlockArea.h" #include "Bindings/PluginManager.h" -#include "Entities/TNTEntity.h" #include "Blocks/BlockHandler.h" #include "MobCensus.h" #include "MobSpawner.h" @@ -20,7 +19,6 @@ #include "Blocks/ChunkInterface.h" #include "Entities/Pickup.h" #include "DeadlockDetect.h" -#include "BlockEntities/BlockEntity.h" @@ -840,8 +838,8 @@ void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, void cChunkMap::CompareChunkClients(cChunk * a_Chunk1, cChunk * a_Chunk2, cClientDiffCallback & a_Callback) { - auto Clients1 = a_Chunk1->GetAllClients(); - auto Clients2 = a_Chunk2->GetAllClients(); + const auto & Clients1 = a_Chunk1->GetAllClients(); + const auto & Clients2 = a_Chunk2->GetAllClients(); // Find "removed" clients: for (auto * Client : Clients1) @@ -1074,360 +1072,17 @@ bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEnti -bool cChunkMap::ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, cBrewingstandCallback a_Callback) +bool cChunkMap::DoWithBlockEntityAt(const Vector3i a_Position, cBlockEntityCallback a_Callback) { + const auto ChunkPosition = cChunkDef::BlockToChunk(a_Position); + const auto Relative = cChunkDef::AbsoluteToRelative(a_Position, ChunkPosition); cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->ForEachBrewingstand(a_Callback); -} - - - - - -bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback a_Callback) -{ - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->ForEachChest(a_Callback); -} - - - - - -bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback a_Callback) -{ - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->ForEachDispenser(a_Callback); -} - - - - - -bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback a_Callback) -{ - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->ForEachDropper(a_Callback); -} - - - - - -bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback a_Callback) -{ - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->ForEachDropSpenser(a_Callback); -} - - - - - -bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback a_Callback) -{ - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->ForEachFurnace(a_Callback); -} - - - - - -bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithBlockEntityAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithBeaconAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithBedAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithBrewingstandAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithChestAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithDispenserAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithDropperAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithDropSpenserAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithFurnaceAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithHopperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithHopperAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithNoteBlockAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithCommandBlockAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithMobHeadAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback a_Callback) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->DoWithFlowerPotAt({ BlockX, BlockY, BlockZ }, a_Callback); -} - - - - - -bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) -{ - int ChunkX, ChunkZ; - int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; - cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSChunks); - const auto Chunk = FindChunk(ChunkX, ChunkZ); + const auto Chunk = FindChunk(ChunkPosition.m_ChunkX, ChunkPosition.m_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } - return Chunk->GetSignLines({ BlockX, BlockY, BlockZ }, a_Line1, a_Line2, a_Line3, a_Line4); + return Chunk->DoWithBlockEntityAt(Relative, a_Callback); } @@ -1479,23 +1134,6 @@ void cChunkMap::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ) -bool cChunkMap::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) -{ - cCSLock Lock(m_CSChunks); - int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - const auto Chunk = FindChunk(ChunkX, ChunkZ); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - return Chunk->SetSignLines(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4); -} - - - - - void cChunkMap::MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSChunks); diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 99a1d764d..d0aeb867c 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -18,19 +18,6 @@ class cItems; class cChunkStay; class cChunk; class cPlayer; -class cBeaconEntity; -class cBedEntity; -class cBrewingstandEntity; -class cChestEntity; -class cDispenserEntity; -class cDropperEntity; -class cDropSpenserEntity; -class cFurnaceEntity; -class cHopperEntity; -class cNoteEntity; -class cCommandBlockEntity; -class cMobHeadEntity; -class cFlowerPotEntity; class cBlockArea; class cMobCensus; class cMobSpawner; @@ -40,22 +27,9 @@ class cDeadlockDetect; struct SetChunkData; typedef std::list<cClientHandle *> cClientHandleList; -using cEntityCallback = cFunctionRef<bool(cEntity &)>; -using cBeaconCallback = cFunctionRef<bool(cBeaconEntity &)>; -using cBedCallback = cFunctionRef<bool(cBedEntity &)>; -using cBlockEntityCallback = cFunctionRef<bool(cBlockEntity &)>; -using cBrewingstandCallback = cFunctionRef<bool(cBrewingstandEntity &)>; -using cChestCallback = cFunctionRef<bool(cChestEntity &)>; -using cChunkCallback = cFunctionRef<bool(cChunk &)>; -using cDispenserCallback = cFunctionRef<bool(cDispenserEntity &)>; -using cDropperCallback = cFunctionRef<bool(cDropperEntity &)>; -using cDropSpenserCallback = cFunctionRef<bool(cDropSpenserEntity &)>; -using cFurnaceCallback = cFunctionRef<bool(cFurnaceEntity &)>; -using cHopperCallback = cFunctionRef<bool(cHopperEntity &)>; -using cNoteBlockCallback = cFunctionRef<bool(cNoteEntity &)>; -using cCommandBlockCallback = cFunctionRef<bool(cCommandBlockEntity &)>; -using cMobHeadCallback = cFunctionRef<bool(cMobHeadEntity &)>; -using cFlowerPotCallback = cFunctionRef<bool(cFlowerPotEntity &)>; +using cChunkCallback = cFunctionRef<bool(cChunk &)>; +using cEntityCallback = cFunctionRef<bool(cEntity &)>; +using cBlockEntityCallback = cFunctionRef<bool(cBlockEntity &)>; @@ -228,88 +202,9 @@ public: Returns true if all block entities processed, false if the callback aborted by returning true. */ bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback a_Callback); // Lua-accessible - /** Calls the callback for brewingstand in the specified chunk. - Returns true if all brewingstands processed, false if the callback aborted by returning true. */ - bool ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, cBrewingstandCallback a_Callback); // Lua-accessible - - /** Calls the callback for each chest in the specified chunk. - Returns true if all chests processed, false if the callback aborted by returning true. */ - bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback a_Callback); // Lua-accessible - - /** Calls the callback for each dispenser in the specified chunk. - Returns true if all dispensers processed, false if the callback aborted by returning true. */ - bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback a_Callback); - - /** Calls the callback for each dropper in the specified chunk. - Returns true if all droppers processed, false if the callback aborted by returning true. */ - bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback a_Callback); - - /** Calls the callback for each dropspenser in the specified chunk. - Returns true if all dropspensers processed, false if the callback aborted by returning true. */ - bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback a_Callback); - - /** Calls the callback for each furnace in the specified chunk. - Returns true if all furnaces processed, false if the callback aborted by returning true. */ - bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback a_Callback); // Lua-accessible - /** Calls the callback for the block entity at the specified coords. - Returns false if there's no block entity at those coords, true if found. */ - bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback a_Callback); // Lua-acessible - - /** Calls the callback for the beacon at the specified coords. - Returns false if there's no beacon at those coords, true if found. */ - bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback a_Callback); // Lua-acessible - - /** Calls the callback for the bed at the specified coords. - Returns false if there's no bed at those coords, true if found. */ - bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback a_Callback); // Lua-acessible - - /** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */ - bool DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback a_Callback); // Lua-acessible - - /** Calls the callback for the chest at the specified coords. - Returns false if there's no chest at those coords, true if found. */ - bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback a_Callback); // Lua-acessible - - /** Calls the callback for the dispenser at the specified coords. - Returns false if there's no dispenser at those coords or callback returns true, returns true if found. */ - bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback a_Callback); // Lua-accessible - - /** Calls the callback for the dropper at the specified coords. - Returns false if there's no dropper at those coords or callback returns true, returns true if found. */ - bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback a_Callback); // Lua-accessible - - /** Calls the callback for the dropspenser at the specified coords. - Returns false if there's no dropspenser at those coords or callback returns true, returns true if found. */ - bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback a_Callback); // Lua-accessible - - /** Calls the callback for the furnace at the specified coords. - Returns false if there's no furnace at those coords or callback returns true, returns true if found. */ - bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback a_Callback); // Lua-accessible - - /** Calls the callback for the hopper at the specified coords. - Returns false if there's no hopper at those coords or callback returns true, returns true if found. */ - bool DoWithHopperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperCallback a_Callback); // Lua-accessible - - /** Calls the callback for the noteblock at the specified coords. - Returns false if there's no noteblock at those coords or callback returns true, returns true if found. */ - bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback a_Callback); // Lua-accessible - - /** Calls the callback for the command block at the specified coords. - Returns false if there's no command block at those coords or callback returns true, returns true if found. */ - bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback a_Callback); // Lua-accessible - - /** Calls the callback for the mob head block at the specified coords. - Returns false if there's no mob head block at those coords or callback returns true, returns true if found. */ - bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback a_Callback); // Lua-accessible - - /** Calls the callback for the flower pot at the specified coords. - Returns false if there's no flower pot at those coords or callback returns true, returns true if found. */ - bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback a_Callback); // Lua-accessible - - /** Retrieves the test on the sign at the specified coords. - Returns false if there's no sign at those coords, true if found. */ - bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible + Returns false if there's no block entity at those coords, and whatever the callback returns if found. */ + bool DoWithBlockEntityAt(Vector3i a_Position, cBlockEntityCallback a_Callback); // Lua-acessible /** Queues the chunk for preparing - making sure that it's generated and lit. The specified chunk is queued to be loaded or generated, and lit if needed. @@ -324,9 +219,6 @@ public: /** Marks the chunk as failed-to-load */ void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ); - /** Sets the sign text. Returns true if sign text changed. */ - bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); - /** Marks the chunk as being regenerated - all its clients want that chunk again (used by cWorld::RegenerateChunk()) */ void MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ); diff --git a/src/ChunkSender.cpp b/src/ChunkSender.cpp index 2ab9a5a4d..1fa74977f 100644 --- a/src/ChunkSender.cpp +++ b/src/ChunkSender.cpp @@ -121,7 +121,7 @@ void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, Priority a_Prior -void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, Priority a_Priority, cChunkClientHandles a_Clients) +void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, Priority a_Priority, const std::vector<cClientHandle *> & a_Clients) { { cChunkCoords Chunk{a_ChunkX, a_ChunkZ}; diff --git a/src/ChunkSender.h b/src/ChunkSender.h index 7fe47c360..75d261af5 100644 --- a/src/ChunkSender.h +++ b/src/ChunkSender.h @@ -72,7 +72,7 @@ public: /** Queues a chunk to be sent to a specific client */ void QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, Priority a_Priority, cClientHandle * a_Client); - void QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, Priority a_Priority, cChunkClientHandles a_Client); + void QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, Priority a_Priority, const std::vector<cClientHandle *> & a_Clients); protected: diff --git a/src/Items/ItemBanner.h b/src/Items/ItemBanner.h index 7b9e6d05b..3f082c5a5 100644 --- a/src/Items/ItemBanner.h +++ b/src/Items/ItemBanner.h @@ -203,13 +203,15 @@ public: } const auto BannerPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); - return a_World.DoWithBlockEntityAt(BannerPos.x, BannerPos.y, BannerPos.z, [Color](cBlockEntity & a_BlockEntity) + a_World.DoWithBlockEntityAt(BannerPos, [Color](cBlockEntity & a_BlockEntity) { ASSERT((a_BlockEntity.GetBlockType() == E_BLOCK_STANDING_BANNER) || (a_BlockEntity.GetBlockType() == E_BLOCK_WALL_BANNER)); auto & Banner = static_cast<cBannerEntity &>(a_BlockEntity); Banner.SetBaseColor(Color); - return true; + return false; }); + + return true; } }; diff --git a/src/Items/ItemEnchantingTable.h b/src/Items/ItemEnchantingTable.h index c8eb42cac..12835cb4a 100644 --- a/src/Items/ItemEnchantingTable.h +++ b/src/Items/ItemEnchantingTable.h @@ -46,16 +46,12 @@ private: } const auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); - a_World.DoWithBlockEntityAt(PlacePos.x, PlacePos.y, PlacePos.z, [&a_EquippedItem](cBlockEntity & a_Entity) + a_World.DoWithBlockEntityAt(PlacePos, [&a_EquippedItem](cBlockEntity & a_Entity) { - if (a_Entity.GetBlockType() != E_BLOCK_ENCHANTMENT_TABLE) - { - return true; - } + ASSERT(a_Entity.GetBlockType() == E_BLOCK_ENCHANTMENT_TABLE); - auto & EnchantingTable = static_cast<cEnchantingTableEntity &>(a_Entity); - EnchantingTable.SetCustomName(a_EquippedItem.m_CustomName); - return true; + static_cast<cEnchantingTableEntity &>(a_Entity).SetCustomName(a_EquippedItem.m_CustomName); + return false; }); return true; diff --git a/src/Items/ItemMobHead.h b/src/Items/ItemMobHead.h index ef16f6c96..f1e963e1f 100644 --- a/src/Items/ItemMobHead.h +++ b/src/Items/ItemMobHead.h @@ -75,26 +75,22 @@ public: auto BlockMeta = static_cast<NIBBLETYPE>(a_ClickedBlockFace); // Use a callback to set the properties of the mob head block entity: - a_World.DoWithBlockEntityAt(a_PlacePos.x, a_PlacePos.y, a_PlacePos.z, [&](cBlockEntity & a_BlockEntity) - { - if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD) - { - return false; - } - auto & MobHeadEntity = static_cast<cMobHeadEntity &>(a_BlockEntity); + a_World.DoWithBlockEntityAt(a_PlacePos, [&](cBlockEntity & a_BlockEntity) + { + ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_HEAD); - int Rotation = 0; - if (BlockMeta == 1) - { - Rotation = FloorC(a_Player.GetYaw() * 16.0f / 360.0f + 0.5f) & 0x0f; - } + auto & MobHeadEntity = static_cast<cMobHeadEntity &>(a_BlockEntity); - MobHeadEntity.SetType(HeadType); - MobHeadEntity.SetRotation(static_cast<eMobHeadRotation>(Rotation)); - MobHeadEntity.GetWorld()->BroadcastBlockEntity(MobHeadEntity.GetPos()); - return false; + int Rotation = 0; + if (BlockMeta == 1) + { + Rotation = FloorC(a_Player.GetYaw() * 16.0f / 360.0f + 0.5f) & 0x0f; } - ); + + MobHeadEntity.SetType(HeadType); + MobHeadEntity.SetRotation(static_cast<eMobHeadRotation>(Rotation)); + return false; + }); } @@ -243,23 +239,23 @@ public: return false; } - // If it is a mob head, check the correct head type using the block entity: - if (BlockType == E_BLOCK_HEAD) - { - bool IsWitherHead = false; - a_World.DoWithBlockEntityAt(BlockX, BlockY, BlockZ, [&](cBlockEntity & a_Entity) + // If it is a mob head, check it's a wither skull using the block entity: + if ( + (BlockType == E_BLOCK_HEAD) && + !a_World.DoWithBlockEntityAt({ BlockX, BlockY, BlockZ }, [&](cBlockEntity & a_BlockEntity) + { + if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD) { - ASSERT(a_Entity.GetBlockType() == E_BLOCK_HEAD); - auto & MobHead = static_cast<cMobHeadEntity &>(a_Entity); - IsWitherHead = (MobHead.GetType() == SKULL_TYPE_WITHER); - return true; + return false; } - ); - if (!IsWitherHead) - { - return false; - } + + return static_cast<cMobHeadEntity &>(a_BlockEntity).GetType() == SKULL_TYPE_WITHER; + }) + ) + { + return false; } + // Matched, continue checking AirBlocks.emplace_back(BlockX, BlockY, BlockZ, E_BLOCK_AIR, 0); } // for i - a_Image diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index 378051163..e9c4e6ca7 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -2,6 +2,7 @@ #include "Globals.h" #include "Path.h" +#include "BlockType.h" #include "../BlockInfo.h" #include "../Chunk.h" diff --git a/src/Mobs/PathFinder.cpp b/src/Mobs/PathFinder.cpp index 423c4a0c6..9e63b7362 100644 --- a/src/Mobs/PathFinder.cpp +++ b/src/Mobs/PathFinder.cpp @@ -1,5 +1,6 @@ #include "Globals.h" #include "PathFinder.h" +#include "BlockType.h" #include "../BlockInfo.h" #include "../Chunk.h" diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp index 15197ad07..db4ed5502 100644 --- a/src/Protocol/Protocol_1_11.cpp +++ b/src/Protocol/Protocol_1_11.cpp @@ -30,13 +30,8 @@ Implements the 1.11 protocol classes: #include "../Mobs/IncludeAllMonsters.h" -#include "../BlockEntities/BannerEntity.h" -#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/BedEntity.h" -#include "../BlockEntities/CommandBlockEntity.h" -#include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/MobSpawnerEntity.h" -#include "../BlockEntities/FlowerPotEntity.h" #include "../Root.h" #include "../Server.h" diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index 4ebf826bf..0669e6a1a 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -45,13 +45,7 @@ Implements the 1.9 protocol classes: #include "../Mobs/IncludeAllMonsters.h" #include "../UI/HorseWindow.h" -#include "../BlockEntities/BannerEntity.h" -#include "../BlockEntities/BeaconEntity.h" -#include "../BlockEntities/CommandBlockEntity.h" -#include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/MobSpawnerEntity.h" -#include "../BlockEntities/FlowerPotEntity.h" -#include "../Bindings/PluginManager.h" diff --git a/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h index c216d12bc..0a5ffe136 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h @@ -31,9 +31,14 @@ namespace CommandBlockHandler return; } - a_Chunk.DoWithCommandBlockAt(a_Position, [](cCommandBlockEntity & a_CommandBlock) + a_Chunk.DoWithBlockEntityAt(a_Position, [](cBlockEntity & a_BlockEntity) { - a_CommandBlock.Activate(); + if (a_BlockEntity.GetBlockType() != E_BLOCK_COMMAND_BLOCK) + { + return false; + } + + static_cast<cCommandBlockEntity &>(a_BlockEntity).Activate(); return false; }); } diff --git a/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h b/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h index 309fa757a..4dd87e972 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h @@ -46,9 +46,14 @@ namespace DropSpenserHandler if (IsPoweredNow && !WasPoweredPreviously) { - a_Chunk.DoWithDropSpenserAt(a_Position, [](cDropSpenserEntity & a_DropSpenser) + a_Chunk.DoWithBlockEntityAt(a_Position, [](cBlockEntity & a_BlockEntity) { - a_DropSpenser.Activate(); + if ((a_BlockEntity.GetBlockType() != E_BLOCK_DISPENSER) && (a_BlockEntity.GetBlockType() != E_BLOCK_DROPPER)) + { + return false; + } + + static_cast<cDropSpenserEntity &>(a_BlockEntity).Activate(); return false; }); } diff --git a/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h b/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h index 998a98677..379f7c7d8 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h @@ -30,9 +30,14 @@ namespace HopperHandler return; } - a_Chunk.DoWithHopperAt(a_Position, [Power](cHopperEntity & a_Hopper) + a_Chunk.DoWithBlockEntityAt(a_Position, [Power](cBlockEntity & a_BlockEntity) { - a_Hopper.SetLocked(Power != 0); + if (a_BlockEntity.GetBlockType() != E_BLOCK_HOPPER) + { + return false; + } + + static_cast<cHopperEntity &>(a_BlockEntity).SetLocked(Power != 0); return false; }); } diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h index e8cd4bf5d..b13d1f6f5 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h @@ -1,6 +1,7 @@ #pragma once +#include "BlockType.h" #include "../RedstoneSimulator.h" #include "RedstoneSimulatorChunkData.h" diff --git a/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h index 6a2f66737..8bd639357 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h @@ -31,9 +31,14 @@ namespace NoteBlockHandler return; } - a_Chunk.DoWithNoteBlockAt(a_Position, [](cNoteEntity & a_NoteBlock) + a_Chunk.DoWithBlockEntityAt(a_Position, [](cBlockEntity & a_BlockEntity) { - a_NoteBlock.MakeSound(); + if (a_BlockEntity.GetBlockType() != E_BLOCK_NOTE_BLOCK) + { + return false; + } + + static_cast<cNoteEntity &>(a_BlockEntity).MakeSound(); return false; }); } diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.cpp b/src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.cpp index 63da4c0dc..ab6b35c0b 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.cpp @@ -5,6 +5,7 @@ #include "RedstoneDataHelper.h" #include "ForEachSourceCallback.h" +#include "BlockType.h" #include "CommandBlockHandler.h" #include "DaylightSensorHandler.h" #include "DoorHandler.h" diff --git a/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h b/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h index 619401d80..145c5dc83 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h @@ -22,14 +22,16 @@ namespace TrappedChestHandler static unsigned char GetPowerLevel(cChunk & a_Chunk, Vector3i a_Position) { int NumberOfPlayers = 0; - VERIFY( - !a_Chunk.DoWithChestAt(a_Position, [&](cChestEntity & a_Chest) + a_Chunk.DoWithBlockEntityAt(a_Position, [&NumberOfPlayers](cBlockEntity & a_BlockEntity) + { + if (a_BlockEntity.GetBlockType() != E_BLOCK_TRAPPED_CHEST) { - ASSERT(a_Chest.GetBlockType() == E_BLOCK_TRAPPED_CHEST); - NumberOfPlayers = a_Chest.GetNumberOfPlayers(); - return true; - }) - ); + return false; + } + + NumberOfPlayers = static_cast<cChestEntity &>(a_BlockEntity).GetNumberOfPlayers(); + return false; + }); return static_cast<unsigned char>(std::min(NumberOfPlayers, 15)); } diff --git a/src/Simulator/VaporizeFluidSimulator.cpp b/src/Simulator/VaporizeFluidSimulator.cpp index 82f71c03f..6256c8e78 100644 --- a/src/Simulator/VaporizeFluidSimulator.cpp +++ b/src/Simulator/VaporizeFluidSimulator.cpp @@ -5,6 +5,7 @@ #include "Globals.h" #include "VaporizeFluidSimulator.h" +#include "BlockType.h" #include "../OpaqueWorld.h" #include "../Chunk.h" #include "../Blocks/BroadcastInterface.h" diff --git a/src/World.cpp b/src/World.cpp index 84f8bb9c6..0a03110e2 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -29,7 +29,7 @@ #include "Entities/TNTEntity.h" #include "BlockEntities/CommandBlockEntity.h" -#include "BlockEntities/BeaconEntity.h" +#include "BlockEntities/SignEntity.h" // Simulators: #include "Simulator/FloodyFluidSimulator.h" @@ -1342,60 +1342,6 @@ bool cWorld::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityC -bool cWorld::ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, cBrewingstandCallback a_Callback) -{ - return m_ChunkMap.ForEachBrewingstandInChunk(a_ChunkX, a_ChunkZ, a_Callback); -} - - - - - -bool cWorld::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback a_Callback) -{ - return m_ChunkMap.ForEachChestInChunk(a_ChunkX, a_ChunkZ, a_Callback); -} - - - - - -bool cWorld::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback a_Callback) -{ - return m_ChunkMap.ForEachDispenserInChunk(a_ChunkX, a_ChunkZ, a_Callback); -} - - - - - -bool cWorld::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback a_Callback) -{ - return m_ChunkMap.ForEachDropperInChunk(a_ChunkX, a_ChunkZ, a_Callback); -} - - - - - -bool cWorld::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback a_Callback) -{ - return m_ChunkMap.ForEachDropSpenserInChunk(a_ChunkX, a_ChunkZ, a_Callback); -} - - - - - -bool cWorld::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback a_Callback) -{ - return m_ChunkMap.ForEachFurnaceInChunk(a_ChunkX, a_ChunkZ, a_Callback); -} - - - - - void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) { cLock Lock(*this); @@ -1431,126 +1377,9 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo -bool cWorld::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback a_Callback) -{ - return m_ChunkMap.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback a_Callback) -{ - return m_ChunkMap.DoWithBeaconAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback a_Callback) -{ - return m_ChunkMap.DoWithBedAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback a_Callback) -{ - return m_ChunkMap.DoWithBrewingstandAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback a_Callback) -{ - return m_ChunkMap.DoWithChestAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback a_Callback) -{ - return m_ChunkMap.DoWithDispenserAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback a_Callback) -{ - return m_ChunkMap.DoWithDropperAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback a_Callback) -{ - return m_ChunkMap.DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback a_Callback) +bool cWorld::DoWithBlockEntityAt(const Vector3i a_Position, cBlockEntityCallback a_Callback) { - return m_ChunkMap.DoWithFurnaceAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithHopperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperCallback a_Callback) -{ - return m_ChunkMap.DoWithHopperAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback a_Callback) -{ - return m_ChunkMap.DoWithNoteBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback a_Callback) -{ - return m_ChunkMap.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback a_Callback) -{ - return m_ChunkMap.DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); -} - - - - - -bool cWorld::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback a_Callback) -{ - return m_ChunkMap.DoWithFlowerPotAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); + return m_ChunkMap.DoWithBlockEntityAt(a_Position, a_Callback); } @@ -1559,7 +1388,20 @@ bool cWorld::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlower bool cWorld::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) { - return m_ChunkMap.GetSignLines(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4); + return DoWithBlockEntityAt({ a_BlockX, a_BlockY, a_BlockZ }, [&a_Line1, &a_Line2, &a_Line3, &a_Line4](cBlockEntity & a_BlockEntity) + { + if ((a_BlockEntity.GetBlockType() != E_BLOCK_WALLSIGN) && (a_BlockEntity.GetBlockType() != E_BLOCK_SIGN_POST)) + { + return false; // Not a sign + } + + const auto & Sign = static_cast<cSignEntity &>(a_BlockEntity); + a_Line1 = Sign.GetLine(0); + a_Line2 = Sign.GetLine(1); + a_Line3 = Sign.GetLine(2); + a_Line4 = Sign.GetLine(3); + return true; + }); } @@ -2672,6 +2514,8 @@ void cWorld::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ) bool cWorld::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player) { + // TODO: rvalue these strings + AString Line1(a_Line1); AString Line2(a_Line2); AString Line3(a_Line3); @@ -2682,7 +2526,18 @@ bool cWorld::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AStrin return false; } - if (m_ChunkMap.SetSignLines(a_BlockX, a_BlockY, a_BlockZ, Line1, Line2, Line3, Line4)) + if ( + DoWithBlockEntityAt({ a_BlockX, a_BlockY, a_BlockZ }, [&Line1, &Line2, &Line3, &Line4](cBlockEntity & a_BlockEntity) + { + if ((a_BlockEntity.GetBlockType() != E_BLOCK_WALLSIGN) && (a_BlockEntity.GetBlockType() != E_BLOCK_SIGN_POST)) + { + return false; // Not a sign + } + + static_cast<cSignEntity &>(a_BlockEntity).SetLines(Line1, Line2, Line3, Line4); + return true; + }) + ) { cRoot::Get()->GetPluginManager()->CallHookUpdatedSign(*this, a_BlockX, a_BlockY, a_BlockZ, Line1, Line2, Line3, Line4, a_Player); return true; @@ -2697,12 +2552,16 @@ bool cWorld::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AStrin bool cWorld::SetCommandBlockCommand(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Command) { - return DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, [&](cCommandBlockEntity & a_CommandBlock) + return DoWithBlockEntityAt({ a_BlockX, a_BlockY, a_BlockZ }, [&](cBlockEntity & a_BlockEntity) + { + if (a_BlockEntity.GetBlockType() != E_BLOCK_COMMAND_BLOCK) { - a_CommandBlock.SetCommand(a_Command); return false; } - ); + + static_cast<cCommandBlockEntity &>(a_BlockEntity).SetCommand(a_Command); + return true; + }); } diff --git a/src/World.h b/src/World.h index 0f0ade751..9bb1f8b6b 100644 --- a/src/World.h +++ b/src/World.h @@ -615,71 +615,14 @@ public: /** Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true */ bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback a_Callback); // Exported in ManualBindings.cpp - /** Calls the callback for each brewingstand in the specified chunk; returns true if all brewingstands processed, false if the callback aborted by returning true */ - bool ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, cBrewingstandCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true */ - bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true */ - bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback a_Callback); - - /** Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true */ - bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback a_Callback); - - /** Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true */ - bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback a_Callback); - - /** Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true */ - bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback a_Callback); // Exported in ManualBindings.cpp - /** Does an explosion with the specified strength at the specified coordinates. Executes the HOOK_EXPLODING and HOOK_EXPLODED hooks as part of the processing. a_SourceData exact type depends on the a_Source, see the declaration of the esXXX constants in Defines.h for details. Exported to Lua manually in ManualBindings_World.cpp in order to support the variable a_SourceData param. */ virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) override; - /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ - virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback a_Callback) override; // Exported in ManualBindings.cpp - - /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ - bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for the bed at the specified coords; returns false if there's no bed at those coords, true if found */ - virtual bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback a_Callback) override; // Exported in ManualBindings.cpp - - /** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */ - bool DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback a_Callback); // Lua-acessible - - /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ - bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */ - bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */ - bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */ - bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */ - bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for the hopper at the specified coords; returns false if there's no hopper at those coords or callback returns true, returns true if found */ - bool DoWithHopperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */ - bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */ - bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */ - bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback a_Callback); // Exported in ManualBindings.cpp - - /** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */ - bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback a_Callback); // Exported in ManualBindings.cpp + /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, and whatever the callback returns if found. */ + virtual bool DoWithBlockEntityAt(Vector3i a_Position, cBlockEntityCallback a_Callback) override; // Exported in ManualBindings.cpp /** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */ bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Exported in ManualBindings.cpp |