370 lines
14 KiB
TypeScript
370 lines
14 KiB
TypeScript
|
||
import { scheduleJob, Job, } from 'node-schedule';
|
||
import { PVPConfigModel, PVPConfigType } from '../db/SystemConfig';
|
||
import { nowSeconds, getTimeFun, getSeconds } from '../pubUtils/timeUtil';
|
||
import { getTodayGuildActivity, gameData } from '../pubUtils/data';
|
||
import { pvpSeasonEnd } from './pvpService';
|
||
import { getAllOnlineRoles, getAllServers, delGuildActivityRank } from './redisService';
|
||
import { GUILD_ACTIVITY_TYPE, REFRESH_TIME, SEND_NAME, SERVER_OPEN_TIME, COUNTER, AUCTION_TIME } from '../consts';
|
||
import { RoleModel } from '../db/Role';
|
||
import { pinus } from 'pinus';
|
||
import { indexOf } from 'underscore';
|
||
import { PvpSeasonResultModel } from '../db/PvpSeasonResult';
|
||
import { settleGuildWeekly } from './guildService';
|
||
import { sendMailByContent } from './mailService';
|
||
import { getGuildActivityByDic, sendEndMsgToAll, autoDeclare, sendGuildActivityStatus } from './guildActivityService';
|
||
import { sendUngotDividendJob, startGuildAuction, startWorldAuction, stopAuction } from './auctionService';
|
||
import { DicGuildActivity } from '../pubUtils/dictionary/DicGuildActivity';
|
||
import { dispatch } from '../pubUtils/dispatcher';
|
||
import { Rank } from './rankService';
|
||
import { checkTask } from './taskService';
|
||
import { everydayRefresh } from './connectorService';
|
||
import { initMarquee, initMaintenance } from './gmService';
|
||
import moment = require('moment');
|
||
import { CounterModel } from '../db/Counter';
|
||
import { reportOneOnline } from './authenticateService';
|
||
import { PVP } from '../pubUtils/dicParam';
|
||
|
||
const PER_SECOND = 1 * 1000;
|
||
const PER_DAY = 24 * 60 * 60;
|
||
const PER_HOUR = 1 * 60 * 60;
|
||
const SETTLE_DIFF_SECONDS = 29 * 60;
|
||
const PER_MINUTE = 1 * 60;
|
||
var seasonMakeRewardTimJobId: Job;
|
||
var warJobId: Job;
|
||
var seasonRefreshTimeJobId: Job;
|
||
let guildWeeklyJobId: Job;
|
||
let guildActStartJobId: Job; // 军团活动开启后每10(or 1)秒循环的定时任务,到结束活动清除
|
||
let guildActSecondsJobId: Job; // 军团活动开启后每10(or 1)秒循环的定时任务,到结束活动清除
|
||
let guildActEndJobId: Job; // 军团活动开启后每10(or 1)秒循环的定时任务,到结束活动清除
|
||
let pvpMakeRewardInterval = null;
|
||
let pvpRefreshInterval = null;
|
||
|
||
/**
|
||
* 服务器启动即开启定时任务,结算时常是23-24点,实际结算的时间点是23:31分钟
|
||
*/
|
||
export async function init() {
|
||
|
||
// pvp赛季
|
||
await setPvpSeason();
|
||
|
||
// 周功勋结算任务
|
||
guildWeeklyJobId = scheduleJob('settleGuildWeekly', '0 0 0 * * 1', settleGuildWeekly);
|
||
|
||
// 每5分钟汇报在线玩家在线情况
|
||
scheduleJob('reportOnline', '0 0/5 * * * *', reportOnlineSchedule);
|
||
|
||
// 军团活动排行榜
|
||
guildActivitySchedule();
|
||
|
||
// 拍卖行刷新:拍卖阶段刷新,分红发放
|
||
auctionSchedule();
|
||
|
||
// 每天5点推送刷新时间消息
|
||
// 顺便每天0点计算前一天活跃玩家中位数战力
|
||
scheduleJob('everyDayRefresh', `0 0 ${REFRESH_TIME} * * ?`, everydayRefresh);
|
||
|
||
// 跑马灯
|
||
await initMarquee();
|
||
|
||
// 维护信息
|
||
await initMaintenance();
|
||
}
|
||
|
||
function getSeasonContinueDay(seasonNum: number) {
|
||
const pvpSeasonDuring = PVP.PVP_SEASON_DAYS.split('|').map(cur => {
|
||
let arr = cur.split('&');
|
||
let seasonNum = parseInt(arr[0]);
|
||
let day = parseInt(arr[1]);
|
||
if(isNaN(seasonNum) || isNaN(day)) return null;
|
||
return { seasonNum, day }
|
||
}).filter(cur => !!cur);
|
||
|
||
let maxDay = 0;
|
||
for(let {seasonNum: dicSeasonNum, day } of pvpSeasonDuring) {
|
||
if(seasonNum == dicSeasonNum) return day;
|
||
if(maxDay < day) maxDay = day;
|
||
}
|
||
return maxDay;
|
||
}
|
||
|
||
async function setPvpSeasonJob() {
|
||
await setPvpSeason();
|
||
}
|
||
|
||
async function setPvpSeason(isForce?: boolean, hour?: number) {
|
||
console.log(`******** setPvpSeason1: isForce-${isForce}, hour-${hour}`)
|
||
|
||
let during = hour? hour * PER_HOUR: null; // 下一次重置赛季天数
|
||
let oldPvpConfig = await PVPConfigModel.findCurPVPConfig();
|
||
let pvpConfig = oldPvpConfig;
|
||
console.log(`******** setPvpSeason2: during-${during}, seasonEndTime-${pvpConfig?.seasonEndTime}, now-${nowSeconds()}`)
|
||
if(!pvpConfig || pvpConfig.seasonEndTime <= nowSeconds() || isForce) {
|
||
if(pvpConfig && !pvpConfig.hasSettleReward) {
|
||
await pvpSeasonEnd(pvpConfig);
|
||
}
|
||
|
||
let lastSeasonNum = pvpConfig? pvpConfig.seasonNum: 0;
|
||
let lastSeasonEndTime = pvpConfig? pvpConfig.seasonEndTime: 0;
|
||
console.log(`******** setPvpSeason3: lastSeasonNum-${lastSeasonNum}, lastSeasonEndTime-${lastSeasonEndTime}`)
|
||
|
||
let newSeasonStartTime = lastSeasonEndTime + PER_MINUTE;
|
||
if(!during) during = getSeasonContinueDay(lastSeasonNum + 1) * PER_DAY;
|
||
let rewardTime = SETTLE_DIFF_SECONDS;
|
||
if(nowSeconds() - newSeasonStartTime > during) {
|
||
newSeasonStartTime = <number>getTimeFun().getDayZeroPoint(0);
|
||
}
|
||
console.log(`******** setPvpSeason4: newSeasonStartTime-${newSeasonStartTime}, during-${during}`)
|
||
|
||
if(isForce) { // debug使用,如果seasonEndTime是未来的,强行结束掉,新赛季从现在开始
|
||
newSeasonStartTime = nowSeconds();
|
||
} else { // 不是用debug的情况,如果(因为debug)newSeasonStartTime不是每天0点结算,那么改成lastSeasonEndTime之后的0点开始
|
||
let d = new Date(newSeasonStartTime * 1000);
|
||
if(d.getHours() != 0) {
|
||
d.setHours(0, 0, 0, 0);
|
||
newSeasonStartTime = getSeconds(d);
|
||
}
|
||
}
|
||
console.log(`******** setPvpSeason5: isForce-${isForce}, newSeasonStartTime-${newSeasonStartTime}`)
|
||
let newSeasonNum = await CounterModel.getNewCounter(COUNTER.PVP_SEASON_NUM);
|
||
pvpConfig = await PVPConfigModel.createPVPConfig(newSeasonNum, newSeasonStartTime, newSeasonStartTime + during - rewardTime, newSeasonStartTime + during - PER_MINUTE);
|
||
}
|
||
await setPvpSeasonMakeRewardJob(oldPvpConfig);
|
||
await setNextSeasonJob(pvpConfig);
|
||
setPvpSeasonNum(pvpConfig);
|
||
return pvpConfig;
|
||
}
|
||
|
||
function setPvpSeasonNum(pvpConfig: PVPConfigType) {
|
||
if(pvpConfig) {
|
||
pinus.app.set('pvpSeasonNum', pvpConfig.seasonNum);
|
||
pinus.app.set('pvpSeasonEndTime', pvpConfig.seasonEndTime);
|
||
pinus.app.rpc.battle.battleRemote.setPvpSeasonNum.broadcast(pvpConfig);
|
||
pinus.app.rpc.role.roleRemote.setPvpSeasonNum.broadcast(pvpConfig);
|
||
}
|
||
}
|
||
|
||
async function setPvpSeasonMakeRewardJob(pvpConfig: PVPConfigType) {
|
||
if (!!seasonMakeRewardTimJobId) {
|
||
seasonMakeRewardTimJobId.cancel();
|
||
}
|
||
if(!pvpConfig) return;
|
||
if(pvpConfig.seasonRewardTime < nowSeconds() && !pvpConfig.hasSettleReward) { // 未发奖励
|
||
await pvpSeasonEnd(pvpConfig);
|
||
} else {
|
||
seasonMakeRewardTimJobId = scheduleJob('seasonMakeRewardTimJobId', pvpConfig.seasonRewardTime, async () => {
|
||
await pvpSeasonEnd(pvpConfig);
|
||
});
|
||
}
|
||
}
|
||
|
||
async function setNextSeasonJob(pvpConfig: PVPConfigType) {
|
||
if (!!seasonRefreshTimeJobId) {
|
||
seasonRefreshTimeJobId.cancel();
|
||
}
|
||
//定时开启新赛季,比seasonEndTime多定一分钟,保证定时器时间没错
|
||
seasonRefreshTimeJobId = scheduleJob('seasonRefreshTimeJobId', pvpConfig.seasonEndTime + PER_MINUTE, setPvpSeasonJob);
|
||
}
|
||
|
||
/**
|
||
* debug接口
|
||
* @param hour
|
||
*/
|
||
export async function resetPvpSeasonTime(hour: number) {
|
||
return await setPvpSeason(true, hour);
|
||
}
|
||
|
||
export async function reportOnlineSchedule() {
|
||
let allRoles = await getAllOnlineRoles();
|
||
console.log('reportOnlineSchedule all roles count: ', allRoles.length)
|
||
for (let { roleId, userCode, sid } of allRoles) {
|
||
let result = reportOneOnline(roleId, userCode, sid, false);
|
||
if (!result) continue;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 军团活动,每晚8点开启
|
||
*/
|
||
export async function guildActivitySchedule() {
|
||
/***********guildActivitySchedule***********/
|
||
if (guildActStartJobId) {
|
||
guildActStartJobId.cancel();
|
||
}
|
||
if (guildActSecondsJobId) {
|
||
guildActSecondsJobId.cancel();
|
||
guildActSecondsJobId = undefined;
|
||
}
|
||
if (guildActEndJobId) {
|
||
guildActEndJobId.cancel();
|
||
guildActEndJobId = undefined;
|
||
}
|
||
|
||
let dicGuildActivity = getTodayGuildActivity();
|
||
await delGuildActivityRank(dicGuildActivity.id);
|
||
|
||
console.log(dicGuildActivity)
|
||
|
||
guildActStartJobId = scheduleJob('guildActivityStart', `${dicGuildActivity.startSeconds} ${dicGuildActivity.startMinute} ${dicGuildActivity.startTime} * * ?`, guildActivityStartSchedule);
|
||
}
|
||
|
||
// 军团晚间活动,每天8点开始
|
||
async function guildActivityStartSchedule() {
|
||
await guildActivityStart();
|
||
}
|
||
|
||
export async function guildActivityStart(dicGuildActivity?: DicGuildActivity) {
|
||
console.log('*******开始军团晚间活动****')
|
||
if (!dicGuildActivity) dicGuildActivity = getTodayGuildActivity();
|
||
if (!dicGuildActivity) return;
|
||
|
||
console.log('********', dicGuildActivity.id, Date.now() + dicGuildActivity.duringTime * 1000)
|
||
let servers = await getAllServers(); // 玩家serverId列表
|
||
if (dicGuildActivity.id == GUILD_ACTIVITY_TYPE.GATE_ACTIVITY) {
|
||
guildActSecondsJobId = scheduleJob('guildActivitySeconds', '*/10 * * * * *', gateActivitySeconds);
|
||
// 结束时间
|
||
guildActEndJobId = scheduleJob('guildActivityEnd', Date.now() + dicGuildActivity.duringTime * 1000, gateActivityEnd);
|
||
} else if (dicGuildActivity.id == GUILD_ACTIVITY_TYPE.CITY_ACTIVITY) {
|
||
guildActSecondsJobId = scheduleJob('guildActivitySeconds', '*/10 * * * * *', cityActivitySeconds);
|
||
// 结束时间
|
||
guildActEndJobId = scheduleJob('guildActivityEnd', Date.now() + dicGuildActivity.duringTime * 1000, cityActivityEnd);
|
||
} else if (dicGuildActivity.id == GUILD_ACTIVITY_TYPE.RACE_ACTIVITY) {
|
||
|
||
// 开始活动
|
||
let guildServers = pinus.app.getServersByType('guild');
|
||
for (let serverId of servers) {
|
||
let sid = dispatch(serverId.toString(), guildServers, 'guild');
|
||
await pinus.app.rpc.guild.guildActivityRemote.raceActivityStart.toServer(sid.id, serverId);
|
||
}
|
||
|
||
guildActSecondsJobId = scheduleJob('guildActivitySeconds', '*/1 * * * * *', raceActivitySeconds);
|
||
// 结束时间
|
||
guildActEndJobId = scheduleJob('guildActivityEnd', Date.now() + dicGuildActivity.duringTime * 1000, raceActivityEnd);
|
||
}
|
||
|
||
for (let serverId of servers) {
|
||
await sendGuildActivityStatus(serverId);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// 蛮夷入侵
|
||
// 结束军团活动
|
||
export async function gateActivityEnd() {
|
||
|
||
console.log('*****gateActivityEnd');
|
||
await sendEndMsgToAll();
|
||
await pinus.app.rpc.guild.guildActivityRemote.guildActivityEnd.broadcast(GUILD_ACTIVITY_TYPE.GATE_ACTIVITY);
|
||
|
||
if (guildActSecondsJobId) {
|
||
guildActSecondsJobId.cancel();
|
||
guildActSecondsJobId = undefined;
|
||
}
|
||
if (guildActEndJobId) {
|
||
guildActEndJobId.cancel();
|
||
guildActEndJobId = undefined;
|
||
}
|
||
}
|
||
|
||
// 每10秒下发一次的任务
|
||
export async function gateActivitySeconds() {
|
||
console.log('*****gateActivitySeconds')
|
||
await pinus.app.rpc.guild.guildActivityRemote.sendRankToGuilds.broadcast(GUILD_ACTIVITY_TYPE.GATE_ACTIVITY);
|
||
}
|
||
|
||
// 诸侯混战
|
||
// 结束军团活动
|
||
export async function cityActivityEnd() {
|
||
console.log('*****cityActivityEnd');
|
||
await sendEndMsgToAll();
|
||
await pinus.app.rpc.guild.guildActivityRemote.guildActivityEnd.broadcast(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY);
|
||
|
||
// 发完之后再做下周自动宣战
|
||
let serverlists = await getAllServers();
|
||
for (let serverId of serverlists) {
|
||
await autoDeclare(serverId);
|
||
}
|
||
if (guildActSecondsJobId) {
|
||
guildActSecondsJobId.cancel();
|
||
guildActSecondsJobId = undefined;
|
||
}
|
||
if (guildActEndJobId) {
|
||
guildActEndJobId.cancel();
|
||
guildActEndJobId = undefined;
|
||
}
|
||
}
|
||
|
||
// 每10秒下发一次的任务
|
||
export async function cityActivitySeconds() {
|
||
console.log('*****cityActivitySeconds')
|
||
await pinus.app.rpc.guild.guildActivityRemote.sendRankToGuilds.broadcast(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY);
|
||
}
|
||
|
||
// 粮草先行
|
||
// 结束军团活动
|
||
export async function raceActivityEnd() {
|
||
console.log('*****raceActivityEnd');
|
||
await sendEndMsgToAll();
|
||
await pinus.app.rpc.guild.guildActivityRemote.guildActivityEnd.broadcast(GUILD_ACTIVITY_TYPE.RACE_ACTIVITY);
|
||
|
||
if (guildActSecondsJobId) {
|
||
guildActSecondsJobId.cancel();
|
||
guildActSecondsJobId = undefined;
|
||
}
|
||
if (guildActEndJobId) {
|
||
guildActEndJobId.cancel();
|
||
guildActEndJobId = undefined;
|
||
}
|
||
}
|
||
|
||
// 每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, 'guild');
|
||
await pinus.app.rpc.guild.guildActivityRemote.calWoodenHorseAndSend.toServer(sid.id, serverId);
|
||
}
|
||
}
|
||
|
||
let startGuildAuctionJobId: Job;
|
||
let startWorldAuctionJobId: Job;
|
||
let stopAuctionJobId: Job;
|
||
let sendUngotDividendJobId: Job;
|
||
|
||
export function auctionSchedule() {
|
||
clearAuctionSchedule();
|
||
let guildOpen = gameData.auctionTime.get(AUCTION_TIME.GUILD_OPEN);
|
||
let worldOpen = gameData.auctionTime.get(AUCTION_TIME.WORLD_OPEN);
|
||
let worldClose = gameData.auctionTime.get(AUCTION_TIME.WORLD_CLOSE);
|
||
|
||
console.log('***** auctionSchedule', guildOpen.hour, guildOpen.minute, guildOpen.seconds);
|
||
console.log('***** auctionSchedule', worldOpen.hour, worldOpen.minute, worldOpen.seconds);
|
||
console.log('***** auctionSchedule', worldClose.hour, worldClose.minute, worldClose.seconds);
|
||
startGuildAuctionJobId = scheduleJob('startGuildAuction', `${guildOpen.seconds} ${guildOpen.minute} ${guildOpen.hour} * * ?`, startGuildAuction);
|
||
startWorldAuctionJobId = scheduleJob('startWorldAuction', `${worldOpen.seconds} ${worldOpen.minute} ${worldOpen.hour} * * ?`, startWorldAuction);
|
||
stopAuctionJobId = scheduleJob('stopAuction', `${worldClose.seconds} ${worldClose.minute} ${worldClose.hour} * * ?`, stopAuction);
|
||
sendUngotDividendJobId = scheduleJob('sendUngotDividendJob', '0 0 5 00 * ?', sendUngotDividendJob);
|
||
|
||
}
|
||
|
||
function clearAuctionSchedule() {
|
||
if (startGuildAuctionJobId) {
|
||
startGuildAuctionJobId.cancel();
|
||
startGuildAuctionJobId = undefined;
|
||
}
|
||
if (startWorldAuctionJobId) {
|
||
startWorldAuctionJobId.cancel();
|
||
startWorldAuctionJobId = undefined;
|
||
}
|
||
if (stopAuctionJobId) {
|
||
stopAuctionJobId.cancel();
|
||
stopAuctionJobId = undefined;
|
||
}
|
||
if (sendUngotDividendJobId) {
|
||
sendUngotDividendJobId.cancel();
|
||
sendUngotDividendJobId = undefined;
|
||
}
|
||
} |