转载:https://www.cnblogs.com/skyxu123/p/9810741.html
我觉得很有学习意义~~
若有不妥。请联系我删除!
先上个效果图:
使用cocoscreator 1.9.1 + node.js + websocket实现,没有使用socket.io, 全部自己封装,长连接进行封装后可以和短连接使用方法一样,使用简单,方便以后开发网络游戏。
1、客户端:
主要就是聊天内容的显示,自动换行和背景扩展,代码大概如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
cc.Class({
extends: cc.Component,
properties: {
msgLabel: cc.Label,
uidLabel: cc.Label,
msgLayout: cc.Layout,
msgBg: cc.Node,
maxLen: 500,
},
// LIFE-CYCLE CALLBACKS:
// onLoad () {},
start () {
this.node.runAction(cc.fadeTo(0.5, 255))
},
initMsg(msg, uid){
this.msgLabel.string = msg;
this.uidLabel.string = uid;
this.msgLabel.overflow = cc.Label.Overflow.NONE;
// this.msgBg.width = this.msgLabel.node.width + 10;
// this.msgBg.height = this.msgLabel.node.height + 10;
// this.node.height = this.msgBg.height + 40;
this.scheduleOnce((dt)=>{
if ( this.msgLabel.node.width >= this.maxLen){
this.msgLabel.overflow = cc.Label.Overflow.RESIZE_HEIGHT;
this.msgLabel.node.width = this.maxLen;
}
this.msgBg.width = this.msgLabel.node.width + 10;
this.msgBg.height = this.msgLabel.node.height + 10;
this.node.height = this.msgBg.height + 40;
}, 0);
this.node.opacity = 0;
}
// update (dt) {},
});
网络部分分成了四层:
1、socket 封装基础的websocket, 这里是最底层,也是真正链接的开始
2、network 控制socket链接层,实现各回调接口
3、netproxy 封装各服务功能,把长连接变成短连接的请求方式
4、netprotocols 和服务器协商,确定每个请求的请求体格式和回复格式
各部分代码如下:
GameWebSocket.js:
复制代码
/**
- @enum {number}
*/
var GameWebSocketState = cc.Enum({
CONNECTING: 1,
OPEN: 2,
CLOSING: 3,
CLOSED: 4
});
/**
-
@interface
*/
var GameWebSocketDelegate = cc.Class({onSocketOpen: function () {
},
/**
- 收到了消息
- @param {string|Uint8Array} data
*/
onSocketMessage: function (data) {
},
onSocketError: function () {
},
/**
- 连接关闭
- @param {string} reason
*/
onSocketClosed: function (reason) {
}
});
/**
-
@interface
*/
var GameWebSocketInterface = cc.Class({connect: function () {
},
send: function () {
},
close: function () {
},
getState: function () {
}
});
var GameWebSocket = cc.Class({
extends: GameWebSocketInterface,
properties: {
/**
* @type {String} 服务器地址
*/
_address: null,
/**
* @type {GameWebSocketDelegate}
*/
_delegate: null,
/**
* @type {WebSocket}
*/
_webSocket: null,
},
/**
* @param {string} address 服务器地址
* @param {GameWebSocketDelegate} delegate 回调接口
*/
init: function(address, delegate){
this._address = address;
this._delegate = delegate;
this._webSocket = null;
},
connect: function () {
cc.log('connect to '+ this._address);
var ws = this._webSocket = new WebSocket(this._address);
ws.onopen = this._delegate.onSocketOpen.bind(this._delegate);
ws.onmessage = function (param) {
this._delegate.onSocketMessage(param.data);
}.bind(this);
ws.onerror = this._delegate.onSocketError.bind(this._delegate);
// function({code: Number, reason: String, wasClean: Boolean})}
ws.onclose = function (param) {
this._delegate.onSocketClosed(param.reason);
}.bind(this);
},
/**
* 发送数据
* @param {string|Uint8Array} stringOrBinary
*/
send: function (stringOrBinary) {
this._webSocket.send(stringOrBinary);
},
close: function () {
if (!this._webSocket) {
return;
}
try {
this._webSocket.close();
} catch (err) {
cc.log('error while closing webSocket', err.toString());
}
this._webSocket = null;
},
getState: function () {
if (this._webSocket) {
switch(this._webSocket.readyState){
case WebSocket.OPEN:
return GameWebSocketState.OPEN;
case WebSocket.CONNECTING:
return GameWebSocketState.CONNECTING;
case WebSocket.CLOSING:
return GameWebSocketState.CLOSING;
case WebSocket.CLOSED:
return GameWebSocketState.CLOSED;
}
}
return GameWebSocketState.CLOSED;
}
});
module.exports = {
GameWebSocketState: GameWebSocketState,
GameWebSocketDelegate: GameWebSocketDelegate,
GameWebSocketInterface: GameWebSocketInterface,
GameWebSocket: GameWebSocket
};
复制代码
GameNetwork.js
复制代码
/**
- Created by skyxu on 2018/10/9.
*/
“use strict”;
let GameWebSocket = require("./GameWebSocket");
let GameProtocols = require("./GameProtocols");
/**
- 服务器回复消息状态,判断回复消息的各种问题
*/
var response_state = {
ERROR_OK : ‘0’
};
/**
-
请求回调对象,收到服务器回调后的回调方法
*/
var NetworkCallback = cc.Class({properties: {
/** * @type {BaseRequest} request */ request: null, /** * 请求回调对方法 */ callback: null
},
/**
- @param {BaseRequest} request
- @param {function(BaseResponse): boolean} callback
*/
init: function (request, callback) {
this.request = request;
this.callback = callback;
}
});
let GameNetwork = cc.Class({
extends: GameWebSocket.GameWebSocketDelegate,
ctor: function() {
this._socket = null;
this._delegate = null;
/**
* 每次发送请求,都需要有一个唯一的编号
* @type {number}
* @private
*/
this._requestSequenceId = 0;
/**
* 接受服务器主动下发的response回调
* key 表示BaseResponse.act
* @type {Object.<string, function(object.<string, *>)>}
*/
this.pushResponseCallback = {};
/**
* 根据seq保存Request和其callback,以便在收到服务器的响应后回调
* @type {Object.<int, NetworkCallback>}
* @private
*/
this._networkCallbacks = {};
},
setDelegate: function (delegate) {
this._delegate = delegate;
},
/**
* 注册服务器主动推送的response 回调
*/
registerPushResponseCallback : function(act, callback){
this.pushResponseCallback[act] = callback;
},
/**
* 判断socket已连接成功,可以通信
* @returns {boolean}
*/
isSocketOpened: function(){
return (this._socket && this._socket.getState() == GameWebSocket.GameWebSocketState.OPEN);
},
isSocketClosed: function () {
return this._socket == null;
},
/**
* 启动连接
*/
connect: function (url) {
cc.log("webSocketUrls=" + url);
this._requestSequenceId = 0;
this._socket = new GameWebSocket.GameWebSocket();
this._socket.init(url, this);
this._socket.connect();
},
closeConnect: function () {
if(this._socket){
this._socket.close();
}
},
onSocketOpen: function () {
cc.log('Socket:onOpen');
if(this._delegate && this._delegate.onNetworkOpen){
this._delegate.onNetworkOpen();
}
},
onSocketError: function () {
cc.log('Socket:onError');
},
onSocketClosed: function (reason) {
cc.log('Socket:onClose', reason);
if (this._socket) {
this._socket.close();
}
this._socket = null;
if(this._delegate && this._delegate.onNetworkClose){
this._delegate.onNetworkClose();
}
},
onSocketMessage: function (msg) {
this._onResponse(msg);
},
_onResponse: function(responseData){
cc.log('response->resp:', responseData);
var responseJson = JSON.parse(responseData);
var responseClass = GameProtocols.response_classes[responseJson.act];
/**
* @type {object.<BaseResponse>}
*/
var response = new responseClass();
response.loadData(responseJson.data);
response.act = responseJson.act;
response.seq = responseJson.seq;
response.err = responseJson.err;
response.ts = responseJson.ts;
// 如果指定了回调函数,先回调
var ignoreError = false;
if(response.seq != -1){
// 处理服务器推送消息
var pushCallback = this.pushResponseCallback[response.act];
if(pushCallback){
pushCallback(response);
}
// request回调
var callbackObj = this._networkCallbacks[response.seq];
if(callbackObj){
ignoreError = callbackObj.callback(response);
// try {
// ignoreError = callbackObj.callback(response);
// } catch (err) {
// cc.log(err + " error in response callback of " + response.act);
// } finally {
// delete this._networkCallbacks[response.seq];
// }
}
}
//有错,且不忽略,则统一处理错误
if(response.err && response.err != response_state.ERROR_OK && !ignoreError){
if (response.is_async) { // 异步请求,如果出错了,应该需要重新登录
// todo 重新登录?或者重新同步数据?
} else { // 同步请求,如果出错了,需要显示错误信息
// todo 显示错误
var msg = responseJson.msg;
cc.log('server err ' + msg);
}
}
},
/**
* 向服务器发送请求。
*
* 如果提供了callback,在收到response后会被回调。如果response是一个错误(status!=ERR_OK),则需要决定由谁来负责处理错误。
* 如果callback中已经对错误进行了处理,应该返回true,这样会忽略该错误。否则应该返回false,则负责处理该错误。
*
* 特别注意:如果这是一个异步(is_async)请求,且出错,一般来讲应该重新登录/同步。但是如果callback返回了true,不会进行
* 任何处理,也就是不会重新登录/同步。请小心确定返回值。
*
* @param {object.<BaseRequest>}
* @param {function(BaseResponse): boolean=} opt_callback 回调函数。出错的情况下,如果返回true,则不会再次处理错误。
*/
sendRequest: function (request, opt_callback) {
// 每个请求的seq应该唯一,且递增
request.seq = ++this._requestSequenceId;
//生成NetworkCallback对象,绑定请求seq和回调方法
if(opt_callback){
this._networkCallbacks[request.seq] = new NetworkCallback();
this._networkCallbacks[request.seq].init(request, opt_callback);
}
this._sendSocketRequest(false, request);
},
/**
* sendRequest的不发送data字段
*/
sendRequestNoData: function (request, opt_callback) {
// 每个请求的seq应该唯一,且递增
request.seq = ++this._requestSequenceId;
//生成NetworkCallback对象,绑定请求seq和回调方法
if(opt_callback){
this._networkCallbacks[request.seq] = new NetworkCallback();
this._networkCallbacks[request.seq].init(request, opt_callback);
}
this._sendSocketRequest(true, request);
},
/**
* @param {Boolean} isNoData
* @param {object.<BaseRequest>} req
*/
_sendSocketRequest: function (isNoData, req) {
cc.assert(this._socket);
if (this.isSocketOpened()){
//通过json的方法生成请求字符串
var msg = null;
if(isNoData){
msg = JSON.stringify({seq:req.seq, act:req.act});
}else{
msg = JSON.stringify({seq:req.seq, act:req.act, data:req});
}
cc.log("WebSocketDelegate::send->" + msg);
this._socket.send(msg);
} else{
// todo
}
}
});
module.exports = GameNetwork;
复制代码
GameProtocols.js
复制代码
/**
- Created by skyxu on 2018/10/9.
*/
“use strict”;
/**
-
消息基类对象,请求消息BaseRequest, 回调消息BaseResponse都继承BaseProtocol
/
let BaseProtocol = cc.Class({
ctor: function () {
/*
* 请求动作类型
*/
this.act = ‘’;/** * 每个请求的sequence_id应该唯一 */ this.seq = 0; /** * 错误代码,0为正常 */ this.err = 0; /** * 是否需要等待服务器回调 */ this.is_async = false;
}
});
/**
- 请求消息基类,客户端的请求都继承这个类
*/
let BaseRequest = cc.Class({
extends: BaseProtocol
});
/**
-
服务器返回的消息对应的对象,包含返回数据,一般和BaseRequest成对使用
-
@class BaseResponse
-
@extends BaseProtocol
*/
let BaseResponse = cc.Class({
extends: BaseProtocol,/**
-
读取返回数据,设置BaseResponse对象
*/
loadData: function (data) {
var key;
for (key in data) {
if(!this.hasOwnProperty(key)){
continue;
}if(data[key] !== undefined && data[key] !== null){ this[key] = data[key]; }
}
}
});
-
let HeartRequest = cc.Class({
extends: BaseRequest,
ctor(){
this.act = ‘heart’;
this.t = -1; // 发送时间
}
});
let HeartResponse = cc.Class({
extends: BaseResponse,
ctor(){
this.act = 'heart';
this.t = -1;
}
});
let ChatRequest = cc.Class({
extends: BaseRequest,
ctor(){
this.act = ‘chat’;
this.msg = ‘’;
this.uid = ‘’;
}
});
let ChatResponse = cc.Class({
extends: BaseResponse,
ctor(){
this.act = ‘chat’;
this.msg = ‘’;
this.uid = ‘’;
}
});
let LoginRequest = cc.Class({
extends: BaseRequest,
ctor: function () {
this.act = 'login';
/**
* facebook用户的accessToken,或游客的UUID
*/
this.token = '';
/**
* token来源,默认0:游客,1:facebook
*/
this.origin = 0;
/**
* 平台: 必须为以下几种之一:android/ios/winphone/pc
*/
this.os = '';
/**
* 平台系统版本
*/
this.osVersion = '';
/**
* 设备产品型号, 示例 iPhone8,2, SM-G 9280
*/
this.deviceModel = '';
/**
* 渠道ID
*/
this.channelId = 0;
/**
* Ios设备广告标示符
*/
this.idfa = '';
/**
* 安卓设备id
*/
this.androidId = '';
/**
* Google广告平台账号,安装了google play的设备可取到
*/
this.googleAid = '';
/**
* 应用版本号
*/
this.appVersion = '';
/**
* 取package name或者bundle id
*/
this.packName = '';
/**
* 设备语言
* @type {string}
*/
this.language = '';
this.locale = "";
}
});
let LoginResponse = cc.Class({
extends: BaseResponse,
ctor: function () {
this.act = 'login';
/**
* 游客第一次登录时返回的token,需要客户端保存
*/
this.token = '';
/**
* 离体力下次恢复点的剩余时间秒数
* @type {number}
*/
this.spStepLeftTime = 0;
/**
* 体力恢复周期
* @type {Number}
*/
this.spInterval = 0;
/**
* 农场每天产出量,产出未解锁时为-1
* @type {number}
*/
this.farmDailyOut = -1;
/**
* 农场已产出量
* @type {number}
*/
this.farmCoins = 0;
/**
* 农场产出间隔
* @type {number}
*/
this.farmInterval = null;
/**
* 用json object表示的一个player对象,字段说明参见player json对象
*/
this.me = {};
/**
* 建筑数据数组
* @type {Array}
*/
this.buildings = [];
/**
* 农民数据数组
* @type {Array}
*/
this.farms = [];
/**
* 富豪数据
*/
this.cashking = {};
/**
* 行星配置
*/
this.planetConf = {};
/**
* 农民配置
*/
this.farmConfList = [];
/**
* 其他配置
*/
this.settingConf = {};
/**
* 好友数据
*/
this.friends = [];
/**
* 好友通缉的目标列表
*/
this.helpWantList = [];
/**
* 邮件消息列表
*/
this.newsList = [];
/**
* 复仇列表
*/
this.revengeList = [];
/**
* 商品信息
* @type {Array}
*/
this.rechargeConfs = [];
/**
* 总岛数
* @type {Number}
*/
this.planetConfListSize = 0;
/**
* 他人行星信息对象,仅在转到fire断线重新登录时有效
* @type {Object}
*/
this.fireTarget = null;
/**
* 他人行星信息对象列表,仅在转到steal断线重新登录时有效
* @type {Array}
*/
this.stealTarget = null;
}
});
let LogoutRequest = cc.Class({
extends: BaseRequest,
ctor: function () {
this.act = 'logout';
}
});
let LogoutResponse = cc.Class({
extends: BaseResponse,
ctor: function () {
this.act = 'logout';
}
});
/**
-
绑定fb账号
-
@extends BaseRequest
*/
let BindFacebookRequest = cc.Class({
extends: BaseRequest,ctor: function () {
this.act = ‘bindFb’;/** * facebook用户的accessToken,或游客的UUID */ this.token = '';
}
});
/** -
绑定fb账号
-
@extends BaseResponse
*/
let BindFacebookResponse = cc.Class({
extends: BaseResponse,ctor: function () {
this.act = ‘bindFb’;/** * fb数据 */ this.me = 0; /** * fb好友 */ this.friends = 0;
}
});
let SpinRequest = cc.Class({
extends: BaseRequest,
ctor: function () {
this.act = 'spin';
/**
* 倍数
* @type {Number}
*/
this.x = 1;
}
});
let SpinResponse = cc.Class({
extends: BaseResponse,
ctor: function () {
this.act = 'spin';
/**
* 摇中的转盘ID
*/
this.hit = 0;
/**
* 转到护盾,但护盾已满时,存在
* @type {number}
*/
this.shieldfull = 0;
/**
* 玩家数据对象
*/
this.me = {};
/**
* 他人行星信息对象,仅在转到fire时有效
* @type {*}
*/
this.fireTarget = {};
/**
* 偷取对象数据
*/
this.stealTarget = [];
/**
* 离体力下次恢复点的剩余时间秒数
* @type {number}
*/
this.spStepLeftTime = 0;
/**
* 体力恢复周期
* @type {Number}
*/
this.spInterval = 0;
/**
* 倍数
* @type {Number}
*/
this.x = 1;
}
});
/**
-
获取排名
-
@extends BaseRequest
*/
let RankRequest = cc.Class({
extends: BaseRequest,ctor: function () {
this.act = ‘rankboard’;/** * 请求动作类型{ 0全部,1本地,2好友 } * @type {int} */ this.type = 0;
}
});
/** -
获取排名
-
@extends BaseResponse
*/
let RankResponse = cc.Class({
extends: BaseResponse,ctor: function () {
this.act = ‘rankboard’;/** * 我的排名 */ this.myRank = 0; /** * 排名玩家数据 */ this.men = [];
}
});
//push------------------------------------------------------------------------------
/**
-
推送消息 被攻击
-
@extends BaseResponse
*/
var PushAttackedResponse = cc.Class({
extends: BaseResponse,ctor: function () {
this.act = ‘attacked’;/** * 玩家更新数据 */ this.me = null; /** * 建筑数据 */ this.building = null; /** * 敌人 */ this.hatredman = null; /** * 消息 */ this.news = null;
}
});
/**
-
推送消息 推送消息好友已赠送体力
-
@extends BaseResponse
*/
var PushSendSpResponse = cc.Class({
extends: BaseResponse,ctor: function () {
this.act = ‘sendSpNotify’;/** * 好友对象 */ this.friend = null;
}
});
/**
-
推送消息 推送消息好友已领取赠送的体力
-
@extends BaseResponse
*/
var PushTakeSpResponse = cc.Class({
extends: BaseResponse,ctor: function () {
this.act = ‘takeSpNotify’;/** * 好友对象 */ this.friend = null;
}
});
/**
-
推送消息 同步好友信息
-
@extends BaseResponse
*/
var PushSyncFriendInfo = cc.Class({
extends: BaseResponse,ctor: function () {
this.act = ‘friendInfoSync’;/** * 好友 */ this.friend = null;
}
});
/**
-
推送消息 新增好友
-
@extends BaseResponse
*/
var PushAddNewFriend = cc.Class({
extends: BaseResponse,ctor: function () {
this.act = 'newFriend'; /** * 好友 */ this.friend = null; /** * 消息 */ this.news = null;
}
});
/**
-
debug回调
-
@extends BaseRequest
*/
let DebugChangeMeRequest = cc.Class({
extends: BaseRequest,ctor: function () {
this.act = "cmdTest"; //请求动作类型 this.cmd = ""; // "player coins add 100", cmd格式:player field value 或者 player field add value // Building field [add] value where playerId value type value
}
});
/**
-
debug回调
-
@extends BaseResponse
*/
let DebugChangeMeResponse = cc.Class({
extends: BaseResponse,ctor: function () {
this.act = “cmdTest”;/** * 玩家数据 * @type {Object} */ this.me = {}; /** * 体力恢复周期 * @type {Number} */ this.spInterval = null; /** * 体力恢复剩余时间 * @type {Number} */ this.spStepLeftTime = null; /** * 存钱罐速度 * @type {Number} */ this.farmDailyOut = null; /** * 存钱罐可回收金币 * @type {Number} */ this.farmCoins = null; /** * 存钱罐回收周期 * @type {Number} */ this.farmInterval = null; /** * 岛屿建筑数据 * @type {Array} */ this.buildings = null;
}
});
let response_classes = {
login: LoginResponse,
logout: LogoutResponse,
spin: SpinResponse,
bindFb: BindFacebookResponse,
rankboard: RankResponse,
heart: HeartResponse,
chat: ChatResponse,
//push
attacked: PushAttackedResponse,
sendSpNotify: PushSendSpResponse,
takeSpNotify: PushTakeSpResponse,
newFriend: PushAddNewFriend,
friendInfoSync: PushSyncFriendInfo,
// debug
cmdTest: DebugChangeMeResponse,
};
module.exports = {
LoginRequest: LoginRequest,
LoginResponse: LoginResponse,
LogoutRequest: LogoutRequest,
LogoutResponse: LogoutResponse,
SpinRequest: SpinRequest,
SpinResponse: SpinResponse,
BindFacebookRequest: BindFacebookRequest,
BindFacebookResponse: BindFacebookResponse,
RankRequest: RankRequest,
RankResponse: RankResponse,
HeartRequest: HeartRequest,
HeartResponse: HeartResponse,
ChatRequest: ChatRequest,
ChatResponse: ChatResponse,
// debug
DebugChangeMeRequest: DebugChangeMeRequest,
DebugChangeMeResponse: DebugChangeMeResponse,
//push消息
PushAttackedResponse: PushAttackedResponse,
PushSendSpResponse: PushSendSpResponse,
PushTakeSpResponse: PushTakeSpResponse,
PushAddNewFriend: PushAddNewFriend,
PushSyncFriendInfo: PushSyncFriendInfo,
response_classes: response_classes
};
复制代码
NetProxy.js
/**
- Created by skyxu on 2018/10/9.
*/
“use strict”;
let GameNetwork = require("./GameNetwork");
let GameProtocols = require("./GameProtocols");
let GAME_SERVER_URL = ‘ws://127.0.0.1:3000’;
// GAME_SERVER_URL = ‘wss://echo.websocket.org’;
let NetProxy = cc.Class({
ctor: function () {
this.network = null;
this._cachePushCallback = [];
},
init: function () {
this.network = new GameNetwork();
this.network.setDelegate(this);
this.initPushCallback();
},
connect: function () {
this.network.connect(GAME_SERVER_URL);
},
closeConnect: function () {
this.network.closeConnect();
},
isNetworkOpened: function () {
return this.network.isSocketOpened();
},
isNetworkClosed: function () {
return this.network.isSocketClosed();
},
onNetworkOpen: function () {
Global.eventMgr.emit(Global.config.EVENT_NETWORK_OPENED);
},
onNetworkClose: function () {
Global.eventMgr.emit(Global.config.EVENT_NETWORK_CLOSED);
},
/**
* 注册push回调接口
*/
initPushCallback: function () {
let self = this;
let pushCallback = function (resp) {
self.pushCallback(resp);
};
this.network.registerPushResponseCallback('chat', pushCallback);
// let pushCallback = function(response){
// if(Util.DNN(farm.game) && farm.game.loginSuccess){
// this.dealCachePush();
// this.pushCallback(response);
// }else{
// this._cachePushCallback.push(response);
// }
// }.bind(this);
// this.network.registerPushResponseCallback('attacked', pushCallback);
// this.network.registerPushResponseCallback('acceptWantHelp', pushCallback);
// this.network.registerPushResponseCallback('sendSpNotify', pushCallback);
// this.network.registerPushResponseCallback('takeSpNotify', pushCallback);
// this.network.registerPushResponseCallback('wanted', pushCallback);
// this.network.registerPushResponseCallback('incomplete', pushCallback);
// this.network.registerPushResponseCallback('newFriend', pushCallback);
// this.network.registerPushResponseCallback('news', pushCallback);
// this.network.registerPushResponseCallback('hatredInfoSync', pushCallback);
// this.network.registerPushResponseCallback('friendInfoSync', pushCallback);
},
/**
* 处理缓存push
*/
dealCachePush: function () {
// if(this._cachePushCallback.length > 0){
// for(var i = 0; i < this._cachePushCallback.length; i++){
// this.pushCallback(this._cachePushCallback[i]);
// }
// }
// this._cachePushCallback = [];
},
beatHeart: function (callback) {
let req = new GameProtocols.HeartRequest();
req.t = Date.now();
this.network.sendRequest(req, callback);
},
chat: function (msg) {
let req = new GameProtocols.ChatRequest();
let uid = cc.sys.localStorage.getItem("chat_uid");
req.uid = uid;
req.msg = msg;
this.network.sendRequest(req);
},
/**
* Facebook或者游客登录接口
* @param {Object.<LoginOriginType>} origin
* @param token
*/
login: function (origin, token) {
// let req = new GameProtocols.LoginRequest();
// if(token) req.token = token;
// req.origin = origin;
// req.os = cc.sys.os;
// req.osVersion = cc.sys.osVersion;
// // req.language = cc.sys.language;//farm.FarmPlatformHelper.jsToOc(farm.FarmPlatformHelper.JSB_EVENT_JTO_GetCurrentLanguage);
// /*
// req.deviceModel = '';
// req.channelId = 0;
// req.idfa = '';
// req.androidId = '';
// req.googleAid = '';
// req.appVersion = '';
// req.packName = '';
// */
// let callback = function (resp) {
// if(resp.err != 0){
// Global.eventMgr.emit(farm.game.gmConst.SP_EVENT_LOGIN_FAILED, resp);
// return;
// }
// if(resp.token && resp.token.length > 0){
// farm.localStorage.setItem(farm.game.gmConst.GLS_KEY_GUEST_TOKEN, resp.token);
// }
// farm.localStorage.removeItem(farm.game.gmConst.GLS_KEY_IS_LOGOUT);
//
// //
// farm.game.initConfig(resp);
// farm.game.initData(resp);
// farm.game.loginSuccess = true;
//
// // js 调取其他平台的sdk,传过去玩家id
// farm.FarmPlatformHelper.jsToOc(farm.FarmPlatformHelper.JSB_EVENT_JTO_setSessionWithUid, farm.game.player.id.toString());
// //
//
// //登录
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_LOGIN_SUCCESS);
// };
// this.network.sendRequest(req, callback);
},
/**
* Facebook或者游客登出
*/
logout: function () {
// let req = new GameProtocols.LogoutRequest();
// this.network.sendRequest(req, function (resp) {
// if(resp.err != 0){
// cc.log("网络请求---LogoutRequest 失败");
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_LOGOUT_FAILED);
// return;
// }
// cc.log("网络请求---LogoutRequest 成功");
// Global.eventMgr.emit(farm.game.gmConst.SP_EVENT_LOGOUT_SUCCESS);
// });
},
/**
* 绑定fb账号
* @param {String} token
*/
bindFacebook: function (token) {
// let req = new GameProtocols.BindFacebookRequest();
// req.token = token;
// let callback = function (resp) {
// //绑定过得逻辑
// if(resp.err == farm.game.gmConst.ERROR_USER_HAS_REGISTERED){
// cc.log("网络请求---BindFacebookRequest 已绑定");
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_HAS_BIND_FACEBOOK);
// return;
// }
// //绑定失败
// if(resp.err != 0){
// cc.log("网络请求---BindFacebookRequest 失败");
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_BIND_FACEBOOK_FAILED);
// return;
// }
// //绑定成功
// cc.log("网络请求---BindFacebookRequest 成功");
// if(resp.me){
// farm.game.player.parse(resp.me);
// }
// if(resp.friends){
// farm.game.initFriends(resp.friends);
// }
// //绑定成功后删除本地token
// farm.localStorage.removeItem(farm.game.gmConst.GLS_KEY_GUEST_TOKEN);
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_BIND_FACEBOOK_SUCCESS);
// };
// this.network.sendRequest(req, callback);
},
/**
* 启动转盘
*/
spin: function (x) {
// let req = new GameProtocols.SpinRequest();
// if(farm.util.isNumber(x)){
// req.x = x;
// }
// var callback = function (resp) {
// if(resp.err != 0){
// cc.log("网络请求---spin 失败");
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_SPIN_FAILED, resp);
// return;
// }
// cc.log("网络请求---spin 成功");
// farm.game.player.parse(resp.me);
// farm.game.spTimer.updateSpTime(resp.spStepLeftTime, resp.spInterval);
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_SPIN_SUCCESS, resp);
// };
// this.network.sendRequest(req, callback);
},
/**
* 获取排名
* @param {Number} rankType 0全部,1本地,2好友
*/
getRank: function (rankType) {
// let req = new GameProtocols.RankRequest();
// req.type = rankType;
// let callback = function (resp) {
// if(resp.err != 0){
// cc.log("网络请求---getRank 失败");
// Global.eventMgr.emit(farm.game.gmConst.SP_EVENT_GET_RANK_FAILED, resp);
// return;
// }
// cc.log("网络请求---getRank 成功");
// // todo 暂定排名类型
// resp._rankType = rankType;
// //farm.game.initLeaderBoardArray(rankType, resp.myRank, resp.men);
// if(rankType == 2 && resp.men){
// farm.game.updateFriends(resp.men);
// resp.men = farm.game.sortFriendsByStar();
// }
// Global.eventMgr.emit(farm.game.gmConst.SP_EVENT_GET_RANK_SUCCESS, resp);
// };
// this.network.sendRequest(req, callback);
},
//push回调------------------------------------------------------------------------------
/**
* 推送回调
*/
pushCallback: function (response) {
switch (response.act){
case "sendSpNotify":
case "takeSpNotify":
case "friendInfoSync":
this.pushFriendSendTakeSp(response);
break;
case "stole":
this.pushStole(response);
break;
case "attacked":
this.pushAttacked(response);
break;
case "newFriend":
this.pushAddNewFriend(response);
break;
case "chat":
this.pushChat(response);
break;
}
},
/**
* 好友间互赠体力推送
* @param {PushSendSpResponse|PushTakeSpResponse} resp
*/
pushFriendSendTakeSp: function (resp) {
// cc.log("网络请求---push--- pushFriendSendTakeSp 成功");
// if(resp.friend) farm.game.updateFriends(resp.friend);
// farm.eventManager.emit(farm.game.gmConst.SP_PUSH_EVENT_UPDATE_FRIEND);
},
/**
* 被偷
* @param {PushStolenResponse} resp
*/
pushStole: function (resp) {
// cc.log("网络请求---push--- pushStole 成功");
// if(resp.me) farm.game.player.parse(resp.me);
// //if(resp.building) farm.game.buildings[resp.building.type].parse(resp.building);
// if(resp.hatredman && !farm.game.getHelpWant(resp.hatredman.id)){
// farm.game.addEnemy(resp.hatredman);
// }
// if(resp.news){
// resp.news = farm.game.addNews(resp.news);
// }
// farm.eventManager.emit(farm.game.gmConst.SP_PUSH_EVENT_BE_STOLE_SUCCESS, resp);
},
/**
* 被攻击
* @param {PushAttackedResponse} resp
*/
pushAttacked: function (resp) {
// cc.log("网络请求---push--- pushAttacked 成功");
// if(resp.me) {
// farm.game.player.parse(resp.me);
// farm.game.dataUpdater.updateStar();
// }
// if(resp.building) farm.game.buildings[resp.building.type].parse(resp.building);
// if(resp.hatredman){
// farm.game.addBadass(resp.hatredman);
// if(!farm.game.getHelpWant(resp.hatredman.id)){
// farm.game.addEnemy(resp.hatredman);
// }
// }
// if(resp.news){
// resp.news = farm.game.addNews(resp.news);
// }
// farm.eventManager.emit(farm.game.gmConst.SP_PUSH_EVENT_BE_ATTACK_SUCCESS, resp);
},
/**
* 新增好友
* @param {PushAddNewFriend} resp
*/
pushAddNewFriend: function (resp) {
// cc.log("网络请求---push--- pushAddNewFriend 成功");
// if(resp.friend){
// resp.friend = farm.game.addFriend(resp.friend);
// }
// if(resp.news){
// resp.news = farm.game.addNews(resp.news);
// }
// farm.eventManager.emit(farm.game.gmConst.SP_PUSH_EVENT_ADD_FRIEND_SUCCESS, resp);
},
pushChat: function (resp) {
Global.eventMgr.emit(Global.config.EVENT_CHAT, resp);
},
/**
* debug调试请求
* @param {String} name
*/
debug_addCoins: function (name) {
var req = new GameProtocols.DebugChangeMeRequest();
if (name === "btnAddCoins") {
req.cmd = "player coins add 100000000";
} else if (name === "btnClearCoins") {
req.cmd = "player coins 0";
} else if (name === "btnAddEnergy") {
req.cmd = "player sp add 10";
} else if (name === "btnClearEnergy") {
req.cmd = "player sp 0";
} else if (name == "btnAddWp") {
req.cmd = "player wp add 10";
} else if (name == "btnClearWp") {
req.cmd = "player wp 0";
} else if (name == "btnUnwrap"){
req.cmd = "player fbuid null";
} else if (name == "btnWizard1"){
req.cmd = "player wizard1 0";
} else if (name == "btnWizard2"){
req.cmd = "player wizard2 0";
} else if (name == "btnClearShield"){
req.cmd = "player shield 0";
} else if (name == "btnSpEc"){
req.cmd = "SpEc stepInterval 60000";
} else if (name == "btnFarmEc"){
req.cmd = "FarmEc stepInterval 60000";
} else if (name == "btnSpEcBack"){
req.cmd = "SpEc stepInterval 3600000";
} else if (name == "btnFarmBack"){
req.cmd = "FarmEc stepInterval 86400000";
} else if (name == "btnUpdateBuild"){
req.cmd = "Building lv 5";
} else {
req.cmd = name;
}
// var callback = function (resp) {
// if (resp.err != 0) {
// return;
// }
// farm.game.player.parse(resp.me);
// farm.game.spTimer.updateSpTime(resp.spStepLeftTime, resp.spInterval);
// farm.game.dataUpdater.updateCoin();
// farm.game.dataUpdater.updateSp();
// farm.game.dataUpdater.updateShield();
// farm.game.dataUpdater.updateStar();
// //
// if((req.cmd == "FarmEc stepInterval 60000" || req.cmd == "FarmEc stepInterval 86400000")
// && farm.util.isNumber(resp.farmDailyOut)
// && farm.util.isNumber(resp.farmCoins)){
// farm.game.piggyBankTimer.init(resp.farmDailyOut, resp.farmCoins, resp.farmInterval);
// }
// if(req.cmd == "SpEc stepInterval 60000" || req.cmd == "SpEc stepInterval 3600000"){
// farm.game.spTimer.updateSpTime(resp.spStepLeftTime, resp.spInterval);
// }
// if(resp.buildings){
// for(var i = 0; i < resp.buildings.length; ++i){
// farm.game.buildings[i].parse(resp.buildings[i]);
// }
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_UPGRADE_BUILDING_SUCCESS, resp);
// farm.eventManager.emit(farm.game.gmConst.SP_DEBUG_EVENT_BUILD_TO_24_SUCCESS, resp);
// }
// };
// this.network.sendRequest(req, callback);
},
});
module.exports = NetProxy;
2、服务端
使用express + express-ws组件,调用WSRouter的init初始化连接即可,
复制代码
let expressWS = require(‘express-ws’);
let work = require(’./work’);
let wsRouter = null;
function WSRouter(app, server){
this.app = app;
this.server = server;
this.clients = [];
expressWS(app, server);
this.listenClientConnection = ()=>{
app.ws('/', (socket, req)=>{
console.log('client connect to server successful.');
this.clients.push(socket);
console.log('clients: ' + this.clients.length);
socket.on('message', (msg)=>{
console.log('on message: ' + msg);
work(this, socket, msg);
});
socket.on('close', (msg)=>{
console.log('on close: ' + msg);
for (let index=0; index<this.clients.length; index++){
if (this.clients[index] == socket){
this.clients.splice(index,1);
}
}
console.log('clients: ' + this.clients.length);
});
socket.on('error', (err)=>{
console.log('on error: ' + error);
});
})
}
}
module.exports = {
init: function(app, server){
if (wsRouter == null){
wsRouter = new WSRouter(app, server);
}
return wsRouter;
}
}
复制代码
复制代码
module.exports = function(wsRouter, ws, msg){
let msgObj = JSON.parse(msg);
switch (msgObj.act){
case ‘heart’:{
msgObj.data.t = Date.now();
ws.send(JSON.stringify(msgObj));
break;
}
case ‘chat’: {
for (let w of wsRouter.clients){
w.send(msg);
}
break;
}
default:
break;
}
}