1
0
Fork 0

Corrected wakeup sequences

* Pistons/Ice no longer need to FastSetBlock first (#4600), and the former don't drop items when broken in creative
- Begin migration away from stationary fluids
* Tick the chunk after applying a client's changed
* Broadcast pending blocks at the end of a tick
This commit is contained in:
Tiger Wang 2020-08-01 11:25:06 +01:00
parent 6bdd130aab
commit c3d6afe47e
10 changed files with 70 additions and 139 deletions

View File

@ -43,32 +43,6 @@ public:
virtual void Check(
cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk
) override
{
switch (m_BlockType)
{
case E_BLOCK_STATIONARY_LAVA:
{
a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_LAVA, a_Chunk.GetMeta(a_RelPos));
break;
}
case E_BLOCK_STATIONARY_WATER:
{
a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_WATER, a_Chunk.GetMeta(a_RelPos));
break;
}
}
Super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk);
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{ {
UNUSED(a_Meta); UNUSED(a_Meta);

View File

@ -19,10 +19,6 @@ public:
{ {
} }
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{ {
// Only drop self when using silk-touch: // Only drop self when using silk-touch:
@ -36,10 +32,6 @@ public:
} }
} }
virtual void OnBroken( virtual void OnBroken(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos, Vector3i a_BlockPos,
@ -51,19 +43,14 @@ public:
{ {
return; return;
} }
auto blockTypeBelow = a_ChunkInterface.GetBlock(a_BlockPos.addedY(-1));
if (cBlockInfo::FullyOccupiesVoxel(blockTypeBelow) || IsBlockLiquid(blockTypeBelow)) const auto Below = a_ChunkInterface.GetBlock(a_BlockPos.addedY(-1));
if (cBlockInfo::FullyOccupiesVoxel(Below) || IsBlockLiquid(Below))
{ {
// Setting air with FastSetBlock prevents SetBlock recursively calling OnBroken.
a_ChunkInterface.FastSetBlock(a_BlockPos, E_BLOCK_AIR, 0);
a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_WATER, 0); a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_WATER, 0);
} }
} }
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{ {
UNUSED(a_Meta); UNUSED(a_Meta);

View File

@ -32,14 +32,19 @@ void cBlockPistonHandler::OnBroken(
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) )
{ {
// If the piston is extended, destroy the extension as well if (!IsExtended(a_OldBlockMeta))
if (IsExtended(a_OldBlockMeta))
{ {
auto extPos = a_BlockPos + MetadataToOffset(a_OldBlockMeta); return;
if (a_ChunkInterface.GetBlock(extPos) == E_BLOCK_PISTON_EXTENSION) }
{
a_ChunkInterface.DropBlockAsPickups(extPos); const auto Extension = a_BlockPos + MetadataToOffset(a_OldBlockMeta);
} if (
cChunkDef::IsValidHeight(Extension.y) &&
(a_ChunkInterface.GetBlock(Extension) == E_BLOCK_PISTON_EXTENSION)
)
{
// If the piston is extended, destroy the extension as well:
a_ChunkInterface.SetBlock(Extension, E_BLOCK_AIR, 0);
} }
} }
@ -75,7 +80,7 @@ void cBlockPistonHandler::PushBlocks(
cWorld & a_World, const Vector3i & a_PushDir cWorld & a_World, const Vector3i & a_PushDir
) )
{ {
// Sort blocks to move the blocks first, which are farest away from the piston // Sort blocks to move the blocks first, which are farthest away from the piston
// This prevents the overwriting of existing blocks // This prevents the overwriting of existing blocks
std::vector<Vector3i> sortedBlocks(a_BlocksToPush.begin(), a_BlocksToPush.end()); std::vector<Vector3i> sortedBlocks(a_BlocksToPush.begin(), a_BlocksToPush.end());
std::sort(sortedBlocks.begin(), sortedBlocks.end(), [a_PushDir](const Vector3i & a, const Vector3i & b) std::sort(sortedBlocks.begin(), sortedBlocks.end(), [a_PushDir](const Vector3i & a, const Vector3i & b)
@ -281,8 +286,7 @@ void cBlockPistonHandler::RetractPiston(Vector3i a_BlockPos, cWorld & a_World)
return; return;
} }
// Remove extension, update base state. Calling FastSetBlock inhibits OnBroken being called by SetBlock. // Remove extension, update base state:
World.FastSetBlock(extensionPos, E_BLOCK_AIR, 0);
World.SetBlock(extensionPos, E_BLOCK_AIR, 0); World.SetBlock(extensionPos, E_BLOCK_AIR, 0);
World.SetBlock(a_BlockPos, pistonBlock, pistonMeta & ~(8)); World.SetBlock(a_BlockPos, pistonBlock, pistonMeta & ~(8));
@ -334,11 +338,17 @@ void cBlockPistonHeadHandler::OnBroken(
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) )
{ {
// Drop the base of the piston: const auto Base = a_BlockPos - cBlockPistonHandler::MetadataToOffset(a_OldBlockMeta);
auto basePos = a_BlockPos - cBlockPistonHandler::MetadataToOffset(a_OldBlockMeta); if (!cChunkDef::IsValidHeight(Base.y))
if (cChunkDef::IsValidHeight(basePos.y))
{ {
a_ChunkInterface.DropBlockAsPickups(basePos); return;
}
const auto Block = a_ChunkInterface.GetBlock(Base);
if ((Block == E_BLOCK_PISTON) || (Block == E_BLOCK_STICKY_PISTON))
{
// Remove the base of the piston:
a_ChunkInterface.SetBlock(Base, E_BLOCK_AIR, 0);
} }
} }
@ -346,3 +356,9 @@ void cBlockPistonHeadHandler::OnBroken(
cItems cBlockPistonHeadHandler::ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool)
{
// Give a normal\sticky piston base, not piston extension
// With 1.7, the item forms of these technical blocks have been removed, so giving someone this will crash their client...
return { cItem(((a_BlockMeta & 0x8) == 0x8) ? E_BLOCK_STICKY_PISTON : E_BLOCK_PISTON) };
}

View File

@ -155,10 +155,5 @@ public:
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) override; ) override;
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override;
{
// No pickups
// Also with 1.7, the item forms of these technical blocks have been removed, so giving someone this will crash their client...
return {};
}
} ; } ;

View File

@ -19,44 +19,25 @@ 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
{
a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & a_Chunk) { CheckSoaked(a_Chunk.AbsoluteToRelative(a_BlockPos), a_Chunk); return true; });
}
/** Check blocks around the sponge to see if they are water. /** Check blocks around the sponge to see if they are water.
If a dry sponge is touching water, soak up up to 65 blocks of water, If a dry sponge is touching water, soak up up to 65 blocks of water,
with a taxicab distance of 7, and turn the sponge into a wet sponge. with a taxicab distance of 7, and turn the sponge into a wet sponge. */
Returns TRUE if the block was changed. */ void CheckSoaked(Vector3i a_Rel, cChunk & a_Chunk)
bool GetSoaked(Vector3i a_Rel, cChunk & a_Chunk)
{ {
static const std::array<Vector3i, 6> WaterCheck
{
{
{ 1, 0, 0},
{-1, 0, 0},
{ 0, 0, 1},
{ 0, 0, -1},
{ 0, 1, 0},
{ 0, -1, 0},
}
};
struct sSeed struct sSeed
{ {
sSeed(Vector3i pos, int d) sSeed(Vector3i pos, int d)
@ -68,27 +49,25 @@ public:
int m_Depth; int m_Depth;
}; };
// Check if this is a dry sponge next to a water block. // Check if this is a dry sponge next to a water block.
NIBBLETYPE TargetMeta = a_Chunk.GetMeta(a_Rel.x, a_Rel.y, a_Rel.z); NIBBLETYPE TargetMeta = a_Chunk.GetMeta(a_Rel.x, a_Rel.y, a_Rel.z);
if (TargetMeta != E_META_SPONGE_DRY) if (TargetMeta != E_META_SPONGE_DRY)
{ {
return false; return;
} }
bool ShouldSoak = std::any_of(WaterCheck.cbegin(), WaterCheck.cend(), [a_Rel, & a_Chunk](Vector3i a_Offset) const auto & WaterCheck = cSimulator::AdjacentOffsets;
{ const bool ShouldSoak = std::any_of(WaterCheck.cbegin(), WaterCheck.cend(), [a_Rel, &a_Chunk](Vector3i a_Offset)
return IsWet(a_Rel + a_Offset, a_Chunk); {
} return IsWet(a_Rel + a_Offset, a_Chunk);
); });
// Early return if the sponge isn't touching any water. // Early return if the sponge isn't touching any water.
if (! ShouldSoak) if (!ShouldSoak)
{ {
return false; return;
} }
// Use a queue to hold blocks that we want to check, so our search is breadth-first. // Use a queue to hold blocks that we want to check, so our search is breadth-first.
std::queue<sSeed> Seeds; std::queue<sSeed> Seeds;
int count = 0; int count = 0;
@ -100,7 +79,6 @@ public:
Seeds.emplace(a_Rel + WaterCheck[i], maxDepth - 1); Seeds.emplace(a_Rel + WaterCheck[i], maxDepth - 1);
} }
// Keep checking blocks that are touching water blocks, or until 65 have been soaked up. // Keep checking blocks that are touching water blocks, or until 65 have been soaked up.
while (!Seeds.empty() && count < 65) while (!Seeds.empty() && count < 65)
{ {
@ -122,24 +100,16 @@ public:
} }
Seeds.pop(); Seeds.pop();
} }
a_Chunk.SetBlock(a_Rel, E_BLOCK_SPONGE, E_META_SPONGE_WET); a_Chunk.SetBlock(a_Rel, E_BLOCK_SPONGE, E_META_SPONGE_WET);
return true;
} }
static void DryUp(Vector3i a_Rel, cChunk & a_Chunk) static void DryUp(Vector3i a_Rel, cChunk & a_Chunk)
{ {
// TODO: support evaporating waterlogged blocks. // TODO: support evaporating waterlogged blocks.
a_Chunk.UnboundedRelSetBlock(a_Rel.x, a_Rel.y, a_Rel.z, E_BLOCK_AIR, 0); a_Chunk.UnboundedRelSetBlock(a_Rel.x, a_Rel.y, a_Rel.z, E_BLOCK_AIR, 0);
} }
static bool IsWet(Vector3i a_Rel, cChunk & a_Chunk) static bool IsWet(Vector3i a_Rel, cChunk & a_Chunk)
{ {
// TODO: support detecting waterlogged blocks. // TODO: support detecting waterlogged blocks.
@ -147,18 +117,9 @@ public:
return(a_Chunk.UnboundedRelGetBlockType(a_Rel.x, a_Rel.y, a_Rel.z, Type) && IsBlockWater(Type)); return(a_Chunk.UnboundedRelGetBlockType(a_Rel.x, a_Rel.y, a_Rel.z, Type) && IsBlockWater(Type));
} }
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{ {
UNUSED(a_Meta); UNUSED(a_Meta);
return 18; return 18;
} }
}; };

View File

@ -162,12 +162,12 @@ public:
virtual void Check( virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override
cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk
) override
{ {
a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & a_Chunk)
{
const auto a_RelPos = a_Chunk.AbsoluteToRelative(a_BlockPos);
NIBBLETYPE CurMeta = a_Chunk.GetMeta(a_RelPos); NIBBLETYPE CurMeta = a_Chunk.GetMeta(a_RelPos);
NIBBLETYPE MaxMeta = GetMaxMeta(a_Chunk, a_RelPos); NIBBLETYPE MaxMeta = GetMaxMeta(a_Chunk, a_RelPos);
@ -190,14 +190,13 @@ public:
a_ChunkInterface.DropBlockAsPickups(a_Chunk.RelativeToAbsolute(a_RelPos)); a_ChunkInterface.DropBlockAsPickups(a_Chunk.RelativeToAbsolute(a_RelPos));
} }
a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0); a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0);
return; return false;
} }
a_Chunk.SetBlock(a_RelPos, m_BlockType, Common); a_Chunk.SetBlock(a_RelPos, m_BlockType, Common);
} }
else
{ return false;
a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(a_Chunk, a_RelPos); });
}
} }

View File

@ -651,8 +651,6 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt)
return; return;
} }
BroadcastPendingBlockChanges();
CheckBlocks(); CheckBlocks();
// Tick simulators: // Tick simulators:
@ -716,6 +714,8 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt)
} // for itr - m_Entitites[] } // for itr - m_Entitites[]
ApplyWeatherToTop(); ApplyWeatherToTop();
BroadcastPendingBlockChanges();
} }

View File

@ -121,7 +121,7 @@ void cDelayedFluidSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a
void cDelayedFluidSimulator::AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) void cDelayedFluidSimulator::AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block)
{ {
if (a_Block != m_FluidBlock) if ((a_Block != m_FluidBlock) && (a_Block != m_StationaryFluidBlock))
{ {
return; return;
} }

View File

@ -28,7 +28,7 @@ public:
virtual ~cSimulator() {} virtual ~cSimulator() {}
// Contains our direct adjacents // Contains our direct adjacents
inline static std::array<Vector3i, 6> AdjacentOffsets static constexpr std::array<Vector3i, 6> AdjacentOffsets
{ {
{ {
{ 1, 0, 0 }, { 1, 0, 0 },

View File

@ -1036,12 +1036,11 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La
// Add players waiting in the queue to be added: // Add players waiting in the queue to be added:
AddQueuedPlayers(); AddQueuedPlayers();
m_ChunkMap->Tick(a_Dt);
TickMobs(a_Dt);
m_MapManager.TickMaps();
TickClients(static_cast<float>(a_Dt.count())); TickClients(static_cast<float>(a_Dt.count()));
TickQueuedBlocks(); TickQueuedBlocks();
m_ChunkMap->Tick(a_Dt); // Tick chunk after clients to apply at least one round of queued ticks (e.g. cBlockHandler::Check) this tick
TickMobs(a_Dt);
m_MapManager.TickMaps();
TickQueuedTasks(); TickQueuedTasks();
GetSimulatorManager()->Simulate(static_cast<float>(a_Dt.count())); GetSimulatorManager()->Simulate(static_cast<float>(a_Dt.count()));