资源分析


  之前已经介绍过了整个游戏的汉化流程,我也提到过其实汉化的流程虽然简单,但是每一个步骤里面都包含了许多细节,甚至于有时候一个细节就会让整个汉化宣布失败。今天主要讲的就是第一个步骤,资源分析(包括资源的解包和封包),我用一个汉化实例的来说明,游戏是PS3下的ICO HD(又叫古堡迷踪,PS2下一款经典老游戏),之所以选择这个游戏,是因为它很简单,上手非常容易,这个游戏没有字库,所有的文本都是以图片形式存在的,游戏汉化的主要工作就是解包资源,改图,然后封包。

  我们先来看一下这个游戏的整体目录结构:

  熟悉PS3游戏的朋友应该知道PS3的目录结构,实际上游戏的主要文件都是放在PS_Game/USRDIR下的,汉化的时候,也是主要处理这个目录下的资源文件。USRDIR下的最重要的文件就是那个EBOOT.BIN,我之前说过,PS3是一个类Unix系统,EBOOT.BIN就是PS3的可执行文件,实际上这个文件本身是ELF(Executable and Linkable Format,Unix-Like系统的可执行文件),但是Sony对这个文件进行了加密,所以变成了BIN,可执行文件的解密工具可以在这里下载(注意是C的源文件,要使用的话,请自行make一下,另外,这里就不提供Key了,需要的朋友可以去Google一下,EBOOT的解密和加密一定要学会,因为有些游戏的文本就包含在这里面,比如我们之前汉化的一个游戏,托托莉的工作室)。关于EBOOT.BIN,以后在教程中逐步讲解,今天不会对这个文件进行任何处理。

  继续来看文件,除了EBOOT.BIN,其他文件基本都是资源或者游戏脚本,而ICO只有一个文件,就是ICO/ico.psarc,实际上,游戏厂商为了提升游戏对文件读取的处理效率,使用了一个封包,将所有的资源都打包了(不大包的话,会有很多零散的小文件,PS3读取起来那叫一个慢啊),打包方式采用了Sony自家的PlayStation Archivie格式(在PS3下,读取这个包里面的内容就像读取本地内容一样轻松)。为什么我会知道它是采用的Sony的封包格式呢,其实最开始我也不知道psarc是什么格式,主要也是Google告诉我的。这里说下题外话,做程序,无论是不是搞汉化,学会用搜索引擎是个很重要的技能。另外,推荐一个国外专门研究游戏(是研究游戏结构、资源、破解)的论坛,有一些高手,而且各种资源解包的BMS脚本也多,网址是:http://forum.xentax.com/,在搜索的时候,可以这样来用Google(建议使用www.google.ph,速度比hk快的多),“site:forum.xentax.com psarc”,这样就可以搜索站内相关资源了。OK,继续,PSARC的解包要用到一个psarc工具,下面我详细说明下(很多游戏都用到了psarc格式)。

PSARC工具的使用


  该工具是个命令行工具,运行后如下:

  最重要的功能有三个,create,extract,list。使用方法为:psarc.exe extract ico.psarc。其他的选项不过多介绍了,help里面写的非常详细,主要这里说下list和-a选项。

  list是列出包里所有文件,为什么说它重要呢,因为打包的时候要用到!一般来说,默认打包会按照文件路径顺序打包,但是部分游戏会出现异常,比如ICO,我们汉化的时候,只要打包放回游戏,就回出现死机的问题,测试了一下午,最后发现必须按照打包顺序放回去。那么list的功能就出来了,它回输出文件的原始顺序,而这个打包工具提供了一个功能,--inputfile的选项,可以让你指定一个文件,来描述要打包的文件路径。例如:psarc.exe create --inputfile=list.txt。这样就可以保证游戏不出问题了(所有游戏都可以采用这个方式打包)。

  不过这里需要注意一点,在cmd下运行list命令时,要这样写:psarc.exe list ico.psarc >> list.txt才会输出到文件,否则直接打印在控制台窗口中。另外,输出的文件列表每一行都包含了文件的大小信息,需要写一个程序来统一处理,把里面的每一行都换成与psarc.exe的相对路径。例如下面这个list.txt:

  说明下,因为我在mac下不能用我上面提到的那个工具,所以我找了个linux版本的psarc,输出的列表有些差异,不过大同小异。好了,列表里面,比如第一行,我们就要去掉1 469.09mb这些与路径无关的字符串。下面的代码就是我之前写的转换ICO的List的(当时赶时间,顺便写了下,可以专门写成一个通用处理程序):

namespace ListConverter
{class Program{static void Main(string[] args){string[] alltxts = File.ReadAllLines("ico.txt");List<string> temp = new List<string>();foreach (string s in alltxts){string t = s.Substring(0,s.LastIndexOf("(")-1);t = t.Substring(1, t.Length - 1);temp.Add(t);}File.AppendAllLines("ico_m.txt", temp);Console.WriteLine("complete");}}
}

  上面差不多就是psarc的使用方式和注意事项,接下来我们就要解压ico.psarc并开始进行正式的资源分析了。

文件格式的分析


  解压ico.psarc后,我们得到如下的文件结构:

  一共37704个文件,1.9G解压出来有4个多G。之前我说过,这个游戏没有文本和字库(关于如何确定游戏的文本,我会在下一节讲解)。但是我才拿到这个游戏的时候,是如何确定它没有文本的呢。首先我们翻一下游戏目录,在bp_precache/text/menu_pal_eg/_ps3下,我们发现了一系列ctxr文件,这个是什么文件?起初我也不知道,先不急分析,Google一下(能有现成的为啥不用)。最后,还是在xentax发现了一片帖子,说这种文件实际上是dds图片格式的封装,首先要把ctxr转换成gtf文件,然后将gtf文件转换为dds,并且还附带了对文件头信息描述的说明,于是,先搜索了gtf2dds,一个转换程序,然后需要写个批量处理程序来转换ctxr,转换之前,首先要确认ctxr的文件头信息,所以WinHex是汉化必不可少的工具,用它来查询16进制,并研究里面记录的数据。我先把ctxr的头文件数据贴上来,然后比照我的转换代码可以看出是如何来分析并转换的。

  到偏移位置0x80以前,都是头文件信息,之后的就是图片的数据了。转换的代码如下(记住转换程序一定要写双向的啊,xentax上大部分脚本都是有去无回的):

#region 引用using System;
using System.IO;#endregionnamespace CtxrProcessor
{internal class Ctxr{public void ToGtf(FileInfo file){string baseName = file.Name.Replace(file.Extension, "");string rcdPath = string.Empty;string gtfPath = string.Empty;if (file.DirectoryName != null){rcdPath = Path.Combine(file.DirectoryName, baseName + ".dat");gtfPath = Path.Combine(file.DirectoryName, baseName + ".gtf");}Console.WriteLine("正在处理:{0}", file.FullName);using (FileStream fileReader = file.OpenRead()){using (BinaryReader binReader = new BinaryReader(fileReader)){using (MemoryStream fileData = new MemoryStream()){byte[] fixHead = binReader.ReadBytes(0x18);fixHead[1] = 1;fixHead[2] = 1;fileData.Write(fixHead, 0, fixHead.Length);//需要记录的数据byte[] recordData = binReader.ReadBytes(0xc);File.WriteAllBytes(rcdPath, recordData);byte[] imgData = binReader.ReadBytes(0x14);fileData.Write(imgData, 0, imgData.Length);byte[] zeroData = new byte[0x80 - fileData.Length];fileData.Write(zeroData, 0, zeroData.Length);//写入基础数据fileReader.Seek(0x80, SeekOrigin.Begin);int bodyDataLength = (int)(fileReader.Length - 0x80);byte[] bodyData = binReader.ReadBytes(bodyDataLength);fileData.Write(bodyData, 0, bodyData.Length);File.WriteAllBytes(gtfPath, fileData.ToArray());}}}file.Delete();}public void ToCtxr(FileInfo file){string baseName = file.Name.Replace(file.Extension, "");string rcdPath = string.Empty;string cxtrPath = string.Empty;if (file.DirectoryName != null){rcdPath = Path.Combine(file.DirectoryName, baseName + ".dat");cxtrPath = Path.Combine(file.DirectoryName, baseName + ".ctxr");}Console.WriteLine("正在处理:{0}", file.FullName);using (FileStream fileReader = file.OpenRead()){using (BinaryReader binReader = new BinaryReader(fileReader)){using (MemoryStream fileData = new MemoryStream()){byte[] fixHead = binReader.ReadBytes(0x18);fixHead[1] = 0;fixHead[2] = 0;fileData.Write(fixHead, 0, fixHead.Length);byte[] recordData = File.ReadAllBytes(rcdPath);fileData.Write(recordData, 0, recordData.Length);byte[] imgData = binReader.ReadBytes(0x14);fileData.Write(imgData, 0, imgData.Length);byte[] zeroData = new byte[0x80 - fileData.Length];fileData.Write(zeroData, 0, zeroData.Length);//写入基础数据fileReader.Seek(0x80, SeekOrigin.Begin);int bodyDataLength = (int)(fileReader.Length - 0x80);byte[] bodyData = binReader.ReadBytes(bodyDataLength);fileData.Write(bodyData, 0, bodyData.Length);File.WriteAllBytes(cxtrPath, fileData.ToArray());}}}file.Delete();File.Delete(rcdPath);}}
}

#region 引用using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;#endregionnamespace CtxrProcessor
{internal class Program{private static void Main(string[] args){if (args.Length != 2){PrintUsage();return;}string option = args[0];string path = args[1];bool isFile = File.Exists(path);bool isDirectory = false;if (!isFile)isDirectory = Directory.Exists(path);if (!isFile && !isDirectory){Console.WriteLine("指定的文件或路径不存在");Console.ReadKey();return;}Ctxr c = new Ctxr();if (isFile){FileInfo file = new FileInfo(path);switch (option.ToLower()){case "c2g":c.ToGtf(file);break;case "g2c":c.ToCtxr(file);break;default:PrintUsage();break;}}else{switch (option.ToLower()){case "c2g":string[] cFiles = GetAllFiles(new DirectoryInfo(path), ".ctxr");foreach (string cSingle in cFiles){FileInfo cFile = new FileInfo(cSingle);c.ToGtf(cFile);}break;case "g2c":string[] gFiles = GetAllFiles(new DirectoryInfo(path), ".gtf");foreach (string gSingle in gFiles){FileInfo gFile = new FileInfo(gSingle);c.ToCtxr(gFile);}break;default:PrintUsage();break;}}Console.WriteLine("处理完成\r\n按任意键退出");Console.ReadKey();}private static void PrintUsage(){Console.WriteLine("CtxrProcessor.exe c2g[g2c] [file|path]");Console.WriteLine("c2g: ctxr转换为gtf\r\ng2c: gtf转换为ctxr");Console.WriteLine("可以指定文件或路径(指定路径为批量处理)");}private static string[] GetAllFiles(DirectoryInfo directory, string extension){List<string> allFiles = new List<string>();DirectoryInfo[] allDirectory = directory.GetDirectories();if (allDirectory.Length > 0){foreach (string[] files in allDirectory.Select(single => GetAllFiles(single, extension))){allFiles.AddRange(files);}FileInfo[] fileInfos = directory.GetFiles();allFiles.AddRange(from file in fileInfoswhere file.Extension.ToLower().Equals(extension)select file.FullName);return allFiles.ToArray();}else{FileInfo[] files = directory.GetFiles();allFiles.AddRange(from file in fileswhere file.Extension.ToLower().Equals(extension)select file.FullName);return allFiles.ToArray();}}}
}

  因为要考虑转换回去,我在上面多生产了一个dat文件,用来记录固定不变的数据,转换回去的时候好写回原文件,程序写好了以后,记住测试一下,就针对原始文件来转换并转回,然后比较MD5值,如果相同,那么程序基本就没有什么问题了。

  得到gtf文件后,就可以用下载的gtf2dds.exe,dds2gtf.exe来进行转换,最后用PS打开(dds图片需要去Nvidia官方网站下载一个插件),你就发现,上面例子中的图片原来是Sony的Logo,你可以尝试修改一下放回游戏~

  这里特别说明下,本身gtf2dds.exe和dds2gtf.exe是支持批量处理的,但是需要一个文件列表,不过我们不可能去手写这个列表啊,所以,最简单的方式是利用windows的搜索功能,搜索"*.gtf",然后windows就把列表给你做好了,你要做的就是将这些文件拖动到gtf2dds.exe程序图标上即可。

  最后我们大概预览下生成的图片,就发现了游戏文本,原来都在图片里,游戏开发商太懒了。然后果断的顺便修改几个图片,打包回去放回游戏,好了,中文正常显示,汉化成功,接下来就是美工和翻译下体力了。

结束语


  这个游戏的汉化过程其实非常简单,当初唯一难住我们的就是psarc封包的时候的顺序问题,不过不轻易放弃,不断的尝试各种方式,总会成功的。另外,很大一部分游戏的资源解包没有那么简单,有些时候,你就是找遍了各大网站,都找不到相关的说明或者工具,这个时候,就只有自己来分析头文件并编写程序了,这个才是真正的挑战,我在后面的教程也会不断加强汉化难度来讲解。最后,上面的所有源代码可以在Github上下载。另外,需要其他的工具的可以在站内PM我,或者在我Blog留言(一般我登陆我的Blog较多,博客园都是要写文章的时候才来,欢迎到我Blog灌水!)。

转载于:https://www.cnblogs.com/sweetwxh/archive/2013/02/23/game_localization_tutorial_2.html

游戏汉化教程2-资源分析相关推荐

  1. 游戏汉化教程1-汉化流程

    游戏汉化流程 游戏汉化是非常具有挑战和成就感的,挑战在于和游戏开发商斗智斗勇,想尽一切办法层层拨开文件,得到最后需要汉化的资源,其过程不亚于一段推理.成就感就不用说了,和开发程序一样的,谁不愿意看到自 ...

  2. (转载)iPhone软件和游戏汉化教程,让你轻松成为汉化高手!

    说到软件汉化,一般朋友可能会觉得很复杂,其实iPhone的汉化相对于Windows软件的汉化来说,技术上要简单一些,因为iPhone属于Mac OS的简化版,Mac OS本身有非常直观的多语言环境支持 ...

  3. galgame 游戏汉化和galgame 游戏翻译入门经典教程

    最近有人问起来 galgame 游戏汉化和galgame 游戏翻译问题,这类问题不再一个一个回答了写本文给 galgame 游戏爱好者好了 希望大家喜欢 翻译galgame 游戏 核心软件就是agth ...

  4. MyEclipse 汉化教程(含资源)

    MyEclipse 汉化插件.汉化图文教程 一. 汉化教程 · 图文解说 点击查看文章:百度经验 官网首页的顶部导航栏中找到,"项目(翻译:Projects)",并点击进入, 然后 ...

  5. MySQL Workbench 6.3CE 汉化教程(内附资源链接)

    1.下载MySQL Workbench 客户端 官方下载地址:https://dev.mysql.com/downloads/workbench/ 2.安装 安装教程:https://jingyan. ...

  6. PPC/SP/PC汉化教程:如何汉化一个软件

    [以前也想过汉化一些软件,但那时候对PE文件都不是很了解,脱壳是什么都不知道,今天看到这篇文章,觉得不错,就转载来看下,以便以后需要用的时候能找到] 其实PC和PPC/SP在汉化的许多地方都是相似的, ...

  7. 第七章 : Git 介绍 (上)[Learn Android Studio 汉化教程]

    Learn Android Studio 汉化教程 [翻译]Git介绍 Git版本控制系统(VCS)快速成为Android应用程序开发以及常规的软件编程领域内的事实标准.有别于需要中心服务器支持的早期 ...

  8. 4K网络视频下载器:4K Video Downloader mac汉化教程

    4K Video Downloader for Mac版是一款4K网络视频下载器,现在我们的视频除了1080P还有4K超高清视频品质的影片,但是随着视频文件的扩大,下载速度却跟不上,这成了一个很大的问 ...

  9. 游戏汉化技术内幕 第2章解包封包

    作者: 坑神姐姐 AD http://kdays.cn/ 第1章 KRKR游戏系统汉化说明 封包(Pack) -- 相对的就是解包(Unpack) 实际上能解包的 不代表就能封包 因为解包仅仅代表是从 ...

最新文章

  1. 笔记 - AliCloud CDN 分发网络简介
  2. Delphi实现的透明阴影以及蒙版效果菜单
  3. android 6.0 ios9谁快,没安卓6.0流畅?iOS 9突飞猛进终于不卡
  4. c3p0 参数 模糊查询_Hibernate day03笔记
  5. win7系统如何清理系统日志
  6. shell获取路径文件的文件名
  7. 总结阐述Cocos2d-X与Cocos2d-iphone区别
  8. Java阻塞队列的实现
  9. 在ASP.NET中显示Linq To SQL输出的SQL语句
  10. Hadoop上传和下载大存储的HIVE表
  11. 未来计算机教师职业愿景展望,教师愿景与职业规划
  12. RMAN delete noprompt obsolete参数研究
  13. 猪悟能淘宝商品下载专家v3版开发手记
  14. 【翻译】“PE文件格式”1.9版 完整译文(附注释)
  15. 怎么成为日上会员直邮_怎么成为日上会员vip
  16. 500+分区Mini LED,海信电视E8H让画质更纯净
  17. 机器人简化图画手绘图_如何画机器人的简笔画 经验告诉你该这样
  18. 【n子棋】不只是三子棋,也可以是五子棋,一百子棋。
  19. 统计素数并求和,C语言
  20. 冒险岛linux服务端 143端

热门文章

  1. 按下( )组合键 可以快速锁定计算机,锁定计算机,小编教你锁定计算机的快捷键...
  2. 用udp实现可靠传输python_一种基于UDP协议实时可靠图像传输方案的制作方法
  3. 来自西弗吉利亚大学li xin整理的CV代码合集
  4. 贩妖记 第六十一章,小妖开口
  5. 当代罪恶:山西黑砖窑
  6. 计算机知识小课堂宣传标语,创建高效课堂宣传标语50条
  7. 用hive或mr清洗app数据
  8. 把彩色图片变成适合素描的黑白图片
  9. python判断中文相等_Python判断中文字符串是否相等
  10. 浅析步进电机常见的三种驱动方式