# Midnight Club: Los Angeles — RECOMP Recompilação estática de **Midnight Club: Los Angeles** (Xbox 360) para PC. Não é emulação do processador: o código PowerPC do `default.xex` é traduzido para C++ e compilado nativamente para x64. O SDK trata do kernel do 360, do sistema de ficheiros, do áudio e da GPU (Xenos → Direct3D 12). ![logo](midnight_recomp.png) ## Precisa do seu próprio disco **Este repositório não traz o jogo, nem pode.** Não há aqui dados, texturas, áudio nem o executável original — e também não há o C++ gerado a partir dele, porque esse continua a ser o código do jogo noutra forma. Para compilar precisa de um ISO da sua própria cópia de Midnight Club: Los Angeles para Xbox 360. O projeto foi feito contra uma versão específica do disco: `default.xex` com 9.252.864 bytes, SHA-1 do primeiro MB `2ac1e4f500e06f4267c9180a36aa1056e0303f29`. Outra versão provavelmente não arranca — o código traduzido deixa de bater com os dados. ## Estado | | | |---|---| | Jogável | free roam em Los Angeles, corridas, menus, cutscenes | | Desempenho | ~30 FPS numa GTX 1650 a 1280×720 | | Resolução interna | 720p / 1080p / 1440p / 4K | | Reescalonamento | FSR 2 e FSR 3.1, com nitidez ajustável em tempo real | | Idioma do menu | português do Brasil | Teclas: **F1** abre as opções, **F2** o monitor de desempenho. ## Compilar ``` 0-PATCH.bat aplica os patches ao xex (~1 s) 1-CODEGEN.bat xex → generated/default/*.cpp (~11 s) 2-BUILD.bat [n] cpp → Midnight Club L.A RECOMP.exe (n = tarefas, 4 por omissão) 3-JOGAR.bat corre o jogo ``` Precisa do **rexglue 0.9.0** e de aplicar `rexglue-sdk.patch` ao SDK. Sem esse patch o build passa, mas perde o monitor de desempenho, os contadores por fase, o título de janela próprio e os ajustes de memória. ## Estrutura ``` mclarecomp/ src/ código do porte: hooks, menu, monitor, render nativo config/ configuração de codegen e opções de origem tools/ codegen, benchmark, empacotamento, gerador do ícone recursos/ ícone e informação de versão do executável patches/ patches do xex rexglue-sdk/ o SDK, com as alterações deste porte já aplicadas game/ dados do jogo + as definições .toml (não versionado) ``` O `rexglue-sdk/` é o [rexglue](https://github.com/rexglue/rexglue-sdk) do Tom Clay, sob licença BSD de 3 cláusulas e derivado do [Xenia](https://xenia.jp). As bibliotecas de terceiros dele são submódulos — daí o `--recursive` ao clonar. O `game/` fica com os dados extraídos do ISO **e** com o ficheiro de definições `Midnight Club L.A RECOMP.toml`. A ideia é que essa pasta se baste a si mesma: leva consigo o jogo e a configuração, e o executável fica sem estado. ## Launcher O launcher **não está neste repositório** — vai pronto nos [Releases](../../releases). É uma aplicação que aceita o ISO arrastado, valida-o, extrai-o para `game/` com progresso e lança o jogo. Quem só quer jogar não precisa de compilar nada. ### O disco é verificado, não apenas pedido O launcher recusa-se a trabalhar com um disco que não seja a versão de que este executável foi traduzido: - **ao aceitar o ISO** — confere o `default.xex` dentro da imagem antes de extrair, para não gastar minutos em 6,5 GB que não vão servir; - **em cada arranque** — reconfere os bytes do `default.xex` já extraído, e não um ficheiro-marcador do género "já verifiquei", que qualquer pessoa editaria; - **contra extrações a meio** — se a pasta tiver menos de 12 ficheiros ou menos de 6 GB, o jogo conta como não instalado. Sem esses três, o botão de jogar não aparece. ## Desempenho — o que já foi medido Um quadro típico reparte-se assim: ``` 33 ms = 13 CPU de desenho + 2,5 upload + 9 GPU + ~8 lógica do jogo 3266 desenhos por quadro, ~4 µs cada ``` **A GPU não é o gargalo.** O custo está na CPU, por desenho, e espalhado por várias fases sem nenhum ponto quente. Os picos de frametime durante os carregamentos são de textura: num quadro de 634 ms, `RequestTextures` sozinho levou 343 ms. Onde vão os ~4 µs de cada desenho, em µs: ``` vfetch 0,52 prim 0,50 texturas 0,35 bindings 0,32 rtcache 0,22 pipeline 0,12 inicio 0,06 sysconst 0,06 submissao 0,05 fixedfn 0,03 ``` ### Como reproduzir estas medições **F2** abre o monitor. Para números em ficheiro: ```bat 3-JOGAR.bat --perf_log=true --estado_nativo_log=true --fps_limit=0 ``` Escreve no log, uma vez por segundo, a repartição do quadro e o custo de cada fase; e para cada quadro acima de 45 ms, o que esse quadro fez. `tools/bench.py` carrega um save de referência e mede sempre a mesma cena — medir na sequência de atração dá números que não querem dizer nada. ### Quatro hipóteses testadas, e todas falharam Não repita estas sem uma ideia nova: | hipótese | resultado | |---|---| | Saltar estado que não mudou | acerta **2,8%** — o jogo reescreve constantes de fetch em 74% dos desenhos | | Estreitar a invalidação de memória | upload −88%, mas **FPS 30 → 20**: as falhas de página custam mais | | Desligar a cache de índices convertidos | pior, e com piores picos | | `readback_resolve` no modo rápido | mais FPS, mas parte o visual | **Uma armadilha que custa um dia:** ao medir se o estado mudou entre desenhos, exclua `VGT_DRAW_INITIATOR` (0x21FC), `VGT_INDX_OFFSET` (0x2102), `VGT_DMA_BASE` (0x21FA) e `VGT_DMA_SIZE` (0x21FB). São o próprio comando de desenho, escritos em todos os desenhos por definição — contá-los deixa qualquer caminho rápido a 0% de acerto e parece que o jogo nunca repete estado. ### O caminho nativo, e onde ficou O jogo mantém **um espelho do ficheiro de registadores do Xenos dentro do seu próprio contexto**. O estado gráfico completo está em memória, em claro, antes de virar pacote PM4 — um caminho nativo lê dali em vez de decodificar pacotes. O mapa não foi deduzido: está escrito no código recompilado, que emite estado sempre como `addi r6,rCTX,` + `li r5,` + `bl 0x82423548`. Dez funções independentes do jogo concordam: ``` reg 0x2000 <- ctx+0x2880 reg 0x2280 <- ctx+0x2964 reg 0x2100 <- ctx+0x28CC reg 0x2300 <- ctx+0x29B8 reg 0x2180 <- ctx+0x2920 reg 0x2380 <- ctx+0x2A50 reg 0x2200 <- ctx+0x2934 reg 0x4000 <- ctx+0x0780 (constantes de vértice) reg 0x4400 <- ctx+0x1780 (constantes de píxel) ``` Validado a correr: `ctx+0x28CC` deu `RB_SURFACE_INFO` igual ao que o emulador tinha decodificado, e a viewport leu-se com semântica correta. Implementado em `src/mcla_espelho_regs.*` e `src/mcla_estado_desenho.*`, a correr em modo sombra — lê e regista, ainda não desenha. **Falta:** a tesoura (`0x2081`/`0x2082`) cai fora das zonas mapeadas, e as constantes de fetch (texturas e buffers de vértices) ainda não foram mapeadas. ## Licença O código deste repositório é do autor do porte. **Não abrange** o jogo, os seus dados, nem o código traduzido a partir dele — esses continuam a ser da Rockstar Games. Este projeto não distribui nada disso e exige que cada pessoa use a sua própria cópia.