10 enum SCR_EGameModeRecordType
28 class SCR_IGameModeRecord
35 SCR_EGameModeRecordType GetRecordType();
48 return string.Format(
"%1;%2;%3",
49 GetRecordType().ToString(),
50 GetTimestamp().ToString(),
57 protected string Save();
61 protected void Load(array<string> tokens);
65 static ref SCR_IGameModeRecord LoadFromString(
string str)
67 array<string> tokens = {};
68 str.Split(
";", tokens,
false);
70 int type = tokens[0].ToInt();
71 tokens.RemoveOrdered(0);
73 float timeStamp = tokens[0].ToFloat();
74 tokens.RemoveOrdered(0);
78 case SCR_EGameModeRecordType.Death:
80 ref SCR_IGameModeRecord record =
new SCR_DeathRecord();
81 record.m_fTimestamp = timeStamp;
87 case SCR_EGameModeRecordType.Movement:
89 ref SCR_IGameModeRecord record =
new SCR_MovementRecord();
90 record.m_fTimestamp = timeStamp;
96 case SCR_EGameModeRecordType.Connection:
98 ref SCR_IGameModeRecord record =
new SCR_ConnectionRecord();
99 record.m_fTimestamp = timeStamp;
105 case SCR_EGameModeRecordType.Spawn:
107 ref SCR_IGameModeRecord record =
new SCR_SpawnRecord();
108 record.m_fTimestamp = timeStamp;
114 case SCR_EGameModeRecordType.AILOD:
116 ref SCR_IGameModeRecord record =
new SCR_AILODRecord();
117 record.m_fTimestamp = timeStamp;
128 sealed
class SCR_DeathRecord : SCR_IGameModeRecord
131 vector m_InstigatorPosition;
133 FactionKey m_InstigatorFaction;
139 sealed
override SCR_EGameModeRecordType GetRecordType()
141 return SCR_EGameModeRecordType.Death;
145 override string Save()
148 string ipos =
string.Format(
"%1,%2,%3", m_InstigatorPosition[0], m_InstigatorPosition[1], m_InstigatorPosition[2]);
149 return string.Format(
"%1;%2;%3;%4;%5;%6;%7", pos, ipos,
m_Faction, m_InstigatorFaction, (
int)m_WeaponType, m_PlayerId, m_InstigatorId);
153 protected sealed
override void Load(array<string> tokens)
155 array <string> pos = {};
156 tokens[0].Split(
",", pos,
true);
157 m_Position = Vector(pos[0].ToFloat(), pos[1].ToFloat(), pos[2].ToFloat());
159 array <string> ipos = {};
160 tokens[1].Split(
",", ipos,
true);
161 m_InstigatorPosition = Vector(ipos[0].ToFloat(), ipos[1].ToFloat(), ipos[2].ToFloat());
164 m_InstigatorFaction = tokens[3];
166 m_WeaponType = tokens[4].ToInt();
167 m_PlayerId = tokens[5].ToInt();
168 m_InstigatorId = tokens[6].ToInt();
178 static ref SCR_DeathRecord CreateNew(
int playerId, IEntity playerEntity, IEntity killerEntity,
Instigator killer)
180 SCR_DeathRecord record =
new SCR_DeathRecord();
181 record.m_Position = playerEntity.GetOrigin();
182 record.m_fTimestamp = playerEntity.GetWorld().GetWorldTime();
183 record.m_PlayerId = playerId;
184 record.m_InstigatorId = killer.GetInstigatorPlayerID();
185 FactionAffiliationComponent factionComponent = FactionAffiliationComponent.Cast(playerEntity.FindComponent(FactionAffiliationComponent));
186 if (factionComponent)
188 Faction faction = factionComponent.GetAffiliatedFaction();
190 record.m_Faction = faction.GetFactionKey();
195 record.m_InstigatorPosition = killerEntity.GetOrigin();
197 ChimeraCharacter ch = ChimeraCharacter.Cast(killerEntity);
200 BaseWeaponManagerComponent wpm = ch.GetCharacterController().GetWeaponManagerComponent();
205 record.m_WeaponType = weapon.GetWeaponType();
209 FactionAffiliationComponent instigatorFactionComponent = FactionAffiliationComponent.Cast(killerEntity.FindComponent(FactionAffiliationComponent));
210 if (instigatorFactionComponent)
212 Faction instigatorFaction = instigatorFactionComponent.GetAffiliatedFaction();
213 if (instigatorFaction)
214 record.m_InstigatorFaction = instigatorFaction.GetFactionKey();
224 sealed
class SCR_MovementRecord : SCR_IGameModeRecord
230 sealed
override SCR_EGameModeRecordType GetRecordType()
232 return SCR_EGameModeRecordType.Movement;
236 override string Save()
239 return string.Format(
"%1;%2;", pos, m_PlayerId);
243 protected sealed
override void Load(array<string> tokens)
245 array <string> pos = {};
246 tokens[0].Split(
",", pos,
true);
247 m_Position = Vector(pos[0].ToFloat(), pos[1].ToFloat(), pos[2].ToFloat());
248 m_PlayerId = tokens[1].ToInt();
256 static ref SCR_MovementRecord CreateNew(IEntity player,
int playerId)
258 SCR_MovementRecord record =
new SCR_MovementRecord();
259 record.m_Position = player.GetOrigin();
260 record.m_PlayerId = playerId;
261 record.m_fTimestamp = player.GetWorld().GetWorldTime();
267 sealed
class SCR_ConnectionRecord : SCR_IGameModeRecord
273 sealed
override SCR_EGameModeRecordType GetRecordType()
275 return SCR_EGameModeRecordType.Connection;
279 override string Save()
281 return string.Format(
"%1;%2;", m_PlayerId, m_PlayerName);
285 protected sealed
override void Load(array<string> tokens)
287 m_PlayerId = tokens[0].ToInt();
288 m_PlayerName = tokens[1];
296 static ref SCR_ConnectionRecord CreateNew(
int playerId,
string playerName)
298 SCR_ConnectionRecord record =
new SCR_ConnectionRecord();
299 record.m_PlayerId = playerId;
300 record.m_PlayerName = playerName;
301 record.m_fTimestamp =
GetGame().GetWorld().GetWorldTime();
306 sealed
class SCR_SpawnRecord : SCR_IGameModeRecord
311 sealed
override SCR_EGameModeRecordType GetRecordType()
313 return SCR_EGameModeRecordType.Spawn;
316 override string Save()
318 return string.Format(
"%1;%2;", m_PlayerId, m_FactionColor);
321 protected sealed
override void Load(array<string> tokens)
323 m_PlayerId = tokens[0].ToInt();
324 m_FactionColor = tokens[1].ToInt();
329 void SCR_SpawnRecord()
337 static ref SCR_SpawnRecord CreateNew(
int playerId,
int factionColor)
339 SCR_SpawnRecord record =
new SCR_SpawnRecord();
340 record.m_PlayerId = playerId;
341 record.m_FactionColor = factionColor;
342 record.m_fTimestamp =
GetGame().GetWorld().GetWorldTime();
347 sealed
class SCR_AILODRecord : SCR_IGameModeRecord
354 int m_PerceptionCounter = 0;
356 sealed
override SCR_EGameModeRecordType GetRecordType()
358 return SCR_EGameModeRecordType.AILOD;
361 override string Save()
364 return string.Format(
"%1;%2;%3;%4;%5;%6", m_ID, pos, m_LOD,
m_Type, m_BTCounter, m_PerceptionCounter);
367 protected sealed
override void Load(array<string> tokens)
369 array <string> pos = {};
371 tokens[1].Split(
",", pos,
true);
372 m_Position = Vector(pos[0].ToFloat(), pos[1].ToFloat(), pos[2].ToFloat());
373 m_LOD = tokens[2].ToInt();
374 m_Type = tokens[3].ToInt();
375 m_BTCounter = tokens[4].ToInt();
376 m_PerceptionCounter = tokens[5].ToInt();
383 static ref SCR_AILODRecord CreateNew(AIAgent agent)
385 SCR_AILODRecord record =
new SCR_AILODRecord();
386 record.m_fTimestamp =
GetGame().GetWorld().GetWorldTime();
387 record.m_LOD = agent.GetLOD();
389 IEntity ent = agent.GetControlledEntity();
392 record.m_Type = ETypeOfAgent.Group;
393 record.m_Position = group.GetCenterOfMass();
398 record.m_Position = ent.GetOrigin();
399 if (AIFlock.Cast(agent))
400 record.m_Type = ETypeOfAgent.Bird;
402 record.m_Type = ETypeOfAgent.Player;
404 record.m_Type = ETypeOfAgent.Agent;
407 AIChimeraBehaviorTreeComponent btComp = AIChimeraBehaviorTreeComponent.Cast(agent.FindComponent(AIChimeraBehaviorTreeComponent));
409 record.m_BTCounter = btComp.GetSimulateCounter();
413 PerceptionComponent percComp = PerceptionComponent.Cast(ent.FindComponent(PerceptionComponent));
415 record.m_PerceptionCounter = percComp.GetSimulateCounter();
417 record.m_ID = agent.GetID().ToString().Substring(2,16);
423 class SCR_GameModeStatistics
426 static const int RECORD_INTERVAL_MS = 1000;
429 private static ref array<ref SCR_IGameModeRecord> s_aRecordBuffer = {};
432 private static ref FileHandle s_pFileHandle;
435 private static const string k_sExtension =
".txt";
439 static bool IsRecording()
449 static void StartRecording()
453 Debug.Error(
"Already recording!");
457 string filename =
"GameStatistics_" + FormatTimestamp() + k_sExtension;
458 s_pFileHandle = FileIO.OpenFile(
"$logs:/" + filename, FileMode.WRITE);
463 static bool CanFlush()
465 return s_aRecordBuffer.Count() > 0;
474 Debug.Error(
"Cannot flush buffer, statistics are not being recorded!");
482 for (
int i = 0, count = s_aRecordBuffer.Count(); i < count; i++)
484 SCR_IGameModeRecord record = s_aRecordBuffer[i];
488 string entry = record.SaveToString();
492 s_pFileHandle.WriteLine(entry);
496 s_aRecordBuffer.Clear();
501 static void StopRecording()
505 Debug.Error(
"Not recording!");
513 s_pFileHandle.Close();
514 s_pFileHandle =
null;
523 static void RecordDeath(
int playerId, IEntity playerEntity, IEntity killerEntity,
Instigator killer)
525 SCR_DeathRecord rec = SCR_DeathRecord.CreateNew(playerId, playerEntity, killerEntity, killer);
526 s_aRecordBuffer.Insert(rec);
533 static void RecordMovement(IEntity player,
int playerId)
535 SCR_MovementRecord rec = SCR_MovementRecord.CreateNew(player, playerId);
536 s_aRecordBuffer.Insert(rec);
543 static void RecordConnection(
int playerId,
string playerName)
545 SCR_ConnectionRecord rec = SCR_ConnectionRecord.CreateNew(playerId, playerName);
546 s_aRecordBuffer.Insert(rec);
553 static void RecordSpawn(
int playerId,
int factionColor)
555 SCR_SpawnRecord rec = SCR_SpawnRecord.CreateNew(playerId, factionColor);
556 s_aRecordBuffer.Insert(rec);
562 static void RecordAILOD(AIAgent aiagent)
564 SCR_AILODRecord rec = SCR_AILODRecord.CreateNew(aiagent);
565 s_aRecordBuffer.Insert(rec);
570 static int OpenStatistics(
string filename, notnull array<ref SCR_IGameModeRecord> outRecords)
573 if (!filename.EndsWith(k_sExtension))
574 filename += k_sExtension;
576 if (!FileIO.FileExists(filename))
579 FileHandle fileHnd = FileIO.OpenFile(filename, FileMode.READ);
585 while (fileHnd.ReadLine(temp) > 0)
587 ref SCR_IGameModeRecord record = SCR_IGameModeRecord.LoadFromString(temp);
590 outRecords.Insert(record);
602 static void FilterRecords(
typename predicate, notnull array<SCR_IGameModeRecord> records, out array<SCR_IGameModeRecord> filteredRecords)
604 foreach (SCR_IGameModeRecord record : records)
606 if (record.Type().IsInherited(predicate))
607 filteredRecords.Insert(record);
613 static void FilterRecordsRefRef(
typename predicate, notnull array<ref SCR_IGameModeRecord> records, out array<ref SCR_IGameModeRecord> filteredRecords)
615 foreach (SCR_IGameModeRecord record : records)
617 if (record.Type().IsInherited(predicate))
618 filteredRecords.Insert(record);
624 static void FilterRecordsWeakRef(
typename predicate, notnull array<SCR_IGameModeRecord> records, out array<ref SCR_IGameModeRecord> filteredRecords)
626 foreach (SCR_IGameModeRecord record : records)
628 if (record.Type().IsInherited(predicate))
629 filteredRecords.Insert(record);
635 private static string FormatTimestamp()
637 int year, month, day;
638 System.GetYearMonthDay(year, month, day);
641 smonth =
string.Format(
"0%1", month);
643 smonth =
string.Format(
"%1", month);
646 sday =
string.Format(
"0%1", day);
648 sday =
string.Format(
"%1", day);
651 System.GetHourMinuteSecond(h, m, s);
654 sh =
string.Format(
"0%1", h);
656 sh =
string.Format(
"%1", h);
659 sm =
string.Format(
"0%1", m);
661 sm =
string.Format(
"%1", m);
663 ss =
string.Format(
"0%1", s);
665 ss =
string.Format(
"%1", s);
667 return string.Format(
"%1%2%3-%4%5%6", year, smonth, sday, sh, sm, ss);
672 class SCR_StatisticsDrawerEntityClass : GenericEntityClass
679 protected ref array<ref SCR_IGameModeRecord> m_aRecords;
682 protected bool m_bUseHistory =
false;
685 protected bool m_bNoZBuffer =
false;
688 protected float m_fGizmosScaleMultiplier = 1.0;
691 protected int m_iUniquePlayerCount = 0;
694 protected int m_iTargetPlayer = 0;
697 protected bool m_bDraw =
true;
700 protected bool m_bDrawDeaths =
true;
703 protected bool m_bDrawDeathsInfo =
true;
706 protected bool m_bDrawMovement =
true;
709 protected bool m_bDrawPlayerNames =
true;
712 protected bool m_bDrawAILODs =
true;
715 protected bool m_bAutoPlay;
718 protected float m_fPlaybackSpeed = 1.0;
721 protected float m_fCurrentTime;
724 protected float m_fMaxTime;
727 protected float m_fHistoryLength = 10000;
730 protected ref map<int, ref array<ref SCR_IGameModeRecord>> m_aDeathRecords =
new map<int, ref array<ref SCR_IGameModeRecord>>();
733 protected ref map<int, ref array<ref SCR_IGameModeRecord>> m_aMovementRecords =
new map<int, ref array<ref SCR_IGameModeRecord>>();
736 protected ref map<int, ref array<ref SCR_IGameModeRecord>> m_aSpawnRecords =
new map<int, ref array<ref SCR_IGameModeRecord>>();
739 protected ref array<ref SCR_IGameModeRecord> m_aConnectionRecords = {};
742 protected ref map<string, ref array<ref SCR_IGameModeRecord>> m_aAILODRecords =
new map<string, ref array<ref SCR_IGameModeRecord>>();
744 protected ref array<ref Shape> m_aShapes = {};
745 protected ref array<ref DebugText> m_aTexts = {};
748 protected ref map<int, string> m_mPlayerNames =
new map<int, string>();
753 private static const float MAX_MOVEMENT_SPEED = 11.1;
755 protected static const float TELEPORT_DISTANCE = MAX_MOVEMENT_SPEED * (SCR_GameModeStatistics.RECORD_INTERVAL_MS / 1000.0);
756 protected static const float TELEPORT_DISTANCE_SQ = TELEPORT_DISTANCE * TELEPORT_DISTANCE;
759 protected static const int PLAYER_COLORS_COUNT = 27;
760 protected static const vector PLAYER_COLORS_ARRAY[PLAYER_COLORS_COUNT] = {
761 "255 255 255",
"169 244 0",
"244 67 54",
"233 30 99",
"156 39 176",
"63 81 181",
"0 188 212",
"0 150 136",
"76 175 80",
"205 220 57",
762 "255 235 59",
"255 152 0",
"121 85 72",
"95 125 139",
"62 69 81",
"3 159 244",
"244 67 54",
"233 30 99",
"156 39 176",
763 "63 81 181",
"0 188 212",
"0 150 136",
"76 175 80",
"205 220 57",
"255 235 59",
"255 157 0",
"121 85 139"
766 protected static const vector AILOD_COLORS_ARRAY[11] = {
780 protected bool m_bFactionColors =
false;
784 protected bool IsEmpty()
786 if (!m_aRecords || m_aRecords.Count() < 1)
794 protected bool OpenStatisticsFile(
string filename)
797 int count = SCR_GameModeStatistics.OpenStatistics(filename, m_aRecords);
803 protected void Clear()
807 m_aDeathRecords.Clear();
808 m_aMovementRecords.Clear();
809 m_aConnectionRecords.Clear();
810 m_aAILODRecords.Clear();
818 protected void Close()
826 protected void LoadRecords(array<ref SCR_IGameModeRecord> records)
831 array<ref SCR_IGameModeRecord> deaths = {};
832 SCR_GameModeStatistics.FilterRecordsRefRef(SCR_DeathRecord, records, deaths);
834 array<ref SCR_IGameModeRecord> movement = {};
835 SCR_GameModeStatistics.FilterRecordsRefRef(SCR_MovementRecord, records, movement);
837 array<ref SCR_IGameModeRecord> lodRecords = {};
838 SCR_GameModeStatistics.FilterRecordsRefRef(SCR_AILODRecord, records, lodRecords);
840 SCR_GameModeStatistics.FilterRecordsRefRef(SCR_ConnectionRecord, records, m_aConnectionRecords);
842 array<ref SCR_IGameModeRecord> spawn = {};
843 SCR_GameModeStatistics.FilterRecordsRefRef(SCR_SpawnRecord, records, spawn);
845 vector max =
"-999999 -999999 -999999";
846 vector min =
"999999 999999 999999";
849 m_aMovementRecords.Clear();
850 foreach (SCR_IGameModeRecord record : movement)
852 SCR_MovementRecord movementRecord = SCR_MovementRecord.Cast(record);
853 if (!m_aMovementRecords.Contains(movementRecord.m_PlayerId))
856 m_aMovementRecords.Insert(movementRecord.m_PlayerId,
new array<ref SCR_IGameModeRecord>());
860 m_aMovementRecords[movementRecord.m_PlayerId].Insert(movementRecord);
863 for (
int i = 0; i < 3; i++)
865 if (movementRecord.m_Position[i] < min[i])
866 min[i] = movementRecord.m_Position[i];
868 if (movementRecord.m_Position[i] > max[i])
869 max[i] = movementRecord.m_Position[i];
874 m_aDeathRecords.Clear();
875 foreach (SCR_IGameModeRecord record : deaths)
877 SCR_DeathRecord deathRecord = SCR_DeathRecord.Cast(record);
878 if (!m_aDeathRecords.Contains(deathRecord.m_PlayerId))
881 m_aDeathRecords.Insert(deathRecord.m_PlayerId,
new array<ref SCR_IGameModeRecord>());
885 m_aDeathRecords[deathRecord.m_PlayerId].Insert(deathRecord);
890 m_aSpawnRecords.Clear();
891 foreach (SCR_IGameModeRecord record : spawn)
893 SCR_SpawnRecord spawnRecord = SCR_SpawnRecord.Cast(record);
894 if (!m_aSpawnRecords.Contains(spawnRecord.m_PlayerId))
897 m_aSpawnRecords.Insert(spawnRecord.m_PlayerId,
new array<ref SCR_IGameModeRecord>());
901 m_aSpawnRecords[spawnRecord.m_PlayerId].Insert(spawnRecord);
905 m_aAILODRecords.Clear();
906 foreach (SCR_IGameModeRecord record : lodRecords)
908 SCR_AILODRecord lodRecord = SCR_AILODRecord.Cast(record);
909 if (!m_aAILODRecords.Contains(lodRecord.m_ID))
912 m_aAILODRecords.Insert(lodRecord.m_ID,
new array<ref SCR_IGameModeRecord>());
916 m_aAILODRecords[lodRecord.m_ID].Insert(lodRecord);
920 if (records.Count() > 0)
921 m_fMaxTime = records[records.Count() - 1].GetTimestamp();
926 m_iUniquePlayerCount = 0;
927 m_mPlayerNames.Clear();
928 for (
int i = 0, count = m_aConnectionRecords.Count(); i < count; ++i)
930 SCR_ConnectionRecord record = SCR_ConnectionRecord.Cast(m_aConnectionRecords[i]);
931 int playerId = record.m_PlayerId;
935 if (!m_mPlayerNames.Contains(playerId))
937 string name =
"Unnamed";
938 if (!record.m_PlayerName.IsEmpty())
939 name = record.m_PlayerName;
941 m_mPlayerNames.Insert(playerId, name);
942 ++m_iUniquePlayerCount;
952 private bool DrawCheck(
string label, inout
bool outValue)
954 bool previousValue = outValue;
955 DbgUI.Check(label, outValue);
956 return previousValue != outValue;
961 private bool DrawSlider(
string label, inout
float outValue,
float min,
float max,
int pxWidth)
963 float previousValue = outValue;
964 DbgUI.SliderFloat(label, outValue, min, max, pxWidth);
965 return previousValue != outValue;
970 private bool DrawAdvancementButton(
string negativeLabel,
string positiveLabel, inout
float refValue,
float addValue)
972 float previousValue = refValue;
973 if (DbgUI.Button(negativeLabel)) refValue = refValue - addValue;
975 if (DbgUI.Button(positiveLabel)) refValue = refValue + addValue;
976 return (previousValue != refValue);
980 protected override void EOnFrame(IEntity owner,
float timeSlice)
982 bool isDirty =
false;
984 int spacerHeight = 32;
986 DbgUI.Begin(
"GameMode Statistics");
991 DbgUI.Text(
"File to open: ");
992 string filename =
"MyFile.gmstats";
993 DbgUI.InputText(
"", filename, pxWidth);
995 if (DbgUI.Button(
"Open"))
999 OpenStatisticsFile(filename);
1000 LoadRecords(m_aRecords);
1007 DbgUI.Text(
"No data, load statistics first!");
1014 if (DbgUI.Button(
"Close"))
1019 m_fCurrentTime = 0.0;
1020 m_bAutoPlay =
false;
1027 DbgUI.Text(
string.Format(
"Total Records: %1", m_aRecords.Count()));
1030 DbgUI.Spacer(spacerHeight);
1031 DbgUI.Text(
"Properties");
1032 if (DrawCheck(
"Enabled", m_bDraw)) isDirty =
true;
1033 if (DrawCheck(
"Draw Death Records", m_bDrawDeaths)) isDirty =
true;
1034 if (m_bDrawDeaths && DrawCheck(
"Draw Death Infoboxes", m_bDrawDeathsInfo)) isDirty =
true;
1035 if (DrawCheck(
"Draw Movement Records", m_bDrawMovement)) isDirty =
true;
1036 if (DrawCheck(
"Draw Player List", m_bDrawPlayerNames)) isDirty =
true;
1037 if (DrawCheck(
"Draw AILODs", m_bDrawAILODs)) isDirty =
true;
1038 if (DrawCheck(
"Limit History Length", m_bUseHistory)) isDirty =
true;
1039 if (DrawCheck(
"No Z Buffer", m_bNoZBuffer)) isDirty =
true;
1040 if (DrawCheck(
"Faction Colors", m_bFactionColors)) isDirty =
true;
1041 if (DrawSlider(
"Gizmos Scale", m_fGizmosScaleMultiplier, 0.1, 25.0, pxWidth)) isDirty =
true;
1042 if (DbgUI.Button(
"Re-center camera"))
1048 DbgUI.Text(
"History Length = " + m_fHistoryLength * 0.001 +
"s");
1049 if (DrawSlider(
"History Length", m_fHistoryLength, 100, 1000000, pxWidth)) isDirty =
true;
1051 DbgUI.Spacer(spacerHeight);
1052 DbgUI.Text(
"Playback");
1053 DbgUI.Text(
string.Format(
"Time: %1 / %2 s", m_fCurrentTime * 0.001, m_fMaxTime * 0.001));
1055 string autoPlayText;
1057 autoPlayText =
"Pause";
1059 autoPlayText =
"Play";
1062 if (DbgUI.Button(autoPlayText))
1063 m_bAutoPlay = !m_bAutoPlay;
1066 if (DbgUI.Button(
"Stop"))
1068 m_bAutoPlay =
false;
1069 m_fCurrentTime = 0.0;
1074 if (DrawSlider(
"Playback Speed: " + m_fPlaybackSpeed +
"x", m_fPlaybackSpeed, 0.0, 16.0, pxWidth)) {}
1078 DbgUI.InputInt(
"Seek Time: (s)", seekTime, pxWidth);
1080 if (DbgUI.Button(
"Seek"))
1082 m_fCurrentTime = seekTime * 1000.0;
1087 if (DrawAdvancementButton(
"-1s",
"+1s", m_fCurrentTime, 1000)) isDirty =
true;
1089 if (DrawAdvancementButton(
"-2s",
"+2s", m_fCurrentTime, 2000)) isDirty =
true;
1091 if (DrawAdvancementButton(
"-5s",
"+5s", m_fCurrentTime, 5000)) isDirty =
true;
1093 if (DrawAdvancementButton(
"-10s",
"+10s", m_fCurrentTime, 10000)) isDirty =
true;
1095 if (DrawAdvancementButton(
"-30s",
"+30s", m_fCurrentTime, 30000)) isDirty =
true;
1097 if (DrawAdvancementButton(
"-60s",
"+60s", m_fCurrentTime, 60000)) isDirty =
true;
1099 if (DrawAdvancementButton(
"-100s",
"+100s", m_fCurrentTime, 100000)) isDirty =
true;
1101 if (DrawAdvancementButton(
"-300s",
"+300s", m_fCurrentTime, 300000)) isDirty =
true;
1103 if (DrawAdvancementButton(
"-600s",
"+600s", m_fCurrentTime, 600000)) isDirty =
true;
1106 m_fCurrentTime = Math.Clamp(m_fCurrentTime, 0, m_fMaxTime);
1111 m_fCurrentTime += timeSlice * m_fPlaybackSpeed * 1000.0;
1120 if (m_bDrawPlayerNames)
1121 if (DrawPlayerList(pxWidth, spacerHeight)) isDirty =
true;
1131 protected void Repaint()
1141 if (m_bDrawMovement)
1142 RepaintMovement(m_iTargetPlayer);
1145 RepaintDeaths(m_iTargetPlayer);
1153 protected bool DrawPlayerList(
int pxWidth = 150,
int spacerHeight = 16)
1155 bool isDirty =
false;
1156 DbgUI.Begin(
"Player List");
1159 string filterText =
"Filter : ";
1160 if (m_iTargetPlayer <= 0)
1161 filterText +=
"All players";
1165 if (m_mPlayerNames.Contains(m_iTargetPlayer))
1166 filterText += m_mPlayerNames[m_iTargetPlayer];
1168 filterText +=
"N/A";
1171 filterText =
string.Format(
"%1 (Id: %2)", filterText, m_iTargetPlayer);
1175 int previousValue = m_iTargetPlayer;
1176 DbgUI.Text(filterText);
1177 if (DrawSlider(
"", m_iTargetPlayer, 0, m_iUniquePlayerCount, pxWidth)) isDirty =
true;
1180 DbgUI.Spacer(spacerHeight);
1181 DbgUI.Text(
"Players: ");
1182 foreach (
int playerId,
string playerName : m_mPlayerNames)
1184 string playerText =
string.Format(
"%1: %2", playerId, playerName);
1187 vector rgb = PLAYER_COLORS_ARRAY[ playerId % PLAYER_COLORS_COUNT ];
1188 int color = ARGB(255, rgb[0], rgb[1], rgb[2]);
1189 DbgUI.Panel(playerText+
"_panel", 16, 16, color);
1192 DbgUI.Text(playerText);
1200 protected float GetAlpha(
float timeStamp)
1202 return Math.InverseLerp(m_fCurrentTime - m_fHistoryLength, m_fCurrentTime, timeStamp);
1206 protected int GetShapeFlags()
1208 int flags = ShapeFlags.TRANSP;
1210 flags |= ShapeFlags.NOZBUFFER;
1216 protected void RepaintAILODs()
1218 vector characterRGB = PLAYER_COLORS_ARRAY[0];
1219 vector groupRGB = PLAYER_COLORS_ARRAY[1];
1221 int shapeFlags = GetShapeFlags();
1222 float baseSphereScale = m_fGizmosScaleMultiplier * 0.25;
1223 float baseCylinderScale = m_fGizmosScaleMultiplier * 2.5;
1224 foreach(array<ref SCR_IGameModeRecord> lodRecords : m_aAILODRecords)
1227 for (
int j = 0; j < lodRecords.Count(); j++)
1229 SCR_AILODRecord aiRecord = SCR_AILODRecord.Cast(lodRecords[j]);
1230 SCR_AILODRecord prevAiRecord;
1232 prevAiRecord = SCR_AILODRecord.Cast(lodRecords[j-1]);
1233 float timeStamp = aiRecord.GetTimestamp();
1239 if (timeStamp > m_fCurrentTime)
1243 alpha = GetAlpha(timeStamp);
1244 if (alpha <= 0.0 || alpha > 1.0)
1249 vector LODcolor = AILOD_COLORS_ARRAY[aiRecord.m_LOD];
1250 color = ARGB(255 * alpha, LODcolor[0], LODcolor[1], LODcolor[2]);
1252 float scaleAlpha = Math.Lerp(0.7, 1.0, alpha);
1253 if (aiRecord.m_Type == ETypeOfAgent.Group)
1255 ref Shape cylinder = Shape.CreateCylinder(color, shapeFlags | ShapeFlags.NOOUTLINE, aiRecord.m_Position, baseSphereScale * scaleAlpha, baseCylinderScale * scaleAlpha);
1256 m_aShapes.Insert(cylinder);
1258 else if ((aiRecord.m_Type == ETypeOfAgent.Agent))
1260 ref Shape sphere = Shape.CreateSphere(color, shapeFlags | ShapeFlags.NOOUTLINE, aiRecord.m_Position, baseSphereScale * scaleAlpha);
1261 m_aShapes.Insert(sphere);
1263 else if ((aiRecord.m_Type == ETypeOfAgent.Bird))
1266 points[0] = aiRecord.m_Position - Vector(m_fGizmosScaleMultiplier, 0, 0);
1267 points[1] = aiRecord.m_Position + Vector(m_fGizmosScaleMultiplier, 0, 0);
1268 points[2] = aiRecord.m_Position - Vector(0, m_fGizmosScaleMultiplier, 0);
1269 points[3] = aiRecord.m_Position + Vector(0, m_fGizmosScaleMultiplier, 0);
1270 points[4] = aiRecord.m_Position - Vector(0, 0, m_fGizmosScaleMultiplier);
1271 points[5] = aiRecord.m_Position + Vector(0, 0, m_fGizmosScaleMultiplier);
1272 points[6] = aiRecord.m_Position - Vector(m_fGizmosScaleMultiplier, 0, 0);
1273 ref Shape sphere = Shape.CreateLines(color, shapeFlags | ShapeFlags.NOOUTLINE, points, 7);
1274 m_aShapes.Insert(sphere);
1278 ref Shape cylinder = Shape.CreateCylinder(ARGB(255 * alpha, 0xff, 0xff, 0 ),
1279 shapeFlags | ShapeFlags.NOOUTLINE, aiRecord.m_Position, baseSphereScale * scaleAlpha, baseCylinderScale * scaleAlpha);
1280 m_aShapes.Insert(cylinder);
1282 int btCounterNum = aiRecord.m_BTCounter;
1283 int percCounterNum = aiRecord.m_PerceptionCounter;
1284 if (!btCounterNum && !percCounterNum)
1288 btCounterNum -= prevAiRecord.m_BTCounter;
1289 percCounterNum -= prevAiRecord.m_PerceptionCounter;
1291 string text =
string.Format(
"%1,%2", btCounterNum, percCounterNum);
1296 mat[3] = aiRecord.m_Position + 3 * vector.Up;
1298 ref DebugText textShape = DebugTextWorldSpace.CreateInWorld(GetWorld(), text, DebugTextFlags.FACE_CAMERA | DebugTextFlags.CENTER, mat, 0.5, color, 0xFF111111);
1299 m_aTexts.Insert(textShape);
1305 protected void RepaintDeaths(
int filterPlayerId = -1)
1307 const int black50A = ARGB(100, 0, 0, 0);
1308 int shapeFlags = GetShapeFlags();
1310 foreach (
int playerId, array<ref SCR_IGameModeRecord> playerRecords : m_aDeathRecords)
1313 if (filterPlayerId > 0)
1315 if (filterPlayerId != playerId)
1319 array<ref SCR_IGameModeRecord> spawnRecords= m_aSpawnRecords.Get(playerId);
1322 const vector extents =
"0.25 0.25 0.25";
1323 vector scaledExtents = m_fGizmosScaleMultiplier * extents;
1324 foreach (SCR_IGameModeRecord genericRecord : playerRecords)
1326 SCR_DeathRecord record = SCR_DeathRecord.Cast(genericRecord);
1327 float timeStamp = record.GetTimestamp();
1333 if (timeStamp > m_fCurrentTime)
1337 alpha = GetAlpha(timeStamp);
1338 if (alpha <= 0.0 || alpha > 1.0)
1342 int instigatorColor = black50A;
1344 vector victimRGB = PLAYER_COLORS_ARRAY[ record.m_PlayerId % PLAYER_COLORS_COUNT ];
1346 if (m_bFactionColors && spawnRecords)
1348 while(spawnId > -1 && spawnRecords[spawnId].GetTimestamp() > timeStamp)
1350 while(spawnId+1 < spawnRecords.Count() && spawnRecords[spawnId+1].GetTimestamp() < timeStamp)
1352 victimColor = SCR_SpawnRecord.Cast(spawnRecords[spawnId]).m_FactionColor;
1355 victimColor = ARGB(255 * alpha, victimRGB[0], victimRGB[1], victimRGB[2]);
1358 vector instigatorPosition;
1360 if (m_bDrawDeathsInfo)
1367 string victimName =
"Unknown";
1368 if (m_mPlayerNames.Contains(record.m_PlayerId))
1369 victimName = m_mPlayerNames[record.m_PlayerId];
1372 string instigatorName =
"Unknown";
1373 if (record.m_InstigatorId > 0)
1374 if (m_mPlayerNames.Contains(record.m_InstigatorId))
1375 instigatorName = m_mPlayerNames[record.m_InstigatorId];
1379 if (record.m_InstigatorId != record.m_PlayerId &&
1380 record.m_InstigatorPosition != record.m_Position)
1382 vector instigatorRGB = PLAYER_COLORS_ARRAY[ record.m_InstigatorId % PLAYER_COLORS_COUNT ];
1383 instigatorColor = ARGB(alpha * 255, instigatorRGB[0], instigatorRGB[1], instigatorRGB[2]);
1385 ref Shape arrowShape = Shape.CreateArrow(record.m_InstigatorPosition, record.m_Position, 0.5, instigatorColor, shapeFlags);
1386 m_aShapes.Insert(arrowShape);
1388 float distance = vector.Distance(record.m_InstigatorPosition, record.m_Position);
1389 deathText =
string.Format(
"Victim: %1\nFaction: %2\n\nInstigator: %3\nFaction: %4\n\nDistance: %5m\nWeapon: %6\nTime: %7s",
1393 record.m_InstigatorFaction,
1395 typename.EnumToString(
EWeaponType, record.m_WeaponType),
1399 instigatorPosition = record.m_InstigatorPosition;
1404 deathText =
string.Format(
"Victim: %1\nFaction:(%2)\n\nInstigator: (Self/Unknown)\n\nTime: %3s",
1411 instigatorPosition = record.m_Position;
1412 instigatorColor = victimColor;
1416 int backgroundColor = ARGB(100 * alpha, 0.0, 0.0, 0.0);
1419 vector textPosition = vector.Lerp(record.m_Position, instigatorPosition, 0.5) +
"0 0.1 0";
1420 ref DebugText textShape = DebugTextWorldSpace.Create(GetWorld(), deathText, DebugTextFlags.FACE_CAMERA | DebugTextFlags.CENTER, textPosition[0], textPosition[1], textPosition[2], 16.0, color: instigatorColor, bgColor: backgroundColor);
1421 m_aTexts.Insert(textShape);
1425 ref Shape deathShape = Shape.Create(ShapeType.BBOX, victimColor, shapeFlags, -scaledExtents, scaledExtents);
1426 vector transformation[4];
1427 Math3D.MatrixIdentity3(transformation);
1428 transformation[3] = record.m_Position;
1429 deathShape.SetMatrix(transformation);
1431 m_aShapes.Insert(deathShape);
1437 protected void RepaintMovement(
int filterPlayerId = -1)
1439 int shapeFlags = GetShapeFlags();
1440 float baseSphereScale = m_fGizmosScaleMultiplier * 0.125;
1441 float baseArrowScale = m_fGizmosScaleMultiplier * 0.25;
1442 foreach (
int playerId, array<ref SCR_IGameModeRecord> playerRecords : m_aMovementRecords)
1445 if (filterPlayerId > 0)
1447 if (filterPlayerId != playerId)
1452 array<ref SCR_IGameModeRecord> spawnRecords= m_aSpawnRecords.Get(playerId);
1455 for (
int i = 0, count = playerRecords.Count(); i < count - 1; i++)
1457 SCR_MovementRecord record = SCR_MovementRecord.Cast(playerRecords[i]);
1458 float timeStamp = record.GetTimestamp();
1461 SCR_MovementRecord nextRecord = SCR_MovementRecord.Cast(playerRecords[i+1]);
1466 if (timeStamp > m_fCurrentTime)
1470 alpha = GetAlpha(timeStamp);
1471 if (alpha <= 0.0 || alpha > 1.0)
1477 if (vector.DistanceSqXZ(record.m_Position, nextRecord.m_Position) >= TELEPORT_DISTANCE_SQ)
1480 vector playerRGB = PLAYER_COLORS_ARRAY[ record.m_PlayerId % PLAYER_COLORS_COUNT ];
1482 if (m_bFactionColors && spawnRecords)
1484 while(spawnId > -1 && spawnRecords[spawnId].GetTimestamp() > timeStamp)
1486 while(spawnId+1 < spawnRecords.Count() && spawnRecords[spawnId+1].GetTimestamp() < timeStamp)
1488 playerColor = SCR_SpawnRecord.Cast(spawnRecords[spawnId]).m_FactionColor;
1491 playerColor = ARGB(255 * alpha, playerRGB[0], playerRGB[1], playerRGB[2]);
1496 float scaleAlpha = Math.Lerp(0.7, 1.0, alpha);
1497 ref Shape arrowShape = Shape.CreateArrow(record.m_Position, nextRecord.m_Position, baseArrowScale * scaleAlpha, playerColor, shapeFlags);
1498 ref Shape sphereShape = Shape.CreateSphere(playerColor, shapeFlags | ShapeFlags.NOOUTLINE, record.m_Position, baseSphereScale * scaleAlpha);
1499 m_aShapes.Insert(arrowShape);
1500 m_aShapes.Insert(sphereShape);
1506 protected void FocusCamera(vector mins, vector maxs,
float height = 100.0)
1508 CameraManager cameraManager =
GetGame().GetCameraManager();
1512 CameraBase camera = cameraManager.CurrentCamera();
1516 vector center = vector.Lerp(mins, maxs, 0.5);
1517 vector
position = Vector(center[0], center[1] + height, center[2]);
1519 vector transform[4];
1520 Math3D.AnglesToMatrix(
"0 -89.9 0", transform);
1523 camera.SetWorldTransform(transform);
1530 void SCR_StatisticsDrawerEntity(IEntitySource src, IEntity parent)
1532 SetEventMask(EntityEvent.INIT | EntityEvent.FRAME);
1538 void ~SCR_StatisticsDrawerEntity()