Level and cup header information: Hashing for referencing by name

Foundational assistive work.
Also guarantees a consistent cup name length in memory, as some places read/wrote 15 bytes, and some places read/wrote 16 bytes. We settle on the latter (including null terminator) for the broadest backwards compatibility.
This commit is contained in:
toaster 2023-05-23 17:41:32 +01:00
parent ff23501e74
commit 533508d7b0
5 changed files with 60 additions and 30 deletions

View file

@ -953,6 +953,7 @@ void readlevelheader(MYFILE *f, char * name)
if (mapheaderinfo[num]->lumpname == NULL) if (mapheaderinfo[num]->lumpname == NULL)
{ {
mapheaderinfo[num]->lumpname = Z_StrDup(name); mapheaderinfo[num]->lumpname = Z_StrDup(name);
mapheaderinfo[num]->lumpnamehash = quickncasehash(mapheaderinfo[num]->lumpname, MAXMAPLUMPNAME);
} }
do do
@ -2638,9 +2639,10 @@ static void readcondition(UINT8 set, UINT32 id, char *word2)
ty = UCRP_PODIUMCUP; ty = UCRP_PODIUMCUP;
{ {
cupheader_t *cup = kartcupheaders; cupheader_t *cup = kartcupheaders;
UINT32 hash = quickncasehash(params[1], MAXCUPNAME);
while (cup) while (cup)
{ {
if (!strcmp(cup->name, params[1])) if (hash == cup->namehash && !strcmp(cup->name, params[1]))
break; break;
cup = cup->next; cup = cup->next;
} }

View file

@ -465,39 +465,51 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
// //
else if (fastcmp(word, "CUP")) else if (fastcmp(word, "CUP"))
{ {
cupheader_t *cup = kartcupheaders; size_t len = strlen(word2);
cupheader_t *prev = NULL; if (len <= MAXCUPNAME-1)
while (cup)
{ {
if (fastcmp(cup->name, word2)) cupheader_t *cup = kartcupheaders;
cupheader_t *prev = NULL;
UINT32 hash = quickncasehash(word2, MAXCUPNAME);
while (cup)
{ {
// Only a major mod if editing stuff that isn't your own! if (hash == cup->namehash && fastcmp(cup->name, word2))
G_SetGameModified(multiplayer, true); {
break; // Only a major mod if editing stuff that isn't your own!
G_SetGameModified(multiplayer, true);
break;
}
prev = cup;
cup = cup->next;
} }
prev = cup; // Nothing found, add to the end.
cup = cup->next; if (!cup)
} {
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL);
cup->id = numkartcupheaders;
cup->monitor = 1;
deh_strlcpy(cup->name, word2,
sizeof(cup->name), va("Cup header %s: name", word2));
cup->namehash = hash;
if (prev != NULL)
prev->next = cup;
if (kartcupheaders == NULL)
kartcupheaders = cup;
numkartcupheaders++;
CONS_Printf("Added cup %d ('%s')\n", cup->id, cup->name);
}
// Nothing found, add to the end. readcupheader(f, cup);
if (!cup)
}
else
{ {
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL); deh_warning("Cup header's name %s is too long (%s characters VS %d max)", word2, sizeu1(len), (MAXCUPNAME-1));
cup->id = numkartcupheaders; ignorelines(f);
cup->monitor = 1;
deh_strlcpy(cup->name, word2,
sizeof(cup->name), va("Cup header %s: name", word2));
if (prev != NULL)
prev->next = cup;
if (kartcupheaders == NULL)
kartcupheaders = cup;
numkartcupheaders++;
CONS_Printf("Added cup %d ('%s')\n", cup->id, cup->name);
} }
readcupheader(f, cup);
} }
else if (fastcmp(word, "WEATHER") || fastcmp(word, "PRECIP") || fastcmp(word, "PRECIPITATION")) else if (fastcmp(word, "WEATHER") || fastcmp(word, "PRECIP") || fastcmp(word, "PRECIPITATION"))
{ {

View file

@ -363,11 +363,16 @@ struct customoption_t
#define CUPCACHE_SPECIAL (CUPCACHE_BONUS+MAXBONUSLIST) #define CUPCACHE_SPECIAL (CUPCACHE_BONUS+MAXBONUSLIST)
#define CUPCACHE_MAX (CUPCACHE_SPECIAL+1) #define CUPCACHE_MAX (CUPCACHE_SPECIAL+1)
#define MAXCUPNAME 16 // includes \0, for cleaner savedata
struct cupheader_t struct cupheader_t
{ {
UINT16 id; ///< Cup ID UINT16 id; ///< Cup ID
UINT8 monitor; ///< Monitor graphic 1-9 or A-Z UINT8 monitor; ///< Monitor graphic 1-9 or A-Z
char name[15]; ///< Cup title (14 chars)
char name[MAXCUPNAME]; ///< Cup title
UINT32 namehash; ///< Cup title hash
char icon[9]; ///< Name of the icon patch char icon[9]; ///< Name of the icon patch
char *levellist[CUPCACHE_MAX]; ///< List of levels that belong to this cup char *levellist[CUPCACHE_MAX]; ///< List of levels that belong to this cup
INT16 cachedlevels[CUPCACHE_MAX]; ///< IDs in levellist, bonusgame, and specialstage INT16 cachedlevels[CUPCACHE_MAX]; ///< IDs in levellist, bonusgame, and specialstage
@ -400,6 +405,7 @@ struct mapheader_t
{ {
// Core game information, not user-modifiable directly // Core game information, not user-modifiable directly
char *lumpname; ///< Lump name can be really long char *lumpname; ///< Lump name can be really long
UINT32 lumpnamehash; ///< quickncasehash(->lumpname, MAXMAPLUMPNAME)
lumpnum_t lumpnum; ///< Lump number for the map, used by vres_GetMap lumpnum_t lumpnum; ///< Lump number for the map, used by vres_GetMap
void *thumbnailPic; ///< Lump data for the level select thumbnail. void *thumbnailPic; ///< Lump data for the level select thumbnail.

View file

@ -807,9 +807,13 @@ INT32 G_MapNumber(const char * name)
#endif #endif
{ {
INT32 map; INT32 map;
UINT32 hash = quickncasehash(name, MAXMAPLUMPNAME);
for (map = 0; map < nummapheaders; ++map) for (map = 0; map < nummapheaders; ++map)
{ {
if (hash != mapheaderinfo[map]->lumpnamehash)
continue;
if (strcasecmp(mapheaderinfo[map]->lumpname, name) != 0) if (strcasecmp(mapheaderinfo[map]->lumpname, name) != 0)
continue; continue;
@ -4980,15 +4984,20 @@ void G_LoadGameData(void)
for (i = 0; i < numgamedatacups; i++) for (i = 0; i < numgamedatacups; i++)
{ {
char cupname[16]; char cupname[MAXCUPNAME];
cupheader_t *cup; cupheader_t *cup;
// Find the relevant cup. // Find the relevant cup.
READSTRINGN(save.p, cupname, sizeof(cupname)); READSTRINGN(save.p, cupname, sizeof(cupname));
UINT32 hash = quickncasehash(cupname, MAXCUPNAME);
for (cup = kartcupheaders; cup; cup = cup->next) for (cup = kartcupheaders; cup; cup = cup->next)
{ {
if (cup->namehash != hash)
continue;
if (strcmp(cup->name, cupname)) if (strcmp(cup->name, cupname))
continue; continue;
break; break;
} }

View file

@ -2064,9 +2064,10 @@ cupheader_t *M_UnlockableCup(unlockable_t *unlock)
if (unlock->stringVarCache == -1) if (unlock->stringVarCache == -1)
{ {
// Get the cup from the string. // Get the cup from the string.
UINT32 hash = quickncasehash(unlock->stringVar, MAXCUPNAME);
while (cup) while (cup)
{ {
if (!strcmp(cup->name, unlock->stringVar)) if (hash == cup->namehash && !strcmp(cup->name, unlock->stringVar))
break; break;
cup = cup->next; cup = cup->next;
} }