From 5b62c4c3145c08b093521e42c565922fa85de4ad Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 26 Jun 2015 17:24:51 -0500 Subject: Reorganised the redstone simulator -> Many thanks to @worktycho for the idea, and @Haxi52 for the implementation plan! * Uses classes and inheritance now * Speed should be improved --- src/Simulator/IncrementalRedstoneSimulator.cpp | 2298 ------------------------ 1 file changed, 2298 deletions(-) delete mode 100644 src/Simulator/IncrementalRedstoneSimulator.cpp (limited to 'src/Simulator/IncrementalRedstoneSimulator.cpp') diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp deleted file mode 100644 index fc3dc0a73..000000000 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ /dev/null @@ -1,2298 +0,0 @@ - -#include "Globals.h" - -#include "BlockEntities/ChestEntity.h" - -#include "Chunk.h" -#include "World.h" -#include "Blocks/GetHandlerCompileTimeTemplate.h" -#include "Blocks/BlockComparator.h" -#include "Blocks/BlockTorch.h" -#include "Blocks/BlockLever.h" -#include "Blocks/BlockButton.h" -#include "Blocks/BlockTripwireHook.h" -#include "Blocks/BlockDoor.h" -#include "Blocks/BlockPiston.h" - - -#include "IncrementalRedstoneSimulator.h" -#include "BoundingBox.h" -#include "Blocks/ChunkInterface.h" -#include "RedstoneSimulator.h" - - - - - -void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) -{ - 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_RelBlockPosition.y < 0) || (a_RelBlockPosition.y >= cChunkDef::Height)) - { - return; - } - - // The relative block position is relative to the neighboring chunk should it be passed as an argument - - BLOCKTYPE Block; - NIBBLETYPE Meta; - - if (a_NeighborChunk != nullptr) - { - a_NeighborChunk->UnboundedRelGetBlock(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, Meta); - - // 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_NeighborChunk->SetIsRedstoneDirty(true); - } - else - { - 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 - // Checking only when a block is changed, as opposed to every tick, also improves performance - - if ( - !IsPotentialSource(Block) || - ( - // Changeable sources - ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) || - ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) || - ((Block == E_BLOCK_DETECTOR_RAIL) && ((Meta & 0x08) == 0)) || - (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) || - ((Block == E_BLOCK_TRIPWIRE_HOOK) && ((Meta & 0x08) == 0)) - ) - ) - { - SetSourceUnpowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_NeighborChunk != nullptr ? a_NeighborChunk : a_OriginalChunk); - } - - if (!IsViableMiddleBlock(Block)) - { - SetInvalidMiddleBlock(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_NeighborChunk != nullptr ? a_NeighborChunk : a_OriginalChunk); - } - - 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 RedstoneSimulatorData = static_cast(a_OriginalChunk->GetRedstoneSimulatorData()); - - auto & SimulatedPlayerToggleableBlocks = RedstoneSimulatorData->m_SimulatedPlayerToggleableBlocks; - if (DoesIgnorePlayerToggle(Block)) - { - // Initialise the toggleable blocks list so that trapdoors etc. aren't reset on restart (#1887) - SimulatedPlayerToggleableBlocks.emplace( - a_RelBlockPosition, - AreCoordsDirectlyPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk) || AreCoordsLinkedPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk) - ); // This map won't insert if key already present, so no need to check - } - else - { - SimulatedPlayerToggleableBlocks.erase(a_RelBlockPosition); - } - - if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF)) - { - RedstoneSimulatorData->m_RepeatersDelayList.erase(a_RelBlockPosition); - } - - auto & RedstoneSimulatorChunkData = RedstoneSimulatorData->m_ChunkData; - auto Iterator = RedstoneSimulatorChunkData.find(a_RelBlockPosition); - if (!IsAllowedBlock(Block)) - { - if (Iterator != RedstoneSimulatorChunkData.end()) - { - Iterator->second.second = true; // The new blocktype is not redstone; it must be queued to be removed from this list - } - return; - } - else - { - if (Iterator != RedstoneSimulatorChunkData.end()) - { - Iterator->second.second = false; // De-schedule removal from list - Iterator->second.first = Block; // Update block information - return; - } - } - - RedstoneSimulatorChunkData.emplace(a_RelBlockPosition, std::make_pair(Block, false)); -} - - - - - -void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) -{ - 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()) - { - return; - } - - m_PoweredBlocks = &m_RedstoneSimulatorChunkData->m_PoweredBlocks; - m_RepeatersDelayList = &m_RedstoneSimulatorChunkData->m_RepeatersDelayList; - m_SimulatedPlayerToggleableBlocks = &m_RedstoneSimulatorChunkData->m_SimulatedPlayerToggleableBlocks; - m_LinkedPoweredBlocks = &m_RedstoneSimulatorChunkData->m_LinkedBlocks; - m_Chunk = a_Chunk; - bool ShouldUpdateSimulateOnceBlocks = false; - - if (a_Chunk->IsRedstoneDirty()) - { - // Simulate the majority of devices only if something (blockwise or power-wise) has changed - // Make sure to allow the chunk to resimulate after the initial run if there was a power change (ShouldUpdateSimulateOnceBlocks helps to do this) - a_Chunk->SetIsRedstoneDirty(false); - ShouldUpdateSimulateOnceBlocks = true; - } - - HandleRedstoneRepeaterDelays(); - - for (auto dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.begin(); dataitr != m_RedstoneSimulatorChunkData->m_ChunkData.end();) - { - if (dataitr->second.second) - { - // Removal was scheduled - do so - dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.erase(dataitr); - continue; - } - - switch (dataitr->second.first) // Call the appropriate simulator for the entry's block type - { - case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_TRIPWIRE: HandleTripwire(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_TRIPWIRE_HOOK: HandleTripwireHook(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - - case E_BLOCK_WOODEN_PRESSURE_PLATE: - case E_BLOCK_STONE_PRESSURE_PLATE: - case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: - case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: - { - HandlePressurePlate(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); - break; - } - default: break; - } - - if (ShouldUpdateSimulateOnceBlocks) - { - switch (dataitr->second.first) - { - case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_LEVER: HandleRedstoneLever(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_TNT: HandleTNT(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_IRON_TRAPDOOR: HandleTrapdoor(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_TRAPPED_CHEST: HandleTrappedChest(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - - case E_BLOCK_ACTIVATOR_RAIL: - case E_BLOCK_DETECTOR_RAIL: - case E_BLOCK_POWERED_RAIL: - { - HandleRail(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); - break; - } - case E_BLOCK_ACACIA_DOOR: - case E_BLOCK_BIRCH_DOOR: - case E_BLOCK_DARK_OAK_DOOR: - case E_BLOCK_JUNGLE_DOOR: - case E_BLOCK_SPRUCE_DOOR: - case E_BLOCK_OAK_DOOR: - case E_BLOCK_IRON_DOOR: - { - HandleDoor(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - case E_BLOCK_ACACIA_FENCE_GATE: - case E_BLOCK_BIRCH_FENCE_GATE: - case E_BLOCK_DARK_OAK_FENCE_GATE: - case E_BLOCK_OAK_FENCE_GATE: - case E_BLOCK_JUNGLE_FENCE_GATE: - case E_BLOCK_SPRUCE_FENCE_GATE: - { - HandleFenceGate(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - case E_BLOCK_REDSTONE_LAMP_OFF: - case E_BLOCK_REDSTONE_LAMP_ON: - { - HandleRedstoneLamp(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); - break; - } - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - { - HandleDropSpenser(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: - { - HandlePiston(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - { - HandleRedstoneRepeater(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); - break; - } - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: - { - HandleRedstoneTorch(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); - break; - } - case E_BLOCK_STONE_BUTTON: - case E_BLOCK_WOODEN_BUTTON: - { - HandleRedstoneButton(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - case E_BLOCK_ACTIVE_COMPARATOR: - case E_BLOCK_INACTIVE_COMPARATOR: - { - HandleRedstoneComparator(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - default: break; - } - } - ++dataitr; - } -} - - - - - -void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * 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 - - 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); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) -{ - static const struct // Define which directions the torch can power - { - int x, y, z; - } gCrossCoords[] = - { - { 1, 0, 0 }, - { -1, 0, 0 }, - { 0, 0, 1 }, - { 0, 0, -1 }, - { 0, 1, 0 }, - }; - - if (a_MyState == E_BLOCK_REDSTONE_TORCH_ON) - { - // Check if the block the torch is on is powered - int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ; - AddFaceDirection(X, Y, Z, GetHandlerCompileTime::type::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on - - cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(X, Z); - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - - if (AreCoordsDirectlyPowered(X, Y, Z, Neighbour)) - { - // There was a match, torch goes off - m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - return; - } - - // Torch still on, make all 4(X, Z) + 1(Y) sides powered - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) - { - 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 (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last) - { - if ( - IsMechanism(Type) && // Is it a mechanism? Not block / other torch etc. - (!Vector3i(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on - ) - { - SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - } - } - else - { - // Top side, power whatever is there, including blocks - SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - // Power all blocks surrounding block above torch - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YP); - } - } - - if (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath - { - BLOCKTYPE Type = m_Chunk->GetBlock(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ); - - if (IsMechanism(Type)) // Still can't make a normal block powered though! - { - SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - } - } - } - else - { - // Check if the block the torch is on is powered - int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ; - AddFaceDirection(X, Y, Z, GetHandlerCompileTime::type::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on - - cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(X, Z); - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - - // See if off state torch can be turned on again - if (AreCoordsDirectlyPowered(X, Y, Z, Neighbour)) - { - return; // Something matches, torch still powered - } - - // Block torch on not powered, can be turned on again! - m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Set self as powered -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (IsLeverOn(Meta)) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - - eBlockFace Dir = GetHandlerCompileTime::type::BlockMetaDataToBlockFace(Meta); - - Dir = ReverseBlockFace(Dir); - - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - NIBBLETYPE MetaData = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) - { - if ((MetaData & 0x4) == 0) - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData | 0x4); - m_Chunk->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_DOOR_OPEN_CLOSE, BlockX, a_RelBlockY, BlockZ, 0); - } - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); - } - } - else - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) - { - if ((MetaData & 0x4) != 0) - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData & ~0x04); - m_Chunk->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_DOOR_OPEN_CLOSE, BlockX, a_RelBlockY, BlockZ, 0); - } - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (IsButtonOn(Meta)) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - - eBlockFace Dir = GetHandlerCompileTime::type::BlockMetaDataToBlockFace(Meta); - Dir = ReverseBlockFace(Dir); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - static const eBlockFace BlockFaceOffsets[] = - { - BLOCK_FACE_XM, - BLOCK_FACE_XP, - BLOCK_FACE_ZM, - BLOCK_FACE_ZP - }; - - static const Vector3i VectorOffsets[] = - { - { -1, 0, 0 }, - { 1, 0, 0 }, - { 0, 0, -1 }, - { 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(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); - return; - } - - 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.first, Current.second); - } - } - else if (MyPower == 1) - { - return; - } - - // Wire still powered, power blocks beneath and in direction of facing - MyPower--; - - 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 OffsetToPower; - - for (const auto & Offset : VectorOffsets) - { - BLOCKTYPE Block; - Vector3i AdjustedOffset = RelBlock + Offset; - if (m_Chunk->UnboundedRelGetBlockType(AdjustedOffset.x, AdjustedOffset.y, AdjustedOffset.z, Block)) - { - switch (Block) - { - case E_BLOCK_REDSTONE_REPEATER_OFF: - { - BorderingMechanismCount++; - if (!RepeaterPresent) - { - // TODO: only if wire is actually connected to repeater (repeater facing right way) - RepeaterPresent = true; - OffsetToPower = { -Offset.x, Offset.y, -Offset.z }; // Negate to obtain offset in opposite direction since wire powers that way - } - SetBlockPowered(AdjustedOffset, RelBlock, MyPower); - } - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_REDSTONE_WIRE: - { - BorderingMechanismCount++; - if (!RepeaterPresent) - { - OffsetToPower = { -Offset.x, Offset.y, -Offset.z }; - } - } - default: break; - } - } - } - - if (BorderingMechanismCount == 0) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - for (const auto & BlockFaceOffset : BlockFaceOffsets) - { - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BlockFaceOffset, MyPower); - } - } - else if (BorderingMechanismCount == 1) - { - eBlockFace Face = BlockFaceOffsets[std::distance(VectorOffsets, std::find(VectorOffsets, VectorOffsets + ARRAYCOUNT(VectorOffsets), OffsetToPower))]; - SetBlockPowered(RelBlock + OffsetToPower, RelBlock, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Face, MyPower); - } -} - - - - - -void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const Vector3i & a_EntryRelBlockPosition, cChunk * a_EntryChunk) -{ - static const Vector3i LevelOffsets[] = // Wires on same level - { - { 1, 0, 0 }, - { -1, 0, 0 }, - { 0, 0, 1 }, - { 0, 0, -1 }, - }; - static const Vector3i HigherOffsets[] = // Wires one higher, surrounding self - { - { 1, 1, 0 }, - { -1, 1, 0 }, - { 0, 1, 1 }, - { 0, 1, -1 }, - }; - static const Vector3i LowerOffsets[] = // Wires one lower, surrounding self - { - { 1, -1, 0 }, - { -1, -1, 0 }, - { 0, -1, 1 }, - { 0, -1, -1 }, - }; - - for (auto Offset : LevelOffsets) - { - auto AdjustedPos = a_EntryRelBlockPosition + Offset; - auto Neighbour = a_EntryChunk->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); - auto MyPower = IsWirePowered(a_EntryRelBlockPosition, a_EntryChunk); - - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - - if ((Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) - { - PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, MyPower); - } - } - - for (auto Offset : HigherOffsets) - { - auto AdjustedPos = a_EntryRelBlockPosition + Offset; - auto Neighbour = a_EntryChunk->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); - auto MyPower = IsWirePowered(a_EntryRelBlockPosition, a_EntryChunk); - - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - - if ( - (Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && - (!cBlockInfo::FullyOccupiesVoxel(a_EntryChunk->GetBlock(a_EntryRelBlockPosition.x, a_EntryRelBlockPosition.y + 1, a_EntryRelBlockPosition.z)) || - (a_EntryChunk->GetBlock(a_EntryRelBlockPosition.x, a_EntryRelBlockPosition.y + 1, a_EntryRelBlockPosition.z) == E_BLOCK_GLOWSTONE)) && - (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) - { - PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, MyPower); - } - } - - for (auto Offset : LowerOffsets) - { - auto AdjustedPos = a_EntryRelBlockPosition + Offset; - auto Neighbour = a_EntryChunk->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); - auto MyPower = IsWirePowered(a_EntryRelBlockPosition, a_EntryChunk); - - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - - if ( - (Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && - (!cBlockInfo::FullyOccupiesVoxel(Neighbour->GetBlock(AdjustedPos.x, AdjustedPos.y + 1, AdjustedPos.z)) || - (Neighbour->GetBlock(AdjustedPos.x, AdjustedPos.y + 1, AdjustedPos.z) == E_BLOCK_GLOWSTONE)) && - (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) - { - PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, MyPower); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::PowerBorderingWires(std::vector> & a_PotentialWireList, const Vector3i & a_EntryRelSourcePosition, cChunk * a_EntryChunk, const Vector3i & a_AdjustedPos, cChunk * a_NeighbourChunk, unsigned char a_MyPower) -{ - auto SourcePos = a_EntryRelSourcePosition + Vector3i((a_EntryChunk->GetPosX() - a_NeighbourChunk->GetPosX()) * cChunkDef::Width, 0, (a_EntryChunk->GetPosZ() - a_NeighbourChunk->GetPosZ()) * cChunkDef::Width); - auto & PoweredBlocks = static_cast(a_NeighbourChunk->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position - auto Position = std::find_if(PoweredBlocks.begin(), PoweredBlocks.end(), [a_AdjustedPos, SourcePos, a_MyPower](const sPoweredBlocks & itr) { return ((itr.m_BlockPos == a_AdjustedPos) && (itr.m_SourcePos == SourcePos)); }); - if (Position != PoweredBlocks.end()) - { - Position->m_PowerLevel = a_MyPower - 1; - } - else - { - PoweredBlocks.emplace_back(a_AdjustedPos, SourcePos, a_MyPower - 1); - - a_NeighbourChunk->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); - } - - a_NeighbourChunk->SetMeta(a_AdjustedPos.x, a_AdjustedPos.y, a_AdjustedPos.z, a_MyPower - 1); - a_PotentialWireList.emplace_back(std::make_pair(a_AdjustedPos, a_NeighbourChunk)); -} - - - - - -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)), 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; - - class cContainerCallback : public cBlockEntityCallback - { - public: - cContainerCallback() : m_SignalStrength(0) - { - } - - virtual bool Item(cBlockEntity * a_BlockEntity) override - { - auto & Contents = static_cast(a_BlockEntity)->GetContents(); - float Fullness = 0; // Is a floating-point type to allow later calculation to produce a non-truncated value - for (int Slot = 0; Slot != Contents.GetNumSlots(); ++Slot) - { - Fullness += Contents.GetSlot(Slot).m_ItemCount / Contents.GetSlot(Slot).GetMaxStackSize(); - } - - m_SignalStrength = static_cast(1 + (Fullness / Contents.GetNumSlots()) * 14); - return false; - } - - unsigned char m_SignalStrength; - } CCB; - - auto AbsoluteComparatorCoords = cChunkDef::RelativeToAbsolute(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), m_Chunk->GetPosX(), m_Chunk->GetPosZ()); - 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)), m_Chunk)); - - if ((Meta & 0x4) == 0x4) - { - // Subtraction mode - Power = std::max(static_cast(RearPower - HighestSidePower), std::numeric_limits::min()); - } - else - { - // Comparison mode - Power = (std::max(HighestSidePower, RearPower) == HighestSidePower) ? 0 : RearPower; - } - - if (Power > 0) - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0x8); - SetBlockPowered(FrontCoordinate, Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), Power); - } - else - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) -{ - /* Repeater Orientation Mini Guide: - =================================== - - | - | Z Axis - V - - X Axis ----> - - Repeater directions, values from a WorldType::GetBlockMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) lookup: - - East (Right) (X+): 0x1 - West (Left) (X-): 0x3 - North (Up) (Z-): 0x2 - South (Down) (Z+): 0x0 - // TODO: Add E_META_XXX enum entries for all meta values and update project with them - - Sun rises from East (X+) - - */ - - // Create a variable holding my meta to avoid multiple lookups. - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - bool IsOn = (a_MyState == E_BLOCK_REDSTONE_REPEATER_ON); - - if (!IsRepeaterLocked(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta)) // If we're locked, change nothing. Otherwise: - { - bool IsSelfPowered = IsRepeaterPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta); - if (IsSelfPowered && !IsOn) // Queue a power change if powered, but not on and not locked. - { - QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta, true); - } - else if (!IsSelfPowered && IsOn) // Queue a power change if unpowered, on, and not locked. - { - QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta, false); - } - } - - if (IsOn) - { - switch (Meta & 0x3) // We only want the direction (bottom) bits - { - case 0x0: - { - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM); - break; - } - case 0x1: - { - SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP); - break; - } - case 0x2: - { - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP); - break; - } - case 0x3: - { - SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM); - break; - } - } - } -} - - -void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays() -{ - for (auto itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end();) - { - if (itr->second.a_ElapsedTicks >= itr->second.a_DelayTicks) // Has the elapsed ticks reached the target ticks? - { - BLOCKTYPE Block; - NIBBLETYPE Meta; - m_Chunk->GetBlockTypeMeta(itr->first.x, itr->first.y, itr->first.z, Block, Meta); - if (itr->second.ShouldPowerOn) - { - if (Block != E_BLOCK_REDSTONE_REPEATER_ON) // For performance - { - m_Chunk->SetBlock(itr->first, E_BLOCK_REDSTONE_REPEATER_ON, Meta); - } - } - else if (Block != E_BLOCK_REDSTONE_REPEATER_OFF) - { - m_Chunk->SetBlock(itr->first.x, itr->first.y, itr->first.z, E_BLOCK_REDSTONE_REPEATER_OFF, Meta); - } - itr = m_RepeatersDelayList->erase(itr); - } - else - { - LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->first.x, itr->first.y, itr->first.z, itr->second.a_ElapsedTicks, itr->second.a_DelayTicks); - itr->second.a_ElapsedTicks++; - ++itr; - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - - if (IsPistonPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness) - { - GetHandlerCompileTime::type::ExtendPiston(Vector3i(BlockX, a_RelBlockY, BlockZ), &this->m_World); - } - else - { - GetHandlerCompileTime::type::RetractPiston(Vector3i(BlockX, a_RelBlockY, BlockZ), &this->m_World); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - class cSetPowerToDropSpenser : - public cRedstonePoweredCallback - { - bool m_IsPowered; - public: - cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} - - virtual bool Item(cRedstonePoweredEntity * a_DropSpenser) override - { - a_DropSpenser->SetRedstonePower(m_IsPowered); - return false; - } - } DrSpSP(AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, DrSpSP); -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) -{ - if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF) - { - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0); - } - } - else - { - if (!AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - m_Chunk->BroadcastSoundEffect("game.tnt.primed", static_cast(BlockX), static_cast(a_RelBlockY), static_cast(BlockZ), 0.5f, 0.6f); - m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_AIR, 0); - this->m_World.SpawnPrimedTNT(BlockX + 0.5, a_RelBlockY + 0.5, BlockZ + 0.5); // 80 ticks to boom - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - - typedef GetHandlerCompileTime::type DoorHandler; - - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) - { - cChunkInterface ChunkInterface(this->m_World.GetChunkMap()); - if (!DoorHandler::IsOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ)) - { - DoorHandler::SetOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ, true); - m_Chunk->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_DOOR_OPEN_CLOSE, BlockX, a_RelBlockY, BlockZ, 0); - } - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); - } - } - else - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) - { - cChunkInterface ChunkInterface(this->m_World.GetChunkMap()); - if (DoorHandler::IsOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ)) - { - DoorHandler::SetOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ, false); - m_Chunk->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_DOOR_OPEN_CLOSE, BlockX, a_RelBlockY, BlockZ, 0); - } - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - class cSetPowerToCommandBlock : - public cRedstonePoweredCallback - { - bool m_IsPowered; - public: - cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} - - virtual bool Item(cRedstonePoweredEntity * a_CommandBlock) override - { - a_CommandBlock->SetRedstonePower(m_IsPowered); - return false; - } - } CmdBlockSP(AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, CmdBlockSP); -} - - - - - -void cIncrementalRedstoneSimulator::HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType) -{ - switch (a_MyType) - { - case E_BLOCK_DETECTOR_RAIL: - { - if ((m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x08) == 0x08) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_MyType); - } - break; - } - case E_BLOCK_ACTIVATOR_RAIL: - case E_BLOCK_POWERED_RAIL: - { - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0x08); - } - else - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x07); - } - break; - } - default: LOGD("Unhandled type of rail in %s", __FUNCTION__); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) - { - this->m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, true); - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); - } - } - else - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) - { - this->m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, false); - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - bool m_bAreCoordsPowered = AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - - if (m_bAreCoordsPowered) - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) - { - class cSetPowerToNoteBlock : - public cRedstonePoweredCallback - { - public: - cSetPowerToNoteBlock() {} - - virtual bool Item(cRedstonePoweredEntity * a_NoteBlock) override - { - a_NoteBlock->SetRedstonePower(true); - return false; - } - } NoteBlockSP; - - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, NoteBlockSP); - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); - } - } - else - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) - { - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX, BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ); - - if (!m_World.IsChunkLighted(ChunkX, ChunkZ)) - { - m_World.QueueLightChunk(ChunkX, ChunkZ); - } - else - { - if (m_Chunk->GetTimeAlteredLight(m_Chunk->GetSkyLight(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ)) > 8) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - } - else - { - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - - switch (a_MyType) - { - case E_BLOCK_STONE_PRESSURE_PLATE: - { - // MCS feature - stone pressure plates can only be triggered by players :D - cPlayer * a_Player = this->m_World.FindClosestPlayer(Vector3f(BlockX + 0.5f, static_cast(a_RelBlockY), BlockZ + 0.5f), 0.5f, false); - - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (a_Player != nullptr) - { - if (Meta == E_META_PRESSURE_PLATE_RAISED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.5F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x1); - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM); - } - else - { - if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.6F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } - break; - } - case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: - { - class cPressurePlateCallback : - public cEntityCallback - { - public: - cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : - m_NumberOfEntities(0), - m_X(a_BlockX), - m_Y(a_BlockY), - m_Z(a_BlockZ) - { - } - - virtual bool Item(cEntity * a_Entity) override - { - Vector3f EntityPos = a_Entity->GetPosition(); - Vector3f BlockPos(m_X + 0.5f, static_cast(m_Y), m_Z + 0.5f); - double Distance = (EntityPos - BlockPos).Length(); - - if (Distance <= 0.5) - { - m_NumberOfEntities++; - } - return false; - } - - bool GetPowerLevel(unsigned char & a_PowerLevel) const - { - a_PowerLevel = static_cast(std::min(m_NumberOfEntities, MAX_POWER_LEVEL)); - return (a_PowerLevel > 0); - } - - protected: - int m_NumberOfEntities; - - int m_X; - int m_Y; - int m_Z; - }; - - cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); - - unsigned char Power; - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (PressurePlateCallback.GetPowerLevel(Power)) - { - if (Meta == E_META_PRESSURE_PLATE_RAISED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.5F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, Power); - } - else - { - if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.6F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } - - break; - } - case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: - { - class cPressurePlateCallback : - public cEntityCallback - { - public: - cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : - m_NumberOfEntities(0), - m_X(a_BlockX), - m_Y(a_BlockY), - m_Z(a_BlockZ) - { - } - - virtual bool Item(cEntity * a_Entity) override - { - Vector3f EntityPos = a_Entity->GetPosition(); - Vector3f BlockPos(m_X + 0.5f, static_cast(m_Y), m_Z + 0.5f); - double Distance = (EntityPos - BlockPos).Length(); - - if (Distance <= 0.5) - { - m_NumberOfEntities++; - } - return false; - } - - bool GetPowerLevel(unsigned char & a_PowerLevel) const - { - a_PowerLevel = static_cast(std::min(static_cast(ceil(m_NumberOfEntities / 10.f)), MAX_POWER_LEVEL)); - return (a_PowerLevel > 0); - } - - protected: - int m_NumberOfEntities; - - int m_X; - int m_Y; - int m_Z; - }; - - cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); - - unsigned char Power; - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (PressurePlateCallback.GetPowerLevel(Power)) - { - if (Meta == E_META_PRESSURE_PLATE_RAISED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.5F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, Power); - } - else - { - if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.6F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } - - break; - } - case E_BLOCK_WOODEN_PRESSURE_PLATE: - { - class cPressurePlateCallback : - public cEntityCallback - { - public: - cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : - m_FoundEntity(false), - m_X(a_BlockX), - m_Y(a_BlockY), - m_Z(a_BlockZ) - { - } - - virtual bool Item(cEntity * a_Entity) override - { - Vector3f EntityPos = a_Entity->GetPosition(); - Vector3f BlockPos(m_X + 0.5f, static_cast(m_Y), m_Z + 0.5f); - double Distance = (EntityPos - BlockPos).Length(); - - if (Distance <= 0.5) - { - m_FoundEntity = true; - return true; // Break out, we only need to know for plates that at least one entity is on top - } - return false; - } - - bool FoundEntity(void) const - { - return m_FoundEntity; - } - - protected: - bool m_FoundEntity; - - int m_X; - int m_Y; - int m_Z; - }; - - cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); - - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (PressurePlateCallback.FoundEntity()) - { - if (Meta == E_META_PRESSURE_PLATE_RAISED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.5F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM); - } - else - { - if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.6F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } - break; - } - default: - { - LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(cItem(a_MyType)).c_str()); - break; - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int RelX = a_RelBlockX, RelZ = a_RelBlockZ; - bool FoundActivated = false; - eBlockFace FaceToGoTowards = GetHandlerCompileTime::type::MetadataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - - for (int i = 0; i < 40; ++i) // Tripwires can be connected up to 40 blocks - { - BLOCKTYPE Type; - NIBBLETYPE Meta; - - AddFaceDirection(RelX, a_RelBlockY, RelZ, FaceToGoTowards); - m_Chunk->UnboundedRelGetBlock(RelX, a_RelBlockY, RelZ, Type, Meta); - - if (Type == E_BLOCK_TRIPWIRE) - { - if (Meta == 0x1) - { - FoundActivated = true; - } - } - else if (Type == E_BLOCK_TRIPWIRE_HOOK) - { - if (ReverseBlockFace(GetHandlerCompileTime::type::MetadataToDirection(Meta)) == FaceToGoTowards) - { - // Other hook facing in opposite direction - circuit completed! - break; - } - else - { - // Tripwire hook not connected at all, AND away all the power state bits - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - return; - } - } - else - { - // Tripwire hook not connected at all, AND away all the power state bits - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - return; - } - } - - if (FoundActivated) - { - // Connected and activated, set the 3rd and 4th highest bits - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0xC); - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - } - else - { - // Connected but not activated, AND away the highest bit - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7) | 0x4); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - class cGetTrappedChestPlayers : - public cItemCallback - { - public: - cGetTrappedChestPlayers(void) : - m_NumberOfPlayers(0) - { - } - - virtual ~cGetTrappedChestPlayers() - { - } - - virtual bool Item(cChestEntity * a_Chest) override - { - ASSERT(a_Chest->GetBlockType() == E_BLOCK_TRAPPED_CHEST); - m_NumberOfPlayers = a_Chest->GetNumberOfPlayers(); - return (m_NumberOfPlayers <= 0); - } - - unsigned char GetPowerLevel(void) const - { - return static_cast(std::min(m_NumberOfPlayers, MAX_POWER_LEVEL)); - } - - private: - int m_NumberOfPlayers; - - } GTCP; - - int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX; - int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ; - if (m_Chunk->DoWithChestAt(BlockX, a_RelBlockY, BlockZ, GTCP)) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, GTCP.GetPowerLevel()); - } - else - { - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleTripwire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX; - int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ; - - class cTripwireCallback : - public cEntityCallback - { - public: - cTripwireCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : - m_FoundEntity(false), - m_X(a_BlockX), - m_Y(a_BlockY), - m_Z(a_BlockZ) - { - } - - virtual bool Item(cEntity * a_Entity) override - { - cBoundingBox bbWire(m_X, m_X + 1, m_Y, m_Y + 0.1, m_Z, m_Z + 1); - cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); - - if (bbEntity.DoesIntersect(bbWire)) - { - m_FoundEntity = true; - return true; // One entity is sufficient to trigger the wire - } - return false; - } - - bool FoundEntity(void) const - { - return m_FoundEntity; - } - - protected: - bool m_FoundEntity; - - int m_X; - int m_Y; - int m_Z; - }; - - cTripwireCallback TripwireCallback(BlockX, a_RelBlockY, BlockZ); - this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), TripwireCallback); - - if (TripwireCallback.FoundEntity()) - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x1); - } - else - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); - } -} - - - - - -bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk) -{ - // Torches want to access neighbour's data when on a wall, hence the extra chunk parameter - - 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.m_BlockPos == Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }) != Data.end(); -} - - - - - -bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk) -{ - 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(); -} - - - - - -bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) -{ - // Repeaters cannot be powered by any face except their back; verify that this is true for a source - - for (const auto & itr : *m_PoweredBlocks) - { - if (!itr.m_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - continue; - } - - switch (a_Meta & 0x3) - { - case 0x0: - { - // Flip the coords to check the back of the repeater - if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1))) - { - return true; - } - break; - } - case 0x1: - { - if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - break; - } - case 0x2: - { - if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1))) - { - return true; - } - break; - } - case 0x3: - { - if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - break; - } - } - } // for itr - m_PoweredBlocks[] - - for (const auto & itr : *m_LinkedPoweredBlocks) - { - if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - continue; - } - - switch (a_Meta & 0x3) - { - case 0x0: - { - if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1))) - { - return true; - } - break; - } - case 0x1: - { - if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - break; - } - case 0x2: - { - if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1))) - { - return true; - } - break; - } - case 0x3: - { - if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - break; - } - } - } // for itr - m_LinkedPoweredBlocks[] - return false; // Couldn't find power source behind repeater -} - - - - - -bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) -{ - switch (a_Meta & 0x3) // We only want the 'direction' part of our metadata - { - // If the repeater is looking up or down (If parallel to the Z axis) - case 0x0: - case 0x2: - { - // Check if eastern (right) neighbor is a powered on repeater who is facing us - BLOCKTYPE Block = 0; - NIBBLETYPE OtherRepeaterDir = 0; - if ( - m_Chunk->UnboundedRelGetBlock(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, Block, OtherRepeaterDir) && - (Block == E_BLOCK_REDSTONE_REPEATER_ON) - ) - { - if ((OtherRepeaterDir & 0x03) == 0x3) - { - return true; - } // If so, I am latched / locked - } - - // Check if western(left) neighbor is a powered on repeater who is facing us - if ( - m_Chunk->UnboundedRelGetBlock(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, Block, OtherRepeaterDir) && - (Block == E_BLOCK_REDSTONE_REPEATER_ON) - ) - { - if ((OtherRepeaterDir & 0x03) == 0x1) - { - return true; - } // If so, I am latched / locked - } - - break; - } - - // If the repeater is looking left or right (If parallel to the x axis) - case 0x1: - case 0x3: - { - // Check if southern(down) neighbor is a powered on repeater who is facing us - BLOCKTYPE Block = 0; - NIBBLETYPE OtherRepeaterDir = 0; - - if ( - m_Chunk->UnboundedRelGetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, Block, OtherRepeaterDir) && - (Block == E_BLOCK_REDSTONE_REPEATER_ON) - ) - { - if ((OtherRepeaterDir & 0x30) == 0x00) - { - return true; - } // If so, I am latched / locked - } - - // Check if northern(up) neighbor is a powered on repeater who is facing us - if ( - m_Chunk->UnboundedRelGetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, Block, OtherRepeaterDir) && - (Block == E_BLOCK_REDSTONE_REPEATER_ON) - ) - { - if ((OtherRepeaterDir & 0x03) == 0x02) - { - return true; - } // If so, I am latched / locked - } - - break; - } - } - - return false; // None of the checks succeeded, I am not a locked repeater -} - - - - -bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) -{ - // Pistons cannot be powered through their front face; this function verifies that a source meets this requirement - - eBlockFace Face = GetHandlerCompileTime::type::MetaDataToDirection(a_Meta); - - for (const auto & itr : *m_PoweredBlocks) - { - if (!itr.m_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - continue; - } - - int X = a_RelBlockX, Z = a_RelBlockZ; - AddFaceDirection(X, a_RelBlockY, Z, Face); - - if (!itr.m_SourcePos.Equals(AdjustRelativeCoords(Vector3i(X, a_RelBlockY, Z)))) - { - return true; - } - } - - for (const auto & itr : *m_LinkedPoweredBlocks) - { - if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - continue; - } - - int X = a_RelBlockX, Z = a_RelBlockZ; - AddFaceDirection(X, a_RelBlockY, Z, Face); - - if (!itr.a_MiddlePos.Equals(AdjustRelativeCoords(Vector3i(X, a_RelBlockY, Z)))) - { - return true; - } - } - return false; // Source was in front of the piston's front face -} - - - - -unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPosition, cChunk * a_Chunk) -{ - unsigned char PowerLevel = 0; - - for (const auto & itr : static_cast(a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks) // Check powered list - { - if (itr.m_BlockPos != a_RelBlockPosition) - { - continue; - } - PowerLevel = std::max(itr.m_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 : static_cast(a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks) // Check linked powered list - { - if (itr.a_BlockPos != a_RelBlockPosition) - { - continue; - } - - BLOCKTYPE Type = E_BLOCK_AIR; - if (!a_Chunk->UnboundedRelGetBlockType(itr.a_SourcePos.x, itr.a_SourcePos.y, itr.a_SourcePos.z, Type) || (Type == E_BLOCK_REDSTONE_WIRE)) - { - continue; - } - PowerLevel = std::max(itr.a_PowerLevel, PowerLevel); - } - - return PowerLevel; -} - - - - - -bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered) -{ - for (const auto & itr : *m_SimulatedPlayerToggleableBlocks) - { - if (itr.first.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - if (itr.second != IsCurrentStatePowered) // Was the last power state different to the current? - { - return false; // It was, coordinates are no longer simulated - } - else - { - return true; // It wasn't, don't resimulate block, and allow players to toggle - } - } - } - return false; // Block wasn't even in the list, not simulated -} - - - - - -void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel) -{ - BLOCKTYPE MiddleBlock = 0; - switch (a_Direction) - { - case BLOCK_FACE_XM: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX - 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - case BLOCK_FACE_XP: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX + 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - case BLOCK_FACE_YM: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - case BLOCK_FACE_YP: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - case BLOCK_FACE_ZM: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - case BLOCK_FACE_ZP: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - default: - { - ASSERT(!"Unhandled face direction when attempting to set blocks as linked powered!"); // Zombies, that wasn't supposed to happen... - break; - } - } -} - - - - - -void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel) -{ - static const Vector3i Offsets[] = - { - {1, 0, 0}, - { -1, 0, 0}, - {0, 0, 1}, - {0, 0, -1}, - {0, 1, 0}, - {0, -1, 0} - }; - - for (auto Offset : Offsets) // Loop through struct to power all directions - { - SetBlockPowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ) + Offset, Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), a_PowerLevel); - } -} - - - - - -void cIncrementalRedstoneSimulator::SetBlockPowered(Vector3i a_RelBlockPosition, Vector3i a_RelSourcePosition, unsigned char a_PowerLevel) -{ - cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockPosition.x, a_RelBlockPosition.z); // Adjust coordinates for the later call using these values - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - a_RelSourcePosition.x += (m_Chunk->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width; - a_RelSourcePosition.z += (m_Chunk->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width; - - 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) - { - if ((itr.m_BlockPos == a_RelBlockPosition) && (itr.m_SourcePos == a_RelSourcePosition)) - { - if (itr.m_PowerLevel != a_PowerLevel) - { - // Update power level, don't add a new listing - Neighbour->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); - itr.m_PowerLevel = a_PowerLevel; - } - return; - } - } - - Powered.emplace_back(a_RelBlockPosition, a_RelSourcePosition, a_PowerLevel); - Neighbour->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); -} - - - - - -void cIncrementalRedstoneSimulator::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_MiddleBlock, unsigned char a_PowerLevel - ) -{ - if (!IsViableMiddleBlock(a_MiddleBlock)) - { - return; - } - - cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ); - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - a_RelMiddleX += (m_Chunk->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width; - a_RelMiddleZ += (m_Chunk->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width; - a_RelSourceX += (m_Chunk->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width; - a_RelSourceZ += (m_Chunk->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width; - - auto & Linked = static_cast(Neighbour->GetRedstoneSimulatorData())->m_LinkedBlocks; - for (auto & itr : Linked) // Check linked powered list - { - if ( - itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) && - itr.a_MiddlePos.Equals(Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)) && - itr.a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ)) - ) - { - if (itr.a_PowerLevel != a_PowerLevel) - { - // Update power level, don't add a new listing - Neighbour->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); - itr.a_PowerLevel = a_PowerLevel; - } - return; - } - } - - sLinkedPoweredBlocks RC; - RC.a_BlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - RC.a_MiddlePos = Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ); - RC.a_SourcePos = Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ); - RC.a_PowerLevel = a_PowerLevel; - Linked.emplace_back(RC); - Neighbour->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); -} - - - - - -void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool a_WasLastStatePowered) -{ - m_SimulatedPlayerToggleableBlocks->operator[](Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) = a_WasLastStatePowered; -} - - - - - -void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool a_ShouldPowerOn) -{ - sRepeatersDelayList RC; - - // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.) - // Multiply by 2 because in MCS, 1 redstone tick = 1 world tick, but in Vanilla, 1 redstone tick = 2 world ticks, and we need to maintain compatibility - RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; - RC.a_ElapsedTicks = 0; - RC.ShouldPowerOn = a_ShouldPowerOn; - - auto Result = m_RepeatersDelayList->emplace(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), RC); - if (!Result.second) - { - // Key exists - if (a_ShouldPowerOn == Result.first->second.ShouldPowerOn) - { - // We are queued already for the same thing, don't replace entry - return; - } - - Result.first->second.a_DelayTicks = RC.a_DelayTicks; - Result.first->second.a_ElapsedTicks = 0; - Result.first->second.ShouldPowerOn = a_ShouldPowerOn; - } -} - - - - - -void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk) -{ - if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) - { - return; - } - std::vector> BlocksPotentiallyUnpowered = { std::make_pair(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ), a_Chunk) }; - - auto UnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_LambdaChunk, const Vector3i & a_RelSource) - { - BLOCKTYPE RepeaterType; - if (a_LambdaChunk->UnboundedRelGetBlockType(a_RelSource.x, a_RelSource.y, a_RelSource.z, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) - { - return; - } - - auto Data = static_cast(a_LambdaChunk->GetRedstoneSimulatorData()); - Data->m_PoweredBlocks.erase(std::remove_if(Data->m_PoweredBlocks.begin(), Data->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, a_LambdaChunk, a_RelSource](const sPoweredBlocks & itr) - { - if (itr.m_SourcePos != a_RelSource) - { - return false; - } - - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.m_BlockPos, a_LambdaChunk)); - a_LambdaChunk->SetIsRedstoneDirty(true); - return true; - } - ), Data->m_PoweredBlocks.end()); - - Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_LambdaChunk, a_RelSource](const sLinkedPoweredBlocks & itr) - { - if (itr.a_SourcePos != a_RelSource) - { - return false; - } - - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_LambdaChunk)); - a_LambdaChunk->SetIsRedstoneDirty(true); - return true; - } - ), Data->m_LinkedBlocks.end()); - - for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_LambdaChunk)) - { - auto BoundaryData = static_cast(BoundaryChunk->GetRedstoneSimulatorData()); - Vector3i ChunkAdjustedSource = a_RelSource; - ChunkAdjustedSource.x += (a_LambdaChunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; - ChunkAdjustedSource.z += (a_LambdaChunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; - - if ( - (std::find_if(BoundaryData->m_PoweredBlocks.begin(), BoundaryData->m_PoweredBlocks.end(), [ChunkAdjustedSource](const sPoweredBlocks & itr) { return (itr.m_SourcePos == ChunkAdjustedSource); }) != BoundaryData->m_PoweredBlocks.end()) || - (std::find_if(BoundaryData->m_LinkedBlocks.begin(), BoundaryData->m_LinkedBlocks.end(), [ChunkAdjustedSource](const sLinkedPoweredBlocks & itr) { return (itr.a_SourcePos == ChunkAdjustedSource); }) != BoundaryData->m_LinkedBlocks.end()) - ) - { - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(ChunkAdjustedSource, BoundaryChunk)); - } - } - }; - - while (!BlocksPotentiallyUnpowered.empty()) - { - auto End = BlocksPotentiallyUnpowered.back(); - BlocksPotentiallyUnpowered.pop_back(); - UnpoweringFunction(End.second, End.first); - } -} - - - - - -void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk) -{ - std::vector> BlocksPotentiallyUnpowered; - - BLOCKTYPE RepeaterType; - if (a_Chunk->UnboundedRelGetBlockType(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) - { - return; - } - - auto MiddleBlockUnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_LambdaChunk, const Vector3i & a_RelMiddle) - { - auto Data = static_cast(a_LambdaChunk->GetRedstoneSimulatorData()); - Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_LambdaChunk, a_RelMiddle](const sLinkedPoweredBlocks & itr) - { - if (itr.a_MiddlePos != a_RelMiddle) - { - return false; - } - - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_LambdaChunk)); - a_LambdaChunk->SetIsRedstoneDirty(true); - return true; - } - ), Data->m_LinkedBlocks.end()); - }; - - MiddleBlockUnpoweringFunction(a_Chunk, Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)); - for (const auto & BoundaryChunk : GetAdjacentChunks(Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ), a_Chunk)) - { - Vector3i ChunkAdjustedMiddlePos = Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ); - ChunkAdjustedMiddlePos.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; - ChunkAdjustedMiddlePos.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; - - MiddleBlockUnpoweringFunction(a_Chunk, Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)); - } - - for (const auto & itr : BlocksPotentiallyUnpowered) - { - if (!AreCoordsPowered(itr.first.x, itr.first.y, itr.first.z)) - { - SetSourceUnpowered(itr.first.x, itr.first.y, itr.first.z, itr.second); - } - } -} - - - - - -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) -{ - std::vector AdjacentChunks; - AdjacentChunks.reserve(2); // At most bordering two chunks; reserve that many - - auto CheckAndEmplace = [&AdjacentChunks](cChunk * a_LambdaChunk) - { - if ((a_LambdaChunk != nullptr) && a_LambdaChunk->IsValid()) - { - AdjacentChunks.emplace_back(a_LambdaChunk); - } - }; - - // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks - if (a_RelBlockPosition.x <= 1) - { - CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x - 2, a_RelBlockPosition.z)); - } - if (a_RelBlockPosition.x >= 14) - { - CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x + 2, a_RelBlockPosition.z)); - } - if (a_RelBlockPosition.z <= 1) - { - CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z - 2)); - } - if (a_RelBlockPosition.z >= 14) - { - CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z + 2)); - } - - return AdjacentChunks; -} - - - - -- cgit v1.2.3