From b5e0a157a534fff41006880f245384bd63cb3571 Mon Sep 17 00:00:00 2001 From: KeybadeBlox Date: Sun, 19 Apr 2026 17:16:01 -0400 Subject: [PATCH 1/3] Delink ActSequence.obj One symbol, fSequenceMethods, won't match up automatically in objdiff until the mangling script is updated to handle method pointers properly. --- decompile/Makefile | 7 +- decompile/objdiff.json | 40 ++- decompile/src/JSRF/ActSequence.cpp | 425 +++++++++++++++++++++++++++++ decompile/src/JSRF/ActSequence.hpp | 90 ++++++ ghidra/make_header.sh | 1 + ghidra/objects.csv | 1 + 6 files changed, 549 insertions(+), 15 deletions(-) create mode 100644 decompile/src/JSRF/ActSequence.cpp create mode 100644 decompile/src/JSRF/ActSequence.hpp diff --git a/decompile/Makefile b/decompile/Makefile index 5e468b5..1f41eca 100644 --- a/decompile/Makefile +++ b/decompile/Makefile @@ -2,8 +2,8 @@ # An NMAKE Makefile to compile the game with the Visual C++ 7.0 toolchain # All object files to link together -OBJ = src/JSRF/Jet2.obj src/JSRF/Action.obj src/JSRF/SaveData.obj\ - src/XDK/Xapi/xapi0.obj +OBJ = src/JSRF/Jet2.obj src/JSRF/Action.obj src/JSRF/ActSequence.obj\ + src/JSRF/SaveData.obj src/XDK/Xapi/xapi0.obj # Import library for the only thing we don't compile ourselves, the Xbox kernel LIB = lib/xboxkrnl.lib @@ -44,6 +44,9 @@ src/JSRF/Jet2.obj: src/JSRF/Action.hpp src/XDK/CRT/stddef.h src/XDK/D3D.h\ src/JSRF/Action.obj: src/JSRF/Action.hpp src/MUSASHI/MMatrix.hpp\ src/XDK/CRT/stddef.h src/XDK/D3D.h src/XDK/Win32.h +src/JSRF/ActSequence.obj: src/JSRF/Action.hpp src/JSRF/ActSequence.hpp\ + src/JSRF/SaveData.hpp src/XDK/Win32.h + src/JSRF/SaveData.obj: src/JSRF/SaveData.hpp src/XDK/Xapi/xapi0.obj: src/XDK/Win32.h diff --git a/decompile/objdiff.json b/decompile/objdiff.json index 10bce88..de5fd0c 100644 --- a/decompile/objdiff.json +++ b/decompile/objdiff.json @@ -7,6 +7,33 @@ "*.hpp" ], "units": [ + { + "name": "JSRF/Action", + "target_path": "target/JSRF/Action.obj", + "base_path": "src/JSRF/Action.obj", + "metadata": { + "complete": false, + "source_path": "src/JSRF/Action.cpp" + }, + "symbol_mappings": { + "?nopMethod0Arg@CActBase@@UAEXXZ": "?Exec0Default@CActBase@@UAEXXZ", + "?nopMethod1Arg@CActBase@@UAEXI@Z": "?DrawListDefault@CActBase@@UAEXI@Z" + } + }, + { + "name": "JSRF/ActSequence", + "target_path": "target/JSRF/ActSequence.obj", + "base_path": "src/JSRF/ActSequence.obj", + "metadata": { + "complete": false, + "source_path": "src/JSRF/ActSequence.cpp" + }, + "symbol_mappings": { + "?Exec0Default__jumptable@CActSequence@@3EA": "$L1709", + "?Exec0Default__jumptargets@CActSequence@@3PAPAXA": "$L1710", + "?fSequenceMethods@CActSequence@@3PAP6EXPAU1@@ZA": "?fSequenceMethods@@3PAP8CActSequence@@AEXXZA" + } + }, { "name": "JSRF/Jet2", "target_path": "target/JSRF/Jet2.obj", @@ -23,19 +50,6 @@ "[.rdata-0]": "[.xdata$x-0]" } }, - { - "name": "JSRF/Action", - "target_path": "target/JSRF/Action.obj", - "base_path": "src/JSRF/Action.obj", - "metadata": { - "complete": false, - "source_path": "src/JSRF/Action.cpp" - }, - "symbol_mappings": { - "?nopMethod0Arg@CActBase@@UAEXXZ": "?Exec0Default@CActBase@@UAEXXZ", - "?nopMethod1Arg@CActBase@@UAEXI@Z": "?DrawListDefault@CActBase@@UAEXI@Z" - } - }, { "name": "JSRF/SaveData", "target_path": "target/JSRF/SaveData.obj", diff --git a/decompile/src/JSRF/ActSequence.cpp b/decompile/src/JSRF/ActSequence.cpp new file mode 100644 index 0000000..5b5737f --- /dev/null +++ b/decompile/src/JSRF/ActSequence.cpp @@ -0,0 +1,425 @@ +/* JSRF Decompilation: JSRF/ActSequence.cpp +CActSequence class managing the top-level game logic. +*/ + +#pragma bss_seg(".data") + +#include "ActSequence.hpp" +#include "SaveData.hpp" + +// Array of methods forming state machine; m_dwNextMethod holds the index of +// the method to call in the exec phase +void (CActSequence::*fSequenceMethods[])() = { + &CActSequence::Init, + &CActSequence::LoadSprNorm, + &CActSequence::WaitLoadSprNorm, + &CActSequence::StartBuildCache, + &CActSequence::WaitDestructAct0x1, + &CActSequence::SwitchOnGlobal, + &CActSequence::LoadLogos, + &CActSequence::StartLogos, + &CActSequence::WaitDestructLogos, + &CActSequence::FreeLogos, + &CActSequence::PrepareTitle, + &CActSequence::SetGlobal, + &CActSequence::WaitEndTitle, + &CActSequence::SwitchOnGlobal, + &CActSequence::PrepareHandleTitleMenuSelection, + &CActSequence::PrepareLoadGameMenu, + &CActSequence::WaitEndLoadGameMenu, + &CActSequence::LoadTags_MAYBE, + &CActSequence::WaitLoadTags_MAYBE, + &CActSequence::StartHandleTitleMenuSelection, + &CActSequence::LoadFullRoboyMenu, + &CActSequence::StartFullRoboyMenu, + &CActSequence::WaitEndFullRoboyMenu, + &CActSequence::ReturnFromFullRoboyMenu, + &CActSequence::nop, // Guess these were dummied out + &CActSequence::nop, + &CActSequence::nop, + &CActSequence::nop, + &CActSequence::PrepareStoryOrVsMission, + &CActSequence::NopStoryOrVsMission, + &CActSequence::WaitEndStoryOrVsMission, + &CActSequence::ReturnFromStoryOrVsMission, + &CActSequence::PrepareTutorial, + &CActSequence::NopTutorial, + &CActSequence::WaitEndTutorial, + &CActSequence::ReturnFromTutorial, + &CActSequence::PrepareTestRun, + &CActSequence::NopTestRun, + &CActSequence::WaitEndTestRun, + &CActSequence::ReturnFromTestRun, + &CActSequence::PrepareUnused, + &CActSequence::NopUnused, + &CActSequence::WaitEndUnused, + &CActSequence::ReturnFromUnused, + &CActSequence::PrepareGraffitiMenu, + &CActSequence::WaitLoadGraffitiMenu, + &CActSequence::WaitEndGraffitiMenu, + &CActSequence::ReturnFromGraffitiMenu, + &CActSequence::NopStinger, + &CActSequence::PrepareStinger, + &CActSequence::WaitEndStinger, + &CActSequence::ReturnFromStinger, + &CActSequence::PrepareEnding, + &CActSequence::WaitLoadEnding, + &CActSequence::WaitEndEnding, + &CActSequence::ReturnFromEnding, + &CActSequence::PrepareVsMenu, + &CActSequence::WaitLoadVsMenu, + &CActSequence::WaitEndVsMenu, + &CActSequence::ReturnFromVsMenu, + &CActSequence::PrepareEndingSaveMenu, + &CActSequence::StartEndingSaveMenu, + &CActSequence::WaitEndEndingSaveMenu, + &CActSequence::ReturnFromEndingSaveMenu +}; + +// Address: 0x0007BC10 +// Status: unimplemented +CActSequence::CActSequence(CActBase *lpParent, eACTID ActID, eACTFLAG ActFlag) : + CActBase(lpParent, ActID, ActFlag) { +} + +// Address: 0x0007BC90 +// Status: unimplemented +CActSequence::~CActSequence() { +} + +// Address: 0x0007BDD0 +// Status: matching +void CActSequence::Exec0Default() { + // Call queued state machine method + if (this->m_dwNextMethod < sizeof fSequenceMethods / sizeof *fSequenceMethods) + (this->*fSequenceMethods[this->m_dwNextMethod])(); + + // Increment save time for certain states + switch (this->m_dwNextMethod) { + case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: + case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: + case 0x1e: case 0x1f: case 0x20: case 0x21: case 0x22: + case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + g_SaveData.IncreasePlaytime(); + } +} + +// Eliminated by link time code generation (aliased with 0x0007BDD0) +void CActSequence::Exec0Event() { + this->Exec0Default(); +} + +// Eliminated by link time code generation (aliased with 0x0007BDD0) +void CActSequence::Exec0CoveredPause() { + this->Exec0Default(); +} + +// Eliminated by link time code generation (aliased with 0x0007BDD0) +void CActSequence::Exec0FreezeCam() { + this->Exec0Default(); +} + +// Eliminated by link time code generation (aliased with 0x0007BDD0) +void CActSequence::Exec0UncoveredPause() { + this->Exec0Default(); +} + +// Eliminated by link time code generation (aliased with 0x00011C90) +void CActSequence::nop() { +} + +// Address: 0x0007BE30 +// Status: unimplemented +void CActSequence::Init() { +} + +// Address: 0x0007BFD0 +// Status: unimplemented +void CActSequence::LoadSprNorm() { +} + +// Address: 0x0007C020 +// Status: unimplemented +void CActSequence::WaitLoadSprNorm() { +} + +// Address: 0x0007C050 +// Status: unimplemented +void CActSequence::StartBuildCache() { +} + +// Address: 0x0007C070 +// Status: unimplemented +void CActSequence::WaitDestructAct0x1() { +} + +// Address: 0x0007C090 +// Status: unimplemented +void CActSequence::LoadLogos() { +} + +// Address: 0x0007C0D0 +// Status: unimplemented +void CActSequence::StartLogos() { +} + +// Address: 0x0007C110 +// Status: unimplemented +void CActSequence::WaitDestructLogos() { +} + +// Address: 0x0007C140 +// Status: unimplemented +void CActSequence::FreeLogos() { +} + +// Address: 0x0007C160 +// Status: unimplemented +void CActSequence::PrepareTitle() { +} + +// Address: 0x0007C230 +// Status: unimplemented +void CActSequence::SetGlobal() { +} + +// Address: 0x0007C250 +// Status: unimplemented +void CActSequence::WaitEndTitle() { +} + +// Address: 0x0007C270 +// Status: unimplemented +void CActSequence::SwitchOnGlobal() { +} + +// Address: 0x0007C290 +// Status: unimplemented +void CActSequence::PrepareHandleTitleMenuSelection() { +} + +// Address: 0x0007C410 +// Status: unimplemented +void CActSequence::PrepareLoadGameMenu() { +} + +// Address: 0x0007C450 +// Status: unimplemented +void CActSequence::WaitEndLoadGameMenu() { +} + +// Address: 0x0007C4B0 +// Status: unimplemented +void CActSequence::LoadTags_MAYBE() { +} + +// Address: 0x0007C510 +// Status: unimplemented +void CActSequence::WaitLoadTags_MAYBE() { +} + +// Address: 0x0007C560 +// Status: unimplemented +void CActSequence::StartHandleTitleMenuSelection() { +} + +// Address: 0x0007C600 +// Status: unimplemented +void CActSequence::LoadFullRoboyMenu() { +} + +// Address: 0x0007C720 +// Status: unimplemented +void CActSequence::StartFullRoboyMenu() { +} + +// Address: 0x0007C7E0 +// Status: unimplemented +void CActSequence::WaitEndFullRoboyMenu() { +} + +// Address: 0x0007C800 +// Status: unimplemented +void CActSequence::ReturnFromFullRoboyMenu() { +} + +// Address: 0x0007C9E0 +// Status: unimplemented +void CActSequence::PrepareStoryOrVsMission() { +} + +// Address: 0x0007CA60 +// Status: unimplemented +void CActSequence::NopStoryOrVsMission() { +} + +// Address: 0x0007CA70 +// Status: unimplemented +void CActSequence::WaitEndStoryOrVsMission() { +} + +// Address: 0x0007CA90 +// Status: unimplemented +void CActSequence::ReturnFromStoryOrVsMission() { +} + +// Address: 0x0007CAE0 +// Status: unimplemented +void CActSequence::PrepareTutorial() { +} + +// Address: 0x0007CBB0 +// Status: unimplemented +void CActSequence::NopTutorial() { +} + +// Address: 0x0007CBC0 +// Status: unimplemented +void CActSequence::WaitEndTutorial() { +} + +// Address: 0x0007CBE0 +// Status: unimplemented +void CActSequence::ReturnFromTutorial() { +} + +// Address: 0x0007CC40 +// Status: unimplemented +void CActSequence::PrepareTestRun() { +} + +// Address: 0x0007CD10 +// Status: unimplemented +void CActSequence::NopTestRun() { +} + +// Address: 0x0007CD20 +// Status: unimplemented +void CActSequence::WaitEndTestRun() { +} + +// Address: 0x0007CD40 +// Status: unimplemented +void CActSequence::ReturnFromTestRun() { +} + +// Address: 0x0007CDA0 +// Status: unimplemented +void CActSequence::PrepareUnused() { +} + +// Address: 0x0007CE70 +// Status: unimplemented +void CActSequence::NopUnused() { +} + +// Address: 0x0007CE80 +// Status: unimplemented +void CActSequence::WaitEndUnused() { +} + +// Address: 0x0007CEA0 +// Status: unimplemented +void CActSequence::ReturnFromUnused() { +} + +// Address: 0x0007CF00 +// Status: unimplemented +void CActSequence::PrepareGraffitiMenu() { +} + +// Address: 0x0007CFB0 +// Status: unimplemented +void CActSequence::WaitLoadGraffitiMenu() { +} + +// Address: 0x0007CFE0 +// Status: unimplemented +void CActSequence::WaitEndGraffitiMenu() { +} + +// Address: 0x0007D000 +// Status: unimplemented +void CActSequence::ReturnFromGraffitiMenu() { +} + +// Address: 0x0007D030 +// Status: unimplemented +void CActSequence::PrepareVsMenu() { +} + +// Address: 0x0007D080 +// Status: unimplemented +void CActSequence::WaitLoadVsMenu() { +} + +// Address: 0x0007D100 +// Status: unimplemented +void CActSequence::WaitEndVsMenu() { +} + +// Address: 0x0007D120 +// Status: unimplemented +void CActSequence::ReturnFromVsMenu() { +} + +// Address: 0x0007D1A0 +// Status: unimplemented +void CActSequence::PrepareEndingSaveMenu() { +} + +// Address: 0x0007D210 +// Status: unimplemented +void CActSequence::StartEndingSaveMenu() { +} + +// Address: 0x0007D270 +// Status: unimplemented +void CActSequence::WaitEndEndingSaveMenu() { +} + +// Address: 0x0007D290 +// Status: unimplemented +void CActSequence::ReturnFromEndingSaveMenu() { +} + +// Address: 0x0007D2D0 +// Status: unimplemented +void CActSequence::PrepareEnding() { +} + +// Address: 0x0007D320 +// Status: unimplemented +void CActSequence::WaitLoadEnding() { +} + +// Address: 0x0007D3D0 +// Status: unimplemented +void CActSequence::WaitEndEnding() { +} + +// Address: 0x0007D3F0 +// Status: unimplemented +void CActSequence::ReturnFromEnding() { +} + +// Address: 0x0007D450 +// Status: unimplemented +void CActSequence::NopStinger() { +} + +// Address: 0x0007D460 +// Status: unimplemented +void CActSequence::PrepareStinger() { +} + +// Address: 0x0007D520 +// Status: unimplemented +void CActSequence::WaitEndStinger() { +} + +// Address: 0x0007D540 +// Status: unimplemented +void CActSequence::ReturnFromStinger() { +} diff --git a/decompile/src/JSRF/ActSequence.hpp b/decompile/src/JSRF/ActSequence.hpp new file mode 100644 index 0000000..10d4c66 --- /dev/null +++ b/decompile/src/JSRF/ActSequence.hpp @@ -0,0 +1,90 @@ +/* JSRF Decompilation: JSRF/ActSequence.hpp +CActSequence class managing the top-level game logic. +*/ + +#ifndef ACTSEQUENCE_HPP +#define ACTSEQUENCE_HPP + +#include "Action.hpp" +#include "../XDK/Win32.h" + + +struct CActSequence : CActBase { + DWORD m_dwChapterBackup; // Holds chapter to return to + DWORD m_dwNextMethod; // Next method to call in state machine + + CActSequence(CActBase *lpParent, eACTID ActID, eACTFLAG Flags); + virtual ~CActSequence(); + + void Exec0Default(); + void Exec0Event(); + void Exec0CoveredPause(); + void Exec0FreezeCam(); + void Exec0UncoveredPause(); + + void nop(); + + // Methods forming state machine + void Init(); + void LoadSprNorm(); + void WaitLoadSprNorm(); + void StartBuildCache(); + void WaitDestructAct0x1(); + void LoadLogos(); + void StartLogos(); + void WaitDestructLogos(); + void FreeLogos(); + void PrepareTitle(); + void SetGlobal(); + void WaitEndTitle(); + void SwitchOnGlobal(); + void PrepareHandleTitleMenuSelection(); + void PrepareLoadGameMenu(); + void WaitEndLoadGameMenu(); + void LoadTags_MAYBE(); + void WaitLoadTags_MAYBE(); + void StartHandleTitleMenuSelection(); + void LoadFullRoboyMenu(); + void StartFullRoboyMenu(); + void WaitEndFullRoboyMenu(); + void ReturnFromFullRoboyMenu(); + void PrepareStoryOrVsMission(); + void NopStoryOrVsMission(); + void WaitEndStoryOrVsMission(); + void ReturnFromStoryOrVsMission(); + void PrepareTutorial(); + void NopTutorial(); + void WaitEndTutorial(); + void ReturnFromTutorial(); + void PrepareTestRun(); + void NopTestRun(); + void WaitEndTestRun(); + void ReturnFromTestRun(); + void PrepareUnused(); + void NopUnused(); + void WaitEndUnused(); + void ReturnFromUnused(); + void PrepareGraffitiMenu(); + void WaitLoadGraffitiMenu(); + void WaitEndGraffitiMenu(); + void ReturnFromGraffitiMenu(); + void PrepareVsMenu(); + void WaitLoadVsMenu(); + void WaitEndVsMenu(); + void ReturnFromVsMenu(); + void PrepareEndingSaveMenu(); + void StartEndingSaveMenu(); + void WaitEndEndingSaveMenu(); + void ReturnFromEndingSaveMenu(); + void PrepareEnding(); + void WaitLoadEnding(); + void WaitEndEnding(); + void ReturnFromEnding(); + void NopStinger(); + void PrepareStinger(); + void WaitEndStinger(); + void ReturnFromStinger(); +}; + + +#endif diff --git a/ghidra/make_header.sh b/ghidra/make_header.sh index a2aaabf..d0a3050 100755 --- a/ghidra/make_header.sh +++ b/ghidra/make_header.sh @@ -14,6 +14,7 @@ HEADERS=" XDK/D3D.h MUSASHI/MMatrix.hpp JSRF/Action.hpp + JSRF/ActSequence.hpp JSRF/SaveData.hpp " diff --git a/ghidra/objects.csv b/ghidra/objects.csv index 5b18483..635602c 100644 --- a/ghidra/objects.csv +++ b/ghidra/objects.csv @@ -2,6 +2,7 @@ Object,Delink?,.text,.text$yc,.text$yd,.text$x,D3D,DSOUND,MMATRIX,XGRPH,XPP,.rda JSRF/Action.obj,true,0x00011000-0x00013FEB,,,0x00186BA0-0x00186C14,,,,,,0x001C4390-0x001C44F9,0x001E4D20-0x001E4DAB,,0x001EB880-0x001EB933, JSRF/SaveData.obj,true,0x00039B50-0x0003B937,0x0018AD60-0x0018AD75,0x0018C9A0-0x0018C9AA,,,,,,,0x001CA16C-0x001CA3DB,,0x001EB790-0x001EB793,0x001EFC88-0x001F7047, JSRF/Jet2.obj,true,0x0006F9E0-0x0006FA6F,,,0x00187710-0x00187724,,,,,,,0x001E620C-0x001E622F,,0x0022FCE0-0x0022FCE3, +JSRF/ActSequence.obj,true,0x0007BC10-0x0007D5CF,,,0x00187C70-0x00187CD4,,,,,,0x001CCEB8-0x001CCEF7,0x001E67EC-0x001E69CF,,0x0020D2B8-0x0020D3B7, ADX (need to decompose),false,0x0013A570-0x0014555F,?,?,?,?,,,,,,?,?,?, Xapi (need to decompose),false,0x00145560-0x0014B79F,?,?,?,?,,,,,,?,?,?, XDK/Xapi/xapi0.obj,true,0x00147FB4-0x0014807C,,,,,,,,,,,,, From 639bb551085072e5455832b81dfeaf3cceccc340 Mon Sep 17 00:00:00 2001 From: KeybadeBlox Date: Sun, 19 Apr 2026 17:29:59 -0400 Subject: [PATCH 2/3] Update progress --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 25abed9..698c211 100644 --- a/readme.md +++ b/readme.md @@ -2,8 +2,8 @@ A matching decompilation of the Xbox game Jet Set Radio Future. ## Progress -- Delinking progress: 1.03% (26559 out of 2574172 bytes in XBE address space) -- Decompilation progress: 19.6% (33 out of the 168 functions delinked so far) +- Delinking progress: 1.32% (34051 out of 2574172 bytes in XBE address space) +- Decompilation progress: 14.6% (37 out of the 241 delinked `.text` symbols) - **Estimated total progress: 0.20%** (previous two multiplied together) ## Roadmap From ef16b09a968608fc260df2d2a32919b9fa539e6f Mon Sep 17 00:00:00 2001 From: KeybadeBlox Date: Sun, 19 Apr 2026 17:31:41 -0400 Subject: [PATCH 3/3] Revise progress wording We're not only counting .text, but any sections meant to hold code (e.g. MMATRIX). --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 698c211..ac92b92 100644 --- a/readme.md +++ b/readme.md @@ -3,7 +3,7 @@ A matching decompilation of the Xbox game Jet Set Radio Future. ## Progress - Delinking progress: 1.32% (34051 out of 2574172 bytes in XBE address space) -- Decompilation progress: 14.6% (37 out of the 241 delinked `.text` symbols) +- Decompilation progress: 14.6% (37 out of the 241 delinked code symbols) - **Estimated total progress: 0.20%** (previous two multiplied together) ## Roadmap