2015年1月29日 星期四

cocos2dx 使用 pomelo 踩坑教學

序:想著pomelo比較好擴充,範例看起來也滿順眼的,所以我選擇了pomelo來當我的socket service. 其實我也搞不懂,為什麼COCOS2DX要連結POMELO居然這麼麻煩。。。

目標:使用quick cocos2dx v2.2.1跟v3.3,在lua中連結上pomelo的chat範例。 
首先我嘗試了https://github.com/luoxinliang/pomelo_quick_x 這個,一個以lua開發的pomelo lib, 但它的版本好像是v2.1,
而我是用v2.21使用的時候,一點點websocket的api有點差異,最主要的是sendBinary這個api我的版本裡沒有....我改成了sendBinaryMsg 感覺好像可以,但我在接到回傳值的時候,無法通過原本的Package.decode = function(binary) 會報local a = bit.lshift(bytes[index],16) 的index索引到nil。 事實上回來的binary是字串,不是table,我不知道為什麼,原lib的作法是先通過Package.decode可以取得type跟body, 可是我回來的就只是個binary的字串。於是我使用string.format("0x%02x", string.byte(binary, i)把每一個字串轉成number, 再用string.char轉成char,最後組成string,就變成有意義的json格式字串了,但前面幾個char是亂碼....我估計這是type。只是我轉不出來 把json decode出來後(捨去type的部份,type固定填1試試),感覺好像能跑了,但是會一直遞迴,想必是type是控制流程的flag, 嘛 算了 搞不出type..... 

另外關於pomelo的chat範例有https://github.com/NetEase/chatofpomelo跟https://github.com/NetEase/chatofpomelo-websocket 
我只有用https://github.com/NetEase/chatofpomelo-websocket,連的上。
前面那個 怎麼講 忘了 沒有再繼續交差比對,反正後面那個比較沒問題 

再來在v3.3的版本上,問題超多,像bit 的lib也要自已載進來,而且有的函式名不一樣,而且也沒有sendBinaryMsg,只有sendString... 雖然這個sendString感覺像多態用法,(我是參考自帶範例中的websocket),不過僅管我再試,也只是server接到訊息,但client收不到。 一直都是 open error close,然後沒有一個有用的訊息(我沒有直接在c++中看線程怎麼跑的) 
估計使用純lua的https://github.com/luoxinliang/pomelo_quick_x太麻煩了,像這種快速方案如果不快速,還是果斷換另一條路吧 

當然這是因為一開始也就知道 正規一點的作法是使用pomelo的 libpomelo來做。
 只不過要寫c++ 比較麻煩就是。
 要碰到c++,思路就是,把先的lib掛上去,確定能work,接著接到lua bind上。然後在lua中調用。 也是得做2個版本,(誰讓我維護2個版本的案子,又懶得全部改到3.3呢) 

先來做v3.3的版本 網上有個範例https://github.com/cokeboL/pomeloTolua4cocos2dxChat ,
這個不錯,他有個源碼下載(含cocos2dx),它好像是v3.0 不過下載來編譯後直接就能work了~好棒棒~ 證明了 libpomelo可以正常運作 而且我們有一個參考用的project。

 接著換我們來把v3.3也搞成一樣的例子。 我是直接開啟quick cocos2dx 3.3的player 專案,(參考http://cn.cocos2d-x.org/tutorial/show?id=1489) 
在E:\Cocos\quick-3.3\external底下git clone https://github.com/NetEase/libpomelo.git E:\Cocos\quick-3.3\external\libpomelo>cd libpomelo 
E:\Cocos\quick-3.3\external\libpomelo>mkdir build 
E:\Cocos\quick-3.3\external\libpomelo>git clone https://github.com/martine/gyp.git build/gyp
E:\Cocos\quick-3.3\external\libpomelo>build\gyp\gyp.bat --depth=. pomelo.gyp -Dlibrary=static_library -DTO=pc E:\Cocos\quick-3.3\external>cd libpomelo\deps\uv

E:\Cocos\quick-3.3\external\libpomelo\deps\uv>vcbuild.bat 

接著把以下的vcxproj加入player 專案裡,我是用vs2013
 E:\Cocos\quick-3.3\external\libpomelo\libpomelo.vcxproj 
 E:\Cocos\quick-3.3\external\libpomelo\deps\jansson\jansson.vcxproj 
 E:\Cocos\quick-3.3\external\libpomelo\deps\uv\libuv.vcxproj 
在vs裡的方案裡點

add exitsing project...,陸續把三個vcxproj都加進去。
再點擊player3專案右鍵屬性頁,
將3個project都加進來,
紅框是我新增的include。

有箭頭的部份是新增的lib連結。
然後開始建置整個方案,過了之後找一下libpomelo.lib跟libuv.lib及jansson.lib在哪裡
把他們復製到E:\Cocos\quick-3.3\quick\player\proj.win32\Debug.win32底下
接著把範例中的
Net.h
NetTolua.cpp
ThreadSafeQueue.h
Net.cpp
加進player3專案裡,
我在Net.h裡的這一行會出錯#include "CCNode.h"
我改成了#include "2d/CCNode.h"

你可以先建置看看。

接著修改AppDelegate.cpp
加入
#include "Net.h"
extern int luaopen_net(lua_State* tolua_S);
extern int luaopen_update(lua_State* tolua_S);
void registerLuas(lua_State* tolua_S)
{
luaopen_net(tolua_S);
}
//在director那邊加上一句(這是讓畫面在更新時會去查看有沒有新的封包進來要處理)
director->setNotificationNode(Net::getInstance());
//然後最後在L建立出來後加上(L是指lua_State* L = engine->getLuaStack()->getLuaState();)
registerLuas(L);

這樣就可以了,
我另外修改了一個地方,
由於一開始我Net.cpp裡的visit一直執行不到,就是畫面更新時,只會跑ccnode的visit,而不會跑net.cpp的visit,我才發現這版的visit的引數已經變了,引數不一樣,就沒辦法override
所以把net裡的visit引數改成跟這版裡的ccnode的visit一樣,就ok了。

接著lua的部份,就沒什麼好講,照範例裡的跟著照抄一份自已的版本就好了。
※在vc裡要debug,不能讓工作目錄指到welcome,要指到你的lua專案才行debug,所以記得更改預開專案的目錄。把ProjectConfig.cpp裡的path.append("quick/welcome");換掉就好了。

其他遇到的坑 'ssize_t' : redefinition; different basic types
cocos2d-x中使用libpomelo编译错误问题 http://blog.csdn.net/chana1101/article/details/40071917

OK V3.3完工,


V2.2.1 待續
OKAY 剛剛試著加入v2.2.1 發現加入libpomelo沒什麼問題,但加入範例的code,net.cpp 要修改的地方太大了。先來寫pomelo好了,寫完之後沒找著相關的參考資料,乾脆就換用v3.3寫吧

2015/04/20 後記
今天才試著發佈android版本。
mk設置的部份參考這個就好了https://github.com/cokeboL/pomeloTolua4cocos2dxChat/blob/master/frameworks/runtime-src/Classes/AppDelegate.cpp
編譯完之後,我試跑了一下,居然crash了,一直crash,後來查了一下是死在net.cpp裡的connect函式的ip=_ip
實在是搞不懂啊。所以就先用寫死ip的方式。
接著又發現 director->setNotificationNode(Net::getInstance());下的位置錯了。把他改成放在auto director = Director::getInstance();底下之後,才可以正常的連線。
接著把剛剛的ip=_ip改回來,居然就好了。太神奇了,不過因為用eclipse跑的時候沒什麼錯誤提示,也是沒辦法的事,能解決真是太好了。緊接著快來試試ios版吧...