네푸네푸빌런의 한국어패치 지상락원

[PSP] 이레귤러헌터 X 작업 본문

한국어패치 작업/구조분석

[PSP] 이레귤러헌터 X 작업

네푸네푸빌런 2018. 10. 29. 16:48

지난달 쯤에 공개한 이레귤러헌터X의 작업내용을 블로그에 공개합니다.

같은 내용의 글이 네이버의 한식구카페에도 있지만 블로그가 편한 분들도 계실것 같아 여기에 올립니다.


1. 전체적인 게임분석

이레귤러헌터X는 데이터가 하나의 큰 파일로 묶여있어 구조가 한번에 보이지 않았다.

UMDGen 으로 보거나 그냥 마운트 시켜서 확인해보면 rockx_pack.dat, rockx_pack.loc 이라는 상당히 의심스런 파일들이 있다.

.dat 파일은 전체 게임용량의 상당수를 차지한다는 점에서 상당히 의심스럽다.




dat 파일은 헥스에디터로 열어보면 아무 것도 알 수 없는 아주 큰 파일이다. 이걸 크리스탈타일로 열어도 딱히 보이는 것은 없었다. 다시말해 압축이 되어있다는 것인데 이 큰 파일에서 압축된 부분을 찾아 풀기란 쉬운일이 아니다.


loc 파일은 이름처럼 dat 파일에 묶여있는 각종 데이터들의 위치와 크기가 기록된 파일이다. 블록친 부분에서 앞의 4바이트는 dat 파일에서의 상대적인 위치, 뒤의 4바이트는 그 데이터의 크기이다. PSP 의 처리장치는 리틀엔디안을 쓰므로 1바이트씩 뒤에서 읽어주어야한다.




dat 파일을 열고 0x00000800 로 이동해서 보면 LINK 라는 헤더가 있다.


loc 파일의 다른 부분을 보고 dat 에서 이동해도 이와 비슷하게 LINK 등의 다른 내부헤더를 찾을 수 있는 것으로 보아 loc 파일이 dat 에서의 각종 데이터의 위치를 다루고 있음은 거의 확실하다.


이 정보를 이용하면 파일을 분해하여 여러 개의 파일들로 쪼개거나 다시 합치는 것이 가능하다.

파이썬을 이용한다면 아주 간단하게 만들 수 있지만 이미 해외에서 quickbms 를 이용해 파일을 풀 수 있도록 만들어 두었기에 그냥 썼다.

구조가 약간만 다른 록맨록맨을 작업하게 된다면 파이썬으로 직접만들필요가 있다. 아주 간단한 코드로 만들 수 있다.


loc 파일에서 위치와 크기를 읽어오고 dat 파일의 오프셋을 loc의 그것으로 이동, 크기 만큼 읽어서 새로운 파일에 써주면 그만이다.


위의 LINK 는 또 다시 다른 데이터들을 묶어놓은 데이터더어리에 대한 헤더인데 loc 파일과 비슷한 구조로 되어있다. 모든 정보를 분석한 것은 아니지만 LINK 영역 안에서의 위치와 크기가 기록되어있다는 점은 loc과 다를게 없다.


첫 8바이트 가운데 4바이트가 LINK, 뒤의 4바이트는 LINK 에 대한 정보이다. 위의 그림에서 0x4 는 링크안의 파일 수라고 보면 된다. 이 기본 정보 이후로는 16바이트씩 끊어서 읽는다. 이 묶음이 LINK에 묶인 데이터에 관한 정보를 가지고 있음을 확인하였다. 4바이트 오프셋, 4바이트 크기, 4바이트의 알 수 없는 데이터(알아내려면 알아낼 수는 있겠지만 한글화에는 필요가 없었다. 일단은 데어터의 종류 따위로 추정된다.)



LINK도 dat, loc 과 비슷한 방식으로 풀어주면 

이런 식으로 안에 들어있는 데이터들을 얻을 수 있다. (위의 링크 파일을 쪼개지 않고 그냥 캡쳐했으니 오프셋은 무시)


CPK 라는 헤더가 보이지만 일반적으로 쓰이는 압축 방식은 아니고 제작자들이 마음대로 만든 이름이다. 실제로는 LZ01 알고리즘을 쓰고 있다는 것을 역어셈블러로 확인했다. LZ01 압축은 이미 압축해제 도구가 잘 만들어져 있으니 직접할 필요는 없었다. CPK0 아래의 헤더는 압출을 풀면 나오는 데이터의 헤더이다.


2. 압축

위의 그림에서 CPK0 은 사실 LZ01 임을 역어셈블러로 확인하였는데 


이런 식으로 불려온 텍스처의 주소에 브레이크를 걸어서 데이터를 올리는 순간을 잡아 동작을 확인하는 방법을 썼다. PPSSPP 는 메모리접근에도 브레이크를 걸 수 있어 편리하다.


확인해보니 절대다수의 데이터는 LZ01 방식으로 압축되어있다. 일부 동영상을 빼면(PSMF) 거의 다 압축되어서 압축을 풀지 않으면 대사도 그림도 보이지 않는다. 보통 텍스처가 조금은 보이지만 LZ01 은 그냥 안보였다.


3. 그림


이레귤러헌터X 에서 모든 그림은 PTEX 라는 헤더를 가지고 있다. 




첫 줄의 PTEX 다음의 4바이트는 PTEX 전체 크기, 그 뒤에 02 02 01 00 00 에서 02 02 는 텍스처와 팔레트의 수로 보이는데 늘 같은 것 같다. 팔레트랑 텍스처가 순서대로 짝이 지어지므로 같은게 당연한데 뭐하러 또 적은 건지는 모르겠다. 그 뒤의 01 은 버전으로 추정된다.

첫 줄 다음에 16 바이트씩 텍스처/팔레트의 정보
텍스처
0 - 3 : 오프셋
4 - 7 : 크기
8 : X 픽셀수(2^n 식), 9 : Y 픽셀수(2^n 식)
A : 픽셀 깊이 코드
B : 더미
C : 순서(별 의미는 없는 듯)
D - F : 더미

팔레트
0 - 3 : 오프셋
4 - 7 : 크기
8 : 색상 수(4 bit, 8 bit 이런거)
9 : 팔레트 수(팔레트 스왑)
A : 색 방식(텍스처의 픽셀 깊이 같은 것으로 항상 3, 3이 팔레트 코드인듯)
B - F : 더미

여기서 타일 크기가 없는데 타일 크기는 PSP GPU 의 처리단위와 같다. 한번에 128 바이트를 처리하므로 타일 1개 크기는 128 바이트이다. 이 게임 에서 볼 수 있는 모든 PTEX 는 세로가 8픽셀이었는데 편의상 고전시킨것 같다. 따라서 화소깊이에 따라 타일 안의 가로픽셀 수가 결정된다.

크리스탈 타일로 보면

32 x 8, 4 bpp(GBA) 로 본 모습이다.

엑스가 납작해졌는데 화소깊이를 잘못맞췄기 때문이다. 게임을 실행해보면 알 수 있겠지만 저 엑스는 8비트다.

깊이가 절반이 되어 가로가 그만큼 길어진 것이다.

반면 아래의 라이센스 정보는 멀쩡하다. 이건 또 4 bpp 가 맞기 때문이다. 같은 PTEX 파일에서도 서로 다른 타일 정보를 가지는 것을 확인할 수 있다.




16 x 8, 8 bpp 에서 로고가 잘 보인다.


PTEX 파일의 아래에는 팔레트가 들어있다.



PSP는 이 팔레트를 읽어서 그림을 출력해준다.


문제는 이 팔레트가 완전히 독자규격 느낌이 강한 것인데, 보통 PC 에서 쓰는 팔레트는 투명도라는 개념이 없다. 과거 그림카드의 성능이 부족했을 때 쓰던 방식일텐데 투명도라는 개념이 널리 쓰일 땐 이미 32 비트를 그냥 처리할 정도로 발전했을 것이다. PSP 는 그러기엔 성능이 부족한 것이 사실인만큼 투명도개념을 가진 n bit -> 32 bit 팔레트를 가지고 있다.


PTEX 를 편집할 프로그램은 없으므로 파이썬을 이용, 팔레트와 텍스처를 짝지어주었다.





이것을 잘 고쳐서 다시 PTEX로 만들고 다시 압축해서 다시 파일을 묶어서 작업하였다.


4. 글꼴과 대사

  


글꼴은 그림과 다를것이 없다

32 x 6, 4 bpp(GBA) 로 잘 보였다. 물론, 이미 PTEX 를 해석할 수 있으므로 그런 정보는 중요하지 않지만


특이한 점으로는 스테이지, 캐릭터 조합 별로 글꼴이 다 다르다는 것이다. 정확히 왼쪽의 그림은 항상 쓰이고 오른쪽은 상황에 따라 다른 글꼴그림이 불러와진다. 이렇게 만들어 얻는 이점은 대사압축이다.

오른 쪽 그림에서 가장 위, 가장 왼쪽은 1D00 마지막 글자인 가장 오른쪽, 가장 아래는 1DFF 이다. 한 그림에 256 글자가 들어있다.

왼쪽은 조금 특이한데 첫 글자라고 할 수 있는 빈칸이 1C20 이다. 보통 글읽는 순서대로 1CFF 까지 가면 아래에 글자가 조금 남는데 특이하게도 1CFF 다음은 1C00 이다. 아마 아스키코드와 부분호환성을 위해서 이렇게 만든 것 같다. 1C20-1CFF 는 1C 를 생략할 수 있어 1바이트 표기가 가능하다. 자주 쓰이는 글자를 1 쪽에(왼쪽 글꼴)에 넣어 대사를 줄였다.


대사 확장은 어려운 것은 아니지만 귀찮은 것이 사실이며, 쓸 수 있는 글자의 수가 한정되어 있으므로 스테이지, 상황별로 필요한 글자만을 추출, 그림편집 프로그램으로 글골을 만들어 주었다. 많이 쓰이는 글자를 1쪽에 넣어 대사의 길이가 늘어나는 것도 최대한 막았다.


대사는 평범한 수준이다. 특별히 쉽지도 어렵지도 않다.

대충 이렇게 생겼다.


대사 파일의 맨 위는 포인터 모음이다. 저 위치에 대사가 있는 것이다.

첫 2바이트는 대사 포인터 테이블에 있는 포인터의 수입니다. (또는 테이블 크기의 절반)
0x02 - 03 은 첫 대사의 포인터로 이후에 같은 값이 나오면 이번 페이즈는 끝이란 신호(서로 다른 씬이란 뜻)

스테이지별로 대사파일이 있고 플레이어, 장면 번호에 맞는 대사를 읽어오는 구조
0x40 주기로 새로운 대사가 시작(이게 꼭 0x40 주기인지, CA 00 (이번 파일의 경우) 가 아닌 값이 나올 때 장면이 바뀌는 건진 확인해보지 않았다. 이 포인터의 수를 바꿀 일은 없기 때문이다.)

00 CA 로 가보면 0A 01 19 0F 가 있는데 0A 는 대사 시작 제어코드, 01 은 대사창 위치(00, 01 둘 중 하나는 왼쪽 다른 하나는 오른쪽, 무슨 의민지 모르겠다면 게임 영상을 보실 것을 권장) 19 는 목소리 재생, 0F 는 목소리 번호 이 외에 줄바꿈 문자 등도 있었다. (02)



이런 제어문자, 포인터 구조를 다 분석하면 대사를 추출하거나 대사파일을 만들 수 있다.

원본 글꼴에 있는 글자를 모두 적어넣어 일본어 대사를 추출했고 번역된 대사를 집어 넣어 문자코드와 대사파일을 생성했다. 글꼴을 이미지 편집 도구로 따로만들어 넣어주었다.


5. 기타

wav 도 있던데 골든웨이브에 관련 코덱 깔면 재생된다. 스테이지 배경음도 있어서 대사 찾기에 좋다. LINK 는 한번에 쓰일 데이터의 묶음이라 스테이지 배경음과 대사는 같은 LINK 에 들어있다.

PMF 는 조금 특이한지 대부분의 PSMF 디코더로 잘 안열린다. 되는 파일이 조금 있으니 잘 뒤져봐야한다.

시그마의 날에서 장을 고르는 방법은 잘 모르겠다.

Comments