summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Chunk.cpp1
-rw-r--r--src/ChunkMap.cpp51
-rw-r--r--src/ChunkMap.h3
-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
-rw-r--r--src/World.cpp2
-rw-r--r--src/World.h2
9 files changed, 93 insertions, 56 deletions
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 9ddee2343..282293c0f 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -430,7 +430,6 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock
int BaseZ = BlockStartZ - a_MinBlockZ;
// Copy blocktype and blockmeta:
- // TODO: Right now each changed block is transmitted to all clients as a separate packet. Optimize this for larger areas.
BLOCKTYPE * AreaBlockTypes = a_Area.GetBlockTypes();
NIBBLETYPE * AreaBlockMetas = a_Area.GetBlockMetas();
for (int y = 0; y < SizeY; y++)
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index f04af4340..491bc4752 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -757,48 +757,6 @@ void cChunkMap::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ)
-void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ)
-{
- // Limit the Y coords:
- a_MinBlockY = std::max(a_MinBlockY, 0);
- a_MaxBlockY = std::min(a_MaxBlockY, cChunkDef::Height - 1);
-
- cSimulatorManager * SimMgr = m_World->GetSimulatorManager();
- int MinChunkX, MinChunkZ, MaxChunkX, MaxChunkZ;
- cChunkDef::BlockToChunk(a_MinBlockX, a_MinBlockZ, MinChunkX, MinChunkZ);
- cChunkDef::BlockToChunk(a_MaxBlockX, a_MaxBlockZ, MaxChunkX, MaxChunkZ);
- cCSLock Lock(m_CSChunks);
- for (int z = MinChunkZ; z <= MaxChunkZ; z++)
- {
- int MinZ = std::max(a_MinBlockZ, z * cChunkDef::Width);
- int MaxZ = std::min(a_MaxBlockZ, z * cChunkDef::Width + cChunkDef::Width - 1);
- for (int x = MinChunkX; x <= MaxChunkX; x++)
- {
- cChunkPtr Chunk = GetChunkNoGen(x, z);
- if ((Chunk == nullptr) || !Chunk->IsValid())
- {
- continue;
- }
- int MinX = std::max(a_MinBlockX, x * cChunkDef::Width);
- int MaxX = std::min(a_MaxBlockX, x * cChunkDef::Width + cChunkDef::Width - 1);
- for (int BlockY = a_MinBlockY; BlockY <= a_MaxBlockY; BlockY++)
- {
- for (int BlockZ = MinZ; BlockZ <= MaxZ; BlockZ++)
- {
- for (int BlockX = MinX; BlockX <= MaxX; BlockX++)
- {
- SimMgr->WakeUp(BlockX, BlockY, BlockZ, Chunk);
- } // for BlockX
- } // for BlockZ
- } // for BlockY
- } // for x - chunks
- } // for z = chunks
-}
-
-
-
-
-
void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CSChunks);
@@ -1863,11 +1821,10 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
ForEachEntity(TNTDamageCallback);
// Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391):
- WakeUpSimulatorsInArea(
- bx - ExplosionSizeInt - 1, bx + ExplosionSizeInt + 1,
- MinY, MaxY,
- bz - ExplosionSizeInt - 1, bz + ExplosionSizeInt + 1
- );
+ m_World->GetSimulatorManager()->WakeUpArea(cCuboid(
+ bx - ExplosionSizeInt - 1, MinY, bz - ExplosionSizeInt - 1,
+ bx + ExplosionSizeInt + 1, MaxY, bz + ExplosionSizeInt + 1
+ ));
}
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index 7c57f9669..130c4b062 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -114,9 +114,6 @@ public:
/** Wakes up simulators for the specified block */
void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Wakes up the simulators for the specified area of blocks */
- void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ);
-
void MarkChunkDirty (int a_ChunkX, int a_ChunkZ);
void MarkChunkSaving (int a_ChunkX, int a_ChunkZ);
void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
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:
diff --git a/src/World.cpp b/src/World.cpp
index da7d8fb2d..3f26fe809 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1305,7 +1305,7 @@ void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ)
void cWorld::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ)
{
- return m_ChunkMap->WakeUpSimulatorsInArea(a_MinBlockX, a_MaxBlockX, a_MinBlockY, a_MaxBlockY, a_MinBlockZ, a_MaxBlockZ);
+ m_SimulatorManager->WakeUpArea(cCuboid(a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_MaxBlockX, a_MaxBlockY, a_MaxBlockZ));
}
diff --git a/src/World.h b/src/World.h
index a3180e008..7d8d8bf7f 100644
--- a/src/World.h
+++ b/src/World.h
@@ -432,7 +432,7 @@ public:
Returns true if all chunks have been processed.
Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too.
a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together.
- */
+ Doesn't wake up simulators, use WakeUpSimulatorsInArea() for that. */
virtual bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes) override;
// tolua_begin