1
0

Redstone wire and trapdoor fixes

* Fixes #1887
* Fixes #1763
* Fixes #1083
This commit is contained in:
Tiger Wang 2015-04-26 00:38:41 +01:00
parent bd48475085
commit 84534dfeb2
4 changed files with 345 additions and 333 deletions

View File

@ -96,6 +96,19 @@ public:
a_Z = a_Z - a_ChunkZ * Width; 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 */ /** 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) inline static Vector3i RelativeToAbsolute(const Vector3i & a_RelBlockPosition, int a_ChunkX, int a_ChunkZ)
{ {

View File

@ -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; return;
} }
else if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) else if ((a_RelBlockPosition.y < 0) || (a_RelBlockPosition.y >= cChunkDef::Height))
{ {
return; return;
} }
// We may be called with coordinates in a chunk that is not the first chunk parameter // The relative block position is relative to the neighboring chunk should it be passed as an argument
// 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
int RelX = 0;
int RelZ = 0;
BLOCKTYPE Block; BLOCKTYPE Block;
NIBBLETYPE Meta; NIBBLETYPE Meta;
if (a_OtherChunk != nullptr) if (a_NeighborChunk != nullptr)
{ {
RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width; a_NeighborChunk->UnboundedRelGetBlock(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, Meta);
RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width;
a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, 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 // 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 else
{ {
RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; a_OriginalChunk->GetBlockTypeMeta(a_RelBlockPosition.x, a_RelBlockPosition.y, a_RelBlockPosition.z, Block, Meta);
RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, 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 // 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)) 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; if (a_NeighborChunk != nullptr)
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)
{ {
// 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 // 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; return;
} }
cCoordWithBlockAndBoolVector & RedstoneSimulatorChunkData = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_ChunkData; auto & SimulatedPlayerToggleableBlocks = static_cast<cIncrementalRedstoneSimulatorChunkData *>(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 == a_RelBlockPosition) && !DoesIgnorePlayerToggle(Block);
}
), SimulatedPlayerToggleableBlocks.end());
auto & RepeatersDelayList = static_cast<cIncrementalRedstoneSimulatorChunkData *>(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<cIncrementalRedstoneSimulatorChunkData *>(a_OriginalChunk->GetRedstoneSimulatorData())->m_ChunkData;
for (auto & itr : RedstoneSimulatorChunkData) 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)) if (!IsAllowedBlock(Block))
{ {
@ -128,16 +143,16 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
return; return;
} }
cCoordWithBlockAndBoolVector & QueuedData = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData; auto & QueuedData = static_cast<cIncrementalRedstoneSimulatorChunkData *>(a_OriginalChunk->GetRedstoneSimulatorData())->m_QueuedChunkData;
for (const auto & itr : QueuedData) 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 // 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; 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) 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) if (m_RedstoneSimulatorChunkData == nullptr)
{ {
m_RedstoneSimulatorChunkData = new cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData(); m_RedstoneSimulatorChunkData = new cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData();
a_Chunk->SetRedstoneSimulatorData(m_RedstoneSimulatorChunkData); 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<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData.empty())
{ {
return; 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) 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 })) auto CurrentChunkRelative = cChunkDef::AbsoluteToRelative({a_BlockX, a_BlockY, a_BlockZ}, a_Chunk->GetPosX(), a_Chunk->GetPosZ());
AddBlock(CurrentChunkRelative, a_Chunk); // Alert the current chunk which the block is present in
for (const auto & BoundaryChunk : GetAdjacentChunks(CurrentChunkRelative, a_Chunk))
{ {
// On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk) // On a chunk boundary, alert all neighbouring chunks which may have a connection with this block
AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); AddBlock(cChunkDef::AbsoluteToRelative({a_BlockX, a_BlockY, a_BlockZ}, BoundaryChunk->GetPosX(), BoundaryChunk->GetPosZ()), a_Chunk, BoundaryChunk);
// 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;
} }
// Not on boundary, just alert this chunk for speed
AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
} }
@ -508,10 +514,111 @@ void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_RelBlockX, int a_
void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) 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; BLOCK_FACE_XM,
} gCrossCoords[] = BLOCK_FACE_XP,
BLOCK_FACE_ZM,
BLOCK_FACE_ZP
};
static const Vector3i VectorOffsets[] =
{
{ -1, 0, 0 },
{ 1, 0, 0 },
{ 0, 0, -1 },
{ 0, 0, 1 }
};
auto RelBlock = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
// Check to see if directly beside a power source
unsigned char MyPower = IsWirePowered(RelBlock, m_Chunk);
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
if (MyPower == 0)
{
SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk);
return;
}
if (MyPower == MAX_POWER_LEVEL)
{
std::vector<std::pair<Vector3i, cChunk *>> 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--;
// 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)
{
BLOCKTYPE Block;
auto Offset = RelBlock + VectorOffsets[OffsetIdx];
if (m_Chunk->UnboundedRelGetBlockType(Offset.x, Offset.y, Offset.z, Block))
{
switch (Block)
{
case E_BLOCK_REDSTONE_REPEATER_OFF:
{
BorderingMechanismCount++;
if (!RepeaterPresent)
{
// TODO: only if wire is actually connected to repeater (repeater facing right way)
RepeaterPresent = true;
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;
}
}
}
if (BorderingMechanismCount == 0)
{
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);
}
}
void cIncrementalRedstoneSimulator::FindAndPowerBorderingWires(std::vector<std::pair<Vector3i, cChunk *>> & a_PotentialWireList, const std::pair<Vector3i, cChunk *> & a_Entry)
{
std::vector<std::pair<Vector3i, cChunk *>> NewAdditions;
const Vector3i Offsets[] =
{ {
{ 1, 0, 0 }, /* Wires on same level start */ { 1, 0, 0 }, /* Wires on same level start */
{ -1, 0, 0 }, { -1, 0, 0 },
@ -526,129 +633,26 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re
{ 0, -1, 1 }, { 0, -1, 1 },
{ 0, -1, -1 }, /* Wires one lower, surrounding self stop */ { 0, -1, -1 }, /* Wires one lower, surrounding self stop */
}; };
static const struct // Define which directions the wire will check for repeater prescence for (auto Offset : Offsets)
{ {
int x, y, z; auto AdjustedPos = a_Entry.first + Offset;
} gSideCoords[] = auto Neighbour = a_Entry.second->GetRelNeighborChunkAdjustCoords(AdjustedPos.x, AdjustedPos.z);
{ auto MyPower = IsWirePowered(a_Entry.first, a_Entry.second);
{ 1, 0, 0 },
{ -1, 0, 0 },
{ 0, 0, 1 },
{ 0, 0, -1 },
{ 0, 1, 0 },
};
// Check to see if directly beside a power source if ((Neighbour->GetBlock(AdjustedPos) == E_BLOCK_REDSTONE_WIRE) && (MyPower > 1) && (MyPower > IsWirePowered(AdjustedPos, Neighbour)))
unsigned char MyPower = IsWirePowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); {
if (MyPower == 0) sPoweredBlocks RC;
{ RC.a_BlockPos = AdjustedPos;
SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); RC.a_SourcePos = a_Entry.first + Vector3i((a_Entry.second->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width, 0, (a_Entry.second->GetPosZ() - Neighbour->GetPosZ()) * cChunkDef::Width);
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0); RC.a_PowerLevel = MyPower - 1;
return; ((cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks.emplace_back(RC); // We need to insert the value into the chunk who owns the block position
}
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); Neighbour->SetIsRedstoneDirty(true);
m_Chunk->SetIsRedstoneDirty(true);
MyPower--; Neighbour->SetMeta(AdjustedPos.x, AdjustedPos.y, AdjustedPos.z, MyPower - 1);
a_PotentialWireList.emplace_back(std::make_pair(AdjustedPos, Neighbour));
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power
{
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 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;
}
}
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
{
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);
}
}
// 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))
{
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);
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:
{
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;
} }
} }
} }
@ -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) void cIncrementalRedstoneSimulator::HandleRedstoneComparator(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{ {
auto Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, 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)); auto FrontCoordinate = AdjustRelativeCoords(cBlockComparatorHandler::GetFrontCoordinate(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Meta & 0x3));
unsigned char Power = 0; 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); auto AbsoluteRearCoords = cBlockComparatorHandler::GetRearCoordinate(AbsoluteComparatorCoords.x, AbsoluteComparatorCoords.y, AbsoluteComparatorCoords.z, Meta & 0x3);
m_Chunk->DoWithBlockEntityAt(AbsoluteRearCoords.x, AbsoluteRearCoords.y, AbsoluteRearCoords.z, CCB); 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) if ((Meta & 0x4) == 0x4)
{ // Subtraction mode { // 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 // 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 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.a_BlockPos == Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }) != Data.end();
if (itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
{
return true;
}
}
return false;
} }
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 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();
if (itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
{
return true;
}
}
return false;
} }
@ -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; 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 != a_RelBlockPosition) 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) 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<cIncrementalRedstoneSimulatorChunkData *>(a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks) // Check linked powered list
{ {
if (itr.a_BlockPos != a_RelBlockPosition) if (itr.a_BlockPos != a_RelBlockPosition)
{ {
@ -1785,7 +1777,7 @@ unsigned char cIncrementalRedstoneSimulator::IsWirePowered(Vector3i a_RelBlockPo
} }
BLOCKTYPE Type = E_BLOCK_AIR; 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; 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) void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel)
{ {
static const struct static const Vector3i Offsets[] =
{ {
Vector3i Offset; {1, 0, 0},
} gCrossCoords[] = { -1, 0, 0},
{ {0, 0, 1},
Vector3i(1, 0, 0), {0, 0, -1},
Vector3i(-1, 0, 0), {0, 1, 0},
Vector3i(0, 0, 1), {0, -1, 0}
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 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.x += (m_Chunk->GetPosX() - Neighbour->GetPosX()) * cChunkDef::Width;
a_RelSourcePosition.z += (m_Chunk->GetPosZ() - Neighbour->GetPosZ()) * 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<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) for (auto itr = Powered.begin(); itr != Powered.end(); ++itr)
{ {
if ((itr->a_BlockPos == a_RelBlockPosition) && (itr->a_SourcePos == a_RelSourcePosition)) if ((itr->a_BlockPos == a_RelBlockPosition) && (itr->a_SourcePos == a_RelSourcePosition))
@ -2012,7 +2001,7 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
return; return;
} }
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 for (auto & itr : Linked) // Check linked powered list
{ {
if ( 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; continue;
} }
// Update listing // Update listing
itr->WasLastStatePowered = WasLastStatePowered; itr.WasLastStatePowered = a_WasLastStatePowered;
return; return;
} }
// We have arrived here; no block must be in list - add one // We have arrived here; no block must be in list - add one
sSimulatedPlayerToggleableList RC; sSimulatedPlayerToggleableList RC;
RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
RC.WasLastStatePowered = WasLastStatePowered; RC.WasLastStatePowered = a_WasLastStatePowered;
m_SimulatedPlayerToggleableBlocks->emplace_back(RC); 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 UnpoweringFunction = [&BlocksPotentiallyUnpowered](cChunk * a_Chunk, const Vector3i & a_RelSource)
{ {
auto Data = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData(); auto Data = static_cast<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) 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) if (itr.a_SourcePos != a_RelSource)
@ -2117,16 +2106,16 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R
return false; return false;
} }
auto ChunkBoundaryTestCoords = a_RelSource + GetCoordinateAdjacentChunk(a_RelSource); for (const auto & BoundaryChunk : GetAdjacentChunks(a_RelSource, a_Chunk))
auto BoundaryChunk = a_Chunk->GetRelNeighborChunk(ChunkBoundaryTestCoords.x, ChunkBoundaryTestCoords.z);
if (BoundaryChunk != a_Chunk)
{ {
Vector3i ChunkAdjustedSource = a_RelSource; if (BoundaryChunk != a_Chunk)
ChunkAdjustedSource.x += (a_Chunk->GetPosX() - BoundaryChunk->GetPosX()) * cChunkDef::Width; {
ChunkAdjustedSource.z += (a_Chunk->GetPosZ() - BoundaryChunk->GetPosZ()) * cChunkDef::Width; 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(); 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) 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) if (itr.a_SourcePos != ChunkAdjustedSource)
{ {
@ -2137,7 +2126,8 @@ void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_R
BoundaryChunk->SetIsRedstoneDirty(true); BoundaryChunk->SetIsRedstoneDirty(true);
return true; return true;
} }
), BoundaryData->m_PoweredBlocks.end()); ), BoundaryData->m_PoweredBlocks.end());
}
} }
if (a_Chunk->GetBlock(a_RelSource) == E_BLOCK_REDSTONE_REPEATER_ON) 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_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); return false;
a_Chunk->SetIsRedstoneDirty(true);
return true;
} }
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()) while (!BlocksPotentiallyUnpowered.empty())
@ -2187,7 +2207,7 @@ void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int
} }
std::vector<Vector3i> BlocksPotentiallyUnpowered; std::vector<Vector3i> BlocksPotentiallyUnpowered;
auto Data = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData(); auto Data = static_cast<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) 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,72 +2243,6 @@ void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int
cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
int Dir = REDSTONE_NONE;
BLOCKTYPE NegX = 0;
if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, NegX))
{
if (IsPotentialSource(NegX))
{
Dir |= (REDSTONE_X_POS);
}
}
BLOCKTYPE PosX = 0;
if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, PosX))
{
if (IsPotentialSource(PosX))
{
Dir |= (REDSTONE_X_NEG);
}
}
BLOCKTYPE NegZ = 0;
if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, NegZ))
{
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;
}
}
BLOCKTYPE PosZ = 0;
if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, PosZ))
{
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;
}
}
return (eRedstoneDirection)Dir;
}
bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta) bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta)
{ {
// Extract the ON bit from metadata and return if true if it is set: // Extract the ON bit from metadata and return if true if it is set:
@ -2298,3 +2252,33 @@ bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta)
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
// 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));
}
if ((a_RelBlockPosition.x % cChunkDef::Width) >= 14)
{
AdjacentChunks.emplace_back(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));
}
if ((a_RelBlockPosition.z % cChunkDef::Width) >= 14)
{
AdjacentChunks.emplace_back(a_Chunk->GetRelNeighborChunk(a_RelBlockPosition.x, a_RelBlockPosition.z + 2));
}
return AdjacentChunks;
}

View File

@ -3,6 +3,7 @@
#include "RedstoneSimulator.h" #include "RedstoneSimulator.h"
#include "BlockEntities/RedstonePoweredEntity.h" #include "BlockEntities/RedstonePoweredEntity.h"
#include <bitset>
class cWorld; class cWorld;
class cChunk; class cChunk;
@ -37,15 +38,14 @@ public:
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override { return IsRedstone(a_BlockType); } 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; virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override;
enum eRedstoneDirection enum eRedstoneWireDirectionBitfieldPositions
{ {
REDSTONE_NONE = 0, eWbpXP = 0,
REDSTONE_X_POS = 0x1, eWbpXN = 1,
REDSTONE_X_NEG = 0x2, eWbpZP = 2,
REDSTONE_Z_POS = 0x4, eWbpZN = 3,
REDSTONE_Z_NEG = 0x8,
}; };
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: private:
@ -108,8 +108,9 @@ private:
SimulatedPlayerToggleableList * m_SimulatedPlayerToggleableBlocks; SimulatedPlayerToggleableList * m_SimulatedPlayerToggleableBlocks;
RepeatersDelayList * m_RepeatersDelayList; 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); } virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override;
void RedstoneAddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk, cChunk * a_OtherChunk = nullptr);
void AddBlock(const Vector3i & a_BlockPosition, cChunk * a_Chunk, cChunk * a_OtherChunk = nullptr);
cChunk * m_Chunk; 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 // 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(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); } 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<std::pair<Vector3i, cChunk *>> & a_PotentialWireList, const std::pair<Vector3i, cChunk *> & a_Entry);
/** Marks a block as being powered through another block */ /** 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); 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); 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 */ /** 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 */ /** 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 */ /** 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) */ /** 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); bool AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered);
@ -236,7 +240,7 @@ private:
/** Returns if a wire is powered /** 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 */ 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 **/ /** Handles delayed updates to repeaters **/
void HandleRedstoneRepeaterDelays(void); void HandleRedstoneRepeaterDelays(void);
@ -249,14 +253,14 @@ private:
/** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */ /** 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) /** 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 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_DOOR:
case E_BLOCK_ACACIA_FENCE_GATE: case E_BLOCK_ACACIA_FENCE_GATE:
@ -298,9 +302,9 @@ private:
} }
/** Returns if a block has the potential to output power */ /** 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_DETECTOR_RAIL:
case E_BLOCK_DAYLIGHT_SENSOR: case E_BLOCK_DAYLIGHT_SENSOR:
@ -326,9 +330,9 @@ private:
} }
/** Returns if a block is any sort of redstone device */ /** 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 // All redstone devices, please alpha sort
case E_BLOCK_ACACIA_DOOR: 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 switch (a_Block)
if ((a_BlockPos.x % cChunkDef::Width) <= 1) { return{ -2, 0, 0 }; } {
if ((a_BlockPos.x % cChunkDef::Width) >= 14) { return{ 2, 0, 0 }; } case E_BLOCK_ACACIA_FENCE_GATE:
if ((a_BlockPos.z % cChunkDef::Width) <= 1) { return{ 0, 0, -2 }; } case E_BLOCK_BIRCH_FENCE_GATE:
if ((a_BlockPos.z % cChunkDef::Width) >= 14) { return{ 0, 0, 2 }; } case E_BLOCK_DARK_OAK_FENCE_GATE:
return { 0, 0, 0 }; 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<cChunk *> GetAdjacentChunks(const Vector3i & a_RelBlockPosition, cChunk * a_Chunk);
inline static Vector3i AdjustRelativeCoords(const Vector3i & a_RelPosition) inline static Vector3i AdjustRelativeCoords(const Vector3i & a_RelPosition)
{ {
if ( if (

View File

@ -2964,7 +2964,7 @@ bool cWorld::SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Op
return false; return false;
} }
bool IsOpen = (Meta & 0x4) > 0; bool IsOpen = (Meta & 0x4) != 0;
if (a_Open != IsOpen) if (a_Open != IsOpen)
{ {
SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta ^ 0x4); SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta ^ 0x4);