M_PrecacheLevelLocks(void): Implement a SECOND level of cacheing for Map and Cup unlocks

Determining whether a map or cup is unlocked or not is now linear-time.
- Attempted to cache SECRET_SKIN et al as well, but skins are loaded after unlocks... oh well.
- Was staring down the barrel of a triple-nested loop for implementing SECRET_ALTMUSIC, so did this first to set good precedent.
This commit is contained in:
toaster 2023-10-08 18:25:20 +01:00
parent 2368ee89e6
commit 8fd809f8b1
4 changed files with 73 additions and 4 deletions

View file

@ -491,6 +491,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL);
cup->id = numkartcupheaders;
cup->monitor = 1;
cup->cache_cuplock = MAXUNLOCKABLES;
deh_strlcpy(cup->name, word2,
sizeof(cup->name), va("Cup header %s: name", word2));
cup->namehash = hash;

View file

@ -408,6 +408,8 @@ struct cupheader_t
boolean playcredits; ///< Play the credits?
UINT16 cache_cuplock; ///< Cached Unlockable ID
cupwindata_t windata[4]; ///< Data for cup visitation
cupheader_t *next; ///< Next cup in linked list
};
@ -534,6 +536,7 @@ struct mapheader_t
UINT32 _saveid; ///< Purely assistive in gamedata save processes
UINT16 cache_spraycan; ///< Cached Spraycan ID
UINT16 cache_maplock; ///< Cached Unlockable ID
// Lua information
UINT8 numCustomOptions; ///< Internal. For Lua custom value support.

View file

@ -684,7 +684,16 @@ void M_ClearSecrets(void)
{
if (!mapheaderinfo[i])
continue;
mapheaderinfo[i]->cache_spraycan = UINT16_MAX;
mapheaderinfo[i]->cache_maplock = MAXUNLOCKABLES;
}
cupheader_t *cup;
for (cup = kartcupheaders; cup; cup = cup->next)
{
cup->cache_cuplock = MAXUNLOCKABLES;
}
for (i = 0; i < numskincolors; i++)
@ -820,10 +829,54 @@ static void M_AssignSpraycans(void)
}
}
static void M_PrecacheLevelLocks(void)
{
UINT16 i, j;
for (i = 0; i < MAXUNLOCKABLES; ++i)
{
switch (unlockables[i].type)
{
// SECRET_SKIN, SECRET_COLOR, SECRET_FOLLOWER are instantiated too late to use
case SECRET_MAP:
{
UINT16 map = M_UnlockableMapNum(&unlockables[i]);
if (map < nummapheaders
&& mapheaderinfo[map])
{
if (mapheaderinfo[map]->cache_maplock != MAXUNLOCKABLES)
CONS_Alert(CONS_ERROR, "Unlockable %u: Too many SECRET_MAPs associated with Level %s\n", i, mapheaderinfo[map]->lumpname);
mapheaderinfo[map]->cache_maplock = i;
}
break;
}
case SECRET_CUP:
{
cupheader_t *cup = M_UnlockableCup(&unlockables[i]);
if (cup)
{
if (cup->cache_cuplock != MAXUNLOCKABLES)
CONS_Alert(CONS_ERROR, "Unlockable %u: Too many SECRET_CUPs associated with Cup %s\n", i, cup->name);
cup->cache_cuplock = i;
break;
}
break;
}
default:
break;
}
}
}
void M_FinaliseGameData(void)
{
//M_PopulateChallengeGrid(); -- This can be done lazily when we actually need it
// Precache as many unlockables as is meaningfully feasible
M_PrecacheLevelLocks();
// Place the spraycans, which CAN'T be done lazily.
M_AssignSpraycans();
@ -2341,8 +2394,6 @@ boolean M_SecretUnlocked(INT32 type, boolean local)
boolean M_CupLocked(cupheader_t *cup)
{
UINT16 i;
// Don't lock maps in dedicated servers.
// That just makes hosts' lives hell.
if (dedicated)
@ -2355,6 +2406,9 @@ boolean M_CupLocked(cupheader_t *cup)
if (!cup)
return false;
#if 0 // perfect uncached behaviour
UINT16 i;
for (i = 0; i < MAXUNLOCKABLES; ++i)
{
if (unlockables[i].type != SECRET_CUP)
@ -2363,14 +2417,16 @@ boolean M_CupLocked(cupheader_t *cup)
continue;
return !M_CheckNetUnlockByID(i);
}
#else
if (cup->cache_cuplock < MAXUNLOCKABLES)
return !M_CheckNetUnlockByID(cup->cache_cuplock);
#endif
return false;
}
boolean M_MapLocked(UINT16 mapnum)
{
UINT16 i;
// Don't lock maps in dedicated servers.
// That just makes hosts' lives hell.
if (dedicated)
@ -2391,6 +2447,9 @@ boolean M_MapLocked(UINT16 mapnum)
return M_CupLocked(mapheaderinfo[mapnum-1]->cup);
}
#if 0 // perfect uncached behaviour
UINT16 i;
for (i = 0; i < MAXUNLOCKABLES; ++i)
{
if (unlockables[i].type != SECRET_MAP)
@ -2399,6 +2458,10 @@ boolean M_MapLocked(UINT16 mapnum)
continue;
return !M_CheckNetUnlockByID(i);
}
#else
if (mapheaderinfo[mapnum-1]->cache_maplock < MAXUNLOCKABLES)
return !M_CheckNetUnlockByID(mapheaderinfo[mapnum-1]->cache_maplock);
#endif
return false;
}

View file

@ -464,6 +464,8 @@ static void P_ClearSingleMapHeaderInfo(INT16 num)
mapheaderinfo[num]->cache_spraycan = UINT16_MAX;
mapheaderinfo[num]->cache_maplock = MAXUNLOCKABLES;
mapheaderinfo[num]->customopts = NULL;
mapheaderinfo[num]->numCustomOptions = 0;
}