mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Unloaded cupheader windata tracking
IMPORTANT NOTE - increments gamedata minor version to 3, as it is necessary to backfill windata to prevent losing existing cup records.
This is essentially commit 1482fd5 but for cups.
- All cups currently loaded with nonzero windata are written on gamedata save.
- This reduces gamedata size for a player who has not unlocked every cup!
- On gamedata load, if a cup is not loaded, store the extra windata on a linked list.
- On cup header creation, check the linked list to see if an associated unloaded cupheader windata exists.
- If it does, write the record onto the cup structure directly, and delete the "unloaded cupheader" storage struct!
- Then on the NEXT gamedata save, in addition to all loaded cupheaders, it writes the extra windata kept in long term storage in exactly the same format.
This commit is contained in:
parent
b186e89353
commit
65f679c0bc
4 changed files with 176 additions and 37 deletions
|
|
@ -494,6 +494,36 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
|
|||
deh_strlcpy(cup->name, word2,
|
||||
sizeof(cup->name), va("Cup header %s: name", word2));
|
||||
cup->namehash = hash;
|
||||
|
||||
// Check to see if we have any custom cup record data that we could substitute in.
|
||||
unloaded_cupheader_t *unloadedcup, *unloadedprev = NULL;
|
||||
for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedprev = unloadedcup, unloadedcup = unloadedcup->next)
|
||||
{
|
||||
if (unloadedcup->namehash != hash)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(word2, unloadedcup->name) != 0)
|
||||
continue;
|
||||
|
||||
// Copy in standings, etc.
|
||||
M_Memcpy(&cup->windata, &unloadedcup->windata, sizeof(cup->windata));
|
||||
|
||||
// Remove this entry from the chain.
|
||||
if (unloadedprev)
|
||||
{
|
||||
unloadedprev->next = unloadedcup->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
unloadedcupheaders = unloadedcup->next;
|
||||
}
|
||||
|
||||
// Finally, free.
|
||||
Z_Free(unloadedcup);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (prev != NULL)
|
||||
prev->next = cup;
|
||||
if (kartcupheaders == NULL)
|
||||
|
|
|
|||
|
|
@ -387,6 +387,18 @@ struct cupheader_t
|
|||
extern cupheader_t *kartcupheaders; // Start of cup linked list
|
||||
extern UINT16 numkartcupheaders;
|
||||
|
||||
struct unloaded_cupheader_t
|
||||
{
|
||||
char name[MAXCUPNAME];
|
||||
UINT32 namehash;
|
||||
|
||||
cupwindata_t windata[4];
|
||||
|
||||
unloaded_cupheader_t *next;
|
||||
};
|
||||
|
||||
extern unloaded_cupheader_t *unloadedcupheaders;
|
||||
|
||||
#define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata
|
||||
#define MAXSTAFF 3
|
||||
|
||||
|
|
|
|||
170
src/g_game.c
170
src/g_game.c
|
|
@ -206,6 +206,8 @@ unloaded_mapheader_t *unloadedmapheaders = NULL;
|
|||
cupheader_t *kartcupheaders = NULL;
|
||||
UINT16 numkartcupheaders = 0;
|
||||
|
||||
unloaded_cupheader_t *unloadedcupheaders = NULL;
|
||||
|
||||
static boolean exitgame = false;
|
||||
static boolean retrying = false;
|
||||
static boolean retryingmodeattack = false;
|
||||
|
|
@ -456,20 +458,28 @@ void G_ClearRecords(void)
|
|||
memset(&mapheaderinfo[i]->records, 0, sizeof(recorddata_t));
|
||||
}
|
||||
|
||||
unloaded_mapheader_t *unloadedmap, *next = NULL;
|
||||
for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = next)
|
||||
{
|
||||
next = unloadedmap->next;
|
||||
Z_Free(unloadedmap->lumpname);
|
||||
Z_Free(unloadedmap);
|
||||
}
|
||||
unloadedmapheaders = NULL;
|
||||
|
||||
cupheader_t *cup;
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
memset(&cup->windata, 0, sizeof(cup->windata));
|
||||
}
|
||||
|
||||
unloaded_mapheader_t *unloadedmap, *nextunloadedmap = NULL;
|
||||
for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = nextunloadedmap)
|
||||
{
|
||||
nextunloadedmap = unloadedmap->next;
|
||||
Z_Free(unloadedmap->lumpname);
|
||||
Z_Free(unloadedmap);
|
||||
}
|
||||
unloadedmapheaders = NULL;
|
||||
|
||||
unloaded_cupheader_t *unloadedcup, *nextunloadedcup = NULL;
|
||||
for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = nextunloadedcup)
|
||||
{
|
||||
nextunloadedcup = unloadedcup->next;
|
||||
Z_Free(unloadedcup);
|
||||
}
|
||||
unloadedcupheaders = NULL;
|
||||
}
|
||||
|
||||
// For easy retrieval of records
|
||||
|
|
@ -4743,7 +4753,7 @@ void G_LoadGameSettings(void)
|
|||
}
|
||||
|
||||
#define GD_VERSIONCHECK 0xBA5ED123 // Change every major version, as usual
|
||||
#define GD_VERSIONMINOR 2 // Change every format update
|
||||
#define GD_VERSIONMINOR 3 // Change every format update
|
||||
|
||||
static const char *G_GameDataFolder(void)
|
||||
{
|
||||
|
|
@ -4991,6 +5001,8 @@ void G_LoadGameData(void)
|
|||
char cupname[MAXCUPNAME];
|
||||
cupheader_t *cup;
|
||||
|
||||
cupwindata_t dummywindata[4];
|
||||
|
||||
// Find the relevant cup.
|
||||
READSTRINGN(save.p, cupname, sizeof(cupname));
|
||||
UINT32 hash = quickncasehash(cupname, MAXCUPNAME);
|
||||
|
|
@ -5010,19 +5022,45 @@ void G_LoadGameData(void)
|
|||
{
|
||||
rtemp = READUINT8(save.p);
|
||||
|
||||
// ...but only record it if we actually found the associated cup.
|
||||
if (cup)
|
||||
{
|
||||
cup->windata[j].best_placement = (rtemp & 0x0F);
|
||||
cup->windata[j].best_grade = (rtemp & 0x70)>>4;
|
||||
if (rtemp & 0x80)
|
||||
{
|
||||
if (j == 0)
|
||||
goto datacorrupt;
|
||||
dummywindata[j].best_placement = (rtemp & 0x0F);
|
||||
dummywindata[j].best_grade = (rtemp & 0x70)>>4;
|
||||
if (rtemp & 0x80)
|
||||
dummywindata[j].got_emerald = true;
|
||||
}
|
||||
|
||||
cup->windata[j].got_emerald = true;
|
||||
}
|
||||
}
|
||||
if (versionMinor < 3 && dummywindata[0].best_placement == 0)
|
||||
{
|
||||
// We now require backfilling of placement information.
|
||||
M_Memcpy(&dummywindata[0], &dummywindata[1], sizeof(dummywindata[0]));
|
||||
}
|
||||
|
||||
if (cup)
|
||||
{
|
||||
// We found a cup, so assign the windata.
|
||||
|
||||
M_Memcpy(&cup->windata, &dummywindata, sizeof(cup->windata));
|
||||
}
|
||||
else if (dummywindata[0].best_placement != 0)
|
||||
{
|
||||
// Invalid, but we don't want to lose all the juicy statistics.
|
||||
// Instead, update a FILO linked list of "unloaded cupheaders".
|
||||
|
||||
unloaded_cupheader_t *unloadedcup =
|
||||
Z_Malloc(
|
||||
sizeof(unloaded_cupheader_t),
|
||||
PU_STATIC, NULL
|
||||
);
|
||||
|
||||
// Establish properties, for later retrieval on file add.
|
||||
strlcpy(unloadedcup->name, cupname, sizeof(unloadedcup->name));
|
||||
unloadedcup->namehash = quickncasehash(cupname, MAXCUPNAME);
|
||||
|
||||
// Insert at the head, just because it's convenient.
|
||||
unloadedcup->next = unloadedcupheaders;
|
||||
unloadedcupheaders = unloadedcup;
|
||||
|
||||
// Finally, copy into.
|
||||
M_Memcpy(&unloadedcup->windata, &dummywindata, sizeof(unloadedcup->windata));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5087,7 +5125,7 @@ void G_DirtyGameData(void)
|
|||
void G_SaveGameData(void)
|
||||
{
|
||||
size_t length;
|
||||
INT32 i, j, numcups;
|
||||
INT32 i, j;
|
||||
cupheader_t *cup;
|
||||
UINT8 btemp;
|
||||
savebuffer_t save = {0};
|
||||
|
|
@ -5152,12 +5190,37 @@ void G_SaveGameData(void)
|
|||
|
||||
length += 4 + (numgamedatamapheaders * (MAXMAPLUMPNAME+1+4+4));
|
||||
|
||||
numcups = 0;
|
||||
UINT32 numgamedatacups = 0;
|
||||
unloaded_cupheader_t *unloadedcup;
|
||||
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
numcups++;
|
||||
// Results are populated downwards, so no Easy win
|
||||
// means there's no important player data to save.
|
||||
if (cup->windata[0].best_placement == 0)
|
||||
continue;
|
||||
|
||||
numgamedatacups++;
|
||||
}
|
||||
length += 4 + (numcups * (4+16));
|
||||
|
||||
for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = unloadedcup->next)
|
||||
{
|
||||
// Ditto, with the exception that we should warn about it.
|
||||
if (unloadedcup->windata[0].best_placement == 0)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Unloaded cup \"%s\" has no windata!\n", unloadedcup->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// It's far off on the horizon, beyond many memory limits, but prevent a potential misery moment of losing ALL your data.
|
||||
if (++numgamedatacups == UINT32_MAX)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Some unloaded cup standings data has been dropped due to datatype limitations.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
length += 4 + (numgamedatacups * (4+16));
|
||||
|
||||
if (P_SaveBufferAlloc(&save, length) == false)
|
||||
{
|
||||
|
|
@ -5298,22 +5361,55 @@ void G_SaveGameData(void)
|
|||
}
|
||||
}
|
||||
|
||||
WRITEUINT32(save.p, numcups); // 4
|
||||
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
WRITEUINT32(save.p, numgamedatacups); // 4
|
||||
|
||||
{
|
||||
// For figuring out which header to assign it to on load
|
||||
WRITESTRINGN(save.p, cup->name, 16);
|
||||
// (numgamedatacups * (4+16))
|
||||
|
||||
for (i = 0; i < KARTGP_MAX; i++)
|
||||
{
|
||||
btemp = min(cup->windata[i].best_placement, 0x0F);
|
||||
btemp |= (cup->windata[i].best_grade<<4);
|
||||
if (i != 0 && cup->windata[i].got_emerald == true)
|
||||
btemp |= 0x80;
|
||||
UINT32 writtengamedatacups = 0;
|
||||
|
||||
WRITEUINT8(save.p, btemp); // 4 * numcups
|
||||
#define WRITECUPWINDATA(maybeunloadedcup) \
|
||||
for (i = 0; i < KARTGP_MAX; i++) \
|
||||
{ \
|
||||
btemp = min(maybeunloadedcup->windata[i].best_placement, 0x0F); \
|
||||
btemp |= (maybeunloadedcup->windata[i].best_grade<<4); \
|
||||
if (maybeunloadedcup->windata[i].got_emerald == true) \
|
||||
btemp |= 0x80; \
|
||||
\
|
||||
WRITEUINT8(save.p, btemp); \
|
||||
}
|
||||
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
if (cup->windata[0].best_placement == 0)
|
||||
continue;
|
||||
|
||||
WRITESTRINGN(save.p, cup->name, MAXCUPNAME);
|
||||
|
||||
WRITECUPWINDATA(cup);
|
||||
|
||||
if (++writtengamedatacups >= numgamedatacups)
|
||||
break;
|
||||
}
|
||||
|
||||
if (writtengamedatacups < numgamedatacups)
|
||||
{
|
||||
for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = unloadedcup->next)
|
||||
{
|
||||
if (unloadedcup->windata[0].best_placement == 0)
|
||||
continue;
|
||||
|
||||
WRITESTRINGN(save.p, unloadedcup->name, MAXCUPNAME);
|
||||
|
||||
WRITECUPWINDATA(unloadedcup);
|
||||
|
||||
if (++writtengamedatacups >= numgamedatacups)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#undef WRITECUPWINDATA
|
||||
}
|
||||
|
||||
length = save.p - save.buffer;
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ TYPEDEF (mapheader_t);
|
|||
TYPEDEF (unloaded_mapheader_t);
|
||||
TYPEDEF (tolinfo_t);
|
||||
TYPEDEF (cupheader_t);
|
||||
TYPEDEF (unloaded_cupheader_t);
|
||||
|
||||
// font.h
|
||||
TYPEDEF (font_t);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue