View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0000493 | Gameplay + OpenGL | [All Projects] Feature | public | 2017-03-27 08:27 | 2017-03-29 07:28 |
Reporter | hobomaster22 | ||||
Assigned To | |||||
Priority | normal | Severity | feature | Reproducibility | N/A |
Status | closed | Resolution | won't fix | ||
Summary | 0000493: Write level statistics | ||||
Description | ZDoom used to write level statistics in the old binary save game format that Doom Launcher would read to track statistics. The ability for Doom Launcher to track statistics with the new save game format has been lost. I am proposing a proper statistic feature that saves level statistics as a separate file. | ||||
Additional Information | I have edited the source code and leveraged the existing json code for save games to write an addition statistics file. Basically, it starts clean on a new game and writes all completed level statistics to a json file when a level is exited. I have attached stats_test_code.txt with the necessary code changes to write level statistics. It may not be the best way but I'm hoping it's helpful. I have also attached stats.zip which is the output that is generated from completing e1m1 and e1m2. | ||||
Tags | No tags attached. | ||||
stats.zip (287 bytes)
stats_test_code.txt (2,410 bytes)
g_level.h ------------------ struct FLevelStats { FString MapName; int maptime; // time in the map int totaltime; // time in the game int total_secrets; int found_secrets; int total_items; int found_items; int total_monsters; int killed_monsters; }; void LevelLocalToStat(FLevelStats& stat, FLevelLocals& level); g_level.cpp ------------------ TArray<FLevelStats> levelstats; //level statistics since new game has started void LevelLocalToStat(FLevelStats& stat, FLevelLocals& level) { stat.MapName = level.MapName; stat.MapName.ToLower(); stat.maptime = level.maptime; stat.totaltime = level.totaltime; stat.total_secrets = level.total_secrets; stat.found_secrets = level.found_secrets; stat.total_items = level.total_items; stat.found_items = level.found_items; stat.total_monsters = level.total_monsters; stat.killed_monsters = level.killed_monsters; } void G_NewInit () { ...G_NewInit code levelstats.Clear(); } void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill) { FSerializer arc; if (arc.OpenWriter()) { Renderer->StartSerialize(arc); FLevelStats stat; LevelLocalToStat(stat, level); levelstats.Push(stat); arc.BeginArray("levels"); unsigned int count = levelstats.Size(); for (unsigned int i = 0; i < count; i++) Serialize(arc, nullptr, levelstats[i]); arc.EndArray(); Renderer->EndSerialize(arc); FCompressedBuffer buffer = arc.GetCompressedOutput(); TArray<FString> filenames; TArray<FCompressedBuffer> content; filenames.Push("maps.json"); content.Push(buffer); WriteZip("stats.zip", filenames, content); } ....G_ChangeLevel } serializer.h ------------------ FSerializer &Serialize(FSerializer &arc, const char *key, FLevelStats &stats); d_protocol.cpp ------------------ FSerializer &Serialize(FSerializer &arc, const char *key, FLevelStats &stats) { if (arc.BeginObject(key)) { arc("MapName", stats.MapName) ("found_secrets", stats.found_secrets) ("found_items", stats.found_items) ("killed_monsters", stats.killed_monsters) ("total_secrets", stats.total_secrets) ("total_items", stats.total_items) ("total_monsters", stats.total_monsters) ("maptime", stats.maptime) ("totaltime", stats.totaltime) .EndObject(); } return arc; } |
|
Look what you can find in globals.json in the savegame: "statistics": { "startlevel": "map01", "levels": [{ "totalkills": 19, "killcount": 19, "totalsecrets": 5, "secretcount": 0, "leveltime": 294, "levelname": "map01" }, { "totalkills": 70, "killcount": 0, "totalsecrets": 1, "secretcount": 0, "leveltime": 95, "levelname": "MAP02" }] }, All there, except the items... Doing this to a separate file comes with a large can of worms attached that are not trivially solvable. |
|
Thanks, this works. While I'm here I will bring up the issue of the last level in an episode will not be written to the statistics in a save game (like E1M8). Should I modify this request to add items and maybe a solution for writing statistics for the last level in an episode? Or should it be a new one entirely? | |
That's because there is no save after the last level. The statistics are gathered to be output to a text file that gets written at the end of an episode. That's not JSON but formatted for human readability. Check these two CVARs: CVAR(Int, savestatistics, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(String, statfile, "zdoomstat.txt", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) It may make sense to replace or complement that with JSON, now that a parser is present, it would certainly make it easier to process that data by external tools. |
|
I had made a post about the savestatistics flag a while back. It would be incredibly useful if the savestatistics flag was changed to write the zdoomstat.txt file on every level exit rather than the end of an episode. This is more or less what I proposed. Like I said my exact implementation that I originally posted may not be the best, it was an example. If savestatistics could write the file on every level exit, json or not, that would be a huge improvement. | |
Date Modified | Username | Field | Change |
---|---|---|---|
2017-03-27 08:27 | hobomaster22 | New Issue | |
2017-03-27 08:27 | hobomaster22 | File Added: stats.zip | |
2017-03-27 08:27 | hobomaster22 | File Added: stats_test_code.txt | |
2017-03-28 15:15 | Graf Zahl | Note Added: 0001140 | |
2017-03-28 15:15 | Graf Zahl | Status | new => closed |
2017-03-28 15:15 | Graf Zahl | Resolution | open => won't fix |
2017-03-28 15:36 | hobomaster22 | Note Added: 0001143 | |
2017-03-28 18:24 | Graf Zahl | Note Added: 0001155 | |
2017-03-29 07:28 | hobomaster22 | Note Added: 0001164 |