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() { console.log('******* init systimer *******') // 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 = 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); pinus.app.rpc.connector.connectorRemote.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; } }