Files
SpartanPort/tests/test_orb_multiplier.cpp
Felipe Prado 226fb0e969 Refactor(Branding): renamed the project to SpartanPort (#755)
EN-US

- Renamed code, binaries, packaging, CI and docs to SpartanPort, with the SP monogram and the SpartanPort logo
- Renamed only the names in the shadPS4 core and the FSR patch, keeping authors, dates and licenses
- Added scripts/legacy.py, the only place with the former name, kept for three releases
- Added a one-time copy of the game settings, the launcher settings and the Linux data folder from their former names, without overwriting or deleting anything
- Updated the Linux data move to leave the GPU caches (user/cache) and the run views (out/) in the former folder
- Added forwarding of the former GOW3_ variables to SPARTAN_
- Added the launcher under its former names, so the 2.5.0 updater and existing shortcuts keep working
- Added a note to the READMEs that the project was gow3_pc and that 2.5.0 players keep their saves and settings
- Passed the full Python suite (531 tests, 0 failures) and the Windows zip and Linux AppImage CI builds

---

PT-BR

- Renomeados código, executáveis, empacotamento, CI e docs para SpartanPort, com o monograma SP e o logotipo SpartanPort
- Renomeados só os nomes no núcleo do shadPS4 e no patch do FSR, mantendo autores, datas e licenças
- Adicionado o scripts/legacy.py, único lugar com o nome antigo, mantido por três releases
- Adicionada a cópia única das configurações do jogo, das configurações do launcher e da pasta de dados do Linux a partir dos nomes antigos, sem sobrescrever nem apagar nada
- Atualizada a migração da pasta de dados do Linux para deixar os caches da GPU (user/cache) e as pastas de execução (out/) na pasta antiga
- Adicionado o repasse das variáveis GOW3_ antigas para SPARTAN_
- Adicionado o launcher com os nomes antigos, para que o atualizador da 2.5.0 e os atalhos existentes continuem funcionando
- Adicionada aos READMEs a nota de que o projeto era o gow3_pc e de que jogadores da 2.5.0 mantêm saves e configurações
- Aprovadas a suíte Python completa (531 testes, 0 falhas) e as builds de CI do zip do Windows e da AppImage do Linux
2026-10-19 18:18:13 -03:00

120 lines
4.8 KiB
C++

#include <cassert>
#include <cmath>
#include <limits>
#include "spartanport_orbs.h"
#include "../src/orb_hook.h"
#include <vector>
#include <array>
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include "spartanport_settings.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#endif
extern "C" float __attribute__((sysv_abi)) spartanport_orbs_gain(void*, float);
extern "C" void spartanport_orbs_status(int);
extern "C" void spartanport_cheat_status(unsigned);
static void __attribute__((sysv_abi)) Setter(void* player, float balance) {
balance = std::min(balance, 999999.0f);
std::memcpy(static_cast<unsigned char*>(player) + 0x1e8, &balance, 4);
}
int main(int argc, char** argv) {
assert(SpartanOrbs::Scale(100, 110, 2) == 120);
assert(SpartanOrbs::Scale(100, 90, 100) == 90);
assert(SpartanOrbs::Scale(100, 100, 100) == 100);
assert(SpartanOrbs::Scale(100, 110, 1) == 110);
assert(SpartanOrbs::Scale(0, 1, 100) == 100);
float balance = 0;
for (int i = 0; i < 10; ++i) balance = SpartanOrbs::Scale(balance, balance + 1, 0.1f);
assert(std::abs(balance - 1) < 0.00001f);
assert(SpartanOrbs::Scale(balance, balance + 2, 2) == balance + 4);
assert(SpartanOrbs::Scale(100, 110, std::numeric_limits<float>::quiet_NaN()) == 110);
assert(SpartanOrbs::ClampMultiplier(0) == 0.1f);
assert(SpartanOrbs::ClampMultiplier(101) == 100);
assert(SpartanOrbs::ClampMultiplier(std::numeric_limits<float>::infinity()) == 1);
std::vector<unsigned char> image(0x6fbdc);
uint64_t calls[3];
assert(spartanport_orb_find(image.data(), image.size(), calls) == UINT64_MAX);
assert(spartanport_orb_find(image.data(), 1, calls) == UINT64_MAX);
if (argc > 1) {
FILE* file = std::fopen(argv[1], "rb");
assert(file && !std::fseek(file, 0x4000, SEEK_SET));
assert(std::fread(image.data(), 1, image.size(), file) == image.size());
std::fclose(file);
assert(spartanport_orb_find(image.data(), image.size(), calls) == 0x6a9f0);
image[calls[1] + 1] ^= 1;
assert(spartanport_orb_find(image.data(), image.size(), calls) == UINT64_MAX);
}
#ifdef _WIN32
auto* stub = static_cast<unsigned char*>(VirtualAlloc(nullptr, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
#else
auto* stub = static_cast<unsigned char*>(mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
assert(stub != MAP_FAILED);
#endif
assert(stub);
spartanport_orb_build_stub(stub, reinterpret_cast<uintptr_t>(spartanport_orbs_gain), reinterpret_cast<uintptr_t>(Setter));
#ifdef _WIN32
DWORD previous;
assert(VirtualProtect(stub, 4096, PAGE_EXECUTE_READ, &previous));
FlushInstructionCache(GetCurrentProcess(), stub, 26);
#else
assert(!mprotect(stub, 4096, PROT_READ | PROT_EXEC));
#endif
using Hook = void (__attribute__((sysv_abi)) *)(void*, float);
auto hook = reinterpret_cast<Hook>(stub);
std::array<unsigned char, 0x200> player{};
balance = 100;
std::memcpy(player.data() + 0x1e8, &balance, 4);
auto& settings = SpartanSettings::Get();
settings.red_orb_multiplier = 2;
hook(player.data(), 110);
std::memcpy(&balance, player.data() + 0x1e8, 4);
assert(balance == 120);
settings.cheats[4] = true;
assert(spartanport_orbs_gain(player.data(), 130) == 140);
spartanport_cheat_status(4);
assert(spartanport_orbs_gain(player.data(), 130) == 130);
settings.cheats[4] = false;
assert(spartanport_orbs_gain(player.data(), 130) == 140);
settings.red_orb_multiplier = 100;
hook(player.data(), 90);
std::memcpy(&balance, player.data() + 0x1e8, 4);
assert(balance == 90);
hook(player.data(), 100000);
std::memcpy(&balance, player.data() + 0x1e8, 4);
assert(balance == 999999);
spartanport_orbs_status(1);
assert(settings.red_orbs_supported);
spartanport_orbs_status(0);
assert(!settings.red_orbs_supported);
auto config = std::filesystem::temp_directory_path() / "spartanport-orb-multiplier-test.ini";
assert(!std::filesystem::exists(config));
#ifdef _WIN32
_putenv_s("SPARTAN_CONFIG", config.string().c_str());
#else
setenv("SPARTAN_CONFIG", config.string().c_str(), 1);
#endif
settings.red_orb_multiplier = 0.125f;
settings.cheats[0] = true;
settings.cheats[2] = true;
SpartanSettings::Save();
settings.red_orb_multiplier = 1;
settings.cheats[0] = false;
settings.cheats[2] = false;
SpartanSettings::Load();
assert(settings.red_orb_multiplier == 0.125f);
assert(settings.cheats[0] && settings.cheats[2] && !settings.cheats[1] && !settings.cheats[4]);
assert(std::filesystem::remove(config));
#ifdef _WIN32
VirtualFree(stub, 0, MEM_RELEASE);
#else
munmap(stub, 4096);
#endif
std::puts("orb-multiplier-test: OK (gains, spending, fractions, signatures, executable hook)");
}