From c3d6afe47e8e50f9b029caf012c69d1e6ee4e76a Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 1 Aug 2020 11:25:06 +0100 Subject: [PATCH] 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 --- src/Blocks/BlockFluid.h | 26 -------- src/Blocks/BlockIce.h | 19 +----- src/Blocks/BlockPiston.cpp | 44 +++++++++----- src/Blocks/BlockPiston.h | 7 +-- src/Blocks/BlockSponge.h | 79 +++++++------------------ src/Blocks/BlockVine.h | 19 +++--- src/Chunk.cpp | 4 +- src/Simulator/DelayedFluidSimulator.cpp | 2 +- src/Simulator/Simulator.h | 2 +- src/World.cpp | 7 +-- 10 files changed, 70 insertions(+), 139 deletions(-) diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h index e856dba38..35b702f4b 100644 --- a/src/Blocks/BlockFluid.h +++ b/src/Blocks/BlockFluid.h @@ -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); diff --git a/src/Blocks/BlockIce.h b/src/Blocks/BlockIce.h index 5e2fd9dbb..a4372d0ea 100644 --- a/src/Blocks/BlockIce.h +++ b/src/Blocks/BlockIce.h @@ -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); diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index e68e05809..b68a59461 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -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 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) }; +} diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h index 7ff478a68..8799ba3ca 100644 --- a/src/Blocks/BlockPiston.h +++ b/src/Blocks/BlockPiston.h @@ -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; } ; diff --git a/src/Blocks/BlockSponge.h b/src/Blocks/BlockSponge.h index 88981567a..2ef078ea1 100644 --- a/src/Blocks/BlockSponge.h +++ b/src/Blocks/BlockSponge.h @@ -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 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 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; } - - - - - }; diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index 68e6e2ddc..25b6efe47 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -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; + }); } diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 21261e828..25af8d6fb 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -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(); } diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp index ec1918617..9bec01359 100644 --- a/src/Simulator/DelayedFluidSimulator.cpp +++ b/src/Simulator/DelayedFluidSimulator.cpp @@ -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; } diff --git a/src/Simulator/Simulator.h b/src/Simulator/Simulator.h index f82b579cb..e18465bee 100644 --- a/src/Simulator/Simulator.h +++ b/src/Simulator/Simulator.h @@ -28,7 +28,7 @@ public: virtual ~cSimulator() {} // Contains our direct adjacents - inline static std::array AdjacentOffsets + static constexpr std::array AdjacentOffsets { { { 1, 0, 0 }, diff --git a/src/World.cpp b/src/World.cpp index f70343889..d19d9f6c6 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -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(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(a_Dt.count()));