fixed save games 2

fixed save games 2
This commit is contained in:
Jessica_Natalia
2026-08-18 04:09:42 -03:00
parent 82fbb0fa58
commit 3bdd8699c2
12 changed files with 149 additions and 7 deletions
+4
View File
@@ -99,3 +99,7 @@ Its source lives in `profiles/vcs/tools/vcs_codegen_main.cpp`. Profile-only lowe
## Development history
Old stage reports, validation notes and handoffs are stored under `profiles/vcs/progress`. That directory is intentionally ignored by the repository so development history does not pollute the public source tree.
### Internal SAVE_REPRO diagnostics
`VCSNative.ini` ships with `[Testing] SaveRepro=false`. This keeps the F8 checkpoint and F10 trace harness completely unavailable during normal play. Developers may temporarily set it to `true` for controlled debugging. `RESTORE_SAVE_REPRO.bat` explicitly opts the harness in for its own process and does not require changing the normal INI. These checkpoints are diagnostic snapshots, not supported gameplay save states.
+1
View File
@@ -20,6 +20,7 @@ if not exist "%GAME%\PSP_GAME\SYSDIR\EBOOT_DECRYPTED.ELF" (
exit /b 3
)
if exist "%TRACE%" del /q "%TRACE%" >nul 2>&1
set "PSPRECOMP_SAVE_REPRO_TESTING=1"
set "PSPRECOMP_SAVE_REPRO_AUTO_RESTORE=1"
echo ================================================================
echo VCS SAVE REPRO - AUTO RESTORE
+7
View File
@@ -113,6 +113,13 @@ InvertCameraY=false
PedCameraUpLimitDegrees=10
ModernControlScheme=false
[Testing]
; INTERNAL DEVELOPER TOOL ONLY. This is not a general gameplay save-state.
; false = F8/F10 checkpoint/trace hotkeys are completely disabled in normal play.
; true = F8 captures SAVE_REPRO checkpoint and F10 dumps its diagnostic trace.
; RESTORE_SAVE_REPRO.bat explicitly enables this harness only for its own run.
SaveRepro=false
[Diagnostics]
LogToFile=true
LogFile=VCSNative.log
+2 -1
View File
@@ -452,7 +452,8 @@ LRESULT CALLBACK window_procedure(HWND window, UINT message, WPARAM wparam, LPAR
// Gameplay keys keep using the existing sampled-input path. Diagnostic
// F8/F10 edges are queued here on the UI thread, with auto-repeat
// ignored, so no GetAsyncKeyState call is added to guest timing.
if ((static_cast<std::uint32_t>(lparam) & (1u << 30u)) == 0u) {
if (save_repro_testing_enabled() &&
(static_cast<std::uint32_t>(lparam) & (1u << 30u)) == 0u) {
if (wparam == VK_F8)
state.save_repro_commands.fetch_or(0x1u, std::memory_order_release);
else if (wparam == VK_F10)
+28
View File
@@ -561,6 +561,16 @@ void apply_timing_key(VcsConfiguration &config, const std::string &key,
warning(config, line, "unknown [Timing] key '" + key + "'");
}
void apply_testing_key(VcsConfiguration &config, const std::string &key,
const std::string &value, std::size_t line) {
if (key == "saverepro" || key == "savereprodiagnostics") {
if (!parse_bool(value, config.testing.save_repro))
warning(config, line, "Testing.SaveRepro expects true/false");
return;
}
warning(config, line, "unknown [Testing] key '" + key + "'");
}
void apply_diagnostics_key(VcsConfiguration &config, const std::string &key,
const std::string &value, std::size_t line) {
if (key == "logtofile" || key == "enablelog" || key == "enabled") {
@@ -760,6 +770,8 @@ VcsConfiguration load_vcs_configuration(const std::filesystem::path &path) {
apply_timing_key(config, key, value, line_number);
else if (section == "diagnostics" || section == "logging")
apply_diagnostics_key(config, key, value, line_number);
else if (section == "testing")
apply_testing_key(config, key, value, line_number);
else if (section == "widescreen")
apply_widescreen_key(config, key, value, line_number);
else if (section == "controls")
@@ -801,6 +813,17 @@ void initialize_vcs_configuration(const std::filesystem::path &executable_direct
VcsConfiguration loaded = load_vcs_configuration(path);
load_proper_shaders_configuration(loaded, executable_directory / "ProperShaders.ini");
// SAVE_REPRO is intentionally off in the shipped INI. The internal restore
// script/environment is an explicit developer opt-in and may enable it for
// that process without requiring the user's normal configuration to change.
const auto env_enabled = [](const char *name) noexcept {
const char *value = std::getenv(name);
return value != nullptr && *value != '\0' && std::string_view(value) != "0";
};
if (env_enabled("PSPRECOMP_SAVE_REPRO_TESTING") ||
env_enabled("PSPRECOMP_SAVE_REPRO_AUTO_RESTORE")) {
loaded.testing.save_repro = true;
}
loaded.initialized = true;
loaded.executable_directory = executable_directory;
{
@@ -879,6 +902,11 @@ const VcsConfiguration &vcs_configuration() {
return global_configuration();
}
bool save_repro_testing_enabled() noexcept {
const VcsConfiguration &config = global_configuration();
return config.initialized && config.testing.save_repro;
}
const char *display_resolution_mode_name(DisplayResolutionMode mode) noexcept {
switch (mode) {
case DisplayResolutionMode::PspNative: return "PSP";
+11
View File
@@ -151,6 +151,13 @@ struct TimingConfiguration {
std::uint64_t realtime_speed_interval_vblanks{120u};
};
struct TestingConfiguration {
// Internal developer-only SAVE_REPRO checkpoint/trace harness. This is not
// a general user save-state system: checkpoints can contain host-side state
// that is only safe for controlled diagnostics. Keep disabled for normal play.
bool save_repro{false};
};
struct DiagnosticsConfiguration {
// Optional text log beside the executable. Used for startup failures,
// DirectX 12 device/present errors, missing-asset reports and other host
@@ -272,6 +279,7 @@ struct VcsConfiguration {
AudioConfiguration audio{};
TimingConfiguration timing{};
DiagnosticsConfiguration diagnostics{};
TestingConfiguration testing{};
WidescreenConfiguration widescreen{};
VolumetricCloudsConfiguration volumetric_clouds{};
std::filesystem::path source_path{};
@@ -294,6 +302,9 @@ struct VcsConfiguration {
void initialize_vcs_configuration(const std::filesystem::path &executable_directory);
[[nodiscard]] const VcsConfiguration &vcs_configuration();
// Resolved once at startup. Explicit SAVE_REPRO restore/test environment flags
// can opt the internal harness in even when the INI keeps it disabled.
[[nodiscard]] bool save_repro_testing_enabled() noexcept;
[[nodiscard]] const char *display_resolution_mode_name(DisplayResolutionMode mode) noexcept;
[[nodiscard]] const char *display_aspect_mode_name(DisplayAspectMode mode) noexcept;
[[nodiscard]] const char *display_upscale_filter_name(DisplayUpscaleFilter filter) noexcept;
+4
View File
@@ -3135,6 +3135,9 @@ void save_repro_dump_trace(psprecomp::Runtime &runtime, std::string_view reason)
}
void save_repro_vblank_hotkeys(psprecomp::Runtime &runtime, const psprecomp::AllegrexContext &ctx) {
// Shipped builds keep SAVE_REPRO disabled. Return before even touching the
// UI command atomic so normal gameplay follows the V8.2.7 path exactly.
if (!save_repro_testing_enabled()) return;
// The UI thread records F8/F10 edges in WindowState. Before F8/restore this
// stays one atomic exchange per vblank, preserving the V8.2.5 mission and
// cutscene path. Once tracing is armed we additionally poll F10 on Windows:
@@ -11568,6 +11571,7 @@ void vcs_starvation_tick(psprecomp::Runtime &, psprecomp::AllegrexContext &ctx)
} // namespace
bool restore_save_repro_checkpoint_if_requested(psprecomp::Runtime &runtime, std::string &error) {
if (!save_repro_testing_enabled()) return false;
const char *value = std::getenv("PSPRECOMP_SAVE_REPRO_AUTO_RESTORE");
if (value == nullptr || *value == '\0' || std::string_view(value) == "0") return false;
return save_repro_restore_checkpoint_impl(runtime, error);
+5 -3
View File
@@ -65,12 +65,14 @@ void runtime_log_initialize(const VcsConfiguration &configuration) {
return;
}
s.file << "VCSNative runtime log\n";
s.file << "stage=correctness-v8.2.7-save-thread-lifecycle-fix-2026-08-18\n";
s.file << "stage=correctness-v8.2.7a-internal-save-repro-gate-2026-08-18\n";
s.file << "config=" << configuration.source_path.string() << '\n';
s.file << "started=" << timestamp_now() << '\n';
s.file << "perf_telemetry=" << (configuration.diagnostics.perf_telemetry ? 1 : 0)
<< " interval_vblanks=" << configuration.diagnostics.perf_telemetry_interval_vblanks
<< "\n";
s.file << "save_repro_testing=" << (configuration.testing.save_repro ? 1 : 0)
<< " default=0 internal_only=1\n";
s.file << "guest_hotspot=" << (configuration.diagnostics.guest_hotspot_profile ? 1 : 0)
<< " sample_stride=256 interval_vblanks=300"
#if defined(PSPRECOMP_RUNTIME_CHAIN_TELEMETRY)
@@ -85,9 +87,9 @@ void runtime_log_initialize(const VcsConfiguration &configuration) {
<< " unwind_fix=1 reentry_guard=1 dataflow=1 vfpu_block32=133 mem_runs=35 mem_words=287"
<< " append32=51 advance32=89 simd_mat4=4 simd_matvec=19"
<< " gpr_shadow_clusters=4 gpr_shadow_regs=24 gpr_shadow_occurrences=3461 geometry_shadow=0"
<< " perf_layer=8 cpu_lean_revision=2 correctness_revision=827 recovery_from_821=1"
<< " perf_layer=8 cpu_lean_revision=2 correctness_revision=8271 recovery_from_821=1"
<< " save_transaction=1 save_lifecycle_v82=1 sas_endflag_latched=1 sas_loop_history_restore=1"
<< " atrac_virtual_source=1 atrac_stall_diag=1 atrac_stream_resident_status=1 atrac_nonloop_resident=-2 atrac_loop_resident=-3 output2_success_zero=1 output2_master_watermark=1 output2_late_catchup=0 save_repro_checkpoint=1 save_repro_trace=1 save_repro_hotkey_f8=1 save_repro_trace_hotkey_f10=1 save_repro_auto_restore=1 save_repro_dispatch_sample_stride=64 save_repro_passive_until_f8=1 save_repro_hle_hotpath=0 save_repro_ui_hotkeys=1 save_repro_f10_async_fallback=1 save_repro_collector_partial_bundle=1 save_exitdelete_semantics=1 save_repro_legacy_exitdelete_repair=1 save_partition_reuse=1 news_atrac_v825_guard=1 runtime_chain_telemetry_default=0 arch_fastmem=1 aot_direct_fastmem_default=1"
<< " atrac_virtual_source=1 atrac_stall_diag=1 atrac_stream_resident_status=1 atrac_nonloop_resident=-2 atrac_loop_resident=-3 output2_success_zero=1 output2_master_watermark=1 output2_late_catchup=0 save_repro_checkpoint=1 save_repro_trace=1 save_repro_hotkey_f8=1 save_repro_trace_hotkey_f10=1 save_repro_auto_restore=1 save_repro_dispatch_sample_stride=64 save_repro_passive_until_f8=1 save_repro_hle_hotpath=0 save_repro_ui_hotkeys=1 save_repro_f10_async_fallback=1 save_repro_collector_partial_bundle=1 save_repro_internal_ini_gate=1 save_repro_default_enabled=0 save_exitdelete_semantics=1 save_repro_legacy_exitdelete_repair=1 save_partition_reuse=1 news_atrac_v825_guard=1 runtime_chain_telemetry_default=0 arch_fastmem=1 aot_direct_fastmem_default=1"
<< " tier2_direct_fastmem=1 tier2_direct_mem_sites=1969 tier2_deep_telemetry_default=0 geometry_fusion_rollback=1"
<< " entity_leaf_inline=1 entity_leaf_scheduler_accounting=1 entity_leaf_resume_pc_fix=1"
<< " ge_async_default=0 parallel_vertex_decode_default=0"
+16 -1
View File
@@ -113,6 +113,7 @@ set "CORRECTNESS_V826_SAVE_REPRO_STAMP=%BUILD%\.vcs_correctness_v826_save_repro_
set "CORRECTNESS_V826A_SAVE_REPRO_STAMP=%BUILD%\.vcs_correctness_v826a_save_repro_passive_20260818"
set "CORRECTNESS_V826B_SAVE_REPRO_STAMP=%BUILD%\.vcs_correctness_v826b_save_repro_trace_20260818"
set "CORRECTNESS_V827_SAVE_THREAD_STAMP=%BUILD%\.vcs_correctness_v827_save_thread_lifecycle_20260818"
set "CORRECTNESS_V827A_SAVE_REPRO_GATE_STAMP=%BUILD%\.vcs_correctness_v827a_save_repro_gate_20260818"
if not defined PSPRECOMP_TIER2_DEEP_TELEMETRY set "PSPRECOMP_TIER2_DEEP_TELEMETRY=OFF"
if not defined PSPRECOMP_RUNTIME_CHAIN_TELEMETRY set "PSPRECOMP_RUNTIME_CHAIN_TELEMETRY=OFF"
if /I "%PSPRECOMP_TIER2_DEEP_TELEMETRY%"=="1" set "PSPRECOMP_TIER2_DEEP_TELEMETRY=ON"
@@ -131,7 +132,7 @@ echo Ninja: %NINJA_EXE%
echo Ninja workers: %JOBS%
echo cl.exe /MP: OFF ^(Ninja owns compile parallelism^)
echo Generated AOT: O3, cold /Ob0, measured hot /Ob3; V8.2 runtime-chain lean + V8.1 Geometry/direct-fastmem baseline
echo Correctness: V8.2.6B SAVE REPRO TRACE HOTFIX over protected V8.2.5 NEWS audio
echo Correctness: V8.2.7A SAVE lifecycle + internal SAVE_REPRO gate; protected V8.2.5 NEWS audio
echo Host/core LTCG: ON
echo AVX2/fast paths: ON
echo Tier2 deep diag: %PSPRECOMP_TIER2_DEEP_TELEMETRY%
@@ -159,6 +160,8 @@ rem V8.2.6 passive checkpoint contract and the corrected PSP ExitDelete lifecycl
rem Older revision checkers pin exact stage strings and must not gate this stage.
%PYTHON3_CMD% "%PROFILE%\tests\check_v827_save_thread_lifecycle.py"
if errorlevel 1 goto :FAIL
%PYTHON3_CMD% "%PROFILE%\tests\check_v827a_internal_save_repro_gate.py"
if errorlevel 1 goto :FAIL
if exist "%BUILD%" if not exist "%SUPERBLOCK_STAMP%" (
echo.
@@ -383,6 +386,17 @@ if exist "%BUILD%" if not exist "%CORRECTNESS_V827_SAVE_THREAD_STAMP%" (
del /s /q "%BUILD%\*vcs_runtime_log*.obj" >nul 2>&1
)
if exist "%BUILD%" if not exist "%CORRECTNESS_V827A_SAVE_REPRO_GATE_STAMP%" (
echo.
echo [0c-v827a/7] V8.2.7A INTERNAL SAVE_REPRO GATE - rebuilding host config/diagnostic objects only...
rem Normal gameplay has SAVE_REPRO disabled in VCSNative.ini. The internal
rem restore script opts in explicitly; generated AOT/Tier2/DX12 are unchanged.
del /s /q "%BUILD%\*vcs_config*.obj" >nul 2>&1
del /s /q "%BUILD%\*display_window*.obj" >nul 2>&1
del /s /q "%BUILD%\*vcs_profile*.obj" >nul 2>&1
del /s /q "%BUILD%\*vcs_runtime_log*.obj" >nul 2>&1
)
if exist "%BUILD%" if not exist "%BOOTFIX_STAMP%" (
echo.
echo [0c/7] BOOTFIX revision changed - invalidating stale .obj/.pch once...
@@ -440,6 +454,7 @@ if errorlevel 1 goto :FAIL
>"%CORRECTNESS_V826A_SAVE_REPRO_STAMP%" echo VCS V8.2.6A SAVE REPRO PASSIVE RECOVERY 2026-08-18
>"%CORRECTNESS_V826B_SAVE_REPRO_STAMP%" echo VCS V8.2.6B SAVE REPRO TRACE HOTFIX 2026-08-18
>"%CORRECTNESS_V827_SAVE_THREAD_STAMP%" echo VCS V8.2.7 SAVE THREAD LIFECYCLE FIX 2026-08-18
>"%CORRECTNESS_V827A_SAVE_REPRO_GATE_STAMP%" echo VCS V8.2.7A INTERNAL SAVE_REPRO GATE 2026-08-18
echo.
echo [2b/7] Building tests and DX12 probes...
@@ -18,8 +18,8 @@ def need(cond, msg):
raise SystemExit(1)
print('PASS:', msg)
need('stage=correctness-v8.2.7-save-thread-lifecycle-fix-2026-08-18' in log, 'V8.2.7 runtime stage')
need('correctness_revision=827' in log, 'V8.2.7 correctness revision')
need(('stage=correctness-v8.2.7-save-thread-lifecycle-fix-2026-08-18' in log) or ('stage=correctness-v8.2.7a-internal-save-repro-gate-2026-08-18' in log), 'V8.2.7/V8.2.7A runtime stage')
need(('correctness_revision=827 ' in log) or ('correctness_revision=8271 ' in log), 'V8.2.7/V8.2.7A correctness revision')
need('save_exitdelete_semantics=1' in log and 'save_repro_legacy_exitdelete_repair=1' in log and 'save_partition_reuse=1' in log,
'ExitDelete/partition fix and migration metadata')
need('atrac_stream_resident_status=1' in log and 'atrac_nonloop_resident=-2' in log and
@@ -0,0 +1,63 @@
#!/usr/bin/env python3
from pathlib import Path
root = Path(__file__).resolve().parents[3]
profile = root / 'profiles' / 'vcs'
host = profile / 'host'
config_h = (host / 'vcs_config.hpp').read_text(encoding='utf-8')
config_cpp = (host / 'vcs_config.cpp').read_text(encoding='utf-8')
profile_cpp = (host / 'vcs_profile.cpp').read_text(encoding='utf-8')
display_cpp = (host / 'display_window.cpp').read_text(encoding='utf-8')
log = (host / 'vcs_runtime_log.cpp').read_text(encoding='utf-8')
ini = (profile / 'config' / 'VCSNative.ini').read_text(encoding='utf-8')
restore = (profile / 'RESTORE_SAVE_REPRO.bat').read_text(encoding='utf-8')
config_tests = (profile / 'tests' / 'vcs_config_tests.cpp').read_text(encoding='utf-8')
def need(cond, msg):
if not cond:
print('FAIL:', msg)
raise SystemExit(1)
print('PASS:', msg)
need('stage=correctness-v8.2.7a-internal-save-repro-gate-2026-08-18' in log,
'V8.2.7A runtime stage')
need('correctness_revision=8271' in log, 'V8.2.7A correctness revision')
need('save_repro_internal_ini_gate=1' in log and 'save_repro_default_enabled=0' in log,
'internal-only gate metadata')
need('struct TestingConfiguration' in config_h and 'bool save_repro{false};' in config_h,
'SAVE_REPRO configuration defaults off in code')
need('[Testing]' in ini and 'SaveRepro=false' in ini,
'shipped INI disables SAVE_REPRO')
need('INTERNAL DEVELOPER TOOL ONLY' in ini and 'not a general gameplay save-state' in ini,
'INI labels SAVE_REPRO as internal diagnostics')
need('apply_testing_key' in config_cpp and 'Testing.SaveRepro expects true/false' in config_cpp,
'Testing.SaveRepro parser exists')
need('else if (section == "testing")' in config_cpp and 'apply_testing_key(config, key, value, line_number);' in config_cpp,
'[Testing] section is accepted')
need('bool save_repro_testing_enabled() noexcept' in config_cpp and
'return config.initialized && config.testing.save_repro;' in config_cpp,
'resolved runtime gate is a cheap config boolean')
need('PSPRECOMP_SAVE_REPRO_TESTING' in config_cpp and 'PSPRECOMP_SAVE_REPRO_AUTO_RESTORE' in config_cpp,
'explicit internal environment paths can opt in before runtime')
need('if (save_repro_testing_enabled() &&' in display_cpp,
'WndProc ignores F8/F10 while diagnostics are disabled')
need('if (!save_repro_testing_enabled()) return;' in profile_cpp,
'vblank checkpoint path exits before touching command queue when disabled')
need('if (!save_repro_testing_enabled()) return false;' in profile_cpp,
'auto-restore refuses non-testing runs')
need('set "PSPRECOMP_SAVE_REPRO_TESTING=1"' in restore and
'set "PSPRECOMP_SAVE_REPRO_AUTO_RESTORE=1"' in restore,
'internal restore script explicitly opts the harness in')
need('SaveRepro=true' in config_tests and 'SAVE_REPRO must be disabled by default' in config_tests,
'configuration tests cover opt-in and safe default')
# Protected correctness/performance guards.
for token, label in [
('save_exitdelete_semantics=1', 'Save memory lifecycle fix preserved'),
('atrac_nonloop_resident=-2', 'NEWS non-loop ATRAC sentinel preserved'),
('atrac_loop_resident=-3', 'NEWS loop ATRAC sentinel preserved'),
('output2_late_catchup=0', 'rejected Output2 pacing remains off'),
('hot_blocks=1060', 'V8.2 CPU shape preserved'),
('geometry_fusion_rollback=1', 'Geometry rollback preserved'),
]:
need(token in log, label)
print('V8.2.7A INTERNAL SAVE_REPRO GATE audit PASS')
+6
View File
@@ -62,6 +62,8 @@ int main() {
<< "MouseSensitivity=17\n"
<< "InvertCameraY=true\n"
<< "PedCameraUpLimitDegrees=40\n"
<< "[Testing]\n"
<< "SaveRepro=true\n"
<< "[Widescreen]\n"
<< "Enabled=true\n"
<< "AspectRatio=21:9\n"
@@ -148,6 +150,8 @@ int main() {
require(config.controls.invert_camera_y, "camera inversion was not parsed");
require(config.controls.ped_camera_up_limit_degrees == 40u,
"on-foot camera upper limit was not parsed");
require(config.testing.save_repro,
"Testing.SaveRepro was not parsed");
const vcs::PresentationRectangle fit = vcs::calculate_presentation_rectangle(
1920u, 1080u, 480u, 272u, vcs::DisplayAspectMode::Preserve, false);
@@ -164,6 +168,8 @@ int main() {
const vcs::VcsConfiguration missing =
vcs::load_vcs_configuration(root / "missing.ini");
require(!missing.testing.save_repro,
"SAVE_REPRO must be disabled by default");
{
std::ofstream proper(root / "ProperShaders.ini", std::ios::trunc);
proper << "[VolumetricClouds]\n"