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

View file

@ -465,39 +465,51 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
//
else if (fastcmp(word, "CUP"))
{
cupheader_t *cup = kartcupheaders;
cupheader_t *prev = NULL;
while (cup)
size_t len = strlen(word2);
if (len <= MAXCUPNAME-1)
{
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!
G_SetGameModified(multiplayer, true);
break;
if (hash == cup->namehash && fastcmp(cup->name, word2))
{
// Only a major mod if editing stuff that isn't your own!
G_SetGameModified(multiplayer, true);
break;
}
prev = cup;
cup = cup->next;
}
prev = cup;
cup = cup->next;
}
// Nothing found, add to the end.
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.
if (!cup)
readcupheader(f, cup);
}
else
{
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));
if (prev != NULL)
prev->next = cup;
if (kartcupheaders == NULL)
kartcupheaders = cup;
numkartcupheaders++;
CONS_Printf("Added cup %d ('%s')\n", cup->id, cup->name);
deh_warning("Cup header's name %s is too long (%s characters VS %d max)", word2, sizeu1(len), (MAXCUPNAME-1));
ignorelines(f);
}
readcupheader(f, cup);
}
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_MAX (CUPCACHE_SPECIAL+1)
#define MAXCUPNAME 16 // includes \0, for cleaner savedata
struct cupheader_t
{
UINT16 id; ///< Cup ID
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 *levellist[CUPCACHE_MAX]; ///< List of levels that belong to this cup
INT16 cachedlevels[CUPCACHE_MAX]; ///< IDs in levellist, bonusgame, and specialstage
@ -400,6 +405,7 @@ struct mapheader_t
{
// Core game information, not user-modifiable directly
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
void *thumbnailPic; ///< Lump data for the level select thumbnail.

View file

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

View file

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