From 5b62c4c3145c08b093521e42c565922fa85de4ad Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 26 Jun 2015 17:24:51 -0500 Subject: Reorganised the redstone simulator -> Many thanks to @worktycho for the idea, and @Haxi52 for the implementation plan! * Uses classes and inheritance now * Speed should be improved --- src/BlockEntities/CMakeLists.txt | 1 - src/BlockEntities/CommandBlockEntity.cpp | 14 - src/BlockEntities/CommandBlockEntity.h | 8 +- src/BlockEntities/DropSpenserEntity.cpp | 16 +- src/BlockEntities/DropSpenserEntity.h | 8 - src/BlockEntities/NoteEntity.cpp | 4 +- src/BlockEntities/NoteEntity.h | 12 - src/BlockEntities/RedstonePoweredEntity.h | 30 - src/Blocks/BlockButton.h | 26 +- src/Blocks/BlockComparator.h | 47 +- src/Blocks/BlockLever.h | 6 + src/Blocks/BlockPiston.h | 2 +- src/Blocks/BlockRail.h | 7 +- src/Blocks/BlockRedstoneRepeater.h | 36 + src/Blocks/ChunkInterface.cpp | 10 - src/Blocks/ChunkInterface.h | 2 - src/CMakeLists.txt | 7 +- src/Chunk.cpp | 96 - src/Chunk.h | 14 +- src/ChunkMap.cpp | 123 +- src/ChunkMap.h | 7 - src/ClientHandle.cpp | 6 + src/Simulator/CMakeLists.txt | 3 - src/Simulator/IncrementalRedstoneSimulator.cpp | 2298 -------------------- src/Simulator/IncrementalRedstoneSimulator.h | 419 ---- .../IncrementalRedstoneSimulator/CMakeLists.txt | 38 + .../CommandBlockHandler.h | 70 + .../IncrementalRedstoneSimulator/DoorHandler.h | 59 + .../DropSpenserHandler.h | 69 + .../IncrementalRedstoneSimulator.cpp | 170 ++ .../IncrementalRedstoneSimulator.h | 167 ++ .../NoteBlockHandler.h | 71 + .../IncrementalRedstoneSimulator/PistonHandler.h | 68 + .../PoweredRailHandler.h | 100 + .../PressurePlateHandler.h | 111 + .../RedstoneBlockHandler.h | 51 + .../RedstoneComparatorHandler.h | 128 ++ .../IncrementalRedstoneSimulator/RedstoneHandler.h | 130 ++ .../RedstoneLampHandler.h | 62 + .../RedstoneRepeaterHandler.h | 73 + .../RedstoneSimulatorChunkData.h | 70 + .../RedstoneToggleHandler.h | 111 + .../RedstoneTorchHandler.h | 99 + .../RedstoneWireHandler.h | 134 ++ .../SmallGateHandler.h | 56 + .../SolidBlockHandler.h | 71 + .../IncrementalRedstoneSimulator/TNTHandler.h | 58 + .../TrappedChestHandler.h | 93 + .../TripwireHookHandler.h | 136 ++ src/Simulator/NoopRedstoneSimulator.h | 2 - src/Simulator/RedstoneSimulator.h | 25 +- src/UI/ChestWindow.cpp | 16 +- src/Vector3.h | 5 + src/World.cpp | 6 +- src/World.h | 8 - 55 files changed, 2337 insertions(+), 3122 deletions(-) delete mode 100644 src/BlockEntities/RedstonePoweredEntity.h delete mode 100644 src/Simulator/IncrementalRedstoneSimulator.cpp delete mode 100644 src/Simulator/IncrementalRedstoneSimulator.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt create mode 100644 src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/DropSpenserHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp create mode 100644 src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/NoteBlockHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/PistonHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/PoweredRailHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/PressurePlateHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/RedstoneBlockHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/RedstoneComparatorHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/RedstoneLampHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/RedstoneRepeaterHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/RedstoneSimulatorChunkData.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/RedstoneToggleHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/RedstoneTorchHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/SmallGateHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/SolidBlockHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/TNTHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/TrappedChestHandler.h create mode 100644 src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h diff --git a/src/BlockEntities/CMakeLists.txt b/src/BlockEntities/CMakeLists.txt index 931484be0..fbf85d2af 100644 --- a/src/BlockEntities/CMakeLists.txt +++ b/src/BlockEntities/CMakeLists.txt @@ -42,7 +42,6 @@ SET (HDRS MobHeadEntity.h MobSpawnerEntity.h NoteEntity.h - RedstonePoweredEntity.h SignEntity.h ) diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index 2709201f4..c4a742bc0 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -20,7 +20,6 @@ cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) : super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World), m_ShouldExecute(false), - m_IsPowered(false), m_Result(0) {} @@ -113,19 +112,6 @@ void cCommandBlockEntity::Activate(void) -void cCommandBlockEntity::SetRedstonePower(bool a_IsPowered) -{ - if (a_IsPowered && !m_IsPowered) - { - Activate(); - } - m_IsPowered = a_IsPowered; -} - - - - - bool cCommandBlockEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { UNUSED(a_Dt); diff --git a/src/BlockEntities/CommandBlockEntity.h b/src/BlockEntities/CommandBlockEntity.h index 0f93ff916..184211ce0 100644 --- a/src/BlockEntities/CommandBlockEntity.h +++ b/src/BlockEntities/CommandBlockEntity.h @@ -10,7 +10,6 @@ #pragma once #include "BlockEntity.h" -#include "RedstonePoweredEntity.h" @@ -19,8 +18,7 @@ // tolua_begin class cCommandBlockEntity : - public cBlockEntity, - public cRedstonePoweredEntity + public cBlockEntity { typedef cBlockEntity super; @@ -43,9 +41,6 @@ public: // tolua_begin - /** Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate */ - virtual void SetRedstonePower(bool a_IsPowered) override; - /** Sets the command block to execute a command in the next tick */ void Activate(void); @@ -69,7 +64,6 @@ private: void Execute(); bool m_ShouldExecute; - bool m_IsPowered; AString m_Command; diff --git a/src/BlockEntities/DropSpenserEntity.cpp b/src/BlockEntities/DropSpenserEntity.cpp index 6a8b5311e..7270c9586 100644 --- a/src/BlockEntities/DropSpenserEntity.cpp +++ b/src/BlockEntities/DropSpenserEntity.cpp @@ -17,8 +17,7 @@ cDropSpenserEntity::cDropSpenserEntity(BLOCKTYPE a_BlockType, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World), - m_ShouldDropSpense(false), - m_IsPowered(false) + m_ShouldDropSpense(false) { } @@ -114,19 +113,6 @@ void cDropSpenserEntity::Activate(void) -void cDropSpenserEntity::SetRedstonePower(bool a_IsPowered) -{ - if (a_IsPowered && !m_IsPowered) - { - Activate(); - } - m_IsPowered = a_IsPowered; -} - - - - - bool cDropSpenserEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { UNUSED(a_Dt); diff --git a/src/BlockEntities/DropSpenserEntity.h b/src/BlockEntities/DropSpenserEntity.h index 9e73269fb..fa1f37454 100644 --- a/src/BlockEntities/DropSpenserEntity.h +++ b/src/BlockEntities/DropSpenserEntity.h @@ -11,7 +11,6 @@ #pragma once #include "BlockEntityWithItems.h" -#include "RedstonePoweredEntity.h" @@ -26,9 +25,6 @@ class cClientHandle; // tolua_begin class cDropSpenserEntity : public cBlockEntityWithItems - // tolua_end - , public cRedstonePoweredEntity - // tolua_begin { typedef cBlockEntityWithItems super; @@ -60,13 +56,9 @@ public: void Activate(void); // tolua_end - - /** Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate */ - virtual void SetRedstonePower(bool a_IsPowered) override; protected: bool m_ShouldDropSpense; ///< If true, the dropspenser will dropspense an item in the next tick - bool m_IsPowered; ///< Set to true when the dropspenser receives redstone power. /** Does the actual work on dropspensing an item. Chooses the slot, calls DropSpenseFromSlot() and handles smoke / sound effects */ void DropSpense(cChunk & a_Chunk); diff --git a/src/BlockEntities/NoteEntity.cpp b/src/BlockEntities/NoteEntity.cpp index 0b110b14e..0eef633dc 100644 --- a/src/BlockEntities/NoteEntity.cpp +++ b/src/BlockEntities/NoteEntity.cpp @@ -44,7 +44,7 @@ void cNoteEntity::MakeSound(void) { // TODO: add other wood-based blocks if needed instrument = E_INST_DOUBLE_BASS; - sampleName = "note.db"; + sampleName = "note.bassattack"; break; } @@ -76,7 +76,7 @@ void cNoteEntity::MakeSound(void) { // TODO: add other stone-based blocks if needed instrument = E_INST_BASS_DRUM; - sampleName = "note.bassattack"; + sampleName = "note.bd"; break; } diff --git a/src/BlockEntities/NoteEntity.h b/src/BlockEntities/NoteEntity.h index 3a70ffec5..2cd703c52 100644 --- a/src/BlockEntities/NoteEntity.h +++ b/src/BlockEntities/NoteEntity.h @@ -2,7 +2,6 @@ #pragma once #include "BlockEntity.h" -#include "RedstonePoweredEntity.h" @@ -25,9 +24,6 @@ enum ENUM_NOTE_INSTRUMENTS class cNoteEntity : public cBlockEntity - // tolua_end - , public cRedstonePoweredEntity - // tolua_begin { typedef cBlockEntity super; public: @@ -51,14 +47,6 @@ public: virtual bool UsedBy(cPlayer * a_Player) override; virtual void SendTo(cClientHandle &) override {} - - virtual void SetRedstonePower(bool a_Value) override - { - if (a_Value) - { - MakeSound(); - } - } private: char m_Pitch; diff --git a/src/BlockEntities/RedstonePoweredEntity.h b/src/BlockEntities/RedstonePoweredEntity.h deleted file mode 100644 index 06856f3ea..000000000 --- a/src/BlockEntities/RedstonePoweredEntity.h +++ /dev/null @@ -1,30 +0,0 @@ - -// RedstonePoweredEntity.h - -// Declares the cRedstonePoweredEntity class representing a mix-in for block entities that respond to redstone - - - - - -#pragma once - - - - - -/** Interface class representing a mix-in for block entities that respond to redstone */ -class cRedstonePoweredEntity -{ -public: - - virtual ~cRedstonePoweredEntity() {} - - /** Sets the internal redstone power flag to "on" or "off", depending on the parameter. - Calls Activate() if appropriate */ - virtual void SetRedstonePower(bool a_IsPowered) = 0; -}; - - - - diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index 7f6c3e56f..354d563fd 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -38,14 +38,18 @@ public: a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("random.click", x, y, z, 0.5f, 0.6f); // Queue a button reset (unpress) - int delay = (m_BlockType == E_BLOCK_STONE_BUTTON) ? 20 : 30; - - a_ChunkInterface.QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07), delay, m_BlockType, a_WorldInterface); - - a_Player->GetWorld()->ScheduleTask(delay, [x, y, z](cWorld & a_World) - { - a_World.BroadcastSoundEffect("random.click", x, y, z, 0.5f, 0.5f); - }); + auto TickDelay = (m_BlockType == E_BLOCK_STONE_BUTTON) ? 20 : 30; + a_Player->GetWorld()->ScheduleTask(TickDelay, [x, y, z, a_BlockX, a_BlockY, a_BlockZ, this](cWorld & a_World) + { + if (a_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == m_BlockType) + { + // Block hasn't change in the meantime; set its meta + a_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07); + a_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + a_World.BroadcastSoundEffect("random.click", x, y, z, 0.5f, 0.5f); + } + } + ); return true; } @@ -129,6 +133,12 @@ public: UNUSED(a_Meta); return 0; } + + /** Extracts the ON bit from metadata and returns if true if it is set */ + static bool IsButtonOn(NIBBLETYPE a_BlockMeta) + { + return ((a_BlockMeta & 0x8) == 0x8); + } } ; diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h index d4ec08dff..8f1822299 100644 --- a/src/Blocks/BlockComparator.h +++ b/src/Blocks/BlockComparator.h @@ -60,16 +60,17 @@ public: return true; } - inline static Vector3i GetSideCoordinate(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool a_bInverse) + inline static Vector3i GetSideCoordinate(const Vector3i & a_Position, NIBBLETYPE a_Meta, bool a_bInverse) { + auto Position = a_Position; if (!a_bInverse) { switch (a_Meta) { - case 0x0: a_BlockX++; break; - case 0x1: a_BlockZ--; break; - case 0x2: a_BlockX--; break; - case 0x3: a_BlockZ++; break; + case 0x0: Position.x++; break; + case 0x1: Position.z--; break; + case 0x2: Position.x--; break; + case 0x3: Position.z++; break; default: { LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta); @@ -82,10 +83,10 @@ public: { switch (a_Meta) { - case 0x0: a_BlockX--; break; - case 0x1: a_BlockZ++; break; - case 0x2: a_BlockX++; break; - case 0x3: a_BlockZ--; break; + case 0x0: Position.x--; break; + case 0x1: Position.z++; break; + case 0x2: Position.x++; break; + case 0x3: Position.z--; break; default: { LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta); @@ -95,17 +96,18 @@ public: } } - return Vector3i(a_BlockX, a_BlockY, a_BlockZ); + return Position; } - inline static Vector3i GetRearCoordinate(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) + inline static Vector3i GetRearCoordinate(const Vector3i & a_Position, NIBBLETYPE a_Meta) { + auto Position = a_Position; switch (a_Meta) { - case 0x0: a_BlockZ++; break; - case 0x1: a_BlockX--; break; - case 0x2: a_BlockZ--; break; - case 0x3: a_BlockX++; break; + case 0x0: Position.z++; break; + case 0x1: Position.x--; break; + case 0x2: Position.z--; break; + case 0x3: Position.x++; break; default: { LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta); @@ -114,17 +116,18 @@ public: } } - return Vector3i(a_BlockX, a_BlockY, a_BlockZ); + return Position; } - inline static Vector3i GetFrontCoordinate(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) + inline static Vector3i GetFrontCoordinate(const Vector3i & a_Position, NIBBLETYPE a_Meta) { + auto Position = a_Position; switch (a_Meta) { - case 0x0: a_BlockZ--; break; - case 0x1: a_BlockX++; break; - case 0x2: a_BlockZ++; break; - case 0x3: a_BlockX--; break; + case 0x0: Position.z--; break; + case 0x1: Position.x++; break; + case 0x2: Position.z++; break; + case 0x3: Position.x--; break; default: { LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta); @@ -133,7 +136,7 @@ public: } } - return Vector3i(a_BlockX, a_BlockY, a_BlockZ); + return Position; } virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 85fd2f28d..a3bbd54f5 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -156,6 +156,12 @@ public: UNUSED(a_Meta); return 0; } + + /** Extracts the ON bit from metadata and returns if true if it is set */ + static bool IsLeverOn(NIBBLETYPE a_BlockMeta) + { + return ((a_BlockMeta & 0x8) == 0x8); + } } ; diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h index e0066e8ab..6a384b85d 100644 --- a/src/Blocks/BlockPiston.h +++ b/src/Blocks/BlockPiston.h @@ -65,7 +65,7 @@ public: static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData) { - switch (a_MetaData) + switch (a_MetaData & 0x7) // We only want the bottom three bits (4th controls extended-ness)) { case 0x0: return BLOCK_FACE_YM; case 0x1: return BLOCK_FACE_YP; diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index b603bb1a7..734ee93c7 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -73,10 +73,11 @@ public: virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - if (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ) && (Meta != FindMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ))) + auto Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + auto NewMeta = FindMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); + if (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ) && (Meta != NewMeta)) { - a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, FindMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ)); + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, (m_BlockType == E_BLOCK_RAIL) ? NewMeta : NewMeta | (Meta & 0x08)); } } diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 5f413e10a..033ba82de 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -110,6 +110,42 @@ public: UNUSED(a_Meta); return 11; } + + + inline static Vector3i GetRearCoordinateOffset(NIBBLETYPE a_Meta) + { + switch (a_Meta & 0x3) // We only want the direction (bottom) bits + { + case 0x0: return {0, 0, 1}; + case 0x1: return {-1, 0, 0}; + case 0x2: return {0, 0, -1}; + case 0x3: return {1, 0, 0}; + default: + { + LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta); + ASSERT(!"Unknown metadata while determining orientation of repeater!"); + return {0, 0, 0}; + } + } + } + + + inline static Vector3i GetFrontCoordinateOffset(NIBBLETYPE a_Meta) + { + switch (a_Meta & 0x3) // We only want the direction (bottom) bits + { + case 0x0: return {0, 0, -1}; + case 0x1: return {1, 0, 0}; + case 0x2: return {0, 0, 1}; + case 0x3: return {-1, 0, 0}; + default: + { + LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta); + ASSERT(!"Unknown metadata while determining orientation of repeater!"); + return {0, 0, 0}; + } + } + } } ; diff --git a/src/Blocks/ChunkInterface.cpp b/src/Blocks/ChunkInterface.cpp index d8a7fc919..7fa2981e9 100644 --- a/src/Blocks/ChunkInterface.cpp +++ b/src/Blocks/ChunkInterface.cpp @@ -72,16 +72,6 @@ void cChunkInterface::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIB -void cChunkInterface::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay, BLOCKTYPE a_PreviousBlockType, cWorldInterface & a_WorldInterface) -{ - m_ChunkMap->QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_WorldInterface.GetWorldAge() + a_TickDelay, a_PreviousBlockType); -} - - - - - - /** Sets the block at the specified coords to the specified value. The replacement doesn't trigger block updates. The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block) diff --git a/src/Blocks/ChunkInterface.h b/src/Blocks/ChunkInterface.h index 7b5f0d7fc..ee9bf9da7 100644 --- a/src/Blocks/ChunkInterface.h +++ b/src/Blocks/ChunkInterface.h @@ -29,8 +29,6 @@ public: void SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData); - void QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay, BLOCKTYPE a_PreviousBlockType, cWorldInterface & a_WorldInterface); - /** Sets the block at the specified coords to the specified value. The replacement doesn't trigger block updates. The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4e168834a..3d09da852 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,8 +9,8 @@ include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/libevent/include set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++ Bindings - WorldStorage Mobs Entities Simulator BlockEntities UI - Noise + WorldStorage Mobs Entities Simulator Simulator/IncrementalRedstoneSimulator + BlockEntities UI Noise ) SET (SRCS @@ -366,7 +366,8 @@ if (NOT MSVC) target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks Noise Protocol Generating WorldStorage - Mobs Entities Simulator BlockEntities UI PolarSSL++ + Mobs Entities Simulator IncrementalRedstoneSimulator + BlockEntities UI PolarSSL++ ) endif () if (WIN32) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index b991e073f..99311c1b1 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -605,9 +605,6 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) { BroadcastPendingBlockChanges(); - // Set all blocks that have been queued for setting later: - ProcessQueuedSetBlocks(); - CheckBlocks(); // Tick simulators: @@ -726,50 +723,6 @@ void cChunk::MoveEntityToNewChunk(cEntity * a_Entity) -void cChunk::ProcessQueuedSetBlocks(void) -{ - Int64 CurrTick = m_World->GetWorldAge(); - for (sSetBlockQueueVector::iterator itr = m_SetBlockQueue.begin(); itr != m_SetBlockQueue.end();) - { - if (itr->m_Tick <= CurrTick) - { - if (itr->m_PreviousType != E_BLOCK_AIR) // PreviousType defaults to 0 if not specified - { - if (GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ) == itr->m_PreviousType) - { - // Current world age is bigger than / equal to target world age - delay time reached AND - // Previous block type was the same as current block type (to prevent duplication) - SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta); // SetMeta doesn't send to client - itr = m_SetBlockQueue.erase(itr); - LOGD("Successfully set queued block - previous and current types matched"); - } - else - { - itr = m_SetBlockQueue.erase(itr); - LOGD("Failure setting queued block - previous and current blocktypes didn't match"); - } - } - else - { - // Current world age is bigger than / equal to target world age - delay time reached - SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta); - itr = m_SetBlockQueue.erase(itr); - LOGD("Successfully set queued block - previous type ignored"); - } - } - else - { - // Not yet - ++itr; - continue; - } - } // for itr - m_SetBlockQueue[] -} - - - - - void cChunk::BroadcastPendingBlockChanges(void) { if (m_PendingSendBlocks.empty()) @@ -1505,15 +1458,6 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, -void cChunk::QueueSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType) -{ - m_SetBlockQueue.push_back(sSetBlockQueueItem(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta, a_Tick, a_PreviousBlockType)); -} - - - - - void cChunk::QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ) { ASSERT ( @@ -2221,46 +2165,6 @@ bool cChunk::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBloc - -bool cChunk::DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cRedstonePoweredCallback & a_Callback) -{ - // The blockentity list is locked by the parent chunkmap's CS - for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2) - { - ++itr2; - if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ)) - { - continue; - } - switch ((*itr)->GetBlockType()) - { - case E_BLOCK_DROPPER: - case E_BLOCK_DISPENSER: - case E_BLOCK_NOTE_BLOCK: - { - break; - } - default: - { - // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out - return false; - } - } - - if (a_Callback.Item(dynamic_cast(*itr))) // Needs dynamic_cast due to multiple inheritance - { - return false; - } - return true; - } // for itr - m_BlockEntitites[] - - // Not found: - return false; -} - - - - bool cChunk::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback) { // The blockentity list is locked by the parent chunkmap's CS diff --git a/src/Chunk.h b/src/Chunk.h index a382f3e17..b2cf90cb9 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -7,7 +7,7 @@ #include "Simulator/FireSimulator.h" #include "Simulator/SandSimulator.h" -#include "Simulator/IncrementalRedstoneSimulator.h" +#include "Simulator/RedstoneSimulator.h" #include "Blocks/GetHandlerCompileTimeTemplate.h" @@ -49,7 +49,6 @@ class cBlockArea; class cFluidSimulatorData; class cMobCensus; class cMobSpawner; -class cRedstonePoweredEntity; class cSetChunkData; typedef std::list cClientHandleList; @@ -63,7 +62,6 @@ typedef cItemCallback cNoteBlockCallback; typedef cItemCallback cCommandBlockCallback; typedef cItemCallback cMobHeadCallback; typedef cItemCallback cFlowerPotCallback; -typedef cItemCallback cRedstonePoweredCallback; @@ -176,9 +174,6 @@ public: // SetBlock() does a lot of work (heightmap, tickblocks, blockentities) so a BlockIdx version doesn't make sense void SetBlock( const Vector3i & a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { SetBlock( a_RelBlockPos.x, a_RelBlockPos.y, a_RelBlockPos.z, a_BlockType, a_BlockMeta); } - /** Queues a block change till the specified world tick */ - void QueueSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR); - /** Queues block for ticking (m_ToTickQueue) */ void QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ); @@ -279,8 +274,6 @@ public: /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible - /** Calls the callback for the redstone powered entity at the specified coords; returns false if there's no redstone powered entity at those coords, true if found */ - bool DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cRedstonePoweredCallback & a_Callback); /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible @@ -489,8 +482,6 @@ private: std::vector m_ToTickBlocks; sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients - sSetBlockQueueVector m_SetBlockQueue; ///< Block changes that are queued to a specific tick - // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers std::vector m_LoadedByClient; cEntityList m_Entities; @@ -569,9 +560,6 @@ private: /** Called by Tick() when an entity moves out of this chunk into a neighbor; moves the entity and sends spawn / despawn packet to clients */ void MoveEntityToNewChunk(cEntity * a_Entity); - - /** Processes all blocks that have been scheduled for replacement by the QueueSetBlock() function */ - void ProcessQueuedSetBlocks(void); }; typedef cChunk * cChunkPtr; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index f2b22f4b9..edf42abe7 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1099,58 +1099,6 @@ bool cChunkMap::TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height) -void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList) -{ - sSetBlockList Failed; - - // Process all items from a_BlockList, either successfully or by placing into Failed - while (!a_BlockList.empty()) - { - int ChunkX = a_BlockList.front().m_ChunkX; - int ChunkZ = a_BlockList.front().m_ChunkZ; - cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); - if ((Chunk != nullptr) && Chunk->IsValid()) - { - for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();) - { - if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ)) - { - Chunk->FastSetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta); - itr = a_BlockList.erase(itr); - } - else - { - ++itr; - } - } // for itr - a_BlockList[] - } - else - { - // The chunk is not valid, move all blocks within this chunk to Failed - for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();) - { - if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ)) - { - Failed.push_back(*itr); - itr = a_BlockList.erase(itr); - } - else - { - ++itr; - } - } // for itr - a_BlockList[] - } - } - - // Return the failed: - std::swap(Failed, a_BlockList); -} - - - - - void cChunkMap::SetBlocks(const sSetBlockVector & a_Blocks) { cCSLock lock(m_CSLayers); @@ -1212,19 +1160,7 @@ BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ) int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); - // First check if it isn't queued in the m_FastSetBlockQueue: - { - cCSLock Lock(m_CSFastSetBlock); - for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr) - { - if ((itr->m_RelX == X) && (itr->m_RelY == Y) && (itr->m_RelZ == Z) && (itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ)) - { - return itr->m_BlockType; - } - } // for itr - m_FastSetBlockQueue[] - } - - // Not in the queue, query the chunk, if loaded: + // Query the chunk, if loaded: cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) @@ -1244,19 +1180,7 @@ NIBBLETYPE cChunkMap::GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ) int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); - // First check if it isn't queued in the m_FastSetBlockQueue: - { - cCSLock Lock(m_CSFastSetBlock); - for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr) - { - if ((itr->m_RelX == X) && (itr->m_RelY == Y) && (itr->m_RelZ == Z) && (itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ)) - { - return itr->m_BlockMeta; - } - } // for itr - m_FastSetBlockQueue[] - } - - // Not in the queue, query the chunk, if loaded: + // Query the chunk, if loaded: cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) @@ -1346,23 +1270,6 @@ void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_B -void cChunkMap::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType) -{ - int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; - cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); - - cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); - if ((Chunk != nullptr) && Chunk->IsValid()) - { - Chunk->QueueSetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_Tick, a_PreviousBlockType); - } -} - - - - - bool cChunkMap::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) { int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; @@ -3187,28 +3094,14 @@ void cChunkMap::cChunkLayer::UnloadUnusedChunks(void) void cChunkMap::FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - cCSLock Lock(m_CSFastSetBlock); - m_FastSetBlockQueue.push_back(sSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta)); -} - - - - + int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; + cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); -void cChunkMap::FastSetQueuedBlocks() -{ - // Asynchronously set blocks: - sSetBlockList FastSetBlockQueueCopy; - { - cCSLock Lock(m_CSFastSetBlock); - std::swap(FastSetBlockQueueCopy, m_FastSetBlockQueue); - } - this->FastSetBlocks(FastSetBlockQueueCopy); - if (!FastSetBlockQueueCopy.empty()) + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); + if ((Chunk != nullptr) && Chunk->IsValid()) { - // Some blocks failed, store them for next tick: - cCSLock Lock(m_CSFastSetBlock); - m_FastSetBlockQueue.splice(m_FastSetBlockQueue.end(), FastSetBlockQueueCopy); + Chunk->FastSetBlock(X, Y, Z, a_BlockType, a_BlockMeta); } } diff --git a/src/ChunkMap.h b/src/ChunkMap.h index a43e43895..6b7df7610 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -147,9 +147,6 @@ public: int GetHeight (int a_BlockX, int a_BlockZ); // Waits for the chunk to get loaded / generated bool TryGetHeight (int a_BlockX, int a_BlockZ, int & a_Height); // Returns false if chunk not loaded / generated void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); - - void FastSetQueuedBlocks(); - void FastSetBlocks(sSetBlockList & a_BlockList); /** Performs the specified single-block set operations simultaneously, as if SetBlock() was called for each item. Is more efficient than calling SetBlock() multiple times. @@ -164,7 +161,6 @@ public: NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ); void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta); void SetBlock (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true); - void QueueSetBlock (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR); bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); @@ -516,9 +512,6 @@ private: cWorld * m_World; - cCriticalSection m_CSFastSetBlock; - sSetBlockList m_FastSetBlockQueue; - /** The cChunkStay descendants that are currently enabled in this chunkmap */ cChunkStays m_ChunkStays; diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 9062d8cab..74556d2a0 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -927,6 +927,12 @@ void cClientHandle::HandleBeaconSelection(int a_PrimaryEffect, int a_SecondaryEf void cClientHandle::HandleCommandBlockBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_NewCommand) { + if (a_NewCommand.empty()) + { + Kick("Command block string unexpectedly empty - hacked client?"); + return; + } + cWorld * World = m_Player->GetWorld(); if (World->AreCommandBlocksEnabled()) { diff --git a/src/Simulator/CMakeLists.txt b/src/Simulator/CMakeLists.txt index 966acd264..a798e4b02 100644 --- a/src/Simulator/CMakeLists.txt +++ b/src/Simulator/CMakeLists.txt @@ -9,7 +9,6 @@ SET (SRCS FireSimulator.cpp FloodyFluidSimulator.cpp FluidSimulator.cpp - IncrementalRedstoneSimulator.cpp SandSimulator.cpp Simulator.cpp SimulatorManager.cpp @@ -21,7 +20,6 @@ SET (HDRS FireSimulator.h FloodyFluidSimulator.h FluidSimulator.h - IncrementalRedstoneSimulator.h NoopFluidSimulator.h NoopRedstoneSimulator.h RedstoneSimulator.h @@ -35,7 +33,6 @@ SET (HDRS if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set_source_files_properties(FireSimulator.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=sign-conversion") set_source_files_properties(FluidSimulator.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=sign-conversion -Wno-error=shadow") - set_source_files_properties(IncrementalRedstoneSimulator.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=conversion ") endif() if(NOT MSVC) diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp deleted file mode 100644 index fc3dc0a73..000000000 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ /dev/null @@ -1,2298 +0,0 @@ - -#include "Globals.h" - -#include "BlockEntities/ChestEntity.h" - -#include "Chunk.h" -#include "World.h" -#include "Blocks/GetHandlerCompileTimeTemplate.h" -#include "Blocks/BlockComparator.h" -#include "Blocks/BlockTorch.h" -#include "Blocks/BlockLever.h" -#include "Blocks/BlockButton.h" -#include "Blocks/BlockTripwireHook.h" -#include "Blocks/BlockDoor.h" -#include "Blocks/BlockPiston.h" - - -#include "IncrementalRedstoneSimulator.h" -#include "BoundingBox.h" -#include "Blocks/ChunkInterface.h" -#include "RedstoneSimulator.h" - - - - - -void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) -{ - AddBlock(cChunkDef::AbsoluteToRelative({ a_BlockX, a_BlockY, a_BlockZ }, a_Chunk->GetPosX(), a_Chunk->GetPosZ()), a_Chunk, nullptr); -} - - - - - -void cIncrementalRedstoneSimulator::AddBlock(const Vector3i & a_RelBlockPosition, cChunk * a_OriginalChunk, cChunk * a_NeighborChunk) -{ - if ((a_OriginalChunk == nullptr) || !a_OriginalChunk->IsValid()) - { - return; - } - else if ((a_RelBlockPosition.y < 0) || (a_RelBlockPosition.y >= cChunkDef::Height)) - { - return; - } - - // The relative block position is relative to the neighboring chunk should it be passed as an argument - - BLOCKTYPE Block; - NIBBLETYPE Meta; - - if (a_NeighborChunk != nullptr) - { - a_NeighborChunk->UnboundedRelGetBlock(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, Meta); - - // If a_OtherChunk is passed (not nullptr), it is the neighbouring chunk of a_Chunk, which itself is the chunk with the block change - // Because said neighbouring chunk does not know of this change but still needs to update its redstone, we set it to dirty - a_NeighborChunk->SetIsRedstoneDirty(true); - } - else - { - a_OriginalChunk->GetBlockTypeMeta(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, Meta); - } - - // Every time a block is changed (AddBlock called), we want to go through all lists and check to see if the coordiantes stored within are still valid - // Checking only when a block is changed, as opposed to every tick, also improves performance - - if ( - !IsPotentialSource(Block) || - ( - // Changeable sources - ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) || - ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) || - ((Block == E_BLOCK_DETECTOR_RAIL) && ((Meta & 0x08) == 0)) || - (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) || - ((Block == E_BLOCK_TRIPWIRE_HOOK) && ((Meta & 0x08) == 0)) - ) - ) - { - SetSourceUnpowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_NeighborChunk != nullptr ? a_NeighborChunk : a_OriginalChunk); - } - - if (!IsViableMiddleBlock(Block)) - { - SetInvalidMiddleBlock(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_NeighborChunk != nullptr ? a_NeighborChunk : a_OriginalChunk); - } - - if (a_NeighborChunk != nullptr) - { - // DO NOT touch our chunk's data structure if we are being called with coordinates from another chunk - this one caused me massive grief :P - return; - } - auto RedstoneSimulatorData = static_cast(a_OriginalChunk->GetRedstoneSimulatorData()); - - auto & SimulatedPlayerToggleableBlocks = RedstoneSimulatorData->m_SimulatedPlayerToggleableBlocks; - if (DoesIgnorePlayerToggle(Block)) - { - // Initialise the toggleable blocks list so that trapdoors etc. aren't reset on restart (#1887) - SimulatedPlayerToggleableBlocks.emplace( - a_RelBlockPosition, - AreCoordsDirectlyPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk) || AreCoordsLinkedPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk) - ); // This map won't insert if key already present, so no need to check - } - else - { - SimulatedPlayerToggleableBlocks.erase(a_RelBlockPosition); - } - - if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF)) - { - RedstoneSimulatorData->m_RepeatersDelayList.erase(a_RelBlockPosition); - } - - auto & RedstoneSimulatorChunkData = RedstoneSimulatorData->m_ChunkData; - auto Iterator = RedstoneSimulatorChunkData.find(a_RelBlockPosition); - if (!IsAllowedBlock(Block)) - { - if (Iterator != RedstoneSimulatorChunkData.end()) - { - Iterator->second.second = true; // The new blocktype is not redstone; it must be queued to be removed from this list - } - return; - } - else - { - if (Iterator != RedstoneSimulatorChunkData.end()) - { - Iterator->second.second = false; // De-schedule removal from list - Iterator->second.first = Block; // Update block information - return; - } - } - - RedstoneSimulatorChunkData.emplace(a_RelBlockPosition, std::make_pair(Block, false)); -} - - - - - -void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) -{ - m_RedstoneSimulatorChunkData = static_cast(a_Chunk->GetRedstoneSimulatorData()); - if (m_RedstoneSimulatorChunkData == nullptr) - { - m_RedstoneSimulatorChunkData = new cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData(); - a_Chunk->SetRedstoneSimulatorData(m_RedstoneSimulatorChunkData); - } - if (m_RedstoneSimulatorChunkData->m_ChunkData.empty()) - { - return; - } - - m_PoweredBlocks = &m_RedstoneSimulatorChunkData->m_PoweredBlocks; - m_RepeatersDelayList = &m_RedstoneSimulatorChunkData->m_RepeatersDelayList; - m_SimulatedPlayerToggleableBlocks = &m_RedstoneSimulatorChunkData->m_SimulatedPlayerToggleableBlocks; - m_LinkedPoweredBlocks = &m_RedstoneSimulatorChunkData->m_LinkedBlocks; - m_Chunk = a_Chunk; - bool ShouldUpdateSimulateOnceBlocks = false; - - if (a_Chunk->IsRedstoneDirty()) - { - // Simulate the majority of devices only if something (blockwise or power-wise) has changed - // Make sure to allow the chunk to resimulate after the initial run if there was a power change (ShouldUpdateSimulateOnceBlocks helps to do this) - a_Chunk->SetIsRedstoneDirty(false); - ShouldUpdateSimulateOnceBlocks = true; - } - - HandleRedstoneRepeaterDelays(); - - for (auto dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.begin(); dataitr != m_RedstoneSimulatorChunkData->m_ChunkData.end();) - { - if (dataitr->second.second) - { - // Removal was scheduled - do so - dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.erase(dataitr); - continue; - } - - switch (dataitr->second.first) // Call the appropriate simulator for the entry's block type - { - case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_TRIPWIRE: HandleTripwire(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_TRIPWIRE_HOOK: HandleTripwireHook(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - - case E_BLOCK_WOODEN_PRESSURE_PLATE: - case E_BLOCK_STONE_PRESSURE_PLATE: - case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: - case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: - { - HandlePressurePlate(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); - break; - } - default: break; - } - - if (ShouldUpdateSimulateOnceBlocks) - { - switch (dataitr->second.first) - { - case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_LEVER: HandleRedstoneLever(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_TNT: HandleTNT(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_IRON_TRAPDOOR: HandleTrapdoor(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - case E_BLOCK_TRAPPED_CHEST: HandleTrappedChest(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; - - case E_BLOCK_ACTIVATOR_RAIL: - case E_BLOCK_DETECTOR_RAIL: - case E_BLOCK_POWERED_RAIL: - { - HandleRail(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); - break; - } - case E_BLOCK_ACACIA_DOOR: - case E_BLOCK_BIRCH_DOOR: - case E_BLOCK_DARK_OAK_DOOR: - case E_BLOCK_JUNGLE_DOOR: - case E_BLOCK_SPRUCE_DOOR: - case E_BLOCK_OAK_DOOR: - case E_BLOCK_IRON_DOOR: - { - HandleDoor(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - case E_BLOCK_ACACIA_FENCE_GATE: - case E_BLOCK_BIRCH_FENCE_GATE: - case E_BLOCK_DARK_OAK_FENCE_GATE: - case E_BLOCK_OAK_FENCE_GATE: - case E_BLOCK_JUNGLE_FENCE_GATE: - case E_BLOCK_SPRUCE_FENCE_GATE: - { - HandleFenceGate(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - case E_BLOCK_REDSTONE_LAMP_OFF: - case E_BLOCK_REDSTONE_LAMP_ON: - { - HandleRedstoneLamp(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); - break; - } - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - { - HandleDropSpenser(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: - { - HandlePiston(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - { - HandleRedstoneRepeater(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); - break; - } - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: - { - HandleRedstoneTorch(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); - break; - } - case E_BLOCK_STONE_BUTTON: - case E_BLOCK_WOODEN_BUTTON: - { - HandleRedstoneButton(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - case E_BLOCK_ACTIVE_COMPARATOR: - case E_BLOCK_INACTIVE_COMPARATOR: - { - HandleRedstoneComparator(dataitr->first.x, dataitr->first.y, dataitr->first.z); - break; - } - default: break; - } - } - ++dataitr; - } -} - - - - - -void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) -{ - auto CurrentChunkRelative = cChunkDef::AbsoluteToRelative({a_BlockX, a_BlockY, a_BlockZ}, a_Chunk->GetPosX(), a_Chunk->GetPosZ()); - AddBlock(CurrentChunkRelative, a_Chunk); // Alert the current chunk which the block is present in - - for (const auto & BoundaryChunk : GetAdjacentChunks(CurrentChunkRelative, a_Chunk)) - { - // On a chunk boundary, alert all neighbouring chunks which may have a connection with this block - AddBlock(cChunkDef::AbsoluteToRelative({a_BlockX, a_BlockY, a_BlockZ}, BoundaryChunk->GetPosX(), BoundaryChunk->GetPosZ()), a_Chunk, BoundaryChunk); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) -{ - static const struct // Define which directions the torch can power - { - int x, y, z; - } gCrossCoords[] = - { - { 1, 0, 0 }, - { -1, 0, 0 }, - { 0, 0, 1 }, - { 0, 0, -1 }, - { 0, 1, 0 }, - }; - - if (a_MyState == E_BLOCK_REDSTONE_TORCH_ON) - { - // Check if the block the torch is on is powered - int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ; - AddFaceDirection(X, Y, Z, GetHandlerCompileTime::type::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on - - cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(X, Z); - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - - if (AreCoordsDirectlyPowered(X, Y, Z, Neighbour)) - { - // There was a match, torch goes off - m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - return; - } - - // Torch still on, make all 4(X, Z) + 1(Y) sides powered - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) - { - BLOCKTYPE Type = 0; - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type)) - { - continue; - } - if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last) - { - if ( - IsMechanism(Type) && // Is it a mechanism? Not block / other torch etc. - (!Vector3i(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on - ) - { - SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - } - } - else - { - // Top side, power whatever is there, including blocks - SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - // Power all blocks surrounding block above torch - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YP); - } - } - - if (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath - { - BLOCKTYPE Type = m_Chunk->GetBlock(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ); - - if (IsMechanism(Type)) // Still can't make a normal block powered though! - { - SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - } - } - } - else - { - // Check if the block the torch is on is powered - int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ; - AddFaceDirection(X, Y, Z, GetHandlerCompileTime::type::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on - - cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(X, Z); - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - - // See if off state torch can be turned on again - if (AreCoordsDirectlyPowered(X, Y, Z, Neighbour)) - { - return; // Something matches, torch still powered - } - - // Block torch on not powered, can be turned on again! - m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Set self as powered -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (IsLeverOn(Meta)) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - - eBlockFace Dir = GetHandlerCompileTime::type::BlockMetaDataToBlockFace(Meta); - - Dir = ReverseBlockFace(Dir); - - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - NIBBLETYPE MetaData = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) - { - if ((MetaData & 0x4) == 0) - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData | 0x4); - m_Chunk->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_DOOR_OPEN_CLOSE, BlockX, a_RelBlockY, BlockZ, 0); - } - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); - } - } - else - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) - { - if ((MetaData & 0x4) != 0) - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData & ~0x04); - m_Chunk->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_DOOR_OPEN_CLOSE, BlockX, a_RelBlockY, BlockZ, 0); - } - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (IsButtonOn(Meta)) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - - eBlockFace Dir = GetHandlerCompileTime::type::BlockMetaDataToBlockFace(Meta); - Dir = ReverseBlockFace(Dir); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - static const eBlockFace BlockFaceOffsets[] = - { - BLOCK_FACE_XM, - BLOCK_FACE_XP, - BLOCK_FACE_ZM, - BLOCK_FACE_ZP - }; - - static const Vector3i VectorOffsets[] = - { - { -1, 0, 0 }, - { 1, 0, 0 }, - { 0, 0, -1 }, - { 0, 0, 1 } - }; - - auto RelBlock = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - - // Check to see if directly beside a power source - unsigned char MyPower = IsWirePowered(RelBlock, m_Chunk); - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - if (MyPower == 0) - { - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - return; - } - - if (MyPower == MAX_POWER_LEVEL) - { - std::vector> PotentialWireList = { std::make_pair(RelBlock, m_Chunk) }; - while (!PotentialWireList.empty()) - { - auto Current = PotentialWireList.back(); - PotentialWireList.pop_back(); - FindAndPowerBorderingWires(PotentialWireList, Current.first, Current.second); - } - } - else if (MyPower == 1) - { - return; - } - - // Wire still powered, power blocks beneath and in direction of facing - MyPower--; - - SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, MyPower); - - int BorderingMechanismCount = 0; - bool RepeaterPresent = false; - Vector3i OffsetToPower; - - for (const auto & Offset : VectorOffsets) - { - BLOCKTYPE Block; - Vector3i AdjustedOffset = RelBlock + Offset; - if (m_Chunk->UnboundedRelGetBlockType(AdjustedOffset.x, AdjustedOffset.y, AdjustedOffset.z, Block)) - { - switch (Block) - { - case E_BLOCK_REDSTONE_REPEATER_OFF: - { - BorderingMechanismCount++; - if (!RepeaterPresent) - { - // TODO: only if wire is actually connected to repeater (repeater facing right way) - RepeaterPresent = true; - OffsetToPower = { -Offset.x, Offset.y, -Offset.z }; // Negate to obtain offset in opposite direction since wire powers that way - } - SetBlockPowered(AdjustedOffset, RelBlock, MyPower); - } - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_REDSTONE_WIRE: - { - BorderingMechanismCount++; - if (!RepeaterPresent) - { - OffsetToPower = { -Offset.x, Offset.y, -Offset.z }; - } - } - default: break; - } - } - } - - if (BorderingMechanismCount == 0) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - for (const auto & BlockFaceOffset : BlockFaceOffsets) - { - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BlockFaceOffset, MyPower); - } - } - else if (BorderingMechanismCount == 1) - { - eBlockFace Face = BlockFaceOffsets[std::distance(VectorOffsets, std::find(VectorOffsets, VectorOffsets + ARRAYCOUNT(VectorOffsets), OffsetToPower))]; - SetBlockPowered(RelBlock + OffsetToPower, RelBlock, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Face, MyPower); - } -} - - - - - -void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const Vector3i & a_EntryRelBlockPosition, cChunk * a_EntryChunk) -{ - static const Vector3i LevelOffsets[] = // Wires on same level - { - { 1, 0, 0 }, - { -1, 0, 0 }, - { 0, 0, 1 }, - { 0, 0, -1 }, - }; - static const Vector3i HigherOffsets[] = // Wires one higher, surrounding self - { - { 1, 1, 0 }, - { -1, 1, 0 }, - { 0, 1, 1 }, - { 0, 1, -1 }, - }; - static const Vector3i LowerOffsets[] = // Wires one lower, surrounding self - { - { 1, -1, 0 }, - { -1, -1, 0 }, - { 0, -1, 1 }, - { 0, -1, -1 }, - }; - - for (auto Offset : LevelOffsets) - { - auto AdjustedPos = a_EntryRelBlockPosition + Offset; - auto Neighbour = a_EntryChunk->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); - auto MyPower = IsWirePowered(a_EntryRelBlockPosition, a_EntryChunk); - - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - - if ((Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) - { - PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, MyPower); - } - } - - for (auto Offset : HigherOffsets) - { - auto AdjustedPos = a_EntryRelBlockPosition + Offset; - auto Neighbour = a_EntryChunk->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); - auto MyPower = IsWirePowered(a_EntryRelBlockPosition, a_EntryChunk); - - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - - if ( - (Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && - (!cBlockInfo::FullyOccupiesVoxel(a_EntryChunk->GetBlock(a_EntryRelBlockPosition.x, a_EntryRelBlockPosition.y + 1, a_EntryRelBlockPosition.z)) || - (a_EntryChunk->GetBlock(a_EntryRelBlockPosition.x, a_EntryRelBlockPosition.y + 1, a_EntryRelBlockPosition.z) == E_BLOCK_GLOWSTONE)) && - (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) - { - PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, MyPower); - } - } - - for (auto Offset : LowerOffsets) - { - auto AdjustedPos = a_EntryRelBlockPosition + Offset; - auto Neighbour = a_EntryChunk->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); - auto MyPower = IsWirePowered(a_EntryRelBlockPosition, a_EntryChunk); - - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - - if ( - (Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && - (!cBlockInfo::FullyOccupiesVoxel(Neighbour->GetBlock(AdjustedPos.x, AdjustedPos.y + 1, AdjustedPos.z)) || - (Neighbour->GetBlock(AdjustedPos.x, AdjustedPos.y + 1, AdjustedPos.z) == E_BLOCK_GLOWSTONE)) && - (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) - { - PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, MyPower); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::PowerBorderingWires(std::vector> & a_PotentialWireList, const Vector3i & a_EntryRelSourcePosition, cChunk * a_EntryChunk, const Vector3i & a_AdjustedPos, cChunk * a_NeighbourChunk, unsigned char a_MyPower) -{ - auto SourcePos = a_EntryRelSourcePosition + Vector3i((a_EntryChunk->GetPosX() - a_NeighbourChunk->GetPosX()) * cChunkDef::Width, 0, (a_EntryChunk->GetPosZ() - a_NeighbourChunk->GetPosZ()) * cChunkDef::Width); - auto & PoweredBlocks = static_cast(a_NeighbourChunk->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position - auto Position = std::find_if(PoweredBlocks.begin(), PoweredBlocks.end(), [a_AdjustedPos, SourcePos, a_MyPower](const sPoweredBlocks & itr) { return ((itr.m_BlockPos == a_AdjustedPos) && (itr.m_SourcePos == SourcePos)); }); - if (Position != PoweredBlocks.end()) - { - Position->m_PowerLevel = a_MyPower - 1; - } - else - { - PoweredBlocks.emplace_back(a_AdjustedPos, SourcePos, a_MyPower - 1); - - a_NeighbourChunk->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); - } - - a_NeighbourChunk->SetMeta(a_AdjustedPos.x, a_AdjustedPos.y, a_AdjustedPos.z, a_MyPower - 1); - a_PotentialWireList.emplace_back(std::make_pair(a_AdjustedPos, a_NeighbourChunk)); -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneComparator(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - auto Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - auto HighestSidePower = std::max(IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetSideCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3, false)), m_Chunk), IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetSideCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3, true)), m_Chunk)); - auto FrontCoordinate = AdjustRelativeCoords(cBlockComparatorHandler::GetFrontCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3)); - unsigned char Power = 0; - - class cContainerCallback : public cBlockEntityCallback - { - public: - cContainerCallback() : m_SignalStrength(0) - { - } - - virtual bool Item(cBlockEntity * a_BlockEntity) override - { - auto & Contents = static_cast(a_BlockEntity)->GetContents(); - float Fullness = 0; // Is a floating-point type to allow later calculation to produce a non-truncated value - for (int Slot = 0; Slot != Contents.GetNumSlots(); ++Slot) - { - Fullness += Contents.GetSlot(Slot).m_ItemCount / Contents.GetSlot(Slot).GetMaxStackSize(); - } - - m_SignalStrength = static_cast(1 + (Fullness / Contents.GetNumSlots()) * 14); - return false; - } - - unsigned char m_SignalStrength; - } CCB; - - auto AbsoluteComparatorCoords = cChunkDef::RelativeToAbsolute(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), m_Chunk->GetPosX(), m_Chunk->GetPosZ()); - auto AbsoluteRearCoords = cBlockComparatorHandler::GetRearCoordinate(AbsoluteComparatorCoords.x, AbsoluteComparatorCoords.y, AbsoluteComparatorCoords.z, Meta & 0x3); - - m_Chunk->DoWithBlockEntityAt(AbsoluteRearCoords.x, AbsoluteRearCoords.y, AbsoluteRearCoords.z, CCB); - auto RearPower = std::max(CCB.m_SignalStrength, IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetRearCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3)), m_Chunk)); - - if ((Meta & 0x4) == 0x4) - { - // Subtraction mode - Power = std::max(static_cast(RearPower - HighestSidePower), std::numeric_limits::min()); - } - else - { - // Comparison mode - Power = (std::max(HighestSidePower, RearPower) == HighestSidePower) ? 0 : RearPower; - } - - if (Power > 0) - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0x8); - SetBlockPowered(FrontCoordinate, Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), Power); - } - else - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) -{ - /* Repeater Orientation Mini Guide: - =================================== - - | - | Z Axis - V - - X Axis ----> - - Repeater directions, values from a WorldType::GetBlockMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) lookup: - - East (Right) (X+): 0x1 - West (Left) (X-): 0x3 - North (Up) (Z-): 0x2 - South (Down) (Z+): 0x0 - // TODO: Add E_META_XXX enum entries for all meta values and update project with them - - Sun rises from East (X+) - - */ - - // Create a variable holding my meta to avoid multiple lookups. - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - bool IsOn = (a_MyState == E_BLOCK_REDSTONE_REPEATER_ON); - - if (!IsRepeaterLocked(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta)) // If we're locked, change nothing. Otherwise: - { - bool IsSelfPowered = IsRepeaterPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta); - if (IsSelfPowered && !IsOn) // Queue a power change if powered, but not on and not locked. - { - QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta, true); - } - else if (!IsSelfPowered && IsOn) // Queue a power change if unpowered, on, and not locked. - { - QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta, false); - } - } - - if (IsOn) - { - switch (Meta & 0x3) // We only want the direction (bottom) bits - { - case 0x0: - { - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM); - break; - } - case 0x1: - { - SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP); - break; - } - case 0x2: - { - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP); - break; - } - case 0x3: - { - SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM); - break; - } - } - } -} - - -void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays() -{ - for (auto itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end();) - { - if (itr->second.a_ElapsedTicks >= itr->second.a_DelayTicks) // Has the elapsed ticks reached the target ticks? - { - BLOCKTYPE Block; - NIBBLETYPE Meta; - m_Chunk->GetBlockTypeMeta(itr->first.x, itr->first.y, itr->first.z, Block, Meta); - if (itr->second.ShouldPowerOn) - { - if (Block != E_BLOCK_REDSTONE_REPEATER_ON) // For performance - { - m_Chunk->SetBlock(itr->first, E_BLOCK_REDSTONE_REPEATER_ON, Meta); - } - } - else if (Block != E_BLOCK_REDSTONE_REPEATER_OFF) - { - m_Chunk->SetBlock(itr->first.x, itr->first.y, itr->first.z, E_BLOCK_REDSTONE_REPEATER_OFF, Meta); - } - itr = m_RepeatersDelayList->erase(itr); - } - else - { - LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->first.x, itr->first.y, itr->first.z, itr->second.a_ElapsedTicks, itr->second.a_DelayTicks); - itr->second.a_ElapsedTicks++; - ++itr; - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - - if (IsPistonPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness) - { - GetHandlerCompileTime::type::ExtendPiston(Vector3i(BlockX, a_RelBlockY, BlockZ), &this->m_World); - } - else - { - GetHandlerCompileTime::type::RetractPiston(Vector3i(BlockX, a_RelBlockY, BlockZ), &this->m_World); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - class cSetPowerToDropSpenser : - public cRedstonePoweredCallback - { - bool m_IsPowered; - public: - cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} - - virtual bool Item(cRedstonePoweredEntity * a_DropSpenser) override - { - a_DropSpenser->SetRedstonePower(m_IsPowered); - return false; - } - } DrSpSP(AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, DrSpSP); -} - - - - - -void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) -{ - if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF) - { - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0); - } - } - else - { - if (!AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - m_Chunk->BroadcastSoundEffect("game.tnt.primed", static_cast(BlockX), static_cast(a_RelBlockY), static_cast(BlockZ), 0.5f, 0.6f); - m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_AIR, 0); - this->m_World.SpawnPrimedTNT(BlockX + 0.5, a_RelBlockY + 0.5, BlockZ + 0.5); // 80 ticks to boom - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - - typedef GetHandlerCompileTime::type DoorHandler; - - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) - { - cChunkInterface ChunkInterface(this->m_World.GetChunkMap()); - if (!DoorHandler::IsOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ)) - { - DoorHandler::SetOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ, true); - m_Chunk->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_DOOR_OPEN_CLOSE, BlockX, a_RelBlockY, BlockZ, 0); - } - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); - } - } - else - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) - { - cChunkInterface ChunkInterface(this->m_World.GetChunkMap()); - if (DoorHandler::IsOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ)) - { - DoorHandler::SetOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ, false); - m_Chunk->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_DOOR_OPEN_CLOSE, BlockX, a_RelBlockY, BlockZ, 0); - } - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - class cSetPowerToCommandBlock : - public cRedstonePoweredCallback - { - bool m_IsPowered; - public: - cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} - - virtual bool Item(cRedstonePoweredEntity * a_CommandBlock) override - { - a_CommandBlock->SetRedstonePower(m_IsPowered); - return false; - } - } CmdBlockSP(AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, CmdBlockSP); -} - - - - - -void cIncrementalRedstoneSimulator::HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType) -{ - switch (a_MyType) - { - case E_BLOCK_DETECTOR_RAIL: - { - if ((m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x08) == 0x08) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_MyType); - } - break; - } - case E_BLOCK_ACTIVATOR_RAIL: - case E_BLOCK_POWERED_RAIL: - { - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0x08); - } - else - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x07); - } - break; - } - default: LOGD("Unhandled type of rail in %s", __FUNCTION__); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - - if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) - { - this->m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, true); - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); - } - } - else - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) - { - this->m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, false); - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - bool m_bAreCoordsPowered = AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - - if (m_bAreCoordsPowered) - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) - { - class cSetPowerToNoteBlock : - public cRedstonePoweredCallback - { - public: - cSetPowerToNoteBlock() {} - - virtual bool Item(cRedstonePoweredEntity * a_NoteBlock) override - { - a_NoteBlock->SetRedstonePower(true); - return false; - } - } NoteBlockSP; - - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, NoteBlockSP); - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); - } - } - else - { - if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) - { - SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX, BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ); - - if (!m_World.IsChunkLighted(ChunkX, ChunkZ)) - { - m_World.QueueLightChunk(ChunkX, ChunkZ); - } - else - { - if (m_Chunk->GetTimeAlteredLight(m_Chunk->GetSkyLight(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ)) > 8) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - } - else - { - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType) -{ - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - - switch (a_MyType) - { - case E_BLOCK_STONE_PRESSURE_PLATE: - { - // MCS feature - stone pressure plates can only be triggered by players :D - cPlayer * a_Player = this->m_World.FindClosestPlayer(Vector3f(BlockX + 0.5f, static_cast(a_RelBlockY), BlockZ + 0.5f), 0.5f, false); - - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (a_Player != nullptr) - { - if (Meta == E_META_PRESSURE_PLATE_RAISED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.5F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x1); - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM); - } - else - { - if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.6F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } - break; - } - case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: - { - class cPressurePlateCallback : - public cEntityCallback - { - public: - cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : - m_NumberOfEntities(0), - m_X(a_BlockX), - m_Y(a_BlockY), - m_Z(a_BlockZ) - { - } - - virtual bool Item(cEntity * a_Entity) override - { - Vector3f EntityPos = a_Entity->GetPosition(); - Vector3f BlockPos(m_X + 0.5f, static_cast(m_Y), m_Z + 0.5f); - double Distance = (EntityPos - BlockPos).Length(); - - if (Distance <= 0.5) - { - m_NumberOfEntities++; - } - return false; - } - - bool GetPowerLevel(unsigned char & a_PowerLevel) const - { - a_PowerLevel = static_cast(std::min(m_NumberOfEntities, MAX_POWER_LEVEL)); - return (a_PowerLevel > 0); - } - - protected: - int m_NumberOfEntities; - - int m_X; - int m_Y; - int m_Z; - }; - - cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); - - unsigned char Power; - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (PressurePlateCallback.GetPowerLevel(Power)) - { - if (Meta == E_META_PRESSURE_PLATE_RAISED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.5F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, Power); - } - else - { - if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.6F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } - - break; - } - case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: - { - class cPressurePlateCallback : - public cEntityCallback - { - public: - cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : - m_NumberOfEntities(0), - m_X(a_BlockX), - m_Y(a_BlockY), - m_Z(a_BlockZ) - { - } - - virtual bool Item(cEntity * a_Entity) override - { - Vector3f EntityPos = a_Entity->GetPosition(); - Vector3f BlockPos(m_X + 0.5f, static_cast(m_Y), m_Z + 0.5f); - double Distance = (EntityPos - BlockPos).Length(); - - if (Distance <= 0.5) - { - m_NumberOfEntities++; - } - return false; - } - - bool GetPowerLevel(unsigned char & a_PowerLevel) const - { - a_PowerLevel = static_cast(std::min(static_cast(ceil(m_NumberOfEntities / 10.f)), MAX_POWER_LEVEL)); - return (a_PowerLevel > 0); - } - - protected: - int m_NumberOfEntities; - - int m_X; - int m_Y; - int m_Z; - }; - - cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); - - unsigned char Power; - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (PressurePlateCallback.GetPowerLevel(Power)) - { - if (Meta == E_META_PRESSURE_PLATE_RAISED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.5F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, Power); - } - else - { - if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.6F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } - - break; - } - case E_BLOCK_WOODEN_PRESSURE_PLATE: - { - class cPressurePlateCallback : - public cEntityCallback - { - public: - cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : - m_FoundEntity(false), - m_X(a_BlockX), - m_Y(a_BlockY), - m_Z(a_BlockZ) - { - } - - virtual bool Item(cEntity * a_Entity) override - { - Vector3f EntityPos = a_Entity->GetPosition(); - Vector3f BlockPos(m_X + 0.5f, static_cast(m_Y), m_Z + 0.5f); - double Distance = (EntityPos - BlockPos).Length(); - - if (Distance <= 0.5) - { - m_FoundEntity = true; - return true; // Break out, we only need to know for plates that at least one entity is on top - } - return false; - } - - bool FoundEntity(void) const - { - return m_FoundEntity; - } - - protected: - bool m_FoundEntity; - - int m_X; - int m_Y; - int m_Z; - }; - - cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); - - NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (PressurePlateCallback.FoundEntity()) - { - if (Meta == E_META_PRESSURE_PLATE_RAISED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.5F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM); - } - else - { - if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) - { - m_Chunk->BroadcastSoundEffect("random.click", static_cast(BlockX) + 0.5, static_cast(a_RelBlockY) + 0.1, static_cast(BlockZ) + 0.5, 0.3F, 0.6F); - } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } - break; - } - default: - { - LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(cItem(a_MyType)).c_str()); - break; - } - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int RelX = a_RelBlockX, RelZ = a_RelBlockZ; - bool FoundActivated = false; - eBlockFace FaceToGoTowards = GetHandlerCompileTime::type::MetadataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - - for (int i = 0; i < 40; ++i) // Tripwires can be connected up to 40 blocks - { - BLOCKTYPE Type; - NIBBLETYPE Meta; - - AddFaceDirection(RelX, a_RelBlockY, RelZ, FaceToGoTowards); - m_Chunk->UnboundedRelGetBlock(RelX, a_RelBlockY, RelZ, Type, Meta); - - if (Type == E_BLOCK_TRIPWIRE) - { - if (Meta == 0x1) - { - FoundActivated = true; - } - } - else if (Type == E_BLOCK_TRIPWIRE_HOOK) - { - if (ReverseBlockFace(GetHandlerCompileTime::type::MetadataToDirection(Meta)) == FaceToGoTowards) - { - // Other hook facing in opposite direction - circuit completed! - break; - } - else - { - // Tripwire hook not connected at all, AND away all the power state bits - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - return; - } - } - else - { - // Tripwire hook not connected at all, AND away all the power state bits - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - return; - } - } - - if (FoundActivated) - { - // Connected and activated, set the 3rd and 4th highest bits - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0xC); - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - } - else - { - // Connected but not activated, AND away the highest bit - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7) | 0x4); - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - class cGetTrappedChestPlayers : - public cItemCallback - { - public: - cGetTrappedChestPlayers(void) : - m_NumberOfPlayers(0) - { - } - - virtual ~cGetTrappedChestPlayers() - { - } - - virtual bool Item(cChestEntity * a_Chest) override - { - ASSERT(a_Chest->GetBlockType() == E_BLOCK_TRAPPED_CHEST); - m_NumberOfPlayers = a_Chest->GetNumberOfPlayers(); - return (m_NumberOfPlayers <= 0); - } - - unsigned char GetPowerLevel(void) const - { - return static_cast(std::min(m_NumberOfPlayers, MAX_POWER_LEVEL)); - } - - private: - int m_NumberOfPlayers; - - } GTCP; - - int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX; - int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ; - if (m_Chunk->DoWithChestAt(BlockX, a_RelBlockY, BlockZ, GTCP)) - { - SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, GTCP.GetPowerLevel()); - } - else - { - SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); - } -} - - - - - -void cIncrementalRedstoneSimulator::HandleTripwire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ - int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX; - int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ; - - class cTripwireCallback : - public cEntityCallback - { - public: - cTripwireCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : - m_FoundEntity(false), - m_X(a_BlockX), - m_Y(a_BlockY), - m_Z(a_BlockZ) - { - } - - virtual bool Item(cEntity * a_Entity) override - { - cBoundingBox bbWire(m_X, m_X + 1, m_Y, m_Y + 0.1, m_Z, m_Z + 1); - cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); - - if (bbEntity.DoesIntersect(bbWire)) - { - m_FoundEntity = true; - return true; // One entity is sufficient to trigger the wire - } - return false; - } - - bool FoundEntity(void) const - { - return m_FoundEntity; - } - - protected: - bool m_FoundEntity; - - int m_X; - int m_Y; - int m_Z; - }; - - cTripwireCallback TripwireCallback(BlockX, a_RelBlockY, BlockZ); - this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), TripwireCallback); - - if (TripwireCallback.FoundEntity()) - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x1); - } - else - { - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); - } -} - - - - - -bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk) -{ - // Torches want to access neighbour's data when on a wall, hence the extra chunk parameter - - const auto & Data = static_cast(a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks; - return std::find_if(Data.begin(), Data.end(), [a_RelBlockX, a_RelBlockY, a_RelBlockZ](const sPoweredBlocks & itr) { return itr.m_BlockPos == Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }) != Data.end(); -} - - - - - -bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk) -{ - const auto & Data = static_cast(a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks; - return std::find_if(Data.begin(), Data.end(), [a_RelBlockX, a_RelBlockY, a_RelBlockZ](const sLinkedPoweredBlocks & itr) { return itr.a_BlockPos == Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }) != Data.end(); -} - - - - - -bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) -{ - // Repeaters cannot be powered by any face except their back; verify that this is true for a source - - for (const auto & itr : *m_PoweredBlocks) - { - if (!itr.m_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - continue; - } - - switch (a_Meta & 0x3) - { - case 0x0: - { - // Flip the coords to check the back of the repeater - if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1))) - { - return true; - } - break; - } - case 0x1: - { - if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - break; - } - case 0x2: - { - if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1))) - { - return true; - } - break; - } - case 0x3: - { - if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - break; - } - } - } // for itr - m_PoweredBlocks[] - - for (const auto & itr : *m_LinkedPoweredBlocks) - { - if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - continue; - } - - switch (a_Meta & 0x3) - { - case 0x0: - { - if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1))) - { - return true; - } - break; - } - case 0x1: - { - if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - break; - } - case 0x2: - { - if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1))) - { - return true; - } - break; - } - case 0x3: - { - if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - break; - } - } - } // for itr - m_LinkedPoweredBlocks[] - return false; // Couldn't find power source behind repeater -} - - - - - -bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) -{ - switch (a_Meta & 0x3) // We only want the 'direction' part of our metadata - { - // If the repeater is looking up or down (If parallel to the Z axis) - case 0x0: - case 0x2: - { - // Check if eastern (right) neighbor is a powered on repeater who is facing us - BLOCKTYPE Block = 0; - NIBBLETYPE OtherRepeaterDir = 0; - if ( - m_Chunk->UnboundedRelGetBlock(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, Block, OtherRepeaterDir) && - (Block == E_BLOCK_REDSTONE_REPEATER_ON) - ) - { - if ((OtherRepeaterDir & 0x03) == 0x3) - { - return true; - } // If so, I am latched / locked - } - - // Check if western(left) neighbor is a powered on repeater who is facing us - if ( - m_Chunk->UnboundedRelGetBlock(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, Block, OtherRepeaterDir) && - (Block == E_BLOCK_REDSTONE_REPEATER_ON) - ) - { - if ((OtherRepeaterDir & 0x03) == 0x1) - { - return true; - } // If so, I am latched / locked - } - - break; - } - - // If the repeater is looking left or right (If parallel to the x axis) - case 0x1: - case 0x3: - { - // Check if southern(down) neighbor is a powered on repeater who is facing us - BLOCKTYPE Block = 0; - NIBBLETYPE OtherRepeaterDir = 0; - - if ( - m_Chunk->UnboundedRelGetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, Block, OtherRepeaterDir) && - (Block == E_BLOCK_REDSTONE_REPEATER_ON) - ) - { - if ((OtherRepeaterDir & 0x30) == 0x00) - { - return true; - } // If so, I am latched / locked - } - - // Check if northern(up) neighbor is a powered on repeater who is facing us - if ( - m_Chunk->UnboundedRelGetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, Block, OtherRepeaterDir) && - (Block == E_BLOCK_REDSTONE_REPEATER_ON) - ) - { - if ((OtherRepeaterDir & 0x03) == 0x02) - { - return true; - } // If so, I am latched / locked - } - - break; - } - } - - return false; // None of the checks succeeded, I am not a locked repeater -} - - - - -bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) -{ - // Pistons cannot be powered through their front face; this function verifies that a source meets this requirement - - eBlockFace Face = GetHandlerCompileTime::type::MetaDataToDirection(a_Meta); - - for (const auto & itr : *m_PoweredBlocks) - { - if (!itr.m_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - continue; - } - - int X = a_RelBlockX, Z = a_RelBlockZ; - AddFaceDirection(X, a_RelBlockY, Z, Face); - - if (!itr.m_SourcePos.Equals(AdjustRelativeCoords(Vector3i(X, a_RelBlockY, Z)))) - { - return true; - } - } - - for (const auto & itr : *m_LinkedPoweredBlocks) - { - if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - continue; - } - - int X = a_RelBlockX, Z = a_RelBlockZ; - AddFaceDirection(X, a_RelBlockY, Z, Face); - - if (!itr.a_MiddlePos.Equals(AdjustRelativeCoords(Vector3i(X, a_RelBlockY, Z)))) - { - return true; - } - } - return false; // Source was in front of the piston's front face -} - - - - -unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPosition, cChunk * a_Chunk) -{ - unsigned char PowerLevel = 0; - - for (const auto & itr : static_cast(a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks) // Check powered list - { - if (itr.m_BlockPos != a_RelBlockPosition) - { - continue; - } - PowerLevel = std::max(itr.m_PowerLevel, PowerLevel); // Get the highest power level (a_PowerLevel is initialised already and there CAN be multiple levels for one block) - } - - for (const auto & itr : static_cast(a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks) // Check linked powered list - { - if (itr.a_BlockPos != a_RelBlockPosition) - { - continue; - } - - BLOCKTYPE Type = E_BLOCK_AIR; - if (!a_Chunk->UnboundedRelGetBlockType(itr.a_SourcePos.x, itr.a_SourcePos.y, itr.a_SourcePos.z, Type) || (Type == E_BLOCK_REDSTONE_WIRE)) - { - continue; - } - PowerLevel = std::max(itr.a_PowerLevel, PowerLevel); - } - - return PowerLevel; -} - - - - - -bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered) -{ - for (const auto & itr : *m_SimulatedPlayerToggleableBlocks) - { - if (itr.first.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - if (itr.second != IsCurrentStatePowered) // Was the last power state different to the current? - { - return false; // It was, coordinates are no longer simulated - } - else - { - return true; // It wasn't, don't resimulate block, and allow players to toggle - } - } - } - return false; // Block wasn't even in the list, not simulated -} - - - - - -void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel) -{ - BLOCKTYPE MiddleBlock = 0; - switch (a_Direction) - { - case BLOCK_FACE_XM: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX - 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - case BLOCK_FACE_XP: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX + 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - case BLOCK_FACE_YM: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - case BLOCK_FACE_YP: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - case BLOCK_FACE_ZM: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - case BLOCK_FACE_ZP: - { - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, MiddleBlock)) - { - return; - } - - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); - - break; - } - default: - { - ASSERT(!"Unhandled face direction when attempting to set blocks as linked powered!"); // Zombies, that wasn't supposed to happen... - break; - } - } -} - - - - - -void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel) -{ - static const Vector3i Offsets[] = - { - {1, 0, 0}, - { -1, 0, 0}, - {0, 0, 1}, - {0, 0, -1}, - {0, 1, 0}, - {0, -1, 0} - }; - - for (auto Offset : Offsets) // Loop through struct to power all directions - { - SetBlockPowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ) + Offset, Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), a_PowerLevel); - } -} - - - - - -void cIncrementalRedstoneSimulator::SetBlockPowered(Vector3i a_RelBlockPosition, Vector3i a_RelSourcePosition, unsigned char a_PowerLevel) -{ - cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockPosition.x, a_RelBlockPosition.z); // Adjust coordinates for the later call using these values - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - a_RelSourcePosition.x += (m_Chunk->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width; - a_RelSourcePosition.z += (m_Chunk->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width; - - auto & Powered = static_cast(Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position - for (auto & itr : Powered) - { - if ((itr.m_BlockPos == a_RelBlockPosition) && (itr.m_SourcePos == a_RelSourcePosition)) - { - if (itr.m_PowerLevel != a_PowerLevel) - { - // Update power level, don't add a new listing - Neighbour->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); - itr.m_PowerLevel = a_PowerLevel; - } - return; - } - } - - Powered.emplace_back(a_RelBlockPosition, a_RelSourcePosition, a_PowerLevel); - Neighbour->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); -} - - - - - -void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( - int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, - int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, - int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, - BLOCKTYPE a_MiddleBlock, unsigned char a_PowerLevel - ) -{ - if (!IsViableMiddleBlock(a_MiddleBlock)) - { - return; - } - - cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ); - if ((Neighbour == nullptr) || !Neighbour->IsValid()) - { - return; - } - a_RelMiddleX += (m_Chunk->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width; - a_RelMiddleZ += (m_Chunk->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width; - a_RelSourceX += (m_Chunk->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width; - a_RelSourceZ += (m_Chunk->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width; - - auto & Linked = static_cast(Neighbour->GetRedstoneSimulatorData())->m_LinkedBlocks; - for (auto & itr : Linked) // Check linked powered list - { - if ( - itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) && - itr.a_MiddlePos.Equals(Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)) && - itr.a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ)) - ) - { - if (itr.a_PowerLevel != a_PowerLevel) - { - // Update power level, don't add a new listing - Neighbour->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); - itr.a_PowerLevel = a_PowerLevel; - } - return; - } - } - - sLinkedPoweredBlocks RC; - RC.a_BlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - RC.a_MiddlePos = Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ); - RC.a_SourcePos = Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ); - RC.a_PowerLevel = a_PowerLevel; - Linked.emplace_back(RC); - Neighbour->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); -} - - - - - -void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool a_WasLastStatePowered) -{ - m_SimulatedPlayerToggleableBlocks->operator[](Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) = a_WasLastStatePowered; -} - - - - - -void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool a_ShouldPowerOn) -{ - sRepeatersDelayList RC; - - // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.) - // Multiply by 2 because in MCS, 1 redstone tick = 1 world tick, but in Vanilla, 1 redstone tick = 2 world ticks, and we need to maintain compatibility - RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; - RC.a_ElapsedTicks = 0; - RC.ShouldPowerOn = a_ShouldPowerOn; - - auto Result = m_RepeatersDelayList->emplace(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), RC); - if (!Result.second) - { - // Key exists - if (a_ShouldPowerOn == Result.first->second.ShouldPowerOn) - { - // We are queued already for the same thing, don't replace entry - return; - } - - Result.first->second.a_DelayTicks = RC.a_DelayTicks; - Result.first->second.a_ElapsedTicks = 0; - Result.first->second.ShouldPowerOn = a_ShouldPowerOn; - } -} - - - - - -void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk) -{ - if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) - { - return; - } - std::vector> BlocksPotentiallyUnpowered = { std::make_pair(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ), a_Chunk) }; - - auto UnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_LambdaChunk, const Vector3i & a_RelSource) - { - BLOCKTYPE RepeaterType; - if (a_LambdaChunk->UnboundedRelGetBlockType(a_RelSource.x, a_RelSource.y, a_RelSource.z, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) - { - return; - } - - auto Data = static_cast(a_LambdaChunk->GetRedstoneSimulatorData()); - Data->m_PoweredBlocks.erase(std::remove_if(Data->m_PoweredBlocks.begin(), Data->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, a_LambdaChunk, a_RelSource](const sPoweredBlocks & itr) - { - if (itr.m_SourcePos != a_RelSource) - { - return false; - } - - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.m_BlockPos, a_LambdaChunk)); - a_LambdaChunk->SetIsRedstoneDirty(true); - return true; - } - ), Data->m_PoweredBlocks.end()); - - Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_LambdaChunk, a_RelSource](const sLinkedPoweredBlocks & itr) - { - if (itr.a_SourcePos != a_RelSource) - { - return false; - } - - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_LambdaChunk)); - a_LambdaChunk->SetIsRedstoneDirty(true); - return true; - } - ), Data->m_LinkedBlocks.end()); - - for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_LambdaChunk)) - { - auto BoundaryData = static_cast(BoundaryChunk->GetRedstoneSimulatorData()); - Vector3i ChunkAdjustedSource = a_RelSource; - ChunkAdjustedSource.x += (a_LambdaChunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; - ChunkAdjustedSource.z += (a_LambdaChunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; - - if ( - (std::find_if(BoundaryData->m_PoweredBlocks.begin(), BoundaryData->m_PoweredBlocks.end(), [ChunkAdjustedSource](const sPoweredBlocks & itr) { return (itr.m_SourcePos == ChunkAdjustedSource); }) != BoundaryData->m_PoweredBlocks.end()) || - (std::find_if(BoundaryData->m_LinkedBlocks.begin(), BoundaryData->m_LinkedBlocks.end(), [ChunkAdjustedSource](const sLinkedPoweredBlocks & itr) { return (itr.a_SourcePos == ChunkAdjustedSource); }) != BoundaryData->m_LinkedBlocks.end()) - ) - { - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(ChunkAdjustedSource, BoundaryChunk)); - } - } - }; - - while (!BlocksPotentiallyUnpowered.empty()) - { - auto End = BlocksPotentiallyUnpowered.back(); - BlocksPotentiallyUnpowered.pop_back(); - UnpoweringFunction(End.second, End.first); - } -} - - - - - -void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk) -{ - std::vector> BlocksPotentiallyUnpowered; - - BLOCKTYPE RepeaterType; - if (a_Chunk->UnboundedRelGetBlockType(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) - { - return; - } - - auto MiddleBlockUnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_LambdaChunk, const Vector3i & a_RelMiddle) - { - auto Data = static_cast(a_LambdaChunk->GetRedstoneSimulatorData()); - Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_LambdaChunk, a_RelMiddle](const sLinkedPoweredBlocks & itr) - { - if (itr.a_MiddlePos != a_RelMiddle) - { - return false; - } - - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_LambdaChunk)); - a_LambdaChunk->SetIsRedstoneDirty(true); - return true; - } - ), Data->m_LinkedBlocks.end()); - }; - - MiddleBlockUnpoweringFunction(a_Chunk, Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)); - for (const auto & BoundaryChunk : GetAdjacentChunks(Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ), a_Chunk)) - { - Vector3i ChunkAdjustedMiddlePos = Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ); - ChunkAdjustedMiddlePos.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; - ChunkAdjustedMiddlePos.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; - - MiddleBlockUnpoweringFunction(a_Chunk, Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)); - } - - for (const auto & itr : BlocksPotentiallyUnpowered) - { - if (!AreCoordsPowered(itr.first.x, itr.first.y, itr.first.z)) - { - SetSourceUnpowered(itr.first.x, itr.first.y, itr.first.z, itr.second); - } - } -} - - - - - -bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta) -{ - // Extract the ON bit from metadata and return if true if it is set: - return ((a_BlockMeta & 0x8) == 0x8); -} - - - - - -std::vector cIncrementalRedstoneSimulator::GetAdjacentChunks(const Vector3i & a_RelBlockPosition, cChunk * a_Chunk) -{ - std::vector AdjacentChunks; - AdjacentChunks.reserve(2); // At most bordering two chunks; reserve that many - - auto CheckAndEmplace = [&AdjacentChunks](cChunk * a_LambdaChunk) - { - if ((a_LambdaChunk != nullptr) && a_LambdaChunk->IsValid()) - { - AdjacentChunks.emplace_back(a_LambdaChunk); - } - }; - - // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks - if (a_RelBlockPosition.x <= 1) - { - CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x - 2, a_RelBlockPosition.z)); - } - if (a_RelBlockPosition.x >= 14) - { - CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x + 2, a_RelBlockPosition.z)); - } - if (a_RelBlockPosition.z <= 1) - { - CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z - 2)); - } - if (a_RelBlockPosition.z >= 14) - { - CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z + 2)); - } - - return AdjacentChunks; -} - - - - diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h deleted file mode 100644 index 429bc6785..000000000 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ /dev/null @@ -1,419 +0,0 @@ - -#pragma once - -#include "RedstoneSimulator.h" -#include "BlockEntities/RedstonePoweredEntity.h" -#include - -class cWorld; -class cChunk; - - - - - -typedef cItemCallback cRedstonePoweredCallback; - - - -class cIncrementalRedstoneSimulator : - public cRedstoneSimulator -{ - typedef cRedstoneSimulator super; -public: - - cIncrementalRedstoneSimulator(cWorld & a_World) - : cRedstoneSimulator(a_World), - m_Chunk(nullptr) - { - } - - virtual cRedstoneSimulatorChunkData * CreateChunkData() override - { - return new cIncrementalRedstoneSimulatorChunkData; - } - - virtual void Simulate(float a_Dt) override { UNUSED(a_Dt); } // not used - virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; - virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override { return IsRedstone(a_BlockType); } - virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; - -private: - -#define MAX_POWER_LEVEL 15 - - struct sPoweredBlocks // Define structure of the directly powered blocks list - { - sPoweredBlocks(Vector3i a_BlockPos, Vector3i a_SourcePos, unsigned char a_PowerLevel) : - m_BlockPos(a_BlockPos), - m_SourcePos(a_SourcePos), - m_PowerLevel(a_PowerLevel) - { - } - - Vector3i m_BlockPos; // Position of powered block - Vector3i m_SourcePos; // Position of source powering the block at a_BlockPos - unsigned char m_PowerLevel; - }; - - struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side) - { - Vector3i a_BlockPos; - Vector3i a_MiddlePos; // Position of block that is betwixt a source and the destination - Vector3i a_SourcePos; - unsigned char a_PowerLevel; - }; - - struct sRepeatersDelayList // Define structure of list containing repeaters' delay states - { - unsigned char a_DelayTicks; // For how many ticks should the repeater delay - unsigned char a_ElapsedTicks; // How much of the previous has been elapsed? - bool ShouldPowerOn; // What happens when the delay time is fulfilled? - }; - - /** Per-chunk data for the simulator, specified individual chunks to simulate */ - class cIncrementalRedstoneSimulatorChunkData : - public cRedstoneSimulatorChunkData - { - public: - /** test */ - std::unordered_map, VectorHasher> m_ChunkData; - std::vector m_PoweredBlocks; - std::vector m_LinkedBlocks; - std::unordered_map> m_SimulatedPlayerToggleableBlocks; - std::unordered_map> m_RepeatersDelayList; - }; - -public: - - typedef std::vector PoweredBlocksList; - typedef std::vector LinkedBlocksList; - typedef std::unordered_map> SimulatedPlayerToggleableList; - typedef std::unordered_map> RepeatersDelayList; - -private: - - cIncrementalRedstoneSimulatorChunkData * m_RedstoneSimulatorChunkData; - PoweredBlocksList * m_PoweredBlocks; - LinkedBlocksList * m_LinkedPoweredBlocks; - SimulatedPlayerToggleableList * m_SimulatedPlayerToggleableBlocks; - RepeatersDelayList * m_RepeatersDelayList; - - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; - - void AddBlock(const Vector3i & a_BlockPosition, cChunk * a_Chunk, cChunk * a_OtherChunk = nullptr); - cChunk * m_Chunk; - - // We want a_MyState for devices needing a full FastSetBlock (as opposed to meta) because with our simulation model, we cannot keep setting the block if it is already set correctly - // In addition to being non-performant, it would stop the player from actually breaking said device - - - /** Handles the redstone torch */ - void HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); - - /** Handles the redstone block */ - void HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles levers */ - void HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles buttons */ - void HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles daylight sensors */ - void HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles pressure plates */ - void HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType); - - /** Handles tripwire hooks - Performs correct meta and power setting for self by going in the direction it faces and looking for a continous line of tripwire bounded by another oppositely facing hook - If this line is complete, it verifies that at least on wire reports an entity is on top (via its meta), and performs its task - */ - void HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles trapped chests */ - void HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - - /** Handles redstone wire */ - void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles repeaters */ - void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); - - /** Handles comparators */ - void HandleRedstoneComparator(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - - /** Handles pistons */ - void HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles dispensers and droppers */ - void HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles TNT (exploding) */ - void HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles redstone lamps */ - void HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); - - /** Handles doords */ - void HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles command blocks */ - void HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles activator, detector, and powered rails */ - void HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType); - - /** Handles trapdoors */ - void HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles fence gates */ - void HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles noteblocks */ - void HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - /** Handles tripwires */ - void HandleTripwire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); - - - /** Marks a block as powered */ - void SetBlockPowered(Vector3i a_RelBlockPosition, Vector3i a_RelSourcePosition, unsigned char a_PowerLevel = MAX_POWER_LEVEL); - void SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL) { SetBlockPowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ), a_PowerLevel); } - - /** Recursively searches for a wire path and powers everything that should be powered */ - void FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const Vector3i & a_EntryRelBlockPosition, cChunk * a_EntryChunk); - - /** Powers a specified wire block position with the specified source wire position - Checks are performed to ensure one wire does not power the same location more than once - a_EntryChunk will be the chunk which the source resides, and a_NeighbourChunk will be that which the to-be-powered wire resides - a_PotentialWireList is updated to include the new powered wire so that FindAndPowerBorderingWires can continue the redstone wire line tracing process - */ - void PowerBorderingWires(std::vector> & a_PotentialWireList, const Vector3i & a_EntryRelSourcePosition, cChunk * a_EntryChunk, const Vector3i & a_AdjustedPos, cChunk * a_NeighbourChunk, unsigned char a_MyPower); - - /** Marks a block as being powered through another block */ - void SetBlockLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); - - /** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */ - void SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered); - - /** Marks the second block in a direction as linked powered */ - void SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel = MAX_POWER_LEVEL); - - /** Marks all blocks immediately surrounding a coordinate as powered */ - void SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL); - - /** Queues a repeater to be powered or unpowered and returns if the m_RepeatersDelayList iterators were invalidated */ - void QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); - - /** Removes a block from the Powered and LinkedPowered lists - Recursively removes all blocks powered by the given one - */ - void SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk); - void SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk); - - /** Returns if a coordinate is powered or linked powered */ - bool AreCoordsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { return AreCoordsDirectlyPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); } - - /** Returns if a coordinate is in the directly powered blocks list */ - static bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk); - - /** Returns if a coordinate is in the indirectly powered blocks list */ - static bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk); - - /** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */ - bool AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered); - - /** Returns if a repeater is powered by testing for power sources behind the repeater */ - bool IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta); - - /** Returns if a repeater is locked */ - bool IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta); - - /** Returns if a piston is powered */ - bool IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta); - - /** Returns if a wire is powered - The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire */ - static unsigned char IsWirePowered(Vector3i a_RelBlockPosition, cChunk * a_Chunk); - - /** Handles delayed updates to repeaters */ - void HandleRedstoneRepeaterDelays(void); - - /** Returns if lever metadata marks it as emitting power */ - bool IsLeverOn(NIBBLETYPE a_BlockMeta); - - /** Returns if button metadata marks it as emitting power */ - bool IsButtonOn(NIBBLETYPE a_BlockMeta) { return IsLeverOn(a_BlockMeta); } - - - /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */ - inline static bool IsViableMiddleBlock(BLOCKTYPE a_Block) { return cBlockInfo::FullyOccupiesVoxel(a_Block); } - - /** Returns if a block is a mechanism (something that accepts power and does something) - Used by torches to determine if they power a block whilst not standing on the ground - */ - inline static bool IsMechanism(BLOCKTYPE a_Block) - { - switch (a_Block) - { - case E_BLOCK_ACACIA_DOOR: - case E_BLOCK_ACACIA_FENCE_GATE: - case E_BLOCK_ACTIVATOR_RAIL: - case E_BLOCK_ACTIVE_COMPARATOR: - case E_BLOCK_BIRCH_DOOR: - case E_BLOCK_BIRCH_FENCE_GATE: - case E_BLOCK_COMMAND_BLOCK: - case E_BLOCK_DARK_OAK_DOOR: - case E_BLOCK_DARK_OAK_FENCE_GATE: - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - case E_BLOCK_OAK_FENCE_GATE: - case E_BLOCK_HOPPER: - case E_BLOCK_INACTIVE_COMPARATOR: - case E_BLOCK_IRON_DOOR: - case E_BLOCK_IRON_TRAPDOOR: - case E_BLOCK_JUNGLE_DOOR: - case E_BLOCK_JUNGLE_FENCE_GATE: - case E_BLOCK_NOTE_BLOCK: - case E_BLOCK_PISTON: - case E_BLOCK_POWERED_RAIL: - case E_BLOCK_REDSTONE_LAMP_OFF: - case E_BLOCK_REDSTONE_LAMP_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_WIRE: - case E_BLOCK_SPRUCE_DOOR: - case E_BLOCK_SPRUCE_FENCE_GATE: - case E_BLOCK_STICKY_PISTON: - case E_BLOCK_TNT: - case E_BLOCK_TRAPDOOR: - case E_BLOCK_OAK_DOOR: - { - return true; - } - default: return false; - } - } - - /** Returns if a block has the potential to output power */ - inline static bool IsPotentialSource(BLOCKTYPE a_Block) - { - switch (a_Block) - { - case E_BLOCK_DETECTOR_RAIL: - case E_BLOCK_DAYLIGHT_SENSOR: - case E_BLOCK_WOODEN_BUTTON: - case E_BLOCK_STONE_BUTTON: - case E_BLOCK_REDSTONE_WIRE: - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_LEVER: - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_BLOCK_OF_REDSTONE: - case E_BLOCK_ACTIVE_COMPARATOR: - case E_BLOCK_INACTIVE_COMPARATOR: - case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: - case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: - case E_BLOCK_STONE_PRESSURE_PLATE: - case E_BLOCK_WOODEN_PRESSURE_PLATE: - case E_BLOCK_TRAPPED_CHEST: - { - return true; - } - default: return false; - } - } - - /** Returns if a block is any sort of redstone device */ - inline static bool IsRedstone(BLOCKTYPE a_Block) - { - switch (a_Block) - { - // All redstone devices, please alpha sort - case E_BLOCK_ACACIA_DOOR: - case E_BLOCK_ACACIA_FENCE_GATE: - case E_BLOCK_ACTIVATOR_RAIL: - case E_BLOCK_ACTIVE_COMPARATOR: - case E_BLOCK_BIRCH_DOOR: - case E_BLOCK_BIRCH_FENCE_GATE: - case E_BLOCK_BLOCK_OF_REDSTONE: - case E_BLOCK_COMMAND_BLOCK: - case E_BLOCK_DARK_OAK_DOOR: - case E_BLOCK_DARK_OAK_FENCE_GATE: - case E_BLOCK_DAYLIGHT_SENSOR: - case E_BLOCK_DETECTOR_RAIL: - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - case E_BLOCK_OAK_FENCE_GATE: - case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: - case E_BLOCK_HOPPER: - case E_BLOCK_INACTIVE_COMPARATOR: - case E_BLOCK_IRON_DOOR: - case E_BLOCK_IRON_TRAPDOOR: - case E_BLOCK_JUNGLE_DOOR: - case E_BLOCK_JUNGLE_FENCE_GATE: - case E_BLOCK_LEVER: - case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: - case E_BLOCK_NOTE_BLOCK: - case E_BLOCK_POWERED_RAIL: - case E_BLOCK_REDSTONE_LAMP_OFF: - case E_BLOCK_REDSTONE_LAMP_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_REDSTONE_WIRE: - case E_BLOCK_SPRUCE_DOOR: - case E_BLOCK_SPRUCE_FENCE_GATE: - case E_BLOCK_STICKY_PISTON: - case E_BLOCK_STONE_BUTTON: - case E_BLOCK_STONE_PRESSURE_PLATE: - case E_BLOCK_TNT: - case E_BLOCK_TRAPDOOR: - case E_BLOCK_TRAPPED_CHEST: - case E_BLOCK_TRIPWIRE_HOOK: - case E_BLOCK_TRIPWIRE: - case E_BLOCK_WOODEN_BUTTON: - case E_BLOCK_OAK_DOOR: - case E_BLOCK_WOODEN_PRESSURE_PLATE: - case E_BLOCK_PISTON: - { - return true; - } - default: return false; - } - } - - inline static bool DoesIgnorePlayerToggle(BLOCKTYPE a_Block) - { - switch (a_Block) - { - case E_BLOCK_ACACIA_FENCE_GATE: - case E_BLOCK_BIRCH_FENCE_GATE: - case E_BLOCK_DARK_OAK_FENCE_GATE: - case E_BLOCK_OAK_FENCE_GATE: - case E_BLOCK_JUNGLE_FENCE_GATE: - case E_BLOCK_SPRUCE_FENCE_GATE: - case E_BLOCK_IRON_TRAPDOOR: - case E_BLOCK_TRAPDOOR: - { - return true; - } - default: return false; - } - } - - inline static std::vector GetAdjacentChunks(const Vector3i & a_RelBlockPosition, cChunk * a_Chunk); - - inline static Vector3i AdjustRelativeCoords(const Vector3i & a_RelPosition) - { - return { (a_RelPosition.x % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width, a_RelPosition.y, (a_RelPosition.z % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width }; - } -}; - - - - diff --git a/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt b/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt new file mode 100644 index 000000000..e37f3595c --- /dev/null +++ b/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required (VERSION 2.6) +project (MCServer) + +include_directories ("${PROJECT_SOURCE_DIR}/../") + +set (SRCS + IncrementalRedstoneSimulator.cpp +) + +set (HDRS + CommandBlockHandler.h + DoorHandler.h + DropSpenserHandler.h + IncrementalRedstoneSimulator.h + RedstoneHandler.h + RedstoneSimulatorChunkData.h + SolidBlockHandler.h + RedstoneComparatorHandler.h + RedstoneRepeaterHandler.h + RedstoneBlockHandler.h + RedstoneTorchHandler.h + RedstoneWireHandler.h + RedstoneLampHandler.h + RedstoneToggleHandler.h + PistonHandler.h + SmallGateHandler.h + NoteBlockHandler.h + TNTHandler.h + TrappedChestHandler.h + TripwireHookHandler.h + PoweredRailHandler.h + PressurePlateHandler.h +) + +if(NOT MSVC) + add_library(IncrementalRedstoneSimulator ${SRCS} ${HDRS}) +endif() + diff --git a/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h b/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h new file mode 100644 index 000000000..ddf66ba43 --- /dev/null +++ b/src/Simulator/IncrementalRedstoneSimulator/CommandBlockHandler.h @@ -0,0 +1,70 @@ + +#pragma once + +#include "RedstoneHandler.h" +#include "BlockEntities/CommandBlockEntity.h" + + + + + +class cCommandBlockHandler : public cRedstoneHandler +{ + typedef cRedstoneHandler super; +public: + + cCommandBlockHandler(cWorld & a_World) : + super(a_World) + { + } + + virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override + { + UNUSED(a_Position); + UNUSED(a_BlockType); + UNUSED(a_Meta); + UNUSED(a_QueryPosition); + UNUSED(a_QueryBlockType); + return 0; + } + + virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override + { + UNUSED(a_Position); + UNUSED(a_BlockType); + UNUSED(a_Meta); + return 0; + } + + virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override + { + LOGD("Evaluating commander the cmdblck (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); + + auto Previous = static_cast(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(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 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(a_World); + + case E_BLOCK_ACTIVE_COMPARATOR: + case E_BLOCK_INACTIVE_COMPARATOR: return cpp14::make_unique(a_World); + + case E_BLOCK_DISPENSER: + case E_BLOCK_DROPPER: return cpp14::make_unique(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(a_World); + + case E_BLOCK_FENCE_GATE: + case E_BLOCK_IRON_TRAPDOOR: + case E_BLOCK_TRAPDOOR: return cpp14::make_unique(a_World); + + case E_BLOCK_REDSTONE_LAMP_OFF: + case E_BLOCK_REDSTONE_LAMP_ON: return cpp14::make_unique(a_World); + + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: return cpp14::make_unique(a_World); + + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: return cpp14::make_unique(a_World); + + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: return cpp14::make_unique(a_World); + + case E_BLOCK_LEVER: + case E_BLOCK_STONE_BUTTON: + case E_BLOCK_WOODEN_BUTTON: return cpp14::make_unique(a_World); + + case E_BLOCK_BLOCK_OF_REDSTONE: return cpp14::make_unique(a_World); + case E_BLOCK_COMMAND_BLOCK: return cpp14::make_unique(a_World); + case E_BLOCK_NOTE_BLOCK: return cpp14::make_unique(a_World); + case E_BLOCK_REDSTONE_WIRE: return cpp14::make_unique(a_World); + case E_BLOCK_TNT: return cpp14::make_unique(a_World); + case E_BLOCK_TRAPPED_CHEST: return cpp14::make_unique(a_World); + case E_BLOCK_TRIPWIRE_HOOK: return cpp14::make_unique(a_World); + default: + { + if (cBlockDoorHandler::IsDoorBlockType(a_BlockType)) + { + return cpp14::make_unique(a_World); + } + + if (cBlockInfo::FullyOccupiesVoxel(a_BlockType)) + { + return cpp14::make_unique(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 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(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(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(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(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(CeilC(PressurePlateCallback.m_NumberOfEntities / 10.f)), static_cast(15)); + } + case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: + { + return std::min(static_cast(PressurePlateCallback.m_NumberOfEntities), static_cast(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(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(a_BlockEntity)->GetContents(); + float Fullness = 0; // Is a floating-point type to allow later calculation to produce a non-truncated value + for (int Slot = 0; Slot != Contents.GetNumSlots(); ++Slot) + { + Fullness += Contents.GetSlot(Slot).m_ItemCount / Contents.GetSlot(Slot).GetMaxStackSize(); + } + + m_SignalStrength = static_cast(1 + (Fullness / Contents.GetNumSlots()) * 14); + return false; + } + + unsigned char m_SignalStrength; + } CCB; + + auto 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(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(std::max(static_cast(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(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(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(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 + 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(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 + + + + + +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 * 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, VectorHasher> m_MechanismDelays; + std::unordered_map> m_UpdateOncePositions; + +private: + + cVector3iArray m_ActiveBlocks; + + // TODO: map -> Position of torch + it's heat level + + std::unordered_map> 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(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(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(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(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(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(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 + { + 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(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(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, PoweringData(a_BlockType, Power)); + + if (Power != PreviousPower.PowerLevel) + { + return GetAdjustedRelatives(a_Position, StaticAppend(GetRelativeLaterals(), cVector3iArray{ OffsetYM() })); + } + + return {}; + } + + virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override + { + UNUSED(a_Position); + UNUSED(a_BlockType); + UNUSED(a_Meta); + + return {}; + } +}; diff --git a/src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h b/src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h new file mode 100644 index 000000000..d472d2dfb --- /dev/null +++ b/src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h @@ -0,0 +1,136 @@ + +#pragma once + +#include "RedstoneHandler.h" +#include "Blocks/BlockTripwireHook.h" + + + + + +class cTripwireHookHandler : public cRedstoneHandler +{ + typedef cRedstoneHandler super; +public: + + cTripwireHookHandler(cWorld & a_World) : + super(a_World) + { + } + + virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override + { + UNUSED(a_QueryBlockType); + UNUSED(a_QueryPosition); + + return (GetPowerLevel(a_Position, a_BlockType, a_Meta) == 15) ? 15 : 0; + } + + virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override + { + UNUSED(a_BlockType); + + bool FoundActivated = false; + auto Position = a_Position; + eBlockFace FaceToGoTowards = cBlockTripwireHookHandler::MetadataToDirection(a_Meta); + + for (int i = 0; i < 40; ++i) // Tripwires can be connected up to 40 blocks + { + BLOCKTYPE Type; + NIBBLETYPE Meta; + + AddFaceDirection(Position.x, Position.y, Position.z, FaceToGoTowards); + m_World.GetBlockTypeMeta(Position.x, Position.y, Position.z, Type, Meta); + + if (Type == E_BLOCK_TRIPWIRE) + { + class cTripwireCallback : + public cEntityCallback + { + public: + cTripwireCallback(void) : + m_NumberOfEntities(0), + m_FoundPlayer(false) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + return true; + } + + unsigned int m_NumberOfEntities; + bool m_FoundPlayer; + } TripwireCallback; + + if (!m_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + Position, 0.5, 0.5), TripwireCallback)) + { + FoundActivated = true; + } + } + else if (Type == E_BLOCK_TRIPWIRE_HOOK) + { + if (ReverseBlockFace(cBlockTripwireHookHandler::MetadataToDirection(Meta)) == FaceToGoTowards) + { + // Other hook facing in opposite direction - circuit completed! + return FoundActivated ? 15 : 1; + } + else + { + // Tripwire hook not connected at all + return 0; + } + } + else + { + // Tripwire hook not connected at all + return 0; + } + } + + return 0; + } + + virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override + { + // LOGD("Evaluating hooky the tripwire hook (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); + + auto Power = GetPowerLevel(a_Position, a_BlockType, a_Meta); + NIBBLETYPE Meta; + if (Power == 0) + { + Meta = (a_Meta & 0x3); + } + else if (Power == 1) + { + // Connected but not activated, AND away the highest bit + Meta = (a_Meta & 0x7) | 0x4; + } + else if (Power == 15) + { + // Connected and activated, set the 3rd and 4th highest bits + Meta = (a_Meta | 0xC); + } + else + { + ASSERT(!"Unexpected tripwire hook power level!"); + return {}; + } + + if (Meta != a_Meta) + { + m_World.SetBlockMeta(a_Position, Meta); + return GetAdjustedRelatives(a_Position, GetRelativeAdjacents()); + } + + return {}; + } + + virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override + { + UNUSED(a_BlockType); + UNUSED(a_Meta); + UNUSED(a_Position); + return {}; + } +}; diff --git a/src/Simulator/NoopRedstoneSimulator.h b/src/Simulator/NoopRedstoneSimulator.h index b8c797472..34c8627d2 100644 --- a/src/Simulator/NoopRedstoneSimulator.h +++ b/src/Simulator/NoopRedstoneSimulator.h @@ -18,8 +18,6 @@ public: { } - // ~cRedstoneNoopSimulator(); - virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override { diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index b0ad08aa4..863ba2532 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -1,30 +1,41 @@ #pragma once -#include "Simulator.h" +#include "ChunkDef.h" +#include "Simulator/Simulator.h" + + + class cRedstoneSimulatorChunkData { public: virtual ~cRedstoneSimulatorChunkData() = 0; -} ; - +}; inline cRedstoneSimulatorChunkData::~cRedstoneSimulatorChunkData() {} + + + class cRedstoneSimulator : public cSimulator { typedef cSimulator super; - public: + cRedstoneSimulator(cWorld & a_World) : - super(a_World) + super(a_World) { } - + + virtual void Simulate(float a_Dt) = 0; + virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) = 0; + virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) = 0; + virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) = 0; + virtual cRedstoneSimulatorChunkData * CreateChunkData() = 0; -} ; +}; diff --git a/src/UI/ChestWindow.cpp b/src/UI/ChestWindow.cpp index 44992453e..8c9f33045 100644 --- a/src/UI/ChestWindow.cpp +++ b/src/UI/ChestWindow.cpp @@ -74,17 +74,13 @@ cChestWindow::~cChestWindow() bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) { - int ChunkX, ChunkZ; - m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() - 1); - cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ); - m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); + m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosY(), m_PrimaryChest->GetPosZ()); if (m_SecondaryChest != nullptr) { m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1); - cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ); - m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); + m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosY(), m_SecondaryChest->GetPosZ()); } cWindow::ClosedByPlayer(a_Player, a_CanRefuse); @@ -97,17 +93,13 @@ bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) void cChestWindow::OpenedByPlayer(cPlayer & a_Player) { - int ChunkX, ChunkZ; - m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() + 1); - cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ); - m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); + m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosY(), m_PrimaryChest->GetPosZ()); if (m_SecondaryChest != nullptr) { m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1); - cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ); - m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ); + m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosY(), m_SecondaryChest->GetPosZ()); } cWindow::OpenedByPlayer(a_Player); diff --git a/src/Vector3.h b/src/Vector3.h index 74cffac33..900ad65e3 100644 --- a/src/Vector3.h +++ b/src/Vector3.h @@ -255,6 +255,11 @@ public: ); } + inline Vector3 operator - (void) const + { + return Vector3(-x, -y, -z); + } + inline Vector3 operator * (const Vector3& a_Rhs) const { return Vector3( diff --git a/src/World.cpp b/src/World.cpp index 3f4e8dfea..47a4e9303 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -34,8 +34,8 @@ #include "Simulator/FireSimulator.h" #include "Simulator/NoopFluidSimulator.h" #include "Simulator/NoopRedstoneSimulator.h" +#include "Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h" #include "Simulator/SandSimulator.h" -#include "Simulator/IncrementalRedstoneSimulator.h" #include "Simulator/VanillaFluidSimulator.h" #include "Simulator/VaporizeFluidSimulator.h" @@ -991,8 +991,6 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La TickWeather(static_cast(a_Dt.count())); - m_ChunkMap->FastSetQueuedBlocks(); - if (m_WorldAge - m_LastSave > std::chrono::minutes(5)) // Save each 5 minutes { SaveAllChunks(); @@ -3626,7 +3624,7 @@ cRedstoneSimulator * cWorld::InitializeRedstoneSimulator(cIniFile & a_IniFile) res = new cRedstoneNoopSimulator(*this); } - m_SimulatorManager->RegisterSimulator(res, 1); + m_SimulatorManager->RegisterSimulator(res, 2 /* Two game ticks is a redstone tick */); return res; } diff --git a/src/World.h b/src/World.h index 5f1ce393b..04c9bb4de 100644 --- a/src/World.h +++ b/src/World.h @@ -392,14 +392,6 @@ public: m_ChunkMap->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); } - /** Queues a SetBlock() with the specified parameters after the specified number of ticks. - Calls SetBlock(), so performs full processing of the replaced block. - */ - void QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR) - { - m_ChunkMap->QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, GetWorldAge() + a_TickDelay, a_PreviousBlockType); - } - BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ) { return m_ChunkMap->GetBlock(a_BlockX, a_BlockY, a_BlockZ); -- cgit v1.2.3