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;
|
||||
|
||||
// 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++)
|
||||
|
@ -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
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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));
|
||||
|
@ -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:
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user