summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 5b8e9b8)
raw | patch | inline | side by side (parent: 5b8e9b8)
author | fgsfds <pvt.fgsfds@gmail.com> | |
Mon, 23 Dec 2019 22:37:35 +0000 (01:37 +0300) | ||
committer | fgsfds <pvt.fgsfds@gmail.com> | |
Mon, 23 Dec 2019 22:37:35 +0000 (01:37 +0300) |
src/game/g_game.pas | patch | blob | history | |
src/game/g_main.pas | patch | blob | history | |
src/game/g_options.pas | patch | blob | history | |
src/shared/utils.pas | patch | blob | history |
diff --git a/src/game/g_game.pas b/src/game/g_game.pas
index ca8ee633877789f8b162f376495952d0c8800025..686f15692b6a73af4f9c728254ef1948967cba24 100644 (file)
--- a/src/game/g_game.pas
+++ b/src/game/g_game.pas
procedure g_Game_Announce_BodyKill(SpawnerUID: Word);
procedure g_Game_StartVote(Command, Initiator: string);
procedure g_Game_CheckVote;
-procedure g_TakeScreenShot();
+procedure g_TakeScreenShot(Filename: string = ''; StatShot: Boolean = False);
procedure g_FatalError(Text: String);
procedure g_SimpleError(Text: String);
function g_Game_IsTestMap(): Boolean;
DEFAULT_PLAYERS = 1;
{$ENDIF}
+ STATFILE_VERSION = $03;
+
var
gStdFont: DWORD;
gGameSettings: TGameSettings;
{$IFDEF ENABLE_HOLMES}
g_holmes,
{$ENDIF}
- e_texture, e_res, g_textures, g_main, g_window, g_menu,
+ e_texture, e_res, g_textures, g_window, g_menu,
e_input, e_log, g_console, g_items, g_map, g_panel,
g_playermodel, g_gfx, g_options, Math,
g_triggers, g_monsters, e_sound, CONFIG,
- g_language, g_net,
+ g_language, g_net, g_main,
ENet, e_msg, g_netmsg, g_netmaster,
sfs, wadreader, g_system;
MapList: SSArray = nil;
MapIndex: Integer = -1;
InterReadyTime: Integer = -1;
+ StatShotDone: Boolean = False;
+ StatFilename: string = ''; // used by stat screenshot to save with the same name as the csv
+ StatDate: string = '';
MegaWAD: record
info: TMegaWADInfo;
endpic: String;
end;
end;
+// saves a shitty CSV containing the game stats passed to it
+procedure SaveGameStat(Stat: TEndCustomGameStat; Path: string);
+var
+ s: TextFile;
+ dir, fname, map, mode, etime: String;
+ I: Integer;
+begin
+ try
+ dir := e_GetWriteableDir(StatsDirs);
+ // stats are placed in stats/yy/mm/dd/*.csv
+ fname := e_CatPath(dir, Path);
+ ForceDirectories(fname); // ensure yy/mm/dd exists within the stats dir
+ fname := e_CatPath(fname, StatFilename + '.csv');
+ AssignFile(s, fname);
+ try
+ Rewrite(s);
+ // line 1: stats version, datetime, server name, map name, game mode, time limit, score limit, dmflags, game time, number of players
+ if g_Game_IsNet then fname := NetServerName else fname := '';
+ map := g_ExtractWadNameNoPath(gMapInfo.Map) + ':/' + g_ExtractFileName(gMapInfo.Map);
+ mode := g_Game_ModeToText(Stat.GameMode);
+ etime := Format('%d:%.2d:%.2d', [Stat.GameTime div 1000 div 3600,
+ (Stat.GameTime div 1000 div 60) mod 60,
+ Stat.GameTime div 1000 mod 60]);
+ WriteLn(s, 'stats_ver,datetime,server,map,mode,timelimit,scorelimit,dmflags,time,num_players');
+ WriteLn(s,
+ Format('%d,%s,%s,%s,%s,%u,%u,%u,%s,%d',
+ [STATFILE_VERSION, StatDate, fname, map, mode, gGameSettings.TimeLimit, gGameSettings.GoalLimit, gGameSettings.Options, etime, Length(Stat.PlayerStat)]));
+ // line 2: game specific shit
+ // if it's a team game: red score, blue score
+ // if it's a coop game: monsters killed, monsters total, secrets found, secrets total
+ // otherwise nothing
+ if Stat.GameMode in [GM_TDM, GM_CTF] then
+ WriteLn(s, Format('red_score,blue_score' + LineEnding + '%d,%d', [Stat.TeamStat[TEAM_RED].Goals, Stat.TeamStat[TEAM_BLUE].Goals]))
+ else if Stat.GameMode in [GM_COOP, GM_SINGLE] then
+ WriteLn(s, Format('mon_killed,mon_total,secrets_found,secrets_total' + LineEnding + '%d,%d,%d,%d', [gCoopMonstersKilled, gTotalMonsters, gCoopSecretsFound, gSecretsCount]));
+ // lines 3-...: team, player name, frags, deaths
+ WriteLn(s, 'team,name,frags,deaths');
+ for I := Low(Stat.PlayerStat) to High(Stat.PlayerStat) do
+ with Stat.PlayerStat[I] do
+ WriteLn(s, Format('%d,%s,%d,%d', [Team, Name, Frags, Deaths]));
+ except
+ g_Console_Add(Format(_lc[I_CONSOLE_ERROR_WRITE], [fname]));
+ end;
+ except
+ g_Console_Add('could not create gamestats file "' + fname + '"');
+ end;
+ CloseFile(s);
+end;
+
function g_Game_ModeToText(Mode: Byte): string;
begin
Result := '';
var
a: Integer;
FileName: string;
+ t: TDateTime;
begin
if g_Game_IsNet and g_Game_IsServer then
MH_SEND_GameEvent(NET_EV_MAPEND, Byte(gMissionFailed));
end;
SortGameStat(CustomStat.PlayerStat);
+
+ if gSaveStats or gScreenshotStats then
+ begin
+ t := Now;
+ if g_Game_IsNet then StatFilename := NetServerName else StatFilename := 'local';
+ StatDate := FormatDateTime('yymmdd_hhnnss', t);
+ StatFilename := StatFilename + '_' + CustomStat.Map + '_' + g_Game_ModeToText(CustomStat.GameMode);
+ StatFilename := sanitizeFilename(StatFilename) + '_' + StatDate;
+ if gSaveStats then SaveGameStat(CustomStat, FormatDateTime('yyyy"/"mm"/"dd', t));
+ end;
+
+ StatShotDone := False;
end;
g_Game_ExecuteEvent('onmapend');
and (not gJustChatted) and (not gConsoleShow) and (not gChatShow)
and (g_ActiveWindow = nil)
)
- or (g_Game_IsNet and ((gInterTime > gInterEndTime) or (gInterReadyCount >= NetClientCount)))
+ or (g_Game_IsNet and ((gInterTime > gInterEndTime) or ((gInterReadyCount >= NetClientCount) and (NetClientCount > 0))))
)
then
begin // Íàæàëè <Enter>/<Ïðîáåë> èëè ïðîøëî äîñòàòî÷íî âðåìåíè:
_y := _y+24;
end;
end;
+
+ // HACK: take stats screenshot immediately after the first frame of the stats showing
+ if gScreenshotStats and not StatShotDone then
+ begin
+ g_TakeScreenShot('stats/' + StatFilename, True);
+ StatShotDone := True;
+ end;
end;
procedure DrawSingleStat();
end;
end;
-procedure g_TakeScreenShot;
+procedure g_TakeScreenShot(Filename: string = ''; StatShot: Boolean = False);
var s: TStream; t: TDateTime; dir, date, name: String;
begin
if e_NoGraphics then Exit;
try
- t := Now;
dir := e_GetWriteableDir(ScreenshotDirs);
- DateTimeToString(date, 'yyyy-mm-dd-hh-nn-ss', t);
- name := e_CatPath(dir, 'screenshot-' + date + '.png');
+
+ if Filename = '' then
+ begin
+ t := Now;
+ DateTimeToString(date, 'yyyy-mm-dd-hh-nn-ss', t);
+ Filename := 'screenshot-' + date;
+ end;
+
+ name := e_CatPath(dir, Filename + '.png');
s := createDiskFile(name);
try
e_MakeScreenshot(s, gScreenWidth, gScreenHeight);
diff --git a/src/game/g_main.pas b/src/game/g_main.pas
index c290df5e6b2176f743ae93748f919b73bd14add9..7a9785b6964cd331222219282a1f9b4310d4605f 100644 (file)
--- a/src/game/g_main.pas
+++ b/src/game/g_main.pas
CacheDirs: SSArray;
ConfigDirs: SSArray;
ScreenshotDirs: SSArray;
+ StatsDirs: SSArray;
MapDownloadDirs: SSArray;
WadDownloadDirs: SSArray;
AddDir(MapDownloadDirs, e_CatPath(rwdir, 'maps/downloads'));
AddDir(WadDownloadDirs, e_CatPath(rwdir, 'wads/downloads'));
AddDir(ScreenshotDirs, e_CatPath(rwdir, 'screenshots'));
+ AddDir(StatsDirs, e_CatPath(rwdir, 'stats'));
(* RO *)
AddDir(DataDirs, e_CatPath(rwdir, 'data'));
AddDir(ModelDirs, e_CatPath(rwdir, 'data/models'));
AddDef(MapDownloadDirs, rwdirs, 'maps/downloads');
AddDef(WadDownloadDirs, rwdirs, 'wads/downloads');
AddDef(ScreenshotDirs, rwdirs, 'screenshots');
+ AddDef(StatsDirs, rwdirs, 'stats');
for i := 0 to High(MapDirs) do
AddDir(AllMapDirs, MapDirs[i]);
{$ENDIF}
end
end;
+
+ // HACK: ensure the screenshots folder also has a stats subfolder in it
+ rwdir := e_GetWriteableDir(ScreenshotDirs, false);
+ if rwdir <> '' then CreateDir(rwdir + '/stats');
end;
procedure InitPrep;
PrintDirs('CacheDirs', CacheDirs);
PrintDirs('ConfigDirs', ConfigDirs);
PrintDirs('ScreenshotDirs', ScreenshotDirs);
+ PrintDirs('StatsDirs', StatsDirs);
PrintDirs('MapDownloadDirs', MapDownloadDirs);
PrintDirs('WadDownloadDirs', WadDownloadDirs);
diff --git a/src/game/g_options.pas b/src/game/g_options.pas
index d523da8c511b83be4d6d6bc68af001e49598654d..d4f92e86617af3c35036b96df4f798c117de4c68 100644 (file)
--- a/src/game/g_options.pas
+++ b/src/game/g_options.pas
gRevertPlayers: Boolean;
gLanguage: String;
gAskLanguage: Boolean;
+ gSaveStats: Boolean = False;
+ gScreenshotStats: Boolean = False;
gcMap: String;
gcGameMode: String;
gcTimeLimit: Word;
gDefaultMegawadStart := DF_Default_Megawad_Start;
gBerserkAutoswitch := True;
g_dbg_scale := 1.0;
+ gSaveStats := False;
gAskLanguage := True;
gLanguage := LANGUAGE_ENGLISH;
conRegVar('sfs_fastmode', @wadoptFast, '', '');
conRegVar('g_fast_screenshots', @e_FastScreenshots, '', '');
conRegVar('g_default_megawad', @gDefaultMegawadStart, '', '');
-
+ conRegVar('g_save_stats', @gSaveStats, '', '');
+ conRegVar('g_screenshot_stats', @gScreenshotStats, '', '');
end.
diff --git a/src/shared/utils.pas b/src/shared/utils.pas
index 948ac697f8c948b37be295ec3db9aa1a432c2a16..f5f762c6e983c96a5dd7c54ad3fb68c82110d058 100644 (file)
--- a/src/shared/utils.pas
+++ b/src/shared/utils.pas
// rewrites slashes to '/'
function fixSlashes (s: AnsiString): AnsiString;
+// replaces all the shitty characters with '_'
+// (everything except alphanumerics, '_', '.')
+function sanitizeFilename (s: AnsiString): AnsiString;
+
function isAbsolutePath (const s: AnsiString): Boolean;
function isRootPath (const s: AnsiString): Boolean;
{$ENDIF}
end;
+// replaces all the shitty characters with '_'
+// (everything except alphanumerics, '_', '.')
+function sanitizeFilename (s: AnsiString): AnsiString;
+var
+ i: Integer;
+const
+ leaveChars: set of Char = [ '0'..'9', 'A'..'Z', 'a'..'z', '_', '.', #192..#255 ];
+ replaceWith: Char = '_';
+begin
+ result := s;
+ for i := 1 to length(result) do
+ if not (result[i] in leaveChars) then
+ result[i] := replaceWith;
+end;
function isAbsolutePath (const s: AnsiString): Boolean;
begin