军团活动:粮草先行部分计算逻辑

This commit is contained in:
luying
2021-03-27 11:02:39 +08:00
parent ca7f9a0b31
commit 2441a8d473
18 changed files with 765 additions and 84 deletions
@@ -1,7 +1,8 @@
import { Application, ChannelService, BackendSession } from "pinus";
import { GUILD_ACTIVITY_TYPE, STATUS } from "../../../consts";
import { GUILD_ACTIVITY_TYPE, STATUS, GUILD_ACTIVITY_STATUS } from "../../../consts";
import { resResult } from "../../../pubUtils/util";
import { getGuildActivityStatus } from "../../../services/guildActivityService";
import { getGuildActivityStatus, getRaceActivityObj, getRaceActivityRank, getWoodenHorseList, calWoodenHorseAndSend } from "../../../services/guildActivityService";
import { UserGuildModel } from "../../../db/UserGuild";
export default function (app: Application) {
return new RaceActivityHandler(app);
@@ -14,11 +15,39 @@ export class RaceActivityHandler {
this.channelService = app.get('channelService');
}
private aid = GUILD_ACTIVITY_TYPE.GATE_ACTIVITY; // 蛮夷入侵id
private aid = GUILD_ACTIVITY_TYPE.RACE_ACTIVITY; // 蛮夷入侵id
// 进入粮草先行界面
async getRaceActivity(msg: {}, session: BackendSession) {
const roleId = session.get('roleId');
const serverId = session.get('serverId');
const guildCode = session.get('guildCode');
if(!guildCode) return resResult(STATUS.GUILD_AUTH_NOT_ENOUGH);
let statusResult = getGuildActivityStatus(this.aid);
if(!statusResult) return resResult(STATUS.DIC_DATA_NOT_FOUND);
let obj = getRaceActivityObj();
let woodenHorse = await obj.getWoodenHorse(guildCode, serverId);
if(!woodenHorse) return resResult(STATUS.GUILD_AUTH_NOT_ENOUGH);
let events = obj.getEvents(guildCode, woodenHorse.distance);
let ranks = await getRaceActivityRank(guildCode, serverId);
let hasJoin = obj.hasJoin(guildCode, roleId);
return resResult(STATUS.SUCCESS, {
...statusResult,
hasJoin,
woodenHorse,
...ranks,
events
});
}
// 加入木马
async join(msg: {}, session: BackendSession) {
const roleId = session.get('roleId');
const roleName = session.get('roleName');
const serverId = session.get('serverId');
@@ -28,15 +57,57 @@ export class RaceActivityHandler {
let statusResult = getGuildActivityStatus(this.aid);
if(!statusResult) return resResult(STATUS.DIC_DATA_NOT_FOUND);
let obj = getRaceActivityObj();
let myGuild = await UserGuildModel.getMyGuild(roleId, 'job');
let woodenHorse = obj.joinWoodenHorse(guildCode, roleId, roleName, myGuild.job);
if(!woodenHorse) return resResult(STATUS.GUILD_AUTH_NOT_ENOUGH);
let events = obj.getEvents(guildCode, woodenHorse.distance);
let hasJoin = obj.hasJoin(guildCode, roleId);
return resResult(STATUS.SUCCESS, {
...statusResult,
hasJoin: true,
woodenHorse: {},
guildRank:[]
hasJoin,
woodenHorse,
events
});
}
// 打开竞赛页面
async getRace(msg: {}, session: BackendSession) {
const roleId = session.get('roleId');
const roleName = session.get('roleName');
const serverId = session.get('serverId');
const guildCode = session.get('guildCode');
if(!guildCode) return resResult(STATUS.GUILD_AUTH_NOT_ENOUGH);
let statusResult = getGuildActivityStatus(this.aid);
if(!statusResult) return resResult(STATUS.DIC_DATA_NOT_FOUND);
if(statusResult.status != GUILD_ACTIVITY_STATUS.START) {
return resResult(STATUS.GUILD_ACTIVITY_NOT_OPEN);
}
let obj = getRaceActivityObj();
let woodenHorse = await obj.getWoodenHorse(guildCode, serverId);
if(!woodenHorse) return resResult(STATUS.GUILD_AUTH_NOT_ENOUGH);
let events = obj.getEvents(guildCode, woodenHorse.distance);
let hasJoin = obj.hasJoin(guildCode, roleId);
let woodenHorseList = await getWoodenHorseList(guildCode, serverId);
return resResult(STATUS.SUCCESS, {
...statusResult,
hasJoin,
woodenHorseList,
events
});
}
async test(msg: { serverId: number }, session: BackendSession) {
let {serverId} = msg;
await calWoodenHorseAndSend(serverId);
}
}
@@ -1,5 +1,5 @@
import { Application, ChannelService } from 'pinus';
import { sendAllGuildRanks, sendGuildActEndMsg } from '../../../services/guildActivityService';
import { sendAllGuildRanks, sendGuildActEndMsg, calWoodenHorseAndSend } from '../../../services/guildActivityService';
export default function (app: Application) {
return new GuildActivityRemote(app);
@@ -27,4 +27,11 @@ export class GuildActivityRemote {
public async guildActivityEnd(aid: number) {
await sendGuildActEndMsg(aid);
}
/**
* 计算粮草先行木马状态并发送
*/
public async calWoodenHorseAndSend(serverId: number) {
await calWoodenHorseAndSend(serverId);
}
}
@@ -6,11 +6,11 @@ import { gameData, getGuildAuctionRewards, getCityActivityRewards } from "../pub
import { getCurHourPoint, getCutDay, nowSeconds } from "../pubUtils/timeUtil";
import { GUILD_ACTIVITY_STATUS, GET_POINT_WAYS, GUILD_ACTIVITY_TYPE, REDIS_KEY, AUCTION_SOURCE, MAIL_TYPE, CITY_STATUS } from "../consts";
import { Record, UserGuildActivityRecModel } from "../db/UserGuildActivityRec";
import { GateMembersRec, GateActivityObject, CityActivityObject, CityParam, Member } from "../domain/battleField/guildActivity";
import { GateMembersRec, GateActivityObject, CityActivityObject, CityParam, Member, RaceActivityObject, WoodenHorse } from "../domain/battleField/guildActivity";
import { DicGuildActivity } from "../pubUtils/dictionary/DicGuildActivity";
import { getUnionRank, getRank, getGuildKeyName, getMyUnionRank, getRankScore, getCityKeyName, getAllServers } from "./redisService";
import { getUnionRank, getRank, getGuildKeyName, getMyUnionRank, getRankScore, getCityKeyName, getAllServers, getUnionRankRange } from "./redisService";
import { GuildModel } from "../db/Guild";
import { SimpleGuildRankParam, SimpleRoleRankParam } from "../domain/rank";
import { SimpleGuildRankParam, SimpleRoleRankParam, SimpleGuildRankWithTimeParam } from "../domain/rank";
import { getGuildChannelSid, getWorldChannelSid, getCityChannelSid } from "./chatChannelService";
import { pinus } from "pinus";
import { GuildActivityRecordModel } from "../db/GuildActivityRec";
@@ -21,6 +21,7 @@ import { GuildActivityCityType, GuildActivityCityModel } from "../db/GuildActivi
let gateActivityObj: GateActivityObject;
let cityActivityObj: CityActivityObject;
let raceActivityObj: RaceActivityObject;
export function getGateActivityObj() {
if(!gateActivityObj) {
gateActivityObj = new GateActivityObject();
@@ -32,7 +33,14 @@ export function getCityActivityObj() {
if(!cityActivityObj) {
cityActivityObj = new CityActivityObject();
}
return cityActivityObj
return cityActivityObj;
}
export function getRaceActivityObj() {
if(!raceActivityObj) {
raceActivityObj = new RaceActivityObject();
}
return raceActivityObj;
}
/**
@@ -159,6 +167,53 @@ export async function getCityActivityRank(guildCode: string, serverId: number, c
return rec;
}
export async function getRaceActivityRank(guildCode: string, serverId: number) {
let guildKey = REDIS_KEY.RACE_ACTIVITY;
let obj = getRaceActivityObj();
let guildRankResult = await getUnionRank(guildKey, serverId, guildCode);
let guildRank = new Array<SimpleGuildRankWithTimeParam>();
for(let { rank, code, name, num } of guildRankResult.ranks) {
let _obj = await obj.getWoodenHorse(code, serverId);
let param = new SimpleGuildRankWithTimeParam(rank, code, name, num, _obj?_obj.time:0, _obj?_obj.durability:0);
guildRank.push(param);
}
let myGuildRank: SimpleGuildRankWithTimeParam;
if(guildRankResult.myRank) {
let { rank, code, name, num } = guildRankResult.myRank;
let _obj = await obj.getWoodenHorse(code, serverId);
myGuildRank = new SimpleGuildRankWithTimeParam(rank, code, name, num, _obj?_obj.time:0, _obj?_obj.durability:0);
} else {
let guild = await GuildModel.findByCode(guildCode, serverId, 'name');
let _obj = await obj.getWoodenHorse(guildCode, serverId);
myGuildRank = new SimpleGuildRankWithTimeParam(0, guildCode, guild?.name, 0, _obj?_obj.time:0, _obj?_obj.durability:0);
}
return { guildRank, myGuildRank }
}
/**
* 获取和自己同屏的5个木牛流马
* @param guildCode
* @param serverId
*/
export async function getWoodenHorseList(guildCode: string, serverId: number) {
let guildKey = REDIS_KEY.RACE_ACTIVITY;
let obj = getRaceActivityObj();
let myRank = await getMyUnionRank(guildKey, serverId, guildCode);
let startRank = myRank - 2 > 0? myRank - 2: 1;
let endRank = startRank + 4;
let range = await getUnionRankRange(guildKey, serverId, startRank, endRank);
let woodenHorseList = new Array<WoodenHorse>();
for(let { code } of range) {
let woodenHorse = await obj.getWoodenHorse(code, serverId);
if(woodenHorse) {
woodenHorseList.push(woodenHorse);
}
}
return woodenHorseList;
}
/**
* 获得军团活动排行榜
* @param guildCode
@@ -477,4 +532,45 @@ export function getCityStatus(guildCode: string, cityId: number, preCity: number
}
}
return status;
}
export async function calWoodenHorseAndSend(serverId: number) {
console.log('calWoodenHorseAndSend');
let guildKey = REDIS_KEY.RACE_ACTIVITY;
let obj = getRaceActivityObj();
let { ranks } = await getUnionRank(guildKey, serverId, '');
let map = new Map<number, WoodenHorse[]>();
let user = new Map<number, string>();
for(let i = 0; i < ranks.length; i++) {
let { code } = ranks[i];
for(let j = i; j <= i + 2; j++) {
if(j <= ranks.length - 1 && !map.has(j)) {
map.set(j, new Array<WoodenHorse>());
}
}
user.set(i, code);
for(let [rank, woodenHorseList] of map) {
let woodenHorse = await obj.getWoodenHorse(code, serverId);
if(woodenHorse) {
map.get(rank).push(woodenHorse);
} else {
map.get(rank).push(new WoodenHorse(rank.toString(), 's',0));
}
let len = map.get(rank).length;
let limit = 5;
if(rank - 2 < 0) limit += rank - 2;
if(rank + 2 > ranks.length - 1) limit -= (rank + 2) - (ranks.length - 1);
if( len >= limit) {
// 发送
let roleId = user.get(rank);
console.log('send', roleId, woodenHorseList.length, JSON.stringify(woodenHorseList));
map.delete(rank);
}
}
}
return ;
}
+34 -3
View File
@@ -579,14 +579,13 @@ async function updateRankAtom(key: string, serverId: number, field: string, scor
return newScore;
}
async function generateUnionRank(key: string, serverId: number) {
async function generateUnionRank(key: string, serverId: number, timelen = 10) {
let unionKey = getKeyName(key, serverId, 'union'); // 联合的key
let existsKey = await redisClient().existsAsync(unionKey);
if(!existsKey) {
let originKey = getKeyName(key, serverId);
let timeKey = getKeyName(key, serverId, 'time');
let timelen = 10;
let pow = Math.pow(10, timelen + 1);
await redisClient().zunionstoreAsync(unionKey, 2, originKey, timeKey, 'WEIGHTS', pow, 1);
await redisClient().expireAsync(unionKey, 10); // 10秒更新一次
@@ -600,7 +599,7 @@ async function generateUnionRank(key: string, serverId: number) {
* @param serverId 区服id
* @param roleId 自己的id
*/
export async function getUnionRank(key: string, serverId: number, roleId: string, limit = 100) {
export async function getUnionRank(key: string, serverId: number, roleId: string, timelen = 10, limit = 100) {
let ranks = [], myRank = null;
let unionKey = await generateUnionRank(key, serverId);
@@ -627,6 +626,38 @@ export async function getUnionRank(key: string, serverId: number, roleId: string
return {ranks, myRank}
}
/**
* 获取(分两个zset的)排行的一段排名内的数据
* @param key 配置在REDIS_KEY中的key
* @param serverId 区服id
* @param startRank 开始排名
* @param endRank 结束排名
*/
export async function getUnionRankRange(key: string, serverId: number, startRank: number, endRank: number) {
let ranks = [];
let unionKey = await generateUnionRank(key, serverId);
const rankFromDb = await redisClient().zrevrangeAsync(unionKey, startRank - 1, endRank - 1, "WITHSCORES");
let _key = key.split(':')[0];
let infoKey = REDIS_RANK_TO_INFO.get(_key)||REDIS_KEY.USER_INFO;
for(let ii = 0; ii < rankFromDb.length; ii+=2) {
const _roleId = rankFromDb[ii];
const _score = decodeScoreWithTime(rankFromDb[ii + 1]);
const info = await redisClient().hgetAsync(infoKey, _roleId);
const _userInfo = JSON.parse(info);
const tmp = {..._userInfo, num: _score, rank: Math.floor(ii/2)+1};
if(infoKey == REDIS_KEY.USER_INFO) {
tmp["roleId"] = _roleId;
} else if(infoKey == REDIS_KEY.GUILD_INFO) {
tmp["code"] = _roleId;
}
ranks.push(tmp);
}
return ranks
}
// 获取我的排名
export async function getMyUnionRank(key: string, serverId: number, roleId: string) {
let unionKey = await generateUnionRank(key, serverId);
+19 -5
View File
@@ -7,7 +7,7 @@ import { nowSeconds, getTodayZeroPoint, getAge } from '../pubUtils/timeUtil';
import { getPvpGkWarIds, getPvpRankRewards, getPvpHeroRewards, getResultMaxRank, getTodayGuildActivity } from '../pubUtils/data';
import { deepCopy, getRandomArr, resResult } from '../pubUtils/util';
import { getLvByScore } from './pvpService';
import { getMyRank, setRank, resetPvpRanks, getAllOnlineRoles, delGuildActivityRank } from './redisService';
import { getMyRank, setRank, resetPvpRanks, getAllOnlineRoles, delGuildActivityRank, getAllServers } from './redisService';
import { MAIL_TYPE, REDIS_KEY, ADULT_AGE, GUEST_MAX_TIME, ADDICTION_PREVENTION_CODE, GUILD_ACTIVITY_STATUS, GUILD_ACTIVITY_TYPE } from '../consts';
import { RankParam } from '../domain/rank';
import { RoleModel } from '../db/Role';
@@ -24,6 +24,7 @@ import { getGuildActivityByDic, setMedianCe, sendEndMsgToAll } from './guildActi
import { sendUngotDividendJob, startGuildAuction, startWorldAuction, stopAuction } from './auctionService';
import { DicGuildActivity } from '../pubUtils/dictionary/DicGuildActivity';
import { GuildModel } from '../db/Guild';
import { dispatch } from '../util/dispatcher';
const PER_SECOND = 1 * 1000;
const PER_DAY = 24 * 60 * 60;
@@ -364,11 +365,13 @@ async function guildActivitySchedule() {
if(statusResult.status == GUILD_ACTIVITY_STATUS.START) {
if(!guildActSecondsJobId) {
let seconds = 10; // 每10秒下发一次
if(dicGuildActivity.id == GUILD_ACTIVITY_TYPE.RACE_ACTIVITY) {
seconds = 1;
if(dicGuildActivity.id == GUILD_ACTIVITY_TYPE.GATE_ACTIVITY) {
guildActSecondsJobId = scheduleJob('guildActivitySeconds', `*/10 * * * * *`, gateActivitySeconds);
} else if(dicGuildActivity.id == GUILD_ACTIVITY_TYPE.CITY_ACTIVITY) {
guildActSecondsJobId = scheduleJob('guildActivitySeconds', `*/10 * * * * *`, cityActivitySeconds);
} else if(dicGuildActivity.id == GUILD_ACTIVITY_TYPE.RACE_ACTIVITY) {
// guildActSecondsJobId = scheduleJob('guildActivitySeconds', `*/1 * * * * *`, raceActivitySeconds);
}
guildActSecondsJobId = scheduleJob('guildActivitySeconds', `*/${seconds} * * * * *`, gateActivitySeconds);
}
if(!guildActEndJobId) {
@@ -452,6 +455,17 @@ export async function cityActivitySeconds() {
}
}
// 每10秒下发一次的任务
export async function raceActivitySeconds() {
console.log('*****raveActivitySeconds')
let servers = await getAllServers(); // 玩家serverId列表
let guildServers = pinus.app.getServersByType('guild');
for(let serverId of servers) {
let sid = dispatch(serverId.toString(), guildServers);
await pinus.app.rpc.guild.guildActivityRemote.calWoodenHorseAndSend.toServer(sid.id, serverId);
}
}
function auctionSchedule() {
scheduleJob('startGuildAuction', '0 0 20 20 * ?', startGuildAuction);
scheduleJob('startWorldAuction', '0 0 20 30 * ?', startWorldAuction);
+8 -1
View File
@@ -72,11 +72,18 @@ export function guild(session: Session, msg: any, app: Application, cb: (err: Er
'guild.cityActivityHandler.checkBattle',
'guild.cityActivityHandler.hitGate',
'guild.cityActivityHandler.battleEnd'
].indexOf(arg.route) !== -1) {
].indexOf(arg.route) !== -1) {
if (arg.body.cityId) {
rid = arg.body.cityId.toString();
}
} else if (['guild.raceActivityHandler.getRaceActivity',
'guild.raceActivityHandler.join',
'guild.raceActivityHandler.getRace',
]) {
rid = session.get('serverId').toString();
}
}
}
+1 -1
View File
@@ -53,7 +53,7 @@ declare module 'redis' {
// 返回有序集中指定成员的排名,从大到小
zrevrankAsync(key: string, field: string): Promise<number>;
// 命令返回有序集中,指定区间内的成员,从大到小
zrevrangeAsync(key: string, start: number, end: number): Promise<string[]>;
zrevrangeAsync(key: string, start: number, end: number, withscores?: string): Promise<string[]>;
// 对有序集合中指定成员的分数加上增量 increment
zincrbyAsync(key: string, increment: number, member: string): Promise<number>;
// 对有序集合中指定成员的分数加上增量 increment