Optimisation: reduce the number of calls to M_CheckUnlockConditions

- For P_Ticker()'s calls to M_UpdateUnlockablesAndExtraEmblems
    - Do not check non-UCRP_REQUIRESPLAYING conditions
        - Controlled by a new `boolean doall` parameter to M_UpdateUnlockablesAndExtraEmblems
        - Most other contexts have this as true
        - Forced true if update is meant to be silent
    - Only check UCRP_REQUIRESPLAYING conditions if a relevant property has been touched
        - Controlled by a new `boolean checkthisframe` property on roundcondition_t
        - Set in all contexts where roundcondition_t is modified
        - Would also be set on lap change, but that case is already covered by the following
- Check all conditions, both UCRP_REQUIRESPLAYING and not, on:
    - local player K_HandleLapIncrement
    - local player P_DoPlayerExit
    - local player P_DoTimeOver
    - Controlled by a new `boolean deferredconditioncheck` property on gamedata_t
This commit is contained in:
toaster 2023-03-12 13:52:28 +00:00
parent 5a9281ecfb
commit 01f6eb71f5
19 changed files with 106 additions and 43 deletions

View file

@ -337,6 +337,9 @@ struct botvars_t
struct roundconditions_t struct roundconditions_t
{ {
// Reduce the number of checks by only updating when this is true
boolean checkthisframe;
// Trivial Yes/no events across multiple UCRP's // Trivial Yes/no events across multiple UCRP's
boolean fell_off; boolean fell_off;
boolean touched_offroad; boolean touched_offroad;

View file

@ -1083,7 +1083,7 @@ void F_GameEvaluationTicker(void)
{ {
++gamedata->timesBeaten; ++gamedata->timesBeaten;
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
G_SaveGameData(true); G_SaveGameData(true);
} }
else else

View file

@ -4194,7 +4194,7 @@ void G_SaveDemo(void)
if (gamedata->eversavedreplay == false) if (gamedata->eversavedreplay == false)
{ {
gamedata->eversavedreplay = true; gamedata->eversavedreplay = true;
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
G_SaveGameData(true); G_SaveGameData(true);
} }
} }

View file

@ -667,7 +667,7 @@ void G_UpdateRecords(void)
S_StartSound(NULL, sfx_ncitem); S_StartSound(NULL, sfx_ncitem);
} }
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
gamedata->deferredsave = true; gamedata->deferredsave = true;
} }
@ -3838,7 +3838,7 @@ static void G_UpdateVisited(void)
if ((earnedEmblems = M_CompletionEmblems())) if ((earnedEmblems = M_CompletionEmblems()))
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
G_SaveGameData(true); G_SaveGameData(true);
} }
@ -3930,7 +3930,7 @@ static void G_GetNextMap(void)
if (gamedata->everseenspecial == false) if (gamedata->everseenspecial == false)
{ {
gamedata->everseenspecial = true; gamedata->everseenspecial = true;
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
G_SaveGameData(true); G_SaveGameData(true);
} }
} }
@ -4158,7 +4158,7 @@ static void G_DoCompleted(void)
gamedata->pendingkeyrounds++; gamedata->pendingkeyrounds++;
// Done before forced addition of PF_NOCONTEST to make UCRP_NOCONTEST harder to achieve // Done before forced addition of PF_NOCONTEST to make UCRP_NOCONTEST harder to achieve
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
gamedata->deferredsave = true; gamedata->deferredsave = true;
} }
@ -4528,7 +4528,7 @@ void G_LoadGameData(void)
{ {
// Don't load at all. // Don't load at all.
// The following used to be in M_ClearSecrets, but that was silly. // The following used to be in M_ClearSecrets, but that was silly.
M_UpdateUnlockablesAndExtraEmblems(false); M_UpdateUnlockablesAndExtraEmblems(false, true);
return; return;
} }
@ -4764,7 +4764,7 @@ void G_LoadGameData(void)
gamedata->loaded = true; gamedata->loaded = true;
// Silent update unlockables in case they're out of sync with conditions // Silent update unlockables in case they're out of sync with conditions
M_UpdateUnlockablesAndExtraEmblems(false); M_UpdateUnlockablesAndExtraEmblems(false, true);
return; return;
} }

View file

@ -414,7 +414,10 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2)
if (t1->health > 1) if (t1->health > 1)
{ {
if (t1->target && t1->target->player) if (t1->target && t1->target->player)
{
t1->target->player->roundconditions.landmine_dunk = true; t1->target->player->roundconditions.landmine_dunk = true;
t1->target->player->roundconditions.checkthisframe = true;
}
S_StartSound(t2, sfx_bsnipe); S_StartSound(t2, sfx_bsnipe);
} }

View file

@ -1133,8 +1133,12 @@ static void K_UpdateOffroad(player_t *player)
if (player->offroad > offroadstrength) if (player->offroad > offroadstrength)
player->offroad = offroadstrength; player->offroad = offroadstrength;
if (player->offroad > (2*offroadstrength) / TICRATE) if (player->roundconditions.touched_offroad == false
&& player->offroad > (2*offroadstrength) / TICRATE)
{
player->roundconditions.touched_offroad = true; player->roundconditions.touched_offroad = true;
player->roundconditions.checkthisframe = true;
}
} }
else else
player->offroad = 0; player->offroad = 0;
@ -4233,8 +4237,12 @@ void K_ApplyTripWire(player_t *player, tripwirestate_t state)
if (state == TRIPSTATE_PASSED) if (state == TRIPSTATE_PASSED)
{ {
S_StartSound(player->mo, sfx_ssa015); S_StartSound(player->mo, sfx_ssa015);
if (player->hyudorotimer > 0) if (player->roundconditions.tripwire_hyuu == false
&& player->hyudorotimer > 0)
{
player->roundconditions.tripwire_hyuu = true; player->roundconditions.tripwire_hyuu = true;
player->roundconditions.checkthisframe = true;
}
} }
else if (state == TRIPSTATE_BLOCKED) else if (state == TRIPSTATE_BLOCKED)
{ {
@ -5903,8 +5911,12 @@ void K_DoSneaker(player_t *player, INT32 type)
{ {
const fixed_t intendedboost = FRACUNIT/2; const fixed_t intendedboost = FRACUNIT/2;
if (player->floorboost != 0) if (player->roundconditions.touched_sneakerpanel == false
&& player->floorboost != 0)
{
player->roundconditions.touched_sneakerpanel = true; player->roundconditions.touched_sneakerpanel = true;
player->roundconditions.checkthisframe = true;
}
if (player->floorboost == 0 || player->floorboost == 3) if (player->floorboost == 0 || player->floorboost == 3)
{ {

View file

@ -290,7 +290,7 @@ void K_FinishCeremony(void)
podiumData.ranking = true; podiumData.ranking = true;
// Play the noise now // Play the noise now
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
G_SaveGameData(true); G_SaveGameData(true);
} }

View file

@ -427,7 +427,7 @@ void K_CashInPowerLevels(void)
if (gamedataupdate) if (gamedataupdate)
{ {
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
G_SaveGameData(true); G_SaveGameData(true);
} }
@ -643,7 +643,7 @@ void K_PlayerForfeit(UINT8 playerNum, boolean pointLoss)
{ {
pr->powerlevels[powerType] = yourPower + inc; pr->powerlevels[powerType] = yourPower + inc;
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
G_SaveGameData(true); G_SaveGameData(true);
} }
} }

View file

@ -1530,7 +1530,7 @@ static boolean M_CheckUnlockConditions(player_t *player)
return ret; return ret;
} }
boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud) boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall)
{ {
UINT16 i = 0, response = 0, newkeys = 0; UINT16 i = 0, response = 0, newkeys = 0;
@ -1546,16 +1546,27 @@ boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud)
// Done first so that emblems are ready before check // Done first so that emblems are ready before check
M_CheckLevelEmblems(); M_CheckLevelEmblems();
M_CompletionEmblems(); M_CompletionEmblems();
doall = true;
} }
response = M_CheckUnlockConditions(NULL); if (gamedata->deferredconditioncheck == true)
while ((gamedata->keyspending + gamedata->chaokeys + gamedata->usedkeys) < GDMAX_CHAOKEYS
&& ((gamedata->pendingkeyrounds + gamedata->pendingkeyroundoffset)/GDCONVERT_ROUNDSTOKEY) > gamedata->keyspending)
{ {
gamedata->keyspending++; // Handle deferred all-condition checks
newkeys++; gamedata->deferredconditioncheck = false;
response |= true; doall = true;
}
if (doall)
{
response = M_CheckUnlockConditions(NULL);
while ((gamedata->keyspending + gamedata->chaokeys + gamedata->usedkeys) < GDMAX_CHAOKEYS
&& ((gamedata->pendingkeyrounds + gamedata->pendingkeyroundoffset)/GDCONVERT_ROUNDSTOKEY) > gamedata->keyspending)
{
gamedata->keyspending++;
newkeys++;
response |= true;
}
} }
if (!demo.playback && Playing() && (gamestate == GS_LEVEL || K_PodiumRanking() == true)) if (!demo.playback && Playing() && (gamestate == GS_LEVEL || K_PodiumRanking() == true))
@ -1566,7 +1577,10 @@ boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud)
continue; continue;
if (players[g_localplayers[i]].spectator) if (players[g_localplayers[i]].spectator)
continue; continue;
if (!doall && players[g_localplayers[i]].roundconditions.checkthisframe == false)
continue;
response |= M_CheckUnlockConditions(&players[g_localplayers[i]]); response |= M_CheckUnlockConditions(&players[g_localplayers[i]]);
players[g_localplayers[i]].roundconditions.checkthisframe = false;
} }
} }

View file

@ -246,6 +246,7 @@ struct gamedata_t
// WHENEVER OR NOT WE'RE READY TO SAVE // WHENEVER OR NOT WE'RE READY TO SAVE
boolean loaded; boolean loaded;
boolean deferredsave; boolean deferredsave;
boolean deferredconditioncheck;
// CONDITION SETS ACHIEVED // CONDITION SETS ACHIEVED
boolean achieved[MAXCONDITIONSETS]; boolean achieved[MAXCONDITIONSETS];
@ -327,7 +328,7 @@ void M_ClearStats(void);
// Updating conditions and unlockables // Updating conditions and unlockables
boolean M_CheckCondition(condition_t *cn, player_t *player); boolean M_CheckCondition(condition_t *cn, player_t *player);
boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud); boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall);
#define PENDING_CHAOKEYS (UINT16_MAX-1) #define PENDING_CHAOKEYS (UINT16_MAX-1)
UINT16 M_GetNextAchievedUnlock(void); UINT16 M_GetNextAchievedUnlock(void);

View file

@ -205,7 +205,7 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
{ {
UINT16 i, newunlock; UINT16 i, newunlock;
M_UpdateUnlockablesAndExtraEmblems(false); M_UpdateUnlockablesAndExtraEmblems(false, true);
newunlock = M_GetNextAchievedUnlock(); newunlock = M_GetNextAchievedUnlock();
@ -397,7 +397,7 @@ void M_ChallengesTick(void)
{ {
// Unlock animation... also tied directly to the actual unlock! // Unlock animation... also tied directly to the actual unlock!
gamedata->unlocked[challengesmenu.currentunlock] = true; gamedata->unlocked[challengesmenu.currentunlock] = true;
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
// Update shown description just in case..? // Update shown description just in case..?
challengesmenu.unlockcondition = M_BuildConditionSetString(challengesmenu.currentunlock); challengesmenu.unlockcondition = M_BuildConditionSetString(challengesmenu.currentunlock);

View file

@ -66,7 +66,7 @@ static void M_EraseDataResponse(INT32 ch)
if (optionsmenu.erasecontext & EC_CHALLENGES) if (optionsmenu.erasecontext & EC_CHALLENGES)
M_ClearSecrets(); M_ClearSecrets();
M_UpdateUnlockablesAndExtraEmblems(false); M_UpdateUnlockablesAndExtraEmblems(false, true);
F_StartIntro(); F_StartIntro();
M_ClearMenus(true); M_ClearMenus(true);

View file

@ -552,7 +552,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (P_IsLocalPlayer(player) && !gamedata->collected[special->health-1]) if (P_IsLocalPlayer(player) && !gamedata->collected[special->health-1])
{ {
gamedata->collected[special->health-1] = gotcollected = true; gamedata->collected[special->health-1] = gotcollected = true;
if (!M_UpdateUnlockablesAndExtraEmblems(true)) if (!M_UpdateUnlockablesAndExtraEmblems(true, true))
S_StartSound(NULL, sfx_ncitem); S_StartSound(NULL, sfx_ncitem);
gamedata->deferredsave = true; gamedata->deferredsave = true;
} }
@ -1938,7 +1938,11 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source,
{ {
case DMG_DEATHPIT: case DMG_DEATHPIT:
// Respawn kill types // Respawn kill types
player->roundconditions.fell_off = true; if (player->roundconditions.fell_off == true)
{
player->roundconditions.fell_off = true;
player->roundconditions.checkthisframe = true;
}
K_DoIngameRespawn(player); K_DoIngameRespawn(player);
player->mo->health -= K_DestroyBumpers(player, 1); player->mo->health -= K_DestroyBumpers(player, 1);
return false; return false;
@ -2062,9 +2066,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
case MT_SPB: case MT_SPB:
spbpop = (damagetype & DMG_TYPEMASK) == DMG_VOLTAGE; spbpop = (damagetype & DMG_TYPEMASK) == DMG_VOLTAGE;
if (spbpop && source && source->player) if (spbpop && source && source->player
&& source->player->roundconditions.spb_neuter == false)
{ {
source->player->roundconditions.spb_neuter = true; source->player->roundconditions.spb_neuter = true;
source->player->roundconditions.checkthisframe = true;
} }
break; break;
@ -2142,10 +2148,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
if (inflictor && source && source->player) if (inflictor && source && source->player)
{ {
if (P_IsKartFieldItem(source->type) if (source->player->roundconditions.hit_midair == false
&& target->player->airtime > TICRATE/2 && P_IsKartFieldItem(source->type)
&& source->player->airtime > TICRATE/2) && target->player->airtime > TICRATE/2
&& source->player->airtime > TICRATE/2)
{
source->player->roundconditions.hit_midair = true; source->player->roundconditions.hit_midair = true;
source->player->roundconditions.checkthisframe = true;
}
} }
// Instant-Death // Instant-Death

View file

@ -3426,7 +3426,19 @@ void P_MobjCheckWater(mobj_t *mobj)
return; return;
} }
p->roundconditions.wet_player |= (mobj->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER|MFE_GOOWATER)); if (!(p->roundconditions.wet_player & MFE_TOUCHWATER)
&& (mobj->eflags & MFE_TOUCHWATER))
{
p->roundconditions.wet_player |= MFE_TOUCHWATER;
p->roundconditions.checkthisframe = true;
}
if (!(p->roundconditions.wet_player & MFE_UNDERWATER)
&& (mobj->eflags & MFE_UNDERWATER))
{
p->roundconditions.wet_player |= MFE_UNDERWATER;
p->roundconditions.checkthisframe = true;
}
} }
if (mobj->flags & MF_APPLYTERRAIN) if (mobj->flags & MF_APPLYTERRAIN)

View file

@ -7965,7 +7965,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
{ {
mapheaderinfo[gamemap-1]->mapvisited |= MV_VISITED; mapheaderinfo[gamemap-1]->mapvisited |= MV_VISITED;
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
G_SaveGameData(true); G_SaveGameData(true);
} }

View file

@ -2115,6 +2115,12 @@ static void K_HandleLapIncrement(player_t *player)
} }
lastLowestLap = lowestLap; lastLowestLap = lowestLap;
if (P_IsLocalPlayer(player))
{
player->roundconditions.checkthisframe = true;
gamedata->deferredconditioncheck = true;
}
} }
else if (player->starpostnum) else if (player->starpostnum)
{ {
@ -3427,12 +3433,7 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha
} }
mo->player->roundconditions.unlocktriggers |= flag; mo->player->roundconditions.unlocktriggers |= flag;
mo->player->roundconditions.checkthisframe = true;
// Unlocked something?
if (!demo.playback && M_UpdateUnlockablesAndExtraEmblems(true))
{
gamedata->deferredsave = true; // only save if unlocked something
}
} }
} }
break; break;

View file

@ -618,7 +618,7 @@ void P_Ticker(boolean run)
ps_playerthink_time = I_GetPreciseTime() - ps_playerthink_time; ps_playerthink_time = I_GetPreciseTime() - ps_playerthink_time;
// TODO would this be laggy with more conditions in play... // TODO would this be laggy with more conditions in play...
if (((!demo.playback && leveltime > introtime && M_UpdateUnlockablesAndExtraEmblems(true)) if (((!demo.playback && leveltime > introtime && M_UpdateUnlockablesAndExtraEmblems(true, false))
|| (gamedata && gamedata->deferredsave))) || (gamedata && gamedata->deferredsave)))
G_SaveGameData(true); G_SaveGameData(true);
} }

View file

@ -521,9 +521,10 @@ INT32 P_GivePlayerRings(player_t *player, INT32 num_rings)
player->rings += num_rings; player->rings += num_rings;
if (player->rings < 0) if (player->roundconditions.debt_rings == false && player->rings < 0)
{ {
player->roundconditions.debt_rings = true; player->roundconditions.debt_rings = true;
player->roundconditions.checkthisframe = true;
} }
return num_rings; return num_rings;
@ -1281,7 +1282,11 @@ void P_DoPlayerExit(player_t *player)
return; return;
if (P_IsLocalPlayer(player) && (!player->spectator && !demo.playback)) if (P_IsLocalPlayer(player) && (!player->spectator && !demo.playback))
{
legitimateexit = true; legitimateexit = true;
player->roundconditions.checkthisframe = true;
gamedata->deferredconditioncheck = true;
}
if (G_GametypeUsesLives() && losing) if (G_GametypeUsesLives() && losing)
{ {
@ -3819,6 +3824,8 @@ void P_DoTimeOver(player_t *player)
if (P_IsLocalPlayer(player) && !demo.playback) if (P_IsLocalPlayer(player) && !demo.playback)
{ {
legitimateexit = true; // SRB2kart: losing a race is still seeing it through to the end :p legitimateexit = true; // SRB2kart: losing a race is still seeing it through to the end :p
player->roundconditions.checkthisframe = true;
gamedata->deferredconditioncheck = true;
} }
if (netgame && !player->bot && !(gametyperules & GTR_BOSS)) if (netgame && !player->bot && !(gametyperules & GTR_BOSS))

View file

@ -818,7 +818,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
if ((mainfile == false) && (gamedata != NULL) && (gamedata->everloadedaddon == false)) if ((mainfile == false) && (gamedata != NULL) && (gamedata->everloadedaddon == false))
{ {
gamedata->everloadedaddon = true; gamedata->everloadedaddon = true;
M_UpdateUnlockablesAndExtraEmblems(true); M_UpdateUnlockablesAndExtraEmblems(true, true);
G_SaveGameData(true); G_SaveGameData(true);
} }