summaryrefslogtreecommitdiffstats
path: root/src/Simulator/RedstoneSimulator.cpp
diff options
context:
space:
mode:
authorSTRWarrior <niels.breuker@hotmail.nl>2014-02-07 22:59:08 +0100
committerSTRWarrior <niels.breuker@hotmail.nl>2014-02-07 22:59:08 +0100
commit3a897844a0796ce91e51e0154acbbce2d8e807e5 (patch)
tree395c3322c924d61d4cbf8b82d5c7cbb2f6357d1a /src/Simulator/RedstoneSimulator.cpp
parentFixed some end of lines (diff)
downloadcuberite-3a897844a0796ce91e51e0154acbbce2d8e807e5.tar
cuberite-3a897844a0796ce91e51e0154acbbce2d8e807e5.tar.gz
cuberite-3a897844a0796ce91e51e0154acbbce2d8e807e5.tar.bz2
cuberite-3a897844a0796ce91e51e0154acbbce2d8e807e5.tar.lz
cuberite-3a897844a0796ce91e51e0154acbbce2d8e807e5.tar.xz
cuberite-3a897844a0796ce91e51e0154acbbce2d8e807e5.tar.zst
cuberite-3a897844a0796ce91e51e0154acbbce2d8e807e5.zip
Diffstat (limited to 'src/Simulator/RedstoneSimulator.cpp')
-rw-r--r--src/Simulator/RedstoneSimulator.cpp1523
1 files changed, 4 insertions, 1519 deletions
diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp
index 298175ad7..a83f21106 100644
--- a/src/Simulator/RedstoneSimulator.cpp
+++ b/src/Simulator/RedstoneSimulator.cpp
@@ -1,21 +1,15 @@
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+#include "Globals.h"
#include "RedstoneSimulator.h"
-#include "../BlockEntities/DropSpenserEntity.h"
-#include "../BlockEntities/NoteEntity.h"
-#include "../BlockEntities/CommandBlockEntity.h"
-#include "../Entities/TNTEntity.h"
-#include "../Blocks/BlockTorch.h"
-#include "../Blocks/BlockDoor.h"
-#include "../Piston.h"
+#include "../World.h"
-cRedstoneSimulator::cRedstoneSimulator(cWorld & a_World)
- : super(a_World)
+cRedstoneSimulator::cRedstoneSimulator(cWorld & a_World) :
+ super(a_World)
{
}
@@ -23,1512 +17,3 @@ cRedstoneSimulator::cRedstoneSimulator(cWorld & a_World)
-cRedstoneSimulator::~cRedstoneSimulator()
-{
-}
-
-
-
-
-
-void cRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
-{
- if ((a_Chunk == NULL) || !a_Chunk->IsValid())
- {
- return;
- }
- else if ((a_BlockY < 0) || (a_BlockY > cChunkDef::Height))
- {
- return;
- }
-
- int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
- int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
-
- BLOCKTYPE Block;
- NIBBLETYPE Meta;
- 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
- // Checking only when a block is changed, as opposed to every tick, also improves performance
-
- for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
- {
- if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- continue;
- }
-
- if (!IsPotentialSource(Block))
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_PoweredBlocks.erase(itr);
- break;
- }
- else if (
- // Changeable sources
- ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
- ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
- ((Block == E_BLOCK_DETECTOR_RAIL) && (Meta & 0x08) == 0) ||
- (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ||
- (((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0))
- )
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_PoweredBlocks.erase(itr);
- break;
- }
- else if (Block == E_BLOCK_DAYLIGHT_SENSOR)
- {
- if (!a_Chunk->IsLightValid())
- {
- m_World.QueueLightChunk(a_Chunk->GetPosX(), a_Chunk->GetPosZ());
- break;
- }
- else
- {
- NIBBLETYPE SkyLight;
- a_Chunk->UnboundedRelGetBlockSkyLight(RelX, itr->a_SourcePos.y + 1, RelZ, SkyLight);
-
- if (a_Chunk->GetTimeAlteredLight(SkyLight) <= 8) // Could use SkyLight - m_World.GetSkyDarkness();
- {
- LOGD("cRedstoneSimulator: Erased daylight sensor from powered blocks list due to insufficient light level");
- m_PoweredBlocks.erase(itr);
- break;
- }
- }
- }
- }
-
- for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
- {
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- if (!IsPotentialSource(Block))
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_LinkedPoweredBlocks.erase(itr);
- break;
- }
- else if (
- // Things that can send power through a block but which depends on meta
- ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
- ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
- (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta)))
- )
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_LinkedPoweredBlocks.erase(itr);
- break;
- }
- }
- else if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- if (!IsViableMiddleBlock(Block))
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer powered through a valid middle block", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_LinkedPoweredBlocks.erase(itr);
- break;
- }
- }
- }
-
- for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- continue;
- }
-
- if (!IsAllowedBlock(Block))
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_SimulatedPlayerToggleableBlocks.erase(itr);
- break;
- }
- }
-
- for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- continue;
- }
-
- if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF))
- {
- m_RepeatersDelayList.erase(itr);
- break;
- }
- }
-
- cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData();
- for (cRedstoneSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr)
- {
- 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->Data = Block; // Update block information
- }
- return;
- }
- }
-
- if (!IsAllowedBlock(Block))
- {
- return;
- }
-
- ChunkData.push_back(cCoordWithBlockAndBool(RelX, a_BlockY, RelZ, Block, false));
-}
-
-
-
-
-
-void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
-{
- // We still attempt to simulate all blocks in the chunk every tick, because of outside influence that needs to be taken into account
- // For example, repeaters need to be ticked, pressure plates checked for entities, daylight sensor checked for light changes, etc.
- // The easiest way to make this more efficient is probably just to reduce code within the handlers that put too much strain on server, like getting or setting blocks
- // A marking dirty system might be a TODO for later on, perhaps
-
- cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData();
- if (ChunkData.empty())
- {
- return;
- }
-
- int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
- int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;
-
- for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(); dataitr != ChunkData.end();)
- {
- if (dataitr->DataTwo)
- {
- dataitr = ChunkData.erase(dataitr);
- continue;
- }
-
- int a_X = BaseX + dataitr->x;
- int a_Z = BaseZ + dataitr->z;
- switch (dataitr->Data)
- {
- case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(a_X, dataitr->y, a_Z); break;
-
- case E_BLOCK_REDSTONE_TORCH_OFF:
- case E_BLOCK_REDSTONE_TORCH_ON:
- {
- HandleRedstoneTorch(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- case E_BLOCK_STONE_BUTTON:
- case E_BLOCK_WOODEN_BUTTON:
- {
- HandleRedstoneButton(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- {
- HandleRedstoneRepeater(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- case E_BLOCK_PISTON:
- case E_BLOCK_STICKY_PISTON:
- {
- HandlePiston(a_X, dataitr->y, a_Z);
- break;
- }
- case E_BLOCK_REDSTONE_LAMP_OFF:
- case E_BLOCK_REDSTONE_LAMP_ON:
- {
- HandleRedstoneLamp(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DROPPER:
- {
- HandleDropSpenser(a_X, dataitr->y, a_Z);
- break;
- }
- case E_BLOCK_WOODEN_DOOR:
- case E_BLOCK_IRON_DOOR:
- {
- HandleDoor(a_X, dataitr->y, a_Z);
- break;
- }
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_DETECTOR_RAIL:
- case E_BLOCK_POWERED_RAIL:
- {
- HandleRail(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- case E_BLOCK_WOODEN_PRESSURE_PLATE:
- case E_BLOCK_STONE_PRESSURE_PLATE:
- {
- HandlePressurePlate(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- }
- ++dataitr;
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
-{
- static const struct // Define which directions the torch can power
- {
- int x, y, z;
- } gCrossCoords[] =
- {
- { 1, 0, 0},
- {-1, 0, 0},
- { 0, 0, 1},
- { 0, 0, -1},
- { 0, 1, 0},
- } ;
-
- if (a_MyState == E_BLOCK_REDSTONE_TORCH_ON)
- {
- // Check if the block the torch is on is powered
- int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ;
- AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on
-
- if (AreCoordsDirectlyPowered(X, Y, Z))
- {
- // There was a match, torch goes off
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ));
- return;
- }
-
- // Torch still on, make all 4(X, Z) + 1(Y) sides powered
- for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
- {
- BLOCKTYPE Type = m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z);
- if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last)
- {
- if (
- ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc.
- (!Vector3i(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on
- )
- {
- SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
- }
- }
- else
- {
- // Top side, power whatever is there, including blocks
- SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
- // Power all blocks surrounding block above torch
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_REDSTONE_TORCH_ON);
- }
- }
-
- if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath
- {
- BLOCKTYPE Type = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
-
- if ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) // Still can't make a normal block powered though!
- {
- SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
- }
- }
- }
- else
- {
- // Check if the block the torch is on is powered
- int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ;
- AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on
-
- // See if off state torch can be turned on again
- if (AreCoordsDirectlyPowered(X, Y, Z))
- {
- return; // Something matches, torch still powered
- }
-
- // Block torch on not powered, can be turned on again!
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ));
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE);
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); // Set self as powered
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- if (IsLeverOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)))
- {
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LEVER);
-
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_LEVER);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
-{
- if (IsButtonOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)))
- {
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockType);
-
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, a_BlockType);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- static const struct // Define which directions the wire can receive power from
- {
- int x, y, z;
- } gCrossCoords[] =
- {
- { 1, 0, 0}, /* Wires on same level start */
- {-1, 0, 0},
- { 0, 0, 1},
- { 0, 0, -1}, /* Wires on same level stop */
- { 1, 1, 0}, /* Wires one higher, surrounding self start */
- {-1, 1, 0},
- { 0, 1, 1},
- { 0, 1, -1}, /* Wires one higher, surrounding self stop */
- { 1,-1, 0}, /* Wires one lower, surrounding self start */
- {-1,-1, 0},
- { 0,-1, 1},
- { 0,-1, -1}, /* Wires one lower, surrounding self stop */
- } ;
-
- static const struct // Define which directions the wire will check for repeater prescence
- {
- int x, y, z;
- } gSideCoords[] =
- {
- { 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 (IsWirePowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 15); // Maximum power
- }
- else
- {
- NIBBLETYPE MetaToSet = 0;
- NIBBLETYPE MyMeta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
- int TimesMetaSmaller = 0, TimesFoundAWire = 0;
-
- 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...
- {
- if (g_BlockIsSolid[m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ)]) // 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
- {
- if (g_BlockIsSolid[m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y + 1, a_BlockZ + gCrossCoords[i].z)])
- {
- continue;
- }
- }
-
- BLOCKTYPE SurroundType;
- NIBBLETYPE SurroundMeta;
- m_World.GetBlockTypeMeta(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, SurroundType, SurroundMeta);
-
- if (SurroundType == E_BLOCK_REDSTONE_WIRE)
- {
- TimesFoundAWire++;
-
- if (SurroundMeta > 1) // Wires of power 1 or 0 cannot transfer power TO ME, don't bother checking
- {
- // 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)
- {
- MetaToSet = SurroundMeta - 1; // To improve performance
- }
- }
-
- if (SurroundMeta < MyMeta) // Go through all surroundings to see if self power is larger than everyone else's
- {
- TimesMetaSmaller++;
- }
- }
- }
-
- if (TimesMetaSmaller == TimesFoundAWire)
- {
- // All surrounding metas were smaller - self must have been a wire that was
- // transferring power to other wires around.
- // However, self not directly powered anymore, so source must have been removed,
- // therefore, self must be set to meta zero
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, 0); // SetMeta & WakeUpSims doesn't seem to work here, so SetBlock
- return; // No need to process block power sets because self not powered
- }
- else
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaToSet);
- }
- }
-
- if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0) // A powered wire
- {
- for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them
- {
- if (m_World.GetBlock(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z) == E_BLOCK_REDSTONE_REPEATER_OFF)
- {
- SetBlockPowered(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- }
- }
-
- // Wire still powered, power blocks beneath
- SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE);
-
- switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ))
- {
- case REDSTONE_NONE:
- {
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
-
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_X_POS:
- {
- SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_X_NEG:
- {
- SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_Z_POS:
- {
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_Z_NEG:
- {
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
-{
- NIBBLETYPE a_Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
-
- bool IsOn = ((a_MyState == E_BLOCK_REDSTONE_REPEATER_ON) ? true : false); // Cache if repeater is on
- bool IsSelfPowered = IsRepeaterPowered(a_BlockX, a_BlockY, a_BlockZ, a_Meta & 0x3); // Cache if repeater is pwoered
-
- if (IsSelfPowered && !IsOn) // Queue a power change if I am receiving power but not on
- {
- QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, true);
- }
- else if (!IsSelfPowered && IsOn) // Queue a power change if I am not receiving power but on
- {
- QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, false);
- }
-
- for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- continue;
- }
-
- if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks?
- {
- if (itr->ShouldPowerOn)
- {
- if (!IsOn)
- {
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); // For performance
- }
-
- switch (a_Meta & 0x3) // We only want the direction (bottom) bits
- {
- case 0x0:
- {
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_REPEATER_ON);
- break;
- }
- case 0x1:
- {
- SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_REPEATER_ON);
- break;
- }
- case 0x2:
- {
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_REPEATER_ON);
- break;
- }
- case 0x3:
- {
- SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_REPEATER_ON);
- break;
- }
- }
-
- // Removal of the data entry will be handled in SimChunk - we still want to continue trying to power blocks, even if our delay time has reached
- // Otherwise, the power state of blocks in front won't update after we have powered on
- return;
- }
- else
- {
- if (IsOn)
- {
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta);
- }
- m_RepeatersDelayList.erase(itr); // We can remove off repeaters which don't need further updating
- return;
- }
- }
- else
- {
- // Apparently, incrementing ticks only works reliably here, and not in SimChunk;
- // With a world with lots of redstone, the repeaters simply do not delay
- // I am confounded to say why. Perhaps optimisation failure.
- LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
- itr->a_ElapsedTicks++;
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- cPiston Piston(&m_World);
- if (IsPistonPowered(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness)
- {
- Piston.ExtendPiston(a_BlockX, a_BlockY, a_BlockZ);
- }
- else
- {
- Piston.RetractPiston(a_BlockX, a_BlockY, a_BlockZ);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- class cSetPowerToDropSpenser :
- public cDropSpenserCallback
- {
- bool m_IsPowered;
- public:
- cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
-
- virtual bool Item(cDropSpenserEntity * a_DropSpenser) override
- {
- a_DropSpenser->SetRedstonePower(m_IsPowered);
- return false;
- }
- } DrSpSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ));
-
- m_World.DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, DrSpSP);
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
-{
- if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF)
- {
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0);
- }
- }
- else
- {
- if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0);
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- m_World.BroadcastSoundEffect("random.fuse", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
- m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
- {
- cChunkInterface ChunkInterface(m_World.GetChunkMap());
- cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
- }
- }
- else
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
- {
- cChunkInterface ChunkInterface(m_World.GetChunkMap());
- cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- class cSetPowerToCommandBlock :
- public cCommandBlockCallback
- {
- bool m_IsPowered;
- public:
- cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
-
- virtual bool Item(cCommandBlockEntity * a_CommandBlock) override
- {
- a_CommandBlock->SetRedstonePower(m_IsPowered);
- return false;
- }
- } CmdBlockSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ));
-
- m_World.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockSP);
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType)
-{
- switch (a_MyType)
- {
- case E_BLOCK_DETECTOR_RAIL:
- {
- if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08)
- {
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType);
- }
- break;
- }
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_POWERED_RAIL:
- {
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x08);
- }
- else
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07);
- }
- break;
- }
- default: LOGD("Unhandled type of rail in %s", __FUNCTION__);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x4);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
- }
- }
- else
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0xB); // Take into account that the fourth bit is needed for trapdoors too
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- bool m_bAreCoordsPowered = AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ);
-
- if (m_bAreCoordsPowered)
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
- {
- class cSetPowerToNoteBlock :
- public cNoteBlockCallback
- {
- bool m_IsPowered;
- public:
- cSetPowerToNoteBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
-
- virtual bool Item(cNoteEntity * a_NoteBlock) override
- {
- if (m_IsPowered)
- {
- a_NoteBlock->MakeSound();
- }
- return false;
- }
- } NoteBlockSP(m_bAreCoordsPowered);
-
- m_World.DoWithNoteBlockAt(a_BlockX, a_BlockY, a_BlockZ, NoteBlockSP);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
- }
- }
- else
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
- {
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- int a_ChunkX, a_ChunkZ;
- cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, a_ChunkX, a_ChunkZ);
-
- if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ))
- {
- m_World.QueueLightChunk(a_ChunkX, a_ChunkZ);
- }
- else
- {
- NIBBLETYPE SkyLight = m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) - m_World.GetSkyDarkness();
- if (SkyLight > 8)
- {
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR);
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType)
-{
- switch (a_MyType)
- {
- case E_BLOCK_STONE_PRESSURE_PLATE:
- {
- // MCS feature - stone pressure plates can only be triggered by players :D
- cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(a_BlockX + 0.5f, (float)a_BlockY, a_BlockZ + 0.5f), 0.5f, false);
-
- if (a_Player != NULL)
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1);
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_STONE_PRESSURE_PLATE);
- }
- else
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
- m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
- }
- break;
- }
- case E_BLOCK_WOODEN_PRESSURE_PLATE:
- {
- class cWoodenPressurePlateCallback :
- public cEntityCallback
- {
- public:
- cWoodenPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
- m_Entity(NULL),
- m_World(a_World),
- m_X(a_BlockX),
- m_Y(a_BlockY),
- m_Z(a_BlockZ)
- {
- }
-
- virtual bool Item(cEntity * a_Entity) override
- {
- Vector3f EntityPos = a_Entity->GetPosition();
- Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
- float Distance = (EntityPos - BlockPos).Length();
-
- if (Distance < 0.5)
- {
- m_Entity = a_Entity;
- return true; // Break out, we only need to know for wooden plates that at least one entity is on top
- }
- return false;
- }
-
- bool FoundEntity(void) const
- {
- return m_Entity != NULL;
- }
-
- protected:
- cEntity * m_Entity;
- cWorld * m_World;
-
- int m_X;
- int m_Y;
- int m_Z;
- } ;
-
- cWoodenPressurePlateCallback WoodenPressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ, &m_World);
- m_World.ForEachEntity(WoodenPressurePlateCallback);
-
- if (WoodenPressurePlateCallback.FoundEntity())
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1);
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WOODEN_PRESSURE_PLATE);
- }
- else
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
- m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
- }
- break;
- }
- default:
- LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str());
- break;
- }
-}
-
-
-
-
-
-bool cRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list
- {
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- return true;
- }
- }
- return false;
-}
-
-
-
-
-
-bool cRedstoneSimulator::AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list
- {
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- return true;
- }
- }
- return false;
-}
-
-
-
-
-
-bool cRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta)
-{
- // Repeaters cannot be powered by any face except their back; verify that this is true for a source
-
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- switch (a_Meta)
- {
- case 0x0:
- {
- // Flip the coords to check the back of the repeater
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; }
- break;
- }
- case 0x1:
- {
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; }
- break;
- }
- case 0x2:
- {
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; }
- break;
- }
- case 0x3:
- {
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; }
- break;
- }
- }
- }
-
- for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- switch (a_Meta)
- {
- case 0x0:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; }
- break;
- }
- case 0x1:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; }
- break;
- }
- case 0x2:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; }
- break;
- }
- case 0x3:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; }
- break;
- }
- }
- }
- return false; // Couldn't find power source behind repeater
-}
-
-
-
-
-bool cRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta)
-{
- // Pistons cannot be powered through their front face; this function verifies that a source meets this requirement
-
- int OldX = a_BlockX, OldY = a_BlockY, OldZ = a_BlockZ;
- eBlockFace Face = cPiston::MetaDataToDirection(a_Meta);
-
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face);
-
- if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- return true;
- }
-
- a_BlockX = OldX;
- a_BlockY = OldY;
- a_BlockZ = OldZ;
- }
-
- for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face);
-
- if (!itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- return true;
- }
-
- a_BlockX = OldX;
- a_BlockY = OldY;
- a_BlockZ = OldZ;
- }
- return false; // Source was in front of the piston's front face
-}
-
-
-
-
-bool cRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
- {
- return true;
- }
- }
-
- for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
- {
- return true;
- }
- }
- return false; // Source was in front of the piston's front face
-}
-
-
-
-
-
-bool cRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered)
-{
- for (SimulatedPlayerToggleableList::const_iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr)
- {
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- if (itr->WasLastStatePowered != IsCurrentStatePowered) // Was the last power state different to the current?
- {
- return false; // It was, coordinates are no longer simulated
- }
- else
- {
- return true; // It wasn't, don't resimulate block, and allow players to toggle
- }
- }
- }
- return false; // Block wasn't even in the list, not simulated
-}
-
-
-
-
-
-void cRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType)
-{
- switch (a_Direction)
- {
- case BLOCK_FACE_XM:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ);
-
- SetBlockLinkedPowered(a_BlockX - 2, a_BlockY, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- case BLOCK_FACE_XP:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ);
-
- SetBlockLinkedPowered(a_BlockX + 2, a_BlockY, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- case BLOCK_FACE_YM:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
-
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 2, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- case BLOCK_FACE_YP:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
-
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 2, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- case BLOCK_FACE_ZM:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1);
-
- SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ - 2, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- case BLOCK_FACE_ZP:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1);
-
- SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ + 2, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- default:
- {
- ASSERT(!"Unhandled face direction when attempting to set blocks as linked powered!"); // Zombies, that wasn't supposed to happen...
- break;
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock)
-{
- 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 }
- };
-
- for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions
- {
- SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock)
-{
- BLOCKTYPE Block = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- if (Block == E_BLOCK_AIR)
- {
- // Don't set air, fixes some bugs (wires powering themselves)
- return;
- }
-
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list
- {
- if (
- itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
- itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))
- )
- {
- // Check for duplicates
- return;
- }
- }
-
- sPoweredBlocks RC;
- RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
- RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
- m_PoweredBlocks.push_back(RC);
-}
-
-
-
-
-
-void cRedstoneSimulator::SetBlockLinkedPowered(
- int a_BlockX, int a_BlockY, int a_BlockZ,
- int a_MiddleX, int a_MiddleY, int a_MiddleZ,
- int a_SourceX, int a_SourceY, int a_SourceZ,
- BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock
-)
-{
- BLOCKTYPE DestBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- if (DestBlock == E_BLOCK_AIR)
- {
- // Don't set air, fixes some bugs (wires powering themselves)
- return;
- }
- if (!IsViableMiddleBlock(a_MiddleBlock))
- {
- return;
- }
-
- for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list
- {
- if (
- itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
- itr->a_MiddlePos.Equals(Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ)) &&
- itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))
- )
- {
- // Check for duplicates
- return;
- }
- }
-
- sLinkedPoweredBlocks RC;
- RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
- RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ);
- RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
- m_LinkedPoweredBlocks.push_back(RC);
-}
-
-
-
-
-
-void cRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered)
-{
- for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- 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_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
- RC.WasLastStatePowered = WasLastStatePowered;
- m_SimulatedPlayerToggleableBlocks.push_back(RC);
-}
-
-
-
-
-
-void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn)
-{
- for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
- {
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- if (ShouldPowerOn == itr->ShouldPowerOn) // We are queued already for the same thing, don't replace entry
- {
- return;
- }
-
- // 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) + (ShouldPowerOn ? 1 : 0)) * 2; // See below for description
- itr->a_ElapsedTicks = 0;
- itr->ShouldPowerOn = ShouldPowerOn;
- return;
- }
- }
-
- // Self not in list, add self to list
- sRepeatersDelayList RC;
- RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
-
- // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.)
- // * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed
- // We don't +1 when powering off because everything seems to already delay a tick when powering off, why? No idea :P
- RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2;
-
-
- RC.a_ElapsedTicks = 0;
- RC.ShouldPowerOn = ShouldPowerOn;
- m_RepeatersDelayList.push_back(RC);
- return;
-}
-
-
-
-
-
-cRedstoneSimulator::eRedstoneDirection cRedstoneSimulator::GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- int Dir = REDSTONE_NONE;
-
- BLOCKTYPE NegX = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ);
- if (IsPotentialSource(NegX))
- {
- Dir |= (REDSTONE_X_POS);
- }
-
- BLOCKTYPE PosX = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ);
- if (IsPotentialSource(PosX))
- {
- Dir |= (REDSTONE_X_NEG);
- }
-
- BLOCKTYPE NegZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1);
- if (IsPotentialSource(NegZ))
- {
- if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
- {
- Dir ^= REDSTONE_X_POS;
- Dir |= REDSTONE_X_NEG;
- }
- if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
- {
- Dir ^= REDSTONE_X_NEG;
- Dir |= REDSTONE_X_POS;
- }
- Dir |= REDSTONE_Z_POS;
- }
-
- BLOCKTYPE PosZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 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;
- }
- return (eRedstoneDirection)Dir;
-}
-
-
-
-
-
-bool cRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta)
-{
- // Extract the ON bit from metadata and return if true if it is set:
- return ((a_BlockMeta & 0x8) == 0x8);
-}
-
-
-
-
-
-bool cRedstoneSimulator::IsButtonOn(NIBBLETYPE a_BlockMeta)
-{
- return IsLeverOn(a_BlockMeta);
-}
-
-
-
-