三國殺移動(dòng)版拆包教程

這篇文章介紹手殺的拆包方法。都是批量完成的。確保某一步完成之后再繼續(xù)下一步。消耗的時(shí)間可能會(huì)相當(dāng)長。

下載三國殺移動(dòng)版

點(diǎn)擊這里下載三國殺移動(dòng)版

下載必需軟件

對(duì)于ArchLinux用戶,直接yay -S pvr-tex-tool-bin imagemagick

對(duì)于Windows用戶,因?yàn)楣俜较螺dPVRTexTool要注冊,所以只能去軟件園下載了,自己百度解決。

ImageMagick可以在官網(wǎng)下載,當(dāng)然就那破網(wǎng)速我還是建議去軟件園下載。

此外Windows還需要額外準(zhǔn)備一個(gè)解壓縮軟件,我推薦7zip。

記得安裝Python。

解包三國殺移動(dòng)版

把下載下來的apk文件后綴名改成.zip(其實(shí)也不用改),然后把a(bǔ)ssets文件夾解壓縮出來。素材都在這里面。

去解壓好的assets文件夾下面,把res文件夾單獨(dú)拿出來。素材都在這里面。(再放送)

res下面有這些:

  1. audios文件夾:音頻素材,直接可以聽。
  2. font:圖片素材的字體
  3. fonts:ttf字體
  4. ui:里面是ui素材。

.pvr.ccz@alpha轉(zhuǎn).pvr.ccz

我們可以注意到里面有許多.pvr.ccz文件。ccz文件就是pvr文件的壓縮包形式,所以我們先把ccz文件轉(zhuǎn)為pvr文件。注意到有.pvr.ccz@alpha結(jié)尾的,這個(gè)其實(shí)也是.pvr.ccz文件,只是在文件名后面加了個(gè)alpha。所以我們先把所有的<name>.pvr.ccz@alpha改成<name>_alpha.pvr.ccz形式,方便下一步操作。

由于pvr.ccz文件實(shí)在是太多了,手動(dòng)重名極其折磨人,我們需要寫個(gè)自動(dòng)化腳本。我只會(huì)shell腳本,Windows用戶請(qǐng)裝個(gè)git bash用來跑shell腳本。

假設(shè)你在手剎素材目錄,也就是res目錄下面。現(xiàn)在請(qǐng)新建一個(gè)文本文件,然后改名為rename_alpha.sh(txt拓展名也要改掉)。然后用文本編輯器打開它并粘貼以下內(nèi)容:

for l in `find -name '*@alpha'`
do
  mv $l ${l%*.pvr.ccz@alpha}"_alpha.pvr.ccz";
done

保存。在文件夾里面右鍵,點(diǎn)“Git Bash Here”,然后輸入命令bash rename_alpha.sh,回車?,F(xiàn)在重命名工作已經(jīng)完成了。

.pvr.ccz轉(zhuǎn).pvr

.pvr.ccz就是一個(gè)pvr文件用zlib壓縮了加個(gè)16字節(jié)文件頭而已。我們寫個(gè)python腳本就能把一個(gè).pvr.ccz轉(zhuǎn)成.pvr文件了。

現(xiàn)在新建一個(gè)文本文件,重命名為ccz2pvr.py。然后打開并粘貼以下內(nèi)容:

import zlib
import sys

ccz = sys.argv[1]
pvr = ccz[0:len(ccz) - 4]
ccz = open(ccz, "rb").read()
pvr = open(pvr, "wb")
pvr.write(zlib.decompress(ccz[16:len(ccz)]))
pvr.close()

保存。然后在git bash中輸入命令python,回車,如果看到的是這樣:

Python 3.10.1 (main, Dec 18 2021, 23:53:45) [GCC 11.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

反正不是啥報(bào)錯(cuò)之類的,說明python正常安裝,按Ctrl+D重新回到bash里面。如果是報(bào)錯(cuò)信息,請(qǐng)確認(rèn)python是否正常安裝。

然后我們創(chuàng)建ccz2pvr.sh,輸入以下內(nèi)容:

for l in `find -name '*.ccz'`
do
  python ccz2pvr.py $l
  rm $l
done

保存,運(yùn)行它?,F(xiàn)在ccz文件都被轉(zhuǎn)為pvr了。

pvr轉(zhuǎn)png

現(xiàn)在該我們PVRTexTool上場了。新建文件pvr2png.sh,輸入:

for l in `find -name '*.pvr'`
do
  pvr-tex-tool -ics sRGB -i $l -d ${l%.pvr}.png
  rm $l
  rm ${l%.pvr}.Out.pvr
done

如果你是Windows用戶,情況又稍微不同。需要輸入的命令改為

for l in `find -name '*.pvr'`
do
  C:/PowerVR/GraphicsSDK/PVRTexTool/CLI/Windows_x86_64/PVRTexToolCLI.exe -ics sRGB -i $l -d ${l%.pvr}.png
  rm $l
  rm ${l%.pvr}.Out.pvr
done

那一長串自然是你的PVRTexToolCLI.exe文件的路徑了。注意了,路徑里面的反斜杠“\”記得改成斜杠"/"。

保存,運(yùn)行命令。現(xiàn)在pvr文件都變成png了。

合并RGB通道和alpha通道

我們可以注意到拿出來的png文件有些是純黑底的,有些是黑白的。那些黑白的是alpha通道信息。現(xiàn)在我們把這兩個(gè)合并起來,得到真正可用的透明底的png圖片。

這里要用到ImageMagick。

新建alpha_png.sh,輸入以下內(nèi)容:

for l in `find -name '*_alpha.png'`
do
  n=${l%*_alpha.png}.png
  convert $n $l -compose copy-opacity -composite $n
  rm $l
done

對(duì)于Windows用戶,輸入這些:

for l in `find -name '*_alpha.png'`
do
  n=${l%*_alpha.png}.png
  <你的ImageMagick安裝目錄>/convert.exe $n $l -compose copy-opacity -composite $n
  rm $l
done

注意目錄里面的反斜杠要改成斜杠哦。保存,運(yùn)行。

plist拆圖

可以看到有些圖是很多小圖拼成的大圖。有些大圖有同名.plist文件,另一些有同名.atlas文件。我們先來把plist圖拆開成小圖。

這里也是找了個(gè)plist拆圖的python腳本。我們創(chuàng)建一個(gè)plist_split.py的文件,輸入下面的內(nèi)容:

import plistlib
import os
import sys
from PIL import Image


def export_image(img, pathname, item):
    # 去透明后的子圖矩形
    x, y, w, h = tuple(map(int, item['frame']))
    # 子圖原始大小
    size = tuple(map(int, item['sourceSize']))
    # 子圖在原始圖片中的偏移
    ox, oy, _, _ = tuple(map(int, item['sourceColorRect']))

    # 獲取子圖左上角,右下角
    if item['rotated']:
        box = (x, y, x + h, y + w)
    else:
        box = (x, y, x + w, y + h)

    # 使用原始大小創(chuàng)建圖像,全透明
    image = Image.new('RGBA', size, (0, 0, 0, 0))
    # 從圖集中裁剪出子圖
    sprite = img.crop(box)

    # rotated紋理旋轉(zhuǎn)90度
    if item['rotated']:
        sprite = sprite.transpose(Image.ROTATE_90)

    # 粘貼子圖,設(shè)置偏移
    image.paste(sprite, (ox, oy))

    # 保存到文件
    print('保存文件:%s' % pathname)
    image.save(pathname, 'png')

# 獲取 frame 參數(shù)
def get_frame(frame):
    result = {}
    if frame['frame']:
        result['frame'] = frame['frame'].replace('}', '').replace('{', '').split(',')
        result['sourceSize'] = frame['sourceSize'].replace('}', '').replace('{', '').split(',')
        result['sourceColorRect'] = frame['sourceColorRect'].replace('}', '').replace('{', '').split(',')
        result['rotated'] = frame['rotated']
    return result

# 生成圖片
def gen_image(file_name, export_path):
    # 檢查文件是否存在
    plist = file_name + '.plist'
    if not os.path.exists(plist):
        print('plist文件【%s】不存在!請(qǐng)檢查' % plist)
        return

    png = file_name + '.png'
    if not os.path.exists(png):
        print('png文件【%s】不存在!請(qǐng)檢查' % plist)
        return

    # 檢查導(dǎo)出目錄
    if not os.path.exists(export_path):
        try:
            os.mkdir(export_path)
        except Exception as e:
            print(e)
            return

    # 使用plistlib庫加載 plist 文件
    lp = plistlib.load(open(plist, 'rb'))
    # 加載 png 圖片文件
    img = Image.open(file_name + '.png')

    # 讀取所有小圖數(shù)據(jù)
    frames = lp['frames']
    for key in frames:
        item = get_frame(frames[key])
        export_image(img, os.path.join(export_path, key), item)


if __name__ == '__main__':
    if len(sys.argv) == 3:
        filename = sys.argv[1]
        exportPath = sys.argv[2]
        gen_image(filename, exportPath)

然后新建plist_split.sh,輸入:

for l in `find -name '*.plist'`; do
    pic=${l%%.plist}
    python plist_split.py $pic $pic'_plist'
    rm $pic'.png'
    rm $pic'.plist'
done

atlas拆圖

新建atlas_split.py,輸入

import os
import sys
import re
from PIL import Image

xymatcher = re.compile("\s*xy: (\d+),\s*(\d+)")
sizematcher = re.compile("\s*size: (\d+),\s*(\d+)")
indexmatcher = re.compile("\s*index: ([\-\d]+)")
origmatcher = re.compile("\s*orig: (\d+),\s*(\d+)")
offsetmatcher = re.compile("\s*offset: (\d+),\s*(\d+)")

def write_image(name, sprites, atlas_file, out_dir):
    """Get next texture info from the atlas and write it to the
    directory"""
    rotate = atlas_file.readline() #ignore rotate
    if ("true" in rotate):
        rotate = True
    xy = xymatcher.match(atlas_file.readline())
    x = int(xy.group(1))
    y = int(xy.group(2))
    sizes = sizematcher.match(atlas_file.readline())
    width = int(sizes.group(1))
    height = int(sizes.group(2))
    #split = atlas_file.readline()
    #if "split" in split:
    #    atlas_file.readline() #ignore origin
    #atlas_file.readline() #ignore offset
    orig = origmatcher.match(atlas_file.readline())
    origw = int(orig.group(1))
    origh = int(orig.group(2))
    offset = offsetmatcher.match(atlas_file.readline())
    offsetx = int(offset.group(1))
    offsety = int(offset.group(2))
    index_match = indexmatcher.match(atlas_file.readline())
    index = index_match.group(1)
    box = x, y, x + width, y + height
    if rotate == True:
        box = x, y, x + height, y + width
    tile = sprites.crop(box)
    if rotate == True:
        tile = tile.transpose(Image.ROTATE_270)
    target = Image.new("RGBA", (origw, origh))
    target.paste(tile, (offsetx, offsety))
    name = name if index == "-1" else name + "_" + index
    #return
    out_path = os.path.join(out_dir, name + ".png")
    os.system("mkdir -p " + out_path)
    os.system("rm -r " + out_path)
    print ("Writing sprite: ", name, " to: ", out_path, " sizes: ", width, height, x, y)
    target.save(out_path, "PNG")

def split(atlas, out_dir):
    """Open's the sheet, reads each atlas item and writes it into
    the out directory"""
    #sprites = Image.open(sheet).convert("RGBA")
    atlas_file = open(atlas)
    #read first few lines
    atlas_file.readline() #blank line
    sheet = os.path.join(os.path.dirname(atlas), atlas_file.readline().rstrip("\n"))
    sprites = Image.open(sheet).convert("RGBA") #use rgba for now
    while True:
        line = atlas_file.readline()
        if line.startswith("repeat"):
            break

    while True:
        name = atlas_file.readline()
        if name:
            write_image(name.rstrip("\n"), sprites, atlas_file, out_dir)
        else:
            break


def print_usage():
    print ("Usage : python atlas_splitter.py atlas out_dir")

if len(sys.argv) < 3:
    print_usage()
elif sys.argv[1] == "--help":
    print_usage()
else:
    split(sys.argv[1], sys.argv[2])

再新建atlas_split.sh,輸入

for l in `find -name "*.atlas"`
do
    mkdir ${l}_out
    python atlas_split.py $l ${l}_out
done

保存運(yùn)行。

未完待續(xù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 用到的組件 1、通過CocoaPods安裝 2、第三方類庫安裝 3、第三方服務(wù) 友盟社會(huì)化分享組件 友盟用戶反饋 ...
    SunnyLeong閱讀 15,164評(píng)論 1 180
  • 一、架構(gòu) 二、框架部署 2.1 準(zhǔn)備 準(zhǔn)備三臺(tái)虛擬機(jī),操作系統(tǒng)為CentOS 7.x,每臺(tái)內(nèi)存至少8G以上。 步驟...
    CJ21閱讀 1,215評(píng)論 0 3
  • 在你完成應(yīng)用程序的beta版本后,最后會(huì)有些人去幫你測試,使你去完善應(yīng)用程序……或者會(huì)有投資青睞。但是如果測試人員...
    zmp1123閱讀 6,882評(píng)論 15 46
  • 安裝包組成: 談到 App 瘦身,最直接的想法莫過于分析一個(gè)安裝包內(nèi)部結(jié)構(gòu),了解其每一部分的來源。解壓一個(gè) ipa...
    孔雨露閱讀 3,524評(píng)論 1 7
  • 轉(zhuǎn)載[https://www.cnblogs.com/crstyl/p/14690895.html] 前言 項(xiàng)目閑...
    iLeooooo閱讀 8,918評(píng)論 1 23

友情鏈接更多精彩內(nèi)容