From adb86a75dac91a210149fc28b1dbf5225896f66c Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 29 Jul 2020 20:15:09 +0100 Subject: [PATCH] Do not GetBlock individually in simulators * Have the simulator manager get the block and pass it on + Add new overload for WakeUp, called when the manager wakes face positions --- src/Simulator/DelayedFluidSimulator.cpp | 30 +++---- src/Simulator/DelayedFluidSimulator.h | 3 +- .../IncrementalRedstoneSimulator.cpp | 85 ++++++++----------- .../IncrementalRedstoneSimulator.h | 3 +- src/Simulator/Simulator.h | 19 ++++- src/Simulator/SimulatorManager.cpp | 24 +++++- src/Simulator/SimulatorManager.h | 4 +- 7 files changed, 93 insertions(+), 75 deletions(-) diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp index b27e34e5f..ec1918617 100644 --- a/src/Simulator/DelayedFluidSimulator.cpp +++ b/src/Simulator/DelayedFluidSimulator.cpp @@ -78,21 +78,6 @@ cDelayedFluidSimulator::cDelayedFluidSimulator(cWorld & a_World, BLOCKTYPE a_Flu -void cDelayedFluidSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) -{ - if (!cChunkDef::IsValidHeight(a_Position.y)) - { - // Not inside the world (may happen when rclk with a full bucket - the client sends Y = -1) - return; - } - - Super::WakeUp(a_Chunk, a_Position, a_Block); -} - - - - - void cDelayedFluidSimulator::Simulate(float a_Dt) { m_AddSlotNum = m_SimSlotNum; @@ -153,3 +138,18 @@ void cDelayedFluidSimulator::AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLO ++m_TotalBlocks; } + + + + + +void cDelayedFluidSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) +{ + if (!cChunkDef::IsValidHeight(a_Position.y)) + { + // Not inside the world (may happen when rclk with a full bucket - the client sends Y = -1) + return; + } + + AddBlock(a_Chunk, a_Position, a_Block); +} diff --git a/src/Simulator/DelayedFluidSimulator.h b/src/Simulator/DelayedFluidSimulator.h index e307e4ad7..3022c9753 100644 --- a/src/Simulator/DelayedFluidSimulator.h +++ b/src/Simulator/DelayedFluidSimulator.h @@ -54,13 +54,12 @@ public: cDelayedFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, int a_TickDelay); - virtual void WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override; - protected: virtual void Simulate(float a_Dt) override; virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; virtual void AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override; + virtual void WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override; virtual cFluidSimulatorData * CreateChunkData(void) override { return new cDelayedFluidSimulatorChunkData(m_TickDelay); } int m_TickDelay; // Count of the m_Slots array in each ChunkData diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp index f2c8b7e65..e3177e420 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp @@ -128,53 +128,6 @@ std::unique_ptr cIncrementalRedstoneSimulator::CreateComponent -void cIncrementalRedstoneSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) -{ - Super::WakeUp(a_Chunk, a_Position, a_Block); - - auto & ChunkData = *static_cast(a_Chunk.GetRedstoneSimulatorData()); - - // Never update blocks without a handler: - if (GetComponentHandler(a_Block) == nullptr) - { - ChunkData.ErasePowerData(a_Position); - return; - } - - // Only update others if there is a redstone device nearby - for (int x = -1; x < 2; ++x) - { - for (int y = -1; y < 2; ++y) - { - if (!cChunkDef::IsValidHeight(a_Position.y + y)) - { - continue; - } - - for (int z = -1; z < 2; ++z) - { - auto CheckPos = a_Position + Vector3i{ x, y, z }; - BLOCKTYPE Block; - NIBBLETYPE Meta; - - // If we can't read the block, assume it is a mechanism - if ( - !a_Chunk.UnboundedRelGetBlock(CheckPos, Block, Meta) || - IsRedstone(Block) - ) - { - ChunkData.WakeUp(a_Position); - return; - } - } - } - } -} - - - - - void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) { auto & ChunkData = *static_cast(a_Chunk->GetRedstoneSimulatorData()); @@ -273,13 +226,16 @@ void cIncrementalRedstoneSimulator::ProcessWorkItem(cChunk & Chunk, cChunk & Tic void cIncrementalRedstoneSimulator::AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) { - auto & ChunkData = *static_cast(a_Chunk.GetRedstoneSimulatorData()); - if (!IsRedstone(a_Block)) { return; } + // Never update blocks without a handler: + ASSERT(GetComponentHandler(a_Block) != nullptr); + + auto & ChunkData = *static_cast(a_Chunk.GetRedstoneSimulatorData()); + if (IsAlwaysTicked(a_Block)) { ChunkData.AlwaysTickedPositions.emplace(a_Position); @@ -288,3 +244,34 @@ void cIncrementalRedstoneSimulator::AddBlock(cChunk & a_Chunk, Vector3i a_Positi // Always update redstone devices: ChunkData.WakeUp(a_Position); } + + + + + +void cIncrementalRedstoneSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) +{ + // Having WakeUp called on us directly means someone called SetBlock (or WakeUp) + // Since the simulator never does this, something external changed. Clear cached data: + static_cast(a_Chunk.GetRedstoneSimulatorData())->ErasePowerData(a_Position); + + // Queue the block, in case the set block was redstone: + AddBlock(a_Chunk, a_Position, a_Block); +} + + + + + +void cIncrementalRedstoneSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, Vector3i a_Offset, BLOCKTYPE a_Block) +{ + // This is an automatic cross-coords wakeup by cSimulatorManager + // There is no need to erase power data; if a component was destroyed the 3-arg WakeUp will handle it + + AddBlock(a_Chunk, a_Position, a_Block); + + // The only thing to do go one block farther than this cross-coord, in the direction of Offset + // in order to notify linked-powered positions that there was a change + + // TODO: use a_Offset, exclude a_Position and a_Position - a_Offset +} diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h index 44c63a5a8..e20880b7a 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h @@ -147,7 +147,6 @@ public: private: - virtual void WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override; virtual void Simulate(float Dt) override {}; virtual void SimulateChunk(std::chrono::milliseconds Dt, int ChunkX, int ChunkZ, cChunk * Chunk) override; @@ -159,6 +158,8 @@ private: } virtual void AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override; + virtual void WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override; + virtual void WakeUp(cChunk & a_Chunk, Vector3i a_Position, Vector3i a_Offset, BLOCKTYPE a_Block) override; private: diff --git a/src/Simulator/Simulator.h b/src/Simulator/Simulator.h index aacd5f52f..f82b579cb 100644 --- a/src/Simulator/Simulator.h +++ b/src/Simulator/Simulator.h @@ -13,9 +13,9 @@ class cCuboid; Each descendant provides an implementation of what needs to be done on each world tick. The descendant may choose to do all processing in a single call for the entire world (Simulate()) or do per-chunk calculations (SimulateChunk()). -Whenever a block is changed, the WakeUp() or WakeUpArea() functions are called to notify all simulators. -The functions add all affected blocks and all their direct neighbors using the AddBlock() function. The simulator -may update its internal state based on this call. */ +Whenever a block is changed, the WakeUp() functions are called to notify all simulators by the simulator manager. +The functions are invoked to add all affected blocks and their direct neighbors using the AddBlock() function. +The simulator may update its internal state based on this call. */ class cSimulator { public: @@ -27,7 +27,18 @@ public: virtual ~cSimulator() {} - virtual void WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block); + // Contains our direct adjacents + inline static std::array AdjacentOffsets + { + { + { 1, 0, 0 }, + { -1, 0, 0 }, + { 0, 1, 0 }, + { 0, -1, 0 }, + { 0, 0, 1 }, + { 0, 0, -1 }, + } + }; protected: diff --git a/src/Simulator/SimulatorManager.cpp b/src/Simulator/SimulatorManager.cpp index f10c285e0..07b4a7214 100644 --- a/src/Simulator/SimulatorManager.cpp +++ b/src/Simulator/SimulatorManager.cpp @@ -63,9 +63,29 @@ void cSimulatorManager::WakeUp(cChunk & a_Chunk, Vector3i a_Position) { ASSERT(a_Chunk.IsValid()); - for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr) + for (const auto Item : m_Simulators) { - itr->first->WakeUp(a_Chunk, a_Position, a_Chunk.GetBlock(a_Position)); + Item.first->WakeUp(a_Chunk, a_Position, a_Chunk.GetBlock(a_Position)); + } + + for (const auto Offset : cSimulator::AdjacentOffsets) + { + auto Relative = a_Position + Offset; + auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Relative); + + if ((Chunk == nullptr) || !Chunk->IsValid()) + { + continue; + } + + // Stored block to give to simulators for performance + // Since they all need this we save them querying it themselves + const auto Block = Chunk->GetBlock(Relative); + + for (const auto Item : m_Simulators) + { + Item.first->WakeUp(*Chunk, Relative, Offset, Block); + } } } diff --git a/src/Simulator/SimulatorManager.h b/src/Simulator/SimulatorManager.h index b5f54381c..4594bd7d6 100644 --- a/src/Simulator/SimulatorManager.h +++ b/src/Simulator/SimulatorManager.h @@ -38,8 +38,8 @@ public: /** Called in each tick for each chunk, a_Dt is the time passed since the last tick, in msec; direct access to chunk data available. */ void SimulateChunk(std::chrono::milliseconds a_DT, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk); - /* Called when a single block changes, wakes all simulators up for the block. - The simulator implementation may also decide to wake the block's face-neighbors or blocks farther away. */ + /* Called when a single block changes, wakes all simulators up for the block and its face-neighbors. + The simulator implementation may also decide to wake blocks farther away. */ void WakeUp(cChunk & a_Chunk, Vector3i a_Position); /** Does the same processing as WakeUp, but for all blocks within the specified area.