2014-04-08 13:49:53 -04:00
2014-09-11 12:48:21 -04:00
# include "Globals.h"
2014-02-07 16:59:08 -05:00
2014-09-17 13:40:10 -04:00
# include "BlockEntities/ChestEntity.h"
2014-09-11 12:48:21 -04:00
# include "Chunk.h"
# include "World.h"
# include "Blocks/GetHandlerCompileTimeTemplate.h"
2015-02-08 11:35:10 -05:00
# include "Blocks/BlockComparator.h"
2014-09-11 12:48:21 -04:00
# include "Blocks/BlockTorch.h"
# include "Blocks/BlockLever.h"
# include "Blocks/BlockButton.h"
# include "Blocks/BlockTripwireHook.h"
# include "Blocks/BlockDoor.h"
# include "Blocks/BlockPiston.h"
2014-10-25 16:54:00 -04:00
# include "IncrementalRedstoneSimulator.h"
# include "BoundingBox.h"
# include "Blocks/ChunkInterface.h"
# include "RedstoneSimulator.h"
2015-04-25 19:38:41 -04:00
void cIncrementalRedstoneSimulator : : AddBlock ( int a_BlockX , int a_BlockY , int a_BlockZ , cChunk * a_Chunk )
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
AddBlock ( cChunkDef : : AbsoluteToRelative ( { a_BlockX , a_BlockY , a_BlockZ } , a_Chunk - > GetPosX ( ) , a_Chunk - > GetPosZ ( ) ) , a_Chunk , nullptr ) ;
}
void cIncrementalRedstoneSimulator : : AddBlock ( const Vector3i & a_RelBlockPosition , cChunk * a_OriginalChunk , cChunk * a_NeighborChunk )
{
if ( ( a_OriginalChunk = = nullptr ) | | ! a_OriginalChunk - > IsValid ( ) )
2014-10-25 16:54:00 -04:00
{
return ;
}
2015-04-25 19:38:41 -04:00
else if ( ( a_RelBlockPosition . y < 0 ) | | ( a_RelBlockPosition . y > = cChunkDef : : Height ) )
2014-10-25 16:54:00 -04:00
{
return ;
}
2015-04-25 19:38:41 -04:00
// The relative block position is relative to the neighboring chunk should it be passed as an argument
2014-10-25 16:54:00 -04:00
BLOCKTYPE Block ;
NIBBLETYPE Meta ;
2015-04-25 19:38:41 -04:00
if ( a_NeighborChunk ! = nullptr )
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
a_NeighborChunk - > UnboundedRelGetBlock ( a_RelBlockPosition . x , a_RelBlockPosition . y , a_RelBlockPosition . z , Block , Meta ) ;
2014-10-25 16:54:00 -04:00
2015-04-25 19:38:41 -04:00
// If a_OtherChunk is passed (not nullptr), it is the neighbouring chunk of a_Chunk, which itself is the chunk with the block change
2014-10-25 16:54:00 -04:00
// Because said neighbouring chunk does not know of this change but still needs to update its redstone, we set it to dirty
2015-04-25 19:38:41 -04:00
a_NeighborChunk - > SetIsRedstoneDirty ( true ) ;
2014-10-25 16:54:00 -04:00
}
else
{
2015-04-25 19:38:41 -04:00
a_OriginalChunk - > GetBlockTypeMeta ( a_RelBlockPosition . x , a_RelBlockPosition . y , a_RelBlockPosition . z , Block , Meta ) ;
2014-10-25 16:54:00 -04:00
}
// 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-10-29 12:02:59 -04:00
if (
! IsPotentialSource ( Block ) | |
(
2014-10-25 16:54:00 -04:00
// 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 ) )
2014-10-29 12:02:59 -04:00
)
)
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
SetSourceUnpowered ( a_RelBlockPosition . x , a_RelBlockPosition . y , a_RelBlockPosition . z , a_NeighborChunk ! = nullptr ? a_NeighborChunk : a_OriginalChunk ) ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
if ( ! IsViableMiddleBlock ( Block ) )
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
SetInvalidMiddleBlock ( a_RelBlockPosition . x , a_RelBlockPosition . y , a_RelBlockPosition . z , a_NeighborChunk ! = nullptr ? a_NeighborChunk : a_OriginalChunk ) ;
2014-10-25 16:54:00 -04:00
}
2015-04-25 19:38:41 -04:00
if ( a_NeighborChunk ! = nullptr )
{
// DO NOT touch our chunk's data structure if we are being called with coordinates from another chunk - this one caused me massive grief :P
return ;
}
auto & SimulatedPlayerToggleableBlocks = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( a_OriginalChunk - > GetRedstoneSimulatorData ( ) ) - > m_SimulatedPlayerToggleableBlocks ;
2015-06-02 08:29:52 -04:00
if ( DoesIgnorePlayerToggle ( Block ) )
2015-04-25 19:38:41 -04:00
{
// Initialise the toggleable blocks list so that trapdoors etc. aren't reset on restart (#1887)
2015-06-02 08:29:52 -04:00
SimulatedPlayerToggleableBlocks . emplace (
a_RelBlockPosition ,
AreCoordsDirectlyPowered ( a_RelBlockPosition . x , a_RelBlockPosition . y , a_RelBlockPosition . z , a_OriginalChunk ) | | AreCoordsLinkedPowered ( a_RelBlockPosition . x , a_RelBlockPosition . y , a_RelBlockPosition . z , a_OriginalChunk )
) ; // This map won't insert if key already present, so no need to check
}
else
{
SimulatedPlayerToggleableBlocks . erase ( a_RelBlockPosition ) ;
2015-04-25 19:38:41 -04:00
}
2015-06-02 08:29:52 -04:00
if ( ( Block ! = E_BLOCK_REDSTONE_REPEATER_ON ) & & ( Block ! = E_BLOCK_REDSTONE_REPEATER_OFF ) )
2014-10-25 16:54:00 -04:00
{
2015-06-02 08:29:52 -04:00
static_cast < cIncrementalRedstoneSimulatorChunkData * > ( a_OriginalChunk - > GetRedstoneSimulatorData ( ) ) - > m_RepeatersDelayList . erase ( a_RelBlockPosition ) ;
2014-10-25 16:54:00 -04:00
}
2015-06-02 08:29:52 -04:00
auto & RedstoneSimulatorChunkData = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( a_OriginalChunk - > GetRedstoneSimulatorData ( ) ) - > m_ChunkData ;
auto Iterator = RedstoneSimulatorChunkData . find ( a_RelBlockPosition ) ;
2014-10-25 16:54:00 -04:00
if ( ! IsAllowedBlock ( Block ) )
{
2015-06-02 08:29:52 -04:00
if ( Iterator ! = RedstoneSimulatorChunkData . end ( ) )
{
Iterator - > second . second = true ; // The new blocktype is not redstone; it must be queued to be removed from this list
}
2014-10-25 16:54:00 -04:00
return ;
}
2015-06-02 08:29:52 -04:00
else
2014-10-25 16:54:00 -04:00
{
2015-06-02 08:29:52 -04:00
if ( Iterator ! = RedstoneSimulatorChunkData . end ( ) )
2014-10-25 16:54:00 -04:00
{
2015-06-02 08:29:52 -04:00
Iterator - > second . second = false ;
Iterator - > second . first = Block ; // Update block information
2014-10-25 16:54:00 -04:00
return ;
}
}
2015-06-02 08:29:52 -04:00
RedstoneSimulatorChunkData . emplace ( a_RelBlockPosition , std : : make_pair ( Block , false ) ) ;
2014-10-25 16:54:00 -04:00
}
2015-01-11 16:12:26 -05:00
void cIncrementalRedstoneSimulator : : SimulateChunk ( std : : chrono : : milliseconds a_Dt , int a_ChunkX , int a_ChunkZ , cChunk * a_Chunk )
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
m_RedstoneSimulatorChunkData = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( a_Chunk - > GetRedstoneSimulatorData ( ) ) ;
2014-12-16 18:18:59 -05:00
if ( m_RedstoneSimulatorChunkData = = nullptr )
2014-10-25 16:54:00 -04:00
{
m_RedstoneSimulatorChunkData = new cIncrementalRedstoneSimulator : : cIncrementalRedstoneSimulatorChunkData ( ) ;
a_Chunk - > SetRedstoneSimulatorData ( m_RedstoneSimulatorChunkData ) ;
}
2015-06-02 08:29:52 -04:00
if ( m_RedstoneSimulatorChunkData - > m_ChunkData . empty ( ) )
2014-10-25 16:54:00 -04:00
{
return ;
}
m_PoweredBlocks = & m_RedstoneSimulatorChunkData - > m_PoweredBlocks ;
m_RepeatersDelayList = & m_RedstoneSimulatorChunkData - > m_RepeatersDelayList ;
m_SimulatedPlayerToggleableBlocks = & m_RedstoneSimulatorChunkData - > m_SimulatedPlayerToggleableBlocks ;
m_LinkedPoweredBlocks = & m_RedstoneSimulatorChunkData - > m_LinkedBlocks ;
m_Chunk = a_Chunk ;
bool ShouldUpdateSimulateOnceBlocks = false ;
if ( a_Chunk - > IsRedstoneDirty ( ) )
{
// Simulate the majority of devices only if something (blockwise or power-wise) has changed
// Make sure to allow the chunk to resimulate after the initial run if there was a power change (ShouldUpdateSimulateOnceBlocks helps to do this)
a_Chunk - > SetIsRedstoneDirty ( false ) ;
ShouldUpdateSimulateOnceBlocks = true ;
}
HandleRedstoneRepeaterDelays ( ) ;
2014-10-29 12:02:59 -04:00
for ( auto dataitr = m_RedstoneSimulatorChunkData - > m_ChunkData . begin ( ) ; dataitr ! = m_RedstoneSimulatorChunkData - > m_ChunkData . end ( ) ; )
2014-10-25 16:54:00 -04:00
{
2015-06-02 08:29:52 -04:00
if ( dataitr - > second . second )
2014-10-25 16:54:00 -04:00
{
dataitr = m_RedstoneSimulatorChunkData - > m_ChunkData . erase ( dataitr ) ;
continue ;
}
2015-06-02 08:29:52 -04:00
switch ( dataitr - > second . first )
2014-10-25 16:54:00 -04:00
{
2015-06-02 08:29:52 -04:00
case E_BLOCK_DAYLIGHT_SENSOR : HandleDaylightSensor ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
case E_BLOCK_TRIPWIRE : HandleTripwire ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
case E_BLOCK_TRIPWIRE_HOOK : HandleTripwireHook ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
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 :
{
2015-06-02 08:29:52 -04:00
HandlePressurePlate ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z , dataitr - > second . first ) ;
2014-10-29 12:02:59 -04:00
break ;
}
default : break ;
2014-10-25 16:54:00 -04:00
}
if ( ShouldUpdateSimulateOnceBlocks )
{
2015-06-02 08:29:52 -04:00
switch ( dataitr - > second . first )
2014-10-25 16:54:00 -04:00
{
2015-06-02 08:29:52 -04:00
case E_BLOCK_REDSTONE_WIRE : HandleRedstoneWire ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
case E_BLOCK_COMMAND_BLOCK : HandleCommandBlock ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
case E_BLOCK_NOTE_BLOCK : HandleNoteBlock ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
case E_BLOCK_BLOCK_OF_REDSTONE : HandleRedstoneBlock ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
case E_BLOCK_LEVER : HandleRedstoneLever ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
case E_BLOCK_TNT : HandleTNT ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
case E_BLOCK_IRON_TRAPDOOR : HandleTrapdoor ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
case E_BLOCK_TRAPDOOR : HandleTrapdoor ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
case E_BLOCK_TRAPPED_CHEST : HandleTrappedChest ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ; break ;
2014-10-29 12:02:59 -04:00
case E_BLOCK_ACTIVATOR_RAIL :
case E_BLOCK_DETECTOR_RAIL :
case E_BLOCK_POWERED_RAIL :
{
2015-06-02 08:29:52 -04:00
HandleRail ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z , dataitr - > second . first ) ;
2014-10-29 12:02:59 -04:00
break ;
}
case E_BLOCK_ACACIA_DOOR :
case E_BLOCK_BIRCH_DOOR :
case E_BLOCK_DARK_OAK_DOOR :
case E_BLOCK_JUNGLE_DOOR :
case E_BLOCK_SPRUCE_DOOR :
case E_BLOCK_WOODEN_DOOR :
case E_BLOCK_IRON_DOOR :
{
2015-06-02 08:29:52 -04:00
HandleDoor ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ;
2014-10-29 12:02:59 -04:00
break ;
}
case E_BLOCK_ACACIA_FENCE_GATE :
case E_BLOCK_BIRCH_FENCE_GATE :
case E_BLOCK_DARK_OAK_FENCE_GATE :
case E_BLOCK_FENCE_GATE :
case E_BLOCK_JUNGLE_FENCE_GATE :
case E_BLOCK_SPRUCE_FENCE_GATE :
{
2015-06-02 08:29:52 -04:00
HandleFenceGate ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ;
2014-10-29 12:02:59 -04:00
break ;
}
case E_BLOCK_REDSTONE_LAMP_OFF :
case E_BLOCK_REDSTONE_LAMP_ON :
{
2015-06-02 08:29:52 -04:00
HandleRedstoneLamp ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z , dataitr - > second . first ) ;
2014-10-29 12:02:59 -04:00
break ;
}
case E_BLOCK_DISPENSER :
case E_BLOCK_DROPPER :
{
2015-06-02 08:29:52 -04:00
HandleDropSpenser ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ;
2014-10-29 12:02:59 -04:00
break ;
}
case E_BLOCK_PISTON :
case E_BLOCK_STICKY_PISTON :
{
2015-06-02 08:29:52 -04:00
HandlePiston ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ;
2014-10-29 12:02:59 -04:00
break ;
}
case E_BLOCK_REDSTONE_REPEATER_OFF :
case E_BLOCK_REDSTONE_REPEATER_ON :
{
2015-06-02 08:29:52 -04:00
HandleRedstoneRepeater ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z , dataitr - > second . first ) ;
2014-10-29 12:02:59 -04:00
break ;
}
case E_BLOCK_REDSTONE_TORCH_OFF :
case E_BLOCK_REDSTONE_TORCH_ON :
{
2015-06-02 08:29:52 -04:00
HandleRedstoneTorch ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z , dataitr - > second . first ) ;
2014-10-29 12:02:59 -04:00
break ;
}
case E_BLOCK_STONE_BUTTON :
case E_BLOCK_WOODEN_BUTTON :
{
2015-06-02 08:29:52 -04:00
HandleRedstoneButton ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ;
2014-10-29 12:02:59 -04:00
break ;
}
2015-02-08 11:35:10 -05:00
case E_BLOCK_ACTIVE_COMPARATOR :
case E_BLOCK_INACTIVE_COMPARATOR :
{
2015-06-02 08:29:52 -04:00
HandleRedstoneComparator ( dataitr - > first . x , dataitr - > first . y , dataitr - > first . z ) ;
2015-02-08 11:35:10 -05:00
break ;
}
2014-10-29 12:02:59 -04:00
default : break ;
2014-10-25 16:54:00 -04:00
}
}
+ + dataitr ;
}
}
void cIncrementalRedstoneSimulator : : WakeUp ( int a_BlockX , int a_BlockY , int a_BlockZ , cChunk * a_Chunk )
{
2015-04-25 19:38:41 -04:00
auto CurrentChunkRelative = cChunkDef : : AbsoluteToRelative ( { a_BlockX , a_BlockY , a_BlockZ } , a_Chunk - > GetPosX ( ) , a_Chunk - > GetPosZ ( ) ) ;
AddBlock ( CurrentChunkRelative , a_Chunk ) ; // Alert the current chunk which the block is present in
2014-10-25 16:54:00 -04:00
2015-04-25 19:38:41 -04:00
for ( const auto & BoundaryChunk : GetAdjacentChunks ( CurrentChunkRelative , a_Chunk ) )
{
// On a chunk boundary, alert all neighbouring chunks which may have a connection with this block
AddBlock ( cChunkDef : : AbsoluteToRelative ( { a_BlockX , a_BlockY , a_BlockZ } , BoundaryChunk - > GetPosX ( ) , BoundaryChunk - > GetPosZ ( ) ) , a_Chunk , BoundaryChunk ) ;
2014-10-25 16:54:00 -04:00
}
}
void cIncrementalRedstoneSimulator : : HandleRedstoneTorch ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , BLOCKTYPE a_MyState )
{
static const struct / / Define which directions the torch can power
{
int x , y , z ;
} gCrossCoords [ ] =
{
{ 1 , 0 , 0 } ,
{ - 1 , 0 , 0 } ,
{ 0 , 0 , 1 } ,
{ 0 , 0 , - 1 } ,
{ 0 , 1 , 0 } ,
} ;
if ( a_MyState = = E_BLOCK_REDSTONE_TORCH_ON )
{
// Check if the block the torch is on is powered
int X = a_RelBlockX ; int Y = a_RelBlockY ; int Z = a_RelBlockZ ;
AddFaceDirection ( X , Y , Z , GetHandlerCompileTime < E_BLOCK_TORCH > : : type : : MetaDataToDirection ( m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) , true ) ; // Inverse true to get the block torch is on
2014-10-29 12:02:59 -04:00
cChunk * Neighbour = m_Chunk - > GetRelNeighborChunkAdjustCoords ( X , Z ) ;
2014-12-16 18:18:59 -05:00
if ( ( Neighbour = = nullptr ) | | ! Neighbour - > IsValid ( ) )
2014-10-25 16:54:00 -04:00
{
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 (
2015-05-09 03:25:09 -04:00
IsMechanism ( Type ) & & // Is it a mechanism? Not block / other torch etc.
2014-10-25 16:54:00 -04:00
( ! 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
2014-10-29 12:02:59 -04:00
cChunk * Neighbour = m_Chunk - > GetRelNeighborChunkAdjustCoords ( X , Z ) ;
2014-12-16 18:18:59 -05:00
if ( ( Neighbour = = nullptr ) | | ! Neighbour - > IsValid ( ) )
2014-10-25 16:54:00 -04:00
{
return ;
}
// See if off state torch can be turned on again
if ( AreCoordsDirectlyPowered ( X , Y , Z , Neighbour ) )
{
return ; // Something matches, torch still powered
}
// Block torch on not powered, can be turned on again!
m_Chunk - > SetBlock ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , E_BLOCK_REDSTONE_TORCH_ON , m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) ;
}
}
void cIncrementalRedstoneSimulator : : HandleRedstoneBlock ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
SetAllDirsAsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
SetBlockPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ; // Set self as powered
}
void cIncrementalRedstoneSimulator : : HandleRedstoneLever ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
NIBBLETYPE Meta = m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
if ( IsLeverOn ( Meta ) )
{
SetAllDirsAsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
eBlockFace Dir = GetHandlerCompileTime < E_BLOCK_LEVER > : : type : : BlockMetaDataToBlockFace ( Meta ) ;
Dir = ReverseBlockFace ( Dir ) ;
SetDirectionLinkedPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Dir ) ;
}
}
void cIncrementalRedstoneSimulator : : HandleFenceGate ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
int BlockX = ( m_Chunk - > GetPosX ( ) * cChunkDef : : Width ) + a_RelBlockX ;
int BlockZ = ( m_Chunk - > GetPosZ ( ) * cChunkDef : : Width ) + a_RelBlockZ ;
NIBBLETYPE MetaData = m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
if ( AreCoordsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) )
{
if ( ! AreCoordsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , true ) )
{
if ( ( MetaData & 0x4 ) = = 0 )
{
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , MetaData | 0x4 ) ;
m_Chunk - > BroadcastSoundParticleEffect ( 1003 , BlockX , a_RelBlockY , BlockZ , 0 ) ;
}
SetPlayerToggleableBlockAsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , true ) ;
}
}
else
{
if ( ! AreCoordsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , false ) )
{
if ( ( MetaData & 0x4 ) ! = 0 )
{
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , MetaData & ~ 0x04 ) ;
m_Chunk - > BroadcastSoundParticleEffect ( 1003 , BlockX , a_RelBlockY , BlockZ , 0 ) ;
}
SetPlayerToggleableBlockAsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , false ) ;
}
}
}
void cIncrementalRedstoneSimulator : : HandleRedstoneButton ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
NIBBLETYPE Meta = m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
if ( IsButtonOn ( Meta ) )
{
SetAllDirsAsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
eBlockFace Dir = GetHandlerCompileTime < E_BLOCK_STONE_BUTTON > : : type : : BlockMetaDataToBlockFace ( Meta ) ;
Dir = ReverseBlockFace ( Dir ) ;
SetDirectionLinkedPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Dir ) ;
}
}
void cIncrementalRedstoneSimulator : : HandleRedstoneWire ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
2015-04-25 19:38:41 -04:00
static const eBlockFace BlockFaceOffsets [ ] =
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
BLOCK_FACE_XM ,
BLOCK_FACE_XP ,
BLOCK_FACE_ZM ,
BLOCK_FACE_ZP
2014-10-25 16:54:00 -04:00
} ;
2015-04-25 19:38:41 -04:00
static const Vector3i VectorOffsets [ ] =
2014-10-25 16:54:00 -04:00
{
{ - 1 , 0 , 0 } ,
2015-04-25 19:38:41 -04:00
{ 1 , 0 , 0 } ,
2014-10-25 16:54:00 -04:00
{ 0 , 0 , - 1 } ,
2015-04-25 19:38:41 -04:00
{ 0 , 0 , 1 }
2014-10-25 16:54:00 -04:00
} ;
2015-04-25 19:38:41 -04:00
auto RelBlock = Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
2014-10-25 16:54:00 -04:00
// Check to see if directly beside a power source
2015-04-25 19:38:41 -04:00
unsigned char MyPower = IsWirePowered ( RelBlock , m_Chunk ) ;
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , MyPower ) ;
2015-02-08 11:35:10 -05:00
if ( MyPower = = 0 )
2014-10-25 16:54:00 -04:00
{
2015-02-08 11:35:10 -05:00
SetSourceUnpowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk ) ;
2014-10-25 16:54:00 -04:00
return ;
}
2015-04-25 19:38:41 -04:00
if ( MyPower = = MAX_POWER_LEVEL )
{
std : : vector < std : : pair < Vector3i , cChunk * > > PotentialWireList = { std : : make_pair ( RelBlock , m_Chunk ) } ;
while ( ! PotentialWireList . empty ( ) )
{
auto Current = PotentialWireList . back ( ) ;
PotentialWireList . pop_back ( ) ;
FindAndPowerBorderingWires ( PotentialWireList , Current ) ;
2015-05-01 17:55:43 -04:00
}
2015-04-25 19:38:41 -04:00
}
else if ( MyPower = = 1 )
{
return ;
}
2014-10-25 16:54:00 -04:00
2015-05-01 17:55:43 -04:00
// Wire still powered, power blocks beneath and in direction of facing
2014-10-25 16:54:00 -04:00
MyPower - - ;
2015-04-25 19:38:41 -04:00
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 ) ;
int BorderingMechanismCount = 0 ;
bool RepeaterPresent = false ;
2015-05-01 17:55:43 -04:00
Vector3i OffsetToPower ;
2015-04-25 19:38:41 -04:00
2015-05-01 17:55:43 -04:00
for ( const auto & Offset : VectorOffsets )
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
BLOCKTYPE Block ;
2015-05-01 17:55:43 -04:00
Vector3i AdjustedOffset = RelBlock + Offset ;
if ( m_Chunk - > UnboundedRelGetBlockType ( AdjustedOffset . x , AdjustedOffset . y , AdjustedOffset . z , Block ) )
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
switch ( Block )
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
case E_BLOCK_REDSTONE_REPEATER_OFF :
{
BorderingMechanismCount + + ;
if ( ! RepeaterPresent )
{
// TODO: only if wire is actually connected to repeater (repeater facing right way)
RepeaterPresent = true ;
2015-05-01 17:55:43 -04:00
OffsetToPower = { - Offset . x , Offset . y , - Offset . z } ; // Negate to obtain offset in opposite direction since wire powers that way
2015-04-25 19:38:41 -04:00
}
2015-05-01 17:55:43 -04:00
SetBlockPowered ( AdjustedOffset , RelBlock , MyPower ) ;
2015-04-25 19:38:41 -04:00
}
case E_BLOCK_REDSTONE_TORCH_ON :
case E_BLOCK_REDSTONE_WIRE :
{
BorderingMechanismCount + + ;
if ( ! RepeaterPresent )
{
2015-05-01 17:55:43 -04:00
OffsetToPower = { - Offset . x , Offset . y , - Offset . z } ;
2015-04-25 19:38:41 -04:00
}
}
default : break ;
2014-10-25 16:54:00 -04:00
}
}
}
2015-04-25 19:38:41 -04:00
if ( BorderingMechanismCount = = 0 )
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
SetAllDirsAsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
2015-05-01 17:55:43 -04:00
for ( const auto & BlockFaceOffset : BlockFaceOffsets )
{
SetDirectionLinkedPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , BlockFaceOffset , MyPower ) ;
}
2014-10-25 16:54:00 -04:00
}
2015-04-25 19:38:41 -04:00
else if ( BorderingMechanismCount = = 1 )
{
2015-05-01 17:55:43 -04:00
eBlockFace Face = BlockFaceOffsets [ std : : distance ( VectorOffsets , std : : find ( VectorOffsets , VectorOffsets + ARRAYCOUNT ( VectorOffsets ) , OffsetToPower ) ) ] ;
SetBlockPowered ( RelBlock + OffsetToPower , RelBlock , MyPower ) ;
2015-04-25 19:38:41 -04:00
SetDirectionLinkedPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Face , MyPower ) ;
}
}
2014-10-25 16:54:00 -04:00
2015-04-25 19:38:41 -04:00
void cIncrementalRedstoneSimulator : : FindAndPowerBorderingWires ( std : : vector < std : : pair < Vector3i , cChunk * > > & a_PotentialWireList , const std : : pair < Vector3i , cChunk * > & a_Entry )
{
2015-05-01 17:55:43 -04:00
static const Vector3i LevelOffsets [ ] = // Wires on same level
2014-10-25 16:54:00 -04:00
{
2015-05-01 17:55:43 -04:00
{ 1 , 0 , 0 } ,
2015-04-25 19:38:41 -04:00
{ - 1 , 0 , 0 } ,
{ 0 , 0 , 1 } ,
2015-05-01 17:55:43 -04:00
{ 0 , 0 , - 1 } ,
} ;
static const Vector3i HigherOffsets [ ] = // Wires one higher, surrounding self
{
{ 1 , 1 , 0 } ,
2015-04-25 19:38:41 -04:00
{ - 1 , 1 , 0 } ,
{ 0 , 1 , 1 } ,
2015-05-01 17:55:43 -04:00
{ 0 , 1 , - 1 } ,
} ;
static const Vector3i LowerOffsets [ ] = // Wires one lower, surrounding self
{
{ 1 , - 1 , 0 } ,
2015-04-25 19:38:41 -04:00
{ - 1 , - 1 , 0 } ,
{ 0 , - 1 , 1 } ,
2015-05-01 17:55:43 -04:00
{ 0 , - 1 , - 1 } ,
2015-04-25 19:38:41 -04:00
} ;
2015-05-01 17:55:43 -04:00
for ( auto Offset : LevelOffsets )
2015-04-25 19:38:41 -04:00
{
auto AdjustedPos = a_Entry . first + Offset ;
auto Neighbour = a_Entry . second - > GetRelNeighborChunkAdjustCoords ( AdjustedPos . x , AdjustedPos . z ) ;
auto MyPower = IsWirePowered ( a_Entry . first , a_Entry . second ) ;
2014-10-25 16:54:00 -04:00
2015-05-01 17:55:43 -04:00
if ( ( Neighbour = = nullptr ) | | ! Neighbour - > IsValid ( ) )
{
return ;
}
2015-04-25 20:16:23 -04:00
2015-04-25 19:38:41 -04:00
if ( ( Neighbour - > GetBlock ( AdjustedPos ) = = E_BLOCK_REDSTONE_WIRE ) & & ( MyPower > 1 ) & & ( MyPower > IsWirePowered ( AdjustedPos , Neighbour ) ) )
2014-10-29 12:02:59 -04:00
{
2015-05-01 17:55:43 -04:00
PowerBorderingWires ( a_PotentialWireList , a_Entry , AdjustedPos , Neighbour , MyPower ) ;
}
}
2015-04-25 20:16:23 -04:00
2015-05-01 17:55:43 -04:00
for ( auto Offset : HigherOffsets )
{
auto AdjustedPos = a_Entry . first + Offset ;
auto Neighbour = a_Entry . second - > GetRelNeighborChunkAdjustCoords ( AdjustedPos . x , AdjustedPos . z ) ;
auto MyPower = IsWirePowered ( a_Entry . first , a_Entry . second ) ;
if ( ( Neighbour = = nullptr ) | | ! Neighbour - > IsValid ( ) )
{
return ;
}
if (
( Neighbour - > GetBlock ( AdjustedPos ) = = E_BLOCK_REDSTONE_WIRE ) & &
( ! cBlockInfo : : FullyOccupiesVoxel ( a_Entry . second - > GetBlock ( a_Entry . first . x , a_Entry . first . y + 1 , a_Entry . first . z ) ) ) & &
( MyPower > 1 ) & & ( MyPower > IsWirePowered ( AdjustedPos , Neighbour ) ) )
{
PowerBorderingWires ( a_PotentialWireList , a_Entry , AdjustedPos , Neighbour , MyPower ) ;
}
}
for ( auto Offset : LowerOffsets )
{
auto AdjustedPos = a_Entry . first + Offset ;
auto Neighbour = a_Entry . second - > GetRelNeighborChunkAdjustCoords ( AdjustedPos . x , AdjustedPos . z ) ;
auto MyPower = IsWirePowered ( a_Entry . first , a_Entry . second ) ;
2015-04-25 19:38:41 -04:00
2015-05-01 17:55:43 -04:00
if ( ( Neighbour = = nullptr ) | | ! Neighbour - > IsValid ( ) )
{
return ;
}
if (
( Neighbour - > GetBlock ( AdjustedPos ) = = E_BLOCK_REDSTONE_WIRE ) & &
( ! cBlockInfo : : FullyOccupiesVoxel ( Neighbour - > GetBlock ( AdjustedPos . x , AdjustedPos . y + 1 , AdjustedPos . z ) ) ) & &
( MyPower > 1 ) & & ( MyPower > IsWirePowered ( AdjustedPos , Neighbour ) ) )
{
PowerBorderingWires ( a_PotentialWireList , a_Entry , AdjustedPos , Neighbour , MyPower ) ;
2014-10-29 12:02:59 -04:00
}
2014-10-25 16:54:00 -04:00
}
}
2015-05-01 17:55:43 -04:00
void cIncrementalRedstoneSimulator : : PowerBorderingWires ( std : : vector < std : : pair < Vector3i , cChunk * > > & a_PotentialWireList , const std : : pair < Vector3i , cChunk * > & a_Entry , const Vector3i & a_AdjustedPos , cChunk * a_NeighbourChunk , unsigned char a_MyPower )
{
sPoweredBlocks RC ;
RC . a_BlockPos = a_AdjustedPos ;
RC . a_SourcePos = a_Entry . first + Vector3i ( ( a_Entry . second - > GetPosX ( ) - a_NeighbourChunk - > GetPosX ( ) ) * cChunkDef : : Width , 0 , ( a_Entry . second - > GetPosZ ( ) - a_NeighbourChunk - > GetPosZ ( ) ) * cChunkDef : : Width ) ;
RC . a_PowerLevel = a_MyPower - 1 ;
auto & PoweredBlocks = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( a_NeighbourChunk - > GetRedstoneSimulatorData ( ) ) - > m_PoweredBlocks ; // We need to insert the value into the chunk who owns the block position
2015-05-26 18:30:50 -04:00
auto Position = std : : find_if ( PoweredBlocks . begin ( ) , PoweredBlocks . end ( ) , [ RC ] ( const sPoweredBlocks & itr ) { return ( ( itr . a_BlockPos = = RC . a_BlockPos ) & & ( itr . a_SourcePos = = RC . a_SourcePos ) ) ; } ) ;
2015-05-01 17:55:43 -04:00
if ( Position ! = PoweredBlocks . end ( ) )
{
Position - > a_PowerLevel = RC . a_PowerLevel ;
}
else
{
PoweredBlocks . emplace_back ( RC ) ;
a_NeighbourChunk - > SetIsRedstoneDirty ( true ) ;
m_Chunk - > SetIsRedstoneDirty ( true ) ;
}
a_NeighbourChunk - > SetMeta ( RC . a_BlockPos . x , RC . a_BlockPos . y , RC . a_BlockPos . z , RC . a_PowerLevel ) ;
a_PotentialWireList . emplace_back ( std : : make_pair ( RC . a_BlockPos , a_NeighbourChunk ) ) ;
}
2015-02-08 11:35:10 -05:00
void cIncrementalRedstoneSimulator : : HandleRedstoneComparator ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
auto Meta = m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
2015-04-25 19:38:41 -04:00
auto HighestSidePower = std : : max ( IsWirePowered ( AdjustRelativeCoords ( cBlockComparatorHandler : : GetSideCoordinate ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Meta & 0x3 , false ) ) , m_Chunk ) , IsWirePowered ( AdjustRelativeCoords ( cBlockComparatorHandler : : GetSideCoordinate ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Meta & 0x3 , true ) ) , m_Chunk ) ) ;
2015-02-08 11:35:10 -05:00
auto FrontCoordinate = AdjustRelativeCoords ( cBlockComparatorHandler : : GetFrontCoordinate ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Meta & 0x3 ) ) ;
unsigned char Power = 0 ;
class cContainerCallback : public cBlockEntityCallback
{
public :
cContainerCallback ( ) : m_SignalStrength ( 0 )
{
}
virtual bool Item ( cBlockEntity * a_BlockEntity ) override
{
auto & Contents = static_cast < cBlockEntityWithItems * > ( a_BlockEntity ) - > GetContents ( ) ;
float Fullness = 0 ; // Is a floating-point type to allow later calculation to produce a non-truncated value
for ( int Slot = 0 ; Slot ! = Contents . GetNumSlots ( ) ; + + Slot )
{
Fullness + = Contents . GetSlot ( Slot ) . m_ItemCount / Contents . GetSlot ( Slot ) . GetMaxStackSize ( ) ;
}
m_SignalStrength = static_cast < unsigned char > ( 1 + ( Fullness / Contents . GetNumSlots ( ) ) * 14 ) ;
return false ;
}
unsigned char m_SignalStrength ;
} CCB ;
auto AbsoluteComparatorCoords = cChunkDef : : RelativeToAbsolute ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) , m_Chunk - > GetPosX ( ) , m_Chunk - > GetPosZ ( ) ) ;
auto AbsoluteRearCoords = cBlockComparatorHandler : : GetRearCoordinate ( AbsoluteComparatorCoords . x , AbsoluteComparatorCoords . y , AbsoluteComparatorCoords . z , Meta & 0x3 ) ;
m_Chunk - > DoWithBlockEntityAt ( AbsoluteRearCoords . x , AbsoluteRearCoords . y , AbsoluteRearCoords . z , CCB ) ;
2015-04-25 19:38:41 -04:00
auto RearPower = std : : max ( CCB . m_SignalStrength , IsWirePowered ( AdjustRelativeCoords ( cBlockComparatorHandler : : GetRearCoordinate ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Meta & 0x3 ) ) , m_Chunk ) ) ;
2015-02-08 11:35:10 -05:00
if ( ( Meta & 0x4 ) = = 0x4 )
2015-05-01 17:55:43 -04:00
{ // Subtraction mode
Power = std : : max ( static_cast < unsigned char > ( RearPower - HighestSidePower ) , std : : numeric_limits < unsigned char > : : min ( ) ) ;
2015-02-08 11:35:10 -05:00
}
else
2015-05-01 17:55:43 -04:00
{ // Comparison mode
Power = ( std : : max ( HighestSidePower , RearPower ) = = HighestSidePower ) ? 0 : RearPower ;
2015-02-08 11:35:10 -05:00
}
if ( Power > 0 )
{
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) | 0x8 ) ;
SetBlockPowered ( FrontCoordinate , Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) , Power ) ;
}
else
{
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) & 0x7 ) ;
SetSourceUnpowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk ) ;
}
}
2014-10-25 16:54:00 -04:00
void cIncrementalRedstoneSimulator : : HandleRedstoneRepeater ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , BLOCKTYPE a_MyState )
{
/* Repeater Orientation Mini Guide:
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
| Z Axis
V
X Axis - - - - >
Repeater directions , values from a WorldType : : GetBlockMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) lookup :
East ( Right ) ( X + ) : 0x1
West ( Left ) ( X - ) : 0x3
North ( Up ) ( Z - ) : 0x2
South ( Down ) ( Z + ) : 0x0
// TODO: Add E_META_XXX enum entries for all meta values and update project with them
Sun rises from East ( X + )
*/
// Create a variable holding my meta to avoid multiple lookups.
2015-05-26 18:30:50 -04:00
NIBBLETYPE Meta = m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
2014-10-25 16:54:00 -04:00
bool IsOn = ( a_MyState = = E_BLOCK_REDSTONE_REPEATER_ON ) ;
2015-05-26 18:30:50 -04:00
if ( ! IsRepeaterLocked ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Meta ) ) // If we're locked, change nothing. Otherwise:
2014-10-25 16:54:00 -04:00
{
2015-05-26 18:30:50 -04:00
bool IsSelfPowered = IsRepeaterPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Meta ) ;
2014-10-25 16:54:00 -04:00
if ( IsSelfPowered & & ! IsOn ) // Queue a power change if powered, but not on and not locked.
{
2015-05-26 18:30:50 -04:00
QueueRepeaterPowerChange ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Meta , true ) ;
2014-10-25 16:54:00 -04:00
}
else if ( ! IsSelfPowered & & IsOn ) // Queue a power change if unpowered, on, and not locked.
{
2015-05-26 18:30:50 -04:00
QueueRepeaterPowerChange ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Meta , false ) ;
}
}
if ( IsOn )
{
switch ( Meta & 0x3 ) // We only want the direction (bottom) bits
{
case 0x0 :
{
SetBlockPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ - 1 , a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
SetDirectionLinkedPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , BLOCK_FACE_ZM ) ;
break ;
}
case 0x1 :
{
SetBlockPowered ( a_RelBlockX + 1 , a_RelBlockY , a_RelBlockZ , a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
SetDirectionLinkedPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , BLOCK_FACE_XP ) ;
break ;
}
case 0x2 :
{
SetBlockPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ + 1 , a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
SetDirectionLinkedPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , BLOCK_FACE_ZP ) ;
break ;
}
case 0x3 :
{
SetBlockPowered ( a_RelBlockX - 1 , a_RelBlockY , a_RelBlockZ , a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
SetDirectionLinkedPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , BLOCK_FACE_XM ) ;
break ;
}
2014-10-25 16:54:00 -04:00
}
}
}
void cIncrementalRedstoneSimulator : : HandleRedstoneRepeaterDelays ( )
2014-09-16 15:29:31 -04:00
{
2014-10-29 12:02:59 -04:00
for ( auto itr = m_RepeatersDelayList - > begin ( ) ; itr ! = m_RepeatersDelayList - > end ( ) ; )
2014-10-25 16:54:00 -04:00
{
2015-06-02 08:29:52 -04:00
if ( itr - > second . a_ElapsedTicks > = itr - > second . a_DelayTicks ) // Has the elapsed ticks reached the target ticks?
2014-10-25 16:54:00 -04:00
{
BLOCKTYPE Block ;
NIBBLETYPE Meta ;
2015-06-02 08:29:52 -04:00
m_Chunk - > GetBlockTypeMeta ( itr - > first . x , itr - > first . y , itr - > first . z , Block , Meta ) ;
if ( itr - > second . ShouldPowerOn )
2014-10-25 16:54:00 -04:00
{
if ( Block ! = E_BLOCK_REDSTONE_REPEATER_ON ) // For performance
{
2015-06-02 08:29:52 -04:00
m_Chunk - > SetBlock ( itr - > first , E_BLOCK_REDSTONE_REPEATER_ON , Meta ) ;
2014-10-25 16:54:00 -04:00
}
}
else if ( Block ! = E_BLOCK_REDSTONE_REPEATER_OFF )
{
2015-06-02 08:29:52 -04:00
m_Chunk - > SetBlock ( itr - > first . x , itr - > first . y , itr - > first . z , E_BLOCK_REDSTONE_REPEATER_OFF , Meta ) ;
2014-10-25 16:54:00 -04:00
}
itr = m_RepeatersDelayList - > erase ( itr ) ;
}
else
{
2015-06-02 08:29:52 -04:00
LOGD ( " Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i " , itr - > first . x , itr - > first . y , itr - > first . z , itr - > second . a_ElapsedTicks , itr - > second . a_DelayTicks ) ;
itr - > second . a_ElapsedTicks + + ;
+ + itr ;
2014-10-25 16:54:00 -04:00
}
}
}
void cIncrementalRedstoneSimulator : : HandlePiston ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
int BlockX = ( m_Chunk - > GetPosX ( ) * cChunkDef : : Width ) + a_RelBlockX ;
int BlockZ = ( m_Chunk - > GetPosZ ( ) * cChunkDef : : Width ) + a_RelBlockZ ;
if ( IsPistonPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) & 0x7 ) ) // We only want the bottom three bits (4th controls extended-ness)
{
GetHandlerCompileTime < E_BLOCK_PISTON > : : type : : ExtendPiston ( BlockX , a_RelBlockY , BlockZ , & this - > m_World ) ;
}
else
{
GetHandlerCompileTime < E_BLOCK_PISTON > : : type : : RetractPiston ( BlockX , a_RelBlockY , BlockZ , & this - > m_World ) ;
}
2014-09-16 15:29:31 -04:00
}
2014-10-25 16:54:00 -04:00
void cIncrementalRedstoneSimulator : : HandleDropSpenser ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
class cSetPowerToDropSpenser :
public cRedstonePoweredCallback
{
bool m_IsPowered ;
public :
cSetPowerToDropSpenser ( bool a_IsPowered ) : m_IsPowered ( a_IsPowered ) { }
virtual bool Item ( cRedstonePoweredEntity * a_DropSpenser ) override
{
a_DropSpenser - > SetRedstonePower ( m_IsPowered ) ;
return false ;
}
} DrSpSP ( AreCoordsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) ;
int BlockX = ( m_Chunk - > GetPosX ( ) * cChunkDef : : Width ) + a_RelBlockX ;
int BlockZ = ( m_Chunk - > GetPosZ ( ) * cChunkDef : : Width ) + a_RelBlockZ ;
m_Chunk - > DoWithRedstonePoweredEntityAt ( BlockX , a_RelBlockY , BlockZ , DrSpSP ) ;
}
void cIncrementalRedstoneSimulator : : HandleRedstoneLamp ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , BLOCKTYPE a_MyState )
{
if ( a_MyState = = E_BLOCK_REDSTONE_LAMP_OFF )
{
if ( AreCoordsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) )
{
m_Chunk - > SetBlock ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , E_BLOCK_REDSTONE_LAMP_ON , 0 ) ;
}
}
else
{
if ( ! AreCoordsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) )
{
m_Chunk - > SetBlock ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , E_BLOCK_REDSTONE_LAMP_OFF , 0 ) ;
}
}
}
void cIncrementalRedstoneSimulator : : HandleTNT ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
int BlockX = ( m_Chunk - > GetPosX ( ) * cChunkDef : : Width ) + a_RelBlockX ;
int BlockZ = ( m_Chunk - > GetPosZ ( ) * cChunkDef : : Width ) + a_RelBlockZ ;
if ( AreCoordsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) )
{
m_Chunk - > BroadcastSoundEffect ( " game.tnt.primed " , ( double ) BlockX , ( double ) a_RelBlockY , ( double ) BlockZ , 0.5f , 0.6f ) ;
m_Chunk - > SetBlock ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , E_BLOCK_AIR , 0 ) ;
this - > m_World . SpawnPrimedTNT ( BlockX + 0.5 , a_RelBlockY + 0.5 , BlockZ + 0.5 ) ; // 80 ticks to boom
}
}
void cIncrementalRedstoneSimulator : : HandleDoor ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
int BlockX = ( m_Chunk - > GetPosX ( ) * cChunkDef : : Width ) + a_RelBlockX ;
int BlockZ = ( m_Chunk - > GetPosZ ( ) * cChunkDef : : Width ) + a_RelBlockZ ;
typedef GetHandlerCompileTime < E_BLOCK_WOODEN_DOOR > : : type DoorHandler ;
if ( AreCoordsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) )
{
if ( ! AreCoordsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , true ) )
{
cChunkInterface ChunkInterface ( this - > m_World . GetChunkMap ( ) ) ;
if ( ! DoorHandler : : IsOpen ( ChunkInterface , BlockX , a_RelBlockY , BlockZ ) )
{
DoorHandler : : SetOpen ( ChunkInterface , BlockX , a_RelBlockY , BlockZ , true ) ;
m_Chunk - > BroadcastSoundParticleEffect ( 1003 , BlockX , a_RelBlockY , BlockZ , 0 ) ;
}
SetPlayerToggleableBlockAsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , true ) ;
}
}
else
{
if ( ! AreCoordsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , false ) )
{
cChunkInterface ChunkInterface ( this - > m_World . GetChunkMap ( ) ) ;
if ( DoorHandler : : IsOpen ( ChunkInterface , BlockX , a_RelBlockY , BlockZ ) )
{
DoorHandler : : SetOpen ( ChunkInterface , BlockX , a_RelBlockY , BlockZ , false ) ;
m_Chunk - > BroadcastSoundParticleEffect ( 1003 , BlockX , a_RelBlockY , BlockZ , 0 ) ;
}
SetPlayerToggleableBlockAsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , false ) ;
}
}
}
void cIncrementalRedstoneSimulator : : HandleCommandBlock ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
class cSetPowerToCommandBlock :
public cRedstonePoweredCallback
{
bool m_IsPowered ;
public :
cSetPowerToCommandBlock ( bool a_IsPowered ) : m_IsPowered ( a_IsPowered ) { }
virtual bool Item ( cRedstonePoweredEntity * a_CommandBlock ) override
{
a_CommandBlock - > SetRedstonePower ( m_IsPowered ) ;
return false ;
}
} CmdBlockSP ( AreCoordsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) ;
int BlockX = ( m_Chunk - > GetPosX ( ) * cChunkDef : : Width ) + a_RelBlockX ;
int BlockZ = ( m_Chunk - > GetPosZ ( ) * cChunkDef : : Width ) + a_RelBlockZ ;
m_Chunk - > DoWithRedstonePoweredEntityAt ( BlockX , a_RelBlockY , BlockZ , CmdBlockSP ) ;
}
void cIncrementalRedstoneSimulator : : HandleRail ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , BLOCKTYPE a_MyType )
{
switch ( a_MyType )
{
2014-10-29 12:02:59 -04:00
case E_BLOCK_DETECTOR_RAIL :
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( ( m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) & 0x08 ) = = 0x08 )
{
SetAllDirsAsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , a_MyType ) ;
}
break ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
case E_BLOCK_ACTIVATOR_RAIL :
case E_BLOCK_POWERED_RAIL :
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
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 ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
default : LOGD ( " Unhandled type of rail in %s " , __FUNCTION__ ) ;
2014-10-25 16:54:00 -04:00
}
}
void cIncrementalRedstoneSimulator : : HandleTrapdoor ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
int BlockX = ( m_Chunk - > GetPosX ( ) * cChunkDef : : Width ) + a_RelBlockX ;
int BlockZ = ( m_Chunk - > GetPosZ ( ) * cChunkDef : : Width ) + a_RelBlockZ ;
if ( AreCoordsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) )
{
if ( ! AreCoordsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , true ) )
{
this - > m_World . SetTrapdoorOpen ( BlockX , a_RelBlockY , BlockZ , true ) ;
SetPlayerToggleableBlockAsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , true ) ;
}
}
else
{
if ( ! AreCoordsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , false ) )
{
this - > m_World . SetTrapdoorOpen ( BlockX , a_RelBlockY , BlockZ , false ) ;
SetPlayerToggleableBlockAsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , false ) ;
}
}
}
void cIncrementalRedstoneSimulator : : HandleNoteBlock ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
bool m_bAreCoordsPowered = AreCoordsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
if ( m_bAreCoordsPowered )
{
if ( ! AreCoordsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , true ) )
{
class cSetPowerToNoteBlock :
public cRedstonePoweredCallback
{
public :
cSetPowerToNoteBlock ( ) { }
virtual bool Item ( cRedstonePoweredEntity * a_NoteBlock ) override
{
a_NoteBlock - > SetRedstonePower ( true ) ;
return false ;
}
} NoteBlockSP ;
int BlockX = ( m_Chunk - > GetPosX ( ) * cChunkDef : : Width ) + a_RelBlockX ;
int BlockZ = ( m_Chunk - > GetPosZ ( ) * cChunkDef : : Width ) + a_RelBlockZ ;
m_Chunk - > DoWithRedstonePoweredEntityAt ( BlockX , a_RelBlockY , BlockZ , NoteBlockSP ) ;
SetPlayerToggleableBlockAsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , true ) ;
}
}
else
{
if ( ! AreCoordsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , false ) )
{
SetPlayerToggleableBlockAsSimulated ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , false ) ;
}
}
}
void cIncrementalRedstoneSimulator : : HandleDaylightSensor ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
int BlockX = ( m_Chunk - > GetPosX ( ) * cChunkDef : : Width ) + a_RelBlockX , BlockZ = ( m_Chunk - > GetPosZ ( ) * cChunkDef : : Width ) + a_RelBlockZ ;
int ChunkX , ChunkZ ;
cChunkDef : : BlockToChunk ( BlockX , BlockZ , ChunkX , ChunkZ ) ;
2015-02-08 11:35:10 -05:00
if ( ! m_World . IsChunkLighted ( ChunkX , ChunkZ ) )
2014-10-25 16:54:00 -04:00
{
2015-02-08 11:35:10 -05:00
m_World . QueueLightChunk ( ChunkX , ChunkZ ) ;
2014-10-25 16:54:00 -04:00
}
else
{
2015-02-08 11:35:10 -05:00
if ( m_Chunk - > GetTimeAlteredLight ( m_Chunk - > GetSkyLight ( a_RelBlockX , a_RelBlockY + 1 , a_RelBlockZ ) ) > 8 )
2014-10-25 16:54:00 -04:00
{
SetAllDirsAsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
}
else
{
2015-02-08 11:35:10 -05:00
SetSourceUnpowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk ) ;
2014-10-25 16:54:00 -04:00
}
}
}
void cIncrementalRedstoneSimulator : : HandlePressurePlate ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , BLOCKTYPE a_MyType )
{
int BlockX = ( m_Chunk - > GetPosX ( ) * cChunkDef : : Width ) + a_RelBlockX ;
int BlockZ = ( m_Chunk - > GetPosZ ( ) * cChunkDef : : Width ) + a_RelBlockZ ;
switch ( a_MyType )
{
2014-10-29 12:02:59 -04:00
case E_BLOCK_STONE_PRESSURE_PLATE :
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
// MCS feature - stone pressure plates can only be triggered by players :D
cPlayer * a_Player = this - > m_World . FindClosestPlayer ( Vector3f ( BlockX + 0.5f , ( float ) a_RelBlockY , BlockZ + 0.5f ) , 0.5f , false ) ;
2014-12-16 18:18:59 -05:00
if ( a_Player ! = nullptr )
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
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 ) ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
else
{
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , 0x0 ) ;
SetSourceUnpowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk ) ;
}
break ;
}
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE :
{
class cPressurePlateCallback :
public cEntityCallback
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
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 )
{
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
virtual bool Item ( cEntity * a_Entity ) override
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
Vector3f EntityPos = a_Entity - > GetPosition ( ) ;
Vector3f BlockPos ( m_X + 0.5f , ( float ) m_Y , m_Z + 0.5f ) ;
double Distance = ( EntityPos - BlockPos ) . Length ( ) ;
if ( Distance < = 0.5 )
{
m_NumberOfEntities + + ;
}
return false ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
bool GetPowerLevel ( unsigned char & a_PowerLevel ) const
{
a_PowerLevel = std : : min ( m_NumberOfEntities , MAX_POWER_LEVEL ) ;
return ( a_PowerLevel > 0 ) ;
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
protected :
int m_NumberOfEntities ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
int m_X ;
int m_Y ;
int m_Z ;
} ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
cPressurePlateCallback PressurePlateCallback ( BlockX , a_RelBlockY , BlockZ ) ;
this - > m_World . ForEachEntityInChunk ( m_Chunk - > GetPosX ( ) , m_Chunk - > GetPosZ ( ) , PressurePlateCallback ) ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
unsigned char Power ;
NIBBLETYPE Meta = m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
if ( PressurePlateCallback . GetPowerLevel ( Power ) )
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( Meta = = E_META_PRESSURE_PLATE_RAISED )
{
m_Chunk - > BroadcastSoundEffect ( " random.click " , ( double ) BlockX + 0.5 , ( double ) a_RelBlockY + 0.1 , ( double ) BlockZ + 0.5 , 0.3F , 0.5F ) ;
}
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , E_META_PRESSURE_PLATE_DEPRESSED ) ;
SetAllDirsAsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Power ) ;
SetDirectionLinkedPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , BLOCK_FACE_YM , a_MyType ) ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
else
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( Meta = = E_META_PRESSURE_PLATE_DEPRESSED )
{
m_Chunk - > BroadcastSoundEffect ( " random.click " , ( double ) BlockX + 0.5 , ( double ) a_RelBlockY + 0.1 , ( double ) BlockZ + 0.5 , 0.3F , 0.6F ) ;
}
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , E_META_PRESSURE_PLATE_RAISED ) ;
SetSourceUnpowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk ) ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
break ;
}
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE :
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
class cPressurePlateCallback :
public cEntityCallback
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
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 )
{
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
virtual bool Item ( cEntity * a_Entity ) override
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
Vector3f EntityPos = a_Entity - > GetPosition ( ) ;
Vector3f BlockPos ( m_X + 0.5f , ( float ) m_Y , m_Z + 0.5f ) ;
double Distance = ( EntityPos - BlockPos ) . Length ( ) ;
if ( Distance < = 0.5 )
{
m_NumberOfEntities + + ;
}
return false ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
bool GetPowerLevel ( unsigned char & a_PowerLevel ) const
{
a_PowerLevel = std : : min ( ( int ) ceil ( m_NumberOfEntities / 10.f ) , MAX_POWER_LEVEL ) ;
return ( a_PowerLevel > 0 ) ;
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
protected :
int m_NumberOfEntities ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
int m_X ;
int m_Y ;
int m_Z ;
} ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
cPressurePlateCallback PressurePlateCallback ( BlockX , a_RelBlockY , BlockZ ) ;
this - > m_World . ForEachEntityInChunk ( m_Chunk - > GetPosX ( ) , m_Chunk - > GetPosZ ( ) , PressurePlateCallback ) ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
unsigned char Power ;
NIBBLETYPE Meta = m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
if ( PressurePlateCallback . GetPowerLevel ( Power ) )
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( Meta = = E_META_PRESSURE_PLATE_RAISED )
{
m_Chunk - > BroadcastSoundEffect ( " random.click " , ( double ) BlockX + 0.5 , ( double ) a_RelBlockY + 0.1 , ( double ) BlockZ + 0.5 , 0.3F , 0.5F ) ;
}
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , E_META_PRESSURE_PLATE_DEPRESSED ) ;
SetAllDirsAsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , Power ) ;
SetDirectionLinkedPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , BLOCK_FACE_YM , a_MyType ) ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
else
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( Meta = = E_META_PRESSURE_PLATE_DEPRESSED )
{
m_Chunk - > BroadcastSoundEffect ( " random.click " , ( double ) BlockX + 0.5 , ( double ) a_RelBlockY + 0.1 , ( double ) BlockZ + 0.5 , 0.3F , 0.6F ) ;
}
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , E_META_PRESSURE_PLATE_RAISED ) ;
SetSourceUnpowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk ) ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
break ;
}
case E_BLOCK_WOODEN_PRESSURE_PLATE :
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
class cPressurePlateCallback :
public cEntityCallback
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
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 )
{
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
virtual bool Item ( cEntity * a_Entity ) override
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
Vector3f EntityPos = a_Entity - > GetPosition ( ) ;
Vector3f BlockPos ( m_X + 0.5f , ( float ) m_Y , m_Z + 0.5f ) ;
double Distance = ( EntityPos - BlockPos ) . Length ( ) ;
if ( Distance < = 0.5 )
{
m_FoundEntity = true ;
return true ; // Break out, we only need to know for plates that at least one entity is on top
}
return false ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
bool FoundEntity ( void ) const
{
return m_FoundEntity ;
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
protected :
bool m_FoundEntity ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
int m_X ;
int m_Y ;
int m_Z ;
} ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
cPressurePlateCallback PressurePlateCallback ( BlockX , a_RelBlockY , BlockZ ) ;
this - > m_World . ForEachEntityInChunk ( m_Chunk - > GetPosX ( ) , m_Chunk - > GetPosZ ( ) , PressurePlateCallback ) ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
NIBBLETYPE Meta = m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
if ( PressurePlateCallback . FoundEntity ( ) )
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( Meta = = E_META_PRESSURE_PLATE_RAISED )
{
m_Chunk - > BroadcastSoundEffect ( " random.click " , ( double ) BlockX + 0.5 , ( double ) a_RelBlockY + 0.1 , ( double ) BlockZ + 0.5 , 0.3F , 0.5F ) ;
}
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , E_META_PRESSURE_PLATE_DEPRESSED ) ;
SetAllDirsAsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
SetDirectionLinkedPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , BLOCK_FACE_YM , a_MyType ) ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
else
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( Meta = = E_META_PRESSURE_PLATE_DEPRESSED )
{
m_Chunk - > BroadcastSoundEffect ( " random.click " , ( double ) BlockX + 0.5 , ( double ) a_RelBlockY + 0.1 , ( double ) BlockZ + 0.5 , 0.3F , 0.6F ) ;
}
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , E_META_PRESSURE_PLATE_RAISED ) ;
SetSourceUnpowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk ) ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
break ;
}
default :
{
LOGD ( " Unimplemented pressure plate type %s in cRedstoneSimulator " , ItemToFullString ( cItem ( a_MyType ) ) . c_str ( ) ) ;
break ;
2014-10-25 16:54:00 -04:00
}
}
}
void cIncrementalRedstoneSimulator : : HandleTripwireHook ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
int RelX = a_RelBlockX , RelZ = a_RelBlockZ ;
bool FoundActivated = false ;
eBlockFace FaceToGoTowards = GetHandlerCompileTime < E_BLOCK_TRIPWIRE_HOOK > : : type : : MetadataToDirection ( m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) ;
for ( int i = 0 ; i < 40 ; + + i ) // Tripwires can be connected up to 40 blocks
{
BLOCKTYPE Type ;
NIBBLETYPE Meta ;
AddFaceDirection ( RelX , a_RelBlockY , RelZ , FaceToGoTowards ) ;
m_Chunk - > UnboundedRelGetBlock ( RelX , a_RelBlockY , RelZ , Type , Meta ) ;
if ( Type = = E_BLOCK_TRIPWIRE )
{
if ( Meta = = 0x1 )
{
FoundActivated = true ;
}
}
else if ( Type = = E_BLOCK_TRIPWIRE_HOOK )
{
if ( ReverseBlockFace ( GetHandlerCompileTime < E_BLOCK_TRIPWIRE_HOOK > : : type : : MetadataToDirection ( Meta ) ) = = FaceToGoTowards )
{
// Other hook facing in opposite direction - circuit completed!
break ;
}
else
{
// Tripwire hook not connected at all, AND away all the power state bits
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk - > GetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) & 0x3 ) ;
2014-10-29 12:02:59 -04:00
SetSourceUnpowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk ) ;
2014-10-25 16:54:00 -04:00
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 ) ;
2014-10-29 12:02:59 -04:00
SetSourceUnpowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk ) ;
2014-10-25 16:54:00 -04:00
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 ) ;
2014-10-29 12:02:59 -04:00
SetSourceUnpowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk ) ;
2014-10-25 16:54:00 -04:00
}
}
void cIncrementalRedstoneSimulator : : HandleTrappedChest ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
class cGetTrappedChestPlayers :
public cItemCallback < cChestEntity >
{
public :
cGetTrappedChestPlayers ( void ) :
m_NumberOfPlayers ( 0 )
{
}
virtual ~ cGetTrappedChestPlayers ( )
{
}
virtual bool Item ( cChestEntity * a_Chest ) override
{
ASSERT ( a_Chest - > GetBlockType ( ) = = E_BLOCK_TRAPPED_CHEST ) ;
m_NumberOfPlayers = a_Chest - > GetNumberOfPlayers ( ) ;
return ( m_NumberOfPlayers < = 0 ) ;
}
unsigned char GetPowerLevel ( void ) const
{
return std : : min ( m_NumberOfPlayers , MAX_POWER_LEVEL ) ;
}
private :
int m_NumberOfPlayers ;
} GTCP ;
int BlockX = m_Chunk - > GetPosX ( ) * cChunkDef : : Width + a_RelBlockX ;
int BlockZ = m_Chunk - > GetPosZ ( ) * cChunkDef : : Width + a_RelBlockZ ;
if ( m_Chunk - > DoWithChestAt ( BlockX , a_RelBlockY , BlockZ , GTCP ) )
{
SetAllDirsAsPowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , GTCP . GetPowerLevel ( ) ) ;
}
else
{
2014-10-29 12:02:59 -04:00
SetSourceUnpowered ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , m_Chunk ) ;
2014-10-25 16:54:00 -04:00
}
}
void cIncrementalRedstoneSimulator : : HandleTripwire ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ )
{
int BlockX = m_Chunk - > GetPosX ( ) * cChunkDef : : Width + a_RelBlockX ;
int BlockZ = m_Chunk - > GetPosZ ( ) * cChunkDef : : Width + a_RelBlockZ ;
class cTripwireCallback :
public cEntityCallback
{
public :
cTripwireCallback ( int a_BlockX , int a_BlockY , int a_BlockZ ) :
m_FoundEntity ( false ) ,
m_X ( a_BlockX ) ,
m_Y ( a_BlockY ) ,
m_Z ( a_BlockZ )
{
}
virtual bool Item ( cEntity * a_Entity ) override
{
cBoundingBox bbWire ( m_X , m_X + 1 , m_Y , m_Y + 0.1 , m_Z , m_Z + 1 ) ;
cBoundingBox bbEntity ( a_Entity - > GetPosition ( ) , a_Entity - > GetWidth ( ) / 2 , a_Entity - > GetHeight ( ) ) ;
if ( bbEntity . DoesIntersect ( bbWire ) )
{
m_FoundEntity = true ;
return true ; // One entity is sufficient to trigger the wire
}
return false ;
}
bool FoundEntity ( void ) const
{
return m_FoundEntity ;
}
protected :
bool m_FoundEntity ;
int m_X ;
int m_Y ;
int m_Z ;
} ;
cTripwireCallback TripwireCallback ( BlockX , a_RelBlockY , BlockZ ) ;
this - > m_World . ForEachEntityInChunk ( m_Chunk - > GetPosX ( ) , m_Chunk - > GetPosZ ( ) , TripwireCallback ) ;
if ( TripwireCallback . FoundEntity ( ) )
{
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , 0x1 ) ;
}
else
{
m_Chunk - > SetMeta ( a_RelBlockX , a_RelBlockY , a_RelBlockZ , 0x0 ) ;
}
}
bool cIncrementalRedstoneSimulator : : AreCoordsDirectlyPowered ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , cChunk * a_Chunk )
{
// Torches want to access neighbour's data when on a wall, hence the extra chunk parameter
2015-04-25 19:38:41 -04:00
const auto & Data = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( a_Chunk - > GetRedstoneSimulatorData ( ) ) - > m_PoweredBlocks ;
return std : : find_if ( Data . begin ( ) , Data . end ( ) , [ a_RelBlockX , a_RelBlockY , a_RelBlockZ ] ( const sPoweredBlocks & itr ) { return itr . a_BlockPos = = Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ; } ) ! = Data . end ( ) ;
2014-10-25 16:54:00 -04:00
}
2015-04-25 19:38:41 -04:00
bool cIncrementalRedstoneSimulator : : AreCoordsLinkedPowered ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , cChunk * a_Chunk )
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
const auto & Data = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( a_Chunk - > GetRedstoneSimulatorData ( ) ) - > m_LinkedBlocks ;
return std : : find_if ( Data . begin ( ) , Data . end ( ) , [ a_RelBlockX , a_RelBlockY , a_RelBlockZ ] ( const sLinkedPoweredBlocks & itr ) { return itr . a_BlockPos = = Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ; } ) ! = Data . end ( ) ;
2014-10-25 16:54:00 -04:00
}
bool cIncrementalRedstoneSimulator : : 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
2014-10-29 12:02:59 -04:00
for ( const auto & itr : * m_PoweredBlocks )
2014-10-25 16:54:00 -04:00
{
2014-12-24 18:44:09 -05:00
if ( ! itr . a_BlockPos . Equals ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) )
{
continue ;
}
2014-10-25 16:54:00 -04:00
switch ( a_Meta & 0x3 )
{
2014-10-29 12:02:59 -04:00
case 0x0 :
{
// Flip the coords to check the back of the repeater
2015-05-01 17:55:43 -04:00
if ( itr . a_SourcePos . Equals ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ + 1 ) ) )
2014-12-24 18:44:09 -05:00
{
return true ;
}
2014-10-29 12:02:59 -04:00
break ;
}
case 0x1 :
{
2015-05-01 17:55:43 -04:00
if ( itr . a_SourcePos . Equals ( Vector3i ( a_RelBlockX - 1 , a_RelBlockY , a_RelBlockZ ) ) )
2014-12-24 18:44:09 -05:00
{
return true ;
}
2014-10-29 12:02:59 -04:00
break ;
}
case 0x2 :
{
2015-05-01 17:55:43 -04:00
if ( itr . a_SourcePos . Equals ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ - 1 ) ) )
2014-12-24 18:44:09 -05:00
{
return true ;
}
2014-10-29 12:02:59 -04:00
break ;
}
case 0x3 :
{
2015-05-01 17:55:43 -04:00
if ( itr . a_SourcePos . Equals ( Vector3i ( a_RelBlockX + 1 , a_RelBlockY , a_RelBlockZ ) ) )
2014-12-24 18:44:09 -05:00
{
return true ;
}
2014-10-29 12:02:59 -04:00
break ;
}
2014-10-25 16:54:00 -04:00
}
2014-12-24 18:44:09 -05:00
} // for itr - m_PoweredBlocks[]
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
for ( const auto & itr : * m_LinkedPoweredBlocks )
2014-10-25 16:54:00 -04:00
{
2014-12-24 18:44:09 -05:00
if ( ! itr . a_BlockPos . Equals ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) )
{
continue ;
}
2014-10-25 16:54:00 -04:00
switch ( a_Meta & 0x3 )
{
2014-10-29 12:02:59 -04:00
case 0x0 :
{
2015-05-01 17:55:43 -04:00
if ( itr . a_MiddlePos . Equals ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ + 1 ) ) )
2014-12-24 18:44:09 -05:00
{
return true ;
}
2014-10-29 12:02:59 -04:00
break ;
}
case 0x1 :
{
2015-05-01 17:55:43 -04:00
if ( itr . a_MiddlePos . Equals ( Vector3i ( a_RelBlockX - 1 , a_RelBlockY , a_RelBlockZ ) ) )
2014-12-24 18:44:09 -05:00
{
return true ;
}
2014-10-29 12:02:59 -04:00
break ;
}
case 0x2 :
{
2015-05-01 17:55:43 -04:00
if ( itr . a_MiddlePos . Equals ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ - 1 ) ) )
2014-12-24 18:44:09 -05:00
{
return true ;
}
2014-10-29 12:02:59 -04:00
break ;
}
case 0x3 :
{
2015-05-01 17:55:43 -04:00
if ( itr . a_MiddlePos . Equals ( Vector3i ( a_RelBlockX + 1 , a_RelBlockY , a_RelBlockZ ) ) )
2014-12-24 18:44:09 -05:00
{
return true ;
}
2014-10-29 12:02:59 -04:00
break ;
}
2014-10-25 16:54:00 -04:00
}
2014-12-24 18:44:09 -05:00
} // for itr - m_LinkedPoweredBlocks[]
2014-10-25 16:54:00 -04:00
return false ; // Couldn't find power source behind repeater
}
bool cIncrementalRedstoneSimulator : : IsRepeaterLocked ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , NIBBLETYPE a_Meta )
{
switch ( a_Meta & 0x3 ) // We only want the 'direction' part of our metadata
{
// If the repeater is looking up or down (If parallel to the Z axis)
2014-10-29 12:02:59 -04:00
case 0x0 :
case 0x2 :
2014-10-25 16:54:00 -04:00
{
2014-12-24 18:44:09 -05:00
// Check if eastern (right) neighbor is a powered on repeater who is facing us
2014-10-29 12:02:59 -04:00
BLOCKTYPE Block = 0 ;
NIBBLETYPE OtherRepeaterDir = 0 ;
2014-12-24 18:44:09 -05:00
if (
m_Chunk - > UnboundedRelGetBlock ( a_RelBlockX + 1 , a_RelBlockY , a_RelBlockZ , Block , OtherRepeaterDir ) & &
( Block = = E_BLOCK_REDSTONE_REPEATER_ON )
)
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( ( OtherRepeaterDir & 0x03 ) = = 0x3 )
{
return true ;
2015-05-09 03:25:09 -04:00
} // If so, I am latched / locked
2014-10-29 12:02:59 -04:00
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
// Check if western(left) neighbor is a powered on repeater who is facing us
2014-12-24 18:44:09 -05:00
if (
m_Chunk - > UnboundedRelGetBlock ( a_RelBlockX - 1 , a_RelBlockY , a_RelBlockZ , Block , OtherRepeaterDir ) & &
( Block = = E_BLOCK_REDSTONE_REPEATER_ON )
)
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( ( OtherRepeaterDir & 0x03 ) = = 0x1 )
{
return true ;
2015-05-09 03:25:09 -04:00
} // If so, I am latched / locked
2014-10-29 12:02:59 -04:00
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
break ;
}
2014-10-25 16:54:00 -04:00
// If the repeater is looking left or right (If parallel to the x axis)
2014-10-29 12:02:59 -04:00
case 0x1 :
case 0x3 :
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
// Check if southern(down) neighbor is a powered on repeater who is facing us
BLOCKTYPE Block = 0 ;
NIBBLETYPE OtherRepeaterDir = 0 ;
2014-12-24 18:44:09 -05:00
if (
m_Chunk - > UnboundedRelGetBlock ( a_RelBlockX , a_RelBlockY , a_RelBlockZ + 1 , Block , OtherRepeaterDir ) & &
( Block = = E_BLOCK_REDSTONE_REPEATER_ON )
)
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( ( OtherRepeaterDir & 0x30 ) = = 0x00 )
{
return true ;
2015-05-09 03:25:09 -04:00
} // If so, I am latched / locked
2014-10-29 12:02:59 -04:00
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
// Check if northern(up) neighbor is a powered on repeater who is facing us
2014-12-24 18:44:09 -05:00
if (
m_Chunk - > UnboundedRelGetBlock ( a_RelBlockX , a_RelBlockY , a_RelBlockZ - 1 , Block , OtherRepeaterDir ) & &
( Block = = E_BLOCK_REDSTONE_REPEATER_ON )
)
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( ( OtherRepeaterDir & 0x03 ) = = 0x02 )
{
return true ;
2015-05-09 03:25:09 -04:00
} // If so, I am latched / locked
2014-10-29 12:02:59 -04:00
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
break ;
}
2014-10-25 16:54:00 -04:00
}
return false ; // None of the checks succeeded, I am not a locked repeater
}
bool cIncrementalRedstoneSimulator : : IsPistonPowered ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , NIBBLETYPE a_Meta )
{
// Pistons cannot be powered through their front face; this function verifies that a source meets this requirement
eBlockFace Face = GetHandlerCompileTime < E_BLOCK_PISTON > : : type : : MetaDataToDirection ( a_Meta ) ;
2014-10-29 12:02:59 -04:00
for ( const auto & itr : * m_PoweredBlocks )
2014-10-25 16:54:00 -04:00
{
2014-12-24 18:44:09 -05:00
if ( ! itr . a_BlockPos . Equals ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) )
{
continue ;
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
int X = a_RelBlockX , Z = a_RelBlockZ ;
AddFaceDirection ( X , a_RelBlockY , Z , Face ) ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
if ( ! itr . a_SourcePos . Equals ( AdjustRelativeCoords ( Vector3i ( X , a_RelBlockY , Z ) ) ) )
2014-10-25 16:54:00 -04:00
{
return true ;
}
}
2014-10-29 12:02:59 -04:00
for ( const auto & itr : * m_LinkedPoweredBlocks )
2014-10-25 16:54:00 -04:00
{
2014-12-24 18:44:09 -05:00
if ( ! itr . a_BlockPos . Equals ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) )
{
continue ;
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
int X = a_RelBlockX , Z = a_RelBlockZ ;
AddFaceDirection ( X , a_RelBlockY , Z , Face ) ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
if ( ! itr . a_MiddlePos . Equals ( AdjustRelativeCoords ( Vector3i ( X , a_RelBlockY , Z ) ) ) )
2014-10-25 16:54:00 -04:00
{
return true ;
}
}
return false ; // Source was in front of the piston's front face
}
2015-04-25 19:38:41 -04:00
unsigned char cIncrementalRedstoneSimulator : : IsWirePowered ( Vector3i a_RelBlockPosition , cChunk * a_Chunk )
2014-10-25 16:54:00 -04:00
{
2015-02-08 11:35:10 -05:00
unsigned char PowerLevel = 0 ;
2014-10-25 16:54:00 -04:00
2015-04-25 19:38:41 -04:00
for ( const auto & itr : static_cast < cIncrementalRedstoneSimulatorChunkData * > ( a_Chunk - > GetRedstoneSimulatorData ( ) ) - > m_PoweredBlocks ) // Check powered list
2014-10-25 16:54:00 -04:00
{
2015-02-08 11:35:10 -05:00
if ( itr . a_BlockPos ! = a_RelBlockPosition )
2014-10-25 16:54:00 -04:00
{
continue ;
}
2015-02-08 11:35:10 -05:00
PowerLevel = std : : max ( itr . a_PowerLevel , PowerLevel ) ; // Get the highest power level (a_PowerLevel is initialised already and there CAN be multiple levels for one block)
2014-10-25 16:54:00 -04:00
}
2015-04-25 19:38:41 -04:00
for ( const auto & itr : static_cast < cIncrementalRedstoneSimulatorChunkData * > ( a_Chunk - > GetRedstoneSimulatorData ( ) ) - > m_LinkedBlocks ) // Check linked powered list
2014-10-25 16:54:00 -04:00
{
2015-02-08 11:35:10 -05:00
if ( itr . a_BlockPos ! = a_RelBlockPosition )
2014-10-25 16:54:00 -04:00
{
continue ;
}
BLOCKTYPE Type = E_BLOCK_AIR ;
2015-04-25 19:38:41 -04:00
if ( ! a_Chunk - > UnboundedRelGetBlockType ( itr . a_SourcePos . x , itr . a_SourcePos . y , itr . a_SourcePos . z , Type ) | | ( Type = = E_BLOCK_REDSTONE_WIRE ) )
2014-10-25 16:54:00 -04:00
{
continue ;
}
2015-02-08 11:35:10 -05:00
PowerLevel = std : : max ( itr . a_PowerLevel , PowerLevel ) ;
2014-10-25 16:54:00 -04:00
}
2015-02-08 11:35:10 -05:00
return PowerLevel ;
2014-10-25 16:54:00 -04:00
}
bool cIncrementalRedstoneSimulator : : AreCoordsSimulated ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , bool IsCurrentStatePowered )
{
2014-10-29 12:02:59 -04:00
for ( const auto & itr : * m_SimulatedPlayerToggleableBlocks )
2014-10-25 16:54:00 -04:00
{
2015-06-02 08:29:52 -04:00
if ( itr . first . Equals ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) )
2014-10-25 16:54:00 -04:00
{
2015-06-02 08:29:52 -04:00
if ( itr . second ! = IsCurrentStatePowered ) // Was the last power state different to the current?
2014-10-25 16:54:00 -04:00
{
return false ; // It was, coordinates are no longer simulated
}
else
{
return true ; // It wasn't, don't resimulate block, and allow players to toggle
}
}
}
return false ; // Block wasn't even in the list, not simulated
}
void cIncrementalRedstoneSimulator : : SetDirectionLinkedPowered ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , char a_Direction , unsigned char a_PowerLevel )
{
BLOCKTYPE MiddleBlock = 0 ;
switch ( a_Direction )
{
2014-10-29 12:02:59 -04:00
case BLOCK_FACE_XM :
2014-10-25 16:54:00 -04:00
{
2014-10-29 12:02:59 -04:00
if ( ! m_Chunk - > UnboundedRelGetBlockType ( a_RelBlockX - 1 , a_RelBlockY , a_RelBlockZ , MiddleBlock ) )
{
return ;
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
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 ) ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
break ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
case BLOCK_FACE_XP :
{
if ( ! m_Chunk - > UnboundedRelGetBlockType ( a_RelBlockX + 1 , a_RelBlockY , a_RelBlockZ , MiddleBlock ) )
{
return ;
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
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 ) ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
break ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
case BLOCK_FACE_YM :
{
if ( ! m_Chunk - > UnboundedRelGetBlockType ( a_RelBlockX , a_RelBlockY - 1 , a_RelBlockZ , MiddleBlock ) )
{
return ;
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
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 ) ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
break ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
case BLOCK_FACE_YP :
{
if ( ! m_Chunk - > UnboundedRelGetBlockType ( a_RelBlockX , a_RelBlockY + 1 , a_RelBlockZ , MiddleBlock ) )
{
return ;
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
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 ) ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
break ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
case BLOCK_FACE_ZM :
{
if ( ! m_Chunk - > UnboundedRelGetBlockType ( a_RelBlockX , a_RelBlockY , a_RelBlockZ - 1 , MiddleBlock ) )
{
return ;
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
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 ) ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
break ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
case BLOCK_FACE_ZP :
{
if ( ! m_Chunk - > UnboundedRelGetBlockType ( a_RelBlockX , a_RelBlockY , a_RelBlockZ + 1 , MiddleBlock ) )
{
return ;
}
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
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 ) ;
2014-10-25 16:54:00 -04:00
2014-10-29 12:02:59 -04:00
break ;
}
default :
{
ASSERT ( ! " Unhandled face direction when attempting to set blocks as linked powered! " ) ; // Zombies, that wasn't supposed to happen...
break ;
}
2014-10-25 16:54:00 -04:00
}
}
void cIncrementalRedstoneSimulator : : SetAllDirsAsPowered ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , unsigned char a_PowerLevel )
{
2015-04-25 19:38:41 -04:00
static const Vector3i Offsets [ ] =
{
{ 1 , 0 , 0 } ,
{ - 1 , 0 , 0 } ,
{ 0 , 0 , 1 } ,
{ 0 , 0 , - 1 } ,
{ 0 , 1 , 0 } ,
{ 0 , - 1 , 0 }
2014-10-25 16:54:00 -04:00
} ;
2015-04-25 19:38:41 -04:00
for ( auto Offset : Offsets ) // Loop through struct to power all directions
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
SetBlockPowered ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) + Offset , Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) , a_PowerLevel ) ;
2014-10-25 16:54:00 -04:00
}
}
2015-02-08 11:35:10 -05:00
void cIncrementalRedstoneSimulator : : SetBlockPowered ( Vector3i a_RelBlockPosition , Vector3i a_RelSourcePosition , unsigned char a_PowerLevel )
2014-10-25 16:54:00 -04:00
{
2015-02-08 11:35:10 -05:00
cChunk * Neighbour = m_Chunk - > GetRelNeighborChunkAdjustCoords ( a_RelBlockPosition . x , a_RelBlockPosition . z ) ; // Adjust coordinates for the later call using these values
2014-12-16 18:18:59 -05:00
if ( ( Neighbour = = nullptr ) | | ! Neighbour - > IsValid ( ) )
2014-10-25 16:54:00 -04:00
{
return ;
}
2015-02-08 11:35:10 -05:00
a_RelSourcePosition . x + = ( m_Chunk - > GetPosX ( ) - Neighbour - > GetPosX ( ) ) * cChunkDef : : Width ;
a_RelSourcePosition . z + = ( m_Chunk - > GetPosZ ( ) - Neighbour - > GetPosZ ( ) ) * cChunkDef : : Width ;
2014-10-25 16:54:00 -04:00
2015-04-25 19:38:41 -04:00
auto & Powered = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( Neighbour - > GetRedstoneSimulatorData ( ) ) - > m_PoweredBlocks ; // We need to insert the value into the chunk who owns the block position
2015-05-26 18:30:50 -04:00
for ( auto & itr : Powered )
2014-10-25 16:54:00 -04:00
{
2015-05-26 18:30:50 -04:00
if ( ( itr . a_BlockPos = = a_RelBlockPosition ) & & ( itr . a_SourcePos = = a_RelSourcePosition ) )
2014-10-25 16:54:00 -04:00
{
2015-05-26 18:30:50 -04:00
if ( itr . a_PowerLevel ! = a_PowerLevel )
2014-10-25 16:54:00 -04:00
{
2015-02-08 11:35:10 -05:00
// Update power level, don't add a new listing
Neighbour - > SetIsRedstoneDirty ( true ) ;
m_Chunk - > SetIsRedstoneDirty ( true ) ;
2015-05-26 18:30:50 -04:00
itr . a_PowerLevel = a_PowerLevel ;
2014-10-25 16:54:00 -04:00
}
2015-02-08 11:35:10 -05:00
return ;
2014-10-25 16:54:00 -04:00
}
}
sPoweredBlocks RC ;
2015-02-08 11:35:10 -05:00
RC . a_BlockPos = a_RelBlockPosition ;
RC . a_SourcePos = a_RelSourcePosition ;
2014-10-25 16:54:00 -04:00
RC . a_PowerLevel = a_PowerLevel ;
2014-10-29 12:02:59 -04:00
Powered . emplace_back ( RC ) ;
2014-10-25 16:54:00 -04:00
Neighbour - > SetIsRedstoneDirty ( true ) ;
m_Chunk - > SetIsRedstoneDirty ( true ) ;
}
void cIncrementalRedstoneSimulator : : SetBlockLinkedPowered (
int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ ,
int a_RelMiddleX , int a_RelMiddleY , int a_RelMiddleZ ,
int a_RelSourceX , int a_RelSourceY , int a_RelSourceZ ,
BLOCKTYPE a_MiddleBlock , unsigned char a_PowerLevel
)
{
if ( ! IsViableMiddleBlock ( a_MiddleBlock ) )
{
return ;
}
2014-10-29 12:02:59 -04:00
cChunk * Neighbour = m_Chunk - > GetRelNeighborChunkAdjustCoords ( a_RelBlockX , a_RelBlockZ ) ;
2014-12-16 18:18:59 -05:00
if ( ( Neighbour = = nullptr ) | | ! Neighbour - > IsValid ( ) )
2014-10-25 16:54:00 -04:00
{
return ;
}
2015-05-26 18:30:50 -04:00
a_RelMiddleX + = ( m_Chunk - > GetPosX ( ) - Neighbour - > GetPosX ( ) ) * cChunkDef : : Width ;
a_RelMiddleZ + = ( m_Chunk - > GetPosZ ( ) - Neighbour - > GetPosZ ( ) ) * cChunkDef : : Width ;
a_RelSourceX + = ( m_Chunk - > GetPosX ( ) - Neighbour - > GetPosX ( ) ) * cChunkDef : : Width ;
a_RelSourceZ + = ( m_Chunk - > GetPosZ ( ) - Neighbour - > GetPosZ ( ) ) * cChunkDef : : Width ;
2014-10-25 16:54:00 -04:00
2015-04-25 19:38:41 -04:00
auto & Linked = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( Neighbour - > GetRedstoneSimulatorData ( ) ) - > m_LinkedBlocks ;
2014-10-29 12:02:59 -04:00
for ( auto & itr : Linked ) // Check linked powered list
2014-10-25 16:54:00 -04:00
{
if (
2014-10-29 12:02:59 -04:00
itr . a_BlockPos . Equals ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) & &
itr . a_MiddlePos . Equals ( Vector3i ( a_RelMiddleX , a_RelMiddleY , a_RelMiddleZ ) ) & &
itr . a_SourcePos . Equals ( Vector3i ( a_RelSourceX , a_RelSourceY , a_RelSourceZ ) )
2014-10-25 16:54:00 -04:00
)
{
2015-05-26 18:30:50 -04:00
if ( itr . a_PowerLevel ! = a_PowerLevel )
{
// Update power level, don't add a new listing
Neighbour - > SetIsRedstoneDirty ( true ) ;
m_Chunk - > SetIsRedstoneDirty ( true ) ;
itr . a_PowerLevel = a_PowerLevel ;
}
2014-10-25 16:54:00 -04:00
return ;
}
}
sLinkedPoweredBlocks RC ;
2014-10-29 12:02:59 -04:00
RC . a_BlockPos = Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ;
RC . a_MiddlePos = Vector3i ( a_RelMiddleX , a_RelMiddleY , a_RelMiddleZ ) ;
RC . a_SourcePos = Vector3i ( a_RelSourceX , a_RelSourceY , a_RelSourceZ ) ;
2014-10-25 16:54:00 -04:00
RC . a_PowerLevel = a_PowerLevel ;
2014-10-29 12:02:59 -04:00
Linked . emplace_back ( RC ) ;
2014-10-25 16:54:00 -04:00
Neighbour - > SetIsRedstoneDirty ( true ) ;
m_Chunk - > SetIsRedstoneDirty ( true ) ;
}
2015-04-25 19:38:41 -04:00
void cIncrementalRedstoneSimulator : : SetPlayerToggleableBlockAsSimulated ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , bool a_WasLastStatePowered )
2014-10-25 16:54:00 -04:00
{
2015-06-02 08:29:52 -04:00
m_SimulatedPlayerToggleableBlocks - > operator [ ] ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) ) = a_WasLastStatePowered ;
2014-10-25 16:54:00 -04:00
}
2015-06-02 08:29:52 -04:00
void cIncrementalRedstoneSimulator : : QueueRepeaterPowerChange ( int a_RelBlockX , int a_RelBlockY , int a_RelBlockZ , NIBBLETYPE a_Meta , bool a_ShouldPowerOn )
2014-10-25 16:54:00 -04:00
{
sRepeatersDelayList RC ;
// 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 ;
2015-06-02 08:29:52 -04:00
RC . ShouldPowerOn = a_ShouldPowerOn ;
auto Result = m_RepeatersDelayList - > emplace ( Vector3i ( a_RelBlockX , a_RelBlockY , a_RelBlockZ ) , RC ) ;
if ( ! Result . second )
{
// Key exists
if ( a_ShouldPowerOn = = Result . first - > second . ShouldPowerOn )
{
// We are queued already for the same thing, don't replace entry
return ;
}
Result . first - > second . a_DelayTicks = RC . a_DelayTicks ;
Result . first - > second . a_ElapsedTicks = 0 ;
Result . first - > second . ShouldPowerOn = a_ShouldPowerOn ;
}
2014-10-25 16:54:00 -04:00
}
2015-03-20 18:30:20 -04:00
void cIncrementalRedstoneSimulator : : SetSourceUnpowered ( int a_RelSourceX , int a_RelSourceY , int a_RelSourceZ , cChunk * a_Chunk )
2014-10-25 16:54:00 -04:00
{
2015-05-01 17:55:43 -04:00
if ( ( a_Chunk = = nullptr ) | | ! a_Chunk - > IsValid ( ) )
{
return ;
}
2015-03-20 18:30:20 -04:00
std : : vector < std : : pair < Vector3i , cChunk * > > BlocksPotentiallyUnpowered = { std : : make_pair ( Vector3i ( a_RelSourceX , a_RelSourceY , a_RelSourceZ ) , a_Chunk ) } ;
auto UnpoweringFunction = [ & BlocksPotentiallyUnpowered ] ( cChunk * a_Chunk , const Vector3i & a_RelSource )
2014-10-25 16:54:00 -04:00
{
2015-05-26 18:30:50 -04:00
BLOCKTYPE RepeaterType ;
if ( a_Chunk - > UnboundedRelGetBlockType ( a_RelSource . x , a_RelSource . y , a_RelSource . z , RepeaterType ) & & ( RepeaterType = = E_BLOCK_REDSTONE_REPEATER_ON ) )
{
return ;
}
2015-04-25 19:38:41 -04:00
auto Data = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( a_Chunk - > GetRedstoneSimulatorData ( ) ) ;
2015-03-20 18:30:20 -04:00
Data - > m_PoweredBlocks . erase ( std : : remove_if ( Data - > m_PoweredBlocks . begin ( ) , Data - > m_PoweredBlocks . end ( ) , [ & BlocksPotentiallyUnpowered , a_Chunk , a_RelSource ] ( const sPoweredBlocks & itr )
{
if ( itr . a_SourcePos ! = a_RelSource )
{
return false ;
}
2014-10-25 16:54:00 -04:00
2015-03-20 18:30:20 -04:00
BlocksPotentiallyUnpowered . emplace_back ( std : : make_pair ( itr . a_BlockPos , a_Chunk ) ) ;
2014-10-29 12:02:59 -04:00
a_Chunk - > SetIsRedstoneDirty ( true ) ;
return true ;
}
2015-03-20 18:30:20 -04:00
) , Data - > m_PoweredBlocks . end ( ) ) ;
2015-05-26 18:30:50 -04:00
2015-04-25 19:38:41 -04:00
Data - > m_LinkedBlocks . erase ( std : : remove_if ( Data - > m_LinkedBlocks . begin ( ) , Data - > m_LinkedBlocks . end ( ) , [ & BlocksPotentiallyUnpowered , a_Chunk , a_RelSource ] ( const sLinkedPoweredBlocks & itr )
2014-10-29 12:02:59 -04:00
{
2015-04-25 19:38:41 -04:00
if ( itr . a_SourcePos ! = a_RelSource )
2015-03-20 18:30:20 -04:00
{
2015-04-25 19:38:41 -04:00
return false ;
2015-03-20 18:30:20 -04:00
}
2015-04-25 19:38:41 -04:00
BlocksPotentiallyUnpowered . emplace_back ( std : : make_pair ( itr . a_BlockPos , a_Chunk ) ) ;
a_Chunk - > SetIsRedstoneDirty ( true ) ;
return true ;
2014-10-29 12:02:59 -04:00
}
2015-04-25 19:38:41 -04:00
) , Data - > m_LinkedBlocks . end ( ) ) ;
2015-05-26 18:30:50 -04:00
for ( const auto & BoundaryChunk : GetAdjacentChunks ( a_RelSource , a_Chunk ) )
{
auto BoundaryData = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( BoundaryChunk - > GetRedstoneSimulatorData ( ) ) ;
Vector3i ChunkAdjustedSource = a_RelSource ;
ChunkAdjustedSource . x + = ( a_Chunk - > GetPosX ( ) - BoundaryChunk - > GetPosX ( ) ) * cChunkDef : : Width ;
ChunkAdjustedSource . z + = ( a_Chunk - > GetPosZ ( ) - BoundaryChunk - > GetPosZ ( ) ) * cChunkDef : : Width ;
if (
( std : : find_if ( BoundaryData - > m_PoweredBlocks . begin ( ) , BoundaryData - > m_PoweredBlocks . end ( ) , [ ChunkAdjustedSource ] ( const sPoweredBlocks & itr ) { return ( itr . a_SourcePos = = ChunkAdjustedSource ) ; } ) ! = BoundaryData - > m_PoweredBlocks . end ( ) ) | |
( std : : find_if ( BoundaryData - > m_LinkedBlocks . begin ( ) , BoundaryData - > m_LinkedBlocks . end ( ) , [ ChunkAdjustedSource ] ( const sLinkedPoweredBlocks & itr ) { return ( itr . a_SourcePos = = ChunkAdjustedSource ) ; } ) ! = BoundaryData - > m_LinkedBlocks . end ( ) )
)
{
BlocksPotentiallyUnpowered . emplace_back ( std : : make_pair ( ChunkAdjustedSource , BoundaryChunk ) ) ;
}
}
2015-03-20 18:30:20 -04:00
} ;
2014-10-29 12:02:59 -04:00
2015-03-20 18:30:20 -04:00
while ( ! BlocksPotentiallyUnpowered . empty ( ) )
2014-10-25 16:54:00 -04:00
{
2015-03-20 18:30:20 -04:00
auto End = BlocksPotentiallyUnpowered . back ( ) ;
BlocksPotentiallyUnpowered . pop_back ( ) ;
UnpoweringFunction ( End . second , End . first ) ;
2014-10-25 16:54:00 -04:00
}
2014-10-29 12:02:59 -04:00
}
2015-05-26 18:30:50 -04:00
void cIncrementalRedstoneSimulator : : SetInvalidMiddleBlock ( int a_RelMiddleX , int a_RelMiddleY , int a_RelMiddleZ , cChunk * a_Chunk )
2014-10-29 12:02:59 -04:00
{
2015-05-26 18:30:50 -04:00
std : : vector < std : : pair < Vector3i , cChunk * > > BlocksPotentiallyUnpowered ;
2015-04-25 19:38:41 -04:00
auto Data = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( a_Chunk - > GetRedstoneSimulatorData ( ) ) ;
2014-10-29 12:02:59 -04:00
Data - > m_LinkedBlocks . erase ( std : : remove_if ( Data - > m_LinkedBlocks . begin ( ) , Data - > m_LinkedBlocks . end ( ) , [ & BlocksPotentiallyUnpowered , a_Chunk , a_RelMiddleX , a_RelMiddleY , a_RelMiddleZ ] ( const sLinkedPoweredBlocks & itr )
{
2015-05-26 18:30:50 -04:00
if ( ! itr . a_MiddlePos . Equals ( Vector3i ( a_RelMiddleX , a_RelMiddleY , a_RelMiddleZ ) ) )
2014-10-29 12:02:59 -04:00
{
2015-05-26 18:30:50 -04:00
return false ;
2014-10-29 12:02:59 -04:00
}
2015-05-26 18:30:50 -04:00
for ( const auto & BoundaryChunk : GetAdjacentChunks ( Vector3i ( a_RelMiddleX , a_RelMiddleY , a_RelMiddleZ ) , a_Chunk ) )
{
Vector3i ChunkAdjustedMiddlePos = Vector3i ( a_RelMiddleX , a_RelMiddleY , a_RelMiddleZ ) ;
ChunkAdjustedMiddlePos . x + = ( a_Chunk - > GetPosX ( ) - BoundaryChunk - > GetPosX ( ) ) * cChunkDef : : Width ;
ChunkAdjustedMiddlePos . z + = ( a_Chunk - > GetPosZ ( ) - BoundaryChunk - > GetPosZ ( ) ) * cChunkDef : : Width ;
auto BoundaryData = static_cast < cIncrementalRedstoneSimulatorChunkData * > ( BoundaryChunk - > GetRedstoneSimulatorData ( ) ) ;
BoundaryData - > m_LinkedBlocks . erase ( std : : remove_if ( BoundaryData - > m_LinkedBlocks . begin ( ) , BoundaryData - > m_LinkedBlocks . end ( ) , [ & BlocksPotentiallyUnpowered , BoundaryChunk , ChunkAdjustedMiddlePos ] ( const sLinkedPoweredBlocks & itr )
{
if ( itr . a_MiddlePos ! = ChunkAdjustedMiddlePos )
{
return false ;
}
BlocksPotentiallyUnpowered . emplace_back ( std : : make_pair ( itr . a_BlockPos , BoundaryChunk ) ) ;
BoundaryChunk - > SetIsRedstoneDirty ( true ) ;
return true ;
}
) , BoundaryData - > m_LinkedBlocks . end ( ) ) ;
}
BLOCKTYPE RepeaterType ;
if ( a_Chunk - > UnboundedRelGetBlockType ( a_RelMiddleX , a_RelMiddleY , a_RelMiddleZ , RepeaterType ) & & ( RepeaterType = = E_BLOCK_REDSTONE_REPEATER_ON ) )
{
return false ;
}
BlocksPotentiallyUnpowered . emplace_back ( std : : make_pair ( itr . a_BlockPos , a_Chunk ) ) ;
a_Chunk - > SetIsRedstoneDirty ( true ) ;
return true ;
2014-10-29 12:02:59 -04:00
}
) , Data - > m_LinkedBlocks . end ( ) ) ;
for ( const auto & itr : BlocksPotentiallyUnpowered )
{
2015-05-26 18:30:50 -04:00
if ( ! AreCoordsPowered ( itr . first . x , itr . first . y , itr . first . z ) )
2014-10-29 12:02:59 -04:00
{
2015-05-26 18:30:50 -04:00
SetSourceUnpowered ( itr . first . x , itr . first . y , itr . first . z , itr . second ) ;
2014-10-29 12:02:59 -04:00
}
2014-10-25 16:54:00 -04:00
}
}
2015-04-25 19:38:41 -04:00
bool cIncrementalRedstoneSimulator : : IsLeverOn ( NIBBLETYPE a_BlockMeta )
{
// Extract the ON bit from metadata and return if true if it is set:
return ( ( a_BlockMeta & 0x8 ) = = 0x8 ) ;
}
std : : vector < cChunk * > cIncrementalRedstoneSimulator : : GetAdjacentChunks ( const Vector3i & a_RelBlockPosition , cChunk * a_Chunk )
2014-10-25 16:54:00 -04:00
{
2015-04-25 19:38:41 -04:00
std : : vector < cChunk * > AdjacentChunks ;
AdjacentChunks . reserve ( 2 ) ; // At most bordering two chunks; reserve that many
2014-10-25 16:54:00 -04:00
2015-05-01 17:55:43 -04:00
auto CheckAndEmplace = [ & AdjacentChunks ] ( cChunk * a_Chunk )
{
if ( ( a_Chunk ! = nullptr ) & & a_Chunk - > IsValid ( ) )
{
AdjacentChunks . emplace_back ( a_Chunk ) ;
}
} ;
2015-04-25 19:38:41 -04:00
// Are we on a chunk boundary? +- 2 because of LinkedPowered blocks
2015-05-26 18:30:50 -04:00
if ( a_RelBlockPosition . x < = 1 )
2014-10-25 16:54:00 -04:00
{
2015-05-01 17:55:43 -04:00
CheckAndEmplace ( a_Chunk - > GetRelNeighborChunk ( a_RelBlockPosition . x - 2 , a_RelBlockPosition . z ) ) ;
2014-10-25 16:54:00 -04:00
}
2015-05-26 18:30:50 -04:00
if ( a_RelBlockPosition . x > = 14 )
2014-10-25 16:54:00 -04:00
{
2015-05-01 17:55:43 -04:00
CheckAndEmplace ( a_Chunk - > GetRelNeighborChunk ( a_RelBlockPosition . x + 2 , a_RelBlockPosition . z ) ) ;
2014-10-25 16:54:00 -04:00
}
2015-05-26 18:30:50 -04:00
if ( a_RelBlockPosition . z < = 1 )
2014-10-25 16:54:00 -04:00
{
2015-05-01 17:55:43 -04:00
CheckAndEmplace ( a_Chunk - > GetRelNeighborChunk ( a_RelBlockPosition . x , a_RelBlockPosition . z - 2 ) ) ;
2014-10-25 16:54:00 -04:00
}
2015-05-26 18:30:50 -04:00
if ( a_RelBlockPosition . z > = 14 )
2014-10-25 16:54:00 -04:00
{
2015-05-01 17:55:43 -04:00
CheckAndEmplace ( a_Chunk - > GetRelNeighborChunk ( a_RelBlockPosition . x , a_RelBlockPosition . z + 2 ) ) ;
2014-10-25 16:54:00 -04:00
}
2015-04-25 19:38:41 -04:00
return AdjacentChunks ;
2014-10-25 16:54:00 -04:00
}