Separated the loading and initialization of global scripts

* now the loading occurs before the start of a new game.
This commit is contained in:
NovaRain
2021-02-01 11:55:21 +08:00
parent 191beb8e0c
commit 1d42a2242c
5 changed files with 54 additions and 50 deletions
+30 -33
View File
@@ -138,7 +138,7 @@ void HookScripts::RegisterHook(fo::Program* script, int id, int procNum, bool sp
ScriptProgram *prog = ScriptExtender::GetGlobalScriptProgram(script);
if (prog) {
dlog_f("Global script: %08x registered as hook ID %d\n", DL_HOOK, script, id);
dlog_f("Script: %s registered as hook ID %d\n", DL_HOOK, script->fileName, id);
HookScript hook;
hook.prog = *prog;
hook.callback = procNum;
@@ -165,13 +165,15 @@ void HookScripts::RunHookScriptsAtProc(DWORD procId) {
}
void HookScripts::LoadHookScript(const char* name, int id) {
//if (id >= numHooks || IsGameScript(name)) return;
char filePath[MAX_PATH];
bool hookIsLoaded = HookScripts::LoadHookScriptFile(name, id);
if (hookIsLoaded || injectHooks[id].injectState == 1 || (injectAllHooks && id != HOOK_SUBCOMBATDAMAGE)) {
sprintf(filePath, "scripts\\%s.int", name);
bool hookHasScript = fo::func::db_access(filePath);
if (hookHasScript || injectHooks[id].injectState == 1 || (injectAllHooks && id != HOOK_SUBCOMBATDAMAGE)) {
HookScripts::InjectingHook(id); // inject hook to engine code
if (!hookIsLoaded) return; // only inject
if (!hookHasScript) return; // only inject
HookFile hookFile = { id, name };
HookScripts::hookScriptFilesList.push_back(hookFile);
@@ -179,30 +181,25 @@ void HookScripts::LoadHookScript(const char* name, int id) {
}
bool HookScripts::LoadHookScriptFile(const char* name, int id) {
char filename[MAX_PATH];
sprintf(filename, "scripts\\%s.int", name);
ScriptProgram prog;
if (fo::func::db_access(filename)) {
dlog("> ", DL_HOOK);
dlog(name, DL_HOOK);
LoadScriptProgram(prog, name);
if (prog.ptr) {
dlogr(" Done", DL_HOOK);
HookScript hook;
hook.prog = prog;
hook.callback = -1;
hook.isGlobalScript = false;
hooks[id].push_back(hook);
ScriptExtender::AddProgramToMap(prog);
} else {
dlogr(" Error!", DL_HOOK);
}
dlog("> ", DL_HOOK);
dlog(name, DL_HOOK);
LoadScriptProgram(prog, name);
if (prog.ptr) {
HookScript hook;
hook.prog = prog;
hook.callback = -1;
hook.isGlobalScript = false;
hooks[id].push_back(hook);
ScriptExtender::AddProgramToMap(prog);
dlogr(" Done", DL_HOOK);
} else {
dlogr(" Error!", DL_HOOK);
}
return (prog.ptr != nullptr);
}
static void HookScriptInit() {
void HookScripts::LoadHookScripts() {
dlogr("Loading hook scripts:", DL_HOOK|DL_INIT);
static bool hooksFilesLoaded = false;
@@ -221,17 +218,18 @@ static void HookScriptInit() {
HookScripts::LoadHookScript("hs_gamemodechange", HOOK_GAMEMODECHANGE);
hooksFilesLoaded = !alwaysFindScripts;
} else {
for (auto& hook : HookScripts::hookScriptFilesList) {
HookScripts::LoadHookScriptFile(hook.name.c_str(), hook.id);
}
}
dlogr("Finished loading hook scripts.", DL_HOOK|DL_INIT);
}
void HookScripts::LoadHookScripts() {
isGlobalScriptLoading = 1; // this should allow to register global exported variables
HookScriptInit();
void HookScripts::InitHookScripts() {
// Note: here isGlobalScriptLoading must be already set, this should allow to register global exported variables
dlogr("Running hook scripts...", DL_HOOK);
for (auto& hook : HookScripts::hookScriptFilesList) {
HookScripts::LoadHookScriptFile(hook.name.c_str(), hook.id);
}
initingHookScripts = 1;
for (int i = 0; i < numHooks; i++) {
if (!hooks[i].empty()) {
@@ -239,12 +237,11 @@ void HookScripts::LoadHookScripts() {
InitScriptProgram(hooks[i][0].prog); // zero hook is always hs_*.int script because Hook scripts are loaded BEFORE global scripts
}
}
isGlobalScriptLoading = 0;
initingHookScripts = 0;
}
void HookScripts::HookScriptClear() {
for(int i = 0; i < numHooks; i++) {
for (int i = 0; i < numHooks; i++) {
hooks[i].clear();
}
std::memset(hooksInfo, 0, numHooks * sizeof(HooksPositionInfo));
+1
View File
@@ -95,6 +95,7 @@ public:
static void LoadHookScript(const char* name, int id);
static bool LoadHookScriptFile(const char* name, int id);
static void LoadHookScripts();
static void InitHookScripts();
static void HookScriptClear();
static bool HookHasScript(int hookId);
+1 -4
View File
@@ -318,11 +318,9 @@ static void __stdcall NewGame_Before() {
}
static void __stdcall NewGame_After() {
dlogr("New Game started.", DL_MAIN);
onAfterNewGame.invoke();
onAfterGameStarted.invoke();
dlogr("New Game started.", DL_MAIN);
gameLoaded = true;
}
@@ -333,7 +331,6 @@ static void __declspec(naked) main_load_new_hook() {
pop eax;
call fo::funcoffs::main_load_new_;
jmp NewGame_After;
//retn;
}
}
+22 -12
View File
@@ -124,8 +124,8 @@ typedef std::unordered_map<__int64, int>::iterator glob_itr;
typedef std::unordered_map<__int64, int>::const_iterator glob_citr;
DWORD availableGlobalScriptTypes = 0;
DWORD isGlobalScriptLoading = 0;
bool isGameLoading;
static DWORD isGlobalScriptLoading = 0;
static bool isGameReset;
bool alwaysFindScripts;
fo::ScriptInstance overrideScript = {0};
@@ -304,7 +304,7 @@ proceedNormal:
// this hook prevents sfall scripts from being removed after switching to another map, since normal script engine re-loads completely
static void __stdcall FreeProgram(fo::Program* progPtr) {
if (isGameLoading || (sfallProgsMap.find(progPtr) == sfallProgsMap.end())) { // only delete non-sfall scripts or when actually loading the game
if (isGameReset || (sfallProgsMap.find(progPtr) == sfallProgsMap.end())) { // only delete non-sfall scripts or when actually loading the game
__asm {
mov eax, progPtr;
call fo::funcoffs::interpretFreeProgram_;
@@ -483,27 +483,37 @@ bool IsGameScript(const char* filename) {
}
static void LoadGlobalScriptsList() {
dlogr("Running global scripts...", DL_SCRIPT);
ScriptProgram prog;
for (auto& item : globalScriptFilesList) {
auto &scriptFile = item.second;
dlog("> " + scriptFile, DL_SCRIPT);
isGlobalScriptLoading = 1;
LoadScriptProgram(prog, scriptFile.c_str(), true);
if (prog.ptr) {
dlogr(" Done", DL_SCRIPT);
GlobalScript gscript = GlobalScript(prog);
gscript.startProc = prog.procLookup[fo::Scripts::ScriptProc::start]; // get 'start' procedure position
globalScripts.push_back(gscript);
ScriptExtender::AddProgramToMap(prog);
dlogr(" Done", DL_SCRIPT);
// initialize script (start proc will be executed for the first time) -- this needs to be after script is added to "globalScripts" array
InitScriptProgram(prog);
} else {
dlogr(" Error!", DL_SCRIPT);
}
isGlobalScriptLoading = 0;
}
}
static void InitGlobalScripts() {
isGameReset = false;
isGlobalScriptLoading = 1; // this should allow to register global exported variables
HookScripts::InitHookScripts();
LoadGlobalScriptsList();
isGlobalScriptLoading = 0;
}
static void PrepareGlobalScriptsListByMask() {
globalScriptFilesList.clear();
for (auto& fileMask : globalScriptPathList) {
@@ -518,6 +528,7 @@ static void PrepareGlobalScriptsListByMask() {
std::string baseName(name);
int lastDot = baseName.find_last_of('.');
if ((baseName.length() - lastDot) > 4) continue; // skip files with invalid extension (bug in db_get_file_list fuction)
dlog_f("Found global script: %s\n", DL_INIT, name);
baseName = baseName.substr(0, lastDot); // script name without extension
if (basePath != fo::var::script_path_base || !IsGameScript(baseName.c_str())) {
@@ -536,10 +547,9 @@ static void PrepareGlobalScriptsListByMask() {
}
}
// this runs after the game was loaded/started
// this runs before the game was loaded/started
static void LoadGlobalScripts() {
static bool listIsPrepared = false;
isGameLoading = false;
HookScripts::LoadHookScripts();
@@ -549,7 +559,6 @@ static void LoadGlobalScripts() {
listIsPrepared = !alwaysFindScripts;
if (listIsPrepared) globalScriptPathList.clear(); // clear path list, it is no longer needed
}
LoadGlobalScriptsList();
dlogr("Finished loading global scripts.", DL_SCRIPT|DL_INIT);
}
@@ -569,7 +578,6 @@ int __stdcall ScriptExtender::ScriptHasLoaded(fo::Program* script) {
lastProgram.script = script;
lastProgram.index = i;
return loaded;
}
}
@@ -579,7 +587,8 @@ int __stdcall ScriptExtender::ScriptHasLoaded(fo::Program* script) {
// this runs before actually loading/starting the game
static void ClearGlobalScripts() {
isGameLoading = true;
devlog_f("\nReset global scripts.", DL_MAIN);
isGameReset = true;
lastProgram.script = nullptr;
sfallProgsMap.clear();
globalScripts.clear();
@@ -889,7 +898,8 @@ static void BuildSortedIndexList() {
void ScriptExtender::init() {
LoadGameHook::OnAfterGameInit() += BuildSortedIndexList;
LoadGameHook::OnAfterGameStarted() += LoadGlobalScripts;
LoadGameHook::OnBeforeGameStart() += LoadGlobalScripts; // loading sfall scripts
LoadGameHook::OnAfterGameStarted() += InitGlobalScripts; // running sfall scripts
LoadGameHook::OnGameReset() += [] () {
ClearGlobalScripts();
ClearGlobals();
-1
View File
@@ -109,7 +109,6 @@ void RunScriptProc(ScriptProgram* prog, long procId);
int RunScriptStartProc(ScriptProgram* prog);
// variables
extern DWORD isGlobalScriptLoading;
extern DWORD availableGlobalScriptTypes;
extern bool alwaysFindScripts;