Files
cuberite-2a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp
T

140 lines
3.6 KiB
C++
Raw Normal View History

2015-06-26 17:24:51 -05:00
#include "Globals.h"
#include "IncrementalRedstoneSimulator.h"
#include "RedstoneHandler.h"
2020-08-08 18:22:16 +01:00
#include "ForEachSourceCallback.h"
2015-06-26 17:24:51 -05:00
2020-07-26 14:15:00 +01:00
void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
2015-06-26 17:24:51 -05:00
{
2020-07-26 14:15:00 +01:00
auto & ChunkData = *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData());
for (auto & DelayInfo : ChunkData.m_MechanismDelays)
2015-06-26 17:24:51 -05:00
{
if ((--DelayInfo.second.first) == 0)
{
2020-07-26 14:15:00 +01:00
ChunkData.WakeUp(DelayInfo.first);
2015-06-26 17:24:51 -05:00
}
}
// Build our work queue
2020-07-26 14:15:00 +01:00
auto & WorkQueue = ChunkData.GetActiveBlocks();
2015-06-26 17:24:51 -05:00
// Process the work queue
while (!WorkQueue.empty())
{
// Grab the first element and remove it from the list
2020-07-26 14:15:00 +01:00
Vector3i CurrentLocation = WorkQueue.top();
WorkQueue.pop();
2015-06-26 17:24:51 -05:00
2020-07-26 14:15:00 +01:00
const auto NeighbourChunk = a_Chunk->GetRelNeighborChunkAdjustCoords(CurrentLocation);
if ((NeighbourChunk == nullptr) || !NeighbourChunk->IsValid())
2015-06-26 17:24:51 -05:00
{
2020-07-26 16:08:20 +01:00
continue;
2015-06-26 17:24:51 -05:00
}
2020-07-26 14:15:00 +01:00
ProcessWorkItem(*NeighbourChunk, *a_Chunk, CurrentLocation);
}
for (const auto Position : ChunkData.AlwaysTickedPositions)
{
ChunkData.WakeUp(Position);
}
}
2015-06-26 17:24:51 -05:00
2020-07-24 09:11:40 +01:00
2015-06-26 17:24:51 -05:00
2020-07-26 14:15:00 +01:00
void cIncrementalRedstoneSimulator::ProcessWorkItem(cChunk & Chunk, cChunk & TickingSource, const Vector3i Position)
{
BLOCKTYPE CurrentBlock;
NIBBLETYPE CurrentMeta;
Chunk.GetBlockTypeMeta(Position, CurrentBlock, CurrentMeta);
2020-08-08 18:22:16 +01:00
ForEachSourceCallback Callback(Chunk, Position, CurrentBlock);
RedstoneHandler::ForValidSourcePositions(Chunk, Position, CurrentBlock, CurrentMeta, Callback);
2020-07-26 14:15:00 +01:00
// Inform the handler to update
RedstoneHandler::Update(Chunk, TickingSource, Position, CurrentBlock, CurrentMeta, Callback.Power);
2015-06-26 17:24:51 -05:00
}
2020-07-29 00:12:45 +01:00
void cIncrementalRedstoneSimulator::AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block)
{
// Never update blocks without a handler:
2020-07-29 01:18:59 +01:00
if (!IsRedstone(a_Block))
{
return;
}
2020-07-29 20:15:09 +01:00
auto & ChunkData = *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk.GetRedstoneSimulatorData());
2020-07-29 01:18:59 +01:00
if (IsAlwaysTicked(a_Block))
{
2020-07-29 01:18:59 +01:00
ChunkData.AlwaysTickedPositions.emplace(a_Position);
}
2020-08-08 18:22:16 +01:00
// Temporary: in the absence of block state support calculate our own:
if (a_Block == E_BLOCK_REDSTONE_WIRE)
{
RedstoneHandler::SetWireState(a_Chunk, a_Position);
2020-08-08 18:22:16 +01:00
}
2020-07-29 00:12:45 +01:00
// Always update redstone devices:
2020-07-29 01:18:59 +01:00
ChunkData.WakeUp(a_Position);
}
2020-07-29 20:15:09 +01:00
void cIncrementalRedstoneSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block)
{
// Having WakeUp called on us directly means someone called SetBlock (or WakeUp)
// Since the simulator never does this, something external changed. Clear cached data:
static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk.GetRedstoneSimulatorData())->ErasePowerData(a_Position);
// Queue the block, in case the set block was redstone:
AddBlock(a_Chunk, a_Position, a_Block);
}
void cIncrementalRedstoneSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position, Vector3i a_Offset, BLOCKTYPE a_Block)
{
// This is an automatic cross-coords wakeup by cSimulatorManager
// There is no need to erase power data; if a component was destroyed the 3-arg WakeUp will handle it
AddBlock(a_Chunk, a_Position, a_Block);
// The only thing to do go one block farther than this cross-coord, in the direction of Offset
// in order to notify linked-powered positions that there was a change
2020-08-08 18:22:16 +01:00
for (const auto Offset : cSimulator::GetLinkedOffsets(a_Offset))
{
auto Relative = a_Position - a_Offset + Offset;
if (!cChunkDef::IsValidHeight(Relative.y))
{
continue;
}
auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Relative);
if ((Chunk == nullptr) || !Chunk->IsValid())
{
continue;
}
const auto Block = Chunk->GetBlock(Relative);
AddBlock(*Chunk, Relative, Block);
}
2020-07-29 20:15:09 +01:00
}