1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 /*************************************************************************
4 -------------------------------------------------------------------------
7 Description: Class for recording and sending matchmaking data.
8 Aim is to record the data we used to rate the available sessions and the session we chose
9 (so we can later find out if we are making good decisions)
10 and also data on the actual performance of the session
11 (so we can see if our decisions are based on good data).
12 -------------------------------------------------------------------------
14 - 02:06:2011 : Created By Andrew Blackwell
16 *************************************************************************/
19 //////////////////////////////////////////////////////////////////////////
21 #include "MatchMakingTelemetry.h"
23 #include "TelemetryCollector.h"
24 #include "GameLobby.h"
25 #include "GameLobbyData.h"
26 #include "GameRulesModules/IGameRulesStateModule.h"
27 #include "GameRulesModules/IGameRulesPlayerStatsModule.h"
28 #include "RecordingBuffer.h"
30 #include "PlaylistManager.h"
32 #define MATCHMAKING_BUFFER_SIZE (4*1024)
34 //-------------------------------------------------------------------------
35 //Matchmaking Telemetry main class/event collector section
37 //-------------------------------------------------------------------------
39 CMatchmakingTelemetry::CMatchmakingTelemetry()
42 m_currentTranscript
= eMMTelTranscript_None
;
45 //--------------------------------------------------------------------------
47 CMatchmakingTelemetry::~CMatchmakingTelemetry()
49 if( m_pBuffer
&& m_pBuffer
->size() != 0 )
51 CryWarning( VALIDATOR_MODULE_GAME
, VALIDATOR_COMMENT
, "Destroying Matchmaking Telemetry object with non-transfered data present" );
54 //Need to check if there's any data in transit to telemetry servers here and halt it
56 SAFE_DELETE( m_pBuffer
);
59 //-------------------------------------------------------------------------
60 CMatchmakingTelemetry::EMMTelRetVal
CMatchmakingTelemetry::BeginMatchMakingTranscript( EMMTelTranscriptType type
)
62 CRY_ASSERT( m_currentTranscript
== eMMTelTranscript_None
);
63 m_currentTranscript
= type
;
65 if( m_pBuffer
== NULL
)
67 m_pBuffer
= new CRecordingBuffer( MATCHMAKING_BUFFER_SIZE
);
68 m_pBuffer
->SetPacketDiscardCallback( NULL
, NULL
);
69 return eMMTelRV_Success
;
73 return eMMTelRV_ErrorWrongState
;
77 //-------------------------------------------------------------------------
78 CMatchmakingTelemetry::EMMTelRetVal
CMatchmakingTelemetry::EndMatchmakingTranscript( EMMTelTranscriptType transcript
, bool logLocally
)
80 EMMTelRetVal retVal
= eMMTelRV_Success
;
82 //TODO: Decide on valid ways to use Begin/End Transcript, and promote comments to warnings if these are invalid
83 if( transcript
!= m_currentTranscript
)
85 CryWarning( VALIDATOR_MODULE_GAME
, VALIDATOR_COMMENT
, "MMTel: Tried to close a type %d transcript block but current type is %d", transcript
, m_currentTranscript
);
86 retVal
= eMMTelRV_ErrorWrongState
;
88 else if( m_pBuffer
== NULL
|| m_pBuffer
->size() == 0 )
90 //there is actually no data to send
91 CryWarning( VALIDATOR_MODULE_GAME
, VALIDATOR_COMMENT
, "MMTel: When close a type %d transcript block there was no data to send", m_currentTranscript
);
92 retVal
= eMMTelRV_ErrorWrongState
;
96 //pass our buffer to our telemetry producer, the producer takes ownership of it
98 CTelemetryCollector
*tc
=static_cast<CTelemetryCollector
*>(static_cast<CGame
*>(g_pGame
)->GetITelemetryCollector());
99 ITelemetryProducer
*pProducer
= new CMMTelemetryProducer( m_pBuffer
);
101 const char* nameBase
;
105 case eMMTelTranscript_QuickMatch
:
106 nameBase
= "matchmakingdata";
108 case eMMTelTranscript_SessionQuality
:
109 nameBase
= "sessionperformance";
112 nameBase
= "unknowndata";
117 CryFixedStringT
<24> localFilename
;
118 localFilename
.Format( "%s%d.xml", nameBase
, gEnv
->pSystem
->GetApplicationInstance() );
120 CTelemetrySaveToFile
* pLogger
= new CTelemetrySaveToFile( pProducer
, localFilename
.c_str() );
124 CryFixedStringT
<24> remoteFilename
;
125 remoteFilename
.Format( "%s.xml", nameBase
);
127 tc
->SubmitTelemetryProducer( pProducer
, remoteFilename
.c_str() );
129 //clear out buffer pointer
131 m_currentTranscript
= eMMTelTranscript_None
;
134 CryLog( "MMT: End Transcript call finished" );
139 //-------------------------------------------------------------------------
140 void CMatchmakingTelemetry::AddEvent( const SMatchMakingEvent
& event
)
144 m_pBuffer
->AddPacket( event
);
148 //-------------------------------------------------------------------------
149 void CMatchmakingTelemetry::OnOwnClientEnteredGame()
151 //called on every client before the game starts
152 #if defined(TRACK_MATCHMAKING)
153 CryLog("MMT: End Quick match Telemetry");
154 EndMatchmakingTranscript( eMMTelTranscript_QuickMatch
, true );
158 //-------------------------------------------------------------------------
159 void CMatchmakingTelemetry::OnClientEnteredGame( int channelId
, bool isReset
, EntityId playerId
)
161 //called on the server for every player. called after OnOwnClientEnteredGame
163 if( m_currentTranscript
== eMMTelTranscript_None
)
165 CryLog("MMT: Start Session Quality Telemetry");
166 BeginMatchMakingTranscript( eMMTelTranscript_SessionQuality
);
169 //tell the Telemetry System this player has joined so we know to record their session performance
170 CGameLobby
* pGameLobby
= g_pGame
->GetGameLobby();
171 if( pGameLobby
!= NULL
&& pGameLobby
->GetState() == eLS_Game
)
173 SCryMatchMakingConnectionUID conUID
= pGameLobby
->GetConnectionUIDFromChannelID( channelId
);
174 CryUserID guid
= pGameLobby
->GetUserIDFromChannelID( channelId
);
176 CryFixedStringT
<CRYLOBBY_USER_NAME_LENGTH
> name
;
178 pGameLobby
->GetPlayerNameFromChannelId( channelId
, name
);
180 AddEvent( SMMPlayerJoinedEvent( name
, guid
, conUID
) );
184 //-------------------------------------------------------------------------
185 void CMatchmakingTelemetry::OnClientDisconnect( int channelId
, EntityId playerId
)
187 CryLog("MMT: OnClienDisconnect");
189 //tell the Telemetry System this player has left so we know to not expect anymore session performance records
190 CGameLobby
* pGameLobby
= g_pGame
->GetGameLobby();
193 SCryMatchMakingConnectionUID conUID
= pGameLobby
->GetConnectionUIDFromChannelID( channelId
);
194 CryUserID guid
= pGameLobby
->GetUserIDFromChannelID( channelId
);
195 AddEvent( SMMPlayerLeftEvent( guid
, conUID
) );
199 //-------------------------------------------------------------------------
200 //Matchmaking Telemetry Producer Section
202 //-------------------------------------------------------------------------
204 CMMTelemetryProducer::CMMTelemetryProducer( CRecordingBuffer
* pInBuffer
)
205 : m_pDataBuffer( pInBuffer
),
206 m_currentElement( pInBuffer
->begin() )
210 //-------------------------------------------------------------------------
212 CMMTelemetryProducer::~CMMTelemetryProducer()
214 //delete the buffer we took ownership of
215 SAFE_DELETE( m_pDataBuffer
);
218 //-------------------------------------------------------------------------
219 ITelemetryProducer::EResult
CMMTelemetryProducer::ProduceTelemetry( char *pOutBuffer
, int inMinRequired
, int inBufferSize
, int *pOutWritten
)
221 ITelemetryProducer::EResult retVal
= eTS_Available
;
222 uint32 writtingIndex
= 0;
223 //change to unsigned for signed/unsigned mis-match protection
224 uint32 bufferSize
= inBufferSize
;
226 EventDataString entryString
;
227 CRecordingBuffer::iterator end
= m_pDataBuffer
->end();
228 bool writtenEnough
= false;
231 if( m_currentElement
== m_pDataBuffer
->begin() )
233 //open a top level XML tag
234 entryString
.Format( "<MatchMakingTelemetryXML>\n" );
235 if( (writtingIndex
+ entryString
.length()) < bufferSize
)
237 memcpy( pOutBuffer
+ writtingIndex
, entryString
.c_str(), entryString
.length() );
238 writtingIndex
+= entryString
.length();
242 while( !writtenEnough
&& m_currentElement
!= end
)
244 switch( m_currentElement
->type
)
246 case eMMTelE_StartSearch
:
247 OutputStartSearchData( *m_currentElement
, entryString
);
249 case eMMTelE_FoundSession
:
250 OutputFoundSessionData( *m_currentElement
, entryString
);
252 case eMMTelE_ChosenSession
:
253 OutputChosenSessionData( *m_currentElement
, entryString
);
255 case eMMTelE_NoServerSelected
:
256 OutputNoServerSelectedData( *m_currentElement
, entryString
);
258 case eMMTelE_SearchTimedOut
:
259 OutputSearchTimedOutData( *m_currentElement
, entryString
);
261 case eMMTelE_ServerConnectFailed
:
262 OutputServerConnectFailedData( *m_currentElement
, entryString
);
264 case eMMTelE_MigrateHostLobby
:
265 OutputMigrateHostLobbyData( *m_currentElement
, entryString
);
267 case eMMTelE_BecomeServer
:
268 OutputBecomeHostData( *m_currentElement
, entryString
);
270 case eMMTelE_DemotedToClient
:
271 OutputDemotedData( *m_currentElement
, entryString
);
273 case eMMTelE_MigrateCompleted
:
274 OutputMigrateCompletedData( *m_currentElement
, entryString
);
276 case eMMTelE_ServerRequestMerge
:
277 OutputServerRequestingMergeData( *m_currentElement
, entryString
);
279 case eMMTelE_MergeRequested
:
280 OutputMergeRequestedData( *m_currentElement
, entryString
);
282 case eMMTelE_LaunchGame
:
283 OutputLaunchGameData( *m_currentElement
, entryString
);
285 case eMMTelE_LeaveMatchMaking
:
286 OutputLeaveMatchMakingData( *m_currentElement
, entryString
);
288 case eMMTelE_PlayerJoinedMM
:
289 OutputPlayerJoinedMMData( *m_currentElement
, entryString
);
291 case eMMTelE_PlayerLeftMM
:
292 OutputPlayerLeftMMData( *m_currentElement
, entryString
);
294 case eMMTelE_PlayerJoined
:
295 OutputPlayerJoinedData( *m_currentElement
, entryString
);
297 case eMMTelE_PlayerLeft
:
298 OutputPlayerLeftData( *m_currentElement
, entryString
);
300 case eMMTelE_PlayerPing
:
301 OutputPlayerPingData( *m_currentElement
, entryString
);
303 case eMMTelE_PlayerReportLag
:
304 OutputPlayerReportLagData( *m_currentElement
, entryString
);
307 case eMMTelE_GenericLog
:
308 OutputGenericLogData( *m_currentElement
, entryString
);
311 //Still Need to support these types:
312 //eMMTelE_MigrationClientAvailable:
313 //eMMTelE_MigrationClientChosen:
315 default: //not a type we have data for
319 //check we have space then add the data to the buffer
320 if( (writtingIndex
+ entryString
.length()) < bufferSize
)
322 memcpy( pOutBuffer
+ writtingIndex
, entryString
.c_str(), entryString
.length() );
323 writtingIndex
+= entryString
.length();
325 //successfully written element, move onto next
330 CRY_ASSERT_MESSAGE( (int)writtingIndex
>= inMinRequired
, "MatchMaking Telemetry event is too large to send" );
331 writtenEnough
= true;
335 if( m_currentElement
== end
)
337 //close the top level XML tag
338 entryString
.Format( "</MatchMakingTelemetryXML>" );
340 //check we're not going to run out of space
341 if( (writtingIndex
+ entryString
.length()) < bufferSize
)
343 memcpy( pOutBuffer
+ writtingIndex
, entryString
.c_str(), entryString
.length() );
344 writtingIndex
+= entryString
.length();
345 retVal
= eTS_EndOfStream
;
349 *pOutWritten
= writtingIndex
;
354 //-------------------------------------------------------------------------
355 void CMMTelemetryProducer::OutputStartSearchData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
357 SMMStartSearchEvent
& searchEvent
= reinterpret_cast<SMMStartSearchEvent
&>( eventPacket
);
359 entryString
.Format( "<searchParams searchID=\"%d\" numFreeSlots=\"%d\" ranked=\"%d\" ", searchEvent
.m_searchID
, searchEvent
.m_numFreeSlots
, searchEvent
.m_ranked
);
361 EventDataString row
; //needs to be same type and size as dest string
362 if( searchEvent
.m_version
!= -1 )
364 row
.Format( "version=\"%d\" ", searchEvent
.m_version
);
368 if( CPlaylistManager
* pPlaylistmanager
= g_pGame
->GetPlaylistManager() )
370 if( searchEvent
.m_playlist
!= -1 )
372 row
.Format( "playlist=\"%s\" ", pPlaylistmanager
->GetPlaylistNameById(searchEvent
.m_playlist
) );
376 if( searchEvent
.m_variant
!= -1 )
378 row
.Format( "variant=\"%s\" ", pPlaylistmanager
->GetVariantName(searchEvent
.m_variant
) );
383 if( searchEvent
.m_searchRegion
!= -1 )
385 row
.Format( "searchRegion=\"%d\" ", searchEvent
.m_variant
);
390 row
.Format( "regionlessSearch=\"1\" " );
394 row
.Format( "timestamp=\"%" PRIi64
"\" />\n", searchEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
399 //-------------------------------------------------------------------------
400 void CMMTelemetryProducer::OutputFoundSessionData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
402 SMMFoundSessionEvent
& sessionEvent
= reinterpret_cast<SMMFoundSessionEvent
&>( eventPacket
);
404 const char* pStatusName
= NULL
;
406 switch( sessionEvent
.m_status
)
408 case CGameLobby::eAS_Lobby
:
409 pStatusName
= "Lobby";
411 case CGameLobby::eAS_Game
:
412 pStatusName
= "InGame";
414 case CGameLobby::eAS_EndGame
:
415 pStatusName
= "EndGame";
417 case CGameLobby::eAS_StartingGame
:
418 pStatusName
= "StartGame";
422 entryString
.Format( "<foundSession serverName=\"%s\" sessionId=\"%s\" ping=\"%d\" filledSlots=\"%d\" status=\"%s\" rankDifference=\"%d\" region=\"%d\" language=\"%d\" badServer=\"%d\" c2mmscore=\"%.3f\" timestamp=\"%" PRIi64
"\" />\n",
423 sessionEvent
.m_sessionName
, sessionEvent
.m_sessionID
, sessionEvent
.m_ping
, sessionEvent
.m_filledSlots
,
424 pStatusName
, sessionEvent
.m_rankDiff
, sessionEvent
.m_region
, sessionEvent
.m_language
, sessionEvent
.m_badServer
,
425 sessionEvent
.m_score
, sessionEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
428 //-------------------------------------------------------------------------
429 void CMMTelemetryProducer::OutputChosenSessionData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
431 SMMChosenSessionEvent
& sessionEvent
= reinterpret_cast<SMMChosenSessionEvent
&>( eventPacket
);
435 if( sessionEvent
.m_created
)
437 tagName
= "createdServer";
441 tagName
= "chosenServer";
444 entryString
.Format( "<%s searchID=\"%d\" rulesUsed=\"%s\" serverName=\"%s\" sessionId=\"%s\" isPrimary=\"%d\" timestamp=\"%" PRIi64
"\" />\n",
445 tagName
, sessionEvent
.m_searchID
, sessionEvent
.m_rulesDescription
, sessionEvent
.m_sessionName
,
446 sessionEvent
.m_sessionID
, sessionEvent
.m_primary
, sessionEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
449 //-------------------------------------------------------------------------
450 void CMMTelemetryProducer::OutputServerConnectFailedData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
452 SMMServerConnectFailedEvent
& failedEvent
= reinterpret_cast<SMMServerConnectFailedEvent
&>( eventPacket
);
453 entryString
.Format( "<failedToConnectToServer sessionId=\"%s\" primarySession=\"%d\" errorCode=\"%d\" timestamp=\"%" PRIi64
"\" />\n",
454 failedEvent
.m_sessionID
, failedEvent
.m_wasPrimary
, failedEvent
.m_errorCode
, failedEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
457 //-------------------------------------------------------------------------
458 void CMMTelemetryProducer::OutputNoServerSelectedData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
460 SMMNoServerSelectedEvent
& noJoinEvent
= reinterpret_cast<SMMNoServerSelectedEvent
&>( eventPacket
);
461 entryString
.Format( "<noServerSelected searchID=\"%d\" reason=\"%s\" timestamp=\"%" PRIi64
"\" />\n", noJoinEvent
.m_searchID
, noJoinEvent
.m_reason
, noJoinEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
464 //-------------------------------------------------------------------------
465 void CMMTelemetryProducer::OutputSearchTimedOutData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
467 SMMSearchTimedOutEvent
& timedoutEvent
= reinterpret_cast<SMMSearchTimedOutEvent
&>( eventPacket
);
468 entryString
.Format( "<searchTimedOut searchID=\"%d\" searchingAgain=\"%d\" timestamp=\"%" PRIi64
"\" />\n", timedoutEvent
.m_searchID
, timedoutEvent
.m_searchingAgain
, timedoutEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
471 //-------------------------------------------------------------------------
472 void CMMTelemetryProducer::OutputMigrateHostLobbyData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
474 SMMMigrateHostLobbyEvent
& promoteEvent
= reinterpret_cast<SMMMigrateHostLobbyEvent
&>( eventPacket
);
475 entryString
.Format( "<startMigrateHostInLobby timestamp=\"%" PRIi64
"\" />\n", promoteEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
478 //-------------------------------------------------------------------------
479 void CMMTelemetryProducer::OutputBecomeHostData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
481 SMMBecomeHostEvent
& promoteEvent
= reinterpret_cast<SMMBecomeHostEvent
&>( eventPacket
);
482 entryString
.Format( "<promotedToHost timestamp=\"%" PRIi64
"\" />\n", promoteEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
485 //-------------------------------------------------------------------------
486 void CMMTelemetryProducer::OutputDemotedData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
488 SMMBecomeHostEvent
& demoteEvent
= reinterpret_cast<SMMBecomeHostEvent
&>( eventPacket
);
489 entryString
.Format( "<demotedToClient timestamp=\"%" PRIi64
"\" />\n", demoteEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
492 //-------------------------------------------------------------------------
493 void CMMTelemetryProducer::OutputMigrateCompletedData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
495 SMMMigrateCompletedEvent
& migrateEvent
= reinterpret_cast<SMMMigrateCompletedEvent
&>( eventPacket
);
496 entryString
.Format( "<migrationCompleted newHostName=\"%s\" newSessionId=\"%s\" timestamp=\"%" PRIi64
"\" />\n", migrateEvent
.m_newServer
, migrateEvent
.m_newSessionID
, migrateEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
499 //-------------------------------------------------------------------------
500 void CMMTelemetryProducer::OutputServerRequestingMergeData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
502 SMMServerRequestingMerge
& mergeEvent
= reinterpret_cast<SMMServerRequestingMerge
&>( eventPacket
);
503 entryString
.Format( "<requestingMerge currentSessionId=\"%s\" newSessionId=\"%s\" timestamp=\"%" PRIi64
"\" />\n",
504 mergeEvent
.m_currentSessionID
, mergeEvent
.m_newSessionID
, mergeEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
507 //-------------------------------------------------------------------------
508 void CMMTelemetryProducer::OutputMergeRequestedData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
510 SMMMergeRequestedEvent
& mergeEvent
= reinterpret_cast<SMMMergeRequestedEvent
&>( eventPacket
);
511 entryString
.Format( "<mergeRequested newSessionId=\"%s\" timestamp=\"%" PRIi64
"\" />\n", mergeEvent
.m_sessionID
, mergeEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
514 //-------------------------------------------------------------------------
515 void CMMTelemetryProducer::OutputLaunchGameData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
517 SMMLaunchGameEvent
& launchEvent
= reinterpret_cast<SMMLaunchGameEvent
&>( eventPacket
);
518 entryString
.Format( "<matchStarted sessionId=\"%s\" timestamp=\"%" PRIi64
"\" />\n", launchEvent
.m_sessionID
, launchEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
521 //-------------------------------------------------------------------------
522 void CMMTelemetryProducer::OutputLeaveMatchMakingData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
524 SMMLeaveMatchMakingEvent
& leaveEvent
= reinterpret_cast<SMMLeaveMatchMakingEvent
&>( eventPacket
);
525 entryString
.Format( "<leftMatchMaking timestamp=\"%" PRIi64
"\" />\n", leaveEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
528 //-------------------------------------------------------------------------
529 void CMMTelemetryProducer::OutputPlayerJoinedMMData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
531 SMMPlayerJoinedMMEvent
& playerEvent
= reinterpret_cast<SMMPlayerJoinedMMEvent
&>( eventPacket
);
532 entryString
.Format( "<playerJoined guid=\"%s\" username=\"%s\" sessionId=\"%s\" numCurrentPlayers=\"%d\" isLocal=\"%d\" timestamp = \"%" PRIi64
"\" />\n",
533 playerEvent
.m_guid
, playerEvent
.m_userName
, playerEvent
.m_sessionID
, playerEvent
.m_nCurrentPlayers
,
534 playerEvent
.m_local
, playerEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
537 //-------------------------------------------------------------------------
538 void CMMTelemetryProducer::OutputPlayerLeftMMData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
540 SMMPlayerLeftMMEvent
& playerEvent
= reinterpret_cast<SMMPlayerLeftMMEvent
&>( eventPacket
);
541 entryString
.Format( "<playerLeft guid=\"%s\" username=\"%s\" sessionId=\"%s\" numCurrentPlayers=\"%d\" isLocal=\"%d\" timestamp=\"%" PRIi64
"\" />\n",
542 playerEvent
.m_guid
, playerEvent
.m_userName
, playerEvent
.m_sessionID
, playerEvent
.m_nCurrentPlayers
,
543 playerEvent
.m_local
, playerEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
546 //-------------------------------------------------------------------------
547 void CMMTelemetryProducer::OutputPlayerJoinedData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
549 SMMPlayerJoinedEvent
& playerEvent
= reinterpret_cast<SMMPlayerJoinedEvent
&>( eventPacket
);
551 entryString
.Format( "<playerJoined GUID=\"%s\" conUID=\"%d\" name=\"%s\" timestamp=\"%" PRIi64
"\" />\n",
552 playerEvent
.m_guid
, playerEvent
.m_conUID
.m_uid
, playerEvent
.m_name
, playerEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
555 //-------------------------------------------------------------------------
556 void CMMTelemetryProducer::OutputPlayerLeftData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
558 SMMPlayerLeftEvent
& playerEvent
= reinterpret_cast<SMMPlayerLeftEvent
&>( eventPacket
);
559 entryString
.Format( "<playerLeft GUID=\"%s\" conUID=\"%d\" timestamp=\"%" PRIi64
"\" />\n",
560 playerEvent
.m_guid
, playerEvent
.m_conUID
.m_uid
, playerEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
563 //-------------------------------------------------------------------------
564 void CMMTelemetryProducer::OutputPlayerPingData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
566 SMMPlayerPingEvent
& pingEvent
= reinterpret_cast<SMMPlayerPingEvent
&>( eventPacket
);
567 entryString
.Format( "<playerPing GUID=\"%s\" conUID=\"%d\" ping=\"%d\" timestamp=\"%" PRIi64
"\" />\n",
568 pingEvent
.m_guid
, pingEvent
.m_conUID
.m_uid
, pingEvent
.m_ping
, pingEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
571 //-------------------------------------------------------------------------
572 void CMMTelemetryProducer::OutputPlayerReportLagData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
574 SMMPlayerReportLagEvent
& lagEvent
= reinterpret_cast<SMMPlayerReportLagEvent
&>( eventPacket
);
575 entryString
.Format( "<playerReportLag GUID=\"%s\" timestamp=\"%" PRIi64
"\" />\n", lagEvent
.m_guid
, lagEvent
.m_timeStamp
.GetMilliSecondsAsInt64() );
578 void CMMTelemetryProducer::OutputGenericLogData( SRecording_Packet
& eventPacket
, EventDataString
& entryString
)
580 SMMGenericLogEvent
& logEvent
= reinterpret_cast<SMMGenericLogEvent
&>( eventPacket
);
582 if( logEvent
.m_bError
)
584 entryString
.Format( "<error message=\"%s\" />\n", logEvent
.m_message
);
588 entryString
.Format( "<log message=\"%s\" />\n", logEvent
.m_message
);