diff --git a/frontend/assets/scenes/offline_map.fire b/frontend/assets/scenes/offline_map.fire index 58b6939..7d4d203 100644 --- a/frontend/assets/scenes/offline_map.fire +++ b/frontend/assets/scenes/offline_map.fire @@ -547,7 +547,7 @@ "array": [ 0, 0, - 210.43935996345485, + 210.53572189052173, 0, 0, 0, diff --git a/frontend/assets/scripts/OfflineMap.js b/frontend/assets/scripts/OfflineMap.js index ae7d85b..27aa291 100644 --- a/frontend/assets/scripts/OfflineMap.js +++ b/frontend/assets/scripts/OfflineMap.js @@ -145,6 +145,16 @@ cc.Class({ JoinIndex: 1, }; if (cc.sys.isNative) { + window.onUdpMessage = (args) => { + const len = args.length; + const ui8Arr = new Uint8Array(len); + for (let i = 0; i < len; i++) { + ui8Arr[i] = args.charCodeAt(i); + } + cc.log(`#1 Js called back by CPP: onUdpMessage: args=${args}, typeof(args)=${typeof (args)}, argslen=${args.length}, ui8Arr=${ui8Arr}`); + const echoed = window.pb.protos.HolePunchUpsync.decode(ui8Arr); + cc.log(`#2 Js called back by CPP: onUdpMessage: ${JSON.stringify(echoed)}`); + }; DelayNoMore.UdpSession.upsertPeerUdpAddr(self.selfPlayerInfo.JoinIndex, "192.168.31.194", 6789, 123456); const res1 = DelayNoMore.UdpSession.openUdpSession(8888 + self.selfPlayerInfo.JoinIndex); const holePunchDate = window.pb.protos.HolePunchUpsync.encode({ diff --git a/frontend/assets/scripts/WsSessionMgr.js b/frontend/assets/scripts/WsSessionMgr.js index 76d409e..20e9d24 100644 --- a/frontend/assets/scripts/WsSessionMgr.js +++ b/frontend/assets/scripts/WsSessionMgr.js @@ -66,7 +66,9 @@ window.handleHbRequirements = function(resp) { } if (window.handleBattleColliderInfo) { - window.initSecondarySession(null, window.boundRoomId); + if (!cc.sys.isNative) { + window.initSecondarySession(null, window.boundRoomId); + } window.handleBattleColliderInfo(resp.bciFrame); } }; diff --git a/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp b/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp index 10958bd..2b9e373 100644 --- a/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp +++ b/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp @@ -1,10 +1,12 @@ #include "udp_session.hpp" #include "base/ccMacros.h" +#include "cocos/platform/CCApplication.h" +#include "cocos/base/CCScheduler.h" #include "cocos/scripting/js-bindings/jswrapper/SeApi.h" #include "uv/uv.h" -#include uv_udp_t* udpSocket = NULL; + uv_loop_t* loop = NULL; // Only this loop is used for this simple PoC int const sendBufferLen = 1024; @@ -18,12 +20,34 @@ void _onRead(uv_udp_t* req, ssize_t nread, const uv_buf_t* buf, const struct soc return; } - char sender[17] = { 0 }; - uv_ip4_name((const struct sockaddr_in*)addr, sender, 16); - CCLOG("Recv from %s", sender); + char senderAddrStr[64] = { 0 }; + uv_ip4_name((const struct sockaddr_in*)addr, senderAddrStr, 16); + //uv_udp_recv_stop(req); + + int const gameThreadMsgSize = 256; + char* const gameThreadMsg = (char* const)malloc(gameThreadMsgSize); + memset(gameThreadMsg, 0, gameThreadMsgSize); + memcpy(gameThreadMsg, buf->base, nread); + + CCLOG("Recv %d bytes from %s, converted to %d bytes for the JS callback", nread, senderAddrStr, strlen(gameThreadMsg)); free(buf->base); - uv_udp_recv_stop(req); + + cocos2d::Application::getInstance()->getScheduler()->performFunctionInCocosThread([=]() { + // [WARNING] Use of the "ScriptEngine" is only allowed in "GameThread a.k.a. CocosThread"! + se::Value onUdpMessageCb; + se::ScriptEngine::getInstance()->getGlobalObject()->getProperty("onUdpMessage", &onUdpMessageCb); + // [WARNING] Declaring "AutoHandleScope" is critical here, otherwise "onUdpMessageCb.toObject()" wouldn't be recognized as a function of the ScriptEngine! + se::AutoHandleScope hs; + se::ValueArray args = { se::Value(gameThreadMsg) }; + if (onUdpMessageCb.isObject() && onUdpMessageCb.toObject()->isFunction()) { + bool ok = onUdpMessageCb.toObject()->call(args, NULL /* Temporarily assume that the "this" ptr within callback is NULL. */); + if (!ok) { + se::ScriptEngine::getInstance()->clearException(); + } + } + free(gameThreadMsg); + }); } static void _allocBuffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { @@ -39,6 +63,7 @@ void startRecvLoop(void* arg) { } bool DelayNoMore::UdpSession::openUdpSession(int port) { + uv_mutex_init(&sendLock); uv_mutex_init(&recvLock); @@ -86,22 +111,6 @@ bool DelayNoMore::UdpSession::upsertPeerUdpAddr(int joinIndex, CHARC* const ip, return true; } -void DelayNoMore::UdpSession::onMessage(BYTEC* const bytes) { - se::ScriptEngine* se = se::ScriptEngine::getInstance(); - - se::Value func; - se->getGlobalObject()->getProperty("onUdpMessage", &func); - - se::ValueArray args; - args.push_back(se::Value(bytes)); - if (func.isObject() && func.toObject()->isFunction()) { - bool ok = func.toObject()->call(args, NULL /* Temporarily assume that the "this" ptr within callback is NULL. */); - if (!ok) { - se::ScriptEngine::getInstance()->clearException(); - } - } -} - void _onSend(uv_udp_send_t* req, int status) { free(req); if (status) { @@ -110,12 +119,17 @@ void _onSend(uv_udp_send_t* req, int status) { } bool DelayNoMore::UdpSession::punchToServer(BYTEC* const bytes) { - uv_mutex_lock(&sendLock); + /* + [WARNING] The RAM space used for "bytes", either on stack or in heap, is preallocatedand managed by the caller. + + Moreover, there's no need to lock on "bytes". Only "udpSocket" is possibly accessed by multiple threads. + */ uv_udp_send_t* req = (uv_udp_send_t*)malloc(sizeof(uv_udp_send_t)); - uv_buf_t sendBuffer = uv_buf_init(bytes, sizeof bytes); // [WARNING] The RAM space used for "bytes", either on stack or in heap, is preallocated and managed by the caller. + uv_buf_t sendBuffer = uv_buf_init(bytes, strlen(bytes)); SOCKADDR_IN destAddr; uv_ip4_addr("127.0.0.1", 3000, &destAddr); + uv_mutex_lock(&sendLock); uv_udp_send(req, udpSocket, &sendBuffer, 1, (struct sockaddr const*)&destAddr, _onSend); uv_mutex_unlock(&sendLock); return true; diff --git a/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.hpp b/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.hpp index 0e68091..5cca478 100644 --- a/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.hpp +++ b/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.hpp @@ -14,7 +14,6 @@ namespace DelayNoMore { static bool upsertPeerUdpAddr(int joinIndex, CHARC* const ip, int port, uint32_t authKey); //static bool clearPeerUDPAddrList(); static bool punchToServer(BYTEC* const bytes); - static void onMessage(BYTEC* const bytes); }; } #endif diff --git a/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session_bridge.cpp b/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session_bridge.cpp index 9c2b3f8..90cec0c 100644 --- a/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session_bridge.cpp +++ b/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session_bridge.cpp @@ -9,6 +9,7 @@ bool openUdpSession(se::State& s) { if (1 == argc && args[0].isNumber()) { SE_PRECONDITION2(ok, false, "openUdpSession: Error processing arguments"); int port = args[0].toInt32(); + return DelayNoMore::UdpSession::openUdpSession(port); } SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d; or wrong arg type!", (int)argc, 1); @@ -27,7 +28,10 @@ bool punchToServer(se::State& s) { memset(bytes, 0, sizeof bytes); se::Object* obj = args[0].toObject(); size_t sz = 0; - obj->getTypedArrayData((uint8_t**)&bytes, &sz); + uint8_t* ptr; + obj->getTypedArrayData(&ptr, &sz); + memcpy(bytes, ptr, sz); + CCLOG("Should punch by %d bytes v.s. strlen(bytes)=%u.", sz, strlen(bytes)); return DelayNoMore::UdpSession::punchToServer(bytes); } SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d; or wrong arg type!", (int)argc, 1); diff --git a/udp_server_prac/main.go b/udp_server_prac/main.go index 600613b..d386f37 100644 --- a/udp_server_prac/main.go +++ b/udp_server_prac/main.go @@ -26,6 +26,14 @@ func main() { } data := strings.TrimSpace(string(message[:rlen])) - fmt.Printf("received: %s from %s\n", data, remote) + fmt.Printf("received: %d bytes, content=%s from %s\n", rlen, data, remote) + + // echo + rlen, wrerr := conn.WriteTo(message[0:rlen], remote) + if wrerr != nil { + fmt.Printf("net.WriteTo() error: %s\n", wrerr) + } else { + fmt.Printf("Wrote %d bytes to socket\n", rlen) + } } }