summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHowaner <franzi.moos@googlemail.com>2014-12-17 17:33:30 +0100
committerHowaner <franzi.moos@googlemail.com>2014-12-17 17:33:30 +0100
commit6ee7fd3c6792235c873e24b16331e3a8278021cc (patch)
tree707fb63ebda192bad5603c5c280d99746b510cc4 /src
parentImplemented vanilla-like shift click. (diff)
parentMerge pull request #1674 from gushromp/master (diff)
downloadcuberite-6ee7fd3c6792235c873e24b16331e3a8278021cc.tar
cuberite-6ee7fd3c6792235c873e24b16331e3a8278021cc.tar.gz
cuberite-6ee7fd3c6792235c873e24b16331e3a8278021cc.tar.bz2
cuberite-6ee7fd3c6792235c873e24b16331e3a8278021cc.tar.lz
cuberite-6ee7fd3c6792235c873e24b16331e3a8278021cc.tar.xz
cuberite-6ee7fd3c6792235c873e24b16331e3a8278021cc.tar.zst
cuberite-6ee7fd3c6792235c873e24b16331e3a8278021cc.zip
Diffstat (limited to '')
-rw-r--r--src/BlockEntities/MobSpawnerEntity.cpp4
-rw-r--r--src/BlockInfo.cpp1
-rw-r--r--src/Blocks/BlockCocoaPod.h96
-rw-r--r--src/Blocks/BlockHandler.cpp2
-rw-r--r--src/Blocks/BlockPressurePlate.h3
-rw-r--r--src/Blocks/BlockRail.h4
-rw-r--r--src/Blocks/BlockTallGrass.h2
-rw-r--r--src/Blocks/BlockTorch.h1
-rw-r--r--src/Blocks/CMakeLists.txt1
-rw-r--r--src/Chunk.cpp6
-rw-r--r--src/ChunkMap.cpp2
-rw-r--r--src/Entities/Player.cpp6
-rw-r--r--src/Generating/Caves.cpp25
-rw-r--r--src/Items/ItemDye.h46
-rw-r--r--src/Simulator/FireSimulator.h2
-rw-r--r--src/Simulator/FloodyFluidSimulator.cpp15
-rw-r--r--src/Simulator/FluidSimulator.h4
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp2193
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.h390
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.inc2597
-rw-r--r--src/Simulator/NoopRedstoneSimulator.h4
-rw-r--r--src/Simulator/RedstoneSimulator.h8
-rw-r--r--src/Simulator/SandSimulator.h2
-rw-r--r--src/Simulator/Simulator.cpp28
-rw-r--r--src/Simulator/Simulator.h20
-rw-r--r--src/Simulator/Simulator.inc45
-rw-r--r--src/Simulator/SimulatorManager.cpp2
-rw-r--r--src/Simulator/SimulatorManager.h4
-rw-r--r--src/World.cpp23
-rw-r--r--src/World.h7
30 files changed, 2838 insertions, 2705 deletions
diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp
index 5edee888a..a7d29638a 100644
--- a/src/BlockEntities/MobSpawnerEntity.cpp
+++ b/src/BlockEntities/MobSpawnerEntity.cpp
@@ -150,7 +150,7 @@ void cMobSpawnerEntity::SpawnEntity(void)
int RelZ = (int) (m_RelZ + (double)(Random.NextFloat() - Random.NextFloat()) * 4.0);
cChunk * Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(RelX, RelZ);
- if ((Chunk == NULL) || !Chunk->IsValid())
+ if ((Chunk == nullptr) || !Chunk->IsValid())
{
continue;
}
@@ -162,7 +162,7 @@ void cMobSpawnerEntity::SpawnEntity(void)
double PosZ = Chunk->GetPosZ() * cChunkDef::Width + RelZ;
cMonster * Monster = cMonster::NewMonsterFromType(m_MobType);
- if (Monster == NULL)
+ if (Monster == nullptr)
{
continue;
}
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index bcab21e77..3c5e8d7b7 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -452,7 +452,6 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_AIR ].m_IsSolid = false;
a_Info[E_BLOCK_BIG_FLOWER ].m_IsSolid = false;
a_Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSolid = false;
- a_Info[E_BLOCK_CAKE ].m_IsSolid = false;
a_Info[E_BLOCK_CARROTS ].m_IsSolid = false;
a_Info[E_BLOCK_COBWEB ].m_IsSolid = false;
a_Info[E_BLOCK_CROPS ].m_IsSolid = false;
diff --git a/src/Blocks/BlockCocoaPod.h b/src/Blocks/BlockCocoaPod.h
new file mode 100644
index 000000000..1b659d48f
--- /dev/null
+++ b/src/Blocks/BlockCocoaPod.h
@@ -0,0 +1,96 @@
+#pragma once
+
+#include "BlockHandler.h"
+#include "../FastRandom.h"
+
+
+
+
+
+class cBlockCocoaPodHandler :
+ public cBlockHandler
+{
+public:
+ cBlockCocoaPodHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+
+ virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
+ {
+ eBlockFace BlockFace = MetaToBlockFace(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
+ AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockFace, true);
+
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta);
+
+ return ((BlockType == E_BLOCK_LOG) && ((BlockMeta & 0x3) == E_META_LOG_JUNGLE));
+ }
+
+
+ virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
+ {
+ cFastRandom Random;
+
+ if (Random.NextInt(5) == 0)
+ {
+ NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
+ NIBBLETYPE TypeMeta = Meta & 0x03;
+ int GrowState = Meta >> 2;
+
+ if (GrowState < 2)
+ {
+ ++GrowState;
+ a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, (NIBBLETYPE) (GrowState << 2 | TypeMeta));
+ }
+ }
+ }
+
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ int GrowState = a_BlockMeta >> 2;
+ a_Pickups.Add(E_ITEM_DYE, ((GrowState >= 2) ? 3 : 1), E_META_DYE_BROWN);
+ }
+
+
+ static eBlockFace MetaToBlockFace(NIBBLETYPE a_Meta)
+ {
+ switch (a_Meta & 0x3)
+ {
+ case 0: return BLOCK_FACE_ZM;
+ case 1: return BLOCK_FACE_XP;
+ case 2: return BLOCK_FACE_ZP;
+ case 3: return BLOCK_FACE_XM;
+ default:
+ {
+ ASSERT(!"Bad meta");
+ return BLOCK_FACE_NONE;
+ }
+ }
+ }
+
+
+ static NIBBLETYPE BlockFaceToMeta(eBlockFace a_BlockFace)
+ {
+ switch (a_BlockFace)
+ {
+ case BLOCK_FACE_ZM: return 0;
+ case BLOCK_FACE_XM: return 3;
+ case BLOCK_FACE_XP: return 1;
+ case BLOCK_FACE_ZP: return 2;
+ default:
+ {
+ ASSERT(!"Unknown face");
+ return 0;
+ }
+ }
+ }
+
+} ;
+
+
+
+
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 60f13a747..d532aa1dc 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -17,6 +17,7 @@
#include "BlockChest.h"
#include "BlockCloth.h"
#include "BlockCobWeb.h"
+#include "BlockCocoaPod.h"
#include "BlockCommandBlock.h"
#include "BlockComparator.h"
#include "BlockCrops.h"
@@ -198,6 +199,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_CAULDRON: return new cBlockCauldronHandler (a_BlockType);
case E_BLOCK_CHEST: return new cBlockChestHandler (a_BlockType);
case E_BLOCK_COAL_ORE: return new cBlockOreHandler (a_BlockType);
+ case E_BLOCK_COCOA_POD: return new cBlockCocoaPodHandler (a_BlockType);
case E_BLOCK_COMMAND_BLOCK: return new cBlockCommandBlockHandler (a_BlockType);
case E_BLOCK_ACTIVE_COMPARATOR: return new cBlockComparatorHandler (a_BlockType);
case E_BLOCK_COBBLESTONE: return new cBlockStoneHandler (a_BlockType);
diff --git a/src/Blocks/BlockPressurePlate.h b/src/Blocks/BlockPressurePlate.h
index a5c34a776..bd2f283a2 100644
--- a/src/Blocks/BlockPressurePlate.h
+++ b/src/Blocks/BlockPressurePlate.h
@@ -28,8 +28,7 @@ public:
return false;
}
- BLOCKTYPE BlockBelow = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
- return (cBlockInfo::IsSolid(BlockBelow));
+ return (cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)));
}
} ;
diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h
index 21a34d8ce..02fe3aa95 100644
--- a/src/Blocks/BlockRail.h
+++ b/src/Blocks/BlockRail.h
@@ -98,7 +98,7 @@ public:
{
return false;
}
- if (!cBlockInfo::IsSolid(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)))
+ if (!cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)))
{
return false;
}
@@ -130,7 +130,7 @@ public:
// Too close to the edge, cannot simulate
return true;
}
- return cBlockInfo::IsSolid(BlockType);
+ return cBlockInfo::FullyOccupiesVoxel(BlockType);
}
}
return true;
diff --git a/src/Blocks/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h
index 8e821b899..4134a01f8 100644
--- a/src/Blocks/BlockTallGrass.h
+++ b/src/Blocks/BlockTallGrass.h
@@ -38,7 +38,7 @@ public:
virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override
{
- if (a_CanDrop && (a_Digger != NULL) && (a_Digger->GetEquippedWeapon().m_ItemType == E_ITEM_SHEARS))
+ if (a_CanDrop && (a_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_ItemType == E_ITEM_SHEARS))
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
cItems Drops;
diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h
index e77bbd1b8..d63df94cf 100644
--- a/src/Blocks/BlockTorch.h
+++ b/src/Blocks/BlockTorch.h
@@ -2,6 +2,7 @@
#include "BlockHandler.h"
#include "../Chunk.h"
+#include "ChunkInterface.h"
#include "MetaRotator.h"
diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt
index eed949aab..ed3e321d4 100644
--- a/src/Blocks/CMakeLists.txt
+++ b/src/Blocks/CMakeLists.txt
@@ -24,6 +24,7 @@ SET (HDRS
BlockChest.h
BlockCloth.h
BlockCobWeb.h
+ BlockCocoaPod.h
BlockCommandBlock.h
BlockComparator.h
BlockCrops.h
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 017ceda26..39e97f5cf 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -1371,9 +1371,9 @@ void cChunk::CreateBlockEntities(void)
void cChunk::WakeUpSimulators(void)
{
- cSimulator<cChunk, cWorld> * WaterSimulator = m_World->GetWaterSimulator();
- cSimulator<cChunk, cWorld> * LavaSimulator = m_World->GetLavaSimulator();
- cSimulator<cChunk, cWorld> * RedstoneSimulator = m_World->GetRedstoneSimulator();
+ cSimulator * WaterSimulator = m_World->GetWaterSimulator();
+ cSimulator * LavaSimulator = m_World->GetLavaSimulator();
+ cSimulator * RedstoneSimulator = m_World->GetRedstoneSimulator();
int BaseX = m_PosX * cChunkDef::Width;
int BaseZ = m_PosZ * cChunkDef::Width;
for (int x = 0; x < Width; x++)
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 222a756b1..6aff3a754 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -3075,7 +3075,7 @@ void cChunkMap::cChunkLayer::UnloadUnusedChunks(void)
)
{
// The cChunk destructor calls our GetChunk() while removing its entities
- // so we still need to be able to return the chunk. Therefore we first delete, then NULLify
+ // so we still need to be able to return the chunk. Therefore we first delete, then nullptrify
// Doing otherwise results in bug http://forum.mc-server.org/showthread.php?tid=355
delete m_Chunks[i];
m_Chunks[i] = nullptr;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 17f0d4074..716e20663 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -1604,6 +1604,12 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn)
// Update the view distance.
m_ClientHandle->SetViewDistance(m_ClientHandle->GetRequestedViewDistance());
+ // Send current weather of target world to player
+ if (a_World->GetDimension() == dimOverworld)
+ {
+ m_ClientHandle->SendWeather(a_World->GetWeather());
+ }
+
return true;
}
diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp
index e4735cb83..1e8dbef90 100644
--- a/src/Generating/Caves.cpp
+++ b/src/Generating/Caves.cpp
@@ -100,6 +100,7 @@ public:
void ProcessChunk(
int a_ChunkX, int a_ChunkZ,
cChunkDef::BlockTypes & a_BlockTypes,
+ cChunkDesc::BlockNibbleBytes & a_BlockMetas,
cChunkDef::HeightMap & a_HeightMap
);
@@ -455,6 +456,7 @@ void cCaveTunnel::CalcBoundingBox(void)
void cCaveTunnel::ProcessChunk(
int a_ChunkX, int a_ChunkZ,
cChunkDef::BlockTypes & a_BlockTypes,
+ cChunkDesc::BlockNibbleBytes & a_BlockMetas,
cChunkDef::HeightMap & a_HeightMap
)
{
@@ -505,6 +507,22 @@ void cCaveTunnel::ProcessChunk(
cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_AIR);
}
}
+ else if (SqDist <= SqRad * 2)
+ {
+ if (cChunkDef::GetBlock(a_BlockTypes, x, y, z) == E_BLOCK_SAND)
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(x, y, z);
+ if (a_BlockMetas[Index] == 1)
+ {
+ a_BlockMetas[Index] = 0;
+ cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_RED_SANDSTONE);
+ }
+ else
+ {
+ cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_SANDSTONE);
+ }
+ }
+ }
} // for y
} // for x, z
} // for itr - m_Points[]
@@ -596,11 +614,12 @@ void cStructGenWormNestCaves::cCaveSystem::DrawIntoChunk(cChunkDesc & a_ChunkDes
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
- cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes();
- cChunkDef::HeightMap & HeightMap = a_ChunkDesc.GetHeightMap();
+ cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes();
+ cChunkDef::HeightMap & HeightMap = a_ChunkDesc.GetHeightMap();
+ cChunkDesc::BlockNibbleBytes & BlockMetas = a_ChunkDesc.GetBlockMetasUncompressed();
for (cCaveTunnels::const_iterator itr = m_Tunnels.begin(), end = m_Tunnels.end(); itr != end; ++itr)
{
- (*itr)->ProcessChunk(ChunkX, ChunkZ, BlockTypes, HeightMap);
+ (*itr)->ProcessChunk(ChunkX, ChunkZ, BlockTypes, BlockMetas, HeightMap);
} // for itr - m_Tunnels[]
}
diff --git a/src/Items/ItemDye.h b/src/Items/ItemDye.h
index ccf4714f7..da978040d 100644
--- a/src/Items/ItemDye.h
+++ b/src/Items/ItemDye.h
@@ -4,6 +4,7 @@
#include "ItemHandler.h"
#include "../World.h"
#include "../Entities/Player.h"
+#include "../Blocks/BlockCocoaPod.h"
@@ -16,10 +17,9 @@ public:
cItemDyeHandler(int a_ItemType)
: cItemHandler(a_ItemType)
{
-
}
- virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
{
// Handle growing the plants:
if (a_Item.m_ItemDamage == E_META_DYE_WHITE)
@@ -34,8 +34,50 @@ public:
}
}
}
+ else if ((a_Item.m_ItemDamage == E_META_DYE_BROWN) && (a_BlockFace >= BLOCK_FACE_ZM) && (a_BlockFace <= BLOCK_FACE_XP))
+ {
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
+
+ // Check if the block that the player clicked is a jungle log.
+ if ((BlockType != E_BLOCK_LOG) || ((BlockMeta & 0x3) != E_META_LOG_JUNGLE))
+ {
+ return false;
+ }
+
+ // Get the location from the new cocoa pod.
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false);
+ BlockMeta = cBlockCocoaPodHandler::BlockFaceToMeta(a_BlockFace);
+
+ if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_AIR)
+ {
+ return false;
+ }
+
+ // Check plugins
+ if (cRoot::Get()->GetPluginManager()->CallHookPlayerPlacingBlock(*a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, 0, 0, 0, E_BLOCK_COCOA_POD, BlockMeta))
+ {
+ a_World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ a_Player->GetInventory().SendEquippedSlot();
+ return false;
+ }
+
+ // Set block and broadcast place sound
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_COCOA_POD, BlockMeta);
+ a_World->BroadcastSoundEffect("dig.stone", a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 1.0f, 0.8f);
+
+ // Remove one cocoa pod from the inventory
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+ cRoot::Get()->GetPluginManager()->CallHookPlayerPlacedBlock(*a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, 0, 0, 0, E_BLOCK_COCOA_POD, BlockMeta);
+ return true;
+ }
return false;
}
+
} ;
diff --git a/src/Simulator/FireSimulator.h b/src/Simulator/FireSimulator.h
index f76dbe342..9ccc3ef4f 100644
--- a/src/Simulator/FireSimulator.h
+++ b/src/Simulator/FireSimulator.h
@@ -16,7 +16,7 @@ it progresses to the next step (blockmeta++). This value is updated if a neighbo
The simulator reads its parameters from the ini file given to the constructor.
*/
class cFireSimulator :
- public cSimulator<cChunk, cWorld>
+ public cSimulator
{
public:
cFireSimulator(cWorld & a_World, cIniFile & a_IniFile);
diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp
index e95ef216d..37d58307b 100644
--- a/src/Simulator/FloodyFluidSimulator.cpp
+++ b/src/Simulator/FloodyFluidSimulator.cpp
@@ -83,7 +83,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
return;
}
}
-
+
// New meta for the spreading to neighbors:
// If this is a source block or was falling, the new meta is just the falloff
// Otherwise it is the current meta plus falloff (may be larger than max height, will be checked later)
@@ -103,6 +103,11 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
SpreadFurther = false;
}
}
+ // Spread to the neighbors:
+ if (SpreadFurther && (NewMeta < 8))
+ {
+ SpreadXZ(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta);
+ }
// If source creation is on, check for it here:
else if (
(m_NumNeighborsForSource > 0) && // Source creation is on
@@ -116,13 +121,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
return;
}
}
-
- if (SpreadFurther && (NewMeta < 8))
- {
- // Spread to the neighbors:
- SpreadXZ(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta);
- }
-
+
// Mark as processed:
a_Chunk->FastSetBlock(a_RelX, a_RelY, a_RelZ, m_StationaryFluidBlock, MyMeta);
}
diff --git a/src/Simulator/FluidSimulator.h b/src/Simulator/FluidSimulator.h
index d65a8e78b..6d2c6a679 100644
--- a/src/Simulator/FluidSimulator.h
+++ b/src/Simulator/FluidSimulator.h
@@ -37,9 +37,9 @@ public:
class cFluidSimulator :
- public cSimulator<cChunk, cWorld>
+ public cSimulator
{
- typedef cSimulator<cChunk, cWorld> super;
+ typedef cSimulator super;
public:
cFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid);
diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp
index df05a9fee..8a56287a8 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.cpp
+++ b/src/Simulator/IncrementalRedstoneSimulator.cpp
@@ -5,8 +5,6 @@
typedef cItemCallback<cChestEntity> cChestCallback;
-#include "IncrementalRedstoneSimulator.inc"
-
#include "Chunk.h"
#include "World.h"
#include "Blocks/GetHandlerCompileTimeTemplate.h"
@@ -17,8 +15,2195 @@ typedef cItemCallback<cChestEntity> cChestCallback;
#include "Blocks/BlockDoor.h"
#include "Blocks/BlockPiston.h"
-cRedstoneSimulator<cChunk, cWorld> * MakeIncrementalRedstoneSimulator(cWorld & a_World)
+
+#include "IncrementalRedstoneSimulator.h"
+#include "BoundingBox.h"
+#include "Blocks/ChunkInterface.h"
+#include "RedstoneSimulator.h"
+
+
+
+
+
+void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk, cChunk * a_OtherChunk)
+{
+ if ((a_Chunk == nullptr) || !a_Chunk->IsValid())
+ {
+ return;
+ }
+ else if ((a_BlockY < 0) || (a_BlockY > cChunkDef::Height))
+ {
+ return;
+ }
+
+ // We may be called with coordinates in a chunk that is not the first chunk parameter
+ // In that case, the actual chunk (which the coordinates are in), will be passed as the second parameter
+ // Use that Chunk pointer to get a relative position
+
+ int RelX = 0;
+ int RelZ = 0;
+ BLOCKTYPE Block;
+ NIBBLETYPE Meta;
+
+ if (a_OtherChunk != nullptr)
+ {
+ RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width;
+ RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width;
+ a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
+
+ // If a_OtherChunk is passed (not nullptr), it is the chunk that had a block change, and a_Chunk will be the neighbouring chunk of that block
+ // 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
+ {
+ RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
+ RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
+ a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
+ }
+
+ // 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
+
+ if (
+ !IsPotentialSource(Block) ||
+ (
+ // 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_TRIPWIRE_HOOK) && ((Meta & 0x08) == 0))
+ )
+ )
+ {
+ SetSourceUnpowered(RelX, a_BlockY, RelZ, a_OtherChunk != nullptr ? a_OtherChunk : a_Chunk);
+ }
+
+ if (!IsViableMiddleBlock(Block))
+ {
+ SetInvalidMiddleBlock(RelX, a_BlockY, RelZ, a_OtherChunk != nullptr ? a_OtherChunk : a_Chunk);
+ }
+
+ auto & SimulatedPlayerToggleableBlocks = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_SimulatedPlayerToggleableBlocks;
+ SimulatedPlayerToggleableBlocks.erase(std::remove_if(SimulatedPlayerToggleableBlocks.begin(), SimulatedPlayerToggleableBlocks.end(), [RelX, a_BlockY, RelZ, Block, this](const sSimulatedPlayerToggleableList & itr)
+ {
+ return itr.a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)) && !IsAllowedBlock(Block);
+ }
+ ), SimulatedPlayerToggleableBlocks.end());
+
+
+ auto & RepeatersDelayList = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_RepeatersDelayList;
+ RepeatersDelayList.erase(std::remove_if(RepeatersDelayList.begin(), RepeatersDelayList.end(), [RelX, a_BlockY, RelZ, Block](const sRepeatersDelayList & itr)
+ {
+ return itr.a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)) && (Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF);
+ }
+ ), RepeatersDelayList.end());
+
+ if (a_OtherChunk != nullptr)
+ {
+ // DO NOT touch our chunk's data structure if we are being called with coordinates from another chunk - this one caused me massive grief :P
+ return;
+ }
+
+ cCoordWithBlockAndBoolVector & RedstoneSimulatorChunkData = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_ChunkData;
+ for (auto & itr : RedstoneSimulatorChunkData)
+ {
+ if ((itr.x == RelX) && (itr.y == a_BlockY) && (itr.z == RelZ)) // We are at an entry matching the current (changed) block
+ {
+ if (!IsAllowedBlock(Block))
+ {
+ itr.DataTwo = true; // The new blocktype is not redstone; it must be queued to be removed from this list
+ }
+ else
+ {
+ itr.DataTwo = false;
+ itr.Data = Block; // Update block information
+ }
+ return;
+ }
+ }
+
+ if (!IsAllowedBlock(Block))
+ {
+ return;
+ }
+
+ cCoordWithBlockAndBoolVector & QueuedData = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData;
+ for (const auto & itr : QueuedData)
+ {
+ if ((itr.x == RelX) && (itr.y == a_BlockY) && (itr.z == RelZ))
+ {
+ // Can't have duplicates in here either, in case something adds the block again before the structure can written to the main chunk data
+ return;
+ }
+ }
+ QueuedData.emplace_back(cCoordWithBlockAndBool(RelX, a_BlockY, RelZ, Block, false));
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
+{
+ m_RedstoneSimulatorChunkData = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData();
+ if (m_RedstoneSimulatorChunkData == nullptr)
+ {
+ m_RedstoneSimulatorChunkData = new cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData();
+ a_Chunk->SetRedstoneSimulatorData(m_RedstoneSimulatorChunkData);
+ }
+ if (m_RedstoneSimulatorChunkData->m_ChunkData.empty() && ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData.empty())
+ {
+ return;
+ }
+
+ m_RedstoneSimulatorChunkData->m_ChunkData.insert(
+ m_RedstoneSimulatorChunkData->m_ChunkData.end(),
+ m_RedstoneSimulatorChunkData->m_QueuedChunkData.begin(),
+ m_RedstoneSimulatorChunkData->m_QueuedChunkData.end()
+ );
+
+ m_RedstoneSimulatorChunkData->m_QueuedChunkData.clear();
+
+ m_PoweredBlocks = &m_RedstoneSimulatorChunkData->m_PoweredBlocks;
+ m_RepeatersDelayList = &m_RedstoneSimulatorChunkData->m_RepeatersDelayList;
+ m_SimulatedPlayerToggleableBlocks = &m_RedstoneSimulatorChunkData->m_SimulatedPlayerToggleableBlocks;
+ m_LinkedPoweredBlocks = &m_RedstoneSimulatorChunkData->m_LinkedBlocks;
+ m_Chunk = a_Chunk;
+ bool ShouldUpdateSimulateOnceBlocks = false;
+
+ if (a_Chunk->IsRedstoneDirty())
+ {
+ // Simulate the majority of devices only if something (blockwise or power-wise) has changed
+ // Make sure to allow the chunk to resimulate after the initial run if there was a power change (ShouldUpdateSimulateOnceBlocks helps to do this)
+ a_Chunk->SetIsRedstoneDirty(false);
+ ShouldUpdateSimulateOnceBlocks = true;
+ }
+
+ HandleRedstoneRepeaterDelays();
+
+ for (auto dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.begin(); dataitr != m_RedstoneSimulatorChunkData->m_ChunkData.end();)
+ {
+ if (dataitr->DataTwo)
+ {
+ dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.erase(dataitr);
+ continue;
+ }
+
+ 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:
+ case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
+ {
+ HandlePressurePlate(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
+ break;
+ }
+ default: break;
+ }
+
+ 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;
+ case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_LEVER: HandleRedstoneLever(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_TNT: HandleTNT(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_IRON_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break;
+ case E_BLOCK_TRAPPED_CHEST: HandleTrappedChest(dataitr->x, dataitr->y, dataitr->z); break;
+
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_DETECTOR_RAIL:
+ case E_BLOCK_POWERED_RAIL:
+ {
+ HandleRail(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
+ break;
+ }
+ case E_BLOCK_ACACIA_DOOR:
+ case E_BLOCK_BIRCH_DOOR:
+ case E_BLOCK_DARK_OAK_DOOR:
+ case E_BLOCK_JUNGLE_DOOR:
+ case E_BLOCK_SPRUCE_DOOR:
+ case E_BLOCK_WOODEN_DOOR:
+ case E_BLOCK_IRON_DOOR:
+ {
+ HandleDoor(dataitr->x, dataitr->y, dataitr->z);
+ break;
+ }
+ case E_BLOCK_ACACIA_FENCE_GATE:
+ case E_BLOCK_BIRCH_FENCE_GATE:
+ case E_BLOCK_DARK_OAK_FENCE_GATE:
+ case E_BLOCK_FENCE_GATE:
+ case E_BLOCK_JUNGLE_FENCE_GATE:
+ case E_BLOCK_SPRUCE_FENCE_GATE:
+ {
+ HandleFenceGate(dataitr->x, dataitr->y, dataitr->z);
+ break;
+ }
+ case E_BLOCK_REDSTONE_LAMP_OFF:
+ case E_BLOCK_REDSTONE_LAMP_ON:
+ {
+ HandleRedstoneLamp(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
+ break;
+ }
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DROPPER:
+ {
+ HandleDropSpenser(dataitr->x, dataitr->y, dataitr->z);
+ break;
+ }
+ case E_BLOCK_PISTON:
+ case E_BLOCK_STICKY_PISTON:
+ {
+ HandlePiston(dataitr->x, dataitr->y, dataitr->z);
+ break;
+ }
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ {
+ HandleRedstoneRepeater(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
+ break;
+ }
+ case E_BLOCK_REDSTONE_TORCH_OFF:
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ {
+ HandleRedstoneTorch(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
+ break;
+ }
+ case E_BLOCK_STONE_BUTTON:
+ case E_BLOCK_WOODEN_BUTTON:
+ {
+ HandleRedstoneButton(dataitr->x, dataitr->y, dataitr->z);
+ break;
+ }
+ default: break;
+ }
+ }
+ ++dataitr;
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
+{
+ if (AreCoordsOnChunkBoundary(a_BlockX, a_BlockY, a_BlockZ))
+ {
+ // On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk)
+ AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
+
+ // Pass the original coordinates, because when adding things to our simulator lists, we get the chunk that they are in, and therefore any updates need to preseve their position
+ // RedstoneAddBlock to pass both the neighbouring chunk and the chunk which the coordinates are in and +- 2 in GetNeighbour() to accomodate for LinkedPowered blocks being 2 away from chunk boundaries
+ RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 2, a_BlockZ), a_Chunk);
+ RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 2, a_BlockZ), a_Chunk);
+ RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 2), a_Chunk);
+ RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ + 2), a_Chunk);
+
+ return;
+ }
+
+ // Not on boundary, just alert this chunk for speed
+ AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
+}
+
+
+
+
+
+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
+ {
+ 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_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ;
+ AddFaceDirection(X, Y, Z, GetHandlerCompileTime<E_BLOCK_TORCH>::type::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on
+
+ cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(X, Z);
+ if ((Neighbour == nullptr) || !Neighbour->IsValid())
+ {
+ return;
+ }
+
+ 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));
+ return;
+ }
+
+ // Torch still on, make all 4(X, Z) + 1(Y) sides powered
+ for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
+ {
+ BLOCKTYPE Type = 0;
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type))
+ {
+ continue;
+ }
+ if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last)
+ {
+ if (
+ 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);
+ }
+ }
+ else
+ {
+ // Top side, power whatever is there, including blocks
+ SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ // Power all blocks surrounding block above torch
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YP);
+ }
+ }
+
+ 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)) // Still can't make a normal block powered though!
+ {
+ SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ }
+ }
+ }
+ else
+ {
+ // 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, GetHandlerCompileTime<E_BLOCK_TORCH>::type::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on
+
+ cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(X, Z);
+ if ((Neighbour == nullptr) || !Neighbour->IsValid())
+ {
+ return;
+ }
+
+ // See if off state torch can be turned on again
+ if (AreCoordsDirectlyPowered(X, Y, Z, Neighbour))
+ {
+ return; // Something matches, torch still powered
+ }
+
+ // Block torch on not powered, can be turned on again!
+ m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
+ }
+}
+
+
+
+
+
+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
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ if (IsLeverOn(Meta))
+ {
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+
+ eBlockFace Dir = GetHandlerCompileTime<E_BLOCK_LEVER>::type::BlockMetaDataToBlockFace(Meta);
+
+ Dir = ReverseBlockFace(Dir);
+
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleFenceGate(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;
+ NIBBLETYPE MetaData = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+
+ if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
+ {
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
+ {
+ if ((MetaData & 0x4) == 0)
+ {
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData | 0x4);
+ m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ }
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
+ }
+ }
+ else
+ {
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
+ {
+ if ((MetaData & 0x4) != 0)
+ {
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData & ~0x04);
+ m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ }
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ if (IsButtonOn(Meta))
+ {
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+
+ eBlockFace Dir = GetHandlerCompileTime<E_BLOCK_STONE_BUTTON>::type::BlockMetaDataToBlockFace(Meta);
+ Dir = ReverseBlockFace(Dir);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ static const struct // Define which directions the wire can receive power from
+ {
+ int x, y, z;
+ } gCrossCoords[] =
+ {
+ { 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
+ unsigned char MyPower;
+ if (!IsWirePowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower))
+ {
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0);
+ return;
+ }
+
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+
+ if (MyPower < 1)
+ {
+ return;
+ }
+
+ MyPower--;
+
+ for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power
+ {
+ if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above...
+ {
+ BLOCKTYPE Type = 0;
+ if (a_RelBlockY + 1 >= cChunkDef::Height)
+ {
+ continue;
+ }
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, Type))
+ {
+ continue;
+ }
+ if (cBlockInfo::IsSolid(Type)) // If there is something solid above us (wire cut off)...
+ {
+ continue; // We don't receive power from that wire
+ }
+ }
+ else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us
+ {
+ BLOCKTYPE Type = 0;
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY, a_RelBlockZ + gCrossCoords[i].z, Type))
+ {
+ continue;
+ }
+ if (cBlockInfo::IsSolid(Type))
+ {
+ continue;
+ }
+ }
+
+ BLOCKTYPE Type = 0;
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type))
+ {
+ continue;
+ }
+ if (Type == E_BLOCK_REDSTONE_WIRE)
+ {
+ SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ }
+ }
+
+ for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them
+ {
+ BLOCKTYPE Type = 0;
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, Type))
+ {
+ continue;
+ }
+ if (Type == E_BLOCK_REDSTONE_REPEATER_OFF)
+ {
+ SetBlockPowered(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ }
+ }
+
+ // Wire still powered, power blocks beneath
+ SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, MyPower);
+
+ switch (GetWireDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
+ {
+ case REDSTONE_NONE:
+ {
+ SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower);
+ break;
+ }
+ case REDSTONE_X_POS:
+ {
+ SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower);
+ break;
+ }
+ case REDSTONE_X_NEG:
+ {
+ SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower);
+ break;
+ }
+ case REDSTONE_Z_POS:
+ {
+ SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower);
+ break;
+ }
+ case REDSTONE_Z_NEG:
+ {
+ SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower);
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState)
+{
+ /* Repeater Orientation Mini Guide:
+ ===================================
+
+ |
+ | Z Axis
+ V
+
+ X Axis ---->
+
+ Repeater directions, values from a WorldType::GetBlockMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) lookup:
+
+ East (Right) (X+): 0x1
+ West (Left) (X-): 0x3
+ North (Up) (Z-): 0x2
+ South (Down) (Z+): 0x0
+ // TODO: Add E_META_XXX enum entries for all meta values and update project with them
+
+ Sun rises from East (X+)
+
+ */
+
+ // 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:
+ {
+ 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.
+ {
+ QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, true);
+ }
+ else if (!IsSelfPowered && IsOn) // Queue a power change if unpowered, on, and not locked.
+ {
+ QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, false);
+ }
+ }
+}
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
+{
+ for (auto itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end();)
+ {
+ if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks?
+ {
+ int RelBlockX = itr->a_RelBlockPos.x;
+ int RelBlockY = itr->a_RelBlockPos.y;
+ int RelBlockZ = itr->a_RelBlockPos.z;
+ BLOCKTYPE Block;
+ NIBBLETYPE Meta;
+ m_Chunk->GetBlockTypeMeta(RelBlockX, RelBlockY, RelBlockZ, Block, Meta);
+ if (itr->ShouldPowerOn)
+ {
+ if (Block != E_BLOCK_REDSTONE_REPEATER_ON) // For performance
+ {
+ m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta);
+ }
+
+ switch (Meta & 0x3) // We only want the direction (bottom) bits
+ {
+ case 0x0:
+ {
+ SetBlockPowered(RelBlockX, RelBlockY, RelBlockZ - 1, RelBlockX, RelBlockY, RelBlockZ);
+ SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_ZM);
+ break;
+ }
+ case 0x1:
+ {
+ SetBlockPowered(RelBlockX + 1, RelBlockY, RelBlockZ, RelBlockX, RelBlockY, RelBlockZ);
+ SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_XP);
+ break;
+ }
+ case 0x2:
+ {
+ SetBlockPowered(RelBlockX, RelBlockY, RelBlockZ + 1, RelBlockX, RelBlockY, RelBlockZ);
+ SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_ZP);
+ break;
+ }
+ case 0x3:
+ {
+ SetBlockPowered(RelBlockX - 1, RelBlockY, RelBlockZ, RelBlockX, RelBlockY, RelBlockZ);
+ SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_XM);
+ break;
+ }
+ }
+ }
+ else if (Block != E_BLOCK_REDSTONE_REPEATER_OFF)
+ {
+ m_Chunk->SetBlock(RelBlockX, RelBlockY, RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, Meta);
+ }
+ itr = m_RepeatersDelayList->erase(itr);
+ }
+ else
+ {
+ LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
+ itr->a_ElapsedTicks++;
+ itr++;
+ }
+ }
+}
+
+
+
+
+
+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)
+ {
+ GetHandlerCompileTime<E_BLOCK_PISTON>::type::ExtendPiston(BlockX, a_RelBlockY, BlockZ, &this->m_World);
+ }
+ else
+ {
+ GetHandlerCompileTime<E_BLOCK_PISTON>::type::RetractPiston(BlockX, a_RelBlockY, BlockZ, &this->m_World);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ class cSetPowerToDropSpenser :
+ public cRedstonePoweredCallback
+ {
+ bool m_IsPowered;
+ public:
+ cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
+
+ virtual bool Item(cRedstonePoweredEntity * a_DropSpenser) override
+ {
+ a_DropSpenser->SetRedstonePower(m_IsPowered);
+ return false;
+ }
+ } DrSpSP(AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
+
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, DrSpSP);
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState)
+{
+ if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF)
+ {
+ if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
+ {
+ m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0);
+ }
+ }
+ else
+ {
+ if (!AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
+ {
+ m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0);
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleTNT(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 (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
+ {
+ 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);
+ this->m_World.SpawnPrimedTNT(BlockX + 0.5, a_RelBlockY + 0.5, BlockZ + 0.5); // 80 ticks to boom
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleDoor(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;
+
+ typedef GetHandlerCompileTime<E_BLOCK_WOODEN_DOOR>::type DoorHandler;
+
+ if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
+ {
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
+ {
+ cChunkInterface ChunkInterface(this->m_World.GetChunkMap());
+ if (!DoorHandler::IsOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ))
+ {
+ DoorHandler::SetOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ, true);
+ m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ }
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
+ }
+ }
+ else
+ {
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
+ {
+ cChunkInterface ChunkInterface(this->m_World.GetChunkMap());
+ if (DoorHandler::IsOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ))
+ {
+ DoorHandler::SetOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ, false);
+ m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
+ }
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ class cSetPowerToCommandBlock :
+ public cRedstonePoweredCallback
+ {
+ bool m_IsPowered;
+ public:
+ cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
+
+ virtual bool Item(cRedstonePoweredEntity * a_CommandBlock) override
+ {
+ a_CommandBlock->SetRedstonePower(m_IsPowered);
+ return false;
+ }
+ } CmdBlockSP(AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
+
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, CmdBlockSP);
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType)
+{
+ switch (a_MyType)
+ {
+ case E_BLOCK_DETECTOR_RAIL:
+ {
+ if ((m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x08) == 0x08)
+ {
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_MyType);
+ }
+ break;
+ }
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_POWERED_RAIL:
+ {
+ if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
+ {
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0x08);
+ }
+ else
+ {
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x07);
+ }
+ break;
+ }
+ default: LOGD("Unhandled type of rail in %s", __FUNCTION__);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleTrapdoor(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 (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
+ {
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
+ {
+ this->m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, true);
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
+ }
+ }
+ else
+ {
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
+ {
+ this->m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, false);
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ bool m_bAreCoordsPowered = AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+
+ if (m_bAreCoordsPowered)
+ {
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
+ {
+ class cSetPowerToNoteBlock :
+ public cRedstonePoweredCallback
+ {
+ public:
+ cSetPowerToNoteBlock() {}
+
+ virtual bool Item(cRedstonePoweredEntity * a_NoteBlock) override
+ {
+ a_NoteBlock->SetRedstonePower(true);
+ return false;
+ }
+ } NoteBlockSP;
+
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, NoteBlockSP);
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
+ }
+ }
+ else
+ {
+ if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
+ {
+ SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX, BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+ int ChunkX, ChunkZ;
+ cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
+
+ if (!this->m_World.IsChunkLighted(ChunkX, ChunkZ))
+ {
+ this->m_World.QueueLightChunk(ChunkX, ChunkZ);
+ }
+ else
+ {
+ if (m_Chunk->GetTimeAlteredLight(this->m_World.GetBlockSkyLight(BlockX, a_RelBlockY + 1, BlockZ)) > 8)
+ {
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ }
+ else
+ {
+ WakeUp(BlockX, a_RelBlockY, BlockZ, m_Chunk);
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType)
+{
+ int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
+ int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
+
+ switch (a_MyType)
+ {
+ case E_BLOCK_STONE_PRESSURE_PLATE:
+ {
+ // MCS feature - stone pressure plates can only be triggered by players :D
+ cPlayer * a_Player = this->m_World.FindClosestPlayer(Vector3f(BlockX + 0.5f, (float)a_RelBlockY, BlockZ + 0.5f), 0.5f, false);
+
+ if (a_Player != nullptr)
+ {
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x1);
+ SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
+ }
+ else
+ {
+ m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0);
+ SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk);
+ }
+ break;
+ }
+ case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
+ {
+ class cPressurePlateCallback :
+ public cEntityCallback
+ {
+ public:
+ cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ m_NumberOfEntities(0),
+ 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);
+ double Distance = (EntityPos - BlockPos).Length();
+
+ if (Distance <= 0.5)
+ {
+ m_NumberOfEntities++;
+ }
+ return false;
+ }
+
+ bool GetPowerLevel(unsigned char & a_PowerLevel) const
+ {
+ a_PowerLevel = std::min(m_NumberOfEntities, MAX_POWER_LEVEL);
+ return (a_PowerLevel > 0);
+ }
+
+ protected:
+ int m_NumberOfEntities;
+
+ int m_X;
+ int m_Y;
+ int m_Z;
+ };
+
+ cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ);
+ this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback);
+
+ unsigned char Power;
+ NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ if (PressurePlateCallback.GetPowerLevel(Power))
+ {
+ if (Meta == E_META_PRESSURE_PLATE_RAISED)
+ {
+ 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);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
+ }
+ else
+ {
+ if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
+ {
+ 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);
+ SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk);
+ }
+
+ break;
+ }
+ case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
+ {
+ class cPressurePlateCallback :
+ public cEntityCallback
+ {
+ public:
+ cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ m_NumberOfEntities(0),
+ 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);
+ double Distance = (EntityPos - BlockPos).Length();
+
+ if (Distance <= 0.5)
+ {
+ m_NumberOfEntities++;
+ }
+ return false;
+ }
+
+ bool GetPowerLevel(unsigned char & a_PowerLevel) const
+ {
+ a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / 10.f), MAX_POWER_LEVEL);
+ return (a_PowerLevel > 0);
+ }
+
+ protected:
+ int m_NumberOfEntities;
+
+ int m_X;
+ int m_Y;
+ int m_Z;
+ };
+
+ cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ);
+ this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback);
+
+ unsigned char Power;
+ NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ if (PressurePlateCallback.GetPowerLevel(Power))
+ {
+ if (Meta == E_META_PRESSURE_PLATE_RAISED)
+ {
+ 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);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
+ }
+ else
+ {
+ if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
+ {
+ 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);
+ SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk);
+ }
+
+ break;
+ }
+ case E_BLOCK_WOODEN_PRESSURE_PLATE:
+ {
+ class cPressurePlateCallback :
+ public cEntityCallback
+ {
+ public:
+ cPressurePlateCallback(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
+ {
+ Vector3f EntityPos = a_Entity->GetPosition();
+ Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
+ double Distance = (EntityPos - BlockPos).Length();
+
+ 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 false;
+ }
+
+ bool FoundEntity(void) const
+ {
+ return m_FoundEntity;
+ }
+
+ protected:
+ bool m_FoundEntity;
+
+ int m_X;
+ int m_Y;
+ int m_Z;
+ };
+
+ cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ);
+ this->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", (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);
+ SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
+ }
+ else
+ {
+ if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
+ {
+ 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);
+ SetSourceUnpowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk);
+ }
+ break;
+ }
+ default:
+ {
+ LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(cItem(a_MyType)).c_str());
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ int RelX = a_RelBlockX, RelZ = a_RelBlockZ;
+ bool FoundActivated = false;
+ eBlockFace FaceToGoTowards = GetHandlerCompileTime<E_BLOCK_TRIPWIRE_HOOK>::type::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(GetHandlerCompileTime<E_BLOCK_TRIPWIRE_HOOK>::type::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(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 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(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 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(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ class cGetTrappedChestPlayers :
+ public cItemCallback<cChestEntity>
+ {
+ public:
+ cGetTrappedChestPlayers(void) :
+ m_NumberOfPlayers(0)
+ {
+ }
+
+ virtual ~cGetTrappedChestPlayers()
+ {
+ }
+
+ 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(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 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);
+ this->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
+
+ for (const auto & itr : ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks) // Check powered list
+ {
+ if (itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
+bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ for (const auto & itr : *m_LinkedPoweredBlocks) // Check linked powered list
+ {
+ if (itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
+bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta)
{
- return new cIncrementalRedstoneSimulator<cChunk, cWorld, GetHandlerCompileTime, cChestEntity>(a_World);
+ // Repeaters cannot be powered by any face except their back; verify that this is true for a source
+
+ for (const auto & itr : *m_PoweredBlocks)
+ {
+ if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; }
+
+ switch (a_Meta & 0x3)
+ {
+ case 0x0:
+ {
+ // Flip the coords to check the back of the repeater
+ if (itr.a_SourcePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1)))) { return true; }
+ break;
+ }
+ case 0x1:
+ {
+ if (itr.a_SourcePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ)))) { return true; }
+ break;
+ }
+ case 0x2:
+ {
+ if (itr.a_SourcePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1)))) { return true; }
+ break;
+ }
+ case 0x3:
+ {
+ if (itr.a_SourcePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ)))) { return true; }
+ break;
+ }
+ }
+ }
+
+ for (const auto & itr : *m_LinkedPoweredBlocks)
+ {
+ if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; }
+
+ switch (a_Meta & 0x3)
+ {
+ case 0x0:
+ {
+ if (itr.a_MiddlePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1)))) { return true; }
+ break;
+ }
+ case 0x1:
+ {
+ if (itr.a_MiddlePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ)))) { return true; }
+ break;
+ }
+ case 0x2:
+ {
+ if (itr.a_MiddlePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1)))) { return true; }
+ break;
+ }
+ case 0x3:
+ {
+ if (itr.a_MiddlePos.Equals(AdjustRelativeCoords(Vector3i(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ)))) { return true; }
+ break;
+ }
+ }
+ }
+ return false; // Couldn't find power source behind repeater
}
+
+
+
+
+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
+ {
+ // If the repeater is looking up or down (If parallel to the Z axis)
+ case 0x0:
+ case 0x2:
+ {
+ // Check if eastern(right) neighbor is a powered on repeater who is facing us
+ BLOCKTYPE Block = 0;
+ NIBBLETYPE OtherRepeaterDir = 0;
+ if (m_Chunk->UnboundedRelGetBlock(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, Block, OtherRepeaterDir) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) // Is right neighbor a powered repeater?
+ {
+ if ((OtherRepeaterDir & 0x03) == 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->UnboundedRelGetBlock(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, Block, OtherRepeaterDir) && (Block == E_BLOCK_REDSTONE_REPEATER_ON))
+ {
+ if ((OtherRepeaterDir & 0x03) == 0x1)
+ {
+ return true;
+ } // If so, I am latched/locked
+ }
+
+ break;
+ }
+
+ // If the repeater is looking left or right (If parallel to the x axis)
+ case 0x1:
+ case 0x3:
+ {
+ // Check if southern(down) neighbor is a powered on repeater who is facing us
+ BLOCKTYPE Block = 0;
+ NIBBLETYPE OtherRepeaterDir = 0;
+
+ if (m_Chunk->UnboundedRelGetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, Block, OtherRepeaterDir) && (Block == E_BLOCK_REDSTONE_REPEATER_ON))
+ {
+ if ((OtherRepeaterDir & 0x30) == 0x00)
+ {
+ return true;
+ } // If so, am latched/locked
+ }
+
+ // Check if northern(up) neighbor is a powered on repeater who is facing us
+ if (m_Chunk->UnboundedRelGetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, Block, OtherRepeaterDir) && (Block == E_BLOCK_REDSTONE_REPEATER_ON))
+ {
+ if ((OtherRepeaterDir & 0x03) == 0x02)
+ {
+ return true;
+ } // If so, I am latched/locked
+ }
+
+ break;
+ }
+ }
+
+ return false; // None of the checks succeeded, I am not a locked repeater
+}
+
+
+
+
+bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta)
+{
+ // Pistons cannot be powered through their front face; this function verifies that a source meets this requirement
+
+ eBlockFace Face = GetHandlerCompileTime<E_BLOCK_PISTON>::type::MetaDataToDirection(a_Meta);
+
+ for (const auto & itr : *m_PoweredBlocks)
+ {
+ if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; }
+
+ int X = a_RelBlockX, Z = a_RelBlockZ;
+ AddFaceDirection(X, a_RelBlockY, Z, Face);
+
+ if (!itr.a_SourcePos.Equals(AdjustRelativeCoords(Vector3i(X, a_RelBlockY, Z))))
+ {
+ return true;
+ }
+ }
+
+ for (const auto & itr : *m_LinkedPoweredBlocks)
+ {
+ if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; }
+
+ int X = a_RelBlockX, Z = a_RelBlockZ;
+ AddFaceDirection(X, a_RelBlockY, Z, Face);
+
+ if (!itr.a_MiddlePos.Equals(AdjustRelativeCoords(Vector3i(X, a_RelBlockY, Z))))
+ {
+ return true;
+ }
+ }
+ return false; // Source was in front of the piston's front face
+}
+
+
+
+
+bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel)
+{
+ a_PowerLevel = 0;
+
+ for (const auto & itr : *m_PoweredBlocks) // Check powered list
+ {
+ if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
+ {
+ continue;
+ }
+ a_PowerLevel = std::max(itr.a_PowerLevel, a_PowerLevel); // Get the highest power level (a_PowerLevel is initialised already and there CAN be multiple levels for one block)
+ }
+
+ for (const auto & itr : *m_LinkedPoweredBlocks) // Check linked powered list
+ {
+ if (!itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
+ {
+ continue;
+ }
+
+ BLOCKTYPE Type = E_BLOCK_AIR;
+ if (!m_Chunk->UnboundedRelGetBlockType(itr.a_SourcePos.x, itr.a_SourcePos.y, itr.a_SourcePos.z, Type) || (Type == E_BLOCK_REDSTONE_WIRE))
+ {
+ continue;
+ }
+ a_PowerLevel = std::max(itr.a_PowerLevel, a_PowerLevel);
+ }
+
+ return (a_PowerLevel != 0); // Answer the inital question: is the wire powered?
+}
+
+
+
+
+
+bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered)
+{
+ for (const auto & itr : *m_SimulatedPlayerToggleableBlocks)
+ {
+ 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?
+ {
+ 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 cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel)
+{
+ BLOCKTYPE MiddleBlock = 0;
+ switch (a_Direction)
+ {
+ case BLOCK_FACE_XM:
+ {
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, MiddleBlock))
+ {
+ return;
+ }
+
+ SetBlockLinkedPowered(a_RelBlockX - 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+
+ break;
+ }
+ case BLOCK_FACE_XP:
+ {
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, MiddleBlock))
+ {
+ return;
+ }
+
+ SetBlockLinkedPowered(a_RelBlockX + 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+
+ break;
+ }
+ case BLOCK_FACE_YM:
+ {
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, MiddleBlock))
+ {
+ return;
+ }
+
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+
+ break;
+ }
+ case BLOCK_FACE_YP:
+ {
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, MiddleBlock))
+ {
+ return;
+ }
+
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+
+ break;
+ }
+ case BLOCK_FACE_ZM:
+ {
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, MiddleBlock))
+ {
+ return;
+ }
+
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+
+ break;
+ }
+ case BLOCK_FACE_ZP:
+ {
+ if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, MiddleBlock))
+ {
+ return;
+ }
+
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+ SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
+
+ break;
+ }
+ default:
+ {
+ ASSERT(!"Unhandled face direction when attempting to set blocks as linked powered!"); // Zombies, that wasn't supposed to happen...
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel)
+{
+ static const struct
+ {
+ int x, y, z;
+ } gCrossCoords[] =
+ {
+ { 1, 0, 0 },
+ { -1, 0, 0 },
+ { 0, 0, 1 },
+ { 0, 0, -1 },
+ { 0, 1, 0 },
+ { 0, -1, 0 }
+ };
+
+ 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);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel)
+{
+ cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ); // Adjust coordinates for the later call using these values
+ if ((Neighbour == nullptr) || !Neighbour->IsValid())
+ {
+ return;
+ }
+
+ auto & Powered = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position
+ for (auto itr = Powered.begin(); itr != Powered.end(); ++itr)
+ {
+ if (
+ itr->a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) &&
+ itr->a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ))
+ )
+ {
+ // Check for duplicates, update power level, don't add a new listing
+ itr->a_PowerLevel = a_PowerLevel;
+ return;
+ }
+ }
+
+ // No need to get neighbouring chunk as we can guarantee that when something is powering us, the entry will be in our chunk
+ for (auto itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr)
+ {
+ if (
+ itr->a_BlockPos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ)) &&
+ itr->a_SourcePos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) &&
+ (m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE)
+ )
+ {
+ BLOCKTYPE Block;
+ NIBBLETYPE Meta;
+ Neighbour->GetBlockTypeMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block, Meta);
+
+ if (Block == E_BLOCK_REDSTONE_WIRE)
+ {
+ if (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;
+ }
+ }
+ }
+ }
+
+ sPoweredBlocks RC;
+ RC.a_BlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ RC.a_SourcePos = Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ);
+ RC.a_PowerLevel = a_PowerLevel;
+ Powered.emplace_back(RC);
+ Neighbour->SetIsRedstoneDirty(true);
+ m_Chunk->SetIsRedstoneDirty(true);
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
+ int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ,
+ int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ,
+ int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ,
+ BLOCKTYPE a_MiddleBlock, unsigned char a_PowerLevel
+ )
+{
+ if (!IsViableMiddleBlock(a_MiddleBlock))
+ {
+ return;
+ }
+
+ cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ);
+ m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelMiddleX, a_RelMiddleZ);
+ if ((Neighbour == nullptr) || !Neighbour->IsValid())
+ {
+ return;
+ }
+
+ auto & Linked = ((cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_LinkedBlocks;
+ for (auto & itr : Linked) // Check linked powered list
+ {
+ if (
+ itr.a_BlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) &&
+ itr.a_MiddlePos.Equals(Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)) &&
+ itr.a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ))
+ )
+ {
+ // Check for duplicates, update power level, don't add a new listing
+ itr.a_PowerLevel = a_PowerLevel;
+ return;
+ }
+ }
+
+ sLinkedPoweredBlocks RC;
+ RC.a_BlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ RC.a_MiddlePos = Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ);
+ RC.a_SourcePos = Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ);
+ RC.a_PowerLevel = a_PowerLevel;
+ Linked.emplace_back(RC);
+ Neighbour->SetIsRedstoneDirty(true);
+ m_Chunk->SetIsRedstoneDirty(true);
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered)
+{
+ for (auto itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr)
+ {
+ if (!itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
+ {
+ continue;
+ }
+
+ if (itr->WasLastStatePowered != WasLastStatePowered)
+ {
+ // If power states different, update listing
+ itr->WasLastStatePowered = WasLastStatePowered;
+ return;
+ }
+ else
+ {
+ // If states the same, just ignore
+ return;
+ }
+ }
+
+ // We have arrive here; no block must be in list - add one
+ sSimulatedPlayerToggleableList RC;
+ RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+ RC.WasLastStatePowered = WasLastStatePowered;
+ m_SimulatedPlayerToggleableBlocks->emplace_back(RC);
+}
+
+
+
+
+
+bool cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn)
+{
+ for (auto itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr)
+ {
+ if (itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
+ {
+ if (ShouldPowerOn == itr->ShouldPowerOn) // We are queued already for the same thing, don't replace entry
+ {
+ return false;
+ }
+
+ // Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit
+ itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; // See below for description
+ itr->a_ElapsedTicks = 0;
+ itr->ShouldPowerOn = ShouldPowerOn;
+ return false;
+ }
+ }
+
+ // Self not in list, add self to list
+ sRepeatersDelayList RC;
+ RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
+
+ // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.)
+ // Multiply by 2 because in MCS, 1 redstone tick = 1 world tick, but in Vanilla, 1 redstone tick = 2 world ticks, and we need to maintain compatibility
+ RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2;
+
+ RC.a_ElapsedTicks = 0;
+ RC.ShouldPowerOn = ShouldPowerOn;
+ m_RepeatersDelayList->emplace_back(RC);
+ return true;
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk, bool a_IsFirstCall)
+{
+ if (!a_IsFirstCall) // The neighbouring chunks passed when this parameter is false may be invalid
+ {
+ if ((a_Chunk == nullptr) || !a_Chunk->IsValid())
+ {
+ return;
+ }
+ }
+
+ std::vector<Vector3i> BlocksPotentiallyUnpowered;
+
+ auto Data = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData();
+ Data->m_PoweredBlocks.erase(std::remove_if(Data->m_PoweredBlocks.begin(), Data->m_PoweredBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSourceX, a_RelSourceY, a_RelSourceZ](const sPoweredBlocks & itr)
+ {
+ if (itr.a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ)))
+ {
+ BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos);
+ a_Chunk->SetIsRedstoneDirty(true);
+ return true;
+ }
+ return false;
+ }
+ ), Data->m_PoweredBlocks.end());
+
+ Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelSourceX, a_RelSourceY, a_RelSourceZ](const sLinkedPoweredBlocks & itr)
+ {
+ if (itr.a_SourcePos.Equals(Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ)))
+ {
+ BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos);
+ a_Chunk->SetIsRedstoneDirty(true);
+ return true;
+ }
+ return false;
+ }
+ ), Data->m_LinkedBlocks.end());
+
+ if (a_IsFirstCall && AreCoordsOnChunkBoundary(a_RelSourceX, a_RelSourceY, a_RelSourceZ))
+ {
+ // +- 2 to accomodate linked powered blocks
+ SetSourceUnpowered(a_RelSourceX, a_RelSourceY, a_RelSourceZ, a_Chunk->GetRelNeighborChunk(a_RelSourceX - 2, a_RelSourceZ), false);
+ SetSourceUnpowered(a_RelSourceX, a_RelSourceY, a_RelSourceZ, a_Chunk->GetRelNeighborChunk(a_RelSourceX + 2, a_RelSourceZ), false);
+ SetSourceUnpowered(a_RelSourceX, a_RelSourceY, a_RelSourceZ, a_Chunk->GetRelNeighborChunk(a_RelSourceX, a_RelSourceZ - 2), false);
+ SetSourceUnpowered(a_RelSourceX, a_RelSourceY, a_RelSourceZ, a_Chunk->GetRelNeighborChunk(a_RelSourceX, a_RelSourceZ + 2), false);
+ }
+
+ for (const auto & itr : BlocksPotentiallyUnpowered)
+ {
+ if (!AreCoordsPowered(itr.x, itr.y, itr.z))
+ {
+ SetSourceUnpowered(itr.x, itr.y, itr.z, a_Chunk->GetRelNeighborChunk(itr.x, itr.z));
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk, bool a_IsFirstCall)
+{
+ if (!a_IsFirstCall) // The neighbouring chunks passed when this parameter is false may be invalid
+ {
+ if ((a_Chunk == nullptr) || !a_Chunk->IsValid())
+ {
+ return;
+ }
+ }
+
+ std::vector<Vector3i> BlocksPotentiallyUnpowered;
+ auto Data = (cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData();
+
+ Data->m_LinkedBlocks.erase(std::remove_if(Data->m_LinkedBlocks.begin(), Data->m_LinkedBlocks.end(), [&BlocksPotentiallyUnpowered, a_Chunk, a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ](const sLinkedPoweredBlocks & itr)
+ {
+ if (itr.a_MiddlePos.Equals(Vector3i(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ)))
+ {
+ BlocksPotentiallyUnpowered.emplace_back(itr.a_BlockPos);
+ a_Chunk->SetIsRedstoneDirty(true);
+ return true;
+ }
+ return false;
+ }
+ ), Data->m_LinkedBlocks.end());
+
+ if (a_IsFirstCall && AreCoordsOnChunkBoundary(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ))
+ {
+ // +- 2 to accomodate linked powered blocks
+ SetInvalidMiddleBlock(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, a_Chunk->GetRelNeighborChunk(a_RelMiddleX - 2, a_RelMiddleZ), false);
+ SetInvalidMiddleBlock(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, a_Chunk->GetRelNeighborChunk(a_RelMiddleX + 2, a_RelMiddleZ), false);
+ SetInvalidMiddleBlock(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, a_Chunk->GetRelNeighborChunk(a_RelMiddleX, a_RelMiddleZ - 2), false);
+ SetInvalidMiddleBlock(a_RelMiddleX, a_RelMiddleY, a_RelMiddleZ, a_Chunk->GetRelNeighborChunk(a_RelMiddleX, a_RelMiddleZ + 2), false);
+ }
+
+ for (const auto & itr : BlocksPotentiallyUnpowered)
+ {
+ if (!AreCoordsPowered(itr.x, itr.y, itr.z))
+ {
+ SetSourceUnpowered(itr.x, itr.y, itr.z, a_Chunk->GetRelNeighborChunk(itr.x, itr.z));
+ }
+ }
+}
+
+
+
+
+
+cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
+{
+ int Dir = REDSTONE_NONE;
+
+ BLOCKTYPE NegX = 0;
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, NegX))
+ {
+ if (IsPotentialSource(NegX))
+ {
+ Dir |= (REDSTONE_X_POS);
+ }
+ }
+
+ BLOCKTYPE PosX = 0;
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, PosX))
+ {
+ if (IsPotentialSource(PosX))
+ {
+ Dir |= (REDSTONE_X_NEG);
+ }
+ }
+
+ BLOCKTYPE NegZ = 0;
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, NegZ))
+ {
+ if (IsPotentialSource(NegZ))
+ {
+ if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
+ {
+ Dir ^= REDSTONE_X_POS;
+ Dir |= REDSTONE_X_NEG;
+ }
+ if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
+ {
+ Dir ^= REDSTONE_X_NEG;
+ Dir |= REDSTONE_X_POS;
+ }
+ Dir |= REDSTONE_Z_POS;
+ }
+ }
+
+ BLOCKTYPE PosZ = 0;
+ if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, PosZ))
+ {
+ if (IsPotentialSource(PosZ))
+ {
+ if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
+ {
+ Dir ^= REDSTONE_X_POS;
+ Dir |= REDSTONE_X_NEG;
+ }
+ if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
+ {
+ Dir ^= REDSTONE_X_NEG;
+ Dir |= REDSTONE_X_POS;
+ }
+ Dir |= REDSTONE_Z_NEG;
+ }
+ }
+ return (eRedstoneDirection)Dir;
+}
+
+
+
+
+
+bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta)
+{
+ // Extract the ON bit from metadata and return if true if it is set:
+ return ((a_BlockMeta & 0x8) == 0x8);
+}
+
+
+
+
diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h
index 5bd1ad95d..3d2962c08 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.h
+++ b/src/Simulator/IncrementalRedstoneSimulator.h
@@ -2,8 +2,396 @@
#pragma once
#include "RedstoneSimulator.h"
+#include "BlockEntities/RedstonePoweredEntity.h"
class cWorld;
class cChunk;
-cRedstoneSimulator<cChunk, cWorld> * MakeIncrementalRedstoneSimulator(cWorld & a_World);
+
+
+
+
+typedef cItemCallback<cRedstonePoweredEntity> cRedstonePoweredCallback;
+
+
+
+class cIncrementalRedstoneSimulator :
+ public cRedstoneSimulator
+{
+ typedef cRedstoneSimulator super;
+public:
+
+ cIncrementalRedstoneSimulator(cWorld & a_World)
+ : cRedstoneSimulator(a_World)
+ {
+ }
+
+ virtual cRedstoneSimulatorChunkData * CreateChunkData() override
+ {
+ return new cIncrementalRedstoneSimulatorChunkData;
+ }
+
+ 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 bool IsAllowedBlock(BLOCKTYPE a_BlockType) override { return IsRedstone(a_BlockType); }
+ virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override;
+
+ enum eRedstoneDirection
+ {
+ REDSTONE_NONE = 0,
+ REDSTONE_X_POS = 0x1,
+ REDSTONE_X_NEG = 0x2,
+ REDSTONE_Z_POS = 0x4,
+ REDSTONE_Z_NEG = 0x8,
+ };
+ eRedstoneDirection GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+private:
+
+#define MAX_POWER_LEVEL 15
+
+ 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
+ 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)
+ {
+ Vector3i a_BlockPos;
+ 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)
+ {
+ Vector3i a_RelBlockPos;
+ 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
+ {
+ 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?
+ };
+
+ class cIncrementalRedstoneSimulatorChunkData :
+ public cRedstoneSimulatorChunkData
+ {
+ public:
+ /// Per-chunk data for the simulator, specified individual chunks to simulate
+ cCoordWithBlockAndBoolVector m_ChunkData;
+ cCoordWithBlockAndBoolVector m_QueuedChunkData;
+ std::vector<sPoweredBlocks> m_PoweredBlocks;
+ std::vector<sLinkedPoweredBlocks> m_LinkedBlocks;
+ std::vector<sSimulatedPlayerToggleableList> m_SimulatedPlayerToggleableBlocks;
+ std::vector<sRepeatersDelayList> m_RepeatersDelayList;
+ };
+
+public:
+
+ typedef std::vector <sPoweredBlocks> PoweredBlocksList;
+ typedef std::vector <sLinkedPoweredBlocks> LinkedBlocksList;
+ typedef std::vector <sSimulatedPlayerToggleableList> SimulatedPlayerToggleableList;
+ typedef std::vector <sRepeatersDelayList> RepeatersDelayList;
+
+private:
+
+ cIncrementalRedstoneSimulatorChunkData * m_RedstoneSimulatorChunkData;
+ PoweredBlocksList * m_PoweredBlocks;
+ LinkedBlocksList * m_LinkedPoweredBlocks;
+ SimulatedPlayerToggleableList * m_SimulatedPlayerToggleableBlocks;
+ RepeatersDelayList * m_RepeatersDelayList;
+
+ virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override { RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); }
+ void RedstoneAddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk, cChunk * a_OtherChunk = nullptr);
+ cChunk * m_Chunk;
+
+ // We want a_MyState for devices needing a full FastSetBlock (as opposed to meta) because with our simulation model, we cannot keep setting the block if it is already set correctly
+ // In addition to being non-performant, it would stop the player from actually breaking said device
+
+ /* ====== SOURCES ====== */
+ /** Handles the redstone torch */
+ void HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
+ /** Handles the redstone block */
+ void HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
+ /** Handles levers */
+ void HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
+ /** Handles buttons */
+ void HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
+ /** Handles daylight sensors */
+ 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 ====== */
+ /** Handles redstone wire */
+ 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);
+ /* ====================== */
+
+ /* ====== DEVICES ====== */
+ /** Handles pistons */
+ void HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
+ /** Handles dispensers and droppers */
+ void HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
+ /** Handles TNT (exploding) */
+ void HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
+ /** Handles redstone lamps */
+ void HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
+ /** Handles doords */
+ void HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
+ /** Handles command blocks */
+ void HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
+ /** Handles activator, detector, and powered rails */
+ void HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType);
+ /** Handles trapdoors */
+ void HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
+ /** Handles fence gates */
+ 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 ====== */
+ /** Marks a block as powered */
+ void SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
+ /** Marks a block as being powered through another block */
+ void SetBlockLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
+ /** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */
+ void SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered);
+ /** Marks the second block in a direction as linked powered */
+ void SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
+ /** Marks all blocks immediately surrounding a coordinate as powered */
+ 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);
+ void SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk, bool a_IsFirstCall = true);
+
+ /** Returns if a coordinate is powered or linked powered */
+ 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, 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) */
+ bool AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered);
+ /** Returns if a repeater is powered by testing for power sources behind the repeater */
+ bool IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
+ /** Returns if a repeater is locked */
+ bool IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
+ /** Returns if a piston is powered */
+ bool IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
+ /** 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);
+ /** Returns if button metadata marks it as emitting power */
+ bool IsButtonOn(NIBBLETYPE a_BlockMeta) { return IsLeverOn(a_BlockMeta); }
+ /* ============================== */
+
+ /* ====== Misc Functions ====== */
+ /** 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)
+ Used by torches to determine if they power a block whilst not standing on the ground
+ */
+ inline static bool IsMechanism(BLOCKTYPE Block)
+ {
+ switch (Block)
+ {
+ case E_BLOCK_ACACIA_DOOR:
+ case E_BLOCK_ACACIA_FENCE_GATE:
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_BIRCH_DOOR:
+ case E_BLOCK_BIRCH_FENCE_GATE:
+ case E_BLOCK_COMMAND_BLOCK:
+ case E_BLOCK_DARK_OAK_DOOR:
+ case E_BLOCK_DARK_OAK_FENCE_GATE:
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DROPPER:
+ case E_BLOCK_FENCE_GATE:
+ case E_BLOCK_HOPPER:
+ case E_BLOCK_IRON_DOOR:
+ case E_BLOCK_IRON_TRAPDOOR:
+ case E_BLOCK_JUNGLE_DOOR:
+ case E_BLOCK_JUNGLE_FENCE_GATE:
+ case E_BLOCK_NOTE_BLOCK:
+ case E_BLOCK_PISTON:
+ case E_BLOCK_POWERED_RAIL:
+ case E_BLOCK_REDSTONE_LAMP_OFF:
+ case E_BLOCK_REDSTONE_LAMP_ON:
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ case E_BLOCK_REDSTONE_WIRE:
+ case E_BLOCK_SPRUCE_DOOR:
+ case E_BLOCK_SPRUCE_FENCE_GATE:
+ case E_BLOCK_STICKY_PISTON:
+ case E_BLOCK_TNT:
+ case E_BLOCK_TRAPDOOR:
+ case E_BLOCK_WOODEN_DOOR:
+ {
+ return true;
+ }
+ default: return false;
+ }
+ }
+
+ /** Returns if a block has the potential to output power */
+ inline static bool IsPotentialSource(BLOCKTYPE Block)
+ {
+ switch (Block)
+ {
+ case E_BLOCK_DETECTOR_RAIL:
+ case E_BLOCK_DAYLIGHT_SENSOR:
+ case E_BLOCK_WOODEN_BUTTON:
+ case E_BLOCK_STONE_BUTTON:
+ case E_BLOCK_REDSTONE_WIRE:
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ case E_BLOCK_LEVER:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ case E_BLOCK_BLOCK_OF_REDSTONE:
+ case E_BLOCK_ACTIVE_COMPARATOR:
+ case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
+ 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;
+ }
+ default: return false;
+ }
+ }
+
+ /** Returns if a block is any sort of redstone device */
+ inline static bool IsRedstone(BLOCKTYPE Block)
+ {
+ switch (Block)
+ {
+ // All redstone devices, please alpha sort
+ case E_BLOCK_ACACIA_DOOR:
+ case E_BLOCK_ACACIA_FENCE_GATE:
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_ACTIVE_COMPARATOR:
+ case E_BLOCK_BIRCH_DOOR:
+ case E_BLOCK_BIRCH_FENCE_GATE:
+ case E_BLOCK_BLOCK_OF_REDSTONE:
+ case E_BLOCK_COMMAND_BLOCK:
+ case E_BLOCK_DARK_OAK_DOOR:
+ case E_BLOCK_DARK_OAK_FENCE_GATE:
+ case E_BLOCK_DAYLIGHT_SENSOR:
+ case E_BLOCK_DETECTOR_RAIL:
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DROPPER:
+ case E_BLOCK_FENCE_GATE:
+ case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
+ case E_BLOCK_HOPPER:
+ case E_BLOCK_INACTIVE_COMPARATOR:
+ case E_BLOCK_IRON_DOOR:
+ case E_BLOCK_IRON_TRAPDOOR:
+ case E_BLOCK_JUNGLE_DOOR:
+ case E_BLOCK_JUNGLE_FENCE_GATE:
+ case E_BLOCK_LEVER:
+ case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
+ case E_BLOCK_NOTE_BLOCK:
+ case E_BLOCK_POWERED_RAIL:
+ case E_BLOCK_REDSTONE_LAMP_OFF:
+ case E_BLOCK_REDSTONE_LAMP_ON:
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ case E_BLOCK_REDSTONE_TORCH_OFF:
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ case E_BLOCK_REDSTONE_WIRE:
+ case E_BLOCK_SPRUCE_DOOR:
+ case E_BLOCK_SPRUCE_FENCE_GATE:
+ case E_BLOCK_STICKY_PISTON:
+ case E_BLOCK_STONE_BUTTON:
+ 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;
+ }
+ 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)
+ );
+ }
+
+ inline static Vector3i AdjustRelativeCoords(const Vector3i & a_RelPosition)
+ {
+ if (
+ (a_RelPosition.x >= 0) && (a_RelPosition.x < cChunkDef::Width) &&
+ (a_RelPosition.z >= 0) && (a_RelPosition.z < cChunkDef::Width)
+ )
+ {
+ return a_RelPosition;
+ }
+
+ Vector3i RelPos = a_RelPosition;
+
+ // Request for a different chunk, calculate chunk offset:
+ while (RelPos.x >= cChunkDef::Width)
+ {
+ RelPos.x -= cChunkDef::Width;
+ }
+ while (RelPos.x < 0)
+ {
+ RelPos.x += cChunkDef::Width;
+ }
+ while (RelPos.z >= cChunkDef::Width)
+ {
+ RelPos.z -= cChunkDef::Width;
+ }
+ while (RelPos.z < 0)
+ {
+ RelPos.z += cChunkDef::Width;
+ }
+
+ return RelPos;
+ }
+};
+
+
+
+
diff --git a/src/Simulator/IncrementalRedstoneSimulator.inc b/src/Simulator/IncrementalRedstoneSimulator.inc
deleted file mode 100644
index 2d03584e2..000000000
--- a/src/Simulator/IncrementalRedstoneSimulator.inc
+++ /dev/null
@@ -1,2597 +0,0 @@
-
-#include "IncrementalRedstoneSimulator.h"
-#include "BoundingBox.h"
-#include "BlockEntities/RedstonePoweredEntity.h"
-#include "Blocks/ChunkInterface.h"
-#include "RedstoneSimulator.h"
-
-
-typedef cItemCallback<cEntity> cEntityCallback;
-
-
-
-
-
-typedef cItemCallback<cRedstonePoweredEntity> cRedstonePoweredCallback;
-
-
-template<class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-class cIncrementalRedstoneSimulator :
- public cRedstoneSimulator<ChunkType, WorldType>
-{
- typedef cRedstoneSimulator<ChunkType, WorldType> super;
-public:
-
- cIncrementalRedstoneSimulator(WorldType & a_World)
- : cRedstoneSimulator<ChunkType, WorldType>(a_World)
- {
- }
- ~cIncrementalRedstoneSimulator();
-
- virtual cRedstoneSimulatorChunkData * CreateChunkData() override
- {
- return new cIncrementalRedstoneSimulatorChunkData;
- }
-
- virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used
- virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, ChunkType * a_Chunk) override;
- virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override { return IsRedstone(a_BlockType); }
- virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, ChunkType * a_Chunk) override;
-
- enum eRedstoneDirection
- {
- REDSTONE_NONE = 0,
- REDSTONE_X_POS = 0x1,
- REDSTONE_X_NEG = 0x2,
- REDSTONE_Z_POS = 0x4,
- REDSTONE_Z_NEG = 0x8,
- };
- eRedstoneDirection GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ);
-
-private:
-
- #define MAX_POWER_LEVEL 15
-
- 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
- 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)
- {
- Vector3i a_BlockPos;
- 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)
- {
- Vector3i a_RelBlockPos;
- 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
- {
- 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?
- };
-
- class cIncrementalRedstoneSimulatorChunkData :
- public cRedstoneSimulatorChunkData
- {
- public:
- /// Per-chunk data for the simulator, specified individual chunks to simulate
- cCoordWithBlockAndBoolVector m_ChunkData;
- cCoordWithBlockAndBoolVector m_QueuedChunkData;
- std::vector<sPoweredBlocks> m_PoweredBlocks;
- std::vector<sLinkedPoweredBlocks> m_LinkedBlocks;
- std::vector<sSimulatedPlayerToggleableList> m_SimulatedPlayerToggleableBlocks;
- std::vector<sRepeatersDelayList> m_RepeatersDelayList;
- };
-
-public:
-
- typedef std::vector <sPoweredBlocks> PoweredBlocksList;
- typedef std::vector <sLinkedPoweredBlocks> LinkedBlocksList;
- typedef std::vector <sSimulatedPlayerToggleableList> SimulatedPlayerToggleableList;
- typedef std::vector <sRepeatersDelayList> RepeatersDelayList;
-
-private:
-
- cIncrementalRedstoneSimulatorChunkData * m_RedstoneSimulatorChunkData;
- PoweredBlocksList * m_PoweredBlocks;
- LinkedBlocksList * m_LinkedPoweredBlocks;
- SimulatedPlayerToggleableList * m_SimulatedPlayerToggleableBlocks;
- RepeatersDelayList * m_RepeatersDelayList;
-
- virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, ChunkType * a_Chunk) override { RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); }
- void RedstoneAddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, ChunkType * a_Chunk, ChunkType * a_OtherChunk = NULL);
- ChunkType * m_Chunk;
-
- // We want a_MyState for devices needing a full FastSetBlock (as opposed to meta) because with our simulation model, we cannot keep setting the block if it is already set correctly
- // In addition to being non-performant, it would stop the player from actually breaking said device
-
- /* ====== SOURCES ====== */
- /** Handles the redstone torch */
- void HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
- /** Handles the redstone block */
- void HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
- /** Handles levers */
- void HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
- /** Handles buttons */
- void HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
- /** Handles daylight sensors */
- 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 ====== */
- /** Handles redstone wire */
- 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);
- /* ====================== */
-
- /* ====== DEVICES ====== */
- /** Handles pistons */
- void HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
- /** Handles dispensers and droppers */
- void HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
- /** Handles TNT (exploding) */
- void HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
- /** Handles redstone lamps */
- void HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
- /** Handles doords */
- void HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
- /** Handles command blocks */
- void HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
- /** Handles activator, detector, and powered rails */
- void HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType);
- /** Handles trapdoors */
- void HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
- /** Handles fence gates */
- 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 ====== */
- /** Marks a block as powered */
- void SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
- /** Marks a block as being powered through another block */
- void SetBlockLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
- /** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */
- void SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered);
- /** Marks the second block in a direction as linked powered */
- void SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
- /** Marks all blocks immediately surrounding a coordinate as powered */
- 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, ChunkType * 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, 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, ChunkType * 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) */
- bool AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered);
- /** Returns if a repeater is powered by testing for power sources behind the repeater */
- bool IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
- /** Returns if a repeater is locked */
- bool IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
- /** Returns if a piston is powered */
- bool IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
- /** 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);
- /** Returns if button metadata marks it as emitting power */
- bool IsButtonOn(NIBBLETYPE a_BlockMeta) { return IsLeverOn(a_BlockMeta); }
- /* ============================== */
-
- /* ====== Misc Functions ====== */
- /** 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)
- Used by torches to determine if they power a block whilst not standing on the ground
- */
- inline static bool IsMechanism(BLOCKTYPE Block)
- {
- switch (Block)
- {
- case E_BLOCK_ACACIA_DOOR:
- case E_BLOCK_ACACIA_FENCE_GATE:
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_BIRCH_DOOR:
- case E_BLOCK_BIRCH_FENCE_GATE:
- case E_BLOCK_COMMAND_BLOCK:
- case E_BLOCK_DARK_OAK_DOOR:
- case E_BLOCK_DARK_OAK_FENCE_GATE:
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DROPPER:
- case E_BLOCK_FENCE_GATE:
- case E_BLOCK_HOPPER:
- case E_BLOCK_IRON_DOOR:
- case E_BLOCK_IRON_TRAPDOOR:
- case E_BLOCK_JUNGLE_DOOR:
- case E_BLOCK_JUNGLE_FENCE_GATE:
- case E_BLOCK_NOTE_BLOCK:
- case E_BLOCK_PISTON:
- case E_BLOCK_POWERED_RAIL:
- case E_BLOCK_REDSTONE_LAMP_OFF:
- case E_BLOCK_REDSTONE_LAMP_ON:
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- case E_BLOCK_REDSTONE_WIRE:
- case E_BLOCK_SPRUCE_DOOR:
- case E_BLOCK_SPRUCE_FENCE_GATE:
- case E_BLOCK_STICKY_PISTON:
- case E_BLOCK_TNT:
- case E_BLOCK_TRAPDOOR:
- case E_BLOCK_WOODEN_DOOR:
- {
- return true;
- }
- default: return false;
- }
- }
-
- /** Returns if a block has the potential to output power */
- inline static bool IsPotentialSource(BLOCKTYPE Block)
- {
- switch (Block)
- {
- case E_BLOCK_DETECTOR_RAIL:
- case E_BLOCK_DAYLIGHT_SENSOR:
- case E_BLOCK_WOODEN_BUTTON:
- case E_BLOCK_STONE_BUTTON:
- case E_BLOCK_REDSTONE_WIRE:
- case E_BLOCK_REDSTONE_TORCH_ON:
- case E_BLOCK_LEVER:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- case E_BLOCK_BLOCK_OF_REDSTONE:
- case E_BLOCK_ACTIVE_COMPARATOR:
- case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
- 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;
- }
- default: return false;
- }
- }
-
- /** Returns if a block is any sort of redstone device */
- inline static bool IsRedstone(BLOCKTYPE Block)
- {
- switch (Block)
- {
- // All redstone devices, please alpha sort
- case E_BLOCK_ACACIA_DOOR:
- case E_BLOCK_ACACIA_FENCE_GATE:
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_ACTIVE_COMPARATOR:
- case E_BLOCK_BIRCH_DOOR:
- case E_BLOCK_BIRCH_FENCE_GATE:
- case E_BLOCK_BLOCK_OF_REDSTONE:
- case E_BLOCK_COMMAND_BLOCK:
- case E_BLOCK_DARK_OAK_DOOR:
- case E_BLOCK_DARK_OAK_FENCE_GATE:
- case E_BLOCK_DAYLIGHT_SENSOR:
- case E_BLOCK_DETECTOR_RAIL:
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DROPPER:
- case E_BLOCK_FENCE_GATE:
- case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
- case E_BLOCK_HOPPER:
- case E_BLOCK_INACTIVE_COMPARATOR:
- case E_BLOCK_IRON_DOOR:
- case E_BLOCK_IRON_TRAPDOOR:
- case E_BLOCK_JUNGLE_DOOR:
- case E_BLOCK_JUNGLE_FENCE_GATE:
- case E_BLOCK_LEVER:
- case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
- case E_BLOCK_NOTE_BLOCK:
- case E_BLOCK_POWERED_RAIL:
- case E_BLOCK_REDSTONE_LAMP_OFF:
- case E_BLOCK_REDSTONE_LAMP_ON:
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- case E_BLOCK_REDSTONE_TORCH_OFF:
- case E_BLOCK_REDSTONE_TORCH_ON:
- case E_BLOCK_REDSTONE_WIRE:
- case E_BLOCK_SPRUCE_DOOR:
- case E_BLOCK_SPRUCE_FENCE_GATE:
- case E_BLOCK_STICKY_PISTON:
- case E_BLOCK_STONE_BUTTON:
- 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;
- }
- 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)
- );
- }
-};
-
-
-
-
-
-template<class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::~cIncrementalRedstoneSimulator()
-{
-}
-
-
-
-
-template<class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::RedstoneAddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, ChunkType * a_Chunk, ChunkType * a_OtherChunk)
-{
- if ((a_Chunk == NULL) || !a_Chunk->IsValid())
- {
- return;
- }
- else if ((a_BlockY < 0) || (a_BlockY > cChunkDef::Height))
- {
- return;
- }
-
- // We may be called with coordinates in a chunk that is not the first chunk parameter
- // In that case, the actual chunk (which the coordinates are in), will be passed as the second parameter
- // Use that Chunk pointer to get a relative position
-
- int RelX = 0;
- int RelZ = 0;
- BLOCKTYPE Block;
- NIBBLETYPE Meta;
-
- 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);
-
- // 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
- {
- RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
- RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
- a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
- }
-
- // 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
-
- cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData * SimulatorChunkData = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData());
- if (SimulatorChunkData == NULL)
- {
- return;
- }
- PoweredBlocksList & PoweredBlocks = SimulatorChunkData->m_PoweredBlocks;
- for (typename PoweredBlocksList::iterator itr = PoweredBlocks.begin(); itr != PoweredBlocks.end();)
- {
- if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- ++itr;
- continue;
- }
-
- if (!IsPotentialSource(Block))
- {
- 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);
- 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_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ||
- ((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);
- continue;
- }
- ++itr;
- }
-
- LinkedBlocksList & LinkedPoweredBlocks = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks;
- // We loop through all values (insteading of breaking out at the first) to make sure everything is gone, as there can be multiple SourceBlock entries for one AddBlock coordinate
- for (typename LinkedBlocksList::iterator itr = LinkedPoweredBlocks.begin(); itr != LinkedPoweredBlocks.end();)
- {
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- if (!IsPotentialSource(Block))
- {
- 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);
- 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)))
- )
- {
- 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);
- continue;
- }
- }
- else if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- if (!IsViableMiddleBlock(Block))
- {
- 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);
- continue;
- }
- }
- ++itr;
- }
-
- SimulatedPlayerToggleableList & SimulatedPlayerToggleableBlocks = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_SimulatedPlayerToggleableBlocks;
- for (typename SimulatedPlayerToggleableList::iterator itr = SimulatedPlayerToggleableBlocks.begin(); itr != SimulatedPlayerToggleableBlocks.end(); ++itr)
- {
- if (!itr->a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)))
- {
- continue;
- }
-
- if (!IsAllowedBlock(Block))
- {
- LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z);
- SimulatedPlayerToggleableBlocks.erase(itr);
- break;
- }
- }
-
- RepeatersDelayList & RepeatersDelayList = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_RepeatersDelayList;
- for (typename RepeatersDelayList::iterator itr = RepeatersDelayList.begin(); itr != RepeatersDelayList.end(); ++itr)
- {
- if (!itr->a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ)))
- {
- continue;
- }
-
- if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF))
- {
- RepeatersDelayList.erase(itr);
- break;
- }
- }
-
- if (a_OtherChunk != NULL)
- {
- // DO NOT touch our chunk's data structure if we are being called with coordinates from another chunk - this one caused me massive grief :P
- return;
- }
-
- cCoordWithBlockAndBoolVector & RedstoneSimulatorChunkData = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_ChunkData;
- for (cCoordWithBlockAndBoolVector::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 (!IsAllowedBlock(Block))
- {
- itr->DataTwo = true; // The new blocktype is not redstone; it must be queued to be removed from this list
- }
- else
- {
- itr->DataTwo = false;
- itr->Data = Block; // Update block information
- }
- return;
- }
- }
-
- if (!IsAllowedBlock(Block))
- {
- return;
- }
-
- cCoordWithBlockAndBoolVector & QueuedData = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData;
- for (cCoordWithBlockAndBoolVector::iterator itr = QueuedData.begin(); itr != QueuedData.end(); ++itr)
- {
- if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ))
- {
- // Can't have duplicates in here either, in case something adds the block again before the structure can written to the main chunk data
- return;
- }
- }
- QueuedData.push_back(cCoordWithBlockAndBool(RelX, a_BlockY, RelZ, Block, false));
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, ChunkType * a_Chunk)
-{
- m_RedstoneSimulatorChunkData = (cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData();
- if (m_RedstoneSimulatorChunkData == NULL)
- {
- m_RedstoneSimulatorChunkData = new cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData();
- a_Chunk->SetRedstoneSimulatorData(m_RedstoneSimulatorChunkData);
- }
- if (m_RedstoneSimulatorChunkData->m_ChunkData.empty() && ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_QueuedChunkData.empty())
- {
- return;
- }
-
- m_RedstoneSimulatorChunkData->m_ChunkData.insert(
- m_RedstoneSimulatorChunkData->m_ChunkData.end(),
- m_RedstoneSimulatorChunkData ->m_QueuedChunkData.begin(),
- m_RedstoneSimulatorChunkData ->m_QueuedChunkData.end());
-
- m_RedstoneSimulatorChunkData->m_QueuedChunkData.clear();
-
- m_PoweredBlocks = &m_RedstoneSimulatorChunkData->m_PoweredBlocks;
- m_RepeatersDelayList = &m_RedstoneSimulatorChunkData->m_RepeatersDelayList;
- m_SimulatedPlayerToggleableBlocks = &m_RedstoneSimulatorChunkData->m_SimulatedPlayerToggleableBlocks;
- m_LinkedPoweredBlocks = &m_RedstoneSimulatorChunkData->m_LinkedBlocks;
- m_Chunk = a_Chunk;
- bool ShouldUpdateSimulateOnceBlocks = false;
-
- if (a_Chunk->IsRedstoneDirty())
- {
- // Simulate the majority of devices only if something (blockwise or power-wise) has changed
- // Make sure to allow the chunk to resimulate after the initial run if there was a power change (ShouldUpdateSimulateOnceBlocks helps to do this)
- a_Chunk->SetIsRedstoneDirty(false);
- ShouldUpdateSimulateOnceBlocks = true;
- }
-
- HandleRedstoneRepeaterDelays();
-
- for (cCoordWithBlockAndBoolVector::iterator dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.begin(); dataitr != m_RedstoneSimulatorChunkData->m_ChunkData.end();)
- {
- if (dataitr->DataTwo)
- {
- dataitr = m_RedstoneSimulatorChunkData->m_ChunkData.erase(dataitr);
- continue;
- }
-
- 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:
- case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
- {
- HandlePressurePlate(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
- break;
- }
- default: break;
- }
-
- 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;
- case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(dataitr->x, dataitr->y, dataitr->z); break;
- case E_BLOCK_LEVER: HandleRedstoneLever(dataitr->x, dataitr->y, dataitr->z); break;
- case E_BLOCK_TNT: HandleTNT(dataitr->x, dataitr->y, dataitr->z); break;
- case E_BLOCK_IRON_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break;
- case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break;
- case E_BLOCK_TRAPPED_CHEST: HandleTrappedChest(dataitr->x, dataitr->y, dataitr->z); break;
-
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_DETECTOR_RAIL:
- case E_BLOCK_POWERED_RAIL:
- {
- HandleRail(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
- break;
- }
- case E_BLOCK_ACACIA_DOOR:
- case E_BLOCK_BIRCH_DOOR:
- case E_BLOCK_DARK_OAK_DOOR:
- case E_BLOCK_JUNGLE_DOOR:
- case E_BLOCK_SPRUCE_DOOR:
- case E_BLOCK_WOODEN_DOOR:
- case E_BLOCK_IRON_DOOR:
- {
- HandleDoor(dataitr->x, dataitr->y, dataitr->z);
- break;
- }
- case E_BLOCK_ACACIA_FENCE_GATE:
- case E_BLOCK_BIRCH_FENCE_GATE:
- case E_BLOCK_DARK_OAK_FENCE_GATE:
- case E_BLOCK_FENCE_GATE:
- case E_BLOCK_JUNGLE_FENCE_GATE:
- case E_BLOCK_SPRUCE_FENCE_GATE:
- {
- HandleFenceGate(dataitr->x, dataitr->y, dataitr->z);
- break;
- }
- case E_BLOCK_REDSTONE_LAMP_OFF:
- case E_BLOCK_REDSTONE_LAMP_ON:
- {
- HandleRedstoneLamp(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
- break;
- }
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DROPPER:
- {
- HandleDropSpenser(dataitr->x, dataitr->y, dataitr->z);
- break;
- }
- case E_BLOCK_PISTON:
- case E_BLOCK_STICKY_PISTON:
- {
- HandlePiston(dataitr->x, dataitr->y, dataitr->z);
- break;
- }
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- {
- HandleRedstoneRepeater(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
- break;
- }
- case E_BLOCK_REDSTONE_TORCH_OFF:
- case E_BLOCK_REDSTONE_TORCH_ON:
- {
- HandleRedstoneTorch(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
- break;
- }
- case E_BLOCK_STONE_BUTTON:
- case E_BLOCK_WOODEN_BUTTON:
- {
- HandleRedstoneButton(dataitr->x, dataitr->y, dataitr->z);
- break;
- }
- default: break;
- }
- }
- ++dataitr;
- }
-}
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, ChunkType * a_Chunk)
-{
- if (AreCoordsOnChunkBoundary(a_BlockX, a_BlockY, a_BlockZ))
- {
- // On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk)
- AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
-
- // Pass the original coordinates, because when adding things to our simulator lists, we get the chunk that they are in, and therefore any updates need to preseve their position
- // RedstoneAddBlock to pass both the neighbouring chunk and the chunk which the coordinates are in and +- 2 in GetNeighbour() to accomodate for LinkedPowered blocks being 2 away from chunk boundaries
- RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 2, a_BlockZ), a_Chunk);
- RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 2, a_BlockZ), a_Chunk);
- RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 2), a_Chunk);
- RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ + 2), a_Chunk);
-
- return;
- }
-
- // Not on boundary, just alert this chunk for speed
- AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, 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_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ;
- AddFaceDirection(X, Y, Z, GetHandlerCompileTime<E_BLOCK_TORCH>::type::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on
-
- ChunkType * Neighbour = m_Chunk->GetRelNeighborChunk(X, Z);
- if ((Neighbour == NULL) || !Neighbour->IsValid())
- {
- return;
- }
-
- 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));
- return;
- }
-
- // Torch still on, make all 4(X, Z) + 1(Y) sides powered
- for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
- {
- BLOCKTYPE Type = 0;
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type))
- {
- continue;
- }
- if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last)
- {
- if (
- 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);
- }
- }
- else
- {
- // Top side, power whatever is there, including blocks
- SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- // Power all blocks surrounding block above torch
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YP);
- }
- }
-
- 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)) // Still can't make a normal block powered though!
- {
- SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- }
- }
- }
- else
- {
- // 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, GetHandlerCompileTime<E_BLOCK_TORCH>::type::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on
-
- ChunkType * 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, Neighbour))
- {
- return; // Something matches, torch still powered
- }
-
- // Block torch on not powered, can be turned on again!
- m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::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
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
-{
- NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- if (IsLeverOn(Meta))
- {
- SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
-
- eBlockFace Dir = GetHandlerCompileTime<E_BLOCK_LEVER>::type::BlockMetaDataToBlockFace(Meta);
-
- Dir = ReverseBlockFace(Dir);
-
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir);
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleFenceGate(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;
- NIBBLETYPE MetaData = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
-
- if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
- {
- if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
- {
- if ((MetaData & 0x4) == 0)
- {
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData | 0x4);
- m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
- }
- SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
- }
- }
- else
- {
- if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
- {
- if ((MetaData & 0x4) != 0)
- {
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData & ~0x04);
- m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
- }
- SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
- }
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
-{
- NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- if (IsButtonOn(Meta))
- {
- SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
-
- eBlockFace Dir = GetHandlerCompileTime<E_BLOCK_STONE_BUTTON>::type::BlockMetaDataToBlockFace(Meta);
- Dir = ReverseBlockFace(Dir);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir);
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
-{
- static const struct // Define which directions the wire can receive power from
- {
- int x, y, z;
- } gCrossCoords[] =
- {
- { 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
- unsigned char MyPower;
- if (!IsWirePowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower))
- {
- int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
- int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0);
- this->m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ);
- return;
- }
-
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
-
- if (MyPower < 1)
- {
- return;
- }
-
- MyPower--;
-
- for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power
- {
- if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above...
- {
- BLOCKTYPE Type = 0;
- if (a_RelBlockY + 1 >= cChunkDef::Height)
- {
- continue;
- }
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, Type))
- {
- continue;
- }
- if (cBlockInfo::IsSolid(Type)) // If there is something solid above us (wire cut off)...
- {
- continue; // We don't receive power from that wire
- }
- }
- else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us
- {
- BLOCKTYPE Type = 0;
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY, a_RelBlockZ + gCrossCoords[i].z, Type))
- {
- continue;
- }
- if (cBlockInfo::IsSolid(Type))
- {
- continue;
- }
- }
-
- BLOCKTYPE Type = 0;
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type))
- {
- continue;
- }
- if (Type == E_BLOCK_REDSTONE_WIRE)
- {
- SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
- }
- }
-
- for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them
- {
- BLOCKTYPE Type = 0;
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, Type))
- {
- continue;
- }
- if (Type == E_BLOCK_REDSTONE_REPEATER_OFF)
- {
- SetBlockPowered(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
- }
- }
-
- // Wire still powered, power blocks beneath
- SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, MyPower);
-
- switch (GetWireDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
- {
- case REDSTONE_NONE:
- {
- SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
- SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
- SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
- SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
-
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower);
- break;
- }
- case REDSTONE_X_POS:
- {
- SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower);
- break;
- }
- case REDSTONE_X_NEG:
- {
- SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower);
- break;
- }
- case REDSTONE_Z_POS:
- {
- SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower);
- break;
- }
- case REDSTONE_Z_NEG:
- {
- SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower);
- break;
- }
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState)
-{
- /* Repeater Orientation Mini Guide:
- ===================================
-
- |
- | Z Axis
- V
-
- X Axis ---->
-
- Repeater directions, values from a WorldType::GetBlockMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) lookup:
-
- East (Right) (X+): 0x1
- West (Left) (X-): 0x3
- North (Up) (Z-): 0x2
- South (Down) (Z+): 0x0
- // TODO: Add E_META_XXX enum entries for all meta values and update project with them
-
- Sun rises from East (X+)
-
- */
-
- // 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:
- {
- 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.
- {
- QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, true);
- }
- else if (!IsSelfPowered && IsOn) // Queue a power change if unpowered, on, and not locked.
- {
- QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, false);
- }
- }
-}
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleRedstoneRepeaterDelays()
-{
- for (typename 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?
- {
- int RelBlockX = itr->a_RelBlockPos.x;
- int RelBlockY = itr->a_RelBlockPos.y;
- int RelBlockZ = itr->a_RelBlockPos.z;
- BLOCKTYPE Block;
- NIBBLETYPE Meta;
- m_Chunk->GetBlockTypeMeta(RelBlockX, RelBlockY, RelBlockZ, Block, Meta);
- if (itr->ShouldPowerOn)
- {
- if (Block != E_BLOCK_REDSTONE_REPEATER_ON) // For performance
- {
- m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta);
- }
-
- switch (Meta & 0x3) // We only want the direction (bottom) bits
- {
- case 0x0:
- {
- SetBlockPowered(RelBlockX, RelBlockY, RelBlockZ - 1, RelBlockX, RelBlockY, RelBlockZ);
- SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_ZM);
- break;
- }
- case 0x1:
- {
- SetBlockPowered(RelBlockX + 1, RelBlockY, RelBlockZ, RelBlockX, RelBlockY, RelBlockZ);
- SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_XP);
- break;
- }
- case 0x2:
- {
- SetBlockPowered(RelBlockX, RelBlockY, RelBlockZ + 1, RelBlockX, RelBlockY, RelBlockZ);
- SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_ZP);
- break;
- }
- case 0x3:
- {
- SetBlockPowered(RelBlockX - 1, RelBlockY, RelBlockZ, RelBlockX, RelBlockY, RelBlockZ);
- SetDirectionLinkedPowered(RelBlockX, RelBlockY, RelBlockZ, BLOCK_FACE_XM);
- break;
- }
- }
- }
- else if (Block != E_BLOCK_REDSTONE_REPEATER_OFF)
- {
- m_Chunk->SetBlock(RelBlockX, RelBlockY, RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, Meta);
- }
- itr = m_RepeatersDelayList->erase(itr);
- }
- else
- {
- LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
- itr->a_ElapsedTicks++;
- itr++;
- }
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::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)
- {
- GetHandlerCompileTime<E_BLOCK_PISTON>::type::ExtendPiston(BlockX, a_RelBlockY, BlockZ, &this->m_World);
- }
- else
- {
- GetHandlerCompileTime<E_BLOCK_PISTON>::type::RetractPiston(BlockX, a_RelBlockY, BlockZ, &this->m_World);
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
-{
- class cSetPowerToDropSpenser :
- public cRedstonePoweredCallback
- {
- bool m_IsPowered;
- public:
- cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
-
- virtual bool Item(cRedstonePoweredEntity * a_DropSpenser) override
- {
- a_DropSpenser->SetRedstonePower(m_IsPowered);
- return false;
- }
- } DrSpSP (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
-
- int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
- int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
- m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, DrSpSP);
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState)
-{
- if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF)
- {
- if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
- {
- m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0);
- }
- }
- else
- {
- if (!AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
- {
- m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0);
- }
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleTNT(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 (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
- {
- 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);
- this->m_World.SpawnPrimedTNT(BlockX + 0.5, a_RelBlockY + 0.5, BlockZ + 0.5); // 80 ticks to boom
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleDoor(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;
-
- typedef typename GetHandlerCompileTime<E_BLOCK_WOODEN_DOOR>::type DoorHandler;
-
- if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
- {
- if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
- {
- cChunkInterface ChunkInterface(this->m_World.GetChunkMap());
- if (!DoorHandler::IsOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ))
- {
- DoorHandler::SetOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ, true);
- m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
- }
- SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
- }
- }
- else
- {
- if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
- {
- cChunkInterface ChunkInterface(this->m_World.GetChunkMap());
- if (DoorHandler::IsOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ))
- {
- DoorHandler::SetOpen(ChunkInterface, BlockX, a_RelBlockY, BlockZ, false);
- m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
- }
- SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
- }
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
-{
- class cSetPowerToCommandBlock :
- public cRedstonePoweredCallback
- {
- bool m_IsPowered;
- public:
- cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
-
- virtual bool Item(cRedstonePoweredEntity * a_CommandBlock) override
- {
- a_CommandBlock->SetRedstonePower(m_IsPowered);
- return false;
- }
- } CmdBlockSP (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
-
- int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
- int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
- m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, CmdBlockSP);
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType)
-{
- switch (a_MyType)
- {
- case E_BLOCK_DETECTOR_RAIL:
- {
- if ((m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x08) == 0x08)
- {
- SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_MyType);
- }
- break;
- }
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_POWERED_RAIL:
- {
- if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
- {
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0x08);
- }
- else
- {
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x07);
- }
- break;
- }
- default: LOGD("Unhandled type of rail in %s", __FUNCTION__);
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleTrapdoor(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 (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
- {
- if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
- {
- this->m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, true);
- SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
- }
- }
- else
- {
- if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
- {
- this->m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, false);
- SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
- }
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
-{
- bool m_bAreCoordsPowered = AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
-
- if (m_bAreCoordsPowered)
- {
- if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
- {
- class cSetPowerToNoteBlock :
- public cRedstonePoweredCallback
- {
- public:
- cSetPowerToNoteBlock() {}
-
- virtual bool Item(cRedstonePoweredEntity * a_NoteBlock) override
- {
- a_NoteBlock->SetRedstonePower(true);
- return false;
- }
- } NoteBlockSP;
-
- int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
- int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
- m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, NoteBlockSP);
- SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
- }
- }
- else
- {
- if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
- {
- SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
- }
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
-{
- int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX, BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
- int ChunkX, ChunkZ;
- cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
-
- if (!this->m_World.IsChunkLighted(ChunkX, ChunkZ))
- {
- this->m_World.QueueLightChunk(ChunkX, ChunkZ);
- }
- else
- {
- if (m_Chunk->GetTimeAlteredLight(this->m_World.GetBlockSkyLight(BlockX, a_RelBlockY + 1, BlockZ)) > 8)
- {
- SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- }
- else
- {
- WakeUp(BlockX, a_RelBlockY, BlockZ, m_Chunk);
- }
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType)
-{
- int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
- int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
-
- switch (a_MyType)
- {
- case E_BLOCK_STONE_PRESSURE_PLATE:
- {
- // MCS feature - stone pressure plates can only be triggered by players :D
- cPlayer * a_Player = this->m_World.FindClosestPlayer(Vector3f(BlockX + 0.5f, (float)a_RelBlockY, BlockZ + 0.5f), 0.5f, false);
-
- if (a_Player != NULL)
- {
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x1);
- SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
- }
- else
- {
- m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0);
- SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
- }
- break;
- }
- case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
- {
- class cPressurePlateCallback :
- public cEntityCallback
- {
- public:
- cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) :
- m_NumberOfEntities(0),
- 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);
- double Distance = (EntityPos - BlockPos).Length();
-
- if (Distance <= 0.5)
- {
- m_NumberOfEntities++;
- }
- return false;
- }
-
- bool GetPowerLevel(unsigned char & a_PowerLevel) const
- {
- a_PowerLevel = std::min(m_NumberOfEntities, MAX_POWER_LEVEL);
- return (a_PowerLevel > 0);
- }
-
- protected:
- int m_NumberOfEntities;
-
- int m_X;
- int m_Y;
- int m_Z;
- };
-
- cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ);
- this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback);
-
- unsigned char Power;
- NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- if (PressurePlateCallback.GetPowerLevel(Power))
- {
- if (Meta == E_META_PRESSURE_PLATE_RAISED)
- {
- 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);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
- }
- else
- {
- if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
- {
- 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);
- SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
- }
-
- break;
- }
- case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
- {
- class cPressurePlateCallback :
- public cEntityCallback
- {
- public:
- cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) :
- m_NumberOfEntities(0),
- 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);
- double Distance = (EntityPos - BlockPos).Length();
-
- if (Distance <= 0.5)
- {
- m_NumberOfEntities++;
- }
- return false;
- }
-
- bool GetPowerLevel(unsigned char & a_PowerLevel) const
- {
- a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / 10.f), MAX_POWER_LEVEL);
- return (a_PowerLevel > 0);
- }
-
- protected:
- int m_NumberOfEntities;
-
- int m_X;
- int m_Y;
- int m_Z;
- };
-
- cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ);
- this->m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback);
-
- unsigned char Power;
- NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- if (PressurePlateCallback.GetPowerLevel(Power))
- {
- if (Meta == E_META_PRESSURE_PLATE_RAISED)
- {
- 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);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
- }
- else
- {
- if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
- {
- 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);
- SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
- }
-
- break;
- }
- case E_BLOCK_WOODEN_PRESSURE_PLATE:
- {
- class cPressurePlateCallback :
- public cEntityCallback
- {
- public:
- cPressurePlateCallback(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
- {
- Vector3f EntityPos = a_Entity->GetPosition();
- Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
- double Distance = (EntityPos - BlockPos).Length();
-
- 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 false;
- }
-
- bool FoundEntity(void) const
- {
- return m_FoundEntity;
- }
-
- protected:
- bool m_FoundEntity;
-
- int m_X;
- int m_Y;
- int m_Z;
- } ;
-
- cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ);
- this->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", (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);
- SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType);
- }
- else
- {
- if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
- {
- 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);
- SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
- }
- break;
- }
- default:
- {
- LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(cItem(a_MyType)).c_str());
- break;
- }
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::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 = GetHandlerCompileTime<E_BLOCK_TRIPWIRE_HOOK>::type::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( GetHandlerCompileTime<E_BLOCK_TRIPWIRE_HOOK>::type::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);
- }
-}
-
-template <class ChestType>
-class cGetTrappedChestPlayers :
- public cItemCallback<ChestType>
-{
-public:
- cGetTrappedChestPlayers(void) :
- m_NumberOfPlayers(0)
- {
- }
-
- virtual ~cGetTrappedChestPlayers()
- {
- }
-
- virtual bool Item(ChestType * 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;
-
-};
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
-{
- cGetTrappedChestPlayers<ChestType> 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);
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::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);
- this->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);
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-bool cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, ChunkType * 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;
-
- for (typename PoweredBlocksList::const_iterator itr = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks.begin(); itr != ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks.end(); ++itr) // Check powered list
- {
- if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)))
- {
- return true;
- }
- }
- return false;
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-bool cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::AreCoordsLinkedPowered(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;
-
- for (typename 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)))
- {
- return true;
- }
- }
- return false;
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-bool cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta)
-{
- // Repeaters cannot be powered by any face except their back; verify that this is true for a source
- int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
- int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
-
- for (typename PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; }
-
- switch (a_Meta & 0x3)
- {
- case 0x0:
- {
- // Flip the coords to check the back of the repeater
- if (itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ + 1))) { return true; }
- break;
- }
- case 0x1:
- {
- if (itr->a_SourcePos.Equals(Vector3i(BlockX - 1, a_RelBlockY, BlockZ))) { return true; }
- break;
- }
- case 0x2:
- {
- if (itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ - 1))) { return true; }
- break;
- }
- case 0x3:
- {
- if (itr->a_SourcePos.Equals(Vector3i(BlockX + 1, a_RelBlockY, BlockZ))) { return true; }
- break;
- }
- }
- }
-
- for (typename LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; }
-
- switch (a_Meta & 0x3)
- {
- case 0x0:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ + 1))) { return true; }
- break;
- }
- case 0x1:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(BlockX - 1, a_RelBlockY, BlockZ))) { return true; }
- break;
- }
- case 0x2:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ - 1))) { return true; }
- break;
- }
- case 0x3:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(BlockX + 1, a_RelBlockY, BlockZ))) { return true; }
- break;
- }
- }
- }
- return false; // Couldn't find power source behind repeater
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-bool cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::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
- {
- // If the repeater is looking up or down (If parallel to the Z axis)
- case 0x0:
- case 0x2:
- {
- // Check if eastern(right) neighbor is a powered on repeater who is facing us
- BLOCKTYPE Block = 0;
- NIBBLETYPE OtherRepeaterDir = 0;
- if (m_Chunk->UnboundedRelGetBlock(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, Block, OtherRepeaterDir) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) // Is right neighbor a powered repeater?
- {
- if ((OtherRepeaterDir & 0x03) == 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->UnboundedRelGetBlock(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, Block, OtherRepeaterDir) && (Block == E_BLOCK_REDSTONE_REPEATER_ON))
- {
- if ((OtherRepeaterDir & 0x03) == 0x1)
- {
- return true;
- } // If so, I am latched/locked
- }
-
- break;
- }
-
- // If the repeater is looking left or right (If parallel to the x axis)
- case 0x1:
- case 0x3:
- {
- // Check if southern(down) neighbor is a powered on repeater who is facing us
- BLOCKTYPE Block = 0;
- NIBBLETYPE OtherRepeaterDir = 0;
-
- if (m_Chunk->UnboundedRelGetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, Block, OtherRepeaterDir) && (Block == E_BLOCK_REDSTONE_REPEATER_ON))
- {
- if ((OtherRepeaterDir & 0x30 ) == 0x00)
- {
- return true;
- } // If so, am latched/locked
- }
-
- // Check if northern(up) neighbor is a powered on repeater who is facing us
- if (m_Chunk->UnboundedRelGetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, Block, OtherRepeaterDir) && (Block == E_BLOCK_REDSTONE_REPEATER_ON))
- {
- if ((OtherRepeaterDir & 0x03) == 0x02)
- {
- return true;
- } // If so, I am latched/locked
- }
-
- break;
- }
- }
-
- return false; // None of the checks succeeded, I am not a locked repeater
-}
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-bool cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta)
-{
- // Pistons cannot be powered through their front face; this function verifies that a source meets this requirement
-
- eBlockFace Face = GetHandlerCompileTime<E_BLOCK_PISTON>::type::MetaDataToDirection(a_Meta);
- int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX;
- int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ;
-
- for (typename PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; }
-
- AddFaceDirection(BlockX, a_RelBlockY, BlockZ, Face);
-
- if (!itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)))
- {
- return true;
- }
-
- AddFaceDirection(BlockX, a_RelBlockY, BlockZ, Face, true);
- }
-
- for (typename LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; }
-
- AddFaceDirection(BlockX, a_RelBlockY, BlockZ, Face);
-
- if (!itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)))
- {
- return true;
- }
-
- AddFaceDirection(BlockX, a_RelBlockY, BlockZ, Face, true);
- }
- return false; // Source was in front of the piston's front face
-}
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-bool cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::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;
-
- for (typename 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 = 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 (typename 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;
- }
-
- 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?
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-bool cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered)
-{
- for (typename SimulatedPlayerToggleableList::const_iterator itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr)
- {
- 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?
- {
- 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
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel)
-{
- BLOCKTYPE MiddleBlock = 0;
- switch (a_Direction)
- {
- case BLOCK_FACE_XM:
- {
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, MiddleBlock))
- {
- return;
- }
-
- SetBlockLinkedPowered(a_RelBlockX - 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
-
- break;
- }
- case BLOCK_FACE_XP:
- {
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, MiddleBlock))
- {
- return;
- }
-
- SetBlockLinkedPowered(a_RelBlockX + 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
-
- break;
- }
- case BLOCK_FACE_YM:
- {
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, MiddleBlock))
- {
- return;
- }
-
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
-
- break;
- }
- case BLOCK_FACE_YP:
- {
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, MiddleBlock))
- {
- return;
- }
-
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
-
- break;
- }
- case BLOCK_FACE_ZM:
- {
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, MiddleBlock))
- {
- return;
- }
-
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
-
- break;
- }
- case BLOCK_FACE_ZP:
- {
- if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, MiddleBlock))
- {
- return;
- }
-
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
- SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel);
-
- break;
- }
- default:
- {
- ASSERT(!"Unhandled face direction when attempting to set blocks as linked powered!"); // Zombies, that wasn't supposed to happen...
- break;
- }
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel)
-{
- static const struct
- {
- int x, y, z;
- } gCrossCoords[] =
- {
- { 1, 0, 0 },
- { -1, 0, 0 },
- { 0, 0, 1 },
- { 0, 0, -1 },
- { 0, 1, 0 },
- { 0, -1, 0 }
- };
-
- 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);
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel)
-{
- int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
- int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
- int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
- int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ;
-
- ChunkType * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ); // Adjust coordinates for the later call using these values
- if ((Neighbour == NULL) || !Neighbour->IsValid())
- {
- return;
- }
-
- PoweredBlocksList & Powered = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_PoweredBlocks; // We need to insert the value into the chunk who owns the block position
- for (typename PoweredBlocksList::iterator itr = Powered.begin(); itr != Powered.end(); ++itr)
- {
- if (
- itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) &&
- itr->a_SourcePos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ))
- )
- {
- // Check for duplicates, update power level, don't add a new listing
- itr->a_PowerLevel = a_PowerLevel;
- return;
- }
- }
-
- // No need to get neighbouring chunk as we can guarantee that when something is powering us, the entry will be in our chunk
- // TODO: on C++11 support, change this to a llama function pased to a std::remove_if
- for (typename 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)) &&
- (m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE)
- )
- {
- BLOCKTYPE Block;
- NIBBLETYPE Meta;
- Neighbour->GetBlockTypeMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block, Meta);
-
- if (Block == E_BLOCK_REDSTONE_WIRE)
- {
- if (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;
- }
- }
- }
- }
-
- sPoweredBlocks RC;
- RC.a_BlockPos = Vector3i(BlockX, a_RelBlockY, BlockZ);
- RC.a_SourcePos = Vector3i(SourceX, a_RelSourceY, SourceZ);
- RC.a_PowerLevel = a_PowerLevel;
- Powered.push_back(RC);
- Neighbour->SetIsRedstoneDirty(true);
- m_Chunk->SetIsRedstoneDirty(true);
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::SetBlockLinkedPowered(
- int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ,
- int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ,
- int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ,
- BLOCKTYPE a_MiddleBlock, unsigned char a_PowerLevel
- )
-{
- int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
- int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
- int MiddleX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelMiddleX;
- int MiddleZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelMiddleZ;
- int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
- int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ;
-
- if (!IsViableMiddleBlock(a_MiddleBlock))
- {
- return;
- }
-
- ChunkType * Neighbour = m_Chunk->GetNeighborChunk(BlockX, BlockZ);
- if ((Neighbour == NULL) || !Neighbour->IsValid())
- {
- return;
- }
-
- LinkedBlocksList & Linked = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)Neighbour->GetRedstoneSimulatorData())->m_LinkedBlocks;
- for (typename LinkedBlocksList::iterator itr = Linked.begin(); itr != Linked.end(); ++itr) // Check linked powered list
- {
- if (
- itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) &&
- itr->a_MiddlePos.Equals(Vector3i(MiddleX, a_RelMiddleY, MiddleZ)) &&
- itr->a_SourcePos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ))
- )
- {
- // Check for duplicates, update power level, don't add a new listing
- itr->a_PowerLevel = a_PowerLevel;
- return;
- }
- }
-
- sLinkedPoweredBlocks RC;
- RC.a_BlockPos = Vector3i(BlockX, a_RelBlockY, BlockZ);
- RC.a_MiddlePos = Vector3i(MiddleX, a_RelMiddleY, MiddleZ);
- RC.a_SourcePos = Vector3i(SourceX, a_RelSourceY, SourceZ);
- RC.a_PowerLevel = a_PowerLevel;
- Linked.push_back(RC);
- Neighbour->SetIsRedstoneDirty(true);
- m_Chunk->SetIsRedstoneDirty(true);
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered)
-{
- for (typename SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr)
- {
- if (!itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
- {
- continue;
- }
-
- if (itr->WasLastStatePowered != WasLastStatePowered)
- {
- // If power states different, update listing
- itr->WasLastStatePowered = WasLastStatePowered;
- return;
- }
- else
- {
- // If states the same, just ignore
- return;
- }
- }
-
- // We have arrive here; no block must be in list - add one
- sSimulatedPlayerToggleableList RC;
- RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
- RC.WasLastStatePowered = WasLastStatePowered;
- m_SimulatedPlayerToggleableBlocks->push_back(RC);
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-bool cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn)
-{
- for (typename RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr)
- {
- if (itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)))
- {
- if (ShouldPowerOn == itr->ShouldPowerOn) // We are queued already for the same thing, don't replace entry
- {
- return false;
- }
-
- // Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit
- itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; // See below for description
- itr->a_ElapsedTicks = 0;
- itr->ShouldPowerOn = ShouldPowerOn;
- return false;
- }
- }
-
- // Self not in list, add self to list
- sRepeatersDelayList RC;
- RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
-
- // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.)
- // Multiply by 2 because in MCS, 1 redstone tick = 1 world tick, but in Vanilla, 1 redstone tick = 2 world ticks, and we need to maintain compatibility
- RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2;
-
- RC.a_ElapsedTicks = 0;
- RC.ShouldPowerOn = ShouldPowerOn;
- m_RepeatersDelayList->push_back(RC);
- return true;
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-void cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::SetSourceUnpowered(int a_SourceX, int a_SourceY, int a_SourceZ, ChunkType * 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 (typename PoweredBlocksList::iterator itr = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks.begin(); itr != ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks.end();)
- {
- if (itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)))
- {
- itr = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_PoweredBlocks.erase(itr);
- a_Chunk->SetIsRedstoneDirty(true);
- continue;
- }
- ++itr;
- }
- for (typename LinkedBlocksList::iterator itr = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks.begin(); itr != ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks.end();)
- {
- if (itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)))
- {
- itr = ((cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::cIncrementalRedstoneSimulatorChunkData *)a_Chunk->GetRedstoneSimulatorData())->m_LinkedBlocks.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);
- }
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-typename cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::eRedstoneDirection cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
-{
- int Dir = REDSTONE_NONE;
-
- BLOCKTYPE NegX = 0;
- if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, NegX))
- {
- if (IsPotentialSource(NegX))
- {
- Dir |= (REDSTONE_X_POS);
- }
- }
-
- BLOCKTYPE PosX = 0;
- if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, PosX))
- {
- if (IsPotentialSource(PosX))
- {
- Dir |= (REDSTONE_X_NEG);
- }
- }
-
- BLOCKTYPE NegZ = 0;
- if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, NegZ))
- {
- if (IsPotentialSource(NegZ))
- {
- if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
- {
- Dir ^= REDSTONE_X_POS;
- Dir |= REDSTONE_X_NEG;
- }
- if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
- {
- Dir ^= REDSTONE_X_NEG;
- Dir |= REDSTONE_X_POS;
- }
- Dir |= REDSTONE_Z_POS;
- }
- }
-
- BLOCKTYPE PosZ = 0;
- if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, PosZ))
- {
- if (IsPotentialSource(PosZ))
- {
- if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
- {
- Dir ^= REDSTONE_X_POS;
- Dir |= REDSTONE_X_NEG;
- }
- if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
- {
- Dir ^= REDSTONE_X_NEG;
- Dir |= REDSTONE_X_POS;
- }
- Dir |= REDSTONE_Z_NEG;
- }
- }
- return (eRedstoneDirection)Dir;
-}
-
-
-
-
-template <class ChunkType, class WorldType, template <BLOCKTYPE block> class GetHandlerCompileTime, class ChestType>
-bool cIncrementalRedstoneSimulator<ChunkType, WorldType, GetHandlerCompileTime, ChestType>::IsLeverOn(NIBBLETYPE a_BlockMeta)
-{
- // Extract the ON bit from metadata and return if true if it is set:
- return ((a_BlockMeta & 0x8) == 0x8);
-}
-
-
-
-
diff --git a/src/Simulator/NoopRedstoneSimulator.h b/src/Simulator/NoopRedstoneSimulator.h
index 832b26dfc..4e05529f5 100644
--- a/src/Simulator/NoopRedstoneSimulator.h
+++ b/src/Simulator/NoopRedstoneSimulator.h
@@ -8,9 +8,9 @@
class cRedstoneNoopSimulator :
- public cRedstoneSimulator<cChunk, cWorld>
+ public cRedstoneSimulator
{
- typedef cRedstoneSimulator<cChunk, cWorld> super;
+ typedef cRedstoneSimulator super;
public:
cRedstoneNoopSimulator(cWorld & a_World) :
diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h
index 6104d39b4..b0ad08aa4 100644
--- a/src/Simulator/RedstoneSimulator.h
+++ b/src/Simulator/RedstoneSimulator.h
@@ -13,14 +13,14 @@ public:
inline cRedstoneSimulatorChunkData::~cRedstoneSimulatorChunkData() {}
-template <class ChunkType, class WorldType>
+
class cRedstoneSimulator :
- public cSimulator<ChunkType, WorldType>
+ public cSimulator
{
- typedef cSimulator<ChunkType, WorldType> super;
+ typedef cSimulator super;
public:
- cRedstoneSimulator(WorldType & a_World) :
+ cRedstoneSimulator(cWorld & a_World) :
super(a_World)
{
}
diff --git a/src/Simulator/SandSimulator.h b/src/Simulator/SandSimulator.h
index feb82b4d5..93b1de8e2 100644
--- a/src/Simulator/SandSimulator.h
+++ b/src/Simulator/SandSimulator.h
@@ -11,7 +11,7 @@ typedef cCoordWithIntList cSandSimulatorChunkData;
/// Despite the class name, this simulator takes care of all blocks that fall when suspended in the air.
class cSandSimulator :
- public cSimulator<cChunk, cWorld>
+ public cSimulator
{
public:
cSandSimulator(cWorld & a_World, cIniFile & a_IniFile);
diff --git a/src/Simulator/Simulator.cpp b/src/Simulator/Simulator.cpp
index 29a1132ad..0175fd67d 100644
--- a/src/Simulator/Simulator.cpp
+++ b/src/Simulator/Simulator.cpp
@@ -6,13 +6,35 @@
#include "../Defines.h"
#include "../Chunk.h"
-#include "Simulator.inc"
-
#ifdef __clang__
#pragma clang diagnostic ignored "-Wweak-template-vtables"
#endif // __clang__
-template class cSimulator<cChunk, cWorld>;
+
+
+#include "Simulator.h"
+
+
+
+
+
+void cSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
+{
+ AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
+ AddBlock(a_BlockX - 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 1, a_BlockZ));
+ AddBlock(a_BlockX + 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 1, a_BlockZ));
+ AddBlock(a_BlockX, a_BlockY, a_BlockZ - 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 1));
+ AddBlock(a_BlockX, a_BlockY, a_BlockZ + 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ + 1));
+ if (a_BlockY > 0)
+ {
+ AddBlock(a_BlockX, a_BlockY - 1, a_BlockZ, a_Chunk);
+ }
+ if (a_BlockY < cChunkDef::Height - 1)
+ {
+ AddBlock(a_BlockX, a_BlockY + 1, a_BlockZ, a_Chunk);
+ }
+}
+
diff --git a/src/Simulator/Simulator.h b/src/Simulator/Simulator.h
index 7cc2f1344..f28a07e35 100644
--- a/src/Simulator/Simulator.h
+++ b/src/Simulator/Simulator.h
@@ -3,24 +3,28 @@
#include "../Vector3.h"
+class cWorld;
+class cChunk;
-template <class ChunkType, class WorldType>
class cSimulator
{
public:
- cSimulator(WorldType & a_World);
- virtual ~cSimulator();
+ cSimulator(cWorld & a_World)
+ : m_World(a_World)
+ {
+ }
+
+ virtual ~cSimulator() {}
/// Called in each tick, a_Dt is the time passed since the last tick, in msec
virtual void Simulate(float a_Dt) = 0;
/// 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, ChunkType * a_Chunk)
+ virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
{
UNUSED(a_Dt);
UNUSED(a_ChunkX);
@@ -29,7 +33,7 @@ public:
}
/// Called when a block changes
- virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, ChunkType * a_Chunk);
+ virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk);
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) = 0;
@@ -37,9 +41,9 @@ protected:
friend class cChunk; // Calls AddBlock() in its WakeUpSimulators() function, to speed things up
/// Called to simulate a new block
- virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, ChunkType * a_Chunk) = 0;
+ virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) = 0;
- WorldType & m_World;
+ cWorld & m_World;
} ;
diff --git a/src/Simulator/Simulator.inc b/src/Simulator/Simulator.inc
deleted file mode 100644
index 511a6b4c2..000000000
--- a/src/Simulator/Simulator.inc
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-#include "Simulator.h"
-
-
-
-
-template <class ChunkType, class WorldType>
-cSimulator<ChunkType, WorldType>::cSimulator(WorldType & a_World)
- : m_World(a_World)
-{
-}
-
-
-
-
-template <class ChunkType, class WorldType>
-cSimulator<ChunkType, WorldType>::~cSimulator()
-{
-}
-
-
-
-
-template <class ChunkType, class WorldType>
-void cSimulator<ChunkType, WorldType>::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, ChunkType * a_Chunk)
-{
- AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
- AddBlock(a_BlockX - 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 1, a_BlockZ));
- AddBlock(a_BlockX + 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 1, a_BlockZ));
- AddBlock(a_BlockX, a_BlockY, a_BlockZ - 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 1));
- AddBlock(a_BlockX, a_BlockY, a_BlockZ + 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ + 1));
- if (a_BlockY > 0)
- {
- AddBlock(a_BlockX, a_BlockY - 1, a_BlockZ, a_Chunk);
- }
- if (a_BlockY < cChunkDef::Height - 1)
- {
- AddBlock(a_BlockX, a_BlockY + 1, a_BlockZ, a_Chunk);
- }
-}
-
-
-
-
diff --git a/src/Simulator/SimulatorManager.cpp b/src/Simulator/SimulatorManager.cpp
index dafdcd239..918bac7a1 100644
--- a/src/Simulator/SimulatorManager.cpp
+++ b/src/Simulator/SimulatorManager.cpp
@@ -70,7 +70,7 @@ void cSimulatorManager::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk
-void cSimulatorManager::RegisterSimulator(cSimulator<cChunk, cWorld> * a_Simulator, int a_Rate)
+void cSimulatorManager::RegisterSimulator(cSimulator * a_Simulator, int a_Rate)
{
m_Simulators.push_back(std::make_pair(a_Simulator, a_Rate));
}
diff --git a/src/Simulator/SimulatorManager.h b/src/Simulator/SimulatorManager.h
index 185141764..31a709316 100644
--- a/src/Simulator/SimulatorManager.h
+++ b/src/Simulator/SimulatorManager.h
@@ -37,10 +37,10 @@ public:
void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk);
- void RegisterSimulator(cSimulator<cChunk, cWorld> * a_Simulator, int a_Rate); // Takes ownership of the simulator object!
+ void RegisterSimulator(cSimulator * a_Simulator, int a_Rate); // Takes ownership of the simulator object!
protected:
- typedef std::vector <std::pair<cSimulator<cChunk, cWorld> *, int> > cSimulators;
+ typedef std::vector <std::pair<cSimulator *, int> > cSimulators;
cWorld & m_World;
cSimulators m_Simulators;
diff --git a/src/World.cpp b/src/World.cpp
index 1bee6e344..69b39f831 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1520,7 +1520,21 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
}
return true;
}
-
+
+ case E_BLOCK_COCOA_POD:
+ {
+ NIBBLETYPE TypeMeta = BlockMeta & 0x03;
+ int GrowState = BlockMeta >> 2;
+
+ if (GrowState < 2)
+ {
+ GrowState++;
+ FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, (NIBBLETYPE) (GrowState << 2 | TypeMeta));
+ BroadcastSoundParticleEffect(2005, a_BlockX, a_BlockY, a_BlockZ, 0);
+ }
+ return true;
+ }
+
case E_BLOCK_CROPS:
{
if (a_IsByBonemeal && !m_IsCropsBonemealable)
@@ -3280,7 +3294,6 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
return -1;
}
- BroadcastSpawnEntity(*a_Monster);
cPluginManager::Get()->CallHookSpawnedMonster(*this, *a_Monster);
return a_Monster->GetUniqueID();
@@ -3373,7 +3386,7 @@ void cWorld::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicke
-cRedstoneSimulator<cChunk, cWorld> * cWorld::InitializeRedstoneSimulator(cIniFile & a_IniFile)
+cRedstoneSimulator * cWorld::InitializeRedstoneSimulator(cIniFile & a_IniFile)
{
AString SimulatorName = a_IniFile.GetValueSet("Physics", "RedstoneSimulator", "Incremental");
@@ -3383,11 +3396,11 @@ cRedstoneSimulator<cChunk, cWorld> * cWorld::InitializeRedstoneSimulator(cIniFil
SimulatorName = "Incremental";
}
- cRedstoneSimulator<cChunk, cWorld> * res = nullptr;
+ cRedstoneSimulator * res = nullptr;
if (NoCaseCompare(SimulatorName, "Incremental") == 0)
{
- res = MakeIncrementalRedstoneSimulator(*this);
+ res = new cIncrementalRedstoneSimulator(*this);
}
else if (NoCaseCompare(SimulatorName, "noop") == 0)
{
diff --git a/src/World.h b/src/World.h
index 6f28ba534..4f24280a4 100644
--- a/src/World.h
+++ b/src/World.h
@@ -34,7 +34,6 @@
class cFireSimulator;
class cFluidSimulator;
class cSandSimulator;
-template <class ChunkType, class WorldType>
class cRedstoneSimulator;
class cItem;
class cPlayer;
@@ -518,7 +517,7 @@ public:
inline cFluidSimulator * GetWaterSimulator(void) { return m_WaterSimulator; }
inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; }
- inline cRedstoneSimulator<cChunk, cWorld> * GetRedstoneSimulator(void) { return m_RedstoneSimulator; }
+ inline cRedstoneSimulator * GetRedstoneSimulator(void) { return m_RedstoneSimulator; }
/** Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true */
bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp
@@ -935,7 +934,7 @@ private:
cFluidSimulator * m_WaterSimulator;
cFluidSimulator * m_LavaSimulator;
std::unique_ptr<cFireSimulator> m_FireSimulator;
- cRedstoneSimulator<cChunk, cWorld> * m_RedstoneSimulator;
+ cRedstoneSimulator * m_RedstoneSimulator;
cCriticalSection m_CSPlayers;
cPlayerList m_Players;
@@ -1079,7 +1078,7 @@ private:
cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);
/** Creates a new redstone simulator.*/
- cRedstoneSimulator<cChunk, cWorld> * InitializeRedstoneSimulator(cIniFile & a_IniFile);
+ cRedstoneSimulator * InitializeRedstoneSimulator(cIniFile & a_IniFile);
/** Adds the players queued in the m_PlayersToAdd queue into the m_Players list.
Assumes it is called from the Tick thread. */