1
0

Unify DoWithBlockEntity (#5168)

+ DoWith calls now broadcast the block entity and mark the chunk dirty
+ Add block entity change queue to synchronise BE updates with block updates
* Fixed a few incorrect assertions about BE type
- Remove manual overloads
This commit is contained in:
Tiger Wang 2021-03-28 14:40:57 +01:00 committed by GitHub
parent 5123850db0
commit 748b121703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 550 additions and 1596 deletions

View File

@ -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,

View File

@ -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)

View File

@ -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);

View File

@ -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);
});
}

View File

@ -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;

View File

@ -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());
}
};

View File

@ -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());
}

View File

@ -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());
}

View File

@ -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)));
}

View File

@ -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;
});
}

View File

@ -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));

View File

@ -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;
});
}
};

View File

@ -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;

View File

@ -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,125 +1712,19 @@ bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback a_Callback, boo
template <class tyEntity, BLOCKTYPE... tBlocktype>
bool cChunk::GenericForEachBlockEntity(cFunctionRef<bool(tyEntity &)> 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(*static_cast<tyEntity *>(Block)))
{
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)
for (auto & KeyPair : m_BlockEntities)
{
return false; // No block entity here
if (a_Callback(*KeyPair.second))
{
return false;
}
}
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));
return true;
}
@ -1871,182 +1732,19 @@ bool cChunk::GenericDoWithBlockEntityAt(Vector3i a_Position, cFunctionRef<bool(t
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);
}
bool cChunk::GetSignLines(Vector3i a_Position, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4)
{
// The blockentity list is locked by the parent chunkmap's CS
auto Entity = GetBlockEntity(a_Position);
if (Entity == nullptr)
const auto BlockEntity = GetBlockEntityRel(a_Position);
if (BlockEntity == nullptr)
{
return false; // Not a block entity
}
if (
(Entity->GetBlockType() != E_BLOCK_WALLSIGN) &&
(Entity->GetBlockType() != E_BLOCK_SIGN_POST)
)
{
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;
}

View File

@ -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;

View File

@ -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
{

View File

@ -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);
const auto Chunk = FindChunk(ChunkPosition.m_ChunkX, ChunkPosition.m_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);
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);

View File

@ -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);

View File

@ -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};

View File

@ -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:

View File

@ -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;
}
};

View File

@ -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;

View File

@ -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)
a_World.DoWithBlockEntityAt(a_PlacePos, [&](cBlockEntity & a_BlockEntity)
{
ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_HEAD);
auto & MobHeadEntity = static_cast<cMobHeadEntity &>(a_BlockEntity);
int Rotation = 0;
if (BlockMeta == 1)
{
if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD)
{
return false;
}
auto & MobHeadEntity = static_cast<cMobHeadEntity &>(a_BlockEntity);
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));
MobHeadEntity.GetWorld()->BroadcastBlockEntity(MobHeadEntity.GetPos());
return false;
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)
{
ASSERT(a_Entity.GetBlockType() == E_BLOCK_HEAD);
auto & MobHead = static_cast<cMobHeadEntity &>(a_Entity);
IsWitherHead = (MobHead.GetType() == SKULL_TYPE_WITHER);
return true;
}
);
if (!IsWitherHead)
// 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)
{
return false;
}
if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD)
{
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

View File

@ -2,6 +2,7 @@
#include "Globals.h"
#include "Path.h"
#include "BlockType.h"
#include "../BlockInfo.h"
#include "../Chunk.h"

View File

@ -1,5 +1,6 @@
#include "Globals.h"
#include "PathFinder.h"
#include "BlockType.h"
#include "../BlockInfo.h"
#include "../Chunk.h"

View File

@ -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"

View File

@ -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"

View File

@ -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;
});
}

View File

@ -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;
});
}

View File

@ -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;
});
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "BlockType.h"
#include "../RedstoneSimulator.h"
#include "RedstoneSimulatorChunkData.h"

View File

@ -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;
});
}

View File

@ -5,6 +5,7 @@
#include "RedstoneDataHelper.h"
#include "ForEachSourceCallback.h"
#include "BlockType.h"
#include "CommandBlockHandler.h"
#include "DaylightSensorHandler.h"
#include "DoorHandler.h"

View File

@ -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));
}

View File

@ -5,6 +5,7 @@
#include "Globals.h"
#include "VaporizeFluidSimulator.h"
#include "BlockType.h"
#include "../OpaqueWorld.h"
#include "../Chunk.h"
#include "../Blocks/BroadcastInterface.h"

View File

@ -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)
bool cWorld::DoWithBlockEntityAt(const Vector3i a_Position, 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)
{
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;
});
}

View File

@ -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