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

@ -34,10 +34,13 @@ public:
const Vector3i a_CursorPos const Vector3i a_CursorPos
) override ) override
{ {
const auto Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
// Toggle the 3rd bit (addition / subtraction): // Toggle the 3rd bit (addition / subtraction):
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta ^ 0x04);
Meta ^= 0x04;
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta); // Update simulators:
a_WorldInterface.WakeUpSimulators(a_BlockPos);
return true; return true;
} }
@ -56,6 +59,7 @@ public:
UNUSED(a_ChunkInterface); UNUSED(a_ChunkInterface);
UNUSED(a_BlockFace); UNUSED(a_BlockFace);
a_WorldInterface.WakeUpSimulators(a_BlockPos);
a_WorldInterface.SendBlockTo(a_BlockPos, a_Player); a_WorldInterface.SendBlockTo(a_BlockPos, a_Player);
} }
@ -120,15 +124,6 @@ public:
inline static bool IsOn(NIBBLETYPE a_Meta)
{
return ((a_Meta & 0x8) == 0x8);
}
inline static Vector3i GetSideCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta, bool a_bInverse) inline static Vector3i GetSideCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta, bool a_bInverse)
{ {
if (!a_bInverse) if (!a_bInverse)

View File

@ -8,16 +8,13 @@
class cCommandBlockHandler: class cCommandBlockHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
@ -26,40 +23,29 @@ public:
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk &, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
UNUSED(a_World);
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating commander the cmdblck (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating commander the cmdblck (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Previous = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData); auto Previous = DataForChunk(a_Chunk).ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
if ((Previous.PowerLevel != 0) || (a_PoweringData.PowerLevel == 0)) if ((Previous.PowerLevel != 0) || (a_PoweringData.PowerLevel == 0))
{ {
// If we're already powered or received an update of no power, don't activate // If we're already powered or received an update of no power, don't activate
return {}; return;
} }
a_World.DoWithCommandBlockAt(a_Position.x, a_Position.y, a_Position.z, [](cCommandBlockEntity & a_CommandBlock) a_Chunk.DoWithCommandBlockAt(a_Position, [](cCommandBlockEntity & a_CommandBlock)
{ {
a_CommandBlock.Activate(); a_CommandBlock.Activate();
return false; return false;
} });
);
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents()); InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
} }
}; };

View File

@ -8,16 +8,13 @@
class cDoorHandler: class cDoorHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
@ -26,46 +23,27 @@ public:
return 0; return 0;
} }
virtual void Update(cChunk & a_Chunk, cChunk &, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
{
UNUSED(a_World);
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating dori the door (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating dori the door (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
if (a_PoweringData != static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData)) cChunkInterface ChunkInterface(a_Chunk.GetWorld()->GetChunkMap());
{ const bool ShouldBeOpen = a_PoweringData.PowerLevel != 0;
cChunkInterface ChunkInterface(a_World.GetChunkMap()); const auto AbsolutePosition = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
cBlockDoorHandler::SetOpen(ChunkInterface, a_Position, (a_PoweringData.PowerLevel != 0)); const bool IsOpen = cBlockDoorHandler::IsOpen(ChunkInterface, AbsolutePosition);
a_World.BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, a_Position, 0);
}
return {}; if (ShouldBeOpen != IsOpen)
{
cBlockDoorHandler::SetOpen(ChunkInterface, AbsolutePosition, ShouldBeOpen);
a_Chunk.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, AbsolutePosition, 0);
}
} }
virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents()); InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
} }
}; };

View File

@ -8,17 +8,15 @@
class cDropSpenserHandler: class cDropSpenserHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
inline static bool IsActivated(NIBBLETYPE a_Meta) inline static bool IsActivated(NIBBLETYPE a_Meta)
{ {
return (a_Meta & E_META_DROPSPENSER_ACTIVATED) != 0; return (a_Meta & E_META_DROPSPENSER_ACTIVATED) != 0;
} }
inline static NIBBLETYPE SetActivationState(NIBBLETYPE a_Meta, bool IsOn) inline static NIBBLETYPE SetActivationState(NIBBLETYPE a_Meta, bool IsOn)
{ {
if (IsOn) if (IsOn)
@ -31,9 +29,9 @@ public:
} }
} }
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
@ -42,45 +40,34 @@ public:
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk &, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
UNUSED(a_World);
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating spencer the dropspenser (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating spencer the dropspenser (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
bool IsPoweredNow = (a_PoweringData.PowerLevel > 0);
bool WasPoweredPreviously = IsActivated(a_Meta); const bool IsPoweredNow = (a_PoweringData.PowerLevel > 0);
const bool WasPoweredPreviously = IsActivated(a_Meta);
if (IsPoweredNow && !WasPoweredPreviously) if (IsPoweredNow && !WasPoweredPreviously)
{ {
a_World.DoWithDropSpenserAt(a_Position.x, a_Position.y, a_Position.z, [](cDropSpenserEntity & a_DropSpenser) a_Chunk.DoWithDropSpenserAt(a_Position, [](cDropSpenserEntity & a_DropSpenser)
{ {
a_DropSpenser.Activate(); a_DropSpenser.Activate();
return false; return false;
} });
);
} }
// Update the internal dropspenser state if necessary // Update the internal dropspenser state if necessary
if (IsPoweredNow != WasPoweredPreviously) if (IsPoweredNow != WasPoweredPreviously)
{ {
a_World.SetBlockMeta(a_Position, SetActivationState(a_Meta, IsPoweredNow)); a_Chunk.SetMeta(a_Position, SetActivationState(a_Meta, IsPoweredNow));
} }
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
} }
}; };

View File

@ -8,16 +8,13 @@
class cHopperHandler: class cHopperHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
@ -26,39 +23,28 @@ public:
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk &, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
UNUSED(a_World); // LOGD("Evaluating holey the hopper (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override auto Previous = DataForChunk(a_Chunk).ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
{ if (Previous.PowerLevel == a_PoweringData.PowerLevel)
// LOGD("Evaluating commander the cmdblck (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Previous = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
if (Previous.PowerLevel != a_PoweringData.PowerLevel)
{ {
return {}; return;
} }
a_World.DoWithHopperAt(a_Position.x, a_Position.y, a_Position.z, [a_PoweringData](cHopperEntity & a_Hopper) a_Chunk.DoWithHopperAt(a_Position, [a_PoweringData](cHopperEntity & a_Hopper)
{ {
a_Hopper.SetLocked(a_PoweringData.PowerLevel != 0); a_Hopper.SetLocked(a_PoweringData.PowerLevel != 0);
return false; return false;
} });
);
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents()); InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
} }
}; };

View File

@ -7,7 +7,6 @@
#include "CommandBlockHandler.h" #include "CommandBlockHandler.h"
#include "DoorHandler.h" #include "DoorHandler.h"
#include "RedstoneHandler.h"
#include "RedstoneTorchHandler.h" #include "RedstoneTorchHandler.h"
#include "RedstoneWireHandler.h" #include "RedstoneWireHandler.h"
#include "RedstoneRepeaterHandler.h" #include "RedstoneRepeaterHandler.h"
@ -31,9 +30,10 @@
const cRedstoneHandler * cIncrementalRedstoneSimulator::GetComponentHandler(BLOCKTYPE a_BlockType) const cRedstoneHandler * cIncrementalRedstoneSimulator::GetComponentHandler(BLOCKTYPE a_BlockType)
{ {
struct sComponents: struct sComponents :
public std::array<std::unique_ptr<cRedstoneHandler>, 256> public std::array<std::unique_ptr<cRedstoneHandler>, 256>
{ {
sComponents() 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) if ((--DelayInfo.second.first) == 0)
{ {
m_Data.GetActiveBlocks().emplace_back(DelayInfo.first); ChunkData.WakeUp(DelayInfo.first);
} }
} }
// Build our work queue // Build our work queue
cVector3iArray WorkQueue; auto & WorkQueue = ChunkData.GetActiveBlocks();
std::swap(WorkQueue, m_Data.GetActiveBlocks());
// Process the work queue // Process the work queue
while (!WorkQueue.empty()) while (!WorkQueue.empty())
{ {
// Grab the first element and remove it from the list // Grab the first element and remove it from the list
Vector3i CurrentLocation = WorkQueue.back(); Vector3i CurrentLocation = WorkQueue.top();
WorkQueue.pop_back(); WorkQueue.pop();
BLOCKTYPE CurrentBlock; const auto NeighbourChunk = a_Chunk->GetRelNeighborChunkAdjustCoords(CurrentLocation);
NIBBLETYPE CurrentMeta; if ((NeighbourChunk == nullptr) || !NeighbourChunk->IsValid())
if (!m_World.GetBlockTypeMeta(CurrentLocation.x, CurrentLocation.y, CurrentLocation.z, CurrentBlock, CurrentMeta))
{ {
continue; return;
} }
auto CurrentHandler = GetComponentHandler(CurrentBlock); ProcessWorkItem(*NeighbourChunk, *a_Chunk, CurrentLocation);
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);
}
} }
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) void cIncrementalRedstoneSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk)
{ {
// Can't inspect block, so queue update anyway // Can't inspect block, ignore:
if (a_Chunk == nullptr) if ((a_Chunk == nullptr) || (!a_Chunk->IsValid()))
{ {
m_Data.WakeUp(a_Block);
return; return;
} }
const auto RelPos = cChunkDef::AbsoluteToRelative(a_Block, a_Chunk->GetPos()); auto & ChunkData = *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData());
const auto CurBlock = a_Chunk->GetBlock(RelPos); const auto Relative = cChunkDef::AbsoluteToRelative(a_Block, a_Chunk->GetPos());
const auto CurrentBlock = a_Chunk->GetBlock(Relative);
// Always update redstone devices // 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; return;
} }
// Never update blocks without a handler // Never update blocks without a handler
if (GetComponentHandler(CurBlock) == nullptr) if (GetComponentHandler(CurrentBlock) == nullptr)
{ {
GetChunkData()->ErasePowerData(a_Block); ChunkData.ErasePowerData(Relative);
return; return;
} }
@ -235,14 +261,14 @@ void cIncrementalRedstoneSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk)
{ {
for (int y = -1; y < 2; ++y) for (int y = -1; y < 2; ++y)
{ {
if (!cChunkDef::IsValidHeight(RelPos.y + y)) if (!cChunkDef::IsValidHeight(Relative.y + y))
{ {
continue; continue;
} }
for (int z = -1; z < 2; ++z) for (int z = -1; z < 2; ++z)
{ {
auto CheckPos = RelPos + Vector3i{x, y, z}; auto CheckPos = Relative + Vector3i{x, y, z};
BLOCKTYPE Block; BLOCKTYPE Block;
NIBBLETYPE Meta; NIBBLETYPE Meta;
@ -252,7 +278,7 @@ void cIncrementalRedstoneSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk)
IsRedstone(Block) IsRedstone(Block)
) )
{ {
m_Data.WakeUp(a_Block); ChunkData.WakeUp(Relative);
return; return;
} }
} }

View File

@ -2,26 +2,29 @@
#pragma once #pragma once
#include "../RedstoneSimulator.h" #include "../RedstoneSimulator.h"
#include "RedstoneHandler.h"
#include "RedstoneSimulatorChunkData.h" #include "RedstoneSimulatorChunkData.h"
class cIncrementalRedstoneSimulator: class cIncrementalRedstoneSimulator final :
public cRedstoneSimulator public cRedstoneSimulator
{ {
using Super = cRedstoneSimulator; using Super = cRedstoneSimulator;
public: public:
cIncrementalRedstoneSimulator(cWorld & a_World): cIncrementalRedstoneSimulator(cWorld & a_World) :
Super(a_World) Super(a_World)
{ {
} }
virtual void Simulate(float a_dt) override; virtual void Simulate(float Dt) override {};
virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override {} virtual void SimulateChunk(std::chrono::milliseconds Dt, int ChunkX, int ChunkZ, cChunk * Chunk) override;
void ProcessWorkItem(cChunk & Chunk, cChunk & TickingSource, const Vector3i Position);
virtual cIncrementalRedstoneSimulatorChunkData * CreateChunkData() override virtual cIncrementalRedstoneSimulatorChunkData * CreateChunkData() override
{ {
@ -36,8 +39,7 @@ public:
virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override; virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override;
/** Returns if a block is a mechanism (something that accepts power and does something) /** Returns if a block is a mechanism (something that accepts power and does something)
Used by torches to determine if they will power a block Used by torches to determine if they will power a block */
*/
inline static bool IsMechanism(BLOCKTYPE Block) inline static bool IsMechanism(BLOCKTYPE Block)
{ {
switch (Block) switch (Block)
@ -158,14 +160,9 @@ public:
} }
} }
cIncrementalRedstoneSimulatorChunkData * GetChunkData() { return &m_Data; }
static const cRedstoneHandler * GetComponentHandler(BLOCKTYPE a_BlockType); static const cRedstoneHandler * GetComponentHandler(BLOCKTYPE a_BlockType);
private: private:
static std::unique_ptr<cRedstoneHandler> CreateComponent(BLOCKTYPE a_BlockType); static std::unique_ptr<cRedstoneHandler> CreateComponent(BLOCKTYPE a_BlockType);
// oh yea its crazy time
cIncrementalRedstoneSimulatorChunkData m_Data;
} ; } ;

View File

@ -8,17 +8,13 @@
class cNoteBlockHandler: class cNoteBlockHandler: public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_World);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
@ -27,41 +23,29 @@ public:
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk &, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
UNUSED(a_World);
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating sparky the magical note block (%d %d %d) %i", a_Position.x, a_Position.y, a_Position.z, a_PoweringData.PowerLevel); // LOGD("Evaluating sparky the magical note block (%d %d %d) %i", a_Position.x, a_Position.y, a_Position.z, a_PoweringData.PowerLevel);
auto Previous = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData); auto Previous = DataForChunk(a_Chunk).ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
if ((Previous.PowerLevel != 0) || (a_PoweringData.PowerLevel == 0)) if ((Previous.PowerLevel != 0) || (a_PoweringData.PowerLevel == 0))
{ {
// If we're already powered or received an update of no power, don't make a sound // If we're already powered or received an update of no power, don't make a sound
return {}; return;
} }
a_World.DoWithNoteBlockAt(a_Position.x, a_Position.y, a_Position.z, [](cNoteEntity & a_NoteBlock) a_Chunk.DoWithNoteBlockAt(a_Position, [](cNoteEntity & a_NoteBlock)
{ {
a_NoteBlock.MakeSound(); a_NoteBlock.MakeSound();
return false; return false;
} });
);
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents()); InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
} }
}; };

View File

@ -8,7 +8,7 @@
class cObserverHandler : public cRedstoneHandler class cObserverHandler final : public cRedstoneHandler
{ {
public: public:
@ -17,24 +17,24 @@ public:
return (a_Meta & 0x8) == 0x8; return (a_Meta & 0x8) == 0x8;
} }
static bool ShouldPowerOn(cWorld & a_World, const Vector3i a_Position, NIBBLETYPE a_Meta, cIncrementalRedstoneSimulatorChunkData * a_Data) static bool ShouldPowerOn(cChunk & Chunk, const Vector3i a_Position, NIBBLETYPE a_Meta, cIncrementalRedstoneSimulatorChunkData & a_Data)
{ {
BLOCKTYPE BlockType; BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta; NIBBLETYPE BlockMeta;
if (!a_World.GetBlockTypeMeta(a_Position + cBlockObserverHandler::GetObservingFaceOffset(a_Meta), BlockType, BlockMeta)) if (!Chunk.UnboundedRelGetBlock(a_Position + cBlockObserverHandler::GetObservingFaceOffset(a_Meta), BlockType, BlockMeta))
{ {
return false; return false;
} }
// Cache the last seen block type and meta in the power data for this position // Cache the last seen block type and meta in the power data for this position
auto Observed = PoweringData(BlockType, BlockMeta); auto Observed = PoweringData(BlockType, BlockMeta);
auto Previous = a_Data->ExchangeUpdateOncePowerData(a_Position, Observed); auto Previous = a_Data.ExchangeUpdateOncePowerData(a_Position, Observed);
// Determine if to signal an update based on the block previously observed changed // Determine if to signal an update based on the block previously observed changed
return (Previous.PoweringBlock != Observed.PoweringBlock) || (Previous.PowerLevel != Observed.PowerLevel); return (Previous.PoweringBlock != Observed.PoweringBlock) || (Previous.PowerLevel != Observed.PowerLevel);
} }
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
if (IsOn(a_Meta) && (a_QueryPosition == (a_Position + cBlockObserverHandler::GetSignalOutputOffset(a_Meta)))) if (IsOn(a_Meta) && (a_QueryPosition == (a_Position + cBlockObserverHandler::GetSignalOutputOffset(a_Meta))))
{ {
@ -44,30 +44,25 @@ public:
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
return IsOn(a_BlockType) ? 15 : 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating Lenny the observer (%i %i %i)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating Lenny the observer (%i %i %i)", a_Position.x, a_Position.y, a_Position.z);
auto Data = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData(); auto & Data = DataForChunk(a_Chunk);
auto DelayInfo = Data->GetMechanismDelayInfo(a_Position); auto DelayInfo = Data.GetMechanismDelayInfo(a_Position);
if (DelayInfo == nullptr) if (DelayInfo == nullptr)
{ {
if (!ShouldPowerOn(a_World, a_Position, a_Meta, Data)) if (!ShouldPowerOn(a_Chunk, a_Position, a_Meta, Data))
{ {
return {}; return;
} }
// From rest, we've determined there was a block update // From rest, we've determined there was a block update
// Schedule power-on 1 tick in the future // Schedule power-on 1 tick in the future
Data->m_MechanismDelays[a_Position] = std::make_pair(1, true); Data.m_MechanismDelays[a_Position] = std::make_pair(1, true);
return {}; return;
} }
int DelayTicks; int DelayTicks;
@ -76,31 +71,30 @@ public:
if (DelayTicks != 0) if (DelayTicks != 0)
{ {
return {}; return;
} }
if (ShouldPowerOn) if (ShouldPowerOn)
{ {
// Remain on for 1 tick before resetting // Remain on for 1 tick before resetting
*DelayInfo = std::make_pair(1, false); *DelayInfo = std::make_pair(1, false);
a_World.SetBlockMeta(a_Position, a_Meta | 0x8); a_Chunk.SetMeta(a_Position, a_Meta | 0x8);
} }
else else
{ {
// We've reset. Erase delay data in preparation for detecting further updates // We've reset. Erase delay data in preparation for detecting further updates
Data->m_MechanismDelays.erase(a_Position); Data.m_MechanismDelays.erase(a_Position);
a_World.SetBlockMeta(a_Position, a_Meta & ~0x8); a_Chunk.SetMeta(a_Position, a_Meta & ~0x8);
} }
return { a_Position + cBlockObserverHandler::GetSignalOutputOffset(a_Meta) }; UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position + cBlockObserverHandler::GetSignalOutputOffset(a_Meta));
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_BlockType); UNUSED(a_BlockType);
return {};
} }
}; };

View File

@ -8,16 +8,13 @@
class cPistonHandler: class cPistonHandler final: public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
@ -26,52 +23,45 @@ public:
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk &, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
UNUSED(a_World);
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating pisty the piston (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating pisty the piston (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
bool ShouldBeExtended = (a_PoweringData.PowerLevel != 0); const bool ShouldBeExtended = a_PoweringData.PowerLevel != 0;
if (ShouldBeExtended == cBlockPistonHandler::IsExtended(a_Meta)) if (ShouldBeExtended == cBlockPistonHandler::IsExtended(a_Meta))
{ {
return {}; return;
} }
a_Position = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
if (ShouldBeExtended) if (ShouldBeExtended)
{ {
cBlockPistonHandler::ExtendPiston(a_Position, a_World); cBlockPistonHandler::ExtendPiston(a_Position, *a_Chunk.GetWorld());
} }
else else
{ {
cBlockPistonHandler::RetractPiston(a_Position, a_World); cBlockPistonHandler::RetractPiston(a_Position, *a_Chunk.GetWorld());
} }
// It is necessary to delay after a signal to prevent an infinite loop (#3168) // It is necessary to delay after a signal to prevent an infinite loop (#3168)
// However, that is present as a side effect of the implementation of piston animation in Blocks\BlockPiston.cpp // However, this delay is already present: as a side effect of the implementation of piston animation in Blocks\BlockPiston.cpp
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
auto PositionsOffset = GetRelativeAdjacents(); const auto Face = cBlockPistonHandler::MetaDataToDirection(a_Meta);
auto Face = cBlockPistonHandler::MetaDataToDirection(a_Meta); const auto FrontOffset = AddFaceDirection(Vector3i(), Face);
int OffsetX = 0, OffsetY = 0, OffsetZ = 0;
AddFaceDirection(OffsetX, OffsetY, OffsetZ, Face); for (const auto Offset : RelativeAdjacents)
PositionsOffset.erase(std::remove(PositionsOffset.begin(), PositionsOffset.end(), Vector3i(OffsetX, OffsetY, OffsetZ)), PositionsOffset.end()); {
if (Offset != FrontOffset)
return GetAdjustedRelatives(a_Position, PositionsOffset); {
Callback(a_Position + Offset);
}
}
} }
}; };

View File

@ -7,11 +7,8 @@
class cPoweredRailHandler: class cPoweredRailHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
static Vector3i GetPoweredRailAdjacentXZCoordinateOffset(NIBBLETYPE a_Meta) // Not in cBlockRailHandler since specific to powered rails static Vector3i GetPoweredRailAdjacentXZCoordinateOffset(NIBBLETYPE a_Meta) // Not in cBlockRailHandler since specific to powered rails
@ -32,27 +29,20 @@ public:
} }
} }
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_QueryBlockType); UNUSED(a_QueryBlockType);
auto Offset = GetPoweredRailAdjacentXZCoordinateOffset(a_Meta); auto Offset = GetPoweredRailAdjacentXZCoordinateOffset(a_Meta);
if (((Offset + a_Position) == a_QueryPosition) || ((-Offset + a_Position) == a_QueryPosition)) if (((Offset + a_Position) == a_QueryPosition) || ((-Offset + a_Position) == a_QueryPosition))
{ {
auto Power = GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta); auto Power = DataForChunk(a_Chunk).GetCachedPowerData(a_Position).PowerLevel;
return (Power <= 7) ? 0 : --Power; return (Power <= 7) ? 0 : --Power;
} }
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTickingChunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
return static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating tracky the rail (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating tracky the rail (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
@ -66,33 +56,37 @@ public:
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_MyType); SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_MyType);
} }
*/ */
return {}; return;
} }
case E_BLOCK_ACTIVATOR_RAIL: case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_POWERED_RAIL: case E_BLOCK_POWERED_RAIL:
{ {
auto Offset = GetPoweredRailAdjacentXZCoordinateOffset(a_Meta); auto Offset = GetPoweredRailAdjacentXZCoordinateOffset(a_Meta);
if (a_PoweringData != static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData)) if (a_PoweringData != DataForChunk(a_Chunk).ExchangeUpdateOncePowerData(a_Position, a_PoweringData))
{ {
a_World.SetBlockMeta(a_Position, (a_PoweringData.PowerLevel == 0) ? (a_Meta & 0x07) : (a_Meta | 0x08)); a_Chunk.SetMeta(a_Position, (a_PoweringData.PowerLevel == 0) ? (a_Meta & 0x07) : (a_Meta | 0x08));
return cVector3iArray{ { Offset + a_Position }, { -Offset + a_Position } };
UpdateAdjustedRelatives(a_Chunk, CurrentlyTickingChunk, a_Position + Offset);
UpdateAdjustedRelatives(a_Chunk, CurrentlyTickingChunk, a_Position + -Offset);
} }
return {}; return;
} }
default: default:
{ {
ASSERT(!"Unhandled type of rail in passed to rail handler!"); ASSERT(!"Unhandled type of rail in passed to rail handler!");
return {};
} }
} }
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
if ((a_BlockType == E_BLOCK_POWERED_RAIL) || (a_BlockType == E_BLOCK_ACTIVATOR_RAIL))
{
InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
}
} }
}; };

View File

@ -9,47 +9,42 @@
class cPressurePlateHandler: class cPressurePlateHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
UNUSED(a_QueryPosition); UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType); UNUSED(a_QueryBlockType);
return static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel; return DataForChunk(a_Chunk).GetCachedPowerData(a_Position).PowerLevel;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override static unsigned char GetPowerLevel(cChunk & Chunk, const Vector3i Position, const BLOCKTYPE BlockType)
{ {
UNUSED(a_Meta); unsigned NumberOfEntities = 0;
int NumberOfEntities = 0;
bool FoundPlayer = false; bool FoundPlayer = false;
a_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + a_Position, 0.5, 0.5), [&](cEntity & a_Entity)
{
if (a_Entity.IsPlayer())
{
FoundPlayer = true;
}
if (a_Entity.IsPickup()) Chunk.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + Position, 0.5, 0.5), [&](cEntity & Entity)
{ {
NumberOfEntities += static_cast<cPickup &>(a_Entity).GetItem().m_ItemCount; if (Entity.IsPlayer())
return false; {
} FoundPlayer = true;
NumberOfEntities++; }
if (Entity.IsPickup())
{
NumberOfEntities += static_cast<cPickup &>(Entity).GetItem().m_ItemCount;
return false; return false;
} }
); NumberOfEntities++;
return false;
});
switch (a_BlockType) switch (BlockType)
{ {
case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE:
{ {
@ -75,18 +70,22 @@ public:
} }
} }
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override static void UpdatePlate(cChunk & Chunk, cChunk & CurrentlyTicking, Vector3i Position)
{
UpdateAdjustedRelatives(Chunk, CurrentlyTicking, Position, RelativeLaterals);
UpdateAdjustedRelatives(Chunk, CurrentlyTicking, Position + OffsetYM);
}
virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
UNUSED(a_PoweringData.PowerLevel);
// LOGD("Evaluating clicky the pressure plate (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating clicky the pressure plate (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto ChunkData = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData(); auto & ChunkData = DataForChunk(a_Chunk);
const auto PreviousPower = ChunkData->GetCachedPowerData(a_Position); const auto PreviousPower = ChunkData.GetCachedPowerData(a_Position);
auto Power = GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta); // Get the current power of the platey const auto Absolute = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
const auto Power = GetPowerLevel(a_Chunk, Absolute, a_BlockType); // Get the current power of the platey
const auto PlateUpdates = GetAdjustedRelatives(a_Position, StaticAppend(GetRelativeLaterals(), cVector3iArray{ OffsetYM() })); const auto DelayInfo = ChunkData.GetMechanismDelayInfo(a_Position);
auto DelayInfo = ChunkData->GetMechanismDelayInfo(a_Position);
// Resting state? // Resting state?
if (DelayInfo == nullptr) if (DelayInfo == nullptr)
@ -94,22 +93,21 @@ public:
if (Power == 0) if (Power == 0)
{ {
// Nothing happened, back to rest // Nothing happened, back to rest
return {}; return;
} }
// From rest, a player stepped on us // From rest, a player stepped on us
// Schedule a minimum 0.5 second delay before even thinking about releasing // Schedule a minimum 0.5 second delay before even thinking about releasing
ChunkData->m_MechanismDelays[a_Position] = std::make_pair(5, true); ChunkData.m_MechanismDelays[a_Position] = std::make_pair(5, true);
auto soundToPlay = GetClickOnSound(a_BlockType); a_Chunk.GetWorld()->BroadcastSoundEffect(GetClickOnSound(a_BlockType), Absolute, 0.5f, 0.6f);
a_World.BroadcastSoundEffect(soundToPlay, a_Position, 0.5f, 0.6f);
// Update power // Update power
ChunkData->SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power)); ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
// Immediately depress plate // Immediately depress plate
a_World.SetBlockMeta(a_Position, E_META_PRESSURE_PLATE_DEPRESSED); a_Chunk.SetMeta(a_Position, E_META_PRESSURE_PLATE_DEPRESSED);
return PlateUpdates; return UpdatePlate(a_Chunk, CurrentlyTicking, a_Position);
} }
// Not a resting state // Not a resting state
@ -124,7 +122,7 @@ public:
// Nothing changes, if there is nothing on it anymore, because the state is locked. // Nothing changes, if there is nothing on it anymore, because the state is locked.
if (Power == 0) if (Power == 0)
{ {
return {}; return;
} }
// Yes. Are we waiting to release, and found that the player stepped on it again? // Yes. Are we waiting to release, and found that the player stepped on it again?
@ -138,11 +136,11 @@ public:
if (Power != PreviousPower.PowerLevel) if (Power != PreviousPower.PowerLevel)
{ {
// Yes. Update power // Yes. Update power
ChunkData->SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power)); ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
return PlateUpdates; return UpdatePlate(a_Chunk, CurrentlyTicking, a_Position);
} }
return {}; return;
} }
// Not waiting for anything. Has the initial delay elapsed? // Not waiting for anything. Has the initial delay elapsed?
@ -153,54 +151,51 @@ public:
{ {
// Yes. Go into subsequent release delay, for a further 0.5 seconds // Yes. Go into subsequent release delay, for a further 0.5 seconds
*DelayInfo = std::make_pair(5, false); *DelayInfo = std::make_pair(5, false);
return {}; return;
} }
// Did the power level change and is still above zero? // Did the power level change and is still above zero?
if (Power != PreviousPower.PowerLevel) if (Power != PreviousPower.PowerLevel)
{ {
// Yes. Update power // Yes. Update power
ChunkData->SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power)); ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
return PlateUpdates; return UpdatePlate(a_Chunk, CurrentlyTicking, a_Position);
} }
// Yes, but player's still on the plate, do nothing // Yes, but player's still on the plate, do nothing
return {}; return;
} }
// Just got out of the subsequent release phase, reset everything and raise the plate // Just got out of the subsequent release phase, reset everything and raise the plate
ChunkData->m_MechanismDelays.erase(a_Position); ChunkData.m_MechanismDelays.erase(a_Position);
auto soundToPlay = GetClickOffSound(a_BlockType); a_Chunk.GetWorld()->BroadcastSoundEffect(GetClickOffSound(a_BlockType), Absolute, 0.5f, 0.5f);
a_World.BroadcastSoundEffect(soundToPlay, a_Position, 0.5f, 0.5f); ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
ChunkData->SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
a_World.SetBlockMeta(a_Position, E_META_PRESSURE_PLATE_RAISED); a_Chunk.SetMeta(a_Position, E_META_PRESSURE_PLATE_RAISED);
return PlateUpdates; return UpdatePlate(a_Chunk, CurrentlyTicking, a_Position);
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
return {}; UNUSED(Callback);
} }
private: private:
static AString GetClickOnSound(BLOCKTYPE a_BlockType)
static const char * GetClickOnSound(BLOCKTYPE a_BlockType)
{ {
// manage on-sound // manage on-sound
switch (a_BlockType) switch (a_BlockType)
{ {
case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE: return "block.stone_pressureplate.click_on";
return "block.stone_pressureplate.click_on"; case E_BLOCK_WOODEN_PRESSURE_PLATE: return "block.wood_pressureplate.click_on";
case E_BLOCK_WOODEN_PRESSURE_PLATE:
return "block.wood_pressureplate.click_on";
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return "block.metal_pressureplate.click_on";
return "block.metal_pressureplate.click_on";
default: default:
{ {
ASSERT(!"No on sound for this one!"); ASSERT(!"No on sound for this one!");
@ -209,18 +204,15 @@ private:
} }
} }
static AString GetClickOffSound(BLOCKTYPE a_BlockType) static const char * GetClickOffSound(BLOCKTYPE a_BlockType)
{ {
// manage off-sound // manage off-sound
switch (a_BlockType) switch (a_BlockType)
{ {
case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE: return "block.stone_pressureplate.click_off";
return "block.stone_pressureplate.click_off"; case E_BLOCK_WOODEN_PRESSURE_PLATE: return "block.wood_pressureplate.click_off";
case E_BLOCK_WOODEN_PRESSURE_PLATE:
return "block.wood_pressureplate.click_off";
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return "block.metal_pressureplate.click_off";
return "block.metal_pressureplate.click_off";
default: default:
{ {
ASSERT(!"No off sound for this one!"); ASSERT(!"No off sound for this one!");

View File

@ -7,16 +7,13 @@
class cRedstoneBlockHandler: class cRedstoneBlockHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
@ -24,27 +21,17 @@ public:
return cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType) ? 15 : 0; return cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType) ? 15 : 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
UNUSED(a_World);
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 15;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating crimson the redstone block (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating crimson the redstone block (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
return {}; UNUSED(Callback);
} }
}; };

View File

@ -8,14 +8,11 @@
class cRedstoneComparatorHandler: class cRedstoneComparatorHandler : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
unsigned char GetFrontPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, unsigned char a_HighestSidePowerLevel, unsigned char a_HighestRearPowerLevel) const static unsigned char GetFrontPowerLevel(NIBBLETYPE a_Meta, unsigned char a_HighestSidePowerLevel, unsigned char a_HighestRearPowerLevel)
{ {
if (cBlockComparatorHandler::IsInSubtractionMode(a_Meta)) if (cBlockComparatorHandler::IsInSubtractionMode(a_Meta))
{ {
@ -29,107 +26,120 @@ public:
} }
} }
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_QueryPosition); UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType); UNUSED(a_QueryBlockType);
auto ChunkData = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData();
return ( return (
(cBlockComparatorHandler::GetFrontCoordinate(a_Position, a_Meta & 0x3) == a_QueryPosition) ? (cBlockComparatorHandler::GetFrontCoordinate(a_Position, a_Meta & 0x3) == a_QueryPosition) ?
ChunkData->GetCachedPowerData(a_Position).PowerLevel : 0 DataForChunk(a_Chunk).GetCachedPowerData(a_Position).PowerLevel : 0
); );
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override static unsigned char GetPowerLevel(cChunk & a_Chunk, Vector3i Position, BLOCKTYPE BlockType, NIBBLETYPE Meta)
{ {
UNUSED(a_Position);
UNUSED(a_BlockType);
UInt8 SignalStrength = 0; UInt8 SignalStrength = 0;
auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(a_Position, a_Meta & 0x3); auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(Position, Meta & 0x3);
a_World.DoWithBlockEntityAt(RearCoordinate.x, RearCoordinate.y, RearCoordinate.z, [&](cBlockEntity & a_BlockEntity)
{
// Skip BlockEntities that don't have slots
auto BlockEntityWithItems = dynamic_cast<cBlockEntityWithItems *>(&a_BlockEntity);
if (BlockEntityWithItems == nullptr)
{
return false;
}
auto & Contents = BlockEntityWithItems->GetContents(); auto RearChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RearCoordinate);
float Fullness = 0; // Is a floating-point type to allow later calculation to produce a non-truncated value if ((RearChunk == nullptr) || !RearChunk->IsValid())
for (int Slot = 0; Slot != Contents.GetNumSlots(); ++Slot)
{
Fullness += static_cast<float>(Contents.GetSlot(Slot).m_ItemCount) / Contents.GetSlot(Slot).GetMaxStackSize();
}
SignalStrength = (Fullness < 0.001 /* container empty? */) ? 0 : static_cast<UInt8>(1 + (Fullness / Contents.GetNumSlots()) * 14);
return false;
}
);
auto RearPower = SignalStrength;
auto RearType = a_World.GetBlock(RearCoordinate);
auto PotentialSourceHandler = cIncrementalRedstoneSimulator::GetComponentHandler(RearType);
if (PotentialSourceHandler != nullptr)
{ {
NIBBLETYPE RearMeta = a_World.GetBlockMeta(RearCoordinate); return SignalStrength;
RearPower = std::max(SignalStrength, PotentialSourceHandler->GetPowerDeliveredToPosition(a_World, RearCoordinate, RearType, RearMeta, a_Position, a_BlockType));
} }
return RearPower; RearChunk->DoWithBlockEntityAt(RearCoordinate, [&](cBlockEntity & a_BlockEntity)
{
// Skip BlockEntities that don't have slots
auto BlockEntityWithItems = dynamic_cast<cBlockEntityWithItems *>(&a_BlockEntity);
if (BlockEntityWithItems == nullptr)
{
return false;
}
// TODO: handle double chests
auto & Contents = BlockEntityWithItems->GetContents();
float Fullness = 0; // Is a floating-point type to allow later calculation to produce a non-truncated value
for (int Slot = 0; Slot != Contents.GetNumSlots(); ++Slot)
{
Fullness += static_cast<float>(Contents.GetSlot(Slot).m_ItemCount) / Contents.GetSlot(Slot).GetMaxStackSize();
}
SignalStrength = (Fullness < 0.001 /* container empty? */) ? 0 : static_cast<UInt8>(1 + (Fullness / Contents.GetNumSlots()) * 14);
return false;
});
BLOCKTYPE RearType;
NIBBLETYPE RearMeta;
RearChunk->GetBlockTypeMeta(RearCoordinate, RearType, RearMeta);
auto PotentialSourceHandler = cIncrementalRedstoneSimulator::GetComponentHandler(RearType);
if (PotentialSourceHandler == nullptr)
{
return SignalStrength;
}
return std::max(
SignalStrength,
PotentialSourceHandler->GetPowerDeliveredToPosition(
*RearChunk, RearCoordinate, RearType, RearMeta,
cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(a_Chunk, *RearChunk, Position), BlockType
)
);
} }
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// Note that a_PoweringData here contains the maximum * side * power level, as specified by GetValidSourcePositions // Note that a_PoweringData here contains the maximum * side * power level, as specified by GetValidSourcePositions
// LOGD("Evaluating ALU the comparator (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating ALU the comparator (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Data = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData();
auto DelayInfo = Data->GetMechanismDelayInfo(a_Position); auto & Data = DataForChunk(a_Chunk);
auto DelayInfo = Data.GetMechanismDelayInfo(a_Position);
// Delay is used here to prevent an infinite loop (#3168) // Delay is used here to prevent an infinite loop (#3168)
if (DelayInfo == nullptr) if (DelayInfo == nullptr)
{ {
auto RearPower = GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta); const auto RearPower = GetPowerLevel(a_Chunk, a_Position, a_BlockType, a_Meta);
auto FrontPower = GetFrontPowerLevel(a_World, a_Position, a_BlockType, a_Meta, a_PoweringData.PowerLevel, RearPower); const auto FrontPower = GetFrontPowerLevel(a_Meta, a_PoweringData.PowerLevel, RearPower);
auto PreviousFrontPower = Data->ExchangeUpdateOncePowerData(a_Position, PoweringData(a_PoweringData.PoweringBlock, FrontPower)); const auto PreviousFrontPower = Data.GetCachedPowerData(a_Position);
const bool ShouldUpdate = (FrontPower != PreviousFrontPower.PowerLevel); // "Business logic" (:P) - determined by side and rear power levels
bool ShouldBeOn = (RearPower > 0); // Provide visual indication by examining * rear * power level if (ShouldUpdate)
bool ShouldUpdate = (FrontPower != PreviousFrontPower.PowerLevel); // "Business logic" (:P) - determine by examining *side* power levels
if (ShouldUpdate || (ShouldBeOn != cBlockComparatorHandler::IsOn(a_Meta)))
{ {
Data->m_MechanismDelays[a_Position] = std::make_pair(1, ShouldBeOn); Data.m_MechanismDelays[a_Position] = std::make_pair(1, bool());
} }
} }
else else
{ {
int DelayTicks; int DelayTicks;
bool ShouldPowerOn; std::tie(DelayTicks, std::ignore) = *DelayInfo;
std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo;
if (DelayTicks == 0) if (DelayTicks == 0)
{ {
a_World.SetBlockMeta(a_Position, ShouldPowerOn ? (a_Meta | 0x8) : (a_Meta & 0x7)); const auto RearPower = GetPowerLevel(a_Chunk, a_Position, a_BlockType, a_Meta);
Data->m_MechanismDelays.erase(a_Position); const auto FrontPower = GetFrontPowerLevel(a_Meta, a_PoweringData.PowerLevel, RearPower);
const auto NewMeta = (FrontPower > 0) ? (a_Meta | 0x8) : (a_Meta & 0x7);
// Assume that an update (to front power) is needed. // Don't care about the previous power level so return value ignored
// Note: potential inconsistencies will arise as power data is updated before-delay due to limitations of the power data caching functionality (only stores one bool) Data.ExchangeUpdateOncePowerData(a_Position, PoweringData(a_PoweringData.PoweringBlock, FrontPower));
// This means that other mechanisms like wires may get our new power data before our delay has finished
// This also means that we have to manually update ourselves to be aware of any changes that happened in the previous redstone tick a_Chunk.SetMeta(a_Position, NewMeta);
return StaticAppend(GetAdjustedRelatives(a_Position, GetRelativeLaterals()), cVector3iArray{ a_Position }); Data.m_MechanismDelays.erase(a_Position);
// Assume that an update (to front power) is needed:
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, cBlockComparatorHandler::GetFrontCoordinate(a_Position, a_Meta & 0x3));
} }
} }
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
return cVector3iArray {cBlockComparatorHandler::GetSideCoordinate(a_Position, a_Meta & 0x3, false), cBlockComparatorHandler::GetSideCoordinate(a_Position, a_Meta & 0x3, true)};
Callback(cBlockComparatorHandler::GetSideCoordinate(a_Position, a_Meta & 0x3, false));
Callback(cBlockComparatorHandler::GetSideCoordinate(a_Position, a_Meta & 0x3, true));
} }
}; };

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
#include "../../World.h" #include "../../Chunk.h"
#include "RedstoneSimulatorChunkData.h"
@ -14,50 +15,11 @@ public:
cRedstoneHandler() = default; cRedstoneHandler() = default;
DISALLOW_COPY_AND_ASSIGN(cRedstoneHandler); DISALLOW_COPY_AND_ASSIGN(cRedstoneHandler);
struct PoweringData using SourceCallback = cFunctionRef<void(Vector3i)>;
{
public:
PoweringData(BLOCKTYPE a_PoweringBlock, unsigned char a_PowerLevel) :
PoweringBlock(a_PoweringBlock),
PowerLevel(a_PowerLevel)
{
}
PoweringData(void) : virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const = 0;
PoweringBlock(E_BLOCK_AIR), virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const = 0;
PowerLevel(0) virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const = 0;
{
}
BLOCKTYPE PoweringBlock;
unsigned char PowerLevel;
inline friend bool operator < (const PoweringData & a_Lhs, const PoweringData & a_Rhs)
{
return (
(a_Lhs.PowerLevel < a_Rhs.PowerLevel) ||
(
(a_Lhs.PowerLevel == a_Rhs.PowerLevel) &&
((a_Lhs.PoweringBlock == E_BLOCK_REDSTONE_WIRE) && (a_Rhs.PoweringBlock != E_BLOCK_REDSTONE_WIRE))
)
);
}
inline friend bool operator == (const PoweringData & a_Lhs, const PoweringData & a_Rhs)
{
return (a_Lhs.PowerLevel == a_Rhs.PowerLevel);
}
inline friend bool operator != (const PoweringData & a_Lhs, const PoweringData & a_Rhs)
{
return !operator ==(a_Lhs, a_Rhs);
}
};
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const = 0;
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const = 0;
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const = 0;
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const = 0;
// Force a virtual destructor // Force a virtual destructor
virtual ~cRedstoneHandler() {} virtual ~cRedstoneHandler() {}
@ -72,15 +34,9 @@ protected:
return ToReturn; return ToReturn;
} }
inline static Vector3i OffsetYP() inline static Vector3i OffsetYP{ 0, 1, 0 };
{
return Vector3i(0, 1, 0);
}
inline static Vector3i OffsetYM() inline static Vector3i OffsetYM{ 0, -1, 0 };
{
return Vector3i(0, -1, 0);
}
static cVector3iArray GetAdjustedRelatives(Vector3i a_Position, cVector3iArray a_Relatives) static cVector3iArray GetAdjustedRelatives(Vector3i a_Position, cVector3iArray a_Relatives)
{ {
@ -91,31 +47,68 @@ protected:
return a_Relatives; return a_Relatives;
} }
inline static cVector3iArray GetRelativeAdjacents() inline static cIncrementalRedstoneSimulatorChunkData & DataForChunk(cChunk & a_Chunk)
{ {
return return *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk.GetRedstoneSimulatorData());
{
{
{ 1, 0, 0 },
{ -1, 0, 0 },
{ 0, 1, 0 },
{ 0, -1, 0 },
{ 0, 0, 1 },
{ 0, 0, -1 },
}
};
} }
inline static cVector3iArray GetRelativeLaterals() template <typename... ArrayTypes>
static void UpdateAdjustedRelatives(cChunk & From, cChunk & To, const Vector3i Position)
{ {
return DataForChunk(To).WakeUp(cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(From, To, Position));
}
template <typename ArrayType, typename... ArrayTypes>
static void UpdateAdjustedRelatives(cChunk & From, cChunk & To, const Vector3i Position, const ArrayType & Relative, const ArrayTypes &... Relatives)
{
for (const auto Offset : Relative)
{ {
{ DataForChunk(To).GetActiveBlocks().push(cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(From, To, Position + Offset));
{ 1, 0, 0 }, }
{ -1, 0, 0 },
{ 0, 0, 1 }, UpdateAdjustedRelatives(From, To, Position, Relatives...);
{ 0, 0, -1 }, }
}
}; template <typename ArrayType, typename... ArrayTypes>
static void InvokeForAdjustedRelatives(SourceCallback Callback, Vector3i Position, const ArrayType & Relative, const ArrayTypes &... Relatives)
{
for (const auto Offset : Relative)
{
Callback(Position + Offset);
}
InvokeForAdjustedRelatives(Callback, Position, Relatives...);
}
inline static std::array<Vector3i, 6> RelativeAdjacents
{
{
{ 1, 0, 0 },
{ -1, 0, 0 },
{ 0, 1, 0 },
{ 0, -1, 0 },
{ 0, 0, 1 },
{ 0, 0, -1 },
}
};
inline static std::array<Vector3i, 4> RelativeLaterals
{
{
{ 1, 0, 0 },
{ -1, 0, 0 },
{ 0, 0, 1 },
{ 0, 0, -1 },
}
};
private:
static void UpdateAdjustedRelatives(cVector3iArray &, Vector3i)
{
}
static void InvokeForAdjustedRelatives(SourceCallback, Vector3i)
{
} }
}; };

View File

@ -5,7 +5,7 @@
class cRedstoneLampHandler : public cRedstoneHandler class cRedstoneLampHandler final : public cRedstoneHandler
{ {
public: public:
@ -14,17 +14,12 @@ public:
return (a_BlockType == E_BLOCK_REDSTONE_LAMP_ON); return (a_BlockType == E_BLOCK_REDSTONE_LAMP_ON);
} }
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk &, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
return 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating lamp (%i %i %i)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating lamp (%i %i %i)", a_Position.x, a_Position.y, a_Position.z);
@ -32,25 +27,23 @@ public:
{ {
if (!IsOn(a_BlockType)) if (!IsOn(a_BlockType))
{ {
a_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, E_BLOCK_REDSTONE_LAMP_ON, 0); a_Chunk.FastSetBlock(a_Position, E_BLOCK_REDSTONE_LAMP_ON, 0);
} }
} }
else else
{ {
if (IsOn(a_BlockType)) if (IsOn(a_BlockType))
{ {
a_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, E_BLOCK_REDSTONE_LAMP_OFF, 0); a_Chunk.FastSetBlock(a_Position, E_BLOCK_REDSTONE_LAMP_OFF, 0);
} }
} }
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Meta); UNUSED(a_Meta);
UNUSED(a_BlockType); UNUSED(a_BlockType);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents()); InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
} }
}; };

View File

@ -15,37 +15,27 @@ class cRedstoneRepeaterHandler:
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
return ( return ((a_QueryPosition == (a_Position + cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta))) && IsOn(a_BlockType)) ? 15 : 0;
(a_QueryPosition == (a_Position + cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta))) ?
GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta) : 0
);
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
UNUSED(a_World);
UNUSED(a_Position);
UNUSED(a_Meta);
return IsOn(a_BlockType) ? 15 : 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating loopy the repeater (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating loopy the repeater (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Data = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData();
auto DelayInfo = Data->GetMechanismDelayInfo(a_Position); auto & Data = DataForChunk(a_Chunk);
const auto DelayInfo = Data.GetMechanismDelayInfo(a_Position);
// If the repeater is locked by another, ignore and forget all power changes: // If the repeater is locked by another, ignore and forget all power changes:
if (IsLocked(a_World, a_Position, a_Meta)) if (IsLocked(a_Chunk, a_Position, a_Meta))
{ {
if (DelayInfo != nullptr) if (DelayInfo != nullptr)
{ {
Data->m_MechanismDelays.erase(a_Position); Data.m_MechanismDelays.erase(a_Position);
} }
return {}; return;
} }
if (DelayInfo == nullptr) if (DelayInfo == nullptr)
@ -53,7 +43,7 @@ public:
bool ShouldBeOn = (a_PoweringData.PowerLevel != 0); bool ShouldBeOn = (a_PoweringData.PowerLevel != 0);
if (ShouldBeOn != IsOn(a_BlockType)) if (ShouldBeOn != IsOn(a_BlockType))
{ {
Data->m_MechanismDelays[a_Position] = std::make_pair((((a_Meta & 0xC) >> 0x2) + 1), ShouldBeOn); Data.m_MechanismDelays[a_Position] = std::make_pair((((a_Meta & 0xC) >> 0x2) + 1), ShouldBeOn);
} }
} }
else else
@ -64,18 +54,23 @@ public:
if (DelayTicks == 0) if (DelayTicks == 0)
{ {
a_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, ShouldPowerOn ? E_BLOCK_REDSTONE_REPEATER_ON : E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta); const auto NewType = ShouldPowerOn ? E_BLOCK_REDSTONE_REPEATER_ON : E_BLOCK_REDSTONE_REPEATER_OFF;
Data->m_MechanismDelays.erase(a_Position); a_Chunk.FastSetBlock(a_Position, NewType, a_Meta);
return cVector3iArray{ cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta) + a_Position }; Data.m_MechanismDelays.erase(a_Position);
// While sleeping, we ignore any power changes and apply our saved ShouldBeOn when sleep expires
// Now, we need to recalculate to be aware of any new changes that may e.g. cause a new output change
// FastSetBlock doesn't wake simulators, so manually update ourselves:
Update(a_Chunk, CurrentlyTicking, a_Position, NewType, a_Meta, a_PoweringData);
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position + cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta));
} }
} }
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
return { cBlockRedstoneRepeaterHandler::GetRearCoordinateOffset(a_Meta) + a_Position }; Callback(cBlockRedstoneRepeaterHandler::GetRearCoordinateOffset(a_Meta) + a_Position);
} }
private: private:
@ -87,12 +82,12 @@ private:
/** Returns a pair with first element indicating if the block at the given position is an activated repeater. /** Returns a pair with first element indicating if the block at the given position is an activated repeater.
If it is activated, the second element is the repeater metadata. */ If it is activated, the second element is the repeater metadata. */
static std::pair<bool, NIBBLETYPE> IsOnRepeater(cWorld & a_World, const Vector3i a_Position) static std::pair<bool, NIBBLETYPE> IsOnRepeater(cChunk & Chunk, const Vector3i a_Position)
{ {
BLOCKTYPE Type; BLOCKTYPE Type;
NIBBLETYPE Meta; NIBBLETYPE Meta;
if (!a_World.GetBlockTypeMeta(a_Position, Type, Meta)) if (!Chunk.UnboundedRelGetBlock(a_Position, Type, Meta))
{ {
return std::make_pair(false, 0); return std::make_pair(false, 0);
} }
@ -103,20 +98,20 @@ private:
/** Determine if a repeater is locked. /** Determine if a repeater is locked.
A locked repeater is one with another powered repeater facing them, to their immediate left or right sides. A locked repeater is one with another powered repeater facing them, to their immediate left or right sides.
"Left" is relative to the direction the repeater output faces, naturally. */ "Left" is relative to the direction the repeater output faces, naturally. */
inline static bool IsLocked(cWorld & a_World, const Vector3i a_Position, const NIBBLETYPE a_Meta) inline static bool IsLocked(cChunk & Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta)
{ {
// The left hand side offset. Will be negated to get the rhs offset // The left hand side offset. Will be negated to get the rhs offset
const auto LhsOffset = cBlockRedstoneRepeaterHandler::GetLeftCoordinateOffset(a_Meta); const auto LhsOffset = cBlockRedstoneRepeaterHandler::GetLeftCoordinateOffset(a_Meta);
// Test the block to the left of us // Test the block to the left of us
const auto Lhs = IsOnRepeater(a_World, LhsOffset + a_Position); const auto Lhs = IsOnRepeater(Chunk, LhsOffset + a_Position);
if (Lhs.first && DoesLhsLockMe(Lhs.second, a_Meta)) if (Lhs.first && DoesLhsLockMe(Lhs.second, a_Meta))
{ {
return true; return true;
} }
// Test the right side, flipping the argument order to DoesLhsLockMe // Test the right side, flipping the argument order to DoesLhsLockMe
const auto Rhs = IsOnRepeater(a_World, -LhsOffset + a_Position); const auto Rhs = IsOnRepeater(Chunk, -LhsOffset + a_Position);
return Rhs.first && DoesLhsLockMe(a_Meta, Rhs.second); return Rhs.first && DoesLhsLockMe(a_Meta, Rhs.second);
} }

View File

@ -1,73 +1,132 @@
#pragma once #pragma once
#include "RedstoneHandler.h" #include <stack>
#include "../RedstoneSimulator.h" #include "../RedstoneSimulator.h"
struct PoweringData
{
public:
PoweringData(BLOCKTYPE a_PoweringBlock, unsigned char a_PowerLevel) :
PoweringBlock(a_PoweringBlock),
PowerLevel(a_PowerLevel)
{
}
PoweringData(void) :
PoweringBlock(E_BLOCK_AIR),
PowerLevel(0)
{
}
BLOCKTYPE PoweringBlock;
unsigned char PowerLevel;
inline friend bool operator < (const PoweringData & Lhs, const PoweringData & Rhs)
{
return (
(Lhs.PowerLevel < Rhs.PowerLevel) ||
(
(Lhs.PowerLevel == Rhs.PowerLevel) &&
((Lhs.PoweringBlock == E_BLOCK_REDSTONE_WIRE) && (Rhs.PoweringBlock != E_BLOCK_REDSTONE_WIRE))
)
);
}
inline friend bool operator == (const PoweringData & Lhs, const PoweringData & Rhs)
{
return (Lhs.PowerLevel == Rhs.PowerLevel);
}
inline friend bool operator != (const PoweringData & Lhs, const PoweringData & Rhs)
{
return !operator ==(Lhs, Rhs);
}
};
class cIncrementalRedstoneSimulatorChunkData : public cRedstoneSimulatorChunkData class cIncrementalRedstoneSimulatorChunkData : public cRedstoneSimulatorChunkData
{ {
public: public:
void WakeUp(const Vector3i & a_Position) void WakeUp(const Vector3i & a_Position)
{ {
m_ActiveBlocks.push_back(a_Position); ActiveBlocks.push(a_Position);
} }
cVector3iArray & GetActiveBlocks() auto & GetActiveBlocks()
{ {
return m_ActiveBlocks; return ActiveBlocks;
} }
const cRedstoneHandler::PoweringData GetCachedPowerData(const Vector3i & a_Position) const const PoweringData GetCachedPowerData(const Vector3i Position) const
{ {
auto Result = m_CachedPowerLevels.find(a_Position); auto Result = CachedPowerLevels.find(Position);
return (Result == m_CachedPowerLevels.end()) ? cRedstoneHandler::PoweringData() : Result->second; return (Result == CachedPowerLevels.end()) ? PoweringData() : Result->second;
} }
void SetCachedPowerData(const Vector3i & a_Position, cRedstoneHandler::PoweringData a_PoweringData) void SetCachedPowerData(const Vector3i Position, PoweringData PoweringData)
{ {
m_CachedPowerLevels[a_Position] = a_PoweringData; CachedPowerLevels[Position] = PoweringData;
} }
std::pair<int, bool> * GetMechanismDelayInfo(const Vector3i & a_Position) std::pair<int, bool> * GetMechanismDelayInfo(const Vector3i Position)
{ {
auto Result = m_MechanismDelays.find(a_Position); auto Result = m_MechanismDelays.find(Position);
return (Result == m_MechanismDelays.end()) ? nullptr : &Result->second; return (Result == m_MechanismDelays.end()) ? nullptr : &Result->second;
} }
/** Erase cached PowerData for position */ /** Erase all cached redstone data for position. */
void ErasePowerData(const Vector3i & a_Position) void ErasePowerData(const Vector3i Position)
{ {
m_CachedPowerLevels.erase(a_Position); CachedPowerLevels.erase(Position);
m_MechanismDelays.erase(a_Position); m_MechanismDelays.erase(Position);
AlwaysTickedPositions.erase(Position);
} }
cRedstoneHandler::PoweringData ExchangeUpdateOncePowerData(const Vector3i & a_Position, cRedstoneHandler::PoweringData a_PoweringData) PoweringData ExchangeUpdateOncePowerData(const Vector3i & a_Position, PoweringData a_PoweringData)
{ {
auto Result = m_CachedPowerLevels.find(a_Position); auto Result = CachedPowerLevels.find(a_Position);
if (Result == m_CachedPowerLevels.end()) if (Result == CachedPowerLevels.end())
{ {
m_CachedPowerLevels[a_Position] = a_PoweringData; CachedPowerLevels[a_Position] = a_PoweringData;
return cRedstoneHandler::PoweringData(); return PoweringData();
} }
std::swap(Result->second, a_PoweringData); std::swap(Result->second, a_PoweringData);
return a_PoweringData; return a_PoweringData;
} }
/** Adjust From-relative coordinates into To-relative coordinates. */
inline static Vector3i RebaseRelativePosition(cChunk & From, cChunk & To, const Vector3i Position)
{
return
{
Position.x + (From.GetPosX() - To.GetPosX()) * cChunkDef::Width,
Position.y,
Position.z + (From.GetPosZ() - To.GetPosZ()) * cChunkDef::Width
};
}
std::unordered_set<Vector3i, VectorHasher<int>> AlwaysTickedPositions;
/** Structure storing position of mechanism + it's delay ticks (countdown) & if to power on */ /** Structure storing position of mechanism + it's delay ticks (countdown) & if to power on */
std::unordered_map<Vector3i, std::pair<int, bool>, VectorHasher<int>> m_MechanismDelays; std::unordered_map<Vector3i, std::pair<int, bool>, VectorHasher<int>> m_MechanismDelays;
private: private:
cVector3iArray m_ActiveBlocks; std::stack<Vector3i, std::vector<Vector3i>> ActiveBlocks;
// TODO: map<Vector3i, int> -> Position of torch + it's heat level // TODO: map<Vector3i, int> -> Position of torch + it's heat level
std::unordered_map<Vector3i, cRedstoneHandler::PoweringData, VectorHasher<int>> m_CachedPowerLevels; std::unordered_map<Vector3i, PoweringData, VectorHasher<int>> CachedPowerLevels;
friend class cRedstoneHandlerFactory; friend class cRedstoneHandlerFactory;

View File

@ -9,11 +9,8 @@
class cRedstoneToggleHandler: class cRedstoneToggleHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
inline static Vector3i GetPositionAttachedTo(Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) inline static Vector3i GetPositionAttachedTo(Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta)
@ -65,21 +62,18 @@ public:
} }
} }
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_QueryBlockType); UNUSED(a_QueryBlockType);
if ((GetPositionAttachedTo(a_Position, a_BlockType, a_Meta) == a_QueryPosition) || cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType)) if ((GetPositionAttachedTo(a_Position, a_BlockType, a_Meta) == a_QueryPosition) || cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType))
{ {
return GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta); return GetPowerLevel(a_BlockType, a_Meta);
} }
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override static unsigned char GetPowerLevel(BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta)
{ {
UNUSED(a_World);
UNUSED(a_Position);
switch (a_BlockType) switch (a_BlockType)
{ {
case E_BLOCK_LEVER: return cBlockLeverHandler::IsLeverOn(a_Meta) ? 15 : 0; case E_BLOCK_LEVER: return cBlockLeverHandler::IsLeverOn(a_Meta) ? 15 : 0;
@ -93,18 +87,17 @@ public:
} }
} }
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating templatio<> the lever/button (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating templatio<> the lever/button (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
return {}; UNUSED(Callback);
} }
}; };

View File

@ -7,7 +7,7 @@
class cRedstoneTorchHandler : public cRedstoneHandler class cRedstoneTorchHandler final : public cRedstoneHandler
{ {
public: public:
@ -33,12 +33,12 @@ public:
} }
} }
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
if ( if (
IsOn(a_BlockType) && IsOn(a_BlockType) &&
(a_QueryPosition != (a_Position + GetOffsetAttachedTo(a_Position, a_Meta))) && (a_QueryPosition != (a_Position + GetOffsetAttachedTo(a_Position, a_Meta))) &&
(cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType) || (cBlockInfo::FullyOccupiesVoxel(a_QueryBlockType) && (a_QueryPosition == (a_Position + OffsetYP())))) (cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType) || (cBlockInfo::FullyOccupiesVoxel(a_QueryBlockType) && (a_QueryPosition == (a_Position + OffsetYP))))
) )
{ {
return 15; return 15;
@ -46,24 +46,19 @@ public:
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
return IsOn(a_BlockType) ? 15 : 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating torchy the redstone torch (%i %i %i)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating torchy the redstone torch (%i %i %i)", a_Position.x, a_Position.y, a_Position.z);
auto Data = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData(); auto & Data = DataForChunk(a_Chunk);
auto DelayInfo = Data->GetMechanismDelayInfo(a_Position); auto DelayInfo = Data.GetMechanismDelayInfo(a_Position);
if (DelayInfo == nullptr) if (DelayInfo == nullptr)
{ {
bool ShouldBeOn = (a_PoweringData.PowerLevel == 0); bool ShouldBeOn = (a_PoweringData.PowerLevel == 0);
if (ShouldBeOn != IsOn(a_BlockType)) if (ShouldBeOn != IsOn(a_BlockType))
{ {
Data->m_MechanismDelays[a_Position] = std::make_pair(1, ShouldBeOn); Data.m_MechanismDelays[a_Position] = std::make_pair(1, ShouldBeOn);
} }
} }
else else
@ -72,24 +67,28 @@ public:
bool ShouldPowerOn; bool ShouldPowerOn;
std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo; std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo;
if (DelayTicks == 0) if (DelayTicks != 0)
{ {
a_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, ShouldPowerOn ? E_BLOCK_REDSTONE_TORCH_ON : E_BLOCK_REDSTONE_TORCH_OFF, a_Meta); return;
Data->m_MechanismDelays.erase(a_Position); }
cVector3iArray RelativePositions = GetRelativeAdjacents(); a_Chunk.SetBlock(a_Position, ShouldPowerOn ? E_BLOCK_REDSTONE_TORCH_ON : E_BLOCK_REDSTONE_TORCH_OFF, a_Meta);
RelativePositions.erase(std::remove(RelativePositions.begin(), RelativePositions.end(), GetOffsetAttachedTo(a_Position, a_Meta)), RelativePositions.end()); Data.m_MechanismDelays.erase(a_Position);
return GetAdjustedRelatives(a_Position, RelativePositions);
for (const auto Adjacent : RelativeAdjacents)
{
if (Adjacent != GetOffsetAttachedTo(a_Position, a_Meta))
{
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position + Adjacent);
}
} }
} }
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
return { (a_Position + GetOffsetAttachedTo(a_Position, a_Meta)) }; Callback(a_Position + GetOffsetAttachedTo(a_Position, a_Meta));
} }
}; };

View File

@ -7,11 +7,8 @@
class cRedstoneWireHandler: class cRedstoneWireHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
inline static bool IsDirectlyConnectingMechanism(BLOCKTYPE a_Block, NIBBLETYPE a_BlockMeta, const Vector3i a_Offset) inline static bool IsDirectlyConnectingMechanism(BLOCKTYPE a_Block, NIBBLETYPE a_BlockMeta, const Vector3i a_Offset)
@ -40,133 +37,170 @@ public:
} }
} }
cVector3iArray GetTerracingConnectionOffsets(cWorld & a_World, const Vector3i a_Position) const template <class OffsetCallback>
static bool ForTerracingConnectionOffsets(cChunk & a_Chunk, const Vector3i a_Position, OffsetCallback Callback)
{ {
auto RelativePositions = GetRelativeLaterals(); const auto YPTerraceBlock = a_Chunk.GetBlock(a_Position + OffsetYP);
const auto YPTerraceBlock = a_World.GetBlock(a_Position + OffsetYP());
const bool IsYPTerracingBlocked = cBlockInfo::IsSolid(YPTerraceBlock) && !cBlockInfo::IsTransparent(YPTerraceBlock); const bool IsYPTerracingBlocked = cBlockInfo::IsSolid(YPTerraceBlock) && !cBlockInfo::IsTransparent(YPTerraceBlock);
for (const auto & Adjacent : GetRelativeLaterals()) for (const auto Adjacent : RelativeLaterals)
{ {
if ( // All laterals are counted as terracing, duh
// A block above us blocks all YP terracing, so the check is static in the loop if (Callback(Adjacent))
!IsYPTerracingBlocked &&
(a_World.GetBlock(a_Position + Adjacent + OffsetYP()) == E_BLOCK_REDSTONE_WIRE)
)
{ {
RelativePositions.emplace_back(Adjacent + OffsetYP()); return true;
} }
const auto YMTerraceBlock = a_World.GetBlock(a_Position + Adjacent);
if ( if (
// IsYMTerracingBlocked (i.e. check block above lower terracing position, a.k.a. just the plain adjacent) BLOCKTYPE YPBlock;
(!cBlockInfo::IsSolid(YMTerraceBlock) || cBlockInfo::IsTransparent(YMTerraceBlock)) &&
(a_World.GetBlock(a_Position + Adjacent + OffsetYM()) == E_BLOCK_REDSTONE_WIRE) // A block above us blocks all YP terracing, so the check is static in the loop
!IsYPTerracingBlocked &&
a_Chunk.UnboundedRelGetBlockType(a_Position + Adjacent + OffsetYP, YPBlock) &&
(YPBlock == E_BLOCK_REDSTONE_WIRE)
) )
{ {
RelativePositions.emplace_back(Adjacent + OffsetYM()); if (Callback(Adjacent + OffsetYP))
{
return true;
}
}
if (
BLOCKTYPE YMTerraceBlock, YMDiagonalBlock;
// IsYMTerracingBlocked (i.e. check block above lower terracing position, a.k.a. just the plain adjacent)
a_Chunk.UnboundedRelGetBlockType(a_Position + Adjacent, YMTerraceBlock) &&
(!cBlockInfo::IsSolid(YMTerraceBlock) || cBlockInfo::IsTransparent(YMTerraceBlock)) &&
a_Chunk.UnboundedRelGetBlockType(a_Position + Adjacent + OffsetYM, YMDiagonalBlock) &&
(YMDiagonalBlock == E_BLOCK_REDSTONE_WIRE)
)
{
if (Callback(Adjacent + OffsetYM))
{
return true;
}
} }
} }
return RelativePositions; return false;
} }
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
if (a_QueryPosition == (a_Position + OffsetYP())) if (a_QueryPosition == (a_Position + OffsetYP))
{ {
// Wires do not power things above them // Wires do not power things above them
return 0; return 0;
} }
if (a_QueryBlockType != E_BLOCK_REDSTONE_WIRE) if (a_QueryBlockType == E_BLOCK_REDSTONE_WIRE)
{ {
// For mechanisms, wire of power one will still power them // For mechanisms, wire of power one will still power them
a_Meta++; // But for wire-to-wire connections, power level decreases by 1
return (a_Meta != 0) ? --a_Meta : a_Meta;
} }
// Wires always deliver power to the block underneath, and any directly connecting mechanisms // Wires always deliver power to the block underneath, and any directly connecting mechanisms
if ( if (
(a_QueryPosition != (a_Position + OffsetYM())) && NIBBLETYPE QueryMeta;
!IsDirectlyConnectingMechanism(a_QueryBlockType, a_World.GetBlockMeta(a_QueryPosition), a_QueryPosition - a_Position)
(a_QueryPosition == (a_Position + OffsetYM)) ||
(a_Chunk.UnboundedRelGetBlockMeta(a_QueryPosition, QueryMeta) && IsDirectlyConnectingMechanism(a_QueryBlockType, QueryMeta, a_QueryPosition - a_Position))
) )
{ {
/* return a_Meta;
Okay, we do not directly connect to the wire. }
If there are no DC mechanisms at all, the wire powers all laterals. Great, we fall out the loop.
If there is one DC mechanism, the wire "goes straight" along the axis of the wire and mechanism.
The only possible way for us to be powered is for us to be on the opposite end, with the wire pointing towards us.
If there is more than one DC, no non-DCs are powered.
*/
Vector3i PotentialOffset; /*
bool FoundOneBorderingMechanism = false; Okay, we do not directly connect to the wire.
If there are no DC mechanisms at all, the wire powers all laterals. Great, we fall out the loop.
If there is one DC mechanism, the wire "goes straight" along the axis of the wire and mechanism.
The only possible way for us to be powered is for us to be on the opposite end, with the wire pointing towards us.
If there is more than one DC, no non-DCs are powered.
*/
for (const auto & Offset : GetTerracingConnectionOffsets(a_World, a_Position)) Vector3i PotentialOffset;
bool FoundOneBorderingMechanism = false;
if (
ForTerracingConnectionOffsets(a_Chunk, a_Position, [&a_Chunk, a_Position, &FoundOneBorderingMechanism, &PotentialOffset](const Vector3i Offset)
{ {
BLOCKTYPE Block; BLOCKTYPE Block;
NIBBLETYPE Meta; NIBBLETYPE Meta;
if ( if (
!a_World.GetBlockTypeMeta(Offset + a_Position, Block, Meta) || !a_Chunk.UnboundedRelGetBlock(Offset + a_Position, Block, Meta) ||
!IsDirectlyConnectingMechanism(Block, Meta, Offset) !IsDirectlyConnectingMechanism(Block, Meta, Offset)
) )
{ {
continue; return false;
} }
if (FoundOneBorderingMechanism) if (FoundOneBorderingMechanism)
{ {
// Case 3 // Case 3
return 0; return true;
} }
// Potential case 2 // Potential case 2
FoundOneBorderingMechanism = true; FoundOneBorderingMechanism = true;
PotentialOffset = { -Offset.x, 0, -Offset.z }; PotentialOffset = { -Offset.x, 0, -Offset.z };
}
if (FoundOneBorderingMechanism && (a_QueryPosition != (a_Position + PotentialOffset))) return false;
{ })
// Case 2 fail )
return 0; {
} // Case 3
return 0;
// Case 1
// Case 2 success
} }
return (a_Meta != 0) ? --a_Meta : a_Meta; if (FoundOneBorderingMechanism && (a_QueryPosition != (a_Position + PotentialOffset)))
} {
// Case 2 fail
return 0;
}
// Case 1
// Case 2 success
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
{
UNUSED(a_World);
UNUSED(a_Position);
UNUSED(a_BlockType);
return a_Meta; return a_Meta;
} }
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
UNUSED(a_BlockType);
// LOGD("Evaluating dusty the wire (%d %d %d) %i", a_Position.x, a_Position.y, a_Position.z, a_PoweringData.PowerLevel); // LOGD("Evaluating dusty the wire (%d %d %d) %i", a_Position.x, a_Position.y, a_Position.z, a_PoweringData.PowerLevel);
if (a_Meta != a_PoweringData.PowerLevel) if (a_Meta != a_PoweringData.PowerLevel)
{ {
a_World.SetBlockMeta(a_Position, a_PoweringData.PowerLevel); a_Chunk.SetMeta(a_Position, a_PoweringData.PowerLevel);
return GetAdjustedRelatives(a_Position, StaticAppend(StaticAppend(GetRelativeLaterals(), GetTerracingConnectionOffsets(a_World, a_Position)), cVector3iArray{ OffsetYM() }));
}
return {}; // Notify block below us to update:
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position + OffsetYM);
// Notify all terracing positions:
ForTerracingConnectionOffsets(a_Chunk, a_Position, [&a_Chunk, &CurrentlyTicking, a_Position](const Vector3i Offset)
{
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position + Offset);
return false;
});
}
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, StaticAppend(GetRelativeAdjacents(), GetTerracingConnectionOffsets(a_World, a_Position))); Callback(a_Position + OffsetYP);
Callback(a_Position + OffsetYM);
ForTerracingConnectionOffsets(a_Chunk, a_Position, [&Callback, a_Position](const Vector3i Offset)
{
Callback(a_Position + Offset);
return false;
});
} }
}; };

View File

@ -7,16 +7,13 @@
class cSmallGateHandler: class cSmallGateHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
@ -25,32 +22,24 @@ public:
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk &, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
UNUSED(a_World);
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating gateydory the fence gate/trapdoor (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating gateydory the fence gate/trapdoor (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Data = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData();
if (a_PoweringData != Data->ExchangeUpdateOncePowerData(a_Position, a_PoweringData))
{
a_World.SetBlockMeta(a_Position, (a_PoweringData.PowerLevel > 0) ? (a_Meta | 0x4) : (a_Meta & ~0x04));
}
return {}; const bool ShouldBeOpen = a_PoweringData.PowerLevel != 0;
const bool IsOpen = (a_Meta & 0x4) == 0x4;
if (ShouldBeOpen != IsOpen)
{
a_Chunk.SetMeta(a_Position, ShouldBeOpen ? (a_Meta | 0x4) : (a_Meta & ~0x04));
}
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents()); InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
} }
}; };

View File

@ -14,41 +14,34 @@ class cSolidBlockHandler:
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
// TODO: wire isn't linked powered only if the source was a wire, not just because it is a wire const auto SolidBlock = DataForChunk(a_Chunk).GetCachedPowerData(a_Position);
return ( return (
!cIncrementalRedstoneSimulator::IsRedstone(a_QueryBlockType) || !cIncrementalRedstoneSimulator::IsRedstone(a_QueryBlockType) ||
( (
(a_QueryBlockType == E_BLOCK_REDSTONE_WIRE) && (a_QueryBlockType == E_BLOCK_REDSTONE_WIRE) &&
(static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PoweringBlock == E_BLOCK_REDSTONE_WIRE) (SolidBlock.PoweringBlock == E_BLOCK_REDSTONE_WIRE)
) )
) ? 0 : GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta); ) ? 0 : SolidBlock.PowerLevel;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
return static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
// LOGD("Evaluating blocky the generic block (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating blocky the generic block (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto PreviousPower = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData); auto PreviousPower = DataForChunk(a_Chunk).ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
if ((a_PoweringData != PreviousPower) || (a_PoweringData.PoweringBlock != PreviousPower.PoweringBlock)) if ((a_PoweringData != PreviousPower) || (a_PoweringData.PoweringBlock != PreviousPower.PoweringBlock))
{ {
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents()); UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents);
} }
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
@ -64,6 +57,6 @@ public:
} }
} }
*/ */
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents()); InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
} }
}; };

View File

@ -7,16 +7,13 @@
class cTNTHandler: class cTNTHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
@ -25,31 +22,21 @@ public:
return 0; return 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void Update(cChunk & a_Chunk, cChunk &, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
UNUSED(a_World);
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating explodinator the trinitrotoluene (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating explodinator the trinitrotoluene (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
if (a_PoweringData.PowerLevel != 0) if (a_PoweringData.PowerLevel != 0)
{ {
a_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, E_BLOCK_AIR, 0); a_Chunk.SetBlock(a_Position, E_BLOCK_AIR, 0);
a_World.SpawnPrimedTNT(Vector3d(a_Position) + Vector3d(0.5, 0.5, 0.5)); // 80 ticks to boom a_Chunk.GetWorld()->SpawnPrimedTNT(Vector3d(0.5, 0.5, 0.5) + cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos())); // 80 ticks to boom
} }
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents()); InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
} }
}; };

View File

@ -15,54 +15,51 @@ class cTrappedChestHandler:
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
UNUSED(a_QueryPosition); UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType); UNUSED(a_QueryBlockType);
return static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel; return DataForChunk(a_Chunk).GetCachedPowerData(a_Position).PowerLevel;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override static unsigned char GetPowerLevel(cChunk & a_Chunk, Vector3i a_Position)
{ {
UNUSED(a_BlockType);
UNUSED(a_Meta);
int NumberOfPlayers = 0; int NumberOfPlayers = 0;
VERIFY(!a_World.DoWithChestAt(a_Position.x, a_Position.y, a_Position.z, [&](cChestEntity & a_Chest) VERIFY(
!a_Chunk.DoWithChestAt(a_Position, [&](cChestEntity & a_Chest)
{ {
ASSERT(a_Chest.GetBlockType() == E_BLOCK_TRAPPED_CHEST); ASSERT(a_Chest.GetBlockType() == E_BLOCK_TRAPPED_CHEST);
NumberOfPlayers = a_Chest.GetNumberOfPlayers(); NumberOfPlayers = a_Chest.GetNumberOfPlayers();
return true; return true;
} })
)); );
return static_cast<unsigned char>(std::min(NumberOfPlayers, 15)); return static_cast<unsigned char>(std::min(NumberOfPlayers, 15));
} }
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating tricky the trapped chest (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating tricky the trapped chest (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Power = GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta); const auto Power = GetPowerLevel(a_Chunk, a_Position);
auto PreviousPower = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, PoweringData(a_BlockType, Power)); const auto PreviousPower = DataForChunk(a_Chunk).ExchangeUpdateOncePowerData(a_Position, PoweringData(a_BlockType, Power));
if (Power != PreviousPower.PowerLevel) if (Power != PreviousPower.PowerLevel)
{ {
return GetAdjustedRelatives(a_Position, StaticAppend(GetRelativeLaterals(), cVector3iArray{ OffsetYM() })); UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, OffsetYM);
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeLaterals);
} }
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
UNUSED(Callback);
return {};
} }
}; };

View File

@ -8,43 +8,53 @@
class cTripwireHookHandler: class cTripwireHookHandler final : public cRedstoneHandler
public cRedstoneHandler
{ {
using Super = cRedstoneHandler;
public: public:
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{ {
UNUSED(a_BlockType);
UNUSED(a_QueryBlockType); UNUSED(a_QueryBlockType);
UNUSED(a_QueryPosition); UNUSED(a_QueryPosition);
return (GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta) == 15) ? 15 : 0; return (GetPowerLevel(a_Chunk, a_Position, a_Meta) == 15) ? 15 : 0;
} }
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override static unsigned char GetPowerLevel(cChunk & a_Chunk, Vector3i a_Position, NIBBLETYPE a_Meta)
{ {
UNUSED(a_BlockType);
bool FoundActivated = false; bool FoundActivated = false;
auto Position = a_Position; const auto FaceToGoTowards = cBlockTripwireHookHandler::MetadataToDirection(a_Meta);
eBlockFace FaceToGoTowards = cBlockTripwireHookHandler::MetadataToDirection(a_Meta);
for (int i = 0; i < 40; ++i) // Tripwires can be connected up to 40 blocks for (int i = 0; i < 40; ++i) // Tripwires can be connected up to 40 blocks
{ {
BLOCKTYPE Type; BLOCKTYPE Type;
NIBBLETYPE Meta; NIBBLETYPE Meta;
AddFaceDirection(Position.x, Position.y, Position.z, FaceToGoTowards); a_Position = AddFaceDirection(a_Position, FaceToGoTowards);
a_World.GetBlockTypeMeta(Position.x, Position.y, Position.z, Type, Meta); if (!a_Chunk.UnboundedRelGetBlock(a_Position, Type, Meta))
{
return 0;
}
if (Type == E_BLOCK_TRIPWIRE) if (Type == E_BLOCK_TRIPWIRE)
{ {
if (!a_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + Position, 0.5, 0.5), [](cEntity &) { return true; })) if (FoundActivated)
{
continue;
}
if (
!a_Chunk.ForEachEntityInBox(
cBoundingBox(Vector3d(0.5, 0, 0.5) + cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos()), 0.5, 0.5),
[](cEntity &) { return true; }
)
)
{ {
FoundActivated = true; FoundActivated = true;
} }
continue;
} }
else if (Type == E_BLOCK_TRIPWIRE_HOOK) else if (Type == E_BLOCK_TRIPWIRE_HOOK)
{ {
@ -53,27 +63,20 @@ public:
// Other hook facing in opposite direction - circuit completed! // Other hook facing in opposite direction - circuit completed!
return FoundActivated ? 15 : 1; return FoundActivated ? 15 : 1;
} }
else
{
// Tripwire hook not connected at all
return 0;
}
}
else
{
// Tripwire hook not connected at all
return 0;
} }
// Tripwire hook not connected at all
return 0;
} }
return 0; return 0;
} }
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{ {
// LOGD("Evaluating hooky the tripwire hook (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); // LOGD("Evaluating hooky the tripwire hook (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Power = GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta); const auto Power = GetPowerLevel(a_Chunk, a_Position, a_Meta);
NIBBLETYPE Meta; NIBBLETYPE Meta;
if (Power == 0) if (Power == 0)
{ {
@ -91,25 +94,22 @@ public:
} }
else else
{ {
ASSERT(!"Unexpected tripwire hook power level!"); UNREACHABLE("Unexpected tripwire hook power level!");
return {};
} }
if (Meta != a_Meta) if (Meta != a_Meta)
{ {
a_World.SetBlockMeta(a_Position, Meta); a_Chunk.SetMeta(a_Position, Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents()); UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents);
} }
return {};
} }
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{ {
UNUSED(a_World); UNUSED(a_Chunk);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
UNUSED(a_Position); UNUSED(a_Position);
return {}; UNUSED(Callback);
} }
}; };

View File

@ -7,7 +7,7 @@
class cRedstoneNoopSimulator: class cRedstoneNoopSimulator final :
public cRedstoneSimulator public cRedstoneSimulator
{ {
using Super = cRedstoneSimulator; using Super = cRedstoneSimulator;