summaryrefslogtreecommitdiffstats
path: root/src/Simulator
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Simulator/CMakeLists.txt3
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp2298
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.h419
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt38
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h70
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h59
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h69
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp170
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h167
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h71
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/PistonHandler.h68
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/PoweredRailHandler.h100
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/PressurePlateHandler.h111
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/RedstoneBlockHandler.h51
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/RedstoneComparatorHandler.h128
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.h130
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/RedstoneLampHandler.h62
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h73
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/RedstoneSimulatorChunkData.h70
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/RedstoneToggleHandler.h111
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/RedstoneTorchHandler.h99
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h134
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/SmallGateHandler.h56
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/SolidBlockHandler.h71
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/TNTHandler.h58
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h93
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h136
-rw-r--r--src/Simulator/NoopRedstoneSimulator.h2
-rw-r--r--src/Simulator/RedstoneSimulator.h25
29 files changed, 2213 insertions, 2729 deletions
diff --git a/src/Simulator/CMakeLists.txt b/src/Simulator/CMakeLists.txt
index 966acd264..a798e4b02 100644
--- a/src/Simulator/CMakeLists.txt
+++ b/src/Simulator/CMakeLists.txt
@@ -9,7 +9,6 @@ SET (SRCS
FireSimulator.cpp
FloodyFluidSimulator.cpp
FluidSimulator.cpp
- IncrementalRedstoneSimulator.cpp
SandSimulator.cpp
Simulator.cpp
SimulatorManager.cpp
@@ -21,7 +20,6 @@ SET (HDRS
FireSimulator.h
FloodyFluidSimulator.h
FluidSimulator.h
- IncrementalRedstoneSimulator.h
NoopFluidSimulator.h
NoopRedstoneSimulator.h
RedstoneSimulator.h
@@ -35,7 +33,6 @@ SET (HDRS
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set_source_files_properties(FireSimulator.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=sign-conversion")
set_source_files_properties(FluidSimulator.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=sign-conversion -Wno-error=shadow")
- set_source_files_properties(IncrementalRedstoneSimulator.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=conversion ")
endif()
if(NOT MSVC)
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<cIncrementalRedstoneSimulatorChunkData *>(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<cIncrementalRedstoneSimulatorChunkData *>(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<E_BLOCK_TORCH>::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<E_BLOCK_TORCH>::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<E_BLOCK_LEVER>::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<E_BLOCK_STONE_BUTTON>::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<std::pair<Vector3i, cChunk *>> 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<std::pair<Vector3i, cChunk *>> & 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<std::pair<Vector3i, cChunk *>> & 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<cIncrementalRedstoneSimulatorChunkData *>(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<cBlockEntityWithItems *>(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<unsigned char>(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<unsigned char>(RearPower - HighestSidePower), std::numeric_limits<unsigned char>::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<E_BLOCK_PISTON>::type::ExtendPiston(Vector3i(BlockX, a_RelBlockY, BlockZ), &this->m_World);
- }
- else
- {
- GetHandlerCompileTime<E_BLOCK_PISTON>::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<double>(BlockX), static_cast<double>(a_RelBlockY), static_cast<double>(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<E_BLOCK_OAK_DOOR>::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<float>(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<double>(BlockX) + 0.5, static_cast<double>(a_RelBlockY) + 0.1, static_cast<double>(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<double>(BlockX) + 0.5, static_cast<double>(a_RelBlockY) + 0.1, static_cast<double>(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<float>(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<unsigned char>(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<double>(BlockX) + 0.5, static_cast<double>(a_RelBlockY) + 0.1, static_cast<double>(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<double>(BlockX) + 0.5, static_cast<double>(a_RelBlockY) + 0.1, static_cast<double>(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<float>(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<Byte>(std::min(static_cast<int>(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<double>(BlockX) + 0.5, static_cast<double>(a_RelBlockY) + 0.1, static_cast<double>(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<double>(BlockX) + 0.5, static_cast<double>(a_RelBlockY) + 0.1, static_cast<double>(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<float>(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<double>(BlockX) + 0.5, static_cast<double>(a_RelBlockY) + 0.1, static_cast<double>(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<double>(BlockX) + 0.5, static_cast<double>(a_RelBlockY) + 0.1, static_cast<double>(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<E_BLOCK_TRIPWIRE_HOOK>::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<E_BLOCK_TRIPWIRE_HOOK>::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<cChestEntity>
- {
- 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<unsigned char>(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<cIncrementalRedstoneSimulatorChunkData *>(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<cIncrementalRedstoneSimulatorChunkData *>(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<E_BLOCK_PISTON>::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<cIncrementalRedstoneSimulatorChunkData *>(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<cIncrementalRedstoneSimulatorChunkData *>(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<cIncrementalRedstoneSimulatorChunkData *>(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<cIncrementalRedstoneSimulatorChunkData *>(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<std::pair<Vector3i, cChunk *>> 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<cIncrementalRedstoneSimulatorChunkData *>(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<cIncrementalRedstoneSimulatorChunkData *>(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<std::pair<Vector3i, cChunk *>> 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<cIncrementalRedstoneSimulatorChunkData *>(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<cChunk *> cIncrementalRedstoneSimulator::GetAdjacentChunks(const Vector3i & a_RelBlockPosition, cChunk * a_Chunk)
-{
- std::vector<cChunk *> 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;
-}
-
-
-
-
diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h
deleted file mode 100644
index 429bc6785..000000000
--- a/src/Simulator/IncrementalRedstoneSimulator.h
+++ /dev/null
@@ -1,419 +0,0 @@
-
-#pragma once
-
-#include "RedstoneSimulator.h"
-#include "BlockEntities/RedstonePoweredEntity.h"
-#include <unordered_map>
-
-class cWorld;
-class cChunk;
-
-
-
-
-
-typedef cItemCallback<cRedstonePoweredEntity> cRedstonePoweredCallback;
-
-
-
-class cIncrementalRedstoneSimulator :
- public cRedstoneSimulator
-{
- typedef cRedstoneSimulator super;
-public:
-
- cIncrementalRedstoneSimulator(cWorld & a_World)
- : cRedstoneSimulator(a_World),
- m_Chunk(nullptr)
- {
- }
-
- virtual cRedstoneSimulatorChunkData * CreateChunkData() override
- {
- return new cIncrementalRedstoneSimulatorChunkData;
- }
-
- virtual void Simulate(float a_Dt) override { UNUSED(a_Dt); } // not used
- virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override;
- 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;
-
-private:
-
-#define MAX_POWER_LEVEL 15
-
- struct sPoweredBlocks // Define structure of the directly powered blocks list
- {
- sPoweredBlocks(Vector3i a_BlockPos, Vector3i a_SourcePos, unsigned char a_PowerLevel) :
- m_BlockPos(a_BlockPos),
- m_SourcePos(a_SourcePos),
- m_PowerLevel(a_PowerLevel)
- {
- }
-
- Vector3i m_BlockPos; // Position of powered block
- Vector3i m_SourcePos; // Position of source powering the block at a_BlockPos
- unsigned char m_PowerLevel;
- };
-
- struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side)
- {
- Vector3i a_BlockPos;
- Vector3i a_MiddlePos; // Position of block that is betwixt a source and the destination
- Vector3i a_SourcePos;
- unsigned char a_PowerLevel;
- };
-
- struct sRepeatersDelayList // Define structure of list containing repeaters' delay states
- {
- unsigned char a_DelayTicks; // For how many ticks should the repeater delay
- unsigned char a_ElapsedTicks; // How much of the previous has been elapsed?
- bool ShouldPowerOn; // What happens when the delay time is fulfilled?
- };
-
- /** Per-chunk data for the simulator, specified individual chunks to simulate */
- class cIncrementalRedstoneSimulatorChunkData :
- public cRedstoneSimulatorChunkData
- {
- public:
- /** test */
- std::unordered_map<Vector3i, std::pair<BLOCKTYPE, bool>, VectorHasher<int>> m_ChunkData;
- std::vector<sPoweredBlocks> m_PoweredBlocks;
- std::vector<sLinkedPoweredBlocks> m_LinkedBlocks;
- std::unordered_map<Vector3i, bool, VectorHasher<int>> m_SimulatedPlayerToggleableBlocks;
- std::unordered_map<Vector3i, sRepeatersDelayList, VectorHasher<int>> m_RepeatersDelayList;
- };
-
-public:
-
- typedef std::vector <sPoweredBlocks> PoweredBlocksList;
- typedef std::vector <sLinkedPoweredBlocks> LinkedBlocksList;
- typedef std::unordered_map<Vector3i, bool, VectorHasher<int>> SimulatedPlayerToggleableList;
- typedef std::unordered_map<Vector3i, sRepeatersDelayList, VectorHasher<int>> RepeatersDelayList;
-
-private:
-
- cIncrementalRedstoneSimulatorChunkData * m_RedstoneSimulatorChunkData;
- PoweredBlocksList * m_PoweredBlocks;
- LinkedBlocksList * m_LinkedPoweredBlocks;
- SimulatedPlayerToggleableList * m_SimulatedPlayerToggleableBlocks;
- RepeatersDelayList * m_RepeatersDelayList;
-
- 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
- // In addition to being non-performant, it would stop the player from actually breaking said device
-
-
- /** Handles the redstone torch */
- void HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
-
- /** Handles the redstone block */
- void HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles levers */
- void HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles buttons */
- void HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles daylight sensors */
- void HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles pressure plates */
- void HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType);
-
- /** Handles tripwire hooks
- Performs correct meta and power setting for self by going in the direction it faces and looking for a continous line of tripwire bounded by another oppositely facing hook
- If this line is complete, it verifies that at least on wire reports an entity is on top (via its meta), and performs its task
- */
- void HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles trapped chests */
- void HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
-
- /** Handles redstone wire */
- void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles repeaters */
- void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
-
- /** Handles comparators */
- void HandleRedstoneComparator(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
-
- /** Handles pistons */
- void HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles dispensers and droppers */
- void HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles TNT (exploding) */
- void HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles redstone lamps */
- void HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
-
- /** Handles doords */
- void HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles command blocks */
- void HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles activator, detector, and powered rails */
- void HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType);
-
- /** Handles trapdoors */
- void HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles fence gates */
- void HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles noteblocks */
- void HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
- /** Handles tripwires */
- void HandleTripwire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
-
-
- /** Marks a block as powered */
- 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<std::pair<Vector3i, cChunk *>> & a_PotentialWireList, const Vector3i & a_EntryRelBlockPosition, cChunk * a_EntryChunk);
-
- /** Powers a specified wire block position with the specified source wire position
- Checks are performed to ensure one wire does not power the same location more than once
- a_EntryChunk will be the chunk which the source resides, and a_NeighbourChunk will be that which the to-be-powered wire resides
- a_PotentialWireList is updated to include the new powered wire so that FindAndPowerBorderingWires can continue the redstone wire line tracing process
- */
- void PowerBorderingWires(std::vector<std::pair<Vector3i, cChunk *>> & a_PotentialWireList, const Vector3i & a_EntryRelSourcePosition, cChunk * a_EntryChunk, const Vector3i & a_AdjustedPos, cChunk * a_NeighbourChunk, unsigned char a_MyPower);
-
- /** 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);
-
- /** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */
- void SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered);
-
- /** Marks the second block in a direction as linked powered */
- void SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
-
- /** Marks all blocks immediately surrounding a coordinate as powered */
- void SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
-
- /** Queues a repeater to be powered or unpowered and returns if the m_RepeatersDelayList iterators were invalidated */
- void QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn);
-
- /** Removes a block from the Powered and LinkedPowered lists
- Recursively removes all blocks powered by the given one
- */
- void SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk);
- void SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk);
-
- /** 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, m_Chunk); }
-
- /** Returns if a coordinate is in the directly powered blocks list */
- 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 */
- 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);
-
- /** Returns if a repeater is powered by testing for power sources behind the repeater */
- bool IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
-
- /** Returns if a repeater is locked */
- bool IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
-
- /** Returns if a piston is powered */
- bool IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
-
- /** 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 */
- static unsigned char IsWirePowered(Vector3i a_RelBlockPosition, cChunk * a_Chunk);
-
- /** Handles delayed updates to repeaters */
- void HandleRedstoneRepeaterDelays(void);
-
- /** Returns if lever metadata marks it as emitting power */
- bool IsLeverOn(NIBBLETYPE a_BlockMeta);
-
- /** Returns if button metadata marks it as emitting power */
- bool IsButtonOn(NIBBLETYPE a_BlockMeta) { return IsLeverOn(a_BlockMeta); }
-
-
- /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */
- 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 a_Block)
- {
- switch (a_Block)
- {
- case E_BLOCK_ACACIA_DOOR:
- case E_BLOCK_ACACIA_FENCE_GATE:
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_ACTIVE_COMPARATOR:
- case E_BLOCK_BIRCH_DOOR:
- case E_BLOCK_BIRCH_FENCE_GATE:
- case E_BLOCK_COMMAND_BLOCK:
- case E_BLOCK_DARK_OAK_DOOR:
- case E_BLOCK_DARK_OAK_FENCE_GATE:
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DROPPER:
- case E_BLOCK_OAK_FENCE_GATE:
- case E_BLOCK_HOPPER:
- case E_BLOCK_INACTIVE_COMPARATOR:
- case E_BLOCK_IRON_DOOR:
- case E_BLOCK_IRON_TRAPDOOR:
- case E_BLOCK_JUNGLE_DOOR:
- case E_BLOCK_JUNGLE_FENCE_GATE:
- case E_BLOCK_NOTE_BLOCK:
- case E_BLOCK_PISTON:
- case E_BLOCK_POWERED_RAIL:
- case E_BLOCK_REDSTONE_LAMP_OFF:
- case E_BLOCK_REDSTONE_LAMP_ON:
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- case E_BLOCK_REDSTONE_WIRE:
- case E_BLOCK_SPRUCE_DOOR:
- case E_BLOCK_SPRUCE_FENCE_GATE:
- case E_BLOCK_STICKY_PISTON:
- case E_BLOCK_TNT:
- case E_BLOCK_TRAPDOOR:
- case E_BLOCK_OAK_DOOR:
- {
- return true;
- }
- default: return false;
- }
- }
-
- /** Returns if a block has the potential to output power */
- inline static bool IsPotentialSource(BLOCKTYPE a_Block)
- {
- switch (a_Block)
- {
- case E_BLOCK_DETECTOR_RAIL:
- case E_BLOCK_DAYLIGHT_SENSOR:
- case E_BLOCK_WOODEN_BUTTON:
- case E_BLOCK_STONE_BUTTON:
- case E_BLOCK_REDSTONE_WIRE:
- case E_BLOCK_REDSTONE_TORCH_ON:
- case E_BLOCK_LEVER:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- case E_BLOCK_BLOCK_OF_REDSTONE:
- case E_BLOCK_ACTIVE_COMPARATOR:
- case E_BLOCK_INACTIVE_COMPARATOR:
- case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
- case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
- case E_BLOCK_STONE_PRESSURE_PLATE:
- case E_BLOCK_WOODEN_PRESSURE_PLATE:
- case E_BLOCK_TRAPPED_CHEST:
- {
- return true;
- }
- default: return false;
- }
- }
-
- /** Returns if a block is any sort of redstone device */
- inline static bool IsRedstone(BLOCKTYPE a_Block)
- {
- switch (a_Block)
- {
- // All redstone devices, please alpha sort
- case E_BLOCK_ACACIA_DOOR:
- case E_BLOCK_ACACIA_FENCE_GATE:
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_ACTIVE_COMPARATOR:
- case E_BLOCK_BIRCH_DOOR:
- case E_BLOCK_BIRCH_FENCE_GATE:
- case E_BLOCK_BLOCK_OF_REDSTONE:
- case E_BLOCK_COMMAND_BLOCK:
- case E_BLOCK_DARK_OAK_DOOR:
- case E_BLOCK_DARK_OAK_FENCE_GATE:
- case E_BLOCK_DAYLIGHT_SENSOR:
- case E_BLOCK_DETECTOR_RAIL:
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DROPPER:
- case E_BLOCK_OAK_FENCE_GATE:
- case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
- case E_BLOCK_HOPPER:
- case E_BLOCK_INACTIVE_COMPARATOR:
- case E_BLOCK_IRON_DOOR:
- case E_BLOCK_IRON_TRAPDOOR:
- case E_BLOCK_JUNGLE_DOOR:
- case E_BLOCK_JUNGLE_FENCE_GATE:
- case E_BLOCK_LEVER:
- case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
- case E_BLOCK_NOTE_BLOCK:
- case E_BLOCK_POWERED_RAIL:
- case E_BLOCK_REDSTONE_LAMP_OFF:
- case E_BLOCK_REDSTONE_LAMP_ON:
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- case E_BLOCK_REDSTONE_TORCH_OFF:
- case E_BLOCK_REDSTONE_TORCH_ON:
- case E_BLOCK_REDSTONE_WIRE:
- case E_BLOCK_SPRUCE_DOOR:
- case E_BLOCK_SPRUCE_FENCE_GATE:
- case E_BLOCK_STICKY_PISTON:
- case E_BLOCK_STONE_BUTTON:
- case E_BLOCK_STONE_PRESSURE_PLATE:
- case E_BLOCK_TNT:
- case E_BLOCK_TRAPDOOR:
- case E_BLOCK_TRAPPED_CHEST:
- case E_BLOCK_TRIPWIRE_HOOK:
- case E_BLOCK_TRIPWIRE:
- case E_BLOCK_WOODEN_BUTTON:
- case E_BLOCK_OAK_DOOR:
- case E_BLOCK_WOODEN_PRESSURE_PLATE:
- case E_BLOCK_PISTON:
- {
- return true;
- }
- default: return false;
- }
- }
-
- inline static bool DoesIgnorePlayerToggle(BLOCKTYPE a_Block)
- {
- 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_OAK_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<cChunk *> GetAdjacentChunks(const Vector3i & a_RelBlockPosition, cChunk * a_Chunk);
-
- inline static Vector3i AdjustRelativeCoords(const Vector3i & a_RelPosition)
- {
- return { (a_RelPosition.x % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width, a_RelPosition.y, (a_RelPosition.z % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width };
- }
-};
-
-
-
-
diff --git a/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt b/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt
new file mode 100644
index 000000000..e37f3595c
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required (VERSION 2.6)
+project (MCServer)
+
+include_directories ("${PROJECT_SOURCE_DIR}/../")
+
+set (SRCS
+ IncrementalRedstoneSimulator.cpp
+)
+
+set (HDRS
+ CommandBlockHandler.h
+ DoorHandler.h
+ DropSpenserHandler.h
+ IncrementalRedstoneSimulator.h
+ RedstoneHandler.h
+ RedstoneSimulatorChunkData.h
+ SolidBlockHandler.h
+ RedstoneComparatorHandler.h
+ RedstoneRepeaterHandler.h
+ RedstoneBlockHandler.h
+ RedstoneTorchHandler.h
+ RedstoneWireHandler.h
+ RedstoneLampHandler.h
+ RedstoneToggleHandler.h
+ PistonHandler.h
+ SmallGateHandler.h
+ NoteBlockHandler.h
+ TNTHandler.h
+ TrappedChestHandler.h
+ TripwireHookHandler.h
+ PoweredRailHandler.h
+ PressurePlateHandler.h
+)
+
+if(NOT MSVC)
+ add_library(IncrementalRedstoneSimulator ${SRCS} ${HDRS})
+endif()
+
diff --git a/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h
new file mode 100644
index 000000000..ddf66ba43
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h
@@ -0,0 +1,70 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "BlockEntities/CommandBlockEntity.h"
+
+
+
+
+
+class cCommandBlockHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cCommandBlockHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ UNUSED(a_QueryPosition);
+ UNUSED(a_QueryBlockType);
+ return 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating commander the cmdblck (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+
+ auto Previous = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
+ if ((Previous.PowerLevel != 0) || (a_PoweringData.PowerLevel == 0))
+ {
+ // If we're already powered or received an update of no power, don't activate
+ return {};
+ }
+
+ class cSetPowerToCommandBlock : public cCommandBlockCallback
+ {
+ public:
+ virtual bool Item(cCommandBlockEntity * a_CommandBlock) override
+ {
+ a_CommandBlock->Activate();
+ return false;
+ }
+ } CmdBlockSP;
+
+ m_World.DoWithCommandBlockAt(a_Position.x, a_Position.y, a_Position.z, CmdBlockSP);
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());;
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h b/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h
new file mode 100644
index 000000000..45bdb06fe
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h
@@ -0,0 +1,59 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "Blocks/BlockDoor.h"
+
+
+
+
+
+class cDoorHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cDoorHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ UNUSED(a_QueryPosition);
+ UNUSED(a_QueryBlockType);
+ return 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating dori the door (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+
+ if (a_PoweringData != static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData))
+ {
+ cChunkInterface ChunkInterface(m_World.GetChunkMap());
+ cBlockDoorHandler::SetOpen(ChunkInterface, a_Position.x, a_Position.y, a_Position.z, (a_PoweringData.PowerLevel != 0));
+ m_World.BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_DOOR_OPEN_CLOSE, a_Position.x, a_Position.y, a_Position.z, 0);
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());;
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h b/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h
new file mode 100644
index 000000000..69268f004
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h
@@ -0,0 +1,69 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "BlockEntities/DropSpenserEntity.h"
+
+
+
+
+
+class cDropSpenserHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cDropSpenserHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ UNUSED(a_QueryPosition);
+ UNUSED(a_QueryBlockType);
+ return 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating spencer the dropspenser (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+
+ if (a_PoweringData.PowerLevel > 0)
+ {
+ class cSetPowerToDropSpenser :
+ public cDropSpenserCallback
+ {
+ public:
+ virtual bool Item(cDropSpenserEntity * a_DropSpenser) override
+ {
+ a_DropSpenser->Activate();
+ return false;
+ }
+ } DrSpSP;
+
+ m_World.DoWithDropSpenserAt(a_Position.x, a_Position.y, a_Position.z, DrSpSP);
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+
+ return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp
new file mode 100644
index 000000000..f0a913757
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp
@@ -0,0 +1,170 @@
+
+
+#include "Globals.h"
+
+#include "IncrementalRedstoneSimulator.h"
+#include "Chunk.h"
+
+#include "CommandBlockHandler.h"
+#include "DoorHandler.h"
+#include "RedstoneHandler.h"
+#include "RedstoneTorchHandler.h"
+#include "RedstoneWireHandler.h"
+#include "RedstoneRepeaterHandler.h"
+#include "RedstoneToggleHandler.h"
+#include "SolidBlockHandler.h"
+#include "RedstoneLampHandler.h"
+#include "RedstoneBlockHandler.h"
+#include "PistonHandler.h"
+#include "SmallGateHandler.h"
+#include "NoteBlockHandler.h"
+#include "TNTHandler.h"
+#include "PoweredRailHandler.h"
+#include "PressurePlateHandler.h"
+#include "TripwireHookHandler.h"
+#include "DropSpenserHandler.h"
+#include "RedstoneComparatorHandler.h"
+#include "TrappedChestHandler.h"
+
+
+
+
+
+std::unique_ptr<cRedstoneHandler> cIncrementalRedstoneSimulator::CreateComponent(cWorld & a_World, BLOCKTYPE a_BlockType, cIncrementalRedstoneSimulatorChunkData * a_Data)
+{
+ switch (a_BlockType)
+ {
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_DETECTOR_RAIL:
+ case E_BLOCK_POWERED_RAIL: return cpp14::make_unique<cPoweredRailHandler>(a_World);
+
+ case E_BLOCK_ACTIVE_COMPARATOR:
+ case E_BLOCK_INACTIVE_COMPARATOR: return cpp14::make_unique<cRedstoneComparatorHandler>(a_World);
+
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DROPPER: return cpp14::make_unique<cDropSpenserHandler>(a_World);
+
+ case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
+ case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
+ case E_BLOCK_STONE_PRESSURE_PLATE:
+ case E_BLOCK_WOODEN_PRESSURE_PLATE: return cpp14::make_unique<cPressurePlateHandler>(a_World);
+
+ case E_BLOCK_FENCE_GATE:
+ case E_BLOCK_IRON_TRAPDOOR:
+ case E_BLOCK_TRAPDOOR: return cpp14::make_unique<cSmallGateHandler>(a_World);
+
+ case E_BLOCK_REDSTONE_LAMP_OFF:
+ case E_BLOCK_REDSTONE_LAMP_ON: return cpp14::make_unique<cRedstoneLampHandler>(a_World);
+
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_REDSTONE_REPEATER_ON: return cpp14::make_unique<cRedstoneRepeaterHandler>(a_World);
+
+ case E_BLOCK_REDSTONE_TORCH_OFF:
+ case E_BLOCK_REDSTONE_TORCH_ON: return cpp14::make_unique<cRedstoneTorchHandler>(a_World);
+
+ case E_BLOCK_PISTON:
+ case E_BLOCK_STICKY_PISTON: return cpp14::make_unique<cPistonHandler>(a_World);
+
+ case E_BLOCK_LEVER:
+ case E_BLOCK_STONE_BUTTON:
+ case E_BLOCK_WOODEN_BUTTON: return cpp14::make_unique<cRedstoneToggleHandler>(a_World);
+
+ case E_BLOCK_BLOCK_OF_REDSTONE: return cpp14::make_unique<cRedstoneBlockHandler>(a_World);
+ case E_BLOCK_COMMAND_BLOCK: return cpp14::make_unique<cCommandBlockHandler>(a_World);
+ case E_BLOCK_NOTE_BLOCK: return cpp14::make_unique<cNoteBlockHandler>(a_World);
+ case E_BLOCK_REDSTONE_WIRE: return cpp14::make_unique<cRedstoneWireHandler>(a_World);
+ case E_BLOCK_TNT: return cpp14::make_unique<cTNTHandler>(a_World);
+ case E_BLOCK_TRAPPED_CHEST: return cpp14::make_unique<cTrappedChestHandler>(a_World);
+ case E_BLOCK_TRIPWIRE_HOOK: return cpp14::make_unique<cTripwireHookHandler>(a_World);
+ default:
+ {
+ if (cBlockDoorHandler::IsDoorBlockType(a_BlockType))
+ {
+ return cpp14::make_unique<cDoorHandler>(a_World);
+ }
+
+ if (cBlockInfo::FullyOccupiesVoxel(a_BlockType))
+ {
+ return cpp14::make_unique<cSolidBlockHandler>(a_World);
+ }
+ return nullptr;
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::Simulate(float a_dt)
+{
+ for (auto & DelayInfo : m_Data.m_MechanismDelays)
+ {
+ if ((--DelayInfo.second.first) == 0)
+ {
+ m_Data.GetActiveBlocks().emplace_back(DelayInfo.first);
+ }
+ }
+
+ // Build our work queue
+ cVector3iArray WorkQueue;
+ std::swap(WorkQueue, m_Data.GetActiveBlocks());
+
+ // Process the work queue
+ while (!WorkQueue.empty())
+ {
+ // Grab the first element and remove it from the list
+ Vector3i CurrentLocation = WorkQueue.back();
+ WorkQueue.pop_back();
+
+ BLOCKTYPE CurrentBlock;
+ NIBBLETYPE CurrentMeta;
+ if (!m_World.GetBlockTypeMeta(CurrentLocation.x, CurrentLocation.y, CurrentLocation.z, CurrentBlock, CurrentMeta))
+ {
+ continue;
+ }
+
+ auto CurrentHandler = std::move(cIncrementalRedstoneSimulator::CreateComponent(m_World, CurrentBlock, &m_Data));
+ if (CurrentHandler == nullptr)
+ {
+ continue;
+ }
+
+ cRedstoneHandler::PoweringData Power;
+ for (const auto & Location : CurrentHandler->GetValidSourcePositions(CurrentLocation, CurrentBlock, CurrentMeta))
+ {
+ BLOCKTYPE PotentialBlock;
+ NIBBLETYPE PotentialMeta;
+ if ((Location.y < 0) || (Location.y > cChunkDef::Height))
+ {
+ continue;
+ }
+ m_World.GetBlockTypeMeta(Location.x, Location.y, Location.z, PotentialBlock, PotentialMeta);
+
+ auto PotentialSourceHandler = std::move(cIncrementalRedstoneSimulator::CreateComponent(m_World, PotentialBlock, &m_Data));
+ if (PotentialSourceHandler == nullptr)
+ {
+ continue;
+ }
+
+ decltype(Power) PotentialPower(PotentialBlock, PotentialSourceHandler->GetPowerDeliveredToPosition(Location, PotentialBlock, PotentialMeta, CurrentLocation, CurrentBlock));
+ Power = std::max(Power, PotentialPower);
+ }
+
+ // Inform the handler to update
+ cVector3iArray Updates = CurrentHandler->Update(CurrentLocation, CurrentBlock, CurrentMeta, Power);
+ WorkQueue.insert(WorkQueue.end(), Updates.begin(), Updates.end());
+
+ if (IsAlwaysTicked(CurrentBlock))
+ {
+ m_Data.GetActiveBlocks().emplace_back(CurrentLocation);
+ }
+
+ #ifdef _DEBUG
+ for (const auto & UpdateLocation : Updates)
+ {
+ LOGD("Queueing block for reupdate (%i %i %i)", UpdateLocation.x, UpdateLocation.y, UpdateLocation.z);
+ }
+ #endif
+ }
+}
diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h
new file mode 100644
index 000000000..a43a6e49b
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h
@@ -0,0 +1,167 @@
+
+#pragma once
+
+#include "../RedstoneSimulator.h"
+#include "RedstoneSimulatorChunkData.h"
+
+
+
+
+
+class cIncrementalRedstoneSimulator :
+ public cRedstoneSimulator
+{
+ typedef cRedstoneSimulator super;
+public:
+ cIncrementalRedstoneSimulator(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual void Simulate(float a_dt) override;
+ virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override {}
+
+ virtual cIncrementalRedstoneSimulatorChunkData * CreateChunkData() override
+ {
+ return new cIncrementalRedstoneSimulatorChunkData;
+ }
+
+ virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override
+ {
+ return IsRedstone(a_BlockType);
+ }
+
+ virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override
+ {
+ m_Data.WakeUp({ a_BlockX, a_BlockY, a_BlockZ });
+ }
+
+ /** Returns if a block is a mechanism (something that accepts power and does something)
+ Used by torches to determine if they will power a block
+ */
+ inline static bool IsMechanism(BLOCKTYPE Block)
+ {
+ switch (Block)
+ {
+ case E_BLOCK_ACACIA_DOOR:
+ case E_BLOCK_ACACIA_FENCE_GATE:
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_ACTIVE_COMPARATOR:
+ case E_BLOCK_BIRCH_DOOR:
+ case E_BLOCK_BIRCH_FENCE_GATE:
+ case E_BLOCK_COMMAND_BLOCK:
+ case E_BLOCK_DARK_OAK_DOOR:
+ case E_BLOCK_DARK_OAK_FENCE_GATE:
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DROPPER:
+ case E_BLOCK_FENCE_GATE:
+ case E_BLOCK_HOPPER:
+ case E_BLOCK_INACTIVE_COMPARATOR:
+ case E_BLOCK_IRON_DOOR:
+ case E_BLOCK_IRON_TRAPDOOR:
+ case E_BLOCK_JUNGLE_DOOR:
+ case E_BLOCK_JUNGLE_FENCE_GATE:
+ case E_BLOCK_NOTE_BLOCK:
+ case E_BLOCK_PISTON:
+ case E_BLOCK_POWERED_RAIL:
+ case E_BLOCK_REDSTONE_LAMP_OFF:
+ case E_BLOCK_REDSTONE_LAMP_ON:
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ case E_BLOCK_REDSTONE_WIRE:
+ case E_BLOCK_SPRUCE_DOOR:
+ case E_BLOCK_SPRUCE_FENCE_GATE:
+ case E_BLOCK_STICKY_PISTON:
+ case E_BLOCK_TNT:
+ case E_BLOCK_TRAPDOOR:
+ case E_BLOCK_WOODEN_DOOR:
+ {
+ return true;
+ }
+ default: return false;
+ }
+ }
+
+ /** Returns if a redstone device is always ticked due to influence by its environment */
+ inline static bool IsAlwaysTicked(BLOCKTYPE a_Block)
+ {
+ switch (a_Block) // Call the appropriate simulator for the entry's block type
+ {
+ case E_BLOCK_DAYLIGHT_SENSOR:
+ case E_BLOCK_TRIPWIRE_HOOK:
+ 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: return true;
+ default: return false;
+ }
+ }
+
+ /** Returns if a block is any sort of redstone device */
+ inline static bool IsRedstone(BLOCKTYPE a_Block)
+ {
+ switch (a_Block)
+ {
+ // All redstone devices, please alpha sort
+ case E_BLOCK_ACACIA_DOOR:
+ case E_BLOCK_ACACIA_FENCE_GATE:
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_ACTIVE_COMPARATOR:
+ case E_BLOCK_BIRCH_DOOR:
+ case E_BLOCK_BIRCH_FENCE_GATE:
+ case E_BLOCK_BLOCK_OF_REDSTONE:
+ case E_BLOCK_COMMAND_BLOCK:
+ case E_BLOCK_DARK_OAK_DOOR:
+ case E_BLOCK_DARK_OAK_FENCE_GATE:
+ case E_BLOCK_DAYLIGHT_SENSOR:
+ case E_BLOCK_DETECTOR_RAIL:
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DROPPER:
+ case E_BLOCK_FENCE_GATE:
+ case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
+ case E_BLOCK_HOPPER:
+ case E_BLOCK_INACTIVE_COMPARATOR:
+ case E_BLOCK_IRON_DOOR:
+ case E_BLOCK_IRON_TRAPDOOR:
+ case E_BLOCK_JUNGLE_DOOR:
+ case E_BLOCK_JUNGLE_FENCE_GATE:
+ case E_BLOCK_LEVER:
+ case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
+ case E_BLOCK_NOTE_BLOCK:
+ case E_BLOCK_POWERED_RAIL:
+ case E_BLOCK_REDSTONE_LAMP_OFF:
+ case E_BLOCK_REDSTONE_LAMP_ON:
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ case E_BLOCK_REDSTONE_TORCH_OFF:
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ case E_BLOCK_REDSTONE_WIRE:
+ case E_BLOCK_SPRUCE_DOOR:
+ case E_BLOCK_SPRUCE_FENCE_GATE:
+ case E_BLOCK_STICKY_PISTON:
+ case E_BLOCK_STONE_BUTTON:
+ case E_BLOCK_STONE_PRESSURE_PLATE:
+ case E_BLOCK_TNT:
+ case E_BLOCK_TRAPDOOR:
+ case E_BLOCK_TRAPPED_CHEST:
+ case E_BLOCK_TRIPWIRE_HOOK:
+ case E_BLOCK_TRIPWIRE:
+ case E_BLOCK_WOODEN_BUTTON:
+ case E_BLOCK_WOODEN_DOOR:
+ case E_BLOCK_WOODEN_PRESSURE_PLATE:
+ case E_BLOCK_PISTON:
+ {
+ return true;
+ }
+ default: return false;
+ }
+ }
+
+ cIncrementalRedstoneSimulatorChunkData * GetChunkData() { return &m_Data; }
+ static std::unique_ptr<cRedstoneHandler> CreateComponent(cWorld & a_World, BLOCKTYPE a_BlockType, cIncrementalRedstoneSimulatorChunkData * a_Data);
+
+private:
+
+ // oh yea its crazy time
+ cIncrementalRedstoneSimulatorChunkData m_Data;
+} ;
diff --git a/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h
new file mode 100644
index 000000000..606f2438b
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h
@@ -0,0 +1,71 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "BlockEntities/NoteEntity.h"
+
+
+
+
+
+class cNoteBlockHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cNoteBlockHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ UNUSED(a_QueryPosition);
+ UNUSED(a_QueryBlockType);
+ return 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating sparky the magical note block (%d %d %d) %i", a_Position.x, a_Position.y, a_Position.z, a_PoweringData.PowerLevel);
+
+ auto Previous = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
+ if ((Previous.PowerLevel != 0) || (a_PoweringData.PowerLevel == 0))
+ {
+ // If we're already powered or received an update of no power, don't make a sound
+ return {};
+ }
+
+ class cSetPowerToNoteBlock : public cNoteBlockCallback
+ {
+ public:
+ virtual bool Item(cNoteEntity * a_NoteBlock) override
+ {
+ a_NoteBlock->MakeSound();
+ return false;
+ }
+ } NoteBlockSP;
+
+ m_World.DoWithNoteBlockAt(a_Position.x, a_Position.y, a_Position.z, NoteBlockSP);
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());;
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/PistonHandler.h b/src/Simulator/IncrementalRedstoneSimulator/PistonHandler.h
new file mode 100644
index 000000000..1992c63a8
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/PistonHandler.h
@@ -0,0 +1,68 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "Blocks/BlockPiston.h"
+
+
+
+
+
+class cPistonHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cPistonHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ UNUSED(a_QueryPosition);
+ UNUSED(a_QueryBlockType);
+ return 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating pisty the piston (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+
+ if (a_PoweringData.PowerLevel > 0)
+ {
+ cBlockPistonHandler::ExtendPiston(a_Position, &m_World);
+ }
+ else
+ {
+ cBlockPistonHandler::RetractPiston(a_Position, &m_World);
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+
+ auto PositionsOffset = GetRelativeAdjacents();
+ auto Face = cBlockPistonHandler::MetaDataToDirection(a_Meta);
+ int OffsetX = 0, OffsetY = 0, OffsetZ = 0;
+
+ AddFaceDirection(OffsetX, OffsetY, OffsetZ, Face);
+ PositionsOffset.erase(std::remove(PositionsOffset.begin(), PositionsOffset.end(), Vector3i(OffsetX, OffsetY, OffsetZ)), PositionsOffset.end());
+
+ return GetAdjustedRelatives(a_Position, PositionsOffset);
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/PoweredRailHandler.h b/src/Simulator/IncrementalRedstoneSimulator/PoweredRailHandler.h
new file mode 100644
index 000000000..c0c47a324
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/PoweredRailHandler.h
@@ -0,0 +1,100 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+
+
+
+
+
+class cPoweredRailHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cPoweredRailHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ static const Vector3i GetPoweredRailAdjacentXZCoordinateOffset(NIBBLETYPE a_Meta) // Not in cBlockRailHandler since specific to powered rails
+ {
+ switch (a_Meta & 0x7)
+ {
+ case E_META_RAIL_ZM_ZP: return { 0, 0, 1 };
+ case E_META_RAIL_XM_XP: return { 1, 0, 0 };
+ case E_META_RAIL_ASCEND_XP: return { 1, 1, 0 };
+ case E_META_RAIL_ASCEND_XM: return { 1, 1, 0 };
+ case E_META_RAIL_ASCEND_ZM: return { 0, 1, 1 };
+ case E_META_RAIL_ASCEND_ZP: return { 0, 1, 1 };
+ default:
+ {
+ ASSERT(!"Impossible rail meta! wat wat wat");
+ return { 0, 0, 0 };
+ }
+ }
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_QueryBlockType);
+
+ auto Offset = GetPoweredRailAdjacentXZCoordinateOffset(a_Meta);
+ if (((Offset + a_Position) == a_QueryPosition) || ((-Offset + a_Position) == a_QueryPosition))
+ {
+ auto Power = GetPowerLevel(a_Position, a_BlockType, a_Meta);
+ return (Power <= 7) ? 0 : --Power;
+ }
+ return 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating tracky the rail (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+
+ switch (a_BlockType)
+ {
+ 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);
+ }
+ */
+ return {};
+ }
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_POWERED_RAIL:
+ {
+ auto Offset = GetPoweredRailAdjacentXZCoordinateOffset(a_Meta);
+ if (a_PoweringData != static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData))
+ {
+ m_World.SetBlockMeta(a_Position, (a_PoweringData.PowerLevel == 0) ? (a_Meta & 0x07) : (a_Meta | 0x08));
+ return cVector3iArray{ { Offset + a_Position }, { -Offset + a_Position } };
+ }
+
+ return {};
+ }
+ default:
+ {
+ ASSERT(!"Unhandled type of rail in passed to rail handler!");
+ return {};
+ }
+ }
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/PressurePlateHandler.h b/src/Simulator/IncrementalRedstoneSimulator/PressurePlateHandler.h
new file mode 100644
index 000000000..07bb1fdc1
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/PressurePlateHandler.h
@@ -0,0 +1,111 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "BoundingBox.h"
+
+
+
+
+
+class cPressurePlateHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cPressurePlateHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ UNUSED(a_QueryPosition);
+ UNUSED(a_QueryBlockType);
+
+ return static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Meta);
+
+ class cPressurePlateCallback :
+ public cEntityCallback
+ {
+ public:
+ cPressurePlateCallback(void) :
+ m_NumberOfEntities(0),
+ m_FoundPlayer(false)
+ {
+ }
+
+ virtual bool Item(cEntity * a_Entity) override
+ {
+ if (a_Entity->IsPlayer())
+ {
+ m_FoundPlayer = true;
+ }
+
+ m_NumberOfEntities++;
+ return false;
+ }
+
+ unsigned int m_NumberOfEntities;
+ bool m_FoundPlayer;
+ } PressurePlateCallback;
+ m_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + a_Position, 0.5, 0.5), PressurePlateCallback);
+
+ switch (a_BlockType)
+ {
+ case E_BLOCK_STONE_PRESSURE_PLATE:
+ {
+ return (PressurePlateCallback.m_FoundPlayer ? 15 : 0);
+ }
+ case E_BLOCK_WOODEN_PRESSURE_PLATE:
+ {
+ return (PressurePlateCallback.m_NumberOfEntities != 0 ? 15 : 0);
+ }
+ case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
+ {
+ return std::min(static_cast<unsigned char>(CeilC(PressurePlateCallback.m_NumberOfEntities / 10.f)), static_cast<unsigned char>(15));
+ }
+ case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
+ {
+ return std::min(static_cast<unsigned char>(PressurePlateCallback.m_NumberOfEntities), static_cast<unsigned char>(15));
+ }
+ default:
+ {
+ ASSERT(!"Unhandled/unimplemented block in pressure plate handler!");
+ return 0;
+ }
+ }
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ UNUSED(a_PoweringData.PowerLevel);
+ // LOGD("Evaluating clicky the pressure plate (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+
+ auto Power = GetPowerLevel(a_Position, a_BlockType, a_Meta);
+ auto PreviousPower = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, PoweringData(a_BlockType, Power));
+
+ if (Power != PreviousPower.PowerLevel)
+ {
+ m_World.SetBlockMeta(a_Position, (Power == 0) ? E_META_PRESSURE_PLATE_RAISED : E_META_PRESSURE_PLATE_DEPRESSED);
+ return GetAdjustedRelatives(a_Position, StaticAppend(GetRelativeLaterals(), cVector3iArray{ OffsetYM() }));
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return {};
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneBlockHandler.h
new file mode 100644
index 000000000..401638fc8
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneBlockHandler.h
@@ -0,0 +1,51 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+
+
+
+
+
+class cRedstoneBlockHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cRedstoneBlockHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ UNUSED(a_QueryPosition);
+ UNUSED(a_QueryBlockType);
+ return 15;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return 15;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating crimson the redstone block (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return {};
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneComparatorHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneComparatorHandler.h
new file mode 100644
index 000000000..1d5f16e9a
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneComparatorHandler.h
@@ -0,0 +1,128 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "Blocks/BlockComparator.h"
+
+
+
+
+
+class cRedstoneComparatorHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cRedstoneComparatorHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ unsigned char GetFrontPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, unsigned char a_HighestSidePowerLevel)
+ {
+ class cContainerCallback : public cBlockEntityCallback
+ {
+ public:
+ cContainerCallback() : m_SignalStrength(0)
+ {
+ }
+
+ virtual bool Item(cBlockEntity * a_BlockEntity) override
+ {
+ auto & Contents = static_cast<cBlockEntityWithItems *>(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<unsigned char>(1 + (Fullness / Contents.GetNumSlots()) * 14);
+ return false;
+ }
+
+ unsigned char m_SignalStrength;
+ } CCB;
+
+ auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(a_Position, a_Meta & 0x3);
+ m_World.DoWithBlockEntityAt(RearCoordinate.x, RearCoordinate.y, RearCoordinate.z, CCB);
+ auto RearPower = CCB.m_SignalStrength;
+ auto PotentialSourceHandler = std::move(cIncrementalRedstoneSimulator::CreateComponent(m_World, m_World.GetBlock(RearCoordinate), static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()));
+ if (PotentialSourceHandler != nullptr)
+ {
+ BLOCKTYPE Type;
+ NIBBLETYPE Meta;
+ if (m_World.GetBlockTypeMeta(RearCoordinate.x, RearCoordinate.y, RearCoordinate.z, Type, Meta))
+ {
+ RearPower = std::max(CCB.m_SignalStrength, PotentialSourceHandler->GetPowerDeliveredToPosition(RearCoordinate, Type, Meta, a_Position, a_BlockType));
+ }
+ }
+
+ if ((a_Meta & 0x4) == 0x4)
+ {
+ // Subtraction mode
+ return static_cast<unsigned char>(std::max(static_cast<char>(RearPower) - a_HighestSidePowerLevel, 0));
+ }
+ else
+ {
+ // Comparison mode
+ return (std::max(a_HighestSidePowerLevel, RearPower) == a_HighestSidePowerLevel) ? 0 : RearPower;
+ }
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_QueryPosition);
+ UNUSED(a_QueryBlockType);
+
+ return (cBlockComparatorHandler::GetFrontCoordinate(a_Position, a_Meta & 0x3) == a_QueryPosition) ? static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel : 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+
+ auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(a_Position, a_Meta & 0x3);
+ auto PotentialSourceHandler = std::move(cIncrementalRedstoneSimulator::CreateComponent(m_World, m_World.GetBlock(RearCoordinate), static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()));
+ if (PotentialSourceHandler != nullptr)
+ {
+ BLOCKTYPE Type;
+ NIBBLETYPE Meta;
+ if (m_World.GetBlockTypeMeta(RearCoordinate.x, RearCoordinate.y, RearCoordinate.z, Type, Meta))
+ {
+ return PotentialSourceHandler->GetPowerDeliveredToPosition(RearCoordinate, Type, Meta, a_Position, a_BlockType);
+ }
+ }
+
+ return 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating ALU the comparator (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+
+ if (GetPowerLevel(a_Position, a_BlockType, a_Meta) > 0)
+ {
+ m_World.SetBlockMeta(a_Position, a_Meta | 0x8);
+ }
+ else
+ {
+ m_World.SetBlockMeta(a_Position, a_Meta & 0x7);
+ }
+
+ auto Power = GetFrontPowerLevel(a_Position, a_BlockType, a_Meta, a_PoweringData.PowerLevel);
+ auto PreviousFrontPower = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, PoweringData(a_PoweringData.PoweringBlock, Power));
+ if (Power != PreviousFrontPower.PowerLevel)
+ {
+ return GetAdjustedRelatives(a_Position, GetRelativeLaterals());
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ return cVector3iArray {cBlockComparatorHandler::GetSideCoordinate(a_Position, a_Meta & 0x3, false), cBlockComparatorHandler::GetSideCoordinate(a_Position, a_Meta & 0x3, true)};
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.h
new file mode 100644
index 000000000..36fe640f1
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.h
@@ -0,0 +1,130 @@
+
+#pragma once
+
+#include "World.h"
+#include "Vector3.h"
+
+
+
+
+
+class cRedstoneHandler
+{
+public:
+
+ cRedstoneHandler(cWorld & a_World) :
+ m_World(a_World)
+ {
+ }
+
+public:
+
+ // Disable the copy constructor and assignment operator
+ cRedstoneHandler(const cRedstoneHandler &) = delete;
+ cRedstoneHandler & operator=(const cRedstoneHandler &) = delete;
+
+ struct PoweringData
+ {
+ public:
+ PoweringData(BLOCKTYPE a_PoweringBlock, unsigned char a_PowerLevel) :
+ PoweringBlock(a_PoweringBlock),
+ PowerLevel(a_PowerLevel)
+ {
+ }
+
+ PoweringData(void) :
+ PoweringBlock(E_BLOCK_AIR),
+ PowerLevel(0)
+ {
+ }
+
+ BLOCKTYPE PoweringBlock;
+ unsigned char PowerLevel;
+
+ inline friend bool operator < (const PoweringData & a_Lhs, const PoweringData & a_Rhs)
+ {
+ return (
+ (a_Lhs.PowerLevel < a_Rhs.PowerLevel) ||
+ (
+ (a_Lhs.PowerLevel == a_Rhs.PowerLevel) &&
+ ((a_Lhs.PoweringBlock == E_BLOCK_REDSTONE_WIRE) && (a_Rhs.PoweringBlock != E_BLOCK_REDSTONE_WIRE))
+ )
+ );
+ }
+
+ inline friend bool operator == (const PoweringData & a_Lhs, const PoweringData & a_Rhs)
+ {
+ return (a_Lhs.PowerLevel == a_Rhs.PowerLevel);
+ }
+
+ inline friend bool operator != (const PoweringData & a_Lhs, const PoweringData & a_Rhs)
+ {
+ return !operator ==(a_Lhs, a_Rhs);
+ }
+ };
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) = 0;
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) = 0;
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) = 0;
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) = 0;
+
+ // Force a virtual destructor
+ virtual ~cRedstoneHandler() {}
+
+protected:
+
+ cWorld & m_World;
+
+ template <class Container>
+ static const Container StaticAppend(const Container && a_Lhs, const Container && a_Rhs)
+ {
+ Container ToReturn = a_Lhs;
+ std::copy(a_Rhs.begin(), a_Rhs.end(), std::back_inserter(ToReturn));
+ return ToReturn;
+ }
+
+ inline static const Vector3i OffsetYP()
+ {
+ return Vector3i(0, 1, 0);
+ }
+
+ inline static const Vector3i OffsetYM()
+ {
+ return Vector3i(0, -1, 0);
+ }
+
+ static const cVector3iArray GetAdjustedRelatives(const Vector3i & a_Position, const cVector3iArray & a_Relatives)
+ {
+ cVector3iArray Adjusted = a_Relatives;
+ std::for_each(Adjusted.begin(), Adjusted.end(), [a_Position](cVector3iArray::value_type & a_Entry) { a_Entry += a_Position; });
+ return Adjusted;
+ }
+
+ inline static const cVector3iArray GetRelativeAdjacents()
+ {
+ return
+ {
+ {
+ { 1, 0, 0 },
+ { -1, 0, 0 },
+ { 0, 1, 0 },
+ { 0, -1, 0 },
+ { 0, 0, 1 },
+ { 0, 0, -1 },
+ }
+ };
+ }
+
+ inline static const cVector3iArray GetRelativeLaterals()
+ {
+ return
+ {
+ {
+ { 1, 0, 0 },
+ { -1, 0, 0 },
+ { 0, 0, 1 },
+ { 0, 0, -1 },
+ }
+ };
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneLampHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneLampHandler.h
new file mode 100644
index 000000000..b0ae33662
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneLampHandler.h
@@ -0,0 +1,62 @@
+
+#pragma once
+
+#include "IncrementalRedstoneSimulator.h"
+
+
+
+
+
+class cRedstoneLampHandler : public cRedstoneHandler
+{
+public:
+
+ cRedstoneLampHandler(cWorld & a_World) :
+ cRedstoneHandler(a_World)
+ {
+ }
+
+ inline static bool IsOn(BLOCKTYPE a_BlockType)
+ {
+ return (a_BlockType == E_BLOCK_REDSTONE_LAMP_ON);
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ return 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ return 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating lamp (%i %i %i)", a_Position.x, a_Position.y, a_Position.z);
+
+ if (a_PoweringData.PowerLevel > 0)
+ {
+ if (!IsOn(a_BlockType))
+ {
+ m_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, E_BLOCK_REDSTONE_LAMP_ON, 0);
+ }
+ }
+ else
+ {
+ if (IsOn(a_BlockType))
+ {
+ m_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, E_BLOCK_REDSTONE_LAMP_OFF, 0);
+ }
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Meta);
+ UNUSED(a_BlockType);
+ return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h
new file mode 100644
index 000000000..a41a8217f
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h
@@ -0,0 +1,73 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "Blocks/BlockRedstoneRepeater.h"
+
+
+
+
+
+class cRedstoneRepeaterHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cRedstoneRepeaterHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ inline static bool IsOn(BLOCKTYPE a_Block)
+ {
+ return (a_Block == E_BLOCK_REDSTONE_REPEATER_ON);
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ return (a_QueryPosition == (a_Position + cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta))) ? GetPowerLevel(a_Position, a_BlockType, a_Meta) : 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_Meta);
+ return IsOn(a_BlockType) ? 15 : 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating loopy the repeater (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+ auto Data = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData();
+ auto DelayInfo = Data->GetMechanismDelayInfo(a_Position);
+
+ if (DelayInfo == nullptr)
+ {
+ bool ShouldBeOn = (a_PoweringData.PowerLevel != 0);
+ if (ShouldBeOn != IsOn(a_BlockType))
+ {
+ Data->m_MechanismDelays[a_Position] = std::make_pair((((a_Meta & 0xC) >> 0x2) + 1), ShouldBeOn);
+ }
+ }
+ else
+ {
+ int DelayTicks;
+ bool ShouldPowerOn;
+ std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo;
+
+ if (DelayTicks == 0)
+ {
+ m_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, ShouldPowerOn ? E_BLOCK_REDSTONE_REPEATER_ON : E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta);
+ Data->m_MechanismDelays.erase(a_Position);
+ return cVector3iArray{ cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta) + a_Position };
+ }
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ return { cBlockRedstoneRepeaterHandler::GetRearCoordinateOffset(a_Meta) + a_Position };
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneSimulatorChunkData.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneSimulatorChunkData.h
new file mode 100644
index 000000000..8e025d154
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneSimulatorChunkData.h
@@ -0,0 +1,70 @@
+
+#pragma once
+
+#include "Vector3.h"
+#include "RedstoneHandler.h"
+#include "../RedstoneSimulator.h"
+#include <unordered_map>
+
+
+
+
+
+class cIncrementalRedstoneSimulatorChunkData : public cRedstoneSimulatorChunkData
+{
+
+public:
+ void WakeUp(const Vector3i & a_Position)
+ {
+ m_ActiveBlocks.push_back(a_Position);
+ }
+
+ cVector3iArray & GetActiveBlocks()
+ {
+ return m_ActiveBlocks;
+ }
+
+ const cRedstoneHandler::PoweringData GetCachedPowerData(const Vector3i & a_Position) const
+ {
+ auto Result = m_CachedPowerLevels.find(a_Position);
+ return (Result == m_CachedPowerLevels.end()) ? cRedstoneHandler::PoweringData() : Result->second;
+ }
+
+ void SetCachedPowerData(const Vector3i & a_Position, cRedstoneHandler::PoweringData a_PoweringData)
+ {
+ m_CachedPowerLevels[a_Position] = a_PoweringData;
+ }
+
+ std::pair<int, bool> * GetMechanismDelayInfo(const Vector3i & a_Position)
+ {
+ auto Result = m_MechanismDelays.find(a_Position);
+ return (Result == m_MechanismDelays.end()) ? nullptr : &Result->second;
+ }
+
+ cRedstoneHandler::PoweringData ExchangeUpdateOncePowerData(const Vector3i & a_Position, cRedstoneHandler::PoweringData a_PoweringData)
+ {
+ auto Result = m_CachedPowerLevels.find(a_Position);
+ if (Result == m_CachedPowerLevels.end())
+ {
+ m_CachedPowerLevels[a_Position] = a_PoweringData;
+ return cRedstoneHandler::PoweringData();
+ }
+ std::swap(Result->second, a_PoweringData);
+ return a_PoweringData;
+ }
+
+ /** Structure storing position of mechanism + it's delay ticks (countdown) & if to power on */
+ std::unordered_map<Vector3i, std::pair<int, bool>, VectorHasher<int>> m_MechanismDelays;
+ std::unordered_map<Vector3i, bool, VectorHasher<int>> m_UpdateOncePositions;
+
+private:
+
+ cVector3iArray m_ActiveBlocks;
+
+ // TODO: map<Vector3i, int> -> Position of torch + it's heat level
+
+ std::unordered_map<Vector3i, cRedstoneHandler::PoweringData, VectorHasher<int>> m_CachedPowerLevels;
+
+ friend class cRedstoneHandlerFactory;
+
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneToggleHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneToggleHandler.h
new file mode 100644
index 000000000..075f91ba5
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneToggleHandler.h
@@ -0,0 +1,111 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "Blocks/BlockButton.h"
+#include "Blocks/BlockLever.h"
+
+
+
+
+
+class cRedstoneToggleHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cRedstoneToggleHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ inline static const Vector3i GetPositionAttachedTo(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta)
+ {
+ switch (a_BlockType)
+ {
+ case E_BLOCK_LEVER:
+ {
+ switch (a_Meta & 0x7)
+ {
+ case 0x0:
+ case 0x7: return { a_Position + Vector3i(0, 1, 0) };
+ case 0x1: return { a_Position + Vector3i(-1, 0, 0) };
+ case 0x2: return { a_Position + Vector3i(1, 0, 0) };
+ case 0x3: return { a_Position + Vector3i(0, 0, -1) };
+ case 0x4: return { a_Position + Vector3i(0, 0, 1) };
+ case 0x5:
+ case 0x6: return { a_Position + Vector3i(0, -1, 0) };
+ default:
+ {
+ ASSERT(!"Unhandled lever metadata!");
+ return { 0, 0, 0 };
+ }
+ }
+ }
+ case E_BLOCK_STONE_BUTTON:
+ case E_BLOCK_WOODEN_BUTTON:
+ {
+ switch (a_Meta & 0x7)
+ {
+ case 0x0: return { a_Position + Vector3i(0, 1, 0) };
+ case 0x1: return { a_Position + Vector3i(-1, 0, 0) };
+ case 0x2: return { a_Position + Vector3i(1, 0, 0) };
+ case 0x3: return { a_Position + Vector3i(0, 0, -1) };
+ case 0x4: return { a_Position + Vector3i(0, 0, 1) };
+ case 0x5: return { a_Position + Vector3i(0, -1, 0) };
+ default:
+ {
+ ASSERT(!"Unhandled button metadata!");
+ return { 0, 0, 0 };
+ }
+ }
+ }
+ default:
+ {
+ ASSERT(!"Unexpected block passed to button/lever handler");
+ return { 0, 0, 0 };
+ }
+ }
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_QueryBlockType);
+ if ((GetPositionAttachedTo(a_Position, a_BlockType, a_Meta) == a_QueryPosition) || cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType))
+ {
+ return GetPowerLevel(a_Position, a_BlockType, a_Meta);
+ }
+ return 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+
+ switch (a_BlockType)
+ {
+ case E_BLOCK_LEVER: return cBlockLeverHandler::IsLeverOn(a_Meta) ? 15 : 0;
+ case E_BLOCK_STONE_BUTTON:
+ case E_BLOCK_WOODEN_BUTTON: return cBlockButtonHandler::IsButtonOn(a_Meta) ? 15 : 0;
+ default:
+ {
+ ASSERT(!"Unexpected block passed to button/lever handler");
+ return 0;
+ }
+ }
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating templatio<> the lever/button (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return {};
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneTorchHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneTorchHandler.h
new file mode 100644
index 000000000..eb7db2c8e
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneTorchHandler.h
@@ -0,0 +1,99 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+
+
+
+
+
+class cRedstoneTorchHandler : public cRedstoneHandler
+{
+public:
+
+ cRedstoneTorchHandler(cWorld & a_World) :
+ cRedstoneHandler(a_World)
+ {
+ }
+
+ inline static bool IsOn(BLOCKTYPE a_Block)
+ {
+ return (a_Block == E_BLOCK_REDSTONE_TORCH_ON);
+ }
+
+ inline static const Vector3i GetOffsetAttachedTo(const Vector3i & a_Position, NIBBLETYPE a_Meta)
+ {
+ switch (a_Meta)
+ {
+ case E_META_TORCH_FLOOR: return { 0, -1, 0 };
+ case E_META_TORCH_EAST: return { -1, 0, 0 };
+ case E_META_TORCH_WEST: return { 1, 0, 0 };
+ case E_META_TORCH_NORTH: return { 0, 0, 1 };
+ case E_META_TORCH_SOUTH: return { 0, 0, -1 };
+ default:
+ {
+ ASSERT(!"Unhandled torch metadata");
+ return { 0, 0, 0 };
+ }
+ }
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ if (
+ IsOn(a_BlockType) &&
+ (a_QueryPosition != (a_Position + GetOffsetAttachedTo(a_Position, a_Meta))) &&
+ (cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType) || (cBlockInfo::FullyOccupiesVoxel(a_QueryBlockType) && (a_QueryPosition == (a_Position + OffsetYP()))))
+ )
+ {
+ return 15;
+ }
+ return 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ return IsOn(a_BlockType) ? 15 : 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating torchy the redstone torch (%i %i %i)", a_Position.x, a_Position.y, a_Position.z);
+
+ auto Data = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData();
+ auto DelayInfo = Data->GetMechanismDelayInfo(a_Position);
+
+ if (DelayInfo == nullptr)
+ {
+ bool ShouldBeOn = (a_PoweringData.PowerLevel == 0);
+ if (ShouldBeOn != IsOn(a_BlockType))
+ {
+ Data->m_MechanismDelays[a_Position] = std::make_pair(1, ShouldBeOn);
+ }
+ }
+ else
+ {
+ int DelayTicks;
+ bool ShouldPowerOn;
+ std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo;
+
+ if (DelayTicks == 0)
+ {
+ m_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, ShouldPowerOn ? E_BLOCK_REDSTONE_TORCH_ON : E_BLOCK_REDSTONE_TORCH_OFF, a_Meta);
+ Data->m_MechanismDelays.erase(a_Position);
+
+ cVector3iArray RelativePositions = GetRelativeAdjacents();
+ RelativePositions.erase(std::remove(RelativePositions.begin(), RelativePositions.end(), GetOffsetAttachedTo(a_Position, a_Meta)), RelativePositions.end());
+ return GetAdjustedRelatives(a_Position, RelativePositions);
+ }
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ return { (a_Position + GetOffsetAttachedTo(a_Position, a_Meta)) };
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h
new file mode 100644
index 000000000..fbf6eb646
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h
@@ -0,0 +1,134 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+
+
+
+
+
+class cRedstoneWireHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cRedstoneWireHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ inline static bool IsDirectlyConnectingMechanism(BLOCKTYPE a_Block)
+ {
+ switch (a_Block)
+ {
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_ACTIVE_COMPARATOR:
+ case E_BLOCK_INACTIVE_COMPARATOR:
+ case E_BLOCK_REDSTONE_TORCH_OFF:
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ case E_BLOCK_REDSTONE_WIRE: return true;
+ default: return false;
+ }
+ }
+
+ const cVector3iArray GetTerracingConnectionOffsets(const Vector3i & a_Position)
+ {
+ cVector3iArray RelativePositions;
+ bool IsYPTerracingBlocked = cBlockInfo::IsSolid(m_World.GetBlock(a_Position + OffsetYP()));
+
+ for (const auto Adjacent : GetRelativeLaterals())
+ {
+ if (
+ !IsYPTerracingBlocked &&
+ (m_World.GetBlock(a_Position + Adjacent + OffsetYP()) == E_BLOCK_REDSTONE_WIRE)
+ )
+ {
+ RelativePositions.emplace_back(Adjacent + OffsetYP());
+ }
+
+ if (
+ !cBlockInfo::IsSolid(m_World.GetBlock(a_Position + Adjacent)) && // IsYMTerracingBlocked (i.e. check block above lower terracing position, a.k.a. just the plain adjacent)
+ (m_World.GetBlock(a_Position + Adjacent + OffsetYM()) == E_BLOCK_REDSTONE_WIRE)
+ )
+ {
+ RelativePositions.emplace_back(Adjacent + OffsetYM());
+ }
+ }
+
+ return RelativePositions;
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ if (a_QueryPosition == (a_Position + OffsetYP()))
+ {
+ // Wires do not power things above them
+ return 0;
+ }
+
+ if (a_QueryBlockType != E_BLOCK_REDSTONE_WIRE)
+ {
+ // For mechanisms, wire of power one will still power them
+ a_Meta++;
+ }
+
+ if ((a_QueryPosition != (a_Position + OffsetYM())) && !IsDirectlyConnectingMechanism(a_QueryBlockType))
+ {
+ Vector3i PotentialOffset;
+ bool FoundOneBorderingMechanism = false;
+
+ for (const auto & Offset : StaticAppend(GetRelativeLaterals(), GetTerracingConnectionOffsets(a_Position)))
+ {
+ if (IsDirectlyConnectingMechanism(m_World.GetBlock(Offset + a_Position)))
+ {
+ if (FoundOneBorderingMechanism)
+ {
+ return 0;
+ }
+ else
+ {
+ FoundOneBorderingMechanism = true;
+ PotentialOffset = { -Offset.x, 0, -Offset.z };
+ }
+ }
+ }
+
+ if (FoundOneBorderingMechanism && (a_QueryPosition != (a_Position + PotentialOffset)))
+ {
+ return 0;
+ }
+ }
+
+ return (a_Meta != 0) ? --a_Meta : a_Meta;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ return a_Meta;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ UNUSED(a_BlockType);
+ LOGD("Evaluating dusty the wire (%d %d %d) %i", a_Position.x, a_Position.y, a_Position.z, a_PoweringData.PowerLevel);
+
+ if (a_Meta != a_PoweringData.PowerLevel)
+ {
+ m_World.SetBlockMeta(a_Position, a_PoweringData.PowerLevel);
+ return GetAdjustedRelatives(a_Position, StaticAppend(StaticAppend(GetRelativeLaterals(), GetTerracingConnectionOffsets(a_Position)), cVector3iArray{ OffsetYM() }));
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+
+ return GetAdjustedRelatives(a_Position, StaticAppend(GetRelativeAdjacents(), GetTerracingConnectionOffsets(a_Position)));
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/SmallGateHandler.h b/src/Simulator/IncrementalRedstoneSimulator/SmallGateHandler.h
new file mode 100644
index 000000000..64b15c0df
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/SmallGateHandler.h
@@ -0,0 +1,56 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+
+
+
+
+
+class cSmallGateHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cSmallGateHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ UNUSED(a_QueryPosition);
+ UNUSED(a_QueryBlockType);
+ return 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating gateydory the fence gate/trapdoor (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+
+ if (a_PoweringData != static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData))
+ {
+ m_World.SetBlockMeta(a_Position, (a_PoweringData.PowerLevel > 0) ? (a_Meta | 0x4) : (a_Meta & ~0x04));
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());;
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/SolidBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/SolidBlockHandler.h
new file mode 100644
index 000000000..61dbdc998
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/SolidBlockHandler.h
@@ -0,0 +1,71 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+
+
+
+
+
+class cSolidBlockHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cSolidBlockHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ // TODO: wire isn't linked powered only if the source was a wire, not just because it is a wire
+ return (
+ !cIncrementalRedstoneSimulator::IsRedstone(a_QueryBlockType) ||
+ (
+ (a_QueryBlockType == E_BLOCK_REDSTONE_WIRE) &&
+ (static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PoweringBlock == E_BLOCK_REDSTONE_WIRE)
+ )
+ ) ? 0 : GetPowerLevel(a_Position, a_BlockType, a_Meta);
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ return static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ LOGD("Evaluating blocky the generic block (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+
+ auto PreviousPower = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
+ if ((a_PoweringData != PreviousPower) || (a_PoweringData.PoweringBlock != PreviousPower.PoweringBlock))
+ {
+ return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+
+ /* TODO: is this more performant?
+ cVector3iArray Adjacents;
+ for (const auto Offset : GetRelativeAdjacents())
+ {
+ auto Position = Offset + a_Position;
+ auto Block = m_World.GetBlock(Position);
+ if ((Block == E_BLOCK_REDSTONE_REPEATER_ON) || (Block == E_BLOCK_REDSTONE_WIRE) || (Block == E_BLOCK_TRIPWIRE_HOOK))
+ {
+ Adjacents.emplace_back(Position);
+ }
+ }
+ */
+ return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/TNTHandler.h b/src/Simulator/IncrementalRedstoneSimulator/TNTHandler.h
new file mode 100644
index 000000000..f51e39a17
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/TNTHandler.h
@@ -0,0 +1,58 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "Blocks/BlockButton.h"
+#include "Blocks/BlockLever.h"
+
+
+
+
+
+class cTNTHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cTNTHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ UNUSED(a_QueryPosition);
+ UNUSED(a_QueryBlockType);
+ return 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating explodinator the trinitrotoluene (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+ if (a_PoweringData.PowerLevel != 0)
+ {
+ m_World.BroadcastSoundEffect("game.tnt.primed", (double)a_Position.x, (double)a_Position.y, (double)a_Position.z, 0.5f, 0.6f);
+ m_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, E_BLOCK_AIR, 0);
+ m_World.SpawnPrimedTNT(a_Position.x + 0.5, a_Position.y + 0.5, a_Position.z + 0.5); // 80 ticks to boom
+ }
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());;
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h b/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h
new file mode 100644
index 000000000..eb434d611
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h
@@ -0,0 +1,93 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "BlockEntities/ChestEntity.h"
+
+
+
+
+
+class cTrappedChestHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cTrappedChestHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ UNUSED(a_QueryPosition);
+ UNUSED(a_QueryBlockType);
+
+ return static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+
+ class cGetTrappedChestPlayers :
+ public cItemCallback<cChestEntity>
+ {
+ 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 true;
+ }
+
+ unsigned char GetPowerLevel(void) const
+ {
+ return static_cast<unsigned char>(std::min(m_NumberOfPlayers, 15));
+ }
+
+ private:
+ int m_NumberOfPlayers;
+
+ } GTCP;
+
+ VERIFY(!m_World.DoWithChestAt(a_Position.x, a_Position.y, a_Position.z, GTCP));
+ return GTCP.GetPowerLevel();
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ LOGD("Evaluating tricky the trapped chest (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+
+ auto Power = GetPowerLevel(a_Position, a_BlockType, a_Meta);
+ auto PreviousPower = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, PoweringData(a_BlockType, Power));
+
+ if (Power != PreviousPower.PowerLevel)
+ {
+ return GetAdjustedRelatives(a_Position, StaticAppend(GetRelativeLaterals(), cVector3iArray{ OffsetYM() }));
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Position);
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+
+ return {};
+ }
+};
diff --git a/src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h b/src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h
new file mode 100644
index 000000000..d472d2dfb
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h
@@ -0,0 +1,136 @@
+
+#pragma once
+
+#include "RedstoneHandler.h"
+#include "Blocks/BlockTripwireHook.h"
+
+
+
+
+
+class cTripwireHookHandler : public cRedstoneHandler
+{
+ typedef cRedstoneHandler super;
+public:
+
+ cTripwireHookHandler(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
+ {
+ UNUSED(a_QueryBlockType);
+ UNUSED(a_QueryPosition);
+
+ return (GetPowerLevel(a_Position, a_BlockType, a_Meta) == 15) ? 15 : 0;
+ }
+
+ virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+
+ bool FoundActivated = false;
+ auto Position = a_Position;
+ eBlockFace FaceToGoTowards = cBlockTripwireHookHandler::MetadataToDirection(a_Meta);
+
+ for (int i = 0; i < 40; ++i) // Tripwires can be connected up to 40 blocks
+ {
+ BLOCKTYPE Type;
+ NIBBLETYPE Meta;
+
+ AddFaceDirection(Position.x, Position.y, Position.z, FaceToGoTowards);
+ m_World.GetBlockTypeMeta(Position.x, Position.y, Position.z, Type, Meta);
+
+ if (Type == E_BLOCK_TRIPWIRE)
+ {
+ class cTripwireCallback :
+ public cEntityCallback
+ {
+ public:
+ cTripwireCallback(void) :
+ m_NumberOfEntities(0),
+ m_FoundPlayer(false)
+ {
+ }
+
+ virtual bool Item(cEntity * a_Entity) override
+ {
+ return true;
+ }
+
+ unsigned int m_NumberOfEntities;
+ bool m_FoundPlayer;
+ } TripwireCallback;
+
+ if (!m_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + Position, 0.5, 0.5), TripwireCallback))
+ {
+ FoundActivated = true;
+ }
+ }
+ else if (Type == E_BLOCK_TRIPWIRE_HOOK)
+ {
+ if (ReverseBlockFace(cBlockTripwireHookHandler::MetadataToDirection(Meta)) == FaceToGoTowards)
+ {
+ // Other hook facing in opposite direction - circuit completed!
+ return FoundActivated ? 15 : 1;
+ }
+ else
+ {
+ // Tripwire hook not connected at all
+ return 0;
+ }
+ }
+ else
+ {
+ // Tripwire hook not connected at all
+ return 0;
+ }
+ }
+
+ return 0;
+ }
+
+ virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
+ {
+ // LOGD("Evaluating hooky the tripwire hook (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
+
+ auto Power = GetPowerLevel(a_Position, a_BlockType, a_Meta);
+ NIBBLETYPE Meta;
+ if (Power == 0)
+ {
+ Meta = (a_Meta & 0x3);
+ }
+ else if (Power == 1)
+ {
+ // Connected but not activated, AND away the highest bit
+ Meta = (a_Meta & 0x7) | 0x4;
+ }
+ else if (Power == 15)
+ {
+ // Connected and activated, set the 3rd and 4th highest bits
+ Meta = (a_Meta | 0xC);
+ }
+ else
+ {
+ ASSERT(!"Unexpected tripwire hook power level!");
+ return {};
+ }
+
+ if (Meta != a_Meta)
+ {
+ m_World.SetBlockMeta(a_Position, Meta);
+ return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
+ }
+
+ return {};
+ }
+
+ virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_BlockType);
+ UNUSED(a_Meta);
+ UNUSED(a_Position);
+ return {};
+ }
+};
diff --git a/src/Simulator/NoopRedstoneSimulator.h b/src/Simulator/NoopRedstoneSimulator.h
index b8c797472..34c8627d2 100644
--- a/src/Simulator/NoopRedstoneSimulator.h
+++ b/src/Simulator/NoopRedstoneSimulator.h
@@ -18,8 +18,6 @@ public:
{
}
- // ~cRedstoneNoopSimulator();
-
virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used
virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override
{
diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h
index b0ad08aa4..863ba2532 100644
--- a/src/Simulator/RedstoneSimulator.h
+++ b/src/Simulator/RedstoneSimulator.h
@@ -1,30 +1,41 @@
#pragma once
-#include "Simulator.h"
+#include "ChunkDef.h"
+#include "Simulator/Simulator.h"
+
+
+
class cRedstoneSimulatorChunkData
{
public:
virtual ~cRedstoneSimulatorChunkData() = 0;
-} ;
-
+};
inline cRedstoneSimulatorChunkData::~cRedstoneSimulatorChunkData() {}
+
+
+
class cRedstoneSimulator :
public cSimulator
{
typedef cSimulator super;
-
public:
+
cRedstoneSimulator(cWorld & a_World) :
- super(a_World)
+ super(a_World)
{
}
-
+
+ virtual void Simulate(float a_Dt) = 0;
+ virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) = 0;
+ virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) = 0;
+ virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) = 0;
+
virtual cRedstoneSimulatorChunkData * CreateChunkData() = 0;
-} ;
+};