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
{
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
{
// Only drop self when using silk-touch:
@ -36,10 +32,6 @@ public:
}
}
virtual void OnBroken(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
@ -51,19 +43,14 @@ public:
{
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);
}
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -32,14 +32,19 @@ void cBlockPistonHandler::OnBroken(
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);
if (a_ChunkInterface.GetBlock(extPos) == E_BLOCK_PISTON_EXTENSION)
{
a_ChunkInterface.DropBlockAsPickups(extPos);
}
return;
}
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
)
{
// 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
std::vector<Vector3i> sortedBlocks(a_BlocksToPush.begin(), a_BlocksToPush.end());
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;
}
// Remove extension, update base state. Calling FastSetBlock inhibits OnBroken being called by SetBlock.
World.FastSetBlock(extensionPos, E_BLOCK_AIR, 0);
// Remove extension, update base state:
World.SetBlock(extensionPos, E_BLOCK_AIR, 0);
World.SetBlock(a_BlockPos, pistonBlock, pistonMeta & ~(8));
@ -334,11 +338,17 @@ void cBlockPistonHeadHandler::OnBroken(
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
)
{
// Drop the base of the piston:
auto basePos = a_BlockPos - cBlockPistonHandler::MetadataToOffset(a_OldBlockMeta);
if (cChunkDef::IsValidHeight(basePos.y))
const auto Base = a_BlockPos - cBlockPistonHandler::MetadataToOffset(a_OldBlockMeta);
if (!cChunkDef::IsValidHeight(Base.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
) 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 {};
}
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override;
} ;

View File

@ -19,44 +19,25 @@ 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);
}
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.
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.
Returns TRUE if the block was changed. */
bool GetSoaked(Vector3i a_Rel, cChunk & a_Chunk)
with a taxicab distance of 7, and turn the sponge into a wet sponge. */
void CheckSoaked(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
{
sSeed(Vector3i pos, int d)
@ -68,27 +49,25 @@ public:
int m_Depth;
};
// 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);
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)
{
return IsWet(a_Rel + a_Offset, a_Chunk);
}
);
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);
});
// 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.
std::queue<sSeed> Seeds;
int count = 0;
@ -100,7 +79,6 @@ public:
Seeds.emplace(a_Rel + WaterCheck[i], maxDepth - 1);
}
// Keep checking blocks that are touching water blocks, or until 65 have been soaked up.
while (!Seeds.empty() && count < 65)
{
@ -122,24 +100,16 @@ public:
}
Seeds.pop();
}
a_Chunk.SetBlock(a_Rel, E_BLOCK_SPONGE, E_META_SPONGE_WET);
return true;
}
static void DryUp(Vector3i a_Rel, cChunk & a_Chunk)
{
// TODO: support evaporating waterlogged blocks.
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)
{
// 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));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);
return 18;
}
};

View File

@ -162,12 +162,12 @@ public:
virtual void Check(
cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk
) override
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) 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 MaxMeta = GetMaxMeta(a_Chunk, a_RelPos);
@ -190,14 +190,13 @@ public:
a_ChunkInterface.DropBlockAsPickups(a_Chunk.RelativeToAbsolute(a_RelPos));
}
a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0);
return;
return false;
}
a_Chunk.SetBlock(a_RelPos, m_BlockType, Common);
}
else
{
a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(a_Chunk, a_RelPos);
}
return false;
});
}

View File

@ -651,8 +651,6 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt)
return;
}
BroadcastPendingBlockChanges();
CheckBlocks();
// Tick simulators:
@ -716,6 +714,8 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt)
} // for itr - m_Entitites[]
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)
{
if (a_Block != m_FluidBlock)
if ((a_Block != m_FluidBlock) && (a_Block != m_StationaryFluidBlock))
{
return;
}

View File

@ -28,7 +28,7 @@ public:
virtual ~cSimulator() {}
// Contains our direct adjacents
inline static std::array<Vector3i, 6> AdjacentOffsets
static constexpr std::array<Vector3i, 6> AdjacentOffsets
{
{
{ 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:
AddQueuedPlayers();
m_ChunkMap->Tick(a_Dt);
TickMobs(a_Dt);
m_MapManager.TickMaps();
TickClients(static_cast<float>(a_Dt.count()));
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();
GetSimulatorManager()->Simulate(static_cast<float>(a_Dt.count()));