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 OnPlaced(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
virtual void Check(
cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk
) override ) override
{ {
if (GetSoaked(a_RelPos, a_Chunk)) OnNeighborChanged(a_ChunkInterface, a_BlockPos, BLOCK_FACE_NONE);
{
return;
}
Super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk);
} }
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override
/** 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)
{ {
static const std::array<Vector3i, 5> WaterCheck a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & a_Chunk) { CheckSoaked(a_Chunk.AbsoluteToRelative(a_BlockPos), a_Chunk); return true; });
{ }
{
{ 1, 0, 0},
{-1, 0, 0},
{ 0, 0, 1},
{ 0, 0, -1},
{ 0, 1, 0},
}
};
bool ShouldSoak = std::any_of(WaterCheck.cbegin(), WaterCheck.cend(), [a_Rel, & a_Chunk](Vector3i a_Offset) /** 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)
BLOCKTYPE NeighborType; {
return ( const auto & WaterCheck = cSimulator::AdjacentOffsets;
a_Chunk.UnboundedRelGetBlockType(a_Rel.x + a_Offset.x, a_Rel.y + a_Offset.y, a_Rel.z + a_Offset.z, NeighborType) const bool ShouldSoak = std::any_of(WaterCheck.cbegin(), WaterCheck.cend(), [a_Rel, & a_Chunk](Vector3i a_Offset)
&& IsBlockWater(NeighborType) {
); 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) if (ShouldSoak)
{ {
NIBBLETYPE BlockMeta; NIBBLETYPE BlockMeta;
BlockMeta = a_Chunk.GetMeta(a_Rel.x, a_Rel.y, a_Rel.z); BlockMeta = a_Chunk.GetMeta(a_Rel.x, a_Rel.y, a_Rel.z);
a_Chunk.SetBlock(a_Rel, E_BLOCK_CONCRETE, BlockMeta); a_Chunk.SetBlock(a_Rel, E_BLOCK_CONCRETE, BlockMeta);
return true;
} }
return false;
} }
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{ {
switch (a_Meta) 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;
}
if (DoesDropOnUnsuitable())
{
a_ChunkInterface.DropBlockAsPickups(a_BlockPos);
}
void cBlockHandler::OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) else
{ {
// Notify the neighbors a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_AIR, 0);
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);
} }
@ -585,19 +567,13 @@ void cBlockHandler::Check(
cChunk & a_Chunk cChunk & a_Chunk
) )
{ {
if (CanBeAt(a_ChunkInterface, a_RelPos, a_Chunk)) const auto Position = cChunkDef::RelativeToAbsolute(a_RelPos, a_Chunk.GetPos());
{ NeighborChanged(a_ChunkInterface, Position.addedX(-1), BLOCK_FACE_XP);
return; 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);
if (DoesDropOnUnsuitable()) NeighborChanged(a_ChunkInterface, Position.addedZ(-1), BLOCK_FACE_ZP);
{ NeighborChanged(a_ChunkInterface, Position.addedZ(1), BLOCK_FACE_ZM);
a_ChunkInterface.DropBlockAsPickups(a_Chunk.RelativeToAbsolute(a_RelPos));
}
else
{
a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0);
}
} }

View File

@ -65,21 +65,12 @@ public:
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos, Vector3i a_BlockPos,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
); ) {};
/** Called by cPlayer::PlaceBlocks() for each block after it has been set to the world. Called after OnPlaced(). */ /** Called by cPlayer::PlaceBlocks() for each block after it has been set to the world. Called after OnPlaced(). */
virtual void OnPlacedByPlayer( virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange 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. /** 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. 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 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. /** 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. 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. 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, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos, Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
); ) {};
/** Called when a direct neighbor of this block has been changed. /** 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. 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. 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.) */ 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. /** Notifies the specified neighbor that the current block has changed.
a_NeighborPos are the coords of the neighbor to be notified 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. /** 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()), By default drops (DropBlockAsPickup() / SetBlock()) if the position is no longer suitable (CanBeAt(), DoesDropOnUnsuitable()),
otherwise wakes up all simulators on the block. */ otherwise wakes up all simulators on the block. */
virtual void Check( void Check(
cChunkInterface & ChunkInterface, cBlockPluginInterface & a_PluginInterface, cChunkInterface & ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos, Vector3i a_RelPos,
cChunk & a_Chunk cChunk & a_Chunk

View File

@ -44,7 +44,7 @@ public:
} }
case paDeath: 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; break;
} }
case paStay: break; // do nothing 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) BLOCKTYPE cChunkInterface::GetBlock(Vector3i a_Pos)
{ {
return m_ChunkMap->GetBlock(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) bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos)
{ {
BLOCKTYPE blockType; BLOCKTYPE BlockType;
NIBBLETYPE blockMeta; NIBBLETYPE BlockMeta;
GetBlockTypeMeta(a_BlockPos, blockType, blockMeta); GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta);
auto handler = cBlockInfo::GetHandler(blockType);
handler->OnBreaking(*this, a_WorldInterface, a_BlockPos);
if (!m_ChunkMap->DigBlock(a_BlockPos)) if (!m_ChunkMap->DigBlock(a_BlockPos))
{ {
return false; return false;
} }
handler->OnBroken(*this, a_WorldInterface, a_BlockPos, blockType, blockMeta);
cBlockInfo::GetHandler(BlockType)->OnBroken(*this, a_WorldInterface, a_BlockPos, BlockType, BlockMeta);
return true; return true;
} }

View File

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

View File

@ -820,7 +820,7 @@ void cChunk::CheckBlocks()
while (Count != 0) while (Count != 0)
{ {
Vector3i Pos = m_ToTickBlocks.front(); const auto Pos = m_ToTickBlocks.front();
m_ToTickBlocks.pop(); m_ToTickBlocks.pop();
Count--; Count--;
@ -1263,8 +1263,8 @@ void cChunk::SetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_Blo
{ {
FastSetBlock(a_RelPos, a_BlockType, a_BlockMeta); FastSetBlock(a_RelPos, a_BlockType, a_BlockMeta);
// Tick this block and its neighbors: // Tick this block's neighbors via cBlockHandler::Check:
QueueTickBlockNeighbors(a_RelPos); m_ToTickBlocks.push(a_RelPos);
// Wake up the simulators for this block: // Wake up the simulators for this block:
GetWorld()->GetSimulatorManager()->WakeUp(*this, a_RelPos); 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) 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))); 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); 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 // 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(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) 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) 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 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); auto chunk = GetChunk(chunkPos.m_ChunkX, chunkPos.m_ChunkZ);
if ((chunk != nullptr) && chunk->IsValid()) 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); 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) void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);

View File

@ -132,11 +132,6 @@ public:
If the chunk is invalid, the operation is ignored silently. */ If the chunk is invalid, the operation is ignored silently. */
void FastSetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); 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. */ /** Makes the specified player collect all the pickups around them. */
void CollectPickupsByPlayer(cPlayer & a_Player); void CollectPickupsByPlayer(cPlayer & a_Player);
@ -155,9 +150,6 @@ public:
bool GetBlockTypeMeta (Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); 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); 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 */ /** Special function used for growing trees, replaces only blocks that tree may overwrite */
void ReplaceTreeBlocks(const sSetBlockVector & a_Blocks); 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()); cChunkInterface ChunkInterface(World->GetChunkMap());
auto blockHandler = BlockHandler(a_OldBlock); auto blockHandler = BlockHandler(a_OldBlock);
Vector3i absPos(a_BlockX, a_BlockY, a_BlockZ); Vector3i absPos(a_BlockX, a_BlockY, a_BlockZ);
blockHandler->OnPlayerBreakingBlock(ChunkInterface, *World, *m_Player, absPos);
if (m_Player->IsGameModeSurvival()) if (m_Player->IsGameModeSurvival())
{ {
World->DropBlockAsPickups(absPos, m_Player, &m_Player->GetEquippedItem()); 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[] } // for blk - a_Blocks[]
// Set the blocks:
m_World->SetBlocks(a_Blocks);
// Notify the blockhandlers:
cChunkInterface ChunkInterface(m_World->GetChunkMap()); cChunkInterface ChunkInterface(m_World->GetChunkMap());
for (auto blk: a_Blocks) 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); cBlockHandler * newBlock = BlockHandler(blk.m_BlockType);
newBlock->OnPlacedByPlayer(ChunkInterface, *m_World, *this, blk); newBlock->OnPlacedByPlayer(ChunkInterface, *m_World, *this, blk);
}
// Call the "placed" hooks: // Call the "placed" hooks:
for (auto blk: a_Blocks)
{
pm->CallHookPlayerPlacedBlock(*this, blk); pm->CallHookPlayerPlacedBlock(*this, blk);
} }
return true; return true;
} }

View File

@ -54,7 +54,6 @@ public:
Vector3i PlacePos; Vector3i PlacePos;
if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta)) if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta))
{ {
blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, a_ClickedBlockPos);
PlacePos = a_ClickedBlockPos; PlacePos = a_ClickedBlockPos;
} }
else else
@ -75,7 +74,6 @@ public:
{ {
return false; return false;
} }
blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, PlacePos);
} }
// Check that there is at most one single neighbor of the same chest type: // 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: case E_BLOCK_TNT:
{ {
// Activate the 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 a_World->SpawnPrimedTNT(Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5)); // 80 ticks to boom
break; break;
} }
@ -79,7 +79,7 @@ public:
} }
if (a_World->GetBlock(FirePos) == E_BLOCK_AIR) 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); a_World->BroadcastSoundEffect("item.flintandsteel.use", FirePos, 1.0f, 1.04f);
break; 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);
}
cChunkInterface ChunkInterface(GetChunkMap());
cBlockInfo::GetHandler(a_BlockType)->OnPlaced(ChunkInterface, *this, a_Position, a_BlockType, a_BlockMeta);
void cWorld::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType)
{
m_ChunkMap->ReplaceBlocks(a_Blocks, a_FilterBlockType);
} }
@ -2211,17 +2205,18 @@ bool cWorld::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
bool cWorld::DigBlock(Vector3i a_BlockPos) bool cWorld::DigBlock(Vector3i a_BlockPos)
{ {
BLOCKTYPE blockType; BLOCKTYPE BlockType;
NIBBLETYPE blockMeta; NIBBLETYPE BlockMeta;
GetBlockTypeMeta(a_BlockPos, blockType, blockMeta); GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta);
cChunkInterface chunkInterface(GetChunkMap());
auto blockHandler = cBlockInfo::GetHandler(blockType);
blockHandler->OnBreaking(chunkInterface, *this, a_BlockPos);
if (!m_ChunkMap->DigBlock(a_BlockPos)) if (!m_ChunkMap->DigBlock(a_BlockPos))
{ {
return false; 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; return true;
} }

View File

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