diff options
Diffstat (limited to 'src/Simulator/IncrementalRedstoneSimulator')
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 {}; + } +}; |