- changed FraggleScript setup so that the MapLoader does not use the global level variable anymore.

This involves passing the level explicitly to many functions. What was done here may seem a bit excessive but at least it covers everything.
Most importantly, the global ActiveThinker pointer has been moved into FLevelLocals and is now getting tracked properly by the level without using dangerous assumptions about how the game organizes its data.
This commit is contained in:
Christoph Oelckers 2019-01-05 09:40:03 +01:00
parent 95995e4aa3
commit 7b16433e97
16 changed files with 108 additions and 86 deletions

View file

@ -117,7 +117,7 @@ void FS_MapCmd(FScanner &sc)
//
//==========================================================================
void FS_EmulateCmd(char * string)
void FS_EmulateCmd(FLevelLocals *Level, char * string)
{
FScanner sc;
sc.OpenMem("RUNCMD", string, (int)strlen(string));
@ -144,7 +144,7 @@ void FS_EmulateCmd(char * string)
else if (sc.Compare("gravity"))
{
sc.MustGetFloat();
level.gravity=(float)(sc.Float*800);
Level->gravity=(float)(sc.Float*800);
while (sc.GetString())
{
if (sc.Compare(";")) break;
@ -174,15 +174,15 @@ void FS_EmulateCmd(char * string)
{
sc.MustGetNumber();
// Using this disables most MAPINFO fog options!
level.fogdensity = sc.Number * 70 / 400;
level.outsidefogdensity = 0;
level.skyfog = 0;
level.info->outsidefog = 0;
Level->fogdensity = sc.Number * 70 / 400;
Level->outsidefogdensity = 0;
Level->skyfog = 0;
Level->info->outsidefog = 0;
}
else if (sc.Compare("gr_fogcolor"))
{
sc.MustGetString();
level.fadeto = (uint32_t)strtoull(sc.String, NULL, 16);
Level->fadeto = (uint32_t)strtoull(sc.String, NULL, 16);
}
else

View file

@ -7,9 +7,9 @@
struct MapData;
class AActor;
void T_PreprocessScripts();
void T_LoadScripts(MapData * map);
void T_AddSpawnedThing(AActor * );
bool T_RunScript(int snum, AActor * t_trigger);
void T_PreprocessScripts(FLevelLocals *Level);
void T_LoadScripts(FLevelLocals *Level, MapData * map);
void T_AddSpawnedThing(FLevelLocals *Level, AActor * );
bool T_RunScript(FLevelLocals *l, int snum, AActor * t_trigger);
#endif

View file

@ -222,7 +222,7 @@ static PClassActor * ActorTypes[countof(ActorNames_init)];
// Doom index is only supported for the original things up to MBF
//
//==========================================================================
PClassActor * T_GetMobjType(svalue_t arg)
PClassActor * FParser::T_GetMobjType(svalue_t arg)
{
PClassActor * pclass=NULL;
@ -256,7 +256,7 @@ PClassActor * T_GetMobjType(svalue_t arg)
// Input can be either an actor variable or an index value
//
//==========================================================================
static int T_GetPlayerNum(const svalue_t &arg)
int FParser::T_GetPlayerNum(const svalue_t &arg)
{
int playernum;
if(arg.type == svt_mobj)
@ -285,7 +285,7 @@ static int T_GetPlayerNum(const svalue_t &arg)
return playernum;
}
AActor *T_GetPlayerActor(const svalue_t &arg)
AActor *FParser::T_GetPlayerActor(const svalue_t &arg)
{
int num = T_GetPlayerNum(arg);
return num == -1 ? nullptr : players[num].mo;
@ -2080,7 +2080,7 @@ void FParser::SF_CloseDoor(void)
// run console cmd
void FParser::SF_RunCommand(void)
{
FS_EmulateCmd(GetFormatString(0).LockBuffer());
FS_EmulateCmd(Level, GetFormatString(0).LockBuffer());
}
//==========================================================================
@ -3108,7 +3108,7 @@ void FParser::SF_SpawnMissile()
void FParser::SF_MapThingNumExist()
{
auto &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
auto &SpawnedThings = Level->FraggleScriptThinker->SpawnedThings;
int intval;
@ -3137,7 +3137,7 @@ void FParser::SF_MapThingNumExist()
void FParser::SF_MapThings()
{
auto &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
auto &SpawnedThings = Level->FraggleScriptThinker->SpawnedThings;
t_return.type = svt_int;
t_return.value.i = SpawnedThings.Size();
@ -3861,7 +3861,7 @@ void FParser::RunLineSpecial(const FLineSpecial *spec)
DRunningScript *FParser::SaveCurrentScript()
{
DFraggleThinker *th = DFraggleThinker::ActiveThinker;
DFraggleThinker *th = Level->FraggleScriptThinker;
if (th)
{
DRunningScript *runscr = Create<DRunningScript>(Script->trigger, Script, Script->MakeIndex(Rover));
@ -3987,7 +3987,7 @@ void FParser::SF_StartScript()
return;
}
DFraggleThinker *th = DFraggleThinker::ActiveThinker;
DFraggleThinker *th = Level->FraggleScriptThinker;
if (th)
{
@ -4023,7 +4023,7 @@ void FParser::SF_ScriptRunning()
snum = intvalue(t_argv[0]);
for(current = DFraggleThinker::ActiveThinker->RunningScripts->next; current; current=current->next)
for(current = Level->FraggleScriptThinker->RunningScripts->next; current; current=current->next)
{
if(current->script->scriptnum == snum)
{

View file

@ -33,6 +33,7 @@
#include "gi.h"
#include "g_levellocals.h"
#include "xlat/xlat.h"
#include "maploader/maploader.h"
class FScriptLoader
{
@ -47,9 +48,14 @@ class FScriptLoader
int drownflag;
bool HasScripts;
bool IgnoreInfo;
FLevelLocals *Level;
void ParseInfoCmd(char *line, FString &scriptsrc);
public:
FScriptLoader(FLevelLocals *l)
{
Level = l;
}
bool ParseInfo(MapData * map);
};
@ -113,13 +119,13 @@ void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc)
while (*beg<=' ') beg++;
char * comm = strstr(beg, "//");
if (comm) *comm=0;
level.LevelName = beg;
Level->LevelName = beg;
}
else if (sc.Compare("partime"))
{
sc.MustGetStringName("=");
sc.MustGetNumber();
level.partime=sc.Number;
Level->partime=sc.Number;
}
else if (sc.Compare("music"))
{
@ -129,7 +135,7 @@ void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc)
sc.MustGetString();
if (!FS_ChangeMusic(sc.String))
{
S_ChangeMusic(level.Music, level.musicorder);
S_ChangeMusic(Level->Music, Level->musicorder);
}
}
else if (sc.Compare("skyname"))
@ -137,32 +143,32 @@ void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc)
sc.MustGetStringName("=");
sc.MustGetString();
sky2texture = sky1texture = level.skytexture1 = level.skytexture2 = TexMan.GetTextureID (sc.String, ETextureType::Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_ReturnFirst);
sky2texture = sky1texture = Level->skytexture1 = Level->skytexture2 = TexMan.GetTextureID (sc.String, ETextureType::Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_ReturnFirst);
R_InitSkyMap ();
}
else if (sc.Compare("interpic"))
{
sc.MustGetStringName("=");
sc.MustGetString();
level.info->ExitPic = sc.String;
Level->info->ExitPic = sc.String;
}
else if (sc.Compare("gravity"))
{
sc.MustGetStringName("=");
sc.MustGetNumber();
level.gravity=sc.Number*8.f;
Level->gravity=sc.Number*8.f;
}
else if (sc.Compare("nextlevel"))
{
sc.MustGetStringName("=");
sc.MustGetString();
level.NextMap = sc.String;
Level->NextMap = sc.String;
}
else if (sc.Compare("nextsecret"))
{
sc.MustGetStringName("=");
sc.MustGetString();
level.NextSecretMap = sc.String;
Level->NextSecretMap = sc.String;
}
else if (sc.Compare("drown"))
{
@ -176,7 +182,7 @@ void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc)
while (*beg<' ') beg++;
char * comm = strstr(beg, "//");
if (comm) *comm=0;
FS_EmulateCmd(beg);
FS_EmulateCmd(Level, beg);
}
else if (sc.Compare("ignore"))
{
@ -251,11 +257,17 @@ bool FScriptLoader::ParseInfo(MapData * map)
}
if (HasScripts)
{
if (Level->FraggleScriptThinker)
{
I_Error("Only one FraggleThinker is allowed to exist at a time.\nCheck your code.");
}
auto th = Create<DFraggleThinker>();
th->LevelScript->data = copystring(scriptsrc.GetChars());
Level->FraggleScriptThinker = th;
if (drownflag==-1) drownflag = (level.maptype != MAPTYPE_DOOM || fsglobal);
if (!drownflag) level.airsupply=0; // Legacy doesn't to water damage so we need to check if it has to be disabled here.
if (drownflag==-1) drownflag = (Level->maptype != MAPTYPE_DOOM || fsglobal);
if (!drownflag) Level->airsupply=0; // Legacy doesn't to water damage so we need to check if it has to be disabled here.
}
@ -270,10 +282,9 @@ bool FScriptLoader::ParseInfo(MapData * map)
//
//-----------------------------------------------------------------------------
void T_LoadScripts(MapData *map)
void T_LoadScripts(FLevelLocals *Level, MapData *map)
{
FScriptLoader parser;
FScriptLoader parser(Level);
bool HasScripts = parser.ParseInfo(map);
// Hack for Legacy compatibility: Since 272 is normally an MBF sky transfer we have to patch it.
@ -282,8 +293,8 @@ void T_LoadScripts(MapData *map)
// This code then then swaps 270 and 272 - but only if this is either Doom or Heretic and
// the default translator is being used.
// Custom translators will not be patched.
if ((gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Heretic) && level.info->Translator.IsEmpty() &&
level.maptype == MAPTYPE_DOOM && SimpleLineTranslations.Size() > 272 && SimpleLineTranslations[272 - 2*HasScripts].special == FS_Execute)
if ((gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Heretic) && Level->info->Translator.IsEmpty() &&
Level->maptype == MAPTYPE_DOOM && SimpleLineTranslations.Size() > 272 && SimpleLineTranslations[272 - 2*HasScripts].special == FS_Execute)
{
std::swap(SimpleLineTranslations[270], SimpleLineTranslations[272]);
}
@ -296,11 +307,11 @@ void T_LoadScripts(MapData *map)
//
//-----------------------------------------------------------------------------
void T_AddSpawnedThing(AActor * ac)
void T_AddSpawnedThing(FLevelLocals *Level, AActor * ac)
{
if (DFraggleThinker::ActiveThinker)
if (Level->FraggleScriptThinker)
{
auto &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
auto &SpawnedThings = Level->FraggleScriptThinker->SpawnedThings;
SpawnedThings.Push(GC::ReadBarrier(ac));
}
}

View file

@ -89,7 +89,7 @@ void FParser::OPequals(svalue_t &result, int start, int n, int stop)
if(var)
{
EvaluateExpression(result, n+1, stop);
var->SetValue (result);
var->SetValue(Level, result);
}
else
{
@ -490,12 +490,12 @@ void FParser::OPincrement(svalue_t &result, int start, int n, int stop)
{
result.value.i = intvalue(result) + 1;
result.type = svt_int;
var->SetValue (result);
var->SetValue(Level, result);
}
else
{
result.setDouble(floatvalue(result)+1);
var->SetValue (result);
var->SetValue(Level, result);
}
}
else if(stop == n) // n++
@ -515,12 +515,12 @@ void FParser::OPincrement(svalue_t &result, int start, int n, int stop)
{
newvalue.type = svt_int;
newvalue.value.i = intvalue(result) + 1;
var->SetValue (newvalue);
var->SetValue(Level, newvalue);
}
else
{
newvalue.setDouble(floatvalue(result)+1);
var->SetValue (newvalue);
var->SetValue(Level, newvalue);
}
}
else
@ -553,13 +553,13 @@ void FParser::OPdecrement(svalue_t &result, int start, int n, int stop)
{
result.value.i = intvalue(result) - 1;
result.type = svt_int;
var->SetValue (result);
var->SetValue(Level, result);
}
else
{
result.setDouble(floatvalue(result)-1);
result.type = svt_fixed;
var->SetValue (result);
var->SetValue(Level, result);
}
}
else if(stop == n) // n++
@ -579,12 +579,12 @@ void FParser::OPdecrement(svalue_t &result, int start, int n, int stop)
{
newvalue.type = svt_int;
newvalue.value.i = intvalue(result) - 1;
var->SetValue (newvalue);
var->SetValue(Level, newvalue);
}
else
{
newvalue.setDouble(floatvalue(result)-1);
var->SetValue (newvalue);
var->SetValue(Level, newvalue);
}
}
else

View file

@ -176,8 +176,8 @@ void DFsScript::OnDestroy()
void DFsScript::Serialize(FSerializer &arc)
{
Super::Serialize(arc);
// don't save a reference to the global script
if (parent == DFraggleThinker::ActiveThinker->GlobalScript) parent = nullptr;
// don't save a reference to the global script, which contains unserializable data.
if (parent == level.FraggleScriptThinker->GlobalScript) parent = nullptr;
arc("data", data)
("scriptnum", scriptnum)
@ -189,7 +189,7 @@ void DFsScript::Serialize(FSerializer &arc)
.Array("variables", variables, VARIABLESLOTS)
.Array("children", children, MAXSCRIPTS);
if (parent == nullptr) parent = DFraggleThinker::ActiveThinker->GlobalScript;
if (parent == nullptr) parent = level.FraggleScriptThinker->GlobalScript;
}
//==========================================================================
@ -215,7 +215,7 @@ void DFsScript::ParseScript(char *position)
return;
}
DFraggleThinker::ActiveThinker->trigger_obj = trigger; // set trigger
level.FraggleScriptThinker->trigger_obj = trigger; // set trigger
try
{
@ -359,8 +359,6 @@ IMPLEMENT_POINTERS_START(DFraggleThinker)
IMPLEMENT_POINTER(GlobalScript)
IMPLEMENT_POINTERS_END
TObjPtr<DFraggleThinker*> DFraggleThinker::ActiveThinker;
//==========================================================================
//
//
@ -370,22 +368,18 @@ TObjPtr<DFraggleThinker*> DFraggleThinker::ActiveThinker;
DFraggleThinker::DFraggleThinker()
: DThinker(STAT_SCRIPTS)
{
if (ActiveThinker)
GlobalScript = Create<DFsScript>();
GC::WriteBarrier(this, GlobalScript);
// do not create resources which will be filled in by the serializer if being called from there.
if (!bSerialOverride)
{
I_Error ("Only one FraggleThinker is allowed to exist at a time.\nCheck your code.");
}
else
{
ActiveThinker = this;
RunningScripts = Create<DRunningScript>();
GC::WriteBarrier(this, RunningScripts);
GlobalScript = Create<DFsScript>();
GC::WriteBarrier(this, GlobalScript);
LevelScript = Create<DFsScript>();
LevelScript->parent = GlobalScript;
GC::WriteBarrier(this, LevelScript);
InitFunctions();
}
InitFunctions();
}
//==========================================================================
@ -413,7 +407,6 @@ void DFraggleThinker::OnDestroy()
LevelScript = NULL;
SpawnedThings.Clear();
ActiveThinker = NULL;
Super::OnDestroy();
}
@ -609,9 +602,9 @@ void DFraggleThinker::AddRunningScript(DRunningScript *runscr)
//
//==========================================================================
void T_PreprocessScripts()
void T_PreprocessScripts(FLevelLocals *Level)
{
DFraggleThinker *th = DFraggleThinker::ActiveThinker;
DFraggleThinker *th = Level->FraggleScriptThinker;
if (th)
{
// run the levelscript first
@ -631,9 +624,9 @@ void T_PreprocessScripts()
//
//==========================================================================
bool T_RunScript(int snum, AActor * t_trigger)
bool T_RunScript(FLevelLocals *Level, int snum, AActor * t_trigger)
{
DFraggleThinker *th = DFraggleThinker::ActiveThinker;
DFraggleThinker *th = Level->FraggleScriptThinker;
if (th)
{
// [CO] It is far too dangerous to start the script right away.
@ -655,7 +648,7 @@ bool T_RunScript(int snum, AActor * t_trigger)
//==========================================================================
//
//
// This isn't network safe. FraggleScript as a whole most likely isn't...
//
//==========================================================================
@ -669,6 +662,6 @@ CCMD(fpuke)
}
else
{
T_RunScript(atoi(argv[1]), players[consoleplayer].mo);
T_RunScript(&level, atoi(argv[1]), players[consoleplayer].mo);
}
}

View file

@ -129,7 +129,7 @@ int intvalue(const svalue_t & v);
fsfix fixedvalue(const svalue_t & v);
double floatvalue(const svalue_t & v);
const char *stringvalue(const svalue_t & v);
AActor *actorvalue(const svalue_t &svalue);
AActor *actorvalue(FLevelLocals *Level, const svalue_t &svalue);
//==========================================================================
//
@ -185,7 +185,7 @@ public:
DFsVariable(const char *_name = "");
void GetValue(svalue_t &result);
void SetValue(const svalue_t &newvalue);
void SetValue(FLevelLocals *Level, const svalue_t &newvalue);
void Serialize(FSerializer &ar);
};
@ -484,6 +484,15 @@ struct FParser
FString GetFormatString(int startarg);
bool CheckArgs(int cnt);
PClassActor * T_GetMobjType(svalue_t arg);
int T_GetPlayerNum(const svalue_t &arg);
AActor *T_GetPlayerActor(const svalue_t &arg);
AActor* actorvalue(const svalue_t &svalue)
{
return ::actorvalue(Level, svalue);
}
void SF_Print();
void SF_Rnd();
void SF_Continue();
@ -711,7 +720,7 @@ public:
#include "t_fs.h"
void script_error(const char *s, ...) GCCPRINTF(1,2);
void FS_EmulateCmd(char * string);
void FS_EmulateCmd(FLevelLocals *l, char * string);
#endif

View file

@ -29,6 +29,7 @@
//
#include "t_script.h"
#include "g_levellocals.h"
//==========================================================================
//
@ -467,7 +468,7 @@ void FParser::EvaluateFunction(svalue_t &result, int start, int stop)
}
// all the functions are stored in the global script
else if( !(func = DFraggleThinker::ActiveThinker->GlobalScript->VariableForName (Tokens[start])) )
else if( !(func = Level->FraggleScriptThinker->GlobalScript->VariableForName (Tokens[start])) )
{
script_error("no such function: '%s'\n",Tokens[start]);
}
@ -551,7 +552,7 @@ void FParser::OPstructure(svalue_t &result, int start, int n, int stop)
svalue_t argv[MAXARGS];
// all the functions are stored in the global script
if( !(func = DFraggleThinker::ActiveThinker->GlobalScript->VariableForName (Tokens[n+1])) )
if( !(func = Level->FraggleScriptThinker->GlobalScript->VariableForName (Tokens[n+1])) )
{
script_error("no such function: '%s'\n",Tokens[n+1]);
}

View file

@ -42,6 +42,7 @@
#include "t_script.h"
#include "a_pickups.h"
#include "serializer.h"
#include "g_levellocals.h"
//==========================================================================
@ -122,7 +123,7 @@ const char *stringvalue(const svalue_t & v)
//
//==========================================================================
AActor* actorvalue(const svalue_t &svalue)
AActor* actorvalue(FLevelLocals *Level, const svalue_t &svalue)
{
int intval;
@ -138,9 +139,9 @@ AActor* actorvalue(const svalue_t &svalue)
}
else
{
auto &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
auto &SpawnedThings = Level->FraggleScriptThinker->SpawnedThings;
// this requires some creativity. We use the intvalue
// as the thing number of a thing in the level.
// as the thing number of a thing in the level
intval = intvalue(svalue);
if(intval < 0 || intval >= (int)SpawnedThings.Size())
@ -234,7 +235,7 @@ void DFsVariable::GetValue(svalue_t &returnvar)
//
//==========================================================================
void DFsVariable::SetValue(const svalue_t &newvalue)
void DFsVariable::SetValue(FLevelLocals *Level, const svalue_t &newvalue)
{
if(type == svt_const)
{
@ -264,7 +265,7 @@ void DFsVariable::SetValue(const svalue_t &newvalue)
break;
case svt_mobj:
actor = actorvalue(newvalue);
actor = actorvalue(Level, newvalue);
break;
case svt_pInt:
@ -272,7 +273,7 @@ void DFsVariable::SetValue(const svalue_t &newvalue)
break;
case svt_pMobj:
*value.pMobj = actorvalue(newvalue);
*value.pMobj = actorvalue(Level, newvalue);
break;
case svt_function:

View file

@ -1968,6 +1968,7 @@ void FLevelLocals::Tick ()
void FLevelLocals::Mark()
{
GC::Mark(FraggleScriptThinker);
canvasTextureInfo.Mark();
for (auto &s : sectorPortals)
{

View file

@ -47,6 +47,7 @@
#include "r_data/r_sections.h"
#include "r_data/r_canvastexture.h"
class DFraggleThinker;
struct FLevelData
{
@ -200,6 +201,9 @@ struct FLevelLocals : public FLevelData
FDynamicLight *lights;
// links to global game objects
TObjPtr<DFraggleThinker *> FraggleScriptThinker;
bool IsJumpingAllowed() const;
bool IsCrouchingAllowed() const;
bool IsFreelookAllowed() const;

View file

@ -2919,7 +2919,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
{
ForceNodeBuild = true;
}
T_LoadScripts(map);
T_LoadScripts(Level, map);
if (!map->HasBehavior || map->isText)
{

View file

@ -2016,7 +2016,7 @@ FUNC(LS_FS_Execute)
{
if (arg1 && ln && backSide) return false;
if (arg2!=0 && !P_CheckKeys(it, arg2, !!arg3)) return false;
return T_RunScript(arg0,it);
return T_RunScript(&level, arg0, it);
}

View file

@ -5570,7 +5570,7 @@ AActor *SpawnMapThing(int index, FMapThing *mt, int position)
index, mt->pos.X, mt->pos.Y, mt->pos.Z, mt->EdNum, mt->flags,
spawned ? spawned->GetClass()->TypeName.GetChars() : "(none)");
}
T_AddSpawnedThing(spawned);
T_AddSpawnedThing(&level, spawned);
return spawned;
}

View file

@ -57,6 +57,7 @@
#include "g_levellocals.h"
#include "events.h"
#include "p_destructible.h"
#include "fragglescript/t_script.h"
//==========================================================================
//
@ -974,7 +975,8 @@ void G_SerializeLevel(FSerializer &arc, bool hubload)
("level.deathsequence", level.deathsequence)
("level.bodyqueslot", level.bodyqueslot)
("level.spawnindex", level.spawnindex)
.Array("level.bodyque", level.bodyque, level.BODYQUESIZE);
.Array("level.bodyque", level.bodyque, level.BODYQUESIZE)
("level.fragglethinker", level.FraggleScriptThinker);
// Hub transitions must keep the current total time
if (!hubload)

View file

@ -486,7 +486,7 @@ void P_SetupLevel(const char *lumpname, int position, bool newGame)
}
}
T_PreprocessScripts(); // preprocess FraggleScript scripts
T_PreprocessScripts(&level); // preprocess FraggleScript scripts
// build subsector connect matrix
// UNUSED P_ConnectSubsectors ();