Skip to content

Commit

Permalink
Improved redstone speed and fixed a wire bug
Browse files Browse the repository at this point in the history
The redstone simulator no longer goes through the Powered and
LinkedPowered blocks lists for EVERY item in the chunk data, instead,
only at every tick.
Also, wires powering each other that had the same data value is now
fixed.
  • Loading branch information
tigerw committed Nov 30, 2013
1 parent 4741e5e commit 8d88c8f
Showing 1 changed file with 83 additions and 73 deletions.
156 changes: 83 additions & 73 deletions src/Simulator/RedstoneSimulator.cpp
Expand Up @@ -76,92 +76,100 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;

for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;)
// Check to see if PoweredBlocks have invalid items (source is air or unpowered)
for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end();)
{
BLOCKTYPE BlockType = a_Chunk->GetBlock(dataitr->x, dataitr->y, dataitr->z);
if (!IsAllowedBlock(BlockType))
sPoweredBlocks & Change = *itr;

int RelX = Change.a_SourcePos.x - a_ChunkX * cChunkDef::Width;
int RelZ = Change.a_SourcePos.z - a_ChunkZ * cChunkDef::Width;

BLOCKTYPE SourceBlockType;
NIBBLETYPE SourceBlockMeta;
if (!a_Chunk->UnboundedRelGetBlock(RelX, Change.a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta))
{
dataitr = ChunkData.erase(dataitr);
continue;
}

// Check to see if PoweredBlocks have invalid items (source is air or unpowered)
for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end();)
if (SourceBlockType != Change.a_SourceBlock)
{
sPoweredBlocks & Change = *itr;
itr = m_PoweredBlocks.erase(itr);
LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock));
}
else if (
// Changeable sources
((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) ||
((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) ||
((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (SourceBlockMeta & 0x08) == 0x08) ||
(((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta)))
)
{
itr = m_PoweredBlocks.erase(itr);
LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock));
}
else
{
itr++;
}
}

int RelX = Change.a_SourcePos.x - a_ChunkX * cChunkDef::Width;
int RelZ = Change.a_SourcePos.z - a_ChunkZ * cChunkDef::Width;
// Check to see if LinkedPoweredBlocks have invalid items: source, block powered through, or power destination block has changed
for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end();)
{
sLinkedPoweredBlocks & Change = *itr;

BLOCKTYPE SourceBlockType;
NIBBLETYPE SourceBlockMeta;
a_Chunk->UnboundedRelGetBlock(RelX, Change.a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta);
int RelX = Change.a_SourcePos.x - a_ChunkX * cChunkDef::Width;
int RelZ = Change.a_SourcePos.z - a_ChunkZ * cChunkDef::Width;
int MidRelX = Change.a_MiddlePos.x - a_ChunkX * cChunkDef::Width;
int MidRelZ = Change.a_MiddlePos.z - a_ChunkZ * cChunkDef::Width;

if (SourceBlockType != Change.a_SourceBlock)
{
itr = m_PoweredBlocks.erase(itr);
LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock));
}
else if (
// Changeable sources
((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) ||
((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) ||
((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (SourceBlockMeta & 0x08) == 0x08) ||
(((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta)))
)
{
itr = m_PoweredBlocks.erase(itr);
LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock));
}
else
{
itr++;
}
BLOCKTYPE SourceBlockType;
NIBBLETYPE SourceBlockMeta;
BLOCKTYPE MiddleBlockType;
if (
!a_Chunk->UnboundedRelGetBlock(RelX, Change.a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta) ||
!a_Chunk->UnboundedRelGetBlockType(MidRelX, Change.a_MiddlePos.y, MidRelZ, MiddleBlockType)
)
{
continue;
}

// Check to see if LinkedPoweredBlocks have invalid items: source, block powered through, or power destination block has changed
for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end();)
if (SourceBlockType != Change.a_SourceBlock)
{
sLinkedPoweredBlocks & Change = *itr;

int RelX = Change.a_SourcePos.x - a_ChunkX * cChunkDef::Width;
int RelZ = Change.a_SourcePos.z - a_ChunkZ * cChunkDef::Width;
int MidRelX = Change.a_MiddlePos.x - a_ChunkX * cChunkDef::Width;
int MidRelZ = Change.a_MiddlePos.z - a_ChunkZ * cChunkDef::Width;

BLOCKTYPE SourceBlockType;
NIBBLETYPE SourceBlockMeta;
BLOCKTYPE MiddleBlockType;
a_Chunk->UnboundedRelGetBlock(RelX, Change.a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta);
a_Chunk->UnboundedRelGetBlockType(MidRelX, Change.a_MiddlePos.y, MidRelZ, MiddleBlockType);

if (SourceBlockType != Change.a_SourceBlock)
{
itr = m_LinkedPoweredBlocks.erase(itr);
LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock));
}
else if (MiddleBlockType != Change.a_MiddleBlock)
{
itr = m_LinkedPoweredBlocks.erase(itr);
LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past middle block mismatch", ItemToFullString(Change.a_SourceBlock));
}
else if (
// Things that can send power through a block but which depends on meta
((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) ||
((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) ||
(((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta)))
)
{
itr = m_LinkedPoweredBlocks.erase(itr);
LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock));
}
else
{
itr++;
}
itr = m_LinkedPoweredBlocks.erase(itr);
LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past block type mismatch", ItemToFullString(Change.a_SourceBlock));
}
else if (MiddleBlockType != Change.a_MiddleBlock)
{
itr = m_LinkedPoweredBlocks.erase(itr);
LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past middle block mismatch", ItemToFullString(Change.a_SourceBlock));
}
else if (
// Things that can send power through a block but which depends on meta
((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) ||
((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) ||
(((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta)))
)
{
itr = m_LinkedPoweredBlocks.erase(itr);
LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past metadata mismatch", ItemToFullString(Change.a_SourceBlock));
}
else
{
itr++;
}
}

for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;)
{
BLOCKTYPE BlockType = a_Chunk->GetBlock(dataitr->x, dataitr->y, dataitr->z);
if (!IsAllowedBlock(BlockType))
{
dataitr = ChunkData.erase(dataitr);
continue;
}

// PoweredBlock list was fine, now to the actual handling
// PoweredBlock and LinkedPoweredBlock list was fine, now to the actual handling
int a_X = BaseX + dataitr->x;
int a_Z = BaseZ + dataitr->z;
switch (BlockType)
Expand Down Expand Up @@ -407,7 +415,9 @@ void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_Bl

if (SurroundMeta > 1) // Wires of power 1 or 0 cannot transfer power TO ME, don't bother checking
{
if (SurroundMeta > MyMeta) // Does surrounding wire have a higher power level than self?
// Does surrounding wire have a higher power level than self?
// >= to fix a bug where wires bordering each other with the same power level will appear (in terms of meta) to power each other, when they aren't actually in the powered list
if (SurroundMeta >= MyMeta)
{
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, SurroundMeta - 1);
}
Expand Down

0 comments on commit 8d88c8f

Please sign in to comment.