1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #ifndef NL_CLIENT_HOST_H
20 #define NL_CLIENT_HOST_H
22 #include "nel/misc/types_nl.h"
23 #include "nel/misc/vector.h"
24 #include "nel/misc/time_nl.h"
25 #include "nel/net/inet_address.h"
26 #include "nel/net/login_cookie.h"
29 #include "fe_receive_task.h"
30 #include "game_share/action.h"
31 #include "client_entity_id_translator.h"
32 #include "impulse_encoder.h"
33 #include "entity_container.h"
34 #include "game_share/ryzom_entity_id.h"
35 #include "game_share/entity_types.h"
36 #include "game_share/welcome_service_itf.h"
42 const uint32 FirstClientId
= 1;
43 const uint16 InvalidClientId
= 0xFFFF;
64 for ( i
=0; i
<=MaxNbClients
; ++i
)
71 TClientId
getNewClientId()
74 for ( i
=FirstClientId
; i
<=MaxNbClients
; ++i
)
82 return InvalidClientId
;
86 void releaseId( TClientId id
)
88 _UsedPool
[id
] = false;
93 bool _UsedPool
[MAX_NB_CLIENTS
+1];
97 /// Get string for association state
98 const char *associationStateToString( uint8 as
);
103 * \author Olivier Cado
104 * \author Nevrax France
111 CClientHost( const NLNET::CInetAddress
& addr
, TClientId id
) :
113 InstanceId(0xFFFFFFFF),
114 StartupRole(WS::TUserRole::ur_player
),
115 NbFreeEntityItems( 255 ),
119 _Id(NLMISC::CEntityId::Unknown
),
123 _Synchronized(false),
124 _Disconnected(false),
125 _FirstReceiveNumber(0),
126 _ReceiveNumber(0xFFFFFFFF),
129 _DatagramRepeated(0),
130 //SheetId(CLFECOMMON::INVALID_SHEETID),
135 LastReceivedAck(0xFFFFFFFF),
136 ImpulseMultiPartNumber (0),
137 AuthorizedCharSlot(~0),
138 LastReceivedGameCycle(0),
146 //AvailableImpulseBitsize( "AvailImpulseBitsize", MaxImpulseBitSizes[2] ),
147 NbActionsSentAtCycle(0),
150 IdTranslator
.setId( id
);
151 ImpulseEncoder
.setClientHost( this );
152 ConnectionState
= Synchronize
;
153 initClientBandwidth();
159 /// Return IP and port
160 const NLNET::CInetAddress
& address() { return _Address
; }
163 TClientId
clientId() const { return _ClientId
; }
165 /// Return the entity index (for access in the entity container)
166 TEntityIndex
entityIndex() const { return _EntityIndex
; }
169 const NLMISC::CEntityId
& eId() const { return _Id
; }
171 /// Set the entity index
172 void setEntityIndex( const TEntityIndex
& ei
);
174 /// Set the CEntityId
175 void setEId( const NLMISC::CEntityId
& assigned_id
);
177 /// Prepare a clean new outbox with current values
178 void setupOutBox( TOutBox
& outbox
);
180 /// Prepare a clean system header
181 void setupSystemHeader( TOutBox
& outbox
, uint8 code
);
183 /// Compute host stats
184 void computeHostStats( const TReceivedMessage
& msgin
, uint32 currentcounter
, bool updateAcknowledge
);
186 /// Increment send number and return it
187 uint32
getNextSendNumber() { return ++_SendNumber
; }
189 /// R access to last send number
190 uint32
sendNumber() const { return _SendNumber
; }
192 /// R/W access to first receive number
193 uint32
& firstReceiveNumber() { return _FirstReceiveNumber
; }
195 /// R/W access to latest receive number
196 uint32
& receiveNumber() { return _ReceiveNumber
; }
198 /// R/W access to the toggle bit
199 //bool& toggleBit() { return _ToggleBit; }
201 /// Set receive time now
202 void setReceiveTimeNow();
204 /// Return receive time
205 NLMISC::TTime
receiveTime() const { return _ReceiveTime
; }
207 uint32
datagramLost() const { return _DatagramLost
; }
208 void resetDatagramLost() { _DatagramLost
= 0; }
210 uint32
datagramRepeated() const { return _DatagramRepeated
; }
212 /// Setup sync for tick measures with client connection
213 void setFirstSentPacket(uint32 sentPacket
, NLMISC::TGameCycle atTick
)
215 #ifdef HALF_FREQUENCY_SENDING_TO_CLIENT
216 _SendSyncTick
= atTick
- sentPacket
*2;
218 _SendSyncTick
= atTick
- sentPacket
;
222 /// Convert ack contained in client packet into tick date
223 NLMISC::TGameCycle
getPacketTickDate(uint32 receivedPacketAck
) const { return _SendSyncTick
+receivedPacketAck
; }
226 /// Get sync value for this client;
227 NLMISC::TGameCycle
getSync() const { return _SendSyncTick
; }
229 void disconnect() { _Disconnected
= true; }
230 bool isDisconnected() { return _Disconnected
; }
232 // Reset client vision
233 void resetClientVision();
235 /// Set clienthost to synchronize state
236 void setSynchronizeState()
238 ConnectionState
= Synchronize
;
241 /// Set clienthost to synchronize state
242 void setConnectedState()
244 ConnectionState
= Connected
;
247 /// Set clienthost to synchronize state
248 void setStalledState()
250 ConnectionState
= Stalled
;
253 /// Set clienthost to probe state
256 ConnectionState
= Probe
;
259 NumConsecutiveProbes
= 0;
260 LastReceivedProbe
= 0;
263 /// Set clienthost to ForceSynchronize state (i.e. Synchronize must not be replaced by Connected, as a sync must be sent to the client)
264 void setForceSynchronizeState()
266 ConnectionState
= ForceSynchronize
;
269 /// Initialize the counter/flag
270 void initSendCycle( bool initialState
)
272 _WhenToSend
= initialState
;
275 /// Update the counter/flag
278 #ifdef HALF_FREQUENCY_SENDING_TO_CLIENT
279 _WhenToSend
= !_WhenToSend
;
283 /// Return true if the counter/flag state is "to send" for the current cycle
286 #ifdef HALF_FREQUENCY_SENDING_TO_CLIENT
294 void displayClientProperties( bool full
=true, bool allProps
=false, bool sortByDistance
=false,NLMISC::CLog
*log
= NLMISC::InfoLog
) const;
296 /// display nlinfo for one slot
297 void displaySlotProperties( CLFECOMMON::TCLEntityId e
, bool full
=false, NLMISC::CLog
*log
= NLMISC::InfoLog
) const;
299 /// display nlinfo (1 line only)
300 void displayShortProps(NLMISC::CLog
*log
= NLMISC::InfoLog
) const;
302 /// Return the cardinal direction from the player to the seen entity
303 const char * getDirection( CEntity
*seenEntity
, const TEntityIndex
& seenEntityIndex
) const;
305 /// Initialize the client bandwidth (calls setClientBandwidth)
306 void initClientBandwidth();
308 /// Change the client bandwidth (set the nomimal size)
309 void setClientBandwidth( sint32 cbw
)
311 _MaxOutboxSizeInBit
= cbw
;
312 _BitBandwidthUsageAvg
= _MaxOutboxSizeInBit
;
313 _BitImpulsionUsageAvg
= MaxImpulseBitSizes
[2];
314 _ImpulsionPrevRemainingActions
= 0;
317 /// Return the current maximum number of bits that can fit in the outbox
318 sint32
getCurrentThrottle() const
320 return std::min( (sint32
)(_MaxOutboxSizeInBit
*2-_BitBandwidthUsageAvg
), (sint32
)(_MaxOutboxSizeInBit
*3/2) );
323 /// Update the average bits filled that determine the throttle
324 void updateThrottle( TOutBox
& outbox
)
327 sint32 prevThrottle
= getCurrentThrottle();
329 // Update the average of bits sent
330 _BitBandwidthUsageAvg
= (_BitBandwidthUsageAvg
*(_SendNumber
-1) + outbox
.getPosInBit()) / _SendNumber
;
332 sint32 currThrottle
= getCurrentThrottle();
333 if ( currThrottle
!= prevThrottle
)
334 nldebug( "NFC: Client %hu, packet %u: throttle %d, %d filled now, %d average (%d kbps), %d nominal", _ClientId
, _SendNumber
, currThrottle
, outbox
.getPosInBit(), _BitBandwidthUsageAvg
, _BitBandwidthUsageAvg
*5/1000, _MaxOutboxSizeInBit
);
339 * Calculate the current maximum number of bits that can fit for impulsions,
340 * and set AvailableImpulsionBitSize in the mirror, using:
341 * - The number of bits filled (possibly exceeding the max when sending forced actions (database))
342 * - The number of remaining actions not forced
344 void setImpulsionThrottle( sint32 currentNbBitsFilled
, sint32 nominalBitSize
, uint nbRemainingActions
)
346 if ( !_EntityIndex
.isValid() )
349 if ( ((_ImpulsionPrevRemainingActions
>12) && (nbRemainingActions
> _ImpulsionPrevRemainingActions
* 5/4))
350 || _ImpulsionPrevRemainingActions
>100 )
352 // The connection does not manage to send all the impulsions that come from the back-end, stop the database impulsions
353 CMirrorPropValue
<uint16
> availableImpulseBitsize( TheDataset
, _EntityIndex
, DSFirstPropertyAvailableImpulseBitSize
);
354 availableImpulseBitsize
= 0;
356 nldebug( "NFC: Client %hu: Blocking the AvailableImpulseBitsize to prevent impulsion congestion", _ClientId
);
361 // The remaining actions number is stable, calculate the available bitsize
362 _BitImpulsionUsageAvg
= (_BitImpulsionUsageAvg
*(_SendNumber
-1) + currentNbBitsFilled
) / _SendNumber
;
364 if ( _BitImpulsionUsageAvg
< nominalBitSize
)
365 availBitsize
= nominalBitSize
;
367 availBitsize
= std::max( (sint32
)0, nominalBitSize
*2 - _BitImpulsionUsageAvg
);
369 CMirrorPropValue
<uint16
> availableImpulseBitsize( TheDataset
, _EntityIndex
, DSFirstPropertyAvailableImpulseBitSize
);
371 if ( availBitsize
!= availableImpulseBitsize
)
372 nldebug( "NFC: Client %hu, packet %u: AvailableImpulseBitsize %u, %d filled now, %d average, %d nominal", _ClientId
, _SendNumber
, availBitsize
, currentNbBitsFilled
, _BitImpulsionUsageAvg
, nominalBitSize
);
374 availableImpulseBitsize
= (uint16
)availBitsize
;
376 _ImpulsionPrevRemainingActions
= nbRemainingActions
;
379 /// Force the impulsion throttle to 0 to prevent overflooding, when the FS does send any impulsion.
380 void setIdleImpulsionThrottle()
382 if ( !_EntityIndex
.isValid() )
385 CMirrorPropValue
<uint16
> availableImpulseBitsize( TheDataset
, _EntityIndex
, DSFirstPropertyAvailableImpulseBitSize
);
386 availableImpulseBitsize
= 0;
388 nldebug( "NFC: Client %hu: Blocking the AvailableImpulseBitsize to prevent impulsion congestion", _ClientId
);
391 // The FS must not send any impulsion at this time
392 _ImpulsionPrevRemainingActions
= 0;
397 TPairState
& getPairState(CLFECOMMON::TCLEntityId e
);
399 const TPairState
& getPairState(CLFECOMMON::TCLEntityId e
) const;
404 /// User name (put on the NeL Launcher, transmitted by the login system)
405 std::string UserName
;
407 /// User privilege (put on the NeL Launcher, transmitted by the login system)
408 std::string UserPriv
;
410 /// User extended data (put on the NeL Launcher, transmitted by the login system)
411 std::string UserExtended
;
414 std::string LanguageId
;
417 NLNET::CLoginCookie LoginCookie
;
423 WS::TUserRole StartupRole
;
426 //CLFECOMMON::TSheetId SheetId;
428 /// Number of free entity items
429 uint16 NbFreeEntityItems
;
431 // Used to differenciate different multi part impulse
432 uint8 ImpulseMultiPartNumber
;
434 // The only character slot that will be granted to connect [0..4], or 0xF (15) for any character
435 uint8 AuthorizedCharSlot
;
437 /// States of the client connection
444 // Disconnect, // Appears to be unused at least for now
446 ForceSynchronize
, // prevents Synchronize to be replaced by Connected
449 /// The current state of the client connection
450 uint ConnectionState
;
452 /// The last received probe;
453 uint32 LastReceivedProbe
;
455 /// The number of consecutive probes received lastly
456 uint32 NumConsecutiveProbes
;
458 /// The last sent probe;
459 uint32 LastSentProbe
;
461 /// The last sent sync
464 /// The time the last probe was sent
465 NLMISC::TTime LastProbeTime
;
472 uint32 LastSentCounter
;
475 NLMISC::TTime LastCounterTime
;
477 /// @name Generic action multipart handling structures
479 struct CGenericMultiPartTemp
481 CGenericMultiPartTemp () : NbBlock(0xFFFFFFFF) { }
483 uint32 NbCurrentBlock
;
485 std::vector
<std::vector
<uint8
> > Temp
;
487 std::vector
<bool> BlockReceived
;
489 void set (CLFECOMMON::CActionGenericMultiPart
*agmp
, CClientHost
*client
);
492 std::vector
<CGenericMultiPartTemp
> GenericMultiPartTemp
;
500 /// Client IP and port
501 NLNET::CInetAddress _Address
;
507 TEntityIndex _EntityIndex
;
510 NLMISC::CEntityId _Id
;
512 /// Latest send number
515 /// Counter (or flag) determining when to send the prioritized properties to the client
518 /// First tick on front end, corresponding to the first packet sent
519 NLMISC::TGameCycle _SendSyncTick
;
523 /// First receive number
524 uint32 _FirstReceiveNumber
;
526 /// Latest receive number
527 uint32 _ReceiveNumber
;
529 /// Bit for important actions
532 /// Timestamp of latest receiving
533 NLMISC::TTime _ReceiveTime
;
536 uint32 _DatagramLost
;
539 uint32 _DatagramRepeated
;
542 sint32 _MaxOutboxSizeInBit
;
544 /// Number of bits that can be added to the nominal size (>0), or that must be removed from the nominal size (<0)
545 sint32 _DeltaBitsAllowed
;
547 /// Previous number of actions not sent by the impulse encoder
548 uint32 _ImpulsionPrevRemainingActions
;
550 /// Average of total bits sent
551 sint32 _BitBandwidthUsageAvg
;
553 /// Average of impulsion bits sent
554 sint32 _BitImpulsionUsageAvg
;
558 // Client <- frontend entity id translator
559 CClientEntityIdTranslator IdTranslator
;
561 /// Impulse management
562 CImpulseEncoder ImpulseEncoder
;
564 /// Last ack number received from client
565 uint32 LastReceivedAck
;
568 NLMISC::TGameCycle LastReceivedGameCycle
;
571 uint32 LastSentDummy
;
573 // Estimation of available size in bit per cycle
574 //CPropertyBaseType<uint16> AvailableImpulseBitsize;
577 uint NbActionsSentAtCycle
;
593 CLimboClient( CClientHost
* client
) :
594 AddrFrom(client
->address()), Uid(client
->Uid
), UserName(client
->UserName
), UserPriv(client
->UserPriv
), UserExtended(client
->UserExtended
),
595 LanguageId(client
->LanguageId
), QuitId(client
->QuitId
)
597 // Set limbo timeout start
598 Timeout
= NLMISC::CTime::getLocalTime();
599 LoginCookie
= client
->LoginCookie
;
602 NLNET::CInetAddress AddrFrom
;
604 std::string UserName
, UserPriv
, UserExtended
, LanguageId
;
606 NLMISC::TTime Timeout
;
607 NLNET::CLoginCookie LoginCookie
;
611 #endif // NL_CLIENT_HOST_H
613 /* End of client_host.h */