diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..e69d464 --- /dev/null +++ b/.clangd @@ -0,0 +1,16 @@ +CompileFlags: + Add: [-std=c++20] + +--- + +If: + PathMatch: include/SDK.h +Diagnostics: + UnusedIncludes: None + +--- + +If: + PathMatch: .* +Diagnostics: + Suppress: [-Wunused-include:include/SDK.h] \ No newline at end of file diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml new file mode 100644 index 0000000..250a27c --- /dev/null +++ b/.github/workflows/build-check.yml @@ -0,0 +1,43 @@ +name: "Build Check" + +on: + push: + branches-ignore: + - master + pull_request: + branches: + - master + +env: + BUILD_TYPE: Release + +jobs: + build-check: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + + - name: Cache LLVM + id: cache-llvm + uses: actions/cache@v4 + with: + path: C:\Program Files\LLVM + key: llvm-21.1.0-windows + + - name: Install LLVM 21.1.0 + if: steps.cache-llvm.outputs.cache-hit != 'true' + run: choco install llvm --version=21.1.0 -y + shell: powershell + + - name: Add LLVM to PATH + run: echo "C:\Program Files\LLVM\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + shell: powershell + + - name: Pull submodule + run: git submodule update --init + + - name: Configure CMake with Clang-CL + run: cmake -B ${{github.workspace}}/build -G "Ninja" -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DMLDEBUG=OFF + + - name: Build project + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} \ No newline at end of file diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 953bbd7..1d6611c 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -13,11 +13,27 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Cache LLVM + id: cache-llvm + uses: actions/cache@v4 + with: + path: C:\Program Files\LLVM + key: llvm-21.1.0-windows + + - name: Install LLVM 21.1.0 + if: steps.cache-llvm.outputs.cache-hit != 'true' + run: choco install llvm --version=21.1.0 -y + shell: powershell + + - name: Add LLVM to PATH + run: echo "C:\Program Files\LLVM\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + shell: powershell + - name: Pull submodule run: git submodule update --init - - name: Configure CMake - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + - name: Configure CMake with Clang-CL + run: cmake -B ${{github.workspace}}/build -G "Ninja" -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DMLDEBUG=OFF - name: Build project run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} @@ -27,9 +43,10 @@ jobs: with: name: fli-modloader path: | - ./build/Release/ModLoader.dll - ./build/Release/ModLoader.lib - ./build/DllProxy/Release/version.dll + ./build/ModLoader.dll + ./build/ModLoader.lib + ./build/DllProxy/version.dll + release: needs: build runs-on: ubuntu-latest @@ -38,9 +55,11 @@ jobs: run: | DATE_TAG="v$(date +'%Y%m%d.%H%M')" echo "TAG_NAME=$DATE_TAG" >> $GITHUB_ENV - echo "{tag}=$DATE_TAG" + echo "tag=$DATE_TAG" + - name: Download Artifacts uses: actions/download-artifact@v4 + - name: Create GitHub Release id: create_release uses: softprops/action-gh-release@v2 @@ -49,33 +68,7 @@ jobs: body: "Automated release of ${{ github.ref_name }}." generate_release_notes: true token: ${{ secrets.RELEASE_CD_TOKEN }} - - - name: Upload ModLoader.dll - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.RELEASE_CD_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: "./fli-modloader/Release/ModLoader.dll" - asset_name: ModLoader.dll - asset_content_type: application/octet-stream - - - name: Upload version.dll - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.RELEASE_CD_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: "./fli-modloader/DllProxy/Release/version.dll" - asset_name: version.dll - asset_content_type: application/octet-stream - - - name: Upload ModLoader.lib - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.RELEASE_CD_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: "./fli-modloader/Release/ModLoader.lib" - asset_name: ModLoader.lib - asset_content_type: application/octet-stream \ No newline at end of file + files: | + ./fli-modloader/ModLoader.dll + ./fli-modloader/ModLoader.lib + ./fli-modloader/DllProxy/version.dll \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5145fdc..4713cc4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,22 @@ +#Exclude ALL FILES * +#Except : + +# Dll Proxy +!DllProxy +!DllProxy/**/* + +# Source codes !include/ !include/**/* !src/ !src/**/* -#!CMakeLists.txt + +# Configuration and documentation +!CMakeLists.txt +!.clangd !README.md + +# Git Action !.github/ -!.github/**/* -!version_proxy.def \ No newline at end of file +!.github/**/* \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 58c45a0..6ab9dfa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,42 +5,28 @@ set(VERSION 1.00) option(MLDEBUG "Enable ModLoader debug code" ON) add_subdirectory(DllProxy) -add_library(${PROJECT_NAME} SHARED src/ModLoader.cpp) +add_library(${PROJECT_NAME} SHARED) -set_target_properties(${PROJECT_NAME} PROPERTIES - OUTPUT_NAME "ModLoader" - CXX_STANDARD 20 - CXX_STANDARD_REQUIRED YES -) - -target_compile_definitions(${PROJECT_NAME} PRIVATE MLCOMPILED) -target_compile_definitions(${PROJECT_NAME} PRIVATE MLVERSION=${VERSION}) +set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "ModLoader" CXX_STANDARD 20 CXX_STANDARD_REQUIRED YES) +target_compile_definitions(${PROJECT_NAME} PRIVATE MLCOMPILED MLVERSION=${VERSION}) if(MLDEBUG) target_compile_definitions(${PROJECT_NAME} PRIVATE MLDEBUG) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi") - set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG") - - if(MSVC) - target_compile_options(FantasyLifeI-ModLoader PRIVATE /wd4369 /wd4309) - endif() endif() -target_include_directories(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include -) +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options(${PROJECT_NAME} PRIVATE + "-Wno-inconsistent-dllimport" + "-Wno-dllimport-static-field-def" + /EHsc /GS /MD + ) +endif() -target_link_libraries(${PROJECT_NAME} PUBLIC - user32 - kernel32 -) -target_sources(${PROJECT_NAME} PRIVATE src/Lib/miniz.c) -target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/miniz) -target_compile_definitions(${PROJECT_NAME} PRIVATE MZ_ZIP_READER_ONLY) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_link_libraries(${PROJECT_NAME} PRIVATE user32 kernel32) file(GLOB_RECURSE PROJECT_SOURCE "src/*.cpp") -target_sources(${PROJECT_NAME} PUBLIC - ${PROJECT_SOURCE} -) \ No newline at end of file +target_sources(${PROJECT_NAME} PUBLIC src/Lib/miniz.c ${PROJECT_SOURCE}) \ No newline at end of file diff --git a/DllProxy/CMakeLists.txt b/DllProxy/CMakeLists.txt index bfbe086..92efc93 100644 --- a/DllProxy/CMakeLists.txt +++ b/DllProxy/CMakeLists.txt @@ -1,26 +1,24 @@ cmake_minimum_required(VERSION 3.16) project(DllProxy LANGUAGES CXX C) +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") add_library(${PROJECT_NAME} SHARED src/dllmain.cpp) set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "version" - CXX_STANDARD 17 + CXX_STANDARD 20 CXX_STANDARD_REQUIRED YES + LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/version_proxy.def" ) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ) - -if(MSVC) - target_compile_options(${PROJECT_NAME} PRIVATE /MT /EHsc /DWIN32_LEAN_AND_MEAN) - set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/version_proxy.def") -endif() - +target_compile_definitions(${PROJECT_NAME} PRIVATE WIN32_LEAN_AND_MEAN) target_link_libraries(${PROJECT_NAME} PUBLIC user32 kernel32 + shlwapi ) file(GLOB_RECURSE PROJECT_SOURCE "src/*.cpp") diff --git a/DllProxy/src/dllmain.cpp b/DllProxy/src/dllmain.cpp index 91a1157..0c97efb 100644 --- a/DllProxy/src/dllmain.cpp +++ b/DllProxy/src/dllmain.cpp @@ -1,9 +1,5 @@ -#define WIN32_LEAN_AND_MEAN #include #include -#pragma comment(lib, "Shlwapi.lib") -#pragma comment(linker, "/DLL") - static HMODULE hOriginal = NULL; // If needed we can load multiple DLLs diff --git a/README.md b/README.md index 9bf3e42..e4d83b4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Fantasy Life I Mod Loader > [!IMPORTANT] -> HEY!!! This mod loader is currently under development.. Somes features work (about 20%-30%??) but some things might break if you try weird stuff, that said, if you take your time and experiment a little you can already pull off some pretty cool things +> HEY!!! This mod loader is currently under development.. Somes features work (about 25%-35%??) but some things might break if you try weird stuff, that said, if you take your time and experiment a little you can already pull off some pretty cool things > If you're interested in supporting the project, contributions are welcome! Feel free to open a Pull Request!! ### How to install the Mod Loader @@ -53,3 +53,19 @@ Fantasy Life I/ ├── MyMod.fliarchive └── OtherMod.fliarchive ``` + +### Build the ModLoader + +>[!WARNING] +> Use LLVM 21.1.3 OR HIGHER + +```bash + $ cmake -B build -G "Ninja" -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DMLDEBUG=OFF +``` +> [!NOTE] +> For debugging you might need to set `MLDEBUG` to `ON`: `-DMLDEBUG=OFF` +> This is only needed if you require PDB files, otherwise keep this option off. + +```bash + $ cmake --build build --config Release +``` \ No newline at end of file diff --git a/include b/include index 40841b5..887bbf2 160000 --- a/include +++ b/include @@ -1 +1 @@ -Subproject commit 40841b546341b83f20e5beb8d0bb6bc9a4cb1ae8 +Subproject commit 887bbf28a873a9756ebd4c2a95cda25ec9a012ad diff --git a/src/API/Common/Common.cpp b/src/API/Common/Common.cpp index 0556a6f..55accac 100644 --- a/src/API/Common/Common.cpp +++ b/src/API/Common/Common.cpp @@ -2,27 +2,27 @@ #include "ModLoader.hpp" #include "GameCache.hpp" -std::string Common::NounSingular(LANG lang, std::string identifier) +std::string Common::NounSingular(LANG lang, std::string_view identifier) { - if(identifier == "None") return "NO_NAME"; - auto text = ModLoader::gameCache->GetNoun(identifier); + if(identifier == "None") return "nullptr"; + auto text = ModLoader::gameCache->GetNoun(identifier.data()); switch(lang) { - case LANG::JAPANESE: return text->nounSingularForm.ToString(); - case LANG::ENGLISH: return text->nounSingularForm_en.ToString(); - case LANG::FRENCH: return text->nounSingularForm_fr.ToString(); - case LANG::ESPAGNOL: return text->nounSingularForm_es.ToString(); - case LANG::DEUTSCH: return text->nounSingularForm_de.ToString(); - case LANG::ITALIAN: return text->nounSingularForm_it.ToString(); - case LANG::TZH: return text->nounSingularForm_tzh.ToString(); - case LANG::CZH: return text->nounSingularForm_czh.ToString(); - case LANG::KO: return text->nounSingularForm_ko.ToString(); + case LANG::JAPANESE: return text->nounSingularForm.ToString(); break; + case LANG::ENGLISH: return text->nounSingularForm_en.ToString(); break; + case LANG::FRENCH: return text->nounSingularForm_fr.ToString(); break; + case LANG::ESPAGNOL: return text->nounSingularForm_es.ToString(); break; + case LANG::DEUTSCH: return text->nounSingularForm_de.ToString(); break; + case LANG::ITALIAN: return text->nounSingularForm_it.ToString(); break; + case LANG::TZH: return text->nounSingularForm_tzh.ToString(); break; + case LANG::CZH: return text->nounSingularForm_czh.ToString(); break; + case LANG::KO: return text->nounSingularForm_ko.ToString(); break; } return text->nounSingularForm.ToString(); } -void Common::NounSingularSet(LANG lang, std::string identifier, FString value) +void Common::NounSingularSet(LANG lang, std::string_view identifier, FString value) { if(identifier == "None") { @@ -30,41 +30,41 @@ void Common::NounSingularSet(LANG lang, std::string identifier, FString value) return; } - auto text = ModLoader::gameCache->GetNoun(identifier); + auto text = ModLoader::gameCache->GetNoun(identifier.data()); switch(lang) { - case LANG::JAPANESE: text->nounSingularForm = value; - case LANG::ENGLISH: text->nounSingularForm_en = value; - case LANG::FRENCH: text->nounSingularForm_fr = value; - case LANG::ESPAGNOL: text->nounSingularForm_es = value; - case LANG::DEUTSCH: text->nounSingularForm_de = value; - case LANG::ITALIAN: text->nounSingularForm_it = value; - case LANG::TZH: text->nounSingularForm_tzh = value; - case LANG::CZH: text->nounSingularForm_czh = value; - case LANG::KO: text->nounSingularForm_ko = value; + case LANG::JAPANESE: text->nounSingularForm = value; break; + case LANG::ENGLISH: text->nounSingularForm_en = value; break; + case LANG::FRENCH: text->nounSingularForm_fr = value; break; + case LANG::ESPAGNOL: text->nounSingularForm_es = value; break; + case LANG::DEUTSCH: text->nounSingularForm_de = value; break; + case LANG::ITALIAN: text->nounSingularForm_it = value; break; + case LANG::TZH: text->nounSingularForm_tzh = value; break; + case LANG::CZH: text->nounSingularForm_czh = value; break; + case LANG::KO: text->nounSingularForm_ko = value; break; } } -std::string Common::Description(LANG lang, std::string identifier) +std::string Common::Description(LANG lang, std::string_view identifier) { - auto text = ModLoader::gameCache->GetText(identifier); + auto text = ModLoader::gameCache->GetText(identifier.data()); switch(lang) { - case LANG::JAPANESE: return text->Text.ToString(); - case LANG::ENGLISH: return text->text_en.ToString(); - case LANG::FRENCH: return text->text_fr.ToString(); - case LANG::ESPAGNOL: return text->text_es.ToString(); - case LANG::DEUTSCH: return text->text_de.ToString(); - case LANG::ITALIAN: return text->text_de.ToString(); - case LANG::TZH: return text->text_tzh.ToString(); - case LANG::CZH: return text->text_czh.ToString(); - case LANG::KO : return text->text_ko.ToString(); + case LANG::JAPANESE: return text->Text.ToString(); break; + case LANG::ENGLISH: return text->text_en.ToString(); break; + case LANG::FRENCH: return text->text_fr.ToString(); break; + case LANG::ESPAGNOL: return text->text_es.ToString(); break; + case LANG::DEUTSCH: return text->text_de.ToString(); break; + case LANG::ITALIAN: return text->text_de.ToString(); break; + case LANG::TZH: return text->text_tzh.ToString(); break; + case LANG::CZH: return text->text_czh.ToString(); break; + case LANG::KO: return text->text_ko.ToString(); break; } return text->Text.ToString(); } -void Common::DescriptionSet(LANG lang, std::string identifier, FString value) +void Common::DescriptionSet(LANG lang, std::string_view identifier, FString value) { if(identifier == "desc_itm_common") { @@ -72,17 +72,17 @@ void Common::DescriptionSet(LANG lang, std::string identifier, FString value) return; } - auto text = ModLoader::gameCache->GetText(identifier); + auto text = ModLoader::gameCache->GetText(identifier.data()); switch(lang) { - case LANG::JAPANESE: text->Text = value; - case LANG::ENGLISH: text->text_en = value; - case LANG::FRENCH: text->text_fr = value; - case LANG::ESPAGNOL: text->text_es = value; - case LANG::DEUTSCH: text->text_de = value; - case LANG::ITALIAN: text->text_de = value; - case LANG::TZH: text->text_tzh = value; - case LANG::CZH: text->text_czh = value; - case LANG::KO : text->text_ko = value; + case LANG::JAPANESE: text->Text = value; break; + case LANG::ENGLISH: text->text_en = value; break; + case LANG::FRENCH: text->text_fr = value; break; + case LANG::ESPAGNOL: text->text_es = value; break; + case LANG::DEUTSCH: text->text_de = value; break; + case LANG::ITALIAN: text->text_de = value; break; + case LANG::TZH: text->text_tzh = value; break; + case LANG::CZH: text->text_czh = value; break; + case LANG::KO: text->text_ko = value; break; } } \ No newline at end of file diff --git a/src/API/Common/CommonItemEffectParam.cpp b/src/API/Common/CommonItemEffectParam.cpp new file mode 100644 index 0000000..e31f59e --- /dev/null +++ b/src/API/Common/CommonItemEffectParam.cpp @@ -0,0 +1,7 @@ +#include "API/Common/CommonItemEffectParam.hpp" +#include "API/Common/Common.hpp" + +std::string CommonItemEffectParam::GetDescription(LANG lang) +{ + return DESC_GET(lang, getDescIdentifier()); +} diff --git a/src/API/Common/CommonItemTableSetting.cpp b/src/API/Common/CommonItemTableSetting.cpp index d5c2351..68d38cd 100644 --- a/src/API/Common/CommonItemTableSetting.cpp +++ b/src/API/Common/CommonItemTableSetting.cpp @@ -1,24 +1,17 @@ #include "API/Common/CommonItemTableSetting.hpp" -#include "Utils.hpp" -#include "API/Engine/TArrayHelper.hpp" - -std::string CommonItemTableSetting::GetIdentifier() -{ - return Utils::FNameToString(this->_object.tableId); -} ItemTableDetail CommonItemTableSetting::GetData(int index) { - auto raw = TArrayHelper::Get(this->_object.tableData, index); + auto raw = this->_object.tableData.Get(index); return ItemTableDetail(raw); } void CommonItemTableSetting::SetData(int index, ItemTableDetail value) { - TArrayHelper::Set(this->_object.tableData, index, value.getObject()); + this->_object.tableData.Set(index, value.getObject()); } void CommonItemTableSetting::AddData(ItemTableDetail value) { - TArrayHelper::Add(this->_object.tableData, value.getObject()); + this->_object.tableData.Add(value.getObject()); } \ No newline at end of file diff --git a/src/API/Common/CommonPickParamData.cpp b/src/API/Common/CommonPickParamData.cpp deleted file mode 100644 index f57d706..0000000 --- a/src/API/Common/CommonPickParamData.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "API/Common/CommonPickParamData.hpp" -#include "Utils.hpp" - -std::string CommonPickParamData::GetIdentifier() -{ - return Utils::FNameToString(this->_object.ID); -} - -std::string CommonPickParamData::GetGotIdentifier() -{ - return Utils::FNameToString(this->_object.gotId); -} \ No newline at end of file diff --git a/src/API/Entities/CharaData.cpp b/src/API/Entities/CharaData.cpp index 7be32af..74bcf79 100644 --- a/src/API/Entities/CharaData.cpp +++ b/src/API/Entities/CharaData.cpp @@ -1,18 +1,6 @@ #include "API/Entities/CharaData.hpp" -#include "GameCache.hpp" -#include "ModLoader.hpp" #include "API/Common/Common.hpp" -std::string CharaData::GetIdentifier() -{ - return Utils::FNameToString(this->_object.ID); -} - -std::string CharaData::GetNameIdentifier() -{ - return Utils::FNameToString(this->_object.nameId); -} - std::string CharaData::GetName(LANG lang) { return NAME_GET(lang, GetIdentifier()); diff --git a/src/API/Entities/EntityStats.cpp b/src/API/Entities/EntityStats.cpp index ab55cb4..1365b1a 100644 --- a/src/API/Entities/EntityStats.cpp +++ b/src/API/Entities/EntityStats.cpp @@ -1,58 +1,58 @@ #include "API/Entities/EntityStats.hpp" -void EntityStats::setPhysicalAttack(ELifeType life, int32_t physicalAttack) { - FGDCharaParameter_CharaStatusParam ¶m = this->_getParamFrom(life); +void EntityStats::SetPhysicalAttack(ELifeType life, int32_t physicalAttack) { + FGDCharaParameter_CharaStatusParam ¶m = this->getParamFrom(life); param.baseParamMin.physicalOffense = physicalAttack; } -void EntityStats::setMagicalAttack(ELifeType life, int32_t magicalAttack) { - FGDCharaParameter_CharaStatusParam ¶m = this->_getParamFrom(life); +void EntityStats::SetMagicalAttack(ELifeType life, int32_t magicalAttack) { + FGDCharaParameter_CharaStatusParam ¶m = this->getParamFrom(life); param.baseParamMin.magicOffense = magicalAttack; } -void EntityStats::setPhysicalDefense(ELifeType life, int32_t physicalDefense) { - FGDCharaParameter_CharaStatusParam ¶m = this->_getParamFrom(life); +void EntityStats::SetPhysicalDefense(ELifeType life, int32_t physicalDefense) { + FGDCharaParameter_CharaStatusParam ¶m = this->getParamFrom(life); param.baseParamMin.physicalDefense = physicalDefense; } -void EntityStats::setMagicalDefense(ELifeType life, int32_t magicalDefense) { - FGDCharaParameter_CharaStatusParam ¶m = this->_getParamFrom(life); +void EntityStats::SetMagicalDefense(ELifeType life, int32_t magicalDefense) { + FGDCharaParameter_CharaStatusParam ¶m = this->getParamFrom(life); param.baseParamMin.magicDefense = magicalDefense; } -FGDCharaParameter_CharaStatusParam &EntityStats::_getParamFrom(ELifeType life) { +FGDCharaParameter_CharaStatusParam &EntityStats::getParamFrom(ELifeType life) { int index = static_cast(life) - 1; if (!this->_object.charaStatusParamList.Data.IsValidIndex(index)) throw std::out_of_range("Invalid index"); return this->_object.charaStatusParamList.Data[index].Value.Second; } -int32_t EntityStats::getPhysicalAttack(ELifeType life) { - FGDCharaParameter_CharaStatusParam ¶m = this->_getParamFrom(life); +int32_t EntityStats::GetPhysicalAttack(ELifeType life) { + FGDCharaParameter_CharaStatusParam ¶m = this->getParamFrom(life); return param.baseParamMin.physicalOffense; } -int32_t EntityStats::getMagicalAttack(ELifeType life) { - FGDCharaParameter_CharaStatusParam ¶m = this->_getParamFrom(life); +int32_t EntityStats::GetMagicalAttack(ELifeType life) { + FGDCharaParameter_CharaStatusParam ¶m = this->getParamFrom(life); return param.baseParamMin.magicOffense; } -int32_t EntityStats::getPhysicalDefense(ELifeType life) { - FGDCharaParameter_CharaStatusParam ¶m = this->_getParamFrom(life); +int32_t EntityStats::GetPhysicalDefense(ELifeType life) { + FGDCharaParameter_CharaStatusParam ¶m = this->getParamFrom(life); return param.baseParamMin.physicalDefense; } -int32_t EntityStats::getMagicalDefense(ELifeType life) { - FGDCharaParameter_CharaStatusParam ¶m = this->_getParamFrom(life); +int32_t EntityStats::GetMagicalDefense(ELifeType life) { + FGDCharaParameter_CharaStatusParam ¶m = this->getParamFrom(life); return param.baseParamMin.magicDefense; } -int32_t EntityStats::getCriticalRate(ELifeType life) { - FGDCharaParameter_CharaStatusParam ¶m = this->_getParamFrom(life); +int32_t EntityStats::GetCriticalRate(ELifeType life) { + FGDCharaParameter_CharaStatusParam ¶m = this->getParamFrom(life); return param.baseParamMin.criticalRate; } -int32_t EntityStats::getCriticalRateEvasion(ELifeType life) { - FGDCharaParameter_CharaStatusParam ¶m = this->_getParamFrom(life); +int32_t EntityStats::GetCriticalRateEvasion(ELifeType life) { + FGDCharaParameter_CharaStatusParam ¶m = this->getParamFrom(life); return param.baseParamMin.criticalRateEvasion; } \ No newline at end of file diff --git a/src/API/Entities/EntityStatus.cpp b/src/API/Entities/EntityStatus.cpp index bd345cd..5846d1d 100644 --- a/src/API/Entities/EntityStatus.cpp +++ b/src/API/Entities/EntityStatus.cpp @@ -1,27 +1,27 @@ #include "API/Entities/EntityStatus.hpp" -void EntityStatus::setHP(uint32_t hp) { +void EntityStatus::SetHP(uint32_t hp) { this->_permanentStatus.m_nowHp = hp; this->_volatileStatus.m_maxHP = hp; } -void EntityStatus::setSP(uint32_t sp) { +void EntityStatus::SetSP(uint32_t sp) { this->_permanentStatus.m_nowSp = sp; this->_volatileStatus.m_maxSP = sp; } -uint32_t EntityStatus::getHP() { +uint32_t EntityStatus::GetHP() { return this->_permanentStatus.m_nowHp; } -uint32_t EntityStatus::getSP() { +uint32_t EntityStatus::GetSP() { return this->_permanentStatus.m_nowSp; } -FCharaStatusP &EntityStatus::getPermanentStatus() { +FCharaStatusP &EntityStatus::GetPermanentStatus() { return this->_permanentStatus; } -FAvatarCharaStatusV &EntityStatus::getVolatileStatus() { +FAvatarCharaStatusV &EntityStatus::GetVolatileStatus() { return this->_volatileStatus; } \ No newline at end of file diff --git a/src/API/Entities/Player/Player.cpp b/src/API/Entities/Player/Player.cpp index 664748b..62543ef 100644 --- a/src/API/Entities/Player/Player.cpp +++ b/src/API/Entities/Player/Player.cpp @@ -1,34 +1,35 @@ - #include "API/Entities/Player/Player.hpp" -#include "Utils.hpp" -#include "ModLoader.hpp" +#include "API/Engine/FName.hpp" +#include Player::Player(FGDCharaParameter &charaParameter, FCharaStatusP *charaStatusP, FAvatarCharaStatusV &charaStatusV) : stats(charaParameter), status(*charaStatusP, charaStatusV) {} -ELifeType Player::getLifeType() { - FAvatarCharaStatusP *avatarStatus = reinterpret_cast(&this->status.getPermanentStatus()); - std::string &lifeId = Utils::FNameToString(avatarStatus->m_lifeId); +ELifeType Player::GetLifeType() { + FAvatarCharaStatusP *avatarStatus = reinterpret_cast(&this->status.GetPermanentStatus()); + std::string lifeId = avatarStatus->m_lifeId.ToString(); if (lifeId.empty() || lifeId.size() <= 4) return ELifeType::ELifeType__None; - return static_cast(std::stoi(lifeId.c_str() + 4)); + + uint8_t life = std::stoi(lifeId.c_str() + 4); + return static_cast(life + 1); } -void Player::setExp(ELifeType life, uint32_t exp) { - FAvatarCharaStatusP *avatarStatus = reinterpret_cast(&this->status.getPermanentStatus()); +void Player::SetExp(ELifeType life, uint32_t exp) { + FAvatarCharaStatusP *avatarStatus = reinterpret_cast(&this->status.GetPermanentStatus()); avatarStatus->m_exp.Data[static_cast(life) - 1].Value.Second = exp; } -uint32_t Player::getExp(ELifeType life) { - FAvatarCharaStatusP *avatarStatus = reinterpret_cast(&this->status.getPermanentStatus()); +uint32_t Player::GetExp(ELifeType life) { + FAvatarCharaStatusP *avatarStatus = reinterpret_cast(&this->status.GetPermanentStatus()); return avatarStatus->m_exp.Data[static_cast(life) - 1].Value.Second; } -void Player::setLevel(ELifeType life, uint16_t lvl) { - FAvatarCharaStatusP *avatarStatus = reinterpret_cast(&this->status.getPermanentStatus()); +void Player::SetLevel(ELifeType life, uint16_t lvl) { + FAvatarCharaStatusP *avatarStatus = reinterpret_cast(&this->status.GetPermanentStatus()); avatarStatus->m_lv.Data[static_cast(life) - 1].Value.Second = lvl; } -uint16_t Player::getLevel(ELifeType life) { - FAvatarCharaStatusP *avatarStatus = reinterpret_cast(&this->status.getPermanentStatus()); +uint16_t Player::GetLevel(ELifeType life) { + FAvatarCharaStatusP *avatarStatus = reinterpret_cast(&this->status.GetPermanentStatus()); return avatarStatus->m_lv.Data[static_cast(life) - 1].Value.Second; } \ No newline at end of file diff --git a/src/API/Item/ItemData.cpp b/src/API/Item/ItemData.cpp index 87d136a..3e037af 100644 --- a/src/API/Item/ItemData.cpp +++ b/src/API/Item/ItemData.cpp @@ -1,22 +1,7 @@ #include "API/Item/ItemData.hpp" -#include "ModLoader.hpp" -#include "GameCache.hpp" #include "API/Common/Common.hpp" +#include "API/Engine/FName.hpp" -std::string ItemData::GetIdentifier() -{ - return Utils::FNameToString(this->_object.ID); -} - -std::string ItemData::GetNameIdentifier() -{ - return Utils::FNameToString(this->_object.nameId); -} - -std::string ItemData::GetDescIdentifier() -{ - return Utils::FNameToString(this->_object.DescId); -} std::string ItemData::GetName(LANG lang) { @@ -36,9 +21,4 @@ std::string ItemData::GetDescription(LANG lang) void ItemData::SetDescription(LANG lang, FString string) { DESC_SET(lang, GetDescIdentifier(), string); -} - -std::string ItemData::GetOverwriteIcon() -{ - return Utils::FNameToString(this->_object.overwriteIconName); } \ No newline at end of file diff --git a/src/API/Item/ItemEquipData.cpp b/src/API/Item/ItemEquipData.cpp index c2584a8..45781b2 100644 --- a/src/API/Item/ItemEquipData.cpp +++ b/src/API/Item/ItemEquipData.cpp @@ -1,12 +1,24 @@ #include "API/Item/ItemEquipData.hpp" -#include "Utils.hpp" +#include "API/Engine/FName.hpp" +#include "ModLoader.hpp" std::string ItemEquipData::GetModelIdentifier() { - return Utils::FNameToString(reinterpret_cast(&this->_object)->modelID); + return static_cast(this->_object).modelID.ToString(); } void ItemEquipData::SetModel(ItemEquipData item) { - reinterpret_cast(&this->_object)->modelID = reinterpret_cast(&item.getObject())->modelID; + static_cast(this->_object).modelID = static_cast(this->_object).modelID; } + +TArray& ItemEquipData::GetAddSkillLot(int rarity) +{ + auto skillIdRaw = static_cast(this->_object).addSkillLotTableList.Get(rarity); + return ModLoader::gameCache->GetAddSkillTable(skillIdRaw.ToString()); +} + +void ItemEquipData::SetAddSkillTable(int rarity, FName value) +{ + static_cast(this->_object).addSkillLotTableList.Set(rarity, value); +} \ No newline at end of file diff --git a/src/API/Item/ItemLifeToolsData.cpp b/src/API/Item/ItemLifeToolsData.cpp index ef1fddd..09a9a55 100644 --- a/src/API/Item/ItemLifeToolsData.cpp +++ b/src/API/Item/ItemLifeToolsData.cpp @@ -1,7 +1,7 @@ #include "API/Item/ItemLifeToolsData.hpp" -#include "Utils.hpp" +#include "API/Engine/FName.hpp" std::string ItemLifeToolsData::GetSecondModel() { - return Utils::FNameToString(reinterpret_cast(&this->_object)->ModelId2); + return reinterpret_cast(&this->_object)->ModelId2.ToString(); } \ No newline at end of file diff --git a/src/API/Item/ItemUniqueSkillEquipData.cpp b/src/API/Item/ItemUniqueSkillEquipData.cpp index f69a684..8161dea 100644 --- a/src/API/Item/ItemUniqueSkillEquipData.cpp +++ b/src/API/Item/ItemUniqueSkillEquipData.cpp @@ -1,8 +1,6 @@ #include "API/Item/ItemUniqueSkillEquipData.hpp" -#include "API/Engine/TArrayHelper.hpp" void ItemUniqueSkillEquipData::AddSkill(SkillData skill) { - auto data = reinterpret_cast(&this->_object); - TArrayHelper::Add(data->SkillID, skill.getObject().ID.Name); + reinterpret_cast(&this->_object)->SkillID.Add(skill.getObject().ID.Name); } \ No newline at end of file diff --git a/src/API/Life/LifeData.cpp b/src/API/Life/LifeData.cpp index 432a595..a7837be 100644 --- a/src/API/Life/LifeData.cpp +++ b/src/API/Life/LifeData.cpp @@ -1,20 +1,6 @@ #include "API/Life/LifeData.hpp" -#include "GameData.hpp" -#include "Utils.hpp" -#include "ModLoader.hpp" -#include "GameCache.hpp" #include "API/Common/Common.hpp" -std::string LifeData::GetNameIdentifier() -{ - return Utils::FNameToString(this->_object.nameId); -} - -std::string LifeData::GetDescIdentifier() -{ - return Utils::FNameToString(this->_object.DescId); -} - std::string LifeData::GetName(LANG lang) { return NAME_GET(lang, GetNameIdentifier()); diff --git a/src/API/Life/ULifeData.cpp b/src/API/Life/ULifeData.cpp index f29c062..7195397 100644 --- a/src/API/Life/ULifeData.cpp +++ b/src/API/Life/ULifeData.cpp @@ -1,5 +1,5 @@ -#include "Api/Life/ULifeData.hpp" -#include "API/Engine/TArrayHelper.hpp" +#include "API/Life/ULifeData.hpp" +#include "API/Life/LifeData.hpp" LifeData ULifeData::GetLife(ELifeType life) { diff --git a/src/API/Recipe/RecipeData.cpp b/src/API/Recipe/RecipeData.cpp index a5cde6f..a31dfb5 100644 --- a/src/API/Recipe/RecipeData.cpp +++ b/src/API/Recipe/RecipeData.cpp @@ -1,19 +1,7 @@ #include "API/Recipe/RecipeData.hpp" +#include "API/Engine/FName.hpp" #include "ModLoader.hpp" #include "GameCache.hpp" -#include -#include "API/Engine/TArrayHelper.hpp" - - -std::string RecipeData::GetIdentifier() -{ - return Utils::FNameToString(this->_object.recipeId); -} - -std::string RecipeData::GetItemIdentifier() -{ - return Utils::FNameToString(this->_object.ItemId); -} ItemData RecipeData::GetItem() { @@ -22,16 +10,16 @@ ItemData RecipeData::GetItem() RecipeDataItemInfo RecipeData::GetRecipeItem(int index) { - auto raw = TArrayHelper::Get(this->_object.itemList, index); + auto raw = this->_object.itemList.Get(index); return RecipeDataItemInfo(raw); } void RecipeData::SetRecipeItem(ItemData value, int index, int32_t quantity) { - TArrayHelper::Set(this->_object.itemList, index, FGDRecipeData_ItemInfo{value.getObject().ID, quantity}); + this->_object.itemList.Set(index, FGDRecipeData_ItemInfo{value.getObject().ID, quantity}); } void RecipeData::AddRecipeItem(ItemData data, int32_t quantity) { - TArrayHelper::Add(this->_object.itemList, FGDRecipeData_ItemInfo{data.getObject().ID, quantity}); + this->_object.itemList.Add(FGDRecipeData_ItemInfo{data.getObject().ID, quantity}); } \ No newline at end of file diff --git a/src/API/Recipe/RecipeDataItemInfo.cpp b/src/API/Recipe/RecipeDataItemInfo.cpp index 9de1f11..7160f87 100644 --- a/src/API/Recipe/RecipeDataItemInfo.cpp +++ b/src/API/Recipe/RecipeDataItemInfo.cpp @@ -1,8 +1,9 @@ #include "API/Recipe/RecipeDataItemInfo.hpp" +#include "API/Engine/FName.hpp" #include "ModLoader.hpp" #include "GameCache.hpp" ItemData RecipeDataItemInfo::GetItem() { - return ModLoader::gameCache->GetItem(Utils::FNameToString(this->_object.ItemId)); + return ModLoader::gameCache->GetItem(this->_object.ItemId.ToString()); } \ No newline at end of file diff --git a/src/API/Recipe/RecipeDataRewardData.cpp b/src/API/Recipe/RecipeDataRewardData.cpp index df99e1c..f63158b 100644 --- a/src/API/Recipe/RecipeDataRewardData.cpp +++ b/src/API/Recipe/RecipeDataRewardData.cpp @@ -1,24 +1,25 @@ #include "API/Recipe/RecipeDataRewardData.hpp" +#include "API/Engine/FName.hpp" #include "GameCache.hpp" #include "ModLoader.hpp" ItemData RecipeDataRewardData::GetRank0Item() { - return ModLoader::gameCache->GetItem(Utils::FNameToString(this->_object.rank0_itemId)); + return ModLoader::gameCache->GetItem(this->_object.rank0_itemId.ToString()); } ItemData RecipeDataRewardData::GetRank1Item() { - return ModLoader::gameCache->GetItem(Utils::FNameToString(this->_object.rank1_itemId)); + return ModLoader::gameCache->GetItem(this->_object.rank1_itemId.ToString()); } ItemData RecipeDataRewardData::GetRank2Item() { - return ModLoader::gameCache->GetItem(Utils::FNameToString(this->_object.rank2_itemId)); + return ModLoader::gameCache->GetItem(this->_object.rank2_itemId.ToString()); } ItemData RecipeDataRewardData::GetRank3Item() { - return ModLoader::gameCache->GetItem(Utils::FNameToString(this->_object.rank3_itemId)); + return ModLoader::gameCache->GetItem(this->_object.rank3_itemId.ToString()); } diff --git a/src/API/Skill/SkillData.cpp b/src/API/Skill/SkillData.cpp index bac7103..b325204 100644 --- a/src/API/Skill/SkillData.cpp +++ b/src/API/Skill/SkillData.cpp @@ -1,40 +1,12 @@ #include "API/Skill/SkillData.hpp" -#include "ModLoader.hpp" -#include "GameCache.hpp" -#include "Utils.hpp" +#include "API/Engine/FName.hpp" #include "API/Common/Common.hpp" -#include "API/Engine/TArrayHelper.hpp" - -std::string SkillData::GetIdentifier() -{ - return Utils::FNameToString(this->_object.ID.Name); -} - -std::string SkillData::GetNameIdentifier() -{ - return Utils::FNameToString(this->_object.nameTextID); -} - -std::string SkillData::GetName(LANG lang) -{ - return NAME_GET(lang, GetNameIdentifier()); -} void SkillData::SetName(LANG lang, FString string) { NAME_SET(lang, GetNameIdentifier(), string); } -std::string SkillData::GetDescIdentifier() -{ - return Utils::FNameToString(this->_object.dascTextId); -} - -std::string SkillData::GetDescription(LANG lang) -{ - return DESC_GET(lang, GetDescIdentifier()); -} - void SkillData::SetDescription(LANG lang, FString string) { DESC_SET(lang, GetDescIdentifier(), string); @@ -42,16 +14,16 @@ void SkillData::SetDescription(LANG lang, FString string) SkillEffectInfo SkillData::GetSkillEffect(int index) { - auto raw = TArrayHelper::Get(this->_object.skillEffectInfoList, index); + auto raw = this->_object.skillEffectInfoList.Get(index); return SkillEffectInfo(raw); } void SkillData::SetSkillEffect(int index, SkillEffectInfo value) { - TArrayHelper::Set(this->_object.skillEffectInfoList, index, value.getObject()); + this->_object.skillEffectInfoList.Set(index, value.getObject()); } void SkillData::AddSkillEffect(SkillEffectInfo data) { - TArrayHelper::Add(this->_object.skillEffectInfoList, data.getObject()); + this->_object.skillEffectInfoList.Add(data.getObject()); } \ No newline at end of file diff --git a/src/API/Skill/SkillEffectInfo.cpp b/src/API/Skill/SkillEffectInfo.cpp index 4fdc3a0..afbd8bf 100644 --- a/src/API/Skill/SkillEffectInfo.cpp +++ b/src/API/Skill/SkillEffectInfo.cpp @@ -1,20 +1,17 @@ #include "API/Skill/SkillEffectInfo.hpp" -#include -#include "ModLoader.hpp" -#include "API/Engine/TArrayHelper.hpp" EffectCondition SkillEffectInfo::GetEffectCondition(int index) { - auto raw = TArrayHelper::Get(this->_object.effCondList, index); + auto raw = this->_object.effCondList.Get(index); return EffectCondition(raw); } void SkillEffectInfo::SetEffectCondition(int index, EffectCondition value) { - TArrayHelper::Set(this->_object.effCondList, index, value.getObject()); + this->_object.effCondList.Set(index, value.getObject()); } void SkillEffectInfo::AddEffectCondition(EffectCondition value) { - TArrayHelper::Add(this->_object.effCondList, value.getObject()); + this->_object.effCondList.Add(value.getObject()); } \ No newline at end of file diff --git a/src/API/Table/ItemTableDetail.cpp b/src/API/Table/ItemTableDetail.cpp index fc972ff..45b18fe 100644 --- a/src/API/Table/ItemTableDetail.cpp +++ b/src/API/Table/ItemTableDetail.cpp @@ -2,11 +2,6 @@ #include "ModLoader.hpp" #include "GameCache.hpp" -std::string ItemTableDetail::GetItemIdentifier() -{ - return Utils::FNameToString(this->_object.ItemId); -} - ItemData ItemTableDetail::GetItem() { return ModLoader::gameCache->GetItem(GetItemIdentifier()); diff --git a/src/API/World/MapData.cpp b/src/API/World/MapData.cpp index 375c713..fd31397 100644 --- a/src/API/World/MapData.cpp +++ b/src/API/World/MapData.cpp @@ -1,24 +1,7 @@ #include "API/World/MapData.hpp" -#include "ModLoader.hpp" -#include "GameCache.hpp" -#include "Utils.hpp" +#include "API/Engine/FName.hpp" #include "API/Common/Common.hpp" -std::string MapData::GetIdentifier() -{ - return Utils::FNameToString(this->_object.mapId); -} - -std::string MapData::GetPath() -{ - return Utils::FNameToString(this->_object.MapPath); -} - -std::string MapData::GetMapViewCategory() -{ - return Utils::FNameToString(this->_object.MapViewCategory); -} - std::string MapData::GetMapViewName(int index) { if(index < 0 || index >= this->_object.MapViewDataArray.Count) @@ -39,15 +22,6 @@ void MapData::SetMapViewName(int index, FString name) this->_object.MapViewDataArray.Data[index].mapName = name; } -std::string MapData::GetMapSubject() -{ - return Utils::FNameToString(this->_object.MapSubject); -} - -std::string MapData::GetNameIdentifier() -{ - return Utils::FNameToString(this->_object.MapNameID); -} std::string MapData::GetName(LANG lang) { @@ -59,11 +33,6 @@ void MapData::SetName(LANG lang, FString string) NAME_SET(lang, GetNameIdentifier(), string); } -std::string MapData::GetWorldMap() -{ - return Utils::FNameToString(this->_object.WorldMapID); -} - MapDataSubMapData MapData::GetSubMap(int index) { if(index < 0 || index >= this->_object.subMapDataList.Data.Count) diff --git a/src/API/World/MapDataSubMapData.cpp b/src/API/World/MapDataSubMapData.cpp index d222c04..b703d20 100644 --- a/src/API/World/MapDataSubMapData.cpp +++ b/src/API/World/MapDataSubMapData.cpp @@ -1,19 +1,8 @@ #include "API/World/MapDataSubMapData.hpp" #include "ModLoader.hpp" #include "GameCache.hpp" -#include "Utils.hpp" - -std::string MapDataSubMapData::GetSubMapIdentifier() -{ - return Utils::FNameToString(this->_object.subMapId); -} MapSubLevel MapDataSubMapData::GetSubMap() { return ModLoader::gameCache->GetSubLevel(GetSubMapIdentifier()); } - -std::string MapDataSubMapData::GetAreaID() -{ - return Utils::FNameToString(this->_object.AreaID); -} \ No newline at end of file diff --git a/src/API/World/MapSubLevel.cpp b/src/API/World/MapSubLevel.cpp deleted file mode 100644 index d2f057a..0000000 --- a/src/API/World/MapSubLevel.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "API/World/MapSubLevel.hpp" -#include "Utils.hpp" - -std::string MapSubLevel::GetIdentifier() -{ - return Utils::FNameToString(this->_object.SubLevelID); -} - -std::string MapSubLevel::GetMapSubIdentifier() -{ - return Utils::FNameToString(this->_object.mapSubId); -} - -std::string MapSubLevel::GetPath() -{ - return Utils::FNameToString(this->_object.SubLevelInfo.SubLevelPath); -} \ No newline at end of file diff --git a/src/CommonData.cpp b/src/CommonData.cpp new file mode 100644 index 0000000..de5b6ac --- /dev/null +++ b/src/CommonData.cpp @@ -0,0 +1,6 @@ +#include "CommonData.hpp" + +#ifdef _WIN32 +int64_t CommonData::sizeImage = 0; +uintptr_t CommonData::baseAddress = 0; +#endif \ No newline at end of file diff --git a/src/GameCache.cpp b/src/GameCache.cpp index 1808500..a3ef752 100644 --- a/src/GameCache.cpp +++ b/src/GameCache.cpp @@ -1,4 +1,6 @@ #include "GameCache.hpp" + +#include "API/Engine/FName.hpp" #include "ModLoader.hpp" #include "GameData.hpp" @@ -12,6 +14,7 @@ #include "API/Item/ItemKitData.hpp" #include "API/Item/ItemVehicleData.hpp" #include "API/Item/ItemPowerUpData.hpp" +#include GameCache::GameCache() { @@ -36,6 +39,9 @@ GameCache::GameCache() initChara(gmd, sdm); ModLoader::logger->verbose("Cached: Basic Chara Registries"); + + initAddSkillTable(gmd, sdm); + ModLoader::logger->verbose("Cached: AddSkillTable Registries"); } void GameCache::PostLoadCache() @@ -51,484 +57,271 @@ void GameCache::PostLoadCache() ModLoader::logger->info("OK: GameCache has been initialized"); + + uint32_t totalSize = + (this->_cacheNounInfo.size() * sizeof(void*)) + + (this->_cacheTextInfo.size() * sizeof(void*)) + + (this->_cacheItemData.size() * sizeof(void*)) + + (this->_cacheRecipeData.size() * sizeof(void*)) + + (this->_cacheCommonPickParam.size() * sizeof(void*)) + + (this->_cacheCharaData.size() * sizeof(void*)) + + (this->_cacheAddSkillLotTable.size() * sizeof(TArray*)) + + (this->_cacheSubLevel.size() * sizeof(void*)) + + (this->_cacheMap.size() * sizeof(void*)); + + ModLoader::logger->verbose("Total cached size: ", totalSize / 1024, " KB"); } void GameCache::initNoun(GameData* gmd, UStaticDataManager* sdm) { gmd->waitObject(&sdm->m_BattleCommandNameNoun); - for (int i = 0; i < sdm->m_BattleCommandNameNoun->m_dataMap.Data.Count; i++) - { - auto noun = sdm->m_BattleCommandNameNoun->m_dataMap.Data[i].Value.Second.nounInfoArray.Data; - if (noun == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_BattleCommandNameNoun->m_dataMap.Data[i].Value.First); - - this->_cacheNounInfo.emplace(key, noun); - } + for (auto& noun : sdm->m_BattleCommandNameNoun->m_dataMap) + this->_cacheNounInfo.emplace(noun.ID.ToString(), noun.nounInfoArray.GetData()); gmd->waitObject(&sdm->m_PlantDungeonText_Noun); - for (int i = 0; i < sdm->m_PlantDungeonText_Noun->m_dataMap.Data.Count; i++) - { - auto noun = sdm->m_PlantDungeonText_Noun->m_dataMap.Data[i].Value.Second.nounInfoArray.Data; - if (noun == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_PlantDungeonText_Noun->m_dataMap.Data[i].Value.First); - - this->_cacheNounInfo.emplace(key, noun); - } + for (auto& noun : sdm->m_PlantDungeonText_Noun->m_dataMap) + this->_cacheNounInfo.emplace(noun.ID.ToString(), noun.nounInfoArray.GetData()); gmd->waitObject(&sdm->m_ItemText_Noun); - for (int i = 0; i < sdm->m_ItemText_Noun->m_dataMap.Data.Count; i++) - { - auto noun = sdm->m_ItemText_Noun->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (noun == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_ItemText_Noun->m_dataMap.Data[i].Value.First); - - this->_cacheNounInfo.emplace(key, noun); - } + for (auto& noun : sdm->m_ItemText_Noun->m_dataMap) + this->_cacheNounInfo.emplace(noun.ID.ToString(), noun.textInfo.GetData()); // WHY IS THIS FUCKING NAMED TEXTINFO WTF LEVEL 5 PLEASE BE CONSISTENT gmd->waitObject(&sdm->m_LifeText_Noun); - for (int i = 0; i < sdm->m_LifeText_Noun->m_dataMap.Data.Count; i++) - { - auto noun = sdm->m_LifeText_Noun->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (noun == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_LifeText_Noun->m_dataMap.Data[i].Value.First); - - this->_cacheNounInfo.emplace(key, noun); - } + for (auto& textInfo : sdm->m_LifeText_Noun->m_dataMap) + this->_cacheNounInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_SkillText_Noun); - for (int i = 0; i < sdm->m_SkillText_Noun->m_dataMap.Data.Count; i++) - { - auto noun = sdm->m_SkillText_Noun->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (noun == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_SkillText_Noun->m_dataMap.Data[i].Value.First); - - this->_cacheNounInfo.emplace(key, noun); - } + for (auto& textInfo : sdm->m_SkillText_Noun->m_dataMap) + this->_cacheNounInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_QuestRequestMapText_Noun); - for (int i = 0; i < sdm->m_QuestRequestMapText_Noun->m_dataMap.Data.Count; i++) - { - auto noun = sdm->m_QuestRequestMapText_Noun->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (noun == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_QuestRequestMapText_Noun->m_dataMap.Data[i].Value.First); - - this->_cacheNounInfo.emplace(key, noun); - } + for (auto& textInfo : sdm->m_QuestRequestMapText_Noun->m_dataMap) + this->_cacheNounInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_QuestTitleText); - for (int i = 0; i < sdm->m_QuestTitleText->m_dataMap.Data.Count; i++) - { - auto noun = sdm->m_QuestTitleText->m_dataMap.Data[i].Value.Second.Text.Data; - if (noun == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_QuestTitleText->m_dataMap.Data[i].Value.First); - - this->_cacheNounInfo.emplace(key, noun); - } + for (auto& textInfo : sdm->m_QuestTitleText->m_dataMap) + this->_cacheNounInfo.emplace(textInfo.ID.ToString(), textInfo.Text.GetData()); gmd->waitObject(&sdm->m_MapText_Noun); - for (int i = 0; i < sdm->m_MapText_Noun->m_dataMap.Data.Count; i++) - { - auto noun = sdm->m_MapText_Noun->m_dataMap.Data[i].Value.Second.nounInfo.Data; - if (noun == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_MapText_Noun->m_dataMap.Data[i].Value.First); - - this->_cacheNounInfo.emplace(key, noun); - } + for (auto& textInfo : sdm->m_MapText_Noun->m_dataMap) + this->_cacheNounInfo.emplace(textInfo.ID.ToString(), textInfo.nounInfo.GetData()); gmd->waitObject(&sdm->m_MenuText_Noun); - for (int i = 0; i < sdm->m_MenuText_Noun->m_dataMap.Data.Count; i++) - { - auto noun = sdm->m_MenuText_Noun->m_dataMap.Data[i].Value.Second.nounInfoArray.Data; - if (noun == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_MenuText_Noun->m_dataMap.Data[i].Value.First); - - this->_cacheNounInfo.emplace(key, noun); - } + for (auto& textInfo : sdm->m_MenuText_Noun->m_dataMap) + this->_cacheNounInfo.emplace(textInfo.ID.ToString(), textInfo.nounInfoArray.GetData()); gmd->waitObject(&sdm->m_CharaText_Noun); - for (int i = 0; i < sdm->m_CharaText_Noun->m_dataMap.Data.Count; i++) - { - auto noun = sdm->m_CharaText_Noun->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (noun == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_CharaText_Noun->m_dataMap.Data[i].Value.First); - - this->_cacheNounInfo.emplace(key, noun); - } + for (auto& textInfo : sdm->m_CharaText_Noun->m_dataMap) + this->_cacheNounInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_SystemText_Noun); - for (int i = 0; i < sdm->m_SystemText_Noun->m_dataMap.Data.Count; i++) - { - auto noun = sdm->m_SystemText_Noun->m_dataMap.Data[i].Value.Second.nounInfoArray.Data; - if (noun == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_SystemText_Noun->m_dataMap.Data[i].Value.First); - - this->_cacheNounInfo.emplace(key, noun); - } + for (auto& textInfo : sdm->m_SystemText_Noun->m_dataMap) + this->_cacheNounInfo.emplace(textInfo.ID.ToString(), textInfo.nounInfoArray.GetData()); + + ModLoader::logger->verbose("GameCache: NounInfo size: ", this->_cacheNounInfo.size()); } void GameCache::initText(GameData* gmd, UStaticDataManager* sdm) { gmd->waitObject(&sdm->m_AchievementText); - for (int i = 0; i < sdm->m_AchievementText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_AchievementText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_AchievementText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_AchievementText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_CharacterFlavorText); - for (int i = 0; i < sdm->m_CharacterFlavorText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_CharacterFlavorText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_CharacterFlavorText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_CharacterFlavorText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_CharamakeText); - for (int i = 0; i < sdm->m_CharamakeText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_CharamakeText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_CharamakeText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_CharamakeText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_DailyMissionCompleteNotificationText); - for (int i = 0; i < sdm->m_DailyMissionCompleteNotificationText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_DailyMissionCompleteNotificationText->m_dataMap.Data[i].Value.Second.Text.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_DailyMissionCompleteNotificationText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_DailyMissionCompleteNotificationText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.Text.GetData()); gmd->waitObject(&sdm->m_DailyMissionTitleText); - for (int i = 0; i < sdm->m_DailyMissionTitleText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_DailyMissionTitleText->m_dataMap.Data[i].Value.Second.Text.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_DailyMissionTitleText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_DailyMissionTitleText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.Text.GetData()); gmd->waitObject(&sdm->m_GuildRewardText); - for (int i = 0; i < sdm->m_GuildRewardText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_GuildRewardText->m_dataMap.Data[i].Value.Second.Text.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_GuildRewardText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_GuildRewardText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.Text.GetData()); gmd->waitObject(&sdm->m_ItemText); - for (int i = 0; i < sdm->m_ItemText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_ItemText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_ItemText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_ItemText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_LifeText); - for (int i = 0; i < sdm->m_LifeText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_LifeText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_LifeText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_LifeText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_MapText); - for (int i = 0; i < sdm->m_MapText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_MapText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_MapText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_MapText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_MenuText); - for (int i = 0; i < sdm->m_MenuText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_MenuText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_MenuText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_MenuText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_MultiText); - for (int i = 0; i < sdm->m_MultiText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_MultiText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_MultiText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } - + for (auto& textInfo : sdm->m_MultiText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_PhaseTitleText); - for (int i = 0; i < sdm->m_PhaseTitleText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_PhaseTitleText->m_dataMap.Data[i].Value.Second.textInfoArray.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_PhaseTitleText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_PhaseTitleText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfoArray.GetData()); gmd->waitObject(&sdm->m_PlantDungeonText); - for (int i = 0; i < sdm->m_PlantDungeonText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_PlantDungeonText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_PlantDungeonText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_PlantDungeonText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_QuestDetailText); - for (int i = 0; i < sdm->m_QuestDetailText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_QuestDetailText->m_dataMap.Data[i].Value.Second.Text.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_QuestDetailText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_QuestDetailText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.Text.GetData()); gmd->waitObject(&sdm->m_QuestPurposeText); - for (int i = 0; i < sdm->m_QuestPurposeText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_QuestPurposeText->m_dataMap.Data[i].Value.Second.Text.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_QuestPurposeText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_QuestPurposeText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.Text.GetData()); gmd->waitObject(&sdm->m_QuestReportNotificationText); - for (int i = 0; i < sdm->m_QuestReportNotificationText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_QuestReportNotificationText->m_dataMap.Data[i].Value.Second.Text.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_QuestReportNotificationText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_QuestReportNotificationText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.Text.GetData()); gmd->waitObject(&sdm->m_SkillText); - for (int i = 0; i < sdm->m_SkillText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_SkillText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_SkillText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_SkillText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_SystemText); - for (int i = 0; i < sdm->m_SystemText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_SystemText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_SystemText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_SystemText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); gmd->waitObject(&sdm->m_TipsText); - for (int i = 0; i < sdm->m_TipsText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_TipsText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_TipsText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_TipsText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); + + ModLoader::logger->verbose("GameCache: TextInfo size: ", this->_cacheTextInfo.size()); } void GameCache::postInitText(GameData* gmd, UStaticDataManager* sdm) { gmd->waitObject(&sdm->m_PhasePurposeText); - for (int i = 0; i < sdm->m_PhasePurposeText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_PhasePurposeText->m_dataMap.Data[i].Value.Second.textInfoArray.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_PhasePurposeText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_PhasePurposeText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfoArray.GetData()); gmd->waitObject(&sdm->m_BattleCommandDescText); - for (int i = 0; i < sdm->m_BattleCommandDescText->m_dataMap.Data.Count; i++) - { - auto text = sdm->m_BattleCommandDescText->m_dataMap.Data[i].Value.Second.textInfo.Data; - if (text == nullptr) continue; - std::string key = Utils::FNameToString(sdm->m_BattleCommandDescText->m_dataMap.Data[i].Value.First); - - this->_cacheTextInfo.emplace(key, text); - } + for (auto& textInfo : sdm->m_BattleCommandDescText->m_dataMap) + this->_cacheTextInfo.emplace(textInfo.ID.ToString(), textInfo.textInfo.GetData()); + } void GameCache::initSkill(GameData* gmd, UStaticDataManager* sdm) { gmd->waitObject(&sdm->m_SkillData); - for (int i = 0; i < sdm->m_SkillData->m_dataMap.Data.Count; i++) + for (auto& skillInfo : sdm->m_SkillData->m_dataMap) { - std::string key = Utils::FNameToString(sdm->m_SkillData->m_dataMap.Data[i].Value.First.Name); + std::string key = skillInfo.ID.Name.ToString(); if(key == "ps_just_avoid" || key == "ps_just_guard") continue; - SkillData skill{ sdm->m_SkillData->m_dataMap.Data[i].Value.Second }; - - this->_cacheSkillData.emplace(key, std::make_unique(skill)); + this->_cacheSkillData.emplace(key, std::make_unique(skillInfo)); } + ModLoader::logger->verbose("GameCache: SkillData size: ", this->_cacheSkillData.size()); } void GameCache::initCommonPickParam(GameData* gmd, UStaticDataManager* sdm) { gmd->waitObject(&sdm->m_CommonPickParamData); - for (int i = 0; i < sdm->m_CommonPickParamData->m_dataMap.Data.Count; i++) - { - CommonPickParamData param{ sdm->m_CommonPickParamData->m_dataMap.Data[i].Value.Second }; - this->_cacheCommonPickParam.emplace(param.GetIdentifier(), std::make_unique(param)); - } + for (auto& paramInfo : sdm->m_CommonPickParamData->m_dataMap) + this->_cacheCommonPickParam.emplace(paramInfo.ID.ToString(), std::make_unique(paramInfo)); + + ModLoader::logger->verbose("GameCache: CommonPickParamData size: ", this->_cacheCommonPickParam.size()); } void GameCache::initItem(GameData* gmd, UStaticDataManager* sdm) { gmd->waitObject(&sdm->m_ItemMaterialData); - for (int i = 0; i < sdm->m_ItemMaterialData->m_dataMap.Data.Count; i++) - { - ItemMaterialData citem{ sdm->m_ItemMaterialData->m_dataMap.Data[i].Value.Second }; - - _cacheItemData.emplace(citem.GetIdentifier(), std::make_unique(citem)); - - } - + for (auto& itemInfo : sdm->m_ItemMaterialData->m_dataMap) + this->_cacheItemData.emplace(itemInfo.ID.ToString(), std::make_unique(itemInfo)); + gmd->waitObject(&sdm->m_ItemConsumeData); - for (int i = 0; i < sdm->m_ItemConsumeData->m_dataMap.Data.Count; i++) - { - ItemConsumeData citem{ sdm->m_ItemConsumeData->m_dataMap.Data[i].Value.Second }; - - _cacheItemData.emplace(citem.GetIdentifier(), std::make_unique(citem)); - } + for (auto& itemInfo : sdm->m_ItemConsumeData->m_dataMap) + this->_cacheItemData.emplace(itemInfo.ID.ToString(), std::make_unique(itemInfo)); gmd->waitObject(&sdm->m_ItemImportantData); - for (int i = 0; i < sdm->m_ItemImportantData->m_dataMap.Data.Count; i++) - { - ItemImportantData citem{ sdm->m_ItemImportantData->m_dataMap.Data[i].Value.Second }; - - _cacheItemData.emplace(citem.GetIdentifier(), std::make_unique(citem)); - } + for (auto& itemInfo : sdm->m_ItemImportantData->m_dataMap) + this->_cacheItemData.emplace(itemInfo.ID.ToString(), std::make_unique(itemInfo)); gmd->waitObject(&sdm->m_ItemWeaponData); - for (int i = 0; i < sdm->m_ItemWeaponData->m_dataMap.Data.Count; i++) - { - ItemWeaponData citem{ sdm->m_ItemWeaponData->m_dataMap.Data[i].Value.Second }; - - _cacheItemData.emplace(citem.GetIdentifier(), std::make_unique(citem)); - } + for (auto& itemInfo : sdm->m_ItemWeaponData->m_dataMap) + this->_cacheItemData.emplace(itemInfo.ID.ToString(), std::make_unique(itemInfo)); gmd->waitObject(&sdm->m_ItemLifeToolsData); - for (int i = 0; i < sdm->m_ItemLifeToolsData->m_dataMap.Data.Count; i++) - { - ItemLifeToolsData citem{ sdm->m_ItemLifeToolsData->m_dataMap.Data[i].Value.Second }; - - _cacheItemData.emplace(citem.GetIdentifier(), std::make_unique(citem)); - } + for (auto& itemInfo : sdm->m_ItemLifeToolsData->m_dataMap) + this->_cacheItemData.emplace(itemInfo.ID.ToString(), std::make_unique(itemInfo)); gmd->waitObject(&sdm->m_ItemArmorData); - for (int i = 0; i < sdm->m_ItemArmorData->m_dataMap.Data.Count; i++) - { - ItemArmorData citem{ sdm->m_ItemArmorData->m_dataMap.Data[i].Value.Second }; - - _cacheItemData.emplace(citem.GetIdentifier(), std::make_unique(citem)); - } + for (auto& itemInfo : sdm->m_ItemArmorData->m_dataMap) + this->_cacheItemData.emplace(itemInfo.ID.ToString(), std::make_unique(itemInfo)); + gmd->waitObject(&sdm->m_ItemCraftData); - for (int i = 0; i < sdm->m_ItemCraftData->m_dataMap.Data.Count; i++) - { - ItemCraftData citem{ sdm->m_ItemCraftData->m_dataMap.Data[i].Value.Second }; - - _cacheItemData.emplace(citem.GetIdentifier(), std::make_unique(citem)); - } + for (auto& itemInfo : sdm->m_ItemCraftData->m_dataMap) + this->_cacheItemData.emplace(itemInfo.ID.ToString(), std::make_unique(itemInfo)); gmd->waitObject(&sdm->m_ItemKitData); - for (int i = 0; i < sdm->m_ItemKitData->m_dataMap.Data.Count; i++) - { - ItemKitData citem{ sdm->m_ItemKitData->m_dataMap.Data[i].Value.Second }; + for (auto& itemInfo : sdm->m_ItemKitData->m_dataMap) + this->_cacheItemData.emplace(itemInfo.ID.ToString(), std::make_unique(itemInfo)); - _cacheItemData.emplace(citem.GetIdentifier(), std::make_unique(citem)); - } gmd->waitObject(&sdm->m_ItemVehicleData); - for (int i = 0; i < sdm->m_ItemVehicleData->m_dataMap.Data.Count; i++) - { - ItemVehicleData citem{ sdm->m_ItemVehicleData->m_dataMap.Data[i].Value.Second }; - - _cacheItemData.emplace(citem.GetIdentifier(), std::make_unique(citem)); - } + for (auto& itemInfo : sdm->m_ItemVehicleData->m_dataMap) + this->_cacheItemData.emplace(itemInfo.ID.ToString(), std::make_unique(itemInfo)); gmd->waitObject(&sdm->m_ItemPowerUpData); - for (int i = 0; i < sdm->m_ItemPowerUpData->m_dataMap.Data.Count; i++) - { - ItemPowerUpData citem{ sdm->m_ItemPowerUpData->m_dataMap.Data[i].Value.Second }; + for (auto& itemInfo : sdm->m_ItemPowerUpData->m_dataMap) + this->_cacheItemData.emplace(itemInfo.ID.ToString(), std::make_unique(itemInfo)); - _cacheItemData.emplace(citem.GetIdentifier(), std::make_unique(citem)); - } + ModLoader::logger->verbose("GameCache: ItemData size: ", this->_cacheItemData.size()); } void GameCache::initRecipe(GameData* gmd, UStaticDataManager* sdm) { gmd->waitObject(&sdm->m_RecipeData); - for (int i = 0; i < sdm->m_RecipeData->m_dataMap.Data.Count; i++) - { - RecipeData recipe{ sdm->m_RecipeData->m_dataMap.Data[i].Value.Second }; + for (auto& recipeInfo : sdm->m_RecipeData->m_dataMap) + this->_cacheRecipeData.emplace(recipeInfo.recipeId.ToString(), std::make_unique(recipeInfo)); - _cacheRecipeData.emplace(recipe.GetIdentifier(), std::make_unique(recipe)); - } + ModLoader::logger->verbose("GameCache: RecipeData size: ", this->_cacheRecipeData.size()); } void GameCache::initChara(GameData* gmd, UStaticDataManager* sdm) { gmd->waitObject(&sdm->m_CharaData); - for (int i = 0; i < sdm->m_CharaData->m_dataMap.Data.Count; i++) - { - CharaData chara{ sdm->m_CharaData->m_dataMap.Data[i].Value.Second }; + for (auto& charaInfo : sdm->m_CharaData->m_dataMap) + this->_cacheCharaData.emplace(charaInfo.ID.ToString(), std::make_unique(charaInfo)); - _cacheCharaData.emplace(chara.GetIdentifier(), std::make_unique(chara)); - } + ModLoader::logger->verbose("GameCache: CharaData size: ", this->_cacheCharaData.size()); } void GameCache::initSubLevel(GameData* gmd, UStaticDataManager* sdm) { gmd->waitObject(&sdm->m_MapSubLevel); - for (int i = 0; i < sdm->m_MapSubLevel->m_dataMap.Data.Count; i++) - { - MapSubLevel level{ sdm->m_MapSubLevel->m_dataMap.Data[i].Value.Second }; + for (auto& levelInfo : sdm->m_MapSubLevel->m_dataMap) + this->_cacheSubLevel.emplace(levelInfo.SubLevelID.ToString(), std::make_unique(levelInfo)); - _cacheSubLevel.emplace(level.GetIdentifier(), std::make_unique(level)); - } + ModLoader::logger->verbose("GameCache: SubLevel size: ", this->_cacheSubLevel.size()); } void GameCache::initMap(GameData* gmd, UStaticDataManager* sdm) { gmd->waitObject(&sdm->m_MapData); - for (int i = 0; i < sdm->m_MapData->m_dataMap.Data.Count; ++i) - { - MapData map{ sdm->m_MapData->m_dataMap.Data[i].Value.Second }; + for (auto& mapInfo : sdm->m_MapData->m_dataMap) + this->_cacheMap.emplace(mapInfo.mapId.ToString(), std::make_unique(mapInfo)); + + ModLoader::logger->verbose("GameCache: MapData size: ", this->_cacheMap.size()); +} + +void GameCache::initAddSkillTable(GameData* gmd, UStaticDataManager* sdm) +{ + gmd->waitObject(&sdm->m_AddSkillLotTable); + for (auto& addSkillInfo : sdm->m_AddSkillLotTable->m_dataMap) + this->_cacheAddSkillLotTable.emplace(addSkillInfo.ID.ToString(), &addSkillInfo.addSkillInfoList); - _cacheMap.emplace(map.GetIdentifier(), std::make_unique(map)); - } + ModLoader::logger->verbose("GameCache: AddSkillLotTable size: ", this->_cacheAddSkillLotTable.size()); } \ No newline at end of file diff --git a/src/GameData.cpp b/src/GameData.cpp index 8829e4d..052d8d2 100644 --- a/src/GameData.cpp +++ b/src/GameData.cpp @@ -1,14 +1,27 @@ #include "GameData.hpp" +#include "API/Engine/FName.hpp" #include "API/Entities/Player/Player.hpp" #include "ModLoader.hpp" #include "Offset.h" +#include "CommonData.hpp" -GameData::GameData(uintptr_t baseAddress) : _staticDataManager(nullptr), _dynamicDataManager(nullptr) { +#ifdef _WIN32 + #include +#else +#endif + +GameData::GameData() : + _staticDataManager(nullptr), + _dynamicDataManager(nullptr) +{ ModLoader::logger->verbose("Initialize GameData"); - this->_baseAddress = baseAddress; - this->_gObjects = reinterpret_cast(this->_baseAddress + GOBJECTS_OFFSET); - this->_gWorld = reinterpret_cast(this->_baseAddress + GWORLD_OFFSET); - this->_gNames = reinterpret_cast(this->_baseAddress + GNAMES_OFFSET); +} + +void GameData::init() +{ + this->_gObjects = reinterpret_cast(CommonData::GetBaseAddress() + GOBJECTS_OFFSET); + this->_gWorld = reinterpret_cast(CommonData::GetBaseAddress() + GWORLD_OFFSET); + this->_gNames = reinterpret_cast(CommonData::GetBaseAddress() + GNAMES_OFFSET); this->waitObject(&this->_gObjects); this->waitObject(&this->_staticDataManager, "StaticDataManager", 1); ModLoader::logger->verbose("Found StaticDataManager => ", std::hex, this->_staticDataManager); @@ -28,12 +41,28 @@ void GameData::initOthersData() { ModLoader::logger->info("OK: GameData has been initialized"); } -Player *GameData::getPlayer() { - return _player.get(); +UObject* GameData::_getUObject(std::string_view name, bool safe, int nth = 0) +{ + FName apiName(name); + + UObject *object = nullptr; + uint32_t counter = 0; + if (safe) + _gObjects->lock(); + for (int i = 0; i < _gObjects->ObjObjects.NumElements; ++i) { + object = _gObjects->getObject(i); + if (object == nullptr) continue; + if (object->NamePrivate == apiName && ++counter > nth) break; + object = nullptr; + } + if (safe) + _gObjects->unlock(); + + return object; } -uintptr_t GameData::getBaseAddress() { - return _baseAddress; +Player *GameData::getPlayer() { + return _player.get(); } FUObjectArray *GameData::getGObjects() { diff --git a/src/Hook/EventHandler.cpp b/src/Hook/EventHandler.cpp index 69aa9ec..32f7e60 100644 --- a/src/Hook/EventHandler.cpp +++ b/src/Hook/EventHandler.cpp @@ -1,10 +1,7 @@ #include "Hook/EventHandler.hpp" #include "Hook/MemoryHelper.hpp" -#include "ModLoader.hpp" #include "SDK.h" -#include - std::unordered_map)>>> EventHandler::_handlers; std::unordered_map EventHandler::_events; diff --git a/src/Hook/MemoryHelper.cpp b/src/Hook/MemoryHelper.cpp index 1ba9b8b..5bd9bdc 100644 --- a/src/Hook/MemoryHelper.cpp +++ b/src/Hook/MemoryHelper.cpp @@ -1,4 +1,5 @@ #include "Hook/MemoryHelper.hpp" +#include uintptr_t MemoryHelper::findFreeMemory(uintptr_t address, uint8_t length) { unsigned char *ptr = (unsigned char *) address; @@ -22,6 +23,25 @@ bool MemoryHelper::isFree(uintptr_t address, uint8_t length) { return true; } +uintptr_t MemoryHelper::findPattern(uintptr_t start, size_t rangeSize, const uint8_t* pattern, const char* mask) { + size_t patternLength = std::strlen(mask); + for (size_t i = 0; i <= rangeSize - patternLength; ++i) { + uintptr_t currentAddress = start + i; + uint8_t* memory = reinterpret_cast(currentAddress); + bool match = true; + for (size_t j = 0; j < patternLength; ++j) { + if (mask[j] == '?') continue; + if (memory[j] != pattern[j]) { + match = false; + break; + } + } + if (match) + return currentAddress; + } + throw std::out_of_range("Pattern not found"); +} + CONTEXT MemoryHelper::getPreviousFrame(CONTEXT originalCtx, uint8_t nth) { DWORD64 imageBase = 0; CONTEXT newContext = originalCtx; diff --git a/src/Hook/Pattern.cpp b/src/Hook/Pattern.cpp new file mode 100644 index 0000000..30d8147 --- /dev/null +++ b/src/Hook/Pattern.cpp @@ -0,0 +1,32 @@ +#include "Hook/Pattern.hpp" +#include "CommonData.hpp" +#include "GameData.hpp" +#include "Hook/MemoryHelper.hpp" +#include "ModLoader.hpp" + +Pattern::Pattern(uint8_t *pattern, const char *mask) : _pattern(pattern), _mask(mask) {} + +size_t Pattern::getSize() +{ + return strlen(_mask); +} + +uint8_t *Pattern::getPattern() +{ + return _pattern; +} + +const char *Pattern::getMask() +{ + return _mask; +} + +uintptr_t Pattern::find(uintptr_t baseAddress, uint32_t range) +{ + return MemoryHelper::findPattern(baseAddress, range, this->_pattern, this->_mask); +} + +uintptr_t Pattern::find(uintptr_t startOffset) +{ + return MemoryHelper::findPattern(CommonData::GetBaseAddress() + startOffset, CommonData::GetSizeImage(), this->_pattern, this->_mask); +} \ No newline at end of file diff --git a/src/Mod/Configuration/ConfigManager.cpp b/src/Mod/Configuration/ConfigManager.cpp new file mode 100644 index 0000000..9d0f698 --- /dev/null +++ b/src/Mod/Configuration/ConfigManager.cpp @@ -0,0 +1,32 @@ +#include "Mod/Configuration/ConfigManager.hpp" +#include +#include + +ConfigManager::ConfigManager(const std::filesystem::path& configPath) : _configPath(configPath) +{ + std::filesystem::create_directories(_configPath); +} + +void ConfigManager::PushConfig(std::string name, std::function registerFunction) +{ + std::lock_guard lock(_mutex); + auto configPath = _configPath / (name + ".json"); + auto config = std::make_shared(name, configPath); + + registerFunction(*config); + + config->Load(); + _configs[name] = config; +} + +void ConfigManager::SaveAll() +{ + for(const auto& [name, config] : _configs) + config->Save(); +} + +void ConfigManager::ReloadAll() +{ + for(const auto& [name, config] : _configs) + config->Reload(); +} diff --git a/src/Mod/Configuration/ModConfig.cpp b/src/Mod/Configuration/ModConfig.cpp new file mode 100644 index 0000000..71ed9a2 --- /dev/null +++ b/src/Mod/Configuration/ModConfig.cpp @@ -0,0 +1,119 @@ +#include "Mod/Configuration/ModConfig.hpp" +#include +#include +#include +#include +#include +#include "Lib/json.hpp" +#include "ModLoader.hpp" + + +void ModConfig::Load() +{ + std::lock_guard lock(_mutex); + + if(!std::filesystem::exists(_configPath)) + { + FinalizeIntialization(); + return; + } + + try + { + std::ifstream file(_configPath); + if(!file.is_open()) + { + ModLoader::logger->error("Failed to open config file: ", _configPath.string()); + + FinalizeIntialization(); + return; + } + + json Json; + file >> Json; + file.close(); + + for(const auto& [path, value] : Json.items()) + { + ApplyLoadedValue(path, value); + } + + FinalizeIntialization(); + } + catch(const json::exception& e) + { + ModLoader::logger->error("JSON parse error in ", _configPath, " ", e.what()); + FinalizeIntialization(); + } +} + +void ModConfig::Save() +{ + std::lock_guard lock(_mutex); + + try + { + std::filesystem::create_directories(_configPath.parent_path()); + json Json = GetAllValues(); + + std::ofstream file(_configPath); + if(!file.is_open()) throw std::runtime_error("Failed to open config file for writing: " + _configPath.string()); + + file << Json.dump(4); + file.close(); + } catch (const std::exception& e) + { + ModLoader::logger->error("Failed to save config ", _configPath, " : ", e.what()); + } +} + +void ModConfig::Reload() +{ + std::lock_guard lock(_mutex); + for(auto& [path, reg] : _registration) + { + _pending.insert(path); + // TODO: Reset the config value and adding a reset method in reg + } + + Load(); +} + +void ModConfig::ApplyLoadedValue(const std::string& path, const json& value) +{ + auto it = _registration.find(path); + if(it != _registration.end()) + { + try + { + it->second.setter(value); + } catch(const json::exception& e) + { + ModLoader::logger->error("Error loading config value '", path, "': ", e.what()); + it->second.setter(it->second.defaultValue); + } + + _pending.erase(path); + } +} + +void ModConfig::FinalizeIntialization() +{ + // Praying on the fact that the mutex is already locked by caller, if not, ngl we are cook + + for(const auto& path : _pending) + { + auto it = _registration.find(path); + if(it != _registration.end()) it->second.setter(it->second.defaultValue); + } + + _pending.clear(); +} + +json ModConfig::GetAllValues() +{ + json Json; + for(const auto& [path, reg] : _registration) Json[path] = reg.getter(); + + return Json; +} \ No newline at end of file diff --git a/src/ModEnvironnement.cpp b/src/Mod/ModEnvironnement.cpp similarity index 62% rename from src/ModEnvironnement.cpp rename to src/Mod/ModEnvironnement.cpp index 88580d5..20c2da9 100644 --- a/src/ModEnvironnement.cpp +++ b/src/Mod/ModEnvironnement.cpp @@ -1,10 +1,8 @@ #include "Mod/ModEnvironnement.hpp" #include "ModLoader.hpp" -#include #include "Mod/ThreadPool.hpp" -#include -#include "Lib/Json.hpp" +#include "Lib/json.hpp" #include "Lib/miniz.h" @@ -108,22 +106,26 @@ void ModEnvironnement::resolveOrder(std::vector mods) _modsList = std::move(sorted); } -bool ModEnvironnement::findModJsonInArchive(const std::filesystem::path& archivePath, std::string& foundPath) +bool ModEnvironnement::findFileInArchive(const std::filesystem::path& archivePath, const std::string& suffix, std::string& foundPath) { mz_zip_archive archive; memset(&archive, 0, sizeof(archive)); - if(!mz_zip_reader_init_file(&archive, archivePath.string().c_str(), 0)) return false; + if(!mz_zip_reader_init_file(&archive, archivePath.string().c_str(), 0)) + return false; mz_uint num = mz_zip_reader_get_num_files(&archive); + const size_t suffixLen = suffix.size(); + for(mz_uint i = 0; i < num; ++i) { mz_zip_archive_file_stat stat; if(!mz_zip_reader_file_stat(&archive, i, &stat)) continue; - if(!stat.m_filename) break; - std::string fname = stat.m_filename; - if(fname.size() >= 8 && fname.substr(fname.size() - 8) == "Mod.json") + const char* fname = stat.m_filename; + size_t fnameLen = strlen(fname); + + if(fnameLen >= suffixLen && strncmp(fname + fnameLen - suffixLen, suffix.c_str(), suffixLen) == 0) { foundPath = fname; mz_zip_reader_end(&archive); @@ -135,32 +137,6 @@ bool ModEnvironnement::findModJsonInArchive(const std::filesystem::path& archive return false; } -bool ModEnvironnement::findModLibInArchive(const std::filesystem::path& archivePath, const std::string& libName, std::string& foundPath) -{ - mz_zip_archive archive; - memset(&archive, 0, sizeof(archive)); - - if(!mz_zip_reader_init_file(&archive, archivePath.string().c_str(), 0)) return false; - mz_uint num = mz_zip_reader_get_num_files(&archive); - for (mz_uint i = 0; i < num; ++i) { - mz_zip_archive_file_stat st; - if (!mz_zip_reader_file_stat(&archive, i, &st)) continue; - if (st.m_filename) { - std::string fname = st.m_filename; - if (fname.size() >= libName.size() && - fname.compare(fname.size() - libName.size(), libName.size(), libName) == 0) - { - foundPath = fname; - mz_zip_reader_end(&archive); - return true; - } - } - } - - mz_zip_reader_end(&archive); - return false; -} - bool ModEnvironnement::readContentFromArchive(const std::filesystem::path& archivePath, const std::string& internalName, std::vector& bufferOut) { mz_zip_archive archive; @@ -178,8 +154,6 @@ bool ModEnvironnement::readContentFromArchive(const std::filesystem::path& archi { mz_zip_archive_file_stat stat; if(!mz_zip_reader_file_stat(&archive, i, &stat)) continue; - if(!stat.m_filename) break; - std::string fname = stat.m_filename; if(fname.size() >= internalName.size() && fname.compare(fname.size() - internalName.size(), internalName.size(), internalName) == 0) { @@ -246,7 +220,7 @@ void ModEnvironnement::SetupEnvironnnement(std::string modDirs) if(entryPath.extension() == ".fliarchive") { std::string modJsonInternal; - if(!findModJsonInArchive(entryPath, modJsonInternal)) + if(!findFileInArchive(entryPath, "Mod.json", modJsonInternal)) { ModLoader::logger->warn("Invalid mod (no metadata) ", entryPath); continue; @@ -269,7 +243,7 @@ void ModEnvironnement::SetupEnvironnnement(std::string modDirs) std::string internalModPath; std::string modLibIdentifier = "CompiledBin.bin"; - if(!findModLibInArchive(entryPath, modLibIdentifier, internalModPath)) + if(!findFileInArchive(entryPath, modLibIdentifier, internalModPath)) { ModLoader::logger->warn("Invalid mod (no content) ", entryPath); continue; @@ -284,99 +258,52 @@ void ModEnvironnement::SetupEnvironnnement(std::string modDirs) void ModEnvironnement::PreLoad() { - const size_t modListSize = _modsList.size(); - size_t numThreads = std::thread::hardware_concurrency(); - if(numThreads == 0) numThreads = 1; - if(numThreads > modListSize) numThreads = modListSize; + _modLibList.reserve(_modsList.size()); + _modPtrList.reserve(_modsList.size()); - ThreadPool pool{numThreads}; - struct Bucket + for (auto* mod : _modsList) { - std::vector libs; - std::vector> mods; - }; + ModMetaData meta = mod->getMeta(); + std::string identifier = meta.identifier; - std::vector buckets(numThreads); - std::atomic nextBucket { 0 }; + std::vector modBuf; + if(!readContentFromArchive(mod->getContainerPath(), mod->getInternalPath(), modBuf)) + { + ModLoader::logger->error("Failed to decompress content from: ", identifier); + continue; + } - std::latch done(static_cast(modListSize)); + std::filesystem::path libOnDiskPath = writeBufferToTemp(modBuf, ".mod"); + if(libOnDiskPath.empty()) + { + ModLoader::logger->error("Failed to write temporary content for ", identifier); + continue; + } - for (auto * mod : _modsList) - { - pool.enqueue([this, &done, mod, &buckets, &nextBucket, numThreads] - { - size_t index = nextBucket.fetch_add(1) % numThreads; - Bucket& bucket = buckets[index]; - - ModMetaData meta = mod->getMeta(); - std::string identifier = meta.identifier; - ModLoader::logger->info("Loading mod: ", identifier, " v", meta.version); - - std::vector modBuf; - if(!readContentFromArchive(mod->getContainerPath(), mod->getInternalPath(), modBuf)) - { - ModLoader::logger->error("Failed to decompressed content from archive from: ", identifier); - done.count_down(); - return; - } - - std::string suffix = ".mod"; - { - std::string intern = mod->getInternalPath(); - size_t pos = intern.find_last_of('.'); - if(pos != std::string::npos) suffix = intern.substr(pos); - } - - std::filesystem::path libOnDiskPath = writeBufferToTemp(modBuf, suffix); - if(libOnDiskPath.empty()) - { - ModLoader::logger->error("Failed to writee temporary content for ", identifier); - done.count_down(); - return; - } - - { - std::lock_guard lg(_mergeMutex); - _tempFilesToRemove.push_back(libOnDiskPath); - } - - LibHandle lib = LoadLib(libOnDiskPath.string()); - if(!lib) - { - ModLoader::logger->error("Failed to load: ", identifier); - done.count_down(); - return; - } - - using GetModFunc = ModBase *(*)(); - auto getter = reinterpret_cast(GetFunction(lib, "CraftMod")); - if(!getter) - { - ModLoader::logger->error("Missing CraftMod in ", identifier); - CloseLib(lib); - done.count_down(); - return; - } - - auto modPtr = std::unique_ptr(getter()); - modPtr->OnPreLoad(); - - bucket.libs.push_back(lib); - bucket.mods.push_back(std::move(modPtr)); - done.count_down(); - } - ); - } + _tempFilesToRemove.push_back(libOnDiskPath); - done.wait(); - - { - std::lock_guard lg(_mergeMutex); - for(auto& bucket : buckets) + LibHandle lib = LoadLib(libOnDiskPath.string()); + if(!lib) { - _modLibList.insert(_modLibList.end(), bucket.libs.begin(), bucket.libs.end()); - for(auto& modPtr : bucket.mods) _modPtrList.push_back(std::move(modPtr)); + ModLoader::logger->error("Failed to load: ", identifier); + continue; } + + using GetModFunc = ModBase *(*)(); + auto getter = reinterpret_cast(GetFunction(lib, "CraftMod")); + if(!getter) + { + ModLoader::logger->error("Missing CraftMod in ", identifier); + CloseLib(lib); + continue; + } + + ModLoader::logger->info("Loading ", identifier, " v", meta.version); + auto modPtr = std::unique_ptr(getter()); + modPtr->OnPreLoad(); + + _modLibList.push_back(lib); + _modPtrList.push_back(std::move(modPtr)); } } @@ -390,7 +317,8 @@ void ModEnvironnement::PostLoad() ThreadPool pool{numThreads}; for(auto& modPtr : _modPtrList) - pool.enqueue([&modPtr]{modPtr->OnPostLoad();}); + + pool.enqueue([&modPtr]{modPtr->OnPostLoad();}); } void ModEnvironnement::Free() @@ -399,10 +327,15 @@ void ModEnvironnement::Free() delete mod; _modsList.clear(); + + for(auto& modPtr : _modPtrList) + modPtr->OnExit(); + _modPtrList.clear(); for(auto lib : _modLibList) CloseLib(lib); + _modLibList.clear(); for(const std::filesystem::path& p : _tempFilesToRemove) diff --git a/src/ModLoader.cpp b/src/ModLoader.cpp index 3284072..f870ab2 100644 --- a/src/ModLoader.cpp +++ b/src/ModLoader.cpp @@ -1,74 +1,101 @@ #include "ModLoader.hpp" +#include "GameCache.hpp" +#include "GameData.hpp" #include "Hook/EventHandler.hpp" +#include "Patcher/Patcher.hpp" +#include "Patcher/Patches/EventHook.hpp" +#include +#include "CommonData.hpp" GameData *ModLoader::gameData = nullptr; GameCache *ModLoader::gameCache = nullptr; Logger *ModLoader::logger = nullptr; ModEnvironnement *ModLoader::modEnvironnement = nullptr; +ConfigManager *ModLoader::configManager = nullptr; -DWORD WINAPI ModLoader::init(LPVOID lpParam) { +void WINAPI ModLoader::init(MODULEINFO* moduleInfo) +{ logger = new Logger("ModLoader"); logger->info("Mod loader has been started"); + + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + Patcher patcher; - uintptr_t baseAddress = (uintptr_t) GetModuleHandle(nullptr); - // patcher.add(new EventHook(EventType::ClickEvent, 0x657DC32)); broken????? + logger->verbose("Dll module is loaded"); + CommonData::init(moduleInfo->SizeOfImage, (uintptr_t) GetModuleHandle(nullptr)); + // Patcher is crashing the game for unknown reasons - disabling for now, waiting @EltyDev to investigate + // patcher.add(new EventHook(EventType::ClickEvent, 0x657DC32)); // patcher.applyPatches(baseAddress); - gameData = new GameData(reinterpret_cast(GetModuleHandle(nullptr))); + + gameData = new GameData(); + gameData->init(); gameCache = new GameCache(); + configManager = new ConfigManager("../../Content/Settings"); modEnvironnement = new ModEnvironnement("../../Content/Mods"); modEnvironnement->PreLoad(); - + gameCache->PostLoadCache(); gameData->initOthersData(); - modEnvironnement->PostLoad(); - return 0; + modEnvironnement->PostLoad(); + logger->verbose("Mod loader initialization complete"); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { - HANDLE LoaderThread = nullptr; + std::thread* loaderThread; switch(ul_reason_for_call) { case DLL_PROCESS_ATTACH: { AllocConsole(); - freopen_s(reinterpret_cast(stdout), "CONOUT$", "w", stdout); freopen_s(reinterpret_cast(stderr), "CONOUT$", "w", stderr); std::cout.clear(); std::cerr.clear(); - Utils::EnableAnsiColors(); - LoaderThread = CreateThread(nullptr, 0, ModLoader::init, nullptr, 0, nullptr); - if (LoaderThread) - CloseHandle(LoaderThread); + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dwMode = 0; + if(GetConsoleMode(hConsole, &dwMode)) + { + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(hConsole, dwMode); + } + + MODULEINFO moduleInfo{}; + GetModuleInformation(GetCurrentProcess(), GetModuleHandle(nullptr), &moduleInfo, sizeof(MODULEINFO)); + loaderThread = new std::thread(ModLoader::init, &moduleInfo); break; } case DLL_PROCESS_DETACH: { ModLoader::logger->verbose("Mod loader detached from process"); - if (LoaderThread) - CloseHandle(LoaderThread); - FreeConsole(); - - if (ModLoader::gameData != nullptr) - delete ModLoader::gameData; - - if(ModLoader::gameCache != nullptr) - delete ModLoader::gameCache; - if(ModLoader::logger != nullptr) - delete ModLoader::logger; + if (ModLoader::configManager) + delete ModLoader::configManager; - if(ModLoader::modEnvironnement != nullptr) + if (ModLoader::modEnvironnement) { ModLoader::modEnvironnement->Free(); delete ModLoader::modEnvironnement; } + if (ModLoader::gameCache) + delete ModLoader::gameCache; + + if (ModLoader::gameData) + delete ModLoader::gameData; + + if (ModLoader::logger) + delete ModLoader::logger; + + if (loaderThread) + loaderThread->join(); + + FreeConsole(); + break; } } diff --git a/src/Utils.cpp b/src/Utils.cpp deleted file mode 100644 index 60db305..0000000 --- a/src/Utils.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "Utils.hpp" -#include "ModLoader.hpp" -#include "GameData.hpp" -#include "GameCache.hpp" - -std::unordered_map Utils::_strings; - -std::string &Utils::FNameToString(uintptr_t baseAddress, FName fname) { - if (_strings.contains(fname.ComparisonIndex)) - return _strings.at(fname.ComparisonIndex); - char name[NAME_BUFFER + 1] = {0}; - const unsigned int chunkOffset = fname.ComparisonIndex >> 16; - const unsigned short nameOffset = fname.ComparisonIndex; - uintptr_t namePoolChunk = *(uintptr_t *) (baseAddress + GNAMES_OFFSET + 8 * (chunkOffset + 2)) + 2 * nameOffset; - const uint16_t nameLength = *(uint16_t *) (namePoolChunk) >> 6; - if (reinterpret_cast(namePoolChunk + 2) == nullptr) - throw std::invalid_argument("namePoolChunk is null."); - memcpy(name, (void *) (namePoolChunk + 2), nameLength < NAME_BUFFER ? nameLength : NAME_BUFFER); - auto result = _strings.emplace(fname.ComparisonIndex, std::string(name)); - return result.first->second; -} - -std::string &Utils::FNameToString(FName fname) { - return FNameToString(ModLoader::gameData->getBaseAddress(), fname); -} - -std::string &Utils::PC_FNameToString(uintptr_t baseAdress, FName fname) -{ - if(_strings.contains(fname.ComparisonIndex)) - return _strings.at(fname.ComparisonIndex); - - char name[NAME_BUFFER + 1] = { 0 }; - const unsigned int chunkOffset = fname.ComparisonIndex >> 16; - const unsigned short nameOffset = fname.ComparisonIndex; - - uintptr_t namePoolChunk = *(uintptr_t *) (baseAdress + GNAMES_OFFSET + 8 * (chunkOffset +2 )) + 4 * nameOffset; - const uint16_t nameLength = (*(uint16_t *) (namePoolChunk) + 4) >> 1; - if(reinterpret_cast(namePoolChunk + 6) == nullptr) - throw std::invalid_argument("namePoolChunk is null..."); - - memcpy(name, (void*) (namePoolChunk + 6), nameLength < NAME_BUFFER ? nameLength : NAME_BUFFER); - auto result = _strings.emplace(fname.ComparisonIndex, std::string(name)); - return result.first->second; -} - -std::string &Utils::PC_FNameToString(FName fname) -{ - return PC_FNameToString(ModLoader::gameData->getBaseAddress(), fname); -} - -void Utils::EnableAnsiColors() -{ - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - if(hConsole == INVALID_HANDLE_VALUE) return; - - DWORD dwMode = 0; - if(!GetConsoleMode(hConsole, &dwMode)) return; - - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - SetConsoleMode(hConsole, dwMode); -} \ No newline at end of file