summaryrefslogtreecommitdiffstats
path: root/src/Simulator
diff options
context:
space:
mode:
Diffstat (limited to 'src/Simulator')
-rw-r--r--src/Simulator/Simulator.cpp50
-rw-r--r--src/Simulator/Simulator.h20
-rw-r--r--src/Simulator/SimulatorManager.cpp12
-rw-r--r--src/Simulator/SimulatorManager.h8
4 files changed, 87 insertions, 3 deletions
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: