📦mzzvxm / LARecomp
← 返回首页
…
📅 创建于 2026-02-28🔄 更新于 2026-10-31

📄 仓库 README

在 GitHub 查看 ↗
来自 GitHub 仓库自述文件 · 版权归原作者所有

LARecomp

[!CAUTION] At this point, I'm not granting permission to use LARecomp's features in your own recomps. Once we officially launch, feel free to use our code as a reference, but please don't copy and paste our code. Contributions to the repository are welcome.

A static recompilation of Midnight Club: Los Angeles (Complete Edition) for Windows x86-64, built on the ReXGlue SDK.

Static recompilation translates the Xbox 360 PowerPC code inside the game's default.xex into native C++ that compiles and runs on a PC. There is no emulator and no interpreter in the loop. File I/O, GPU commands, audio and threading go through the ReXGlue runtime.

You supply the game data. Nothing from the disc is included here.


What you get

The game boots to the menu, free roam and races work, and saves load. On top of that:

Runs properly above 30 FPS. The original code locks the simulation to a fixed 30 Hz timestep, and the well-known Xenia unlock makes the game run at double speed. LARecomp feeds the simulation the real measured frame time instead, so physics, camera and traffic behave the same at 30, 60, 120 and 144 FPS.

Smooth frame pacing. Frame times used to land on a 15.625 ms grid, which is Windows' default timer resolution rather than anything about the display. Raising timer resolution and taking presentation off vsync removed it and gained about 30% throughput.

Camera and suspension that do not break at high frame rates. Chase camera lag, chassis roll and the ground depth filter step with continuous-time exponential decay calibrated against the 30 FPS console curve, so they behave identically at any frame rate.

A settings menu inside the game. Press Start, open Options, and there are eight tabs: ReXGlue Settings, Recomp Settings, Performance, Fidelity FX, Debug Camera, Time of Day, Carbon Fiber and Languages. Changes apply immediately and save when you leave the submenu.

Quality of life. An ISO install wizard on first launch, save import from Xenia and RPCS3, custom MP3 radio, Discord Rich Presence, a mod loader, a speedometer that switches between mph and km/h, and a language picker that reaches the German and Italian translations the retail NTSC/U build region-gates out.

Under the hood there are 112 mid-asm hooks, 155 settings, and 24,927 named function hints driving codegen.

Known issues

Issue Detail
Dithered alpha on shadows and foliage Visible as a dither pattern on shadow edges and on vegetation leaves. Cause not pinned down: either the GPU plugin's handling of the dither pattern, or the game's own shaders dithering at a pattern scale that assumes the 1280x720 console output and does not hold at higher resolutions. This is the only rendering issue left; car body reflections and the occasional HUD glitches were both fixed by the custom ReXGlue build LARecomp uses.
Intro movies play fast Playback pacing follows the frame rate unlock. Capping to 30, 45 or 60 FPS produces identical speed, so a frame cap does not help. Press A to skip, or turn on skip_intro.
Frame rate collapses below 10 FPS after long sessions Traced to a bug in the SDK's vblank timer, not to this project. See below.

The frame rate collapse

After anywhere from 7 to 30 minutes, the frame rate could fall under 10 FPS and stay there for the rest of the session. It is fixed by a workaround while the SDK issue is addressed upstream:

Start-Process larecomp.exe -ArgumentList "--clock_no_scaling=true"

The cause is an unsigned underflow in the SDK's vblank catch-up loop. Once the guest tick clock steps backwards by even one tick, the loop's exit condition can never be satisfied again, and it dispatches guest interrupts continuously. Measured: 1,010 vblank interrupts per second while healthy, 11,766,658 per second once stuck. clock_no_scaling=true makes the guest tick count a plain function of the host clock, which removes the backwards step. A 33 minute test run with it set never dropped below 24 FPS.

Whether the flag costs frame rate is not settled. It does not change the interrupt load: vblank rate under it averaged 1,014 per second against a 1,010 baseline. It does change what QueryGuestSystemTime returns, so anything pacing off guest system time behaves differently. If you want to know for certain, run the same route twice with MCLA_TIMING_LOG=1 and compare the histograms.

Full write-up in TECHNICAL_NOTES.md.


Getting it running

You need

  • ReXGlue SDK 0.10.0
  • CMake 3.25 or newer
  • Clang, from LLVM or Visual Studio. MSVC will not build this.
  • Ninja
  • Your own copy of the game, extracted from disc

Game data

Point LARecomp at a folder holding default.xex and the xarchive_*.rpf archives:

MCLA_Game_Files/
  default.xex
  xarchive_cache.rpf
  xarchive_audio.rpf
  ...

It looks for that folder on its own, in this order:

  1. --game_data_root on the command line
  2. The MCLA_GAME_DATA environment variable
  3. Walking up from the executable, checking MCLA_Game_Files/, game/, assets/ and the directory itself at each level

A directory only counts if it has default.xex and at least one archive next to it. A half-finished install is rejected at startup rather than failing later with something unhelpful. If nothing is found, the ISO install wizard offers to set it up.

Codegen is separate: larecomp_manifest.toml points at ../MCLA_Game_Files/default.xex, relative to the repo. That path is only read by rexglue codegen, never at runtime.

Build

cmake --preset win-amd64-relwithdebinfo .
cmake --build out/build/win-amd64-relwithdebinfo

The executable lands in out/build/win-amd64-relwithdebinfo/larecomp.exe.

In Visual Studio, open the repo folder, pick Windows AMD64 RelWithDebInfo, and run.

Play

cd out\build\win-amd64-relwithdebinfo
$env:REX_LOG_LEVEL="warn"; Start-Process larecomp.exe

Set REX_LOG_LEVEL=warn. Non-Release builds log at trace, which is roughly 7,500 lines and 1.4 MB of synchronous disk writes per second during gameplay. That is enough to cause stutter on its own.

Everything else is in the pause menu. It defaults to 60 FPS with real frame delta on and vsync off.


Settings

Most settings are cvars, not environment variables. Set them in the pause menu, on the command line as --name=value, or in larecomp.toml beside the executable.

Two rows that sound alike but are not:

Setting What it does
REAL FRAME DELTA Feeds the simulation the measured frame time instead of the fixed 30 Hz timestep. This is what makes high frame rates correct. It is not a frame rate setting.
FPS LIMIT The actual cap: 30, 60, 120, 144 or uncapped.

Turning REAL FRAME DELTA off puts the engine back on its original 30 Hz timestep. The hitch clamp, the FPS cap and the city LOD scale keep working either way.

These are the environment variables the build reads. Everything else moved to cvars:

Variable Default Purpose
REX_LOG_LEVEL trace on non-Release Set to warn. See above.
MCLA_GAME_DATA auto-detect Folder holding default.xex.
MCLA_FPS_CAP unset Overrides the fps_limit cvar.
MCLA_MAX_FRAME_MS 125 Caps how far one frame can advance the clock. Clamped to 16-1000 ms; cannot be turned off.
MCLA_TIMING_LOG off 1 writes frame-time stats and a histogram.
MCLA_TEX_SOFT / MCLA_TEX_HARD / MCLA_TEX_RTT 1536 / 2048 / 64 Texture cache limits in MB.
MCLA_VSYNC false Leave off. On costs about 30% throughput.
MCLA_REFRESH_RATE 60 Guest video mode refresh rate.
MCLA_ALLOW_INVALID_FETCH true Set false if HUD or minimap glitches appear.
MCLA_NO_STUB_SWEEP 0 1 skips stubbing unmapped addresses at startup, saving about 400 ms. Only safe while stubs.txt stays empty.
LARECOMP_LOG_FILE auto Log file path.

logs/effective_config.txt is written every launch and lists what actually took effect, including an ok or FAIL line for each GPU flag. Check it first when a setting seems to do nothing.


Working on the code

Engine patches are [[midasm_hook]] entries in larecomp_config.toml, implemented in src/mc_engine/hooks/, one file per category:

[[midasm_hook]]
name = "MCLAFixedStepPath"
address = 0x821BDB90
after_instruction = true
registers = ["r3", "f11"]

The hook function takes only the registers named in registers, by reference, with ordinary C++ linkage. Not extern "C", not (ctx, base). Float registers arrive as PPCRegister& with the value in .f64. Returning bool drives jump_address_on_true.

After changing hooks or hints:

E:\MCLA\rexglue-sdk-0.10.0\out\install\win-amd64\bin\rexglue.exe codegen larecomp_manifest.toml
cmake --build out/build/win-amd64-relwithdebinfo

Pass the manifest, not the config. The manifest includes the config and sets up module dependencies.

Never edit anything in generated/. Codegen rewrites the whole directory. Hooks survive regeneration because they live in the config and in src/mc_engine/hooks/; hand edits do not.

Layout

larecomp/
  README.md
  documentation/
    RUNNING.md              # run and debug quick reference
    TECHNICAL_NOTES.md      # engine findings, corrections, gotchas
    MCLA_WORKPLAN.md        # investigation log and open work
  src/
    larecomp_app.h          # paths, cvars, GPU flags, stub sweep
    mc_engine/              # hooks, pause menu, HUD, music, mod loader
    isoinstaller/           # first-run ISO install wizard
    saveporter/             # Xenia and RPCS3 save import
    discord_rpc/
    mcla_rage_types.h       # big-endian RAGE structs, offsets static_asserted
  assets/
    gamecontrollerdb.txt    # SDL controller mappings, copied next to the exe
  generated/                # REGENERATED BY CODEGEN, never hand-edit
  larecomp_manifest.toml    # codegen entry point
  larecomp_config.toml      # function hints and hook declarations

Credits & Acknowledgments

mzzvxm, author and maintainer of LARecomp, the original static recompilation of Midnight Club: Los Angeles, in development since 2025. This repository is the LARecomp project: the ReXGlue port, the in-game pause menu and settings system, the ISO install wizard, save porting from Xenia and RPCS3, custom music, Discord Rich Presence, the mod loader, and the bulk of the engine hook work.

Also the custom ReXGlue build LARecomp is developed against, which is not published yet. Its rendering fixes are what removed the broken car body reflections and the intermittent HUD glitches, leaving dithered alpha as the only rendering issue outstanding.

BadassBaboon and the midnightclub fork.

Frame timing and high-frame-rate work, developed in the fork and carried into LARecomp:

  • Real frame delta injection. The 2x speed bug needed hooks on two fixed-timestep paths, not the one the Xenia patch addresses, and it had to keep the timer reset guard that the Xenia patch skips. Dropping that guard caused a loud audio blowout.
  • Frame pacing. Identifying the 15.625 ms grid as Windows timer granularity, and establishing that both timeBeginPeriod(1) and vsync off are required.
  • The wall-clock frame limiter, deliberately not vblank-based so pacing stays continuous.
  • Continuous-time chase camera, chassis roll and ground depth smoothing.
  • Ambient traffic and pedestrian density tuning, with the corrected mcAmbientDensityTuning field offsets.
  • Texture cache sizing that takes texture_cache_misses to zero.

Fixes made directly in LARecomp:

  • Unclickable setup wizards. ReXGlue moved windowing and input to SDL3, but the ISO installer and the save import wizard still pumped messages with Win32 PeekMessageW, which never drains SDL3's event queue. ImGui received no mouse events at all, so the buttons did nothing.
  • Access violation on the aspect ratio patch. flt_8201E7EC sits in .rdata, which the XEX loader maps read-only. Once g_guest_mem was actually populated, the patch stopped exiting early and wrote straight into a read-only page. It now unprotects the page first.
  • Ambient density tuning did nothing. The hook was placed after the density_tuning.xml parse, on a code path that never executes. Moved to the constructor epilogue at 0x826F5CA0, where all 32 zones apply.
  • Pause menu crash on SAVE SETTINGS. The custom row installer clears the list's table-source pointer, and the game's menu update path dereferences it without a null check.
  • Settings that disabled each other. The FPS cap and the city LOD slider were gated behind the frame delta option, so turning that off silently switched both off too. The option was also named "60 FPS" while sitting directly above "FPS LIMIT"; it is now REAL FRAME DELTA.
  • Save button replaced with auto-save, since every setting already applied immediately and the button existed only to write the file.
  • Log noise. A routine "entry not found, create it" branch logged at warning level, producing about 180 warnings per session and burying the real ones. Now 10.
  • Clean builds were broken. enable_language(RC) picked Microsoft rc.exe, which cannot parse clang's line markers and fails with RC2019.
  • Frame-time instrumentation, and the diagnosis of the vblank interrupt storm behind the long-session frame rate collapse.
  • D3D fence spin-wait throttling (Patch_FenceSpinThrottle). Replaced the unconstrained PowerPC pipeline NOP busy-wait loop (mr r31, r31) in sub_82412F98 (called by D3DDevice_BlockOnFence) with host CPU yielding (YieldProcessor() and adaptive SwitchToThread()), dropping Render Thread CPU load from 98.8% to 82.2% during fence waits.
  • Single-tile un-tiled rendering (Patch_SingleTile & Patch_EdramLimit). Raised the internal EDRAM budget clamp from 2,048 tiles (10 MB console limit) to 4,096 tiles (20 MB ReXGlue limit). Guarded Patch_SingleTile to strictly target the main scene framebuffer (r17 == 0) while leaving offscreen passes native (r17 != 0), eliminating 2–3× multi-tile splitting overhead and yielding a 1.5× to 1.6× FPS boost (+15 to +27 FPS in dense areas) without breaking the pause menu or orbital camera.
  • Elimination of PM4 profiler overhead in ReXGlue SDK. Identified and eliminated ~480,000 QueryPerformanceCounter calls per second (PROFILE_SCOPE_US) issued on every PM4 packet in rexgpu-xenos, which consumed 25.1% CPU of the bottleneck GPU Commands thread. Compiling out perf counters recovered this overhead, lifting dense area framerates into the 80–88+ FPS bracket.
  • Adaptive texture cache limits & D3D12 primary buffer submission. Replaced hardcoded texture cache overrides with a universally safe 2560 MB soft / 4096 MB hard baseline that prevents VRAM exhaustion on 6 GB and 8 GB GPUs while respecting user TOML overrides on high-VRAM cards (12 GB–24 GB). Enabled d3d12_submit_on_primary_buffer_end = true to allow asynchronous overlap of GPU rendering with CPU command recording, smoothing out pipeline bubbles.
  • Guest profiler 144 FPS / GPU Commands call-stack sampling. Added profile_gpu_commands.ps1 helper for targeting GPU Commands with RtlVirtualUnwind stack sampling at 144 FPS / 7.0ms threshold.

Foxxyyy, for reverse-engineering work on CodeX.Games.MCLA: the RAGE RSC5 resource format, type layouts and string databases behind the typed structures used here.

ReXGlue Team, for the Xbox 360 static recompilation toolkit and runtime.

Rockstar San Diego, who made the game.

📈 近 7 天 Star 趋势

每日新增 Star(柱)与累计 Star(线)· 数据来自 GitHub

🏆 排名变化趋势

在各榜单中的排名历史(数字越小越靠前)

📋 历史上榜记录

每次快照的详细数据
日期 榜单 排名 周期新增 总 STAR