192 lines
7.4 KiB
TypeScript
192 lines
7.4 KiB
TypeScript
import { GOOD_QUALITY } from './../consts';
|
||
import { RoleModel } from "../db/Role";
|
||
import * as Redis from 'redis';
|
||
import {REDIS_KEY} from '../consts'
|
||
import { GameModel } from "../db/Game";
|
||
import { promisifyAll } from 'bluebird';
|
||
import { pinus } from 'pinus';
|
||
|
||
/**
|
||
* 在服务重新启动时,将信息存入redis
|
||
*/
|
||
export async function initAllRank() {
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
const serverList = await GameModel.getAllServerList();
|
||
await client.delAsync(REDIS_KEY.USER_INFO);
|
||
for(let {id} of serverList) {
|
||
await client.delAsync(getKeyName(REDIS_KEY.TOWER_RANK, id));
|
||
await initRank(id);
|
||
}
|
||
}
|
||
|
||
export async function initRank(serverId: number) {
|
||
// console.log('*****', 'initRank')
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
await client.expireAsync(getKeyName(REDIS_KEY.TOWER_RANK, serverId), 30 * 24 * 60 * 60);
|
||
await client.expireAsync(REDIS_KEY.USER_INFO, 30 * 24 * 60 * 60);
|
||
|
||
let ranks = await RoleModel.getRank('tower', serverId, ['roleId', 'roleName', 'towerLv', 'lv', 'vLv']);
|
||
for(let {towerLv, roleId, roleName, lv, vLv, towerUpTime} of ranks) {
|
||
// console.log(roleId);
|
||
await client.zaddAsync(getKeyName(REDIS_KEY.TOWER_RANK, serverId), encodeScoreWithTime(towerLv, towerUpTime?towerUpTime.getTime():0), roleId);
|
||
await redisUserInfoAdd(roleId, {roleName, lv, vLv, guildName:"", head: "zhaoyun"});
|
||
}
|
||
}
|
||
|
||
// 排行榜是否存在
|
||
export async function existsRank(key: string, serverId: number) {
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
const result = await client.existsAsync(getKeyName(key, serverId));
|
||
return result;
|
||
}
|
||
|
||
export function getKeyName(key: string, serverId: number) {
|
||
return `${key}:${serverId}`;
|
||
}
|
||
|
||
// 更新玩家信息
|
||
export async function redisUserInfoUpdate(roleId: string, arr: Array<{field: string, value:(string|number)}>) {
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
let params = await client.hgetAsync(REDIS_KEY.USER_INFO, roleId);
|
||
if(params) {
|
||
let obj = JSON.parse(params);
|
||
for(let {field, value} of arr) {
|
||
obj[field] = value;
|
||
}
|
||
return await client.hsetAsync(REDIS_KEY.USER_INFO, roleId, JSON.stringify(obj));
|
||
}
|
||
}
|
||
|
||
// 添加玩家信息缓存
|
||
export async function redisUserInfoAdd(roleId: string, params: {roleName: string, lv: number, vLv: number, guildName: string, head: string}) {
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
let value = JSON.stringify(params);
|
||
return await client.hsetAsync(REDIS_KEY.USER_INFO, roleId, value);
|
||
}
|
||
|
||
// 更新排行榜
|
||
export async function setRank(key: string, serverId: number, roleId: string, score: number, timestamp: number, params: {roleName: string, lv: number, vLv: number, guildName: string, head: string}) {
|
||
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
// 更新分数
|
||
const _score = encodeScoreWithTime(score, timestamp);
|
||
await client.zaddAsync(getKeyName(key, serverId), _score, roleId);
|
||
// 移除100名以外
|
||
await client.zremrangebyrankAsync(getKeyName(key, serverId), 100, 10000);
|
||
// 如果没有信息,更新玩家信息
|
||
const hasCurUser = await client.hexistsAsync(REDIS_KEY.USER_INFO, roleId);
|
||
if(!hasCurUser) {
|
||
await redisUserInfoAdd(roleId, params);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// 获取排行榜
|
||
export async function getRank(key: string, serverId: number, roleId: string) {
|
||
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
let ranks = [], myRank = null;
|
||
const rankFromDb = await client.zrevrangebyscoreAsync(getKeyName(key, serverId), '+inf', '-inf', "WITHSCORES", "LIMIT", 0, 100);
|
||
for(let ii = 0; ii < rankFromDb.length; ii+=2) {
|
||
const _roleId = rankFromDb[ii];
|
||
const _score = decodeScoreWithTime(rankFromDb[ii + 1]);
|
||
const userInfo = await client.hgetAsync(REDIS_KEY.USER_INFO, _roleId);
|
||
const _userInfo = JSON.parse(userInfo);
|
||
const tmp = {..._userInfo, roleId: _roleId, num: _score, rank: Math.floor(ii/2)+1}
|
||
ranks.push(tmp);
|
||
if(roleId == _roleId) myRank = tmp;
|
||
}
|
||
return {ranks, myRank}
|
||
}
|
||
|
||
// 有序排行综合时间和得分排序
|
||
function encodeScoreWithTime(score: number, timestamp: number): number {
|
||
// value = score * Math.power(10, 14) + max_time - timestamp
|
||
let timelen = 13;
|
||
let pow = Math.pow(10, timelen + 1);
|
||
return score * pow + pow - 1 - timestamp
|
||
}
|
||
|
||
function decodeScoreWithTime(num: string): number {
|
||
let timelen = 13;
|
||
let pow = Math.pow(10, timelen + 1);
|
||
let _num = parseInt(num);
|
||
return Math.floor(_num/pow);
|
||
}
|
||
|
||
/**************** 寻宝相关 start */
|
||
|
||
// 把寻宝的玩家信息存入 redis
|
||
export async function setTeamSearchReq(roleId: string, sid: string, qualityArr: Array<number>) {
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
let cmds = [];
|
||
qualityArr.forEach(quality => {
|
||
if (quality) {
|
||
cmds.push(['sadd', `${REDIS_KEY.COM_TEAM_SEARCH_PRE}${quality}`, `${roleId}:${sid}`]);
|
||
}
|
||
});
|
||
const multiClient = client.multi(cmds) as Redis.Multi;
|
||
const newMulti = promisifyAll(multiClient) as Redis.Multi;
|
||
const res = await newMulti.execAsync();
|
||
console.log('setTeamSearchReq: ', res);
|
||
return res;
|
||
}
|
||
|
||
// 取出 0 - 2 个某品质的匹配中玩家,并在其它品质中删除此玩家信息
|
||
export async function rmRoleFromQueue(roleId: string, sid: string, qualityArr: Array<number>) {
|
||
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
let cmds = [];
|
||
for (let q of qualityArr) {
|
||
cmds.push(['srem', `${REDIS_KEY.COM_TEAM_SEARCH_PRE}${q}`, `${roleId}:${sid}`]);
|
||
};
|
||
const multiClient = client.multi(cmds) as Redis.Multi;
|
||
const newMulti = promisifyAll(multiClient) as Redis.Multi;
|
||
await newMulti.execAsync();
|
||
}
|
||
|
||
export async function getTeamSearchByQuality(quality: number) {
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
// TODO: 操作不具有原子性
|
||
const userInfos = await client.srandmemberAsync(`${REDIS_KEY.COM_TEAM_SEARCH_PRE}${quality}`, 2);
|
||
console.log('getTeamSearchByQuality: ' + userInfos);
|
||
if (!userInfos || !userInfos.length) return null;
|
||
|
||
let cmds = [];
|
||
let res = [];
|
||
for (let userInfo of userInfos) {
|
||
const decodeData = `${userInfo}`.split(':');
|
||
if (decodeData.length !== 2) return null;
|
||
|
||
res.push({roleId: decodeData[0], sid: decodeData[1]});
|
||
GOOD_QUALITY.forEach((q) => {
|
||
cmds.push(['srem', `${REDIS_KEY.COM_TEAM_SEARCH_PRE}${q}`, userInfo]);
|
||
})
|
||
const multiClient = client.multi(cmds) as Redis.Multi;
|
||
const newMulti = promisifyAll(multiClient) as Redis.Multi;
|
||
await newMulti.execAsync();
|
||
}
|
||
console.log('getTeamSearchByQuality res: ', res);
|
||
return res;
|
||
}
|
||
|
||
export async function checkRoleInQueue(roleId: string, sid: string, qualityArr: Array<number>) {
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
for (let quality of qualityArr) {
|
||
let res = await client.sismemberAsync(`${REDIS_KEY.COM_TEAM_SEARCH_PRE}${quality}`, `${roleId}:${sid}`);
|
||
if (res) {
|
||
return true;
|
||
}
|
||
};
|
||
return false;
|
||
}
|
||
|
||
export async function clearComBtlQueue() {
|
||
const client: Redis.RedisClient = pinus.app.get('redis');
|
||
for (let q of GOOD_QUALITY) {
|
||
client.delAsync(`${REDIS_KEY.COM_TEAM_SEARCH_PRE}${q}`);
|
||
}
|
||
}
|
||
|
||
/**************** 寻宝相关 end */
|