From f5bc53d7801c49f085199fd1348ab3bf98a5ef01 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Thu, 12 Mar 2026 21:32:04 +0800 Subject: [PATCH] Fixed the root cause of crash in PrepareGlobalScriptsListByMask * Calling convention violation - v141_xp uses ebx to store reference, but db_get_file_list does not preserve it. * v140_xp uses esi instead, which is preserved by the engine function. * Reverted some code changes in ScriptExtender.cpp. --- artifacts/ddraw.ini | 2 +- sfall/FalloutEngine/Functions.cpp | 7 +++++++ sfall/FalloutEngine/Functions.h | 4 ++++ sfall/FalloutEngine/Functions_def.h | 5 +---- sfall/Modules/ScriptExtender.cpp | 13 ++++++------- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index d1772421..0a9be8c7 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -847,7 +847,7 @@ DivisionOperatorFix=1 ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX [Scripts] ;Comma-separated list of masked paths to load global scripts from -;Only use single backslash \ as the directory separator +;Use only a single backslash \ as the directory separator ;Paths outside of scripts folder are supported GlobalScriptPaths=scripts\gl*.int,scripts\sfall\gl*.int diff --git a/sfall/FalloutEngine/Functions.cpp b/sfall/FalloutEngine/Functions.cpp index 9c183768..802e536e 100644 --- a/sfall/FalloutEngine/Functions.cpp +++ b/sfall/FalloutEngine/Functions.cpp @@ -167,6 +167,13 @@ long __fastcall db_init(const char* path_dat, const char* path_patches) { WRAP_WATCOM_FCALL2(db_init_, path_dat, path_patches); } +// Searches files in DB by given path/filename mask and stores result in fileList +// fileList is a pointer to a variable, that will be assigned with an address of an array of char* strings +long __fastcall db_get_file_list(const char* searchMask, char*** fileList) { + __asm xor ebx, ebx; // don't delete (bug in db_get_file_list_) + WRAP_WATCOM_FCALL2(db_get_file_list_, searchMask, fileList); +} + long __fastcall tile_num(long x, long y) { __asm xor ebx, ebx; // don't delete (bug in tile_num_) WRAP_WATCOM_FCALL2(tile_num_, x, y); diff --git a/sfall/FalloutEngine/Functions.h b/sfall/FalloutEngine/Functions.h index 514c94f3..8de7ca15 100644 --- a/sfall/FalloutEngine/Functions.h +++ b/sfall/FalloutEngine/Functions.h @@ -54,6 +54,10 @@ void interpretError(const char* fmt, ...); long __fastcall db_init(const char* path_dat, const char* path_patches); +// Searches files in DB by given path/filename mask and stores result in fileList +// fileList is a pointer to a variable, that will be assigned with an address of an array of char* strings +long __fastcall db_get_file_list(const char* searchMask, char*** fileList); // Returns number of elements in *fileList + long __fastcall tile_num(long x, long y); void __fastcall square_xy(long x, long y, long* outSX, long* outSY); diff --git a/sfall/FalloutEngine/Functions_def.h b/sfall/FalloutEngine/Functions_def.h index e3f819de..40648d25 100644 --- a/sfall/FalloutEngine/Functions_def.h +++ b/sfall/FalloutEngine/Functions_def.h @@ -307,7 +307,7 @@ WRAP_WATCOM_FUNC2(fo::DbFile*, db_fopen, const char*, path, const char*, mode) WRAP_WATCOM_FUNC3(char*, db_fgets, char*, buf, long, max_count, fo::DbFile*, file) WRAP_WATCOM_FFUNC4(long, db_fread, void*, buf, long, elsize, long, count, fo::DbFile*, file) WRAP_WATCOM_FFUNC3(long, db_fseek, fo::DbFile*, file, long, pos, long, origin) -WRAP_WATCOM_FUNC2(void, db_free_file_list, char const***, fileList, DWORD, arg2) // Destroys filelist array created by db_get_file_list +WRAP_WATCOM_FUNC2(void, db_free_file_list, char***, fileList, DWORD, arg2) // Destroys filelist array created by db_get_file_list WRAP_WATCOM_FUNC2(long, db_freadByte, fo::DbFile*, file, BYTE*, _out) WRAP_WATCOM_FUNC2(long, db_freadShort, fo::DbFile*, file, WORD*, _out) WRAP_WATCOM_FUNC2(long, db_freadInt, fo::DbFile*, file, DWORD*, _out) @@ -320,9 +320,6 @@ WRAP_WATCOM_FUNC2(long, db_fwriteInt, fo::DbFile*, file, long, value) WRAP_WATCOM_FFUNC3(long, db_fwriteByteCount, fo::DbFile*, file, const BYTE*, cptr, long, count) //WRAP_WATCOM_FFUNC3(long, db_fwriteLongCount, fo::DbFile*, file, DWORD*, dest, long, count) WRAP_WATCOM_FUNC2(long, db_dir_entry, const char*, fileName, DWORD*, sizeOut) // Check fallout file and get file size (result 0 - file exists) -// Searches files in DB by given path/filename mask and stores result in fileList -// fileList is a pointer to a variable, that will be assigned with an address of an array of char* strings -WRAP_WATCOM_FUNC2(long, db_get_file_list, const char*, searchMask, char const***, fileList) // Returns number of elements in *fileList WRAP_WATCOM_FUNC1(void*, dbase_open, const char*, fileName) WRAP_WATCOM_FUNC1(void, dbase_close, void*, dbPtr) diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index 4cbb6c4d..0451cdb0 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -25,8 +25,8 @@ #include "..\FalloutEngine\Fallout2.h" #include "..\InputFuncs.h" #include "..\Logging.h" -#include "..\Version.h" #include "..\Utils.h" +#include "..\version.h" #include "HookScripts.h" #include "LoadGameHook.h" #include "MainLoopHook.h" @@ -505,7 +505,7 @@ static void LoadGlobalScriptsList() { dlogr("Running global scripts...", DL_SCRIPT); ScriptProgram prog; - for (auto& item : globalScriptFilesList) { + for (const auto& item : globalScriptFilesList) { auto &scriptFile = item.second; dlog("> " + scriptFile, DL_SCRIPT); InitScriptProgram(prog, scriptFile.c_str(), true); @@ -538,14 +538,13 @@ static void InitGlobalScripts() { static void PrepareGlobalScriptsListByMask() { globalScriptFilesList.clear(); - for (const std::string fileMask : globalScriptPathList) { - char const** filenames; + for (const auto& fileMask : globalScriptPathList) { + char** filenames; auto basePath = fileMask.substr(0, fileMask.find_last_of("\\/") + 1); // path to scripts without mask int count = fo::func::db_get_file_list(fileMask.c_str(), &filenames); for (int i = 0; i < count; i++) { - std::string name(filenames[i]); - ToLowerCase(name); + char* name = _strlwr(filenames[i]); // name of the script in lower case if (name[0] != 'g' || name[1] != 'l') continue; // fix bug in db_get_file_list fuction (if the script name begins with a non-Latin character) std::string baseName(name); @@ -554,7 +553,7 @@ static void PrepareGlobalScriptsListByMask() { baseName = baseName.substr(0, lastDot); // script name without extension if (basePath != fo::var::script_path_base || !IsGameScript(baseName.c_str())) { - dlog_f("Found global script: %s\n", DL_SCRIPT, name.c_str()); + dlog_f("Found global script: %s\n", DL_SCRIPT, name); std::string fullPath(basePath); fullPath += name; // prevent loading global scripts with the same name from different directories