II. Quy trình
1. Mua vui một vài trống canh
Quy trình để chuyển ngữ một game từ ngôn ngữ này sang ngôn ngữ nọ luôn có những bước chính sau đây, chung cho mọi hệ thống, dù đó là PC, Snes, PS, Xbox, Genesis hay gì đi nữa.
- Tìm, xác định bộ font và sửa đổi nó
- Tìm và xác định text (thoại, chữ) trong ngôn ngữ nguồn, sửa đổi nó sang ngôn ngữ đích
Đây là hai bước chủ chốt, bất di bất dịch, luôn được áp dụng trong mọi trường hợp. Tuy nhiên trong thực tế, ta có thể phải làm nhiều bước nhỏ hơn để đến được hai cái đích lớn này, tùy từng trường hợp. Các bước nhỏ hơn có thể là:
- Giải nén font/text nếu chúng bị nén
- Giải mã font/text nếu chúng bị nén
- Nén lại font/text sau khi chỉnh sửa
- Mã hóa lại font/text sau khi chỉnh sửa
- Viết lại chương trình để tối ưu hóa việc hiển thị/đọc text
- Chỉnh sửa độ rộng của từng ký tự cho phù hợp với văn bản ngôn ngữ đích
- Viết chương trình độ rộng biến thiên theo từng ký tự cho phù hợp với ngôn ngữ đích, nếu như trong ngôn ngữ nguồn không có chương trình này
- Trích xuất (dump) text từ Rom/game ra ngoài file văn bản
- Chèn text đã dịch vào Rom/game
Trên đây chỉ là một số vấn đề nho nhỏ thường gặp trong quá trình dịch game. Đối với các yêu cầu đầu tiên thì đòi hỏi phải có kiến thức chuyên sâu vào game mình cần dịch, hay nói nôm na là kiến thức về ngôn ngữ để viết nên game đó. Cụ thể ở đây là ngôn ngữ Assembly Mips, cộng với kiến thức về đặc trưng phần cứng của hệ máy, nó sẽ giúp ta xác định mọi thứ trong cái game cần dịch.
Ngoài lề: bản thân tôi không phải lập trình viên, không học ngành IT nhưng nhờ ham đọc tài liệu (sách + Google) mà đã có được một số kiến thức cơ bản về phần cứng, Assembly cho các hệ máy. Do vậy đừng nghĩ những gì tôi đề cập bên trên là cao siêu vượt quá tầm của bạn.
2. Cấu trúc đĩa
Game cho PSP được lưu trữ trên đĩa UMD do chính Sony phát triển, nó có thể chứa tối đa 1.8GB dữ liệu nên việc tìm kiếm một thứ gì đó trong đĩa sẽ rất khó, hoặc không thể nếu không có phương pháp tìm kiếm khoa học.
Đầu tiên cần biết về cấu trúc dữ liệu của game PSP lưu trên UMD.
- Thư mục gốc\UMD_DATA.BIN chứa các thông tin về đĩa game như mã số game, phân vùng khu vực.
- Thư mục gốc\PSP_GAME chứa các Icon ở định dạng PNG, các file thông tin khác và hai thư mục quan trọng là SYSDIR và USRDIR.
- SYSDIR chứa file EBOOT.BIN, đây là file khởi động của PSP, tương đương với file .exe trên PC. Nói chung chỉ cần nhìn tên là biết SYSDIR là thư mục hệ thống.
-USRDIR là thư mục User, tùy từng nhà sản xuất game mà tên gọi file, folder bên trong đó khác nhau. Đây là nơi chứa dữ liệu của game.
Nếu bạn mở GOW GOS (bản tiếng Nhật) bằng CD Mage hoặc UMD thì sẽ thấy cấu trúc file/folder như hình dưới đây.
Bạn có thể dùng bất kỳ phần mềm nào khác để mở file ISO, ở đây tôi quen dùng CD Mage.
III. Bắt tay vào việc: tìm và xử lý font chữ
1. Khái niệm về font
Trước tiên cần hiểu khái niệm font chữ. Từ "font" bao hàm cả hai ý nghĩa sau:
- Diện mạo (cao gầy béo lùn to tròn...) hay ngoại quan của chữ
- Dữ liệu (gồm 0 và 1) cấu thành nên cái diện mạo bên trên
Đối với người dùng máy tính ở cấp phổ thông thì khi nói tới font, người ta chỉ nói tới cái ý nghĩa thứ nhất (như font Arial, font Tahoma... là nói tới ngoại quan). Còn ở cấp sâu hơn, phải đề cập tới ý nghĩa thứ hai. Vì lý do này mà hay nghe nhiều bạn kêu khổ:
- Game này không hỗ trợ font tiếng Việt, em gõ dấu toàn ra lỗi
- Game này không dùng font Unicode, em không Việt hóa được
Đó là do chưa hiểu rõ về bản chất của font.
Về bản chất thì font chữ cũng chỉ là một dạng hình ảnh đồ họa. Tất cả mọi thành phần được hiển thị trên màn hình PC, console đều là đồ họa hết, dù ở định dạng gì đi nữa.
Dòng PS của Sony, trong đó có PSP là máy chơi game sử dụng đồ họa pixel. Trái với các dòng NES, SNES của Nintendō là đồ họa dạng mảng (tile). Đối với hai loại máy của Nintendō thì một đơn vị đồ họa nhỏ nhất mà máy thể hiện được là một ô vuông 8x8 pixel, còn đối với dòng PSP thì đơn vị nhỏ nhất là 01 pixel, tức là chiếm diện tích nhỏ hơn 64 lần, khiến hình ảnh mịn hơn.
Quay trở lại ý nghĩa thứ hai của font, về bản chất nó là một chuỗi dài gồm 0 và 1. Khi máy gặp phải giá trị 0, nó sẽ thể hiện khoảng trống ra màn hình. Còn khi gặp giá trị 1, nó thể hiện một điểm (pixel) ra màn hình.
Lấy ví dụ về chữ "a" có kích thước 8x8 pixel như dưới đây. Ta xem những ô trống là 0 (không hiển thị ảnh), những ô có hiển thị ảnh là 1 thì chữ “a” sẽ như sau.
Đổi chuỗi này sang hệ thập lục, ta được $387EC6C6C6C67F3B. Đây là giá trị cho chữ “a” nếu ta xem bằng Hex editor. Còn khi máy tính (Super Famicom) hoạt động, nó chỉ hiểu được chuỗi
11100001111110110001101100011011000110110001100111111100111011 mà thôi.
Ngoài ra còn có khái niệm bitplane, hay bit per pixel. Chữ "a" bên trên là 01 bpp (1 bit cho mỗi pixel) nên nó có hai trạng thái màu: không màu (giá trị 0) và có màu (giá trị 1). Đối với 2bpp, hình ảnh sẽ có 4 màu, 4bpp là 8 màu...
Lấy ví dụ về chữ "a" bên trên, nhưng lần này là 2bpp. Thực chất, 2 bpp là dạng triển khai của 1 bpp, trong đó có 1 bit plane thể hiện phần thịt của chữ, 1 bit plane còn lại thể hiện phần bóng mờ của chữ. Nếu font càng sử dụng nhiều bit plane thì nó sẽ có nhiều cấp độ bóng mờ. Nhiều game console sau này sử dụng font nhiều bit plane để tạo ra hiệu ứng đổ bóng nhiều màu, nhiều cấp độ để việc hiển thị chữ được đẹp hơn, rõ ràng hơn so với việc chỉ dùng 1 bit plane (chỉ gồm phần thịt của chữ, không có bóng).
Lồng ghép vào nhau
2. Xác định font
GOW GOS có nhiều chế độ ngôn ngữ. Bản EU có các ngôn ngữ: Anh, Pháp, Ý, Hy Lạp... trong một đĩa UMD. Còn bản JP có hai ngôn ngữ: Nhật và Anh trong cùng một đĩa UMD. Đối với giả lập PPSSPP, nó sẽ tự động chọn ngôn ngữ trong game dựa vào ngôn ngữ của giả lập.
Đầu tiên, hãy chọn ngôn ngữ tiếng Anh cho giả lập PPSSPP. Ta sẽ tìm font chữ trong bản tiếng Anh. Vào game, chụp lại ảnh màn hình đầu tiên.
Phóng to phần chữ trong phần mềm xem ảnh, để ý kỹ thì sẽ thấy phần chữ có 16 màu. Tức font chữ ở đây là 4bpp.
Bây giờ chọn New Game để xem cảnh mở đầu của GOS. Từ giao diện PPSSPP, vào Debug --> GE Debugger hoặc dùng phím tắt Ctr + G để bật Debugger đồ họa của PPSSPP.
Trong GE Debugger ta thấy có các nút sau và ý nghĩa của chúng sau một thời gian mày mò:
- Step frame: dừng game và cho biết các lệnh xử lý mọi thành phần đồ họa trong frame (khung hình) tiếp theo.
- Step Tex: dừng game và cho biết các lệnh và thông tin liên quan tới texture đang được xử lý.
Font chữ cũng là một dạng texture.
- Step Draw: dừng game và cho biết các lệnh và thông tin liên quan tới những gì sẽ được vẽ ra màn hình
- Step Prim: dừng game và thể hiện các thành phần trong texture sắp được vẽ ra màn hình. Những thành phần này được bôi đỏ ở khung preview bên phải.
- Step Into: dừng game và đi vào từng lệnh đồ họa một, ở cấp chi tiết nhất, hết lệnh này đến lệnh kia.
- Resume: thoát khỏi chế độ debug, cho game tiếp tục chạy.
Như vậy, sau khi click vào ô "Step Tex" nhiều lần, ta sẽ thấy hình ảnh font chữ hiện ra ở khung preview bên phải. Bên dưới là dòng thông tin:
- Texture L0: 0x8cfd3d0 (128x128)
Dòng này có ý nghĩa: Texture (font) cấp độ 0 nằm ở địa chỉ 0x8CFD3D0 trong Ram và bộ font này có kích thước 128x128 pixel.
Đọc tài liệu kỹ thuật về PSP, ta biết được console này có Ram 24MB, bắt đầu từ địa chỉ 0x08800000. Đối với các loại console cũ như NES, SNES do dung lượng Ram hạn chế nên CPU đọc dữ liệu và lệnh xử lý từ Rom. Còn đối với những dòng console đời sau, cấu hình mạnh hơn và nhiều Ram hơn thì CPU thường copy dữ liệu, lệnh từ Rom vào Ram, sau đó mới đọc các dữ liệu này từ Ram.
GOW GOS cũng đọc dữ liệu từ Ram. Bây giờ, từ giao diện PPSSPP vào Debug --> Memory View (hoặc
Ctrl + M) để mở công cụ xem Ram. Gõ địa chỉ 0x8CFD3D0 vào ô "Goto", Enter để đi đến địa chỉ này. Tại đây ta thấy được dữ liệu của font ở khung preview bên phải.
Từ đây ta có hai cách xác định dữ liệu này nằm ở đâu trong đĩa UMD.
Cách thủ thuật:
- Để ý tìm một chuỗi giá trị đặc trưng trong Memory View. Ở đây tôi để ý đến chuỗi 20 22 62 00 30. Bạn có thể dùng chuỗi khác.
- Mở file ISO bằng Hex editor, tìm chuỗi kể trên. Kết quả tôi tìm được chuỗi này nằm ở 0x4A955E75 trong file ISO. Nói cách khác, dữ liệu font bắt đầu ở 0x4A955E10.
- Đọc tài liệu kỹ thuật về đĩa CD/UMD thì ta biết khái niệm LBA. 1 LBA = 0x800 byte. Lấy địa chỉ 0x4A955E10 chia cho 0x800 ta được 0x952AB hay 610987. Điều này cho thấy dữ liệu font nằm ở vị trí LBA 610987.
- Quay trở lại phần cấu trúc UMD, ta thấy file
PSP_GAME\USRDIR\DATA\ENGLISH\GAME.BIN bắt đầu ở LBA 610960 và kết thúc ở 610991. Dữ liệu font nằm ở LBA 610987 thuộc phạm vi này, như vậy ta kết luận font chữ nằm ở file PSP_GAME\USRDIR\DATA\ENGLISH\GAME.BIN.
Cách khoa học:
Nếu đọc tài liệu kỹ thuật của PSP, ta biết CPU MIPS có khái niệm gọi là "syscall". Có thể hiểu nôm na nó là chức năng của hệ điều hành, nói rõ hơn là chức năng của kernel. Khi phần mềm (game) đang chạy, nếu nó gặp lệnh syscall thì nó sẽ giao quyền xử lý cho hệ điều hành.
Đối với MIPS, chức năng của syscall phụ thuộc vào giá trị của register $v0. Chẳng hạn, giá trị này là 1 thì kernel sẽ in con số nguyên ra màn hình console, nếu giá trị này là 4 thì kernel sẽ in chữ ra màn hình console...
Lấy ví dụ:
text: asciiz "Hello"
la $a0, text #đưa địa chỉ chuỗi text vào $a0
li $v0, 4 # đưa giá trị 4 vào $v0
syscall #in ra màn hình console chuỗi text "Hello"
Tùy vào giá trị của $v0 mà nội dung của syscall sẽ khác nhau. Và cũng tùy nội dung mà các tham số cũng thay đổi. Đối với chức năng syscall này thì tham số là register $a0, nhưng đối với chức năng khác thì lại cần $a1, $s0....
Quay trở lại vấn đề chính, ta đã biết dữ liệu font bắt đầu tại địa chỉ 0x8CFD3D0 trong Ram. Tiếp theo:
- Từ giao diện PPSSPP --> Debug --> Disassemble (
Ctr + D).
- Đặt địa chỉ breakpoint: 0x8CFD3D0, chỉ tích mục "write". Điều này có nghĩa là bất cứ khi nào CPU ghi dữ liệu vào địa chỉ trên, nó sẽ dừng game để ta có thể truy lại các lệnh xử dẫn đến việc ghi dữ liệu vào vùng Ram trên.
- Reset lại game (vì GOS ghi font vào Ram từ lúc đầu), lúc này CPU sẽ ngừng xử lý game.
- Khi CPU ngừng game, lần lượt click vào "Step Into" để đi vào từng lệnh chi tiết. Sau một vài lệnh, ta thấy dòng xử lý di chuyển tới 0x880868C trong Ram với nội dung: JAL zz_sceIoRead và giá trị $v0 lúc này là FE18, kích thước của file cần đọc.
- zz_sceIoRead là chức năng syscall đọc file từ đĩa UMD của PSP. Chức năng này sử dụng tham số đường dẫn đến file đã mở trong chức năng zz_sceIoOpen trước đó. Tham số $s3 cho ta biết thông tin về vị trí của file cần đọc trên đĩa.
- Giá trị của $s3 lúc này là 8CFF4A4. Nhảy tới địa chỉ này trong Ram và ta thấy được thông tin về vị trí file trên đĩa:
disc0:/PSP_GAME/USRDIR/DATA/ENGLISH/GAME.BIN
Như vậy, ta đã xác định được file chứa dữ liệu font: GAME.BIN. Đây là một file hỗn hợp gồm nhiều file nhỏ khác nhau. Mở file bằng Hex editor, dễ dàng xác định phần "file chứa font bắt đầu từ 0xDDB0 nhưng dữ liệu font thật sự bắt đầu ở DE10 vì 0x60 byte đầu tiên là header.
Copy dữ liệu từ 0xDDB0 đến hết file GAME.BIN, tạo thành file mới và mở bằng các phần mềm như Crystal Tile hay Tile Molester, điền các thông số như bpp (mà ta đã xác định ở bước đầu tiên) ta sẽ thấy được hình ảnh font.
Lúc này chỉ cần export hình ảnh ra dạng PNG hoặc BMP, chỉnh sửa bộ font này rồi import vào GAME.BIN là kết thúc công việc.
Lưu ý: nếu dùng phần mềm Tile Molester thì phải chèn thêm một số dummy byte vào cuối file để nó hiển thị hết bộ font. Đây là bug của phần mềm.
(Còn tiếp)