2012-05-29 13:31:11 +00:00
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "stdpch.h"
# include "game_share/action_factory.h"
# include "game_share/action_position.h"
# include "game_share/action_sint64.h"
# include "game_share/mode_and_behaviour.h"
# include "game_share/entity_types.h"
# include "distance_prioritizer.h"
# include "client_host.h"
# include "vision_provider.h"
# include <nel/misc/command.h>
# include "frontend_service.h"
# ifdef TEST_LOST_PACKET
# include <nel/misc/variable.h>
# endif
using namespace std ;
using namespace CLFECOMMON ;
using namespace NLMISC ;
using namespace NLNET ;
// Test feature to simulate a lost packet when sending a new sheet. Works with 1 client only.
# ifdef TEST_LOST_PACKET
CVariable < bool > TestPacketLost ( " test " , " TestPacketLost " , " " , true , 0 , 1 ) ;
TGameCycle TestPacketLostTimer = 0 ;
TCLEntityId TestPacketLostSlot = 0 ;
# endif
TClientId verbosePropertiesSent = INVALID_CLIENT ;
// TODO-Minimal visual bandwith
/*sint32 NbMinimalVisualBits;
void cbNbMinimalVisualBytesChanged ( IVariable & var ) ;
CVariable < sint32 > NbMinimalVisualBytes ( " fe " , " NbMinimalVisualBytes " , " Min number of bytes for vision per msg " , 50 , 0 , true , cbNbMinimalVisualBytesChanged , true ) ;
void cbNbMinimalVisualBytesChanged ( IVariable & var )
{
NbMinimalVisualBits = NbMinimalVisualBytes . get ( ) * 8 ;
} */
/// Init
void CDistancePrioritizer : : init ( CVisionArray * va , CVisionProvider * vp , CHistory * hy )
{
_VisionArray = va ;
_VisionProvider = vp ;
_History = hy ;
SortSpreader . init ( ) ;
for ( sint i = 0 ; i ! = NB_VISUAL_PROPERTIES ; + + i )
_DistThresholdTable [ i ] = - 1 ;
_VisualPropertyTreeRoot = ( TVPNodeServer * ) NewNode ( ) ;
sint nbProp = _VisualPropertyTreeRoot - > buildTree ( ) ;
// Check that the last property matches the number of properties-1
if ( nbProp ! = NB_VISUAL_PROPERTIES )
{
nlwarning ( " Found %hu properties in the sheets, the prioritizer knows %hu properties " , NB_VISUAL_PROPERTIES , nbProp ) ;
}
// Init distance thresholds
CLFECOMMON : : initThresholdTable ( _DistThresholdTable ) ;
}
/*
* Calculate the priorities
*/
void CDistancePrioritizer : : calculatePriorities ( )
{
// Sort
if ( SortSpreader . mustProcessNow ( ) )
{
THostMap : : iterator icm ;
sint clientmapindex , outerBoundIndex ;
SortSpreader . getProcessingBounds ( icm , clientmapindex , outerBoundIndex ) ;
while ( clientmapindex < outerBoundIndex )
{
CClientHost * clienthost = GETCLIENTA ( icm ) ;
// Prioritize only at the opposite time of sending for a particular client
if ( ! clienthost - > whenToSend ( ) )
{
// Update priorities
updatePriorityOfEntitiesSeenByClient ( clienthost - > clientId ( ) ) ;
// Sort entities by decreasing priority
sortEntitiesOfClient ( clienthost - > clientId ( ) ) ;
}
+ + clientmapindex ;
+ + icm ;
}
SortSpreader . endProcessing ( icm ) ;
}
SortSpreader . incCycle ( ) ;
}
/*
# define arbitrateDiscreetProperty( name ) \
get # # name # # node ( ) - > BranchHasPayload = entityIsWithinDistanceThreshold ( PROPERTY_ # # name ) & & discreetPropertyHasChanged ( PROPERTY_ # # name , ( TYPE_ # # name * ) NULL )
# define arbitrateDiscreetPropertyWithoutThreshold( name ) \
get # # name # # node ( ) - > BranchHasPayload = discreetPropertyHasChanged ( PROPERTY_ # # name , ( TYPE_ # # name * ) NULL )
# define arbitrateTargetList( name ) \
get # # name # # node ( ) - > BranchHasPayload = targetListHasChanged ( PROPERTY_ # # name , ( TYPE_ # # name * ) NULL )
*/
# ifdef STORE_MIRROR_VP_IN_CLASS
# define arbitrateDiscreetProperty( entry, name ) \
GET_VP_NODE ( name ) - > BranchHasPayload = \
entityIsWithinDistanceThreshold ( PROPERTY_ # # name ) \
& & discreetPropertyHasChanged ( entry . Properties [ PROPERTY_ # # name ] , sentity - > VP_ # # name , PROPERTY_ # # name , ( TYPE_ # # name * ) NULL )
# define arbitrateDiscreetPropertyWithoutThreshold( entry, name ) \
GET_VP_NODE ( name ) - > BranchHasPayload = \
discreetPropertyHasChanged ( entry . Properties [ PROPERTY_ # # name ] , sentity - > VP_ # # name , PROPERTY_ # # name , ( TYPE_ # # name * ) NULL )
# else // STORE_MIRROR_VP_IN_CLASS
# define arbitrateDiscreetProperty( entry, name ) \
GET_VP_NODE ( name ) - > BranchHasPayload = \
entityIsWithinDistanceThreshold ( PROPERTY_ # # name ) \
& & discreetPropertyHasChanged ( entry . Properties [ PROPERTY_ # # name ] , PROPERTY_ # # name , ( TYPE_ # # name * ) NULL )
# define arbitrateDiscreetPropertyWithoutThreshold( entry, name ) \
GET_VP_NODE ( name ) - > BranchHasPayload = \
discreetPropertyHasChanged ( entry . Properties [ PROPERTY_ # # name ] , PROPERTY_ # # name , ( TYPE_ # # name * ) NULL )
# define arbitrateTargetList( entry, name ) \
# endif // STORE_MIRROR_VP_IN_CLASS
# define arbitrateNeverSendProperty( name ) \
GET_VP_NODE ( name ) - > BranchHasPayload = false
# define arbitrateTargetList( entry, name ) \
GET_VP_NODE ( name ) - > BranchHasPayload = \
targetListHasChanged ( entry . Properties [ PROPERTY_ # # name ] , PROPERTY_ # # name , ( TYPE_ # # name * ) NULL )
# define DECLARE_AP(name) CActionSint64 *ap = CActionFactory::getInstance()->getVolatilePropAction( TVPNodeServer::PrioContext.Slot, PROPERTY_##name )
# define DECLARE_AP_INDEX(index) CActionSint64 *ap = CActionFactory::getInstance()->getVolatilePropAction( TVPNodeServer::PrioContext.Slot, index )
# define REMOVE_AP()
/*
# define DECLARE_AP(name) CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_##name )
# define DECLARE_AP_INDEX(index) CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, index )
# define REMOVE_AP() CActionFactory::getInstance()->remove( (CAction*&)ap )
*/
/*
*
*/
void CDistancePrioritizer : : fillOutBox ( CClientHost & client , TOutBox & outbox )
{
H_AUTO ( FillOutBox )
TClientId clientId = client . clientId ( ) ;
initDispatchingCycle ( clientId ) ;
# ifdef NL_DEBUG
client . MoveNumber = 0 ;
# endif
if ( ! client . entityIndex ( ) . isValid ( ) )
return ;
// initialize common context part
TVPNodeServer : : PrioContext . Prioritizer = this ;
TVPNodeServer : : PrioContext . ClientHost = & client ;
TVPNodeServer : : PrioContext . ClientId = clientId ;
CMirrorPropValueRO < TYPE_TARGET_ID > targetIndexOfClient ( TheDataset , client . entityIndex ( ) , DSPropertyTARGET_ID ) ;
// TODO-Minimal visual bandwith
/*sint32 initialPosInBit = outbox.getPosInBit();*/
sint32 currentPosInBit ;
while ( true )
{
currentPosInBit = outbox . getPosInBit ( ) ;
// Browse the seen entities, sorted by distance
TCLEntityId slot = getNextEntityToStudy ( clientId ) ;
if ( slot = = INVALID_SLOT )
{
// Exit when all the pairs have been successfully filled
# ifdef TEST_LOST_PACKET
if ( ( TestPacketLostTimer ! = 0 ) & & ( CTickEventHandler : : getGameCycle ( ) > = TestPacketLostTimer ) )
{
nldebug ( " Negative ack for %hu %hu " , client . clientId ( ) , TestPacketLostSlot ) ;
_History - > _PacketHistory . negativeAck ( client . clientId ( ) , TestPacketLostSlot , PROPERTY_SHEET , 0 ) ;
TestPacketLostTimer = 0 ;
}
# endif
return ;
}
// TODO-Minimal visual bandwith
// Always allow to write a minimal amount of visual properties
/*if ( currentPosInBit - initialPosInBit >= NbMinimalVisualBits )*/
{
// Don't fill if the free space is lower than 32 bits (checked once per pair, not once per property)
if ( currentPosInBit + 32 > client . getCurrentThrottle ( ) )
{
// Exit when the size limit has been reached before all the pairs have been filled
# ifdef NL_DEBUG
uint nbRemainingPairs = ( uint ) _PrioritizedEntitiesByClient [ clientId ] . size ( ) - _CurrentEntitiesToStudy [ clientId ] ;
if ( nbRemainingPairs > 0 )
LOG_WHAT_IS_SENT ( " %u: C%hu S%hu: %u pairs remaining " , CTickEventHandler : : getGameCycle ( ) , clientId , ( uint16 ) slot , nbRemainingPairs ) ;
LOG_WHAT_IS_SENT ( " C%hu: outbox full (%d bits) " , clientId , currentPosInBit ) ;
# endif
# ifdef TEST_LOST_PACKET
if ( ( TestPacketLostTimer ! = 0 ) & & ( CTickEventHandler : : getGameCycle ( ) > = TestPacketLostTimer ) )
{
nldebug ( " Negative ack for %hu %hu " , client . clientId ( ) , TestPacketLostSlot ) ;
_History - > _PacketHistory . negativeAck ( client . clientId ( ) , TestPacketLostSlot , PROPERTY_SHEET , 0 ) ;
TestPacketLostTimer = 0 ;
}
# endif
return ;
}
}
// Get the entity corresponding to the client/slot pair
TPairState & pairState = _VisionArray - > getPairState ( clientId , slot ) ;
CEntity * sentity = NULL ;
TEntityIndex entityIndex = pairState . EntityIndex ;
TVPNodeServer : : PrioContext . EntityIndex = entityIndex ;
if ( entityIndex . isValid ( ) )
sentity = TheEntityContainer - > getEntity ( entityIndex ) ;
if ( pairState . associationSuppressed ( ) )
{
// Pure unassociation case: we must send an empty block
serialSlotHeader ( client , NULL , pairState , slot , outbox ) ;
uint32 bits = 0 ;
outbox . serialAndLog2 ( bits , 2 ) ; // 2 bits for pos & other properties
//nldebug( "Pure unassociation of C%hu S%hu", clientId, (uint16)slot );
// The first time, sentity is non-null. If this is a resending (after a neg-ack), it's null.
if ( sentity )
_VisionProvider - > postRemovePair ( clientId , slot ) ;
}
else
{
if ( sentity = = NULL )
continue ;
H_BEFORE ( OneSlotArbitrate )
H_BEFORE ( OneSlotArbitrateInit )
// Initialize the context
TVPNodeServer : : PrioContext . Slot = slot ;
TVPNodeServer : : PrioContext . EntityIndex = entityIndex ;
TVPNodeServer : : PrioContext . Sentity = sentity ;
//TVPNodeServer::PrioContext.PairState = &pairState;
TVPNodeServer : : PrioContext . DistanceCE = pairState . DistanceCE ;
TVPNodeServer : : PrioContext . Timestamp = 0 ;
TVPNodeServer : : PrioContext . IsTarget = ( targetIndexOfClient ( ) = = entityIndex ) ;
TVPNodeServer : : PrioContext . PositionAlreadySent = ( _History - > getMileage ( clientId , slot ) ! = 0 ) ;
TVPNodeServer : : PrioContext . ZCache = sentity - > z ( entityIndex ) ; // setup Z cache for all later mirror access to entity->z()
const CPropertyHistory : : CEntityEntry & entry = _History - > getEntityEntry ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . Slot ) ;
// Debug display
//nlinfo( "Preparing a block to client %hu (%s) for slot %hu", clientId, client.eId().toString().c_str(), (uint16)slot );
// Continuous properties
uint8 seenEntityType = TheDataset . getEntityId ( entityIndex ) . getType ( ) ;
H_AFTER ( OneSlotArbitrateInit )
bool thetaIntMode = false ;
// Arbitrate all discreet properties
switch ( seenEntityType )
{
default :
arbitrateAllDiscreetProperties ( entry ) ;
break ;
case RYZOMID : : npc :
arbitrateNPCDiscreetProperties ( entry ) ;
break ;
case RYZOMID : : creature :
arbitrateCreatureDiscreetProperties ( entry ) ;
break ;
case RYZOMID : : forageSource :
arbitrateForageSourceDiscreetProperties ( entry ) ;
thetaIntMode = true ;
break ;
}
H_BEFORE ( OneSlotArbitratePropagate )
// Propagate back BranchHasPayload flags
//_VisualPropertyTreeRoot->propagateBackBranchHasPayload();
TVPNodeServer : : fastPropagateBackBranchHasPayload ( ) ;
H_AFTER ( OneSlotArbitratePropagate )
H_AFTER ( OneSlotArbitrate )
// ******** Fill the buffer with the properties ********
// Fill the header
if ( _VisualPropertyTreeRoot - > BranchHasPayload )
{
H_AUTO ( OneSlotFill )
//nldebug( "Filling for C%hu, pass %u, BEFORE HEADER: bitpos: %d", clientId, ++i, outbox.getPosInBit() );
//nlinfo( "C%hu S%hu AB%hu", clientId, (uint16)slot, (uint32)pairState.AssociationChangeBits );
serialSlotHeader ( client , sentity , pairState , slot , outbox ) ;
//nldebug( "AFTER HEADER: pos: %d", outbox.getPosInBit() );
// Fill the position if required
//TVPNodeServer *currentNode = _VisualPropertyTreeRoot;
outbox . serialBitAndLog ( GET_VP_NODE ( POSITION ) - > BranchHasPayload ) ;
if ( GET_VP_NODE ( POSITION ) - > BranchHasPayload )
{
//CActionPosition *ap = (CActionPosition*)(CActionFactory::getInstance()->createByPropIndex( slot, PROPERTY_POSITION ));
//ap->PropertyCode = PROPERTY_POSITION;
CActionPosition * ap = CActionFactory : : getInstance ( ) - > getVolatilePositionAction ( slot ) ;
// When the mode is transmitted or the entity is not in local mode (first bit of Z), transmit the *absolute* position
if ( ( ! ( TVPNodeServer : : PrioContext . ZCache & 0x1 ) ) | |
( GET_VP_NODE ( POSITION ) - > BranchHasPayload & & GET_VP_NODE ( MODE ) - > BranchHasPayload ) )
{
ap - > Position [ 0 ] = sentity - > X ( ) ;
ap - > Position [ 1 ] = sentity - > Y ( ) ;
//ap->Position[2] = sentity->z( entityIndex );
ap - > Position [ 2 ] = TVPNodeServer : : PrioContext . ZCache ;
ap - > IsRelative = false ;
LOG_WHAT_IS_SENT ( " %u: C%hu S%hu: Filling ABSPOS: %d %d %d m " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , sentity - > posXm ( entityIndex ) , sentity - > posYm ( entityIndex ) , sentity - > posZm ( entityIndex ) ) ;
}
else
{
CMirrorPropValueRO < sint32 > propLX ( TheDataset , entityIndex , DSPropertyLocalX ) ;
CMirrorPropValueRO < sint32 > propLY ( TheDataset , entityIndex , DSPropertyLocalY ) ;
CMirrorPropValueRO < sint32 > propLZ ( TheDataset , entityIndex , DSPropertyLocalZ ) ;
ap - > Position [ 0 ] = propLX ( ) ;
ap - > Position [ 1 ] = propLY ( ) ;
ap - > Position [ 2 ] = propLZ ( ) ;
ap - > IsRelative = true ;
LOG_WHAT_IS_SENT ( " %u: C%hu S%hu: Filling RELPOS: %d %d %d mm " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , ap - > Position [ 0 ] , ap - > Position [ 1 ] , ap - > Position [ 2 ] ) ;
}
CActionFactory : : getInstance ( ) - > packFast ( ap , outbox ) ;
_History - > storePosition ( clientId , client . sendNumber ( ) , ap , sentity - > Mileage , TVPNodeServer : : PrioContext . IsTarget , TVPNodeServer : : PrioContext . Timestamp ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
+ + client . NbActionsSentAtCycle ;
}
// Fill the orientation if required
//currentNode = currentNode->B;
TVPNodeServer * currentNode = _VisualPropertyTreeRoot - > B ;
outbox . serialBitAndLog ( currentNode - > BranchHasPayload ) ;
if ( currentNode - > BranchHasPayload )
{
outbox . serialBitAndLog ( currentNode - > A - > BranchHasPayload ) ;
if ( currentNode - > A - > BranchHasPayload )
{
//CActionSint64 *ap = (CActionSint64*)(CActionFactory::getInstance()->createByPropIndex( slot, PROPERTY_ORIENTATION ));
//ap->PropertyCode = PROPERTY_ORIENTATION; // useless: already set by createByPropIndex
DECLARE_AP ( ORIENTATION ) ;
CMirrorPropValueRO < float > prop ( TheDataset , entityIndex , DSPropertyORIENTATION ) ;
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu ORIENT (P%hu) : %.1f " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , prop ( ) ) ;
uint32 value = ( thetaIntMode ? ( uint32 ) ( prop ( ) ) : * ( ( uint32 * ) & ( prop ( ) ) ) ) ;
ap - > setAndPackValue ( value , outbox ) ;
_History - > store ( clientId , client . sendNumber ( ) , ap ) ;
// TODO: send less bits for forage source entity
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + client . NbActionsSentAtCycle ;
}
// Fill the required discreet properties if required
currentNode - > B - > fillDiscreetProperties ( outbox ) ;
//nlinfo("end fill");
//TVPNodeServer::fastFillDiscreetProperties( outbox );
//nlinfo("end fastfill");
}
}
# ifdef NL_DEBUG
if ( _VisualPropertyTreeRoot - > A - > BranchHasPayload )
{
//CClientEntityIdTranslator::CEntityInfo& info = client.IdTranslator.getInfo( slot ); // CHANGED BEN
//if ( info.AssociationState == CClientEntityIdTranslator::CEntityInfo::AwaitingAssAck ) // CHANGED BEN
if ( _VisionArray - > getAssociationState ( clientId , slot ) = = TPairState : : AwaitingAssAck )
{
nlwarning ( " C%hu S%hu: Sending position but sheet id not sent " , clientId , ( uint16 ) slot ) ;
client . displaySlotProperties ( slot ) ;
}
}
//if ( (verbosePropertiesSent==9999) || (verbosePropertiesSent==TVPNodeServer::PrioContext.ClientId) )
//{
// nldebug( "To C%hu", clientId );
// outbox.displayStream();
//}
# endif
// ******** End of iteration ********
//_VisualPropertyTreeRoot->displayStatesOfTreeLeaves();
//nldebug( "C%hu S%hu: end of pair block at bitpos %d", clientId, (uint16)slot, outbox.getPosInBit() );
}
// Reset the priority of the pair, even if nothing was filled
if ( slot ! = 0 )
pairState . resetPrio ( ) ; // note: nothing can remain to be filled, as we allow to exceed the size limit
}
}
/*
* Test the criterion for the position of the entity ' slot ' seen by ' clientId '
*/
bool CDistancePrioritizer : : positionHasChangedEnough ( )
{
// TEMP: do not send if local mode (because the local position is useless for the mektoub)
if ( TVPNodeServer : : PrioContext . ZCache & 0x1 )
return false ;
uint32 lastSentMileage = _History - > getMileage ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . Slot ) ;
if ( lastSentMileage ! = 0 )
{
// Calculate difference distance between current and lastsent mileage (unsigned to allow mileage overflow)
if ( ( TVPNodeServer : : PrioContext . Sentity - > Mileage - lastSentMileage ) * _DistanceDeltaRatio > ( uint32 ) ( TVPNodeServer : : PrioContext . DistanceCE ) )
{
# ifdef NL_DEBUG
+ + ( TVPNodeServer : : PrioContext . ClientHost - > MoveNumber ) ;
# endif
return true ;
}
else
{
if ( verbosePropertiesSent = = 0 )
{
nldebug ( " Ignoring move: Mileage=%u, lastSentMileage=%u, _DistanceDeltaRatio=%u, DistanceCE=%u " ,
( uint32 ) TVPNodeServer : : PrioContext . Sentity - > Mileage ,
( uint32 ) lastSentMileage ,
( uint32 ) _DistanceDeltaRatio ,
( uint32 ) TVPNodeServer : : PrioContext . DistanceCE ) ;
}
return false ;
}
}
else
{
// Not sent yet
return true ;
}
}
/*
* Test the criterion for thetaIntMode
*/
bool CDistancePrioritizer : : thetaIntModehasChanged ( const CPropertyHistory : : CPropertyEntry & entry )
{
if ( ! entityIsWithinDistanceThreshold ( PROPERTY_ORIENTATION ) )
return false ;
if ( entry . HasValue )
{
CMirrorPropValueRO < float > currentTheta ( TheDataset , TVPNodeServer : : PrioContext . EntityIndex , DSPropertyORIENTATION ) ;
return ( ( uint32 ) currentTheta ! = ( uint32 ) entry . LastSent ) ;
}
else
{
return TVPNodeServer : : PrioContext . Sentity - > propertyIsInitialized ( PROPERTY_ORIENTATION , DSPropertyORIENTATION , TVPNodeServer : : PrioContext . EntityIndex , ( TYPE_ORIENTATION * ) NULL ) ;
}
}
/*
* Test the criterion for the orientation of the entity ' slot ' seen by ' clientId ' + initialized
*/
bool CDistancePrioritizer : : orientationHasChangedEnough ( const CPropertyHistory : : CPropertyEntry & entry , float angleRatio )
{
if ( ! entityIsWithinDistanceThreshold ( PROPERTY_ORIENTATION ) )
return false ;
if ( entry . HasValue )
{
CMirrorPropValueRO < float > currentAngle ( TheDataset , TVPNodeServer : : PrioContext . EntityIndex , DSPropertyORIENTATION ) ;
/*
// Orientation is a float angle in radian
const float & oldangle = * ( ( float * ) & ( entry . LastSent ) ) ;
float deltaAngle = ( float ) fabs ( ( float ) ( currentAngle ( ) - oldangle ) ) ;
deltaAngle = ( float ) fmod ( deltaAngle + ( 2 * Pi ) , ( 2 * Pi ) ) ;
//nldebug( "getDelta(theta) : dA=%g", deltaAngle );
return ( deltaAngle > ( float ) Pi / angleRatio ) ; // the orientation is useful only when the pos does not change
*/
float oldangle ;
entry . getValue ( oldangle ) ;
float deltaAngle = ( float ) ( Pi - fabs ( fmod ( currentAngle ( ) - oldangle + 4 * Pi , 2 * Pi ) - Pi ) ) ; // deltaAngle is in [0, 2*Pi]
//nldebug( "getDelta(theta) : dA=%g", deltaAngle );
return ( deltaAngle * angleRatio > ( float ) Pi ) ; // the orientation is useful only when the pos does not change
}
else
{
// Not sent yet => always sent theta, even if it's zero (anyway, it's unlikely to be exactly 0.0: remind that this initial float is determined, for bots, by leveldesigners with the mouse)
return true ;
}
}
/*
* Test the criterion for the specified property of the entity ' slot ' seen by ' clientId '
*/
inline bool CDistancePrioritizer : : entityIsWithinDistanceThreshold ( TPropIndex propIndex )
{
// Compare distance with the threshold
//nldebug( "C%hu - slot %hu - prop %hu: DISTANCE=%d THRESHOL=%d", TVPNodeServer::PrioContext.ClientHost->clientId(), (uint16)TVPNodeServer::PrioContext.Slot, propIndex, TVPNodeServer::PrioContext.DistanceCE, TheEntityTranslator->getDistThreshold( propertyid ) );
return ( TVPNodeServer : : PrioContext . DistanceCE < getDistThreshold ( propIndex ) ) ;
}
/*
* Special arbitrate case for BEHAVIOUR property
* Threshold in this case should be the same than the target list threshold when
* the behaviour is a range attack or projectile behaviour
*/
# ifndef NL_DEBUG
inline
# endif
void CDistancePrioritizer : : arbitrateDiscreetBehaviourProperty ( const CPropertyHistory : : CEntityEntry & entry , CEntity * sentity )
{
# ifdef STORE_MIRROR_VP_IN_CLASS
const CMirrorPropValueRO < TYPE_BEHAVIOUR > & propBehav = sentity - > VP_BEHAVIOUR ;
# else
CMirrorPropValueRO < TYPE_BEHAVIOUR > propBehav ( TheDataset , TVPNodeServer : : PrioContext . EntityIndex , DSPropertyBEHAVIOUR ) ;
# endif
if ( ! discreetPropertyHasChanged ( entry . Properties [ PROPERTY_BEHAVIOUR ] , propBehav , PROPERTY_BEHAVIOUR , ( TYPE_BEHAVIOUR * ) NULL ) )
{
GET_VP_NODE ( BEHAVIOUR ) - > BranchHasPayload = false ;
return ;
}
const MBEHAV : : CBehaviour & behav = propBehav ( ) ;
TPropIndex refDistanceProperty ;
switch ( behav . Behaviour )
{
case MBEHAV : : CAST_OFF_SUCCESS :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_OFF_LINK :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_CUR_SUCCESS :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_CUR_LINK :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_MIX_SUCCESS :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_MIX_LINK :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : RANGE_ATTACK :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_ACID :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_BLIND :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_COLD :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_ELEC :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_FEAR :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_FIRE :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_HEALHP :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_MAD :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_POISON :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_ROOT :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_ROT :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_SHOCK :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_SLEEP :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_SLOW :
refDistanceProperty = PROPERTY_TARGET_LIST ;
break ;
case MBEHAV : : CAST_STUN :
refDistanceProperty = PROPERTY_TARGET_LIST ; // valid distance should be the same than the target list
// because target list and behaviour are sent together
break ;
default :
refDistanceProperty = PROPERTY_BEHAVIOUR ;
break ;
}
//
GET_VP_NODE ( BEHAVIOUR ) - > BranchHasPayload = entityIsWithinDistanceThreshold ( refDistanceProperty ) ;
}
/*
* Fill the BranchHasPayload flags of the tree , using the rules deciding if a discreet property need to be sent
*/
void CDistancePrioritizer : : arbitrateAllDiscreetProperties ( const CPropertyHistory : : CEntityEntry & entry )
{
H_AUTO ( arbitrateAllDiscreetProperties ) ;
CEntity * sentity = TVPNodeServer : : PrioContext . Sentity ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , SHEET ) ;
arbitrateDiscreetBehaviourProperty ( entry , sentity ) ;
// Don't limit to the distance threshold when triggering sending of the name of the target
if ( TVPNodeServer : : PrioContext . IsTarget )
arbitrateDiscreetPropertyWithoutThreshold ( entry , NAME_STRING_ID ) ;
else
arbitrateDiscreetProperty ( entry , NAME_STRING_ID ) ;
//arbitrateDiscreetProperty( entry, TARGET_ID ); // now done in fillOutBox() in "mode switch"
arbitrateDiscreetProperty ( entry , CONTEXTUAL ) ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , MODE ) ;
arbitrateDiscreetProperty ( entry , VPA ) ;
arbitrateDiscreetProperty ( entry , VPB ) ;
arbitrateDiscreetProperty ( entry , VPC ) ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , ENTITY_MOUNTED_ID ) ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , RIDER_ENTITY_ID ) ;
arbitrateTargetList ( entry , TARGET_LIST ) ;
arbitrateDiscreetProperty ( entry , VISUAL_FX ) ;
arbitrateDiscreetProperty ( entry , GUILD_SYMBOL ) ;
arbitrateDiscreetProperty ( entry , GUILD_NAME_ID ) ;
arbitrateDiscreetProperty ( entry , EVENT_FACTION_ID ) ;
arbitrateDiscreetProperty ( entry , PVP_MODE ) ;
arbitrateDiscreetProperty ( entry , PVP_CLAN ) ;
arbitrateNeverSendProperty ( OWNER_PEOPLE ) ;
arbitrateDiscreetProperty ( entry , OUTPOST_INFOS ) ;
if ( TVPNodeServer : : PrioContext . Slot ! = 0 )
{
arbitrateCommonPosAndMode ( entry ) ;
arbitrateDiscreetProperty ( entry , TARGET_ID ) ;
arbitrateDiscreetProperty ( entry , BARS ) ;
}
else
{
arbitrateSlot0PosAndMode ( entry ) ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , TARGET_ID ) ; // no need of threshold
// never send BARS for User Player (no need since sent with the USER:BARS message)
arbitrateNeverSendProperty ( BARS ) ;
}
}
/*
* Fill the BranchHasPayload flags of the tree , using the rules deciding if a discreet property need to be sent
*/
void CDistancePrioritizer : : arbitrateNPCDiscreetProperties ( const CPropertyHistory : : CEntityEntry & entry )
{
H_AUTO ( arbitrateNPCDiscreetProperties ) ;
CEntity * sentity = TVPNodeServer : : PrioContext . Sentity ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , SHEET ) ;
arbitrateDiscreetBehaviourProperty ( entry , sentity ) ;
// Don't limit to the distance threshold when triggering sending of the name of the target
if ( TVPNodeServer : : PrioContext . IsTarget )
arbitrateDiscreetPropertyWithoutThreshold ( entry , NAME_STRING_ID ) ;
else
arbitrateDiscreetProperty ( entry , NAME_STRING_ID ) ;
arbitrateDiscreetProperty ( entry , TARGET_ID ) ; // NPC can never be in Slot 0
// Specific distance for NPCs' contextual property
GET_VP_NODE ( CONTEXTUAL ) - > BranchHasPayload =
TVPNodeServer : : PrioContext . DistanceCE < THRESHOLD_CONTEXTUAL_NPC
& & discreetPropertyHasChanged ( entry . Properties [ PROPERTY_CONTEXTUAL ] , sentity - > VP_CONTEXTUAL , PROPERTY_CONTEXTUAL , ( TYPE_CONTEXTUAL * ) NULL ) ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , MODE ) ;
arbitrateDiscreetProperty ( entry , BARS ) ;
arbitrateDiscreetProperty ( entry , VPA ) ;
arbitrateDiscreetProperty ( entry , VPB ) ;
arbitrateDiscreetProperty ( entry , VPC ) ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , ENTITY_MOUNTED_ID ) ;
arbitrateNeverSendProperty ( RIDER_ENTITY_ID ) ;
arbitrateTargetList ( entry , TARGET_LIST ) ;
arbitrateDiscreetProperty ( entry , VISUAL_FX ) ;
arbitrateDiscreetProperty ( entry , GUILD_SYMBOL ) ;
arbitrateDiscreetProperty ( entry , GUILD_NAME_ID ) ;
arbitrateNeverSendProperty ( EVENT_FACTION_ID ) ;
arbitrateNeverSendProperty ( PVP_MODE ) ;
arbitrateNeverSendProperty ( PVP_CLAN ) ;
arbitrateNeverSendProperty ( OWNER_PEOPLE ) ;
arbitrateDiscreetProperty ( entry , OUTPOST_INFOS ) ;
arbitrateCommonPosAndMode ( entry ) ;
}
/*
* Fill the BranchHasPayload flags of the tree , using the rules deciding if a discreet property need to be sent
*/
void CDistancePrioritizer : : arbitrateCreatureDiscreetProperties ( const CPropertyHistory : : CEntityEntry & entry )
{
H_AUTO ( arbitrateCreatureDiscreetProperties ) ;
CEntity * sentity = TVPNodeServer : : PrioContext . Sentity ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , SHEET ) ;
arbitrateDiscreetBehaviourProperty ( entry , sentity ) ;
// Don't limit to the distance threshold when triggering sending of the name of the target
if ( TVPNodeServer : : PrioContext . IsTarget )
arbitrateDiscreetPropertyWithoutThreshold ( entry , NAME_STRING_ID ) ;
else
arbitrateDiscreetProperty ( entry , NAME_STRING_ID ) ;
arbitrateDiscreetProperty ( entry , TARGET_ID ) ; // Creature can never be in Slot 0
arbitrateDiscreetProperty ( entry , CONTEXTUAL ) ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , MODE ) ;
arbitrateDiscreetProperty ( entry , BARS ) ;
arbitrateNeverSendProperty ( VPA ) ;
arbitrateDiscreetProperty ( entry , VPB ) ;
arbitrateNeverSendProperty ( VPC ) ;
arbitrateNeverSendProperty ( ENTITY_MOUNTED_ID ) ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , RIDER_ENTITY_ID ) ;
arbitrateTargetList ( entry , TARGET_LIST ) ;
arbitrateNeverSendProperty ( VISUAL_FX ) ;
arbitrateNeverSendProperty ( GUILD_SYMBOL ) ;
arbitrateNeverSendProperty ( GUILD_NAME_ID ) ;
arbitrateNeverSendProperty ( EVENT_FACTION_ID ) ;
arbitrateNeverSendProperty ( PVP_MODE ) ;
arbitrateNeverSendProperty ( PVP_CLAN ) ;
arbitrateDiscreetProperty ( entry , OWNER_PEOPLE ) ;
arbitrateNeverSendProperty ( OUTPOST_INFOS ) ;
arbitrateCommonPosAndMode ( entry ) ;
}
/*
* Fill the BranchHasPayload flags of the tree , using the rules deciding if a discreet property need to be sent
*/
void CDistancePrioritizer : : arbitrateForageSourceDiscreetProperties ( const CPropertyHistory : : CEntityEntry & entry )
{
H_AUTO ( arbitrateForageSourceDiscreetProperties ) ;
CEntity * sentity = TVPNodeServer : : PrioContext . Sentity ;
arbitrateDiscreetPropertyWithoutThreshold ( entry , SHEET ) ;
arbitrateNeverSendProperty ( BEHAVIOUR ) ;
arbitrateDiscreetProperty ( entry , NAME_STRING_ID ) ;
arbitrateDiscreetProperty ( entry , TARGET_ID ) ; // ForageSource can never be in Slot 0
arbitrateDiscreetProperty ( entry , CONTEXTUAL ) ;
arbitrateNeverSendProperty ( MODE ) ;
arbitrateDiscreetProperty ( entry , BARS ) ;
arbitrateNeverSendProperty ( VPA ) ;
arbitrateNeverSendProperty ( VPB ) ;
arbitrateNeverSendProperty ( VPC ) ;
arbitrateNeverSendProperty ( ENTITY_MOUNTED_ID ) ;
arbitrateNeverSendProperty ( RIDER_ENTITY_ID ) ;
arbitrateTargetList ( entry , TARGET_LIST ) ;
arbitrateDiscreetProperty ( entry , VISUAL_FX ) ;
arbitrateNeverSendProperty ( GUILD_SYMBOL ) ;
arbitrateNeverSendProperty ( GUILD_NAME_ID ) ;
arbitrateNeverSendProperty ( EVENT_FACTION_ID ) ;
arbitrateNeverSendProperty ( PVP_MODE ) ;
arbitrateNeverSendProperty ( PVP_CLAN ) ;
arbitrateNeverSendProperty ( OWNER_PEOPLE ) ;
arbitrateNeverSendProperty ( OUTPOST_INFOS ) ;
GET_VP_NODE ( POSITION ) - > BranchHasPayload = sentity - > positionIsInitialized ( ) & & positionHasChangedEnough ( ) ;
GET_VP_NODE ( ORIENTATION ) - > BranchHasPayload = thetaIntModehasChanged ( entry . Properties [ PROPERTY_ORIENTATION ] ) ;
}
/*
* Fill the BranchHasPayload flags of the tree , using the rules deciding if a discreet property need to be sent
*/
inline void CDistancePrioritizer : : arbitrateCommonPosAndMode ( const CPropertyHistory : : CEntityEntry & entry )
{
// Position if changed enough (if not carried by mode)
// Orientation if changed > 60<36> (it's head angle only) or in first block (useful for static entities such as bot objects)
bool modeIsChanging = GET_VP_NODE ( MODE ) - > BranchHasPayload ;
bool sheetIsChanging = GET_VP_NODE ( SHEET ) - > BranchHasPayload ;
bool posIsReady = TVPNodeServer : : PrioContext . Sentity - > positionIsInitialized ( ) ;
GET_VP_NODE ( POSITION ) - > BranchHasPayload = ( ! modeIsChanging ) & & posIsReady & & positionHasChangedEnough ( ) ;
GET_VP_NODE ( ORIENTATION ) - > BranchHasPayload = ( sheetIsChanging & & posIsReady ) | | orientationHasChangedEnough ( entry . Properties [ PROPERTY_ORIENTATION ] , 36.0f ) ; // 5<>
}
/*
* Fill the BranchHasPayload flags of the tree , using the rules deciding if a discreet property need to be sent
*/
inline void CDistancePrioritizer : : arbitrateSlot0PosAndMode ( const CPropertyHistory : : CEntityEntry & entry )
{
arbitrateNeverSendProperty ( POSITION ) ;
arbitrateNeverSendProperty ( ORIENTATION ) ;
}
/*
*
*/
inline void CDistancePrioritizer : : serialSlotHeader ( CClientHost & client , CEntity * sentity , TPairState & pairState , CLFECOMMON : : TCLEntityId slot , TOutBox & outbox )
{
// Slot (8 bits)
# ifdef NL_DEBUG
sint beginbitpos = outbox . getPosInBit ( ) ;
# endif
outbox . serialAndLog1 ( slot ) ;
// Association change bits (2 bits)
uint32 associationBits = ( uint32 ) pairState . AssociationChangeBits ;
outbox . serialAndLog2 ( associationBits , 2 ) ;
if ( pairState . AssociationChangeBits ! = pairState . PrevAssociationBits )
{
//LOG_WHAT_IS_SENT( "slot %hu ab %u beginpos %d endpos %d beginbitpos %d endbitpos %d", (uint16)slot, associationBits, beginbitpos/8, outbox.getPosInBit()/8, beginbitpos, outbox.getPosInBit() );
pairState . PrevAssociationBits = pairState . AssociationChangeBits ; // & 0x3;
_History - > storeDisassociation ( client . clientId ( ) , slot , client . sendNumber ( ) , pairState . AssociationChangeBits ) ;
// pairState.AssociationChangeBits &= 0x7F;
}
// Timestamp (1 or 5 bits, depending on the type of entity) (TVPNodeServer::PrioContext.Timestamp initialized to 0)
uint32 timestampDelta = 0 ;
if ( sentity )
{
const CEntityId & seenEntityId = TheDataset . getEntityId ( TVPNodeServer : : PrioContext . EntityIndex ) ;
if ( seenEntityId . getType ( ) = = RYZOMID : : player )
{
// For players, always set the timestamp delta, using TickPosition
// Note: discreet property change times won't be accurate
TVPNodeServer : : PrioContext . Timestamp = sentity - > TickPosition ;
timestampDelta = CTickEventHandler : : getGameCycle ( ) - sentity - > TickPosition ;
if ( timestampDelta > 15 ) // clamp to 4bit
timestampDelta = 15 ;
timestampDelta | = 0x10 ; // 'timestampIsThere bit': first bit is bit 5 (high to low order)
}
else if ( seenEntityId . getType ( ) > = RYZOMID : : object )
{
// For non-players/non-bots types (e.g. bags), set the timestamp delta if entity is being spawned to the client
//if ( _VisualPropertyTreeRoot->B->B->getSHEETnode()->BranchHasPayload ) // assumes this is done after arbitrateDiscreetProperties() // CHANGED BEN
if ( GET_VP_NODE ( SHEET ) - > BranchHasPayload ) // assumes this is done after arbitrateDiscreetProperties()
{
TVPNodeServer : : PrioContext . Timestamp = TheDataset . getOnlineTimestamp ( TVPNodeServer : : PrioContext . EntityIndex ) ;
timestampDelta = CTickEventHandler : : getGameCycle ( ) - TVPNodeServer : : PrioContext . Timestamp ;
if ( timestampDelta > 15 ) // clamp to 4bit
timestampDelta = 15 ;
timestampDelta | = 0x10 ; // 'timestampIsThere bit': first bit is bit 5 (high to low order)
}
}
// For bots, the timestamp is not needed, the client will take _ServerGameCycle
}
outbox . serialAndLog2 ( timestampDelta , ( timestampDelta ! = 0 ) ? 5 : 1 ) ;
}
# ifdef STORE_MIRROR_VP_IN_CLASS
# define caseFillAction( name ) ap->setValue64( TVPNodeServer::PrioContext.Sentity->VP_##name() );
# else // STORE_MIRROR_VP_IN_CLASS
# define caseFillAction( name ) \
CMirrorPropValueRO < TYPE_ # # name > prop ( TheDataset , TVPNodeServer : : PrioContext . EntityIndex , DSProperty # # name ) ; \
ap - > setValue64 ( prop ( ) ) ;
# endif // STORE_MIRROR_VP_IN_CLASS
/*
* SHEET
*/
void fillSHEET ( TOutBox & outbox , TPropIndex )
{
# ifdef NL_DEBUG
// In non-debug cases, it is done in CVisionProvider::addPair()
//CClientEntityIdTranslator::CEntityInfo& info = TVPNodeServer::PrioContext.ClientHost->IdTranslator.getInfo( TVPNodeServer::PrioContext.Slot ); // CHANGED BEN
//info.AssociationState = CClientEntityIdTranslator::CEntityInfo::NormalAssociation; // CHANGED BEN
TVPNodeServer : : PrioContext . Prioritizer - > getVisionArray ( ) - > setAssociationState ( TVPNodeServer : : PrioContext . ClientId ,
TVPNodeServer : : PrioContext . Slot ,
TPairState : : NormalAssociation ) ;
# endif
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_SHEET ); // CHANGED BEN
DECLARE_AP ( SHEET ) ;
// Pack sheet and compressed row into the action
# ifdef STORE_MIRROR_VP_IN_CLASS
CMirrorPropValueRO < TYPE_SHEET > & prop = TVPNodeServer : : PrioContext . Sentity - > VP_SHEET ;
# else
CMirrorPropValueRO < TYPE_SHEET > prop ( TheDataset , TVPNodeServer : : PrioContext . EntityIndex , DSPropertySHEET ) ;
# endif
uint32 sheetValue = prop ( ) ;
TDataSetIndex compressedRow = TVPNodeServer : : PrioContext . EntityIndex . getCompressedIndex ( ) ;
uint64 value = ( uint64 ) sheetValue | ( ( ( uint64 ) compressedRow ) < < 32 ) ;
ap - > setValue64 ( value ) ;
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu SHEET at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_SHEET , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
// Add row into the action
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
// Include alias if non-null in mirror (only for mission giver NPCs)
CMirrorPropValueRO < TYPE_ALIAS > aliasProp ( TheDataset , TVPNodeServer : : PrioContext . EntityIndex , DSPropertyNPC_ALIAS ) ;
if ( aliasProp ( ) ! = 0 )
{
bool aliasBit = true ;
outbox . serialBitAndLog ( aliasBit ) ;
outbox . serialAndLog1 ( const_cast < TYPE_ALIAS & > ( aliasProp ( ) ) ) ; // no need to store in history, alias never changes for an entity
}
else
{
bool aliasBit = false ;
outbox . serialBitAndLog ( aliasBit ) ;
}
# ifdef TEST_LOST_PACKET
if ( TestPacketLost . get ( ) )
{
nldebug ( " This SHEET sending will be dropped... " ) ;
TestPacketLostTimer = CTickEventHandler : : getGameCycle ( ) + 10 ;
TestPacketLost = false ;
TestPacketLostSlot = TVPNodeServer : : PrioContext . Slot ;
}
# endif
}
/*
* BEHAVIOUR
*/
void fillBEHAVIOUR ( TOutBox & outbox , TPropIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_BEHAVIOUR );
DECLARE_AP ( BEHAVIOUR ) ;
caseFillAction ( BEHAVIOUR )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu BEHAVIOUR at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_BEHAVIOUR , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* NAME_STRING_ID
*/
void fillNAME_STRING_ID ( TOutBox & outbox , TPropIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_NAME_STRING_ID );
DECLARE_AP ( NAME_STRING_ID ) ;
caseFillAction ( NAME_STRING_ID )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu NAME_STRING_ID at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_NAME_STRING_ID , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* TARGET_LIST
*/
static vector < TCLEntityId > TargetSlotsList ( 256 ) ;
NLMISC_COMMAND ( displayTargetList , " Display the target list of an entity " , " <entityId> " )
{
if ( args . size ( ) > 1 )
return false ;
CEntityId entity ;
entity . fromString ( args [ 0 ] . c_str ( ) ) ;
CMirrorPropValueList < uint32 > targets ( TheDataset ,
entity ,
" TargetList " ) ;
CMirrorPropValueList < uint32 > : : iterator it ;
it = targets . begin ( ) ;
if ( it ! = targets . end ( ) )
{
const uint32 * effectCycle = & ( ( * it ) ( ) ) ;
log . displayNL ( " TargetStamp: %d " , * effectCycle ) ;
+ + it ;
}
for ( ; it ! = targets . end ( ) ; + + it )
{
uint32 index = ( * it ) ( ) ;
log . displayNL ( " Target: %d " , TDataSetRow : : createFromRawIndex ( index ) . getIndex ( ) ) ;
}
return true ;
}
void fillTARGET_LIST ( TOutBox & outbox , TPropIndex )
{
CClientHost * client = TVPNodeServer : : PrioContext . ClientHost ;
CMirrorPropValueList < uint32 > targets ( TheDataset ,
TVPNodeServer : : PrioContext . EntityIndex ,
DSPropertyTARGET_LIST ) ;
CMirrorPropValueList < uint32 > : : iterator it ;
TargetSlotsList . clear ( ) ;
it = targets . begin ( ) ;
for ( ; it ! = targets . end ( ) ; )
{
TDataSetRow index = TDataSetRow : : createFromRawIndex ( ( * it ) ( ) ) ;
+ + it ;
// check list overflow
if ( it = = targets . end ( ) )
break ;
// distance to target (in 1/127 of 100m)
uint32 dt = * ( & ( ( * it ) ( ) ) ) ;
// translate slot
TCLEntityId slot = client - > IdTranslator . getCEId ( index ) ;
if ( slot ! = INVALID_SLOT )
{
TargetSlotsList . push_back ( slot ) ;
TargetSlotsList . push_back ( ( uint8 ) dt ) ;
}
+ + it ;
}
// serialises branch has payload
bool payLoad = true ;
outbox . serialBitAndLog ( payLoad ) ;
// restricts to 256 entities
uint longListSize = ( uint ) TargetSlotsList . size ( ) ;
if ( longListSize > 32 )
longListSize = 32 ;
uint8 listSize = ( uint8 ) longListSize ;
// serialises short size
outbox . serialAndLog1 ( listSize ) ;
// serialises slot list
if ( listSize > 0 )
outbox . serialBuffer ( & ( TargetSlotsList [ 0 ] ) , listSize ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_TARGET_LIST );
DECLARE_AP ( TARGET_LIST ) ;
ap - > setValue64 ( TheDataset . getChangeTimestamp ( DSPropertyTARGET_LIST , TVPNodeServer : : PrioContext . EntityIndex ) ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu TARGET_LIST at bitpos %d " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_TARGET_LIST , outbox . getPosInBit ( ) ) ;
}
/*
* BARS
*/
void fillBARS ( TOutBox & outbox , TPropIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_BARS );
DECLARE_AP ( BARS ) ;
caseFillAction ( BARS )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu BARS at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_BARS , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* VPA , VPB , VPC
* Assumes :
* - They have the same mirror size
* - There mirror dataset property index is contiguous ( VPC = VPB + 1 = VPA + 2 )
*/
void fillVisualPropertyABC ( TOutBox & outbox , TPropIndex propIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, propIndex );
DECLARE_AP_INDEX ( propIndex ) ;
CMirrorPropValueRO < TYPE_VPA > prop ( TheDataset , TVPNodeServer : : PrioContext . EntityIndex , propIndex - PROPERTY_VPA + DSPropertyVPA ) ; \
ap - > setValue64 ( prop ( ) ) ;
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu %s at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , propIndex , CLFECOMMON : : getPropText ( propIndex ) , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* CONTEXTUAL
*/
void fillCONTEXTUAL ( TOutBox & outbox , TPropIndex propIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_CONTEXTUAL );
DECLARE_AP ( CONTEXTUAL ) ;
caseFillAction ( CONTEXTUAL )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu CONTEXTUAL at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_CONTEXTUAL , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* VISUAL_FX
*/
void fillVISUAL_FX ( TOutBox & outbox , TPropIndex propIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_VISUAL_FX );
DECLARE_AP ( VISUAL_FX ) ;
caseFillAction ( VISUAL_FX )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu VISUAL_FX at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_VISUAL_FX , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* MODE
*/
void fillMODE ( TOutBox & outbox , TPropIndex )
{
// Fill for mode special case
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_MODE );
DECLARE_AP ( MODE ) ;
uint64 modeLong ; // uses 8+4+16+16 = 44 bits
// Mode value (on 8 bits)
CMirrorPropValue < MBEHAV : : TMode > prop ( TheDataset , TVPNodeServer : : PrioContext . EntityIndex , DSPropertyMODE ) ;
// Store in history
ap - > setValue64 ( prop ( ) . RawModeAndParam ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
// Game cycle when mode changed (4 bits -> 1.6 second max)
uint32 tickModeDelta = CTickEventHandler : : getGameCycle ( ) - prop . getTimestamp ( ) ;
if ( tickModeDelta > 15 ) tickModeDelta = 15 ;
// Pack all with position 2D when mode changed, or combat angle (16 bits * 2)
/*
// OBSOLETE: MBEHAV::COMBAT_FLOAT no longer used
if ( prop ( ) . Mode = = MBEHAV : : COMBAT_FLOAT )
{
uint64 theta = ( uint64 ) ( * ( uint32 * ) & ( prop ( ) . Theta ) ) ;
modeLong = ( ( uint64 ) ( prop ( ) . Mode ) ) | ( ( uint64 ) ( tickModeDelta < < 8 ) ) | ( theta < < 12 ) ;
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu MODE at bitpos %d : %u [theta=%g dt=%u] " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_MODE , outbox . getPosInBit ( ) , prop ( ) . Mode , prop ( ) . Theta , tickModeDelta ) ;
}
else
*/
{
uint64 posModeX16 , posModeY16 ;
if ( TVPNodeServer : : PrioContext . PositionAlreadySent )
{
// Take the pos from the mode change
posModeX16 = prop ( ) . Pos . X16 ;
posModeY16 = prop ( ) . Pos . Y16 ;
}
else
{
// Take the current pos
posModeX16 = TVPNodeServer : : PrioContext . Sentity - > X ( ) > > 4 ; // TODO: make a method for this formula
posModeY16 = TVPNodeServer : : PrioContext . Sentity - > Y ( ) > > 4 ;
tickModeDelta = 1 ;
}
modeLong = ( ( uint64 ) ( ( uint8 ) ( prop ( ) . Mode ) ) ) | ( ( uint64 ) ( tickModeDelta < < 8 ) ) | ( posModeX16 < < 12 ) | ( posModeY16 < < 28 ) ;
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu MODE at bitpos %d : %u [x16=%hu y16=%hu dt=%u] %s " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_MODE , outbox . getPosInBit ( ) , prop ( ) . Mode , prop ( ) . Pos . X16 , prop ( ) . Pos . Y16 , tickModeDelta , TVPNodeServer : : PrioContext . PositionAlreadySent ? " " : " WithFirstPos " ) ;
// The pos might be null (if mode set before 1st pos). The client has to handle the case.
/*#ifdef NL_DEBUG
if ( posModeX16 = = 0 | | posModeY16 = = 0 )
nlwarning ( " E%d: The pos16 in the mode is %hu %hu " , TVPNodeServer : : PrioContext . EntityIndex , ( uint16 ) posModeX16 , ( uint16 ) posModeY16 ) ;
# endif* /
}
// Fill
ap - > setAndPackValue ( modeLong , outbox ) ;
//CActionFactory::getInstance()->remove( (CAction*&)act );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* GUILD_NAME_ID
*/
void fillGUILD_NAME_ID ( TOutBox & outbox , TPropIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_GUILD_NAME_ID );
DECLARE_AP ( GUILD_NAME_ID ) ;
caseFillAction ( GUILD_NAME_ID )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu GUILD_NAME_ID at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_GUILD_NAME_ID , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* GUILD_SYMBOL
*/
void fillGUILD_SYMBOL ( TOutBox & outbox , TPropIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_GUILD_SYMBOL );
DECLARE_AP ( GUILD_SYMBOL ) ;
caseFillAction ( GUILD_SYMBOL )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu GUILD_SYMBOL at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_GUILD_SYMBOL , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* EVENT_FACTION_ID
*/
void fillEVENT_FACTION_ID ( TOutBox & outbox , TPropIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_EVENT_FACTION_ID );
DECLARE_AP ( EVENT_FACTION_ID ) ;
caseFillAction ( EVENT_FACTION_ID )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu EVENT_FACTION_ID at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_EVENT_FACTION_ID , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* PVP_MODE
*/
void fillPVP_MODE ( TOutBox & outbox , TPropIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_PVP_MODE );
DECLARE_AP ( PVP_MODE ) ;
caseFillAction ( PVP_MODE )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu PVP_MODE at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_PVP_MODE , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* PVP_CLAN
*/
void fillPVP_CLAN ( TOutBox & outbox , TPropIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_PVP_CLAN );
DECLARE_AP ( PVP_CLAN ) ;
caseFillAction ( PVP_CLAN )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu PVP_CLAN at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_PVP_CLAN , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* OWNER_PEOPLE
*/
void fillOWNER_PEOPLE ( TOutBox & outbox , TPropIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
DECLARE_AP ( OWNER_PEOPLE ) ;
caseFillAction ( OWNER_PEOPLE )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu OWNER_PEOPLE at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_OWNER_PEOPLE , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* OUTPOST_INFOS
*/
void fillOUTPOST_INFOS ( TOutBox & outbox , TPropIndex )
{
bool payloadBit = true ;
outbox . serialBitAndLog ( payloadBit ) ;
DECLARE_AP ( OUTPOST_INFOS ) ;
caseFillAction ( OUTPOST_INFOS )
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu OUTPOST_INFOS at bitpos %d - value % " NL_I64 " u " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , PROPERTY_OUTPOST_INFOS , outbox . getPosInBit ( ) , ap - > getValue ( ) ) ;
ap - > packFast ( outbox ) ;
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
/*
* TARGET_ID , ENTITY_MOUNTED , RIDER_ENTITY
*/
void fillRowProperty ( TOutBox & outbox , TPropIndex propIndex )
{
bool payloadBit = true ;
TCLEntityId slot ;
CMirrorPropValueRO < TDataSetRow > prop ( TheDataset , TVPNodeServer : : PrioContext . EntityIndex , CEntityContainer : : propertyIndexInDataSetToVisualPropIndex ( propIndex ) ) ;
TEntityIndex targetindex ( prop ( ) ) ;
if ( ! targetindex . isValid ( ) )
{
// No target
slot = INVALID_SLOT ;
}
else
{
TEntityIndex seenEntityIndex = TVPNodeServer : : PrioContext . EntityIndex ;
const char * propName = getPropText ( propIndex ) ;
LOG_WHAT_IS_SENT ( " %u: About to send client %hu (%s) the %s '%u --> %u' " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientHost - > clientId ( ) , TVPNodeServer : : PrioContext . ClientHost - > eId ( ) . toString ( ) . c_str ( ) , propName , seenEntityIndex . getIndex ( ) , targetindex . getIndex ( ) ) ;
if ( targetindex = = TVPNodeServer : : PrioContext . ClientHost - > entityIndex ( ) )
{
// The entity targets the client
slot = 0 ;
}
else if ( targetindex = = seenEntityIndex )
{
// The entity targets itself
slot = INVALID_SLOT ;
}
else
{
// Translate CEntityId to slot: get entityid, then slot
TCLEntityId result = TVPNodeServer : : PrioContext . ClientHost - > IdTranslator . getCEId ( targetindex ) ;
if ( result ! = INVALID_SLOT )
{
slot = result ;
}
else
{
LOG_WHAT_IS_SENT ( " %s slot not found: E%u " , propName , targetindex . getIndex ( ) ) ;
payloadBit = false ;
}
}
}
// Fill for property target/mount special case
outbox . serialBitAndLog ( payloadBit ) ;
if ( payloadBit )
{
LOG_WHAT_IS_SENT ( " %u: Filling buffer for C%hu S%hu P%hu %s at bitpos %d - slot %hu " , CTickEventHandler : : getGameCycle ( ) , TVPNodeServer : : PrioContext . ClientId , ( uint16 ) TVPNodeServer : : PrioContext . Slot , propIndex , CLFECOMMON : : getPropText ( propIndex ) , outbox . getPosInBit ( ) , ( uint16 ) slot ) ;
//CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, propIndex );
DECLARE_AP_INDEX ( propIndex ) ;
ap - > setValue64 ( prop ( ) . getIndex ( ) ) ;
// Store the entity index into the history
CFrontEndService : : instance ( ) - > history ( ) - > store ( TVPNodeServer : : PrioContext . ClientId , TVPNodeServer : : PrioContext . ClientHost - > sendNumber ( ) , ap ) ;
// The value that will be sent is the slot, not the entity index
ap - > setAndPackValue ( slot , outbox ) ;
//CActionFactory::getInstance()->remove( (CAction*&)ap );
REMOVE_AP ( ) ;
+ + ( TVPNodeServer : : PrioContext . ClientHost - > NbActionsSentAtCycle ) ;
}
}
TVPNodeServer : : TPrioContext TVPNodeServer : : PrioContext ;
// Flattened Node Tree
TVPNodeServer * TVPNodeServer : : FlatVPTree [ CLFECOMMON : : NB_VISUAL_PROPERTIES ] ;
// Reordered Node tree (used by fastPropagateBackBranchHasPayload())
std : : vector < TVPNodeServer : : CSortedFlatVPTreeItem > TVPNodeServer : : SortedFlatVPTree ;
const bool TVPNodeServer : : FalseBoolPayLoad = false ;
// Reordered Node tree (used by fastFillDiscreetProperties)
std : : vector < TVPNodeServer : : CSortedFlatVPTreeFillItem > TVPNodeServer : : SortedFlatVPTreeFill ;
void TVPNodeServer : : initSortedFlatVPTree ( )
{
if ( isLeaf ( ) )
return ;
CSortedFlatVPTreeItem item ;
item . Node = this ;
if ( a ( ) )
{
item . APayLoad = & ( a ( ) - > BranchHasPayload ) ;
a ( ) - > initSortedFlatVPTree ( ) ;
}
if ( b ( ) )
{
item . BPayLoad = & ( b ( ) - > BranchHasPayload ) ;
b ( ) - > initSortedFlatVPTree ( ) ;
}
SortedFlatVPTree . push_back ( item ) ;
}
void TVPNodeServer : : initSortedFlatVPTreeFill ( )
{
uint thisItem = ( uint ) SortedFlatVPTreeFill . size ( ) ;
SortedFlatVPTreeFill . push_back ( CSortedFlatVPTreeFillItem ( ) ) ;
SortedFlatVPTreeFill [ thisItem ] . Node = this ;
if ( a ( ) ) a ( ) - > initSortedFlatVPTreeFill ( ) ;
if ( b ( ) ) b ( ) - > initSortedFlatVPTreeFill ( ) ;
SortedFlatVPTreeFill [ thisItem ] . NextIfNoPayload = ( uint ) SortedFlatVPTreeFill . size ( ) ;
}
namespace CLFECOMMON
{
// Factory for TVPNodeBase::buildTree()
TVPNodeBase * NewNode ( )
{
return ( TVPNodeBase * ) new TVPNodeServer ( ) ;
}
} ;
# ifdef NL_DEBUG
NLMISC_DYNVARIABLE ( uint32 , MoveNumber , " MoveNumber of entities seen by monitored client " )
{
if ( get )
{
CFrontEndService * fe = CFrontEndService : : instance ( ) ;
//nlassert( fe->MonitoredClient <= MAX_NB_CLIENTS );
CClientHost * client = fe - > receiveSub ( ) - > clientIdCont ( ) [ fe - > MonitoredClient ] ;
if ( client )
{
* pointer = client - > MoveNumber ;
}
else
{
* pointer = 9999 ;
}
}
}
# endif
NLMISC_COMMAND ( verbosePropertiesSent , " Turn on or off or check the state of verbose logging of what is sent " , " <clientId> | all | off " )
{
if ( args . size ( ) > 1 )
return false ;
if ( args . size ( ) = = 1 )
{
if ( args [ 0 ] = = string ( " all " ) )
verbosePropertiesSent = 0 ;
else if ( args [ 0 ] = = string ( " off " ) )
verbosePropertiesSent = INVALID_CLIENT ;
else
NLMISC : : fromString ( args [ 0 ] , verbosePropertiesSent ) ;
}
log . displayNL ( " verbosePropertiesSent is %s " , ( verbosePropertiesSent = = INVALID_CLIENT ) ? " off " : ( ( verbosePropertiesSent = = 0 ) ? " all " : toString ( " C%hu " , verbosePropertiesSent ) . c_str ( ) ) ) ;
return true ;
}