From 63fa01205f9b111c8e6b27b54fe736f834b6b807 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 7 Jan 2022 00:09:59 +0100 Subject: [PATCH] - fixed potential infinite loop in Hexen-style stair builder. --- src/gamedata/r_defs.h | 3 ++- src/playsim/mapthinkers/a_floor.cpp | 9 ++++++--- src/playsim/mapthinkers/a_lights.cpp | 2 +- src/playsim/p_sectors.cpp | 29 ++++++++++++++++++++++------ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index 7ab94f58f9..854512ec45 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -781,7 +781,6 @@ public: bool IsLinked(sector_t *other, bool ceiling) const; - sector_t *NextSpecialSector (int type, sector_t *prev) const; // [RH] void RemoveForceField(); int Index() const { return sectornum; } @@ -1726,6 +1725,8 @@ int GetCeilingLight(const sector_t *); double GetFriction(const sector_t *self, int plane, double *movefac); double HighestCeilingAt(sector_t *sec, double x, double y, sector_t **resultsec = nullptr); double LowestFloorAt(sector_t *sec, double x, double y, sector_t **resultsec = nullptr); +sector_t* P_NextSpecialSector(sector_t* sect, int type, sector_t* prev); +sector_t* P_NextSpecialSectorVC(sector_t* sect, int type); // uses validcount inline void sector_t::RemoveForceField() { return ::RemoveForceField(this); } inline bool sector_t::PlaneMoving(int pos) { return !!::PlaneMoving(this, pos); } diff --git a/src/playsim/mapthinkers/a_floor.cpp b/src/playsim/mapthinkers/a_floor.cpp index 27dc1cf0ed..21eccaa4dc 100644 --- a/src/playsim/mapthinkers/a_floor.cpp +++ b/src/playsim/mapthinkers/a_floor.cpp @@ -40,6 +40,7 @@ #include "r_data/r_interpolate.h" #include "g_levellocals.h" #include "vm.h" +#include "r_utility.h" //========================================================================== // @@ -661,6 +662,7 @@ bool FLevelLocals::EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, d // 1. Find 2-sided line with same sector side[0] (lowest numbered) // 2. Other side is the next sector to raise // 3. Unless already moving, or different texture, then stop building + validcount++; do { ok = 0; @@ -668,12 +670,13 @@ bool FLevelLocals::EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, d if (usespecials & DFloor::stairUseSpecials) { // [RH] Find the next sector by scanning for Stairs_Special? - tsec = sec->NextSpecialSector ( + tsec = P_NextSpecialSectorVC(sec, sec->special == Stairs_Special1 ? - Stairs_Special2 : Stairs_Special1, prev); + Stairs_Special2 : Stairs_Special1); - if ( (ok = (tsec != NULL)) ) + if ( (ok = (tsec != nullptr)) ) { + tsec->validcount = validcount; height += stairstep; // if sector's floor already moving, look for another diff --git a/src/playsim/mapthinkers/a_lights.cpp b/src/playsim/mapthinkers/a_lights.cpp index e53f1a5c51..9cd7fb20f1 100644 --- a/src/playsim/mapthinkers/a_lights.cpp +++ b/src/playsim/mapthinkers/a_lights.cpp @@ -521,7 +521,7 @@ int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev else l = Level->CreateThinker (sector, baselevel); - int numsteps = PhaseHelper (sector->NextSpecialSector ( + int numsteps = PhaseHelper (P_NextSpecialSector (sector, sector->special == LightSequenceSpecial1 ? LightSequenceSpecial2 : LightSequenceSpecial1, prev), index + 1, l->m_BaseLevel, sector); diff --git a/src/playsim/p_sectors.cpp b/src/playsim/p_sectors.cpp index 448808265a..bb535ade8f 100644 --- a/src/playsim/p_sectors.cpp +++ b/src/playsim/p_sectors.cpp @@ -89,27 +89,44 @@ CUSTOM_CVAR(Int, r_fakecontrast, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // // Returns the next special sector attached to this sector // with a certain special. -sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const + +sector_t* P_NextSpecialSectorVC(sector_t* sec, int type) +{ + sector_t* tsec; + for (auto ln : sec->Lines) + { + if (nullptr != (tsec = getNextSector(ln, sec)) && + tsec->validcount != validcount && + tsec->special == type) + { + return tsec; + } + } + return nullptr; +} + + +sector_t *P_NextSpecialSector (sector_t* sec, int type, sector_t *nogood) { sector_t *tsec; - for (auto ln : Lines) + for (auto ln : sec->Lines) { - if (NULL != (tsec = getNextSector (ln, this)) && + if (nullptr != (tsec = getNextSector (ln, sec)) && tsec != nogood && tsec->special == type) { return tsec; } } - return NULL; + return nullptr; } -DEFINE_ACTION_FUNCTION(_Sector, NextSpecialSector) +DEFINE_ACTION_FUNCTION_NATIVE(_Sector, NextSpecialSector, P_NextSpecialSector) { PARAM_SELF_STRUCT_PROLOGUE(sector_t); PARAM_INT(type); PARAM_POINTER(nogood, sector_t); - ACTION_RETURN_POINTER(self->NextSpecialSector(type, nogood)); + ACTION_RETURN_POINTER(P_NextSpecialSector(self, type, nogood)); } //