1
0
Fork 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_CommandBlock.Activate();
return false;
}
);
return {};
a_Chunk.DoWithCommandBlockAt(a_Position, [](cCommandBlockEntity & a_CommandBlock)
{
a_CommandBlock.Activate();
return false;
});
}
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{
UNUSED(a_World);
UNUSED(a_Chunk);
UNUSED(a_BlockType);
UNUSED(a_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_World.GetChunkMap());
cBlockDoorHandler::SetOpen(ChunkInterface, a_Position, (a_PoweringData.PowerLevel != 0));
a_World.BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, a_Position, 0);
}
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);
return {};
if (ShouldBeOpen != IsOpen)
{
cBlockDoorHandler::SetOpen(ChunkInterface, AbsolutePosition, ShouldBeOpen);
a_Chunk.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, AbsolutePosition, 0);
}
}
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_DropSpenser.Activate();
return false;
}
);
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);
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)
auto Previous = DataForChunk(a_Chunk).ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
if (Previous.PowerLevel == a_PoweringData.PowerLevel)
{
return {};
return;
}
a_World.DoWithHopperAt(a_Position.x, a_Position.y, a_Position.z, [a_PoweringData](cHopperEntity & a_Hopper)
{
a_Hopper.SetLocked(a_PoweringData.PowerLevel != 0);
return false;
}
);
return {};
a_Chunk.DoWithHopperAt(a_Position, [a_PoweringData](cHopperEntity & a_Hopper)
{
a_Hopper.SetLocked(a_PoweringData.PowerLevel != 0);
return false;
});
}
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{
UNUSED(a_World);
UNUSED(a_Chunk);
UNUSED(a_BlockType);
UNUSED(a_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,9 +30,10 @@
const cRedstoneHandler * cIncrementalRedstoneSimulator::GetComponentHandler(BLOCKTYPE a_BlockType)
{
struct sComponents:
struct sComponents :
public std::array<std::unique_ptr<cRedstoneHandler>, 256>
{
sComponents()
@ -128,76 +128,98 @@ std::unique_ptr<cRedstoneHandler> cIncrementalRedstoneSimulator::CreateComponent
void cIncrementalRedstoneSimulator::Simulate(float a_dt)
void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
{
for (auto & DelayInfo : m_Data.m_MechanismDelays)
auto & ChunkData = *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData());
for (auto & DelayInfo : ChunkData.m_MechanismDelays)
{
if ((--DelayInfo.second.first) == 0)
{
m_Data.GetActiveBlocks().emplace_back(DelayInfo.first);
ChunkData.WakeUp(DelayInfo.first);
}
}
// Build our work queue
cVector3iArray WorkQueue;
std::swap(WorkQueue, m_Data.GetActiveBlocks());
auto & WorkQueue = ChunkData.GetActiveBlocks();
// Process the work queue
while (!WorkQueue.empty())
{
// Grab the first element and remove it from the list
Vector3i CurrentLocation = WorkQueue.back();
WorkQueue.pop_back();
Vector3i CurrentLocation = WorkQueue.top();
WorkQueue.pop();
BLOCKTYPE CurrentBlock;
NIBBLETYPE CurrentMeta;
if (!m_World.GetBlockTypeMeta(CurrentLocation.x, CurrentLocation.y, CurrentLocation.z, CurrentBlock, CurrentMeta))
const auto NeighbourChunk = a_Chunk->GetRelNeighborChunkAdjustCoords(CurrentLocation);
if ((NeighbourChunk == nullptr) || !NeighbourChunk->IsValid())
{
continue;
return;
}
auto CurrentHandler = GetComponentHandler(CurrentBlock);
if (CurrentHandler == nullptr) // Block at CurrentPosition doesn't have a corresponding redstone handler
{
// Clean up cached PowerData for CurrentPosition
GetChunkData()->ErasePowerData(CurrentLocation);
continue;
}
cRedstoneHandler::PoweringData Power;
for (const auto & Location : CurrentHandler->GetValidSourcePositions(m_World, CurrentLocation, CurrentBlock, CurrentMeta))
{
if (!cChunk::IsValidHeight(Location.y))
{
continue;
}
BLOCKTYPE PotentialBlock;
NIBBLETYPE PotentialMeta;
if (!m_World.GetBlockTypeMeta(Location.x, Location.y, Location.z, PotentialBlock, PotentialMeta))
{
continue;
}
auto PotentialSourceHandler = GetComponentHandler(PotentialBlock);
if (PotentialSourceHandler == nullptr)
{
continue;
}
decltype(Power) PotentialPower(PotentialBlock, PotentialSourceHandler->GetPowerDeliveredToPosition(m_World, Location, PotentialBlock, PotentialMeta, CurrentLocation, CurrentBlock));
Power = std::max(Power, PotentialPower);
}
// Inform the handler to update
cVector3iArray Updates = CurrentHandler->Update(m_World, CurrentLocation, CurrentBlock, CurrentMeta, Power);
WorkQueue.insert(WorkQueue.end(), Updates.begin(), Updates.end());
if (IsAlwaysTicked(CurrentBlock))
{
m_Data.GetActiveBlocks().emplace_back(CurrentLocation);
}
ProcessWorkItem(*NeighbourChunk, *a_Chunk, CurrentLocation);
}
for (const auto Position : ChunkData.AlwaysTickedPositions)
{
ChunkData.WakeUp(Position);
}
}
void cIncrementalRedstoneSimulator::ProcessWorkItem(cChunk & Chunk, cChunk & TickingSource, const Vector3i Position)
{
auto & ChunkData = *static_cast<cIncrementalRedstoneSimulatorChunkData *>(Chunk.GetRedstoneSimulatorData());
BLOCKTYPE CurrentBlock;
NIBBLETYPE CurrentMeta;
Chunk.GetBlockTypeMeta(Position, CurrentBlock, CurrentMeta);
auto CurrentHandler = GetComponentHandler(CurrentBlock);
if (CurrentHandler == nullptr) // Block at CurrentPosition doesn't have a corresponding redstone handler
{
// Clean up cached PowerData for CurrentPosition
ChunkData.ErasePowerData(Position);
return;
}
PoweringData Power;
CurrentHandler->ForValidSourcePositions(Chunk, Position, CurrentBlock, CurrentMeta, [&Chunk, Position, CurrentBlock, &Power](Vector3i Location)
{
if (!cChunk::IsValidHeight(Location.y))
{
return;
}
const auto NeighbourChunk = Chunk.GetRelNeighborChunkAdjustCoords(Location);
if ((NeighbourChunk == nullptr) || !NeighbourChunk->IsValid())
{
return;
}
BLOCKTYPE PotentialBlock;
NIBBLETYPE PotentialMeta;
NeighbourChunk->GetBlockTypeMeta(Location, PotentialBlock, PotentialMeta);
auto PotentialSourceHandler = GetComponentHandler(PotentialBlock);
if (PotentialSourceHandler == nullptr)
{
return;
}
const PoweringData PotentialPower(
PotentialBlock,
PotentialSourceHandler->GetPowerDeliveredToPosition(
*NeighbourChunk, Location, PotentialBlock, PotentialMeta,
cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(Chunk, *NeighbourChunk, Position), CurrentBlock
)
);
Power = std::max(Power, PotentialPower);
});
// Inform the handler to update
CurrentHandler->Update(Chunk, TickingSource, Position, CurrentBlock, CurrentMeta, Power);
}
@ -206,27 +228,31 @@ void cIncrementalRedstoneSimulator::Simulate(float a_dt)
void cIncrementalRedstoneSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk)
{
// Can't inspect block, so queue update anyway
if (a_Chunk == nullptr)
// Can't inspect block, ignore:
if ((a_Chunk == nullptr) || (!a_Chunk->IsValid()))
{
m_Data.WakeUp(a_Block);
return;
}
const auto RelPos = cChunkDef::AbsoluteToRelative(a_Block, a_Chunk->GetPos());
const auto CurBlock = a_Chunk->GetBlock(RelPos);
auto & ChunkData = *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData());
const auto Relative = cChunkDef::AbsoluteToRelative(a_Block, a_Chunk->GetPos());
const auto CurrentBlock = a_Chunk->GetBlock(Relative);
// Always update redstone devices
if (IsRedstone(CurBlock))
if (IsRedstone(CurrentBlock))
{
m_Data.WakeUp(a_Block);
if (IsAlwaysTicked(CurrentBlock))
{
ChunkData.AlwaysTickedPositions.emplace(Relative);
}
ChunkData.WakeUp(Relative);
return;
}
// Never update blocks without a handler
if (GetComponentHandler(CurBlock) == nullptr)
if (GetComponentHandler(CurrentBlock) == nullptr)
{
GetChunkData()->ErasePowerData(a_Block);
ChunkData.ErasePowerData(Relative);
return;
}
@ -235,14 +261,14 @@ void cIncrementalRedstoneSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk)
{
for (int y = -1; y < 2; ++y)
{
if (!cChunkDef::IsValidHeight(RelPos.y + y))
if (!cChunkDef::IsValidHeight(Relative.y + y))
{
continue;
}
for (int z = -1; z < 2; ++z)
{
auto CheckPos = RelPos + Vector3i{x, y, z};
auto CheckPos = Relative + Vector3i{x, y, z};
BLOCKTYPE Block;
NIBBLETYPE Meta;
@ -252,7 +278,7 @@ void cIncrementalRedstoneSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk)
IsRedstone(Block)
)
{
m_Data.WakeUp(a_Block);
ChunkData.WakeUp(Relative);
return;
}
}

View File

@ -2,26 +2,29 @@
#pragma once
#include "../RedstoneSimulator.h"
#include "RedstoneHandler.h"
#include "RedstoneSimulatorChunkData.h"
class cIncrementalRedstoneSimulator:
class cIncrementalRedstoneSimulator final :
public cRedstoneSimulator
{
using Super = cRedstoneSimulator;
public:
cIncrementalRedstoneSimulator(cWorld & a_World):
cIncrementalRedstoneSimulator(cWorld & a_World) :
Super(a_World)
{
}
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_NoteBlock.MakeSound();
return false;
}
);
return {};
a_Chunk.DoWithNoteBlockAt(a_Position, [](cNoteEntity & a_NoteBlock)
{
a_NoteBlock.MakeSound();
return false;
});
}
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{
UNUSED(a_World);
UNUSED(a_Chunk);
UNUSED(a_BlockType);
UNUSED(a_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)
{
if (a_Entity.IsPlayer())
{
FoundPlayer = true;
}
if (a_Entity.IsPickup())
{
NumberOfEntities += static_cast<cPickup &>(a_Entity).GetItem().m_ItemCount;
return false;
}
NumberOfEntities++;
Chunk.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + Position, 0.5, 0.5), [&](cEntity & Entity)
{
if (Entity.IsPlayer())
{
FoundPlayer = true;
}
if (Entity.IsPickup())
{
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,107 +26,120 @@ public:
}
}
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{
UNUSED(a_QueryPosition);
UNUSED(a_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)
{
// Skip BlockEntities that don't have slots
auto BlockEntityWithItems = dynamic_cast<cBlockEntityWithItems *>(&a_BlockEntity);
if (BlockEntityWithItems == nullptr)
{
return false;
}
auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(Position, Meta & 0x3);
auto & Contents = BlockEntityWithItems->GetContents();
float Fullness = 0; // Is a floating-point type to allow later calculation to produce a non-truncated value
for (int Slot = 0; Slot != Contents.GetNumSlots(); ++Slot)
{
Fullness += static_cast<float>(Contents.GetSlot(Slot).m_ItemCount) / Contents.GetSlot(Slot).GetMaxStackSize();
}
SignalStrength = (Fullness < 0.001 /* container empty? */) ? 0 : static_cast<UInt8>(1 + (Fullness / Contents.GetNumSlots()) * 14);
return false;
}
);
auto RearPower = SignalStrength;
auto RearType = a_World.GetBlock(RearCoordinate);
auto PotentialSourceHandler = cIncrementalRedstoneSimulator::GetComponentHandler(RearType);
if (PotentialSourceHandler != nullptr)
auto RearChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RearCoordinate);
if ((RearChunk == nullptr) || !RearChunk->IsValid())
{
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;
RearChunk->DoWithBlockEntityAt(RearCoordinate, [&](cBlockEntity & a_BlockEntity)
{
// Skip BlockEntities that don't have slots
auto BlockEntityWithItems = dynamic_cast<cBlockEntityWithItems *>(&a_BlockEntity);
if (BlockEntityWithItems == nullptr)
{
return false;
}
// TODO: handle double chests
auto & Contents = BlockEntityWithItems->GetContents();
float Fullness = 0; // Is a floating-point type to allow later calculation to produce a non-truncated value
for (int Slot = 0; Slot != Contents.GetNumSlots(); ++Slot)
{
Fullness += static_cast<float>(Contents.GetSlot(Slot).m_ItemCount) / Contents.GetSlot(Slot).GetMaxStackSize();
}
SignalStrength = (Fullness < 0.001 /* container empty? */) ? 0 : static_cast<UInt8>(1 + (Fullness / Contents.GetNumSlots()) * 14);
return false;
});
BLOCKTYPE RearType;
NIBBLETYPE RearMeta;
RearChunk->GetBlockTypeMeta(RearCoordinate, RearType, RearMeta);
auto PotentialSourceHandler = cIncrementalRedstoneSimulator::GetComponentHandler(RearType);
if (PotentialSourceHandler == nullptr)
{
return SignalStrength;
}
return std::max(
SignalStrength,
PotentialSourceHandler->GetPowerDeliveredToPosition(
*RearChunk, RearCoordinate, RearType, RearMeta,
cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(a_Chunk, *RearChunk, Position), BlockType
)
);
}
virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
// Note that a_PoweringData here contains the maximum * side * power level, as specified by GetValidSourcePositions
// 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,31 +47,68 @@ protected:
return a_Relatives;
}
inline static cVector3iArray GetRelativeAdjacents()
inline static cIncrementalRedstoneSimulatorChunkData & DataForChunk(cChunk & a_Chunk)
{
return
{
{
{ 1, 0, 0 },
{ -1, 0, 0 },
{ 0, 1, 0 },
{ 0, -1, 0 },
{ 0, 0, 1 },
{ 0, 0, -1 },
}
};
return *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk.GetRedstoneSimulatorData());
}
inline static cVector3iArray GetRelativeLaterals()
template <typename... ArrayTypes>
static void UpdateAdjustedRelatives(cChunk & From, cChunk & To, const Vector3i Position)
{
return
DataForChunk(To).WakeUp(cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(From, To, Position));
}
template <typename ArrayType, typename... ArrayTypes>
static void UpdateAdjustedRelatives(cChunk & From, cChunk & To, const Vector3i Position, const ArrayType & Relative, const ArrayTypes &... Relatives)
{
for (const auto Offset : Relative)
{
{
{ 1, 0, 0 },
{ -1, 0, 0 },
{ 0, 0, 1 },
{ 0, 0, -1 },
}
};
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 },
{ -1, 0, 0 },
{ 0, 1, 0 },
{ 0, -1, 0 },
{ 0, 0, 1 },
{ 0, 0, -1 },
}
};
inline static std::array<Vector3i, 4> RelativeLaterals
{
{
{ 1, 0, 0 },
{ -1, 0, 0 },
{ 0, 0, 1 },
{ 0, 0, -1 },
}
};
private:
static void UpdateAdjustedRelatives(cVector3iArray &, Vector3i)
{
}
static void InvokeForAdjustedRelatives(SourceCallback, Vector3i)
{
}
};

View File

@ -5,7 +5,7 @@
class cRedstoneLampHandler : public cRedstoneHandler
class cRedstoneLampHandler final : public cRedstoneHandler
{
public:
@ -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);
return;
}
cVector3iArray RelativePositions = GetRelativeAdjacents();
RelativePositions.erase(std::remove(RelativePositions.begin(), RelativePositions.end(), GetOffsetAttachedTo(a_Position, a_Meta)), RelativePositions.end());
return GetAdjustedRelatives(a_Position, RelativePositions);
a_Chunk.SetBlock(a_Position, ShouldPowerOn ? E_BLOCK_REDSTONE_TORCH_ON : E_BLOCK_REDSTONE_TORCH_OFF, a_Meta);
Data.m_MechanismDelays.erase(a_Position);
for (const auto Adjacent : RelativeAdjacents)
{
if (Adjacent != GetOffsetAttachedTo(a_Position, a_Meta))
{
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position + Adjacent);
}
}
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{
UNUSED(a_World);
UNUSED(a_Chunk);
UNUSED(a_BlockType);
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,133 +37,170 @@ public:
}
}
cVector3iArray GetTerracingConnectionOffsets(cWorld & a_World, const Vector3i a_Position) const
template <class OffsetCallback>
static bool ForTerracingConnectionOffsets(cChunk & a_Chunk, const Vector3i a_Position, OffsetCallback Callback)
{
auto RelativePositions = GetRelativeLaterals();
const auto YPTerraceBlock = a_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)
{
if (
// 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)
)
// All laterals are counted as terracing, duh
if (Callback(Adjacent))
{
RelativePositions.emplace_back(Adjacent + OffsetYP());
return true;
}
const auto YMTerraceBlock = a_World.GetBlock(a_Position + Adjacent);
if (
// IsYMTerracingBlocked (i.e. check block above lower terracing position, a.k.a. just the plain adjacent)
(!cBlockInfo::IsSolid(YMTerraceBlock) || cBlockInfo::IsTransparent(YMTerraceBlock)) &&
(a_World.GetBlock(a_Position + Adjacent + OffsetYM()) == E_BLOCK_REDSTONE_WIRE)
BLOCKTYPE YPBlock;
// A block above us blocks all YP terracing, so the check is static in the loop
!IsYPTerracingBlocked &&
a_Chunk.UnboundedRelGetBlockType(a_Position + Adjacent + OffsetYP, YPBlock) &&
(YPBlock == E_BLOCK_REDSTONE_WIRE)
)
{
RelativePositions.emplace_back(Adjacent + OffsetYM());
if (Callback(Adjacent + OffsetYP))
{
return true;
}
}
if (
BLOCKTYPE YMTerraceBlock, YMDiagonalBlock;
// IsYMTerracingBlocked (i.e. check block above lower terracing position, a.k.a. just the plain adjacent)
a_Chunk.UnboundedRelGetBlockType(a_Position + Adjacent, YMTerraceBlock) &&
(!cBlockInfo::IsSolid(YMTerraceBlock) || cBlockInfo::IsTransparent(YMTerraceBlock)) &&
a_Chunk.UnboundedRelGetBlockType(a_Position + Adjacent + OffsetYM, YMDiagonalBlock) &&
(YMDiagonalBlock == E_BLOCK_REDSTONE_WIRE)
)
{
if (Callback(Adjacent + OffsetYM))
{
return true;
}
}
}
return RelativePositions;
return false;
}
virtual unsigned char GetPowerDeliveredToPosition(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override
{
if (a_QueryPosition == (a_Position + OffsetYP()))
if (a_QueryPosition == (a_Position + OffsetYP))
{
// Wires do not power things above them
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))
)
{
/*
Okay, we do not directly connect to the wire.
If there are no DC mechanisms at all, the wire powers all laterals. Great, we fall out the loop.
If there is one DC mechanism, the wire "goes straight" along the axis of the wire and mechanism.
The only possible way for us to be powered is for us to be on the opposite end, with the wire pointing towards us.
If there is more than one DC, no non-DCs are powered.
*/
return a_Meta;
}
Vector3i PotentialOffset;
bool FoundOneBorderingMechanism = false;
/*
Okay, we do not directly connect to the wire.
If there are no DC mechanisms at all, the wire powers all laterals. Great, we fall out the loop.
If there is one DC mechanism, the wire "goes straight" along the axis of the wire and mechanism.
The only possible way for us to be powered is for us to be on the opposite end, with the wire pointing towards us.
If there is more than one DC, no non-DCs are powered.
*/
for (const auto & Offset : GetTerracingConnectionOffsets(a_World, a_Position))
Vector3i PotentialOffset;
bool FoundOneBorderingMechanism = false;
if (
ForTerracingConnectionOffsets(a_Chunk, a_Position, [&a_Chunk, a_Position, &FoundOneBorderingMechanism, &PotentialOffset](const Vector3i Offset)
{
BLOCKTYPE Block;
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 };
}
if (FoundOneBorderingMechanism && (a_QueryPosition != (a_Position + PotentialOffset)))
{
// Case 2 fail
return 0;
}
// Case 1
// Case 2 success
return false;
})
)
{
// Case 3
return 0;
}
return (a_Meta != 0) ? --a_Meta : a_Meta;
}
if (FoundOneBorderingMechanism && (a_QueryPosition != (a_Position + PotentialOffset)))
{
// Case 2 fail
return 0;
}
// Case 1
// Case 2 success
virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
{
UNUSED(a_World);
UNUSED(a_Position);
UNUSED(a_BlockType);
return a_Meta;
}
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);
// Notify all terracing positions:
ForTerracingConnectionOffsets(a_Chunk, a_Position, [&a_Chunk, &CurrentlyTicking, a_Position](const Vector3i Offset)
{
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position + Offset);
return false;
});
}
}
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{
UNUSED(a_World);
UNUSED(a_Chunk);
UNUSED(a_BlockType);
UNUSED(a_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))
{
a_World.SetBlockMeta(a_Position, (a_PoweringData.PowerLevel > 0) ? (a_Meta | 0x4) : (a_Meta & ~0x04));
}
return {};
const bool ShouldBeOpen = a_PoweringData.PowerLevel != 0;
const bool IsOpen = (a_Meta & 0x4) == 0x4;
if (ShouldBeOpen != IsOpen)
{
a_Chunk.SetMeta(a_Position, ShouldBeOpen ? (a_Meta | 0x4) : (a_Meta & ~0x04));
}
}
virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override
virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{
UNUSED(a_World);
UNUSED(a_Chunk);
UNUSED(a_BlockType);
UNUSED(a_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;
}
// 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;