mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Unloaded mapheader record tracking system
In the previous entry in the series, due to level header records existing in a NUMMAPS-sized table always saved and loaded in full, Time Attack times persisted even across game loads without the relevant custom levels added.
However, this was changed with the long map name system. Map records were assigned to level headers, which were only created on level load.
This new system brings Ring Racers up to parity (or better, due to the reduced incidence of header conflicts!)
- All levels currently loaded with records attached are written on gamedata save.
- This reduces gamedata size for a player who has not unlocked every level!
- On gamedata load, if a level is not loaded, store those extra records on a linked list.
- On level header creation, check the linked list to see if an associated unloaded mapheader record exists.
- If it does, write the record onto the map structure directly, and delete the "unloaded mapheader" storage struct!
- Then on the NEXT gamedata save, in addition to all loaded mapheaders, it writes the extra records kept in long term storage in exactly the same format.
This commit is contained in:
parent
4682f03f91
commit
28677da5b9
4 changed files with 159 additions and 30 deletions
|
|
@ -950,8 +950,45 @@ void readlevelheader(MYFILE *f, char * name)
|
|||
|
||||
if (mapheaderinfo[num]->lumpname == NULL)
|
||||
{
|
||||
mapheaderinfo[num]->lumpname = Z_StrDup(name);
|
||||
mapheaderinfo[num]->lumpnamehash = quickncasehash(mapheaderinfo[num]->lumpname, MAXMAPLUMPNAME);
|
||||
mapheaderinfo[num]->lumpnamehash = quickncasehash(name, MAXMAPLUMPNAME);
|
||||
|
||||
// Check to see if we have any custom map record data that we could substitute in.
|
||||
unloaded_mapheader_t *unloadedmap, *prev = NULL;
|
||||
for (unloadedmap = unloadedmapheaders; unloadedmap; prev = unloadedmap, unloadedmap = unloadedmap->next)
|
||||
{
|
||||
if (unloadedmap->lumpnamehash != mapheaderinfo[num]->lumpnamehash)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(name, unloadedmap->lumpname) != 0)
|
||||
continue;
|
||||
|
||||
// Copy in mapvisited, time, lap, etc.
|
||||
M_Memcpy(&mapheaderinfo[num]->records, &unloadedmap->records, sizeof(recorddata_t));
|
||||
|
||||
// Reuse the zone-allocated lumpname string.
|
||||
mapheaderinfo[num]->lumpname = unloadedmap->lumpname;
|
||||
|
||||
// Remove this entry from the chain.
|
||||
if (prev)
|
||||
{
|
||||
prev->next = unloadedmap->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
unloadedmapheaders = unloadedmap->next;
|
||||
}
|
||||
|
||||
// Finally, free.
|
||||
Z_Free(unloadedmap);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (mapheaderinfo[num]->lumpname == NULL)
|
||||
{
|
||||
// If there was no string to reuse, dup our own.
|
||||
mapheaderinfo[num]->lumpname = Z_StrDup(name);
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
|
|
|
|||
|
|
@ -500,6 +500,18 @@ struct mapheader_t
|
|||
extern mapheader_t** mapheaderinfo;
|
||||
extern INT32 nummapheaders, mapallocsize;
|
||||
|
||||
struct unloaded_mapheader_t
|
||||
{
|
||||
char *lumpname;
|
||||
UINT32 lumpnamehash;
|
||||
|
||||
recorddata_t records;
|
||||
|
||||
unloaded_mapheader_t *next;
|
||||
};
|
||||
|
||||
extern unloaded_mapheader_t *unloadedmapheaders;
|
||||
|
||||
// Gametypes
|
||||
#define NUMGAMETYPEFREESLOTS (128)
|
||||
#define MAXGAMETYPELENGTH (32)
|
||||
|
|
|
|||
135
src/g_game.c
135
src/g_game.c
|
|
@ -200,6 +200,8 @@ mapheader_t** mapheaderinfo = {NULL};
|
|||
INT32 nummapheaders = 0;
|
||||
INT32 mapallocsize = 0;
|
||||
|
||||
unloaded_mapheader_t *unloadedmapheaders = NULL;
|
||||
|
||||
// Kart cup definitions
|
||||
cupheader_t *kartcupheaders = NULL;
|
||||
UINT16 numkartcupheaders = 0;
|
||||
|
|
@ -448,13 +450,22 @@ INT32 player_name_changes[MAXPLAYERS];
|
|||
void G_ClearRecords(void)
|
||||
{
|
||||
INT16 i;
|
||||
cupheader_t *cup;
|
||||
|
||||
for (i = 0; i < nummapheaders; ++i)
|
||||
{
|
||||
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));
|
||||
|
|
@ -4920,43 +4931,54 @@ void G_LoadGameData(void)
|
|||
|
||||
// Main records
|
||||
numgamedatamapheaders = READUINT32(save.p);
|
||||
if (numgamedatamapheaders >= NEXTMAP_SPECIAL)
|
||||
goto datacorrupt;
|
||||
|
||||
for (i = 0; i < numgamedatamapheaders; i++)
|
||||
{
|
||||
char mapname[MAXMAPLUMPNAME];
|
||||
INT16 mapnum;
|
||||
tic_t rectime;
|
||||
tic_t reclap;
|
||||
|
||||
READSTRINGN(save.p, mapname, sizeof(mapname));
|
||||
mapnum = G_MapNumber(mapname);
|
||||
|
||||
recorddata_t dummyrecord, *record = &dummyrecord;
|
||||
|
||||
rtemp = READUINT8(save.p);
|
||||
rectime = (tic_t)READUINT32(save.p);
|
||||
reclap = (tic_t)READUINT32(save.p);
|
||||
|
||||
if (rtemp & ~MV_MAX)
|
||||
goto datacorrupt;
|
||||
|
||||
if (mapnum < nummapheaders && mapheaderinfo[mapnum])
|
||||
{
|
||||
// Valid mapheader, time to populate with record data.
|
||||
|
||||
if ((mapheaderinfo[mapnum]->records.mapvisited = rtemp) & ~MV_MAX)
|
||||
goto datacorrupt;
|
||||
|
||||
if (rectime || reclap)
|
||||
{
|
||||
mapheaderinfo[i]->records.time = rectime;
|
||||
mapheaderinfo[i]->records.lap = reclap;
|
||||
//CONS_Printf("ID %d, Time = %d, Lap = %d\n", i, rectime/35, reclap/35);
|
||||
}
|
||||
record = &mapheaderinfo[mapnum]->records;
|
||||
}
|
||||
else
|
||||
else if (rtemp) // Mapvisited will never be 0 for a map with a record.
|
||||
{
|
||||
// Since it's not worth declaring the entire gamedata
|
||||
// corrupt over extra maps, we report and move on.
|
||||
CONS_Alert(CONS_WARNING, "Map with lumpname %s does not exist, time record data will be discarded\n", mapname);
|
||||
// Invalid, but we don't want to lose all the juicy statistics.
|
||||
// Instead, update a FILO linked list of "unloaded mapheaders".
|
||||
|
||||
unloaded_mapheader_t *unloadedmap =
|
||||
Z_Malloc(
|
||||
sizeof(unloaded_mapheader_t),
|
||||
PU_STATIC, NULL
|
||||
);
|
||||
|
||||
// Establish properties, for later retrieval on file add.
|
||||
unloadedmap->lumpname = Z_StrDup(mapname);
|
||||
unloadedmap->lumpnamehash = quickncasehash(mapname, MAXMAPLUMPNAME);
|
||||
|
||||
// Insert at the head, just because it's convenient.
|
||||
unloadedmap->next = unloadedmapheaders;
|
||||
unloadedmapheaders = unloadedmap;
|
||||
|
||||
// Finally, set the pointer to write into.
|
||||
record = &unloadedmap->records;
|
||||
}
|
||||
|
||||
record->mapvisited = rtemp;
|
||||
record->time = (tic_t)READUINT32(save.p);
|
||||
record->lap = (tic_t)READUINT32(save.p);
|
||||
}
|
||||
|
||||
if (versionMinor > 1)
|
||||
|
|
@ -5095,7 +5117,34 @@ void G_SaveGameData(void)
|
|||
{
|
||||
length += gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT;
|
||||
}
|
||||
length += 4 + (nummapheaders * (MAXMAPLUMPNAME+1+4+4));
|
||||
|
||||
UINT32 numgamedatamapheaders = 0;
|
||||
unloaded_mapheader_t *unloadedmap;
|
||||
|
||||
for (i = 0; i < nummapheaders; i++)
|
||||
{
|
||||
// It's safe to assume a level with no mapvisited will have no other data worth keeping, since you get MV_VISITED just for opening it.
|
||||
if (!(mapheaderinfo[i]->records.mapvisited & MV_MAX))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
numgamedatamapheaders++;
|
||||
}
|
||||
|
||||
for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next)
|
||||
{
|
||||
// Ditto, with the exception that we should warn about it.
|
||||
if (!(unloadedmap->records.mapvisited & MV_MAX))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Unloaded map \"%s\" has no mapvisited!\n", unloadedmap->lumpname);
|
||||
continue;
|
||||
}
|
||||
|
||||
numgamedatamapheaders++;
|
||||
}
|
||||
|
||||
length += 4 + (numgamedatamapheaders * (MAXMAPLUMPNAME+1+4+4));
|
||||
|
||||
numcups = 0;
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
|
|
@ -5193,17 +5242,47 @@ void G_SaveGameData(void)
|
|||
WRITEUINT32(save.p, gamedata->timesBeaten); // 4
|
||||
|
||||
// Main records
|
||||
WRITEUINT32(save.p, nummapheaders); // 4
|
||||
WRITEUINT32(save.p, numgamedatamapheaders); // 4
|
||||
|
||||
for (i = 0; i < nummapheaders; i++) // nummapheaders * (255+1+4+4)
|
||||
{
|
||||
// For figuring out which header to assign it to on load
|
||||
WRITESTRINGN(save.p, mapheaderinfo[i]->lumpname, MAXMAPLUMPNAME);
|
||||
// numgamedatamapheaders * (MAXMAPLUMPNAME+1+4+4)
|
||||
|
||||
WRITEUINT8(save.p, (mapheaderinfo[i]->records.mapvisited & MV_MAX));
|
||||
UINT32 writtengamedatamapheaders = 0;
|
||||
|
||||
WRITEUINT32(save.p, mapheaderinfo[i]->records.time);
|
||||
WRITEUINT32(save.p, mapheaderinfo[i]->records.lap);
|
||||
for (i = 0; i < nummapheaders; i++)
|
||||
{
|
||||
if (!(mapheaderinfo[i]->records.mapvisited & MV_MAX))
|
||||
continue;
|
||||
|
||||
WRITESTRINGN(save.p, mapheaderinfo[i]->lumpname, MAXMAPLUMPNAME);
|
||||
|
||||
WRITEUINT8(save.p, (mapheaderinfo[i]->records.mapvisited & MV_MAX));
|
||||
|
||||
WRITEUINT32(save.p, mapheaderinfo[i]->records.time);
|
||||
WRITEUINT32(save.p, mapheaderinfo[i]->records.lap);
|
||||
|
||||
if (++writtengamedatamapheaders >= numgamedatamapheaders)
|
||||
break;
|
||||
}
|
||||
|
||||
if (writtengamedatamapheaders < numgamedatamapheaders)
|
||||
{
|
||||
for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next)
|
||||
{
|
||||
if (!(unloadedmap->records.mapvisited & MV_MAX))
|
||||
continue;
|
||||
|
||||
WRITESTRINGN(save.p, unloadedmap->lumpname, MAXMAPLUMPNAME);
|
||||
|
||||
WRITEUINT8(save.p, (unloadedmap->records.mapvisited & MV_MAX));
|
||||
|
||||
WRITEUINT32(save.p, unloadedmap->records.time);
|
||||
WRITEUINT32(save.p, unloadedmap->records.lap);
|
||||
|
||||
if (++writtengamedatamapheaders >= numgamedatamapheaders)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WRITEUINT32(save.p, numcups); // 4
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ TYPEDEF (customoption_t);
|
|||
TYPEDEF (gametype_t);
|
||||
TYPEDEF (staffbrief_t);
|
||||
TYPEDEF (mapheader_t);
|
||||
TYPEDEF (unloaded_mapheader_t);
|
||||
TYPEDEF (tolinfo_t);
|
||||
TYPEDEF (cupheader_t);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue