45 private string m_cameraEntityName;
48 private string m_pageName;
51 private string m_testName;
54 private string m_heatmapName;
60 private float m_stepWaitTime;
63 private float m_cameraHeight;
65 [
Attribute(
"10",
UIWidgets.Slider,
"Number of slowest points for lowest FPS graph",
"10 50 1")]
66 private int m_lowFrameCount;
69 private string mapName;
73 private bool OverwriteWorldBounds;
76 private int WorldStartX;
79 private int WorldStartZ;
82 private int WorldEndX;
85 private int WorldEndZ;
101 private int fpsRange;
104 private float timeOfTheDay;
107 private string mapID;
109 [
Attribute(
"false",
UIWidgets.CheckBox,
"Skips actual measuring and only feed the json with fake data (meant for testing).")]
110 private bool SimulateHttpPost;
112 [
Attribute(
"true",
UIWidgets.CheckBox,
"Send collected json data to WebApp via HttpPost.")]
113 private bool SendHttpPost;
119 private const string HEATMAP_URL =
"https://ar-heatmap.bistudio.com/";
128 private int m_x = startX;
130 private int m_z = startZ;
132 private int endX_trimed = endX;
133 private int endZ_trimed = endZ;
135 private int m_worldSize;
136 private int m_worldSizeX;
137 private int m_worldSizeZ;
138 private vector m_minBounds, m_maxBounds;
142 private ref array<ref HeatmapData> m_geojson_data =
new array<ref HeatmapData>();
143 private ref array<int> image_file =
new array<int>();
145 private float min_fps = 1000;
146 private float max_fps = 0;
147 private float avg_fps = 0;
151 private bool area_only;
153 private float fps_four_directions[4];
154 private int prev_dir = -1;
156 private int directions[4] = {
163 private int colors[6] = {
172 void SCR_HeatMap_Autotest(IEntitySource src,
IEntity parent)
181 Print(
"[FPS_Autotest] " + text, logLevel);
184 override void EOnInit(
IEntity owner)
186 if(SCR_Global.IsEditMode())
188 ChimeraWorld world =
GetGame().GetWorld();
190 if (world && world.GetTimeAndWeatherManager())
192 world.GetTimeAndWeatherManager().SetTimeOfTheDay(timeOfTheDay);
193 world.GetTimeAndWeatherManager().SetIsDayAutoAdvanced(
false);
198 area_only = (!(startX > endX) || !(startZ > endZ) || !((endX - startX) >= m_step) || !((endZ - startZ) >= m_step));
200 m_camera =
GetGame().FindEntity(m_cameraEntityName);
205 float groundY = m_camera.GetWorld().GetSurfaceY(m_x, m_z);
206 m_y = groundY + m_cameraHeight;
207 m_camera.SetOrigin(
Vector(m_x, m_y, m_z));
209 vector new_angles = m_camera.GetAngles();
211 m_camera.SetAngles(new_angles);
215 PrintToConsole(
"Camera not found.",
LogLevel.ERROR);
220 if(OverwriteWorldBounds)
222 m_minBounds[0] = WorldStartX;
223 m_minBounds[2] = WorldStartZ;
224 m_maxBounds[0] = WorldEndX;
225 m_maxBounds[2] = WorldEndZ;
229 if (
GetGame().GetWorldEntity())
231 if (!OverwriteWorldBounds)
232 GetGame().GetWorldEntity().GetWorldBounds(m_minBounds, m_maxBounds);
242 m_worldSize = Math.Max(m_maxBounds[0] - m_minBounds[0], m_maxBounds[2] - m_minBounds[2]);
251 m_worldSizeX = m_worldSize;
252 m_worldSizeZ = m_worldSize;
260 PrintToConsole(
"Cannot get the world entity.",
LogLevel.ERROR);
266 endX_trimed = startX + m_step * ((endX - startX) / m_step);
267 endZ_trimed = startZ + m_step * ((endZ - startZ) / m_step);
269 platforms.Insert(
EPlatform.WINDOWS,
"62e0e57519098fc05e1b28fe");
270 platforms.Insert(
EPlatform.XBOX_ONE,
"62e0e58f19098fc05e1b28ff");
271 platforms.Insert(
EPlatform.XBOX_SERIES_X,
"632863b8211b59093a5afb79");
272 platforms.Insert(
EPlatform.XBOX_SERIES_S,
"632863cb211b59093a5afb7a");
273 platforms.Insert(
EPlatform.PS5,
"66cdc91e0a90565192210ae0");
278 m_jsonCallback.SetOnSuccess(OnSendDataSuccess);
279 m_jsonCallback.SetOnError(OnSendDataSuccess);
282 override void EOnFrame(
IEntity owner,
float timeSlice)
293 PrintToConsole(
"Measuring step is done or was skipped.");
301 if (SimulateHttpPost)
303 PrintToConsole(
"Simulating the measuring step by feeding it random data for.");
306 int stepsX = ((endX_trimed-startX)/m_step)+1;
307 int stepsZ = ((endZ_trimed-startZ)/m_step)+1;
308 for(
int i = 0; i < stepsX; i++)
310 for(
int j = 0; j < stepsZ; j++)
313 for(
int k = 0; k < 4; k++)
315 fps_four_directions[k] = Math.RandomInt(60,121);
316 fps_avg += fps_four_directions[k];
318 fps_avg = fps_avg / 4;
319 HeatmapData new_geojson_value =
new HeatmapData(fps_avg, fps_four_directions[0], fps_four_directions[1], fps_four_directions[2], fps_four_directions[3],
320 startX+i*m_step, 0, startZ+j*m_step);
321 m_geojson_data.Insert(new_geojson_value);
331 PrintToConsole(
"Camera entity cannot be found!",
LogLevel.ERROR);
336 int cur_fps = System.GetFPS();
337 int cur_dir = ((
m_timer / m_stepWaitTime - Math.Floor(
m_timer / m_stepWaitTime)) * 4);
339 if (cur_dir != prev_dir)
341 vector new_angles = m_camera.GetAngles();
342 new_angles[1] = directions[cur_dir];
343 m_camera.SetAngles(new_angles);
347 fps_four_directions[cur_dir] = cur_fps;
361 PrintToConsole(
"Registering measurement file (HTML): 0_fps_test_descr");
363 if(!descrFile || !descrFile.IsValid())
365 PrintToConsole(
"Cannot create measurement file (HTML).",
LogLevel.ERROR);
369 descrFile.AddData(
string.Format(
"<h1>" + m_heatmapName +
"</h1><p>Camera step: %1m<br/>Step wait time: %2s<br/>Camera height above ground: %3m<br/>Number of worst FPS places: %4</p>", m_step, m_stepWaitTime, m_cameraHeight, m_lowFrameCount));
371 PrintToConsole(
"Registering measurement file (HeatMap): 1_fps_heatmap");
375 PrintToConsole(
"Cannot create measurement file (HeatMap).",
LogLevel.ERROR);
381 int fps_avg = (fps_four_directions[0] + fps_four_directions[1] + fps_four_directions[2] + fps_four_directions[3]) / 4;
383 image_file.Insert(fps_avg);
384 m_heatmapfile.AddData(
string.Format(
"%1,%2,%3", m_x, m_z, fps_avg));
385 HeatmapData new_geojson_value =
new HeatmapData(fps_avg, fps_four_directions[0], fps_four_directions[1], fps_four_directions[2], fps_four_directions[3], m_x, m_y, m_z);
386 m_geojson_data.Insert(new_geojson_value);
388 if (m_x + m_step <= m_worldSizeX)
390 if (fps_avg > max_fps)
392 if (fps_avg < min_fps)
399 if (m_z + m_step <= m_worldSizeZ)
406 PrintToConsole(
"All points measured.");
418 float groundY = m_camera.GetWorld().GetSurfaceY(m_x, m_z);
419 m_y = groundY + m_cameraHeight;
420 m_camera.SetOrigin(
Vector(m_x, m_y, m_z));
425 private void CalculateAvgFPS()
427 int measured_points = m_geojson_data.Count();
428 for (
int i = 0; i < measured_points; ++i)
430 avg_fps += m_geojson_data[i].m_fps / measured_points;
433 if (measured_points == 0)
437 PrintToConsole(
"Avg FPS: " + avg_fps);
440 private void ReverseArray(inout array<int> arr)
442 array<int> temp =
new array<int>();
443 for (
int i = arr.Count()-1; i >= 0; --i)
450 private void GenerateDDS()
453 PrintToConsole(
"Generating DDS file.");
454 int width = (endX_trimed - startX) / m_step + 1;
455 int height = (endZ_trimed - startZ) / m_step;
457 int offset_x = startX / m_step;
458 int offset_z = startZ / m_step;
460 int image_size = m_worldSize / m_step;
465 array <int> image =
new array <int>;
467 for (
int i = 0; i < image_size * image_size; ++i)
469 image.Insert(
ARGB(255, 0, 0, 0));
472 for (
int y = 0; y < height; ++y)
474 array <int> row =
new array <int>;
475 for (
int i = 0; i < image_size; ++i)
477 row.Insert(
ARGB(255, 0, 0, 0));
482 for (
int x = 0; x < width; ++x)
487 int fps = image_file[
id];
489 float level = Math.Clamp(fps / fpsRange, 0, 1);
490 int phase = Math.Floor(level / 0.25);
492 range = Math.Clamp((level - phase * 0.25) / 0.25, 0, 1);
494 int from = colors[phase];
495 int to = colors[phase+1];
497 Color col1 = Color.FromInt(from);
498 Color col2 = Color.FromInt(to);
500 col1.Lerp(col2, range);
501 col = col1.PackToInt();
503 int index = offset_x + x;
505 if (
index < row.Count())
513 for (
int i = 0; i < row.Count(); ++i)
515 int index = (offset_z + id_z) * image_size + i;
516 if (
index < image.Count())
517 image[
index] = row[i];
523 const string ddsFile =
"$logs:heatmap.dds";
524 if(!TexTools.SaveImageData(ddsFile, image_size, image_size, image))
526 PrintToConsole(
"Failed to save the data into the file: " + ddsFile,
LogLevel.ERROR);
529 PrintToConsole(
"Data sucessfully saved into dds file: " + ddsFile);
533 private string GetGeoJSONLine(HeatmapData val)
542 string new_value =
string.Format(
543 "{ \"type\": \"Point\", \"properties\": { \"FPS_AVG\": \"%1\", \"FPS_N\": \"%2\", \"FPS_E\": \"%3\", \"FPS_S\": \"%4\", \"FPS_W\": \"%5\" }, \"geometry\": { \"coordinates\": [ %6, %7, %8] } }",
544 Math.Floor(val.m_fps), Math.Floor(val.m_fps_n), Math.Floor(val.m_fps_e), Math.Floor(val.m_fps_s), Math.Floor(val.m_fps_w),
545 val.m_x, val.m_z, val.m_y);
550 private string GetCSVLine(HeatmapData val)
552 string new_value =
string.Format(
554 val.m_x, val.m_z, Math.Floor(val.m_fps) );
559 private void GenerateGeoJSON()
563 PrintToConsole(
"Creating the GeoJSON file.");
565 string directoryName =
"$logs:/" + mapName;
566 if(!FileIO.MakeDirectory(directoryName))
568 PrintToConsole(
"Failed to make the directory \"" + directoryName +
"\".",
LogLevel.ERROR);
569 PrintToConsole(
"Failed to generate the GeoJSON file.");
573 string filePath = directoryName +
"/" + fileName;
574 file = FileIO.OpenFile(filePath,
FileMode.WRITE);
575 if(!file || !file.IsOpen())
577 PrintToConsole(
"Failed to create/open the file \"" + filePath +
"\". Cannot continue with generating and sending the GeoJSON file.",
LogLevel.ERROR);
581 WriteDataGJSON(file);
583 file = FileIO.OpenFile(filePath,
FileMode.READ);
584 if(!file || !file.IsOpen())
586 PrintToConsole(
"Failed to open the file \"" + filePath +
"\". Cannot continue with sending the GeoJSON file.",
LogLevel.ERROR);
591 file.Read(
data, file.GetLength());
594 RestContext restContext =
GetGame().GetRestApi().GetContext(HEATMAP_URL);
598 PrintToConsole(
"Failed to get RestAPI context. Unable to send data",
LogLevel.ERROR);
602 PrintToConsole(
"Attempting to POST json data");
603 restContext.SetHeaders(
"Content-Type,application/json");
606 postReturnVal = restContext.POST(m_jsonCallback,
"api/fps-statistics",
data);
607 PrintToConsole(
"Returned value of the POST: " + postReturnVal.ToString());
611 PrintToConsole(
"Creating the GeoJSON done.");
614 private void GenerateCSV()
618 PrintToConsole(
"Creating a CSV file");
620 string directoryName =
"$logs:/" + mapName;
621 if(!FileIO.MakeDirectory(directoryName))
623 PrintToConsole(
"Failed to make the directory \"" + directoryName +
"\".",
LogLevel.ERROR);
624 PrintToConsole(
"Failed to generate the CSV file.");
628 string filePath = directoryName +
"/" + fileName;
629 file = FileIO.OpenFile(directoryName,
FileMode.WRITE);
630 if(!file || !file.IsOpen())
632 PrintToConsole(
"Failed to create/open the file \"" + filePath +
"\". Cannot continue with generating the CSV file.",
LogLevel.ERROR);
638 PrintToConsole(
"Creating a CSV done");
641 private void WriteDataGJSON(FileHandle file)
643 if(!file || !file.IsOpen())
645 PrintToConsole(
"No file to write GeoJson data to found.",
LogLevel.ERROR);
649 PrintToConsole(
"Adding data to geojson");
652 platforms.Find(System.GetPlatform(), platform);
656 platform =
"Invalid";
658 PrintToConsole(
"SCR_FPS_Autotest::Invalid platform, GJSON file will fail to post to database",
LogLevel.ERROR);
662 file.WriteLine(
string.Format(
"\"date\": \"%1\",", SCR_DateTimeHelper.GetDateTimeLocal()));
663 file.WriteLine(
string.Format(
"\"platform\": \"%1\",", platform));
664 file.WriteLine(
string.Format(
"\"map\": \"%1\",", mapID));
665 file.WriteLine(
string.Format(
"\"heatmapName\": \"%1\",", m_heatmapName));
666 file.WriteLine(
"\"dimension\": {");
667 file.WriteLine(
string.Format(
" \"startX\": %1,", m_minBounds[0]));
668 file.WriteLine(
string.Format(
" \"startZ\": %1,", m_minBounds[2]));
669 file.WriteLine(
string.Format(
" \"endX\": %1,", m_maxBounds[0]));
670 file.WriteLine(
string.Format(
" \"endZ\": %1,", m_maxBounds[2]));
675 file.WriteLine(
string.Format(
" \"stepSize\": %1},", m_step));
676 file.WriteLine(
"\"featurecollection\": {");
677 file.WriteLine(
"\"type\": \"FeatureCollection\",");
678 file.WriteLine(
"\"name\": \"fps\",");
679 file.WriteLine(
string.Format(
"\"minfps\": %1,", Math.Floor(min_fps)));
680 file.WriteLine(
string.Format(
"\"maxfps\": %1,", Math.Floor(max_fps)));
681 file.WriteLine(
string.Format(
"\"avgfps\": %1,", Math.Floor(avg_fps)));
682 file.WriteLine(
"\"crs\": { \"type\": \"name\", \"properties\": { \"name\": \"urn:ogc:def:crs:EPSG::32632\" } },");
683 file.WriteLine(
"\"features\": [");
685 for (
int i = 0; i < m_geojson_data.Count(); ++i)
687 string line_end =
",";
688 if (i == m_geojson_data.Count()-1)
689 line_end =
string.Empty;
691 file.WriteLine(GetGeoJSONLine(m_geojson_data[i]) + line_end);
694 file.WriteLine(
"]\n}\n}");
695 PrintToConsole(
"Data successfully written to the GeoJSON file.");
698 private void WriteDataCSV(FileHandle file)
700 if(!file || !file.IsOpen())
702 PrintToConsole(
"No file to write CSV data to found.",
LogLevel.ERROR);
706 PrintToConsole(
"Adding data to CSV");
708 file.WriteLine(
"x,z,fps");
710 for (
int i = 0; i < m_geojson_data.Count(); ++i)
711 file.WriteLine(GetCSVLine(m_geojson_data[i]));
716 int year, month, day;
717 System.GetYearMonthDay(year, month, day);
720 smonth =
string.Format(
"0%1", month);
722 smonth =
string.Format(
"%1", month);
725 sday =
string.Format(
"0%1", day);
727 sday =
string.Format(
"%1", day);
729 return string.Format(
"%1%2%3", year, smonth, sday);
732 private void OnSendDataError(RestCallback cb)
734 if (cb.GetRestResult() ==
ERestResult.EREST_ERROR_TIMEOUT)
736 Print(
"[FPS_Autotest] Sending data has timed out",
LogLevel.WARNING);
740 Print(
"[FPS_Autotest] Sending data has failed with errorCode[" + cb.GetHttpCode() +
"]",
LogLevel.WARNING);
746 private void OnSendDataSuccess(RestCallback cb)
748 Print(
"[FPS_Autotest] Data sent successfully. Size: " + cb.GetData().Length());