1
0
Fork 0

OnBroken/OnPlaced are for entity actions

* Call OnPlaced/OnBroken in PlaceBlock/DigBlock
- Remove unused Placing/Breaking handlers
* Have the blockhandler's Check handle neighbour updating, instead of QueueTickBlockNeighbors
This commit is contained in:
Tiger Wang 2020-07-29 19:30:38 +01:00
parent adb86a75da
commit 6bdd130aab
16 changed files with 93 additions and 261 deletions

View File

@ -19,66 +19,41 @@ public:
{
}
virtual void Check(
cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk
virtual void OnPlaced(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override
{
if (GetSoaked(a_RelPos, a_Chunk))
{
return;
}
Super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk);
OnNeighborChanged(a_ChunkInterface, a_BlockPos, BLOCK_FACE_NONE);
}
/** Check blocks above and around to see if they are water. If one is, converts this into concrete block.
Returns true if the block was changed. */
bool GetSoaked(Vector3i a_Rel, cChunk & a_Chunk)
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override
{
static const std::array<Vector3i, 5> WaterCheck
{
{
{ 1, 0, 0},
{-1, 0, 0},
{ 0, 0, 1},
{ 0, 0, -1},
{ 0, 1, 0},
}
};
a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & a_Chunk) { CheckSoaked(a_Chunk.AbsoluteToRelative(a_BlockPos), a_Chunk); return true; });
}
bool ShouldSoak = std::any_of(WaterCheck.cbegin(), WaterCheck.cend(), [a_Rel, & a_Chunk](Vector3i a_Offset)
{
BLOCKTYPE NeighborType;
return (
a_Chunk.UnboundedRelGetBlockType(a_Rel.x + a_Offset.x, a_Rel.y + a_Offset.y, a_Rel.z + a_Offset.z, NeighborType)
&& IsBlockWater(NeighborType)
);
}
);
/** Check blocks above and around to see if they are water. If one is, converts this into concrete block. */
void CheckSoaked(Vector3i a_Rel, cChunk & a_Chunk)
{
const auto & WaterCheck = cSimulator::AdjacentOffsets;
const bool ShouldSoak = std::any_of(WaterCheck.cbegin(), WaterCheck.cend(), [a_Rel, & a_Chunk](Vector3i a_Offset)
{
BLOCKTYPE NeighborType;
return (
a_Chunk.UnboundedRelGetBlockType(a_Rel.x + a_Offset.x, a_Rel.y + a_Offset.y, a_Rel.z + a_Offset.z, NeighborType)
&& IsBlockWater(NeighborType)
);
});
if (ShouldSoak)
{
NIBBLETYPE BlockMeta;
BlockMeta = a_Chunk.GetMeta(a_Rel.x, a_Rel.y, a_Rel.z);
a_Chunk.SetBlock(a_Rel, E_BLOCK_CONCRETE, BlockMeta);
return true;
}
return false;
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
switch (a_Meta)
@ -107,7 +82,3 @@ public:
}
}
};

View File

@ -436,39 +436,21 @@ void cBlockHandler::OnUpdate(
void cBlockHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange)
void cBlockHandler::OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor)
{
OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockChange.GetAbsolutePos(), a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta);
}
if (a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & a_Chunk) { return CanBeAt(a_ChunkInterface, a_Chunk.AbsoluteToRelative(a_BlockPos), a_Chunk); }))
{
return;
}
void cBlockHandler::OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
// Notify the neighbors
NeighborChanged(a_ChunkInterface, a_BlockPos.addedX(-1), BLOCK_FACE_XP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedX( 1), BLOCK_FACE_XM);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedY(-1), BLOCK_FACE_YP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedY( 1), BLOCK_FACE_YM);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ(-1), BLOCK_FACE_ZP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ( 1), BLOCK_FACE_ZM);
}
void cBlockHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta)
{
// Notify the neighbors
NeighborChanged(a_ChunkInterface, a_BlockPos.addedX(-1), BLOCK_FACE_XP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedX( 1), BLOCK_FACE_XM);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedY(-1), BLOCK_FACE_YP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedY( 1), BLOCK_FACE_YM);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ(-1), BLOCK_FACE_ZP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ( 1), BLOCK_FACE_ZM);
if (DoesDropOnUnsuitable())
{
a_ChunkInterface.DropBlockAsPickups(a_BlockPos);
}
else
{
a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_AIR, 0);
}
}
@ -585,19 +567,13 @@ void cBlockHandler::Check(
cChunk & a_Chunk
)
{
if (CanBeAt(a_ChunkInterface, a_RelPos, a_Chunk))
{
return;
}
if (DoesDropOnUnsuitable())
{
a_ChunkInterface.DropBlockAsPickups(a_Chunk.RelativeToAbsolute(a_RelPos));
}
else
{
a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0);
}
const auto Position = cChunkDef::RelativeToAbsolute(a_RelPos, a_Chunk.GetPos());
NeighborChanged(a_ChunkInterface, Position.addedX(-1), BLOCK_FACE_XP);
NeighborChanged(a_ChunkInterface, Position.addedX(1), BLOCK_FACE_XM);
NeighborChanged(a_ChunkInterface, Position.addedY(-1), BLOCK_FACE_YP);
NeighborChanged(a_ChunkInterface, Position.addedY(1), BLOCK_FACE_YM);
NeighborChanged(a_ChunkInterface, Position.addedZ(-1), BLOCK_FACE_ZP);
NeighborChanged(a_ChunkInterface, Position.addedZ(1), BLOCK_FACE_ZM);
}

View File

@ -65,21 +65,12 @@ public:
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
);
) {};
/** Called by cPlayer::PlaceBlocks() for each block after it has been set to the world. Called after OnPlaced(). */
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange
);
/** Called just before the player breaks the block.
The block is still valid in the world.
By default does nothing special; descendants may provide further behavior. */
virtual void OnPlayerBreakingBlock(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
cPlayer & a_Player,
Vector3i a_BlockPos
) {}
) {};
/** Called just after the player breaks the block.
The block is already dug up in the world, the original block type and meta is passed in a_OldBlockType and a_OldBlockMeta.
@ -91,14 +82,6 @@ public:
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) {}
/** Called before a block gets broken (replaced with air), either by player or by natural means.
If by player, it is called after the OnPlayerBreakingBlock() callback.
By default does nothing. */
virtual void OnBreaking(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos
) {}
/** Called after a block gets broken (replaced with air), either by player or by natural means.
If by player, it is called before the OnPlayerBrokeBlock() callback.
The block is already dug up in the world, the original block type and meta is passed in a_OldBlockType and a_OldBlockMeta.
@ -107,13 +90,13 @@ public:
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
);
) {};
/** Called when a direct neighbor of this block has been changed.
The position is the block's own position, NOT the changed neighbor's position.
a_WhichNeighbor indicates which neighbor has changed. For example, BLOCK_FACE_YP meant the neighbor above has changed.
BLOCK_FACE_NONE means that it is a neighbor not directly adjacent (diagonal, etc.) */
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) {}
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor);
/** Notifies the specified neighbor that the current block has changed.
a_NeighborPos are the coords of the neighbor to be notified
@ -208,7 +191,7 @@ public:
/** Called when one of the neighbors gets set; equivalent to MC block update.
By default drops (DropBlockAsPickup() / SetBlock()) if the position is no longer suitable (CanBeAt(), DoesDropOnUnsuitable()),
otherwise wakes up all simulators on the block. */
virtual void Check(
void Check(
cChunkInterface & ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk

View File

@ -44,7 +44,7 @@ public:
}
case paDeath:
{
a_ChunkInterface.DigBlock(a_WorldInterface, a_Chunk.RelativeToAbsolute(a_RelPos));
a_ChunkInterface.SetBlock(a_Chunk.RelativeToAbsolute(a_RelPos), E_BLOCK_AIR, 0);
break;
}
case paStay: break; // do nothing

View File

@ -12,6 +12,15 @@
bool cChunkInterface::DoWithChunkAt(Vector3i a_BlockPos, cChunkCallback a_Callback)
{
return m_ChunkMap->DoWithChunkAt(a_BlockPos, a_Callback);
}
BLOCKTYPE cChunkInterface::GetBlock(Vector3i a_Pos)
{
return m_ChunkMap->GetBlock(a_Pos);
@ -95,16 +104,16 @@ bool cChunkInterface::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a
bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos)
{
BLOCKTYPE blockType;
NIBBLETYPE blockMeta;
GetBlockTypeMeta(a_BlockPos, blockType, blockMeta);
auto handler = cBlockInfo::GetHandler(blockType);
handler->OnBreaking(*this, a_WorldInterface, a_BlockPos);
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta);
if (!m_ChunkMap->DigBlock(a_BlockPos))
{
return false;
}
handler->OnBroken(*this, a_WorldInterface, a_BlockPos, blockType, blockMeta);
cBlockInfo::GetHandler(BlockType)->OnBroken(*this, a_WorldInterface, a_BlockPos, BlockType, BlockMeta);
return true;
}

View File

@ -2,12 +2,14 @@
#pragma once
#include "../ForEachChunkProvider.h"
#include "../FunctionRef.h"
// fwd:
class cItem;
class cChunk;
class cChunkMap;
class cWorldInterface;
class cPlayer;
@ -23,6 +25,8 @@ public:
cChunkInterface(cChunkMap * a_ChunkMap) : m_ChunkMap(a_ChunkMap) {}
bool DoWithChunkAt(Vector3i a_BlockPos, cFunctionRef<bool(cChunk &)> a_Callback);
BLOCKTYPE GetBlock(Vector3i a_Pos);
NIBBLETYPE GetBlockMeta(Vector3i a_Pos);

View File

@ -820,7 +820,7 @@ void cChunk::CheckBlocks()
while (Count != 0)
{
Vector3i Pos = m_ToTickBlocks.front();
const auto Pos = m_ToTickBlocks.front();
m_ToTickBlocks.pop();
Count--;
@ -1263,8 +1263,8 @@ void cChunk::SetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_Blo
{
FastSetBlock(a_RelPos, a_BlockType, a_BlockMeta);
// Tick this block and its neighbors:
QueueTickBlockNeighbors(a_RelPos);
// Tick this block's neighbors via cBlockHandler::Check:
m_ToTickBlocks.push(a_RelPos);
// Wake up the simulators for this block:
GetWorld()->GetSimulatorManager()->WakeUp(*this, a_RelPos);
@ -1311,33 +1311,6 @@ void cChunk::SetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_Blo
void cChunk::QueueTickBlockNeighbors(Vector3i a_Position)
{
m_ToTickBlocks.push(a_Position);
for (const auto & Offset : cSimulator::AdjacentOffsets)
{
auto Relative = a_Position + Offset;
if (!cChunkDef::IsValidHeight(Relative.y))
{
continue;
}
auto Chunk = GetRelNeighborChunkAdjustCoords(Relative);
if ((Chunk == nullptr) || !Chunk->IsValid())
{
continue;
}
Chunk->m_ToTickBlocks.push(Relative);
}
}
void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients)
{
ASSERT(!((a_RelX < 0) || (a_RelX >= Width) || (a_RelY < 0) || (a_RelY >= Height) || (a_RelZ < 0) || (a_RelZ >= Width)));

View File

@ -158,10 +158,6 @@ public:
void SetBlock(Vector3i a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
// SetBlock() does a lot of work (heightmap, tickblocks, blockentities) so a BlockIdx version doesn't make sense
/** Queues the position itself, and all 6 neighbors of the specified position for ticking (m_ToTickQueue).
If any are outside the chunk, relays the checking to the proper neighboring chunk. */
void QueueTickBlockNeighbors(Vector3i a_Position);
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
void FastSetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true)
{

View File

@ -479,34 +479,6 @@ void cChunkMap::FastSetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLET
void cChunkMap::SetBlocks(const sSetBlockVector & a_Blocks)
{
cCSLock lock(m_CSChunks);
cChunkPtr chunk = nullptr;
int lastChunkX = 0x7fffffff; // Bogus coords so that chunk is updated on first pass
int lastChunkZ = 0x7fffffff;
for (auto block: a_Blocks)
{
// Update the chunk, if different from last time:
if ((block.m_ChunkX != lastChunkX) || (block.m_ChunkZ != lastChunkZ))
{
lastChunkX = block.m_ChunkX;
lastChunkZ = block.m_ChunkZ;
chunk = GetChunk(lastChunkX, lastChunkZ);
}
// If the chunk is valid, set the block:
if (chunk != nullptr)
{
chunk->SetBlock({block.m_RelX, block.m_RelY, block.m_RelZ}, block.m_BlockType, block.m_BlockMeta);
}
} // for block - a_Blocks[]
}
void cChunkMap::CollectPickupsByPlayer(cPlayer & a_Player)
{
int BlockX = static_cast<int>(a_Player.GetPosX()); // Truncating doesn't matter much; we're scanning entire chunks anyway
@ -637,15 +609,7 @@ void cChunkMap::SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE
auto chunk = GetChunk(chunkPos.m_ChunkX, chunkPos.m_ChunkZ);
if ((chunk != nullptr) && chunk->IsValid())
{
BLOCKTYPE blockType;
NIBBLETYPE blockMeta;
GetBlockTypeMeta(a_BlockPos, blockType, blockMeta);
cChunkInterface ChunkInterface(this);
BlockHandler(blockType)->OnBroken(ChunkInterface, *m_World, a_BlockPos, blockType, blockMeta);
chunk->SetBlock(relPos, a_BlockType, a_BlockMeta);
BlockHandler(a_BlockType)->OnPlaced(ChunkInterface, *m_World, a_BlockPos, a_BlockType, a_BlockMeta);
}
}
@ -692,28 +656,6 @@ bool cChunkMap::GetBlockInfo(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBL
void cChunkMap::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType)
{
cCSLock Lock(m_CSChunks);
for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr)
{
auto chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ);
if ((chunk == nullptr) || !chunk->IsValid())
{
continue;
}
Vector3i relPos(itr->m_RelX, itr->m_RelY, itr->m_RelZ);
if (chunk->GetBlock(relPos) == a_FilterBlockType)
{
chunk->SetBlock(relPos, itr->m_BlockType, itr->m_BlockMeta);
}
}
}
void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks)
{
cCSLock Lock(m_CSChunks);

View File

@ -132,11 +132,6 @@ public:
If the chunk is invalid, the operation is ignored silently. */
void FastSetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
/** Performs the specified single-block set operations simultaneously, as if SetBlock() was called for each item.
Is more efficient than calling SetBlock() multiple times.
If the chunk for any of the blocks is not loaded, the set operation is ignored silently. */
void SetBlocks(const sSetBlockVector & a_Blocks);
/** Makes the specified player collect all the pickups around them. */
void CollectPickupsByPlayer(cPlayer & a_Player);
@ -155,9 +150,6 @@ public:
bool GetBlockTypeMeta (Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
bool GetBlockInfo (Vector3i, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
/** Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType */
void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType);
/** Special function used for growing trees, replaces only blocks that tree may overwrite */
void ReplaceTreeBlocks(const sSetBlockVector & a_Blocks);

View File

@ -1373,7 +1373,6 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
cChunkInterface ChunkInterface(World->GetChunkMap());
auto blockHandler = BlockHandler(a_OldBlock);
Vector3i absPos(a_BlockX, a_BlockY, a_BlockZ);
blockHandler->OnPlayerBreakingBlock(ChunkInterface, *World, *m_Player, absPos);
if (m_Player->IsGameModeSurvival())
{
World->DropBlockAsPickups(absPos, m_Player, &m_Player->GetEquippedItem());

View File

@ -2910,22 +2910,20 @@ bool cPlayer::PlaceBlocks(const sSetBlockVector & a_Blocks)
}
} // for blk - a_Blocks[]
// Set the blocks:
m_World->SetBlocks(a_Blocks);
// Notify the blockhandlers:
cChunkInterface ChunkInterface(m_World->GetChunkMap());
for (auto blk: a_Blocks)
{
// Set the blocks:
m_World->PlaceBlock(blk.GetAbsolutePos(), blk.m_BlockType, blk.m_BlockMeta);
// Notify the blockhandlers:
cBlockHandler * newBlock = BlockHandler(blk.m_BlockType);
newBlock->OnPlacedByPlayer(ChunkInterface, *m_World, *this, blk);
}
// Call the "placed" hooks:
for (auto blk: a_Blocks)
{
// Call the "placed" hooks:
pm->CallHookPlayerPlacedBlock(*this, blk);
}
return true;
}

View File

@ -54,7 +54,6 @@ public:
Vector3i PlacePos;
if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta))
{
blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, a_ClickedBlockPos);
PlacePos = a_ClickedBlockPos;
}
else
@ -75,7 +74,6 @@ public:
{
return false;
}
blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, PlacePos);
}
// Check that there is at most one single neighbor of the same chest type:

View File

@ -65,7 +65,7 @@ public:
case E_BLOCK_TNT:
{
// Activate the TNT:
a_World->SetBlock(a_ClickedBlockPos, E_BLOCK_AIR, 0);
a_World->DigBlock(a_ClickedBlockPos);
a_World->SpawnPrimedTNT(Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5)); // 80 ticks to boom
break;
}
@ -79,7 +79,7 @@ public:
}
if (a_World->GetBlock(FirePos) == E_BLOCK_AIR)
{
a_World->SetBlock(FirePos, E_BLOCK_FIRE, 0);
a_World->PlaceBlock(FirePos, E_BLOCK_FIRE, 0);
a_World->BroadcastSoundEffect("item.flintandsteel.use", FirePos, 1.0f, 1.04f);
break;
}

View File

@ -2182,18 +2182,12 @@ UInt32 cWorld::SpawnPrimedTNT(Vector3d a_Pos, int a_FuseTicks, double a_InitialV
void cWorld::SetBlocks(const sSetBlockVector & a_Blocks)
void cWorld::PlaceBlock(const Vector3i a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta)
{
m_ChunkMap->SetBlocks(a_Blocks);
}
SetBlock(a_Position, a_BlockType, a_BlockMeta);
void cWorld::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType)
{
m_ChunkMap->ReplaceBlocks(a_Blocks, a_FilterBlockType);
cChunkInterface ChunkInterface(GetChunkMap());
cBlockInfo::GetHandler(a_BlockType)->OnPlaced(ChunkInterface, *this, a_Position, a_BlockType, a_BlockMeta);
}
@ -2211,17 +2205,18 @@ bool cWorld::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
bool cWorld::DigBlock(Vector3i a_BlockPos)
{
BLOCKTYPE blockType;
NIBBLETYPE blockMeta;
GetBlockTypeMeta(a_BlockPos, blockType, blockMeta);
cChunkInterface chunkInterface(GetChunkMap());
auto blockHandler = cBlockInfo::GetHandler(blockType);
blockHandler->OnBreaking(chunkInterface, *this, a_BlockPos);
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta);
if (!m_ChunkMap->DigBlock(a_BlockPos))
{
return false;
}
blockHandler->OnBroken(chunkInterface, *this, a_BlockPos, blockType, blockMeta);
cChunkInterface ChunkInterface(GetChunkMap());
cBlockInfo::GetHandler(BlockType)->OnBroken(ChunkInterface, *this, a_BlockPos, BlockType, BlockMeta);
return true;
}

View File

@ -661,22 +661,18 @@ public:
// tolua_end
/** Performs the specified single-block set operations simultaneously, as if SetBlock() was called for each item.
Is more efficient than calling SetBlock() multiple times.
/** Replaces the specified block with another, and calls the OnPlaced block handler.
Callers MUST ensure the replaced block was destroyed or can handle replacement correctly. Wakes up the simulators.
If the chunk for any of the blocks is not loaded, the set operation is ignored silently. */
void SetBlocks(const sSetBlockVector & a_Blocks);
/** Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType */
void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType);
void PlaceBlock(const Vector3i a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta);
/** Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read. */
bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure);
// tolua_begin
/** Replaces the specified block with air, and calls the apropriate block handlers (OnBreaking(), OnBroken()).
Wakes up the simulators.
Doesn't produce pickups, use DropBlockAsPickups() for that instead.
/** Replaces the specified block with air, and calls the OnBroken block handler.
Wakes up the simulators. Doesn't produce pickups, use DropBlockAsPickups() for that instead.
Returns true on success, false if the chunk is not loaded. */
bool DigBlock(Vector3i a_BlockPos);