diff options
Diffstat (limited to 'src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h')
-rw-r--r-- | src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h | 255 |
1 files changed, 139 insertions, 116 deletions
diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h index 8f5e8c1b7..ea10e004e 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h @@ -9,147 +9,170 @@ namespace RedstoneRepeaterHandler { - static bool IsOn(BLOCKTYPE a_Block) - { - return (a_Block == E_BLOCK_REDSTONE_REPEATER_ON); - } - - /** 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(cChunk & Chunk, const Vector3i a_Position) - { - BLOCKTYPE Type; - NIBBLETYPE Meta; - - if (!Chunk.UnboundedRelGetBlock(a_Position, Type, Meta)) - { - return std::make_pair(false, static_cast<NIBBLETYPE>(0)); - } +static bool IsOn(BLOCKTYPE a_Block) +{ + return (a_Block == E_BLOCK_REDSTONE_REPEATER_ON); +} - return std::make_pair(IsOn(Type), Meta); - } +/** 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(cChunk & Chunk, const Vector3i a_Position) +{ + BLOCKTYPE Type; + NIBBLETYPE Meta; - /** Determine, from the metadata of a repeater on our left side, if they lock us. - To test a repeater on our right, simply invert the order of arguments provided. - "Left" is relative to the direction the repeater output faces, naturally. */ - static bool DoesLhsLockMe(NIBBLETYPE a_MetaLhs, NIBBLETYPE a_MyMeta) + if (!Chunk.UnboundedRelGetBlock(a_Position, Type, Meta)) { - // Get the direction bits - a_MetaLhs &= E_META_REDSTONE_REPEATER_FACING_MASK; - a_MyMeta &= E_META_REDSTONE_REPEATER_FACING_MASK; - - /* - Check for a valid locking configuration, where they are perpendicular and one snuggles into the other. - - Order of comparisons: - XP >^ ZM - ZP |_ XP - XM <| ZP - ZP ^< xM - - Key: - ^ Facing up - _ Facing right - | Facing down - < Facing left - */ - return - ((a_MetaLhs == E_META_REDSTONE_REPEATER_FACING_XP) && (a_MyMeta == E_META_REDSTONE_REPEATER_FACING_ZM)) || - ((a_MetaLhs == E_META_REDSTONE_REPEATER_FACING_ZP) && (a_MyMeta == E_META_REDSTONE_REPEATER_FACING_XP)) || - ((a_MetaLhs == E_META_REDSTONE_REPEATER_FACING_XM) && (a_MyMeta == E_META_REDSTONE_REPEATER_FACING_ZP)) || - ((a_MetaLhs == E_META_REDSTONE_REPEATER_FACING_ZM) && (a_MyMeta == E_META_REDSTONE_REPEATER_FACING_XM)) - ; + return std::make_pair(false, static_cast<NIBBLETYPE>(0)); } - /** 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. */ - 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); + return std::make_pair(IsOn(Type), Meta); +} - // Test the block to the left of us - const auto Lhs = IsOnRepeater(Chunk, LhsOffset + a_Position); - if (Lhs.first && DoesLhsLockMe(Lhs.second, a_Meta)) - { - return true; - } +/** Determine, from the metadata of a repeater on our left side, if they lock us. +To test a repeater on our right, simply invert the order of arguments provided. +"Left" is relative to the direction the repeater output faces, naturally. */ +static bool DoesLhsLockMe(NIBBLETYPE a_MetaLhs, NIBBLETYPE a_MyMeta) +{ + // Get the direction bits + a_MetaLhs &= E_META_REDSTONE_REPEATER_FACING_MASK; + a_MyMeta &= E_META_REDSTONE_REPEATER_FACING_MASK; + + /* + Check for a valid locking configuration, where they are perpendicular and one snuggles into the other. + + Order of comparisons: + XP >^ ZM + ZP |_ XP + XM <| ZP + ZP ^< xM + + Key: + ^ Facing up + _ Facing right + | Facing down + < Facing left + */ + return ((a_MetaLhs == E_META_REDSTONE_REPEATER_FACING_XP) && (a_MyMeta == E_META_REDSTONE_REPEATER_FACING_ZM)) || + ((a_MetaLhs == E_META_REDSTONE_REPEATER_FACING_ZP) && (a_MyMeta == E_META_REDSTONE_REPEATER_FACING_XP)) || + ((a_MetaLhs == E_META_REDSTONE_REPEATER_FACING_XM) && (a_MyMeta == E_META_REDSTONE_REPEATER_FACING_ZP)) || + ((a_MetaLhs == E_META_REDSTONE_REPEATER_FACING_ZM) && (a_MyMeta == E_META_REDSTONE_REPEATER_FACING_XM)); +} + +/** 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. */ +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 right side, flipping the argument order to DoesLhsLockMe - const auto Rhs = IsOnRepeater(Chunk, -LhsOffset + a_Position); - return Rhs.first && DoesLhsLockMe(a_Meta, Rhs.second); + // Test the block to the left of us + const auto Lhs = IsOnRepeater(Chunk, LhsOffset + a_Position); + if (Lhs.first && DoesLhsLockMe(Lhs.second, a_Meta)) + { + return true; } - static PowerLevel GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) + // Test the right side, flipping the argument order to DoesLhsLockMe + const auto Rhs = IsOnRepeater(Chunk, -LhsOffset + a_Position); + return Rhs.first && DoesLhsLockMe(a_Meta, Rhs.second); +} + +static PowerLevel GetPowerDeliveredToPosition( + const cChunk & a_Chunk, + Vector3i a_Position, + BLOCKTYPE a_BlockType, + Vector3i a_QueryPosition, + BLOCKTYPE a_QueryBlockType, + bool IsLinked +) +{ + if (!IsOn(a_BlockType)) { - if (!IsOn(a_BlockType)) - { - return 0; - } - - const auto FrontOffset = cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Chunk.GetMeta(a_Position)); - const auto FrontPosition = a_Position + FrontOffset; - if (a_QueryPosition == FrontPosition) - { - return 15; - } - return 0; } - static void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const PowerLevel Power) + const auto FrontOffset = cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Chunk.GetMeta(a_Position)); + const auto FrontPosition = a_Position + FrontOffset; + if (a_QueryPosition == FrontPosition) { - // LOGD("Evaluating loopy the repeater (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); - - auto & Data = DataForChunk(a_Chunk); - const auto DelayInfo = Data.GetMechanismDelayInfo(a_Position); + return 15; + } - // If the repeater is locked by another, ignore and forget all power changes: - if (IsLocked(a_Chunk, a_Position, a_Meta)) - { - if (DelayInfo != nullptr) - { - Data.m_MechanismDelays.erase(a_Position); - } + return 0; +} + +static void Update( + cChunk & a_Chunk, + cChunk & CurrentlyTicking, + Vector3i a_Position, + BLOCKTYPE a_BlockType, + NIBBLETYPE a_Meta, + const PowerLevel Power +) +{ + // LOGD("Evaluating loopy the repeater (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); - return; - } + auto & Data = DataForChunk(a_Chunk); + const auto DelayInfo = Data.GetMechanismDelayInfo(a_Position); - if (DelayInfo == nullptr) + // If the repeater is locked by another, ignore and forget all power changes: + if (IsLocked(a_Chunk, a_Position, a_Meta)) + { + if (DelayInfo != nullptr) { - bool ShouldBeOn = (Power != 0); - if (ShouldBeOn != IsOn(a_BlockType)) - { - Data.m_MechanismDelays[a_Position] = std::make_pair((((a_Meta & 0xC) >> 0x2) + 1), ShouldBeOn); - } - - return; + Data.m_MechanismDelays.erase(a_Position); } - int DelayTicks; - bool ShouldPowerOn; - std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo; + return; + } - if (DelayTicks != 0) + if (DelayInfo == nullptr) + { + bool ShouldBeOn = (Power != 0); + if (ShouldBeOn != IsOn(a_BlockType)) { - return; + Data.m_MechanismDelays[a_Position] = std::make_pair((((a_Meta & 0xC) >> 0x2) + 1), ShouldBeOn); } - 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, Power); - - UpdateAdjustedRelative(a_Chunk, CurrentlyTicking, a_Position, cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta)); + return; } - static void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, ForEachSourceCallback & Callback) + int DelayTicks; + bool ShouldPowerOn; + std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo; + + if (DelayTicks != 0) { - Callback(cBlockRedstoneRepeaterHandler::GetRearCoordinateOffset(a_Meta) + a_Position); + return; } -}; + + 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, Power); + + UpdateAdjustedRelative( + a_Chunk, + CurrentlyTicking, + a_Position, + cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta) + ); +} + +static void ForValidSourcePositions( + const cChunk & a_Chunk, + Vector3i a_Position, + BLOCKTYPE a_BlockType, + NIBBLETYPE a_Meta, + ForEachSourceCallback & Callback +) +{ + Callback(cBlockRedstoneRepeaterHandler::GetRearCoordinateOffset(a_Meta) + a_Position); +} +}; // namespace RedstoneRepeaterHandler |