mirror of
https://github.com/ethteck/kh1.git
synced 2024-11-26 23:10:45 +00:00
Initial Support for new game version: Final Mix (#59)
* Initial Support for new game version: Final Mix * Rephrased and renamed a few things
This commit is contained in:
parent
0c600c281f
commit
6b154ced98
2
.gitignore
vendored
2
.gitignore
vendored
@ -11,7 +11,9 @@ undefined_funcs_auto.txt
|
||||
.ninja_log
|
||||
.splache
|
||||
build.ninja
|
||||
|
||||
SLPS_251.05*
|
||||
SLPS_251.98*
|
||||
|
||||
*.iso
|
||||
*.bin
|
||||
|
41
README.md
41
README.md
@ -1,12 +1,41 @@
|
||||
# Kingdom Hearts Decompilation
|
||||
# Kingdom Hearts De:Compiled
|
||||
|
||||
We're currently just targeting the main game executable, which is an elf file `SLPS_251.05` with sha1 `9dabbf867a7ec2a030df99ba1ed969f2deef0488`.
|
||||
A decompilation of the Playstation 2 releases of Kingdom Hearts.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Game Version | ELF | Sha1 |
|
||||
|--------------------------|---------------|------------------------------------------|
|
||||
| Original Japanese | `SLPS_251.05` |`9dabbf867a7ec2a030df99ba1ed969f2deef0488`|
|
||||
| Final Mix (JP Exclusive) | `SLPS_251.98` |`e70bda789916142aafb53d85cef2e806b35ad8d8`|
|
||||
|
||||
---
|
||||
|
||||
### Dependencies
|
||||
We require some python deps you can obtain by running `pip install -U -r requirements.txt`.
|
||||
|
||||
Some python dependencies are required, which you can obtain by running `pip install -U -r requirements.txt`.
|
||||
|
||||
---
|
||||
|
||||
### Setup
|
||||
|
||||
1. Extract `SLPS_251.05` from an ISO of the Kingdom Hearts (JP) and place it in the root of the repo.
|
||||
2. `./configure.py`
|
||||
3. `ninja`
|
||||
1. Extract the ELF file from an ISO of the game version you're targeting and place it in the root of the repo.
|
||||
2. Run `./configure.py` to generate the build files.
|
||||
- Optionally, specify the game version you're targeting with the `--version`/`-v` flag. Defaults to the original Japanese version if not specified.
|
||||
- You can clear existing configurations with the `--clean`/`-c` flag
|
||||
- eg: `./configure.py -c -v fm` will clear the existing build configuration and generate a new one for the Final Mix version.
|
||||
|
||||
3. Run `ninja` to build the project. Final output will be stored by version in the `build` directory.
|
||||
|
||||
---
|
||||
|
||||
### Notes
|
||||
|
||||
No game assets are published in this repository. This includes any files required to run the game, such as the game's executable, ISO, or any files extracted from it.
|
||||
|
||||
This repository targets the game's main executable, an elf file named uniquely by the game's serial number. A copy of the elf file is required to build the project, and must be provided by the user by extracting it from a legal copy of the game.
|
||||
|
||||
>[!WARNING]
|
||||
> Additional asset extraction is currently only supported by the JP version of the game.
|
||||
|
||||
Additional assets that are not used in this project may optionally be extracted by running `./tools/iso/extract.py` on the game's ISO. The extracted files are in the `kingdom` directory.
|
||||
|
@ -1 +0,0 @@
|
||||
9dabbf867a7ec2a030df99ba1ed969f2deef0488 build/SLPS_251.05
|
1
config/fm/checksum.sha1
Normal file
1
config/fm/checksum.sha1
Normal file
@ -0,0 +1 @@
|
||||
e70bda789916142aafb53d85cef2e806b35ad8d8 build/fm/SLPS_251.98
|
33
config/fm/symbol_addrs.txt
Normal file
33
config/fm/symbol_addrs.txt
Normal file
@ -0,0 +1,33 @@
|
||||
//=============================
|
||||
// worldfile.c
|
||||
//=============================
|
||||
worldfile_getAbbr = 0x00112270; // type:func
|
||||
worldfile_getNameNoSet = 0x00112298; // type:func
|
||||
worldfile_getNames = 0x00112320; // type:func
|
||||
worldfile_getBinImgName = 0x00112400; // type:func
|
||||
|
||||
//=============================
|
||||
// worldfile.c
|
||||
//=============================
|
||||
worldAbbrs = 0x002BCC28; // size:0x58
|
||||
worldDataExt = 0x002BCC80; // size:0x8
|
||||
roomArchiveExt = 0x002BCC88; // size:0x8
|
||||
|
||||
D_002B91E0 = 0x002BCC90; // size:0x4
|
||||
D_002B91E4 = 0x002BCC94; // size:0x4
|
||||
D_002B91E8 = 0x002BCC98; // size:0x4
|
||||
D_002B91EC = 0x002BCC9C; // size:0x4
|
||||
|
||||
D_002B8678 = 0x002BC128; // size:0x4
|
||||
D_002B8680 = 0x002BC130; // size:0x4
|
||||
|
||||
worldDataFile = 0x002BCCA0; // size:0x40
|
||||
worldBinImgFile = 0x002BCCE0; // size:0x40
|
||||
roomArchiveRaw = 0x002BCD20; // size:0x40
|
||||
roomArchiveFile = 0x002BCD60; // size:0x40
|
||||
|
||||
|
||||
sprintf = 0x00250EB0; // type:func
|
||||
strcat = 0x00250F40; // type:func
|
||||
strcpy = 0x002511B0; // type:func
|
||||
|
0
config/fm/undefined_syms.txt
Normal file
0
config/fm/undefined_syms.txt
Normal file
1
config/jp/checksum.sha1
Normal file
1
config/jp/checksum.sha1
Normal file
@ -0,0 +1 @@
|
||||
9dabbf867a7ec2a030df99ba1ed969f2deef0488 build/jp/SLPS_251.05
|
2
config/jp/undefined_syms.txt
Normal file
2
config/jp/undefined_syms.txt
Normal file
@ -0,0 +1,2 @@
|
||||
D_555ED0 = 0x555ED0;
|
||||
D_00555ED0 = 0x00555ED0;
|
48
config/kh.fm.yaml
Normal file
48
config/kh.fm.yaml
Normal file
@ -0,0 +1,48 @@
|
||||
name: Kingdom Hearts (Final Mix)
|
||||
sha1: e70bda789916142aafb53d85cef2e806b35ad8d8
|
||||
options:
|
||||
basename: SLPS_251.98
|
||||
target_path: SLPS_251.98
|
||||
base_path: ..
|
||||
compiler: EEGCC
|
||||
find_file_boundaries: False
|
||||
platform: ps2
|
||||
create_undefined_funcs_auto: True
|
||||
undefined_funcs_auto_path: config/fm/undefined_funcs_auto.txt
|
||||
create_undefined_syms_auto: True
|
||||
undefined_syms_auto_path: config/fm/undefined_syms_auto.txt
|
||||
symbol_addrs_path: config/fm/symbol_addrs.txt
|
||||
asm_path: asm
|
||||
src_path: src
|
||||
build_path: build/fm
|
||||
extensions_path: tools/splat_ext
|
||||
section_order: [".text", ".data", ".rodata", ".bss"]
|
||||
auto_link_sections: [".data", ".rodata", ".bss"]
|
||||
subalign: 8
|
||||
disasm_unknown: True
|
||||
named_regs_for_c_funcs: False
|
||||
segments:
|
||||
- [0, databin, elf_header]
|
||||
- name: main
|
||||
type: code
|
||||
start: 0x80
|
||||
vram: 0x100000
|
||||
bss_size: 0x1E0F80
|
||||
subsegments:
|
||||
- [0x80, asm, crt0]
|
||||
- [0x258, asm]
|
||||
- [0x122F0, c, worldfile]
|
||||
- [0x12518, asm]
|
||||
|
||||
|
||||
- [0x172CF0, data]
|
||||
- [0x1BCCA8, .data, worldfile]
|
||||
- [0x1BCE20, data]
|
||||
|
||||
- [0x38CC90, rodata]
|
||||
- [0x38CFF0, .rodata, worldfile]
|
||||
- [0x38D088, rodata]
|
||||
|
||||
- [0x394100, databin] # .reginfo / segment_1.2
|
||||
- [0x394118, databin]
|
||||
- [0x3A0CC8]
|
@ -3,21 +3,21 @@ sha1: 9dabbf867a7ec2a030df99ba1ed969f2deef0488
|
||||
options:
|
||||
basename: SLPS_251.05
|
||||
target_path: SLPS_251.05
|
||||
base_path: .
|
||||
base_path: ..
|
||||
compiler: EEGCC
|
||||
find_file_boundaries: False
|
||||
platform: ps2
|
||||
create_undefined_funcs_auto: True
|
||||
undefined_funcs_auto_path: undefined_funcs_auto.txt
|
||||
undefined_funcs_auto_path: config/jp/undefined_funcs_auto.txt
|
||||
create_undefined_syms_auto: True
|
||||
undefined_syms_auto_path: undefined_syms_auto.txt
|
||||
symbol_addrs_path: symbol_addrs.txt
|
||||
undefined_syms_auto_path: config/jp/undefined_syms_auto.txt
|
||||
symbol_addrs_path: config/jp/symbol_addrs.txt
|
||||
asm_path: asm
|
||||
src_path: src
|
||||
build_path: build
|
||||
build_path: build/jp
|
||||
extensions_path: tools/splat_ext
|
||||
section_order: [".text", ".data", ".rodata", ".bss"]
|
||||
auto_all_sections: [".data", ".rodata", ".bss"]
|
||||
auto_link_sections: [".data", ".rodata", ".bss"]
|
||||
subalign: 8
|
||||
disasm_unknown: True
|
||||
named_regs_for_c_funcs: False
|
||||
@ -689,7 +689,8 @@ segments:
|
||||
- [0x38DA70, rodata, libm/sf_atan]
|
||||
# - [0x38DAC4, rodata, libm/sf_floor]
|
||||
- [0x38DAC8, rodata, libm/sf_scalbn]
|
||||
- [0x38DAD8, rodata, lib/libmc]
|
||||
- [0x38DAD8, .rodata, lib/libmc]
|
||||
- [0x38DB60, rodata]
|
||||
- [0x38DB80, databin] # .reginfo / segment_1.2
|
||||
- [0x38DB98, databin]
|
||||
- [0x39A680]
|
41
configure.py
41
configure.py
@ -15,12 +15,14 @@ from splat.segtypes.linker_entry import LinkerEntry
|
||||
ROOT = Path(__file__).parent.resolve()
|
||||
TOOLS_DIR = ROOT / "tools"
|
||||
|
||||
YAML_FILE = "kh.jp.yaml"
|
||||
VERSION = "jp"
|
||||
BASENAME = "SLPS_251.05"
|
||||
YAML_FILE = f"config/kh.{VERSION}.yaml"
|
||||
|
||||
LD_PATH = f"{BASENAME}.ld"
|
||||
ELF_PATH = f"build/{BASENAME}"
|
||||
MAP_PATH = f"build/{BASENAME}.map"
|
||||
PRE_ELF_PATH = f"build/{BASENAME}.elf"
|
||||
ELF_PATH = f"build/{VERSION}/{BASENAME}"
|
||||
MAP_PATH = f"build/{VERSION}/{BASENAME}.map"
|
||||
PRE_ELF_PATH = f"build/{VERSION}/{BASENAME}.elf"
|
||||
|
||||
COMMON_INCLUDES = "-Iinclude -isystem include/sdk/ee -isystem include/gcc"
|
||||
|
||||
@ -94,7 +96,9 @@ def build_stuff(linker_entries: List[LinkerEntry]):
|
||||
# Rules
|
||||
cross = "mips-linux-gnu-"
|
||||
|
||||
ld_args = f"-EL -T undefined_syms.txt -T undefined_syms_auto.txt -T undefined_funcs_auto.txt -Map $mapfile -T $in -o $out"
|
||||
config = f"config/{VERSION}"
|
||||
|
||||
ld_args = f"-EL -T {config}/undefined_syms.txt -T {config}/undefined_syms_auto.txt -T {config}/undefined_funcs_auto.txt -Map $mapfile -T $in -o $out"
|
||||
|
||||
ninja.rule(
|
||||
"as",
|
||||
@ -179,13 +183,19 @@ def build_stuff(linker_entries: List[LinkerEntry]):
|
||||
ninja.build(
|
||||
ELF_PATH + ".ok",
|
||||
"sha1sum",
|
||||
"checksum.sha1",
|
||||
f"config/{VERSION}/checksum.sha1",
|
||||
implicit=[ELF_PATH],
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Configure the project")
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--version",
|
||||
help="Game version to configure for",
|
||||
choices=["jp", "fm"],
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--clean",
|
||||
@ -194,9 +204,28 @@ if __name__ == "__main__":
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.version:
|
||||
VERSION = args.version
|
||||
else:
|
||||
VERSION = "jp"
|
||||
|
||||
BASENAME = {
|
||||
"jp": "SLPS_251.05",
|
||||
"fm": "SLPS_251.98",
|
||||
}[VERSION]
|
||||
|
||||
LD_PATH = f"{BASENAME}.ld"
|
||||
ELF_PATH = f"build/{VERSION}/{BASENAME}"
|
||||
MAP_PATH = f"build/{VERSION}/{BASENAME}.map"
|
||||
PRE_ELF_PATH = f"build/{VERSION}/{BASENAME}.elf"
|
||||
|
||||
if args.clean:
|
||||
clean()
|
||||
|
||||
print(f"Kingdom Hearts De:Compiled ~ Generating build configuration for {VERSION}")
|
||||
|
||||
YAML_FILE = f"config/kh.{VERSION}.yaml"
|
||||
|
||||
split.main([YAML_FILE], modes="all", verbose=False)
|
||||
|
||||
linker_entries = split.linker_writer.entries
|
||||
|
@ -1,4 +1,4 @@
|
||||
spimdisasm>=1.18.0
|
||||
spimdisasm>=1.28.1
|
||||
rabbitizer>=1.8.0
|
||||
splat64>=0.21.0
|
||||
splat64>=0.27.0
|
||||
tqdm
|
||||
|
@ -29,12 +29,6 @@ typedef struct {
|
||||
s32 semaidRegFunc;
|
||||
s32 mcRunCmdNo;
|
||||
|
||||
// todo: rodata split, blocked by libc constants (0x38DB60 to rodata end)
|
||||
char D_0048DA58[24]; // "bind error libmc \n";
|
||||
char D_0048DA70[40]; // "libmc: too old release of mcserv.irx\n";
|
||||
char D_0048DA98[40]; // "libmc: too old release of mcman.irx\n";
|
||||
char D_0048DAC0[32]; // "sceMcUdCheckNewCard RPC faild\n";
|
||||
|
||||
sceSifClientData mcClientID;
|
||||
SifParams mcSifParams;
|
||||
McStatus mcStatus;
|
||||
@ -66,7 +60,7 @@ s32 sceMcInit(void) {
|
||||
|
||||
while (TRUE) {
|
||||
if (sceSifBindRpc(&mcClientID, 0x80000400, 0) < 0) {
|
||||
printf(D_0048DA58);
|
||||
printf("bind error libmc \n");
|
||||
do {
|
||||
/* infinite loop */
|
||||
} while (TRUE);
|
||||
@ -87,12 +81,12 @@ s32 sceMcInit(void) {
|
||||
mcClientID.serve = NULL;
|
||||
return sifServerStat - 100;
|
||||
} else if (mcRetVal[1] < 0x20A) {
|
||||
printf(D_0048DA70);
|
||||
printf("libmc: too old release of mcserv.irx\n");
|
||||
mcClientID.serve = NULL;
|
||||
return sceMcIniOldMcserv;
|
||||
} else {
|
||||
if (mcRetVal[2] < 0x20E) {
|
||||
printf(D_0048DA98);
|
||||
printf("libmc: too old release of mcman.irx\n");
|
||||
mcClientID.serve = NULL;
|
||||
return sceMcIniOldMcman;
|
||||
}
|
||||
@ -344,7 +338,7 @@ INCLUDE_ASM("asm/nonmatchings/lib/libmc", sceMcGetInfo);
|
||||
|
||||
s32 sceMcUdCheckNewCard(void) {
|
||||
if (sceSifCallRpc(&mcClientID, 0x35, 0, &mcSifParams, sizeof(mcSifParams), &mcRetVal, 4, NULL, NULL) != 0) {
|
||||
printf(D_0048DAC0);
|
||||
printf("sceMcUdCheckNewCard RPC faild\n");
|
||||
return -1;
|
||||
}
|
||||
return mcRetVal[0];
|
||||
|
@ -141,11 +141,11 @@ if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument("iso_path", help="Path to ISO file", type=Path)
|
||||
parser.add_argument("out_dir", help="Path to output directory", type=Path)
|
||||
args = parser.parse_args()
|
||||
|
||||
kingdom_files: List[KingdomFile] = []
|
||||
filenames = get_filenames()
|
||||
out_dir: str = "kingdom"
|
||||
|
||||
print("Reading ISO...\r", end="")
|
||||
with open(args.iso_path, "rb") as f:
|
||||
@ -167,7 +167,7 @@ if __name__ == "__main__":
|
||||
for entry in kingdom_files:
|
||||
if entry.filename is None:
|
||||
entry.filename = f"unknown/{entry.hash:08X}.bin"
|
||||
path: Path = args.out_dir / entry.filename
|
||||
path: Path = out_dir / Path(entry.filename)
|
||||
pbar.set_description("Extracting " + path.name.ljust(14))
|
||||
iso_bytes.seek(cnf_start + entry.iso_block * BLOCK_LENGTH)
|
||||
contents = iso_bytes.read(entry.length)
|
||||
|
Loading…
Reference in New Issue
Block a user