Simulators: Added area-based wakeup.
This commit is contained in:
parent
41d016cf5b
commit
167c4bf2e6
|
@ -430,7 +430,6 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock
|
||||||
int BaseZ = BlockStartZ - a_MinBlockZ;
|
int BaseZ = BlockStartZ - a_MinBlockZ;
|
||||||
|
|
||||||
// Copy blocktype and blockmeta:
|
// 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();
|
BLOCKTYPE * AreaBlockTypes = a_Area.GetBlockTypes();
|
||||||
NIBBLETYPE * AreaBlockMetas = a_Area.GetBlockMetas();
|
NIBBLETYPE * AreaBlockMetas = a_Area.GetBlockMetas();
|
||||||
for (int y = 0; y < SizeY; y++)
|
for (int y = 0; y < SizeY; y++)
|
||||||
|
|
|
@ -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)
|
void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSChunks);
|
cCSLock Lock(m_CSChunks);
|
||||||
|
@ -1863,11 +1821,10 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
||||||
ForEachEntity(TNTDamageCallback);
|
ForEachEntity(TNTDamageCallback);
|
||||||
|
|
||||||
// Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391):
|
// Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391):
|
||||||
WakeUpSimulatorsInArea(
|
m_World->GetSimulatorManager()->WakeUpArea(cCuboid(
|
||||||
bx - ExplosionSizeInt - 1, bx + ExplosionSizeInt + 1,
|
bx - ExplosionSizeInt - 1, MinY, bz - ExplosionSizeInt - 1,
|
||||||
MinY, MaxY,
|
bx + ExplosionSizeInt + 1, MaxY, bz + ExplosionSizeInt + 1
|
||||||
bz - ExplosionSizeInt - 1, bz + ExplosionSizeInt + 1
|
));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -114,9 +114,6 @@ public:
|
||||||
/** Wakes up simulators for the specified block */
|
/** Wakes up simulators for the specified block */
|
||||||
void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ);
|
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 MarkChunkDirty (int a_ChunkX, int a_ChunkZ);
|
||||||
void MarkChunkSaving (int a_ChunkX, int a_ChunkZ);
|
void MarkChunkSaving (int a_ChunkX, int a_ChunkZ);
|
||||||
void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
|
void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "../BlockID.h"
|
#include "../BlockID.h"
|
||||||
#include "../Defines.h"
|
#include "../Defines.h"
|
||||||
#include "../Chunk.h"
|
#include "../Chunk.h"
|
||||||
|
#include "../Cuboid.h"
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic ignored "-Wweak-template-vtables"
|
#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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Vector3.h"
|
|
||||||
|
|
||||||
class cWorld;
|
class cWorld;
|
||||||
class cChunk;
|
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
|
class cSimulator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -33,8 +39,16 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when a block changes */
|
/** 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;
|
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -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)
|
void cSimulatorManager::RegisterSimulator(cSimulator * a_Simulator, int a_Rate)
|
||||||
{
|
{
|
||||||
m_Simulators.push_back(std::make_pair(a_Simulator, a_Rate));
|
m_Simulators.push_back(std::make_pair(a_Simulator, a_Rate));
|
||||||
|
|
|
@ -35,8 +35,16 @@ public:
|
||||||
|
|
||||||
void SimulateChunk(std::chrono::milliseconds a_DT, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk);
|
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);
|
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!
|
void RegisterSimulator(cSimulator * a_Simulator, int a_Rate); // Takes ownership of the simulator object!
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -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)
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -432,7 +432,7 @@ public:
|
||||||
Returns true if all chunks have been processed.
|
Returns true if all chunks have been processed.
|
||||||
Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too.
|
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.
|
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;
|
virtual bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes) override;
|
||||||
|
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
|
|
Loading…
Reference in New Issue