From 84534dfeb288dd12d998f3f192ee162a1def5367 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 26 Apr 2015 00:38:41 +0100 Subject: Redstone wire and trapdoor fixes * Fixes #1887 * Fixes #1763 * Fixes #1083 --- src/ChunkDef.h | 13 + src/Simulator/IncrementalRedstoneSimulator.cpp | 550 ++++++++++++------------- src/Simulator/IncrementalRedstoneSimulator.h | 69 ++-- src/World.cpp | 2 +- 4 files changed, 323 insertions(+), 311 deletions(-) diff --git a/src/ChunkDef.h b/src/ChunkDef.h index fb3451db1..a1273bd23 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -96,6 +96,19 @@ public: a_Z = a_Z - a_ChunkZ * Width; } + inline static Vector3i AbsoluteToRelative(Vector3i a_BlockPosition) + { + int ChunkX, ChunkZ; + BlockToChunk(a_BlockPosition.x, a_BlockPosition.z, ChunkX, ChunkZ); + + return {a_BlockPosition.x - ChunkX * Width, a_BlockPosition.y, a_BlockPosition.z - ChunkZ * Width}; + } + + inline static Vector3i AbsoluteToRelative(Vector3i a_BlockPosition, int a_ChunkX, int a_ChunkZ) + { + return {a_BlockPosition.x - a_ChunkX * Width, a_BlockPosition.y, a_BlockPosition.z - a_ChunkZ * Width}; + } + /** Converts relative block coordinates into absolute coordinates with a known chunk location */ inline static Vector3i RelativeToAbsolute(const Vector3i & a_RelBlockPosition, int a_ChunkX, int a_ChunkZ) { diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index ff813a2c0..40829757d 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -24,41 +24,42 @@ -void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk, cChunk * a_OtherChunk) +void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) { - if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) + AddBlock(cChunkDef::AbsoluteToRelative({ a_BlockX, a_BlockY, a_BlockZ }, a_Chunk->GetPosX(), a_Chunk->GetPosZ()), a_Chunk, nullptr); +} + + + + + +void cIncrementalRedstoneSimulator::AddBlock(const Vector3i & a_RelBlockPosition, cChunk * a_OriginalChunk, cChunk * a_NeighborChunk) +{ + if ((a_OriginalChunk == nullptr) || !a_OriginalChunk->IsValid()) { return; } - else if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) + else if ((a_RelBlockPosition.y < 0) || (a_RelBlockPosition.y >= cChunkDef::Height)) { return; } - // We may be called with coordinates in a chunk that is not the first chunk parameter - // In that case, the actual chunk (which the coordinates are in), will be passed as the second parameter - // Use that Chunk pointer to get a relative position + // The relative block position is relative to the neighboring chunk should it be passed as an argument - int RelX = 0; - int RelZ = 0; BLOCKTYPE Block; NIBBLETYPE Meta; - if (a_OtherChunk != nullptr) + if (a_NeighborChunk != nullptr) { - RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width; - RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width; - a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); + a_NeighborChunk->UnboundedRelGetBlock(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, Meta); - // If a_OtherChunk is passed (not nullptr), it is the chunk that had a block change, and a_Chunk will be the neighbouring chunk of that block + // If a_OtherChunk is passed (not nullptr), it is the neighbouring chunk of a_Chunk, which itself is the chunk with the block change // Because said neighbouring chunk does not know of this change but still needs to update its redstone, we set it to dirty - a_Chunk->SetIsRedstoneDirty(true); + a_NeighborChunk->SetIsRedstoneDirty(true); } else { - RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); + a_OriginalChunk->GetBlockTypeMeta(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, Meta); } // Every time a block is changed (AddBlock called), we want to go through all lists and check to see if the coordiantes stored within are still valid @@ -76,39 +77,53 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, ) ) { - SetSourceUnpowered(RelX, a_BlockY, RelZ, a_OtherChunk != nullptr ? a_OtherChunk : a_Chunk); + SetSourceUnpowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_NeighborChunk != nullptr ? a_NeighborChunk : a_OriginalChunk); } if (!IsViableMiddleBlock(Block)) { - SetInvalidMiddleBlock(RelX, a_BlockY, RelZ, a_OtherChunk != nullptr ? a_OtherChunk : a_Chunk); + SetInvalidMiddleBlock(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_NeighborChunk != nullptr ? a_NeighborChunk : a_OriginalChunk); } - auto & SimulatedPlayerToggleableBlocks = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_SimulatedPlayerToggleableBlocks; - SimulatedPlayerToggleableBlocks.erase(std::remove_if(SimulatedPlayerToggleableBlocks.begin(), SimulatedPlayerToggleableBlocks.end(), [RelX, a_BlockY, RelZ, Block, this](const sSimulatedPlayerToggleableList & itr) + if (a_NeighborChunk != nullptr) + { + // DO NOT touch our chunk's data structure if we are being called with coordinates from another chunk - this one caused me massive grief :P + return; + } + + auto & SimulatedPlayerToggleableBlocks = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_SimulatedPlayerToggleableBlocks; + if ( + DoesIgnorePlayerToggle(Block) && + std::find_if(SimulatedPlayerToggleableBlocks.begin(),SimulatedPlayerToggleableBlocks.end(), + [a_RelBlockPosition](const sSimulatedPlayerToggleableList & itr){ return itr.a_RelBlockPos == a_RelBlockPosition; }) == SimulatedPlayerToggleableBlocks.end() + ) + { + // We have arrived here; no block must be in list - add one + sSimulatedPlayerToggleableList RC; + RC.a_RelBlockPos = a_RelBlockPosition; + RC.WasLastStatePowered = AreCoordsDirectlyPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk) || AreCoordsLinkedPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk); + + // Initialise the toggleable blocks list so that trapdoors etc. aren't reset on restart (#1887) + SimulatedPlayerToggleableBlocks.emplace_back(RC); + } + + SimulatedPlayerToggleableBlocks.erase(std::remove_if(SimulatedPlayerToggleableBlocks.begin(), SimulatedPlayerToggleableBlocks.end(), [a_RelBlockPosition, Block, this](const sSimulatedPlayerToggleableList & itr) { - return itr.a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)) && !IsAllowedBlock(Block); + return (itr.a_RelBlockPos == a_RelBlockPosition) && !DoesIgnorePlayerToggle(Block); } ), SimulatedPlayerToggleableBlocks.end()); - - auto & RepeatersDelayList = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_RepeatersDelayList; - RepeatersDelayList.erase(std::remove_if(RepeatersDelayList.begin(), RepeatersDelayList.end(), [RelX, a_BlockY, RelZ, Block](const sRepeatersDelayList & itr) + auto & RepeatersDelayList = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_RepeatersDelayList; + RepeatersDelayList.erase(std::remove_if(RepeatersDelayList.begin(), RepeatersDelayList.end(), [a_RelBlockPosition, Block](const sRepeatersDelayList & itr) { - return itr.a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)) && (Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF); + return (itr.a_RelBlockPos == a_RelBlockPosition) && (Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF); } ), RepeatersDelayList.end()); - if (a_OtherChunk != nullptr) - { - // DO NOT touch our chunk's data structure if we are being called with coordinates from another chunk - this one caused me massive grief :P - return; - } - - cCoordWithBlockAndBoolVector & RedstoneSimulatorChunkData = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_ChunkData; + auto & RedstoneSimulatorChunkData = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_ChunkData; for (auto & itr : RedstoneSimulatorChunkData) { - if ((itr.x == RelX) && (itr.y == a_BlockY) && (itr.z == RelZ)) // We are at an entry matching the current (changed) block + if (a_RelBlockPosition == Vector3i(itr.x, itr.y, itr.z)) // We are at an entry matching the current (changed) block { if (!IsAllowedBlock(Block)) { @@ -128,16 +143,16 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, return; } - cCoordWithBlockAndBoolVector & QueuedData = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData; + auto & QueuedData = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_QueuedChunkData; for (const auto & itr : QueuedData) { - if ((itr.x == RelX) && (itr.y == a_BlockY) && (itr.z == RelZ)) + if (a_RelBlockPosition == Vector3i(itr.x, itr.y, itr.z)) { // Can't have duplicates in here either, in case something adds the block again before the structure can written to the main chunk data return; } } - QueuedData.emplace_back(cCoordWithBlockAndBool(RelX, a_BlockY, RelZ, Block, false)); + QueuedData.emplace_back(cCoordWithBlockAndBool(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, false)); } @@ -146,13 +161,13 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) { - m_RedstoneSimulatorChunkData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData(); + m_RedstoneSimulatorChunkData = static_cast(a_Chunk->GetRedstoneSimulatorData()); if (m_RedstoneSimulatorChunkData == nullptr) { m_RedstoneSimulatorChunkData = new cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData(); a_Chunk->SetRedstoneSimulatorData(m_RedstoneSimulatorChunkData); } - if (m_RedstoneSimulatorChunkData->m_ChunkData.empty() && ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData.empty()) + if (m_RedstoneSimulatorChunkData->m_ChunkData.empty() && static_cast(a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData.empty()) { return; } @@ -304,23 +319,14 @@ void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) { - if (GetCoordinateAdjacentChunk({ a_BlockX, a_BlockY, a_BlockZ }).Equals({ 0, 0, 0 })) - { - // On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk) - AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); - - // Pass the original coordinates, because when adding things to our simulator lists, we get the chunk that they are in, and therefore any updates need to preseve their position - // RedstoneAddBlock to pass both the neighbouring chunk and the chunk which the coordinates are in and +- 2 in GetNeighbour() to accomodate for LinkedPowered blocks being 2 away from chunk boundaries - RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 2, a_BlockZ), a_Chunk); - RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 2, a_BlockZ), a_Chunk); - RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 2), a_Chunk); - RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ + 2), a_Chunk); + auto CurrentChunkRelative = cChunkDef::AbsoluteToRelative({a_BlockX, a_BlockY, a_BlockZ}, a_Chunk->GetPosX(), a_Chunk->GetPosZ()); + AddBlock(CurrentChunkRelative, a_Chunk); // Alert the current chunk which the block is present in - return; + for (const auto & BoundaryChunk : GetAdjacentChunks(CurrentChunkRelative, a_Chunk)) + { + // On a chunk boundary, alert all neighbouring chunks which may have a connection with this block + AddBlock(cChunkDef::AbsoluteToRelative({a_BlockX, a_BlockY, a_BlockZ}, BoundaryChunk->GetPosX(), BoundaryChunk->GetPosZ()), a_Chunk, BoundaryChunk); } - - // Not on boundary, just alert this chunk for speed - AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); } @@ -508,147 +514,145 @@ void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_RelBlockX, int a_ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - static const struct // Define which directions the wire can receive power from + static const eBlockFace BlockFaceOffsets[] = { - int x, y, z; - } gCrossCoords[] = - { - { 1, 0, 0 }, /* Wires on same level start */ - { -1, 0, 0 }, - { 0, 0, 1 }, - { 0, 0, -1 }, /* Wires on same level stop */ - { 1, 1, 0 }, /* Wires one higher, surrounding self start */ - { -1, 1, 0 }, - { 0, 1, 1 }, - { 0, 1, -1 }, /* Wires one higher, surrounding self stop */ - { 1, -1, 0 }, /* Wires one lower, surrounding self start */ - { -1, -1, 0 }, - { 0, -1, 1 }, - { 0, -1, -1 }, /* Wires one lower, surrounding self stop */ + BLOCK_FACE_XM, + BLOCK_FACE_XP, + BLOCK_FACE_ZM, + BLOCK_FACE_ZP }; - static const struct // Define which directions the wire will check for repeater prescence - { - int x, y, z; - } gSideCoords[] = + static const Vector3i VectorOffsets[] = { - { 1, 0, 0 }, { -1, 0, 0 }, - { 0, 0, 1 }, + { 1, 0, 0 }, { 0, 0, -1 }, - { 0, 1, 0 }, + { 0, 0, 1 } }; + auto RelBlock = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + // Check to see if directly beside a power source - unsigned char MyPower = IsWirePowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); + unsigned char MyPower = IsWirePowered(RelBlock, m_Chunk); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); if (MyPower == 0) { SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0); return; } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + if (MyPower == MAX_POWER_LEVEL) + { + std::vector> PotentialWireList = { std::make_pair(RelBlock, m_Chunk) }; + while (!PotentialWireList.empty()) + { + auto Current = PotentialWireList.back(); + PotentialWireList.pop_back(); + FindAndPowerBorderingWires(PotentialWireList, Current); + } + } + else if (MyPower == 1) + { + return; + } MyPower--; - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power + // Wire still powered, power blocks beneath + SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, MyPower); + + int BorderingMechanismCount = 0; + bool RepeaterPresent = false; + Vector3i VectorOffset; + + for (auto OffsetIdx = 0; OffsetIdx != ARRAYCOUNT(VectorOffsets); ++OffsetIdx) { - if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above... - { - BLOCKTYPE Type = 0; - if (a_RelBlockY >= cChunkDef::Height - 1) - { - continue; - } - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, Type)) - { - continue; - } - if (cBlockInfo::IsSolid(Type)) // If there is something solid above us (wire cut off)... - { - continue; // We don't receive power from that wire - } - } - else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us + BLOCKTYPE Block; + auto Offset = RelBlock + VectorOffsets[OffsetIdx]; + if (m_Chunk->UnboundedRelGetBlockType(Offset.x, Offset.y, Offset.z, Block)) { - BLOCKTYPE Type = 0; - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY, a_RelBlockZ + gCrossCoords[i].z, Type)) - { - continue; - } - if (cBlockInfo::IsSolid(Type)) + switch (Block) { - continue; + case E_BLOCK_REDSTONE_REPEATER_OFF: + { + BorderingMechanismCount++; + if (!RepeaterPresent) + { + // TODO: only if wire is actually connected to repeater (repeater facing right way) + RepeaterPresent = true; + VectorOffset = { -VectorOffsets[OffsetIdx].x, VectorOffsets[OffsetIdx].y, -VectorOffsets[OffsetIdx].z }; + } + SetBlockPowered(Offset, RelBlock, MyPower); + } + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_REDSTONE_WIRE: + { + BorderingMechanismCount++; + if (!RepeaterPresent) + { + VectorOffset = { -VectorOffsets[OffsetIdx].x, VectorOffsets[OffsetIdx].y, -VectorOffsets[OffsetIdx].z }; + } + } + default: break; } } - - BLOCKTYPE Type = 0; - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type)) - { - continue; - } - if (Type == E_BLOCK_REDSTONE_WIRE) - { - SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - } } - for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them + if (BorderingMechanismCount == 0) { - BLOCKTYPE Type = 0; - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, Type)) - { - continue; - } - if (Type == E_BLOCK_REDSTONE_REPEATER_OFF) - { - SetBlockPowered(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - } + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); } + else if (BorderingMechanismCount == 1) + { + eBlockFace Face = BlockFaceOffsets[std::distance(VectorOffsets, std::find(VectorOffsets, VectorOffsets + ARRAYCOUNT(VectorOffsets), VectorOffset))]; + SetBlockPowered(RelBlock + VectorOffset, RelBlock, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Face, MyPower); + } +} + - // Wire still powered, power blocks beneath - SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, MyPower); - switch (GetWireDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) + + +void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const std::pair & a_Entry) +{ + std::vector> NewAdditions; + const Vector3i Offsets[] = { - case REDSTONE_NONE: - { - SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + { 1, 0, 0 }, /* Wires on same level start */ + { -1, 0, 0 }, + { 0, 0, 1 }, + { 0, 0, -1 }, /* Wires on same level stop */ + { 1, 1, 0 }, /* Wires one higher, surrounding self start */ + { -1, 1, 0 }, + { 0, 1, 1 }, + { 0, 1, -1 }, /* Wires one higher, surrounding self stop */ + { 1, -1, 0 }, /* Wires one lower, surrounding self start */ + { -1, -1, 0 }, + { 0, -1, 1 }, + { 0, -1, -1 }, /* Wires one lower, surrounding self stop */ + }; + + for (auto Offset : Offsets) + { + auto AdjustedPos = a_Entry.first + Offset; + auto Neighbour = a_Entry.second->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); + auto MyPower = IsWirePowered(a_Entry.first, a_Entry.second); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower); - break; - } - case REDSTONE_X_POS: - { - SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower); - break; - } - case REDSTONE_X_NEG: + if ((Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) { - SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower); - break; - } - case REDSTONE_Z_POS: - { - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower); - break; - } - case REDSTONE_Z_NEG: - { - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower); - break; + sPoweredBlocks RC; + RC.a_BlockPos = AdjustedPos; + RC.a_SourcePos = a_Entry.first + Vector3i((a_Entry.second->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width, 0, (a_Entry.second->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width); + RC.a_PowerLevel = MyPower - 1; + ((cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks.emplace_back(RC); // We need to insert the value into the chunk who owns the block position + + Neighbour->SetIsRedstoneDirty(true); + m_Chunk->SetIsRedstoneDirty(true); + + Neighbour->SetMeta(AdjustedPos.x, AdjustedPos.y, AdjustedPos.z, MyPower - 1); + a_PotentialWireList.emplace_back(std::make_pair(AdjustedPos, Neighbour)); } } } @@ -660,7 +664,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re void cIncrementalRedstoneSimulator::HandleRedstoneComparator(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { auto Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - auto HighestSidePower = std::max(IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetSideCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3, false))), IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetSideCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3, true)))); + auto HighestSidePower = std::max(IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetSideCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3, false)), m_Chunk), IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetSideCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3, true)), m_Chunk)); auto FrontCoordinate = AdjustRelativeCoords(cBlockComparatorHandler::GetFrontCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3)); unsigned char Power = 0; @@ -691,7 +695,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneComparator(int a_RelBlockX, in auto AbsoluteRearCoords = cBlockComparatorHandler::GetRearCoordinate(AbsoluteComparatorCoords.x, AbsoluteComparatorCoords.y, AbsoluteComparatorCoords.z, Meta & 0x3); m_Chunk->DoWithBlockEntityAt(AbsoluteRearCoords.x, AbsoluteRearCoords.y, AbsoluteRearCoords.z, CCB); - auto RearPower = std::max(CCB.m_SignalStrength, IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetRearCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3)))); + auto RearPower = std::max(CCB.m_SignalStrength, IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetRearCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3)), m_Chunk)); if ((Meta & 0x4) == 0x4) { // Subtraction mode @@ -1514,30 +1518,18 @@ bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, in { // Torches want to access neighbour's data when on a wall, hence the extra chunk parameter - for (const auto & itr : ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks) // Check powered list - { - if (itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - } - return false; + const auto & Data = static_cast(a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks; + return std::find_if(Data.begin(), Data.end(), [a_RelBlockX, a_RelBlockY, a_RelBlockZ](const sPoweredBlocks & itr) { return itr.a_BlockPos == Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }) != Data.end(); } -bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) +bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk) { - for (const auto & itr : *m_LinkedPoweredBlocks) // Check linked powered list - { - if (itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - } - return false; + const auto & Data = static_cast(a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks; + return std::find_if(Data.begin(), Data.end(), [a_RelBlockX, a_RelBlockY, a_RelBlockZ](const sLinkedPoweredBlocks & itr) { return itr.a_BlockPos == Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }) != Data.end(); } @@ -1764,11 +1756,11 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBl -unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPosition) +unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPosition, cChunk * a_Chunk) { unsigned char PowerLevel = 0; - for (const auto & itr : *m_PoweredBlocks) // Check powered list + for (const auto & itr : static_cast(a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks) // Check powered list { if (itr.a_BlockPos != a_RelBlockPosition) { @@ -1777,7 +1769,7 @@ unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPo PowerLevel = std::max(itr.a_PowerLevel, PowerLevel); // Get the highest power level (a_PowerLevel is initialised already and there CAN be multiple levels for one block) } - for (const auto & itr : *m_LinkedPoweredBlocks) // Check linked powered list + for (const auto & itr : static_cast(a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks) // Check linked powered list { if (itr.a_BlockPos != a_RelBlockPosition) { @@ -1785,7 +1777,7 @@ unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPo } BLOCKTYPE Type = E_BLOCK_AIR; - if (!m_Chunk->UnboundedRelGetBlockType(itr.a_SourcePos.x, itr.a_SourcePos.y, itr.a_SourcePos.z, Type) || (Type == E_BLOCK_REDSTONE_WIRE)) + if (!a_Chunk->UnboundedRelGetBlockType(itr.a_SourcePos.x, itr.a_SourcePos.y, itr.a_SourcePos.z, Type) || (Type == E_BLOCK_REDSTONE_WIRE)) { continue; } @@ -1931,22 +1923,19 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_RelBlockX, i void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel) { - static const struct - { - Vector3i Offset; - } gCrossCoords[] = - { - Vector3i(1, 0, 0), - Vector3i(-1, 0, 0), - Vector3i(0, 0, 1), - Vector3i(0, 0, -1), - Vector3i(0, 1, 0), - Vector3i(0, -1, 0) + static const Vector3i Offsets[] = + { + {1, 0, 0}, + { -1, 0, 0}, + {0, 0, 1}, + {0, 0, -1}, + {0, 1, 0}, + {0, -1, 0} }; - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions + for (auto Offset : Offsets) // Loop through struct to power all directions { - SetBlockPowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ) + gCrossCoords[i].Offset, Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), a_PowerLevel); + SetBlockPowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ) + Offset, Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), a_PowerLevel); } } @@ -1964,7 +1953,7 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(Vector3i a_RelBlockPosition, a_RelSourcePosition.x += (m_Chunk->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width; a_RelSourcePosition.z += (m_Chunk->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width; - auto & Powered = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position + auto & Powered = static_cast(Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position for (auto itr = Powered.begin(); itr != Powered.end(); ++itr) { if ((itr->a_BlockPos == a_RelBlockPosition) && (itr->a_SourcePos == a_RelSourcePosition)) @@ -2012,7 +2001,7 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( return; } - auto & Linked = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_LinkedBlocks; + auto & Linked = static_cast(Neighbour->GetRedstoneSimulatorData())->m_LinkedBlocks; for (auto & itr : Linked) // Check linked powered list { if ( @@ -2041,24 +2030,24 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( -void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered) +void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool a_WasLastStatePowered) { - for (auto itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr) + for (auto & itr : *m_SimulatedPlayerToggleableBlocks) { - if (!itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) + if (!itr.a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; } // Update listing - itr->WasLastStatePowered = WasLastStatePowered; + itr.WasLastStatePowered = a_WasLastStatePowered; return; } // We have arrived here; no block must be in list - add one sSimulatedPlayerToggleableList RC; RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - RC.WasLastStatePowered = WasLastStatePowered; + RC.WasLastStatePowered = a_WasLastStatePowered; m_SimulatedPlayerToggleableBlocks->emplace_back(RC); } @@ -2109,7 +2098,7 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R auto UnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_Chunk, const Vector3i & a_RelSource) { - auto Data = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData(); + auto Data = static_cast(a_Chunk->GetRedstoneSimulatorData()); Data->m_PoweredBlocks.erase(std::remove_if(Data->m_PoweredBlocks.begin(), Data->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSource](const sPoweredBlocks & itr) { if (itr.a_SourcePos != a_RelSource) @@ -2117,16 +2106,16 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R return false; } - auto ChunkBoundaryTestCoords = a_RelSource + GetCoordinateAdjacentChunk(a_RelSource); - auto BoundaryChunk = a_Chunk->GetRelNeighborChunk(ChunkBoundaryTestCoords.x, ChunkBoundaryTestCoords.z); - if (BoundaryChunk != a_Chunk) + for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_Chunk)) { - Vector3i ChunkAdjustedSource = a_RelSource; - ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; - ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; + if (BoundaryChunk != a_Chunk) + { + Vector3i ChunkAdjustedSource = a_RelSource; + ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; + ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; - auto BoundaryData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)BoundaryChunk->GetRedstoneSimulatorData(); - BoundaryData->m_PoweredBlocks.erase(std::remove_if(BoundaryData->m_PoweredBlocks.begin(), BoundaryData->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedSource](const sPoweredBlocks & itr) + auto BoundaryData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)BoundaryChunk->GetRedstoneSimulatorData(); + BoundaryData->m_PoweredBlocks.erase(std::remove_if(BoundaryData->m_PoweredBlocks.begin(), BoundaryData->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedSource](const sPoweredBlocks & itr) { if (itr.a_SourcePos != ChunkAdjustedSource) { @@ -2137,7 +2126,8 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R BoundaryChunk->SetIsRedstoneDirty(true); return true; } - ), BoundaryData->m_PoweredBlocks.end()); + ), BoundaryData->m_PoweredBlocks.end()); + } } if (a_Chunk->GetBlock(a_RelSource) == E_BLOCK_REDSTONE_REPEATER_ON) @@ -2151,17 +2141,47 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R } ), Data->m_PoweredBlocks.end()); - /*Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSource](const sLinkedPoweredBlocks & itr) + Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSource](const sLinkedPoweredBlocks & itr) { - if (itr.a_SourcePos == a_RelSource) + if (itr.a_SourcePos != a_RelSource) { - BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos); - a_Chunk->SetIsRedstoneDirty(true); - return true; + return false; } - return false; + + for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_Chunk)) + { + if (BoundaryChunk != a_Chunk) + { + Vector3i ChunkAdjustedSource = a_RelSource; + ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; + ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; + + auto BoundaryData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)BoundaryChunk->GetRedstoneSimulatorData(); + BoundaryData->m_LinkedBlocks.erase(std::remove_if(BoundaryData->m_LinkedBlocks.begin(), BoundaryData->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedSource](const sLinkedPoweredBlocks & itr) + { + if (itr.a_SourcePos != ChunkAdjustedSource) + { + return false; + } + + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, BoundaryChunk)); + BoundaryChunk->SetIsRedstoneDirty(true); + return true; + } + ), BoundaryData->m_LinkedBlocks.end()); + } + } + + if (a_Chunk->GetBlock(a_RelSource) == E_BLOCK_REDSTONE_REPEATER_ON) + { + return false; + } + + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_Chunk)); + a_Chunk->SetIsRedstoneDirty(true); + return true; } - ), Data->m_LinkedBlocks.end());*/ + ), Data->m_LinkedBlocks.end()); }; while (!BlocksPotentiallyUnpowered.empty()) @@ -2187,7 +2207,7 @@ void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int } std::vector BlocksPotentiallyUnpowered; - auto Data = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData(); + auto Data = static_cast(a_Chunk->GetRedstoneSimulatorData()); Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ](const sLinkedPoweredBlocks & itr) { @@ -2223,76 +2243,40 @@ void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int -cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) +bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta) +{ + // Extract the ON bit from metadata and return if true if it is set: + return ((a_BlockMeta & 0x8) == 0x8); +} + + + + + +std::vector cIncrementalRedstoneSimulator::GetAdjacentChunks(const Vector3i & a_RelBlockPosition, cChunk * a_Chunk) { - int Dir = REDSTONE_NONE; + std::vector AdjacentChunks; + AdjacentChunks.reserve(2); // At most bordering two chunks; reserve that many - BLOCKTYPE NegX = 0; - if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, NegX)) + // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks + if ((a_RelBlockPosition.x % cChunkDef::Width) <= 1) { - if (IsPotentialSource(NegX)) - { - Dir |= (REDSTONE_X_POS); - } + AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x - 2, a_RelBlockPosition.z)); } - - BLOCKTYPE PosX = 0; - if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, PosX)) + if ((a_RelBlockPosition.x % cChunkDef::Width) >= 14) { - if (IsPotentialSource(PosX)) - { - Dir |= (REDSTONE_X_NEG); - } + AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x + 2, a_RelBlockPosition.z)); } - - BLOCKTYPE NegZ = 0; - if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, NegZ)) + if ((a_RelBlockPosition.z % cChunkDef::Width) <= 1) { - if (IsPotentialSource(NegZ)) - { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner - { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; - } - Dir |= REDSTONE_Z_POS; - } + AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z - 2)); } - - BLOCKTYPE PosZ = 0; - if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, PosZ)) + if ((a_RelBlockPosition.z % cChunkDef::Width) >= 14) { - if (IsPotentialSource(PosZ)) - { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner - { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; - } - Dir |= REDSTONE_Z_NEG; - } + AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z + 2)); } - return (eRedstoneDirection)Dir; -} - - - - -bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta) -{ - // Extract the ON bit from metadata and return if true if it is set: - return ((a_BlockMeta & 0x8) == 0x8); + return AdjacentChunks; } diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index 903dbe82a..c383b6a0b 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -3,6 +3,7 @@ #include "RedstoneSimulator.h" #include "BlockEntities/RedstonePoweredEntity.h" +#include class cWorld; class cChunk; @@ -37,15 +38,14 @@ public: virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override { return IsRedstone(a_BlockType); } virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; - enum eRedstoneDirection + enum eRedstoneWireDirectionBitfieldPositions { - REDSTONE_NONE = 0, - REDSTONE_X_POS = 0x1, - REDSTONE_X_NEG = 0x2, - REDSTONE_Z_POS = 0x4, - REDSTONE_Z_NEG = 0x8, + eWbpXP = 0, + eWbpXN = 1, + eWbpZP = 2, + eWbpZN = 3, }; - eRedstoneDirection GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ); + std::bitset<4> GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ); private: @@ -108,8 +108,9 @@ private: SimulatedPlayerToggleableList * m_SimulatedPlayerToggleableBlocks; RepeatersDelayList * m_RepeatersDelayList; - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override { RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); } - void RedstoneAddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk, cChunk * a_OtherChunk = nullptr); + virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + + void AddBlock(const Vector3i & a_BlockPosition, cChunk * a_Chunk, cChunk * a_OtherChunk = nullptr); cChunk * m_Chunk; // We want a_MyState for devices needing a full FastSetBlock (as opposed to meta) because with our simulation model, we cannot keep setting the block if it is already set correctly @@ -192,6 +193,9 @@ private: void SetBlockPowered(Vector3i a_RelBlockPosition, Vector3i a_RelSourcePosition, unsigned char a_PowerLevel = MAX_POWER_LEVEL); void SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL) { SetBlockPowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ), a_PowerLevel); } + /** Recursively searches for a wire path and powers everything that should be powered */ + void FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const std::pair & a_Entry); + /** Marks a block as being powered through another block */ void SetBlockLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); @@ -214,13 +218,13 @@ private: void SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk, bool a_IsFirstCall = true); /** Returns if a coordinate is powered or linked powered */ - bool AreCoordsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { return AreCoordsDirectlyPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); } + bool AreCoordsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { return AreCoordsDirectlyPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); } /** Returns if a coordinate is in the directly powered blocks list */ - bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk); + static bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk); /** Returns if a coordinate is in the indirectly powered blocks list */ - bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); + static bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk); /** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */ bool AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered); @@ -236,7 +240,7 @@ private: /** Returns if a wire is powered The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire */ - unsigned char IsWirePowered(Vector3i a_RelBlockPosition); + static unsigned char IsWirePowered(Vector3i a_RelBlockPosition, cChunk * a_Chunk); /** Handles delayed updates to repeaters **/ void HandleRedstoneRepeaterDelays(void); @@ -249,14 +253,14 @@ private: /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */ - inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return cBlockInfo::FullyOccupiesVoxel(Block); } + inline static bool IsViableMiddleBlock(BLOCKTYPE a_Block) { return cBlockInfo::FullyOccupiesVoxel(a_Block); } /** Returns if a block is a mechanism (something that accepts power and does something) Used by torches to determine if they power a block whilst not standing on the ground */ - inline static bool IsMechanism(BLOCKTYPE Block) + inline static bool IsMechanism(BLOCKTYPE a_Block) { - switch (Block) + switch (a_Block) { case E_BLOCK_ACACIA_DOOR: case E_BLOCK_ACACIA_FENCE_GATE: @@ -298,9 +302,9 @@ private: } /** Returns if a block has the potential to output power */ - inline static bool IsPotentialSource(BLOCKTYPE Block) + inline static bool IsPotentialSource(BLOCKTYPE a_Block) { - switch (Block) + switch (a_Block) { case E_BLOCK_DETECTOR_RAIL: case E_BLOCK_DAYLIGHT_SENSOR: @@ -326,9 +330,9 @@ private: } /** Returns if a block is any sort of redstone device */ - inline static bool IsRedstone(BLOCKTYPE Block) + inline static bool IsRedstone(BLOCKTYPE a_Block) { - switch (Block) + switch (a_Block) { // All redstone devices, please alpha sort case E_BLOCK_ACACIA_DOOR: @@ -385,16 +389,27 @@ private: } } - inline static Vector3i GetCoordinateAdjacentChunk(const Vector3i & a_BlockPos) + inline static bool DoesIgnorePlayerToggle(BLOCKTYPE a_Block) { - // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks - if ((a_BlockPos.x % cChunkDef::Width) <= 1) { return{ -2, 0, 0 }; } - if ((a_BlockPos.x % cChunkDef::Width) >= 14) { return{ 2, 0, 0 }; } - if ((a_BlockPos.z % cChunkDef::Width) <= 1) { return{ 0, 0, -2 }; } - if ((a_BlockPos.z % cChunkDef::Width) >= 14) { return{ 0, 0, 2 }; } - return { 0, 0, 0 }; + switch (a_Block) + { + case E_BLOCK_ACACIA_FENCE_GATE: + case E_BLOCK_BIRCH_FENCE_GATE: + case E_BLOCK_DARK_OAK_FENCE_GATE: + case E_BLOCK_FENCE_GATE: + case E_BLOCK_JUNGLE_FENCE_GATE: + case E_BLOCK_SPRUCE_FENCE_GATE: + case E_BLOCK_IRON_TRAPDOOR: + case E_BLOCK_TRAPDOOR: + { + return true; + } + default: return false; + } } + inline static std::vector GetAdjacentChunks(const Vector3i & a_RelBlockPosition, cChunk * a_Chunk); + inline static Vector3i AdjustRelativeCoords(const Vector3i & a_RelPosition) { if ( diff --git a/src/World.cpp b/src/World.cpp index f7d2165c7..cf2c35816 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2964,7 +2964,7 @@ bool cWorld::SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Op return false; } - bool IsOpen = (Meta & 0x4) > 0; + bool IsOpen = (Meta & 0x4) != 0; if (a_Open != IsOpen) { SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta ^ 0x4); -- cgit v1.2.3