From 28b81ba3e28f68951a467c4444691ea78f618711 Mon Sep 17 00:00:00 2001 From: RusJJ Date: Fri, 5 Apr 2024 00:17:52 +0300 Subject: [PATCH] FileSystemOperations opcodes --- cleo5opcodes.cpp | 88 +++++++++++++++++++++++++++++++++++++++++++++++- cleohelpers.h | 83 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 169 insertions(+), 2 deletions(-) diff --git a/cleo5opcodes.cpp b/cleo5opcodes.cpp index 1656f1c..fa8004d 100644 --- a/cleo5opcodes.cpp +++ b/cleo5opcodes.cpp @@ -232,6 +232,7 @@ CLEO_Fn(DISPLAY_TEXT_FORMATTED) CLEO_ReadStringEx(handle, fmt, sizeof(fmt)); CLEO_FormatString(handle, buf, sizeof(buf), fmt); + char* introTxtLine = IntroTextLines + *NumberOfIntroTextLinesThisFrame * ValueForGame(0xF4, 0xF4, 0x44); if(*nGameIdent == GTASA) { // new GXT label @@ -239,7 +240,6 @@ CLEO_Fn(DISPLAY_TEXT_FORMATTED) char gxt[8] = { 0x01, 'C', 'L', 'E', 'O', '_', 0x01, 0x00 }; gxt[6] += *NumberOfIntroTextLinesThisFrame; // unique label for each possible entry - char* introTxtLine = IntroTextLines + *NumberOfIntroTextLinesThisFrame * ValueForGame(0xF4, 0xF4, 0x44); AddGXTLabel(gxt, buf); *(float*)(introTxtLine + 0x2C) = posX; @@ -257,6 +257,84 @@ CLEO_Fn(DISPLAY_TEXT_FORMATTED) ++(*NumberOfIntroTextLinesThisFrame); } +// FileSystemOperations +CLEO_Fn(GET_FILE_POSITION) +{ + FILE* file = (FILE*)cleo->ReadParam(handle)->i; + cleo->GetPointerToScriptVar(handle)->i = file ? ftell(file) : 0; +} +CLEO_Fn(READ_BLOCK_FROM_FILE) +{ + FILE* file = (FILE*)cleo->ReadParam(handle)->i; + int size = cleo->ReadParam(handle)->i; + char* buffer = (char*)cleo->ReadParam(handle)->i; + int didRead = fread(buffer, 1, size, file); + fseek(file, 0, SEEK_CUR); // required for RW streams (https://en.wikibooks.org/wiki/C_Programming/stdio.h/fopen) + UpdateCompareFlag(handle, didRead == size); +} +CLEO_Fn(WRITE_BLOCK_TO_FILE) +{ + FILE* file = (FILE*)cleo->ReadParam(handle)->i; + int size = cleo->ReadParam(handle)->i; + char* buffer = (char*)cleo->ReadParam(handle)->i; + int didWrite = fwrite(buffer, 1, size, file); + fseek(file, 0, SEEK_CUR); // required for RW streams (https://en.wikibooks.org/wiki/C_Programming/stdio.h/fopen) + UpdateCompareFlag(handle, didWrite == size); +} +CLEO_Fn(RESOLVE_FILEPATH) +{ + char path[MAX_STR_LEN]; + CLEO_ReadStringEx(handle, path, sizeof(path)); + + std::string resolved = ResolvePath(handle, path); + CLEO_WriteStringEx(handle, resolved.c_str()); +} +CLEO_Fn(GET_SCRIPT_FILENAME) +{ + void* script = (void*)cleo->ReadParam(handle)->i; + bool fullPath = cleo->ReadParam(handle)->i; + + if(script == (void*)-1) script = handle; + + if(GetAddonInfo(script).isCustom) + { + const char* filename = CLEO_GetScriptFilename(script); + if(!filename) + { + SkipOpcodeParameters(handle, 1); + UpdateCompareFlag(handle, false); + return; + } + + if(fullPath) + { + std::string fullfilename = cleo->GetCleoStorageDir(); + if(fullfilename.back() != '/' && fullfilename.back() != '\\') fullfilename += '/'; + fullfilename += filename; + CLEO_WriteStringEx(handle, fullfilename.c_str()); + } + else + { + CLEO_WriteStringEx(handle, filename); + } + } + else + { + if(fullPath) + { + std::string fullfilename = aml->GetAndroidDataPath(); + if(fullfilename.back() != '/' && fullfilename.back() != '\\') fullfilename += '/'; + fullfilename += "data/script/"; + fullfilename += ((GTAScript*)script)->name; + CLEO_WriteStringEx(handle, fullfilename.c_str()); // stupid but ok... + } + else + { + CLEO_WriteStringEx(handle, ((GTAScript*)script)->name); + } + } +} + // CLEO 5 CLEO_Fn(CLEO_RETURN_WITH) { @@ -305,6 +383,14 @@ void Init5Opcodes() CLEO_RegisterOpcode(0x2604, IS_TEXT_SUFFIX); // 2604=3, is_text_suffix %1s% suffix %2s% ignore_case %3d% // originally it's sufix *facepalm* CLEO_RegisterOpcode(0x2605, DISPLAY_TEXT_FORMATTED); // 2605=-1, display_text_formatted offset_left %1d% offset_top %2d% format %3d% args + // FileSystemOperations + // Literally brainless move... #3 + CLEO_RegisterOpcode(0x2300, GET_FILE_POSITION); // 2300=2, get_file_position %1d% store_to %2d% + CLEO_RegisterOpcode(0x2301, READ_BLOCK_FROM_FILE); // 2301=3, read_block_from_file %1d% size %2d% buffer %3d% // IF and SET + CLEO_RegisterOpcode(0x2302, WRITE_BLOCK_TO_FILE); // 2302=3, write_block_to_file %1d% size %2d% address %3d% // IF and SET + CLEO_RegisterOpcode(0x2303, RESOLVE_FILEPATH); // 2303=2, %2s% = resolve_filepath %1s% + CLEO_RegisterOpcode(0x2304, GET_SCRIPT_FILENAME); // 2304=3, %3s% = get_script_filename %1d% full_path %2d% // IF and SET + // CLEO 5 CLEO_RegisterOpcode(0x2002, CLEO_RETURN_WITH); // 2002=-1, cleo_return_with ... CLEO_RegisterOpcode(0x2003, CLEO_RETURN_FAIL); // 2003=-1, cleo_return_fail diff --git a/cleohelpers.h b/cleohelpers.h index dcfad27..e78972e 100644 --- a/cleohelpers.h +++ b/cleohelpers.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "cleo.h" #include "cleoaddon.h" extern eGameIdent* nGameIdent; @@ -918,4 +919,84 @@ struct PausedScriptInfo PausedScriptInfo(GTAScript* ptr, const char* msg) : ptr(ptr), msg(msg) {} PausedScriptInfo(void* ptr, const char* msg) : ptr((GTAScript*)ptr), msg(msg) {} }; -extern std::deque pausedScripts; \ No newline at end of file +extern std::deque pausedScripts; + +static const char DIR_GAME[] = "root:"; // game root directory +static const char DIR_USER[] = "userfiles:"; // game save directory +static const char DIR_SCRIPT[] = "."; // current script directory +static const char DIR_CLEO[] = "cleo:"; // game\cleo directory +static const char DIR_MODULES[] = "modules:"; // game\cleo\modules directory + +inline const char* GetWorkDir() +{ + return aml->GetAndroidDataPath(); +} +inline const char* GetUserDirectory() +{ + return aml->GetDataPath(); +} +inline const char* GetCleoDir() +{ + return cleo->GetCleoStorageDir(); +} +inline const char* GetModulesDir() +{ + return cleo->GetCleoPluginLoadDir(); +} +inline std::string ResolvePath(void* handle, const char* path, const char* customWorkDir = NULL) +{ + if(!path) return ""; + + enum class VPref{ None, Game, User, Script, Cleo, Modules } virtualPrefix = VPref::None; + std::filesystem::path fsPath = std::filesystem::path(path); + std::filesystem::path::iterator root = fsPath.begin(); + if(root != fsPath.end()) + { + if(*root == DIR_GAME) virtualPrefix = VPref::Game; + else if (*root == DIR_USER) virtualPrefix = VPref::User; + else if (*root == DIR_SCRIPT) virtualPrefix = VPref::Script; + else if (*root == DIR_CLEO) virtualPrefix = VPref::Cleo; + else if (*root == DIR_MODULES) virtualPrefix = VPref::Modules; + } + + std::filesystem::path resolved; + switch(virtualPrefix) + { + default: //case VPref::None: + { + if(fsPath.is_relative()) + { + if(customWorkDir != NULL) + fsPath = ResolvePath(handle, customWorkDir) / fsPath; + else + fsPath = GetWorkDir() / fsPath; + } + return std::filesystem::weakly_canonical(fsPath).string(); + } + + case VPref::User: + resolved = GetUserDirectory(); + break; + + case VPref::Script: + if(handle && GetAddonInfo(handle).isCustom) resolved = GetCleoDir(); + else + { + resolved = GetWorkDir(); + resolved /= "data"; + resolved /= "script"; + } + break; + + case VPref::Cleo: + resolved = GetCleoDir(); + break; + + case VPref::Modules: + resolved = GetModulesDir(); + break; + } + + for(auto it = ++fsPath.begin(); it != fsPath.end(); it++) resolved /= *it; + return std::filesystem::weakly_canonical(resolved).string(); // collapse "..\" uses +} \ No newline at end of file