From de5b1401f813985300c33c6b3166b115f9a10dd3 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 8 Feb 2015 16:35:10 +0000 Subject: Comparators --- src/BlockEntities/BlockEntity.h | 2 +- src/BlockEntities/ChestEntity.h | 18 +++ src/Blocks/BlockComparator.h | 79 ++++++++++ src/ChunkDef.h | 6 + src/Globals.h | 7 +- src/Simulator/IncrementalRedstoneSimulator.cpp | 200 ++++++++++++++++--------- src/Simulator/IncrementalRedstoneSimulator.h | 58 +++++-- 7 files changed, 287 insertions(+), 83 deletions(-) diff --git a/src/BlockEntities/BlockEntity.h b/src/BlockEntities/BlockEntity.h index 85f75a523..7b5b6920f 100644 --- a/src/BlockEntities/BlockEntity.h +++ b/src/BlockEntities/BlockEntity.h @@ -91,7 +91,7 @@ public: BLOCKTYPE GetBlockType(void) const { return m_BlockType; } - cWorld * GetWorld(void) const {return m_World; } + cWorld * GetWorld(void) const { return m_World; } int GetChunkX(void) const { return FAST_FLOOR_DIV(m_PosX, cChunkDef::Width); } int GetChunkZ(void) const { return FAST_FLOOR_DIV(m_PosZ, cChunkDef::Width); } diff --git a/src/BlockEntities/ChestEntity.h b/src/BlockEntities/ChestEntity.h index 645dbf4bc..8ead8bda0 100644 --- a/src/BlockEntities/ChestEntity.h +++ b/src/BlockEntities/ChestEntity.h @@ -53,6 +53,24 @@ private: /** Number of players who currently have this chest open */ int m_NumActivePlayers; + + /** cItemGrid::cListener overrides: */ + virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) + { + UNUSED(a_SlotNum); + ASSERT(a_Grid == &m_Contents); + if (m_World != nullptr) + { + if (GetWindow() != nullptr) + { + GetWindow()->BroadcastWholeWindow(); + } + + m_World->MarkChunkDirty(GetChunkX(), GetChunkZ()); + m_World->MarkRedstoneDirty(GetChunkX(), GetChunkZ()); + } + } + } ; // tolua_export diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h index ed73a162e..3babeddad 100644 --- a/src/Blocks/BlockComparator.h +++ b/src/Blocks/BlockComparator.h @@ -64,6 +64,85 @@ public: a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw()); return true; } + + + inline static Vector3i GetSideCoordinate(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool a_bInverse) + { + 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; + default: + { + LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta); + ASSERT(!"Unknown metadata while determining orientation of comparator!"); + break; + } + } + } + else + { + switch (a_Meta) + { + case 0x0: a_BlockX--; break; + case 0x1: a_BlockZ++; break; + case 0x2: a_BlockX++; break; + case 0x3: a_BlockZ--; break; + default: + { + LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta); + ASSERT(!"Unknown metadata while determining orientation of comparator!"); + break; + } + } + } + + return Vector3i(a_BlockX, a_BlockY, a_BlockZ); + } + + + inline static Vector3i GetRearCoordinate(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) + { + switch (a_Meta) + { + case 0x0: a_BlockZ++; break; + case 0x1: a_BlockX--; break; + case 0x2: a_BlockZ--; break; + case 0x3: a_BlockX++; break; + default: + { + LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta); + ASSERT(!"Unknown metadata while determining orientation of comparator!"); + break; + } + } + + return Vector3i(a_BlockX, a_BlockY, a_BlockZ); + } + + + inline static Vector3i GetFrontCoordinate(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) + { + switch (a_Meta) + { + case 0x0: a_BlockZ--; break; + case 0x1: a_BlockX++; break; + case 0x2: a_BlockZ++; break; + case 0x3: a_BlockX--; break; + default: + { + LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta); + ASSERT(!"Unknown metadata while determining orientation of comparator!"); + break; + } + } + + return Vector3i(a_BlockX, a_BlockY, a_BlockZ); + } } ; diff --git a/src/ChunkDef.h b/src/ChunkDef.h index b03a03bff..fb3451db1 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -96,6 +96,12 @@ public: a_Z = a_Z - a_ChunkZ * Width; } + /** Converts relative block coordinates into absolute coordinates with a known chunk location */ + inline static Vector3i RelativeToAbsolute(const Vector3i & a_RelBlockPosition, int a_ChunkX, int a_ChunkZ) + { + return Vector3i(a_RelBlockPosition.x + a_ChunkX * Width, a_RelBlockPosition.y, a_RelBlockPosition.z + a_ChunkZ * Width); + } + /// Converts absolute block coords to chunk coords: inline static void BlockToChunk(int a_X, int a_Z, int & a_ChunkX, int & a_ChunkZ) diff --git a/src/Globals.h b/src/Globals.h index 27d944fcc..8ff7b6894 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -192,14 +192,13 @@ template class SizeChecker; #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT _WIN32_WINNT_WS03 // We want to target Windows XP with Service Pack 2 & Windows Server 2003 with Service Pack 1 and higher + // Windows SDK defines min and max macros, messing up with our std::min and std::max usage + #define NOMINMAX + #include #include #include // IPv6 stuff - // Windows SDK defines min and max macros, messing up with our std::min and std::max usage - #undef min - #undef max - // Windows SDK defines GetFreeSpace as a constant, probably a Win16 API remnant #ifdef GetFreeSpace #undef GetFreeSpace diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 7f320af0d..c1a66243d 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -3,11 +3,10 @@ #include "BlockEntities/ChestEntity.h" -typedef cItemCallback cChestCallback; - #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" @@ -286,6 +285,12 @@ void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt HandleRedstoneButton(dataitr->x, dataitr->y, dataitr->z); break; } + case E_BLOCK_ACTIVE_COMPARATOR: + case E_BLOCK_INACTIVE_COMPARATOR: + { + HandleRedstoneComparator(dataitr->x, dataitr->y, dataitr->z); + break; + } default: break; } } @@ -535,20 +540,16 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re }; // Check to see if directly beside a power source - unsigned char MyPower; - if (!IsWirePowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower)) + unsigned char MyPower = IsWirePowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); + if (MyPower == 0) { + SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0); return; } m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - if (MyPower < 1) - { - return; - } - MyPower--; for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power @@ -656,6 +657,67 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re +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))), IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetSideCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3, true)))); + 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)))); + + if ((Meta & 0x4) == 0x4) + { // Subtraction mode + Power = RearPower - HighestSidePower; + } + else + { // Comparison mode + Power = std::max(HighestSidePower, 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: @@ -1017,19 +1079,19 @@ void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_RelBlockX, int a_ int ChunkX, ChunkZ; cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ); - if (!this->m_World.IsChunkLighted(ChunkX, ChunkZ)) + if (!m_World.IsChunkLighted(ChunkX, ChunkZ)) { - this->m_World.QueueLightChunk(ChunkX, ChunkZ); + m_World.QueueLightChunk(ChunkX, ChunkZ); } else { - if (m_Chunk->GetTimeAlteredLight(this->m_World.GetBlockSkyLight(BlockX, a_RelBlockY + 1, BlockZ)) > 8) + if (m_Chunk->GetTimeAlteredLight(m_Chunk->GetSkyLight(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ)) > 8) { SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); } else { - WakeUp(BlockX, a_RelBlockY, BlockZ, m_Chunk); + SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); } } } @@ -1702,22 +1764,22 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBl -bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel) +unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPosition) { - a_PowerLevel = 0; + unsigned char PowerLevel = 0; for (const auto & itr : *m_PoweredBlocks) // Check powered list { - if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) + if (itr.a_BlockPos != a_RelBlockPosition) { continue; } - a_PowerLevel = std::max(itr.a_PowerLevel, a_PowerLevel); // Get the highest power level (a_PowerLevel is initialised already and there CAN be multiple levels for one block) + PowerLevel = std::max(itr.a_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 : *m_LinkedPoweredBlocks) // Check linked powered list { - if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) + if (itr.a_BlockPos != a_RelBlockPosition) { continue; } @@ -1727,10 +1789,10 @@ bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBloc { continue; } - a_PowerLevel = std::max(itr.a_PowerLevel, a_PowerLevel); + PowerLevel = std::max(itr.a_PowerLevel, PowerLevel); } - return (a_PowerLevel != 0); // Answer the inital question: is the wire powered? + return PowerLevel; } @@ -1871,20 +1933,20 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_R { static const struct { - int x, y, z; + Vector3i Offset; } gCrossCoords[] = { - { 1, 0, 0 }, - { -1, 0, 0 }, - { 0, 0, 1 }, - { 0, 0, -1 }, - { 0, 1, 0 }, - { 0, -1, 0 } + Vector3i(1, 0, 0), + Vector3i(-1, 0, 0), + Vector3i(0, 0, 1), + Vector3i(0, 0, -1), + Vector3i(0, 1, 0), + Vector3i(0, -1, 0) }; for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions { - SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_PowerLevel); + SetBlockPowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ) + gCrossCoords[i].Offset, Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), a_PowerLevel); } } @@ -1892,60 +1954,64 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_R -void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel) +void cIncrementalRedstoneSimulator::SetBlockPowered(Vector3i a_RelBlockPosition, Vector3i a_RelSourcePosition, unsigned char a_PowerLevel) { - cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ); // Adjust coordinates for the later call using these values + 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 = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position for (auto itr = Powered.begin(); itr != Powered.end(); ++itr) { - if ( - itr->a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) && - itr->a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ)) - ) + if ((itr->a_BlockPos == a_RelBlockPosition) && (itr->a_SourcePos == a_RelSourcePosition)) { - // Check for duplicates, update power level, don't add a new listing - itr->a_PowerLevel = a_PowerLevel; - return; - } - } - - // No need to get neighbouring chunk as we can guarantee that when something is powering us, the entry will be in our chunk - for (auto itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) - { - if ( - itr->a_BlockPos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ)) && - itr->a_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) && - (m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE) - ) - { - BLOCKTYPE Block; - NIBBLETYPE Meta; - Neighbour->GetBlockTypeMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block, Meta); - - if (Block == E_BLOCK_REDSTONE_WIRE) + if (itr->a_PowerLevel != a_PowerLevel) { - if (Meta < a_PowerLevel) - { - m_PoweredBlocks->erase(itr); // Powering source with higher power level, allow it - break; - } - else - { - // Powered wires try to power their source - don't let them! - return; - } + // Update power level, don't add a new listing + Neighbour->SetIsRedstoneDirty(true); + m_Chunk->SetIsRedstoneDirty(true); + itr->a_PowerLevel = a_PowerLevel; } + return; } } + //// No need to get neighbouring chunk as we can guarantee that when something is powering us, the entry will be in our chunk + //for (auto itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) + //{ + // if ( + // (itr->a_BlockPos == a_RelBlockPosition) && + // (itr->a_SourcePos == a_RelSourcePosition) && + // (m_Chunk->GetBlock(a_RelSourcePosition) == E_BLOCK_REDSTONE_WIRE) + // ) + // { + // BLOCKTYPE Block; + // NIBBLETYPE Meta; + // Neighbour->GetBlockTypeMeta(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, Meta); + + // if (Block == E_BLOCK_REDSTONE_WIRE) + // { + // if (Meta < a_PowerLevel) + // { + // m_PoweredBlocks->erase(itr); // Powering source with higher power level, allow it + // break; + // } + // else + // { + // // Powered wires try to power their source - don't let them! + // return; + // } + // } + // } + //} + sPoweredBlocks RC; - RC.a_BlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - RC.a_SourcePos = Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ); + RC.a_BlockPos = a_RelBlockPosition; + RC.a_SourcePos = a_RelSourcePosition; RC.a_PowerLevel = a_PowerLevel; Powered.emplace_back(RC); Neighbour->SetIsRedstoneDirty(true); @@ -2123,7 +2189,7 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R for (const auto & itr : BlocksPotentiallyUnpowered) { auto Neighbour = a_Chunk->GetRelNeighborChunk(itr.x, itr.z); - if (!AreCoordsPowered(itr.x, itr.y, itr.z) && (Neighbour->GetBlock(itr) != E_BLOCK_REDSTONE_REPEATER_ON)) + if (Neighbour->GetBlock(itr) != E_BLOCK_REDSTONE_REPEATER_ON) { // Repeaters time themselves with regards to unpowering; ensure we don't do it for them SetSourceUnpowered(itr.x, itr.y, itr.z, Neighbour); diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index 43f0e89d0..65e3ff4af 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -114,73 +114,98 @@ private: // 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 - /* ====== SOURCES ====== */ + /** 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); - /* ==================== */ - /* ====== CARRIERS ====== */ + /** 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); - /* ====================== */ - /* ====== DEVICES ====== */ + /** 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); - /* ===================== */ - /* ====== Helper functions ====== */ + /** Marks a block as powered */ - 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); + 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); } + /** 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 */ bool QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); + /** Removes a block from the Powered and LinkedPowered lists Used for variable sources such as tripwire hooks, daylight sensors, and trapped chests */ @@ -189,31 +214,39 @@ private: /** 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); } + /** Returns if a coordinate is in the directly powered blocks list */ 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 */ bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); + /** 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 */ - bool IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel); + unsigned char IsWirePowered(Vector3i a_RelBlockPosition); + /** 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); } - /* ============================== */ - /* ====== Misc Functions ====== */ + /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */ inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return cBlockInfo::FullyOccupiesVoxel(Block); } @@ -227,6 +260,7 @@ private: 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: @@ -236,6 +270,7 @@ private: 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: @@ -276,6 +311,7 @@ private: 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: -- cgit v1.2.3 From bd484750856586bd2354be2aa6852a63fd102c1b Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 20 Mar 2015 22:30:20 +0000 Subject: Provides improvements to redstone wire Intermediary commit that fixes #1763. --- src/Simulator/IncrementalRedstoneSimulator.cpp | 145 ++++++++++--------------- src/Simulator/IncrementalRedstoneSimulator.h | 19 ++-- 2 files changed, 70 insertions(+), 94 deletions(-) diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index c1a66243d..ff813a2c0 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -304,7 +304,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) { - if (AreCoordsOnChunkBoundary(a_BlockX, a_BlockY, a_BlockZ)) + if (GetCoordinateAdjacentChunk({ a_BlockX, a_BlockY, a_BlockZ }).Equals({ 0, 0, 0 })) { // On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk) AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); @@ -1980,35 +1980,6 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(Vector3i a_RelBlockPosition, } } - //// No need to get neighbouring chunk as we can guarantee that when something is powering us, the entry will be in our chunk - //for (auto itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) - //{ - // if ( - // (itr->a_BlockPos == a_RelBlockPosition) && - // (itr->a_SourcePos == a_RelSourcePosition) && - // (m_Chunk->GetBlock(a_RelSourcePosition) == E_BLOCK_REDSTONE_WIRE) - // ) - // { - // BLOCKTYPE Block; - // NIBBLETYPE Meta; - // Neighbour->GetBlockTypeMeta(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, Meta); - - // if (Block == E_BLOCK_REDSTONE_WIRE) - // { - // if (Meta < a_PowerLevel) - // { - // m_PoweredBlocks->erase(itr); // Powering source with higher power level, allow it - // break; - // } - // else - // { - // // Powered wires try to power their source - don't let them! - // return; - // } - // } - // } - //} - sPoweredBlocks RC; RC.a_BlockPos = a_RelBlockPosition; RC.a_SourcePos = a_RelSourcePosition; @@ -2079,20 +2050,12 @@ void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_Re continue; } - if (itr->WasLastStatePowered != WasLastStatePowered) - { - // If power states different, update listing - itr->WasLastStatePowered = WasLastStatePowered; - return; - } - else - { - // If states the same, just ignore - return; - } + // Update listing + itr->WasLastStatePowered = WasLastStatePowered; + return; } - // We have arrive here; no block must be in list - add one + // We have arrived here; no block must be in list - add one sSimulatedPlayerToggleableList RC; RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); RC.WasLastStatePowered = WasLastStatePowered; @@ -2140,60 +2103,72 @@ bool cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, in -void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk, bool a_IsFirstCall) +void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk) { - if (!a_IsFirstCall) // The neighbouring chunks passed when this parameter is false may be invalid + std::vector> BlocksPotentiallyUnpowered = { std::make_pair(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ), a_Chunk) }; + + auto UnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_Chunk, const Vector3i & a_RelSource) { - if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) - { - return; - } - } + auto Data = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData(); + Data->m_PoweredBlocks.erase(std::remove_if(Data->m_PoweredBlocks.begin(), Data->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSource](const sPoweredBlocks & itr) + { + if (itr.a_SourcePos != a_RelSource) + { + return false; + } - std::vector BlocksPotentiallyUnpowered; + auto ChunkBoundaryTestCoords = a_RelSource + GetCoordinateAdjacentChunk(a_RelSource); + auto BoundaryChunk = a_Chunk->GetRelNeighborChunk(ChunkBoundaryTestCoords.x, ChunkBoundaryTestCoords.z); + if (BoundaryChunk != a_Chunk) + { + Vector3i ChunkAdjustedSource = a_RelSource; + ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; + ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; + + auto BoundaryData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)BoundaryChunk->GetRedstoneSimulatorData(); + BoundaryData->m_PoweredBlocks.erase(std::remove_if(BoundaryData->m_PoweredBlocks.begin(), BoundaryData->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedSource](const sPoweredBlocks & itr) + { + if (itr.a_SourcePos != ChunkAdjustedSource) + { + return false; + } + + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, BoundaryChunk)); + BoundaryChunk->SetIsRedstoneDirty(true); + return true; + } + ), BoundaryData->m_PoweredBlocks.end()); + } - auto Data = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData(); - Data->m_PoweredBlocks.erase(std::remove_if(Data->m_PoweredBlocks.begin(), Data->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSourceX, a_RelSourceY, a_RelSourceZ](const sPoweredBlocks & itr) - { - if (itr.a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ))) - { - BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos); + if (a_Chunk->GetBlock(a_RelSource) == E_BLOCK_REDSTONE_REPEATER_ON) + { + return false; + } + + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_Chunk)); a_Chunk->SetIsRedstoneDirty(true); return true; } - return false; - } - ), Data->m_PoweredBlocks.end()); + ), Data->m_PoweredBlocks.end()); - Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSourceX, a_RelSourceY, a_RelSourceZ](const sLinkedPoweredBlocks & itr) - { - if (itr.a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ))) + /*Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSource](const sLinkedPoweredBlocks & itr) { - BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos); - a_Chunk->SetIsRedstoneDirty(true); - return true; + if (itr.a_SourcePos == a_RelSource) + { + BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos); + a_Chunk->SetIsRedstoneDirty(true); + return true; + } + return false; } - return false; - } - ), Data->m_LinkedBlocks.end()); - - if (a_IsFirstCall && AreCoordsOnChunkBoundary(a_RelSourceX, a_RelSourceY, a_RelSourceZ)) - { - // +- 2 to accomodate linked powered blocks - SetSourceUnpowered(a_RelSourceX, a_RelSourceY, a_RelSourceZ, a_Chunk->GetRelNeighborChunk(a_RelSourceX - 2, a_RelSourceZ), false); - SetSourceUnpowered(a_RelSourceX, a_RelSourceY, a_RelSourceZ, a_Chunk->GetRelNeighborChunk(a_RelSourceX + 2, a_RelSourceZ), false); - SetSourceUnpowered(a_RelSourceX, a_RelSourceY, a_RelSourceZ, a_Chunk->GetRelNeighborChunk(a_RelSourceX, a_RelSourceZ - 2), false); - SetSourceUnpowered(a_RelSourceX, a_RelSourceY, a_RelSourceZ, a_Chunk->GetRelNeighborChunk(a_RelSourceX, a_RelSourceZ + 2), false); - } + ), Data->m_LinkedBlocks.end());*/ + }; - for (const auto & itr : BlocksPotentiallyUnpowered) + while (!BlocksPotentiallyUnpowered.empty()) { - auto Neighbour = a_Chunk->GetRelNeighborChunk(itr.x, itr.z); - if (Neighbour->GetBlock(itr) != E_BLOCK_REDSTONE_REPEATER_ON) - { - // Repeaters time themselves with regards to unpowering; ensure we don't do it for them - SetSourceUnpowered(itr.x, itr.y, itr.z, Neighbour); - } + auto End = BlocksPotentiallyUnpowered.back(); + BlocksPotentiallyUnpowered.pop_back(); + UnpoweringFunction(End.second, End.first); } } @@ -2226,7 +2201,7 @@ void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int } ), Data->m_LinkedBlocks.end()); - if (a_IsFirstCall && AreCoordsOnChunkBoundary(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)) + if (a_IsFirstCall && /*AreCoordsOnChunkBoundary(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)*/1) { // +- 2 to accomodate linked powered blocks SetInvalidMiddleBlock(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, a_Chunk->GetRelNeighborChunk(a_RelMiddleX - 2, a_RelMiddleZ), false); diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index 65e3ff4af..903dbe82a 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -22,7 +22,8 @@ class cIncrementalRedstoneSimulator : public: cIncrementalRedstoneSimulator(cWorld & a_World) - : cRedstoneSimulator(a_World) + : cRedstoneSimulator(a_World), + m_Chunk(nullptr) { } @@ -209,7 +210,7 @@ private: /** Removes a block from the Powered and LinkedPowered lists Used for variable sources such as tripwire hooks, daylight sensors, and trapped chests */ - void SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk, bool a_IsFirstCall = true); + 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, bool a_IsFirstCall = true); /** Returns if a coordinate is powered or linked powered */ @@ -384,14 +385,14 @@ private: } } - inline static bool AreCoordsOnChunkBoundary(int a_BlockX, int a_BlockY, int a_BlockZ) + inline static Vector3i GetCoordinateAdjacentChunk(const Vector3i & a_BlockPos) { - return ( // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks - ((a_BlockX % cChunkDef::Width) <= 1) || - ((a_BlockX % cChunkDef::Width) >= 14) || - ((a_BlockZ % cChunkDef::Width) <= 1) || - ((a_BlockZ % cChunkDef::Width) >= 14) - ); + // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks + if ((a_BlockPos.x % cChunkDef::Width) <= 1) { return{ -2, 0, 0 }; } + if ((a_BlockPos.x % cChunkDef::Width) >= 14) { return{ 2, 0, 0 }; } + if ((a_BlockPos.z % cChunkDef::Width) <= 1) { return{ 0, 0, -2 }; } + if ((a_BlockPos.z % cChunkDef::Width) >= 14) { return{ 0, 0, 2 }; } + return { 0, 0, 0 }; } inline static Vector3i AdjustRelativeCoords(const Vector3i & a_RelPosition) -- cgit v1.2.3 From 84534dfeb288dd12d998f3f192ee162a1def5367 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 26 Apr 2015 00:38:41 +0100 Subject: Redstone wire and trapdoor fixes * Fixes #1887 * Fixes #1763 * Fixes #1083 --- src/ChunkDef.h | 13 + src/Simulator/IncrementalRedstoneSimulator.cpp | 550 ++++++++++++------------- src/Simulator/IncrementalRedstoneSimulator.h | 69 ++-- src/World.cpp | 2 +- 4 files changed, 323 insertions(+), 311 deletions(-) diff --git a/src/ChunkDef.h b/src/ChunkDef.h index fb3451db1..a1273bd23 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -96,6 +96,19 @@ public: a_Z = a_Z - a_ChunkZ * Width; } + inline static Vector3i AbsoluteToRelative(Vector3i a_BlockPosition) + { + int ChunkX, ChunkZ; + BlockToChunk(a_BlockPosition.x, a_BlockPosition.z, ChunkX, ChunkZ); + + return {a_BlockPosition.x - ChunkX * Width, a_BlockPosition.y, a_BlockPosition.z - ChunkZ * Width}; + } + + inline static Vector3i AbsoluteToRelative(Vector3i a_BlockPosition, int a_ChunkX, int a_ChunkZ) + { + return {a_BlockPosition.x - a_ChunkX * Width, a_BlockPosition.y, a_BlockPosition.z - a_ChunkZ * Width}; + } + /** Converts relative block coordinates into absolute coordinates with a known chunk location */ inline static Vector3i RelativeToAbsolute(const Vector3i & a_RelBlockPosition, int a_ChunkX, int a_ChunkZ) { diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index ff813a2c0..40829757d 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -24,41 +24,42 @@ -void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk, cChunk * a_OtherChunk) +void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) { - if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) + 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_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) + else if ((a_RelBlockPosition.y < 0) || (a_RelBlockPosition.y >= cChunkDef::Height)) { return; } - // We may be called with coordinates in a chunk that is not the first chunk parameter - // In that case, the actual chunk (which the coordinates are in), will be passed as the second parameter - // Use that Chunk pointer to get a relative position + // The relative block position is relative to the neighboring chunk should it be passed as an argument - int RelX = 0; - int RelZ = 0; BLOCKTYPE Block; NIBBLETYPE Meta; - if (a_OtherChunk != nullptr) + if (a_NeighborChunk != nullptr) { - RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width; - RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width; - a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); + a_NeighborChunk->UnboundedRelGetBlock(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, Meta); - // If a_OtherChunk is passed (not nullptr), it is the chunk that had a block change, and a_Chunk will be the neighbouring chunk of that block + // 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_Chunk->SetIsRedstoneDirty(true); + a_NeighborChunk->SetIsRedstoneDirty(true); } else { - RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); + 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 @@ -76,39 +77,53 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, ) ) { - SetSourceUnpowered(RelX, a_BlockY, RelZ, a_OtherChunk != nullptr ? a_OtherChunk : a_Chunk); + SetSourceUnpowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_NeighborChunk != nullptr ? a_NeighborChunk : a_OriginalChunk); } if (!IsViableMiddleBlock(Block)) { - SetInvalidMiddleBlock(RelX, a_BlockY, RelZ, a_OtherChunk != nullptr ? a_OtherChunk : a_Chunk); + SetInvalidMiddleBlock(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_NeighborChunk != nullptr ? a_NeighborChunk : a_OriginalChunk); } - auto & SimulatedPlayerToggleableBlocks = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_SimulatedPlayerToggleableBlocks; - SimulatedPlayerToggleableBlocks.erase(std::remove_if(SimulatedPlayerToggleableBlocks.begin(), SimulatedPlayerToggleableBlocks.end(), [RelX, a_BlockY, RelZ, Block, this](const sSimulatedPlayerToggleableList & itr) + 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 & SimulatedPlayerToggleableBlocks = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_SimulatedPlayerToggleableBlocks; + if ( + DoesIgnorePlayerToggle(Block) && + std::find_if(SimulatedPlayerToggleableBlocks.begin(),SimulatedPlayerToggleableBlocks.end(), + [a_RelBlockPosition](const sSimulatedPlayerToggleableList & itr){ return itr.a_RelBlockPos == a_RelBlockPosition; }) == SimulatedPlayerToggleableBlocks.end() + ) + { + // We have arrived here; no block must be in list - add one + sSimulatedPlayerToggleableList RC; + RC.a_RelBlockPos = a_RelBlockPosition; + RC.WasLastStatePowered = AreCoordsDirectlyPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk) || AreCoordsLinkedPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk); + + // Initialise the toggleable blocks list so that trapdoors etc. aren't reset on restart (#1887) + SimulatedPlayerToggleableBlocks.emplace_back(RC); + } + + SimulatedPlayerToggleableBlocks.erase(std::remove_if(SimulatedPlayerToggleableBlocks.begin(), SimulatedPlayerToggleableBlocks.end(), [a_RelBlockPosition, Block, this](const sSimulatedPlayerToggleableList & itr) { - return itr.a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)) && !IsAllowedBlock(Block); + return (itr.a_RelBlockPos == a_RelBlockPosition) && !DoesIgnorePlayerToggle(Block); } ), SimulatedPlayerToggleableBlocks.end()); - - auto & RepeatersDelayList = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_RepeatersDelayList; - RepeatersDelayList.erase(std::remove_if(RepeatersDelayList.begin(), RepeatersDelayList.end(), [RelX, a_BlockY, RelZ, Block](const sRepeatersDelayList & itr) + auto & RepeatersDelayList = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_RepeatersDelayList; + RepeatersDelayList.erase(std::remove_if(RepeatersDelayList.begin(), RepeatersDelayList.end(), [a_RelBlockPosition, Block](const sRepeatersDelayList & itr) { - return itr.a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)) && (Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF); + return (itr.a_RelBlockPos == a_RelBlockPosition) && (Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF); } ), RepeatersDelayList.end()); - if (a_OtherChunk != 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; - } - - cCoordWithBlockAndBoolVector & RedstoneSimulatorChunkData = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_ChunkData; + auto & RedstoneSimulatorChunkData = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_ChunkData; for (auto & itr : RedstoneSimulatorChunkData) { - if ((itr.x == RelX) && (itr.y == a_BlockY) && (itr.z == RelZ)) // We are at an entry matching the current (changed) block + if (a_RelBlockPosition == Vector3i(itr.x, itr.y, itr.z)) // We are at an entry matching the current (changed) block { if (!IsAllowedBlock(Block)) { @@ -128,16 +143,16 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, return; } - cCoordWithBlockAndBoolVector & QueuedData = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData; + auto & QueuedData = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_QueuedChunkData; for (const auto & itr : QueuedData) { - if ((itr.x == RelX) && (itr.y == a_BlockY) && (itr.z == RelZ)) + if (a_RelBlockPosition == Vector3i(itr.x, itr.y, itr.z)) { // Can't have duplicates in here either, in case something adds the block again before the structure can written to the main chunk data return; } } - QueuedData.emplace_back(cCoordWithBlockAndBool(RelX, a_BlockY, RelZ, Block, false)); + QueuedData.emplace_back(cCoordWithBlockAndBool(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, false)); } @@ -146,13 +161,13 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) { - m_RedstoneSimulatorChunkData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData(); + 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() && ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData.empty()) + if (m_RedstoneSimulatorChunkData->m_ChunkData.empty() && static_cast(a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData.empty()) { return; } @@ -304,23 +319,14 @@ void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) { - if (GetCoordinateAdjacentChunk({ a_BlockX, a_BlockY, a_BlockZ }).Equals({ 0, 0, 0 })) - { - // On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk) - AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); - - // Pass the original coordinates, because when adding things to our simulator lists, we get the chunk that they are in, and therefore any updates need to preseve their position - // RedstoneAddBlock to pass both the neighbouring chunk and the chunk which the coordinates are in and +- 2 in GetNeighbour() to accomodate for LinkedPowered blocks being 2 away from chunk boundaries - RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 2, a_BlockZ), a_Chunk); - RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 2, a_BlockZ), a_Chunk); - RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 2), a_Chunk); - RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ + 2), 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 - return; + 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); } - - // Not on boundary, just alert this chunk for speed - AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); } @@ -508,147 +514,145 @@ void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_RelBlockX, int a_ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - static const struct // Define which directions the wire can receive power from + static const eBlockFace BlockFaceOffsets[] = { - int x, y, z; - } gCrossCoords[] = - { - { 1, 0, 0 }, /* Wires on same level start */ - { -1, 0, 0 }, - { 0, 0, 1 }, - { 0, 0, -1 }, /* Wires on same level stop */ - { 1, 1, 0 }, /* Wires one higher, surrounding self start */ - { -1, 1, 0 }, - { 0, 1, 1 }, - { 0, 1, -1 }, /* Wires one higher, surrounding self stop */ - { 1, -1, 0 }, /* Wires one lower, surrounding self start */ - { -1, -1, 0 }, - { 0, -1, 1 }, - { 0, -1, -1 }, /* Wires one lower, surrounding self stop */ + BLOCK_FACE_XM, + BLOCK_FACE_XP, + BLOCK_FACE_ZM, + BLOCK_FACE_ZP }; - static const struct // Define which directions the wire will check for repeater prescence - { - int x, y, z; - } gSideCoords[] = + static const Vector3i VectorOffsets[] = { - { 1, 0, 0 }, { -1, 0, 0 }, - { 0, 0, 1 }, + { 1, 0, 0 }, { 0, 0, -1 }, - { 0, 1, 0 }, + { 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(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); + 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); - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0); return; } - m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + 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); + } + } + else if (MyPower == 1) + { + return; + } MyPower--; - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power + // Wire still powered, power blocks beneath + 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 VectorOffset; + + for (auto OffsetIdx = 0; OffsetIdx != ARRAYCOUNT(VectorOffsets); ++OffsetIdx) { - if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above... - { - BLOCKTYPE Type = 0; - if (a_RelBlockY >= cChunkDef::Height - 1) - { - continue; - } - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, Type)) - { - continue; - } - if (cBlockInfo::IsSolid(Type)) // If there is something solid above us (wire cut off)... - { - continue; // We don't receive power from that wire - } - } - else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us + BLOCKTYPE Block; + auto Offset = RelBlock + VectorOffsets[OffsetIdx]; + if (m_Chunk->UnboundedRelGetBlockType(Offset.x, Offset.y, Offset.z, Block)) { - BLOCKTYPE Type = 0; - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY, a_RelBlockZ + gCrossCoords[i].z, Type)) - { - continue; - } - if (cBlockInfo::IsSolid(Type)) + switch (Block) { - continue; + case E_BLOCK_REDSTONE_REPEATER_OFF: + { + BorderingMechanismCount++; + if (!RepeaterPresent) + { + // TODO: only if wire is actually connected to repeater (repeater facing right way) + RepeaterPresent = true; + VectorOffset = { -VectorOffsets[OffsetIdx].x, VectorOffsets[OffsetIdx].y, -VectorOffsets[OffsetIdx].z }; + } + SetBlockPowered(Offset, RelBlock, MyPower); + } + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_REDSTONE_WIRE: + { + BorderingMechanismCount++; + if (!RepeaterPresent) + { + VectorOffset = { -VectorOffsets[OffsetIdx].x, VectorOffsets[OffsetIdx].y, -VectorOffsets[OffsetIdx].z }; + } + } + default: break; } } - - 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 (Type == E_BLOCK_REDSTONE_WIRE) - { - SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - } } - for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them + if (BorderingMechanismCount == 0) { - BLOCKTYPE Type = 0; - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, Type)) - { - continue; - } - if (Type == E_BLOCK_REDSTONE_REPEATER_OFF) - { - SetBlockPowered(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - } + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); } + else if (BorderingMechanismCount == 1) + { + eBlockFace Face = BlockFaceOffsets[std::distance(VectorOffsets, std::find(VectorOffsets, VectorOffsets + ARRAYCOUNT(VectorOffsets), VectorOffset))]; + SetBlockPowered(RelBlock + VectorOffset, RelBlock, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Face, MyPower); + } +} + - // Wire still powered, power blocks beneath - 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); - switch (GetWireDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) + + +void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const std::pair & a_Entry) +{ + std::vector> NewAdditions; + const Vector3i Offsets[] = { - case REDSTONE_NONE: - { - SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + { 1, 0, 0 }, /* Wires on same level start */ + { -1, 0, 0 }, + { 0, 0, 1 }, + { 0, 0, -1 }, /* Wires on same level stop */ + { 1, 1, 0 }, /* Wires one higher, surrounding self start */ + { -1, 1, 0 }, + { 0, 1, 1 }, + { 0, 1, -1 }, /* Wires one higher, surrounding self stop */ + { 1, -1, 0 }, /* Wires one lower, surrounding self start */ + { -1, -1, 0 }, + { 0, -1, 1 }, + { 0, -1, -1 }, /* Wires one lower, surrounding self stop */ + }; + + for (auto Offset : Offsets) + { + auto AdjustedPos = a_Entry.first + Offset; + auto Neighbour = a_Entry.second->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); + auto MyPower = IsWirePowered(a_Entry.first, a_Entry.second); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower); - break; - } - case REDSTONE_X_POS: - { - SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower); - break; - } - case REDSTONE_X_NEG: + if ((Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) { - SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower); - break; - } - case REDSTONE_Z_POS: - { - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower); - break; - } - case REDSTONE_Z_NEG: - { - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower); - break; + sPoweredBlocks RC; + RC.a_BlockPos = AdjustedPos; + RC.a_SourcePos = a_Entry.first + Vector3i((a_Entry.second->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width, 0, (a_Entry.second->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width); + RC.a_PowerLevel = MyPower - 1; + ((cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks.emplace_back(RC); // We need to insert the value into the chunk who owns the block position + + Neighbour->SetIsRedstoneDirty(true); + m_Chunk->SetIsRedstoneDirty(true); + + Neighbour->SetMeta(AdjustedPos.x, AdjustedPos.y, AdjustedPos.z, MyPower - 1); + a_PotentialWireList.emplace_back(std::make_pair(AdjustedPos, Neighbour)); } } } @@ -660,7 +664,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re 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))), IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetSideCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3, true)))); + 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; @@ -691,7 +695,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneComparator(int a_RelBlockX, in 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)))); + 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 @@ -1514,30 +1518,18 @@ bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, in { // Torches want to access neighbour's data when on a wall, hence the extra chunk parameter - for (const auto & itr : ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks) // Check powered list - { - if (itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - } - return false; + 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.a_BlockPos == Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }) != Data.end(); } -bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) +bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk) { - for (const auto & itr : *m_LinkedPoweredBlocks) // Check linked powered list - { - if (itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - return true; - } - } - return false; + 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(); } @@ -1764,11 +1756,11 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBl -unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPosition) +unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPosition, cChunk * a_Chunk) { unsigned char PowerLevel = 0; - for (const auto & itr : *m_PoweredBlocks) // Check powered list + for (const auto & itr : static_cast(a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks) // Check powered list { if (itr.a_BlockPos != a_RelBlockPosition) { @@ -1777,7 +1769,7 @@ unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPo PowerLevel = std::max(itr.a_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 : *m_LinkedPoweredBlocks) // Check linked powered list + for (const auto & itr : static_cast(a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks) // Check linked powered list { if (itr.a_BlockPos != a_RelBlockPosition) { @@ -1785,7 +1777,7 @@ unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPo } BLOCKTYPE Type = E_BLOCK_AIR; - if (!m_Chunk->UnboundedRelGetBlockType(itr.a_SourcePos.x, itr.a_SourcePos.y, itr.a_SourcePos.z, Type) || (Type == E_BLOCK_REDSTONE_WIRE)) + if (!a_Chunk->UnboundedRelGetBlockType(itr.a_SourcePos.x, itr.a_SourcePos.y, itr.a_SourcePos.z, Type) || (Type == E_BLOCK_REDSTONE_WIRE)) { continue; } @@ -1931,22 +1923,19 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_RelBlockX, i void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel) { - static const struct - { - Vector3i Offset; - } gCrossCoords[] = - { - Vector3i(1, 0, 0), - Vector3i(-1, 0, 0), - Vector3i(0, 0, 1), - Vector3i(0, 0, -1), - Vector3i(0, 1, 0), - Vector3i(0, -1, 0) + static const Vector3i Offsets[] = + { + {1, 0, 0}, + { -1, 0, 0}, + {0, 0, 1}, + {0, 0, -1}, + {0, 1, 0}, + {0, -1, 0} }; - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions + for (auto Offset : Offsets) // Loop through struct to power all directions { - SetBlockPowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ) + gCrossCoords[i].Offset, Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), a_PowerLevel); + SetBlockPowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ) + Offset, Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), a_PowerLevel); } } @@ -1964,7 +1953,7 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(Vector3i a_RelBlockPosition, a_RelSourcePosition.x += (m_Chunk->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width; a_RelSourcePosition.z += (m_Chunk->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width; - auto & Powered = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position + 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.begin(); itr != Powered.end(); ++itr) { if ((itr->a_BlockPos == a_RelBlockPosition) && (itr->a_SourcePos == a_RelSourcePosition)) @@ -2012,7 +2001,7 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( return; } - auto & Linked = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_LinkedBlocks; + auto & Linked = static_cast(Neighbour->GetRedstoneSimulatorData())->m_LinkedBlocks; for (auto & itr : Linked) // Check linked powered list { if ( @@ -2041,24 +2030,24 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( -void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered) +void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool a_WasLastStatePowered) { - for (auto itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr) + for (auto & itr : *m_SimulatedPlayerToggleableBlocks) { - if (!itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) + if (!itr.a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; } // Update listing - itr->WasLastStatePowered = WasLastStatePowered; + itr.WasLastStatePowered = a_WasLastStatePowered; return; } // We have arrived here; no block must be in list - add one sSimulatedPlayerToggleableList RC; RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - RC.WasLastStatePowered = WasLastStatePowered; + RC.WasLastStatePowered = a_WasLastStatePowered; m_SimulatedPlayerToggleableBlocks->emplace_back(RC); } @@ -2109,7 +2098,7 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R auto UnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_Chunk, const Vector3i & a_RelSource) { - auto Data = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData(); + auto Data = static_cast(a_Chunk->GetRedstoneSimulatorData()); Data->m_PoweredBlocks.erase(std::remove_if(Data->m_PoweredBlocks.begin(), Data->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSource](const sPoweredBlocks & itr) { if (itr.a_SourcePos != a_RelSource) @@ -2117,16 +2106,16 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R return false; } - auto ChunkBoundaryTestCoords = a_RelSource + GetCoordinateAdjacentChunk(a_RelSource); - auto BoundaryChunk = a_Chunk->GetRelNeighborChunk(ChunkBoundaryTestCoords.x, ChunkBoundaryTestCoords.z); - if (BoundaryChunk != a_Chunk) + for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_Chunk)) { - Vector3i ChunkAdjustedSource = a_RelSource; - ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; - ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; + if (BoundaryChunk != a_Chunk) + { + Vector3i ChunkAdjustedSource = a_RelSource; + ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; + ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; - auto BoundaryData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)BoundaryChunk->GetRedstoneSimulatorData(); - BoundaryData->m_PoweredBlocks.erase(std::remove_if(BoundaryData->m_PoweredBlocks.begin(), BoundaryData->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedSource](const sPoweredBlocks & itr) + auto BoundaryData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)BoundaryChunk->GetRedstoneSimulatorData(); + BoundaryData->m_PoweredBlocks.erase(std::remove_if(BoundaryData->m_PoweredBlocks.begin(), BoundaryData->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedSource](const sPoweredBlocks & itr) { if (itr.a_SourcePos != ChunkAdjustedSource) { @@ -2137,7 +2126,8 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R BoundaryChunk->SetIsRedstoneDirty(true); return true; } - ), BoundaryData->m_PoweredBlocks.end()); + ), BoundaryData->m_PoweredBlocks.end()); + } } if (a_Chunk->GetBlock(a_RelSource) == E_BLOCK_REDSTONE_REPEATER_ON) @@ -2151,17 +2141,47 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R } ), Data->m_PoweredBlocks.end()); - /*Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSource](const sLinkedPoweredBlocks & itr) + Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSource](const sLinkedPoweredBlocks & itr) { - if (itr.a_SourcePos == a_RelSource) + if (itr.a_SourcePos != a_RelSource) { - BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos); - a_Chunk->SetIsRedstoneDirty(true); - return true; + return false; } - return false; + + for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_Chunk)) + { + if (BoundaryChunk != a_Chunk) + { + Vector3i ChunkAdjustedSource = a_RelSource; + ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; + ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; + + auto BoundaryData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)BoundaryChunk->GetRedstoneSimulatorData(); + BoundaryData->m_LinkedBlocks.erase(std::remove_if(BoundaryData->m_LinkedBlocks.begin(), BoundaryData->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedSource](const sLinkedPoweredBlocks & itr) + { + if (itr.a_SourcePos != ChunkAdjustedSource) + { + return false; + } + + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, BoundaryChunk)); + BoundaryChunk->SetIsRedstoneDirty(true); + return true; + } + ), BoundaryData->m_LinkedBlocks.end()); + } + } + + if (a_Chunk->GetBlock(a_RelSource) == E_BLOCK_REDSTONE_REPEATER_ON) + { + return false; + } + + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_Chunk)); + a_Chunk->SetIsRedstoneDirty(true); + return true; } - ), Data->m_LinkedBlocks.end());*/ + ), Data->m_LinkedBlocks.end()); }; while (!BlocksPotentiallyUnpowered.empty()) @@ -2187,7 +2207,7 @@ void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int } std::vector BlocksPotentiallyUnpowered; - auto Data = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData(); + auto Data = static_cast(a_Chunk->GetRedstoneSimulatorData()); Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ](const sLinkedPoweredBlocks & itr) { @@ -2223,76 +2243,40 @@ void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int -cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) +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) { - int Dir = REDSTONE_NONE; + std::vector AdjacentChunks; + AdjacentChunks.reserve(2); // At most bordering two chunks; reserve that many - BLOCKTYPE NegX = 0; - if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, NegX)) + // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks + if ((a_RelBlockPosition.x % cChunkDef::Width) <= 1) { - if (IsPotentialSource(NegX)) - { - Dir |= (REDSTONE_X_POS); - } + AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x - 2, a_RelBlockPosition.z)); } - - BLOCKTYPE PosX = 0; - if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, PosX)) + if ((a_RelBlockPosition.x % cChunkDef::Width) >= 14) { - if (IsPotentialSource(PosX)) - { - Dir |= (REDSTONE_X_NEG); - } + AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x + 2, a_RelBlockPosition.z)); } - - BLOCKTYPE NegZ = 0; - if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, NegZ)) + if ((a_RelBlockPosition.z % cChunkDef::Width) <= 1) { - if (IsPotentialSource(NegZ)) - { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner - { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; - } - Dir |= REDSTONE_Z_POS; - } + AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z - 2)); } - - BLOCKTYPE PosZ = 0; - if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, PosZ)) + if ((a_RelBlockPosition.z % cChunkDef::Width) >= 14) { - if (IsPotentialSource(PosZ)) - { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner - { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; - } - Dir |= REDSTONE_Z_NEG; - } + AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z + 2)); } - return (eRedstoneDirection)Dir; -} - - - - -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); + return AdjacentChunks; } diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index 903dbe82a..c383b6a0b 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -3,6 +3,7 @@ #include "RedstoneSimulator.h" #include "BlockEntities/RedstonePoweredEntity.h" +#include class cWorld; class cChunk; @@ -37,15 +38,14 @@ public: 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; - enum eRedstoneDirection + enum eRedstoneWireDirectionBitfieldPositions { - REDSTONE_NONE = 0, - REDSTONE_X_POS = 0x1, - REDSTONE_X_NEG = 0x2, - REDSTONE_Z_POS = 0x4, - REDSTONE_Z_NEG = 0x8, + eWbpXP = 0, + eWbpXN = 1, + eWbpZP = 2, + eWbpZN = 3, }; - eRedstoneDirection GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ); + std::bitset<4> GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ); private: @@ -108,8 +108,9 @@ private: SimulatedPlayerToggleableList * m_SimulatedPlayerToggleableBlocks; RepeatersDelayList * m_RepeatersDelayList; - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override { RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); } - void RedstoneAddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk, cChunk * a_OtherChunk = nullptr); + 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 @@ -192,6 +193,9 @@ private: 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 std::pair & a_Entry); + /** 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); @@ -214,13 +218,13 @@ private: void SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk, bool a_IsFirstCall = true); /** 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); } + 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 */ - bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk); + 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 */ - bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); + 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); @@ -236,7 +240,7 @@ private: /** 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 */ - unsigned char IsWirePowered(Vector3i a_RelBlockPosition); + static unsigned char IsWirePowered(Vector3i a_RelBlockPosition, cChunk * a_Chunk); /** Handles delayed updates to repeaters **/ void HandleRedstoneRepeaterDelays(void); @@ -249,14 +253,14 @@ private: /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */ - inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return cBlockInfo::FullyOccupiesVoxel(Block); } + 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 Block) + inline static bool IsMechanism(BLOCKTYPE a_Block) { - switch (Block) + switch (a_Block) { case E_BLOCK_ACACIA_DOOR: case E_BLOCK_ACACIA_FENCE_GATE: @@ -298,9 +302,9 @@ private: } /** Returns if a block has the potential to output power */ - inline static bool IsPotentialSource(BLOCKTYPE Block) + inline static bool IsPotentialSource(BLOCKTYPE a_Block) { - switch (Block) + switch (a_Block) { case E_BLOCK_DETECTOR_RAIL: case E_BLOCK_DAYLIGHT_SENSOR: @@ -326,9 +330,9 @@ private: } /** Returns if a block is any sort of redstone device */ - inline static bool IsRedstone(BLOCKTYPE Block) + inline static bool IsRedstone(BLOCKTYPE a_Block) { - switch (Block) + switch (a_Block) { // All redstone devices, please alpha sort case E_BLOCK_ACACIA_DOOR: @@ -385,16 +389,27 @@ private: } } - inline static Vector3i GetCoordinateAdjacentChunk(const Vector3i & a_BlockPos) + inline static bool DoesIgnorePlayerToggle(BLOCKTYPE a_Block) { - // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks - if ((a_BlockPos.x % cChunkDef::Width) <= 1) { return{ -2, 0, 0 }; } - if ((a_BlockPos.x % cChunkDef::Width) >= 14) { return{ 2, 0, 0 }; } - if ((a_BlockPos.z % cChunkDef::Width) <= 1) { return{ 0, 0, -2 }; } - if ((a_BlockPos.z % cChunkDef::Width) >= 14) { return{ 0, 0, 2 }; } - return { 0, 0, 0 }; + 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_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) { if ( diff --git a/src/World.cpp b/src/World.cpp index f7d2165c7..cf2c35816 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2964,7 +2964,7 @@ bool cWorld::SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Op return false; } - bool IsOpen = (Meta & 0x4) > 0; + bool IsOpen = (Meta & 0x4) != 0; if (a_Open != IsOpen) { SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta ^ 0x4); -- cgit v1.2.3 From 151fe0fc595d580264fdb0d394c74ed9fa6df514 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 26 Apr 2015 01:16:23 +0100 Subject: Fixed wire consuming much resources --- src/Simulator/IncrementalRedstoneSimulator.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 40829757d..f297f7701 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -640,16 +640,26 @@ void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vectorGetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); auto MyPower = IsWirePowered(a_Entry.first, a_Entry.second); + auto & PoweredBlocks = ((cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position + sPoweredBlocks RC; + RC.a_BlockPos = AdjustedPos; + RC.a_SourcePos = a_Entry.first + Vector3i((a_Entry.second->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width, 0, (a_Entry.second->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width); + RC.a_PowerLevel = MyPower - 1; + if ((Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) { - sPoweredBlocks RC; - RC.a_BlockPos = AdjustedPos; - RC.a_SourcePos = a_Entry.first + Vector3i((a_Entry.second->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width, 0, (a_Entry.second->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width); - RC.a_PowerLevel = MyPower - 1; - ((cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks.emplace_back(RC); // We need to insert the value into the chunk who owns the block position + auto Position = std::find_if(PoweredBlocks.begin(), PoweredBlocks.end(), [RC](const sPoweredBlocks & itr) { return itr.a_BlockPos == RC.a_BlockPos && itr.a_SourcePos == RC.a_SourcePos; }); + if (Position != PoweredBlocks.end()) + { + Position->a_PowerLevel = RC.a_PowerLevel; + } + else + { + PoweredBlocks.emplace_back(RC); - Neighbour->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); + Neighbour->SetIsRedstoneDirty(true); + m_Chunk->SetIsRedstoneDirty(true); + } Neighbour->SetMeta(AdjustedPos.x, AdjustedPos.y, AdjustedPos.z, MyPower - 1); a_PotentialWireList.emplace_back(std::make_pair(AdjustedPos, Neighbour)); -- cgit v1.2.3 From bef7cce5ede018a4b0bc0f03cbd7a3a87f066d4c Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 1 May 2015 22:55:43 +0100 Subject: Improved wires and repeaters * Fixed repeater cross-chunk power detection + Re-implemented horizontal wire cut-off checking --- src/Simulator/IncrementalRedstoneSimulator.cpp | 223 +++++++++++++++++-------- src/Simulator/IncrementalRedstoneSimulator.h | 2 + 2 files changed, 152 insertions(+), 73 deletions(-) diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index f297f7701..095fefe7b 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -94,7 +94,7 @@ void cIncrementalRedstoneSimulator::AddBlock(const Vector3i & a_RelBlockPosition auto & SimulatedPlayerToggleableBlocks = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_SimulatedPlayerToggleableBlocks; if ( DoesIgnorePlayerToggle(Block) && - std::find_if(SimulatedPlayerToggleableBlocks.begin(),SimulatedPlayerToggleableBlocks.end(), + std::find_if(SimulatedPlayerToggleableBlocks.begin(), SimulatedPlayerToggleableBlocks.end(), [a_RelBlockPosition](const sSimulatedPlayerToggleableList & itr){ return itr.a_RelBlockPos == a_RelBlockPosition; }) == SimulatedPlayerToggleableBlocks.end() ) { @@ -549,28 +549,28 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re auto Current = PotentialWireList.back(); PotentialWireList.pop_back(); FindAndPowerBorderingWires(PotentialWireList, Current); - } + } } else if (MyPower == 1) { return; } + // Wire still powered, power blocks beneath and in direction of facing MyPower--; - // Wire still powered, power blocks beneath 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 VectorOffset; + Vector3i OffsetToPower; - for (auto OffsetIdx = 0; OffsetIdx != ARRAYCOUNT(VectorOffsets); ++OffsetIdx) + for (const auto & Offset : VectorOffsets) { BLOCKTYPE Block; - auto Offset = RelBlock + VectorOffsets[OffsetIdx]; - if (m_Chunk->UnboundedRelGetBlockType(Offset.x, Offset.y, Offset.z, Block)) + Vector3i AdjustedOffset = RelBlock + Offset; + if (m_Chunk->UnboundedRelGetBlockType(AdjustedOffset.x, AdjustedOffset.y, AdjustedOffset.z, Block)) { switch (Block) { @@ -581,9 +581,9 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re { // TODO: only if wire is actually connected to repeater (repeater facing right way) RepeaterPresent = true; - VectorOffset = { -VectorOffsets[OffsetIdx].x, VectorOffsets[OffsetIdx].y, -VectorOffsets[OffsetIdx].z }; + OffsetToPower = { -Offset.x, Offset.y, -Offset.z }; // Negate to obtain offset in opposite direction since wire powers that way } - SetBlockPowered(Offset, RelBlock, MyPower); + SetBlockPowered(AdjustedOffset, RelBlock, MyPower); } case E_BLOCK_REDSTONE_TORCH_ON: case E_BLOCK_REDSTONE_WIRE: @@ -591,7 +591,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re BorderingMechanismCount++; if (!RepeaterPresent) { - VectorOffset = { -VectorOffsets[OffsetIdx].x, VectorOffsets[OffsetIdx].y, -VectorOffsets[OffsetIdx].z }; + OffsetToPower = { -Offset.x, Offset.y, -Offset.z }; } } default: break; @@ -602,11 +602,15 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re 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), VectorOffset))]; - SetBlockPowered(RelBlock + VectorOffset, RelBlock, MyPower); + 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); } } @@ -617,52 +621,82 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const std::pair & a_Entry) { - std::vector> NewAdditions; - const Vector3i Offsets[] = + static const Vector3i LevelOffsets[] = // Wires on same level { - { 1, 0, 0 }, /* Wires on same level start */ + { 1, 0, 0 }, { -1, 0, 0 }, { 0, 0, 1 }, - { 0, 0, -1 }, /* Wires on same level stop */ - { 1, 1, 0 }, /* Wires one higher, surrounding self start */ + { 0, 0, -1 }, + }; + static const Vector3i HigherOffsets[] = // Wires one higher, surrounding self + { + { 1, 1, 0 }, { -1, 1, 0 }, { 0, 1, 1 }, - { 0, 1, -1 }, /* Wires one higher, surrounding self stop */ - { 1, -1, 0 }, /* Wires one lower, surrounding self start */ + { 0, 1, -1 }, + }; + static const Vector3i LowerOffsets[] = // Wires one lower, surrounding self + { + { 1, -1, 0 }, { -1, -1, 0 }, { 0, -1, 1 }, - { 0, -1, -1 }, /* Wires one lower, surrounding self stop */ + { 0, -1, -1 }, }; - for (auto Offset : Offsets) + for (auto Offset : LevelOffsets) { auto AdjustedPos = a_Entry.first + Offset; auto Neighbour = a_Entry.second->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); auto MyPower = IsWirePowered(a_Entry.first, a_Entry.second); - auto & PoweredBlocks = ((cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position - sPoweredBlocks RC; - RC.a_BlockPos = AdjustedPos; - RC.a_SourcePos = a_Entry.first + Vector3i((a_Entry.second->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width, 0, (a_Entry.second->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width); - RC.a_PowerLevel = MyPower - 1; + if ((Neighbour == nullptr) || !Neighbour->IsValid()) + { + return; + } if ((Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) { - auto Position = std::find_if(PoweredBlocks.begin(), PoweredBlocks.end(), [RC](const sPoweredBlocks & itr) { return itr.a_BlockPos == RC.a_BlockPos && itr.a_SourcePos == RC.a_SourcePos; }); - if (Position != PoweredBlocks.end()) - { - Position->a_PowerLevel = RC.a_PowerLevel; - } - else - { - PoweredBlocks.emplace_back(RC); + PowerBorderingWires(a_PotentialWireList, a_Entry, AdjustedPos, Neighbour, MyPower); + } + } - Neighbour->SetIsRedstoneDirty(true); - m_Chunk->SetIsRedstoneDirty(true); - } + for (auto Offset : HigherOffsets) + { + auto AdjustedPos = a_Entry.first + Offset; + auto Neighbour = a_Entry.second->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); + auto MyPower = IsWirePowered(a_Entry.first, a_Entry.second); + + if ((Neighbour == nullptr) || !Neighbour->IsValid()) + { + return; + } + + if ( + (Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && + (!cBlockInfo::FullyOccupiesVoxel(a_Entry.second->GetBlock(a_Entry.first.x, a_Entry.first.y + 1, a_Entry.first.z))) && + (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) + { + PowerBorderingWires(a_PotentialWireList, a_Entry, AdjustedPos, Neighbour, MyPower); + } + } + + for (auto Offset : LowerOffsets) + { + auto AdjustedPos = a_Entry.first + Offset; + auto Neighbour = a_Entry.second->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); + auto MyPower = IsWirePowered(a_Entry.first, a_Entry.second); - Neighbour->SetMeta(AdjustedPos.x, AdjustedPos.y, AdjustedPos.z, MyPower - 1); - a_PotentialWireList.emplace_back(std::make_pair(AdjustedPos, Neighbour)); + 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))) && + (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) + { + PowerBorderingWires(a_PotentialWireList, a_Entry, AdjustedPos, Neighbour, MyPower); } } } @@ -671,6 +705,35 @@ void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const std::pair & a_Entry, const Vector3i & a_AdjustedPos, cChunk * a_NeighbourChunk, unsigned char a_MyPower) +{ + sPoweredBlocks RC; + RC.a_BlockPos = a_AdjustedPos; + RC.a_SourcePos = a_Entry.first + Vector3i((a_Entry.second->GetPosX() - a_NeighbourChunk->GetPosX()) * cChunkDef::Width, 0, (a_Entry.second->GetPosZ() - a_NeighbourChunk->GetPosZ()) * cChunkDef::Width); + RC.a_PowerLevel = a_MyPower - 1; + + 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(), [RC](const sPoweredBlocks & itr) { return itr.a_BlockPos == RC.a_BlockPos && itr.a_SourcePos == RC.a_SourcePos; }); + if (Position != PoweredBlocks.end()) + { + Position->a_PowerLevel = RC.a_PowerLevel; + } + else + { + PoweredBlocks.emplace_back(RC); + + a_NeighbourChunk->SetIsRedstoneDirty(true); + m_Chunk->SetIsRedstoneDirty(true); + } + + a_NeighbourChunk->SetMeta(RC.a_BlockPos.x, RC.a_BlockPos.y, RC.a_BlockPos.z, RC.a_PowerLevel); + a_PotentialWireList.emplace_back(std::make_pair(RC.a_BlockPos, 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); @@ -708,12 +771,12 @@ void cIncrementalRedstoneSimulator::HandleRedstoneComparator(int a_RelBlockX, in 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 = RearPower - HighestSidePower; + { // Subtraction mode + Power = std::max(static_cast(RearPower - HighestSidePower), std::numeric_limits::min()); } else - { // Comparison mode - Power = std::max(HighestSidePower, RearPower); + { // Comparison mode + Power = (std::max(HighestSidePower, RearPower) == HighestSidePower) ? 0 : RearPower; } if (Power > 0) @@ -1562,7 +1625,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel case 0x0: { // Flip the coords to check the back of the repeater - if (itr.a_SourcePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1)))) + if (itr.a_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1))) { return true; } @@ -1570,7 +1633,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel } case 0x1: { - if (itr.a_SourcePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ)))) + if (itr.a_SourcePos.Equals(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ))) { return true; } @@ -1578,7 +1641,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel } case 0x2: { - if (itr.a_SourcePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1)))) + if (itr.a_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1))) { return true; } @@ -1586,7 +1649,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel } case 0x3: { - if (itr.a_SourcePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ)))) + if (itr.a_SourcePos.Equals(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ))) { return true; } @@ -1606,7 +1669,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel { case 0x0: { - if (itr.a_MiddlePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1)))) + if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1))) { return true; } @@ -1614,7 +1677,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel } case 0x1: { - if (itr.a_MiddlePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ)))) + if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ))) { return true; } @@ -1622,7 +1685,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel } case 0x2: { - if (itr.a_MiddlePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1)))) + if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1))) { return true; } @@ -1630,7 +1693,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel } case 0x3: { - if (itr.a_MiddlePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ)))) + if (itr.a_MiddlePos.Equals(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ))) { return true; } @@ -2104,6 +2167,10 @@ bool cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, in 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_Chunk, const Vector3i & a_RelSource) @@ -2126,21 +2193,22 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R auto BoundaryData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)BoundaryChunk->GetRedstoneSimulatorData(); BoundaryData->m_PoweredBlocks.erase(std::remove_if(BoundaryData->m_PoweredBlocks.begin(), BoundaryData->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedSource](const sPoweredBlocks & itr) - { - if (itr.a_SourcePos != ChunkAdjustedSource) { - return false; + if (itr.a_SourcePos != ChunkAdjustedSource) + { + return false; + } + + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, BoundaryChunk)); + BoundaryChunk->SetIsRedstoneDirty(true); + return true; } - - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, BoundaryChunk)); - BoundaryChunk->SetIsRedstoneDirty(true); - return true; - } ), BoundaryData->m_PoweredBlocks.end()); } } - if (a_Chunk->GetBlock(a_RelSource) == E_BLOCK_REDSTONE_REPEATER_ON) + BLOCKTYPE RepeaterType; + if (a_Chunk->UnboundedRelGetBlockType(a_RelSource.x, a_RelSource.y, a_RelSource.z, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) { return false; } @@ -2168,21 +2236,22 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R auto BoundaryData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)BoundaryChunk->GetRedstoneSimulatorData(); BoundaryData->m_LinkedBlocks.erase(std::remove_if(BoundaryData->m_LinkedBlocks.begin(), BoundaryData->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedSource](const sLinkedPoweredBlocks & itr) - { - if (itr.a_SourcePos != ChunkAdjustedSource) { - return false; + if (itr.a_SourcePos != ChunkAdjustedSource) + { + return false; + } + + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, BoundaryChunk)); + BoundaryChunk->SetIsRedstoneDirty(true); + return true; } - - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, BoundaryChunk)); - BoundaryChunk->SetIsRedstoneDirty(true); - return true; - } ), BoundaryData->m_LinkedBlocks.end()); } } - if (a_Chunk->GetBlock(a_RelSource) == E_BLOCK_REDSTONE_REPEATER_ON) + BLOCKTYPE RepeaterType; + if (a_Chunk->UnboundedRelGetBlockType(a_RelSource.x, a_RelSource.y, a_RelSource.z, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) { return false; } @@ -2268,22 +2337,30 @@ std::vector cIncrementalRedstoneSimulator::GetAdjacentChunks(const Vec std::vector AdjacentChunks; AdjacentChunks.reserve(2); // At most bordering two chunks; reserve that many + auto CheckAndEmplace = [&AdjacentChunks](cChunk * a_Chunk) + { + if ((a_Chunk != nullptr) && a_Chunk->IsValid()) + { + AdjacentChunks.emplace_back(a_Chunk); + } + }; + // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks if ((a_RelBlockPosition.x % cChunkDef::Width) <= 1) { - AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x - 2, a_RelBlockPosition.z)); + CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x - 2, a_RelBlockPosition.z)); } if ((a_RelBlockPosition.x % cChunkDef::Width) >= 14) { - AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x + 2, a_RelBlockPosition.z)); + CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x + 2, a_RelBlockPosition.z)); } if ((a_RelBlockPosition.z % cChunkDef::Width) <= 1) { - AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z - 2)); + CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z - 2)); } if ((a_RelBlockPosition.z % cChunkDef::Width) >= 14) { - AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z + 2)); + 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 index c383b6a0b..5133f7caf 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -196,6 +196,8 @@ private: /** Recursively searches for a wire path and powers everything that should be powered */ void FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const std::pair & a_Entry); + void PowerBorderingWires(std::vector> & a_PotentialWireList, const std::pair & a_Entry, 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); -- cgit v1.2.3 From 6a831c0b6fdf984f0cdf1d30995c9e602bdd41a5 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 26 May 2015 23:30:50 +0100 Subject: Improved link power behaviour --- src/Simulator/IncrementalRedstoneSimulator.cpp | 248 ++++++++++++------------- src/Simulator/IncrementalRedstoneSimulator.h | 34 +--- 2 files changed, 119 insertions(+), 163 deletions(-) diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 095fefe7b..29ea65407 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -713,7 +713,7 @@ void cIncrementalRedstoneSimulator::PowerBorderingWires(std::vector(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(), [RC](const sPoweredBlocks & itr) { return itr.a_BlockPos == RC.a_BlockPos && itr.a_SourcePos == RC.a_SourcePos; }); + auto Position = std::find_if(PoweredBlocks.begin(), PoweredBlocks.end(), [RC](const sPoweredBlocks & itr) { return ((itr.a_BlockPos == RC.a_BlockPos) && (itr.a_SourcePos == RC.a_SourcePos)); }); if (Position != PoweredBlocks.end()) { Position->a_PowerLevel = RC.a_PowerLevel; @@ -819,19 +819,50 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int */ // Create a variable holding my meta to avoid multiple lookups. - NIBBLETYPE a_Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + 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, a_Meta)) // If we're locked, change nothing. Otherwise: + 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, a_Meta); + 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, a_Meta, true); + 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, a_Meta, false); + 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; + } } } } @@ -855,34 +886,6 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays() { m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta); } - - switch (Meta & 0x3) // We only want the direction (bottom) bits - { - case 0x0: - { - SetBlockPowered(RelBlockX, RelBlockY, RelBlockZ - 1, RelBlockX, RelBlockY, RelBlockZ); - SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_ZM); - break; - } - case 0x1: - { - SetBlockPowered(RelBlockX + 1, RelBlockY, RelBlockZ, RelBlockX, RelBlockY, RelBlockZ); - SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_XP); - break; - } - case 0x2: - { - SetBlockPowered(RelBlockX, RelBlockY, RelBlockZ + 1, RelBlockX, RelBlockY, RelBlockZ); - SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_ZP); - break; - } - case 0x3: - { - SetBlockPowered(RelBlockX - 1, RelBlockY, RelBlockZ, RelBlockX, RelBlockY, RelBlockZ); - SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_XM); - break; - } - } } else if (Block != E_BLOCK_REDSTONE_REPEATER_OFF) { @@ -2027,16 +2030,16 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(Vector3i a_RelBlockPosition, 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.begin(); itr != Powered.end(); ++itr) + for (auto & itr : Powered) { - if ((itr->a_BlockPos == a_RelBlockPosition) && (itr->a_SourcePos == a_RelSourcePosition)) + if ((itr.a_BlockPos == a_RelBlockPosition) && (itr.a_SourcePos == a_RelSourcePosition)) { - if (itr->a_PowerLevel != a_PowerLevel) + 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; + itr.a_PowerLevel = a_PowerLevel; } return; } @@ -2068,11 +2071,14 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( } cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ); - m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelMiddleX, a_RelMiddleZ); 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 @@ -2083,8 +2089,13 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( itr.a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ)) ) { - // Check for duplicates, update power level, don't add a new listing - itr.a_PowerLevel = a_PowerLevel; + 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; } } @@ -2175,6 +2186,12 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R auto UnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_Chunk, const Vector3i & a_RelSource) { + BLOCKTYPE RepeaterType; + if (a_Chunk->UnboundedRelGetBlockType(a_RelSource.x, a_RelSource.y, a_RelSource.z, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) + { + return; + } + auto Data = static_cast(a_Chunk->GetRedstoneSimulatorData()); Data->m_PoweredBlocks.erase(std::remove_if(Data->m_PoweredBlocks.begin(), Data->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSource](const sPoweredBlocks & itr) { @@ -2183,42 +2200,12 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R return false; } - for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_Chunk)) - { - if (BoundaryChunk != a_Chunk) - { - Vector3i ChunkAdjustedSource = a_RelSource; - ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; - ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; - - auto BoundaryData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)BoundaryChunk->GetRedstoneSimulatorData(); - BoundaryData->m_PoweredBlocks.erase(std::remove_if(BoundaryData->m_PoweredBlocks.begin(), BoundaryData->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedSource](const sPoweredBlocks & itr) - { - if (itr.a_SourcePos != ChunkAdjustedSource) - { - return false; - } - - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, BoundaryChunk)); - BoundaryChunk->SetIsRedstoneDirty(true); - return true; - } - ), BoundaryData->m_PoweredBlocks.end()); - } - } - - BLOCKTYPE RepeaterType; - if (a_Chunk->UnboundedRelGetBlockType(a_RelSource.x, a_RelSource.y, a_RelSource.z, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) - { - return false; - } - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_Chunk)); a_Chunk->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_Chunk, a_RelSource](const sLinkedPoweredBlocks & itr) { if (itr.a_SourcePos != a_RelSource) @@ -2226,41 +2213,27 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R return false; } - for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_Chunk)) - { - if (BoundaryChunk != a_Chunk) - { - Vector3i ChunkAdjustedSource = a_RelSource; - ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; - ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; - - auto BoundaryData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)BoundaryChunk->GetRedstoneSimulatorData(); - BoundaryData->m_LinkedBlocks.erase(std::remove_if(BoundaryData->m_LinkedBlocks.begin(), BoundaryData->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedSource](const sLinkedPoweredBlocks & itr) - { - if (itr.a_SourcePos != ChunkAdjustedSource) - { - return false; - } - - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, BoundaryChunk)); - BoundaryChunk->SetIsRedstoneDirty(true); - return true; - } - ), BoundaryData->m_LinkedBlocks.end()); - } - } - - BLOCKTYPE RepeaterType; - if (a_Chunk->UnboundedRelGetBlockType(a_RelSource.x, a_RelSource.y, a_RelSource.z, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) - { - return false; - } - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_Chunk)); a_Chunk->SetIsRedstoneDirty(true); return true; } ), Data->m_LinkedBlocks.end()); + + for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_Chunk)) + { + auto BoundaryData = static_cast(BoundaryChunk->GetRedstoneSimulatorData()); + Vector3i ChunkAdjustedSource = a_RelSource; + ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; + ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; + + if ( + (std::find_if(BoundaryData->m_PoweredBlocks.begin(), BoundaryData->m_PoweredBlocks.end(), [ChunkAdjustedSource](const sPoweredBlocks & itr) { return (itr.a_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()) @@ -2275,45 +2248,56 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R -void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk, bool a_IsFirstCall) +void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk) { - if (!a_IsFirstCall) // The neighbouring chunks passed when this parameter is false may be invalid - { - if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) - { - return; - } - } - - std::vector BlocksPotentiallyUnpowered; + std::vector> BlocksPotentiallyUnpowered; auto Data = static_cast(a_Chunk->GetRedstoneSimulatorData()); Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ](const sLinkedPoweredBlocks & itr) { - if (itr.a_MiddlePos.Equals(Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ))) + if (!itr.a_MiddlePos.Equals(Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ))) { - BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos); - a_Chunk->SetIsRedstoneDirty(true); - return true; + return false; } - return false; + + 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; + + auto BoundaryData = static_cast(BoundaryChunk->GetRedstoneSimulatorData()); + BoundaryData->m_LinkedBlocks.erase(std::remove_if(BoundaryData->m_LinkedBlocks.begin(), BoundaryData->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedMiddlePos](const sLinkedPoweredBlocks & itr) + { + if (itr.a_MiddlePos != ChunkAdjustedMiddlePos) + { + return false; + } + + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, BoundaryChunk)); + BoundaryChunk->SetIsRedstoneDirty(true); + return true; + } + ), BoundaryData->m_LinkedBlocks.end()); + } + + BLOCKTYPE RepeaterType; + if (a_Chunk->UnboundedRelGetBlockType(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) + { + return false; + } + + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_Chunk)); + a_Chunk->SetIsRedstoneDirty(true); + return true; } ), Data->m_LinkedBlocks.end()); - if (a_IsFirstCall && /*AreCoordsOnChunkBoundary(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)*/1) - { - // +- 2 to accomodate linked powered blocks - SetInvalidMiddleBlock(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, a_Chunk->GetRelNeighborChunk(a_RelMiddleX - 2, a_RelMiddleZ), false); - SetInvalidMiddleBlock(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, a_Chunk->GetRelNeighborChunk(a_RelMiddleX + 2, a_RelMiddleZ), false); - SetInvalidMiddleBlock(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, a_Chunk->GetRelNeighborChunk(a_RelMiddleX, a_RelMiddleZ - 2), false); - SetInvalidMiddleBlock(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, a_Chunk->GetRelNeighborChunk(a_RelMiddleX, a_RelMiddleZ + 2), false); - } - for (const auto & itr : BlocksPotentiallyUnpowered) { - if (!AreCoordsPowered(itr.x, itr.y, itr.z)) + if (!AreCoordsPowered(itr.first.x, itr.first.y, itr.first.z)) { - SetSourceUnpowered(itr.x, itr.y, itr.z, a_Chunk->GetRelNeighborChunk(itr.x, itr.z)); + SetSourceUnpowered(itr.first.x, itr.first.y, itr.first.z, itr.second); } } } @@ -2346,19 +2330,19 @@ std::vector cIncrementalRedstoneSimulator::GetAdjacentChunks(const Vec }; // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks - if ((a_RelBlockPosition.x % cChunkDef::Width) <= 1) + if (a_RelBlockPosition.x <= 1) { CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x - 2, a_RelBlockPosition.z)); } - if ((a_RelBlockPosition.x % cChunkDef::Width) >= 14) + if (a_RelBlockPosition.x >= 14) { CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x + 2, a_RelBlockPosition.z)); } - if ((a_RelBlockPosition.z % cChunkDef::Width) <= 1) + if (a_RelBlockPosition.z <= 1) { CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z - 2)); } - if ((a_RelBlockPosition.z % cChunkDef::Width) >= 14) + if (a_RelBlockPosition.z >= 14) { CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z + 2)); } diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index 5133f7caf..934a0eab9 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -214,10 +214,10 @@ private: bool QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); /** Removes a block from the Powered and LinkedPowered lists - Used for variable sources such as tripwire hooks, daylight sensors, and trapped chests + 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, bool a_IsFirstCall = true); + 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); } @@ -414,35 +414,7 @@ private: inline static Vector3i AdjustRelativeCoords(const Vector3i & a_RelPosition) { - if ( - (a_RelPosition.x >= 0) && (a_RelPosition.x < cChunkDef::Width) && - (a_RelPosition.z >= 0) && (a_RelPosition.z < cChunkDef::Width) - ) - { - return a_RelPosition; - } - - Vector3i RelPos = a_RelPosition; - - // Request for a different chunk, calculate chunk offset: - while (RelPos.x >= cChunkDef::Width) - { - RelPos.x -= cChunkDef::Width; - } - while (RelPos.x < 0) - { - RelPos.x += cChunkDef::Width; - } - while (RelPos.z >= cChunkDef::Width) - { - RelPos.z -= cChunkDef::Width; - } - while (RelPos.z < 0) - { - RelPos.z += cChunkDef::Width; - } - - return RelPos; + return Vector3i((a_RelPosition.x % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width, a_RelPosition.y, (a_RelPosition.z % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width); } }; -- cgit v1.2.3 From 171c59a01b07b7513cf7a281bbcb141e8182d274 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 2 Jun 2015 13:29:52 +0100 Subject: Changed appropriate containers to unordered_map Thanks to @worktycho for guidance! * Potential speed improvements --- src/ChunkDef.h | 29 ---- src/Mobs/Path.h | 17 +- src/Simulator/IncrementalRedstoneSimulator.cpp | 212 +++++++++---------------- src/Simulator/IncrementalRedstoneSimulator.h | 31 +--- src/Vector3.h | 6 + 5 files changed, 92 insertions(+), 203 deletions(-) diff --git a/src/ChunkDef.h b/src/ChunkDef.h index a1273bd23..57c4e6918 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -514,32 +514,3 @@ typedef cCoordWithData cCoordWithBlock; typedef std::list cCoordWithIntList; typedef std::vector cCoordWithIntVector; - - - - - -/** Generic template that can store two types of any kind of data together with a triplet of 3 coords */ -template class cCoordWithDoubleData -{ -public: - int x; - int y; - int z; - X Data; - Z DataTwo; - - cCoordWithDoubleData(int a_X, int a_Y, int a_Z) : - x(a_X), y(a_Y), z(a_Z) - { - } - - cCoordWithDoubleData(int a_X, int a_Y, int a_Z, const X & a_Data, const Z & a_DataTwo) : - x(a_X), y(a_Y), z(a_Z), Data(a_Data), DataTwo(a_DataTwo) - { - } -}; - -typedef cCoordWithDoubleData cCoordWithBlockAndBool; - -typedef std::vector cCoordWithBlockAndBoolVector; diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h index c250eece2..491165795 100644 --- a/src/Mobs/Path.h +++ b/src/Mobs/Path.h @@ -124,21 +124,6 @@ public: return m_PathPoints.size(); } - struct VectorHasher - { - std::size_t operator()(const Vector3i & a_Vector) const - { - // Guaranteed to have no hash collisions for any 128x128x128 area. Suitable for pathfinding. - int32_t t = 0; - t += static_cast(a_Vector.x); - t = t << 8; - t += static_cast(a_Vector.y); - t = t << 8; - t += static_cast(a_Vector.z); - t = t << 8; - return static_cast(t); - } - }; private: /* General */ @@ -160,7 +145,7 @@ private: /* Pathfinding fields */ std::priority_queue, compareHeuristics> m_OpenList; - std::unordered_map m_Map; + std::unordered_map m_Map; Vector3i m_Destination; Vector3i m_Source; int m_BoundingBoxWidth; diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 29ea65407..f60106fac 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -92,67 +92,45 @@ void cIncrementalRedstoneSimulator::AddBlock(const Vector3i & a_RelBlockPosition } auto & SimulatedPlayerToggleableBlocks = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_SimulatedPlayerToggleableBlocks; - if ( - DoesIgnorePlayerToggle(Block) && - std::find_if(SimulatedPlayerToggleableBlocks.begin(), SimulatedPlayerToggleableBlocks.end(), - [a_RelBlockPosition](const sSimulatedPlayerToggleableList & itr){ return itr.a_RelBlockPos == a_RelBlockPosition; }) == SimulatedPlayerToggleableBlocks.end() - ) + if (DoesIgnorePlayerToggle(Block)) { - // We have arrived here; no block must be in list - add one - sSimulatedPlayerToggleableList RC; - RC.a_RelBlockPos = a_RelBlockPosition; - RC.WasLastStatePowered = AreCoordsDirectlyPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk) || AreCoordsLinkedPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk); - // Initialise the toggleable blocks list so that trapdoors etc. aren't reset on restart (#1887) - SimulatedPlayerToggleableBlocks.emplace_back(RC); + 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); } - SimulatedPlayerToggleableBlocks.erase(std::remove_if(SimulatedPlayerToggleableBlocks.begin(), SimulatedPlayerToggleableBlocks.end(), [a_RelBlockPosition, Block, this](const sSimulatedPlayerToggleableList & itr) - { - return (itr.a_RelBlockPos == a_RelBlockPosition) && !DoesIgnorePlayerToggle(Block); - } - ), SimulatedPlayerToggleableBlocks.end()); - - auto & RepeatersDelayList = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_RepeatersDelayList; - RepeatersDelayList.erase(std::remove_if(RepeatersDelayList.begin(), RepeatersDelayList.end(), [a_RelBlockPosition, Block](const sRepeatersDelayList & itr) - { - return (itr.a_RelBlockPos == a_RelBlockPosition) && (Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF); - } - ), RepeatersDelayList.end()); - - auto & RedstoneSimulatorChunkData = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_ChunkData; - for (auto & itr : RedstoneSimulatorChunkData) + if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF)) { - if (a_RelBlockPosition == Vector3i(itr.x, itr.y, itr.z)) // We are at an entry matching the current (changed) block - { - if (!IsAllowedBlock(Block)) - { - itr.DataTwo = true; // The new blocktype is not redstone; it must be queued to be removed from this list - } - else - { - itr.DataTwo = false; - itr.Data = Block; // Update block information - } - return; - } + static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_RepeatersDelayList.erase(a_RelBlockPosition); } + auto & RedstoneSimulatorChunkData = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->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; } - - auto & QueuedData = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_QueuedChunkData; - for (const auto & itr : QueuedData) + else { - if (a_RelBlockPosition == Vector3i(itr.x, itr.y, itr.z)) + if (Iterator != RedstoneSimulatorChunkData.end()) { - // Can't have duplicates in here either, in case something adds the block again before the structure can written to the main chunk data + Iterator->second.second = false; + Iterator->second.first = Block; // Update block information return; } } - QueuedData.emplace_back(cCoordWithBlockAndBool(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, false)); + + RedstoneSimulatorChunkData.emplace(a_RelBlockPosition, std::make_pair(Block, false)); } @@ -167,19 +145,11 @@ void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt m_RedstoneSimulatorChunkData = new cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData(); a_Chunk->SetRedstoneSimulatorData(m_RedstoneSimulatorChunkData); } - if (m_RedstoneSimulatorChunkData->m_ChunkData.empty() && static_cast(a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData.empty()) + if (m_RedstoneSimulatorChunkData->m_ChunkData.empty()) { return; } - m_RedstoneSimulatorChunkData->m_ChunkData.insert( - m_RedstoneSimulatorChunkData->m_ChunkData.end(), - m_RedstoneSimulatorChunkData->m_QueuedChunkData.begin(), - m_RedstoneSimulatorChunkData->m_QueuedChunkData.end() - ); - - m_RedstoneSimulatorChunkData->m_QueuedChunkData.clear(); - m_PoweredBlocks = &m_RedstoneSimulatorChunkData->m_PoweredBlocks; m_RepeatersDelayList = &m_RedstoneSimulatorChunkData->m_RepeatersDelayList; m_SimulatedPlayerToggleableBlocks = &m_RedstoneSimulatorChunkData->m_SimulatedPlayerToggleableBlocks; @@ -199,24 +169,24 @@ void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt for (auto dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.begin(); dataitr != m_RedstoneSimulatorChunkData->m_ChunkData.end();) { - if (dataitr->DataTwo) + if (dataitr->second.second) { dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.erase(dataitr); continue; } - switch (dataitr->Data) + switch (dataitr->second.first) { - case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(dataitr->x, dataitr->y, dataitr->z); break; - case E_BLOCK_TRIPWIRE: HandleTripwire(dataitr->x, dataitr->y, dataitr->z); break; - case E_BLOCK_TRIPWIRE_HOOK: HandleTripwireHook(dataitr->x, dataitr->y, dataitr->z); break; + 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->x, dataitr->y, dataitr->z, dataitr->Data); + HandlePressurePlate(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); break; } default: break; @@ -224,23 +194,23 @@ void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt if (ShouldUpdateSimulateOnceBlocks) { - switch (dataitr->Data) + switch (dataitr->second.first) { - case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(dataitr->x, dataitr->y, dataitr->z); break; - case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(dataitr->x, dataitr->y, dataitr->z); break; - case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(dataitr->x, dataitr->y, dataitr->z); break; - case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(dataitr->x, dataitr->y, dataitr->z); break; - case E_BLOCK_LEVER: HandleRedstoneLever(dataitr->x, dataitr->y, dataitr->z); break; - case E_BLOCK_TNT: HandleTNT(dataitr->x, dataitr->y, dataitr->z); break; - case E_BLOCK_IRON_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break; - case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break; - case E_BLOCK_TRAPPED_CHEST: HandleTrappedChest(dataitr->x, dataitr->y, dataitr->z); break; + 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->x, dataitr->y, dataitr->z, dataitr->Data); + HandleRail(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); break; } case E_BLOCK_ACACIA_DOOR: @@ -251,7 +221,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt case E_BLOCK_WOODEN_DOOR: case E_BLOCK_IRON_DOOR: { - HandleDoor(dataitr->x, dataitr->y, dataitr->z); + HandleDoor(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; } case E_BLOCK_ACACIA_FENCE_GATE: @@ -261,49 +231,49 @@ void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt case E_BLOCK_JUNGLE_FENCE_GATE: case E_BLOCK_SPRUCE_FENCE_GATE: { - HandleFenceGate(dataitr->x, dataitr->y, dataitr->z); + 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->x, dataitr->y, dataitr->z, dataitr->Data); + HandleRedstoneLamp(dataitr->first.x, dataitr->first.y, dataitr->first.z, dataitr->second.first); break; } case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: { - HandleDropSpenser(dataitr->x, dataitr->y, dataitr->z); + HandleDropSpenser(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; } case E_BLOCK_PISTON: case E_BLOCK_STICKY_PISTON: { - HandlePiston(dataitr->x, dataitr->y, dataitr->z); + 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->x, dataitr->y, dataitr->z, dataitr->Data); + 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->x, dataitr->y, dataitr->z, dataitr->Data); + 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->x, dataitr->y, dataitr->z); + HandleRedstoneButton(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; } case E_BLOCK_ACTIVE_COMPARATOR: case E_BLOCK_INACTIVE_COMPARATOR: { - HandleRedstoneComparator(dataitr->x, dataitr->y, dataitr->z); + HandleRedstoneComparator(dataitr->first.x, dataitr->first.y, dataitr->first.z); break; } default: break; @@ -872,32 +842,29 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays() { for (auto itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end();) { - if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks? + if (itr->second.a_ElapsedTicks >= itr->second.a_DelayTicks) // Has the elapsed ticks reached the target ticks? { - int RelBlockX = itr->a_RelBlockPos.x; - int RelBlockY = itr->a_RelBlockPos.y; - int RelBlockZ = itr->a_RelBlockPos.z; BLOCKTYPE Block; NIBBLETYPE Meta; - m_Chunk->GetBlockTypeMeta(RelBlockX, RelBlockY, RelBlockZ, Block, Meta); - if (itr->ShouldPowerOn) + 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->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta); + m_Chunk->SetBlock(itr->first, E_BLOCK_REDSTONE_REPEATER_ON, Meta); } } else if (Block != E_BLOCK_REDSTONE_REPEATER_OFF) { - m_Chunk->SetBlock(RelBlockX, RelBlockY, RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, Meta); + 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->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks); - itr->a_ElapsedTicks++; - itr++; + 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; } } } @@ -1871,9 +1838,9 @@ bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_RelBlockX, int a_Re { for (const auto & itr : *m_SimulatedPlayerToggleableBlocks) { - if (itr.a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) + if (itr.first.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { - if (itr.WasLastStatePowered != IsCurrentStatePowered) // Was the last power state different to the current? + if (itr.second != IsCurrentStatePowered) // Was the last power state different to the current? { return false; // It was, coordinates are no longer simulated } @@ -2116,60 +2083,37 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool a_WasLastStatePowered) { - for (auto & itr : *m_SimulatedPlayerToggleableBlocks) - { - if (!itr.a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - continue; - } - - // Update listing - itr.WasLastStatePowered = a_WasLastStatePowered; - return; - } - - // We have arrived here; no block must be in list - add one - sSimulatedPlayerToggleableList RC; - RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - RC.WasLastStatePowered = a_WasLastStatePowered; - m_SimulatedPlayerToggleableBlocks->emplace_back(RC); + m_SimulatedPlayerToggleableBlocks->operator[](Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) = a_WasLastStatePowered; } -bool cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn) +void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool a_ShouldPowerOn) { - for (auto itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr) - { - if (itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) - { - if (ShouldPowerOn == itr->ShouldPowerOn) // We are queued already for the same thing, don't replace entry - { - return false; - } - - // Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit - itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; // See below for description - itr->a_ElapsedTicks = 0; - itr->ShouldPowerOn = ShouldPowerOn; - return false; - } - } - - // Self not in list, add self to list sRepeatersDelayList RC; - RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); // 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 = ShouldPowerOn; - m_RepeatersDelayList->emplace_back(RC); - return true; + 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; + } } diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index 934a0eab9..c4be70e97 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -3,7 +3,7 @@ #include "RedstoneSimulator.h" #include "BlockEntities/RedstonePoweredEntity.h" -#include +#include class cWorld; class cChunk; @@ -38,15 +38,6 @@ public: 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; - enum eRedstoneWireDirectionBitfieldPositions - { - eWbpXP = 0, - eWbpXN = 1, - eWbpZP = 2, - eWbpZN = 3, - }; - std::bitset<4> GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ); - private: #define MAX_POWER_LEVEL 15 @@ -66,15 +57,8 @@ private: unsigned char a_PowerLevel; }; - struct sSimulatedPlayerToggleableList // Define structure of the list containing simulate-on-update blocks (such as trapdoors that respond once to a block update, and can be toggled by a player) - { - Vector3i a_RelBlockPos; - bool WasLastStatePowered; // Was the last state powered or not? Determines whether a source update has happened and if I should resimulate - }; - struct sRepeatersDelayList // Define structure of list containing repeaters' delay states { - Vector3i a_RelBlockPos; 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? @@ -85,20 +69,19 @@ private: { public: /// Per-chunk data for the simulator, specified individual chunks to simulate - cCoordWithBlockAndBoolVector m_ChunkData; - cCoordWithBlockAndBoolVector m_QueuedChunkData; + std::unordered_map, Vector3i> m_ChunkData; std::vector m_PoweredBlocks; std::vector m_LinkedBlocks; - std::vector m_SimulatedPlayerToggleableBlocks; - std::vector m_RepeatersDelayList; + std::unordered_map m_SimulatedPlayerToggleableBlocks; + std::unordered_map m_RepeatersDelayList; }; public: typedef std::vector PoweredBlocksList; typedef std::vector LinkedBlocksList; - typedef std::vector SimulatedPlayerToggleableList; - typedef std::vector RepeatersDelayList; + typedef std::unordered_map SimulatedPlayerToggleableList; + typedef std::unordered_map RepeatersDelayList; private: @@ -211,7 +194,7 @@ private: 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 */ - bool QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); + 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 diff --git a/src/Vector3.h b/src/Vector3.h index 346bc1bbb..279fe5cd7 100644 --- a/src/Vector3.h +++ b/src/Vector3.h @@ -235,6 +235,12 @@ public: return *this; } + /** Provides a hash of a vector's contents */ + size_t operator()(const Vector3 & a_Vector) const + { + return ((std::hash()(a_Vector.x) ^ (std::hash()(a_Vector.y) << 1)) ^ std::hash()(a_Vector.z)); + } + // tolua_begin inline Vector3 operator + (const Vector3& a_Rhs) const -- cgit v1.2.3 From a6983ec3c9cfef029c5f86f06b7737f2bce45203 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 3 Jun 2015 21:42:09 +0100 Subject: Improved link unpowering speed Also fixed compile errors --- src/Simulator/IncrementalRedstoneSimulator.cpp | 89 ++++++++++++-------------- 1 file changed, 41 insertions(+), 48 deletions(-) diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index f60106fac..dd4386814 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -2128,47 +2128,47 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R } std::vector> BlocksPotentiallyUnpowered = { std::make_pair(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ), a_Chunk) }; - auto UnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_Chunk, const Vector3i & a_RelSource) + auto UnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_LambdaChunk, const Vector3i & a_RelSource) { BLOCKTYPE RepeaterType; - if (a_Chunk->UnboundedRelGetBlockType(a_RelSource.x, a_RelSource.y, a_RelSource.z, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) + 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_Chunk->GetRedstoneSimulatorData()); - Data->m_PoweredBlocks.erase(std::remove_if(Data->m_PoweredBlocks.begin(), Data->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSource](const sPoweredBlocks & itr) + 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.a_SourcePos != a_RelSource) { return false; } - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_Chunk)); - a_Chunk->SetIsRedstoneDirty(true); + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_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_Chunk, a_RelSource](const sLinkedPoweredBlocks & itr) + 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_Chunk)); - a_Chunk->SetIsRedstoneDirty(true); + 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_Chunk)) + for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_LambdaChunk)) { auto BoundaryData = static_cast(BoundaryChunk->GetRedstoneSimulatorData()); Vector3i ChunkAdjustedSource = a_RelSource; - ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; - ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; + 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.a_SourcePos == ChunkAdjustedSource); }) != BoundaryData->m_PoweredBlocks.end()) || @@ -2197,45 +2197,38 @@ void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int std::vector> BlocksPotentiallyUnpowered; auto Data = static_cast(a_Chunk->GetRedstoneSimulatorData()); - Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ](const sLinkedPoweredBlocks & itr) - { - if (!itr.a_MiddlePos.Equals(Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ))) - { - return false; - } + BLOCKTYPE RepeaterType; + if (a_Chunk->UnboundedRelGetBlockType(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) + { + return; + } - for (const auto & BoundaryChunk : GetAdjacentChunks(Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ), a_Chunk)) + 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) { - 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; + if (itr.a_MiddlePos != a_RelMiddle) + { + return false; + } - auto BoundaryData = static_cast(BoundaryChunk->GetRedstoneSimulatorData()); - BoundaryData->m_LinkedBlocks.erase(std::remove_if(BoundaryData->m_LinkedBlocks.begin(), BoundaryData->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, BoundaryChunk, ChunkAdjustedMiddlePos](const sLinkedPoweredBlocks & itr) - { - if (itr.a_MiddlePos != ChunkAdjustedMiddlePos) - { - return false; - } - - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, BoundaryChunk)); - BoundaryChunk->SetIsRedstoneDirty(true); - return true; - } - ), BoundaryData->m_LinkedBlocks.end()); + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_LambdaChunk)); + a_LambdaChunk->SetIsRedstoneDirty(true); + return true; } + ), Data->m_LinkedBlocks.end()); + }; - BLOCKTYPE RepeaterType; - if (a_Chunk->UnboundedRelGetBlockType(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) - { - return false; - } + 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; - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_Chunk)); - a_Chunk->SetIsRedstoneDirty(true); - return true; - } - ), Data->m_LinkedBlocks.end()); + MiddleBlockUnpoweringFunction(a_Chunk, Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)); + } for (const auto & itr : BlocksPotentiallyUnpowered) { @@ -2265,11 +2258,11 @@ std::vector cIncrementalRedstoneSimulator::GetAdjacentChunks(const Vec std::vector AdjacentChunks; AdjacentChunks.reserve(2); // At most bordering two chunks; reserve that many - auto CheckAndEmplace = [&AdjacentChunks](cChunk * a_Chunk) + auto CheckAndEmplace = [&AdjacentChunks](cChunk * a_LambdaChunk) { - if ((a_Chunk != nullptr) && a_Chunk->IsValid()) + if ((a_LambdaChunk != nullptr) && a_LambdaChunk->IsValid()) { - AdjacentChunks.emplace_back(a_Chunk); + AdjacentChunks.emplace_back(a_LambdaChunk); } }; -- cgit v1.2.3 From ed6c37febc3e5f6bd491317946aae11db73c2d04 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 6 Jun 2015 12:30:08 +0100 Subject: Use emplace to construct structures --- src/Simulator/IncrementalRedstoneSimulator.cpp | 87 ++++++++++++-------------- src/Simulator/IncrementalRedstoneSimulator.h | 28 +++++++-- 2 files changed, 61 insertions(+), 54 deletions(-) diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index dd4386814..75fb314dc 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -518,7 +518,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re { auto Current = PotentialWireList.back(); PotentialWireList.pop_back(); - FindAndPowerBorderingWires(PotentialWireList, Current); + FindAndPowerBorderingWires(PotentialWireList, Current.first, Current.second); } } else if (MyPower == 1) @@ -589,7 +589,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re -void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const std::pair & a_Entry) +void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const Vector3i & a_EntryRelBlockPosition, cChunk * a_EntryChunk) { static const Vector3i LevelOffsets[] = // Wires on same level { @@ -615,9 +615,9 @@ void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vectorGetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); - auto MyPower = IsWirePowered(a_Entry.first, a_Entry.second); + 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()) { @@ -626,15 +626,15 @@ void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vectorGetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) { - PowerBorderingWires(a_PotentialWireList, a_Entry, AdjustedPos, Neighbour, MyPower); + PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, MyPower); } } for (auto Offset : HigherOffsets) { - auto AdjustedPos = a_Entry.first + Offset; - auto Neighbour = a_Entry.second->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); - auto MyPower = IsWirePowered(a_Entry.first, a_Entry.second); + 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()) { @@ -643,18 +643,18 @@ void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vectorGetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && - (!cBlockInfo::FullyOccupiesVoxel(a_Entry.second->GetBlock(a_Entry.first.x, a_Entry.first.y + 1, a_Entry.first.z))) && + (!cBlockInfo::FullyOccupiesVoxel(a_EntryChunk->GetBlock(a_EntryRelBlockPosition.x, a_EntryRelBlockPosition.y + 1, a_EntryRelBlockPosition.z))) && (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) { - PowerBorderingWires(a_PotentialWireList, a_Entry, AdjustedPos, Neighbour, MyPower); + PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, MyPower); } } for (auto Offset : LowerOffsets) { - auto AdjustedPos = a_Entry.first + Offset; - auto Neighbour = a_Entry.second->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z); - auto MyPower = IsWirePowered(a_Entry.first, a_Entry.second); + 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()) { @@ -666,7 +666,7 @@ void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vectorGetBlock(AdjustedPos.x, AdjustedPos.y + 1, AdjustedPos.z))) && (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour))) { - PowerBorderingWires(a_PotentialWireList, a_Entry, AdjustedPos, Neighbour, MyPower); + PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, MyPower); } } } @@ -675,29 +675,25 @@ void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const std::pair & a_Entry, const Vector3i & a_AdjustedPos, cChunk * a_NeighbourChunk, unsigned char a_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) { - sPoweredBlocks RC; - RC.a_BlockPos = a_AdjustedPos; - RC.a_SourcePos = a_Entry.first + Vector3i((a_Entry.second->GetPosX() - a_NeighbourChunk->GetPosX()) * cChunkDef::Width, 0, (a_Entry.second->GetPosZ() - a_NeighbourChunk->GetPosZ()) * cChunkDef::Width); - RC.a_PowerLevel = a_MyPower - 1; - + 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(), [RC](const sPoweredBlocks & itr) { return ((itr.a_BlockPos == RC.a_BlockPos) && (itr.a_SourcePos == RC.a_SourcePos)); }); + 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->a_PowerLevel = RC.a_PowerLevel; + Position->m_PowerLevel = a_MyPower - 1; } else { - PoweredBlocks.emplace_back(RC); + PoweredBlocks.emplace_back(a_AdjustedPos, SourcePos, a_MyPower - 1); a_NeighbourChunk->SetIsRedstoneDirty(true); m_Chunk->SetIsRedstoneDirty(true); } - a_NeighbourChunk->SetMeta(RC.a_BlockPos.x, RC.a_BlockPos.y, RC.a_BlockPos.z, RC.a_PowerLevel); - a_PotentialWireList.emplace_back(std::make_pair(RC.a_BlockPos, a_NeighbourChunk)); + 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)); } @@ -1562,7 +1558,7 @@ bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, in // 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.a_BlockPos == Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }) != Data.end(); + 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(); } @@ -1585,7 +1581,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel for (const auto & itr : *m_PoweredBlocks) { - if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) + if (!itr.m_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; } @@ -1595,7 +1591,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel case 0x0: { // Flip the coords to check the back of the repeater - if (itr.a_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1))) + if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1))) { return true; } @@ -1603,7 +1599,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel } case 0x1: { - if (itr.a_SourcePos.Equals(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ))) + if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ))) { return true; } @@ -1611,7 +1607,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel } case 0x2: { - if (itr.a_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1))) + if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1))) { return true; } @@ -1619,7 +1615,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel } case 0x3: { - if (itr.a_SourcePos.Equals(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ))) + if (itr.m_SourcePos.Equals(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ))) { return true; } @@ -1764,7 +1760,7 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBl for (const auto & itr : *m_PoweredBlocks) { - if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) + if (!itr.m_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; } @@ -1772,7 +1768,7 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBl int X = a_RelBlockX, Z = a_RelBlockZ; AddFaceDirection(X, a_RelBlockY, Z, Face); - if (!itr.a_SourcePos.Equals(AdjustRelativeCoords(Vector3i(X, a_RelBlockY, Z)))) + if (!itr.m_SourcePos.Equals(AdjustRelativeCoords(Vector3i(X, a_RelBlockY, Z)))) { return true; } @@ -1805,11 +1801,11 @@ unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPo for (const auto & itr : static_cast(a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks) // Check powered list { - if (itr.a_BlockPos != a_RelBlockPosition) + if (itr.m_BlockPos != a_RelBlockPosition) { continue; } - PowerLevel = std::max(itr.a_PowerLevel, PowerLevel); // Get the highest power level (a_PowerLevel is initialised already and there CAN be multiple levels for one block) + 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 @@ -1999,24 +1995,20 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(Vector3i a_RelBlockPosition, 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.a_BlockPos == a_RelBlockPosition) && (itr.a_SourcePos == a_RelSourcePosition)) + if ((itr.m_BlockPos == a_RelBlockPosition) && (itr.m_SourcePos == a_RelSourcePosition)) { - if (itr.a_PowerLevel != a_PowerLevel) + if (itr.m_PowerLevel != a_PowerLevel) { // Update power level, don't add a new listing Neighbour->SetIsRedstoneDirty(true); m_Chunk->SetIsRedstoneDirty(true); - itr.a_PowerLevel = a_PowerLevel; + itr.m_PowerLevel = a_PowerLevel; } return; } } - sPoweredBlocks RC; - RC.a_BlockPos = a_RelBlockPosition; - RC.a_SourcePos = a_RelSourcePosition; - RC.a_PowerLevel = a_PowerLevel; - Powered.emplace_back(RC); + Powered.emplace_back(a_RelBlockPosition, a_RelSourcePosition, a_PowerLevel); Neighbour->SetIsRedstoneDirty(true); m_Chunk->SetIsRedstoneDirty(true); } @@ -2139,12 +2131,12 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R 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.a_SourcePos != a_RelSource) + if (itr.m_SourcePos != a_RelSource) { return false; } - BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_LambdaChunk)); + BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.m_BlockPos, a_LambdaChunk)); a_LambdaChunk->SetIsRedstoneDirty(true); return true; } @@ -2171,7 +2163,7 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R 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.a_SourcePos == ChunkAdjustedSource); }) != BoundaryData->m_PoweredBlocks.end()) || + (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()) ) { @@ -2195,7 +2187,6 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk) { std::vector> BlocksPotentiallyUnpowered; - auto Data = static_cast(a_Chunk->GetRedstoneSimulatorData()); BLOCKTYPE RepeaterType; if (a_Chunk->UnboundedRelGetBlockType(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)) diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index c4be70e97..b0d3ad7af 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -44,9 +44,16 @@ private: struct sPoweredBlocks // Define structure of the directly powered blocks list { - Vector3i a_BlockPos; // Position of powered block - Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos - unsigned char a_PowerLevel; + 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) @@ -177,9 +184,14 @@ private: 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 std::pair & a_Entry); + void FindAndPowerBorderingWires(std::vector> & a_PotentialWireList, const Vector3i & a_EntryRelBlockPosition, cChunk * a_EntryChunk); - void PowerBorderingWires(std::vector> & a_PotentialWireList, const std::pair & a_Entry, const Vector3i & a_AdjustedPos, cChunk * a_NeighbourChunk, unsigned char a_MyPower); + /** 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); @@ -397,7 +409,11 @@ private: inline static Vector3i AdjustRelativeCoords(const Vector3i & a_RelPosition) { - return Vector3i((a_RelPosition.x % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width, a_RelPosition.y, (a_RelPosition.z % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width); + return { + (a_RelPosition.x % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width, + a_RelPosition.y, + (a_RelPosition.z % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width + }; } }; -- cgit v1.2.3 From f44d123ba8ca14c3df90afff85a0674a4463cfa2 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 7 Jun 2015 11:52:14 +0100 Subject: Vector hasher is now a separate class --- src/Mobs/Path.h | 2 +- src/Simulator/IncrementalRedstoneSimulator.h | 12 +++++++----- src/Vector3.h | 28 ++++++++++++++++++++++------ 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h index 491165795..d4ad066e3 100644 --- a/src/Mobs/Path.h +++ b/src/Mobs/Path.h @@ -145,7 +145,7 @@ private: /* Pathfinding fields */ std::priority_queue, compareHeuristics> m_OpenList; - std::unordered_map m_Map; + std::unordered_map> m_Map; Vector3i m_Destination; Vector3i m_Source; int m_BoundingBoxWidth; diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index b0d3ad7af..9fbefae73 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -76,19 +76,21 @@ private: { public: /// Per-chunk data for the simulator, specified individual chunks to simulate - std::unordered_map, Vector3i> m_ChunkData; + + /** 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; + 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; + typedef std::unordered_map> SimulatedPlayerToggleableList; + typedef std::unordered_map> RepeatersDelayList; private: diff --git a/src/Vector3.h b/src/Vector3.h index 279fe5cd7..168071469 100644 --- a/src/Vector3.h +++ b/src/Vector3.h @@ -235,12 +235,6 @@ public: return *this; } - /** Provides a hash of a vector's contents */ - size_t operator()(const Vector3 & a_Vector) const - { - return ((std::hash()(a_Vector.x) ^ (std::hash()(a_Vector.y) << 1)) ^ std::hash()(a_Vector.z)); - } - // tolua_begin inline Vector3 operator + (const Vector3& a_Rhs) const @@ -390,6 +384,28 @@ template <> inline Vector3 Vector3::Floor(void) const +template +class VectorHasher +{ +public: + /** Provides a hash of a vector's contents */ + size_t operator()(const Vector3 & a_Vector) const + { + // Guaranteed to have no hash collisions for any 128x128x128 area + size_t Hash = 0; + Hash ^= static_cast(a_Vector.x); + Hash <<= 8; + Hash ^= static_cast(a_Vector.y); + Hash <<= 8; + Hash ^= static_cast(a_Vector.z); + return Hash; + } +}; + + + + + template const double Vector3::EPS = 0.000001; -- cgit v1.2.3 From 061866616d44c127871e95eb8dd6c713bcd3a2c8 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 7 Jun 2015 12:03:28 +0100 Subject: Added moar comments --- src/Simulator/IncrementalRedstoneSimulator.cpp | 20 ++++++++++++-------- src/Simulator/IncrementalRedstoneSimulator.h | 6 +----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 75fb314dc..7d9cc93b2 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -90,15 +90,16 @@ void cIncrementalRedstoneSimulator::AddBlock(const Vector3i & a_RelBlockPosition // 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 = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_SimulatedPlayerToggleableBlocks; + 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 + ); // This map won't insert if key already present, so no need to check } else { @@ -107,10 +108,10 @@ void cIncrementalRedstoneSimulator::AddBlock(const Vector3i & a_RelBlockPosition if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF)) { - static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_RepeatersDelayList.erase(a_RelBlockPosition); + RedstoneSimulatorData->m_RepeatersDelayList.erase(a_RelBlockPosition); } - auto & RedstoneSimulatorChunkData = static_cast(a_OriginalChunk->GetRedstoneSimulatorData())->m_ChunkData; + auto & RedstoneSimulatorChunkData = RedstoneSimulatorData->m_ChunkData; auto Iterator = RedstoneSimulatorChunkData.find(a_RelBlockPosition); if (!IsAllowedBlock(Block)) { @@ -124,7 +125,7 @@ void cIncrementalRedstoneSimulator::AddBlock(const Vector3i & a_RelBlockPosition { if (Iterator != RedstoneSimulatorChunkData.end()) { - Iterator->second.second = false; + Iterator->second.second = false; // De-schedule removal from list Iterator->second.first = Block; // Update block information return; } @@ -171,11 +172,12 @@ void cIncrementalRedstoneSimulator::SimulateChunk(std::chrono::milliseconds a_Dt { if (dataitr->second.second) { + // Removal was scheduled - do so dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.erase(dataitr); continue; } - switch (dataitr->second.first) + 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; @@ -737,11 +739,13 @@ void cIncrementalRedstoneSimulator::HandleRedstoneComparator(int a_RelBlockX, in 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 + { + // Subtraction mode Power = std::max(static_cast(RearPower - HighestSidePower), std::numeric_limits::min()); } else - { // Comparison mode + { + // Comparison mode Power = (std::max(HighestSidePower, RearPower) == HighestSidePower) ? 0 : RearPower; } diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index 9fbefae73..e4250c0b9 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -411,11 +411,7 @@ private: 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 - }; + return { (a_RelPosition.x % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width, a_RelPosition.y, (a_RelPosition.z % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width }; } }; -- cgit v1.2.3