游戏体验
部署游戏
分析思路
游戏服务器的流程除了启动部分外,大部分事件和流程都是并发的,如果按照一个流程去描述这样一件事情,会很混乱,所以我会根据自己对代码的理解,分开不同用户模块,不同业务去分析Lordofpomelo的代码。
Lordofpomelo 服务器介绍
Lordofpomelo启动流程
用户登录模块
用户流程
点击登录->输入账号和密码->输入正确
流程图
1.客户端输入账号密码,发送到register服务器上。
web-server/public/js/ui/clientManager.js
$.post(httpHost + 'login', {username: username, password: pwd}, function(data) {
if (data.code === 501) {
alert('Username or password is invalid!');
loading = false;
return;
}
if (data.code !== 200) {
alert('Username is not exists!');
loading = false;
return;
}
authEntry(data.uid, data.token, function() { //发送token到gate服务器
loading = false;
});
localStorage.setItem('username', username);
});
function authEntry(uid, token, callback) {
queryEntry(uid, function(host, port) { //gate服务器
entry(host, port, token, callback);
});
}
2.Register服务器返回token
3.客户端连接到pomelo的GATE服务器上
pomelo.init({host: config.GATE_HOST, port: config.GATE_PORT, log: true}, function() {})
4.发送uid到pomelo的Gate服务器上,执行服务器函数gate.gateHandler.queryEntry,该函数分配其中一台connector为用户服务,返回改connector服务器对应的IP和端口,客户端收到返回信息后,断开与gate服务器连接,并获得connector服务器的IP和端口。
game-server/app/servers/gate/handler/gateHandler.js
Handler.prototype.queryEntry = function(msg, session, next) {
var uid = msg.uid;
if(!uid) {
next(null, {code: Code.FAIL});
return;
}
var connectors = this.app.getServersByType('connector');
if(!connectors || connectors.length === 0) {
next(null, {code: Code.GATE.NO_SERVER_AVAILABLE});
return;
}
var res = dispatcher.dispatch(uid, connectors);
next(null, {code: Code.OK, host: res.host, port: res.clientPort});
// next(null, {code: Code.OK, host: res.pubHost, port: res.clientPort});
};
5.根据获取的host和ip发送token到指定的connector服务器
客户端
web-server/public/js/ui/clientManager.js
pomelo.request('gate.gateHandler.queryEntry', { uid: uid}, function(data) {
pomelo.disconnect();
if(data.code === 2001) {
alert('Servers error!');
return;
}
callback(data.host, data.port);
});
6.执行connector.entryHandler.entry
7.将token发送到auth服务器,进行验证,验证没问题,生成session
8.服务器最后返回玩家信息给客户端
服务器端
game-server/app/servers/connector/handler/entryHandler.js
/**
* New client entry game server. Check token and bind user info into session.
*
* @param {Object} msg request message
* @param {Object} session current session object
* @param {Function} next next stemp callback
* @return {Void}
*/
pro.entry = function(msg, session, next) {
var token = msg.token, self = this; //验证token信息,生成session
if(!token) {
next(new Error('invalid entry request: empty token'), {code: Code.FAIL});
return;
}
var uid, players, player;
async.waterfall([
function(cb) {
// auth token
self.app.rpc.auth.authRemote.auth(session, token, cb); //通过
}, function(code, user, cb) {
// query player info by user id
if(code !== Code.OK) {
next(null, {code: code});
return;
}
if(!user) {
next(null, {code: Code.ENTRY.FA_USER_NOT_EXIST});
return;
}
uid =