diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1c220f58..262e178a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,7 +51,6 @@ jobs: @REM copy files copy source\cleo_config.ini .output\Release\cleo\.cleo_config.ini copy cleo_plugins\.output\*.cleo .output\Release\cleo\cleo_plugins - copy cleo_plugins\.output\*.cleo5 .output\Release\cleo\cleo_plugins copy cleo_plugins\.output\*.ini .output\Release\cleo\cleo_plugins copy cleo_plugins\Audio\bass\bass.dll .output\Release\bass.dll xcopy /E /I tests\ .output\cleo diff --git a/README.md b/README.md index 52f5bb5f..cae11b92 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,18 @@ CLEO requires an 'ASI Loader' installed to run which is provided with the releas No additional files are replaced, however the following files and folders are added: - cleo\ (CLEO script directory) -- cleo\cleo_plugins\DebugUtils.cleo (script debug utilities plugin) -- cleo\cleo_plugins\FileSystemOperations.cleo (file system plugin) -- cleo\cleo_plugins\IniFiles.cleo (INI config plugin) -- cleo\cleo_plugins\IntOperations.cleo (INT operations plugin) +- cleo\cleo_plugins\SA.Audio.cleo (audio playback utilities powered by BASS.dll library) +- cleo\cleo_plugins\SA.DebugUtils.cleo (script debugging utilities plugin) +- cleo\cleo_plugins\SA.FileSystemOperations.cleo (disk drive files related operations plugin) +- cleo\cleo_plugins\SA.IniFiles.cleo (.ini config files handling plugin) +- cleo\cleo_plugins\SA.IntOperations.cleo (additional math operations plugin) +- cleo\cleo_plugins\SA.MemoryOperations (memory and .dll libraries utilities plugin) - cleo\cleo_saves\ (CLEO save directory) - cleo\cleo_text\ (CLEO text directory) - cleo.asi (core library) - bass.dll (audio engine library) -- vorbisHooked.dll (Silent's ASI Loader) +- vorbisFile.dll (Silent's ASI Loader) +- vorbisHooked.dll (original vorbisFile.dll file) All plugins are optional, however they may be required by various CLEO scripts. diff --git a/cleo_plugins/DebugUtils/DebugUtils.vcxproj b/cleo_plugins/DebugUtils/DebugUtils.vcxproj index 838cf9e1..536eb3b5 100644 --- a/cleo_plugins/DebugUtils/DebugUtils.vcxproj +++ b/cleo_plugins/DebugUtils/DebugUtils.vcxproj @@ -44,14 +44,14 @@ $(SolutionDir).output\ $(ProjectDir).obj\$(Configuration)\ - DebugUtils - .cleo5 + SA.DebugUtils + .cleo $(SolutionDir).output\ $(ProjectDir).obj\$(Configuration)\ - DebugUtils - .cleo5 + SA.DebugUtils + .cleo $(GTA_SA_DIR)\gta_sa.exe @@ -132,7 +132,7 @@ xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\" - + diff --git a/cleo_plugins/DebugUtils/DebugUtils.vcxproj.filters b/cleo_plugins/DebugUtils/DebugUtils.vcxproj.filters index 533d3aa0..b06f5016 100644 --- a/cleo_plugins/DebugUtils/DebugUtils.vcxproj.filters +++ b/cleo_plugins/DebugUtils/DebugUtils.vcxproj.filters @@ -34,6 +34,6 @@ - + \ No newline at end of file diff --git a/cleo_plugins/DebugUtils/DebugUtils.ini b/cleo_plugins/DebugUtils/SA.DebugUtils.ini similarity index 100% rename from cleo_plugins/DebugUtils/DebugUtils.ini rename to cleo_plugins/DebugUtils/SA.DebugUtils.ini diff --git a/cleo_plugins/FileSystemOperations/FileSystemOperations.vcxproj b/cleo_plugins/FileSystemOperations/FileSystemOperations.vcxproj index 5129493b..742cef3a 100644 --- a/cleo_plugins/FileSystemOperations/FileSystemOperations.vcxproj +++ b/cleo_plugins/FileSystemOperations/FileSystemOperations.vcxproj @@ -44,14 +44,14 @@ $(SolutionDir).output\ $(ProjectDir).obj\$(Configuration)\ - FileSystemOperations - .cleo5 + SA.FileSystemOperations + .cleo $(SolutionDir).output\ $(ProjectDir).obj\$(Configuration)\ - FileSystemOperations - .cleo5 + SA.FileSystemOperations + .cleo $(GTA_SA_DIR)\gta_sa.exe @@ -83,7 +83,9 @@ taskkill /IM gta_sa.exe /F /FI "STATUS eq RUNNING" -xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\" +if defined GTA_SA_DIR ( + xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\" +) @@ -106,7 +108,9 @@ xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\" taskkill /IM gta_sa.exe /F /FI "STATUS eq RUNNING" -xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\" +if defined GTA_SA_DIR ( + xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\" +) diff --git a/cleo_plugins/IniFiles/IniFiles.cpp b/cleo_plugins/IniFiles/IniFiles.cpp index 2daff3dd..0064d1e6 100644 --- a/cleo_plugins/IniFiles/IniFiles.cpp +++ b/cleo_plugins/IniFiles/IniFiles.cpp @@ -1,5 +1,6 @@ #include #include "CLEO.h" +#include "CLEO_Utils.h" #include using namespace CLEO; @@ -28,27 +29,24 @@ class IniFiles } } + // resused globals to cut down allocations + static char section[128]; + static char key[128]; + static OpcodeResult WINAPI Script_InifileGetInt(CScriptThread* thread) /**************************************************************** Opcode Format 0AF0=4,%4d% = get_int_from_ini_file %1s% section %2s% key %3s% ****************************************************************/ { - char path[MAX_PATH]; - char sectionName[100]; - char key[100]; - int result; - - CLEO_ReadStringPointerOpcodeParam(thread, path, sizeof(path)); - CLEO_ReadStringPointerOpcodeParam(thread, sectionName, sizeof(sectionName)); - CLEO_ReadStringPointerOpcodeParam(thread, key, sizeof(key)); - - CLEO_ResolvePath(thread, path, sizeof(path)); // convert to absolute path + auto path = OPCODE_READ_PARAM_FILEPATH(); + OPCODE_READ_PARAM_STRING_BUFF(section, sizeof(section)); + OPCODE_READ_PARAM_STRING_BUFF(key, sizeof(key)); - result = GetPrivateProfileInt(sectionName, key, 0x80000000, path); - CLEO_SetIntOpcodeParam(thread, result); - CLEO_SetThreadCondResult(thread, result != 0x80000000); + auto result = GetPrivateProfileInt(section, key, 0x80000000, path); + OPCODE_WRITE_PARAM_INT(result); + OPCODE_CONDITION_RESULT(result != 0x80000000); return OR_CONTINUE; } @@ -58,23 +56,16 @@ class IniFiles 0AF1=4,write_int %1d% to_ini_file %2s% section %3s% key %4s% ****************************************************************/ { - char path[MAX_PATH]; - char sectionName[100]; - char key[100]; - DWORD value; - char strValue[100]; - BOOL result; + auto value = OPCODE_READ_PARAM_INT(); + auto path = OPCODE_READ_PARAM_FILEPATH(); + OPCODE_READ_PARAM_STRING_BUFF(section, sizeof(section)); + OPCODE_READ_PARAM_STRING_BUFF(key, sizeof(key)); - value = CLEO_GetIntOpcodeParam(thread); - CLEO_ReadStringPointerOpcodeParam(thread, path, sizeof(path)); - CLEO_ReadStringPointerOpcodeParam(thread, sectionName, sizeof(sectionName)); - CLEO_ReadStringPointerOpcodeParam(thread, key, sizeof(key)); - - CLEO_ResolvePath(thread, path, sizeof(path)); // convert to absolute path - - result = WritePrivateProfileString(sectionName, key, _itoa(value, strValue, 10), path); - CLEO_SetThreadCondResult(thread, result); + char strValue[32]; + _itoa(value, strValue, 10); + auto result = WritePrivateProfileString(section, key, strValue, path); + OPCODE_CONDITION_RESULT(result); return OR_CONTINUE; } @@ -84,30 +75,23 @@ class IniFiles 0AF2=4,%4d% = get_float_from_ini_file %1s% section %2s% key %3s% ****************************************************************/ { - char path[MAX_PATH]; - char sectionName[100]; - char key[100]; - float value = 0.0f; - char strValue[100]; - BOOL result; - - CLEO_ReadStringPointerOpcodeParam(thread, path, sizeof(path)); - CLEO_ReadStringPointerOpcodeParam(thread, sectionName, sizeof(sectionName)); - CLEO_ReadStringPointerOpcodeParam(thread, key, sizeof(key)); + auto path = OPCODE_READ_PARAM_FILEPATH(); + OPCODE_READ_PARAM_STRING_BUFF(section, sizeof(section)); + OPCODE_READ_PARAM_STRING_BUFF(key, sizeof(key)); - CLEO_ResolvePath(thread, path, sizeof(path)); // convert to absolute path - - result = GetPrivateProfileString(sectionName, key, NULL, strValue, sizeof(strValue), path); + auto value = 0.0f; + char strValue[32]; + auto result = GetPrivateProfileString(section, key, NULL, strValue, sizeof(strValue), path); if (result) { value = (float)atof(strValue); - CLEO_SetFloatOpcodeParam(thread, value); + OPCODE_WRITE_PARAM_FLOAT(value); } else - CLEO_SkipOpcodeParams(thread, 1); - - CLEO_SetThreadCondResult(thread, result); - + { + OPCODE_SKIP_PARAMS(1); + } + OPCODE_CONDITION_RESULT(result); return OR_CONTINUE; } @@ -117,25 +101,16 @@ class IniFiles 0AF3=4,write_float %1d% to_ini_file %2s% section %3s% key %4s% ****************************************************************/ { - char path[MAX_PATH]; - char sectionName[100]; - char key[100]; - float value; - char strValue[100]; - BOOL result; - - value = CLEO_GetFloatOpcodeParam(thread); - CLEO_ReadStringPointerOpcodeParam(thread, path, sizeof(path)); - CLEO_ReadStringPointerOpcodeParam(thread, sectionName, sizeof(sectionName)); - CLEO_ReadStringPointerOpcodeParam(thread, key, sizeof(key)); - - CLEO_ResolvePath(thread, path, sizeof(path)); // convert to absolute path + auto value = OPCODE_READ_PARAM_FLOAT(); + auto path = OPCODE_READ_PARAM_FILEPATH(); + OPCODE_READ_PARAM_STRING_BUFF(section, sizeof(section)); + OPCODE_READ_PARAM_STRING_BUFF(key, sizeof(key)); + char strValue[32]; sprintf(strValue, "%g", value); + auto result = WritePrivateProfileString(section, key, strValue, path); - result = WritePrivateProfileString(sectionName, key, strValue, path); - CLEO_SetThreadCondResult(thread, result); - + OPCODE_CONDITION_RESULT(result); return OR_CONTINUE; } @@ -145,40 +120,21 @@ class IniFiles 0AF4=4,%4d% = read_string_from_ini_file %1s% section %2s% key %3s% ****************************************************************/ { - char path[MAX_PATH]; - char sectionName[100]; - char key[100]; - char strValue[100]; - char *strptr; - BOOL result; - - CLEO_ReadStringPointerOpcodeParam(thread, path, sizeof(path)); - CLEO_ReadStringPointerOpcodeParam(thread, sectionName, sizeof(sectionName)); - CLEO_ReadStringPointerOpcodeParam(thread, key, sizeof(key)); + auto path = OPCODE_READ_PARAM_FILEPATH(); + OPCODE_READ_PARAM_STRING_BUFF(section, sizeof(section)); + OPCODE_READ_PARAM_STRING_BUFF(key, sizeof(key)); - CLEO_ResolvePath(thread, path, sizeof(path)); // convert to absolute path - - result = GetPrivateProfileString(sectionName, key, NULL, strValue, sizeof(strValue), path); + char strValue[MAX_STR_LEN]; + auto result = GetPrivateProfileString(section, key, NULL, strValue, sizeof(strValue), path); if (result) { - switch (CLEO_GetOperandType(thread)) - { - case DT_VAR_STRING: - case DT_LVAR_STRING: - case DT_VAR_TEXTLABEL: - case DT_LVAR_TEXTLABEL: - CLEO_WriteStringOpcodeParam(thread, strValue); - break; - default: - strptr = (char *)CLEO_GetIntOpcodeParam(thread); - strcpy(strptr, strValue); - } + OPCODE_WRITE_PARAM_STRING(strValue); } else - CLEO_SkipOpcodeParams(thread, 1); - - CLEO_SetThreadCondResult(thread, result); - + { + OPCODE_SKIP_PARAMS(1); + } + OPCODE_CONDITION_RESULT(result); return OR_CONTINUE; } @@ -188,23 +144,17 @@ class IniFiles 0AF5=4,write_string %1s% to_ini_file %2s% section %3s% key %4s% ****************************************************************/ { - char path[MAX_PATH]; - char sectionName[100]; - char key[100]; - char strValue[100]; - BOOL result; - - CLEO_ReadStringPointerOpcodeParam(thread, strValue, sizeof(strValue)); - CLEO_ReadStringPointerOpcodeParam(thread, path, sizeof(path)); - CLEO_ReadStringPointerOpcodeParam(thread, sectionName, sizeof(sectionName)); - CLEO_ReadStringPointerOpcodeParam(thread, key, sizeof(key)); + char strValue[MAX_STR_LEN]; OPCODE_READ_PARAM_STRING_BUFF(strValue, sizeof(strValue)); + auto path = OPCODE_READ_PARAM_FILEPATH(); + OPCODE_READ_PARAM_STRING_BUFF(section, sizeof(section)); + OPCODE_READ_PARAM_STRING_BUFF(key, sizeof(key)); - CLEO_ResolvePath(thread, path, sizeof(path)); // convert to absolute path - - result = WritePrivateProfileString(sectionName, key, strValue, path); - - CLEO_SetThreadCondResult(thread, result); + auto result = WritePrivateProfileString(section, key, strValue, path); + OPCODE_CONDITION_RESULT(result); return OR_CONTINUE; } } iniFiles; + +char IniFiles::section[128]; +char IniFiles::key[128]; diff --git a/cleo_plugins/IniFiles/IniFiles.vcxproj b/cleo_plugins/IniFiles/IniFiles.vcxproj index 32eb6071..295783ac 100644 --- a/cleo_plugins/IniFiles/IniFiles.vcxproj +++ b/cleo_plugins/IniFiles/IniFiles.vcxproj @@ -44,14 +44,14 @@ $(SolutionDir).output\ $(ProjectDir).obj\$(Configuration)\ - IniFiles - .cleo5 + SA.IniFiles + .cleo $(SolutionDir).output\ $(ProjectDir).obj\$(Configuration)\ - IniFiles - .cleo5 + SA.IniFiles + .cleo $(GTA_SA_DIR)\gta_sa.exe diff --git a/cleo_plugins/IntOperations/IntOperations.vcxproj b/cleo_plugins/IntOperations/IntOperations.vcxproj index 3d0b82a1..83dd2abd 100644 --- a/cleo_plugins/IntOperations/IntOperations.vcxproj +++ b/cleo_plugins/IntOperations/IntOperations.vcxproj @@ -44,14 +44,14 @@ $(SolutionDir).output\ $(ProjectDir).obj\$(Configuration)\ - IntOperations - .cleo5 + SA.IntOperations + .cleo $(SolutionDir).output\ $(ProjectDir).obj\$(Configuration)\ - IntOperations - .cleo5 + SA.IntOperations + .cleo $(GTA_SA_DIR)\gta_sa.exe diff --git a/cleo_plugins/MemoryOperations/MemoryOperations.vcxproj b/cleo_plugins/MemoryOperations/MemoryOperations.vcxproj index 3a5b08dc..bb8086a3 100644 --- a/cleo_plugins/MemoryOperations/MemoryOperations.vcxproj +++ b/cleo_plugins/MemoryOperations/MemoryOperations.vcxproj @@ -45,14 +45,14 @@ $(SolutionDir).output\ $(ProjectDir).obj\$(Configuration)\ - MemoryOperations - .cleo5 + SA.MemoryOperations + .cleo $(SolutionDir).output\ $(ProjectDir).obj\$(Configuration)\ - MemoryOperations - .cleo5 + SA.MemoryOperations + .cleo $(GTA_SA_DIR)\gta_sa.exe @@ -84,7 +84,9 @@ taskkill /IM gta_sa.exe /F /FI "STATUS eq RUNNING" -xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\" +if defined GTA_SA_DIR ( + xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\" +) @@ -107,7 +109,9 @@ xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\" taskkill /IM gta_sa.exe /F /FI "STATUS eq RUNNING" -xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\" +if defined GTA_SA_DIR ( + xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\" +) diff --git a/source/CCustomOpcodeSystem.cpp b/source/CCustomOpcodeSystem.cpp index 04b3fb53..10430374 100644 --- a/source/CCustomOpcodeSystem.cpp +++ b/source/CCustomOpcodeSystem.cpp @@ -209,7 +209,7 @@ namespace CLEO CCustomOpcodeSystem::CCustomOpcodeSystem() { - // register CLEO opcodes + TRACE("Initializing CLEO core opcodes..."); CLEO_RegisterOpcode(0x0A92, opcode_0A92); CLEO_RegisterOpcode(0x0A93, opcode_0A93); CLEO_RegisterOpcode(0x0A94, opcode_0A94); @@ -2018,7 +2018,7 @@ extern "C" return texture; } - CLEO::HSTREAM WINAPI CLEO_GetInternalAudioStream(CLEO::CRunningScript* thread, DWORD stream) // arg CAudioStream * + DWORD WINAPI CLEO_GetInternalAudioStream(CLEO::CRunningScript* thread, DWORD stream) // arg CAudioStream * { return stream; // CAudioStream::streamInternal offset is 0 } diff --git a/source/CPluginSystem.h b/source/CPluginSystem.h index e807953f..58341806 100644 --- a/source/CPluginSystem.h +++ b/source/CPluginSystem.h @@ -17,39 +17,55 @@ namespace CLEO CPluginSystem() { std::set loaded; - auto LoadPluginsDir = [&](std::string path, std::string extension) - { + auto LoadPluginsDir = [&](std::string path, std::string prefix, std::string extension) + { + std::set> filesWithPrefix; + std::set> filesWithoutPrefix; + FilesWalk(path.c_str(), extension.c_str(), [&](const char* fullPath, const char* filename) { std::string name = filename; name.resize(name.length() - extension.length()); // cut off file type std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { return std::tolower(c); }); - if (loaded.find(name) == loaded.end()) + if (_strnicmp(name.c_str(), prefix.c_str(), prefix.length()) == 0) { - TRACE("Loading plugin '%s'", fullPath); - HMODULE hlib = LoadLibrary(fullPath); - if (!hlib) - { - LOG_WARNING(0, "Error loading plugin '%s'", fullPath); - } - else - { - loaded.insert(name); - plugins.push_back(hlib); - } + filesWithPrefix.insert({ fullPath, name.c_str() + prefix.length() }); } else { - LOG_WARNING(0, "Plugin `%s` already loaded. Skipping '%s'", name.c_str(), fullPath); + filesWithoutPrefix.insert({ fullPath, name }); } }); + + auto loadLib = [&](const char* fullPath, const char* name) + { + if (loaded.find(name) != loaded.end()) + { + LOG_WARNING(0, "Plugin `%s` already loaded. Skipping '%s'", fullPath, name); + return; + } + + TRACE("Loading plugin '%s'", fullPath); + HMODULE hlib = LoadLibrary(fullPath); + if (!hlib) + { + LOG_WARNING(0, "Error loading plugin '%s'", fullPath); + return; + } + + loaded.insert(name); + plugins.push_back(hlib); + }; + + // load with prefix first + for (const auto& entry : filesWithPrefix) loadLib(entry.first.c_str(), entry.second.c_str()); + for (const auto& entry : filesWithoutPrefix) loadLib(entry.first.c_str(), entry.second.c_str()); }; TRACE("Loading plugins..."); - LoadPluginsDir(FS::path(Filepath_Cleo).append("cleo_plugins").string(), ".cleo5"); // CLEO5 plugins - LoadPluginsDir(FS::path(Filepath_Cleo).append("cleo_plugins").string(), ".cleo"); // legacy plugins - LoadPluginsDir(Filepath_Cleo.c_str(), ".cleo"); // legacy plugins location + LoadPluginsDir(FS::path(Filepath_Cleo).append("cleo_plugins").string(), "SA.", ".cleo"); // prioritize with prefix + LoadPluginsDir(Filepath_Cleo.c_str(), "SA.", ".cleo"); // legacy plugins location } ~CPluginSystem() diff --git a/source/CleoBase.cpp b/source/CleoBase.cpp index c872d51d..9a010cf0 100644 --- a/source/CleoBase.cpp +++ b/source/CleoBase.cpp @@ -116,11 +116,10 @@ namespace CLEO if (m_bStarted) return; // already started m_bStarted = true; - FS::create_directory(Filepath_Cleo); - FS::create_directory(FS::path(Filepath_Cleo).append("cleo_modules")); - FS::create_directory(FS::path(Filepath_Cleo).append("cleo_plugins")); - FS::create_directory(FS::path(Filepath_Cleo).append("cleo_saves")); - FS::create_directory(FS::path(Filepath_Cleo).append("cleo_text")); + FS::create_directory(FS::path(Filepath_Root).append("cleo")); + FS::create_directory(FS::path(Filepath_Root).append("cleo\\cleo_modules")); + FS::create_directory(FS::path(Filepath_Root).append("cleo\\cleo_plugins")); + FS::create_directory(FS::path(Filepath_Root).append("cleo\\cleo_saves")); CodeInjector.OpenReadWriteAccess(); // must do this earlier to ensure plugins write access on init GameMenu.Inject(CodeInjector);