1
0
Fork 0

Simulators: Added area-based wakeup.

This commit is contained in:
Mattes D 2017-07-14 16:18:33 +02:00 committed by Lukas Pioch
parent 41d016cf5b
commit 167c4bf2e6
9 changed files with 93 additions and 56 deletions

View File

@ -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++)

View File

@ -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
));
}

View File

@ -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);

View File

@ -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
}

View File

@ -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:

View File

@ -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));

View File

@ -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:

View File

@ -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));
}

View File

@ -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