1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "game_share/action_factory.h"
24 #include "game_share/action_position.h"
25 #include "game_share/action_sint64.h"
26 #include "game_share/mode_and_behaviour.h"
27 #include "game_share/entity_types.h"
28 #include "distance_prioritizer.h"
29 #include "client_host.h"
30 #include "vision_provider.h"
32 #include <nel/misc/command.h>
33 #include "frontend_service.h"
34 #ifdef TEST_LOST_PACKET
35 #include <nel/misc/variable.h>
39 using namespace CLFECOMMON
;
40 using namespace NLMISC
;
41 using namespace NLNET
;
44 // Test feature to simulate a lost packet when sending a new sheet. Works with 1 client only.
45 #ifdef TEST_LOST_PACKET
46 CVariable
<bool> TestPacketLost( "test", "TestPacketLost", "", true, 0, 1 );
47 TGameCycle TestPacketLostTimer
= 0;
48 TCLEntityId TestPacketLostSlot
= 0;
51 TClientId verbosePropertiesSent
= INVALID_CLIENT
;
53 // TODO-Minimal visual bandwith
54 /*sint32 NbMinimalVisualBits;
56 void cbNbMinimalVisualBytesChanged( IVariable& var );
58 CVariable<sint32> NbMinimalVisualBytes( "fe", "NbMinimalVisualBytes", "Min number of bytes for vision per msg", 50, 0, true, cbNbMinimalVisualBytesChanged, true );
60 void cbNbMinimalVisualBytesChanged( IVariable& var )
62 NbMinimalVisualBits = NbMinimalVisualBytes.get() * 8;
67 void CDistancePrioritizer::init( CVisionArray
*va
, CVisionProvider
*vp
, CHistory
*hy
)
74 for ( sint i
=0; i
!=NB_VISUAL_PROPERTIES
; ++i
)
75 _DistThresholdTable
[i
] = -1;
77 _VisualPropertyTreeRoot
= (TVPNodeServer
*)NewNode();
78 sint nbProp
= _VisualPropertyTreeRoot
->buildTree();
80 // Check that the last property matches the number of properties-1
81 if ( nbProp
!= NB_VISUAL_PROPERTIES
)
83 nlwarning( "Found %hu properties in the sheets, the prioritizer knows %hu properties", NB_VISUAL_PROPERTIES
, nbProp
);
86 // Init distance thresholds
87 CLFECOMMON::initThresholdTable( _DistThresholdTable
);
92 * Calculate the priorities
94 void CDistancePrioritizer::calculatePriorities()
97 if ( SortSpreader
.mustProcessNow() )
99 THostMap::iterator icm
;
100 sint clientmapindex
, outerBoundIndex
;
101 SortSpreader
.getProcessingBounds( icm
, clientmapindex
, outerBoundIndex
);
103 while ( clientmapindex
< outerBoundIndex
)
105 CClientHost
*clienthost
= GETCLIENTA(icm
);
107 // Prioritize only at the opposite time of sending for a particular client
108 if ( ! clienthost
->whenToSend() )
111 updatePriorityOfEntitiesSeenByClient( clienthost
->clientId() );
113 // Sort entities by decreasing priority
114 sortEntitiesOfClient( clienthost
->clientId() );
121 SortSpreader
.endProcessing( icm
);
123 SortSpreader
.incCycle();
127 #define arbitrateDiscreetProperty( name ) \
128 get##name##node()->BranchHasPayload = entityIsWithinDistanceThreshold( PROPERTY_##name ) && discreetPropertyHasChanged( PROPERTY_##name, (TYPE_##name*)NULL )
130 #define arbitrateDiscreetPropertyWithoutThreshold( name ) \
131 get##name##node()->BranchHasPayload = discreetPropertyHasChanged( PROPERTY_##name, (TYPE_##name*)NULL )
133 #define arbitrateTargetList( name ) \
134 get##name##node()->BranchHasPayload = targetListHasChanged( PROPERTY_##name, (TYPE_##name*)NULL )
137 #ifdef STORE_MIRROR_VP_IN_CLASS
139 #define arbitrateDiscreetProperty( entry, name ) \
140 GET_VP_NODE(name)->BranchHasPayload = \
141 entityIsWithinDistanceThreshold( PROPERTY_##name ) \
142 && discreetPropertyHasChanged( entry.Properties[PROPERTY_##name], sentity->VP_##name, PROPERTY_##name, (TYPE_##name*)NULL )
144 #define arbitrateDiscreetPropertyWithoutThreshold( entry, name ) \
145 GET_VP_NODE(name)->BranchHasPayload = \
146 discreetPropertyHasChanged( entry.Properties[PROPERTY_##name], sentity->VP_##name, PROPERTY_##name, (TYPE_##name*)NULL )
148 #else // STORE_MIRROR_VP_IN_CLASS
150 #define arbitrateDiscreetProperty( entry, name ) \
151 GET_VP_NODE(name)->BranchHasPayload = \
152 entityIsWithinDistanceThreshold( PROPERTY_##name ) \
153 && discreetPropertyHasChanged( entry.Properties[PROPERTY_##name], PROPERTY_##name, (TYPE_##name*)NULL )
155 #define arbitrateDiscreetPropertyWithoutThreshold( entry, name ) \
156 GET_VP_NODE(name)->BranchHasPayload = \
157 discreetPropertyHasChanged( entry.Properties[PROPERTY_##name], PROPERTY_##name, (TYPE_##name*)NULL )
159 #define arbitrateTargetList( entry, name ) \
161 #endif // STORE_MIRROR_VP_IN_CLASS
164 #define arbitrateNeverSendProperty( name ) \
165 GET_VP_NODE(name)->BranchHasPayload = false
167 #define arbitrateTargetList( entry, name ) \
168 GET_VP_NODE(name)->BranchHasPayload = \
169 targetListHasChanged( entry.Properties[PROPERTY_##name], PROPERTY_##name, (TYPE_##name*)NULL )
172 #define DECLARE_AP(name) CActionSint64 *ap = CActionFactory::getInstance()->getVolatilePropAction( TVPNodeServer::PrioContext.Slot, PROPERTY_##name )
173 #define DECLARE_AP_INDEX(index) CActionSint64 *ap = CActionFactory::getInstance()->getVolatilePropAction( TVPNodeServer::PrioContext.Slot, index )
177 #define DECLARE_AP(name) CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_##name )
178 #define DECLARE_AP_INDEX(index) CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, index )
179 #define REMOVE_AP() CActionFactory::getInstance()->remove( (CAction*&)ap )
186 void CDistancePrioritizer::fillOutBox( CClientHost
& client
, TOutBox
& outbox
)
190 TClientId clientId
= client
.clientId();
191 initDispatchingCycle( clientId
);
193 client
.MoveNumber
= 0;
196 if (!client
.entityIndex().isValid())
199 // initialize common context part
200 TVPNodeServer::PrioContext
.Prioritizer
= this;
201 TVPNodeServer::PrioContext
.ClientHost
= &client
;
202 TVPNodeServer::PrioContext
.ClientId
= clientId
;
203 CMirrorPropValueRO
<TYPE_TARGET_ID
> targetIndexOfClient( TheDataset
, client
.entityIndex(), DSPropertyTARGET_ID
);
205 // TODO-Minimal visual bandwith
206 /*sint32 initialPosInBit = outbox.getPosInBit();*/
207 sint32 currentPosInBit
;
210 currentPosInBit
= outbox
.getPosInBit();
212 // Browse the seen entities, sorted by distance
213 TCLEntityId slot
= getNextEntityToStudy( clientId
);
214 if ( slot
== INVALID_SLOT
)
216 // Exit when all the pairs have been successfully filled
217 #ifdef TEST_LOST_PACKET
218 if ( (TestPacketLostTimer
!=0) && (CTickEventHandler::getGameCycle() >= TestPacketLostTimer
) )
220 nldebug( "Negative ack for %hu %hu", client
.clientId(), TestPacketLostSlot
);
221 _History
->_PacketHistory
.negativeAck( client
.clientId(), TestPacketLostSlot
, PROPERTY_SHEET
, 0 );
222 TestPacketLostTimer
= 0;
228 // TODO-Minimal visual bandwith
229 // Always allow to write a minimal amount of visual properties
230 /*if ( currentPosInBit - initialPosInBit >= NbMinimalVisualBits )*/
232 // Don't fill if the free space is lower than 32 bits (checked once per pair, not once per property)
233 if ( currentPosInBit
+ 32 > client
.getCurrentThrottle() )
235 // Exit when the size limit has been reached before all the pairs have been filled
237 uint nbRemainingPairs
= (uint
)_PrioritizedEntitiesByClient
[clientId
].size() - _CurrentEntitiesToStudy
[clientId
];
238 if ( nbRemainingPairs
> 0 )
239 LOG_WHAT_IS_SENT( "%u: C%hu S%hu: %u pairs remaining", CTickEventHandler::getGameCycle(), clientId
, (uint16
)slot
, nbRemainingPairs
);
240 LOG_WHAT_IS_SENT( "C%hu: outbox full (%d bits)", clientId
, currentPosInBit
);
242 #ifdef TEST_LOST_PACKET
243 if ( (TestPacketLostTimer
!=0) && (CTickEventHandler::getGameCycle() >= TestPacketLostTimer
) )
245 nldebug( "Negative ack for %hu %hu", client
.clientId(), TestPacketLostSlot
);
246 _History
->_PacketHistory
.negativeAck( client
.clientId(), TestPacketLostSlot
, PROPERTY_SHEET
, 0 );
247 TestPacketLostTimer
= 0;
254 // Get the entity corresponding to the client/slot pair
255 TPairState
& pairState
= _VisionArray
->getPairState( clientId
, slot
);
256 CEntity
* sentity
= NULL
;
258 TEntityIndex entityIndex
= pairState
.EntityIndex
;
259 TVPNodeServer::PrioContext
.EntityIndex
= entityIndex
;
261 if ( entityIndex
.isValid() )
262 sentity
= TheEntityContainer
->getEntity( entityIndex
);
264 if ( pairState
.associationSuppressed() )
266 // Pure unassociation case: we must send an empty block
267 serialSlotHeader( client
, NULL
, pairState
, slot
, outbox
);
269 outbox
.serialAndLog2( bits
, 2 ); // 2 bits for pos & other properties
270 //nldebug( "Pure unassociation of C%hu S%hu", clientId, (uint16)slot );
272 // The first time, sentity is non-null. If this is a resending (after a neg-ack), it's null.
274 _VisionProvider
->postRemovePair( clientId
, slot
);
278 if ( sentity
== NULL
)
281 H_BEFORE(OneSlotArbitrate
)
283 H_BEFORE(OneSlotArbitrateInit
)
285 // Initialize the context
286 TVPNodeServer::PrioContext
.Slot
= slot
;
287 TVPNodeServer::PrioContext
.EntityIndex
= entityIndex
;
288 TVPNodeServer::PrioContext
.Sentity
= sentity
;
289 //TVPNodeServer::PrioContext.PairState = &pairState;
290 TVPNodeServer::PrioContext
.DistanceCE
= pairState
.DistanceCE
;
291 TVPNodeServer::PrioContext
.Timestamp
= 0;
292 TVPNodeServer::PrioContext
.IsTarget
= (targetIndexOfClient() == entityIndex
);
293 TVPNodeServer::PrioContext
.PositionAlreadySent
= (_History
->getMileage( clientId
, slot
) != 0);
294 TVPNodeServer::PrioContext
.ZCache
= sentity
->z(entityIndex
); // setup Z cache for all later mirror access to entity->z()
296 const CPropertyHistory::CEntityEntry
& entry
= _History
->getEntityEntry(TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.Slot
);
299 //nlinfo( "Preparing a block to client %hu (%s) for slot %hu", clientId, client.eId().toString().c_str(), (uint16)slot );
301 // Continuous properties
302 uint8 seenEntityType
= TheDataset
.getEntityId( entityIndex
).getType();
304 H_AFTER(OneSlotArbitrateInit
)
306 bool thetaIntMode
= false;
308 // Arbitrate all discreet properties
309 switch (seenEntityType
)
312 arbitrateAllDiscreetProperties(entry
);
316 arbitrateNPCDiscreetProperties(entry
);
319 case RYZOMID::creature
:
320 arbitrateCreatureDiscreetProperties(entry
);
323 case RYZOMID::forageSource
:
324 arbitrateForageSourceDiscreetProperties(entry
);
331 H_BEFORE(OneSlotArbitratePropagate
)
333 // Propagate back BranchHasPayload flags
334 //_VisualPropertyTreeRoot->propagateBackBranchHasPayload();
335 TVPNodeServer::fastPropagateBackBranchHasPayload();
337 H_AFTER(OneSlotArbitratePropagate
)
339 H_AFTER(OneSlotArbitrate
)
341 // ******** Fill the buffer with the properties ********
344 if ( _VisualPropertyTreeRoot
->BranchHasPayload
)
348 //nldebug( "Filling for C%hu, pass %u, BEFORE HEADER: bitpos: %d", clientId, ++i, outbox.getPosInBit() );
349 //nlinfo( "C%hu S%hu AB%hu", clientId, (uint16)slot, (uint32)pairState.AssociationChangeBits );
350 serialSlotHeader( client
, sentity
, pairState
, slot
, outbox
);
352 //nldebug( "AFTER HEADER: pos: %d", outbox.getPosInBit() );
354 // Fill the position if required
355 //TVPNodeServer *currentNode = _VisualPropertyTreeRoot;
357 outbox
.serialBitAndLog( GET_VP_NODE(POSITION
)->BranchHasPayload
);
358 if ( GET_VP_NODE(POSITION
)->BranchHasPayload
)
360 //CActionPosition *ap = (CActionPosition*)(CActionFactory::getInstance()->createByPropIndex( slot, PROPERTY_POSITION ));
361 //ap->PropertyCode = PROPERTY_POSITION;
362 CActionPosition
* ap
= CActionFactory::getInstance()->getVolatilePositionAction(slot
);
364 // When the mode is transmitted or the entity is not in local mode (first bit of Z), transmit the *absolute* position
365 if ( (! (TVPNodeServer::PrioContext
.ZCache
& 0x1)) ||
366 (GET_VP_NODE(POSITION
)->BranchHasPayload
&& GET_VP_NODE(MODE
)->BranchHasPayload
) )
368 ap
->Position
[0] = sentity
->X();
369 ap
->Position
[1] = sentity
->Y();
370 //ap->Position[2] = sentity->z( entityIndex );
371 ap
->Position
[2] = TVPNodeServer::PrioContext
.ZCache
;
372 ap
->IsRelative
= false;
373 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
) );
377 CMirrorPropValueRO
<sint32
> propLX( TheDataset
, entityIndex
, DSPropertyLocalX
);
378 CMirrorPropValueRO
<sint32
> propLY( TheDataset
, entityIndex
, DSPropertyLocalY
);
379 CMirrorPropValueRO
<sint32
> propLZ( TheDataset
, entityIndex
, DSPropertyLocalZ
);
380 ap
->Position
[0] = propLX();
381 ap
->Position
[1] = propLY();
382 ap
->Position
[2] = propLZ();
383 ap
->IsRelative
= true;
384 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] );
387 CActionFactory::getInstance()->packFast( ap
, outbox
);
388 _History
->storePosition( clientId
, client
.sendNumber(), ap
, sentity
->Mileage
, TVPNodeServer::PrioContext
.IsTarget
, TVPNodeServer::PrioContext
.Timestamp
);
389 //CActionFactory::getInstance()->remove( (CAction*&)ap );
390 ++client
.NbActionsSentAtCycle
;
393 // Fill the orientation if required
394 //currentNode = currentNode->B;
395 TVPNodeServer
*currentNode
= _VisualPropertyTreeRoot
->B
;
397 outbox
.serialBitAndLog( currentNode
->BranchHasPayload
);
398 if ( currentNode
->BranchHasPayload
)
400 outbox
.serialBitAndLog( currentNode
->A
->BranchHasPayload
);
401 if ( currentNode
->A
->BranchHasPayload
)
403 //CActionSint64 *ap = (CActionSint64*)(CActionFactory::getInstance()->createByPropIndex( slot, PROPERTY_ORIENTATION ));
404 //ap->PropertyCode = PROPERTY_ORIENTATION; // useless: already set by createByPropIndex
405 DECLARE_AP(ORIENTATION
);
407 CMirrorPropValueRO
<float> prop( TheDataset
, entityIndex
, DSPropertyORIENTATION
);
408 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() );
410 uint32 value
= ( thetaIntMode
? (uint32
)(prop()) : *((uint32
*)&(prop())) );
412 ap
->setAndPackValue( value
, outbox
);
413 _History
->store( clientId
, client
.sendNumber(), ap
);
415 // TODO: send less bits for forage source entity
417 //CActionFactory::getInstance()->remove( (CAction*&)ap );
420 ++client
.NbActionsSentAtCycle
;
423 // Fill the required discreet properties if required
424 currentNode
->B
->fillDiscreetProperties( outbox
);
425 //nlinfo("end fill");
426 //TVPNodeServer::fastFillDiscreetProperties( outbox );
427 //nlinfo("end fastfill");
432 if ( _VisualPropertyTreeRoot
->A
->BranchHasPayload
)
434 //CClientEntityIdTranslator::CEntityInfo& info = client.IdTranslator.getInfo( slot ); // CHANGED BEN
435 //if ( info.AssociationState == CClientEntityIdTranslator::CEntityInfo::AwaitingAssAck ) // CHANGED BEN
436 if ( _VisionArray
->getAssociationState(clientId
, slot
) == TPairState::AwaitingAssAck
)
438 nlwarning( "C%hu S%hu: Sending position but sheet id not sent", clientId
, (uint16
)slot
);
439 client
.displaySlotProperties( slot
);
443 //if ( (verbosePropertiesSent==9999) || (verbosePropertiesSent==TVPNodeServer::PrioContext.ClientId) )
445 // nldebug( "To C%hu", clientId );
446 // outbox.displayStream();
450 // ******** End of iteration ********
451 //_VisualPropertyTreeRoot->displayStatesOfTreeLeaves();
452 //nldebug( "C%hu S%hu: end of pair block at bitpos %d", clientId, (uint16)slot, outbox.getPosInBit() );
455 // Reset the priority of the pair, even if nothing was filled
457 pairState
.resetPrio(); // note: nothing can remain to be filled, as we allow to exceed the size limit
463 * Test the criterion for the position of the entity 'slot' seen by 'clientId'
465 bool CDistancePrioritizer::positionHasChangedEnough()
467 // TEMP: do not send if local mode (because the local position is useless for the mektoub)
468 if ( TVPNodeServer::PrioContext
.ZCache
& 0x1 )
471 uint32 lastSentMileage
= _History
->getMileage( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.Slot
);
472 if ( lastSentMileage
!= 0 )
474 // Calculate difference distance between current and lastsent mileage (unsigned to allow mileage overflow)
475 if ( (TVPNodeServer::PrioContext
.Sentity
->Mileage
- lastSentMileage
) * _DistanceDeltaRatio
> (uint32
)(TVPNodeServer::PrioContext
.DistanceCE
) )
478 ++(TVPNodeServer::PrioContext
.ClientHost
->MoveNumber
);
484 if (verbosePropertiesSent
==0)
486 nldebug("Ignoring move: Mileage=%u, lastSentMileage=%u, _DistanceDeltaRatio=%u, DistanceCE=%u",
487 (uint32
) TVPNodeServer::PrioContext
.Sentity
->Mileage
,
488 (uint32
) lastSentMileage
,
489 (uint32
) _DistanceDeltaRatio
,
490 (uint32
) TVPNodeServer::PrioContext
.DistanceCE
);
504 * Test the criterion for thetaIntMode
506 bool CDistancePrioritizer::thetaIntModehasChanged(const CPropertyHistory::CPropertyEntry
& entry
)
508 if ( ! entityIsWithinDistanceThreshold( PROPERTY_ORIENTATION
) )
511 if ( entry
.HasValue
)
513 CMirrorPropValueRO
<float> currentTheta( TheDataset
, TVPNodeServer::PrioContext
.EntityIndex
, DSPropertyORIENTATION
);
514 return ( (uint32
)currentTheta
!= (uint32
)entry
.LastSent
);
518 return TVPNodeServer::PrioContext
.Sentity
->propertyIsInitialized( PROPERTY_ORIENTATION
, DSPropertyORIENTATION
, TVPNodeServer::PrioContext
.EntityIndex
, (TYPE_ORIENTATION
*)NULL
);
524 * Test the criterion for the orientation of the entity 'slot' seen by 'clientId' + initialized
526 bool CDistancePrioritizer::orientationHasChangedEnough(const CPropertyHistory::CPropertyEntry
& entry
, float angleRatio
)
528 if ( ! entityIsWithinDistanceThreshold( PROPERTY_ORIENTATION
) )
531 if ( entry
.HasValue
)
533 CMirrorPropValueRO
<float> currentAngle( TheDataset
, TVPNodeServer::PrioContext
.EntityIndex
, DSPropertyORIENTATION
);
536 // Orientation is a float angle in radian
537 const float& oldangle = *((float*)&(entry.LastSent));
538 float deltaAngle = (float)fabs( (float)(currentAngle() - oldangle) );
539 deltaAngle = (float)fmod( deltaAngle+(2*Pi), (2*Pi) );
541 //nldebug( "getDelta(theta) : dA=%g", deltaAngle );
542 return ( deltaAngle > (float)Pi/angleRatio ); // the orientation is useful only when the pos does not change
546 entry
.getValue(oldangle
);
547 float deltaAngle
= (float)( Pi
- fabs(fmod(currentAngle()-oldangle
+4*Pi
, 2*Pi
)-Pi
) ); // deltaAngle is in [0, 2*Pi]
549 //nldebug( "getDelta(theta) : dA=%g", deltaAngle );
550 return ( deltaAngle
*angleRatio
> (float)Pi
); // the orientation is useful only when the pos does not change
555 // 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)
562 * Test the criterion for the specified property of the entity 'slot' seen by 'clientId'
564 inline bool CDistancePrioritizer::entityIsWithinDistanceThreshold( TPropIndex propIndex
)
566 // Compare distance with the threshold
567 //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 ) );
568 return ( TVPNodeServer::PrioContext
.DistanceCE
< getDistThreshold( propIndex
) );
572 * Special arbitrate case for BEHAVIOUR property
573 * Threshold in this case should be the same than the target list threshold when
574 * the behaviour is a range attack or projectile behaviour
579 void CDistancePrioritizer::arbitrateDiscreetBehaviourProperty(const CPropertyHistory::CEntityEntry
& entry
, CEntity
* sentity
)
581 #ifdef STORE_MIRROR_VP_IN_CLASS
582 const CMirrorPropValueRO
<TYPE_BEHAVIOUR
>& propBehav
= sentity
->VP_BEHAVIOUR
;
584 CMirrorPropValueRO
<TYPE_BEHAVIOUR
> propBehav( TheDataset
, TVPNodeServer::PrioContext
.EntityIndex
, DSPropertyBEHAVIOUR
);
586 if (!discreetPropertyHasChanged( entry
.Properties
[PROPERTY_BEHAVIOUR
], propBehav
, PROPERTY_BEHAVIOUR
, (TYPE_BEHAVIOUR
*)NULL
))
588 GET_VP_NODE(BEHAVIOUR
)->BranchHasPayload
= false;
591 const MBEHAV::CBehaviour
&behav
= propBehav();
592 TPropIndex refDistanceProperty
;
593 switch(behav
.Behaviour
)
595 case MBEHAV::CAST_OFF_SUCCESS
:
596 refDistanceProperty
= PROPERTY_TARGET_LIST
;
598 case MBEHAV::CAST_OFF_LINK
:
599 refDistanceProperty
= PROPERTY_TARGET_LIST
;
601 case MBEHAV::CAST_CUR_SUCCESS
:
602 refDistanceProperty
= PROPERTY_TARGET_LIST
;
604 case MBEHAV::CAST_CUR_LINK
:
605 refDistanceProperty
= PROPERTY_TARGET_LIST
;
607 case MBEHAV::CAST_MIX_SUCCESS
:
608 refDistanceProperty
= PROPERTY_TARGET_LIST
;
610 case MBEHAV::CAST_MIX_LINK
:
611 refDistanceProperty
= PROPERTY_TARGET_LIST
;
613 case MBEHAV::RANGE_ATTACK
:
614 refDistanceProperty
= PROPERTY_TARGET_LIST
;
616 case MBEHAV::CAST_ACID
:
617 refDistanceProperty
= PROPERTY_TARGET_LIST
;
619 case MBEHAV::CAST_BLIND
:
620 refDistanceProperty
= PROPERTY_TARGET_LIST
;
622 case MBEHAV::CAST_COLD
:
623 refDistanceProperty
= PROPERTY_TARGET_LIST
;
625 case MBEHAV::CAST_ELEC
:
626 refDistanceProperty
= PROPERTY_TARGET_LIST
;
628 case MBEHAV::CAST_FEAR
:
629 refDistanceProperty
= PROPERTY_TARGET_LIST
;
631 case MBEHAV::CAST_FIRE
:
632 refDistanceProperty
= PROPERTY_TARGET_LIST
;
634 case MBEHAV::CAST_HEALHP
:
635 refDistanceProperty
= PROPERTY_TARGET_LIST
;
637 case MBEHAV::CAST_MAD
:
638 refDistanceProperty
= PROPERTY_TARGET_LIST
;
640 case MBEHAV::CAST_POISON
:
641 refDistanceProperty
= PROPERTY_TARGET_LIST
;
643 case MBEHAV::CAST_ROOT
:
644 refDistanceProperty
= PROPERTY_TARGET_LIST
;
646 case MBEHAV::CAST_ROT
:
647 refDistanceProperty
= PROPERTY_TARGET_LIST
;
649 case MBEHAV::CAST_SHOCK
:
650 refDistanceProperty
= PROPERTY_TARGET_LIST
;
652 case MBEHAV::CAST_SLEEP
:
653 refDistanceProperty
= PROPERTY_TARGET_LIST
;
655 case MBEHAV::CAST_SLOW
:
656 refDistanceProperty
= PROPERTY_TARGET_LIST
;
658 case MBEHAV::CAST_STUN
:
659 refDistanceProperty
= PROPERTY_TARGET_LIST
; // valid distance should be the same than the target list
660 // because target list and behaviour are sent together
663 refDistanceProperty
= PROPERTY_BEHAVIOUR
;
667 GET_VP_NODE(BEHAVIOUR
)->BranchHasPayload
= entityIsWithinDistanceThreshold(refDistanceProperty
);
672 * Fill the BranchHasPayload flags of the tree, using the rules deciding if a discreet property need to be sent
674 void CDistancePrioritizer::arbitrateAllDiscreetProperties(const CPropertyHistory::CEntityEntry
& entry
)
676 H_AUTO(arbitrateAllDiscreetProperties
);
678 CEntity
* sentity
= TVPNodeServer::PrioContext
.Sentity
;
680 arbitrateDiscreetPropertyWithoutThreshold( entry
, SHEET
);
681 arbitrateDiscreetBehaviourProperty( entry
, sentity
);
683 // Don't limit to the distance threshold when triggering sending of the name of the target
684 if ( TVPNodeServer::PrioContext
.IsTarget
)
685 arbitrateDiscreetPropertyWithoutThreshold( entry
, NAME_STRING_ID
);
687 arbitrateDiscreetProperty( entry
, NAME_STRING_ID
);
689 //arbitrateDiscreetProperty( entry, TARGET_ID ); // now done in fillOutBox() in "mode switch"
690 arbitrateDiscreetProperty( entry
, CONTEXTUAL
);
691 arbitrateDiscreetPropertyWithoutThreshold( entry
, MODE
);
692 arbitrateDiscreetProperty( entry
, VPA
);
693 arbitrateDiscreetProperty( entry
, VPB
);
694 arbitrateDiscreetProperty( entry
, VPC
);
695 arbitrateDiscreetPropertyWithoutThreshold( entry
, ENTITY_MOUNTED_ID
);
696 arbitrateDiscreetPropertyWithoutThreshold( entry
, RIDER_ENTITY_ID
);
698 arbitrateTargetList( entry
, TARGET_LIST
);
699 arbitrateDiscreetProperty( entry
, VISUAL_FX
);
701 arbitrateDiscreetProperty( entry
, GUILD_SYMBOL
);
702 arbitrateDiscreetProperty( entry
, GUILD_NAME_ID
);
703 arbitrateDiscreetProperty( entry
, EVENT_FACTION_ID
);
704 arbitrateDiscreetProperty( entry
, PVP_MODE
);
705 arbitrateDiscreetProperty( entry
, PVP_CLAN
);
706 arbitrateNeverSendProperty( OWNER_PEOPLE
);
707 arbitrateDiscreetProperty( entry
, OUTPOST_INFOS
);
709 if (TVPNodeServer::PrioContext
.Slot
!= 0)
711 arbitrateCommonPosAndMode(entry
);
712 arbitrateDiscreetProperty( entry
, TARGET_ID
);
713 arbitrateDiscreetProperty( entry
, BARS
);
717 arbitrateSlot0PosAndMode(entry
);
718 arbitrateDiscreetPropertyWithoutThreshold( entry
, TARGET_ID
); // no need of threshold
719 // never send BARS for User Player (no need since sent with the USER:BARS message)
720 arbitrateNeverSendProperty( BARS
);
725 * Fill the BranchHasPayload flags of the tree, using the rules deciding if a discreet property need to be sent
727 void CDistancePrioritizer::arbitrateNPCDiscreetProperties(const CPropertyHistory::CEntityEntry
& entry
)
729 H_AUTO(arbitrateNPCDiscreetProperties
);
731 CEntity
* sentity
= TVPNodeServer::PrioContext
.Sentity
;
733 arbitrateDiscreetPropertyWithoutThreshold( entry
, SHEET
);
734 arbitrateDiscreetBehaviourProperty(entry
, sentity
);
736 // Don't limit to the distance threshold when triggering sending of the name of the target
737 if ( TVPNodeServer::PrioContext
.IsTarget
)
738 arbitrateDiscreetPropertyWithoutThreshold( entry
, NAME_STRING_ID
);
740 arbitrateDiscreetProperty( entry
, NAME_STRING_ID
);
742 arbitrateDiscreetProperty( entry
, TARGET_ID
); // NPC can never be in Slot 0
744 // Specific distance for NPCs' contextual property
745 GET_VP_NODE(CONTEXTUAL
)->BranchHasPayload
=
746 TVPNodeServer::PrioContext
.DistanceCE
< THRESHOLD_CONTEXTUAL_NPC
747 && discreetPropertyHasChanged( entry
.Properties
[PROPERTY_CONTEXTUAL
], sentity
->VP_CONTEXTUAL
, PROPERTY_CONTEXTUAL
, (TYPE_CONTEXTUAL
*)NULL
);
749 arbitrateDiscreetPropertyWithoutThreshold( entry
, MODE
);
750 arbitrateDiscreetProperty( entry
, BARS
);
751 arbitrateDiscreetProperty( entry
, VPA
);
752 arbitrateDiscreetProperty( entry
, VPB
);
753 arbitrateDiscreetProperty( entry
, VPC
);
755 arbitrateDiscreetPropertyWithoutThreshold( entry
, ENTITY_MOUNTED_ID
);
757 arbitrateNeverSendProperty( RIDER_ENTITY_ID
);
759 arbitrateTargetList( entry
, TARGET_LIST
);
760 arbitrateDiscreetProperty( entry
, VISUAL_FX
);
761 arbitrateDiscreetProperty( entry
, GUILD_SYMBOL
);
762 arbitrateDiscreetProperty( entry
, GUILD_NAME_ID
);
763 arbitrateNeverSendProperty( EVENT_FACTION_ID
);
764 arbitrateNeverSendProperty( PVP_MODE
);
765 arbitrateNeverSendProperty( PVP_CLAN
);
766 arbitrateNeverSendProperty( OWNER_PEOPLE
);
767 arbitrateDiscreetProperty( entry
, OUTPOST_INFOS
);
769 arbitrateCommonPosAndMode(entry
);
773 * Fill the BranchHasPayload flags of the tree, using the rules deciding if a discreet property need to be sent
775 void CDistancePrioritizer::arbitrateCreatureDiscreetProperties(const CPropertyHistory::CEntityEntry
& entry
)
777 H_AUTO(arbitrateCreatureDiscreetProperties
);
779 CEntity
* sentity
= TVPNodeServer::PrioContext
.Sentity
;
781 arbitrateDiscreetPropertyWithoutThreshold( entry
, SHEET
);
782 arbitrateDiscreetBehaviourProperty(entry
, sentity
);
784 // Don't limit to the distance threshold when triggering sending of the name of the target
785 if ( TVPNodeServer::PrioContext
.IsTarget
)
786 arbitrateDiscreetPropertyWithoutThreshold( entry
, NAME_STRING_ID
);
788 arbitrateDiscreetProperty( entry
, NAME_STRING_ID
);
790 arbitrateDiscreetProperty( entry
, TARGET_ID
); // Creature can never be in Slot 0
791 arbitrateDiscreetProperty( entry
, CONTEXTUAL
);
792 arbitrateDiscreetPropertyWithoutThreshold( entry
, MODE
);
793 arbitrateDiscreetProperty( entry
, BARS
);
795 arbitrateNeverSendProperty( VPA
);
796 arbitrateDiscreetProperty( entry
, VPB
);
797 arbitrateNeverSendProperty( VPC
);
798 arbitrateNeverSendProperty( ENTITY_MOUNTED_ID
);
800 arbitrateDiscreetPropertyWithoutThreshold( entry
, RIDER_ENTITY_ID
);
801 arbitrateTargetList( entry
, TARGET_LIST
);
803 arbitrateNeverSendProperty( VISUAL_FX
);
804 arbitrateNeverSendProperty( GUILD_SYMBOL
);
805 arbitrateNeverSendProperty( GUILD_NAME_ID
);
806 arbitrateNeverSendProperty( EVENT_FACTION_ID
);
807 arbitrateNeverSendProperty( PVP_MODE
);
808 arbitrateNeverSendProperty( PVP_CLAN
);
809 arbitrateDiscreetProperty( entry
, OWNER_PEOPLE
);
810 arbitrateNeverSendProperty( OUTPOST_INFOS
);
812 arbitrateCommonPosAndMode(entry
);
816 * Fill the BranchHasPayload flags of the tree, using the rules deciding if a discreet property need to be sent
818 void CDistancePrioritizer::arbitrateForageSourceDiscreetProperties(const CPropertyHistory::CEntityEntry
& entry
)
820 H_AUTO(arbitrateForageSourceDiscreetProperties
);
822 CEntity
* sentity
= TVPNodeServer::PrioContext
.Sentity
;
824 arbitrateDiscreetPropertyWithoutThreshold( entry
, SHEET
);
825 arbitrateNeverSendProperty( BEHAVIOUR
);
827 arbitrateDiscreetProperty( entry
, NAME_STRING_ID
);
829 arbitrateDiscreetProperty( entry
, TARGET_ID
); // ForageSource can never be in Slot 0
830 arbitrateDiscreetProperty( entry
, CONTEXTUAL
);
832 arbitrateNeverSendProperty( MODE
);
834 arbitrateDiscreetProperty( entry
, BARS
);
836 arbitrateNeverSendProperty( VPA
);
837 arbitrateNeverSendProperty( VPB
);
838 arbitrateNeverSendProperty( VPC
);
839 arbitrateNeverSendProperty( ENTITY_MOUNTED_ID
);
840 arbitrateNeverSendProperty( RIDER_ENTITY_ID
);
842 arbitrateTargetList( entry
, TARGET_LIST
);
843 arbitrateDiscreetProperty( entry
, VISUAL_FX
);
845 arbitrateNeverSendProperty( GUILD_SYMBOL
);
846 arbitrateNeverSendProperty( GUILD_NAME_ID
);
847 arbitrateNeverSendProperty( EVENT_FACTION_ID
);
848 arbitrateNeverSendProperty( PVP_MODE
);
849 arbitrateNeverSendProperty( PVP_CLAN
);
850 arbitrateNeverSendProperty( OWNER_PEOPLE
);
851 arbitrateNeverSendProperty( OUTPOST_INFOS
);
853 GET_VP_NODE(POSITION
)->BranchHasPayload
= sentity
->positionIsInitialized() && positionHasChangedEnough();
854 GET_VP_NODE(ORIENTATION
)->BranchHasPayload
= thetaIntModehasChanged(entry
.Properties
[PROPERTY_ORIENTATION
]);
859 * Fill the BranchHasPayload flags of the tree, using the rules deciding if a discreet property need to be sent
861 inline void CDistancePrioritizer::arbitrateCommonPosAndMode(const CPropertyHistory::CEntityEntry
& entry
)
863 // Position if changed enough (if not carried by mode)
864 // Orientation if changed > 60 degrees (it's head angle only) or in first block (useful for static entities such as bot objects)
865 bool modeIsChanging
= GET_VP_NODE(MODE
)->BranchHasPayload
;
866 bool sheetIsChanging
= GET_VP_NODE(SHEET
)->BranchHasPayload
;
867 bool posIsReady
= TVPNodeServer::PrioContext
.Sentity
->positionIsInitialized();
869 GET_VP_NODE(POSITION
)->BranchHasPayload
= (!modeIsChanging
) && posIsReady
&& positionHasChangedEnough();
870 GET_VP_NODE(ORIENTATION
)->BranchHasPayload
= (sheetIsChanging
&& posIsReady
) || orientationHasChangedEnough( entry
.Properties
[PROPERTY_ORIENTATION
], 36.0f
); // 5 degrees
874 * Fill the BranchHasPayload flags of the tree, using the rules deciding if a discreet property need to be sent
876 inline void CDistancePrioritizer::arbitrateSlot0PosAndMode(const CPropertyHistory::CEntityEntry
& entry
)
878 arbitrateNeverSendProperty(POSITION
);
879 arbitrateNeverSendProperty(ORIENTATION
);
886 inline void CDistancePrioritizer::serialSlotHeader( CClientHost
& client
, CEntity
*sentity
, TPairState
& pairState
, CLFECOMMON::TCLEntityId slot
, TOutBox
& outbox
)
890 sint beginbitpos
= outbox
.getPosInBit();
892 outbox
.serialAndLog1( slot
);
894 // Association change bits (2 bits)
895 uint32 associationBits
= (uint32
)pairState
.AssociationChangeBits
;
896 outbox
.serialAndLog2( associationBits
, 2 );
897 if ( pairState
.AssociationChangeBits
!= pairState
.PrevAssociationBits
)
899 //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() );
900 pairState
.PrevAssociationBits
= pairState
.AssociationChangeBits
; // & 0x3;
901 _History
->storeDisassociation( client
.clientId(), slot
, client
.sendNumber(), pairState
.AssociationChangeBits
);
902 // pairState.AssociationChangeBits &= 0x7F;
906 // Timestamp (1 or 5 bits, depending on the type of entity) (TVPNodeServer::PrioContext.Timestamp initialized to 0)
907 uint32 timestampDelta
= 0;
910 const CEntityId
& seenEntityId
= TheDataset
.getEntityId( TVPNodeServer::PrioContext
.EntityIndex
);
911 if ( seenEntityId
.getType() == RYZOMID::player
)
913 // For players, always set the timestamp delta, using TickPosition
914 // Note: discreet property change times won't be accurate
915 TVPNodeServer::PrioContext
.Timestamp
= sentity
->TickPosition
;
916 timestampDelta
= CTickEventHandler::getGameCycle() - sentity
->TickPosition
;
917 if ( timestampDelta
> 15 ) // clamp to 4bit
919 timestampDelta
|= 0x10; // 'timestampIsThere bit': first bit is bit 5 (high to low order)
921 else if ( seenEntityId
.getType() > RYZOMID::creature_end
)
923 // For non-players/non-bots types (e.g. bags), set the timestamp delta if entity is being spawned to the client
924 //if ( _VisualPropertyTreeRoot->B->B->getSHEETnode()->BranchHasPayload ) // assumes this is done after arbitrateDiscreetProperties() // CHANGED BEN
925 if ( GET_VP_NODE(SHEET
)->BranchHasPayload
) // assumes this is done after arbitrateDiscreetProperties()
927 TVPNodeServer::PrioContext
.Timestamp
= TheDataset
.getOnlineTimestamp( TVPNodeServer::PrioContext
.EntityIndex
);
928 timestampDelta
= CTickEventHandler::getGameCycle() - TVPNodeServer::PrioContext
.Timestamp
;
929 if ( timestampDelta
> 15 ) // clamp to 4bit
931 timestampDelta
|= 0x10; // 'timestampIsThere bit': first bit is bit 5 (high to low order)
934 // For bots, the timestamp is not needed, the client will take _ServerGameCycle
937 outbox
.serialAndLog2( timestampDelta
, (timestampDelta
!=0) ? 5 : 1 );
940 #ifdef STORE_MIRROR_VP_IN_CLASS
942 #define caseFillAction( name ) ap->setValue64( TVPNodeServer::PrioContext.Sentity->VP_##name() );
944 #else // STORE_MIRROR_VP_IN_CLASS
946 #define caseFillAction( name ) \
947 CMirrorPropValueRO<TYPE_##name> prop( TheDataset, TVPNodeServer::PrioContext.EntityIndex, DSProperty##name ); \
948 ap->setValue64( prop() );
950 #endif // STORE_MIRROR_VP_IN_CLASS
960 void fillSHEET( TOutBox
& outbox
, TPropIndex
)
963 // In non-debug cases, it is done in CVisionProvider::addPair()
964 //CClientEntityIdTranslator::CEntityInfo& info = TVPNodeServer::PrioContext.ClientHost->IdTranslator.getInfo( TVPNodeServer::PrioContext.Slot ); // CHANGED BEN
965 //info.AssociationState = CClientEntityIdTranslator::CEntityInfo::NormalAssociation; // CHANGED BEN
966 TVPNodeServer::PrioContext
.Prioritizer
->getVisionArray()->setAssociationState( TVPNodeServer::PrioContext
.ClientId
,
967 TVPNodeServer::PrioContext
.Slot
,
968 TPairState::NormalAssociation
);
970 bool payloadBit
= true;
971 outbox
.serialBitAndLog( payloadBit
);
973 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_SHEET ); // CHANGED BEN
976 // Pack sheet and compressed row into the action
977 #ifdef STORE_MIRROR_VP_IN_CLASS
978 CMirrorPropValueRO
<TYPE_SHEET
>& prop
= TVPNodeServer::PrioContext
.Sentity
->VP_SHEET
;
980 CMirrorPropValueRO
<TYPE_SHEET
> prop( TheDataset
, TVPNodeServer::PrioContext
.EntityIndex
, DSPropertySHEET
);
983 uint32 sheetValue
= prop();
984 TDataSetIndex compressedRow
= TVPNodeServer::PrioContext
.EntityIndex
.getCompressedIndex();
985 uint64 value
= (uint64
)sheetValue
| (((uint64
)compressedRow
) << 32);
986 ap
->setValue64( value
);
987 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() );
989 // Add row into the action
990 ap
->packFast( outbox
);
991 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
992 //CActionFactory::getInstance()->remove( (CAction*&)ap );
994 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
996 // Include alias if non-null in mirror (only for mission giver NPCs)
997 CMirrorPropValueRO
<TYPE_ALIAS
> aliasProp( TheDataset
, TVPNodeServer::PrioContext
.EntityIndex
, DSPropertyNPC_ALIAS
);
998 if (aliasProp() != 0)
1000 bool aliasBit
= true;
1001 outbox
.serialBitAndLog( aliasBit
);
1002 outbox
.serialAndLog1( const_cast<TYPE_ALIAS
&>(aliasProp()) ); // no need to store in history, alias never changes for an entity
1006 bool aliasBit
= false;
1007 outbox
.serialBitAndLog( aliasBit
);
1010 #ifdef TEST_LOST_PACKET
1011 if ( TestPacketLost
.get() )
1013 nldebug( "This SHEET sending will be dropped..." );
1014 TestPacketLostTimer
= CTickEventHandler::getGameCycle() + 10;
1015 TestPacketLost
= false;
1016 TestPacketLostSlot
= TVPNodeServer::PrioContext
.Slot
;
1025 void fillBEHAVIOUR( TOutBox
& outbox
, TPropIndex
)
1027 bool payloadBit
= true;
1028 outbox
.serialBitAndLog( payloadBit
);
1029 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_BEHAVIOUR );
1030 DECLARE_AP(BEHAVIOUR
);
1031 caseFillAction( BEHAVIOUR
)
1032 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() );
1033 ap
->packFast( outbox
);
1034 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1035 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1037 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1044 void fillNAME_STRING_ID( TOutBox
& outbox
, TPropIndex
)
1046 bool payloadBit
= true;
1047 outbox
.serialBitAndLog( payloadBit
);
1048 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_NAME_STRING_ID );
1049 DECLARE_AP(NAME_STRING_ID
);
1050 caseFillAction( NAME_STRING_ID
)
1051 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() );
1052 ap
->packFast( outbox
);
1053 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1054 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1056 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1062 static vector
<TCLEntityId
> TargetSlotsList(256);
1064 NLMISC_COMMAND(displayTargetList
,"Display the target list of an entity","<entityId>")
1066 if ( args
.size() > 1 )
1071 entity
.fromString(args
[0].c_str());
1073 CMirrorPropValueList
<uint32
> targets(TheDataset
,
1076 CMirrorPropValueList
<uint32
>::iterator it
;
1078 it
= targets
.begin();
1080 if (it
!= targets
.end())
1082 const uint32
*effectCycle
= &((*it
)());
1083 log
.displayNL("TargetStamp: %d", *effectCycle
);
1087 for (; it
!=targets
.end(); ++it
)
1089 uint32 index
= (*it
)();
1090 log
.displayNL("Target: %d", TDataSetRow::createFromRawIndex(index
).getIndex());
1097 void fillTARGET_LIST( TOutBox
& outbox
, TPropIndex
)
1099 CClientHost
*client
= TVPNodeServer::PrioContext
.ClientHost
;
1101 CMirrorPropValueList
<uint32
> targets(TheDataset
,
1102 TVPNodeServer::PrioContext
.EntityIndex
,
1103 DSPropertyTARGET_LIST
);
1104 CMirrorPropValueList
<uint32
>::iterator it
;
1106 TargetSlotsList
.clear();
1108 it
= targets
.begin();
1110 for (; it
!=targets
.end(); )
1112 TDataSetRow index
= TDataSetRow::createFromRawIndex((*it
)());
1115 // check list overflow
1116 if (it
== targets
.end())
1119 // distance to target (in 1/127 of 100m)
1120 uint32 dt
= *(&((*it
)()));
1123 if (it
== targets
.end())
1125 uint32 damage
= (*it
)();
1128 TCLEntityId slot
= client
->IdTranslator
.getCEId(index
);
1129 if (slot
!= INVALID_SLOT
)
1131 TargetSlotsList
.push_back(slot
);
1132 TargetSlotsList
.push_back((uint8
)dt
);
1133 TargetSlotsList
.push_back(uint8(damage
));
1134 TargetSlotsList
.push_back(uint8(damage
>> 8));
1140 // serialises branch has payload
1141 bool payLoad
= true;
1142 outbox
.serialBitAndLog(payLoad
);
1144 // restricts to 256 entities
1145 uint longListSize
= (uint
)TargetSlotsList
.size();
1146 if (longListSize
> 32)
1149 uint8 listSize
= (uint8
)longListSize
;
1151 // serialises short size
1152 outbox
.serialAndLog1(listSize
);
1154 // serialises slot list
1156 outbox
.serialBuffer(&(TargetSlotsList
[0]), listSize
);
1158 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_TARGET_LIST );
1159 DECLARE_AP(TARGET_LIST
);
1160 ap
->setValue64( TheDataset
.getChangeTimestamp( DSPropertyTARGET_LIST
, TVPNodeServer::PrioContext
.EntityIndex
) );
1161 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1162 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1165 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() );
1172 void fillBARS( TOutBox
& outbox
, TPropIndex
)
1174 bool payloadBit
= true;
1175 outbox
.serialBitAndLog( payloadBit
);
1176 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_BARS );
1178 caseFillAction( BARS
)
1179 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() );
1180 ap
->packFast( outbox
);
1181 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1182 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1184 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1191 * - They have the same mirror size
1192 * - There mirror dataset property index is contiguous (VPC = VPB + 1 = VPA + 2)
1194 void fillVisualPropertyABC( TOutBox
& outbox
, TPropIndex propIndex
)
1196 bool payloadBit
= true;
1197 outbox
.serialBitAndLog( payloadBit
);
1198 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, propIndex );
1199 DECLARE_AP_INDEX(propIndex
);
1200 CMirrorPropValueRO
<TYPE_VPA
> prop( TheDataset
, TVPNodeServer::PrioContext
.EntityIndex
, propIndex
-PROPERTY_VPA
+DSPropertyVPA
); \
1201 ap
->setValue64( prop() );
1202 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() );
1203 ap
->packFast( outbox
);
1204 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1205 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1207 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1214 void fillCONTEXTUAL( TOutBox
& outbox
, TPropIndex propIndex
)
1216 bool payloadBit
= true;
1217 outbox
.serialBitAndLog( payloadBit
);
1218 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_CONTEXTUAL );
1219 DECLARE_AP(CONTEXTUAL
);
1220 caseFillAction( CONTEXTUAL
)
1221 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() );
1222 ap
->packFast( outbox
);
1223 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1224 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1226 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1232 void fillVISUAL_FX( TOutBox
& outbox
, TPropIndex propIndex
)
1234 bool payloadBit
= true;
1235 outbox
.serialBitAndLog( payloadBit
);
1236 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_VISUAL_FX );
1237 DECLARE_AP(VISUAL_FX
);
1238 caseFillAction( VISUAL_FX
)
1239 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() );
1240 ap
->packFast( outbox
);
1241 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1242 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1244 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1250 void fillMODE( TOutBox
& outbox
, TPropIndex
)
1252 // Fill for mode special case
1253 bool payloadBit
= true;
1254 outbox
.serialBitAndLog( payloadBit
);
1255 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_MODE );
1257 uint64 modeLong
; // uses 8+4+16+16 = 44 bits
1259 // Mode value (on 8 bits)
1260 CMirrorPropValue
<MBEHAV::TMode
> prop( TheDataset
, TVPNodeServer::PrioContext
.EntityIndex
, DSPropertyMODE
);
1263 ap
->setValue64( prop().RawModeAndParam
);
1264 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1266 // Game cycle when mode changed (4 bits -> 1.6 second max)
1267 uint32 tickModeDelta
= CTickEventHandler::getGameCycle() - prop
.getTimestamp();
1268 if ( tickModeDelta
> 15 ) tickModeDelta
= 15;
1270 // Pack all with position 2D when mode changed, or combat angle (16 bits * 2)
1272 // OBSOLETE: MBEHAV::COMBAT_FLOAT no longer used
1273 if ( prop().Mode == MBEHAV::COMBAT_FLOAT )
1275 uint64 theta = (uint64)(*(uint32*)&(prop().Theta));
1276 modeLong = ((uint64)(prop().Mode)) | ((uint64)(tickModeDelta << 8)) | (theta << 12);
1277 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 );
1282 uint64 posModeX16
, posModeY16
;
1283 if ( TVPNodeServer::PrioContext
.PositionAlreadySent
)
1285 // Take the pos from the mode change
1286 posModeX16
= prop().Pos
.X16
;
1287 posModeY16
= prop().Pos
.Y16
;
1291 // Take the current pos
1292 posModeX16
= TVPNodeServer::PrioContext
.Sentity
->X() >> 4; // TODO: make a method for this formula
1293 posModeY16
= TVPNodeServer::PrioContext
.Sentity
->Y() >> 4;
1296 modeLong
= ((uint64
)((uint8
)(prop().Mode
))) | ((uint64
)(tickModeDelta
<< 8)) | (posModeX16
<< 12) | (posModeY16
<< 28);
1297 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" );
1299 // The pos might be null (if mode set before 1st pos). The client has to handle the case.
1301 if ( posModeX16==0 || posModeY16==0 )
1302 nlwarning( "E%d: The pos16 in the mode is %hu %hu", TVPNodeServer::PrioContext.EntityIndex, (uint16)posModeX16, (uint16)posModeY16 );
1307 ap
->setAndPackValue( modeLong
, outbox
);
1308 //CActionFactory::getInstance()->remove( (CAction*&)act );
1310 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1316 void fillGUILD_NAME_ID( TOutBox
& outbox
, TPropIndex
)
1318 bool payloadBit
= true;
1319 outbox
.serialBitAndLog( payloadBit
);
1320 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_GUILD_NAME_ID );
1321 DECLARE_AP(GUILD_NAME_ID
);
1322 caseFillAction( GUILD_NAME_ID
)
1323 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() );
1324 ap
->packFast( outbox
);
1325 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1326 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1328 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1334 void fillGUILD_SYMBOL( TOutBox
& outbox
, TPropIndex
)
1336 bool payloadBit
= true;
1337 outbox
.serialBitAndLog( payloadBit
);
1338 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_GUILD_SYMBOL );
1339 DECLARE_AP(GUILD_SYMBOL
);
1340 caseFillAction( GUILD_SYMBOL
)
1341 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() );
1342 ap
->packFast( outbox
);
1343 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1344 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1346 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1353 void fillEVENT_FACTION_ID( TOutBox
& outbox
, TPropIndex
)
1355 bool payloadBit
= true;
1356 outbox
.serialBitAndLog( payloadBit
);
1357 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_EVENT_FACTION_ID );
1358 DECLARE_AP(EVENT_FACTION_ID
);
1359 caseFillAction( EVENT_FACTION_ID
)
1360 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() );
1361 ap
->packFast( outbox
);
1362 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1363 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1365 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1372 void fillPVP_MODE( TOutBox
& outbox
, TPropIndex
)
1374 bool payloadBit
= true;
1375 outbox
.serialBitAndLog( payloadBit
);
1376 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_PVP_MODE );
1377 DECLARE_AP(PVP_MODE
);
1378 caseFillAction( PVP_MODE
)
1379 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() );
1380 ap
->packFast( outbox
);
1381 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1382 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1384 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1391 void fillPVP_CLAN( TOutBox
& outbox
, TPropIndex
)
1393 bool payloadBit
= true;
1394 outbox
.serialBitAndLog( payloadBit
);
1395 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, PROPERTY_PVP_CLAN );
1396 DECLARE_AP(PVP_CLAN
);
1397 caseFillAction( PVP_CLAN
)
1398 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() );
1399 ap
->packFast( outbox
);
1400 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1401 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1403 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1410 void fillOWNER_PEOPLE( TOutBox
& outbox
, TPropIndex
)
1412 bool payloadBit
= true;
1413 outbox
.serialBitAndLog( payloadBit
);
1414 DECLARE_AP(OWNER_PEOPLE
);
1415 caseFillAction( OWNER_PEOPLE
)
1416 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() );
1417 ap
->packFast( outbox
);
1418 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1420 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1427 void fillOUTPOST_INFOS( TOutBox
& outbox
, TPropIndex
)
1429 bool payloadBit
= true;
1430 outbox
.serialBitAndLog( payloadBit
);
1431 DECLARE_AP(OUTPOST_INFOS
);
1432 caseFillAction( OUTPOST_INFOS
)
1433 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() );
1434 ap
->packFast( outbox
);
1435 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1437 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1442 * TARGET_ID, ENTITY_MOUNTED, RIDER_ENTITY
1444 void fillRowProperty( TOutBox
& outbox
, TPropIndex propIndex
)
1446 bool payloadBit
= true;
1448 CMirrorPropValueRO
<TDataSetRow
> prop( TheDataset
, TVPNodeServer::PrioContext
.EntityIndex
, CEntityContainer::propertyIndexInDataSetToVisualPropIndex( propIndex
) );
1449 TEntityIndex
targetindex(prop());
1450 if ( !targetindex
.isValid() )
1453 slot
= INVALID_SLOT
;
1457 TEntityIndex seenEntityIndex
= TVPNodeServer::PrioContext
.EntityIndex
;
1458 const char *propName
= getPropText( propIndex
);
1459 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() );
1460 if ( targetindex
== TVPNodeServer::PrioContext
.ClientHost
->entityIndex() )
1462 // The entity targets the client
1465 else if ( targetindex
== seenEntityIndex
)
1467 // The entity targets itself
1468 slot
= INVALID_SLOT
;
1472 // Translate CEntityId to slot: get entityid, then slot
1473 TCLEntityId result
= TVPNodeServer::PrioContext
.ClientHost
->IdTranslator
.getCEId( targetindex
);
1474 if ( result
!= INVALID_SLOT
)
1480 LOG_WHAT_IS_SENT( "%s slot not found: E%u", propName
, targetindex
.getIndex() );
1486 // Fill for property target/mount special case
1487 outbox
.serialBitAndLog( payloadBit
);
1490 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
);
1491 //CActionSint64 *ap = (CActionSint64*)CActionFactory::getInstance()->createByPropIndex( TVPNodeServer::PrioContext.Slot, propIndex );
1492 DECLARE_AP_INDEX(propIndex
);
1493 ap
->setValue64( prop().getIndex() );
1495 // Store the entity index into the history
1496 CFrontEndService::instance()->history()->store( TVPNodeServer::PrioContext
.ClientId
, TVPNodeServer::PrioContext
.ClientHost
->sendNumber(), ap
);
1498 // The value that will be sent is the slot, not the entity index
1499 ap
->setAndPackValue( slot
, outbox
);
1501 //CActionFactory::getInstance()->remove( (CAction*&)ap );
1503 ++(TVPNodeServer::PrioContext
.ClientHost
->NbActionsSentAtCycle
);
1508 TVPNodeServer::TPrioContext
TVPNodeServer::PrioContext
;
1510 // Flattened Node Tree
1511 TVPNodeServer
* TVPNodeServer::FlatVPTree
[CLFECOMMON::NB_VISUAL_PROPERTIES
];
1513 // Reordered Node tree (used by fastPropagateBackBranchHasPayload())
1514 std::vector
<TVPNodeServer::CSortedFlatVPTreeItem
> TVPNodeServer::SortedFlatVPTree
;
1515 const bool TVPNodeServer::FalseBoolPayLoad
= false;
1517 // Reordered Node tree (used by fastFillDiscreetProperties)
1518 std::vector
<TVPNodeServer::CSortedFlatVPTreeFillItem
> TVPNodeServer::SortedFlatVPTreeFill
;
1520 void TVPNodeServer::initSortedFlatVPTree()
1525 CSortedFlatVPTreeItem item
;
1531 item
.APayLoad
= &(a()->BranchHasPayload
);
1532 a()->initSortedFlatVPTree();
1536 item
.BPayLoad
= &(b()->BranchHasPayload
);
1537 b()->initSortedFlatVPTree();
1540 SortedFlatVPTree
.push_back(item
);
1543 void TVPNodeServer::initSortedFlatVPTreeFill()
1545 uint thisItem
= (uint
)SortedFlatVPTreeFill
.size();
1546 SortedFlatVPTreeFill
.push_back(CSortedFlatVPTreeFillItem());
1548 SortedFlatVPTreeFill
[thisItem
].Node
= this;
1550 if (a()) a()->initSortedFlatVPTreeFill();
1551 if (b()) b()->initSortedFlatVPTreeFill();
1553 SortedFlatVPTreeFill
[thisItem
].NextIfNoPayload
= (uint
)SortedFlatVPTreeFill
.size();
1557 namespace CLFECOMMON
1559 // Factory for TVPNodeBase::buildTree()
1560 TVPNodeBase
*NewNode()
1562 return (TVPNodeBase
*) new TVPNodeServer();
1569 NLMISC_DYNVARIABLE( uint32
, MoveNumber
, "MoveNumber of entities seen by monitored client" )
1573 CFrontEndService
*fe
= CFrontEndService::instance();
1574 //nlassert( fe->MonitoredClient <= MAX_NB_CLIENTS );
1575 CClientHost
*client
= fe
->receiveSub()->clientIdCont()[fe
->MonitoredClient
];
1578 *pointer
= client
->MoveNumber
;
1590 NLMISC_COMMAND(verbosePropertiesSent
,"Turn on or off or check the state of verbose logging of what is sent","<clientId> | all | off")
1592 if ( args
.size() > 1 )
1595 if ( args
.size() == 1 )
1597 if ( args
[0] == string("all") )
1598 verbosePropertiesSent
= 0;
1599 else if ( args
[0] == string("off") )
1600 verbosePropertiesSent
= INVALID_CLIENT
;
1602 NLMISC::fromString(args
[0], verbosePropertiesSent
);
1605 log
.displayNL( "verbosePropertiesSent is %s", (verbosePropertiesSent
==INVALID_CLIENT
)?"off":((verbosePropertiesSent
==0)?"all":toString("C%hu", verbosePropertiesSent
).c_str()) );