1
0

Use SimulateChunk in redstone simulator

+ Improved performance, reduces bottleneck in chunkmap lookup
* Stop allocating and throwing away lots of small vectors in Update/GetValidSourcePositions return values
- Remove unused GetPowerLevel virtual
This commit is contained in:
Tiger Wang
2020-07-26 14:15:00 +01:00
parent de06ae7add
commit 4e5ab02a58
27 changed files with 785 additions and 847 deletions

View File

@@ -7,7 +7,6 @@
#include "CommandBlockHandler.h"
#include "DoorHandler.h"
#include "RedstoneHandler.h"
#include "RedstoneTorchHandler.h"
#include "RedstoneWireHandler.h"
#include "RedstoneRepeaterHandler.h"
@@ -31,9 +30,10 @@
const cRedstoneHandler * cIncrementalRedstoneSimulator::GetComponentHandler(BLOCKTYPE a_BlockType)
{
struct sComponents:
struct sComponents :
public std::array<std::unique_ptr<cRedstoneHandler>, 256>
{
sComponents()
@@ -128,76 +128,98 @@ std::unique_ptr<cRedstoneHandler> cIncrementalRedstoneSimulator::CreateComponent
void cIncrementalRedstoneSimulator::Simulate(float a_dt)
void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
{
for (auto & DelayInfo : m_Data.m_MechanismDelays)
auto & ChunkData = *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData());
for (auto & DelayInfo : ChunkData.m_MechanismDelays)
{
if ((--DelayInfo.second.first) == 0)
{
m_Data.GetActiveBlocks().emplace_back(DelayInfo.first);
ChunkData.WakeUp(DelayInfo.first);
}
}
// Build our work queue
cVector3iArray WorkQueue;
std::swap(WorkQueue, m_Data.GetActiveBlocks());
auto & WorkQueue = ChunkData.GetActiveBlocks();
// Process the work queue
while (!WorkQueue.empty())
{
// Grab the first element and remove it from the list
Vector3i CurrentLocation = WorkQueue.back();
WorkQueue.pop_back();
Vector3i CurrentLocation = WorkQueue.top();
WorkQueue.pop();
BLOCKTYPE CurrentBlock;
NIBBLETYPE CurrentMeta;
if (!m_World.GetBlockTypeMeta(CurrentLocation.x, CurrentLocation.y, CurrentLocation.z, CurrentBlock, CurrentMeta))
const auto NeighbourChunk = a_Chunk->GetRelNeighborChunkAdjustCoords(CurrentLocation);
if ((NeighbourChunk == nullptr) || !NeighbourChunk->IsValid())
{
continue;
return;
}
auto CurrentHandler = GetComponentHandler(CurrentBlock);
if (CurrentHandler == nullptr) // Block at CurrentPosition doesn't have a corresponding redstone handler
{
// Clean up cached PowerData for CurrentPosition
GetChunkData()->ErasePowerData(CurrentLocation);
continue;
}
cRedstoneHandler::PoweringData Power;
for (const auto & Location : CurrentHandler->GetValidSourcePositions(m_World, CurrentLocation, CurrentBlock, CurrentMeta))
{
if (!cChunk::IsValidHeight(Location.y))
{
continue;
}
BLOCKTYPE PotentialBlock;
NIBBLETYPE PotentialMeta;
if (!m_World.GetBlockTypeMeta(Location.x, Location.y, Location.z, PotentialBlock, PotentialMeta))
{
continue;
}
auto PotentialSourceHandler = GetComponentHandler(PotentialBlock);
if (PotentialSourceHandler == nullptr)
{
continue;
}
decltype(Power) PotentialPower(PotentialBlock, PotentialSourceHandler->GetPowerDeliveredToPosition(m_World, Location, PotentialBlock, PotentialMeta, CurrentLocation, CurrentBlock));
Power = std::max(Power, PotentialPower);
}
// Inform the handler to update
cVector3iArray Updates = CurrentHandler->Update(m_World, CurrentLocation, CurrentBlock, CurrentMeta, Power);
WorkQueue.insert(WorkQueue.end(), Updates.begin(), Updates.end());
if (IsAlwaysTicked(CurrentBlock))
{
m_Data.GetActiveBlocks().emplace_back(CurrentLocation);
}
ProcessWorkItem(*NeighbourChunk, *a_Chunk, CurrentLocation);
}
for (const auto Position : ChunkData.AlwaysTickedPositions)
{
ChunkData.WakeUp(Position);
}
}
void cIncrementalRedstoneSimulator::ProcessWorkItem(cChunk & Chunk, cChunk & TickingSource, const Vector3i Position)
{
auto & ChunkData = *static_cast<cIncrementalRedstoneSimulatorChunkData *>(Chunk.GetRedstoneSimulatorData());
BLOCKTYPE CurrentBlock;
NIBBLETYPE CurrentMeta;
Chunk.GetBlockTypeMeta(Position, CurrentBlock, CurrentMeta);
auto CurrentHandler = GetComponentHandler(CurrentBlock);
if (CurrentHandler == nullptr) // Block at CurrentPosition doesn't have a corresponding redstone handler
{
// Clean up cached PowerData for CurrentPosition
ChunkData.ErasePowerData(Position);
return;
}
PoweringData Power;
CurrentHandler->ForValidSourcePositions(Chunk, Position, CurrentBlock, CurrentMeta, [&Chunk, Position, CurrentBlock, &Power](Vector3i Location)
{
if (!cChunk::IsValidHeight(Location.y))
{
return;
}
const auto NeighbourChunk = Chunk.GetRelNeighborChunkAdjustCoords(Location);
if ((NeighbourChunk == nullptr) || !NeighbourChunk->IsValid())
{
return;
}
BLOCKTYPE PotentialBlock;
NIBBLETYPE PotentialMeta;
NeighbourChunk->GetBlockTypeMeta(Location, PotentialBlock, PotentialMeta);
auto PotentialSourceHandler = GetComponentHandler(PotentialBlock);
if (PotentialSourceHandler == nullptr)
{
return;
}
const PoweringData PotentialPower(
PotentialBlock,
PotentialSourceHandler->GetPowerDeliveredToPosition(
*NeighbourChunk, Location, PotentialBlock, PotentialMeta,
cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(Chunk, *NeighbourChunk, Position), CurrentBlock
)
);
Power = std::max(Power, PotentialPower);
});
// Inform the handler to update
CurrentHandler->Update(Chunk, TickingSource, Position, CurrentBlock, CurrentMeta, Power);
}
@@ -206,27 +228,31 @@ void cIncrementalRedstoneSimulator::Simulate(float a_dt)
void cIncrementalRedstoneSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk)
{
// Can't inspect block, so queue update anyway
if (a_Chunk == nullptr)
// Can't inspect block, ignore:
if ((a_Chunk == nullptr) || (!a_Chunk->IsValid()))
{
m_Data.WakeUp(a_Block);
return;
}
const auto RelPos = cChunkDef::AbsoluteToRelative(a_Block, a_Chunk->GetPos());
const auto CurBlock = a_Chunk->GetBlock(RelPos);
auto & ChunkData = *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData());
const auto Relative = cChunkDef::AbsoluteToRelative(a_Block, a_Chunk->GetPos());
const auto CurrentBlock = a_Chunk->GetBlock(Relative);
// Always update redstone devices
if (IsRedstone(CurBlock))
if (IsRedstone(CurrentBlock))
{
m_Data.WakeUp(a_Block);
if (IsAlwaysTicked(CurrentBlock))
{
ChunkData.AlwaysTickedPositions.emplace(Relative);
}
ChunkData.WakeUp(Relative);
return;
}
// Never update blocks without a handler
if (GetComponentHandler(CurBlock) == nullptr)
if (GetComponentHandler(CurrentBlock) == nullptr)
{
GetChunkData()->ErasePowerData(a_Block);
ChunkData.ErasePowerData(Relative);
return;
}
@@ -235,14 +261,14 @@ void cIncrementalRedstoneSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk)
{
for (int y = -1; y < 2; ++y)
{
if (!cChunkDef::IsValidHeight(RelPos.y + y))
if (!cChunkDef::IsValidHeight(Relative.y + y))
{
continue;
}
for (int z = -1; z < 2; ++z)
{
auto CheckPos = RelPos + Vector3i{x, y, z};
auto CheckPos = Relative + Vector3i{x, y, z};
BLOCKTYPE Block;
NIBBLETYPE Meta;
@@ -252,7 +278,7 @@ void cIncrementalRedstoneSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk)
IsRedstone(Block)
)
{
m_Data.WakeUp(a_Block);
ChunkData.WakeUp(Relative);
return;
}
}