diff options
Diffstat (limited to 'src/Simulator/IncrementalRedstoneSimulator')
28 files changed, 632 insertions, 525 deletions
diff --git a/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt b/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt index 1857a115a..3f64d6e4e 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt +++ b/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt @@ -1,16 +1,17 @@ target_sources( ${CMAKE_PROJECT_NAME} PRIVATE + ForEachSourceCallback.cpp IncrementalRedstoneSimulator.cpp CommandBlockHandler.h DoorHandler.h DropSpenserHandler.h + ForEachSourceCallback.h HopperHandler.h IncrementalRedstoneSimulator.h RedstoneHandler.h RedstoneSimulatorChunkData.h - SolidBlockHandler.h RedstoneComparatorHandler.h RedstoneRepeaterHandler.h RedstoneBlockHandler.h diff --git a/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h index 31a34236c..89dc55ecd 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h @@ -10,16 +10,14 @@ class cCommandBlockHandler final : public cRedstoneHandler { -public: - - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_Chunk); UNUSED(a_Position); UNUSED(a_BlockType); - UNUSED(a_Meta); UNUSED(a_QueryPosition); UNUSED(a_QueryBlockType); + UNUSED(IsLinked); return 0; } @@ -41,7 +39,7 @@ public: }); } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_BlockType); diff --git a/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h b/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h index c91886f4e..7011b852b 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h @@ -10,16 +10,16 @@ class cDoorHandler final : public cRedstoneHandler { -public: + // "Doormammu, I've come to bargain" - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_Chunk); UNUSED(a_Position); UNUSED(a_BlockType); - UNUSED(a_Meta); UNUSED(a_QueryPosition); UNUSED(a_QueryBlockType); + UNUSED(IsLinked); return 0; } @@ -27,6 +27,19 @@ public: { // LOGD("Evaluating dori the door (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); + if ((a_Meta & 0x8) == 0x8) + { + // We're treating the bottom half as the source of truth, so ignore updates to the top: + return; + } + + const auto TopPosition = a_Position + OffsetYP; + ForEachSourceCallback Callback(a_Chunk, TopPosition, a_BlockType); + ForValidSourcePositions(a_Chunk, TopPosition, a_BlockType, a_Meta, Callback); + + // Factor in what the upper half is getting: + a_PoweringData = std::max(a_PoweringData, Callback.Power); + cChunkInterface ChunkInterface(a_Chunk.GetWorld()->GetChunkMap()); const bool ShouldBeOpen = a_PoweringData.PowerLevel != 0; const auto AbsolutePosition = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos()); @@ -39,7 +52,7 @@ public: } } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_BlockType); diff --git a/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h b/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h index cee8133d8..d953be8c0 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h @@ -10,8 +10,6 @@ class cDropSpenserHandler final : public cRedstoneHandler { -public: - inline static bool IsActivated(NIBBLETYPE a_Meta) { return (a_Meta & E_META_DROPSPENSER_ACTIVATED) != 0; @@ -29,14 +27,14 @@ public: } } - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_Chunk); UNUSED(a_Position); UNUSED(a_BlockType); - UNUSED(a_Meta); UNUSED(a_QueryPosition); UNUSED(a_QueryBlockType); + UNUSED(IsLinked); return 0; } @@ -63,7 +61,7 @@ public: } } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_BlockType); diff --git a/src/Simulator/IncrementalRedstoneSimulator/ForEachSourceCallback.cpp b/src/Simulator/IncrementalRedstoneSimulator/ForEachSourceCallback.cpp new file mode 100644 index 000000000..3bf0fc371 --- /dev/null +++ b/src/Simulator/IncrementalRedstoneSimulator/ForEachSourceCallback.cpp @@ -0,0 +1,113 @@ + +#include "Globals.h" + +#include "ForEachSourceCallback.h" +#include "IncrementalRedstoneSimulator.h" +#include "../../BlockInfo.h" +#include "../../Chunk.h" + + + + + +ForEachSourceCallback::ForEachSourceCallback(const cChunk & Chunk, const Vector3i Position, const BLOCKTYPE CurrentBlock) : + m_Chunk(Chunk), + m_Position(Position), + m_CurrentBlock(CurrentBlock) +{ +} + + + + + +bool ForEachSourceCallback::ShouldQueryLinkedPosition(const Vector3i Location, const BLOCKTYPE Block) +{ + switch (Block) + { + case E_BLOCK_BLOCK_OF_REDSTONE: + case E_BLOCK_TRAPPED_CHEST: return false; + default: return cBlockInfo::IsSolid(Block); + } +} + + + + + +void ForEachSourceCallback::operator()(Vector3i Location) +{ + if (!cChunk::IsValidHeight(Location.y)) + { + return; + } + + const auto NeighbourChunk = m_Chunk.GetRelNeighborChunkAdjustCoords(Location); + if ((NeighbourChunk == nullptr) || !NeighbourChunk->IsValid()) + { + return; + } + + const auto PotentialSourceBlock = NeighbourChunk->GetBlock(Location); + const auto NeighbourRelativeQueryPosition = cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(m_Chunk, *NeighbourChunk, m_Position); + + if (ShouldQueryLinkedPosition(Location, PotentialSourceBlock)) + { + Power = std::max(Power, QueryLinkedPower(*NeighbourChunk, NeighbourRelativeQueryPosition, m_CurrentBlock, Location)); + } + else + { + Power = std::max(Power, QueryPower(*NeighbourChunk, Location, PotentialSourceBlock, NeighbourRelativeQueryPosition, m_CurrentBlock, false)); + } +} + + + + + +PoweringData ForEachSourceCallback::QueryPower(const cChunk & Chunk, const Vector3i SourcePosition, const BLOCKTYPE SourceBlock, const Vector3i QueryPosition, const BLOCKTYPE QueryBlock, const bool IsLinked) +{ + const auto PotentialSourceHandler = cIncrementalRedstoneSimulator::GetComponentHandler(SourceBlock); + if (PotentialSourceHandler == nullptr) + { + return {}; + } + + return + { + SourceBlock, + PotentialSourceHandler->GetPowerDeliveredToPosition( + Chunk, SourcePosition, SourceBlock, + QueryPosition, QueryBlock, IsLinked + ) + }; +} + + + + + +PoweringData ForEachSourceCallback::QueryLinkedPower(const cChunk & Chunk, const Vector3i QueryPosition, const BLOCKTYPE QueryBlock, const Vector3i SolidBlockPosition) +{ + PoweringData Power; + + for (const auto Offset : cSimulator::GetLinkedOffsets(SolidBlockPosition - QueryPosition)) + { + auto SourcePosition = QueryPosition + Offset; + if (!cChunk::IsValidHeight(SourcePosition.y)) + { + continue; + } + + const auto NeighbourChunk = Chunk.GetRelNeighborChunkAdjustCoords(SourcePosition); + if ((NeighbourChunk == nullptr) || !NeighbourChunk->IsValid()) + { + continue; + } + + const auto NeighbourRelativeSolidBlockPosition = cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(Chunk, *NeighbourChunk, SolidBlockPosition); + Power = std::max(Power, QueryPower(*NeighbourChunk, SourcePosition, NeighbourChunk->GetBlock(SourcePosition), NeighbourRelativeSolidBlockPosition, QueryBlock, true)); + } + + return Power; +} diff --git a/src/Simulator/IncrementalRedstoneSimulator/ForEachSourceCallback.h b/src/Simulator/IncrementalRedstoneSimulator/ForEachSourceCallback.h new file mode 100644 index 000000000..4ab3866d3 --- /dev/null +++ b/src/Simulator/IncrementalRedstoneSimulator/ForEachSourceCallback.h @@ -0,0 +1,32 @@ + +#pragma once + +#include "ForEachSourceCallback.h" +#include "RedstoneSimulatorChunkData.h" + +class ForEachSourceCallback +{ +public: + + ForEachSourceCallback(const cChunk & Chunk, Vector3i Position, BLOCKTYPE CurrentBlock); + + /** Returns whether a potential source position should be treated as linked. */ + bool ShouldQueryLinkedPosition(Vector3i Location, BLOCKTYPE Block); + + /** Callback invoked for each potential source position of the redstone component. */ + void operator()(Vector3i Location); + + /** Asks a redstone component at the source position how much power it will deliver to the querying position. */ + static PoweringData QueryPower(const cChunk & Chunk, Vector3i SourcePosition, BLOCKTYPE SourceBlock, Vector3i QueryPosition, BLOCKTYPE QueryBlock, bool IsLinked); + + /** Asks redstone handlers adjacent to a solid block how much power they will deliver to the querying position, via the solid block. */ + static PoweringData QueryLinkedPower(const cChunk & Chunk, Vector3i QueryPosition, BLOCKTYPE QueryBlock, Vector3i SolidBlockPosition); + + PoweringData Power; + +private: + + const cChunk & m_Chunk; + const Vector3i m_Position; + const BLOCKTYPE m_CurrentBlock; +}; diff --git a/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h b/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h index 2f2e5b129..24685e287 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/HopperHandler.h @@ -10,16 +10,14 @@ class cHopperHandler final : public cRedstoneHandler { -public: - - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_Chunk); UNUSED(a_Position); UNUSED(a_BlockType); - UNUSED(a_Meta); UNUSED(a_QueryPosition); UNUSED(a_QueryBlockType); + UNUSED(IsLinked); return 0; } @@ -40,7 +38,7 @@ public: }); } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_BlockType); diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp index e3177e420..056bfb368 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp @@ -1,9 +1,8 @@ - #include "Globals.h" #include "IncrementalRedstoneSimulator.h" -#include "../../Chunk.h" +#include "ForEachSourceCallback.h" #include "CommandBlockHandler.h" #include "DoorHandler.h" @@ -11,7 +10,6 @@ #include "RedstoneWireHandler.h" #include "RedstoneRepeaterHandler.h" #include "RedstoneToggleHandler.h" -#include "SolidBlockHandler.h" #include "RedstoneLampHandler.h" #include "RedstoneBlockHandler.h" #include "PistonHandler.h" @@ -115,10 +113,6 @@ std::unique_ptr<cRedstoneHandler> cIncrementalRedstoneSimulator::CreateComponent return std::make_unique<cDoorHandler>(); } - if (cBlockInfo::FullyOccupiesVoxel(a_BlockType)) - { - return std::make_unique<cSolidBlockHandler>(); - } return nullptr; } } @@ -182,42 +176,11 @@ void cIncrementalRedstoneSimulator::ProcessWorkItem(cChunk & Chunk, cChunk & Tic 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); - }); + ForEachSourceCallback Callback(Chunk, Position, CurrentBlock); + CurrentHandler->ForValidSourcePositions(Chunk, Position, CurrentBlock, CurrentMeta, Callback); // Inform the handler to update - CurrentHandler->Update(Chunk, TickingSource, Position, CurrentBlock, CurrentMeta, Power); + CurrentHandler->Update(Chunk, TickingSource, Position, CurrentBlock, CurrentMeta, Callback.Power); } @@ -241,6 +204,12 @@ void cIncrementalRedstoneSimulator::AddBlock(cChunk & a_Chunk, Vector3i a_Positi ChunkData.AlwaysTickedPositions.emplace(a_Position); } + // Temporary: in the absence of block state support calculate our own: + if (a_Block == E_BLOCK_REDSTONE_WIRE) + { + static_cast<const cRedstoneWireHandler *>(GetComponentHandler(a_Block))->SetWireState(a_Chunk, a_Position); + } + // Always update redstone devices: ChunkData.WakeUp(a_Position); } @@ -273,5 +242,21 @@ void cIncrementalRedstoneSimulator::WakeUp(cChunk & a_Chunk, Vector3i a_Position // The only thing to do go one block farther than this cross-coord, in the direction of Offset // in order to notify linked-powered positions that there was a change - // TODO: use a_Offset, exclude a_Position and a_Position - a_Offset + for (const auto Offset : cSimulator::GetLinkedOffsets(a_Offset)) + { + auto Relative = a_Position - a_Offset + Offset; + if (!cChunkDef::IsValidHeight(Relative.y)) + { + continue; + } + + auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Relative); + if ((Chunk == nullptr) || !Chunk->IsValid()) + { + continue; + } + + const auto Block = Chunk->GetBlock(Relative); + AddBlock(*Chunk, Relative, Block); + } } diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h index e20880b7a..a940b8920 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h @@ -16,58 +16,11 @@ class cIncrementalRedstoneSimulator final : public: - cIncrementalRedstoneSimulator(cWorld & a_World) : - Super(a_World) - { - } + using Super::cRedstoneSimulator; static const cRedstoneHandler * GetComponentHandler(BLOCKTYPE a_BlockType); - /** 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 */ - inline static bool IsMechanism(BLOCKTYPE Block) - { - switch (Block) - { - case E_BLOCK_ACACIA_DOOR: - case E_BLOCK_ACACIA_FENCE_GATE: - case E_BLOCK_ACTIVATOR_RAIL: - case E_BLOCK_ACTIVE_COMPARATOR: - case E_BLOCK_BIRCH_DOOR: - case E_BLOCK_BIRCH_FENCE_GATE: - case E_BLOCK_COMMAND_BLOCK: - case E_BLOCK_DARK_OAK_DOOR: - case E_BLOCK_DARK_OAK_FENCE_GATE: - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - case E_BLOCK_FENCE_GATE: - case E_BLOCK_HOPPER: - case E_BLOCK_INACTIVE_COMPARATOR: - case E_BLOCK_IRON_DOOR: - case E_BLOCK_IRON_TRAPDOOR: - case E_BLOCK_JUNGLE_DOOR: - case E_BLOCK_JUNGLE_FENCE_GATE: - case E_BLOCK_NOTE_BLOCK: - case E_BLOCK_OBSERVER: - case E_BLOCK_PISTON: - case E_BLOCK_POWERED_RAIL: - case E_BLOCK_REDSTONE_LAMP_OFF: - case E_BLOCK_REDSTONE_LAMP_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_WIRE: - case E_BLOCK_SPRUCE_DOOR: - case E_BLOCK_SPRUCE_FENCE_GATE: - case E_BLOCK_STICKY_PISTON: - case E_BLOCK_TNT: - case E_BLOCK_TRAPDOOR: - case E_BLOCK_WOODEN_DOOR: - { - return true; - } - default: return false; - } - } +private: /** Returns if a redstone device is always ticked due to influence by its environment */ inline static bool IsAlwaysTicked(BLOCKTYPE a_Block) @@ -133,7 +86,6 @@ public: case E_BLOCK_TRAPDOOR: case E_BLOCK_TRAPPED_CHEST: case E_BLOCK_TRIPWIRE_HOOK: - case E_BLOCK_TRIPWIRE: case E_BLOCK_WOODEN_BUTTON: case E_BLOCK_WOODEN_DOOR: case E_BLOCK_WOODEN_PRESSURE_PLATE: @@ -145,8 +97,6 @@ public: } } -private: - virtual void Simulate(float Dt) override {}; virtual void SimulateChunk(std::chrono::milliseconds Dt, int ChunkX, int ChunkZ, cChunk * Chunk) override; diff --git a/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h index 7d3ec2f30..e610e6bdf 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h @@ -10,16 +10,14 @@ class cNoteBlockHandler: public cRedstoneHandler { -public: - - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_Chunk); UNUSED(a_Position); UNUSED(a_BlockType); - UNUSED(a_Meta); UNUSED(a_QueryPosition); UNUSED(a_QueryBlockType); + UNUSED(IsLinked); return 0; } @@ -41,7 +39,7 @@ public: }); } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_BlockType); diff --git a/src/Simulator/IncrementalRedstoneSimulator/ObserverHandler.h b/src/Simulator/IncrementalRedstoneSimulator/ObserverHandler.h index 211e3c64a..c0866824b 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/ObserverHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/ObserverHandler.h @@ -10,8 +10,6 @@ class cObserverHandler final : public cRedstoneHandler { -public: - inline static bool IsOn(NIBBLETYPE a_Meta) { return (a_Meta & 0x8) == 0x8; @@ -34,14 +32,10 @@ public: return (Previous.PoweringBlock != Observed.PoweringBlock) || (Previous.PowerLevel != Observed.PowerLevel); } - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { - if (IsOn(a_Meta) && (a_QueryPosition == (a_Position + cBlockObserverHandler::GetSignalOutputOffset(a_Meta)))) - { - return 15; - } - - return 0; + const auto Meta = a_Chunk.GetMeta(a_Position); + return (IsOn(Meta) && (a_QueryPosition == (a_Position + cBlockObserverHandler::GetSignalOutputOffset(Meta)))) ? 15 : 0; } virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override @@ -87,10 +81,10 @@ public: a_Chunk.SetMeta(a_Position, a_Meta & ~0x8); } - UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position + cBlockObserverHandler::GetSignalOutputOffset(a_Meta)); + UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position, cBlockObserverHandler::GetSignalOutputOffset(a_Meta)); } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_Position); diff --git a/src/Simulator/IncrementalRedstoneSimulator/PistonHandler.h b/src/Simulator/IncrementalRedstoneSimulator/PistonHandler.h index b3860a778..14932b95b 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/PistonHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/PistonHandler.h @@ -10,16 +10,14 @@ class cPistonHandler final: public cRedstoneHandler { -public: - - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_Chunk); UNUSED(a_Position); UNUSED(a_BlockType); - UNUSED(a_Meta); UNUSED(a_QueryPosition); UNUSED(a_QueryBlockType); + UNUSED(IsLinked); return 0; } @@ -48,7 +46,7 @@ public: // However, this delay is already present: as a side effect of the implementation of piston animation in Blocks\BlockPiston.cpp } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_BlockType); diff --git a/src/Simulator/IncrementalRedstoneSimulator/PoweredRailHandler.h b/src/Simulator/IncrementalRedstoneSimulator/PoweredRailHandler.h index 9e58e09ad..6f8dbc196 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/PoweredRailHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/PoweredRailHandler.h @@ -9,8 +9,6 @@ class cPoweredRailHandler final : public cRedstoneHandler { -public: - static Vector3i GetPoweredRailAdjacentXZCoordinateOffset(NIBBLETYPE a_Meta) // Not in cBlockRailHandler since specific to powered rails { switch (a_Meta & 0x7) @@ -29,11 +27,12 @@ public: } } - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_QueryBlockType); - auto Offset = GetPoweredRailAdjacentXZCoordinateOffset(a_Meta); + const auto Meta = a_Chunk.GetMeta(a_Position); + const auto Offset = GetPoweredRailAdjacentXZCoordinateOffset(Meta); if (((Offset + a_Position) == a_QueryPosition) || ((-Offset + a_Position) == a_QueryPosition)) { auto Power = DataForChunk(a_Chunk).GetCachedPowerData(a_Position).PowerLevel; @@ -66,8 +65,8 @@ public: { a_Chunk.SetMeta(a_Position, (a_PoweringData.PowerLevel == 0) ? (a_Meta & 0x07) : (a_Meta | 0x08)); - UpdateAdjustedRelative(a_Chunk, CurrentlyTickingChunk, a_Position + Offset); - UpdateAdjustedRelative(a_Chunk, CurrentlyTickingChunk, a_Position + -Offset); + UpdateAdjustedRelative(a_Chunk, CurrentlyTickingChunk, a_Position, Offset); + UpdateAdjustedRelative(a_Chunk, CurrentlyTickingChunk, a_Position, -Offset); } return; @@ -79,7 +78,7 @@ public: } } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_Meta); diff --git a/src/Simulator/IncrementalRedstoneSimulator/PressurePlateHandler.h b/src/Simulator/IncrementalRedstoneSimulator/PressurePlateHandler.h index f6969e15a..979d1ef96 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/PressurePlateHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/PressurePlateHandler.h @@ -11,19 +11,18 @@ class cPressurePlateHandler final : public cRedstoneHandler { -public: - - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_BlockType); - UNUSED(a_Meta); UNUSED(a_QueryPosition); UNUSED(a_QueryBlockType); - return DataForChunk(a_Chunk).GetCachedPowerData(a_Position).PowerLevel; + // Plates only link power blocks below + // Retrieve and return the cached power calculated by Update for performance: + return (IsLinked && (a_QueryPosition != (a_Position + OffsetYM))) ? 0 : DataForChunk(a_Chunk).GetCachedPowerData(a_Position).PowerLevel; } - static unsigned char GetPowerLevel(cChunk & Chunk, const Vector3i Position, const BLOCKTYPE BlockType) + static unsigned char GetPowerLevel(const cChunk & Chunk, const Vector3i Position, const BLOCKTYPE BlockType) { unsigned NumberOfEntities = 0; bool FoundPlayer = false; @@ -70,12 +69,6 @@ public: } } - static void UpdatePlate(cChunk & Chunk, cChunk & CurrentlyTicking, Vector3i Position) - { - UpdateAdjustedRelative(Chunk, CurrentlyTicking, Position + OffsetYM); - UpdateAdjustedRelatives(Chunk, CurrentlyTicking, Position, RelativeLaterals); - } - virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override { // LOGD("Evaluating clicky the pressure plate (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); @@ -107,7 +100,9 @@ public: // Immediately depress plate a_Chunk.SetMeta(a_Position, E_META_PRESSURE_PLATE_DEPRESSED); - return UpdatePlate(a_Chunk, CurrentlyTicking, a_Position); + + UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents); + return; } // Not a resting state @@ -137,7 +132,7 @@ public: { // Yes. Update power ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power)); - return UpdatePlate(a_Chunk, CurrentlyTicking, a_Position); + UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents); } return; @@ -159,7 +154,7 @@ public: { // Yes. Update power ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power)); - return UpdatePlate(a_Chunk, CurrentlyTicking, a_Position); + UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents); } // Yes, but player's still on the plate, do nothing @@ -173,10 +168,10 @@ public: ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power)); a_Chunk.SetMeta(a_Position, E_META_PRESSURE_PLATE_RAISED); - return UpdatePlate(a_Chunk, CurrentlyTicking, a_Position); + UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents); } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_Position); diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneBlockHandler.h index 150723944..51e2162d1 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneBlockHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneBlockHandler.h @@ -11,14 +11,14 @@ class cRedstoneBlockHandler final : public cRedstoneHandler { public: - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_Chunk); UNUSED(a_Position); UNUSED(a_BlockType); - UNUSED(a_Meta); UNUSED(a_QueryPosition); - return cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType) ? 15 : 0; + UNUSED(IsLinked); + return IsLinked ? 0 : 15; } virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override @@ -26,7 +26,7 @@ public: // LOGD("Evaluating crimson the redstone block (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_Position); diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneComparatorHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneComparatorHandler.h index 4ccb6838e..bf781eb7a 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneComparatorHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneComparatorHandler.h @@ -10,8 +10,6 @@ class cRedstoneComparatorHandler : public cRedstoneHandler { -public: - static unsigned char GetFrontPowerLevel(NIBBLETYPE a_Meta, unsigned char a_HighestSidePowerLevel, unsigned char a_HighestRearPowerLevel) { if (cBlockComparatorHandler::IsInSubtractionMode(a_Meta)) @@ -26,13 +24,14 @@ public: } } - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_QueryPosition); UNUSED(a_QueryBlockType); + const auto Meta = a_Chunk.GetMeta(a_Position); return ( - (cBlockComparatorHandler::GetFrontCoordinate(a_Position, a_Meta & 0x3) == a_QueryPosition) ? + (cBlockComparatorHandler::GetFrontCoordinate(a_Position, Meta & 0x3) == a_QueryPosition) ? DataForChunk(a_Chunk).GetCachedPowerData(a_Position).PowerLevel : 0 ); } @@ -71,11 +70,8 @@ public: return false; }); - BLOCKTYPE RearType; - NIBBLETYPE RearMeta; - RearChunk->GetBlockTypeMeta(RearCoordinate, RearType, RearMeta); - - auto PotentialSourceHandler = cIncrementalRedstoneSimulator::GetComponentHandler(RearType); + const auto RearType = RearChunk->GetBlock(RearCoordinate); + const auto PotentialSourceHandler = cIncrementalRedstoneSimulator::GetComponentHandler(RearType); if (PotentialSourceHandler == nullptr) { return SignalStrength; @@ -84,8 +80,8 @@ public: return std::max( SignalStrength, PotentialSourceHandler->GetPowerDeliveredToPosition( - *RearChunk, RearCoordinate, RearType, RearMeta, - cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(a_Chunk, *RearChunk, Position), BlockType + *RearChunk, RearCoordinate, RearType, + cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(a_Chunk, *RearChunk, Position), BlockType, false ) ); } @@ -110,31 +106,33 @@ public: { Data.m_MechanismDelays[a_Position] = std::make_pair(1, bool()); } + + return; } - else + + int DelayTicks; + std::tie(DelayTicks, std::ignore) = *DelayInfo; + + if (DelayTicks != 0) { - int DelayTicks; - std::tie(DelayTicks, std::ignore) = *DelayInfo; + return; + } - if (DelayTicks == 0) - { - 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); + 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); - // Don't care about the previous power level so return value ignored - Data.ExchangeUpdateOncePowerData(a_Position, PoweringData(a_PoweringData.PoweringBlock, FrontPower)); + // 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); + a_Chunk.SetMeta(a_Position, NewMeta); + Data.m_MechanismDelays.erase(a_Position); - // Assume that an update (to front power) is needed: - UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, cBlockComparatorHandler::GetFrontCoordinate(a_Position, a_Meta & 0x3)); - } - } + // Assume that an update (to front power) is needed: + UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position, cBlockComparatorHandler::GetFrontCoordinate(a_Position, a_Meta & 0x3) - a_Position); } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_BlockType); diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.h index 79c410265..9b131ece2 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.h @@ -2,6 +2,7 @@ #pragma once #include "../../Chunk.h" +#include "ForEachSourceCallback.h" #include "RedstoneSimulatorChunkData.h" @@ -15,71 +16,55 @@ public: cRedstoneHandler() = default; DISALLOW_COPY_AND_ASSIGN(cRedstoneHandler); - using SourceCallback = cFunctionRef<void(Vector3i)>; + using SourceCallback = ForEachSourceCallback &; - 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 unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) 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; + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const = 0; // Force a virtual destructor virtual ~cRedstoneHandler() {} protected: - template <class Container> - static Container StaticAppend(const Container & a_Lhs, const Container & a_Rhs) - { - Container ToReturn = a_Lhs; - std::copy(a_Rhs.begin(), a_Rhs.end(), std::back_inserter(ToReturn)); - return ToReturn; - } - - inline static Vector3i OffsetYP{ 0, 1, 0 }; - - inline static Vector3i OffsetYM{ 0, -1, 0 }; - - static cVector3iArray GetAdjustedRelatives(Vector3i a_Position, cVector3iArray a_Relatives) - { - for (auto & Entry : a_Relatives) - { - Entry += a_Position; - } - return a_Relatives; - } - - inline static cIncrementalRedstoneSimulatorChunkData & DataForChunk(cChunk & a_Chunk) + inline static auto & DataForChunk(const cChunk & a_Chunk) { return *static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk.GetRedstoneSimulatorData()); } template <typename... ArrayTypes> - static void UpdateAdjustedRelative(cChunk & From, cChunk & To, const Vector3i Position) + static void UpdateAdjustedRelative(const cChunk & From, const cChunk & To, const Vector3i Position, const Vector3i Offset) { - DataForChunk(To).WakeUp(cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(From, To, Position)); + DataForChunk(To).WakeUp(cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(From, To, Position + Offset)); + + for (const auto LinkedOffset : cSimulator::GetLinkedOffsets(Offset)) + { + DataForChunk(To).WakeUp(cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(From, To, Position + LinkedOffset)); + } } - template <typename ArrayType, typename... ArrayTypes> - static void UpdateAdjustedRelatives(cChunk & From, cChunk & To, const Vector3i Position, const ArrayType & Relative, const ArrayTypes &... Relatives) + template <typename ArrayType> + static void UpdateAdjustedRelatives(const cChunk & From, const cChunk & To, const Vector3i Position, const ArrayType & Relative) { for (const auto Offset : Relative) { - DataForChunk(To).GetActiveBlocks().push(cIncrementalRedstoneSimulatorChunkData::RebaseRelativePosition(From, To, Position + Offset)); + UpdateAdjustedRelative(From, To, Position, Offset); } - - UpdateAdjustedRelatives(From, To, Position, Relatives...); } - template <typename ArrayType, typename... ArrayTypes> - static void InvokeForAdjustedRelatives(SourceCallback Callback, const Vector3i Position, const ArrayType & Relative, const ArrayTypes &... Relatives) + template <typename ArrayType> + static void InvokeForAdjustedRelatives(SourceCallback Callback, const Vector3i Position, const ArrayType & Relative) { for (const auto Offset : Relative) { Callback(Position + Offset); } - - InvokeForAdjustedRelatives(Callback, Position, Relatives...); } + inline static Vector3i OffsetYP{ 0, 1, 0 }; + + inline static Vector3i OffsetYM{ 0, -1, 0 }; + inline static std::array<Vector3i, 6> RelativeAdjacents { { @@ -101,14 +86,4 @@ protected: { 0, 0, -1 }, } }; - -private: - - static void UpdateAdjustedRelatives(cChunk &, cChunk &, const Vector3i) - { - } - - static void InvokeForAdjustedRelatives(SourceCallback, const Vector3i) - { - } }; diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneLampHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneLampHandler.h index 85aa1d743..eb47e2367 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneLampHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneLampHandler.h @@ -7,14 +7,12 @@ class cRedstoneLampHandler final : public cRedstoneHandler { -public: - inline static bool IsOn(BLOCKTYPE a_BlockType) { return (a_BlockType == E_BLOCK_REDSTONE_LAMP_ON); } - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { return 0; } @@ -39,7 +37,7 @@ public: } } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_Meta); diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h index 711d1762d..ce42e0163 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h @@ -8,16 +8,23 @@ -class cRedstoneRepeaterHandler: - public cRedstoneHandler +class cRedstoneRepeaterHandler final : public cRedstoneHandler { - using Super = cRedstoneHandler; + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override + { + if (!IsOn(a_BlockType)) + { + return 0; + } -public: + const auto FrontOffset = cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Chunk.GetMeta(a_Position)); + const auto FrontPosition = a_Position + FrontOffset; + if (a_QueryPosition == FrontPosition) + { + return 15; + } - 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))) && IsOn(a_BlockType)) ? 15 : 0; + return 0; } virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override @@ -45,37 +52,36 @@ public: { Data.m_MechanismDelays[a_Position] = std::make_pair((((a_Meta & 0xC) >> 0x2) + 1), ShouldBeOn); } + + return; } - else + + int DelayTicks; + bool ShouldPowerOn; + std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo; + + if (DelayTicks != 0) { - int DelayTicks; - bool ShouldPowerOn; - std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo; + return; + } - if (DelayTicks == 0) - { - 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); + 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); + // 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); - UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position + cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta)); - UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position + cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta), RelativeAdjacents); - } - } + UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position, cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta)); } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { Callback(cBlockRedstoneRepeaterHandler::GetRearCoordinateOffset(a_Meta) + a_Position); } -private: - inline static bool IsOn(BLOCKTYPE a_Block) { return (a_Block == E_BLOCK_REDSTONE_REPEATER_ON); diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneSimulatorChunkData.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneSimulatorChunkData.h index eb5dfc92d..f8e7eb466 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneSimulatorChunkData.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneSimulatorChunkData.h @@ -4,6 +4,7 @@ #include <stack> #include "../RedstoneSimulator.h" +#include "../../Chunk.h" @@ -53,7 +54,7 @@ public: -class cIncrementalRedstoneSimulatorChunkData : public cRedstoneSimulatorChunkData +class cIncrementalRedstoneSimulatorChunkData final : public cRedstoneSimulatorChunkData { public: @@ -90,6 +91,7 @@ public: m_CachedPowerLevels.erase(Position); m_MechanismDelays.erase(Position); AlwaysTickedPositions.erase(Position); + WireStates.erase(Position); } PoweringData ExchangeUpdateOncePowerData(const Vector3i & a_Position, PoweringData a_PoweringData) @@ -105,7 +107,7 @@ public: } /** Adjust From-relative coordinates into To-relative coordinates. */ - inline static Vector3i RebaseRelativePosition(cChunk & From, cChunk & To, const Vector3i Position) + inline static Vector3i RebaseRelativePosition(const cChunk & From, const cChunk & To, const Vector3i Position) { return { @@ -115,9 +117,12 @@ public: }; } + /** Temporary, should be chunk data: wire block store, to avoid recomputing states every time. */ + std::unordered_map<Vector3i, short, VectorHasher<int>> WireStates; + std::unordered_set<Vector3i, VectorHasher<int>> AlwaysTickedPositions; - /** Structure storing position of mechanism + it's delay ticks (countdown) & if to power on */ + /** Structure storing position of mechanism + it's delay ticks (countdown) & if to power on. */ std::unordered_map<Vector3i, std::pair<int, bool>, VectorHasher<int>> m_MechanismDelays; private: diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneToggleHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneToggleHandler.h index bf9c639b1..b66ce47fd 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneToggleHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneToggleHandler.h @@ -11,9 +11,7 @@ class cRedstoneToggleHandler final : public cRedstoneHandler { -public: - - inline static Vector3i GetPositionAttachedTo(Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) + inline static Vector3i GetOffsetAttachedTo(Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) { switch (a_BlockType) { @@ -22,13 +20,13 @@ public: switch (a_Meta & 0x7) { case 0x0: - case 0x7: return { a_Position + Vector3i(0, 1, 0) }; - case 0x1: return { a_Position + Vector3i(-1, 0, 0) }; - case 0x2: return { a_Position + Vector3i(1, 0, 0) }; - case 0x3: return { a_Position + Vector3i(0, 0, -1) }; - case 0x4: return { a_Position + Vector3i(0, 0, 1) }; + case 0x7: return { 0, 1, 0 }; + case 0x1: return { -1, 0, 0 }; + case 0x2: return { 1, 0, 0 }; + case 0x3: return { 0, 0, -1 }; + case 0x4: return { 0, 0, 1 }; case 0x5: - case 0x6: return { a_Position + Vector3i(0, -1, 0) }; + case 0x6: return { 0, -1, 0 }; default: { ASSERT(!"Unhandled lever metadata!"); @@ -41,12 +39,12 @@ public: { switch (a_Meta & 0x7) { - case 0x0: return { a_Position + Vector3i(0, 1, 0) }; - case 0x1: return { a_Position + Vector3i(-1, 0, 0) }; - case 0x2: return { a_Position + Vector3i(1, 0, 0) }; - case 0x3: return { a_Position + Vector3i(0, 0, -1) }; - case 0x4: return { a_Position + Vector3i(0, 0, 1) }; - case 0x5: return { a_Position + Vector3i(0, -1, 0) }; + case 0x0: return { 0, 1, 0 }; + case 0x1: return { -1, 0, 0 }; + case 0x2: return { 1, 0, 0 }; + case 0x3: return { 0, 0, -1 }; + case 0x4: return { 0, 0, 1 }; + case 0x5: return { 0, -1, 0 }; default: { ASSERT(!"Unhandled button metadata!"); @@ -62,14 +60,19 @@ public: } } - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_QueryBlockType); - if ((GetPositionAttachedTo(a_Position, a_BlockType, a_Meta) == a_QueryPosition) || cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType)) + + const auto Meta = a_Chunk.GetMeta(a_Position); + const auto QueryOffset = a_QueryPosition - a_Position; + + if (IsLinked && (QueryOffset != GetOffsetAttachedTo(a_Position, a_BlockType, Meta))) { - return GetPowerLevel(a_BlockType, a_Meta); + return 0; } - return 0; + + return GetPowerLevel(a_BlockType, Meta); } static unsigned char GetPowerLevel(BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) @@ -92,7 +95,7 @@ public: // LOGD("Evaluating templatio<> the lever/button (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_Position); diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneTorchHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneTorchHandler.h index 65cf32204..77c889aa9 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneTorchHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneTorchHandler.h @@ -9,14 +9,12 @@ class cRedstoneTorchHandler final : public cRedstoneHandler { -public: - inline static bool IsOn(BLOCKTYPE a_Block) { return (a_Block == E_BLOCK_REDSTONE_TORCH_ON); } - inline static Vector3i GetOffsetAttachedTo(Vector3i a_Position, NIBBLETYPE a_Meta) + inline static Vector3i GetOffsetAttachedTo(const NIBBLETYPE a_Meta) { switch (a_Meta) { @@ -33,17 +31,20 @@ public: } } - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { + const auto QueryOffset = a_QueryPosition - a_Position; + 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)))) + !IsOn(a_BlockType) || + (QueryOffset == GetOffsetAttachedTo(a_Chunk.GetMeta(a_Position))) || + (IsLinked && (QueryOffset != OffsetYP)) ) { - return 15; + return 0; } - return 0; + + return 15; } virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override @@ -55,40 +56,42 @@ public: if (DelayInfo == nullptr) { - bool ShouldBeOn = (a_PoweringData.PowerLevel == 0); + const bool ShouldBeOn = (a_PoweringData.PowerLevel == 0); if (ShouldBeOn != IsOn(a_BlockType)) { Data.m_MechanismDelays[a_Position] = std::make_pair(1, ShouldBeOn); } + + return; } - else - { - int DelayTicks; - bool ShouldPowerOn; - std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo; - if (DelayTicks != 0) - { - return; - } + int DelayTicks; + bool ShouldPowerOn; + std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo; - a_Chunk.SetBlock(a_Position, ShouldPowerOn ? E_BLOCK_REDSTONE_TORCH_ON : E_BLOCK_REDSTONE_TORCH_OFF, a_Meta); - Data.m_MechanismDelays.erase(a_Position); + if (DelayTicks != 0) + { + return; + } - for (const auto Adjacent : RelativeAdjacents) + a_Chunk.FastSetBlock(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) + { + // Update all adjacents (including linked power positions) + // apart from our attachment, which can't possibly need an update: + if (Adjacent != GetOffsetAttachedTo(a_Meta)) { - if (Adjacent != GetOffsetAttachedTo(a_Position, a_Meta)) - { - UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position + Adjacent); - } + UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position, Adjacent); } } } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_BlockType); - Callback(a_Position + GetOffsetAttachedTo(a_Position, a_Meta)); + Callback(a_Position + GetOffsetAttachedTo(a_Meta)); } }; diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h index 5bf4afcd3..2772441bd 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h @@ -2,6 +2,7 @@ #pragma once #include "RedstoneHandler.h" +#include "../../Registries/Blocks.h" @@ -9,198 +10,318 @@ class cRedstoneWireHandler final : public cRedstoneHandler { -public: + /** A unified representation of wire direction. */ + enum class TemporaryDirection + { + Up, + Side + }; - inline static bool IsDirectlyConnectingMechanism(BLOCKTYPE a_Block, NIBBLETYPE a_BlockMeta, const Vector3i a_Offset) + /** Adjusts a given wire block so that the direction represented by Offset has state Direction. */ + inline static void SetDirectionState(const Vector3i Offset, short & Block, TemporaryDirection Direction) { - switch (a_Block) + Block = DoWithDirectionState(Offset, Block, [Direction](auto, auto & Front, auto) { - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: + using FrontState = std::remove_reference_t<decltype(Front)>; + switch (Direction) { - a_BlockMeta &= E_META_REDSTONE_REPEATER_FACING_MASK; - if ((a_BlockMeta == E_META_REDSTONE_REPEATER_FACING_XP) || (a_BlockMeta == E_META_REDSTONE_REPEATER_FACING_XM)) + case TemporaryDirection::Up: { - // Wire connects to repeater if repeater is aligned along X - // and wire is in front or behind it (#4639) - return a_Offset.x != 0; + Front = FrontState::Up; + return; + } + case TemporaryDirection::Side: + { + Front = FrontState::Side; + return; } - - return a_Offset.z != 0; } - case E_BLOCK_ACTIVE_COMPARATOR: - case E_BLOCK_INACTIVE_COMPARATOR: - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_REDSTONE_WIRE: return true; - default: return false; - } + }); } + /** Invokes Callback with the wire's left, front, and right direction state corresponding to Offset. + Returns a new block constructed from the directions that the callback may have modified. */ template <class OffsetCallback> - static bool ForTerracingConnectionOffsets(cChunk & a_Chunk, const Vector3i a_Position, OffsetCallback Callback) + inline static short DoWithDirectionState(const Vector3i Offset, short Block, OffsetCallback Callback) + { + auto North = Block::RedstoneWire::North(Block); + auto South = Block::RedstoneWire::South(Block); + auto West = Block::RedstoneWire::West(Block); + auto East = Block::RedstoneWire::East(Block); + + if (Offset.x == -1) + { + Callback(South, West, North); + } + else if (Offset.x == 1) + { + Callback(North, East, South); + } + + if (Offset.z == -1) + { + Callback(West, North, East); + } + else if (Offset.z == 1) + { + Callback(East, South, West); + } + + return Block::RedstoneWire::RedstoneWire(East, North, 0, South, West); + } + +public: + + /** Temporary. Discovers a wire's connection state, including terracing, storing the block inside redstone chunk data. + TODO: once the server supports block states this should go in the block handler, with data saved in the world. */ + void SetWireState(const cChunk & Chunk, const Vector3i Position) const { - const auto YPTerraceBlock = a_Chunk.GetBlock(a_Position + OffsetYP); + auto Block = Block::RedstoneWire::RedstoneWire(); + const auto YPTerraceBlock = Chunk.GetBlock(Position + OffsetYP); const bool IsYPTerracingBlocked = cBlockInfo::IsSolid(YPTerraceBlock) && !cBlockInfo::IsTransparent(YPTerraceBlock); - for (const auto Adjacent : RelativeLaterals) + // Loop through laterals, discovering terracing connections: + for (const auto Offset : RelativeLaterals) { - // All laterals are counted as terracing, duh - if (Callback(Adjacent)) + auto Adjacent = Position + Offset; + auto NeighbourChunk = Chunk.GetRelNeighborChunkAdjustCoords(Adjacent); + + if ((NeighbourChunk == nullptr) || !NeighbourChunk->IsValid()) { - return true; + continue; } - if ( - BLOCKTYPE YPBlock; + BLOCKTYPE LateralBlock; + NIBBLETYPE LateralMeta; + NeighbourChunk->GetBlockTypeMeta(Adjacent, LateralBlock, LateralMeta); - // 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) - ) + if (IsDirectlyConnectingMechanism(LateralBlock, LateralMeta, Offset)) { - if (Callback(Adjacent + OffsetYP)) + // Any direct connections on a lateral means the wire has side connection in that direction: + SetDirectionState(Offset, Block, TemporaryDirection::Side); + + // Temporary: this case will eventually be handled when wires are placed, with the state saved as blocks + // When a neighbour wire was loaded into its chunk, its neighbour chunks may not have loaded yet + // This function is called during chunk load (through AddBlock). Attempt to tell it its new state: + if ((NeighbourChunk != &Chunk) && (LateralBlock == E_BLOCK_REDSTONE_WIRE)) { - return true; + auto & NeighbourBlock = DataForChunk(*NeighbourChunk).WireStates.find(Adjacent)->second; + SetDirectionState(-Offset, NeighbourBlock, TemporaryDirection::Side); } + + continue; } 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) + !IsYPTerracingBlocked && // A block above us blocks all YP terracing, so the check is static in the loop + (Adjacent.y < (cChunkDef::Height - 1)) && + (NeighbourChunk->GetBlock(Adjacent + OffsetYP) == E_BLOCK_REDSTONE_WIRE) // Only terrace YP with another wire ) { - if (Callback(Adjacent + OffsetYM)) + SetDirectionState(Offset, Block, TemporaryDirection::Up); + + if (NeighbourChunk != &Chunk) { - return true; + auto & NeighbourBlock = DataForChunk(*NeighbourChunk).WireStates.find(Adjacent + OffsetYP)->second; + SetDirectionState(-Offset, NeighbourBlock, TemporaryDirection::Side); } + + continue; } - } - return false; - } + if ( + // IsYMTerracingBlocked (i.e. check block above lower terracing position, a.k.a. just the plain adjacent) + (!cBlockInfo::IsSolid(LateralBlock) || cBlockInfo::IsTransparent(LateralBlock)) && + (NeighbourChunk->GetBlock(Adjacent + OffsetYM) == E_BLOCK_REDSTONE_WIRE) // Only terrace YM with another wire + ) + { + SetDirectionState(Offset, Block, TemporaryDirection::Side); - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override - { - if (a_QueryPosition == (a_Position + OffsetYP)) - { - // Wires do not power things above them - return 0; + if (NeighbourChunk != &Chunk) + { + auto & NeighbourBlock = DataForChunk(*NeighbourChunk).WireStates.find(Adjacent + OffsetYM)->second; + SetDirectionState(-Offset, NeighbourBlock, TemporaryDirection::Up); + } + } } - if (a_QueryBlockType == E_BLOCK_REDSTONE_WIRE) + auto & States = DataForChunk(Chunk).WireStates; + const auto FindResult = States.find(Position); + if (FindResult != States.end()) { - // For mechanisms, wire of power one will still power them - // But for wire-to-wire connections, power level decreases by 1 - return (a_Meta != 0) ? --a_Meta : a_Meta; - } + if (Block != FindResult->second) + { + FindResult->second = Block; - // Wires always deliver power to the block underneath, and any directly connecting mechanisms - if ( - NIBBLETYPE QueryMeta; + // TODO: when state is stored as the block, the block handler updating via SetBlock will do this automatically + // When a wire changes connection state, it needs to update its neighbours: + Chunk.GetWorld()->WakeUpSimulators(cChunkDef::RelativeToAbsolute(Position, Chunk.GetPos())); + } - (a_QueryPosition == (a_Position + OffsetYM)) || - (a_Chunk.UnboundedRelGetBlockMeta(a_QueryPosition, QueryMeta) && IsDirectlyConnectingMechanism(a_QueryBlockType, QueryMeta, a_QueryPosition - a_Position)) - ) - { - return a_Meta; + return; } - /* - 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. - */ + DataForChunk(Chunk).WireStates[Position] = Block; + } - Vector3i PotentialOffset; - bool FoundOneBorderingMechanism = false; +private: - if ( - ForTerracingConnectionOffsets(a_Chunk, a_Position, [&a_Chunk, a_Position, &FoundOneBorderingMechanism, &PotentialOffset](const Vector3i Offset) + inline static bool IsDirectlyConnectingMechanism(BLOCKTYPE a_Block, NIBBLETYPE a_BlockMeta, const Vector3i a_Offset) + { + switch (a_Block) + { + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_REDSTONE_REPEATER_OFF: { - BLOCKTYPE Block; - NIBBLETYPE Meta; - - if ( - !a_Chunk.UnboundedRelGetBlock(Offset + a_Position, Block, Meta) || - !IsDirectlyConnectingMechanism(Block, Meta, Offset) - ) + a_BlockMeta &= E_META_REDSTONE_REPEATER_FACING_MASK; + if ((a_BlockMeta == E_META_REDSTONE_REPEATER_FACING_XP) || (a_BlockMeta == E_META_REDSTONE_REPEATER_FACING_XM)) { - return false; + // Wire connects to repeater if repeater is aligned along X + // and wire is in front or behind it (#4639) + return a_Offset.x != 0; } - if (FoundOneBorderingMechanism) - { - // Case 3 - return true; - } + return a_Offset.z != 0; + } + case E_BLOCK_ACTIVE_COMPARATOR: + case E_BLOCK_INACTIVE_COMPARATOR: + case E_BLOCK_BLOCK_OF_REDSTONE: + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_REDSTONE_WIRE: return true; + default: return false; + } + } - // Potential case 2 - FoundOneBorderingMechanism = true; - PotentialOffset = { -Offset.x, 0, -Offset.z }; + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override + { + // Starts off as the wire's meta value, modified appropriately and returned + auto Power = a_Chunk.GetMeta(a_Position); + const auto QueryOffset = a_QueryPosition - a_Position; - return false; - }) + if ( + (QueryOffset == OffsetYP) || // Wires do not power things above them + (IsLinked && (a_QueryBlockType == E_BLOCK_REDSTONE_WIRE)) // Nor do they link power other wires ) { - // Case 3 return 0; } - if (FoundOneBorderingMechanism && (a_QueryPosition != (a_Position + PotentialOffset))) + if (QueryOffset == OffsetYM) { - // Case 2 fail - return 0; + // Wires always deliver power to the block underneath + return Power; } - // Case 1 - // Case 2 success + const auto & Data = DataForChunk(a_Chunk); + const auto Block = Data.WireStates.find(a_Position)->second; + + DoWithDirectionState(QueryOffset, Block, [a_QueryBlockType, &Power](const auto Left, const auto Front, const auto Right) + { + using LeftState = std::remove_reference_t<decltype(Left)>; + using FrontState = std::remove_reference_t<decltype(Front)>; + using RightState = std::remove_reference_t<decltype(Right)>; + + // Wires always deliver power to any directly connecting mechanisms: + if (Front != FrontState::None) + { + if ((a_QueryBlockType == E_BLOCK_REDSTONE_WIRE) && (Power != 0)) + { + // For mechanisms, wire of power one will still power them + // But for wire-to-wire connections, power level decreases by 1: + Power--; + } + + return; + } + + /* + Okay, we do not directly connect to the wire. + 1. If there are no DC mechanisms at all, the wire powers all laterals. Great, left and right are both None. + 2. 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. + Check that left and right are both None. + 3. If there is more than one DC, no non-DCs are powered. Left, right, cannot both be None. + */ + if ((Left == LeftState::None) && (Right == RightState::None)) + { + // Case 1 + // Case 2 + return; + } - return a_Meta; + // Case 3 + Power = 0; + }); + + return Power; } virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override { // LOGD("Evaluating dusty the wire (%d %d %d) %i", a_Position.x, a_Position.y, a_Position.z, a_PoweringData.PowerLevel); - if (a_Meta != a_PoweringData.PowerLevel) + if (a_Meta == a_PoweringData.PowerLevel) { - a_Chunk.SetMeta(a_Position, a_PoweringData.PowerLevel); + return; + } - // Notify block below us to update: - UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position + OffsetYM); + a_Chunk.SetMeta(a_Position, a_PoweringData.PowerLevel); - // Notify all terracing positions: - ForTerracingConnectionOffsets(a_Chunk, a_Position, [&a_Chunk, &CurrentlyTicking, a_Position](const Vector3i Offset) + // Notify all positions, sans YP, to update: + for (const auto Offset : RelativeAdjacents) + { + if (Offset == OffsetYP) { - UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position + Offset); - return false; - }); + continue; + } + + UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position, Offset); } } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { - UNUSED(a_Chunk); UNUSED(a_BlockType); UNUSED(a_Meta); Callback(a_Position + OffsetYP); Callback(a_Position + OffsetYM); - ForTerracingConnectionOffsets(a_Chunk, a_Position, [&Callback, a_Position](const Vector3i Offset) + const auto & Data = DataForChunk(a_Chunk); + const auto Block = Data.WireStates.find(a_Position)->second; + + // Figure out, based on our pre-computed block, where we connect to: + for (const auto Offset : RelativeLaterals) { - Callback(a_Position + Offset); - return false; - }); + const auto Relative = a_Position + Offset; + Callback(Relative); + + DoWithDirectionState(Offset, Block, [&a_Chunk, &Callback, Relative](auto, const auto Front, auto) + { + using FrontState = std::remove_reference_t<decltype(Front)>; + + if (Front == FrontState::Up) + { + Callback(Relative + OffsetYP); + } + else if (Front == FrontState::Side) + { + // Alas, no way to distinguish side lateral and side diagonal + // Have to do a manual check to only accept power from YM diagonal if there's a wire there + + const auto YMDiagonalPosition = Relative + OffsetYM; + if ( + BLOCKTYPE Block; + cChunkDef::IsValidHeight(YMDiagonalPosition.y) && + a_Chunk.UnboundedRelGetBlockType(YMDiagonalPosition, Block) && + (Block == E_BLOCK_REDSTONE_WIRE) + ) + { + Callback(YMDiagonalPosition); + } + } + }); + } } }; diff --git a/src/Simulator/IncrementalRedstoneSimulator/SmallGateHandler.h b/src/Simulator/IncrementalRedstoneSimulator/SmallGateHandler.h index 0bf2faacd..68727284d 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/SmallGateHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/SmallGateHandler.h @@ -9,16 +9,14 @@ class cSmallGateHandler final : public cRedstoneHandler { -public: - - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_Chunk); UNUSED(a_Position); UNUSED(a_BlockType); - UNUSED(a_Meta); UNUSED(a_QueryPosition); UNUSED(a_QueryBlockType); + UNUSED(IsLinked); return 0; } @@ -35,7 +33,7 @@ public: } } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_BlockType); diff --git a/src/Simulator/IncrementalRedstoneSimulator/SolidBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/SolidBlockHandler.h deleted file mode 100644 index abf8dc63b..000000000 --- a/src/Simulator/IncrementalRedstoneSimulator/SolidBlockHandler.h +++ /dev/null @@ -1,62 +0,0 @@ - -#pragma once - -#include "RedstoneHandler.h" - - - - - -class cSolidBlockHandler: - public cRedstoneHandler -{ - using Super = cRedstoneHandler; - -public: - - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override - { - const auto SolidBlock = DataForChunk(a_Chunk).GetCachedPowerData(a_Position); - return ( - !cIncrementalRedstoneSimulator::IsRedstone(a_QueryBlockType) || - ( - (a_QueryBlockType == E_BLOCK_REDSTONE_WIRE) && - (SolidBlock.PoweringBlock == E_BLOCK_REDSTONE_WIRE) - ) - ) ? 0 : SolidBlock.PowerLevel; - } - - 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 = DataForChunk(a_Chunk).ExchangeUpdateOncePowerData(a_Position, a_PoweringData); - if ((a_PoweringData != PreviousPower) || (a_PoweringData.PoweringBlock != PreviousPower.PoweringBlock)) - { - UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents); - } - } - - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override - { - UNUSED(a_Chunk); - UNUSED(a_BlockType); - UNUSED(a_Meta); - - /* TODO: is this more performant? - cVector3iArray Adjacents; - for (const auto Offset : GetRelativeAdjacents()) - { - auto Position = Offset + a_Position; - auto Block = m_World.GetBlock(Position); - if ((Block == E_BLOCK_REDSTONE_REPEATER_ON) || (Block == E_BLOCK_REDSTONE_WIRE) || (Block == E_BLOCK_TRIPWIRE_HOOK)) - { - Adjacents.emplace_back(Position); - } - } - */ - InvokeForAdjustedRelatives(Callback, a_Position, RelativeAdjacents); - } -}; diff --git a/src/Simulator/IncrementalRedstoneSimulator/TNTHandler.h b/src/Simulator/IncrementalRedstoneSimulator/TNTHandler.h index 4b048e5c2..2396660a8 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/TNTHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/TNTHandler.h @@ -9,16 +9,14 @@ class cTNTHandler final : public cRedstoneHandler { -public: - - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_Chunk); UNUSED(a_Position); UNUSED(a_BlockType); - UNUSED(a_Meta); UNUSED(a_QueryPosition); UNUSED(a_QueryBlockType); + UNUSED(IsLinked); return 0; } @@ -32,7 +30,7 @@ public: } } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_BlockType); diff --git a/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h b/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h index e3deea5e9..45014d637 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h @@ -8,19 +8,14 @@ -class cTrappedChestHandler: - public cRedstoneHandler +class cTrappedChestHandler final : public cRedstoneHandler { - using Super = cRedstoneHandler; - -public: - - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_BlockType); - UNUSED(a_Meta); UNUSED(a_QueryPosition); UNUSED(a_QueryBlockType); + UNUSED(IsLinked); return DataForChunk(a_Chunk).GetCachedPowerData(a_Position).PowerLevel; } @@ -49,12 +44,11 @@ public: if (Power != PreviousPower.PowerLevel) { - UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, OffsetYM); - UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeLaterals); + UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents); } } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_Position); diff --git a/src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h b/src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h index 7c00c4e2f..6ae3c2e3c 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h @@ -10,18 +10,16 @@ class cTripwireHookHandler final : public cRedstoneHandler { -public: - - virtual unsigned char GetPowerDeliveredToPosition(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType) const override + virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override { UNUSED(a_BlockType); UNUSED(a_QueryBlockType); UNUSED(a_QueryPosition); - return (GetPowerLevel(a_Chunk, a_Position, a_Meta) == 15) ? 15 : 0; + return (GetPowerLevel(a_Chunk, a_Position, a_Chunk.GetMeta(a_Position)) == 15) ? 15 : 0; } - static unsigned char GetPowerLevel(cChunk & a_Chunk, Vector3i a_Position, NIBBLETYPE a_Meta) + static unsigned char GetPowerLevel(const cChunk & a_Chunk, Vector3i a_Position, NIBBLETYPE a_Meta) { bool FoundActivated = false; const auto FaceToGoTowards = cBlockTripwireHookHandler::MetadataToDirection(a_Meta); @@ -104,7 +102,7 @@ public: } } - virtual void ForValidSourcePositions(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override + virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override { UNUSED(a_Chunk); UNUSED(a_BlockType); |