达达麻将”开房”

目录

达达麻将”开房”

要点

(1)达达麻将版图回顾

(2)达达麻将游戏服务器注册到大厅,来配置负载

(3)创建房间客户端请求;

(4)创建房间服务器响应;

(5)客户端登陆到游戏服务器;


达达麻将版图

寻找客户端发送逻辑

1: 找到创建按钮,并找到关联的函数 --> hall.js: onCreateRoomClicked;

btn_create_room组件按钮----响应JS函数onCreateRoomClicked

    onCreateRoomClicked:function(){if(cc.vv.gameNetMgr.roomId != null){cc.vv.alert.show("提示","房间已经创建!\n必须解散当前房间才能创建新的房间");return;}console.log("onCreateRoomClicked");this.createRoomWin.active = true;   },

寻找this.createRoomWin.active = true;  这句的作用,是在UI界面处理的,代码里面没有做处理:

原来是激活创建房间UI组件。

2: 显示出创建房间的界面,找到这个界面的挂载脚本: createRoom.js

CreateRoom.js的onBtnOK();

3: 创建列表,配置创建的参数, createRoom函数将命令通过http发送到大厅服务器;

   createRoom:function(){var self = this;var onCreate = function(ret){if(ret.errcode !== 0){cc.vv.wc.hide();//console.log(ret.errmsg);if(ret.errcode == 2222){cc.vv.alert.show("提示","房卡不足,创建房间失败!");  }else{cc.vv.alert.show("提示","创建房间失败,错误码:" + ret.errcode);}}else{cc.vv.gameNetMgr.connectGameServer(ret);}};var difen = 0;for(var i = 0; i < self._difenxuanze.length; ++i){if(self._difenxuanze[i].checked){difen = i;break;}}var zimo = 0;for(var i = 0; i < self._zimo.length; ++i){if(self._zimo[i].checked){zimo = i;break;}     }var huansanzhang = self._wanfaxuanze[0].checked;        var jiangdui = self._wanfaxuanze[1].checked;var menqing = self._wanfaxuanze[2].checked;var tiandihu = self._wanfaxuanze[3].checked;var type = 0;for(var i = 0; i < self._leixingxuanze.length; ++i){if(self._leixingxuanze[i].checked){type = i;break;}     }if(type == 0){type = "xzdd";}else{type = "xlch";}var zuidafanshu = 0;for(var i = 0; i < self._zuidafanshu.length; ++i){if(self._zuidafanshu[i].checked){zuidafanshu = i;break;}     }var jushuxuanze = 0;for(var i = 0; i < self._jushuxuanze.length; ++i){if(self._jushuxuanze[i].checked){jushuxuanze = i;break;}     }var dianganghua = 0;for(var i = 0; i < self._dianganghua.length; ++i){if(self._dianganghua[i].checked){dianganghua = i;break;}     }var conf = {type:type,difen:difen,zimo:zimo,jiangdui:jiangdui,huansanzhang:huansanzhang,zuidafanshu:zuidafanshu,jushuxuanze:jushuxuanze,dianganghua:dianganghua,menqing:menqing,tiandihu:tiandihu,   }; var data = {account:cc.vv.userMgr.account,sign:cc.vv.userMgr.sign,conf:JSON.stringify(conf)};console.log(data);cc.vv.wc.show("正在创建房间");cc.vv.http.sendRequest("/create_private_room",data,onCreate);   }

组合长一个表conf,发送给服务器,请求创建房间。

cc.vv.http.sendRequest("/create_private_room",data,onCreate);

转成json字符串  conf:JSON.stringify(conf)

请求提交到:即Client---->大厅服务器的http client service服务

4: 响应地址为:create_private_room, 数据为创建参数, 返回结果回掉: onCreate函数

这里服务器收到client发送过来的data,然后做相应的逻辑处理。

寻找服务器响应

1: hallserver: 配置好的 “/create_private_room”;

//从数据库里面查询玩家数据
    db.get_user_data(account,function(data){

2: 处理步骤:

(1)查询数据库,获取账号信息;  db.js --> get_user_data函数

   gems:房卡数据

(2)检测玩家是否已经在一个房间游戏: get_room_id_of_user,只有没有在游戏才可以创建;

     //验证玩家状态db.get_room_id_of_user(userId,function(roomId){if(roomId != null){http.send(res,-1,"user is playing in room now.");return;}//创建房间

(3)room_service.js 的createRoom:

1>找到最小的负载的server;

2> 获取用户的gems房卡的数目;

db.get_gems(account,function(data){

优化点:这里经过了2次查询房卡,可以进行系统优化;

然后执行room_service.js的createRoom函数:

            //创建房间room_service.createRoom(account,userId,conf,function(err,roomId){

然后消息又发送到http服

http.get(serverinfo.ip,serverinfo.httpPort,"/create_room",reqdata,function(ret,data){

流程:由刚才找到的最小负载游戏服务器开房,通过大厅服务器的room_service找到对应的游戏服http_service处理;

3>麻将服务器http_server, create_room URL响应;

4> roomMgr创建一个createRoom:

roomMgr.createRoom(userId,conf,gems,serverIp,config.CLIENT_PORT,function(errcode,roomId){

//游戏服开房逻辑
exports.createRoom = function(creator,roomConf,gems,ip,port,callback){if(roomConf.type == null|| roomConf.difen == null|| roomConf.zimo == null|| roomConf.jiangdui == null|| roomConf.huansanzhang == null|| roomConf.zuidafanshu == null|| roomConf.jushuxuanze == null|| roomConf.dianganghua == null|| roomConf.menqing == null|| roomConf.tiandihu == null){callback(1,null);return;}if(roomConf.difen < 0 || roomConf.difen > DI_FEN.length){callback(1,null);return;}if(roomConf.zimo < 0 || roomConf.zimo > 2){callback(1,null);return;}if(roomConf.zuidafanshu < 0 || roomConf.zuidafanshu > MAX_FAN.length){callback(1,null);return;}if(roomConf.jushuxuanze < 0 || roomConf.jushuxuanze > JU_SHU.length){callback(1,null);return;}//需要消耗多少房卡var cost = JU_SHU_COST[roomConf.jushuxuanze];if(cost > gems){callback(2222,null);return;}var fnCreate = function(){var roomId = generateRoomId();if(rooms[roomId] != null || creatingRooms[roomId] != null){fnCreate();}else{creatingRooms[roomId] = true;db.is_room_exist(roomId, function(ret) {if(ret){delete creatingRooms[roomId];fnCreate();}else{var createTime = Math.ceil(Date.now()/1000);var roomInfo = {uuid:"",id:roomId,numOfGames:0,createTime:createTime,nextButton:0,seats:[],conf:{type:roomConf.type,baseScore:DI_FEN[roomConf.difen],zimo:roomConf.zimo,jiangdui:roomConf.jiangdui,hsz:roomConf.huansanzhang,dianganghua:parseInt(roomConf.dianganghua),menqing:roomConf.menqing,tiandihu:roomConf.tiandihu,maxFan:MAX_FAN[roomConf.zuidafanshu],maxGames:JU_SHU[roomConf.jushuxuanze],creator:creator,}};if(roomConf.type == "xlch"){roomInfo.gameMgr = require("./gamemgr_xlch");}else{roomInfo.gameMgr = require("./gamemgr_xzdd");}console.log(roomInfo.conf);for(var i = 0; i < 4; ++i){roomInfo.seats.push({userId:0,score:0,name:"",ready:false,seatIndex:i,numZiMo:0,numJiePao:0,numDianPao:0,numAnGang:0,numMingGang:0,numChaJiao:0,});}//写入数据库var conf = roomInfo.conf;db.create_room(roomInfo.id,roomInfo.conf,ip,port,createTime,function(uuid){delete creatingRooms[roomId];if(uuid != null){roomInfo.uuid = uuid;console.log(uuid);rooms[roomId] = roomInfo;totalRooms++;callback(0,roomId);}else{callback(3,null);}});}});}}fnCreate();
};

a:检测创建参数,

两套麻将玩法:血战到底、血流成河;

b:检测房卡的余额,

var cost = JU_SHU_COST[roomConf.jushuxuanze];

c:创建房间;

db.create_room(roomInfo.id,roomInfo.conf,ip,port,createTime,function(uuid){

5>:URL 响应返回后enterRoom

roommgr.js的exports.createRoom将回调callback(0,roomId);传回去给http_service;

然后把roomId发送出去;

http.send(res,0,"ok",{roomid:roomId});

hall_service.js拿到回调数据roomId之后,准备执行进入房间逻辑:

room_service.enterRoom(userId,name,roomId,function(errcode,enterInfo){

优化点:游戏里面进来少用console.log来打印日志数据;会占用服务器的资源;会导致服务器卡;一般日志要做成异步的,专门的日志系统。减少服务器的等待操作。

(4) room_service.js 的enterRoom:


exports.enterRoom = function(userId,name,roomId,fnCallback){var reqdata = {userid:userId,name:name,roomid:roomId};reqdata.sign = crypto.md5(userId + name + roomId + config.ROOM_PRI_KEY);var checkRoomIsRuning = function(serverinfo,roomId,callback){var sign = crypto.md5(roomId + config.ROOM_PRI_KEY);http.get(serverinfo.ip,serverinfo.httpPort,"/is_room_runing",{roomid:roomId,sign:sign},function(ret,data){if(ret){if(data.errcode == 0 && data.runing == true){callback(true);}else{callback(false);}}else{callback(false);}});}var enterRoomReq = function(serverinfo){http.get(serverinfo.ip,serverinfo.httpPort,"/enter_room",reqdata,function(ret,data){console.log(data);if(ret){if(data.errcode == 0){db.set_room_id_of_user(userId,roomId,function(ret){fnCallback(0,{ip:serverinfo.clientip,port:serverinfo.clientport,token:data.token});});}else{console.log(data.errmsg);fnCallback(data.errcode,null);}}else{fnCallback(-1,null);}});};var chooseServerAndEnter = function(serverinfo){serverinfo = chooseServer();if(serverinfo != null){enterRoomReq(serverinfo);}else{fnCallback(-1,null);                 }}db.get_room_addr(roomId,function(ret,ip,port){if(ret){var id = ip + ":" + port;var serverinfo = serverMap[id];if(serverinfo != null){checkRoomIsRuning(serverinfo,roomId,function(isRuning){if(isRuning){enterRoomReq(serverinfo);}else{chooseServerAndEnter(serverinfo);}});}else{chooseServerAndEnter(serverinfo);}}else{fnCallback(-2,null);}});
};

1> 麻将服务器http_server, enter_room URL响应

//加入房间
app.get('/enter_room',function(req,res){var userId = parseInt(req.query.userid);var name = req.query.name;var roomId = req.query.roomid;var sign = req.query.sign;if(userId == null || roomId == null || sign == null){http.send(res,1,"invalid parameters");return;}var md5 = crypto.md5(userId + name + roomId + config.ROOM_PRI_KEY);console.log(req.query);console.log(md5);if(md5 != sign){http.send(res,2,"sign check failed.");return;}//安排玩家坐下roomMgr.enterRoom(roomId,userId,name,function(ret){if(ret != 0){if(ret == 1){http.send(res,4,"room is full.");}else if(ret == 2){http.send(res,3,"can't find room.");} return;     }var token = tokenMgr.createToken(userId,5000);http.send(res,0,"ok",{token:token});});
});

2> roomMgr enterRoom 返回一个token给大厅服务


exports.enterRoom = function(roomId,userId,userName,callback){var fnTakeSeat = function(room){if(exports.getUserRoom(userId) == roomId){//已存在return 0;}for(var i = 0; i < 4; ++i){var seat = room.seats[i];if(seat.userId <= 0){seat.userId = userId;seat.name = userName;userLocation[userId] = {roomId:roomId,seatIndex:i};//console.log(userLocation[userId]);db.update_seat_info(roomId,i,seat.userId,"",seat.name);//正常return 0;}} //房间已满return 1; }var room = rooms[roomId];if(room){var ret = fnTakeSeat(room);callback(ret);}else{db.get_room_data(roomId,function(dbdata){if(dbdata == null){//找不到房间callback(2);}else{//construct room.room = constructRoomFromDb(dbdata);//var ret = fnTakeSeat(room);callback(ret);}});}
};

大厅服room_service.js拿到token,游戏服http_service发过来的;

3> 大厅服务组合麻将服务器的ip, port, token, 房间ID 回给客户端

寻找客户端处理返回

1:获得了麻将服务器的ip, port, token, time;

客户端创建消息的回调函数

拿到服务器的返回信息之后,进行游戏连接

cc.vv.gameNetMgr.connectGameServer(ret);

2: 连接麻将服务器 GameNetManager.js  --> connectGameServer

    connectGameServer:function(data){this.dissoveData = null;cc.vv.net.ip = data.ip + ":" + data.port;console.log(cc.vv.net.ip);var self = this;var onConnectOK = function(){console.log("onConnectOK");var sd = {token:data.token,roomid:data.roomid,time:data.time,sign:data.sign,};cc.vv.net.send("login",sd);};var onConnectFailed = function(){console.log("failed.");cc.vv.wc.hide();};cc.vv.wc.show("正在进入房间");cc.vv.net.connect(onConnectOK,onConnectFailed);}

3: 连接成功后,发送登陆游戏服务器的命令  socket.io发送登陆login

发送长连接请求 cc.vv.net.send("login",sd);

4: 获取房间的信息,包括座位信息等,广播给房间的其他玩家用户来了

         socket.emit('login_result',ret);//通知其它客户端userMgr.broacastInRoom('new_user_comes_push',userData,userId);

5: 发送登陆结果命令  login_result到客户端,客户端保存好;

GameNetMgr.js的    initHandlers:function(){  进行处理:

cc.vv.net.addHandler("login_result",function(data){

cc.vv.net.addHandler("login_finished",function(data){

6: 发送登陆结束命令login_fished 进入到游戏场景;

socket.emit('login_finished');

进入到麻将游戏场景

        cc.vv.net.addHandler("login_finished",function(data){console.log("login_finished");cc.director.loadScene("mjgame",function(){cc.vv.net.ping();cc.vv.wc.hide();});self.dispatchEvent("login_finished");});

服务器的扩展:

心跳/服务器负载:

这里使用load来保存当前服务器的负载信息:

gameServerInfo.load = roomMgr.getTotalRooms();

http.get(config.HALL_IP,config.HALL_PORT,"/register_gs"

下一篇:达达麻将客户端初始化流程

cocos creator麻将教程系列(三)—— 达达麻将开房间流程相关推荐

  1. 从零开始实现自己的Kalimba——Cocos Creator新手教程系列(一)使用瓦片图Tiledmap设计游戏地图

    瓦片图Tiledmap可能是很多2d游戏开发者的偏爱,本节就Cocos Creator如何使用瓦片图进行详细的讲解. Tiled地图编辑器的下载安装不再赘述.下面介绍如何使用地图编辑器. 创建新地图. ...

  2. cocos creator麻将教程系列(二)—— 达达麻将的底层通讯express框架与socketio

    达达麻将网络通讯 目录 达达麻将网络通讯 要点: (1)express框架的基本写法 (2)socket.io的基本原理和使用; (3)creator阅读源码的必杀技巧; (4)一起来看达达麻将的游客 ...

  3. cocos creator麻将教程系列(六)—— 达达麻将的游戏流程

    达达麻将游戏流程 达达麻将版图 登陆到游戏服务器 1:客户端GameNetMgr.js, connectGameServer连接到游戏服务器,并发送"login"命令; var s ...

  4. cocos creator麻将教程系列(七)—— 达达麻将打包与发布

    达达麻将打包与发布 达达麻将版图 打包注意事项 1:打包之前仔细学习creator的android 与h5的打包; 2: 达达麻将打包两个注意点: (1) 录音的代码; (2)微信的登陆代码; 3: ...

  5. cocos creator麻将教程系列(五)—— 达达麻将开房间

    达达麻将开房间 达达麻将版图 达达麻将大厅 1: 大厅挂载了Hall.js 2:  onLoad 代码: // use this for initializationonLoad: function ...

  6. cocos creator麻将教程系列(八)—— 达达麻将语音聊天源码分析

    达达麻将语音聊天源码分析 达达麻将版图 语音聊天 1:语音聊天只支持Native平台,iOS与android; 2: 语音聊天的音频格式为amr; 3: native平台实现了语音的录制和播放,可以移 ...

  7. cocos creator麻将教程系列(四)—— 达达麻将客户端初始化流程

    达达麻将客户端初始化流程 达达麻将版图 客户端代码结构 1: scripts文件夹下: (1) 3rdparty: 第三方代码 socket-io; (2) Comonents: 游戏中挂到节点上的组 ...

  8. cocos creator麻将教程系列(九)—— 幼麟棋牌代码讲解

    这篇文章是官方整理的: 技术栈 客户端 引擎:Cocos Creator 2.0.6. 语言:Javasctipt 可用开发平台:MAC,Windows 可发布平台: iOS,Android,Wind ...

  9. WPF入门教程系列三——Application介绍(续)

    接上文WPF入门教程系列二--Application介绍,我们继续来学习Application 三.WPF应用程序的关闭 WPF应用程序的关闭只有在应用程序的 Shutdown 方法被调用时,应用程序 ...

最新文章

  1. 异常处理:SEVERE: Unable to process Jar entry [......]for annotations java.io.EOFException
  2. CITRIX 5.0,XML服务异常引出事件ID 31003和30016错误
  3. 依赖注入的几种形式及场景
  4. FZU 2082 过路费
  5. 幼儿课外活动游戏_幼儿园户外游戏活动大全
  6. 恩智浦智能车大赛2020_内蒙古科技大学第九届智能车大赛校内公开赛总决赛
  7. python traceback_Python 列表操作,节后大放送
  8. Python DButils
  9. 矩阵论复习笔记:矩阵直积及其应用
  10. 力扣-888 公平的糖果交换
  11. python逻辑型数据也叫什么_python基础(三)python数据类型
  12. 系統封裝(4)--封裝系統(龍帝國封裝工具)
  13. 问的书写规则是什么意思_汉字书写规则
  14. smss lsass http://laji.xrlyy.com病毒解决办法
  15. 深入理解地球的经度和纬度换算
  16. js算法 字母大小写转换
  17. linux常用命令课堂总结
  18. PandoraBox登录无法后台,出现/usr/lib/lua/luci/dispatcher.lua:461(2021-12-19亲测)
  19. 我的世界Java版最大村庄_我的世界:java版完美种子,开局两村庄齐铁套
  20. Single Image Haze Removal Using Dark Channel Prior

热门文章

  1. 作为应届生的你,是不是也有这种疑惑和烦恼!
  2. android甚么手机,安卓什么手机性价比高 2019年8月Android手机性价比推荐
  3. 06-ps中的快捷键
  4. 如何检测半导体射频器件是否损坏——TFN FMT800矢量网络分析仪
  5. 使用FlexCell表格控件 for .NET制作条码标签
  6. 腾讯云高级运维工程师
  7. PS添加文本时怎么换行呢?
  8. notepad++python多行注释快捷键_Notepad++快捷键及使用技巧
  9. Python入门习题大全——宠物
  10. 【从蛋壳到满天飞】JS 数据结构解析和算法实现-集合和映射