Skip to content

Instantly share code, notes, and snippets.

@osyu
Last active October 16, 2024 19:24
Show Gist options
  • Select an option

  • Save osyu/895c38cf77f08853353988780e52dfc0 to your computer and use it in GitHub Desktop.

Select an option

Save osyu/895c38cf77f08853353988780e52dfc0 to your computer and use it in GitHub Desktop.
Ghost Trick remaster docs

(guides assume you're on Windows)

How to extract game assets

short answer

long answer

primer:

  • Ghost Trick runs on Capcom's RE Engine. REtool is an unofficial tool for dealing with the engine's file formats
  • all resources are stored in a big file named re_chunk_000.pak located in the game's installation directory (which is accessible in steam through [right click] > Manage > Browse local files)
  • unlike a typical archive format like .zip/.rar/.7z, .pak files don't have filenames plainly stored in a way that REtool can reliably retrieve, so you also need to give it a list of names to read from so it knows what to name the things it's extracting. if you don't, you'll be stuck with a bunch of files without discernable names and your life will become harder

what to do:

  • download RETool from the link above and extract REtool.exe to the game's installation directory (the same folder as re_chunk_000.pak)
  • download the filepath list from the link above, into the same folder
  • open a command prompt in that folder. there are a billion ways to do this but the easiest way is typing cmd into the address bar in file explorer
  • type retool -h GTPD_PC_Release.list -x re_chunk_000.pak to extract everything. when it's done there'll be a folder named re_chunk_000 with all the stuff
  • you'll notice there are still hundreds of files without proper names (that look something like 15349567-2389623703.bin). this is normal and most of those files are unimportant/not unique to Ghost Trick, so you can ignore them. it happens because the list we passed to REtool has most but not all filenames, so anything missing will end up with a name like that

How to convert game assets to common formats

(everything here assumes you've just done all the things above)

.tex (textures)

  • type for /r %f in (*.tex.*) do retool -tex %f. this will recursively convert every .tex file to .dds, which is readable by image editing programs like paint.net

.asrc (audio)

  • they're just .wav files with an extra header in front. you have two options:
    • if you have Python installed, run this script to convert to and from the format
    • open up a hex editor (e.g. HxD) and remove the first 78 (0x4e) bytes, then change the file extension to .wav

.mov (video)

  • they're just .wmv files. change the file extension to .wmv and you're set
  • except for natives/stm/streaming/movie/igt_op_480x320_500kbps.mov.1, that's an .mp4

.msg (text)

  • download REMSG_Converter, and type for /r %f in (*.msg.*) do remsg_converter %f to convert recursively to .csv, which you can open in excel or any text editor. add -m json to use json instead

.oft (fonts)

  • these are encrypted OpenType and TrueType font files. you can encrypt/decrypt them using REE.FontsCryptor from the REE.PAK.Tool repository (as of writing binaries aren't provided, you'll have to build it yourself)

.user/.scn/.pfb (objects, scenes, prefabs)

  • you can use the RE_RSZ 010 Editor template to read and edit these

Where the hey is everything

(this is a non-exhaustive list)

textures

  • facepics/portraits: natives/stm/charfiles/3d/08_face
  • backgrounds: natives/stm/charfiles/2d/02_bg
  • character animations: natives/stm/charfiles/2d/01_human
  • object animations: natives/stm/charfiles/2d/03_gimmick
  • ui: natives/stm/charfiles/3d/06_id

audio

  • bgm:
    • remastered: natives/stm/streaming/sound/bgm_new
    • original: natives/stm/streaming/sound/bgm_resource
  • sound effects: natives/stm/streaming/sound/se_resource

video

  • cutscenes: natives/stm/streaming/gui/ui010500/tex
  • unused trailer: natives/stm/streaming/movie

text

  • it's all in natives/stm/gamedesign/text

fonts

  • they're in natives/stm/gui/font/outlinefont

Internal names

stages

  • Junkyard - st01
  • Pigeon Man's Office - st02
  • Prison - st03
  • The Chicken Kitchen - st04
  • Lady's Red Apartment - st05
  • Lynne's Apartment - st06
  • Kamila's Old House - st07
  • Office of the Troubled Man - st09
  • Drive to Chicken Kitchen - st10
  • Special Investigation Unit - st11
  • Temsik Park - st13
  • The Yonoa - st14
  • Prologue & Credits - st15

characters

  • Sissel (human) - cicel
  • Sissel (cat) - neko (猫, lit. "cat")
  • Lynne - linne
  • Ray - kuneri
  • Nearsighted Jeego - killera
  • Commander Sith - sisu
  • Masked Muscleman - migi (右, lit. "right")
  • "One Step Ahead" Tengo - killerb
  • Kamila - girl
  • Missile - pome ("pome[narian]")
  • Emma - fujin (婦人, lit. "madam")
  • Amelie - eimin (永眠, lit. "death")
  • Justice Minister - daijin (大臣, lit. "minister")
  • Detective Mccaw - keijig (刑事, lit. "detective g[reen]")
  • The Blue Detective - keijib (刑事, lit. "detective b[lue]")
  • Odd Blue Doctor - doc
  • Inspector Cabanela - kaba
  • Detective Rindge - caron
  • Guardian of the Park - birakubari (ビラ配り, lit. "handing out leaflets")
  • Pigeon Man - kanri (管理, lit. "management")
  • Chicken Kitchen Cook - cock
  • Typical Cop - keikan (警官, lit. "policeman")
  • Officer Bailey - keibia (警備, lit. "guard a")
  • Rock Jailbird - rock
  • Curry-loving Jailbird - shujinb
  • Detective Jowd - jodo
  • SIU Chief - bucho (部長, lit. "department head")
  • Memry - waitress
  • Dandy - yukaib
  • Beauty - yukaia
  • Chicken Kitchen Bartender - barten ("barten[der]")
  • Alma - mama
  • Minor Crew Hand - zako (雑魚, lit. "small fry")

Modding tools

  • Fluffy Mod Manager - mod manager for RE Engine games (for modifying assets)
  • REFramework - scripting and mod framework (for modifying game logic)
@osyu
Copy link
Author

osyu commented Jan 2, 2024

use it in a command prompt with the syntax: REE.FontsCryptor <input filepath> <output filepath>, e.g. REE.FontsCryptor whatever.oft.1 whatever.otf. to re-encrypt pass an unencrypted font in as the input file

@student197
Copy link

Do you know how to edit textures in PS4 and SWITCH versions? In the switch version, after converting from .tex to .dds, textures do not want to open in paint net. And the PS4 version they open, but the image seems to be "distorted".
image

@osyu
Copy link
Author

osyu commented Jan 5, 2024

This gist is for the PC version only, you can find info on modding console versions of RE Engine games elsewhere

@student197
Copy link

How did you create the GTPD_PC_Release.list file? How did you sort the files into folders and give them "normal" names? It's just that when Apollo Justice Ace Attorney trilogy is released, I want to translate it into my own language and such a file would help me a lot.

@osyu
Copy link
Author

osyu commented Jan 15, 2024

RE Engine paks only have a list of filepath hashes (murmur3) in the header rather than the filepaths themselves. thankfully the RSZ data (.user, .pfb, .scn) refer to files by path, and the engine hashes those paths on the fly to find them in the pak file. that's why retool needs a list of known filepaths; it compares each filepath hash to the hashes of each path in the list to find a match.

i made the filelist by naively searching through each RSZ file with regex for things that look like filepaths, doing a bunch of other ugly post-processing on that list to find more paths (e.g. giving each path all the language-specific file extensions), then giving the result to retool, which will filter out all the bad paths (since they don't match any hash in the pak file). this is definitely not the best way, it's far better to parse the RSZ files properly using e.g. the 010 Editor template linked above and then searching its hierarchy for filepaths instead (or better yet, just throw every unique string in the list; retool will take a while but at least you know for sure you're not missing anything).

some filepaths are hardcoded into the engine so their paths are in the game executable rather than referenced by files in the pak. for those you can use the live path dumper at https://github.com/praydog/REFramework/tree/master/reversing/scripts/pathdumper which will list out all the paths the game loads at runtime. this can be used to dump the paths in the RSZ files too but you won't get anything that the game doesn't try to access (e.g. if you don't get to chapter 2 in-game, it can't dump the filepaths for its assets because the game never loads them).

tldr: it's not a fun process and you're better off waiting a few weeks for someone else to make a list for everyone to use. i ended up doing it for ghost trick only because i really wanted to extract some of the game's animations and i had some time on my hands to learn about how re engine works

@niltwill
Copy link

I tried to play around a bit with modding the BGM files, thanks to your .asrc Python script. Here is what I figured out so far, though I have yet to replace any BGM.

Below is an example encoding from cmd (script is placed in the same folder as the audio file), using the bgm01 remastered track, so this should give back the same thing as the original .asrc.26 file:

python asrc.py e -bgm -ls 395447 393550592 bgm01_new.wav

If I understood the help instructions right...

-bgm is for background music, this is probably not to be used with sound effects and other audio that is not of this nature.
-ls is to define the starting loop point sample (also the track should be cut exactly where the looping end sample/point should be).

After that, next is the audio id, which was unspecified how to get. A hex editor is needed now to take a peek in the original .asrc.26 file... After some trial and error, this should probably reflect the original's track ID at block(h) 14-18? And then we need to read the UInt32 value with a hex editor, and provide that. For example, the audio source id for "bgm01_new.asrc.26" is "393550592"

I also figured out how to read the start loop sample. Block(h) 2D-2F is what contains that. To do this manually, this online converter helps.

At "DEC <-> HEX CONVERTER", Tick "LITTLE ENDIAN", and copy the hex bytes after the offset 2C (starting from 2D) until 2F. As I said, this should be the block 2D-2F. Then click on "HEX to DEC" button and use the decimal value. So for the original "bgm01_new.asrc.26", the looping start point would be 395447 (B70806). I tested if that loops properly, and it seems to do so.

Finally, the song's overall length in samples is 3603581. This is read at offset(h) 31, and through UInt32 value + 1.

Any idea on how to repack modded files for this game? Do you need to do it to the big re_chunk_000.pak or can you use a custom pak file? A custom pak file would be better to leave the original game data intact. (re_chunk_000.pak.patch_001.pak? Though I'm not sure if the engine would recognize that in this game. Or if that requires another custom tool or is REtool enough? If so, any examples? Not familiar with RE Engine.)

@osyu
Copy link
Author

osyu commented Jan 16, 2024

when RE Engine needs to load a file it first tries loading from the .pak, and if it can't find it there it resorts to loading loose files from the file system in the working directory as a fallback. generally when people mod the game they just null out (i.e. invalidate) the filepath hash in the .pak header, and then place their modded file in the file system next to the game executable; this is what Fluffy Mod Manager does, and it saves a lot of disk space compared to repacking the .pak file. if you want to do that anyway though, you can use REE.PAK.Tool (and it might be required for console versions of the game, though I have no experience there).

the vast majority of RE Engine games use Wwise for audio, but Ghost Trick (and a few others like Capcom Arcade Stadium) seem to use RE Engine's built-in sound system, which is what .asrc files are for. because they're in so few games I couldn't find any documentation for them, so everything in the script is what I could surmise by looking in a hex editor.

the bgm flag is set only for music and not sound effects, but I never confirmed what it actually does (streaming is just a guess). you should set it anyway to be consistent with the original files.

the audio source id you have to get from the original file with a hex editor. I planned on adding something to the script for printing out the info in the asrc header to make it easier, but never got around to it. as for why it's a thing...

there are two types of .asrc files, with the magic bytes "srch" and "srcd". srch files live in natives/stm/sound and are basically stubs; they just contain the source id and not much else. srcd files are in natives/stm/streaming/sound, and contain a header + the actual audio data (hence "d"), so they're the ones you want to modify; they also contain the same source id as the srch file. the ids in both files must match or else the game won't be able to load the audio; that's why you can't just put any random number there. my best guess is that the ids are stored in a hashmap for sound caching or something similar.

@niltwill
Copy link

Thanks for your assistance. I finished JTPaper's music mod recently, for the Nintendo Switch and PC version of the game.

The Nintendo Switch port's audio files are OGG files instead of WAV (both BGM and SE), most likely to preserve space. They have the same source ID as in the PC version. And for some reason, the "LoopStart" and "LoopEnd" (additional/custom metadata) are set to -1 with every audio file, regardless if the track is looping or not. Quality level is 10 (-q10) - at least for the BGM. You can't use WAV files here. They used libvorbis 1.3.6 ("libvorbis I 20180316") for it, but it's not necessary to use that version. I used the latest 1.3.7 ("libvorbis I 20200704"), which works as well. (I edited your Python script to be able to handle the ogg files instead of wav.)

There is one odd BGM file in the original (classic version of the) OST: bgm11_loop.wav. Despite the name, it doesn't loop, and I believe it could be a leftover that's still included in the game files. No idea what it's really for, it's in both the Switch and PC versions. I ignored this one.

I also found out that there is no need to mess with the existing re_chunk_000.pak file. Although a patch PAK file doesn't exist in the Ghost Trick game by default, but you can still put all your new/modded files into a patch PAK file: re_chunk_000.pak.patch_000.pak. That's going to take priority over re_chunk_000.pak and thus you will get your modded resources loaded with that. I assume that the latest numbered patch pak file gets prioritized (loaded last), so re_chunk_000.pak.patch_001.pak over re_chunk_000.pak.patch_000.pak and so on.

@student197
Copy link

will you sort the apollo justice ace attorney trilogy files?

@osyu
Copy link
Author

osyu commented Jan 25, 2024

Done: https://github.com/Ekey/REE.PAK.Tool/blob/main/Projects/AJ_AAT_PC_Release.list
Ekey also made a list for the Switch version, it's in the same repo

@osyu
Copy link
Author

osyu commented Jan 26, 2024

Wrote a variant of asrc.py to handle AJ:AA Trilogy's .asrc files (version 31) here:
https://gist.github.com/osyu/c3390a4c1c32aaef0ea6d59c2fcb4ea0

Also includes a command to print info from an existing .asrc file without needing a hex editor (since there are a few unknown fields now aside from the source id that you may want to grab from the originals)

@student197
Copy link

Hi, can you make a program to make it easier to edit dialog files or a script to convert them to .txt or something similar. Just editing them in the 010 editor is inconvenient. P.s And how to edit subtitles in aa5 and aa6? they are stored in the same file format as the dialogues, but there is nothing in them.

@osyu
Copy link
Author

osyu commented Jan 28, 2024

The scripts for each game are in the same formats as they were on their native platforms (i.e. AJ uses the GBA/DS bytecode, DD and SOJ use the 3DS format, etc.); the only difference here is that they're wrapped in RSZ user data.

I imagine tools like Kuriimu will add support for this sometime soon (the same way it supports MT Framework's GMD files for TGAA script editing), but in the meantime I wrote a (sufficiently messy) script to convert to and from common formats: https://gist.github.com/osyu/5bb86d49153edef5415a7aba09a48ca1

DD and SOJ will convert to JSON. AJ will convert to the DS bytecode format, which can be edited with e.g. phoenixtools. The script also supports globbing/wildcards to let you convert the entire directory at once.

Anime subtitles are stored in regular .msg files at natives/stm/gamedesign/text/gs5 (and gs6), which can be converted with REMSG_Converter (linked above in the gist). For example, SOJ's opening cutscene is .../gs6/gs6_gs_01_01.msg.22.

@student197
Copy link

can you please tell us in more detail how to use your script

@osyu
Copy link
Author

osyu commented Jan 28, 2024

gs456scr d <user file> to decode, gs456scr e <json or bin file> to encode. e.g. gs456scr d sce00_c000_0000.user.2.en will create sce00_c000_0000.user.2.en.json which you can edit, and gs456scr e sce00_c000_0000.user.2.en.json will convert the .json back into .user

@student197
Copy link

do I need to convert dgs456scr.ry to exe or how do I use it?

@osyu
Copy link
Author

osyu commented Jan 28, 2024

Install Python and then run the script via cmd

@student197
Copy link

I tried, but it didn't work out, maybe I'm doing something wrong

@osyu
Copy link
Author

osyu commented Jan 28, 2024

I don't want to clog up this gist's comments with support questions, so you should contact me by other means if you need more help

@niltwill
Copy link

I tried to run asrc31.py through all the audio files of AJ:AA Trilogy, and there are certain ones that it cannot handle. There are two errors, depending on the files.

These are the offenders with the "smpl chunk size" error. AssertionError: assert read_u32(f) == 44 # smpl chunk size

natives\stm\streaming\sound\common\se\get_medal_1648.asrc.31
natives\stm\streaming\sound\gs4\stream\bgm\interactivemusic\bgm070_bass_1648.asrc.31
natives\stm\streaming\sound\gs4\stream\bgm\interactivemusic\bgm070_click_1648.asrc.31
natives\stm\streaming\sound\gs4\stream\bgm\interactivemusic\bgm070_drums_1648.asrc.31
natives\stm\streaming\sound\gs4\stream\bgm\interactivemusic\bgm070_keyboards_1648.asrc.31
natives\stm\streaming\sound\gs4\stream\bgm\interactivemusic\bgm070_leadguitar_1648.asrc.31
natives\stm\streaming\sound\gs4\stream\bgm\interactivemusic\bgm070_rhythmguitar_1648.asrc.31
natives\stm\streaming\sound\gs5\se\script_com\bikkuri.asrc.31
natives\stm\streaming\sound\gs5\se\se_cr003\kokone_pc_tap_flick.asrc.31
natives\stm\streaming\sound\gs5\se\se_cr203\biyoin_chakushin_both.asrc.31
natives\stm\streaming\sound\gs5\se\se_cr203\biyoin_chakushin_hidari.asrc.31
natives\stm\streaming\sound\gs5\se\se_cr203\biyoin_chakushin_migi.asrc.31
natives\stm\streaming\sound\gs5\se\se_cr207\shoko_performance_ken_hikaru.asrc.31
natives\stm\streaming\sound\gs6\se\yamashinop\yamashinop_coin_break_1648.asrc.31
natives\stm\streaming\sound\startupscreen\museum\animationstudio\se\close_anim_studio_1648.asrc.31
natives\stm\streaming\sound\startupscreen\museum\animationstudio\se\enter_anim_studio_1648.asrc.31
natives\stm\streaming\sound\startupscreen\museum\animationstudio\se\se_court_000.asrc.31
natives\stm\streaming\sound\startupscreen\museum\artlibrary\se\close_art_library_1648.asrc.31
natives\stm\streaming\sound\startupscreen\museum\artlibrary\se\enter_art_library_1648.asrc.31
natives\stm\streaming\sound\startupscreen\museum\artlibrary\se\paper_1648.asrc.31
natives\stm\streaming\sound\startupscreen\museum\artlibrary\se\screendown_1648.asrc.31
natives\stm\streaming\sound\startupscreen\museum\artlibrary\se\screenup_1648.asrc.31
natives\stm\streaming\sound\startupscreen\museum\orchestrahall\se\curtain_close_1648.asrc.31
natives\stm\streaming\sound\startupscreen\museum\orchestrahall\se\curtain_open_1648.asrc.31
natives\stm\streaming\sound\startupscreen\se\entering_titlesel_1648.asrc.31
natives\stm\streaming\sound\startupscreen\se\enter_startup_screen_1648.asrc.31

Also here are some others below that output this AssertionError: assert read_u32(f) == 0xffffffff # always -1

natives\stm\streaming\sound\gs5\stream\all\se301_ikuya_yorokobi_rap_strm_lp.asrc.31
natives\stm\streaming\sound\gs5\stream\all\se302_ikuya_ikari_rap_strm_lp.asrc.31
natives\stm\streaming\sound\gs6\stream\se\reifa_v_ima_1644.asrc.31
natives\stm\streaming\sound\gs6\stream\se\reifa_v_minanomono_1644.asrc.31
natives\stm\streaming\sound\gs6\stream\se\reifa_v_sisosamano_1644.asrc.31
natives\stm\streaming\sound\gs6\stream\se\reifa_v_tokutomiyo_1644.asrc.31

For reference (correct this if I'm wrong), the offsets for the asrc.31:

Block(h) 0-3: Has to be "srcd"
Block(h) 8-A: WAV file's size (without the header)
Offset(h) F: Always 32? (default 32-Bit float depth?)
Offset(h) 10: bgm(?) [as it doesn't always appear for BGMs only, my guesses... 1. audio data behaviour: preload audio data (to make sure it plays as soon as the scene appears/starts?)=1/load in background (it's not prioritized, it can wait to load)=0, 2. normalize the audio (to make sure it's not overly loud/clipping)=1, do not normalize it (use source audio as is)=0]
Block(h) 14-17: file id
Block(h) 18-1B: unknown0 (secondary id used for something else?)
Offset(h) 1C: channels? (2 = stereo, 1 = mono?)
Block(h) 20-22: samples
Block(h) 24-25: 44100? The default sample rate for fallback/default? Tends to be 44100 or 48000, or could this be left channel and the other (28-29) for right channel?
Block(h) 28-29: rate
Offset(h) 2C: exported bit depth format? usually 16
Offset(h) 30: Always 1? (perhaps this is indicating that it is not muted?)
Offset(h) 34: Loop enabled if UInt8 = 1?
Block(h) 35-37: LS (loop start)
Block(h) 39-3B: LE (loop length)
Offset(h) 4E: usually 86(?)
Offset(h) 52: usually 44(?)

I checked se301_ikuya_yorokobi_rap_strm_lp.asrc.31 and se302_ikuya_ikari_rap_strm_lp.asrc.31, and figured out those has more length in their header, inserted (+10) at block(h) 40-4F. The reifa ones in gs6 all have different headers. No idea about the other error with the smpl chunk size. I know this doesn't matter much, as it's unlikely that a modder would wish to replace these audio files, but still.

...It might be a good idea to create a gist for this game too, sharing modding stuff there instead, to stay on focus with Ghost Trick here?

@osyu
Copy link
Author

osyu commented Jan 29, 2024

I've updated the script to fix those issues, thanks for reporting. My bad for not testing against all the files before posting it...

This is what I have currently for the srcd struct:

u32 magic        : "srcd"
4b  <pad>        : always 0
u32 file_size    : size of audio file
u32 type         : "wav " or "ogg "
u32 strm         : bool; streaming audio flag
u32 id           : audio source id, same as corresponding srch file
u32 unk0         : unknown int, NOT a hash of the audio data
u32 channels     : channel count
u32 samples      : sample count (total, not per channel)
u32 urate        : unknown int, looks like a sample rate
u32 rate         : sample rate
u32 depth        : bit depth
4b  <pad>        : always 1
u8  loop         : bool; loop audio flag
u32 lps          : loop start sample position
u32 lpe          : loop end sample position
u32 mark_count   : marker count
for _ in range(mark_count)...
  u32 type       : marker type (usually 0xffffffff/-1)
  u32 pos        : marker sample position
9b  <pad>        : always 0
u32 unk1         : unknown int, usually 0 but sometimes 5
u32 header_size  : size of header, including this field and the next
u32 data_offset  : offset to start of audio data

I monitored the game's file i/o and confirmed that the "bgm" flag is for streaming audio (which is why I've renamed it to strm).

unk0 is definitely not a hash of the audio, since there are some duplicate .asrc files where the only difference between them is unk0 (even the source id is the same). natives/stm/streaming/sound/common/se/cursor_1644.asrc.31 and natives/stm/streaming/sound/gs6/se/sys/cursor_1644.asrc.31 are examples of this. It might be a murmur hash of some string... maybe the source id is too, who knows.

I don't know what urate is for, changing it doesn't seem to affect anything. No idea what unk1 could be either.

Markers are sample positions that are used primarily to sync the game script to streamed sound effects (via stse_mw and stse_mwn) or BGM (via bgm_mw). You'll see them in things like Andistan'dhin's singing and Rayfa's Divination Séance intro.

@niltwill
Copy link

niltwill commented Jan 29, 2024

Thanks for the clarification, struct, and the updated script. Only did some shoddy guesses that didn't pay off with unk0 and others.

What's best practice now? Due to these unknown values that cannot be calculated, does one still have to copy these bytes from the original file when re-encoding a modified file? That's a bit cumbersome with batch operations. But that would be the way to go, right? So that nothing breaks, since there is no telling what they do.

It would be great if the script could also take an additional (optional) input (parameter) for the original .asrc audio file (path) with the encoding function (to fetch all unknown data it cannot generate: id, unk0, urate, markers [if any], unk1). That would make it easier for batch operations (rather than manually hex editing every file one by one). Is it possible to pull that off somehow? I will look into it myself eventually, though I'm bad with Python.

Also, did you test the new script? There's a new error that broke it when trying to handle any file now (not only with the problematic files).

Now I get the following error (line 199, in info):

    mark = ','.join(':'.join(str(y) for y in x) for x in mark)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'NoneType' object is not iterable

Edit: Removed my temporary unclean fix for this after the script update (to make sure it's not getting used in case someone else's reading this).

I tested it with all the aforementioned problematic files, and now it's all OK. Hopefully no other errors now! Yay.

@osyu
Copy link
Author

osyu commented Jan 29, 2024

Oops, again... that line formats the marker list before it gets printed out in the info command, but I forgot to skip that step if it's None (i.e. there are no markers); should be fixed now. I should have caught that but that's what I get for working on things at midnight

You should copy all the unknowns using the info command for now; other things like markers also need to stay, if they exist (you have to have the same amount in your new .asrc or the game script will be liable to break).

I already had plans for an r replace command to do what you're asking for batch operations, I'll work on that next

@osyu
Copy link
Author

osyu commented Jan 29, 2024

Replace command is done; it takes in the input .wav, a base .asrc and an optional output path (if not specified it overwrites the base), plus the loop points and markers. It'll complain if the base has markers and you didn't specify any (or vice versa), so make sure to adjust those for the new audio.

@osyu
Copy link
Author

osyu commented Jan 29, 2024

Updated once more to fix a slew of other bugs, make the out argument required for all commands (to avoid overwriting files you didn't mean to + the splitext stuff wasn't working properly with language suffixes), and add a -cpb option to the replace command which copies the loop positions and markers from the base file rather than using the -lps/-lpe/-mark arguments (useful for batch converting)

@niltwill
Copy link

AJ will convert to the DS bytecode format, which can be edited with e.g. phoenixtools.

You get no actual text, only integers using that (with scripting\script-dis from that repo). Here is an example for "sc0_0_op.user.2.en.bin" (after decoding it with your script):

SECTION 0
 0000	text "{57473}"
 0001	music 57442, 00001
 0004	newline
 0005	text "{57473}"
 0006	sound 57451, 00001
 0009	section_setup
 0010	hideperson
 0011	text "{57433}"
 0012	cmd62
.label0_15:
 0013	text "{00610}{57473}"
 0015	fullscreen_text
 0016	text "{57435}"
 0017	section_setup
 0018	section_setup
 0019	section_setup
 0020	text "{57433}"
 0021	cmd62
 0022	text "{00609}{57340}\n{57473}"
 0026	finger_choice_2_args_jmp 57323, 4294967172
 0029	newline
 0030	hideperson
 0031	text "{57433}"
 0032	cmd62
[...]

For reference, it's supposed to look something like the attached image in this post.

My guess is that the AJ:AA Trilogy uses UTF-16LE encoding for the text itself, which is why it doesn't work? Other than manual editing with a hex editor (you can sort of read the text parts in these files), there's no easy way right now...

@osyu
Copy link
Author

osyu commented Feb 22, 2024

Yeah, it appears that AJ uses a different encoding here than the DS games, which isn't entirely unexpected since the Unity version of the original trilogy also changed the format some. It segfaults on certain scripts as well (e.g. sc0_0_h00) so it might need more work than just fixing the text parsing. I don't have time right now to look into it further through

@mentionmenot
Copy link

mentionmenot commented Apr 10, 2024

Thank you for the helpful information. Could you provide any update info about decoding AJ GS4 script? I'm encountering challenges with it in my localization project.

@niltwill
Copy link

niltwill commented Apr 10, 2024

Update: Now the script should work with every GS4 binary (I also tested every language).

I made a Python script for the GS4 binary script files. It's not too pretty and the text is hard to edit with it, but it's a start. Also remember that the GS4 script binaries still need to be decoded with this converter first.

Some examples:

ajaat-gs4-script.py decode action_studio.user.2.en.bin
ajaat-gs4-script.py encode action_studio.user.2.en.txt
ajaat-gs4-script.py compare action_studio.user.2.en.bin action_studio.user.2.en.encoded.bin

It supports wildcard matching for encoding and decoding, so you can simply use these commands (while having every script binary in the same folder):

ajaat-gs4-script.py decode *.bin
ajaat-gs4-script.py encode *.txt

With that, the decoding will simply use the same filename with the ".txt" extension.
The encoding will add the ".encoded" prefix (so that you end up with a file like "[name].encoded.bin". In this way, you don't accidentally overwrite the existing binaries, especially since a byte comparison is recommended to make sure there are no discrepancies.

However, there are different problematic files with different languages that need some byte correction after encoding. For English, these are the following:

  • sc0_1_h02.user.2.en.bin
  • sc1_0_000.user.2.en.bin
  • sc1_3_h03.user.2.en.bin
  • sc2_0_013.user.2.en.bin
  • sc2_0_016.user.2.en.bin
  • sc2_3_h00.user.2.en.bin
  • sc3_0_00a.user.2.en.bin
  • sc3_3_00c.user.2.en.bin
  • sc3_3_010.user.2.en.bin

To fix those byte differences that only appear in these 9 files, you can use a command like this: ajaat-gs4-script.py compare --fix sc0_1_h02.user.2.en.bin sc0_1_h02.user.2.en.encoded.bin

(Important to put the original binary file first, then the edited, re-encoded binary.)

Or you can use this batch file, as different languages do have other files that need the byte correction, so it's better to run this through each of these files.

@evil-trainer
Copy link

evil-trainer commented Jul 22, 2024

This gist is for the PC version only, you can find info on modding console versions of RE Engine games elsewhere

Sorry to hijack the gist, but I'm a fan translator of Switch games and unfortunately there isn't somewhere else to look, for addressing the Switch tex conversion situation (at least I couldn't find anything anywhere).

But, hope is not lost, since there's a workaround =)

Thanks to the awesome folks from the Modding Haven Discord Server, I learned how to make MHR_Tex CHopper work with Switch textures.

Open up the texture in a hexadecimal editor and replace the 5º byte with the hexadecimal equivalent of "23", which happens to be 1C.

Before:
image

After:
image

Now, save your changes and drag and drop the texture onto MHR_Tex Chopper and it'll do its thing ;)

image

image

Don't forget to disable "Create MipMap" in Paint.Net BEFORE converting back from .dds to .tex. If you are dealing with UI elements textures, use BC7 linear as the compression or use BC7 sRGB if you're dealing with albedo textures instead. To convert from dds back to .tex, just drag and drop yout edited .dds onto MHR_Tex Chopper and it'll spit out a .tex file. Now, just replace the vanilla .tex with your newly edited one and that's it!

All that's left is create a .pak.patch file and test your edit in-game!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment