從Cocos Studio 1.6的csb文件逆向生成UI工程文件

逆向工程這種事情,類似軟件破解,不是萬(wàn)不得已不想去做。

最近有個(gè)需求姻蚓,我們要將一個(gè)老的cocos2d-x 3.2 + cocos Studio1.6做的游戲進(jìn)行改造,必須修改ui和特效里面的東東秋茫。但是由于種種原因史简,我們的UI工程已經(jīng)找不到了。

這就意味著只有兩條路可走肛著,要么結(jié)合程序中用到的各種層級(jí)關(guān)系圆兵,重建一個(gè)新的工程;要么就是根據(jù)原來(lái)的csb去做逆向工程枢贿,重新構(gòu)建一個(gè)可用的工程文件殉农。

先在網(wǎng)上看一看有沒(méi)有相關(guān)的代碼或工具,避免重復(fù)造輪子局荚。

首先找到的超凳,是一個(gè)叫x-studio365的工具,根據(jù)它的介紹:

  • 支持導(dǎo)入CocosStudio ccs工程及反導(dǎo)入CocosStudio發(fā)布的json和csb格式ui, 【文件】
    【導(dǎo)入】【CocosStudio(.ccs/.json)】耀态,【文件】【導(dǎo)入】【CocosStudio(*.csb)】需先新建一個(gè)空工程
  • 支持導(dǎo)入csb(將csb文件拖入編輯器場(chǎng)景即可)和發(fā)布到csb給ccoos2d-x引擎直接使用

按道理是可以用它來(lái)代替cocosStudio的轮傍,但是實(shí)測(cè)了一下,它只支持cocosStudio2.0以上的版本首装,而且最不可思議的是创夜,它不支持打包成plist + png這樣的圖集建立的工程∠陕撸總之驰吓,完全沒(méi)法用。

這里我要順便吐槽一下系奉,cocosStudio2.0以上版本檬贰,相比cocosStudio1.6功能差太多,觸控當(dāng)年如果沒(méi)有收編cocosStudio缺亮,也許今天我們能用到一個(gè)更加強(qiáng)大的動(dòng)畫和UI編輯軟件翁涤,沒(méi)spine和dragonBone什么事了。

然后我看到了這篇文章:cocos2d 由導(dǎo)出文件.csb反推出cocosUI工程。作者首先一通貌似強(qiáng)大的分析迷雪,然后在百度網(wǎng)盤上分享了源碼限书,活雷鋒啊虫蝶,必須給作者一萬(wàn)個(gè)贊章咧!下載"源碼"一看:尼瑪這是啥?完全是cocos2d-x 3.4 cocos studio部分的源碼呀能真,跟作者有半毛錢關(guān)系赁严?然后仔細(xì)看作者的分析,牛頭不對(duì)馬嘴粉铐,根本沒(méi)找到要點(diǎn)疼约。嗯,必須給作者一萬(wàn)個(gè)踩蝙泼!假的技術(shù)文章也好意思寫程剥?浪費(fèi)大家時(shí)間!

那首歌怎么唱的汤踏?從來(lái)沒(méi)有什么救世主织鲸,一切要靠我們自己。

前面談過(guò)溪胶,為了填CocosStudio的坑搂擦,我其實(shí)多次翻過(guò)這部分源碼,大致理解它讀取csb的機(jī)制哗脖,現(xiàn)在要重構(gòu)工程瀑踢,完全可以利用cocos自身的類來(lái)為我們解析。大家可以仔細(xì)研究分析一下CCSGUIReader.cpp中的GUIReader::WidgetFromBinaryFile這個(gè)類才避,怎么讀出json結(jié)構(gòu)的算法就有了橱夭。

由于算法中要用到cocos2d-x里面的很多類,懶得去分析各個(gè)類的依賴關(guān)系桑逝,直接用cocos新建一個(gè)工程來(lái)做這個(gè)轉(zhuǎn)換工程棘劣。我機(jī)器上的cocos2d-x現(xiàn)在是3.6版本,已經(jīng)填過(guò)坑肢娘,可以完美讀取cocosStudio1.6的csb文件呈础,我們就用它來(lái)建新工程吧。

cocos new csb2json -l cpp

然后新建一個(gè)Csb2Json類橱健,包含兩個(gè)文件:Csb2Json.cpp和Csb2Json.h而钞。vs中直接用類向?qū)Ы⒓纯伞4笾聝?nèi)容如下:

1.Csb2Json.h:

#pragma once
#include "cocos2d.h"
#include "cocostudio/CocoStudio.h"
#include <fstream>

USING_NS_CC;
using namespace std;
using namespace cocostudio;

class Csb2Json
{
public:
    Csb2Json();
    ~Csb2Json();
    static Csb2Json * getInstance() {
        static Csb2Json m_instance;
        return &m_instance;
    };

    int run(const string csbName);

private:
    void getTree(CocoLoader *pLoader, stExpCocoNode *pNode, int nTabNum);
    ofstream * m_pOutStream;
};

2.Csb2Json.cpp

#include "Csb2Json.h"

Csb2Json::Csb2Json()
{
}

Csb2Json::~Csb2Json()
{
}

int Csb2Json::run(const string csbName)
{
    std::string fullPath = FileUtils::getInstance()->fullPathForFilename(csbName);
    auto len = csbName.find(".");
    auto pureName = csbName.substr(0, len);
    auto jsonName = pureName + ".json";
    auto fileData = FileUtils::getInstance()->getDataFromFile(fullPath);
    auto fileDataBytes = fileData.getBytes();

    ofstream oStream(jsonName, ios::out);
    m_pOutStream = &oStream;

    CocoLoader  tCocoLoader;
    if (true == tCocoLoader.ReadCocoBinBuff((char*)fileDataBytes))
    {
        *m_pOutStream << "{" << endl;
        stExpCocoNode*  tpRootCocoNode = tCocoLoader.GetRootCocoNode();
        rapidjson::Type tType = tpRootCocoNode->GetType(&tCocoLoader);
        if (rapidjson::kObjectType == tType || rapidjson::kArrayType == tType)
        {
            getTree(&tCocoLoader, tpRootCocoNode,1);
        }
        *m_pOutStream << "}" << endl;
        m_pOutStream->close();
        return 0;
    }
    else {
        return 1;
    }
}

void Csb2Json::getTree(CocoLoader *pLoader, stExpCocoNode *pNode, int nTabNum)
{
    stExpCocoNode* pArray = pNode->GetChildArray(pLoader);
    int nChildNum = pNode->GetChildNum();
    //strTab用于控制縮排拘荡,按cocos原來(lái)的標(biāo)準(zhǔn)臼节,一次縮排2個(gè)空格。
    std::string strTab = "";
    for (int i = 0; i < nTabNum; ++i) {
        strTab = strTab + "  ";
    }
    for (int i = 0; i < nChildNum; ++i) {
        stExpCocoNode *pSubNode = &pArray[i];
        string strKey = pSubNode->GetName(pLoader);
        string strVal = pSubNode->GetValue(pLoader);
        rapidjson::Type tType = pSubNode->GetType(pLoader);

        if (strKey != "") {
            strKey = "\"" + strKey + "\": ";
        }

        if (rapidjson::kObjectType == tType) {
            if (strKey == "\"children\": ") {
                strKey = "";
            }
            *m_pOutStream << strTab << strKey << "{" << endl;
            getTree(pLoader, pSubNode, nTabNum + 1);
            *m_pOutStream << strTab << "}";
        }
        else if (rapidjson::kArrayType == tType) {
            *m_pOutStream << strTab << strKey << "[";
            int subNum = pSubNode->GetChildNum();
            if (subNum == 0) {  //避免空數(shù)組換行。
                *m_pOutStream << "]";
            }
            else {
                *m_pOutStream << endl;
                getTree(pLoader, pSubNode, nTabNum + 1);
                *m_pOutStream << strTab << "]";
            }
        }
        else {
            if (rapidjson::kNullType == tType) {
                strVal = "null";
            }
            else if (rapidjson::kStringType == tType || 83 == tType) {
                strVal = "\"" + strVal + "\"";
            }
            else if ((rapidjson::kNumberType == tType || -8 == tType) && strVal == "1") {
                strVal = "true";
            }
            else if ((rapidjson::kNumberType == tType || -8 == tType) && strVal == "0") {
                strVal = "false";
            }
            *m_pOutStream << strTab << strKey << strVal;
        }

        //判斷并合理使用結(jié)尾的逗號(hào)网缝。
        if (i == nChildNum - 1) {
            *m_pOutStream << endl;
        }
        else {
            *m_pOutStream << "," << endl;
        }
    }
}

**注意:
1.當(dāng)讀取到的類型為0bject或Array時(shí)巨税,getTree函數(shù)要被遞歸調(diào)用。
2.tType是個(gè)1-6的枚舉粉臊,但是實(shí)際取出來(lái)有8草添,-8 , 83等等奇怪的值,必須一一處理扼仲。
3.true和false并不在kTrueType和kFalseType里面远寸,這兩個(gè)類型設(shè)計(jì)出來(lái)就沒(méi)用過(guò)。
4.類型-8以及類型6(Number)里面的1表示true, 0表示false屠凶。
5.真正包含0和1的整數(shù)驰后,大概都在類型8里面,但是依然有很多數(shù)在類型6中矗愧。
6.類型83是要求強(qiáng)制加引號(hào)的灶芝,與類型string一個(gè)意思。
7.當(dāng)對(duì)象名為children時(shí)唉韭,它的上層數(shù)組也是children的時(shí)候夜涕,不顯示……
8.亂到這種程度我已經(jīng)無(wú)力吐槽,前面為cocoStudio叫屈的文字全部作廢纽哥。
9.數(shù)組或?qū)ο罄锩孀詈笠粋€(gè)成員后面必須不能有逗號(hào)钠乏,否則工程報(bào)錯(cuò)!
**

選擇一個(gè)現(xiàn)有的工程來(lái)測(cè)試春塌,同時(shí)輸出csb和json晓避。做個(gè)接口調(diào)用這個(gè)類,將csb文件作為輸入只壳,生成的同名json對(duì)比原工程輸出的json俏拱,一點(diǎn)一點(diǎn)找到匹配規(guī)律,排除各種坑以后吼句,最終形成上面的算法锅必。最后將原來(lái)需要逆向的csb導(dǎo)入,生成的json放回工程中測(cè)試惕艳,順利啟動(dòng)并完全符合需求搞隐。剩下的工作,就是做個(gè)選擇文件的接口远搪,具體不細(xì)說(shuō)了劣纲,有點(diǎn)基礎(chǔ)的朋友都應(yīng)該能自己搞定。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谁鳍,一起剝皮案震驚了整個(gè)濱河市癞季,隨后出現(xiàn)的幾起案子劫瞳,更是在濱河造成了極大的恐慌,老刑警劉巖绷柒,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件志于,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡废睦,警方通過(guò)查閱死者的電腦和手機(jī)伺绽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)郊楣,“玉大人憔恳,你說(shuō)我怎么就攤上這事【辉椋” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵输硝,是天一觀的道長(zhǎng)今瀑。 經(jīng)常有香客問(wèn)我,道長(zhǎng)点把,這世上最難降的妖魔是什么橘荠? 我笑而不...
    開(kāi)封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮郎逃,結(jié)果婚禮上哥童,老公的妹妹穿的比我還像新娘。我一直安慰自己褒翰,他們只是感情好贮懈,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著优训,像睡著了一般朵你。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上揣非,一...
    開(kāi)封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天抡医,我揣著相機(jī)與錄音,去河邊找鬼早敬。 笑死忌傻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的搞监。 我是一名探鬼主播水孩,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼腺逛!你這毒婦竟也來(lái)了荷愕?” 一聲冷哼從身側(cè)響起衡怀,我...
    開(kāi)封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎安疗,沒(méi)想到半個(gè)月后抛杨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡荐类,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年怖现,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玉罐。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡屈嗤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吊输,到底是詐尸還是另有隱情饶号,我是刑警寧澤,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布季蚂,位于F島的核電站茫船,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏扭屁。R本人自食惡果不足惜算谈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望料滥。 院中可真熱鬧然眼,春花似錦、人聲如沸葵腹。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)礁蔗。三九已至觉义,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浴井,已是汗流浹背晒骇。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留磺浙,地道東北人洪囤。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像撕氧,于是被迫代替她去往敵國(guó)和親瘤缩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理伦泥,服務(wù)發(fā)現(xiàn)剥啤,斷路器锦溪,智...
    卡卡羅2017閱讀 134,629評(píng)論 18 139
  • 有點(diǎn)懶得把圖片傳上來(lái)了,請(qǐng)移步這里看 Cocos官方論壇-wiki CocoaChina論壇帖子 上面兩個(gè)是一樣的...
    椒鹽老蟶閱讀 5,218評(píng)論 1 6
  • Cocos2d-x是一個(gè)開(kāi)源的移動(dòng)2D游戲框架府怯,MIT許可證下發(fā)布的刻诊。這是一個(gè)C++ Cocos2d-iPhone...
    黃花菜已涼閱讀 1,102評(píng)論 1 3
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,757評(píng)論 25 707
  • 又開(kāi)始糾結(jié)了:要不要考選調(diào)生?我能考上嗎牺丙?即便考上了我喜歡這份工作嗎则涯?可是不考怎么知道考不上?可是不考還有什么方法...
    青橙汁閱讀 189評(píng)論 0 0