From f089103c2b121f8128abfd6cdf0bd3cfbeca4465 Mon Sep 17 00:00:00 2001 From: Debucquoy Anthony tonitch Date: Sat, 18 Jun 2022 02:09:58 +0200 Subject: Additional Y height checks (#5405) For redstone wire, block area bindings, and fire simulator. Co-authored-by: Tiger Wang --- src/Bindings/ManualBindings_BlockArea.cpp | 37 +++------------- src/Simulator/DelayedFluidSimulator.cpp | 15 ------- src/Simulator/DelayedFluidSimulator.h | 1 - src/Simulator/FireSimulator.cpp | 15 +++++-- src/Simulator/FireSimulator.h | 5 --- .../IncrementalRedstoneSimulator.cpp | 4 +- .../IncrementalRedstoneSimulator.h | 1 - .../RedstoneDataHelper.h | 30 +++++++++---- .../RedstoneWireHandler.h | 48 ++++++++++++--------- src/Simulator/NoopFluidSimulator.h | 16 ++++--- src/Simulator/NoopRedstoneSimulator.h | 10 ++++- src/Simulator/SandSimulator.h | 10 ----- src/Simulator/Simulator.cpp | 50 ++++------------------ src/Simulator/Simulator.h | 13 +----- src/Simulator/SimulatorManager.cpp | 49 +++++++++++++++++++-- src/Simulator/VaporizeFluidSimulator.cpp | 27 ++++++------ src/Simulator/VaporizeFluidSimulator.h | 6 +-- 17 files changed, 156 insertions(+), 181 deletions(-) (limited to 'src') diff --git a/src/Bindings/ManualBindings_BlockArea.cpp b/src/Bindings/ManualBindings_BlockArea.cpp index a53a7bebf..c363e082f 100644 --- a/src/Bindings/ManualBindings_BlockArea.cpp +++ b/src/Bindings/ManualBindings_BlockArea.cpp @@ -590,41 +590,14 @@ static int tolua_cBlockArea_Read(lua_State * a_LuaState) return L.ApiParamError("Invalid baDataTypes combination (%d)", dataTypes); } - // Check the coords, shift if needed: - bounds.Sort(); - if (bounds.p1.y < 0) + // Check the coords: + if (!cChunkDef::IsValidHeight(bounds.p1) || !cChunkDef::IsValidHeight(bounds.p2)) { - FLOGWARNING("cBlockArea:Read(): MinBlockY less than zero, adjusting to zero. Coords: {0} - {1}", - bounds.p1, bounds.p2 - ); - L.LogStackTrace(); - bounds.p1.y = 0; - } - else if (bounds.p1.y >= cChunkDef::Height) - { - FLOGWARNING("cBlockArea:Read(): MinBlockY more than chunk height, adjusting to chunk height. Coords: {0} - {1}", - bounds.p1, bounds.p2 - ); - L.LogStackTrace(); - bounds.p1.y = cChunkDef::Height - 1; - } - if (bounds.p2.y < 0) - { - FLOGWARNING("cBlockArea:Read(): MaxBlockY less than zero, adjusting to zero. Coords: {0} - {1}", - bounds.p1, bounds.p2 - ); - L.LogStackTrace(); - bounds.p2.y = 0; - } - else if (bounds.p2.y > cChunkDef::Height) - { - FLOGWARNING("cBlockArea:Read(): MaxBlockY more than chunk height, adjusting to chunk height. Coords: {0} - {1}", - bounds.p1, bounds.p2 - ); - L.LogStackTrace(); - bounds.p2.y = cChunkDef::Height; + return L.FApiParamError("Coordinates {0} - {1} exceed world bounds", bounds.p1, bounds.p2); } + bounds.Sort(); + // Do the actual read: L.Push(self->Read(*world, bounds, dataTypes)); return 1; diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp index b7f7c890c..7e62acd04 100644 --- a/src/Simulator/DelayedFluidSimulator.cpp +++ b/src/Simulator/DelayedFluidSimulator.cpp @@ -138,18 +138,3 @@ 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)) - { - // 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 826489849..312bc1ff9 100644 --- a/src/Simulator/DelayedFluidSimulator.h +++ b/src/Simulator/DelayedFluidSimulator.h @@ -59,7 +59,6 @@ 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/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index d1eb8618c..a025f6afd 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -363,14 +363,21 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, Vector3i a_RelPos) { for (auto & coord : gNeighborCoords) { - BLOCKTYPE BlockType; auto relPos = a_RelPos + coord; - auto neighbor = a_Chunk->GetRelNeighborChunkAdjustCoords(relPos); - if (neighbor == nullptr) + + if (!cChunkDef::IsValidHeight(relPos)) + { + continue; + } + + const auto neighbor = a_Chunk->GetRelNeighborChunkAdjustCoords(relPos); + + if ((neighbor == nullptr) || !neighbor->IsValid()) { continue; } - BlockType = neighbor->GetBlock(relPos); + + BLOCKTYPE BlockType = neighbor->GetBlock(relPos); if (!IsFuel(BlockType)) { diff --git a/src/Simulator/FireSimulator.h b/src/Simulator/FireSimulator.h index 1e9b0b6d7..37ae3e63f 100644 --- a/src/Simulator/FireSimulator.h +++ b/src/Simulator/FireSimulator.h @@ -27,7 +27,6 @@ public: private: - virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; static bool IsAllowedBlock(BLOCKTYPE a_BlockType); @@ -68,7 +67,3 @@ private: /** Stores individual fire blocks in the chunk; the int data is used as the time [msec] the fire takes to step to another stage (blockmeta++) */ typedef cCoordWithIntList cFireSimulatorChunkData; - - - - diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp index c23af9f75..8063e72a4 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp @@ -217,12 +217,14 @@ void cIncrementalRedstoneSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position for (const auto & Offset : cSimulator::GetLinkedOffsets(a_Offset)) { auto Relative = a_Position - a_Offset + Offset; + if (!cChunkDef::IsValidHeight(Relative)) { continue; } - auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Relative); + const auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Relative); + if ((Chunk == nullptr) || !Chunk->IsValid()) { continue; diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h index 7f08c50af..365f0176e 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h @@ -26,7 +26,6 @@ private: void ProcessWorkItem(cChunk & Chunk, cChunk & TickingSource, const Vector3i Position); - virtual void Simulate(float Dt) override {} virtual void SimulateChunk(std::chrono::milliseconds Dt, int ChunkX, int ChunkZ, cChunk * Chunk) override; virtual void AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override; virtual cRedstoneSimulatorChunkData * CreateChunkData() override; diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneDataHelper.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneDataHelper.h index dc97a34d4..3942f803c 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneDataHelper.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneDataHelper.h @@ -7,23 +7,37 @@ inline auto & DataForChunk(const cChunk & a_Chunk) return *static_cast(a_Chunk.GetRedstoneSimulatorData()); } -template -inline void UpdateAdjustedRelative(const cChunk & From, const cChunk & To, const Vector3i Position, const Vector3i Offset) +inline void UpdateAdjustedRelative(const cChunk & a_Chunk, const cChunk & a_TickingChunk, const Vector3i a_Position, const Vector3i a_Offset) { - DataForChunk(To).WakeUp(cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(From, To, Position + Offset)); + const auto PositionToWake = a_Position + a_Offset; - for (const auto & LinkedOffset : cSimulator::GetLinkedOffsets(Offset)) + if (!cChunkDef::IsValidHeight(PositionToWake)) { - DataForChunk(To).WakeUp(cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(From, To, Position + LinkedOffset)); + // If an offset position is not a valid height, its linked offset positions won't be either. + return; + } + + auto & ChunkData = DataForChunk(a_TickingChunk); + + // Schedule the block in the requested direction to update: + ChunkData.WakeUp(cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(a_Chunk, a_TickingChunk, PositionToWake)); + + // To follow Vanilla behaviour, update all linked positions: + for (const auto & LinkedOffset : cSimulator::GetLinkedOffsets(a_Offset)) + { + if (const auto LinkedPositionToWake = a_Position + LinkedOffset; cChunkDef::IsValidHeight(LinkedPositionToWake)) + { + ChunkData.WakeUp(cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(a_Chunk, a_TickingChunk, LinkedPositionToWake)); + } } } template -inline void UpdateAdjustedRelatives(const cChunk & From, const cChunk & To, const Vector3i Position, const ArrayType & Relative) +inline void UpdateAdjustedRelatives(const cChunk & a_Chunk, const cChunk & a_TickingChunk, const Vector3i a_Position, const ArrayType & a_Relative) { - for (const auto & Offset : Relative) + for (const auto & Offset : a_Relative) { - UpdateAdjustedRelative(From, To, Position, Offset); + UpdateAdjustedRelative(a_Chunk, a_TickingChunk, a_Position, Offset); } } diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h index 5f2026842..b40491820 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h @@ -100,19 +100,32 @@ namespace RedstoneWireHandler } } + static bool IsYPTerracingBlocked(const cChunk & a_Chunk, const Vector3i a_Position) + { + const auto Position = a_Position + OffsetYP; + + if (!cChunkDef::IsValidHeight(Position)) + { + // Certainly cannot terrace at the top of the world: + return true; + } + + const auto YPTerraceBlock = a_Chunk.GetBlock(Position); + return cBlockInfo::IsSolid(YPTerraceBlock) && !cBlockInfo::IsTransparent(YPTerraceBlock); + } + /** Temporary. Discovers a wire's connection state, including terracing, storing the block inside redstone chunk data. TODO: once the server supports block states this should go in the block handler, with data saved in the world. */ - static void SetWireState(const cChunk & Chunk, const Vector3i Position) + static void SetWireState(const cChunk & a_Chunk, const Vector3i a_Position) { auto Block = Block::RedstoneWire::RedstoneWire(); - const auto YPTerraceBlock = Chunk.GetBlock(Position + OffsetYP); - const bool IsYPTerracingBlocked = cBlockInfo::IsSolid(YPTerraceBlock) && !cBlockInfo::IsTransparent(YPTerraceBlock); + const bool IsYPTerracingBlocked = RedstoneWireHandler::IsYPTerracingBlocked(a_Chunk, a_Position); // Loop through laterals, discovering terracing connections: for (const auto & Offset : RelativeLaterals) { - auto Adjacent = Position + Offset; - auto NeighbourChunk = Chunk.GetRelNeighborChunkAdjustCoords(Adjacent); + auto Adjacent = a_Position + Offset; + auto NeighbourChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Adjacent); if ((NeighbourChunk == nullptr) || !NeighbourChunk->IsValid()) { @@ -131,7 +144,7 @@ namespace RedstoneWireHandler // Temporary: this case will eventually be handled when wires are placed, with the state saved as blocks // When a neighbour wire was loaded into its chunk, its neighbour chunks may not have loaded yet // This function is called during chunk load (through AddBlock). Attempt to tell it its new state: - if ((NeighbourChunk != &Chunk) && (LateralBlock == E_BLOCK_REDSTONE_WIRE)) + if ((NeighbourChunk != &a_Chunk) && (LateralBlock == E_BLOCK_REDSTONE_WIRE)) { auto & NeighbourBlock = DataForChunk(*NeighbourChunk).WireStates.find(Adjacent)->second; SetDirectionState(-Offset, NeighbourBlock, TemporaryDirection::Side); @@ -148,7 +161,7 @@ namespace RedstoneWireHandler { SetDirectionState(Offset, Block, cBlockInfo::IsTransparent(LateralBlock) ? TemporaryDirection::Side : TemporaryDirection::Up); - if (NeighbourChunk != &Chunk) + if (NeighbourChunk != &a_Chunk) { auto & NeighbourBlock = DataForChunk(*NeighbourChunk).WireStates.find(Adjacent + OffsetYP)->second; SetDirectionState(-Offset, NeighbourBlock, TemporaryDirection::Side); @@ -166,7 +179,7 @@ namespace RedstoneWireHandler { SetDirectionState(Offset, Block, TemporaryDirection::Side); - if (NeighbourChunk != &Chunk) + if (NeighbourChunk != &a_Chunk) { auto & NeighbourBlock = DataForChunk(*NeighbourChunk).WireStates.find(Adjacent + OffsetYM)->second; SetDirectionState(-Offset, NeighbourBlock, TemporaryDirection::Up); @@ -174,8 +187,8 @@ namespace RedstoneWireHandler } } - auto & States = DataForChunk(Chunk).WireStates; - const auto FindResult = States.find(Position); + auto & States = DataForChunk(a_Chunk).WireStates; + const auto FindResult = States.find(a_Position); if (FindResult != States.end()) { if (Block != FindResult->second) @@ -184,13 +197,13 @@ namespace RedstoneWireHandler // TODO: when state is stored as the block, the block handler updating via SetBlock will do this automatically // When a wire changes connection state, it needs to update its neighbours: - Chunk.GetWorld()->WakeUpSimulators(cChunkDef::RelativeToAbsolute(Position, Chunk.GetPos())); + a_Chunk.GetWorld()->WakeUpSimulators(cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos())); } return; } - DataForChunk(Chunk).WireStates.emplace(Position, Block); + DataForChunk(a_Chunk).WireStates.emplace(a_Position, Block); } static PowerLevel GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) @@ -269,15 +282,8 @@ namespace RedstoneWireHandler a_Chunk.SetMeta(a_Position, Power); // Notify all positions, sans YP, to update: - for (const auto & Offset : RelativeAdjacents) - { - if (Offset == OffsetYP) - { - continue; - } - - UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position, Offset); - } + UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position, OffsetYM); + UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeLaterals); } static void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, ForEachSourceCallback & Callback) diff --git a/src/Simulator/NoopFluidSimulator.h b/src/Simulator/NoopFluidSimulator.h index 1b963f569..93d5cb50a 100644 --- a/src/Simulator/NoopFluidSimulator.h +++ b/src/Simulator/NoopFluidSimulator.h @@ -15,7 +15,7 @@ -class cNoopFluidSimulator: +class cNoopFluidSimulator final : public cFluidSimulator { using Super = cFluidSimulator; @@ -26,15 +26,19 @@ public: private: - virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} + virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override + { + UNUSED(a_Dt); + UNUSED(a_ChunkX); + UNUSED(a_ChunkZ); + UNUSED(a_Chunk); + } + virtual void AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override { UNUSED(a_Block); UNUSED(a_Chunk); } + virtual cFluidSimulatorData * CreateChunkData(void) override { return nullptr; } } ; - - - - diff --git a/src/Simulator/NoopRedstoneSimulator.h b/src/Simulator/NoopRedstoneSimulator.h index 746ee1886..a361b5b12 100644 --- a/src/Simulator/NoopRedstoneSimulator.h +++ b/src/Simulator/NoopRedstoneSimulator.h @@ -19,7 +19,14 @@ public: { } - virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used + virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override + { + UNUSED(a_Dt); + UNUSED(a_ChunkX); + UNUSED(a_ChunkZ); + UNUSED(a_Chunk); + } + virtual void AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override { UNUSED(a_Block); @@ -30,5 +37,4 @@ public: { return nullptr; } - } ; diff --git a/src/Simulator/SandSimulator.h b/src/Simulator/SandSimulator.h index e05b0de80..d27fd5873 100644 --- a/src/Simulator/SandSimulator.h +++ b/src/Simulator/SandSimulator.h @@ -55,7 +55,6 @@ public: private: - virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; bool m_IsInstantFall; // If set to true, blocks don't fall using cFallingBlock entity, but instantly instead @@ -67,12 +66,3 @@ private: /** Performs the instant fall of the block - removes it from top, Finishes it at the bottom */ void DoInstantFall(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ); }; - - - - - - - - - diff --git a/src/Simulator/Simulator.cpp b/src/Simulator/Simulator.cpp index 36b03520c..7bf553912 100644 --- a/src/Simulator/Simulator.cpp +++ b/src/Simulator/Simulator.cpp @@ -3,7 +3,6 @@ #include "Simulator.h" #include "../Chunk.h" -#include "../Cuboid.h" #include "../World.h" @@ -94,62 +93,29 @@ std::array cSimulator::GetLinkedOffsets(const Vector3i Offset) -void cSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) +void cSimulator::Simulate(float a_Dt) { - ASSERT(a_Chunk.IsValid()); - - AddBlock(a_Chunk, a_Position, a_Block); + UNUSED(a_Dt); } -void cSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, Vector3i a_Offset, BLOCKTYPE a_Block) +void cSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) { ASSERT(a_Chunk.IsValid()); - WakeUp(a_Chunk, a_Position, a_Block); + AddBlock(a_Chunk, a_Position, a_Block); } -void cSimulator::WakeUp(const cCuboid & a_Area) +void cSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, Vector3i a_Offset, BLOCKTYPE a_Block) { - cCuboid area(a_Area); - area.Sort(); - area.Expand(1, 1, 1, 1, 1, 1); // Expand the area to contain the neighbors, too. - area.ClampY(0, cChunkDef::Height - 1); - - // Add all blocks, in a per-chunk manner: - cChunkCoords ChunkStart = cChunkDef::BlockToChunk(area.p1); - cChunkCoords ChunkEnd = cChunkDef::BlockToChunk(area.p2); - for (int cz = ChunkStart.m_ChunkZ; cz <= ChunkEnd.m_ChunkZ; ++cz) - { - for (int cx = ChunkStart.m_ChunkX; cx <= ChunkEnd.m_ChunkX; ++cx) - { - m_World.DoWithChunk(cx, cz, [this, &area](cChunk & a_CBChunk) -> bool - { - int startX = std::max(area.p1.x, a_CBChunk.GetPosX() * cChunkDef::Width); - int startZ = std::max(area.p1.z, a_CBChunk.GetPosZ() * cChunkDef::Width); - int endX = std::min(area.p2.x, a_CBChunk.GetPosX() * cChunkDef::Width + cChunkDef::Width - 1); - int endZ = std::min(area.p2.z, a_CBChunk.GetPosZ() * cChunkDef::Width + cChunkDef::Width - 1); - for (int y = area.p1.y; y <= area.p2.y; ++y) - { - for (int z = startZ; z <= endZ; ++z) - { - for (int x = startX; x <= endX; ++x) - { - const auto Position = cChunkDef::AbsoluteToRelative({ x, y, z }); - AddBlock(a_CBChunk, Position, a_CBChunk.GetBlock(Position)); - } // for x - } // for z - } // for y - return true; - } // lambda - ); // DoWithChunk - } // for cx - } // for cz + ASSERT(a_Chunk.IsValid()); + + WakeUp(a_Chunk, a_Position, a_Block); } diff --git a/src/Simulator/Simulator.h b/src/Simulator/Simulator.h index e386c0bcf..5bb8376b0 100644 --- a/src/Simulator/Simulator.h +++ b/src/Simulator/Simulator.h @@ -50,14 +50,8 @@ protected: friend class cChunk; // Calls AddBlock() in its WakeUpSimulators() function, to speed things up friend class cSimulatorManager; // Class reponsible for dispatching calls to the various slave Simulators - virtual void Simulate(float a_Dt) = 0; - virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) - { - UNUSED(a_Dt); - UNUSED(a_ChunkX); - UNUSED(a_ChunkZ); - UNUSED(a_Chunk); - } + virtual void Simulate(float a_Dt); + virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) = 0; /** Called to simulate a new block. Unlike WakeUp this function will perform minimal checking. It queues the block to be simulated as fast as possible, suitable for area wakeups. */ @@ -74,8 +68,5 @@ protected: farther, extra-adjacents blocks to be updated. The simulator manager calls this overload after the 3-argument WakeUp. */ virtual void WakeUp(cChunk & a_Chunk, Vector3i a_Position, Vector3i a_Offset, BLOCKTYPE a_Block); - /** Called to simulate an area by the manager, delegated to cSimulator to avoid virtual calls in tight loops. */ - void WakeUp(const cCuboid & a_Area); - cWorld & m_World; } ; diff --git a/src/Simulator/SimulatorManager.cpp b/src/Simulator/SimulatorManager.cpp index 321035de5..7e5b9d036 100644 --- a/src/Simulator/SimulatorManager.cpp +++ b/src/Simulator/SimulatorManager.cpp @@ -3,6 +3,7 @@ #include "SimulatorManager.h" #include "../Chunk.h" +#include "../Cuboid.h" #include "../World.h" @@ -30,6 +31,7 @@ cSimulatorManager::~cSimulatorManager() void cSimulatorManager::Simulate(float a_Dt) { m_Ticks++; + for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr) { if ((m_Ticks % itr->second) == 0) @@ -46,6 +48,7 @@ void cSimulatorManager::Simulate(float a_Dt) void cSimulatorManager::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) { // m_Ticks has already been increased in Simulate() + for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr) { if ((m_Ticks % itr->second) == 0) @@ -71,12 +74,14 @@ void cSimulatorManager::WakeUp(cChunk & a_Chunk, Vector3i a_Position) for (const auto & Offset : cSimulator::AdjacentOffsets) { auto Relative = a_Position + Offset; + if (!cChunkDef::IsValidHeight(Relative)) { continue; } - auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Relative); + const auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Relative); + if ((Chunk == nullptr) || !Chunk->IsValid()) { continue; @@ -99,10 +104,46 @@ void cSimulatorManager::WakeUp(cChunk & a_Chunk, Vector3i a_Position) void cSimulatorManager::WakeUp(const cCuboid & a_Area) { - for (const auto & Item : m_Simulators) + cCuboid area(a_Area); + area.Sort(); + area.Expand(1, 1, 1, 1, 1, 1); // Expand the area to contain the neighbors, too. + area.ClampY(0, cChunkDef::Height - 1); + + cChunkCoords ChunkStart = cChunkDef::BlockToChunk(area.p1); + cChunkCoords ChunkEnd = cChunkDef::BlockToChunk(area.p2); + + // Add all blocks, in a per-chunk manner: + for (int cz = ChunkStart.m_ChunkZ; cz <= ChunkEnd.m_ChunkZ; ++cz) { - Item.first->WakeUp(a_Area); - } + for (int cx = ChunkStart.m_ChunkX; cx <= ChunkEnd.m_ChunkX; ++cx) + { + m_World.DoWithChunk(cx, cz, [this, &area](cChunk & a_CBChunk) + { + int startX = std::max(area.p1.x, a_CBChunk.GetPosX() * cChunkDef::Width); + int startZ = std::max(area.p1.z, a_CBChunk.GetPosZ() * cChunkDef::Width); + int endX = std::min(area.p2.x, a_CBChunk.GetPosX() * cChunkDef::Width + cChunkDef::Width - 1); + int endZ = std::min(area.p2.z, a_CBChunk.GetPosZ() * cChunkDef::Width + cChunkDef::Width - 1); + + for (const auto & Item : m_Simulators) + { + const auto Simulator = Item.first; + + for (int y = area.p1.y; y <= area.p2.y; ++y) + { + for (int z = startZ; z <= endZ; ++z) + { + for (int x = startX; x <= endX; ++x) + { + const auto Position = cChunkDef::AbsoluteToRelative({ x, y, z }); + Simulator->WakeUp(a_CBChunk, Position, a_CBChunk.GetBlock(Position)); + } // for x + } // for z + } // for y + } + return true; + }); + } // for cx + } // for cz } diff --git a/src/Simulator/VaporizeFluidSimulator.cpp b/src/Simulator/VaporizeFluidSimulator.cpp index 6256c8e78..a0939ebca 100644 --- a/src/Simulator/VaporizeFluidSimulator.cpp +++ b/src/Simulator/VaporizeFluidSimulator.cpp @@ -14,6 +14,20 @@ +void cVaporizeFluidSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) +{ + // Nothing needed + + UNUSED(a_Dt); + UNUSED(a_ChunkX); + UNUSED(a_ChunkZ); + UNUSED(a_Chunk); +} + + + + + void cVaporizeFluidSimulator::AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) { if ((a_Block == m_FluidBlock) || (a_Block == m_StationaryFluidBlock)) @@ -27,16 +41,3 @@ void cVaporizeFluidSimulator::AddBlock(cChunk & a_Chunk, Vector3i a_Position, BL ); } } - - - - - -void cVaporizeFluidSimulator::Simulate(float a_Dt) -{ - // Nothing needed -} - - - - diff --git a/src/Simulator/VaporizeFluidSimulator.h b/src/Simulator/VaporizeFluidSimulator.h index 963cc7bc3..60752bc72 100644 --- a/src/Simulator/VaporizeFluidSimulator.h +++ b/src/Simulator/VaporizeFluidSimulator.h @@ -27,11 +27,7 @@ public: private: - 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 cFluidSimulatorData * CreateChunkData(void) override { return nullptr; } } ; - - - - -- cgit v1.2.3