mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Reconcile current master with validated X4 co-op support for PR23 playtest
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "mod_runtime.h"
|
||||
#include "mod_netplay.h"
|
||||
#include "host_launch_timing.h"
|
||||
#include "host_file_identity.h"
|
||||
#include "mod_packages.h"
|
||||
@@ -30,6 +31,8 @@ static int failures;
|
||||
static int activation_calls;
|
||||
static int plugin_calls;
|
||||
static int restore_calls;
|
||||
static int option_renderer_activations;
|
||||
static void option_renderer_activate(void) { ++option_renderer_activations; }
|
||||
static PsxLobbyMatchCaps test_match_caps;
|
||||
extern "C" const PsxLobbyMatchCaps* psx_lobby_match_caps(void) {
|
||||
return &test_match_caps;
|
||||
@@ -403,7 +406,7 @@ static uint64_t startup_counter(const char* requested) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int main(int argc, char** argv) {
|
||||
#if defined(PSX_LAUNCHER_MOD_COMMIT_WORKER_SAFE)
|
||||
const fs::path root = fs::temp_directory_path() / "psxrecomp-mod-runtime-cache-test";
|
||||
const auto isolated_cache = root / "test-cache";
|
||||
@@ -478,6 +481,10 @@ int main() {
|
||||
"[[feature]]\n"
|
||||
"id = \"vblank-plugin\"\n"
|
||||
"name = \"VBlank Plugin\"\n"
|
||||
"[[option]]\nfeature = \"vblank-plugin\"\nid = \"cameras\"\n"
|
||||
"label = \"Cameras\"\ntype = \"choice\"\ndefault = \"unified\"\n"
|
||||
"[[option.choice]]\nvalue = \"unified\"\nlabel = \"Unified\"\n"
|
||||
"[[option.choice]]\nvalue = \"split\"\nlabel = \"Split\"\n"
|
||||
"[[option]]\n"
|
||||
"feature = \"dynamic-main\"\n"
|
||||
"id = \"count\"\n"
|
||||
@@ -1780,6 +1787,173 @@ int main() {
|
||||
check(!PSXRecompV4::mod_runtime_try_prepare_cached(iso_path), "default runtime does not opt into cached startup");
|
||||
}
|
||||
#endif
|
||||
/* The executable-owned profile forces its trusted plugin, including hooks,
|
||||
* without applying/saving any player's offline patches or selections. */
|
||||
test_match_caps = {};
|
||||
const bool missing_profile = argc > 1 && std::string(argv[1]) == "--missing-profile";
|
||||
const bool missing_renderer = argc > 1 && std::string(argv[1]) == "--missing-renderer";
|
||||
const bool option_renderer_missing = argc > 1 && std::string(argv[1]) == "--option-renderer-missing";
|
||||
const bool profile_options = option_renderer_missing ||
|
||||
(argc > 1 && std::string(argv[1]) == "--profile-options");
|
||||
static const PSXModNetplayProfile profile = {
|
||||
missing_profile ? "runtime.missing-simulation" : "runtime.test-vblank",
|
||||
"runtime-coop-delay-v1", 0, 0, 1, 3u,
|
||||
profile_options ? "runtime.option-renderer" : "runtime.missing-renderer", nullptr, 0,
|
||||
profile_options ? "runtime.test" : nullptr,
|
||||
profile_options ? "vblank-plugin" : nullptr,
|
||||
profile_options ? "cameras" : nullptr,
|
||||
profile_options ? "split" : nullptr
|
||||
};
|
||||
if (profile_options && !option_renderer_missing)
|
||||
check(psx_mod_register_activation_plugin("runtime.option-renderer", option_renderer_activate),
|
||||
"profile option renderer registration");
|
||||
check(psx_mod_register_netplay_profile(&profile), "trusted profile registration");
|
||||
check(PSXRecompV4::mod_runtime_initialize(root, "SLUS-RUNTIME", 0x80002000, {}, &error),
|
||||
"profile reinitialize offline catalog");
|
||||
if (missing_profile || missing_renderer || option_renderer_missing) {
|
||||
if (missing_renderer) check(psx_mod_netplay_set_aspect(1), "select profile renderer");
|
||||
if (option_renderer_missing) {
|
||||
test_match_caps.valid = 1;
|
||||
test_match_caps.mod_count = 1;
|
||||
std::strcpy(test_match_caps.mods[0].id, "runtime.test");
|
||||
std::strcpy(test_match_caps.mods[0].ver, "1.0.0");
|
||||
std::strcpy(test_match_caps.mods[0].feats, "vblank-plugin=cameras~split");
|
||||
std::string fingerprint;
|
||||
check(PSXRecompV4::mod_runtime_netplay_settings_fingerprint(test_match_caps, fingerprint, &error),
|
||||
"missing renderer offer still has a valid settings identity");
|
||||
std::strcpy(test_match_caps.mod_plan_fp, fingerprint.c_str());
|
||||
}
|
||||
check(!PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error) &&
|
||||
!psx_mod_netplay_is_active() && !error.empty(),
|
||||
"missing trusted plugin refuses profile activation with a reason");
|
||||
check(psx_mod_netplay_savestates_supported(), "failed profile cannot latch snapshot policy");
|
||||
const auto before_failed_activation = activation_calls;
|
||||
mod_runtime_activate_plugins();
|
||||
check(activation_calls == before_failed_activation, "failed profile cannot activate stale offline plugin");
|
||||
fs::remove_all(root, ec);
|
||||
return failures ? 1 : 0;
|
||||
}
|
||||
const auto selection_path = root / "state.toml";
|
||||
auto read_selection = [&]() {
|
||||
std::ifstream file(selection_path, std::ios::binary);
|
||||
return std::string(std::istreambuf_iterator<char>(file), {});
|
||||
};
|
||||
std::string offline_selection = read_selection();
|
||||
check(PSXRecompV4::mod_runtime_commit_for_direct_netplay(iso_path, &error), error.c_str());
|
||||
check(psx_mod_netplay_is_active() && !psx_mod_netplay_savestates_supported(),
|
||||
"profile activates host-state snapshot policy");
|
||||
const int activations_before = activation_calls;
|
||||
mod_runtime_activate_plugins();
|
||||
check(activation_calls == activations_before + 1, "profile forces native plugin activation");
|
||||
ram[0x1000] = 0x5a;
|
||||
mod_runtime_on_dispatch(0x80002000);
|
||||
check(ram[0x1000] == 0x5a, "profile excludes offline executable writes");
|
||||
check(psx_mod_read_disc_file("S0/LEVEL.NSF", result.data(), 3000, &bytes) && bytes == 3000,
|
||||
"profile retains original-disc reads");
|
||||
check(read_selection() == offline_selection, "profile does not save temporary selections");
|
||||
check(PSXRecompV4::mod_runtime_commit_netplay_view(iso_path, &error), "profile rematch commit");
|
||||
mod_runtime_activate_plugins();
|
||||
check(activation_calls == activations_before + 2, "profile rematch activates exactly once");
|
||||
CPUState profile_cpu{};
|
||||
test_netplay_active = 1;
|
||||
filter_handles = true;
|
||||
check(psx_mod_function_entry(&profile_cpu, 0x80003008) && profile_cpu.gpr[2] == 42u,
|
||||
"profile retains modern trusted function filters");
|
||||
test_netplay_active = 0;
|
||||
test_match_caps.valid = 1;
|
||||
test_match_caps.mod_count = 1;
|
||||
check(!PSXRecompV4::mod_runtime_commit_for_netplay(iso_path, &error) &&
|
||||
!psx_mod_netplay_is_active(), "profile rejects imported package plans");
|
||||
test_match_caps = {};
|
||||
check(PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error), "profile restores after rejected plan");
|
||||
if (profile_options) {
|
||||
char value[32], unified_identity[65], split_identity[65];
|
||||
check(psx_mod_option_value("runtime.test", "vblank-plugin", "cameras", value, sizeof(value)) &&
|
||||
std::string(value) == "unified", "profile includes default camera option");
|
||||
check(psx_mod_netplay_content_identity("", unified_identity), "default profile content identity");
|
||||
test_match_caps.valid = 1;
|
||||
test_match_caps.mod_count = 1;
|
||||
std::strcpy(test_match_caps.mods[0].id, "runtime.test");
|
||||
std::strcpy(test_match_caps.mods[0].ver, "1.0.0");
|
||||
std::strcpy(test_match_caps.mods[0].feats, "vblank-plugin=cameras~split");
|
||||
std::string fingerprint;
|
||||
check(PSXRecompV4::mod_runtime_netplay_settings_fingerprint(test_match_caps, fingerprint, &error) &&
|
||||
fingerprint == "24a3aeaf6034d1a59df3ac27334227343237550d4938b7b00c6ae77dfec21367",
|
||||
"published settings fingerprint matches the canonical codec fixture");
|
||||
char preview_identity[65];
|
||||
check(psx_mod_netplay_content_identity("", preview_identity) &&
|
||||
std::string(preview_identity) == unified_identity && read_selection() == offline_selection,
|
||||
"offer preview does not mutate the active profile or preferences");
|
||||
check(!PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error), "missing settings fingerprint rejected");
|
||||
std::strcpy(test_match_caps.mod_plan_fp, fingerprint.c_str());
|
||||
test_match_caps.mod_plan_fp[0] = '0';
|
||||
check(!PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error), "tampered settings fingerprint rejected");
|
||||
std::strcpy(test_match_caps.mod_plan_fp, fingerprint.c_str());
|
||||
check(PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error), error.c_str());
|
||||
mod_runtime_activate_plugins();
|
||||
check(psx_mod_option_value("runtime.test", "vblank-plugin", "cameras", value, sizeof(value)) &&
|
||||
std::string(value) == "split", "profile adopts host split camera option");
|
||||
check(option_renderer_activations == 1, "split activates the declared renderer at native aspect");
|
||||
check(psx_mod_netplay_content_identity("", split_identity) &&
|
||||
std::string(split_identity) != unified_identity, "different camera policies cannot handshake");
|
||||
check(read_selection() == offline_selection, "host options do not persist over offline choices");
|
||||
std::strcpy(test_match_caps.mods[0].feats, "vblank-plugin=cameras~unified");
|
||||
check(!PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error), "changed options with stale fingerprint rejected");
|
||||
check(PSXRecompV4::mod_runtime_netplay_settings_fingerprint(test_match_caps, fingerprint, &error),
|
||||
"unified offer fingerprint");
|
||||
std::strcpy(test_match_caps.mod_plan_fp, fingerprint.c_str());
|
||||
check(PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error), error.c_str());
|
||||
mod_runtime_activate_plugins();
|
||||
check(option_renderer_activations == 1, "unified does not activate the option renderer");
|
||||
const char* rejected[] = {"dynamic-main", "vblank-plugin,dynamic-main",
|
||||
"vblank-plugin=cameras~invalid", "vblank-plugin=unknown~split"};
|
||||
for (const char* token : rejected) {
|
||||
std::strcpy(test_match_caps.mods[0].feats, token);
|
||||
check(!PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error) &&
|
||||
!psx_mod_netplay_is_active(), "profile rejects undeclared host policy");
|
||||
}
|
||||
std::strcpy(test_match_caps.mods[0].feats, "vblank-plugin=cameras~split");
|
||||
test_match_caps.mod_count = 2;
|
||||
check(!PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error), "profile rejects extra packages");
|
||||
test_match_caps.mod_count = 1;
|
||||
std::strcpy(test_match_caps.mods[0].ver, "different-version");
|
||||
check(!PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error), "profile rejects different package versions");
|
||||
std::strcpy(test_match_caps.mods[0].ver, "1.0.0");
|
||||
std::strcpy(test_match_caps.mods[0].id, "different-package");
|
||||
check(!PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error), "profile rejects unrelated settings packages");
|
||||
test_match_caps = {};
|
||||
check(PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error), "profile recovers after rejected options");
|
||||
check(read_selection() == offline_selection, "all settings commits preserve offline state");
|
||||
PSXRecompV4::mod_runtime_end_netplay();
|
||||
PSXRecompV4::ModPackageManager preferences(root);
|
||||
check(preferences.scan(&error) && preferences.load_state(&error) &&
|
||||
preferences.set_feature_option("runtime.test", "vblank-plugin", "cameras", "split", &error) &&
|
||||
preferences.save_state(&error), "explicit local split preference");
|
||||
offline_selection = read_selection();
|
||||
check(PSXRecompV4::mod_runtime_initialize(root, "SLUS-RUNTIME", 0x80002000, {}, &error),
|
||||
"profile reloads the explicit local preference");
|
||||
check(PSXRecompV4::mod_runtime_commit_for_direct_netplay(iso_path, &error), error.c_str());
|
||||
check(psx_mod_option_value("runtime.test", "vblank-plugin", "cameras", value, sizeof(value)) &&
|
||||
std::string(value) == "split", "direct sessions use the local agreed preference");
|
||||
check(psx_mod_netplay_content_identity("", split_identity) &&
|
||||
std::string(split_identity) != unified_identity, "direct option identity covers camera policy");
|
||||
test_match_caps.valid = 1;
|
||||
test_match_caps.mod_count = 1;
|
||||
std::strcpy(test_match_caps.mods[0].id, "runtime.test");
|
||||
std::strcpy(test_match_caps.mods[0].ver, "1.0.0");
|
||||
std::strcpy(test_match_caps.mods[0].feats, "vblank-plugin");
|
||||
check(PSXRecompV4::mod_runtime_netplay_settings_fingerprint(test_match_caps, fingerprint, &error),
|
||||
"default host offer fingerprint");
|
||||
std::strcpy(test_match_caps.mod_plan_fp, fingerprint.c_str());
|
||||
check(PSXRecompV4::mod_runtime_commit_netplay(iso_path, &error), error.c_str());
|
||||
check(psx_mod_option_value("runtime.test", "vblank-plugin", "cameras", value, sizeof(value)) &&
|
||||
std::string(value) == "unified", "omitted host options use defaults rather than guest preferences");
|
||||
check(read_selection() == offline_selection, "host defaults preserve the guest's split preference");
|
||||
}
|
||||
PSXRecompV4::mod_runtime_end_netplay();
|
||||
check(!psx_mod_netplay_is_active() && psx_mod_netplay_savestates_supported() &&
|
||||
PSXRecompV4::mod_runtime_fingerprint().empty(), "profile end clears hooks and snapshot policy");
|
||||
check(read_selection() == offline_selection, "profile end preserves offline selection file");
|
||||
fs::remove_all(root, ec);
|
||||
if (failures) return 1;
|
||||
std::cout << "mod runtime tests passed\n";
|
||||
|
||||
Reference in New Issue
Block a user