summaryrefslogtreecommitdiffstats
path: root/src/Simulator/IncrementalRedstoneSimulator
diff options
context:
space:
mode:
Diffstat (limited to 'src/Simulator/IncrementalRedstoneSimulator')
-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
24 files changed, 2195 insertions, 0 deletions
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 {};
+ }
+};