14 void HeatmapData(
float fps,
float x,
float y,
float z)
28 override void OnError(
int errorCode)
30 Print(
"Sending data has failed", LogLevel.WARNING);
35 override void OnTimeout()
37 Print(
"Sending data has timed out", LogLevel.WARNING);
42 override void OnSuccess(
string data,
int dataSize)
44 Print(
"Data sent successfully. Size: " + dataSize);
51 [
Attribute(
"ScriptCamera1", UIWidgets.EditBox,
"Name of camera entity",
"")]
52 private string m_cameraEntityName;
54 [
Attribute(
"", UIWidgets.EditBox,
"Name of Confluence page",
"")]
55 private string m_pageName;
57 [
Attribute(
"Unnamed test", UIWidgets.EditBox,
"Title of particular test",
"")]
58 private string m_testName;
60 [
Attribute(
"Heatmap title", UIWidgets.EditBox,
"Title of heatmap",
"")]
61 private string m_heatmapName;
63 [
Attribute(
"300", UIWidgets.Slider,
"Measurements step",
"10 2000 10")]
66 [
Attribute(
"1", UIWidgets.Slider,
"Wait time",
"0 20 0.1")]
67 private float m_stepWaitTime;
69 [
Attribute(
"80", UIWidgets.Slider,
"Camera height",
"1 300 10")]
70 private float m_cameraHeight;
72 [
Attribute(
"10", UIWidgets.Slider,
"Number of slowest points for lowest FPS graph",
"10 50 1")]
73 private int m_lowFrameCount;
76 private string mapName;
94 private float timeOfTheDay;
99 private ref map<EPlatform, string> platforms =
new map<EPlatform, string>();
103 private const string HEATMAP_URL =
"https://ar-heatmap.bistudio.com/";
105 protected bool m_bDoneGenerating =
false;
107 protected float m_timer;
109 private IEntity m_camera;
111 private int m_x = startX;
113 private int m_z = startZ;
115 private int m_worldSize;
116 private int m_worldSizeX;
117 private int m_worldSizeZ;
119 protected ref MeasurementFile m_heatmapfile;
121 private ref array<ref HeatmapData> m_geojson_data =
new array<ref HeatmapData>();
122 private ref array<int> image_file =
new array<int>();
124 private float min_fps = 1000;
125 private float max_fps = 0;
126 private float avg_fps = 0;
128 protected ref AutotestRegister m_register;
130 private bool area_only;
132 private float fps_four_directions[4];
133 private int prev_dir = -1;
135 private int colors[6] = {
147 SetEventMask(EntityEvent.INIT | EntityEvent.FRAME);
148 SetFlags(EntityFlags.ACTIVE,
true);
151 override void EOnInit(IEntity owner)
154 if (world.GetTimeAndWeatherManager())
156 world.GetTimeAndWeatherManager().SetTimeOfTheDay(timeOfTheDay);
157 world.GetTimeAndWeatherManager().SetIsDayAutoAdvanced(
false);
160 area_only = (endX > 0 || endZ > 0 || startX > 0 || startZ > 0);
162 m_camera =
GetGame().FindEntity(m_cameraEntityName);
166 float groundY = m_camera.GetWorld().GetSurfaceY(m_x, m_z);
167 m_camera.SetOrigin(Vector(m_x, groundY + m_cameraHeight, m_z));
171 if (
GetGame().GetWorldEntity())
174 GetGame().GetWorldEntity().GetWorldBounds(min, max);
175 m_worldSize = Math.Max(max[0] - min[0], max[2] - min[2]);
184 m_worldSizeX = m_worldSize;
185 m_worldSizeZ = m_worldSize;
192 platforms.Insert(EPlatform.WINDOWS,
"62e0e57519098fc05e1b28fe");
193 platforms.Insert(EPlatform.XBOX_ONE,
"62e0e58f19098fc05e1b28ff");
194 platforms.Insert(EPlatform.XBOX_SERIES_X,
"632863b8211b59093a5afb79");
195 platforms.Insert(EPlatform.XBOX_SERIES_S,
"632863cb211b59093a5afb7a");
198 override void EOnFrame(IEntity owner,
float timeSlice)
200 m_timer += timeSlice;
206 if (m_bDoneGenerating)
213 Print(
"Camera entity cannot be found!", LogLevel.ERROR);
218 int cur_fps = System.GetFPS();
219 int cur_dir = ((m_timer / m_stepWaitTime - Math.Floor(m_timer / m_stepWaitTime)) * 4);
221 if (cur_dir != prev_dir)
223 vector new_angles = m_camera.GetAngles();
224 new_angles[1] = new_angles[1] + 90;
225 m_camera.SetAngles(new_angles);
229 fps_four_directions[cur_dir] = cur_fps;
231 if (m_timer > m_stepWaitTime)
233 m_timer -= m_stepWaitTime;
237 float groundY = m_camera.GetWorld().GetSurfaceY(m_x, m_z);
238 m_y = groundY + m_cameraHeight;
239 m_camera.SetOrigin(Vector(m_x, groundY + m_cameraHeight, m_z));
244 m_register =
new AutotestRegister();
245 m_register.Init(m_pageName);
250 ref MeasurementFile descrFile = m_register.OpenMeasurementFile(
"0_fps_test_descr",
"", MeasurementType.HTML);
251 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));
253 m_heatmapfile = m_register.OpenMeasurementFile(
"1_fps_heatmap", m_testName, MeasurementType.HeatMap);
257 int fps = (fps_four_directions[0] + fps_four_directions[1] + fps_four_directions[2] + fps_four_directions[3]) / 4;
259 image_file.Insert(fps);
260 m_heatmapfile.AddData(
string.Format(
"%1,%2,%3", m_x, m_z, fps));
262 if (m_x + m_step <= m_worldSizeX)
266 m_geojson_data.Insert(new_geojson_value);
277 if (m_z + m_step <= m_worldSizeZ - m_step)
287 m_bDoneGenerating =
true;
293 private void CalculateAvgFPS()
295 for (
int i = 0; i < m_geojson_data.Count(); ++i)
297 avg_fps += m_geojson_data[i].m_fps;
300 if (m_geojson_data.Count() == 0)
303 avg_fps /= m_geojson_data.Count();
304 Print(
"Avg FPS: " + avg_fps);
307 private void ReverseArray(inout array<int> arr)
309 array<int> temp =
new array<int>();
310 for (
int i = arr.Count()-1; i >= 0; --i)
317 private void GenerateDDS()
320 int width = (endX - startX) / m_step + 1;
321 int height = (endZ - startZ) / m_step;
323 int offset_x = startX / m_step;
324 int offset_z = startZ / m_step;
326 int image_size = m_worldSize / m_step;
331 array <int> image =
new array <int>;
333 for (
int i = 0; i < image_size * image_size; ++i)
335 image.Insert(ARGB(255, 0, 0, 0));
338 for (
int y = 0; y < height; ++y)
340 array <int> row =
new array <int>;
341 for (
int i = 0; i < image_size; ++i)
343 row.Insert(ARGB(255, 0, 0, 0));
348 for (
int x = 0; x < width; ++x)
353 int fps = image_file[id];
355 float level = Math.Clamp(fps / fpsRange, 0, 1);
356 int phase = Math.Floor(level / 0.25);
358 range = Math.Clamp((level - phase * 0.25) / 0.25, 0, 1);
360 int from = colors[phase];
361 int to = colors[phase+1];
363 Color col1 = Color.FromInt(from);
364 Color col2 = Color.FromInt(to);
366 col1.Lerp(col2, range);
367 col = col1.PackToInt();
369 int index = offset_x + x;
371 if (
index < row.Count())
379 for (
int i = 0; i < row.Count(); ++i)
381 int index = (offset_z + id_z) * image_size + i;
382 if (
index < image.Count())
383 image[
index] = row[i];
389 TexTools.SaveImageData(
"$logs:heatmap.dds", image_size, image_size, image);
395 string new_value =
string.Format(
396 "{ \"properties\": { \"FPS\": \"%1\" }, \"geometry\": { \"coordinates\": [ %2, %3, %4] } }",
397 Math.Floor(val.m_fps), val.m_x, val.m_z, val.m_y);
404 string new_value =
string.Format(
406 val.m_x, val.m_z, Math.Floor(val.m_fps) );
411 private void GenerateGeoJSON()
415 Print(
"Creating a geojson file");
417 FileIO.MakeDirectory(
"$logs:/" + mapName);
418 string filename = FormatTimestamp() +
".geojson";
419 file = FileIO.OpenFile(
"$logs:/" + mapName +
"/" + filename, FileMode.WRITE);
421 WriteDataGJSON(file);
423 file = FileIO.OpenFile(
"$logs:/" + mapName +
"/" + filename, FileMode.READ);
426 file.Read(
data, file.GetLength());
429 RestContext restContext =
GetGame().GetRestApi().GetContext(HEATMAP_URL);
433 Print(
"Failed to get RestAPI context. Unable to send data", LogLevel.ERROR);
437 restContext.SetHeaders(
"Content-Type,application/json");
438 restContext.POST(m_jsonCallback,
"api/fps-statistics",
data);
442 Print(
"Creating a json done");
445 private void GenerateCSV()
449 Print(
"Creating a CSV file");
451 FileIO.MakeDirectory(
"$logs:/" + mapName);
452 string filename = FormatTimestamp() +
".csv";
453 file = FileIO.OpenFile(
"$logs:/" + mapName +
"/" + filename, FileMode.WRITE);
458 Print(
"Creating a CSV done");
461 private void WriteDataGJSON(FileHandle file)
463 Print(
"Adding data to geojson");
466 platforms.Find(System.GetPlatform(), platform);
470 platform =
"Invalid";
472 Print(
"SCR_FPS_Autotest::Invalid platform, GJSON file will fail to post to database", LogLevel.ERROR);
476 file.WriteLine(
string.Format(
"\"date\": \"%1\",",
SCR_DateTimeHelper.GetDateTimeLocal()));
477 file.WriteLine(
string.Format(
"\"platform\": \"%1\",", platform));
478 file.WriteLine(
string.Format(
"\"map\": \"%1\",", mapID));
479 file.WriteLine(
"\"featurecollection\": {");
480 file.WriteLine(
"\"type\": \"FeatureCollection\",");
481 file.WriteLine(
"\"name\": \"fps\",");
482 file.WriteLine(
string.Format(
"\"minfps\": %1,", Math.Floor(min_fps)));
483 file.WriteLine(
string.Format(
"\"maxfps\": %1,", Math.Floor(max_fps)));
484 file.WriteLine(
string.Format(
"\"avgfps\": %1,", Math.Floor(avg_fps)));
485 file.WriteLine(
"\"crs\": { \"type\": \"name\", \"properties\": { \"name\": \"urn:ogc:def:crs:EPSG::32632\" } },");
486 file.WriteLine(
"\"features\": [");
488 for (
int i = 0; i < m_geojson_data.Count(); ++i)
490 string line_end =
",";
491 if (i == m_geojson_data.Count()-1)
492 line_end =
string.Empty;
494 file.WriteLine(GetGeoJSONLine(m_geojson_data[i]) + line_end);
497 file.WriteLine(
"]\n}\n}");
500 private void WriteDataCSV(FileHandle file)
502 Print(
"Adding data to CSV");
504 file.WriteLine(
"x,z,fps");
506 for (
int i = 0; i < m_geojson_data.Count(); ++i)
507 file.WriteLine(GetCSVLine(m_geojson_data[i]));
510 private string FormatTimestamp()
512 int year, month, day;
513 System.GetYearMonthDay(year, month, day);
516 smonth =
string.Format(
"0%1", month);
518 smonth =
string.Format(
"%1", month);
521 sday =
string.Format(
"0%1", day);
523 sday =
string.Format(
"%1", day);
525 return string.Format(
"%1%2%3", year, smonth, sday);