diff options
author | Tiger Wang <ziwei.tiger@hotmail.co.uk> | 2014-07-18 21:10:51 +0200 |
---|---|---|
committer | Tiger Wang <ziwei.tiger@hotmail.co.uk> | 2014-07-18 21:10:51 +0200 |
commit | 37140ae57835680d2c4fb3aa365082622d3a150e (patch) | |
tree | 89a636c74375b3c9f0fe77b20ecbadc693bd0989 /src/Simulator | |
parent | Merge branch 'master' of https://github.com/mc-server/MCServer into portals (diff) | |
parent | Monster fixes (diff) | |
download | cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar.gz cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar.bz2 cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar.lz cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar.xz cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar.zst cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.zip |
Diffstat (limited to '')
-rw-r--r-- | src/Simulator/DelayedFluidSimulator.cpp | 8 | ||||
-rw-r--r-- | src/Simulator/DelayedFluidSimulator.h | 4 | ||||
-rw-r--r-- | src/Simulator/FireSimulator.cpp | 6 | ||||
-rw-r--r-- | src/Simulator/FloodyFluidSimulator.cpp | 62 | ||||
-rw-r--r-- | src/Simulator/FluidSimulator.cpp | 16 | ||||
-rw-r--r-- | src/Simulator/IncrementalRedstoneSimulator.cpp | 552 | ||||
-rw-r--r-- | src/Simulator/IncrementalRedstoneSimulator.h | 64 | ||||
-rw-r--r-- | src/Simulator/NoopFluidSimulator.h | 2 | ||||
-rw-r--r-- | src/Simulator/NoopRedstoneSimulator.h | 4 | ||||
-rw-r--r-- | src/Simulator/SandSimulator.h | 2 | ||||
-rw-r--r-- | src/Simulator/Simulator.h | 2 | ||||
-rw-r--r-- | src/Simulator/VaporizeFluidSimulator.cpp | 4 |
12 files changed, 478 insertions, 248 deletions
diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp index 5ff736231..59ea51aa0 100644 --- a/src/Simulator/DelayedFluidSimulator.cpp +++ b/src/Simulator/DelayedFluidSimulator.cpp @@ -14,7 +14,7 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cDelayedFluidSimulatorChunkData::cSlot bool cDelayedFluidSimulatorChunkData::cSlot::Add(int a_RelX, int a_RelY, int a_RelZ) @@ -40,7 +40,7 @@ bool cDelayedFluidSimulatorChunkData::cSlot::Add(int a_RelX, int a_RelY, int a_R -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cDelayedFluidSimulatorChunkData: cDelayedFluidSimulatorChunkData::cDelayedFluidSimulatorChunkData(int a_TickDelay) : @@ -62,7 +62,7 @@ cDelayedFluidSimulatorChunkData::~cDelayedFluidSimulatorChunkData() -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cDelayedFluidSimulator: cDelayedFluidSimulator::cDelayedFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, int a_TickDelay) : @@ -131,7 +131,7 @@ void cDelayedFluidSimulator::Simulate(float a_Dt) void cDelayedFluidSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) -{ +{ void * ChunkDataRaw = (m_FluidBlock == E_BLOCK_WATER) ? a_Chunk->GetWaterSimulatorData() : a_Chunk->GetLavaSimulatorData(); cDelayedFluidSimulatorChunkData * ChunkData = (cDelayedFluidSimulatorChunkData *)ChunkDataRaw; cDelayedFluidSimulatorChunkData::cSlot & Slot = ChunkData->m_Slots[m_SimSlotNum]; diff --git a/src/Simulator/DelayedFluidSimulator.h b/src/Simulator/DelayedFluidSimulator.h index c81500741..8a6c26c7a 100644 --- a/src/Simulator/DelayedFluidSimulator.h +++ b/src/Simulator/DelayedFluidSimulator.h @@ -50,7 +50,7 @@ class cDelayedFluidSimulator : { typedef cFluidSimulator super; -public: +public: cDelayedFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, int a_TickDelay); // cSimulator overrides: @@ -70,7 +70,7 @@ protected: /* Slots: | 0 | 1 | ... | m_AddSlotNum | m_SimSlotNum | ... | m_TickDelay - 1 | - adding blocks here ^ | ^ simulating here + | adding blocks here ^ | ^ simulating here */ /// Called from SimulateChunk() to simulate each block in one slot of blocks. Descendants override this method to provide custom simulation. diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index 311f8b4c4..9433a8c68 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -63,7 +63,7 @@ static const struct -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cFireSimulator: cFireSimulator::cFireSimulator(cWorld & a_World, cIniFile & a_IniFile) : @@ -306,14 +306,14 @@ void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int // No need to check the coords for equality with the parent block, // it cannot catch fire anyway (because it's not an air block) - if (m_World.GetTickRandomNumber(MAX_CHANCE_FLAMMABILITY) > m_Flammability) + if (m_World.GetTickRandomNumber(MAX_CHANCE_FLAMMABILITY) > m_Flammability) { continue; } // Start the fire in the neighbor {x, y, z} /* - FLOG("FS: Trying to start fire at {%d, %d, %d}.", + FLOG("FS: Trying to start fire at {%d, %d, %d}.", x + a_Chunk->GetPosX() * cChunkDef::Width, y, z + a_Chunk->GetPosZ() * cChunkDef::Width ); */ diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index e95af3a1c..2c5c4b658 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -48,7 +48,7 @@ cFloodyFluidSimulator::cFloodyFluidSimulator( void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) { - FLOG("Simulating block {%d, %d, %d}: block %d, meta %d", + FLOG("Simulating block {%d, %d, %d}: block %d, meta %d", a_Chunk->GetPosX() * cChunkDef::Width + a_RelX, a_RelY, a_Chunk->GetPosZ() * cChunkDef::Width + a_RelZ, a_Chunk->GetBlock(a_RelX, a_RelY, a_RelZ), a_Chunk->GetMeta(a_RelX, a_RelY, a_RelZ) @@ -217,14 +217,20 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i { ASSERT(a_NewMeta <= 8); // Invalid meta values ASSERT(a_NewMeta > 0); // Source blocks aren't spread - - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if (!a_NearChunk->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta)) + + a_NearChunk = a_NearChunk->GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + if ((a_NearChunk == NULL) || (!a_NearChunk->IsValid())) { // Chunk not available return; } + + const int BlockX = a_NearChunk->GetPosX() * cChunkDef::Width + a_RelX; + const int BlockZ = a_NearChunk->GetPosZ() * cChunkDef::Width + a_RelZ; + + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + a_NearChunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta); if (IsAllowedBlock(BlockType)) { @@ -242,19 +248,13 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i { // Lava flowing into water, change to stone / cobblestone based on direction: BLOCKTYPE NewBlock = (a_NewMeta == 8) ? E_BLOCK_STONE : E_BLOCK_COBBLESTONE; - FLOG(" Lava flowing into water, turning water at rel {%d, %d, %d} into stone", + FLOG(" Lava flowing into water, turning water at rel {%d, %d, %d} into stone", a_RelX, a_RelY, a_RelZ, ItemTypeToString(NewBlock).c_str() ); - a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); + a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); - int BaseX = a_NearChunk->GetPosX() * cChunkDef::Width; - int BaseZ = a_NearChunk->GetPosZ() * cChunkDef::Width; - - BaseX += a_RelX; - BaseZ += a_RelZ; - - a_NearChunk->BroadcastSoundEffect("random.fizz", BaseX * 8, a_RelY * 8, BaseZ * 8, 0.5f, 1.5f); + a_NearChunk->BroadcastSoundEffect("random.fizz", (double)BlockX, (double)a_RelY, (double)BlockZ, 0.5f, 1.5f); return; } } @@ -264,18 +264,12 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i { // Water flowing into lava, change to cobblestone / obsidian based on dest block: BLOCKTYPE NewBlock = (BlockMeta == 0) ? E_BLOCK_OBSIDIAN : E_BLOCK_COBBLESTONE; - FLOG(" Water flowing into lava, turning lava at rel {%d, %d, %d} into %s", + FLOG(" Water flowing into lava, turning lava at rel {%d, %d, %d} into %s", a_RelX, a_RelY, a_RelZ, ItemTypeToString(NewBlock).c_str() ); - a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); - - int BaseX = a_NearChunk->GetPosX() * cChunkDef::Width; - int BaseZ = a_NearChunk->GetPosZ() * cChunkDef::Width; - - BaseX += a_RelX; - BaseZ += a_RelZ; + a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); - a_NearChunk->BroadcastSoundEffect("random.fizz", BaseX * 8, a_RelY * 8, BaseZ * 8, 0.5f, 1.5f); + a_NearChunk->BroadcastSoundEffect("random.fizz", (double)BlockX, (double)a_RelY, (double)BlockZ, 0.5f, 1.5f); return; } } @@ -302,22 +296,18 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i ChunkInterface, m_World, PluginInterface, - NULL, - a_NearChunk->GetPosX() * cChunkDef::Width + a_RelX, + NULL, + BlockX, a_RelY, - a_NearChunk->GetPosZ() * cChunkDef::Width + a_RelZ + BlockZ ); } } // if (CanWashAway) - + // Spread: - FLOG(" Spreading to {%d, %d, %d} with meta %d", - a_NearChunk->GetPosX() * cChunkDef::Width + a_RelX, - a_RelY, - a_NearChunk->GetPosZ() * cChunkDef::Width + a_RelZ, - a_NewMeta - ); - a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); + FLOG(" Spreading to {%d, %d, %d} with meta %d", BlockX, a_RelY, BlockZ, a_NewMeta); + a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); + m_World.GetSimulatorManager()->WakeUp(BlockX, a_RelY, BlockZ, a_NearChunk); HardenBlock(a_NearChunk, a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); } @@ -409,13 +399,13 @@ bool cFloodyFluidSimulator::HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY if (a_Meta == 0) { // Source lava block - a_Chunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_OBSIDIAN, 0); + a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_OBSIDIAN, 0); return true; } // Ignore last lava level else if (a_Meta <= 4) { - a_Chunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_COBBLESTONE, 0); + a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_COBBLESTONE, 0); return true; } } diff --git a/src/Simulator/FluidSimulator.cpp b/src/Simulator/FluidSimulator.cpp index f64955cb2..499e204a1 100644 --- a/src/Simulator/FluidSimulator.cpp +++ b/src/Simulator/FluidSimulator.cpp @@ -125,31 +125,31 @@ Direction cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a return NONE; } BLOCKTYPE BlockID = m_World.GetBlock(a_X, a_Y, a_Z); - if (!IsAllowedBlock(BlockID)) // No Fluid -> No Flowing direction :D + if (!IsAllowedBlock(BlockID)) // No Fluid -> No Flowing direction :D { return NONE; } /* Disabled because of causing problems and being useless atm - char BlockBelow = m_World.GetBlock(a_X, a_Y - 1, a_Z); //If there is nothing or fluid below it -> dominating flow is down :D + char BlockBelow = m_World.GetBlock(a_X, a_Y - 1, a_Z); // If there is nothing or fluid below it -> dominating flow is down :D if (BlockBelow == E_BLOCK_AIR || IsAllowedBlock(BlockBelow)) return Y_MINUS; */ - NIBBLETYPE LowestPoint = m_World.GetBlockMeta(a_X, a_Y, a_Z); //Current Block Meta so only lower points will be counted - int X = 0, Z = 0; //Lowest Pos will be stored here + NIBBLETYPE LowestPoint = m_World.GetBlockMeta(a_X, a_Y, a_Z); // Current Block Meta so only lower points will be counted + int X = 0, Z = 0; // Lowest Pos will be stored here - if (IsAllowedBlock(m_World.GetBlock(a_X, a_Y + 1, a_Z)) && a_Over) //check for upper block to flow because this also affects the flowing direction + if (IsAllowedBlock(m_World.GetBlock(a_X, a_Y + 1, a_Z)) && a_Over) // check for upper block to flow because this also affects the flowing direction { return GetFlowingDirection(a_X, a_Y + 1, a_Z, false); } std::vector< Vector3i * > Points; - Points.reserve(4); //Already allocate 4 places :D + Points.reserve(4); // Already allocate 4 places :D - //add blocks around the checking pos + // add blocks around the checking pos Points.push_back(new Vector3i(a_X - 1, a_Y, a_Z)); Points.push_back(new Vector3i(a_X + 1, a_Y, a_Z)); Points.push_back(new Vector3i(a_X, a_Y, a_Z + 1)); @@ -172,7 +172,7 @@ Direction cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a } else if(BlockID == E_BLOCK_AIR) { - LowestPoint = 9; //This always dominates + LowestPoint = 9; // This always dominates X = Pos->x; Z = Pos->z; diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 10446a879..3dd6417dc 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -2,8 +2,10 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "IncrementalRedstoneSimulator.h" +#include "BoundingBox.h" #include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/NoteEntity.h" +#include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../Entities/TNTEntity.h" #include "../Entities/Pickup.h" @@ -12,10 +14,11 @@ #include "../Blocks/BlockButton.h" #include "../Blocks/BlockLever.h" #include "../Blocks/BlockPiston.h" +#include "../Blocks/BlockTripwireHook.h" + - cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulator(cWorld & a_World) : super(a_World), @@ -56,17 +59,19 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, // Use that Chunk pointer to get a relative position int RelX = 0; - int RelZ = 0; + int RelZ = 0; BLOCKTYPE Block; NIBBLETYPE Meta; - cChunk * OtherChunk = a_Chunk; if (a_OtherChunk != NULL) { RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width; RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width; a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); - OtherChunk = a_OtherChunk; + + // If a_OtherChunk is passed (not NULL), it is the chunk that had a block change, and a_Chunk will be the neighbouring chunk of that block + // 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); } else { @@ -91,43 +96,21 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, { LOGD("cIncrementalRedstoneSimulator: 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); itr = PoweredBlocks->erase(itr); - a_Chunk->SetIsRedstoneDirty(true); - OtherChunk->SetIsRedstoneDirty(true); continue; } 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_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)) || - (((Block == E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE) || (Block == E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE)) && (Meta == 0)) + ((Block == E_BLOCK_TRIPWIRE_HOOK) && ((Meta & 0x08) == 0)) ) { LOGD("cIncrementalRedstoneSimulator: 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); itr = PoweredBlocks->erase(itr); - a_Chunk->SetIsRedstoneDirty(true); - OtherChunk->SetIsRedstoneDirty(true); continue; } - else if (Block == E_BLOCK_DAYLIGHT_SENSOR) - { - if (!m_World.IsChunkLighted(OtherChunk->GetPosX(), OtherChunk->GetPosZ())) - { - m_World.QueueLightChunk(OtherChunk->GetPosX(), OtherChunk->GetPosZ()); - } - else - { - if (OtherChunk->GetTimeAlteredLight(OtherChunk->GetSkyLight(RelX, a_BlockY + 1, RelZ)) <= 7) - { - itr = PoweredBlocks->erase(itr); - a_Chunk->SetIsRedstoneDirty(true); - OtherChunk->SetIsRedstoneDirty(true); - continue; - } - } - } ++itr; } @@ -141,23 +124,17 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, { LOGD("cIncrementalRedstoneSimulator: 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); itr = LinkedPoweredBlocks->erase(itr); - a_Chunk->SetIsRedstoneDirty(true); - OtherChunk->SetIsRedstoneDirty(true); continue; } 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))) || - (((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0)) || - (((Block == E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE) || (Block == E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE)) && (Meta == 0)) + (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ) { LOGD("cIncrementalRedstoneSimulator: 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); itr = LinkedPoweredBlocks->erase(itr); - a_Chunk->SetIsRedstoneDirty(true); - OtherChunk->SetIsRedstoneDirty(true); continue; } } @@ -167,8 +144,6 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, { LOGD("cIncrementalRedstoneSimulator: 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); itr = LinkedPoweredBlocks->erase(itr); - a_Chunk->SetIsRedstoneDirty(true); - OtherChunk->SetIsRedstoneDirty(true); continue; } } @@ -215,16 +190,16 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, cRedstoneSimulatorChunkData * RedstoneSimulatorChunkData = a_Chunk->GetRedstoneSimulatorData(); for (cRedstoneSimulatorChunkData::iterator itr = RedstoneSimulatorChunkData->begin(); itr != RedstoneSimulatorChunkData->end(); ++itr) { - if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) // We are at an entry matching the current (changed) block + if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) // We are at an entry matching the current (changed) block { if (!IsAllowedBlock(Block)) { - itr->DataTwo = true; // The new blocktype is not redstone; it must be queued to be removed from this list + itr->DataTwo = true; // The new blocktype is not redstone; it must be queued to be removed from this list } else { itr->DataTwo = false; - itr->Data = Block; // Update block information + itr->Data = Block; // Update block information } return; } @@ -289,6 +264,9 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int switch (dataitr->Data) { case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_TRIPWIRE: HandleTripwire(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_TRIPWIRE_HOOK: HandleTripwireHook(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_WOODEN_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: @@ -303,7 +281,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int if (ShouldUpdateSimulateOnceBlocks) { switch (dataitr->Data) - { + { case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(dataitr->x, dataitr->y, dataitr->z); break; case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(dataitr->x, dataitr->y, dataitr->z); break; case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(dataitr->x, dataitr->y, dataitr->z); break; @@ -312,6 +290,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int case E_BLOCK_FENCE_GATE: HandleFenceGate(dataitr->x, dataitr->y, dataitr->z); break; case E_BLOCK_TNT: HandleTNT(dataitr->x, dataitr->y, dataitr->z); break; case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_TRAPPED_CHEST: HandleTrappedChest(dataitr->x, dataitr->y, dataitr->z); break; case E_BLOCK_ACTIVATOR_RAIL: case E_BLOCK_DETECTOR_RAIL: @@ -374,18 +353,13 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) { - if ( - ((a_BlockX % cChunkDef::Width) <= 1) || - ((a_BlockX % cChunkDef::Width) >= 14) || - ((a_BlockZ % cChunkDef::Width) <= 1) || - ((a_BlockZ % cChunkDef::Width) >= 14) - ) // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks + if (AreCoordsOnChunkBoundary(a_BlockX, a_BlockY, a_BlockZ)) { // On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk) AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); // 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 coordiantes are in and +- 2 in GetNeighbour() to accomodate for LinkedPowered blocks being 2 away from chunk boundaries + // 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); @@ -404,7 +378,7 @@ void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_Blo void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) { - static const struct // Define which directions the torch can power + static const struct // Define which directions the torch can power { int x, y, z; } gCrossCoords[] = @@ -418,11 +392,17 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R if (a_MyState == E_BLOCK_REDSTONE_TORCH_ON) { - // Check if the block the torch is on is powered + // Check if the block the torch is on is powered int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ; - AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on + AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on + + cChunk * Neighbour = m_Chunk->GetRelNeighborChunk(X, Z); + if ((Neighbour == NULL) || !Neighbour->IsValid()) + { + return; + } - if (AreCoordsDirectlyPowered(X, Y, Z)) + if (AreCoordsDirectlyPowered(X, Y, Z, Neighbour)) { // There was a match, torch goes off m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); @@ -437,11 +417,11 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R { continue; } - if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last) + 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_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on + IsMechanism(Type) && // Is it a mechanism? Not block/other torch etc. + (!Vector3i(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on ) { SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ); @@ -456,11 +436,11 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R } } - if (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath + if (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath { BLOCKTYPE Type = m_Chunk->GetBlock(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ); - if ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) // Still can't make a normal block powered though! + if (IsMechanism(Type)) // Still can't make a normal block powered though! { SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); } @@ -468,14 +448,20 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R } else { - // Check if the block the torch is on is powered + // Check if the block the torch is on is powered int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ; - AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on - + AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on + + cChunk * Neighbour = m_Chunk->GetRelNeighborChunk(X, Z); + if ((Neighbour == NULL) || !Neighbour->IsValid()) + { + return; + } + // See if off state torch can be turned on again - if (AreCoordsDirectlyPowered(X, Y, Z)) + if (AreCoordsDirectlyPowered(X, Y, Z, Neighbour)) { - return; // Something matches, torch still powered + return; // Something matches, torch still powered } // Block torch on not powered, can be turned on again! @@ -490,7 +476,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R void cIncrementalRedstoneSimulator::HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Set self as powered + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Set self as powered } @@ -571,7 +557,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_RelBlockX, int a_ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - static const struct // Define which directions the wire can receive power from + static const struct // Define which directions the wire can receive power from { int x, y, z; } gCrossCoords[] = @@ -590,7 +576,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re { 0,-1, -1}, /* Wires one lower, surrounding self stop */ } ; - static const struct // Define which directions the wire will check for repeater prescence + static const struct // Define which directions the wire will check for repeater prescence { int x, y, z; } gSideCoords[] = @@ -622,9 +608,9 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re MyPower--; - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power + 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 ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above... { BLOCKTYPE Type = 0; if (a_RelBlockY + 1 >= cChunkDef::Height) @@ -635,12 +621,12 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re { continue; } - if (cBlockInfo::IsSolid(Type)) // If there is something solid above us (wire cut off)... + if (cBlockInfo::IsSolid(Type)) // If there is something solid above us (wire cut off)... { - continue; // We don't receive power from that wire + continue; // We don't receive power from that wire } } - else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us + 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)) @@ -664,7 +650,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re } } - for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them + 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)) @@ -738,7 +724,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int X Axis ----> - Repeater directions, values from a cWorld::GetBlockMeta(a_RelBlockX , a_RelBlockY, a_RelBlockZ) lookup: + Repeater directions, values from a cWorld::GetBlockMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) lookup: East (Right) (X+): 0x1 West (Left) (X-): 0x3 @@ -753,15 +739,15 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int // Create a variable holding my meta to avoid multiple lookups. NIBBLETYPE a_Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); bool IsOn = (a_MyState == E_BLOCK_REDSTONE_REPEATER_ON); - - if (!IsRepeaterLocked(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta)) // If we're locked, change nothing. Otherwise: + + if (!IsRepeaterLocked(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta)) // If we're locked, change nothing. Otherwise: { bool IsSelfPowered = IsRepeaterPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta); - if (IsSelfPowered && !IsOn) // Queue a power change if powered, but not on and not locked. + if (IsSelfPowered && !IsOn) // Queue a power change if powered, but not on and not locked. { QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, true); } - else if (!IsSelfPowered && IsOn) // Queue a power change if unpowered, on, and not locked. + else if (!IsSelfPowered && IsOn) // Queue a power change if unpowered, on, and not locked. { QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, false); } @@ -772,19 +758,22 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays() { for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end();) { - - if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks? + if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks? { int RelBlockX = itr->a_RelBlockPos.x; int RelBlockY = itr->a_RelBlockPos.y; int RelBlockZ = itr->a_RelBlockPos.z; - NIBBLETYPE Meta = m_Chunk->GetMeta(RelBlockX, RelBlockY, RelBlockZ); + BLOCKTYPE Block; + NIBBLETYPE Meta; + m_Chunk->GetBlockTypeMeta(RelBlockX, RelBlockY, RelBlockZ, Block, Meta); if (itr->ShouldPowerOn) { - - m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta); // For performance + if (Block != E_BLOCK_REDSTONE_REPEATER_ON) // For performance + { + m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta); + } - switch (Meta & 0x3) // We only want the direction (bottom) bits + switch (Meta & 0x3) // We only want the direction (bottom) bits { case 0x0: { @@ -812,7 +801,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays() } } } - else + else if (Block != E_BLOCK_REDSTONE_REPEATER_OFF) { m_Chunk->SetBlock(RelBlockX, RelBlockY, RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, Meta); } @@ -820,9 +809,6 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays() } 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_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks); itr->a_ElapsedTicks++; itr++; @@ -835,11 +821,11 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays() void cIncrementalRedstoneSimulator::HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) -{ +{ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - if (IsPistonPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness) + if (IsPistonPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness) { cBlockPistonHandler::ExtendPiston(BlockX, a_RelBlockY, BlockZ, &m_World); } @@ -907,7 +893,7 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_RelBlockX, int a_RelBlockY, if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - m_Chunk->BroadcastSoundEffect("game.tnt.primed", BlockX * 8, a_RelBlockY * 8, BlockZ * 8, 0.5f, 0.6f); + m_Chunk->BroadcastSoundEffect("game.tnt.primed", (double)BlockX, (double)a_RelBlockY, (double)BlockZ, 0.5f, 0.6f); m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_AIR, 0); m_World.SpawnPrimedTNT(BlockX + 0.5, a_RelBlockY + 0.5, BlockZ + 0.5); // 80 ticks to boom } @@ -1120,7 +1106,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R 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(BlockX + 0.5f, (float)a_RelBlockY, BlockZ + 0.5f), 0.7f, false); + cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(BlockX + 0.5f, (float)a_RelBlockY, BlockZ + 0.5f), 0.5f, false); if (a_Player != NULL) { @@ -1131,7 +1117,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R else { m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); - m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); + SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk); } break; } @@ -1155,7 +1141,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); double Distance = (EntityPos - BlockPos).Length(); - if (Distance <= 0.7) + if (Distance <= 0.5) { m_NumberOfEntities++; } @@ -1177,7 +1163,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R }; cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - m_World.ForEachEntity(PressurePlateCallback); + m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); unsigned char Power; NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); @@ -1185,7 +1171,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R { if (Meta == E_META_PRESSURE_PLATE_RAISED) { - m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F); + m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.5F); } m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); @@ -1195,10 +1181,10 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R { if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) { - m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); + m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.6F); } m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); + SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk); } break; @@ -1223,7 +1209,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); double Distance = (EntityPos - BlockPos).Length(); - if (Distance <= 0.7) + if (Distance <= 0.5) { m_NumberOfEntities++; } @@ -1232,7 +1218,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R bool GetPowerLevel(unsigned char & a_PowerLevel) const { - a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / (float)10), MAX_POWER_LEVEL); + a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / 10.f), MAX_POWER_LEVEL); return (a_PowerLevel > 0); } @@ -1245,7 +1231,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R }; cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - m_World.ForEachEntity(PressurePlateCallback); + m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); unsigned char Power; NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); @@ -1253,7 +1239,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R { if (Meta == E_META_PRESSURE_PLATE_RAISED) { - m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F); + m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.5F); } m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); @@ -1263,10 +1249,10 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R { if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) { - m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); + m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.6F); } m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); + SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk); } break; @@ -1291,10 +1277,10 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); double Distance = (EntityPos - BlockPos).Length(); - if (Distance <= 0.7) + if (Distance <= 0.5) { m_FoundEntity = true; - return true; // Break out, we only need to know for plates that at least one entity is on top + return true; // Break out, we only need to know for plates that at least one entity is on top } return false; } @@ -1313,14 +1299,14 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R } ; cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - m_World.ForEachEntity(PressurePlateCallback); + m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); if (PressurePlateCallback.FoundEntity()) { if (Meta == E_META_PRESSURE_PLATE_RAISED) { - m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F); + m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.5F); } m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); @@ -1330,10 +1316,10 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R { if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) { - m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); + m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.6F); } m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); + SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk); } break; } @@ -1349,20 +1335,190 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R -bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) +void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) +{ + int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX; + int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ; + int RelX = a_RelBlockX, RelZ = a_RelBlockZ; + bool FoundActivated = false; + eBlockFace FaceToGoTowards = cBlockTripwireHookHandler::MetadataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); + + for (int i = 0; i < 40; ++i) // Tripwires can be connected up to 40 blocks + { + BLOCKTYPE Type; + NIBBLETYPE Meta; + + AddFaceDirection(RelX, a_RelBlockY, RelZ, FaceToGoTowards); + m_Chunk->UnboundedRelGetBlock(RelX, a_RelBlockY, RelZ, Type, Meta); + + if (Type == E_BLOCK_TRIPWIRE) + { + if (Meta == 0x1) + { + FoundActivated = true; + } + } + else if (Type == E_BLOCK_TRIPWIRE_HOOK) + { + if (ReverseBlockFace(cBlockTripwireHookHandler::MetadataToDirection(Meta)) == FaceToGoTowards) + { + // Other hook facing in opposite direction - circuit completed! + break; + } + else + { + // Tripwire hook not connected at all, AND away all the power state bits + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3); + SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk); + return; + } + } + else + { + // Tripwire hook not connected at all, AND away all the power state bits + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3); + SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk); + return; + } + } + + if (FoundActivated) + { + // Connected and activated, set the 3rd and 4th highest bits + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0xC); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + } + else + { + // Connected but not activated, AND away the highest bit + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7) | 0x4); + SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk); + } +} + + + + + +void cIncrementalRedstoneSimulator::HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) +{ + class cGetTrappedChestPlayers : + public cChestCallback + { + public: + cGetTrappedChestPlayers(void) : + m_NumberOfPlayers(0) + { + } + + virtual bool Item(cChestEntity * a_Chest) override + { + ASSERT(a_Chest->GetBlockType() == E_BLOCK_TRAPPED_CHEST); + m_NumberOfPlayers = a_Chest->GetNumberOfPlayers(); + return (m_NumberOfPlayers <= 0); + } + + unsigned char GetPowerLevel(void) const + { + return std::min(m_NumberOfPlayers, MAX_POWER_LEVEL); + } + + private: + int m_NumberOfPlayers; + + } GTCP; + + int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX; + int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ; + if (m_Chunk->DoWithChestAt(BlockX, a_RelBlockY, BlockZ, GTCP)) + { + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, GTCP.GetPowerLevel()); + } + else + { + SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk); + } +} + + + + + +void cIncrementalRedstoneSimulator::HandleTripwire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { + int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX; + int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ; + + class cTripwireCallback : + public cEntityCallback + { + public: + cTripwireCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : + m_FoundEntity(false), + m_X(a_BlockX), + m_Y(a_BlockY), + m_Z(a_BlockZ) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + cBoundingBox bbWire(m_X, m_X + 1, m_Y, m_Y + 0.1, m_Z, m_Z + 1); + cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); + + if (bbEntity.DoesIntersect(bbWire)) + { + m_FoundEntity = true; + return true; // One entity is sufficient to trigger the wire + } + return false; + } + + bool FoundEntity(void) const + { + return m_FoundEntity; + } + + protected: + bool m_FoundEntity; + + int m_X; + int m_Y; + int m_Z; + }; + + cTripwireCallback TripwireCallback(BlockX, a_RelBlockY, BlockZ); + m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), TripwireCallback); + + if (TripwireCallback.FoundEntity()) + { + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x1); + } + else + { + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); + } +} + + + + + +bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk) +{ + // Torches want to access neighbour's data when on a wall, hence the extra chunk parameter + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); // Torches want to access neighbour's data when on a wall - for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list + for (PoweredBlocksList::const_iterator itr = a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->begin(); itr != a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->end(); ++itr) // Check powered list { if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { return true; } } - return false; + return false; } @@ -1374,7 +1530,7 @@ bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_RelBlockX, int int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list + for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list { if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { @@ -1452,7 +1608,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel } } } - return false; // Couldn't find power source behind repeater + return false; // Couldn't find power source behind repeater } @@ -1460,8 +1616,8 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_Rel bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) -{ - switch (a_Meta & 0x3) // We only want the 'direction' part of our metadata +{ + switch (a_Meta & 0x3) // We only want the 'direction' part of our metadata { // If the repeater is looking up or down (If parallel to the Z axis) case 0x0: @@ -1469,17 +1625,17 @@ bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_RelBlockX, int a_RelB { // Check if eastern(right) neighbor is a powered on repeater who is facing us BLOCKTYPE Block = 0; - if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) // Is right neighbor a powered repeater? + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) // Is right neighbor a powered repeater? { NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ) & 0x3; - if (OtherRepeaterDir == 0x3) { return true; } // If so, I am latched/locked + if (OtherRepeaterDir == 0x3) { return true; } // If so, I am latched/locked } // Check if western(left) neighbor is a powered on repeater who is facing us if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) { NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX -1, a_RelBlockY, a_RelBlockZ) & 0x3; - if (OtherRepeaterDir == 0x1) { return true; } // If so, I am latched/locked + if (OtherRepeaterDir == 0x1) { return true; } // If so, I am latched/locked } break; @@ -1492,23 +1648,23 @@ bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_RelBlockX, int a_RelB // Check if southern(down) neighbor is a powered on repeater who is facing us BLOCKTYPE Block = 0; if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) - { + { NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1) & 0x3; - if (OtherRepeaterDir == 0x0) { return true; } // If so, am latched/locked + if (OtherRepeaterDir == 0x0) { return true; } // If so, am latched/locked } // Check if northern(up) neighbor is a powered on repeater who is facing us if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) - { + { NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1) & 0x3; - if (OtherRepeaterDir == 0x2) { return true; } // If so, I am latched/locked + if (OtherRepeaterDir == 0x2) { return true; } // If so, I am latched/locked } break; } } - return false; // None of the checks succeeded, I am not a locked repeater + return false; // None of the checks succeeded, I am not a locked repeater } @@ -1549,7 +1705,7 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBl AddFaceDirection(BlockX, a_RelBlockY, BlockZ, Face, true); } - return false; // Source was in front of the piston's front face + return false; // Source was in front of the piston's front face } @@ -1558,28 +1714,36 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBl bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel) { a_PowerLevel = 0; - int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; - int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX; + int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ; - for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list + for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list { if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } - a_PowerLevel = itr->a_PowerLevel; + a_PowerLevel = std::max(itr->a_PowerLevel, a_PowerLevel); // Get the highest power level (a_PowerLevel is initialised already and there CAN be multiple levels for one block) } - for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list + for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list { if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } - a_PowerLevel = itr->a_PowerLevel; + + BLOCKTYPE Type = E_BLOCK_AIR; + int RelSourceX = itr->a_SourcePos.x - m_Chunk->GetPosX() * cChunkDef::Width; + int RelSourceZ = itr->a_SourcePos.z - m_Chunk->GetPosZ() * cChunkDef::Width; + if (!m_Chunk->UnboundedRelGetBlockType(RelSourceX, itr->a_SourcePos.y, RelSourceZ, Type) || (Type == E_BLOCK_REDSTONE_WIRE)) + { + continue; + } + a_PowerLevel = std::max(itr->a_PowerLevel, a_PowerLevel); } - return (a_PowerLevel != 0); // Answer the inital question: is the wire powered? + return (a_PowerLevel != 0); // Answer the inital question: is the wire powered? } @@ -1592,17 +1756,17 @@ bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_RelBlockX, int a_Re { if (itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { - if (itr->WasLastStatePowered != IsCurrentStatePowered) // Was the last power state different to the current? + if (itr->WasLastStatePowered != IsCurrentStatePowered) // Was the last power state different to the current? { - return false; // It was, coordinates are no longer simulated + 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 true; // It wasn't, don't resimulate block, and allow players to toggle } } } - return false; // Block wasn't even in the list, not simulated + return false; // Block wasn't even in the list, not simulated } @@ -1706,7 +1870,7 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_RelBlockX, i } default: { - ASSERT(!"Unhandled face direction when attempting to set blocks as linked powered!"); // Zombies, that wasn't supposed to happen... + ASSERT(!"Unhandled face direction when attempting to set blocks as linked powered!"); // Zombies, that wasn't supposed to happen... break; } } @@ -1731,7 +1895,7 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_R { 0, -1, 0 } }; - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions + for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions { SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_PowerLevel); } @@ -1748,20 +1912,14 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBl int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX; int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ; - BLOCKTYPE Block = 0; - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block)) - { - return; - } - if (Block == E_BLOCK_AIR) + cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ); // Adjust coordinates for the later call using these values + if ((Neighbour == NULL) || !Neighbour->IsValid()) { - // Don't set air, fixes some bugs (wires powering themselves) return; } - cChunk * Neighbour = m_Chunk->GetNeighborChunk(BlockX, BlockZ); - PoweredBlocksList * Powered = Neighbour->GetRedstoneSimulatorPoweredBlocksList(); - for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list + PoweredBlocksList * Powered = Neighbour->GetRedstoneSimulatorPoweredBlocksList(); // We need to insert the value into the chunk who owns the block position + for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr) { if ( itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) && @@ -1774,16 +1932,33 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBl } } - PoweredBlocksList * OtherPowered = m_Chunk->GetNeighborChunk(SourceX, SourceZ)->GetRedstoneSimulatorPoweredBlocksList(); - for (PoweredBlocksList::const_iterator itr = OtherPowered->begin(); itr != OtherPowered->end(); ++itr) // Check powered list + // No need to get neighbouring chunk as we can guarantee that when something is powering us, the entry will be in our chunk + // TODO: on C++11 support, change this to a llama function pased to a std::remove_if + for (PoweredBlocksList::iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) { if ( itr->a_BlockPos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) && - itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) + itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) && + (m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE) ) { - // Powered wires try to power their source - don't let them! - return; + BLOCKTYPE Block; + NIBBLETYPE Meta; + Neighbour->GetBlockTypeMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block, Meta); + + if (Block == E_BLOCK_REDSTONE_WIRE) + { + if (Meta < a_PowerLevel) + { + m_PoweredBlocks->erase(itr); // Powering source with higher power level, allow it + break; + } + else + { + // Powered wires try to power their source - don't let them! + return; + } + } } } @@ -1814,26 +1989,17 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX; int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ; - BLOCKTYPE DestBlock = 0; - if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, DestBlock)) - { - return; - } - if (DestBlock == E_BLOCK_AIR) - { - // Don't set air, fixes some bugs (wires powering themselves) - return; - } - if ((DestBlock == E_BLOCK_REDSTONE_WIRE) && (m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE)) + if (!IsViableMiddleBlock(a_MiddleBlock)) { return; } - if (!IsViableMiddleBlock(a_MiddleBlock)) + + cChunk * Neighbour = m_Chunk->GetNeighborChunk(BlockX, BlockZ); + if ((Neighbour == NULL) || !Neighbour->IsValid()) { return; } - cChunk * Neighbour = m_Chunk->GetNeighborChunk(BlockX, BlockZ); LinkedBlocksList * Linked = Neighbour->GetRedstoneSimulatorLinkedBlocksList(); for (LinkedBlocksList::iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list { @@ -1902,13 +2068,13 @@ bool cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, in { if (itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { - if (ShouldPowerOn == itr->ShouldPowerOn) // We are queued already for the same thing, don't replace entry + if (ShouldPowerOn == itr->ShouldPowerOn) // We are queued already for the same thing, don't replace entry { return false; } // Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit - itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; // See below for description + itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; // See below for description itr->a_ElapsedTicks = 0; itr->ShouldPowerOn = ShouldPowerOn; return false; @@ -1916,11 +2082,11 @@ bool cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, in } // Self not in list, add self to list - sRepeatersDelayList RC; + sRepeatersDelayList RC; RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.) - // * 2 because in MCS, 1 redstone tick = 1 world tick, but in Vanilla, 1 redstone tick = 2 world ticks, and we need to maintain compatibility + // Multiply by 2 because in MCS, 1 redstone tick = 1 world tick, but in Vanilla, 1 redstone tick = 2 world ticks, and we need to maintain compatibility RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; RC.a_ElapsedTicks = 0; @@ -1933,6 +2099,52 @@ bool cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, in +void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_SourceX, int a_SourceY, int a_SourceZ, cChunk * a_Chunk, bool a_IsFirstCall) +{ + if (!a_IsFirstCall) // The neighbouring chunks passed when this parameter is false may be invalid + { + if ((a_Chunk == NULL) || !a_Chunk->IsValid()) + { + return; + } + } + // TODO: on C++11 support, change both of these to llama functions pased to a std::remove_if + + for (PoweredBlocksList::iterator itr = a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->begin(); itr != a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->end();) + { + if (itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))) + { + itr = a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->erase(itr); + a_Chunk->SetIsRedstoneDirty(true); + continue; + } + ++itr; + } + for (LinkedBlocksList::iterator itr = a_Chunk->GetRedstoneSimulatorLinkedBlocksList()->begin(); itr != a_Chunk->GetRedstoneSimulatorLinkedBlocksList()->end();) + { + if (itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))) + { + itr = a_Chunk->GetRedstoneSimulatorLinkedBlocksList()->erase(itr); + a_Chunk->SetIsRedstoneDirty(true); + continue; + } + ++itr; + } + + if (a_IsFirstCall && AreCoordsOnChunkBoundary(a_SourceX, a_SourceY, a_SourceZ)) + { + // +- 2 to accomodate linked powered blocks + SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX - 2, a_SourceZ), false); + SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX + 2, a_SourceZ), false); + SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX, a_SourceZ - 2), false); + SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX, a_SourceZ + 2), false); + } +} + + + + + cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { int Dir = REDSTONE_NONE; diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index 9c1f9460c..79740a8f6 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -38,33 +38,33 @@ private: #define MAX_POWER_LEVEL 15 - struct sPoweredBlocks // Define structure of the directly powered blocks list + struct sPoweredBlocks // Define structure of the directly powered blocks list { - Vector3i a_BlockPos; // Position of powered block - Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos + Vector3i a_BlockPos; // Position of powered block + Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos unsigned char a_PowerLevel; }; - struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side) + struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side) { Vector3i a_BlockPos; - Vector3i a_MiddlePos; // Position of block that is betwixt a source and the destination + Vector3i a_MiddlePos; // Position of block that is betwixt a source and the destination Vector3i a_SourcePos; unsigned char a_PowerLevel; }; - struct sSimulatedPlayerToggleableList // Define structure of the list containing simulate-on-update blocks (such as trapdoors that respond once to a block update, and can be toggled by a player) + struct sSimulatedPlayerToggleableList // Define structure of the list containing simulate-on-update blocks (such as trapdoors that respond once to a block update, and can be toggled by a player) { Vector3i a_RelBlockPos; - bool WasLastStatePowered; // Was the last state powered or not? Determines whether a source update has happened and if I should resimulate + bool WasLastStatePowered; // Was the last state powered or not? Determines whether a source update has happened and if I should resimulate }; - struct sRepeatersDelayList // Define structure of list containing repeaters' delay states + struct sRepeatersDelayList // Define structure of list containing repeaters' delay states { Vector3i a_RelBlockPos; - unsigned char a_DelayTicks; // For how many ticks should the repeater delay - unsigned char a_ElapsedTicks; // How much of the previous has been elapsed? - bool ShouldPowerOn; // What happens when the delay time is fulfilled? + unsigned char a_DelayTicks; // For how many ticks should the repeater delay + unsigned char a_ElapsedTicks; // How much of the previous has been elapsed? + bool ShouldPowerOn; // What happens when the delay time is fulfilled? }; public: @@ -102,6 +102,13 @@ private: void HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles pressure plates */ void HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType); + /** Handles tripwire hooks + Performs correct meta and power setting for self by going in the direction it faces and looking for a continous line of tripwire bounded by another oppositely facing hook + If this line is complete, it verifies that at least on wire reports an entity is on top (via its meta), and performs its task + */ + void HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); + /** Handles trapped chests */ + void HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /* ==================== */ /* ====== CARRIERS ====== */ @@ -109,8 +116,6 @@ private: void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles repeaters */ void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); - /** Handles delayed updates to Repeaters **/ - void HandleRedstoneRepeaterDelays(); /* ====================== */ /* ====== DEVICES ====== */ @@ -134,6 +139,8 @@ private: void HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles noteblocks */ void HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); + /** Handles tripwires */ + void HandleTripwire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /* ===================== */ /* ====== Helper functions ====== */ @@ -149,11 +156,15 @@ private: void SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Queues a repeater to be powered or unpowered and returns if the m_RepeatersDelayList iterators were invalidated */ bool QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); + /** Removes a block from the Powered and LinkedPowered lists + Used for variable sources such as tripwire hooks, daylight sensors, and trapped chests + */ + void SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk, bool a_IsFirstCall = true); /** 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) || 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); } /** Returns if a coordinate is in the directly powered blocks list */ - bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); + bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk); /** Returns if a coordinate is in the indirectly powered blocks list */ bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */ @@ -167,7 +178,8 @@ private: /** Returns if a wire is powered The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire */ bool IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel); - + /** Handles delayed updates to repeaters **/ + void HandleRedstoneRepeaterDelays(void); /** Returns if lever metadata marks it as emitting power */ bool IsLeverOn(NIBBLETYPE a_BlockMeta); @@ -179,7 +191,9 @@ private: /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */ inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return cBlockInfo::FullyOccupiesVoxel(Block); } - /** 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 + */ inline static bool IsMechanism(BLOCKTYPE Block) { switch (Block) @@ -202,6 +216,7 @@ private: case E_BLOCK_REDSTONE_REPEATER_OFF: case E_BLOCK_REDSTONE_REPEATER_ON: case E_BLOCK_POWERED_RAIL: + case E_BLOCK_REDSTONE_WIRE: { return true; } @@ -228,6 +243,7 @@ private: case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_WOODEN_PRESSURE_PLATE: + case E_BLOCK_TRAPPED_CHEST: { return true; } @@ -270,17 +286,29 @@ private: case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_TNT: case E_BLOCK_TRAPDOOR: + case E_BLOCK_TRAPPED_CHEST: case E_BLOCK_TRIPWIRE_HOOK: + case E_BLOCK_TRIPWIRE: case E_BLOCK_WOODEN_BUTTON: case E_BLOCK_WOODEN_DOOR: case E_BLOCK_WOODEN_PRESSURE_PLATE: case E_BLOCK_PISTON: { - return true; + return true; } default: return false; } } + + inline static bool AreCoordsOnChunkBoundary(int a_BlockX, int a_BlockY, int a_BlockZ) + { + return ( // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks + ((a_BlockX % cChunkDef::Width) <= 1) || + ((a_BlockX % cChunkDef::Width) >= 14) || + ((a_BlockZ % cChunkDef::Width) <= 1) || + ((a_BlockZ % cChunkDef::Width) >= 14) + ); + } }; diff --git a/src/Simulator/NoopFluidSimulator.h b/src/Simulator/NoopFluidSimulator.h index 9113aec3c..9fe2f9040 100644 --- a/src/Simulator/NoopFluidSimulator.h +++ b/src/Simulator/NoopFluidSimulator.h @@ -27,7 +27,7 @@ public: } // cSimulator overrides: - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override + virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override { UNUSED(a_BlockX); UNUSED(a_BlockY); diff --git a/src/Simulator/NoopRedstoneSimulator.h b/src/Simulator/NoopRedstoneSimulator.h index fe3949198..4301b8aae 100644 --- a/src/Simulator/NoopRedstoneSimulator.h +++ b/src/Simulator/NoopRedstoneSimulator.h @@ -18,10 +18,10 @@ public: { } - //~cRedstoneNoopSimulator(); + // ~cRedstoneNoopSimulator(); virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used - virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override + virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override { UNUSED(a_Dt); UNUSED(a_ChunkX); diff --git a/src/Simulator/SandSimulator.h b/src/Simulator/SandSimulator.h index 6e64aa425..1262f2792 100644 --- a/src/Simulator/SandSimulator.h +++ b/src/Simulator/SandSimulator.h @@ -37,7 +37,7 @@ public: based on the block currently present in the world at the dest specified coords */ static void FinishFalling( - cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, + cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_FallingBlockType, NIBBLETYPE a_FallingBlockMeta ); diff --git a/src/Simulator/Simulator.h b/src/Simulator/Simulator.h index a2e2a5742..171eba91c 100644 --- a/src/Simulator/Simulator.h +++ b/src/Simulator/Simulator.h @@ -26,7 +26,7 @@ public: /// Called in each tick for each chunk, a_Dt is the time passed since the last tick, in msec; direct access to chunk data available virtual void SimulateChunk(float a_Dt, int a_ChunkX, - int a_ChunkZ, cChunk * a_Chunk) + int a_ChunkZ, cChunk * a_Chunk) { UNUSED(a_Dt); UNUSED(a_ChunkX); diff --git a/src/Simulator/VaporizeFluidSimulator.cpp b/src/Simulator/VaporizeFluidSimulator.cpp index 4206c64d1..484cac334 100644 --- a/src/Simulator/VaporizeFluidSimulator.cpp +++ b/src/Simulator/VaporizeFluidSimulator.cpp @@ -27,7 +27,7 @@ void cVaporizeFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, return; } int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; + int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_BlockY, RelZ); if ( (BlockType == m_FluidBlock) || @@ -35,7 +35,7 @@ void cVaporizeFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, ) { a_Chunk->SetBlock(RelX, a_BlockY, RelZ, E_BLOCK_AIR, 0); - a_Chunk->BroadcastSoundEffect("random.fizz", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 0.6f); + a_Chunk->BroadcastSoundEffect("random.fizz", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.6f); } } |