G_MapIsSafe

Generalized safety test for maps, in an attempt to curb G_GetNextMap
producing an I_Error due to an unchecked override
This commit is contained in:
yamamama 2026-04-29 05:36:27 -04:00
parent aff2b6939a
commit d493dd9029
3 changed files with 59 additions and 7 deletions

View file

@ -4951,6 +4951,14 @@ mapnum_t G_CheckNextMap(boolean noadvancemap)
//boolean spec = G_IsSpecialStage(currentmap);
INT32 i;
// Kill nextmapoverride if it's not a safe move
if (!G_MapIsSafe(nextmapoverride))
{
// At least beat the programmer/host over the head for it
CONS_Alert(CONS_WARNING, "Overriding map ID %d is unsafe!", nextmapoverride);
nextmapoverride = 0;
}
if (nextmapoverride != 0)
{
return nextmapoverride-1;
@ -5104,6 +5112,14 @@ mapnum_t G_CheckNextMap(boolean noadvancemap)
}
}
// Tests if a given map number is safe to go to. If not, this returns false.
boolean G_MapIsSafe(mapnum_t map)
{
return (map != NEXTMAP_INVALID &&
(map >= NEXTMAP_SPECIAL || (map < nummapheaders && mapheaderinfo[map] &&
mapheaderinfo[map]->lumpnum != LUMPERROR)));
}
void G_GetNextMap(void)
{
if (!server)
@ -5222,7 +5238,7 @@ void G_GetNextMap(void)
}
// We are committed to this map now.
if (nextmap == NEXTMAP_INVALID || (nextmap < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR)))
if (!G_MapIsSafe(nextmap))
I_Error("G_GetNextMap: Internal map ID %d not found (nummapheaders = %d)\n", nextmap, nummapheaders);
#if 0 // This is a surprise tool that will help us later.

View file

@ -223,6 +223,7 @@ UINT8 G_GetGametypeColor(INT16 gt);
void G_BeginLevelExit(void);
void G_FinishExitLevel(void);
void G_NextLevel(void);
boolean G_MapIsSafe(mapnum_t map);
mapnum_t G_CheckNextMap(boolean noadvancemap);
void G_GetNextMap(void);
void G_Continue(void);

View file

@ -3502,10 +3502,11 @@ static int lib_gDoReborn(lua_State *L)
}
// Another Lua function that doesn't actually exist!
// Sets nextmapoverride & skipstats without instantly ending the level, for instances where other sources should be exiting the level, like normal signposts.
static int lib_gSetCustomExitVars(lua_State *L)
// Sets nextmapoverride & skipstats without instantly ending the level, for instances where other
// sources should be exiting the level, like normal signposts.
static int lib_gSetCustomExitVars(lua_State* L)
{
int n = lua_gettop(L); // Num arguments
int n = lua_gettop(L); // Num arguments
NOHUD
INLEVEL
@ -3516,15 +3517,36 @@ static int lib_gSetCustomExitVars(lua_State *L)
// G_SetCustomExitVars(nil, int) [skipstats only]
// G_SetCustomExitVars(int, int) [both of the above]
mapnum_t potential_override = 0;
nextmapoverride = 0;
skipstats = 0;
if (n >= 1)
{
nextmapoverride = luaL_optinteger(L, 1, 0);
potential_override = luaL_optinteger(L, 1, 0);
skipstats = (INT16)luaL_optinteger(L, 2, 0);
if (lua_compatmode && nextmapoverride)
nextmapoverride = G_KartMapToNative(nextmapoverride);
if (lua_compatmode && potential_override)
potential_override = G_KartMapToNative(potential_override);
if (potential_override != 0)
{
// Prevent crashes by making sure the override is safe
if (!G_MapIsSafe(potential_override))
{
// Override is very definitively NOT safe; error out
return luaL_error(
L,
"provided map override %d is invalid (nummapheaders = %d)",
potential_override,
nummapheaders);
}
else
{
// Allow the override
nextmapoverride = potential_override;
}
}
}
return 0;
@ -3630,6 +3652,18 @@ static int lib_gTicsToMilliseconds(lua_State *L)
return 1;
}
static int lib_gMapIsSafe(lua_State *L)
{
mapnum_t map = (mapnum_t)luaL_checkinteger(L, 1);
if (lua_compatmode && map)
map = G_KartMapToNative(map);
//HUDSAFE
lua_pushboolean(L, G_MapIsSafe(map));
return 1;
}
// K_KART
////////////
@ -5781,6 +5815,7 @@ static luaL_Reg lib[] = {
{"G_AddGametype", lib_gAddGametype},
{"G_BuildMapName",lib_gBuildMapName},
{"G_MapNumber",lib_gMapNumber},
{"G_MapIsSafe",lib_gMapIsSafe},
{"G_BuildMapTitle",lib_gBuildMapTitle},
{"G_FindMap",lib_gFindMap},
{"G_FindMapByNameOrCode",lib_gFindMapByNameOrCode},