From a03ca230380312e206c01347911ff2e32f96292d Mon Sep 17 00:00:00 2001 From: MiranDMC Date: Sun, 12 Nov 2023 17:09:43 +0100 Subject: [PATCH] Inheriting compatibility mode from parent script. Deducing compatibility mode from script file extension. (#32) --- source/CCustomOpcodeSystem.cpp | 6 +-- source/CScriptEngine.cpp | 80 ++++++++++++++++++++++++++-------- source/CScriptEngine.h | 2 +- 3 files changed, 66 insertions(+), 22 deletions(-) diff --git a/source/CCustomOpcodeSystem.cpp b/source/CCustomOpcodeSystem.cpp index 95e4bb7c..96342dd0 100644 --- a/source/CCustomOpcodeSystem.cpp +++ b/source/CCustomOpcodeSystem.cpp @@ -1457,7 +1457,7 @@ namespace CLEO auto filename = reinterpret_cast(thread)->ResolvePath(path, DIR_CLEO); // legacy: default search location is game\cleo directory TRACE("[0A92] Starting new custom script %s from thread named %s", filename.c_str(), thread->GetName().c_str()); - auto cs = new CCustomScript(filename.c_str()); + auto cs = new CCustomScript(filename.c_str(), false, thread); SetScriptCondResult(thread, cs && cs->IsOK()); if (cs && cs->IsOK()) { @@ -1498,7 +1498,7 @@ namespace CLEO filename += ".cm"; // add custom mission extension TRACE("[0A94] Starting new custom mission %s from thread named %s", filename.c_str(), thread->GetName().c_str()); - auto cs = new CCustomScript(filename.c_str(), true); + auto cs = new CCustomScript(filename.c_str(), true, thread); SetScriptCondResult(thread, cs && cs->IsOK()); if (cs && cs->IsOK()) { @@ -3415,7 +3415,7 @@ extern "C" } // if "label == 0" then "script_name" need to be the file name - auto cs = new CCustomScript(script_name, false, reinterpret_cast(fromThread), label); + auto cs = new CCustomScript(script_name, false, fromThread, label); if (fromThread) SetScriptCondResult(fromThread, cs && cs->IsOK()); if (cs && cs->IsOK()) { diff --git a/source/CScriptEngine.cpp b/source/CScriptEngine.cpp index 6b01570d..936d0818 100644 --- a/source/CScriptEngine.cpp +++ b/source/CScriptEngine.cpp @@ -1302,7 +1302,7 @@ namespace CLEO } // TODO: Consider split into 2 classes: CCustomExternalScript, CCustomChildScript - CCustomScript::CCustomScript(const char *szFileName, bool bIsMiss, CCustomScript *parent, int label) + CCustomScript::CCustomScript(const char *szFileName, bool bIsMiss, CRunningScript *parent, int label) : CRunningScript(), bSaveEnabled(false), bOK(false), LastSearchPed(0), LastSearchCar(0), LastSearchObj(0), CompatVer(CLEO_VER_CUR) @@ -1318,10 +1318,39 @@ namespace CLEO // store script file directory and name FS::path path = szFileName; path = FS::weakly_canonical(path); + + // deduce compatibility mode from filetype extension + if (path.extension() == cs4_ext) + CompatVer = CLEO_VER_4; + else + if (path.extension() == cs3_ext) + CompatVer = CLEO_VER_3; + + if(CompatVer == CLEO_VER_CUR && parent != nullptr && parent-IsCustom()) + { + // inherit compatibility mode from parent + CompatVer = ((CCustomScript*)parent)->GetCompatibility(); + + // try loading file with same compatibility mode filetype extension + auto compatPath = path; + if(CompatVer == CLEO_VER_4) + { + compatPath.replace_extension(cs4_ext); + if(FS::is_regular_file(compatPath)) + path = compatPath; + } + else + if (CompatVer == CLEO_VER_3) + { + compatPath.replace_extension(cs3_ext); + if (FS::is_regular_file(compatPath)) + path = compatPath; + } + } + scriptFileDir = path.parent_path().string(); scriptFileName = path.filename().string(); - - workDir = Filepath_Root; + workDir = Filepath_Root; // game root try { @@ -1331,17 +1360,22 @@ namespace CLEO if (!parent) throw std::logic_error("Trying to create external thread from label without parent thread"); - BaseIP = parent->GetBasePointer(); - CurrentIP = parent->GetBasePointer() - label; - memcpy(Name, parent->Name, sizeof(Name)); - dwChecksum = parent->dwChecksum; - parentThread = parent; - parent->childThreads.push_back(this); + if (!parent->IsCustom()) + throw std::logic_error("Only custom threads can spawn children threads from label"); + + auto cs = (CCustomScript*)parent; + + BaseIP = cs->GetBasePointer(); + CurrentIP = cs->GetBasePointer() - label; + memcpy(Name, cs->Name, sizeof(Name)); + dwChecksum = cs->dwChecksum; + parentThread = cs; + cs->childThreads.push_back(this); } else { using std::ios; - std::ifstream is(szFileName, std::ios::binary); + std::ifstream is(path.string().c_str(), std::ios::binary); is.exceptions(std::ios::badbit | std::ios::failbit); std::size_t length; is.seekg(0, std::ios::end); @@ -1360,23 +1394,33 @@ namespace CLEO } is.read(reinterpret_cast(BaseIP), length); - auto fname = strrchr(szFileName, '\\') + 1; - if (!fname) fname = strrchr(szFileName, '/') + 1; - if (fname < szFileName) fname = szFileName; - memcpy(Name, fname, sizeof(Name)); - Name[7] = '\0'; - dwChecksum = crc32(reinterpret_cast(BaseIP), length); + dwChecksum = crc32(reinterpret_cast(BaseIP), length); + + // thread name from filename + auto threadNamePath = path; + if(threadNamePath.extension() == cs3_ext || threadNamePath.extension() == cs4_ext) + { + threadNamePath.replace_extension(cs_ext); // keep original extension even in compatibility modes + } + auto fName = threadNamePath.filename().string(); + + memset(Name, '\0', sizeof(Name)); + if(!fName.empty()) + { + auto len = min(fName.length(), sizeof(Name) - 1); // and text terminator + memcpy(Name, fName.c_str(), len); + } } lastScriptCreated = this; bOK = true; } catch (std::exception& e) { - LOG_WARNING(0, "Error during loading of custom script %s occured.\nError message: %s", szFileName, e.what()); + LOG_WARNING(0, "Error during loading of custom script %s occured.\nError message: %s", path.string().c_str(), e.what()); } catch (...) { - LOG_WARNING(0, "Unknown error during loading of custom script %s occured.", szFileName); + LOG_WARNING(0, "Unknown error during loading of custom script %s occured.", path.string().c_str()); } } diff --git a/source/CScriptEngine.h b/source/CScriptEngine.h index db9eb44d..ea4e5369 100644 --- a/source/CScriptEngine.h +++ b/source/CScriptEngine.h @@ -55,7 +55,7 @@ namespace CLEO inline DWORD& GetLastSearchPed() { return LastSearchPed; } inline DWORD& GetLastSearchVehicle() { return LastSearchCar; } inline DWORD& GetLastSearchObject() { return LastSearchObj; } - CCustomScript(const char *szFileName, bool bIsMiss = false, CCustomScript *parent = nullptr, int label = 0); + CCustomScript(const char *szFileName, bool bIsMiss = false, CRunningScript *parent = nullptr, int label = 0); ~CCustomScript(); void Process();