欢迎参与讨论,转载请注明出处。
前言
《DNFMobile》的新一波内测到来了,恰好得到了安装包。便欲对比其资源较之端游有何不同,遂试图提取之。在尝试的途中遇到了不少问题,特此记录之。源码地址
读取资源包
与众多手游的习惯一样,初始的安装包所携带的资源甚少,皆需经过更新方才完整。更新后经过观察得知游戏采用Unity制作,那么事情便简单了,直接上UnityStudio读取。虽然资源文件的后缀名为.npk,但实际上则是Unity的AssetBundle,且并未作加密。然而诸多现成的Unity提取工具皆有多少缺陷(无法识别pvr格式、无法批量化操作、导出资源过于原始等),且图片资源是大图形式存在的,需要进行切图,而使用切图工具一则怕不够精确,二则怕无法批量化。于是我选择直接使用Unity制作工具以面对此需求。
由于资源文件本身即是Unity的格式,那么直接调用API加载即可,类似如此:
|
|
切图
这样可谓相当方便,接下来的问题便是切图了。我本以为大图是由Unity自动生成,所以理应资源内会有对应的Sprite资源,这样通过Sprite资源的信息即可进行切割。但实际上并非如此:大图是事先生成好,然后使用脚本填写每帧配置在运行时自动生成Sprite。这种做法也是理所当然的,毕竟Unity的Sprite的pivot与DNF的IMG包提供的偏移点可谓天南地北。(一者为当前图片下的浮点百分比,另一者为实际坐标)通过直接在配置直接对接IMG包的数据然后进行转化这是很正常的做法。可这下子就麻烦了,我们并无法直接知道这脚本的具体信息。幸好UnityStudio的解析中包括了关于MonoBehavior资源配置的信息。
可即使知道也无法直接Unity进行获取,毕竟我们本身是没有该脚本的。鉴于UnityStudio开源的特性,我起初打算阅读源码掌握其解析之法。最后也成功了,可我突然脑内灵光一闪,想到了直接建立一个同名脚本,并根据配置的信息进行模拟。代码如下:
|
|
天可怜见,居然成功了!那么接下来采用类似如下方法即可:
|
|
主要思路便是通过GetPixels方法读取区域像素并覆盖至新图。最后将图片转换为PNG、配置转换为JSON并输出即可。
当然这里还有关于Texture2D的readable问题,隶属于资源包的Texture2D并无法直接使用GetPixels方法,需要对其进行复制,然后利用新图施为,为此我写了个函数:
|
|
以上便是关于切图方面的问题,具体可参阅源码。
内存问题
游戏目前的资源包数量高达2900以上,在尝试一口气全部提取时内存竟然高达5G!最终电脑不堪重负倒下收场。这很显然是资源并未回收所致,是以作此函数:
|
|
这里采用的是DestroyImmediate方法,好处是立即进行回收,但却会因此阻塞,影响提取效率。若使用Destroy方法则不会如此,不过峰值内存会上升。但大规模读取时还是以稳定为主,而小份读取则两者并无所谓。是以选择DestroyImmediate方法。
另外在其他地方涉及到资源生成且是继承自UnityEngine.Object的,皆需注意此问题。在经过优化后,占用由5G跌倒了500M-1.5G之间,成功提取了全部图片资源。大功告成!
后记
这次《DNFMobile》的声音资源经过了高压,原本几M的音乐变成了上百K,可谓惨不忍听,遂无提取的价值。而纸娃娃方面则是采用了类似NPK_Ver4的色板做法,也并无法直接提取到成品。由此可见制作组为了节省空间可是下了不少功夫呀。