2014-09-11 12:48:21 -04:00
#include "IncrementalRedstoneSimulator.h"
#include "BoundingBox.h"
#include "BlockEntities/RedstonePoweredEntity.h"
#include "Blocks/ChunkInterface.h"
2014-09-16 15:29:31 -04:00
#include "RedstoneSimulator.h"
2014-09-11 12:48:21 -04:00
2014-09-17 13:40:10 -04:00
typedef cItemCallback < cEntity > cEntityCallback ;
2014-09-11 12:48:21 -04:00
2014-09-16 15:29:31 -04:00
typedef cItemCallback < cRedstonePoweredEntity > cRedstonePoweredCallback ;
2014-09-11 12:48:21 -04:00
template < class ChunkType , class WorldType , template < BLOCKTYPE block > class GetHandlerCompileTime , class ChestType >
2014-09-16 15:29:31 -04:00
class cIncrementalRedstoneSimulator :
public cRedstoneSimulator < ChunkType , WorldType >
2014-09-11 12:48:21 -04:00
{
2014-09-16 15:29:31 -04:00
typedef cRedstoneSimulator < ChunkType , WorldType > super ;
public :
cIncrementalRedstoneSimulator ( WorldType & a_World )
: cRedstoneSimulator < ChunkType , WorldType > ( a_World )
{
}
~ cIncrementalRedstoneSimulator ();
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 :
2014-09-27 10:24:01 -04:00
public cRedstoneSimulatorChunkData
2014-09-16 15:29:31 -04:00
{
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 )
{
2014-09-26 13:44:06 -04:00
case E_BLOCK_ACACIA_DOOR :
case E_BLOCK_ACACIA_FENCE_GATE :
2014-09-16 15:29:31 -04:00
case E_BLOCK_ACTIVATOR_RAIL :
2014-09-26 13:44:06 -04:00
case E_BLOCK_BIRCH_DOOR :
case E_BLOCK_BIRCH_FENCE_GATE :
2014-09-16 15:29:31 -04:00
case E_BLOCK_COMMAND_BLOCK :
2014-09-26 13:44:06 -04:00
case E_BLOCK_DARK_OAK_DOOR :
case E_BLOCK_DARK_OAK_FENCE_GATE :
2014-09-16 15:29:31 -04:00
case E_BLOCK_DISPENSER :
case E_BLOCK_DROPPER :
case E_BLOCK_FENCE_GATE :
case E_BLOCK_HOPPER :
2014-09-26 13:44:06 -04:00
case E_BLOCK_IRON_DOOR :
case E_BLOCK_IRON_TRAPDOOR :
case E_BLOCK_JUNGLE_DOOR :
case E_BLOCK_JUNGLE_FENCE_GATE :
2014-09-16 15:29:31 -04:00
case E_BLOCK_NOTE_BLOCK :
2014-09-26 13:44:06 -04:00
case E_BLOCK_PISTON :
case E_BLOCK_POWERED_RAIL :
2014-09-16 15:29:31 -04:00
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 :
2014-09-26 13:44:06 -04:00
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 :
2014-09-16 15:29:31 -04:00
{
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
2014-09-26 13:44:06 -04:00
case E_BLOCK_ACACIA_DOOR :
case E_BLOCK_ACACIA_FENCE_GATE :
2014-09-16 15:29:31 -04:00
case E_BLOCK_ACTIVATOR_RAIL :
case E_BLOCK_ACTIVE_COMPARATOR :
2014-09-26 13:44:06 -04:00
case E_BLOCK_BIRCH_DOOR :
case E_BLOCK_BIRCH_FENCE_GATE :
2014-09-16 15:29:31 -04:00
case E_BLOCK_BLOCK_OF_REDSTONE :
case E_BLOCK_COMMAND_BLOCK :
2014-09-26 13:44:06 -04:00
case E_BLOCK_DARK_OAK_DOOR :
case E_BLOCK_DARK_OAK_FENCE_GATE :
case E_BLOCK_DAYLIGHT_SENSOR :
2014-09-16 15:29:31 -04:00
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 :
2014-09-26 13:44:06 -04:00
case E_BLOCK_IRON_TRAPDOOR :
case E_BLOCK_JUNGLE_DOOR :
case E_BLOCK_JUNGLE_FENCE_GATE :
2014-09-16 15:29:31 -04:00
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 :
2014-09-26 13:44:06 -04:00
case E_BLOCK_SPRUCE_DOOR :
case E_BLOCK_SPRUCE_FENCE_GATE :
2014-09-16 15:29:31 -04:00
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 )
);
}
};
2014-09-11 12:48:21 -04:00
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
2014-09-27 16:24:49 -04:00
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 ;
2014-09-16 15:29:31 -04:00
for ( typename PoweredBlocksList :: iterator itr = PoweredBlocks . begin (); itr != PoweredBlocks . end ();)
2014-09-11 12:48:21 -04:00
{
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 );
2014-09-16 15:29:31 -04:00
itr = PoweredBlocks . erase ( itr );
2014-09-11 12:48:21 -04:00
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 );
2014-09-16 15:29:31 -04:00
itr = PoweredBlocks . erase ( itr );
2014-09-11 12:48:21 -04:00
continue ;
}
++ itr ;
}
2014-09-16 15:29:31 -04:00
LinkedBlocksList & LinkedPoweredBlocks = (( cIncrementalRedstoneSimulator < ChunkType , WorldType , GetHandlerCompileTime , ChestType >:: cIncrementalRedstoneSimulatorChunkData * ) a_Chunk -> GetRedstoneSimulatorData ()) -> m_LinkedBlocks ;
2014-09-11 12:48:21 -04:00
// 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
2014-09-16 15:29:31 -04:00
for ( typename LinkedBlocksList :: iterator itr = LinkedPoweredBlocks . begin (); itr != LinkedPoweredBlocks . end ();)
2014-09-11 12:48:21 -04:00
{
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 );
2014-09-16 15:29:31 -04:00
itr = LinkedPoweredBlocks . erase ( itr );
2014-09-11 12:48:21 -04:00
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 );
2014-09-16 15:29:31 -04:00
itr = LinkedPoweredBlocks . erase ( itr );
2014-09-11 12:48:21 -04:00
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 );
2014-09-16 15:29:31 -04:00
itr = LinkedPoweredBlocks . erase ( itr );
2014-09-11 12:48:21 -04:00
continue ;
}
}
++ itr ;
}
2014-09-16 15:29:31 -04:00
SimulatedPlayerToggleableList & SimulatedPlayerToggleableBlocks = (( cIncrementalRedstoneSimulator < ChunkType , WorldType , GetHandlerCompileTime , ChestType >:: cIncrementalRedstoneSimulatorChunkData * ) a_Chunk -> GetRedstoneSimulatorData ()) -> m_SimulatedPlayerToggleableBlocks ;
for ( typename SimulatedPlayerToggleableList :: iterator itr = SimulatedPlayerToggleableBlocks . begin (); itr != SimulatedPlayerToggleableBlocks . end (); ++ itr )
2014-09-11 12:48:21 -04:00
{
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 );
2014-09-16 15:29:31 -04:00
SimulatedPlayerToggleableBlocks . erase ( itr );
2014-09-11 12:48:21 -04:00
break ;
}
}
2014-09-16 15:29:31 -04:00
RepeatersDelayList & RepeatersDelayList = (( cIncrementalRedstoneSimulator < ChunkType , WorldType , GetHandlerCompileTime , ChestType >:: cIncrementalRedstoneSimulatorChunkData * ) a_Chunk -> GetRedstoneSimulatorData ()) -> m_RepeatersDelayList ;
for ( typename RepeatersDelayList :: iterator itr = RepeatersDelayList . begin (); itr != RepeatersDelayList . end (); ++ itr )
2014-09-11 12:48:21 -04:00
{
if ( ! itr -> a_RelBlockPos . Equals ( Vector3i ( RelX , a_BlockY , RelZ )))
{
continue ;
}
if (( Block != E_BLOCK_REDSTONE_REPEATER_ON ) && ( Block != E_BLOCK_REDSTONE_REPEATER_OFF ))
{
2014-09-16 15:29:31 -04:00
RepeatersDelayList . erase ( itr );
2014-09-11 12:48:21 -04:00
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 ;
}
2014-09-16 15:29:31 -04:00
cCoordWithBlockAndBoolVector & RedstoneSimulatorChunkData = (( cIncrementalRedstoneSimulator < ChunkType , WorldType , GetHandlerCompileTime , ChestType >:: cIncrementalRedstoneSimulatorChunkData * ) a_Chunk -> GetRedstoneSimulatorData ()) -> m_ChunkData ;
for ( cCoordWithBlockAndBoolVector :: iterator itr = RedstoneSimulatorChunkData . begin (); itr != RedstoneSimulatorChunkData . end (); ++ itr )
2014-09-11 12:48:21 -04:00
{
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 ;
}
2014-09-16 15:29:31 -04:00
cCoordWithBlockAndBoolVector & QueuedData = (( cIncrementalRedstoneSimulator < ChunkType , WorldType , GetHandlerCompileTime , ChestType >:: cIncrementalRedstoneSimulatorChunkData * ) a_Chunk -> GetRedstoneSimulatorData ()) -> m_QueuedChunkData ;
for ( cCoordWithBlockAndBoolVector :: iterator itr = QueuedData . begin (); itr != QueuedData . end (); ++ itr )
2014-09-11 12:48:21 -04:00
{
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 ;
}
}
2014-09-16 15:29:31 -04:00
QueuedData . push_back ( cCoordWithBlockAndBool ( RelX , a_BlockY , RelZ , Block , false ));
2014-09-11 12:48:21 -04:00
}
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 )
{
2014-09-16 15:29:31 -04:00
m_RedstoneSimulatorChunkData = ( cIncrementalRedstoneSimulator < ChunkType , WorldType , GetHandlerCompileTime , ChestType >:: cIncrementalRedstoneSimulatorChunkData * ) a_Chunk -> GetRedstoneSimulatorData ();
2014-09-27 09:49:03 -04:00
if ( m_RedstoneSimulatorChunkData == NULL )
{
m_RedstoneSimulatorChunkData = new cIncrementalRedstoneSimulator < ChunkType , WorldType , GetHandlerCompileTime , ChestType >:: cIncrementalRedstoneSimulatorChunkData ();
2014-09-27 10:19:32 -04:00
a_Chunk -> SetRedstoneSimulatorData ( m_RedstoneSimulatorChunkData );
2014-09-27 09:49:03 -04:00
}
2014-09-16 15:29:31 -04:00
if ( m_RedstoneSimulatorChunkData -> m_ChunkData . empty () && (( cIncrementalRedstoneSimulator < ChunkType , WorldType , GetHandlerCompileTime , ChestType >:: cIncrementalRedstoneSimulatorChunkData * ) a_Chunk -> GetRedstoneSimulatorData ()) -> m_QueuedChunkData . empty ())
2014-09-11 12:48:21 -04:00
{
return ;
}
2014-09-16 15:29:31 -04:00
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 ();
2014-09-11 12:48:21 -04:00
2014-09-16 15:29:31 -04:00
m_PoweredBlocks = & m_RedstoneSimulatorChunkData -> m_PoweredBlocks ;
m_RepeatersDelayList = & m_RedstoneSimulatorChunkData -> m_RepeatersDelayList ;
m_SimulatedPlayerToggleableBlocks = & m_RedstoneSimulatorChunkData -> m_SimulatedPlayerToggleableBlocks ;
m_LinkedPoweredBlocks = & m_RedstoneSimulatorChunkData -> m_LinkedBlocks ;
2014-09-11 12:48:21 -04:00
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 ();
2014-09-16 15:29:31 -04:00
for ( cCoordWithBlockAndBoolVector :: iterator dataitr = m_RedstoneSimulatorChunkData -> m_ChunkData . begin (); dataitr != m_RedstoneSimulatorChunkData -> m_ChunkData . end ();)
2014-09-11 12:48:21 -04:00
{
if ( dataitr -> DataTwo )
{
2014-09-16 15:29:31 -04:00
dataitr = m_RedstoneSimulatorChunkData -> m_ChunkData . erase ( dataitr );
2014-09-11 12:48:21 -04:00
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 ;
2014-09-26 13:44:06 -04:00
case E_BLOCK_IRON_TRAPDOOR : HandleTrapdoor ( dataitr -> x , dataitr -> y , dataitr -> z ); break ;
2014-09-11 12:48:21 -04:00
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 ;
}
2014-09-26 13:44:06 -04:00
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 :
2014-09-11 12:48:21 -04:00
case E_BLOCK_WOODEN_DOOR :
case E_BLOCK_IRON_DOOR :
{
HandleDoor ( dataitr -> x , dataitr -> y , dataitr -> z );
break ;
2014-09-26 13:44:06 -04:00
}
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 ;
2014-09-11 12:48:21 -04:00
}
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.5 f , 0.6 f );
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.5 f , ( float ) a_RelBlockY , BlockZ + 0.5 f ), 0.5 f , 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.5 f , ( float ) m_Y , m_Z + 0.5 f );
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.3 F , 0.5 F );
}
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.3 F , 0.6 F );
}
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.5 f , ( float ) m_Y , m_Z + 0.5 f );
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.3 F , 0.5 F );
}
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.3 F , 0.6 F );
}
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.5 f , ( float ) m_Y , m_Z + 0.5 f );
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.3 F , 0.5 F );
}
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.3 F , 0.6 F );
}
m_Chunk -> SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , E_META_PRESSURE_PLATE_RAISED );
SetSourceUnpowered ( BlockX , a_RelBlockY , BlockZ , m_Chunk );
}
break ;
}
default :
{
2014-09-17 13:40:10 -04:00
LOGD ( " Unimplemented pressure plate type %s in cRedstoneSimulator " , ItemToFullString ( cItem ( a_MyType )) . c_str ());
2014-09-11 12:48:21 -04:00
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 );
}
}
2014-09-17 13:40:10 -04:00
template < class ChestType >
class cGetTrappedChestPlayers :
public cItemCallback < ChestType >
{
public :
cGetTrappedChestPlayers ( void ) :
m_NumberOfPlayers ( 0 )
{
}
2014-09-11 12:48:21 -04:00
2014-09-17 13:40:10 -04:00
virtual ~ cGetTrappedChestPlayers ()
{
}
2014-09-11 12:48:21 -04:00
2014-09-17 13:40:10 -04:00
virtual bool Item ( ChestType * a_Chest ) override
{
ASSERT ( a_Chest -> GetBlockType () == E_BLOCK_TRAPPED_CHEST );
m_NumberOfPlayers = a_Chest -> GetNumberOfPlayers ();
return ( m_NumberOfPlayers <= 0 );
}
2014-09-11 12:48:21 -04:00
2014-09-17 13:40:10 -04:00
unsigned char GetPowerLevel ( void ) const
2014-09-11 12:48:21 -04:00
{
2014-09-17 13:40:10 -04:00
return std :: min ( m_NumberOfPlayers , MAX_POWER_LEVEL );
}
2014-09-11 12:48:21 -04:00
2014-09-17 13:40:10 -04:00
private :
int m_NumberOfPlayers ;
2014-09-11 12:48:21 -04:00
2014-09-17 13:40:10 -04:00
};
2014-09-11 12:48:21 -04:00
2014-09-17 13:40:10 -04:00
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 ;
2014-09-11 12:48:21 -04:00
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 ;
2014-09-16 15:29:31 -04:00
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
2014-09-11 12:48:21 -04:00
{
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 ;
2014-09-25 12:58:12 -04:00
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?
2014-09-11 12:48:21 -04:00
{
2014-09-25 12:58:12 -04:00
if (( OtherRepeaterDir & 0x03 ) == 0x3 )
{
return true ;
} // If so, I am latched/locked
2014-09-11 12:48:21 -04:00
}
// Check if western(left) neighbor is a powered on repeater who is facing us
2014-09-25 12:58:12 -04:00
if ( m_Chunk -> UnboundedRelGetBlock ( a_RelBlockX - 1 , a_RelBlockY , a_RelBlockZ , Block , OtherRepeaterDir ) && ( Block == E_BLOCK_REDSTONE_REPEATER_ON ))
2014-09-11 12:48:21 -04:00
{
NIBBLETYPE OtherRepeaterDir = m_Chunk -> GetMeta ( a_RelBlockX - 1 , a_RelBlockY , a_RelBlockZ ) & 0x3 ;
2014-09-25 12:58:12 -04:00
if (( OtherRepeaterDir & 0x03 ) == 0x1 )
{
return true ;
} // If so, I am latched/locked
2014-09-11 12:48:21 -04:00
}
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 ;
2014-09-25 12:58:12 -04:00
NIBBLETYPE OtherRepeaterDir = 0 ;
if ( m_Chunk -> UnboundedRelGetBlock ( a_RelBlockX , a_RelBlockY , a_RelBlockZ + 1 , Block , OtherRepeaterDir ) && ( Block == E_BLOCK_REDSTONE_REPEATER_ON ))
2014-09-11 12:48:21 -04:00
{
2014-09-25 12:58:12 -04:00
if (( OtherRepeaterDir & 0x30 ) == 0x00 )
{
return true ;
} // If so, am latched/locked
2014-09-11 12:48:21 -04:00
}
// Check if northern(up) neighbor is a powered on repeater who is facing us
2014-09-25 12:58:12 -04:00
if ( m_Chunk -> UnboundedRelGetBlock ( a_RelBlockX , a_RelBlockY , a_RelBlockZ - 1 , Block , OtherRepeaterDir ) && ( Block == E_BLOCK_REDSTONE_REPEATER_ON ))
2014-09-11 12:48:21 -04:00
{
2014-09-25 12:58:12 -04:00
if (( OtherRepeaterDir & 0x03 ) == 0x02 )
{
return true ;
} // If so, I am latched/locked
2014-09-11 12:48:21 -04:00
}
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 ;
}
2014-09-16 15:29:31 -04:00
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 )
2014-09-11 12:48:21 -04:00
{
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 ;
2014-09-16 15:29:31 -04:00
Powered . push_back ( RC );
2014-09-11 12:48:21 -04:00
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 ;
}
2014-09-16 15:29:31 -04:00
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
2014-09-11 12:48:21 -04:00
{
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 ;
2014-09-16 15:29:31 -04:00
Linked . push_back ( RC );
2014-09-11 12:48:21 -04:00
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
2014-09-16 15:29:31 -04:00
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 ();)
2014-09-11 12:48:21 -04:00
{
if ( itr -> a_SourcePos . Equals ( Vector3i ( a_SourceX , a_SourceY , a_SourceZ )))
{
2014-09-16 15:29:31 -04:00
itr = (( cIncrementalRedstoneSimulator < ChunkType , WorldType , GetHandlerCompileTime , ChestType >:: cIncrementalRedstoneSimulatorChunkData * ) a_Chunk -> GetRedstoneSimulatorData ()) -> m_PoweredBlocks . erase ( itr );
2014-09-11 12:48:21 -04:00
a_Chunk -> SetIsRedstoneDirty ( true );
continue ;
}
++ itr ;
}
2014-09-16 15:29:31 -04:00
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 ();)
2014-09-11 12:48:21 -04:00
{
if ( itr -> a_SourcePos . Equals ( Vector3i ( a_SourceX , a_SourceY , a_SourceZ )))
{
2014-09-16 15:29:31 -04:00
itr = (( cIncrementalRedstoneSimulator < ChunkType , WorldType , GetHandlerCompileTime , ChestType >:: cIncrementalRedstoneSimulatorChunkData * ) a_Chunk -> GetRedstoneSimulatorData ()) -> m_LinkedBlocks . erase ( itr );
2014-09-11 12:48:21 -04:00
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 );
}