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
) override
{
const auto Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
// Toggle the 3rd bit (addition / subtraction):
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
Meta ^= 0x04;
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta);
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta ^ 0x04);
// Update simulators:
a_WorldInterface.WakeUpSimulators(a_BlockPos);
return true;
}
@ -56,6 +59,7 @@ public:
UNUSED(a_ChunkInterface);
UNUSED(a_BlockFace);
a_WorldInterface.WakeUpSimulators(a_BlockPos);
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)
{
if (!a_bInverse)

View File

@ -8,16 +8,13 @@
class cCommandBlockHandler:
public cRedstoneHandler
class cCommandBlockHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
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_BlockType);
UNUSED(a_Meta);
@ -26,40 +23,29 @@ public:
return 0;
}
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
virtual void Update(cChunk & a_Chunk, cChunk &, 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);
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 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();
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_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
}
};

View File

@ -8,16 +8,13 @@
class cDoorHandler:
public cRedstoneHandler
class cDoorHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
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_BlockType);
UNUSED(a_Meta);
@ -26,46 +23,27 @@ public:
return 0;
}
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
virtual void Update(cChunk & a_Chunk, cChunk &, 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);
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;
const auto AbsolutePosition = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
const bool IsOpen = cBlockDoorHandler::IsOpen(ChunkInterface, AbsolutePosition);
if (ShouldBeOpen != IsOpen)
{
cChunkInterface ChunkInterface(a_World.GetChunkMap());
cBlockDoorHandler::SetOpen(ChunkInterface, a_Position, (a_PoweringData.PowerLevel != 0));
a_World.BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, a_Position, 0);
cBlockDoorHandler::SetOpen(ChunkInterface, AbsolutePosition, ShouldBeOpen);
a_Chunk.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, AbsolutePosition, 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_BlockType);
UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
}
};

View File

@ -8,17 +8,15 @@
class cDropSpenserHandler:
public cRedstoneHandler
class cDropSpenserHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
public:
inline static bool IsActivated(NIBBLETYPE a_Meta)
{
return (a_Meta & E_META_DROPSPENSER_ACTIVATED) != 0;
}
inline static NIBBLETYPE SetActivationState(NIBBLETYPE a_Meta, bool 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_BlockType);
UNUSED(a_Meta);
@ -42,45 +40,34 @@ public:
return 0;
}
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
virtual void Update(cChunk & a_Chunk, cChunk &, 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);
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)
{
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();
return false;
}
);
});
}
// Update the internal dropspenser state if necessary
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_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
}
};

View File

@ -8,16 +8,13 @@
class cHopperHandler:
public cRedstoneHandler
class cHopperHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
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_BlockType);
UNUSED(a_Meta);
@ -26,39 +23,28 @@ public:
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;
// LOGD("Evaluating holey the hopper (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Previous = DataForChunk(a_Chunk).ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
if (Previous.PowerLevel == a_PoweringData.PowerLevel)
{
return;
}
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);
auto Previous = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
if (Previous.PowerLevel != a_PoweringData.PowerLevel)
{
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);
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_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
}
};

View File

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

View File

@ -2,13 +2,14 @@
#pragma once
#include "../RedstoneSimulator.h"
#include "RedstoneHandler.h"
#include "RedstoneSimulatorChunkData.h"
class cIncrementalRedstoneSimulator:
class cIncrementalRedstoneSimulator final :
public cRedstoneSimulator
{
using Super = cRedstoneSimulator;
@ -20,8 +21,10 @@ public:
{
}
virtual void Simulate(float a_dt) override;
virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override {}
virtual void Simulate(float Dt) 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
{
@ -36,8 +39,7 @@ public:
virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override;
/** 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)
{
switch (Block)
@ -158,14 +160,9 @@ public:
}
}
cIncrementalRedstoneSimulatorChunkData * GetChunkData() { return &m_Data; }
static const cRedstoneHandler * GetComponentHandler(BLOCKTYPE a_BlockType);
private:
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:
public cRedstoneHandler
class cNoteBlockHandler: public cRedstoneHandler
{
using Super = cRedstoneHandler;
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_World);
UNUSED(a_Chunk);
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
@ -27,41 +23,29 @@ public:
return 0;
}
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
virtual void Update(cChunk & a_Chunk, cChunk &, 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);
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 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();
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_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:
@ -17,24 +17,24 @@ public:
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;
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;
}
// Cache the last seen block type and meta in the power data for this position
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
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))))
{
@ -44,30 +44,25 @@ public:
return 0;
}
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) 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
virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, 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);
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);
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
// 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;
@ -76,31 +71,30 @@ public:
if (DelayTicks != 0)
{
return {};
return;
}
if (ShouldPowerOn)
{
// Remain on for 1 tick before resetting
*DelayInfo = std::make_pair(1, false);
a_World.SetBlockMeta(a_Position, a_Meta | 0x8);
a_Chunk.SetMeta(a_Position, a_Meta | 0x8);
}
else
{
// We've reset. Erase delay data in preparation for detecting further updates
Data->m_MechanismDelays.erase(a_Position);
a_World.SetBlockMeta(a_Position, a_Meta & ~0x8);
Data.m_MechanismDelays.erase(a_Position);
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_BlockType);
UNUSED(a_BlockType);
return {};
}
};

View File

@ -8,16 +8,13 @@
class cPistonHandler:
public cRedstoneHandler
class cPistonHandler final: public cRedstoneHandler
{
using Super = cRedstoneHandler;
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_BlockType);
UNUSED(a_Meta);
@ -26,52 +23,45 @@ public:
return 0;
}
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
virtual void Update(cChunk & a_Chunk, cChunk &, 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);
bool ShouldBeExtended = (a_PoweringData.PowerLevel != 0);
const bool ShouldBeExtended = a_PoweringData.PowerLevel != 0;
if (ShouldBeExtended == cBlockPistonHandler::IsExtended(a_Meta))
{
return {};
return;
}
a_Position = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
if (ShouldBeExtended)
{
cBlockPistonHandler::ExtendPiston(a_Position, a_World);
cBlockPistonHandler::ExtendPiston(a_Position, *a_Chunk.GetWorld());
}
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)
// However, that is present as a side effect of the implementation of piston animation in Blocks\BlockPiston.cpp
return {};
// However, this delay is already present: as a side effect of the implementation of piston animation in Blocks\BlockPiston.cpp
}
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);
auto PositionsOffset = GetRelativeAdjacents();
auto Face = cBlockPistonHandler::MetaDataToDirection(a_Meta);
int OffsetX = 0, OffsetY = 0, OffsetZ = 0;
const auto Face = cBlockPistonHandler::MetaDataToDirection(a_Meta);
const auto FrontOffset = AddFaceDirection(Vector3i(), Face);
AddFaceDirection(OffsetX, OffsetY, OffsetZ, Face);
PositionsOffset.erase(std::remove(PositionsOffset.begin(), PositionsOffset.end(), Vector3i(OffsetX, OffsetY, OffsetZ)), PositionsOffset.end());
return GetAdjustedRelatives(a_Position, PositionsOffset);
for (const auto Offset : RelativeAdjacents)
{
if (Offset != FrontOffset)
{
Callback(a_Position + Offset);
}
}
}
};

View File

@ -7,11 +7,8 @@
class cPoweredRailHandler:
public cRedstoneHandler
class cPoweredRailHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
public:
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);
auto Offset = GetPoweredRailAdjacentXZCoordinateOffset(a_Meta);
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 0;
}
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) 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
virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTickingChunk, 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);
@ -66,33 +56,37 @@ public:
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_MyType);
}
*/
return {};
return;
}
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_POWERED_RAIL:
{
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));
return cVector3iArray{ { Offset + a_Position }, { -Offset + a_Position } };
a_Chunk.SetMeta(a_Position, (a_PoweringData.PowerLevel == 0) ? (a_Meta & 0x07) : (a_Meta | 0x08));
UpdateAdjustedRelatives(a_Chunk, CurrentlyTickingChunk, a_Position + Offset);
UpdateAdjustedRelatives(a_Chunk, CurrentlyTickingChunk, a_Position + -Offset);
}
return {};
return;
}
default:
{
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_BlockType);
UNUSED(a_Chunk);
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:
public cRedstoneHandler
class cPressurePlateHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
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_Meta);
UNUSED(a_QueryPosition);
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);
int NumberOfEntities = 0;
unsigned NumberOfEntities = 0;
bool FoundPlayer = false;
a_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + a_Position, 0.5, 0.5), [&](cEntity & a_Entity)
Chunk.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + Position, 0.5, 0.5), [&](cEntity & Entity)
{
if (a_Entity.IsPlayer())
if (Entity.IsPlayer())
{
FoundPlayer = true;
}
if (a_Entity.IsPickup())
if (Entity.IsPickup())
{
NumberOfEntities += static_cast<cPickup &>(a_Entity).GetItem().m_ItemCount;
NumberOfEntities += static_cast<cPickup &>(Entity).GetItem().m_ItemCount;
return false;
}
NumberOfEntities++;
return false;
}
);
});
switch (a_BlockType)
switch (BlockType)
{
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);
auto ChunkData = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData();
auto & ChunkData = DataForChunk(a_Chunk);
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 PlateUpdates = GetAdjustedRelatives(a_Position, StaticAppend(GetRelativeLaterals(), cVector3iArray{ OffsetYM() }));
auto DelayInfo = ChunkData->GetMechanismDelayInfo(a_Position);
const auto PreviousPower = ChunkData.GetCachedPowerData(a_Position);
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 DelayInfo = ChunkData.GetMechanismDelayInfo(a_Position);
// Resting state?
if (DelayInfo == nullptr)
@ -94,22 +93,21 @@ public:
if (Power == 0)
{
// Nothing happened, back to rest
return {};
return;
}
// From rest, a player stepped on us
// 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_World.BroadcastSoundEffect(soundToPlay, a_Position, 0.5f, 0.6f);
a_Chunk.GetWorld()->BroadcastSoundEffect(GetClickOnSound(a_BlockType), Absolute, 0.5f, 0.6f);
// Update power
ChunkData->SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
// Immediately depress plate
a_World.SetBlockMeta(a_Position, E_META_PRESSURE_PLATE_DEPRESSED);
return PlateUpdates;
a_Chunk.SetMeta(a_Position, E_META_PRESSURE_PLATE_DEPRESSED);
return UpdatePlate(a_Chunk, CurrentlyTicking, a_Position);
}
// Not a resting state
@ -124,7 +122,7 @@ public:
// Nothing changes, if there is nothing on it anymore, because the state is locked.
if (Power == 0)
{
return {};
return;
}
// Yes. Are we waiting to release, and found that the player stepped on it again?
@ -138,11 +136,11 @@ public:
if (Power != PreviousPower.PowerLevel)
{
// Yes. Update power
ChunkData->SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
return PlateUpdates;
ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
return UpdatePlate(a_Chunk, CurrentlyTicking, a_Position);
}
return {};
return;
}
// 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
*DelayInfo = std::make_pair(5, false);
return {};
return;
}
// Did the power level change and is still above zero?
if (Power != PreviousPower.PowerLevel)
{
// Yes. Update power
ChunkData->SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
return PlateUpdates;
ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
return UpdatePlate(a_Chunk, CurrentlyTicking, a_Position);
}
// 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
ChunkData->m_MechanismDelays.erase(a_Position);
ChunkData.m_MechanismDelays.erase(a_Position);
auto soundToPlay = GetClickOffSound(a_BlockType);
a_World.BroadcastSoundEffect(soundToPlay, a_Position, 0.5f, 0.5f);
ChunkData->SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
a_Chunk.GetWorld()->BroadcastSoundEffect(GetClickOffSound(a_BlockType), Absolute, 0.5f, 0.5f);
ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
a_World.SetBlockMeta(a_Position, E_META_PRESSURE_PLATE_RAISED);
return PlateUpdates;
a_Chunk.SetMeta(a_Position, E_META_PRESSURE_PLATE_RAISED);
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_BlockType);
UNUSED(a_Meta);
return {};
UNUSED(Callback);
}
private:
static AString GetClickOnSound(BLOCKTYPE a_BlockType)
static const char * GetClickOnSound(BLOCKTYPE a_BlockType)
{
// manage on-sound
switch (a_BlockType)
{
case E_BLOCK_STONE_PRESSURE_PLATE:
return "block.stone_pressureplate.click_on";
case E_BLOCK_WOODEN_PRESSURE_PLATE:
return "block.wood_pressureplate.click_on";
case E_BLOCK_STONE_PRESSURE_PLATE: return "block.stone_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_LIGHT_WEIGHTED_PRESSURE_PLATE:
return "block.metal_pressureplate.click_on";
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return "block.metal_pressureplate.click_on";
default:
{
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
switch (a_BlockType)
{
case E_BLOCK_STONE_PRESSURE_PLATE:
return "block.stone_pressureplate.click_off";
case E_BLOCK_WOODEN_PRESSURE_PLATE:
return "block.wood_pressureplate.click_off";
case E_BLOCK_STONE_PRESSURE_PLATE: return "block.stone_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_LIGHT_WEIGHTED_PRESSURE_PLATE:
return "block.metal_pressureplate.click_off";
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return "block.metal_pressureplate.click_off";
default:
{
ASSERT(!"No off sound for this one!");

View File

@ -7,16 +7,13 @@
class cRedstoneBlockHandler:
public cRedstoneHandler
class cRedstoneBlockHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
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_BlockType);
UNUSED(a_Meta);
@ -24,27 +21,17 @@ public:
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
{
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
virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, 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);
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_BlockType);
UNUSED(a_Meta);
return {};
UNUSED(Callback);
}
};

View File

@ -8,14 +8,11 @@
class cRedstoneComparatorHandler:
public cRedstoneHandler
class cRedstoneComparatorHandler : public cRedstoneHandler
{
using Super = cRedstoneHandler;
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))
{
@ -29,26 +26,29 @@ 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_QueryBlockType);
auto ChunkData = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData();
return (
(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;
auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(a_Position, a_Meta & 0x3);
a_World.DoWithBlockEntityAt(RearCoordinate.x, RearCoordinate.y, RearCoordinate.z, [&](cBlockEntity & a_BlockEntity)
auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(Position, Meta & 0x3);
auto RearChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RearCoordinate);
if ((RearChunk == nullptr) || !RearChunk->IsValid())
{
return SignalStrength;
}
RearChunk->DoWithBlockEntityAt(RearCoordinate, [&](cBlockEntity & a_BlockEntity)
{
// Skip BlockEntities that don't have slots
auto BlockEntityWithItems = dynamic_cast<cBlockEntityWithItems *>(&a_BlockEntity);
@ -57,6 +57,8 @@ public:
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
@ -67,69 +69,77 @@ public:
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);
});
BLOCKTYPE RearType;
NIBBLETYPE RearMeta;
RearChunk->GetBlockTypeMeta(RearCoordinate, RearType, RearMeta);
auto PotentialSourceHandler = cIncrementalRedstoneSimulator::GetComponentHandler(RearType);
if (PotentialSourceHandler != nullptr)
if (PotentialSourceHandler == nullptr)
{
NIBBLETYPE RearMeta = a_World.GetBlockMeta(RearCoordinate);
RearPower = std::max(SignalStrength, PotentialSourceHandler->GetPowerDeliveredToPosition(a_World, RearCoordinate, RearType, RearMeta, a_Position, a_BlockType));
return SignalStrength;
}
return RearPower;
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
// 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)
if (DelayInfo == nullptr)
{
auto RearPower = GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta);
auto FrontPower = GetFrontPowerLevel(a_World, a_Position, a_BlockType, a_Meta, a_PoweringData.PowerLevel, RearPower);
auto PreviousFrontPower = Data->ExchangeUpdateOncePowerData(a_Position, PoweringData(a_PoweringData.PoweringBlock, FrontPower));
const auto RearPower = GetPowerLevel(a_Chunk, a_Position, a_BlockType, a_Meta);
const auto FrontPower = GetFrontPowerLevel(a_Meta, a_PoweringData.PowerLevel, RearPower);
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
bool ShouldUpdate = (FrontPower != PreviousFrontPower.PowerLevel); // "Business logic" (:P) - determine by examining *side* power levels
if (ShouldUpdate || (ShouldBeOn != cBlockComparatorHandler::IsOn(a_Meta)))
if (ShouldUpdate)
{
Data->m_MechanismDelays[a_Position] = std::make_pair(1, ShouldBeOn);
Data.m_MechanismDelays[a_Position] = std::make_pair(1, bool());
}
}
else
{
int DelayTicks;
bool ShouldPowerOn;
std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo;
std::tie(DelayTicks, std::ignore) = *DelayInfo;
if (DelayTicks == 0)
{
a_World.SetBlockMeta(a_Position, ShouldPowerOn ? (a_Meta | 0x8) : (a_Meta & 0x7));
Data->m_MechanismDelays.erase(a_Position);
const auto RearPower = GetPowerLevel(a_Chunk, a_Position, a_BlockType, a_Meta);
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.
// 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)
// 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
return StaticAppend(GetAdjustedRelatives(a_Position, GetRelativeLaterals()), cVector3iArray{ a_Position });
// Don't care about the previous power level so return value ignored
Data.ExchangeUpdateOncePowerData(a_Position, PoweringData(a_PoweringData.PoweringBlock, FrontPower));
a_Chunk.SetMeta(a_Position, NewMeta);
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);
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
#include "../../World.h"
#include "../../Chunk.h"
#include "RedstoneSimulatorChunkData.h"
@ -14,50 +15,11 @@ public:
cRedstoneHandler() = default;
DISALLOW_COPY_AND_ASSIGN(cRedstoneHandler);
struct PoweringData
{
public:
PoweringData(BLOCKTYPE a_PoweringBlock, unsigned char a_PowerLevel) :
PoweringBlock(a_PoweringBlock),
PowerLevel(a_PowerLevel)
{
}
using SourceCallback = cFunctionRef<void(Vector3i)>;
PoweringData(void) :
PoweringBlock(E_BLOCK_AIR),
PowerLevel(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;
virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const = 0;
virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const = 0;
virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const = 0;
// Force a virtual destructor
virtual ~cRedstoneHandler() {}
@ -72,15 +34,9 @@ protected:
return ToReturn;
}
inline static Vector3i OffsetYP()
{
return Vector3i(0, 1, 0);
}
inline static Vector3i OffsetYP{ 0, 1, 0 };
inline static Vector3i OffsetYM()
{
return Vector3i(0, -1, 0);
}
inline static Vector3i OffsetYM{ 0, -1, 0 };
static cVector3iArray GetAdjustedRelatives(Vector3i a_Position, cVector3iArray a_Relatives)
{
@ -91,9 +47,40 @@ protected:
return a_Relatives;
}
inline static cVector3iArray GetRelativeAdjacents()
inline static cIncrementalRedstoneSimulatorChunkData & DataForChunk(cChunk & a_Chunk)
{
return
return *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk.GetRedstoneSimulatorData());
}
template <typename... ArrayTypes>
static void UpdateAdjustedRelatives(cChunk & From, cChunk & To, const Vector3i Position)
{
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));
}
UpdateAdjustedRelatives(From, To, Position, Relatives...);
}
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 },
@ -104,11 +91,8 @@ protected:
{ 0, 0, -1 },
}
};
}
inline static cVector3iArray GetRelativeLaterals()
{
return
inline static std::array<Vector3i, 4> RelativeLaterals
{
{
{ 1, 0, 0 },
@ -117,5 +101,14 @@ protected:
{ 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:
@ -14,17 +14,12 @@ public:
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;
}
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
{
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 &, 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);
@ -32,25 +27,23 @@ public:
{
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
{
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_BlockType);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
}
};

View File

@ -15,37 +15,27 @@ class cRedstoneRepeaterHandler:
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 (
(a_QueryPosition == (a_Position + cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta))) ?
GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta) : 0
);
return ((a_QueryPosition == (a_Position + cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta))) && IsOn(a_BlockType)) ? 15 : 0;
}
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_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
virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, 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);
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 (IsLocked(a_World, a_Position, a_Meta))
if (IsLocked(a_Chunk, a_Position, a_Meta))
{
if (DelayInfo != nullptr)
{
Data->m_MechanismDelays.erase(a_Position);
Data.m_MechanismDelays.erase(a_Position);
}
return {};
return;
}
if (DelayInfo == nullptr)
@ -53,7 +43,7 @@ public:
bool ShouldBeOn = (a_PoweringData.PowerLevel != 0);
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
@ -64,18 +54,23 @@ public:
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);
Data->m_MechanismDelays.erase(a_Position);
return cVector3iArray{ cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta) + a_Position };
const auto NewType = ShouldPowerOn ? E_BLOCK_REDSTONE_REPEATER_ON : E_BLOCK_REDSTONE_REPEATER_OFF;
a_Chunk.FastSetBlock(a_Position, NewType, a_Meta);
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:
@ -87,12 +82,12 @@ private:
/** 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. */
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;
NIBBLETYPE Meta;
if (!a_World.GetBlockTypeMeta(a_Position, Type, Meta))
if (!Chunk.UnboundedRelGetBlock(a_Position, Type, Meta))
{
return std::make_pair(false, 0);
}
@ -103,20 +98,20 @@ private:
/** Determine if a repeater is locked.
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. */
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
const auto LhsOffset = cBlockRedstoneRepeaterHandler::GetLeftCoordinateOffset(a_Meta);
// 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))
{
return true;
}
// 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);
}

View File

@ -1,73 +1,132 @@
#pragma once
#include "RedstoneHandler.h"
#include <stack>
#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
{
public:
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);
return (Result == m_CachedPowerLevels.end()) ? cRedstoneHandler::PoweringData() : Result->second;
auto Result = CachedPowerLevels.find(Position);
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;
}
/** Erase cached PowerData for position */
void ErasePowerData(const Vector3i & a_Position)
/** Erase all cached redstone data for position. */
void ErasePowerData(const Vector3i Position)
{
m_CachedPowerLevels.erase(a_Position);
m_MechanismDelays.erase(a_Position);
CachedPowerLevels.erase(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);
if (Result == m_CachedPowerLevels.end())
auto Result = CachedPowerLevels.find(a_Position);
if (Result == CachedPowerLevels.end())
{
m_CachedPowerLevels[a_Position] = a_PoweringData;
return cRedstoneHandler::PoweringData();
CachedPowerLevels[a_Position] = a_PoweringData;
return PoweringData();
}
std::swap(Result->second, 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 */
std::unordered_map<Vector3i, std::pair<int, bool>, VectorHasher<int>> m_MechanismDelays;
private:
cVector3iArray m_ActiveBlocks;
std::stack<Vector3i, std::vector<Vector3i>> ActiveBlocks;
// 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;

View File

@ -9,11 +9,8 @@
class cRedstoneToggleHandler:
public cRedstoneHandler
class cRedstoneToggleHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
public:
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);
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;
}
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)
{
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);
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_BlockType);
UNUSED(a_Meta);
return {};
UNUSED(Callback);
}
};

View File

@ -7,7 +7,7 @@
class cRedstoneTorchHandler : public cRedstoneHandler
class cRedstoneTorchHandler final : public cRedstoneHandler
{
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 (
IsOn(a_BlockType) &&
(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;
@ -46,24 +46,19 @@ public:
return 0;
}
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) 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
virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, 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);
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);
if (DelayInfo == nullptr)
{
bool ShouldBeOn = (a_PoweringData.PowerLevel == 0);
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
@ -72,24 +67,28 @@ public:
bool ShouldPowerOn;
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);
Data->m_MechanismDelays.erase(a_Position);
cVector3iArray RelativePositions = GetRelativeAdjacents();
RelativePositions.erase(std::remove(RelativePositions.begin(), RelativePositions.end(), GetOffsetAttachedTo(a_Position, a_Meta)), RelativePositions.end());
return GetAdjustedRelatives(a_Position, RelativePositions);
}
return;
}
return {};
}
a_Chunk.SetBlock(a_Position, ShouldPowerOn ? E_BLOCK_REDSTONE_TORCH_ON : E_BLOCK_REDSTONE_TORCH_OFF, a_Meta);
Data.m_MechanismDelays.erase(a_Position);
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
for (const auto Adjacent : RelativeAdjacents)
{
UNUSED(a_World);
if (Adjacent != GetOffsetAttachedTo(a_Position, a_Meta))
{
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position + Adjacent);
}
}
}
}
virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{
UNUSED(a_Chunk);
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:
public cRedstoneHandler
class cRedstoneWireHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
public:
inline static bool IsDirectlyConnectingMechanism(BLOCKTYPE a_Block, NIBBLETYPE a_BlockMeta, const Vector3i a_Offset)
@ -40,57 +37,82 @@ 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_World.GetBlock(a_Position + OffsetYP());
const auto YPTerraceBlock = a_Chunk.GetBlock(a_Position + OffsetYP);
const bool IsYPTerracingBlocked = cBlockInfo::IsSolid(YPTerraceBlock) && !cBlockInfo::IsTransparent(YPTerraceBlock);
for (const auto & Adjacent : GetRelativeLaterals())
for (const auto Adjacent : RelativeLaterals)
{
// All laterals are counted as terracing, duh
if (Callback(Adjacent))
{
return true;
}
if (
BLOCKTYPE YPBlock;
// A block above us blocks all YP terracing, so the check is static in the loop
!IsYPTerracingBlocked &&
(a_World.GetBlock(a_Position + Adjacent + OffsetYP()) == E_BLOCK_REDSTONE_WIRE)
a_Chunk.UnboundedRelGetBlockType(a_Position + Adjacent + OffsetYP, YPBlock) &&
(YPBlock == E_BLOCK_REDSTONE_WIRE)
)
{
RelativePositions.emplace_back(Adjacent + OffsetYP());
if (Callback(Adjacent + OffsetYP))
{
return true;
}
}
const auto YMTerraceBlock = a_World.GetBlock(a_Position + Adjacent);
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_World.GetBlock(a_Position + Adjacent + OffsetYM()) == E_BLOCK_REDSTONE_WIRE)
a_Chunk.UnboundedRelGetBlockType(a_Position + Adjacent + OffsetYM, YMDiagonalBlock) &&
(YMDiagonalBlock == E_BLOCK_REDSTONE_WIRE)
)
{
RelativePositions.emplace_back(Adjacent + OffsetYM());
}
}
return RelativePositions;
}
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
if (Callback(Adjacent + OffsetYM))
{
if (a_QueryPosition == (a_Position + OffsetYP()))
return true;
}
}
}
return false;
}
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))
{
// Wires do not power things above them
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
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
if (
(a_QueryPosition != (a_Position + OffsetYM())) &&
!IsDirectlyConnectingMechanism(a_QueryBlockType, a_World.GetBlockMeta(a_QueryPosition), a_QueryPosition - a_Position)
NIBBLETYPE QueryMeta;
(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.
@ -102,28 +124,36 @@ public:
Vector3i PotentialOffset;
bool FoundOneBorderingMechanism = false;
for (const auto & Offset : GetTerracingConnectionOffsets(a_World, a_Position))
if (
ForTerracingConnectionOffsets(a_Chunk, a_Position, [&a_Chunk, a_Position, &FoundOneBorderingMechanism, &PotentialOffset](const Vector3i Offset)
{
BLOCKTYPE Block;
NIBBLETYPE Meta;
if (
!a_World.GetBlockTypeMeta(Offset + a_Position, Block, Meta) ||
!a_Chunk.UnboundedRelGetBlock(Offset + a_Position, Block, Meta) ||
!IsDirectlyConnectingMechanism(Block, Meta, Offset)
)
{
continue;
return false;
}
if (FoundOneBorderingMechanism)
{
// Case 3
return 0;
return true;
}
// Potential case 2
FoundOneBorderingMechanism = true;
PotentialOffset = { -Offset.x, 0, -Offset.z };
return false;
})
)
{
// Case 3
return 0;
}
if (FoundOneBorderingMechanism && (a_QueryPosition != (a_Position + PotentialOffset)))
@ -134,39 +164,43 @@ public:
// Case 1
// Case 2 success
}
return (a_Meta != 0) ? --a_Meta : a_Meta;
}
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;
}
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);
if (a_Meta != a_PoweringData.PowerLevel)
{
a_World.SetBlockMeta(a_Position, a_PoweringData.PowerLevel);
return GetAdjustedRelatives(a_Position, StaticAppend(StaticAppend(GetRelativeLaterals(), GetTerracingConnectionOffsets(a_World, a_Position)), cVector3iArray{ OffsetYM() }));
}
a_Chunk.SetMeta(a_Position, a_PoweringData.PowerLevel);
return {};
}
// Notify block below us to update:
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position + OffsetYM);
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
// Notify all terracing positions:
ForTerracingConnectionOffsets(a_Chunk, a_Position, [&a_Chunk, &CurrentlyTicking, a_Position](const Vector3i Offset)
{
UNUSED(a_World);
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position + Offset);
return false;
});
}
}
virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{
UNUSED(a_Chunk);
UNUSED(a_BlockType);
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:
public cRedstoneHandler
class cSmallGateHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
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_BlockType);
UNUSED(a_Meta);
@ -25,32 +22,24 @@ public:
return 0;
}
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
virtual void Update(cChunk & a_Chunk, cChunk &, 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);
auto Data = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData();
if (a_PoweringData != Data->ExchangeUpdateOncePowerData(a_Position, a_PoweringData))
const bool ShouldBeOpen = a_PoweringData.PowerLevel != 0;
const bool IsOpen = (a_Meta & 0x4) == 0x4;
if (ShouldBeOpen != IsOpen)
{
a_World.SetBlockMeta(a_Position, (a_PoweringData.PowerLevel > 0) ? (a_Meta | 0x4) : (a_Meta & ~0x04));
a_Chunk.SetMeta(a_Position, ShouldBeOpen ? (a_Meta | 0x4) : (a_Meta & ~0x04));
}
}
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);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
}
};

View File

@ -14,41 +14,34 @@ class cSolidBlockHandler:
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 (
!cIncrementalRedstoneSimulator::IsRedstone(a_QueryBlockType) ||
(
(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
{
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
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);
UNUSED(a_Meta);
// 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))
{
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_Meta);
@ -64,6 +57,6 @@ public:
}
}
*/
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
}
};

View File

@ -7,16 +7,13 @@
class cTNTHandler:
public cRedstoneHandler
class cTNTHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
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_BlockType);
UNUSED(a_Meta);
@ -25,31 +22,21 @@ public:
return 0;
}
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
virtual void Update(cChunk & a_Chunk, cChunk &, 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);
if (a_PoweringData.PowerLevel != 0)
{
a_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, E_BLOCK_AIR, 0);
a_World.SpawnPrimedTNT(Vector3d(a_Position) + Vector3d(0.5, 0.5, 0.5)); // 80 ticks to boom
a_Chunk.SetBlock(a_Position, E_BLOCK_AIR, 0);
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_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents);
}
};

View File

@ -15,54 +15,51 @@ class cTrappedChestHandler:
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_Meta);
UNUSED(a_QueryPosition);
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;
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);
NumberOfPlayers = a_Chest.GetNumberOfPlayers();
return true;
}
));
})
);
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);
auto Power = GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta);
auto PreviousPower = static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, PoweringData(a_BlockType, Power));
const auto Power = GetPowerLevel(a_Chunk, a_Position);
const auto PreviousPower = DataForChunk(a_Chunk).ExchangeUpdateOncePowerData(a_Position, PoweringData(a_BlockType, Power));
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_BlockType);
UNUSED(a_Meta);
return {};
UNUSED(Callback);
}
};

View File

@ -8,43 +8,53 @@
class cTripwireHookHandler:
public cRedstoneHandler
class cTripwireHookHandler final : public cRedstoneHandler
{
using Super = cRedstoneHandler;
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_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;
auto Position = a_Position;
eBlockFace FaceToGoTowards = cBlockTripwireHookHandler::MetadataToDirection(a_Meta);
const auto FaceToGoTowards = cBlockTripwireHookHandler::MetadataToDirection(a_Meta);
for (int i = 0; i < 40; ++i) // Tripwires can be connected up to 40 blocks
{
BLOCKTYPE Type;
NIBBLETYPE Meta;
AddFaceDirection(Position.x, Position.y, Position.z, FaceToGoTowards);
a_World.GetBlockTypeMeta(Position.x, Position.y, Position.z, Type, Meta);
a_Position = AddFaceDirection(a_Position, FaceToGoTowards);
if (!a_Chunk.UnboundedRelGetBlock(a_Position, Type, Meta))
{
return 0;
}
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;
}
continue;
}
else if (Type == E_BLOCK_TRIPWIRE_HOOK)
{
@ -53,27 +63,20 @@ public:
// Other hook facing in opposite direction - circuit completed!
return FoundActivated ? 15 : 1;
}
else
{
}
// Tripwire hook not connected at all
return 0;
}
}
else
{
// Tripwire hook not connected at all
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);
auto Power = GetPowerLevel(a_World, a_Position, a_BlockType, a_Meta);
const auto Power = GetPowerLevel(a_Chunk, a_Position, a_Meta);
NIBBLETYPE Meta;
if (Power == 0)
{
@ -91,25 +94,22 @@ public:
}
else
{
ASSERT(!"Unexpected tripwire hook power level!");
return {};
UNREACHABLE("Unexpected tripwire hook power level!");
}
if (Meta != a_Meta)
{
a_World.SetBlockMeta(a_Position, Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
a_Chunk.SetMeta(a_Position, Meta);
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_Meta);
UNUSED(a_Position);
return {};
UNUSED(Callback);
}
};

View File

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