diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..79d66374 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,146 @@ +name: Build + +on: + push: + branches: ["**"] + tags: ["v*.*.*"] + pull_request: + workflow_dispatch: + +jobs: + build: + runs-on: windows-2022 + + strategy: + fail-fast: false + matrix: + configuration: [Release, Debug] + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + # ------------------------------------------------------------------- + # Install v141 (VS 2017) toolset and WinXP support on the runner. + # The WinXP component provides the v141_xp toolset required by premake. + # ------------------------------------------------------------------- + - name: Install v141_xp toolset + shell: cmd + run: | + "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\setup.exe" modify ^ + --passive --norestart ^ + --installPath "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" ^ + --add Microsoft.VisualStudio.Component.VC.v141.x86.x64 ^ + --add Microsoft.VisualStudio.Component.WinXP + # Timeout ocasional é esperado; o step falha limpo se o installer + # retornar código != 0, o que torna o problema visível nos logs. + + # ------------------------------------------------------------------- + # Generate VS2015 project files using Premake (premake5.exe included + # in the repository). + # Premake sets PlatformToolset=v140_xp in the .vcxproj files; this is + # overridden when invoking MSBuild below without modifying premake5.lua. + # ------------------------------------------------------------------- + - name: Generate project files (vs2015) + shell: cmd + run: premake5.exe vs2015 --outdir=build_temp + + # ------------------------------------------------------------------- + # Configure MSVC environment for toolset 14.16 (VS 2017 / v141). + # Required so msbuild can locate the correct compiler and toolset. + # ------------------------------------------------------------------- + - name: Setup MSVC environment (v141) + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x86 + toolset: 14.16 # toolset do VS 2017 + + # ------------------------------------------------------------------- + # Build and override PlatformToolset to v141_xp via MSBuild. + # MSBuild command-line properties passed with /p: take precedence over + # project file values. v141_xp is the v141 toolset variant that provides + # WinXP support. + # /m -> enable parallel build using all available cores. + # /v:m -> minimal verbosity for concise logs. + # ------------------------------------------------------------------- + - name: Build (${{ matrix.configuration }}) + shell: cmd + run: | + msbuild build_temp\modloader.sln ^ + /p:Configuration=${{ matrix.configuration }} ^ + /p:Platform=Win32 ^ + /p:PlatformToolset=v141_xp ^ + /m /v:m + + # ------------------------------------------------------------------- + # Collect generated binaries. + # Premake output layout: bin/ (modloader.asi) and + # bin/plugins/gta3/*.dll for plugins. + # ------------------------------------------------------------------- + - name: Collect artifacts + shell: pwsh + run: | + $cfg = "${{ matrix.configuration }}" + $dest = "artifacts\modloader-$cfg" + + # Main ASI binary + New-Item -ItemType Directory -Force -Path "$dest" | Out-Null + Copy-Item "bin\modloader.asi" "$dest\" -ErrorAction SilentlyContinue + + # GTA3 plugins + $pluginSrc = "bin\plugins\gta3" + if (Test-Path $pluginSrc) { + New-Item -ItemType Directory -Force -Path "$dest\plugins\gta3" | Out-Null + Copy-Item "$pluginSrc\*.dll" "$dest\plugins\gta3\" -ErrorAction SilentlyContinue + } + + # PDB files (placed with binaries in the same directory) + Copy-Item "bin\*.pdb" "$dest\" -ErrorAction SilentlyContinue + Copy-Item "bin\plugins\gta3\*.pdb" "$dest\plugins\gta3\" -ErrorAction SilentlyContinue + + # Example docs and configuration files + Copy-Item "doc\config\*.ini.0" "$dest\" -ErrorAction SilentlyContinue + Copy-Item "doc\CHANGELOG.md" "$dest\" -ErrorAction SilentlyContinue + Copy-Item "LICENSE" "$dest\" -ErrorAction SilentlyContinue + + Write-Host "=== Artifacts ===" + Get-ChildItem -Recurse $dest | Select-Object FullName + + - name: Upload artifact – ${{ matrix.configuration }} + uses: actions/upload-artifact@v4 + with: + name: modloader-${{ matrix.configuration }}-${{ github.sha }} + path: artifacts\modloader-${{ matrix.configuration }}\ + if-no-files-found: error + retention-days: 30 + + # ----------------------------------------------------------------------- + # Extra job: create a GitHub Release when a tag matching v*.*.* is pushed. + # Runs only if the build (Release) job completed successfully. + # ----------------------------------------------------------------------- + release: + if: startsWith(github.ref, 'refs/tags/v') + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Download Release artifact + uses: actions/download-artifact@v4 + with: + name: modloader-Release-${{ github.sha }} + path: dist/ + + - name: Zip release + run: | + cd dist + zip -r ../modloader-${{ github.ref_name }}.zip . + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: modloader-${{ github.ref_name }}.zip + generate_release_notes: true diff --git a/src/core/config.cpp b/src/core/config.cpp index dd953f38..37d4731b 100644 --- a/src/core/config.cpp +++ b/src/core/config.cpp @@ -242,7 +242,7 @@ void Loader::UpdateOldConfig_0115_021() for(auto& kv : newer["Priority"]) { auto pr = std::stoi(kv.second); - kv.second = std::to_string(pr > 0 && pr <= 100? 101 - pr : pr); + kv.second = std::to_string(pr > 0 && pr <= priority_limit? (priority_limit + 1) - pr : pr); } newer.write_file(gamePath + "modloader/" + folderConfigFilename); diff --git a/src/core/extras/gta3/menu.cpp b/src/core/extras/gta3/menu.cpp index 186ed6c8..7f42be49 100644 --- a/src/core/extras/gta3/menu.cpp +++ b/src/core/extras/gta3/menu.cpp @@ -610,7 +610,7 @@ void TheMenu::ModPageEvents() // Helper function to setup a integer priority entry in the menu auto SetupPriorityEntry = [this](const char* label, uint32_t& priority, std::function cb) -> std::function { - static const uint32_t min = 0, max = 100, step = 1; + static const uint32_t min = 0, max = priority_limit, step = 1; auto PriorityLabel = [](const uint32_t& priority) { diff --git a/src/core/loader.hpp b/src/core/loader.hpp index 2728ad39..8160dd62 100644 --- a/src/core/loader.hpp +++ b/src/core/loader.hpp @@ -34,6 +34,8 @@ static const char* downurl = "https://github.com/thelink2012/modloader/releases" // static const char* default_profile_name = "Default"; +static const int priority_limit = 9999; + // Functor for sorting based on priority template struct SimplePriorityPred diff --git a/src/core/profiles.cpp b/src/core/profiles.cpp index 94915281..dda4b729 100644 --- a/src/core/profiles.cpp +++ b/src/core/profiles.cpp @@ -256,7 +256,7 @@ void Loader::Profile::SetPriority(std::string name, int priority) if(priority == default_priority) mods_priority.erase(name); else - mods_priority[name] = std::max(std::min(priority, 100), 0); // clamp to 0-100 + mods_priority[name] = std::max(std::min(priority, priority_limit), 0); // clamp to 0-priority_limit } /* diff --git a/src/plugins/gta3/std.asi/args_translator/translator_stdcall.hpp b/src/plugins/gta3/std.asi/args_translator/translator_stdcall.hpp index 5e897635..5a8c384c 100644 --- a/src/plugins/gta3/std.asi/args_translator/translator_stdcall.hpp +++ b/src/plugins/gta3/std.asi/args_translator/translator_stdcall.hpp @@ -9,6 +9,8 @@ #ifndef ARGS_TRANSLATOR_STDCALL_HPP #define ARGS_TRANSLATOR_STDCALL_HPP +#include + #include "translator_basic.hpp" diff --git a/src/plugins/gta3/std.data/cache.hpp b/src/plugins/gta3/std.data/cache.hpp index deef90f8..23f82a09 100644 --- a/src/plugins/gta3/std.data/cache.hpp +++ b/src/plugins/gta3/std.data/cache.hpp @@ -381,25 +381,29 @@ class data_cache : public modloader::basic_cache using stream_type = typename std::conditional::type; using archive_type = typename std::conditional::type; - stream_type ss; + try { + stream_type ss; - std::unique_ptr buffer(new char[buffer_size]); - ss.rdbuf()->pubsetbuf(buffer.get(), buffer_size); + std::unique_ptr buffer(new char[buffer_size]); + ss.rdbuf()->pubsetbuf(buffer.get(), buffer_size); - ss.open(filepath, std::ios::binary); - if(ss.is_open()) - { - uint32_t version = build_identifier(); // This variable won't change in the case of a output stream, - // but will in the case of a input stream, in any case default initialize for the output case - archive_type archive(ss); - archive(version); - if(version == build_identifier()) // Make sure serialization version matches + ss.open(filepath, std::ios::binary); + if(ss.is_open()) { - func(ss, archive); - return true; + uint32_t version = build_identifier(); // This variable won't change in the case of a output stream, + // but will in the case of a input stream, in any case default initialize for the output case + archive_type archive(ss); + archive(version); + if(version == build_identifier()) // Make sure serialization version matches + { + func(ss, archive); + return true; + } + else + plugin_ptr->Log("Warning: Incompatible cache version, a new cache will be generated."); } - else - plugin_ptr->Log("Warning: Incompatible cache version, a new cache will be generated."); + } catch (const std::exception &e) { + plugin_ptr->Log("Error: Failed to perform cache operation: %s on %s", e.what(), filepath.c_str()); } return false; } diff --git a/src/plugins/gta3/std.data/main.cpp b/src/plugins/gta3/std.data/main.cpp index 69985228..38022f62 100644 --- a/src/plugins/gta3/std.data/main.cpp +++ b/src/plugins/gta3/std.data/main.cpp @@ -638,15 +638,20 @@ auto DataPlugin::ReadCachedReadmeListing() -> readme_listing_type { readme_listing_type cached_readme_listing; - std::ifstream ss(cache.GetCachePath("readme.ld"), std::ios::binary); - if(ss.is_open()) - { - cereal::BinaryInputArchive archive(ss); - if(VerifyCachedReadme(ss, archive)) + try { + std::ifstream ss(cache.GetCachePath("readme.ld"), std::ios::binary); + if(ss.is_open()) { - block_reader listing_block(ss); - archive(cached_readme_listing); + cereal::BinaryInputArchive archive(ss); + if(VerifyCachedReadme(ss, archive)) + { + block_reader listing_block(ss); + archive(cached_readme_listing); + } } + } catch(const std::exception& e) { + this->Log("Error: Failed to read cached readme listing: {}", e.what()); + cached_readme_listing.clear(); } return cached_readme_listing; } @@ -659,16 +664,21 @@ auto DataPlugin::ReadCachedReadmeStore() -> readme_data_store { readme_data_store store_lines; - std::ifstream ss(cache.GetCachePath("readme.ld"), std::ios::binary); - if(ss.is_open()) - { - cereal::BinaryInputArchive archive(ss); - if(VerifyCachedReadme(ss, archive)) + try { + std::ifstream ss(cache.GetCachePath("readme.ld"), std::ios::binary); + if(ss.is_open()) { - block_reader::skip(ss); // skip listing block - block_reader lines_block(ss); - archive(store_lines); + cereal::BinaryInputArchive archive(ss); + if(VerifyCachedReadme(ss, archive)) + { + block_reader::skip(ss); // skip listing block + block_reader lines_block(ss); + archive(store_lines); + } } + } catch(const std::exception& e) { + this->Log("Error: Failed to read cached readme store: {}", e.what()); + store_lines.clear(); } return store_lines; }