import {ApiCall, BaseConnection} from "tsrpc"; import {FriendManage} from '../../public/friend/manage'; import {GHManage} from '../../public/gonghui/manage'; import {HeroFun} from "../../public/hero"; import {PlayerFun} from '../../public/player'; import {TaskFun} from "../../public/task"; import {defaultUserAppend, UserFun} from '../../public/user'; import {ReqLogin, ResLogin} from "../../shared/protocols/user/PtlLogin"; import {setUidProcessId} from "../../clusterUtils"; import * as crypto from 'crypto'; import {EmailFun} from "../../public/email"; import {PublicShared} from "../../shared/public/public"; import {getGud, initGud} from "../../public/gud"; //登陆排队中的conn.id let queueLogin = [ //{call:call,binduid,binduid,conn:conn} ] //排队间隔 ms let delay = 1000; setInterval(function () { doLoginQueue(); }, delay); //获取排队顺序 function getQueueIndex(bindUid) { for (let i = 0; i < queueLogin.length; i++) { if (queueLogin[i].bindUid == bindUid) { return i; } } return null; } //conn断开了链接,取消排队 export function unQueueByConn(conn: BaseConnection) { //从queueLogin删除指定conn for (let i = 0; i < queueLogin.length; i++) { if (queueLogin[i].conn == conn) { queueLogin.splice(i, 1); break; } } } //默认入口 export default async function (call: ApiCall) { let bindUid = call.req.bindUid; let index = getQueueIndex(bindUid); if (index == null) { //增加到排队队列 queueLogin.push({call: call, bindUid: bindUid, conn: call.conn}); } else { queueLogin[index].call = call; queueLogin[index].conn = call.conn; } //需要排队的时间 let needTime = delay * queueLogin.length; //需要等待的时间 G.server.sendMsgByUid(call.uid, 'msg_s2c/LoginQueue', { delay: needTime }) } //每N时间消费1个排队 async function doLoginQueue() { let data = queueLogin.shift(); if (!data) return; let kickDelay = await kickUser(data.call.req.bindUid, data.call.req.sid); console.log("排队登陆中,剩余数量", queueLogin.length, "kickDelay", kickDelay); setTimeout(async function () { return await doLogin(data.call); }, kickDelay); } function md5String(password: string): string { const md5 = crypto.createHash('md5'); md5.update(password); return md5.digest('hex'); } async function kickUser(bindUid: string, sid: string) { let delayTime = 0; let user = await G.mongodb.collection('user').findOne({bindUid: bindUid, sid: sid}, { projection: { uid: 1 } }); if (user == null) { return delayTime; } let uid = user.uid; const loginConn = G.server.uid_connections[uid]; let checkPid = await G.redis.hGet("uid2processId", uid); if (checkPid) { if (~~checkPid == process.pid && loginConn) { // 本进程踢线 loginConn.sendMsg('msg_s2c/OtherLogin', loginConn.ip).then(v => { loginConn.close('otherLogin'); }); } else { // 跨进程踢线,注意这里是异步的,留200ms等原进程清理数据 G.server.sendMsgByUid(uid, 'msg_s2c/OtherLogin', '1', String(process.pid)); delayTime = 200; } } return delayTime; } async function doLogin(call: ApiCall) { //合法性检测 let sign = call.req.sign; //本地测试时,直接用通用鉴权秘钥 if (sign != "BPtqdLH9QTVbZk7v" && sign != md5String(call.req.bindUid + "ajklsdhjhquieb")) { return call.error("shibai"); } // 查询账号 let user = await G.mongodb.collection('user').findOne({bindUid: call.req.bindUid, sid: call.req.sid}); let {_id, ...gud} = user ? user : await UserFun.createUser(call.conn, call.req.bindUid, call.req.sid); // 判断账号是否被封禁 if (gud.status == 1) { return call.error(lng.user_10); } await initGud(gud.uid, gud); // 修复公会id await fixUnionData(gud); //记录玩家所在的进程,change: 更换到处理完踢线操作在写入。 // setUidProcessId(gud.uid); let obj = await UserFun.check(gud, call.req); call.conn.onlineTime = G.time; call.conn.uid = gud.uid; call.conn.bindUid = gud.bindUid; call.conn.gud = gud; call.conn.lshd = {}; if (!!!user) { await firstLoginFun(call); firstLoginSendEmail(call) } G.mongodb.collection('loginLog').insertOne({ uid: gud.uid, bindUid: gud.bindUid, sid: gud.sid, loginTime: G.time }) call.succ({ gud: gud, curTime: G.time, openTime: G.config.openTime, openDay: PublicShared.getOpenServerDay(), firstLogin: !!!user, otherData: obj }); if (obj.todayFirstLogin) { // gud.loginTime 在check时已近被赋值为G.time G.emit('FIRST_LOGIN_EVERY_DAY', gud, (gud.loginTime || G.time) - 24 * 3600, G.time); } LoginFun(call); } /**新玩家首次登陆后执行 */ async function firstLoginFun(call: ApiCall) { await Promise.all([ //插入探险数据 G.mongodb.collection('tanxian').insertOne({ uid: call.uid, eventTime: G.time, lastGuaJiTime: G.time, useFastGuaJiNum: 0, receivePrize: [], resetTime: G.time }), // 首号奖励 await PlayerFun.sendPrize(call, G.gc.playerdata.hero), // 自动上阵 HeroFun.setHeroPos(call), TaskFun.generateAllTask(call), ]); } /**新玩家首次登陆后执行 */ function firstLoginSendEmail(call: ApiCall) { let conf = G.gc.yuyuemail if (G.time > conf.overtime || G.time < conf.opentime) return setTimeout(() => { EmailFun.addEmail({ uid: call.conn.uid, type: 'system', title: '', content: '', prize: conf.prize, lngTitle: conf.title, lngContent: conf.content }); }, 10000) } /**玩家登陆后执行 */ async function LoginFun(call: ApiCall) { //检测玩家头像、头像框、聊天框、模型是否过期 let modelChange = false; const model: ResLogin['gud']['model'] = {}; const change: Partial = {}; if (call.conn.gud.head.time > 0 && call.conn.gud.head.time < G.time) { change.head = defaultUserAppend.head; } if (call.conn.gud.headFrame.time > 0 && call.conn.gud.headFrame.time < G.time) { change.headFrame = defaultUserAppend.headFrame; } if (call.conn.gud.chatFrame.time > 0 && call.conn.gud.chatFrame.time < G.time) { change.chatFrame = defaultUserAppend.chatFrame; } Object.entries(call.conn.gud.model).forEach(v => { if (v[1].time > 0 && v[1].time < G.time) { modelChange = true; model[v[0]] = defaultUserAppend.model[v[0]]; } else model[v[0]] = Object.assign({}, v[1]); }); if (modelChange) change.model = model; Object.keys(change).length > 0 && PlayerFun.addAttr(call, change); //上线重算战力 call.conn.refreshPower(); // ### globalDebug GHManage if (call.conn.gud.ghLevel == 1 && await GHManage.getGH(call.conn.gud.ghId)) { GHManage.hzsx(call.conn.gud); } if (!await G.redis.hGet('player:uids', call.conn.gud.uid)) { G.redis.hSet('player:uids', call.conn.gud.uid, 1) } FriendManage.addNew(call.conn.gud.uid); // 更新主线任务 TaskFun.updateMainTask(call) // 推送当前主线任务信息,引导用 let _taskInfo = await TaskFun.getFinishByTtype(call, [2], {finish: 0}); G.server.sendMsgByUid(call.uid, 'msg_s2c/TaskChange', _taskInfo?.[2]?.[0]) // 存入当前玩家多语言信息 G.redis.rawSet(`user:lng:${call.uid}`, call.req.lng, {EX: 259200}) // 临时修补 // fixHeroShiwu(call) } // async function fixHeroShiwu(call: ApiCall) { // let list = await G.mongodb.collection("hero").find({$and: [{"uid": call.uid}, {"shiwu": {$exists: true}}]}).toArray() // // list.map(i => { // let list = R.values(i.shiwu).filter(i => !i._id) // if (list.length == 0) return '' // // let shiwuChange = {} // if (i.shiwu?.['1']?._id) { // shiwuChange['1'] = i.shiwu['1'] // } // if (i.shiwu?.['2']?._id) { // shiwuChange['2'] = i.shiwu['2'] // } // // G.mongodb.collection("hero").findOneAndUpdate({_id: i._id}, {$set: {shiwu: shiwuChange}}) // }) // } // 修复玩家退出公会 但是gud中残留公会id async function fixUnionData(gud: ResLogin["gud"]) { if (gud.ghId) { let ghdata = await G.mongodb.collection("gonghui").findOne( {_id: G.mongodb.conversionId(gud.ghId), 'players.uid': gud.uid} ) if (!ghdata) { gud.ghId = ""; gud.ghName = ""; gud.ghLevel = 0; PlayerFun.changeAttr(gud.uid, {ghId: '', ghLevel: 0}) } } }