From 167c4bf2e691e22240a3c41ebc7181a03933fdb4 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 14 Jul 2017 16:18:33 +0200 Subject: Simulators: Added area-based wakeup. --- src/Simulator/Simulator.cpp | 50 ++++++++++++++++++++++++++++++++++++++ src/Simulator/Simulator.h | 20 ++++++++++++--- src/Simulator/SimulatorManager.cpp | 12 +++++++++ src/Simulator/SimulatorManager.h | 8 ++++++ 4 files changed, 87 insertions(+), 3 deletions(-) (limited to 'src/Simulator') diff --git a/src/Simulator/Simulator.cpp b/src/Simulator/Simulator.cpp index 0175fd67d..275d60161 100644 --- a/src/Simulator/Simulator.cpp +++ b/src/Simulator/Simulator.cpp @@ -5,6 +5,7 @@ #include "../BlockID.h" #include "../Defines.h" #include "../Chunk.h" +#include "../Cuboid.h" #ifdef __clang__ #pragma clang diagnostic ignored "-Wweak-template-vtables" @@ -38,3 +39,52 @@ void cSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chu + +void cSimulator::WakeUpArea(const cCuboid & a_Area) +{ + 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: + int chunkStartX, chunkStartZ, chunkEndX, chunkEndZ; + cChunkDef::BlockToChunk(area.p1.x, area.p1.z, chunkStartX, chunkStartZ); + cChunkDef::BlockToChunk(area.p2.x, area.p2.z, chunkEndX, chunkEndZ); + for (int cz = chunkStartZ; cz <= chunkEndZ; ++cz) + { + for (int cx = chunkStartX; cx <= chunkEndX; ++cx) + { + m_World.DoWithChunk(cx, cz, [this, &area](cChunk & a_CBChunk) -> bool + { + if (!a_CBChunk.IsValid()) + { + LOGWARNING("%s: Trying to wake up inside a non-valid chunk [%d, %d]. Ignoring.", + __FUNCTION__, a_CBChunk.GetPosX(), a_CBChunk.GetPosZ() + ); + return true; + } + 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) + { + AddBlock(x, y, z, &a_CBChunk); + } // for x + } // for z + } // for y + return true; + } // lambda + ); // DoWithChunk + } // for cx + } // for cz +} + + + + diff --git a/src/Simulator/Simulator.h b/src/Simulator/Simulator.h index b0e3b16f4..ef0a3bf68 100644 --- a/src/Simulator/Simulator.h +++ b/src/Simulator/Simulator.h @@ -1,15 +1,21 @@ #pragma once -#include "../Vector3.h" - class cWorld; class cChunk; +class cCuboid; +/** Base class for all block-based physics simulators (such as fluid, fire, falling blocks etc.). +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. */ class cSimulator { public: @@ -33,8 +39,16 @@ public: } /** Called when a block changes */ - virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk); + void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk); + + /** Does the same processing as WakeUp, but for all blocks within the specified area. + Has better performance than calling WakeUp for each block individually, due to neighbor-checking. + All chunks intersected by the area should be valid (outputs a warning if not). + Note that, unlike WakeUp(), this call adds blocks not only face-neighboring, but also edge-neighboring and + corner-neighboring the specified area. So far none of the simulators care about that. */ + void WakeUpArea(const cCuboid & a_Area); + /** Returns true if the specified block type is "interesting" for this simulator. */ virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) = 0; protected: diff --git a/src/Simulator/SimulatorManager.cpp b/src/Simulator/SimulatorManager.cpp index e74642fc0..78c02fc07 100644 --- a/src/Simulator/SimulatorManager.cpp +++ b/src/Simulator/SimulatorManager.cpp @@ -70,6 +70,18 @@ void cSimulatorManager::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk +void cSimulatorManager::WakeUpArea(const cCuboid & a_Area) +{ + for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr) + { + itr->first->WakeUpArea(a_Area); + } +} + + + + + void cSimulatorManager::RegisterSimulator(cSimulator * a_Simulator, int a_Rate) { m_Simulators.push_back(std::make_pair(a_Simulator, a_Rate)); diff --git a/src/Simulator/SimulatorManager.h b/src/Simulator/SimulatorManager.h index e6ad68bf3..daa949157 100644 --- a/src/Simulator/SimulatorManager.h +++ b/src/Simulator/SimulatorManager.h @@ -35,8 +35,16 @@ public: 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 and its face-neighbors. */ void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk); + /** Does the same processing as WakeUp, but for all blocks within the specified area. + Has better performance than calling WakeUp for each block individually, due to neighbor-checking. + All chunks intersected by the area should be valid (outputs a warning if not). + Note that, unlike WakeUp(), this call adds blocks not only face-neighboring, but also edge-neighboring and + corner-neighboring the specified area. So far none of the simulators care about that. */ + void WakeUpArea(const cCuboid & a_Area); + void RegisterSimulator(cSimulator * a_Simulator, int a_Rate); // Takes ownership of the simulator object! protected: -- cgit v1.2.3