const { ccclass, property } = cc._decorator; @ccclass export default class WebSocketSeverClass extends cc.Component { //#region 外調參數 @property({ type: cc.Label }) public Label: cc.Label = null; //#endregion //#region Lifecycle protected onLoad(): void { let self: this = this; // 在原生平台的 Release 模式下或者在 Web/微信小游戏等平台中,WebSocketServer 可能没有定义 if (typeof WebSocketServer === "undefined") { self._addLog("WebSocketServer is not enabled!"); return; } switch (cc.sys.getNetworkType()) { case cc.sys.NetworkType.LAN: { self._addLog("已連接Wifi"); break; } case cc.sys.NetworkType.WWAN: { self._addLog("未連接Wifi"); break; } case cc.sys.NetworkType.NONE: { self._addLog("未連接Network"); return; } default: break; } let ws: any = new WebSocketServer(); ws.onconnection = function (conn: any): any { self._addLog(`${conn.headers["origin:"]} connect!`); conn.ondata = function (data: any): any { self._addLog(`${conn.headers["origin:"]} ondata!`); self.ParseRpcMessage.bind(self)(data); self.SendData.bind(self)(ws, "acc", "666"); }; conn.onclose = function (): any { self._addLog(`${conn.headers["origin:"]} connection gone!`); }; }; ws.onclose = function (): any { self._addLog("server is closed!"); }; ws.listen(9005, (err: any): any => { if (err) { return; } self._addLog("server booted!"); }); } private _addLog(msg: string): void { console.log(msg); this.Label.string += `\n\n${msg}`; } public SendData(ws, Method, Data) { let json = [Method]; if (Data != null && Data != undefined && Data != NaN) { json[1] = Data; } let str = JSON.stringify(json); if (str.length > 65535) { this._addLog("要傳的資料太大囉"); throw new Error('要傳的資料太大囉'); } if (Data != null && Data != undefined && Data != NaN) { this._addLog(`[RPC] 傳送server資料: ${Method}(${JSON.stringify(Data).replace(/\\/g, "")})`); } else { this._addLog(`[RPC] 傳送server資料: ${Method}()`); } let strary = this.GetBytes(str); let buffer = new Uint8Array(4 + strary.byteLength); let u16ary = new Uint16Array(buffer.buffer, 0, 3); u16ary[0] = strary.byteLength; buffer[3] = 0x01; buffer.set(strary, 4); ws.send(buffer, (err: any) => { this._addLog(`${ws.headers["origin:"]} send!`); // }); } public ParseRpcMessage(buffer) { let startIndex = 0, byteLength = buffer.byteLength; while (startIndex + 4 < byteLength) { let strlen = new DataView(buffer, startIndex, 3).getUint16(0, true); let str = this.GetString(new Uint8Array(buffer, startIndex + 4, strlen)); startIndex += strlen + 4; try { let json = JSON.parse(str); let method = json[0]; let status = json[1][0]; let data = json[1][1]; let resp = { Method: method, Status: status, Data: data, IsValid: method && status === 0 }; if (data) { this._addLog(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}(${JSON.stringify(resp.Data)})`); // ResData(resp.Status, resp.Method, resp.Data); } else { this._addLog(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}()`); // ResData(resp.Status, resp.Method); } } catch { this._addLog(`[RPC] 無法解析Server回應: ${str}`); throw new Error(`[RPC] 無法解析Server回應: ${str}`); } } } public GetString(array) { let str = ""; let i = 0, len = array.length; while (i < len) { let c = array[i++]; switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: str += String.fromCharCode(c); break; case 12: case 13: str += String.fromCharCode(((c & 0x1F) << 6) | (array[i++] & 0x3F)); break; case 14: str += String.fromCharCode(((c & 0x0F) << 12) | ((array[i++] & 0x3F) << 6) | ((array[i++] & 0x3F) << 0)); break; } } return str; } public GetBytes(str) { let len = str.length, resPos = -1; let resArr = new Uint8Array(len * 3); for (let point = 0, nextcode = 0, i = 0; i !== len;) { point = str.charCodeAt(i), i += 1; if (point >= 0xD800 && point <= 0xDBFF) { if (i === len) { resArr[resPos += 1] = 0xef; resArr[resPos += 1] = 0xbf; resArr[resPos += 1] = 0xbd; break; } nextcode = str.charCodeAt(i); if (nextcode >= 0xDC00 && nextcode <= 0xDFFF) { point = (point - 0xD800) * 0x400 + nextcode - 0xDC00 + 0x10000; i += 1; if (point > 0xffff) { resArr[resPos += 1] = (0x1e << 3) | (point >>> 18); resArr[resPos += 1] = (0x2 << 6) | ((point >>> 12) & 0x3f); resArr[resPos += 1] = (0x2 << 6) | ((point >>> 6) & 0x3f); resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f); continue; } } else { resArr[resPos += 1] = 0xef; resArr[resPos += 1] = 0xbf; resArr[resPos += 1] = 0xbd; continue; } } if (point <= 0x007f) { resArr[resPos += 1] = (0x0 << 7) | point; } else if (point <= 0x07ff) { resArr[resPos += 1] = (0x6 << 5) | (point >>> 6); resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f); } else { resArr[resPos += 1] = (0xe << 4) | (point >>> 12); resArr[resPos += 1] = (0x2 << 6) | ((point >>> 6) & 0x3f); resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f); } } return resArr.subarray(0, resPos + 1); } //#endregion }