!I (1670414, 1670415, 1670416, 1670424, 1670431):
[CRYENGINE.git] / Code / GameSDK / GameDll / Network / Lobby / MatchmakingTelemetry.cpp
blob29c92284fa79a788529c2f5b35c62f4a95f2b19b
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 /*************************************************************************
4 -------------------------------------------------------------------------
5 $Id$
6 $DateTime$
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 -------------------------------------------------------------------------
13 History:
14 - 02:06:2011 : Created By Andrew Blackwell
16 *************************************************************************/
18 #include "StdAfx.h"
19 //////////////////////////////////////////////////////////////////////////
20 // This Include
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 //-------------------------------------------------------------------------
38 //Constructor
39 CMatchmakingTelemetry::CMatchmakingTelemetry()
41 m_pBuffer = NULL;
42 m_currentTranscript = eMMTelTranscript_None;
45 //--------------------------------------------------------------------------
46 //Destructor
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;
71 else
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;
94 else
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;
103 switch( transcript )
105 case eMMTelTranscript_QuickMatch:
106 nameBase = "matchmakingdata";
107 break;
108 case eMMTelTranscript_SessionQuality:
109 nameBase = "sessionperformance";
110 break;
111 default:
112 nameBase = "unknowndata";
115 if( logLocally )
117 CryFixedStringT<24> localFilename;
118 localFilename.Format( "%s%d.xml", nameBase, gEnv->pSystem->GetApplicationInstance() );
120 CTelemetrySaveToFile* pLogger = new CTelemetrySaveToFile( pProducer, localFilename.c_str() );
121 pProducer = pLogger;
124 CryFixedStringT<24> remoteFilename;
125 remoteFilename.Format( "%s.xml", nameBase );
127 tc->SubmitTelemetryProducer( pProducer, remoteFilename.c_str() );
129 //clear out buffer pointer
130 m_pBuffer = NULL;
131 m_currentTranscript = eMMTelTranscript_None;
134 CryLog( "MMT: End Transcript call finished" );
136 return retVal;
139 //-------------------------------------------------------------------------
140 void CMatchmakingTelemetry::AddEvent( const SMatchMakingEvent& event )
142 if( m_pBuffer )
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 );
155 #endif
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();
191 if( pGameLobby )
193 SCryMatchMakingConnectionUID conUID = pGameLobby->GetConnectionUIDFromChannelID( channelId );
194 CryUserID guid = pGameLobby->GetUserIDFromChannelID( channelId );
195 AddEvent( SMMPlayerLeftEvent( guid, conUID ) );
199 //-------------------------------------------------------------------------
200 //Matchmaking Telemetry Producer Section
202 //-------------------------------------------------------------------------
203 //Constructor
204 CMMTelemetryProducer::CMMTelemetryProducer( CRecordingBuffer* pInBuffer )
205 : m_pDataBuffer( pInBuffer ),
206 m_currentElement( pInBuffer->begin() )
210 //-------------------------------------------------------------------------
211 //Destructor
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 );
248 break;
249 case eMMTelE_FoundSession:
250 OutputFoundSessionData( *m_currentElement, entryString );
251 break;
252 case eMMTelE_ChosenSession:
253 OutputChosenSessionData( *m_currentElement, entryString );
254 break;
255 case eMMTelE_NoServerSelected:
256 OutputNoServerSelectedData( *m_currentElement, entryString );
257 break;
258 case eMMTelE_SearchTimedOut:
259 OutputSearchTimedOutData( *m_currentElement, entryString );
260 break;
261 case eMMTelE_ServerConnectFailed:
262 OutputServerConnectFailedData( *m_currentElement, entryString );
263 break;
264 case eMMTelE_MigrateHostLobby:
265 OutputMigrateHostLobbyData( *m_currentElement, entryString );
266 break;
267 case eMMTelE_BecomeServer:
268 OutputBecomeHostData( *m_currentElement, entryString );
269 break;
270 case eMMTelE_DemotedToClient:
271 OutputDemotedData( *m_currentElement, entryString );
272 break;
273 case eMMTelE_MigrateCompleted:
274 OutputMigrateCompletedData( *m_currentElement, entryString );
275 break;
276 case eMMTelE_ServerRequestMerge:
277 OutputServerRequestingMergeData( *m_currentElement, entryString );
278 break;
279 case eMMTelE_MergeRequested:
280 OutputMergeRequestedData( *m_currentElement, entryString );
281 break;
282 case eMMTelE_LaunchGame:
283 OutputLaunchGameData( *m_currentElement, entryString );
284 break;
285 case eMMTelE_LeaveMatchMaking:
286 OutputLeaveMatchMakingData( *m_currentElement, entryString );
287 break;
288 case eMMTelE_PlayerJoinedMM:
289 OutputPlayerJoinedMMData( *m_currentElement, entryString );
290 break;
291 case eMMTelE_PlayerLeftMM:
292 OutputPlayerLeftMMData( *m_currentElement, entryString );
293 break;
294 case eMMTelE_PlayerJoined:
295 OutputPlayerJoinedData( *m_currentElement, entryString );
296 break;
297 case eMMTelE_PlayerLeft:
298 OutputPlayerLeftData( *m_currentElement, entryString );
299 break;
300 case eMMTelE_PlayerPing:
301 OutputPlayerPingData( *m_currentElement, entryString );
302 break;
303 case eMMTelE_PlayerReportLag:
304 OutputPlayerReportLagData( *m_currentElement, entryString );
305 break;
307 case eMMTelE_GenericLog:
308 OutputGenericLogData( *m_currentElement, entryString );
309 break;
311 //Still Need to support these types:
312 //eMMTelE_MigrationClientAvailable:
313 //eMMTelE_MigrationClientChosen:
315 default: //not a type we have data for
316 entryString.clear();
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
326 ++m_currentElement;
328 else
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;
351 return retVal;
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 );
365 entryString += row;
368 if( CPlaylistManager* pPlaylistmanager = g_pGame->GetPlaylistManager() )
370 if( searchEvent.m_playlist != -1 )
372 row.Format( "playlist=\"%s\" ", pPlaylistmanager->GetPlaylistNameById(searchEvent.m_playlist) );
373 entryString += row;
376 if( searchEvent.m_variant != -1 )
378 row.Format( "variant=\"%s\" ", pPlaylistmanager->GetVariantName(searchEvent.m_variant) );
379 entryString += row;
383 if( searchEvent.m_searchRegion != -1 )
385 row.Format( "searchRegion=\"%d\" ", searchEvent.m_variant );
386 entryString += row;
388 else
390 row.Format( "regionlessSearch=\"1\" " );
391 entryString += row;
394 row.Format( "timestamp=\"%" PRIi64 "\" />\n", searchEvent.m_timeStamp.GetMilliSecondsAsInt64() );
395 entryString += row;
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";
410 break;
411 case CGameLobby::eAS_Game:
412 pStatusName = "InGame";
413 break;
414 case CGameLobby::eAS_EndGame:
415 pStatusName = "EndGame";
416 break;
417 case CGameLobby::eAS_StartingGame:
418 pStatusName = "StartGame";
419 break;
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 );
433 const char* tagName;
435 if( sessionEvent.m_created )
437 tagName = "createdServer";
439 else
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 );
586 else
588 entryString.Format( "<log message=\"%s\" />\n", logEvent.m_message );