2015-06-26 18:24:51 -04:00
# pragma once
# include "RedstoneHandler.h"
# include "Blocks/BlockComparator.h"
class cRedstoneComparatorHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super ;
public :
2017-09-07 04:25:34 -04:00
unsigned char GetFrontPowerLevel ( cWorld & a_World , Vector3i a_Position , BLOCKTYPE a_BlockType , NIBBLETYPE a_Meta , unsigned char a_HighestSidePowerLevel , unsigned char a_HighestRearPowerLevel ) const
2015-06-26 18:24:51 -04:00
{
2016-07-31 16:54:35 -04:00
if ( cBlockComparatorHandler : : IsInSubtractionMode ( a_Meta ) )
{
// Subtraction mode
return static_cast < unsigned char > ( std : : max ( static_cast < char > ( a_HighestRearPowerLevel ) - a_HighestSidePowerLevel , 0 ) ) ;
}
else
{
// Comparison mode
return ( std : : max ( a_HighestSidePowerLevel , a_HighestRearPowerLevel ) = = a_HighestSidePowerLevel ) ? 0 : a_HighestRearPowerLevel ;
}
}
2017-09-07 04:25:34 -04:00
virtual unsigned char GetPowerDeliveredToPosition ( cWorld & a_World , Vector3i a_Position , BLOCKTYPE a_BlockType , NIBBLETYPE a_Meta , Vector3i a_QueryPosition , BLOCKTYPE a_QueryBlockType ) const override
2016-07-31 16:54:35 -04:00
{
UNUSED ( a_QueryPosition ) ;
UNUSED ( a_QueryBlockType ) ;
2017-07-14 22:09:55 -04:00
auto ChunkData = static_cast < cIncrementalRedstoneSimulator * > ( a_World . GetRedstoneSimulator ( ) ) - > GetChunkData ( ) ;
2016-07-31 16:54:35 -04:00
2017-07-14 22:09:55 -04:00
return (
( cBlockComparatorHandler : : GetFrontCoordinate ( a_Position , a_Meta & 0x3 ) = = a_QueryPosition ) ?
ChunkData - > GetCachedPowerData ( a_Position ) . PowerLevel : 0
) ;
2016-07-31 16:54:35 -04:00
}
2017-09-07 04:25:34 -04:00
virtual unsigned char GetPowerLevel ( cWorld & a_World , Vector3i a_Position , BLOCKTYPE a_BlockType , NIBBLETYPE a_Meta ) const override
2016-07-31 16:54:35 -04:00
{
UNUSED ( a_Position ) ;
UNUSED ( a_BlockType ) ;
2017-09-11 17:20:49 -04:00
UInt8 SignalStrength = 0 ;
auto RearCoordinate = cBlockComparatorHandler : : GetRearCoordinate ( a_Position , a_Meta & 0x3 ) ;
a_World . DoWithBlockEntityAt ( RearCoordinate . x , RearCoordinate . y , RearCoordinate . z , [ & ] ( cBlockEntity & a_BlockEntity )
2015-06-26 18:24:51 -04:00
{
2016-12-06 04:40:34 -05:00
// Skip BlockEntities that don't have slots
2017-09-11 17:20:49 -04:00
auto BlockEntityWithItems = dynamic_cast < cBlockEntityWithItems * > ( & a_BlockEntity ) ;
2016-12-06 04:40:34 -05:00
if ( BlockEntityWithItems = = nullptr )
{
return false ;
}
auto & Contents = BlockEntityWithItems - > GetContents ( ) ;
2015-06-26 18:24:51 -04:00
float Fullness = 0 ; // Is a floating-point type to allow later calculation to produce a non-truncated value
2016-07-31 16:54:35 -04:00
2015-06-26 18:24:51 -04:00
for ( int Slot = 0 ; Slot ! = Contents . GetNumSlots ( ) ; + + Slot )
{
2016-07-31 16:54:35 -04:00
Fullness + = static_cast < float > ( Contents . GetSlot ( Slot ) . m_ItemCount ) / Contents . GetSlot ( Slot ) . GetMaxStackSize ( ) ;
2015-06-26 18:24:51 -04:00
}
2017-09-11 17:20:49 -04:00
SignalStrength = ( Fullness < 0.001 /* container empty? */ ) ? 0 : static_cast < UInt8 > ( 1 + ( Fullness / Contents . GetNumSlots ( ) ) * 14 ) ;
2015-06-26 18:24:51 -04:00
return false ;
}
2017-09-11 17:20:49 -04:00
) ;
auto RearPower = SignalStrength ;
2017-07-14 22:09:55 -04:00
auto RearType = a_World . GetBlock ( RearCoordinate ) ;
2016-07-31 16:54:35 -04:00
2017-07-14 22:09:55 -04:00
auto PotentialSourceHandler = cIncrementalRedstoneSimulator : : GetComponentHandler ( RearType ) ;
2015-06-26 18:24:51 -04:00
if ( PotentialSourceHandler ! = nullptr )
{
2017-07-14 22:09:55 -04:00
NIBBLETYPE RearMeta = a_World . GetBlockMeta ( RearCoordinate ) ;
2017-09-11 17:20:49 -04:00
RearPower = std : : max ( SignalStrength , PotentialSourceHandler - > GetPowerDeliveredToPosition ( a_World , RearCoordinate , RearType , RearMeta , a_Position , a_BlockType ) ) ;
2015-06-26 18:24:51 -04:00
}
2016-07-31 16:54:35 -04:00
return RearPower ;
2015-06-26 18:24:51 -04:00
}
2017-09-07 04:25:34 -04:00
virtual cVector3iArray Update ( cWorld & a_World , Vector3i a_Position , BLOCKTYPE a_BlockType , NIBBLETYPE a_Meta , PoweringData a_PoweringData ) const override
2015-06-26 18:24:51 -04:00
{
2016-07-31 16:54:35 -04:00
// Note that a_PoweringData here contains the maximum * side * power level, as specified by GetValidSourcePositions
// LOGD("Evaluating ALU the comparator (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
2017-07-14 22:09:55 -04:00
auto Data = static_cast < cIncrementalRedstoneSimulator * > ( a_World . GetRedstoneSimulator ( ) ) - > GetChunkData ( ) ;
2016-07-31 16:54:35 -04:00
auto DelayInfo = Data - > GetMechanismDelayInfo ( a_Position ) ;
2015-06-26 18:24:51 -04:00
2016-07-31 16:54:35 -04:00
// Delay is used here to prevent an infinite loop (#3168)
if ( DelayInfo = = nullptr )
{
2017-07-14 22:09:55 -04:00
auto RearPower = GetPowerLevel ( a_World , a_Position , a_BlockType , a_Meta ) ;
auto FrontPower = GetFrontPowerLevel ( a_World , a_Position , a_BlockType , a_Meta , a_PoweringData . PowerLevel , RearPower ) ;
auto PreviousFrontPower = Data - > ExchangeUpdateOncePowerData ( a_Position , PoweringData ( a_PoweringData . PoweringBlock , FrontPower ) ) ;
2016-06-05 11:08:47 -04:00
2016-07-31 16:54:35 -04:00
bool ShouldBeOn = ( RearPower > 0 ) ; // Provide visual indication by examining * rear * power level
bool ShouldUpdate = ( FrontPower ! = PreviousFrontPower . PowerLevel ) ; // "Business logic" (:P) - determine by examining *side* power levels
2016-06-05 11:08:47 -04:00
2016-07-31 16:54:35 -04:00
if ( ShouldUpdate | | ( ShouldBeOn ! = cBlockComparatorHandler : : IsOn ( a_Meta ) ) )
2016-06-05 11:08:47 -04:00
{
2016-07-31 16:54:35 -04:00
Data - > m_MechanismDelays [ a_Position ] = std : : make_pair ( 1 , ShouldBeOn ) ;
2016-06-05 11:08:47 -04:00
}
2015-06-26 18:24:51 -04:00
}
else
{
2016-07-31 16:54:35 -04:00
int DelayTicks ;
bool ShouldPowerOn ;
std : : tie ( DelayTicks , ShouldPowerOn ) = * DelayInfo ;
2015-06-26 18:24:51 -04:00
2016-07-31 16:54:35 -04:00
if ( DelayTicks = = 0 )
{
2017-07-14 22:09:55 -04:00
a_World . SetBlockMeta ( a_Position , ShouldPowerOn ? ( a_Meta | 0x8 ) : ( a_Meta & 0x7 ) ) ;
2016-07-31 16:54:35 -04:00
Data - > m_MechanismDelays . erase ( a_Position ) ;
// Assume that an update (to front power) is needed.
// Note: potential inconsistencies will arise as power data is updated before-delay due to limitations of the power data caching functionality (only stores one bool)
// This means that other mechanisms like wires may get our new power data before our delay has finished
// This also means that we have to manually update ourselves to be aware of any changes that happened in the previous redstone tick
return StaticAppend ( GetAdjustedRelatives ( a_Position , GetRelativeLaterals ( ) ) , cVector3iArray { a_Position } ) ;
}
2015-06-26 18:24:51 -04:00
}
return { } ;
}
2017-09-07 04:25:34 -04:00
virtual cVector3iArray GetValidSourcePositions ( cWorld & a_World , Vector3i a_Position , BLOCKTYPE a_BlockType , NIBBLETYPE a_Meta ) const override
2015-06-26 18:24:51 -04:00
{
2017-07-14 22:09:55 -04:00
UNUSED ( a_World ) ;
2015-06-26 18:24:51 -04:00
UNUSED ( a_BlockType ) ;
return cVector3iArray { cBlockComparatorHandler : : GetSideCoordinate ( a_Position , a_Meta & 0x3 , false ) , cBlockComparatorHandler : : GetSideCoordinate ( a_Position , a_Meta & 0x3 , true ) } ;
}
} ;