Restructure replay folder, remove RA flag suffixes

This commit is contained in:
GenericHeroGuy 2025-10-18 01:17:11 +02:00
parent 96bf11c706
commit 2a761e18aa
7 changed files with 112 additions and 158 deletions

View file

@ -1935,7 +1935,7 @@ void D_SRB2Main(void)
}
else if (M_CheckParm("-record") && M_IsNextParm())
{
G_RecordDemo(M_GetNextParm());
G_RecordDemo(va("%s.lmp", M_GetNextParm()));
autostart = true;
}

View file

@ -2719,7 +2719,6 @@ void G_RecordDemo(const char *name)
INT32 maxsize;
strcpy(demoname, name);
strcat(demoname, ".lmp");
maxsize = 1024 * 1024 * cv_netdemosize.value;
P_SaveBufferAlloc(&demobuf, maxsize);

View file

@ -740,6 +740,41 @@ boolean G_EmblemsEnabled(void)
return !demo.playback && !strcmp(currentrecordpreset, "kart");
}
char *G_GetRecordReplayFolder(boolean home, boolean breaker)
{
return xva("%s%smedia"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s",
home ? srb2home : "",
home ? PATHSEP : "",
breaker ? "itembreaker" : "timeattack",
currentrecordpreset
);
}
const char *tasuffixes[] = {
[TA_TIMEBEST] = "time-best",
[TA_LAPBEST] = "lap-best",
[TA_LAST] = "last",
[TA_GUEST] = "guest",
};
char *G_GetRecordReplay(const char *folder, UINT16 mapnum, UINT16 skinnum, timeattackreplay_e which)
{
const char *map = G_BuildMapName(mapnum), *suf = tasuffixes[which];
if (which != TA_GUEST)
return xva("%s"PATHSEP"%s-%s-%s.lmp", folder, map, skins[skinnum].name, suf);
else
return xva("%s"PATHSEP"%s-%s.lmp", folder, map, suf);
}
boolean G_CheckRecordReplay(const char *folder, UINT16 mapnum, UINT16 skinnum, timeattackreplay_e which)
{
const char *map = G_BuildMapName(mapnum), *suf = tasuffixes[which];
if (which != TA_GUEST)
return FIL_FileExists(va("%s"PATHSEP"%s-%s-%s.lmp", folder, map, skins[skinnum].name, suf));
else
return FIL_FileExists(va("%s"PATHSEP"%s-%s.lmp", folder, map, suf));
}
//
// G_UpdateRecordReplays
//
@ -747,11 +782,8 @@ boolean G_EmblemsEnabled(void)
//
static void G_UpdateRecordReplays(void)
{
char *gpath;
char *gamemode = M_AppendGametypeAndModName();
char lastdemo[256], bestdemo[256];
CLEANUP(pfree) char *gpath = NULL, *lastdemo = NULL;
UINT8 earnedEmblems;
int parts;
// Record new best time
maprecord_t *record = G_AllocateMapRecord(G_BuildMapName(gamemap));
@ -779,24 +811,20 @@ static void G_UpdateRecordReplays(void)
}
// Save demo!
bestdemo[255] = '\0';
lastdemo[255] = '\0';
G_SetDemoTime(players[consoleplayer].realtime, bestlap);
G_CheckDemoStatus();
gpath = xva("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s",
srb2home, timeattackfolder, G_BuildMapName(gamemap));
parts = M_PathParts(gpath);
M_MkdirEachUntil(gpath, parts - 4, parts - 1, 0755);
gpath = G_GetRecordReplayFolder(true, modeattacking == ATTACKING_ITEMBREAK);
M_MkdirEach(gpath, M_PathParts(gpath) - 4, 0755);
snprintf(lastdemo, 255, "%s-%s-%s-last.lmp", gpath, skins[cv_chooseskin.value].name, gamemode);
lastdemo = G_GetRecordReplay(gpath, gamemap, cv_chooseskin.value, TA_LAST);
if (FIL_FileExists(lastdemo))
{
UINT8 *buf;
size_t len = FIL_ReadFile(lastdemo, &buf);
snprintf(bestdemo, 255, "%s-%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode);
CLEANUP(pfree) char *bestdemo = G_GetRecordReplay(gpath, gamemap, cv_chooseskin.value, TA_TIMEBEST);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
{ // Better time, save this demo.
if (FIL_FileExists(bestdemo))
@ -807,7 +835,8 @@ static void G_UpdateRecordReplays(void)
if (modeattacking == ATTACKING_TIME)
{
snprintf(bestdemo, 255, "%s-%s-%s-lap-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode);
free(bestdemo);
bestdemo = G_GetRecordReplay(gpath, gamemap, cv_chooseskin.value, TA_LAPBEST);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))
{ // Better lap time, save this demo.
if (FIL_FileExists(bestdemo))
@ -822,9 +851,6 @@ static void G_UpdateRecordReplays(void)
Z_Free(buf);
}
free(gpath);
Z_Free(gamemode);
// Check emblems when level data is updated
if ((earnedEmblems = M_CheckLevelEmblems()))
CONS_Printf(M_GetText("\x82" "Earned %hu medal%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");

View file

@ -312,6 +312,15 @@ typedef struct
maprecordpreset_t *presets;
} maprecord_t;
typedef enum
{
TA_TIMEBEST,
TA_LAPBEST,
TA_LAST,
TA_GUEST,
TA__MAX,
} timeattackreplay_e;
extern maprecord_t **maprecords;
extern size_t nummaprecords;
@ -320,8 +329,11 @@ maprecord_t *G_GetMapRecord(const char *mapname);
maprecordpreset_t *G_AllocateMapRecordPreset(maprecord_t *record, const char *presetname, UINT8 version);
maprecordpreset_t *G_GetMapRecordPreset(maprecord_t *record, const char *presetname);
void G_ClearRecords(void);
boolean G_EmblemsEnabled(void);
tic_t G_GetBestTime(INT16 map);
boolean G_EmblemsEnabled(void);
char *G_GetRecordReplayFolder(boolean home, boolean breaker);
char *G_GetRecordReplay(const char *folder, UINT16 mapnum, UINT16 skinnum, timeattackreplay_e which);
boolean G_CheckRecordReplay(const char *folder, UINT16 mapnum, UINT16 skinnum, timeattackreplay_e which);
FUNCMATH INT32 G_TicsToHours(tic_t tics);
FUNCMATH INT32 G_TicsToMinutes(tic_t tics, boolean full);

View file

@ -652,37 +652,6 @@ if (cv.value >= num) \
strcat(new_str, str); \
}
char *M_AppendGametypeAndModName(void)
{
UINT8 len = 4;
char *new_str;
new_str = Z_Malloc(4, PU_STATIC, NULL);
if ((!Playing() && (levellistmode == LLM_ITEMBREAKER)) || (modeattacking & ATTACKING_ITEMBREAK))
{
strcpy(new_str, "IB-");
}
else
{
strcpy(new_str, "RA-");
}
ADD(cv_dummyattackingrings, "RN-")
ADD(cv_dummyattackingstacking, "ST-")
ADD(cv_dummyattackingchaining, "CH-")
ADD(cv_dummyattackingslipdash, "SD-")
ADD(cv_dummyattackingpurpledrift, "PD-")
ADD(cv_dummyattackingslopeboost, "SB-")
ADD(cv_dummyattackingairdrop, "AD-")
ADDEQUALS(cv_dummyattackingbumpspark, "BD-", BUMPSPARK_NOCHARGE)
ADDGE(cv_dummyattackingbumpspark, "BS-", BUMPSPARK_RESET100)
new_str[len-1] = '\0';
return new_str;
}
// Nextmap. Used for Time Attack.
void Nextmap_OnChange(void)
{
@ -722,35 +691,34 @@ void Nextmap_OnChange(void)
if (menustack[0] == MN_SP_TIMEATTACK || menustack[0] == MN_SP_MODS || menustack[0] == MN_SP_PRES)
{
// see also p_setup.c's P_LoadRecordGhosts
char *gamemode = M_AppendGametypeAndModName();
char *gpath = xva("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value));
CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, levellistmode == LLM_ITEMBREAKER);
boolean visible;
boolean showreplay = false, showguest = false;
// best time
visible = FIL_FileExists(va("%s-%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode));
visible = G_CheckRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, TA_TIMEBEST);
M_SetItemVisible(MN_SP_REPLAY, "REPLAYTIME", visible);
M_SetItemVisible(MN_SP_GUESTREPLAY, "SAVETIME", visible);
if (visible)
showreplay = showguest = true;
// best lap
visible = levellistmode != LLM_ITEMBREAKER && FIL_FileExists(va("%s-%s-%s-lap-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode));
visible = levellistmode != LLM_ITEMBREAKER && G_CheckRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, TA_LAPBEST);
M_SetItemVisible(MN_SP_REPLAY, "REPLAYLAP", visible);
M_SetItemVisible(MN_SP_GUESTREPLAY, "SAVELAP", visible);
if (visible)
showreplay = showguest = true;
// last
visible = FIL_FileExists(va("%s-%s-%s-last.lmp", gpath, skins[cv_chooseskin.value].name, gamemode));
visible = G_CheckRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, TA_LAST);
M_SetItemVisible(MN_SP_REPLAY, "REPLAYLAST", visible);
M_SetItemVisible(MN_SP_GUESTREPLAY, "SAVELAST", visible);
if (visible)
showreplay = showguest = true;
// guest
visible = FIL_FileExists(va("%s-%s-guest.lmp", gpath, gamemode));
visible = G_CheckRecordReplay(gpath, cv_nextmap.value, UINT16_MAX, TA_GUEST);;
M_SetItemVisible(MN_SP_REPLAY, "REPLAYGUEST", visible);
M_SetItemVisible(MN_SP_GUESTREPLAY, "DELETE", visible);
M_SetItemVisible(MN_SP_GHOST, "GUEST", visible);
@ -771,9 +739,6 @@ void Nextmap_OnChange(void)
M_SetItemVisible(MN_SP_TIMEATTACK, "REPLAY", showreplay);
M_SetItemVisible(MN_SP_TIMEATTACK, "GUEST", showguest);
free(gpath);
Z_Free(gamemode);
}
}
@ -5825,32 +5790,22 @@ INT32 MR_QuitTimeAttackMenu(INT32 choice)
// Player has selected the "START" from the time attack screen
INT32 MR_ChooseTimeAttack(INT32 choice)
{
char *gpath;
char *gamemode = M_AppendGametypeAndModName();
char nameofdemo[256];
CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, levellistmode == LLM_ITEMBREAKER);
CLEANUP(pfree) char *demopath = G_GetRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, TA_LAST);
(void)choice;
emeralds = 0;
M_ClearMenus(true);
modeattacking = (levellistmode == LLM_ITEMBREAKER ? ATTACKING_ITEMBREAK : ATTACKING_TIME);
gpath = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s",
srb2home, timeattackfolder);
M_MkdirEach(gpath, M_PathParts(gpath) - 3, 0755);
strcat(gpath, PATHSEP);
strcat(gpath, G_BuildMapName(cv_nextmap.value));
snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-%s-last", gpath, cv_skin[0].string, gamemode);
Z_Free(gamemode);
M_MkdirEach(gpath, M_PathParts(gpath) - 4, 0755);
if (!cv_autorecord.value)
remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo));
remove(demopath);
else
G_RecordDemo(nameofdemo);
G_RecordDemo(demopath);
G_SetPresetCvars(G_GetRecordPresetVersion(currentrecordpreset, currentrecordpresetversion));
G_DeferedInitNew(false, cv_nextmap.value, (UINT8)(cv_chooseskin.value), 0, false);
G_DeferedInitNew(false, cv_nextmap.value, cv_chooseskin.value, 0, false);
return true;
}
@ -5886,36 +5841,19 @@ INT32 MR_TimeAttackPreset(INT32 arg)
// Player has selected the "REPLAY" from the time attack screen
INT32 MR_ReplayTimeAttack(INT32 arg)
{
const char *which;
char *gamemode = M_AppendGametypeAndModName();
if (arg < 0 || arg >= TA__MAX)
return false;
switch(arg) {
default:
case 0: // best time
which = "time-best";
break;
case 1: // best lap
which = "lap-best";
break;
case 2: // last
which = "last";
break;
case 3: // guest
// srb2/replay/main/map01-guest.lmp
COM_BufAddText(va("playdemo media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-guest.lmp -force", timeattackfolder, G_BuildMapName(cv_nextmap.value), gamemode));
Z_Free(gamemode);
return true;
}
// srb2/replay/main/map01-sonic-time-best.lmp
COM_BufAddText(va("playdemo media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s-%s.lmp -force", timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value].name, gamemode, which));
Z_Free(gamemode);
CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(false, levellistmode == LLM_ITEMBREAKER);
CLEANUP(pfree) char *demopath = G_GetRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, arg);
COM_BufAddText(va("playdemo %s -force", demopath));
return true;
}
static void M_EraseGuest(INT32 choice)
{
char *gamemode = M_AppendGametypeAndModName();
const char *rguest = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), gamemode);
CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, levellistmode == LLM_ITEMBREAKER);
CLEANUP(pfree) char *rguest = G_GetRecordReplay(gpath, cv_nextmap.value, UINT16_MAX, TA_GUEST);
(void)choice;
if (FIL_FileExists(rguest))
remove(rguest);
@ -5923,16 +5861,15 @@ static void M_EraseGuest(INT32 choice)
CV_AddValue(&cv_nextmap, -1);
CV_AddValue(&cv_nextmap, 1);
M_StartMessage(M_GetText("Guest replay data erased.\n"),NULL,MM_NOTHING);
Z_Free(gamemode);
}
static void M_OverwriteGuest(const char *which)
static void M_OverwriteGuest(timeattackreplay_e which)
{
char *gamemode = M_AppendGametypeAndModName();
char *rguest = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), gamemode));
CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, levellistmode == LLM_ITEMBREAKER);
CLEANUP(pfree) char *rguest = G_GetRecordReplay(gpath, cv_nextmap.value, UINT16_MAX, TA_GUEST);
CLEANUP(pfree) char *overwrite = G_GetRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, which);
UINT8 *buf;
size_t len;
len = FIL_ReadFile(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value].name, gamemode,which), &buf);
size_t len = FIL_ReadFile(overwrite, &buf);
if (!len) {
return;
}
@ -5941,30 +5878,28 @@ static void M_OverwriteGuest(const char *which)
remove(rguest);
}
FIL_WriteFile(rguest, buf, len);
Z_Free(rguest);
M_ExitMenu();
CV_AddValue(&cv_nextmap, -1);
CV_AddValue(&cv_nextmap, 1);
M_StartMessage(M_GetText("Guest replay data saved.\n"),NULL,MM_NOTHING);
Z_Free(gamemode);
}
static void M_OverwriteGuest_Time(INT32 choice)
{
(void)choice;
M_OverwriteGuest("time-best");
M_OverwriteGuest(TA_TIMEBEST);
}
static void M_OverwriteGuest_Lap(INT32 choice)
{
(void)choice;
M_OverwriteGuest("lap-best");
M_OverwriteGuest(TA_LAPBEST);
}
static void M_OverwriteGuest_Last(INT32 choice)
{
(void)choice;
M_OverwriteGuest("last");
M_OverwriteGuest(TA_LAST);
}
INT32 MR_SetGuestReplay(INT32 arg)
@ -5986,7 +5921,8 @@ INT32 MR_SetGuestReplay(INT32 arg)
M_StartMessage(M_GetText("Are you sure you want to\ndelete the guest replay data?\n\n(Press 'Y' to confirm)\n"), M_EraseGuest, MM_YESNO);
return true;
}
if (FIL_FileExists(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))))
CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, levellistmode == LLM_ITEMBREAKER);
if (G_CheckRecordReplay(gpath, cv_nextmap.value, UINT16_MAX, TA_GUEST))
M_StartMessage(M_GetText("Are you sure you want to\noverwrite the guest replay data?\n\n(Press 'Y' to confirm)\n"), which, MM_YESNO);
else
which(0);

View file

@ -8247,61 +8247,39 @@ static void P_ResetSpawnpoints(void)
skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL;
}
static void P_TryAddGhosts(const char *gpath, boolean all, timeattackreplay_e which)
{
for (INT32 i = 0; i < numskins; i++)
{
if (!all && players[consoleplayer].skin != i)
continue;
CLEANUP(pfree) char *demopath = G_GetRecordReplay(gpath, gamemap, i, which);
if (FIL_FileExists(demopath))
G_AddGhost(demopath);
}
}
static void P_LoadRecordGhosts(void)
{
// see also m_menu.c's Nextmap_OnChange
char *gpath;
INT32 i;
char *gamemode = M_AppendGametypeAndModName();
gpath = xva("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, modeattacking == ATTACKING_ITEMBREAK);
// Best Time ghost
if (cv_ghost_besttime.value)
{
for (i = 0; i < numskins; ++i)
{
if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i)
continue;
if (FIL_FileExists(va("%s-%s-%s-time-best.lmp", gpath, skins[i].name, gamemode)))
G_AddGhost(va("%s-%s-%s-time-best.lmp", gpath, skins[i].name, gamemode));
}
}
P_TryAddGhosts(gpath, cv_ghost_besttime.value != 1, TA_TIMEBEST);
// Best Lap ghost
if (modeattacking != ATTACKING_ITEMBREAK)
{
if (cv_ghost_bestlap.value)
{
for (i = 0; i < numskins; ++i)
{
if (cv_ghost_bestlap.value == 1 && players[consoleplayer].skin != i)
continue;
if (FIL_FileExists(va("%s-%s-%s-lap-best.lmp", gpath, skins[i].name, gamemode)))
G_AddGhost(va("%s-%s-%s-lap-best.lmp", gpath, skins[i].name, gamemode));
}
}
}
if (modeattacking != ATTACKING_ITEMBREAK && cv_ghost_bestlap.value)
P_TryAddGhosts(gpath, cv_ghost_bestlap.value != 1, TA_LAPBEST);
// Last ghost
if (cv_ghost_last.value)
{
for (i = 0; i < numskins; ++i)
{
if (cv_ghost_last.value == 1 && players[consoleplayer].skin != i)
continue;
if (FIL_FileExists(va("%s-%s-%s-last.lmp", gpath, skins[i].name, gamemode)))
G_AddGhost(va("%s-%s-%s-last.lmp", gpath, skins[i].name, gamemode));
}
}
P_TryAddGhosts(gpath, cv_ghost_last.value != 1, TA_LAST);
// Guest ghost
if (cv_ghost_guest.value && FIL_FileExists(va("%s-%s-guest.lmp", gpath, gamemode)))
G_AddGhost(va("%s-guest.lmp", gpath));
if (cv_ghost_guest.value)
P_TryAddGhosts(gpath, false, TA_GUEST);
// Staff Attack ghosts
if (cv_ghost_staff.value)
@ -8315,9 +8293,6 @@ static void P_LoadRecordGhosts(void)
j++;
}
}
free(gpath);
Z_Free(gamemode);
}
static void P_SetupCamera(UINT8 pnum, camera_t *cam)
@ -8466,7 +8441,7 @@ static void P_InitGametype(void)
#else
strcpy(ver, VERSIONSTRING);
#endif
snprintf(buf, sizeof buf, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP"%s"PATHSEP"%d-%s",
snprintf(buf, sizeof buf, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP"%s"PATHSEP"%d-%s.lmp",
srb2home, ver, (int) (time(NULL)), G_BuildMapName(gamemap));
parts = M_PathParts(buf);

View file

@ -16,6 +16,7 @@
#include <stdio.h>
#include "doomtype.h"
#include "doomdef.h"
#ifdef __cplusplus
extern "C" {
@ -153,6 +154,11 @@ FUNCINLINE static ATTRINLINE void Z_Pfree(void *p)
Z_Free(*(void **)p);
}
FUNCINLINE static ATTRINLINE void pfree(void *p)
{
free(*(void **)p);
}
#ifdef __cplusplus
} // extern "C"
#endif