summaryrefslogtreecommitdiffstats
path: root/src/Simulator/IncrementalRedstoneSimulator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Simulator/IncrementalRedstoneSimulator.cpp')
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp1070
1 files changed, 549 insertions, 521 deletions
diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp
index 7f320af0d..7d9cc93b2 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.cpp
+++ b/src/Simulator/IncrementalRedstoneSimulator.cpp
@@ -3,11 +3,10 @@
#include "BlockEntities/ChestEntity.h"
-typedef cItemCallback<cChestEntity> 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"
@@ -25,41 +24,42 @@ typedef cItemCallback<cChestEntity> cChestCallback;
-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
@@ -77,68 +77,61 @@ 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)
- {
- return itr.a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)) && !IsAllowedBlock(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)
- {
- return itr.a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)) && (Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF);
- }
- ), RepeatersDelayList.end());
-
- if (a_OtherChunk != nullptr)
+ if (a_NeighborChunk != nullptr)
{
// DO NOT touch our chunk's data structure if we are being called with coordinates from another chunk - this one caused me massive grief :P
return;
}
+ auto RedstoneSimulatorData = static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_OriginalChunk->GetRedstoneSimulatorData());
- cCoordWithBlockAndBoolVector & RedstoneSimulatorChunkData = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_ChunkData;
- for (auto & itr : RedstoneSimulatorChunkData)
+ auto & SimulatedPlayerToggleableBlocks = RedstoneSimulatorData->m_SimulatedPlayerToggleableBlocks;
+ if (DoesIgnorePlayerToggle(Block))
{
- if ((itr.x == RelX) && (itr.y == a_BlockY) && (itr.z == RelZ)) // 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;
- }
+ // Initialise the toggleable blocks list so that trapdoors etc. aren't reset on restart (#1887)
+ SimulatedPlayerToggleableBlocks.emplace(
+ a_RelBlockPosition,
+ AreCoordsDirectlyPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk) || AreCoordsLinkedPowered(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, a_OriginalChunk)
+ ); // This map won't insert if key already present, so no need to check
+ }
+ else
+ {
+ SimulatedPlayerToggleableBlocks.erase(a_RelBlockPosition);
}
+ if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF))
+ {
+ RedstoneSimulatorData->m_RepeatersDelayList.erase(a_RelBlockPosition);
+ }
+
+ auto & RedstoneSimulatorChunkData = RedstoneSimulatorData->m_ChunkData;
+ auto Iterator = RedstoneSimulatorChunkData.find(a_RelBlockPosition);
if (!IsAllowedBlock(Block))
{
+ if (Iterator != RedstoneSimulatorChunkData.end())
+ {
+ Iterator->second.second = true; // The new blocktype is not redstone; it must be queued to be removed from this list
+ }
return;
}
-
- cCoordWithBlockAndBoolVector & QueuedData = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData;
- for (const auto & itr : QueuedData)
+ else
{
- if ((itr.x == RelX) && (itr.y == a_BlockY) && (itr.z == RelZ))
+ 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; // De-schedule removal from list
+ Iterator->second.first = Block; // Update block information
return;
}
}
- QueuedData.emplace_back(cCoordWithBlockAndBool(RelX, a_BlockY, RelZ, Block, false));
+
+ RedstoneSimulatorChunkData.emplace(a_RelBlockPosition, std::make_pair(Block, false));
}
@@ -147,25 +140,17 @@ 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<cIncrementalRedstoneSimulatorChunkData *>(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())
{
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;
@@ -185,24 +170,25 @@ 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)
{
+ // Removal was scheduled - do so
dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.erase(dataitr);
continue;
}
- switch (dataitr->Data)
+ switch (dataitr->second.first) // Call the appropriate simulator for the entry's block type
{
- 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;
@@ -210,23 +196,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:
@@ -237,7 +223,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:
@@ -247,43 +233,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->first.x, dataitr->first.y, dataitr->first.z);
break;
}
default: break;
@@ -299,23 +291,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 (AreCoordsOnChunkBoundary(a_BlockX, a_BlockY, a_BlockZ))
- {
- // On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk)
- AddBlock(a_BlockX, a_BlockY, a_BlockZ, 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
- // 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);
-
- 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);
}
@@ -503,152 +486,278 @@ 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
- {
- int x, y, z;
- } gCrossCoords[] =
+ static const eBlockFace BlockFaceOffsets[] =
{
- { 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
+ static const Vector3i VectorOffsets[] =
{
- int x, y, z;
- } gSideCoords[] =
- {
- { 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;
- if (!IsWirePowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower))
+ unsigned char MyPower = IsWirePowered(RelBlock, m_Chunk);
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ if (MyPower == 0)
{
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0);
+ SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk);
return;
}
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
-
- if (MyPower < 1)
+ if (MyPower == MAX_POWER_LEVEL)
+ {
+ std::vector<std::pair<Vector3i, cChunk *>> PotentialWireList = { std::make_pair(RelBlock, m_Chunk) };
+ while (!PotentialWireList.empty())
+ {
+ auto Current = PotentialWireList.back();
+ PotentialWireList.pop_back();
+ FindAndPowerBorderingWires(PotentialWireList, Current.first, Current.second);
+ }
+ }
+ else if (MyPower == 1)
{
return;
}
+ // Wire still powered, power blocks beneath and in direction of facing
MyPower--;
- for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power
+ SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, MyPower);
+
+ int BorderingMechanismCount = 0;
+ bool RepeaterPresent = false;
+ Vector3i OffsetToPower;
+
+ for (const auto & Offset : VectorOffsets)
{
- if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above...
+ BLOCKTYPE Block;
+ Vector3i AdjustedOffset = RelBlock + Offset;
+ if (m_Chunk->UnboundedRelGetBlockType(AdjustedOffset.x, AdjustedOffset.y, AdjustedOffset.z, Block))
{
- BLOCKTYPE Type = 0;
- if (a_RelBlockY >= cChunkDef::Height - 1)
+ switch (Block)
{
- 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
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ {
+ BorderingMechanismCount++;
+ if (!RepeaterPresent)
+ {
+ // TODO: only if wire is actually connected to repeater (repeater facing right way)
+ RepeaterPresent = true;
+ OffsetToPower = { -Offset.x, Offset.y, -Offset.z }; // Negate to obtain offset in opposite direction since wire powers that way
+ }
+ SetBlockPowered(AdjustedOffset, RelBlock, MyPower);
+ }
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ case E_BLOCK_REDSTONE_WIRE:
+ {
+ BorderingMechanismCount++;
+ if (!RepeaterPresent)
+ {
+ OffsetToPower = { -Offset.x, Offset.y, -Offset.z };
+ }
+ }
+ default: break;
}
}
- else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us
+ }
+
+ if (BorderingMechanismCount == 0)
+ {
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ for (const auto & BlockFaceOffset : BlockFaceOffsets)
{
- 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))
- {
- continue;
- }
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BlockFaceOffset, MyPower);
}
+ }
+ else if (BorderingMechanismCount == 1)
+ {
+ eBlockFace Face = BlockFaceOffsets[std::distance(VectorOffsets, std::find(VectorOffsets, VectorOffsets + ARRAYCOUNT(VectorOffsets), OffsetToPower))];
+ SetBlockPowered(RelBlock + OffsetToPower, RelBlock, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Face, MyPower);
+ }
+}
- BLOCKTYPE Type = 0;
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type))
+
+
+
+
+void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vector<std::pair<Vector3i, cChunk *>> & a_PotentialWireList, const Vector3i & a_EntryRelBlockPosition, cChunk * a_EntryChunk)
+{
+ static const Vector3i LevelOffsets[] = // Wires on same level
+ {
+ { 1, 0, 0 },
+ { -1, 0, 0 },
+ { 0, 0, 1 },
+ { 0, 0, -1 },
+ };
+ static const Vector3i HigherOffsets[] = // Wires one higher, surrounding self
+ {
+ { 1, 1, 0 },
+ { -1, 1, 0 },
+ { 0, 1, 1 },
+ { 0, 1, -1 },
+ };
+ static const Vector3i LowerOffsets[] = // Wires one lower, surrounding self
+ {
+ { 1, -1, 0 },
+ { -1, -1, 0 },
+ { 0, -1, 1 },
+ { 0, -1, -1 },
+ };
+
+ for (auto Offset : LevelOffsets)
+ {
+ auto AdjustedPos = a_EntryRelBlockPosition + Offset;
+ auto Neighbour = a_EntryChunk->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z);
+ auto MyPower = IsWirePowered(a_EntryRelBlockPosition, a_EntryChunk);
+
+ if ((Neighbour == nullptr) || !Neighbour->IsValid())
{
- continue;
+ return;
}
- if (Type == E_BLOCK_REDSTONE_WIRE)
+
+ if ((Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour)))
{
- SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, MyPower);
}
}
- for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them
+ for (auto Offset : HigherOffsets)
{
- BLOCKTYPE Type = 0;
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, Type))
+ 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())
{
- continue;
+ return;
}
- if (Type == E_BLOCK_REDSTONE_REPEATER_OFF)
+
+ if (
+ (Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) &&
+ (!cBlockInfo::FullyOccupiesVoxel(a_EntryChunk->GetBlock(a_EntryRelBlockPosition.x, a_EntryRelBlockPosition.y + 1, a_EntryRelBlockPosition.z))) &&
+ (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour)))
{
- SetBlockPowered(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, 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))
+ for (auto Offset : LowerOffsets)
{
- 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);
+ auto AdjustedPos = a_EntryRelBlockPosition + Offset;
+ auto Neighbour = a_EntryChunk->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z);
+ auto MyPower = IsWirePowered(a_EntryRelBlockPosition, a_EntryChunk);
- 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:
+ if ((Neighbour == nullptr) || !Neighbour->IsValid())
{
- 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;
+ return;
}
- case REDSTONE_X_NEG:
+
+ 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)))
{
- 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;
+ PowerBorderingWires(a_PotentialWireList, a_EntryRelBlockPosition, a_EntryChunk, AdjustedPos, Neighbour, MyPower);
}
- case REDSTONE_Z_POS:
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::PowerBorderingWires(std::vector<std::pair<Vector3i, cChunk *>> & a_PotentialWireList, const Vector3i & a_EntryRelSourcePosition, cChunk * a_EntryChunk, const Vector3i & a_AdjustedPos, cChunk * a_NeighbourChunk, unsigned char a_MyPower)
+{
+ auto SourcePos = a_EntryRelSourcePosition + Vector3i((a_EntryChunk->GetPosX() - a_NeighbourChunk->GetPosX()) * cChunkDef::Width, 0, (a_EntryChunk->GetPosZ() - a_NeighbourChunk->GetPosZ()) * cChunkDef::Width);
+ auto & PoweredBlocks = static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_NeighbourChunk->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position
+ auto Position = std::find_if(PoweredBlocks.begin(), PoweredBlocks.end(), [a_AdjustedPos, SourcePos, a_MyPower](const sPoweredBlocks & itr) { return ((itr.m_BlockPos == a_AdjustedPos) && (itr.m_SourcePos == SourcePos)); });
+ if (Position != PoweredBlocks.end())
+ {
+ Position->m_PowerLevel = a_MyPower - 1;
+ }
+ else
+ {
+ PoweredBlocks.emplace_back(a_AdjustedPos, SourcePos, a_MyPower - 1);
+
+ a_NeighbourChunk->SetIsRedstoneDirty(true);
+ m_Chunk->SetIsRedstoneDirty(true);
+ }
+
+ a_NeighbourChunk->SetMeta(a_AdjustedPos.x, a_AdjustedPos.y, a_AdjustedPos.z, a_MyPower - 1);
+ a_PotentialWireList.emplace_back(std::make_pair(a_AdjustedPos, a_NeighbourChunk));
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneComparator(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ auto Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ auto HighestSidePower = std::max(IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetSideCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3, false)), m_Chunk), IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetSideCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3, true)), m_Chunk));
+ auto FrontCoordinate = AdjustRelativeCoords(cBlockComparatorHandler::GetFrontCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3));
+ unsigned char Power = 0;
+
+ class cContainerCallback : public cBlockEntityCallback
+ {
+ public:
+ cContainerCallback() : m_SignalStrength(0)
{
- 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:
+
+ virtual bool Item(cBlockEntity * a_BlockEntity) override
{
- 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;
+ auto & Contents = static_cast<cBlockEntityWithItems *>(a_BlockEntity)->GetContents();
+ float Fullness = 0; // Is a floating-point type to allow later calculation to produce a non-truncated value
+ for (int Slot = 0; Slot != Contents.GetNumSlots(); ++Slot)
+ {
+ Fullness += Contents.GetSlot(Slot).m_ItemCount / Contents.GetSlot(Slot).GetMaxStackSize();
+ }
+
+ m_SignalStrength = static_cast<unsigned char>(1 + (Fullness / Contents.GetNumSlots()) * 14);
+ return false;
}
+
+ unsigned char m_SignalStrength;
+ } CCB;
+
+ auto AbsoluteComparatorCoords = cChunkDef::RelativeToAbsolute(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), m_Chunk->GetPosX(), m_Chunk->GetPosZ());
+ auto AbsoluteRearCoords = cBlockComparatorHandler::GetRearCoordinate(AbsoluteComparatorCoords.x, AbsoluteComparatorCoords.y, AbsoluteComparatorCoords.z, Meta & 0x3);
+
+ m_Chunk->DoWithBlockEntityAt(AbsoluteRearCoords.x, AbsoluteRearCoords.y, AbsoluteRearCoords.z, CCB);
+ auto RearPower = std::max(CCB.m_SignalStrength, IsWirePowered(AdjustRelativeCoords(cBlockComparatorHandler::GetRearCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3)), m_Chunk));
+
+ if ((Meta & 0x4) == 0x4)
+ {
+ // Subtraction mode
+ Power = std::max(static_cast<unsigned char>(RearPower - HighestSidePower), std::numeric_limits<unsigned char>::min());
+ }
+ else
+ {
+ // Comparison mode
+ Power = (std::max(HighestSidePower, RearPower) == HighestSidePower) ? 0 : RearPower;
+ }
+
+ if (Power > 0)
+ {
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0x8);
+ SetBlockPowered(FrontCoordinate, Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), Power);
+ }
+ else
+ {
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7);
+ SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk);
}
}
@@ -680,19 +789,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;
+ }
}
}
}
@@ -702,60 +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);
- }
-
- 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;
- }
+ 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;
}
}
}
@@ -1017,19 +1126,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);
}
}
}
@@ -1452,30 +1561,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<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks;
+ return std::find_if(Data.begin(), Data.end(), [a_RelBlockX, a_RelBlockY, a_RelBlockZ](const sPoweredBlocks & itr) { return itr.m_BlockPos == Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }) != Data.end();
}
-bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+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<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks;
+ return std::find_if(Data.begin(), Data.end(), [a_RelBlockX, a_RelBlockY, a_RelBlockZ](const sLinkedPoweredBlocks & itr) { return itr.a_BlockPos == Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }) != Data.end();
}
@@ -1488,7 +1585,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;
}
@@ -1498,7 +1595,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.m_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1)))
{
return true;
}
@@ -1506,7 +1603,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.m_SourcePos.Equals(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ)))
{
return true;
}
@@ -1514,7 +1611,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.m_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1)))
{
return true;
}
@@ -1522,7 +1619,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.m_SourcePos.Equals(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ)))
{
return true;
}
@@ -1542,7 +1639,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;
}
@@ -1550,7 +1647,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;
}
@@ -1558,7 +1655,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;
}
@@ -1566,7 +1663,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;
}
@@ -1667,7 +1764,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;
}
@@ -1675,7 +1772,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;
}
@@ -1702,35 +1799,35 @@ 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, cChunk * a_Chunk)
{
- a_PowerLevel = 0;
+ unsigned char PowerLevel = 0;
- for (const auto & itr : *m_PoweredBlocks) // Check powered list
+ for (const auto & itr : static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks) // Check powered list
{
- if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
+ if (itr.m_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.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 : *m_LinkedPoweredBlocks) // Check linked powered list
+ for (const auto & itr : static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks) // Check linked powered list
{
- if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
+ if (itr.a_BlockPos != a_RelBlockPosition)
{
continue;
}
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;
}
- 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;
}
@@ -1741,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
}
@@ -1869,22 +1966,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
- {
- int x, y, z;
- } gCrossCoords[] =
- {
- { 1, 0, 0 },
- { -1, 0, 0 },
- { 0, 0, 1 },
- { 0, 0, -1 },
- { 0, 1, 0 },
- { 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(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) + Offset, Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), a_PowerLevel);
}
}
@@ -1892,62 +1986,33 @@ 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)
+ auto & Powered = static_cast<cIncrementalRedstoneSimulatorChunkData *>(Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position
+ for (auto & itr : Powered)
{
- if (
- itr->a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) &&
- itr->a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ))
- )
+ if ((itr.m_BlockPos == a_RelBlockPosition) && (itr.m_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.m_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.m_PowerLevel = a_PowerLevel;
}
+ 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_PowerLevel = a_PowerLevel;
- Powered.emplace_back(RC);
+ Powered.emplace_back(a_RelBlockPosition, a_RelSourcePosition, a_PowerLevel);
Neighbour->SetIsRedstoneDirty(true);
m_Chunk->SetIsRedstoneDirty(true);
}
@@ -1969,13 +2034,16 @@ 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 = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_LinkedBlocks;
+ auto & Linked = static_cast<cIncrementalRedstoneSimulatorChunkData *>(Neighbour->GetRedstoneSimulatorData())->m_LinkedBlocks;
for (auto & itr : Linked) // Check linked powered list
{
if (
@@ -1984,8 +2052,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;
}
}
@@ -2004,130 +2077,110 @@ 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)
- {
- if (!itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
- {
- continue;
- }
-
- if (itr->WasLastStatePowered != WasLastStatePowered)
- {
- // If power states different, update listing
- itr->WasLastStatePowered = WasLastStatePowered;
- return;
- }
- else
- {
- // If states the same, just ignore
- return;
- }
- }
-
- // We have arrive here; no block must be in list - add one
- sSimulatedPlayerToggleableList RC;
- RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- RC.WasLastStatePowered = 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;
+ }
}
-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
+ if ((a_Chunk == nullptr) || !a_Chunk->IsValid())
+ {
+ return;
+ }
+ std::vector<std::pair<Vector3i, cChunk *>> BlocksPotentiallyUnpowered = { std::make_pair(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ), a_Chunk) };
+
+ auto UnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_LambdaChunk, const Vector3i & a_RelSource)
{
- if ((a_Chunk == nullptr) || !a_Chunk->IsValid())
+ BLOCKTYPE RepeaterType;
+ if (a_LambdaChunk->UnboundedRelGetBlockType(a_RelSource.x, a_RelSource.y, a_RelSource.z, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON))
{
return;
}
- }
- std::vector<Vector3i> BlocksPotentiallyUnpowered;
+ auto Data = static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_LambdaChunk->GetRedstoneSimulatorData());
+ Data->m_PoweredBlocks.erase(std::remove_if(Data->m_PoweredBlocks.begin(), Data->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, a_LambdaChunk, a_RelSource](const sPoweredBlocks & itr)
+ {
+ if (itr.m_SourcePos != a_RelSource)
+ {
+ return false;
+ }
- 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(std::make_pair(itr.m_BlockPos, a_LambdaChunk));
+ a_LambdaChunk->SetIsRedstoneDirty(true);
+ return true;
+ }
+ ), Data->m_PoweredBlocks.end());
+
+ Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_LambdaChunk, a_RelSource](const sLinkedPoweredBlocks & itr)
{
- BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos);
- a_Chunk->SetIsRedstoneDirty(true);
+ if (itr.a_SourcePos != a_RelSource)
+ {
+ return false;
+ }
+
+ BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_LambdaChunk));
+ a_LambdaChunk->SetIsRedstoneDirty(true);
return true;
}
- return false;
- }
- ), Data->m_PoweredBlocks.end());
+ ), Data->m_LinkedBlocks.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)
+ for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_LambdaChunk))
{
- if (itr.a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ)))
+ auto BoundaryData = static_cast<cIncrementalRedstoneSimulatorChunkData *>(BoundaryChunk->GetRedstoneSimulatorData());
+ Vector3i ChunkAdjustedSource = a_RelSource;
+ ChunkAdjustedSource.x += (a_LambdaChunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width;
+ ChunkAdjustedSource.z += (a_LambdaChunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width;
+
+ if (
+ (std::find_if(BoundaryData->m_PoweredBlocks.begin(), BoundaryData->m_PoweredBlocks.end(), [ChunkAdjustedSource](const sPoweredBlocks & itr) { return (itr.m_SourcePos == ChunkAdjustedSource); }) != BoundaryData->m_PoweredBlocks.end()) ||
+ (std::find_if(BoundaryData->m_LinkedBlocks.begin(), BoundaryData->m_LinkedBlocks.end(), [ChunkAdjustedSource](const sLinkedPoweredBlocks & itr) { return (itr.a_SourcePos == ChunkAdjustedSource); }) != BoundaryData->m_LinkedBlocks.end())
+ )
{
- BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos);
- a_Chunk->SetIsRedstoneDirty(true);
- return true;
+ BlocksPotentiallyUnpowered.emplace_back(std::make_pair(ChunkAdjustedSource, BoundaryChunk));
}
- 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);
- }
+ };
- for (const auto & itr : BlocksPotentiallyUnpowered)
+ while (!BlocksPotentiallyUnpowered.empty())
{
- 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))
- {
- // 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);
}
}
@@ -2135,45 +2188,48 @@ 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
+ std::vector<std::pair<Vector3i, cChunk *>> BlocksPotentiallyUnpowered;
+
+ BLOCKTYPE RepeaterType;
+ if (a_Chunk->UnboundedRelGetBlockType(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, RepeaterType) && (RepeaterType == E_BLOCK_REDSTONE_REPEATER_ON))
{
- if ((a_Chunk == nullptr) || !a_Chunk->IsValid())
- {
- return;
- }
+ return;
}
- std::vector<Vector3i> BlocksPotentiallyUnpowered;
- auto Data = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)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)))
+ auto MiddleBlockUnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_LambdaChunk, const Vector3i & a_RelMiddle)
+ {
+ auto Data = static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_LambdaChunk->GetRedstoneSimulatorData());
+ Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_LambdaChunk, a_RelMiddle](const sLinkedPoweredBlocks & itr)
{
- BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos);
- a_Chunk->SetIsRedstoneDirty(true);
+ if (itr.a_MiddlePos != a_RelMiddle)
+ {
+ return false;
+ }
+
+ BlocksPotentiallyUnpowered.emplace_back(std::make_pair(itr.a_BlockPos, a_LambdaChunk));
+ a_LambdaChunk->SetIsRedstoneDirty(true);
return true;
}
- return false;
- }
- ), Data->m_LinkedBlocks.end());
+ ), Data->m_LinkedBlocks.end());
+ };
- if (a_IsFirstCall && AreCoordsOnChunkBoundary(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ))
+ MiddleBlockUnpoweringFunction(a_Chunk, Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ));
+ for (const auto & BoundaryChunk : GetAdjacentChunks(Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ), a_Chunk))
{
- // +- 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);
+ Vector3i ChunkAdjustedMiddlePos = Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ);
+ ChunkAdjustedMiddlePos.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width;
+ ChunkAdjustedMiddlePos.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width;
+
+ MiddleBlockUnpoweringFunction(a_Chunk, Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ));
}
for (const auto & itr : BlocksPotentiallyUnpowered)
{
- if (!AreCoordsPowered(itr.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);
}
}
}
@@ -2182,76 +2238,48 @@ 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)
{
- int Dir = REDSTONE_NONE;
+ // Extract the ON bit from metadata and return if true if it is set:
+ return ((a_BlockMeta & 0x8) == 0x8);
+}
+
+
+
+
+
+std::vector<cChunk *> cIncrementalRedstoneSimulator::GetAdjacentChunks(const Vector3i & a_RelBlockPosition, cChunk * a_Chunk)
+{
+ std::vector<cChunk *> AdjacentChunks;
+ AdjacentChunks.reserve(2); // At most bordering two chunks; reserve that many
- BLOCKTYPE NegX = 0;
- if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, NegX))
+ auto CheckAndEmplace = [&AdjacentChunks](cChunk * a_LambdaChunk)
{
- if (IsPotentialSource(NegX))
+ if ((a_LambdaChunk != nullptr) && a_LambdaChunk->IsValid())
{
- Dir |= (REDSTONE_X_POS);
+ AdjacentChunks.emplace_back(a_LambdaChunk);
}
- }
+ };
- BLOCKTYPE PosX = 0;
- if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, PosX))
+ // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks
+ if (a_RelBlockPosition.x <= 1)
{
- if (IsPotentialSource(PosX))
- {
- Dir |= (REDSTONE_X_NEG);
- }
+ CheckAndEmplace(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.x >= 14)
{
- 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;
- }
+ CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x + 2, a_RelBlockPosition.z));
}
-
- BLOCKTYPE PosZ = 0;
- if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, PosZ))
+ if (a_RelBlockPosition.z <= 1)
{
- 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;
- }
+ CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z - 2));
+ }
+ if (a_RelBlockPosition.z >= 14)
+ {
+ CheckAndEmplace(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z + 2));
}
- return (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;
}