diff --git a/game-server/app.ts b/game-server/app.ts index 2459ff0b7..c033aa3d7 100644 --- a/game-server/app.ts +++ b/game-server/app.ts @@ -193,6 +193,10 @@ async function treatStartLogic(app: _pinus.Application) { initGuildActivityIndexInPinus() .then(resetJoinWoodenHorse); } + if(app.getServerType() == 'battle'|| app.getServerType() == 'role'|| app.getServerType() == 'connector') { + timeTaskService.setPvpSeasonNum(); + timeTaskService.setPvpSettleSeasonNum(); + } if(app.isMaster()) { redisService.initAllRank(); diff --git a/game-server/app/servers/battle/handler/pvpHandler.ts b/game-server/app/servers/battle/handler/pvpHandler.ts index 1f4c62c76..2cc17f22d 100644 --- a/game-server/app/servers/battle/handler/pvpHandler.ts +++ b/game-server/app/servers/battle/handler/pvpHandler.ts @@ -2,7 +2,7 @@ import { Application, BackendSession, pinus, HandlerService, } from 'pinus'; import { findIndex } from 'underscore'; import { gameData, getPvpBoxBySeasonNumAndIndex } from '../../../pubUtils/data'; -import { refreshEnemies, getEnemies, refChallengeCnt, generPVPOppRecInfo, generMyRecInfo, sendLastSeasonRewardIfNotSent, refreshRefOppCnt, generPvpLineupCe, calLineupScore } from '../../../services/pvpService'; +import { refreshEnemies, getEnemies, refChallengeCnt, generPVPOppRecInfo, generMyRecInfo, sendLastSeasonRewardIfNotSent, refreshRefOppCnt, generPvpLineupCe, calLineupScore, checkPvpSeasonIsStart, checkPvpSeasonIsSummit } from '../../../services/pvpService'; import { RoleModel, RoleType } from '../../../db/Role'; import { STATUS } from '../../../consts/statusCode'; import { resResult, genCode, checkRoleIsRobot, robotIdComBack } from '../../../pubUtils/util'; @@ -10,7 +10,7 @@ import { PvpDefenseModel, pvpUpdateInter } from '../../../db/PvpDefense'; import { PvpSeasonResultModel } from '../../../db/PvpSeasonResult'; import { Rank } from '../../../services/rankService'; import { checkTask, checkTaskInPvpEnd } from '../../../services/task/taskService'; -import { Attack, Defense, DefenseHero, PvpDataReturn } from '../../../domain/battleField/pvp'; +import { Attack, Defense, DefenseHero, PvpDataReturn, pvpSaveDataReturn } from '../../../domain/battleField/pvp'; import { DEBUG_MAGIC_WORD, FIGURE_UNLOCK_CONDITION, ITEM_CHANGE_REASON, LINEUP_NUM, REDIS_KEY, TASK_TYPE } from '../../../consts'; import { PVP } from '../../../pubUtils/dicParam'; import { addItems, getGoldObject, handleCost, unlockFigure } from '../../../services/role/rewardService'; @@ -22,6 +22,8 @@ import { PvpRecordModel } from '../../../db/PvpRecord'; import { pvpEndParamInter } from '../../../pubUtils/interface'; import { getSeconds, nowSeconds } from '../../../pubUtils/timeUtil'; import { PlayerDetail, PlayerDetailHero } from '../../../domain/battleField/guild'; +import { PvpSaveDataModel } from '../../../db/PvpSaveData'; +import { PVPConfigModel } from '../../../db/PvpConfig'; export default function (app: Application) { new HandlerService(app, {}); @@ -44,7 +46,9 @@ export class PvpHandler { // 如果没有发过,将上赛季的奖励发下 pvpDefense = await sendLastSeasonRewardIfNotSent(pvpDefense); let seasonNum: number = this.app.get('pvpSeasonNum'); + let seasonStartTime: number = this.app.get('pvpSeasonStartTime'); let seasonEndTime: number = this.app.get('pvpSeasonEndTime'); + let seasonRewardTime: number = this.app.get('pvpSeasonRewardTime'); let update: pvpUpdateInter = { }; let result = new PvpDataReturn(); // 返回对象 @@ -68,17 +72,16 @@ export class PvpHandler { pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, update); } - result.setPvpConfig(seasonNum, seasonEndTime); + result.setPvpConfig(seasonNum, seasonStartTime, seasonEndTime, seasonRewardTime); result.setPvpDefense(pvpDefense); + result.calHasSaveDefense(); let oppPlayersReturn = await getEnemies(pvpDefense.oppPlayers||[], pvpDefense.winStreakNum); result.setOppPlayers(oppPlayersReturn); // 赛季结算 let pvpSeasonResult = await PvpSeasonResultModel.getPvpSeasonResult(roleId); - if (!!pvpSeasonResult && !!pvpSeasonResult.show && pvpDefense.seasonNum == seasonNum) { + if (!!pvpSeasonResult && !!pvpSeasonResult.show) { result.setPvpSeasonResult(pvpSeasonResult); - result.setIsFirstEntry(true); - update.isFirstEntry = false; await PvpSeasonResultModel.setShow(roleId); } // 拍卖 @@ -153,6 +156,9 @@ export class PvpHandler { if (!warInfo) { return resResult(STATUS.BATTLE_MISS_INFO); } + if(!checkPvpSeasonIsStart()) { + return resResult(STATUS.PVP_SEASON_NOT_OPEN); + } let pvpDefense = await PvpDefenseModel.findByRoleId(roleId); if (!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN); @@ -375,6 +381,30 @@ export class PvpHandler { return resResult(STATUS.SUCCESS, pick(result, ['attack', 'oppPlayers', 'buyAttackCnt', 'setAttackCnt', 'challengeCnt', 'challengeRefTime'])); } + // 获取存档列表 + async getSaveData(msg: {}, session: BackendSession) { + let roleId = session.get('roleId'); + let pvpDefense = await PvpDefenseModel.findByRoleId(roleId); + if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN); + + let pvpConfig = await PVPConfigModel.findCurPVPConfig(); + if(!pvpConfig) return resResult(STATUS.PVP_SEASON_NOT_OPEN); + + let saveDatas = await PvpSaveDataModel.findByRoleId(roleId); + + let list: pvpSaveDataReturn[] = []; + for(let warId of (pvpConfig.warIds||[])) { + let data = new pvpSaveDataReturn(warId); + let curSaveData = saveDatas.find(cur => cur.warId == warId); + data.setUserSaveData(curSaveData); + if(pvpDefense.defense?.warId == warId) { + data.setAsUsing(); + } + list.push(data); + } + return resResult(STATUS.SUCCESS, { list }); + } + //3. 保存防守阵容 async saveDefense(msg: { heroes: { actorId: number, dataId: number, order: number, ai: number }[], warId: number, buff: number }, session: BackendSession) { let { heroes, warId, buff } = msg; @@ -382,10 +412,14 @@ export class PvpHandler { if (heroes.length > LINEUP_NUM || heroes.length <= 0) { return resResult(STATUS.WRONG_PARMS); } + if(checkPvpSeasonIsSummit()) { + return resResult(STATUS.PVP_CAN_NOT_SAVE_DEFENSE); + } let pvpDefense = await PvpDefenseModel.findByRoleId(roleId); if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN); // 刷新次数 + let seasonNum: number = this.app.get('pvpSeasonNum'); let seasonEndTime: number = this.app.get('pvpSeasonEndTime'); let refChallengeObj = await refChallengeCnt(pvpDefense.challengeCnt, pvpDefense.challengeRefTime, seasonEndTime, roleId, session.get('vipStartTime')); // 更新防守阵容 @@ -417,8 +451,8 @@ export class PvpHandler { }); let defense = new Defense(defenseHeroes, scores, warId, buff); let lineupCe = await generPvpLineupCe(roleId, pvpDefense.lineupCe, pvpDefense.attack?.heroes??[], defense.heroes, dbHeroes); - - pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { ...refChallengeObj, defense, lineupCe }); + await PvpSaveDataModel.createSaveData(roleId, warId, buff, defenseHeroes); + pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { ...refChallengeObj, defense, lineupCe, hasDefense: true, seasonNum }); // 返回 let result = new PvpDataReturn(); result.setPvpDefense(pvpDefense); @@ -584,10 +618,8 @@ export class PvpHandler { return resResult(STATUS.SUCCESS, { score, hisScore, heroScores }); } - async debugPvpSeasonResetTime(msg: { day: number }, session: BackendSession) { - let { day: minute } = msg; - let { seasonNum, seasonEndTime } = await pinus.app.rpc.systimer.systimerRemote.resetPvpSeasonTime.toServer('systimer-server-1', minute); - return resResult(STATUS.SUCCESS, { seasonNum, seasonEndTime }); + async debugPvpSeasonResetTime(msg: {}, session: BackendSession) { + return resResult(STATUS.DEBUG_FUNCTION_ERR); } async debugAddChallengeCnt(msg: { challengeCnt: number }, session: BackendSession) { diff --git a/game-server/app/servers/battle/remote/battleRemote.ts b/game-server/app/servers/battle/remote/battleRemote.ts index 177192461..94cb84a30 100644 --- a/game-server/app/servers/battle/remote/battleRemote.ts +++ b/game-server/app/servers/battle/remote/battleRemote.ts @@ -1,10 +1,11 @@ -import { Application, ChannelService, FrontendSession, RemoterClass, HandlerService, } from 'pinus'; -import { PVPConfigModel, PVPConfigType } from '../../../db/SystemConfig'; +import { Application, ChannelService, HandlerService, } from 'pinus'; +import { PVPConfigModel, PVPConfigType } from '../../../db/PvpConfig'; import { reloadResources } from '../../../pubUtils/data'; import { setApiIsClose } from '../../../services/chatService'; import { getServerMainten, setServerMainten, stopServerMainten } from '../../../services/gmService'; import { savePvpSeasonMemory } from '../../../services/log/memoryLogService'; import { taflush } from '../../../services/sdkService'; +import { setPvpSeasonNum, setPvpSettleSeasonNum } from '../../../services/timeTaskService'; import { errlogger } from '../../../util/logger'; export default function (app: Application) { @@ -17,7 +18,6 @@ export class BattleRemote { constructor(private app: Application) { this.app = app; this.channelService = app.get('channelService'); - this.initPvpSeasonNum(); } private channelService: ChannelService; @@ -91,26 +91,23 @@ export class BattleRemote { } - public setPvpSeasonNum(pvpConfig: PVPConfigType) { + public async setPvpSettleSeasonNum(pvpConfig: PVPConfigType) { try { - if(pvpConfig) { - this.app.set('pvpSeasonNum', pvpConfig.seasonNum); - this.app.set('pvpSeasonEndTime', pvpConfig.seasonEndTime); - } + await setPvpSettleSeasonNum(pvpConfig); } catch(e) { errlogger.error(`remote ${__filename} \n ${e.stack}`); } } - public async initPvpSeasonNum() { + public async setPvpSeasonNum(pvpConfig: PVPConfigType) { try { - let pvpConfig = await PVPConfigModel.findCurPVPConfig(); - this.setPvpSeasonNum(pvpConfig); + await setPvpSeasonNum(pvpConfig); } catch(e) { errlogger.error(`remote ${__filename} \n ${e.stack}`); } } + public setServerMainten(serverIds: number[], startTime: number, endTime: number) { try { setServerMainten(serverIds, startTime, endTime); diff --git a/game-server/app/servers/connector/remote/connectorRemote.ts b/game-server/app/servers/connector/remote/connectorRemote.ts index d08e27803..82ea1dcc8 100644 --- a/game-server/app/servers/connector/remote/connectorRemote.ts +++ b/game-server/app/servers/connector/remote/connectorRemote.ts @@ -1,10 +1,8 @@ -import { Application, ChannelService, FrontendSession, pinus, RemoterClass, HandlerService, } from 'pinus'; -import { STATUS } from '../../../consts/statusCode'; -import { resResult } from '../../../pubUtils/util'; +import { Application, HandlerService, } from 'pinus'; import { reloadResources } from '../../../pubUtils/data'; import { UserGuildType } from '../../../db/UserGuild'; import { incServerNum, kickUser } from '../../../services/connectorService'; -import { PVPConfigModel, PVPConfigType } from '../../../db/SystemConfig'; +import { PVPConfigModel, PVPConfigType } from '../../../db/PvpConfig'; import { setDicAuctionTime, setDicGuildActivity } from '../../../services/guildActivity/guildActivityService'; import { getServerMainten, setServerMainten, stopServerMainten } from '../../../services/gmService'; import { taflush } from '../../../services/sdkService'; @@ -12,6 +10,7 @@ import { errlogger } from '../../../util/logger'; import { setWeek } from '../../../pubUtils/timeUtil'; import { savePvpSeasonMemory } from '../../../services/log/memoryLogService'; import { setApiIsClose } from '../../../services/chatService'; +import { setPvpSeasonNum, setPvpSettleSeasonNum } from '../../../services/timeTaskService'; export default function (app: Application) { new HandlerService(app, {}); return new ConnectorRemote(app); @@ -21,7 +20,6 @@ export class ConnectorRemote { constructor(private app: Application) { this.app = app; - this.initPvpSeasonNum(); } public async remoteLogin(uid: string, message?: any) { @@ -105,21 +103,17 @@ export class ConnectorRemote { } } - public setPvpSeasonNum(pvpConfig: PVPConfigType) { + public async setPvpSeasonNum(pvpConfig: PVPConfigType) { try { - if(pvpConfig) { - this.app.set('pvpSeasonNum', pvpConfig.seasonNum); - this.app.set('pvpSeasonEndTime', pvpConfig.seasonEndTime); - } + await setPvpSeasonNum(pvpConfig); } catch(e) { errlogger.error(`remote ${__filename} \n ${e.stack}`); } } - public async initPvpSeasonNum() { + public async setPvpSettleSeasonNum(pvpConfig: PVPConfigType) { try { - let pvpConfig = await PVPConfigModel.findCurPVPConfig(); - this.setPvpSeasonNum(pvpConfig); + await setPvpSettleSeasonNum(pvpConfig); } catch(e) { errlogger.error(`remote ${__filename} \n ${e.stack}`); } diff --git a/game-server/app/servers/gm/handler/gmServerHandler.ts b/game-server/app/servers/gm/handler/gmServerHandler.ts index a4a0f6617..e70fb0e8e 100644 --- a/game-server/app/servers/gm/handler/gmServerHandler.ts +++ b/game-server/app/servers/gm/handler/gmServerHandler.ts @@ -2,7 +2,7 @@ import { Application, BackendSession, pinus } from 'pinus'; import { genCode, getRandSingleEelm, resResult } from '../../../pubUtils/util'; import { STATUS } from '../../../consts/statusCode'; import moment = require('moment'); -import { CreateServerParam, UpdateRegionParams } from '../../../domain/backEndField/params'; +import { CreatePvpConfigParam, CreateServerParam, UpdateRegionParams } from '../../../domain/backEndField/params'; import { RegionModel, RegionType } from '../../../db/Region'; import { gameData } from '../../../pubUtils/data'; import { Maintenance, ServerlistModel, ServerlistUpdate } from '../../../db/Serverlist'; @@ -11,6 +11,7 @@ import { createNewServer, sendOpenServerMail } from '../../../services/gmService import { isNumber } from 'util'; import { MarqueeModel } from '../../../db/Marquee'; import { setApiIsCloseToRemote } from '../../../services/chatService'; +import { PVPConfigModel } from '../../../db/PvpConfig'; export default function (app: Application) { return new GmHandler(app); @@ -180,4 +181,21 @@ export class GmHandler { setApiIsCloseToRemote(region.isCloseApi); return resResult(STATUS.SUCCESS); } + + async savePvpConfig(msg: CreatePvpConfigParam, session: BackendSession) { + let params = new CreatePvpConfigParam(msg); + if(!params.checkParams()) return resResult(STATUS.WRONG_PARMS); + if(params.seasonStartTime >= params.seasonEndTime) return resResult(STATUS.WRONG_PARMS, null, '开始时间不可晚于结束时间'); + if(params.seasonEndTime >= params.seasonRewardTime) return resResult(STATUS.WRONG_PARMS, null, '结束时间不可晚于奖励时间'); + + if(await PVPConfigModel.checkTime(params.seasonNum, params.seasonStartTime, params.seasonRewardTime)) { + return resResult(STATUS.WRONG_PARMS, null, '不可与其他赛季时间重叠'); + } + + let uid = session.get('uid'); + await PVPConfigModel.createPVPConfig(params.seasonNum, params.getUpdateParam(), uid); + pinus.app.rpc.systimer.systimerRemote.setPvpSeasonSchedule.broadcast(true); + + return resResult(STATUS.SUCCESS); + } } \ No newline at end of file diff --git a/game-server/app/servers/role/handler/shopHandler.ts b/game-server/app/servers/role/handler/shopHandler.ts index 805d3a76b..cf154bd3a 100644 --- a/game-server/app/servers/role/handler/shopHandler.ts +++ b/game-server/app/servers/role/handler/shopHandler.ts @@ -1,4 +1,4 @@ -import { Application, BackendSession } from "pinus"; +import { Application, BackendSession, pinus } from "pinus"; import { gameData, hasShopType } from "../../../pubUtils/data"; import { parseGoodStr, resResult } from "../../../pubUtils/util"; import { STATUS, GUILD_STRUCTURE, ITID, CONSUME_TYPE, HERO_QUALITY_TYPE, HERO_GROW_MAX, ITEM_CHANGE_REASON } from "../../../consts"; @@ -51,6 +51,7 @@ export class ShopHandler { let roleName = session.get('roleName'); let sid = session.get('sid'); let serverId = session.get('serverId'); + let seasonNum = pinus.app.get('pvpSeasonNum'); let { activityId = 0, shopItemId, count } = msg; @@ -58,7 +59,7 @@ export class ShopHandler { if(!dicShopItem) return resResult(STATUS.DIC_DATA_NOT_FOUND); if(dicShopItem['productID'] && dicShopItem['productID'] != '&') return resResult(STATUS.CAN_NOT_PURCHASE); - let userShop = await UserShopModel.findByRoleAndItem(roleId, activityId, dicShopItem); + let userShop = await UserShopModel.findByRoleAndItem(roleId, activityId, dicShopItem, seasonNum); let checkResult = await checkShopInPurchase(session, activityId, count, userShop?.count||0, dicShopItem); if(checkResult.code != STATUS.SUCCESS.code) { @@ -71,7 +72,7 @@ export class ShopHandler { if(!costResult) return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH); // 次数 - userShop = await UserShopModel.purchase(roleId, roleName, activityId, dicShopItem, count); + userShop = await UserShopModel.purchase(roleId, roleName, activityId, dicShopItem, count, seasonNum); if(!userShop) return resResult(STATUS.BUY_COUNT_OVER); // 获得 diff --git a/game-server/app/servers/role/remote/roleRemote.ts b/game-server/app/servers/role/remote/roleRemote.ts index c5a694277..900823a3d 100644 --- a/game-server/app/servers/role/remote/roleRemote.ts +++ b/game-server/app/servers/role/remote/roleRemote.ts @@ -1,16 +1,13 @@ import { Application, ChannelService, HandlerService, } from 'pinus'; // import { sendRolesMails } from '../../../services/mailService'; import { reloadResources } from '../../../pubUtils/data'; -import { HeroUpdate } from '../../../db/Hero'; -import { RoleUpdate } from '../../../db/Role'; -import { SkinUpdate } from '../../../db/Skin'; import { RankFirstModel, RankFirstType } from '../../../db/RankFirst'; -import { Figure } from '../../../domain/dbGeneral'; -import { PVPConfigModel, PVPConfigType } from '../../../db/SystemConfig'; +import { PVPConfigModel, PVPConfigType } from '../../../db/PvpConfig'; import { treatRoleName, taflush, sendSurveyMail } from '../../../services/sdkService'; import { getServerMainten, setServerMainten, stopServerMainten } from '../../../services/gmService'; import { errlogger } from '../../../util/logger'; import { setApiIsClose } from '../../../services/chatService'; +import { setPvpSeasonNum, setPvpSettleSeasonNum } from '../../../services/timeTaskService'; export default function (app: Application) { new HandlerService(app, {}); @@ -23,7 +20,6 @@ export class RoleRemote { this.app = app; // this.channelService = app.get('channelService'); this.loadRankFirst(); - this.initPvpSeasonNum(); } // private channelService: ChannelService; @@ -74,21 +70,17 @@ export class RoleRemote { } - public setPvpSeasonNum(pvpConfig: PVPConfigType) { + public async setPvpSeasonNum(pvpConfig: PVPConfigType) { try { - if(pvpConfig) { - this.app.set('pvpSeasonNum', pvpConfig.seasonNum); - this.app.set('pvpSeasonEndTime', pvpConfig.seasonEndTime); - } + await setPvpSeasonNum(pvpConfig); } catch(e) { errlogger.error(`remote ${__filename} \n ${e.stack}`); } } - public async initPvpSeasonNum() { + public async setPvpSettleSeasonNum(pvpConfig: PVPConfigType) { try { - let pvpConfig = await PVPConfigModel.findCurPVPConfig(); - this.setPvpSeasonNum(pvpConfig); + await setPvpSettleSeasonNum(pvpConfig); } catch(e) { errlogger.error(`remote ${__filename} \n ${e.stack}`); } diff --git a/game-server/app/servers/systimer/remote/systimerRemote.ts b/game-server/app/servers/systimer/remote/systimerRemote.ts index c9f7082b1..464ba285d 100644 --- a/game-server/app/servers/systimer/remote/systimerRemote.ts +++ b/game-server/app/servers/systimer/remote/systimerRemote.ts @@ -1,5 +1,5 @@ import { Application, ChannelService } from 'pinus'; -import { resetPvpSeasonTime, guildActivityStart, gateActivityEnd, cityActivityEnd, raceActivityEnd, guildActivitySchedule, auctionSchedule, initMaintenance, stopMaintenance, initAutoCreateServer, addMailsToSchedule, updateTimeLimitRank, setLadderCountDown, cancelLadderCountDown, initSumSchedule } from '../../../services/timeTaskService'; +import { guildActivityStart, gateActivityEnd, cityActivityEnd, raceActivityEnd, guildActivitySchedule, auctionSchedule, initMaintenance, stopMaintenance, initAutoCreateServer, addMailsToSchedule, updateTimeLimitRank, setLadderCountDown, cancelLadderCountDown, initSumSchedule, setPvpSeasonSchedule } from '../../../services/timeTaskService'; import PvpDefenseType from '../../../db/PvpDefense'; import { DicGuildActivity } from '../../../pubUtils/dictionary/DicGuildActivity'; import { reloadResources } from '../../../pubUtils/data'; @@ -30,14 +30,6 @@ export class SystimerRemote { } private channelService: ChannelService; - public async resetPvpSeasonTime(day: number) { - try { - return await resetPvpSeasonTime(day); - } catch(e) { - errlogger.error(`remote ${__filename} \n ${e.stack}`); - } - } - public async guildActivityStart(dicGuildActivity: DicGuildActivity) { try { return await guildActivityStart(dicGuildActivity); @@ -232,4 +224,12 @@ export class SystimerRemote { errlogger.error(`remote ${__filename} \n ${e.stack}`); } } + + public async setPvpSeasonSchedule(fromBackend: boolean) { + try { + setPvpSeasonSchedule(fromBackend); + } catch(e) { + errlogger.error(`remote ${__filename} \n ${e.stack}`); + } + } } diff --git a/game-server/app/services/connectorService.ts b/game-server/app/services/connectorService.ts index 84e7f3732..0d3f8ecdd 100644 --- a/game-server/app/services/connectorService.ts +++ b/game-server/app/services/connectorService.ts @@ -48,6 +48,7 @@ import { ComBattleTeamModel } from '../db/ComBattleTeam'; import { INFO_WINDOW } from '../pubUtils/dicParam'; import { getLadderData } from './ladderService'; import { dispatch } from '../pubUtils/dispatcher'; +import { PvpDataReturn } from '../domain/battleField/pvp'; /** * init: 初始的时候是否推送 true-推 false-不推 @@ -260,11 +261,17 @@ async function getPvpEntryData(roleId: string) { pvpDefense = await sendLastSeasonRewardIfNotSent(pvpDefense); let seasonNum: number = pinus.app.get('pvpSeasonNum'); let seasonEndTime: number = pinus.app.get('pvpSeasonEndTime'); + let seasonStartTime: number = pinus.app.get('pvpSeasonStartTime'); + let seasonRewardTime: number = pinus.app.get('pvpSeasonRewardTime'); + + let result = new PvpDataReturn(); // 返回对象 + result.setPvpConfig(seasonNum, seasonStartTime, seasonEndTime, seasonRewardTime); + result.setPvpDefense(pvpDefense); + result.calHasSaveDefense(); let refChallengeObj = await refChallengeCnt(pvpDefense.challengeCnt, pvpDefense.challengeRefTime, seasonEndTime, roleId); let { challengeCnt } = refChallengeObj; - let { receivedBox, score, seasonWinNum } = pvpDefense; - - return { challengeCnt, score, seasonWinNum, receivedBox, seasonNum, seasonEndTime } + result.setChallengeCnt(challengeCnt); + return pick(result, ['challengeCnt', 'score', 'seasonWinNum', 'receivedBox', 'hasSaveDefense', 'seasonNum', 'seasonEndTime', 'seasonStartTime', 'seasonRewardTime']) } else { return null } diff --git a/game-server/app/services/guildService.ts b/game-server/app/services/guildService.ts index 9a5694e93..dc32ee013 100644 --- a/game-server/app/services/guildService.ts +++ b/game-server/app/services/guildService.ts @@ -5,7 +5,6 @@ import { STATUS, MAIL_TYPE, GUILD_AUTH, GUILD_JOB, REDIS_KEY, CHAT_SERVER, TASK_ import { RoleModel, RoleType } from "../db/Role"; import { UserGuildModel, UserGuildType, WishGood } from "../db/UserGuild"; import { UserGuildApplyModel } from "../db/UserGuildApply"; -import { PVPConfigModel } from "../db/SystemConfig"; import { getZeroPointD, getZeroPointOfTime, getZeroPointOfTimeD, nowSeconds } from "../pubUtils/timeUtil"; import { pinus, BackendSession, FrontendOrBackendSession } from "pinus"; import { ARMY } from "../pubUtils/dicParam"; diff --git a/game-server/app/services/pvpService.ts b/game-server/app/services/pvpService.ts index 8121193b2..4ee1bffd3 100644 --- a/game-server/app/services/pvpService.ts +++ b/game-server/app/services/pvpService.ts @@ -2,23 +2,21 @@ import { PvpDefenseModel, PvpDefenseType, pvpUpdateInter } from '../db/PvpDefense'; import { Defense, Attack, LineupCe, OppPlayer, HeroScore, HeroReward, OppPlayerReturn, AttackHero, DefenseHero } from '../domain/battleField/pvp'; import { RoleType } from '../db/Role'; -import { REDIS_KEY, TASK_TYPE, MAIL_TYPE, TA_EVENT, ITID, getHeadItid, getFrameItid, getSpineItid } from '../consts'; +import { REDIS_KEY, TASK_TYPE, MAIL_TYPE, TA_EVENT, ITID, getHeadItid, getFrameItid, getSpineItid, PVP_SEASON_STATUS } from '../consts'; import { dicPvpOpponent, DicPvpOpponent } from "../pubUtils/dictionary/DicPvpOpponent"; import { getRandSingleIndex, genCode, shouldRefresh, getChineseName, makeRobotId, robotIdComBack, getRandSingleEelm } from '../pubUtils/util'; import { pvpEndParamInter, RewardInter } from '../pubUtils/interface'; import { gameData, getPLvByScore, getPvpHeroRewardsByScore, getPvpRankRewardsByRank, getPvpDifficultByScore, getPlvAndScore, getPvpBoxsBySeasonNum, getPvpRankMaxRewardsBySeasonNum, randomGoodsByItid } from "../pubUtils/data"; import { EXTERIOR, PVP } from '../pubUtils/dicParam'; -import { PVPConfigModel, PVPConfigType } from '../db/SystemConfig' +import { PVPConfigModel } from '../db/PvpConfig' import { nowSeconds, getTimeFun } from '../pubUtils/timeUtil'; import { HeroesRecord, PvpRecordPlayerInfo } from '../db/PvpRecord'; import { HeroModel, HeroType } from '../db/Hero'; import { AttributeCal } from '../domain/roleField/attribute'; import { PvpEnemies, PvpHeroInfo, PvpOtherHeroes } from '../domain/dbGeneral'; -import { DicWarJson } from '../pubUtils/dictionary/DicWarJson'; import { pinus } from 'pinus'; import { PvpHistoryOppModel, PvpHistoryOppType, PvpOppCreateParam } from '../db/PvpHistoryOpp'; import { Rank } from './rankService'; -import { CounterModel } from '../db/Counter'; import { DicRankRewads } from '../pubUtils/dictionary/DicPvpRankReward'; import { PvpSeasonResultModel, PvpSeasonResultType } from '../db/PvpSeasonResult'; import { checkTask } from './task/taskService'; @@ -27,6 +25,7 @@ import { RoleRankInfo } from '../domain/rank'; import { reportTAEvent } from './sdkService'; import { getVipPvpChallengeMaxCnt } from './activity/monthlyTicketService'; import { getHeroesAttributes } from './playerCeService'; +import { setPvpSeasonNumToRemote, setPvpSettleSeasonNumToRemote } from './timeTaskService'; /** * 返回对手三人信息 @@ -166,7 +165,7 @@ export async function matchPlayerByRank(seasonNum: number, chosenOpps: string[], oppRoleId = result[0]; let pvpdefense = await PvpDefenseModel.findByRoleIdIncludeAll(oppRoleId); - if (!pvpdefense || pvpdefense.seasonNum != seasonNum) return null; + if (!pvpdefense || pvpdefense.seasonNum != seasonNum || !pvpdefense.hasDefense) return null; let pvpHistoryOpp = await generPlayerOppHis(pvpdefense, roleId, pos); if (!pvpHistoryOpp) return null; @@ -367,15 +366,21 @@ export async function comsumeChallengeCnt(challengeCnt: number, challengeRefTime } export async function sendLastSeasonRewardIfNotSent(pvpDefense: PvpDefenseType) { - let seasonNum: number = pinus.app.get('pvpSeasonNum'); - if(pvpDefense.seasonNum < seasonNum) { - let oldPvpCongig = await PVPConfigModel.findPVPConfig(pvpDefense.seasonNum); - let result = await sendPVPRewardToUser(pvpDefense, pvpDefense.seasonNum, oldPvpCongig.seasonEndTime); + let seasonSettleNum: number = pinus.app.get('pvpSettleSeasonNum'); + console.log('##### sendLastSeasonRewardIfNotSent seasonSettleNum', seasonSettleNum) + if(seasonSettleNum && !await checkHasSettled(seasonSettleNum, pvpDefense.roleId)) { + let oldPvpCongig = await PVPConfigModel.findPVPConfig(seasonSettleNum); + let result = await sendPVPRewardToUser(pvpDefense, seasonSettleNum, oldPvpCongig.seasonEndTime); pvpDefense = result.pvpDefense; } return pvpDefense; } +async function checkHasSettled(seasonSettleNum: number, roleId: string) { + let hasData = await PvpSeasonResultModel.checkResultBySeasonNum(roleId, seasonSettleNum); + return hasData; +} + // 获取刷新对手次数及消耗 export function refreshRefOppCnt(pvpDefense: PvpDefenseType) { let { refOppCnt = 0, setAttackCnt = 0, buyAttackCnt = 0, refDaily } = pvpDefense; @@ -563,7 +568,8 @@ export async function generPVPOppRecInfo(isSuccess: boolean, curOpp: OppPlayer, let { pvpSeasonResult } = await sendPVPRewardToUser(pvpDefense, pvpConfig.seasonNum, pvpConfig.seasonEndTime); reportTAEvent(roleId, TA_EVENT.PVP_SEASON_END, { top_rank: rank, hero_score: pvpSeasonResult.heroScores }) } - await PVPConfigModel.setReward(pvpConfig.seasonNum); + let settledPvpConfig = await PVPConfigModel.setReward(pvpConfig.seasonNum); + await setPvpSettleSeasonNumToRemote(settledPvpConfig); } /** @@ -593,7 +599,7 @@ export async function sendPVPRewardToUser(pvpDefense: PvpDefenseType, seasonNum: return { pvpSeasonResult, - pvpDefense: await resetPvpScores(pvpDefense, seasonNum + 1, pvpSeasonResult) + pvpDefense: await resetPvpScores(pvpDefense, pvpSeasonResult) } } @@ -612,17 +618,16 @@ async function sendUnreceivedPvpBox(roleId: string, seasonNum: number, seasonWin } } -async function resetPvpScores(pvpDefense: PvpDefenseType, seasonNum: number, pvpSeasonResult: PvpSeasonResultType) { - let { roleId, attack, defense } = pvpDefense; +async function resetPvpScores(pvpDefense: PvpDefenseType, pvpSeasonResult: PvpSeasonResultType) { + let { roleId, attack } = pvpDefense; let { newHeroScores, newScore } = pvpSeasonResult; let initCount = await getVipPvpChallengeMaxCnt(roleId) let newAttack = calLineupScore(attack, newHeroScores); - let newDefense = calLineupScore(defense, newHeroScores); pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { - heroScores: newHeroScores, score: newScore, attack: newAttack, defense: newDefense, - seasonNum, challengeCnt: initCount, challengeRefTime: 0, winStreakNum: 0, isFirstEntry: true, + heroScores: newHeroScores, score: newScore, attack: newAttack, defense: null, hasDefense: false, + challengeCnt: initCount, challengeRefTime: 0, winStreakNum: 0, seasonWinNum: 0, receivedBox: [] }); return pvpDefense; @@ -664,8 +669,9 @@ export async function savePvpSeasonResult(pvpDefense: PvpDefenseType, seasonNum: } //pvp锁定的信息存入赛季结算表中 + let {receivedBox, score, seasonWinNum, heroScores } = pvpDefense; let pvpSeasonResult = await PvpSeasonResultModel.updatePvpSeasonResult(pvpDefense.roleId, seasonNum, { - ...pvpDefense, rankLv, heroGoods, rankGoods, show: true, newScore, newHeroScores, seasonEndTime + receivedBox, score, seasonWinNum, heroScores, rankLv, heroGoods, rankGoods, show: true, newScore, newHeroScores, seasonEndTime });//结算修改玩家pvp信息 if(newScore > 0) { let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum: seasonNum + 1 }); @@ -702,4 +708,29 @@ export async function generPvpLineupCe(roleId: string, lineupCe: LineupCe[], att newLineupCe.push({ hid, ce }); } return newLineupCe; +} + + +export function getPvpSeasonStatus() { + let seasonEndTime: number = pinus.app.get('pvpSeasonEndTime'); + let seasonStartTime: number = pinus.app.get('pvpSeasonStartTime'); + let seasonRewardTime: number = pinus.app.get('pvpSeasonRewardTime'); + let now = nowSeconds(); + if(now >= seasonStartTime && now < seasonEndTime) { + return PVP_SEASON_STATUS.START; + } else if (now >= seasonEndTime && now < seasonRewardTime) { + return PVP_SEASON_STATUS.SUMMIT; + } else { + return PVP_SEASON_STATUS.WAITING; + } +} + +export function checkPvpSeasonIsStart() { + let status = getPvpSeasonStatus(); + return status == PVP_SEASON_STATUS.START; +} + +export function checkPvpSeasonIsSummit() { + let status = getPvpSeasonStatus(); + return status == PVP_SEASON_STATUS.SUMMIT; } \ No newline at end of file diff --git a/game-server/app/services/shopService.ts b/game-server/app/services/shopService.ts index 985331b60..055c0c747 100644 --- a/game-server/app/services/shopService.ts +++ b/game-server/app/services/shopService.ts @@ -9,13 +9,14 @@ import { UserShopTypeModel, UserShopTypeType } from "../db/UserShopType"; import { GuildModel } from "../db/Guild"; import { RoleModel } from "../db/Role"; import { DicShop } from "../pubUtils/dictionary/DicShop"; -import { BackendSession } from "pinus"; +import { BackendSession, pinus } from "pinus"; import { ActivityModelType } from "../db/Activity"; import { addItems } from "./role/rewardService"; import { LadderMatchModel } from "../db/LadderMatch"; export async function getAllShopList(roleId: string, serverId: number) { - let userShopRecs = await UserShopModel.findByRoleId(roleId); + let seasonNum = pinus.app.get('pvpSeasonNum'); + let userShopRecs = await UserShopModel.findByRoleId(roleId, seasonNum); let userShopTypeRecs = await UserShopTypeModel.findByRoleId(roleId); let activities = await getShopActivityDatas(roleId, serverId); @@ -30,7 +31,8 @@ export async function getAllShopList(roleId: string, serverId: number) { } export async function getShopListByType(shop: number, type: number, roleId: string, serverId: number) { - let userShopRecs = await UserShopModel.findByShopType(roleId, shop, type); + let seasonNum = pinus.app.get('pvpSeasonNum'); + let userShopRecs = await UserShopModel.findByShopType(roleId, shop, type, seasonNum); let activities = await getShopActivityDatas(roleId, serverId); let activity = activities.find(cur => cur.shop == shop && cur.type == type); let readRecord = await UserShopTypeModel.findByType(roleId, shop, type); @@ -128,6 +130,7 @@ export async function checkShopInPurchase(session: BackendSession, activityId: n } export async function checkShopCanBuyInOrder(roleId: string, serverId: number, activity: ActivityModelType, productID: string) { + let seasonNum = pinus.app.get('pvpSeasonNum'); let role = await RoleModel.findByRoleId(roleId, 'guildCode createTime vipStartTime'); let { createTime, guildCode, vipStartTime } = role; let serverTime = await getServerCreateTime(serverId); @@ -136,7 +139,7 @@ export async function checkShopCanBuyInOrder(roleId: string, serverId: number, a let dicItem = shopData.findByProductID(productID); if(!dicItem) return false; - let userShop = await UserShopModel.findByRoleAndItem(roleId, activity.activityId, dicItem); + let userShop = await UserShopModel.findByRoleAndItem(roleId, activity.activityId, dicItem, seasonNum); let result = await checkShopItemCanBuy(activity.activityId, dicItem.id, roleId, serverId, guildCode, vipStartTime, 1, userShop?.count||0, dicItem); return result.code == STATUS.SUCCESS.code; } @@ -188,6 +191,7 @@ export async function checkShopItemCanBuy(activityId: number, shopItemId: number * */ export async function makeShopOrder(roleId: string, roleName: string, sid: string, serverId: number, activityId: number, productID: string) { + let seasonNum = pinus.app.get('pvpSeasonNum'); let activityData: ActivityModelType = await getActivityById(activityId); if (!activityData) { return STATUS.ACTIVITY_MISSING; @@ -206,7 +210,7 @@ export async function checkShopItemCanBuy(activityId: number, shopItemId: number }]; await addItems(roleId, roleName, sid, reward, ITEM_CHANGE_REASON.SHOP_PURCHASE); - await UserShopModel.purchase(roleId, roleName, activityId, dicItem, 1); + await UserShopModel.purchase(roleId, roleName, activityId, dicItem, 1, seasonNum); return { code: 0, data: Object.assign({}, { item: { shop: dicItem.shop, type: dicItem.type, shopItemId: dicItem.id }, activityId: activityId }) diff --git a/game-server/app/services/timeTaskService.ts b/game-server/app/services/timeTaskService.ts index 6c21902b1..31257a3db 100644 --- a/game-server/app/services/timeTaskService.ts +++ b/game-server/app/services/timeTaskService.ts @@ -1,6 +1,6 @@ import { scheduleJob, Job, scheduledJobs, } from 'node-schedule'; -import { PVPConfigModel, PVPConfigType } from '../db/SystemConfig'; +import { PVPConfigModel, PVPConfigType } from '../db/PvpConfig'; import { nowSeconds, getTimeFun, getSeconds } from '../pubUtils/timeUtil'; import { getTodayGuildActivity, gameData } from '../pubUtils/data'; import { pvpSeasonEnd } from './pvpService'; @@ -46,6 +46,7 @@ const PER_SECOND = 1 * 1000; const PER_DAY = 24 * 60 * 60; const PER_HOUR = 1 * 60 * 60; const PER_MINUTE = 1 * 60; +var seasonEndJob: Job; var seasonMakeRewardTimJobId: Job; var seasonRefreshTimeJobId: Job; let guildWeeklyJobId: Job; @@ -61,7 +62,7 @@ export async function init() { console.log('******* init systimer *******') // pvp赛季 - await setPvpSeason(true); + await setPvpSeasonSchedule(); // 周功勋结算任务 guildWeeklyJobId = scheduleJob('settleGuildWeekly', '0 0 0 * * 1', settleGuildWeekly); @@ -115,111 +116,115 @@ export async function everydayRefresh() { // —————————————— PVP 及赛季相关 —————————————— // -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; +export async function setPvpSeasonSchedule(fromBackend = false) { + let pvpConfig = await PVPConfigModel.setCurrentPvp(); + await setSeasonEndJob(pvpConfig); + await setPvpSeasonMakeRewardJob(pvpConfig); // 发送奖励定时器 + await setNextSeasonJob(pvpConfig); // 赛季开始定时器 + if(fromBackend) { + setPvpSeasonNumToRemote(pvpConfig); + setPvpSettleSeasonNumToRemote(); + } else { + setPvpSeasonNum(pvpConfig); + setPvpSettleSeasonNum(); } - return maxDay; } -async function setPvpSeasonJob() { - await setPvpSeason(false); -} - -async function setPvpSeason(isFirst: boolean, isForce?: boolean, minute?: number) { - console.log(`******** setPvpSeason1: isForce-${isForce}, minute-${minute}`) - - let during = minute? minute * PER_MINUTE: null; // 下一次重置赛季天数 - let oldPvpConfig = await PVPConfigModel.findCurPVPConfig(); - let pvpConfig = oldPvpConfig; - console.log(`******** setPvpSeason2: during-${during}, seasonEndTime-${pvpConfig?.seasonEndTime}, now-${nowSeconds()}`) - if(!pvpConfig || pvpConfig.seasonEndTime - PER_MINUTE <= nowSeconds() || isForce) { - if(pvpConfig && !pvpConfig.hasSettleReward) { - await pvpSeasonEnd(pvpConfig.seasonNum); - } - - let lastSeasonNum = pvpConfig? pvpConfig.seasonNum: 0; - let lastSeasonEndTime = pvpConfig? pvpConfig.seasonEndTime: 0; - console.log(`******** setPvpSeason3: lastSeasonNum-${lastSeasonNum}, lastSeasonEndTime-${lastSeasonEndTime}`) - - let newSeasonStartTime = lastSeasonEndTime; - if(!during) during = getSeasonContinueDay(lastSeasonNum + 1) * PER_DAY; - let rewardTime = PVP.PVP_SEASON_REWARD_TIME_BEFORE * PER_MINUTE; - 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); +async function setSeasonEndJob(pvpConfig: PVPConfigType) { + if (!!seasonEndJob) { + seasonEndJob.cancel(); } - await setPvpSeasonMakeRewardJob(pvpConfig); - await setNextSeasonJob(pvpConfig); - setPvpSeasonNum(pvpConfig, isFirst); - return pvpConfig; -} -function setPvpSeasonNum(pvpConfig: PVPConfigType, isFirst = false) { - if(pvpConfig) { - pinus.app.set('pvpSeasonNum', pvpConfig.seasonNum); - pinus.app.set('pvpSeasonEndTime', pvpConfig.seasonEndTime); - if(!isFirst) { - pinus.app.rpc.battle.battleRemote.setPvpSeasonNum.broadcast(pvpConfig); - pinus.app.rpc.role.roleRemote.setPvpSeasonNum.broadcast(pvpConfig); - pinus.app.rpc.connector.connectorRemote.setPvpSeasonNum.broadcast(pvpConfig); - } + if(!pvpConfig || pvpConfig.seasonEndTime < nowSeconds()) { + pvpConfig = await PVPConfigModel.findPVPConfig(pvpConfig? pvpConfig.seasonNum + 1: 1); + if(!pvpConfig) return; } + console.log('####### setSeasonEndJob', JSON.stringify(pvpConfig)) + + seasonEndJob = scheduleJob('seasonEndJob', pvpConfig.seasonEndTime * 1000, async () => { + console.log('************ setSeasonEndJob *********'); + setPvpSeasonNumToRemote(pvpConfig); + let nextPvpConfig = await PVPConfigModel.findPVPConfig(pvpConfig.seasonNum + 1); + await setSeasonEndJob(nextPvpConfig); + }); } async function setPvpSeasonMakeRewardJob(pvpConfig: PVPConfigType) { if (!!seasonMakeRewardTimJobId) { seasonMakeRewardTimJobId.cancel(); } - if(!pvpConfig) return; - if(pvpConfig.seasonRewardTime < nowSeconds() && !pvpConfig.hasSettleReward) { // 未发奖励 - await pvpSeasonEnd(pvpConfig.seasonNum); - } else { - seasonMakeRewardTimJobId = scheduleJob('seasonMakeRewardTimJobId', pvpConfig.seasonRewardTime * 1000, async () => { - console.log('************ seasonMakeRewardTimJobId *********'); - await pvpSeasonEnd(pvpConfig.seasonNum); - }); + if(!pvpConfig || pvpConfig.seasonRewardTime - 60 < nowSeconds()) { + pvpConfig = await PVPConfigModel.findPVPConfig(pvpConfig? pvpConfig.seasonNum + 1: 1); + if(!pvpConfig) return; } + console.log('####### setPvpSeasonMakeRewardJob', JSON.stringify(pvpConfig)) + seasonMakeRewardTimJobId = scheduleJob('seasonMakeRewardTimJobId', pvpConfig.seasonRewardTime * 1000 - 60 * 1000, async () => { + console.log('************ seasonMakeRewardTimJobId *********'); + await pvpSeasonEnd(pvpConfig.seasonNum); + let nextPvpConfig = await PVPConfigModel.findPVPConfig(pvpConfig.seasonNum + 1); + await setPvpSeasonMakeRewardJob(nextPvpConfig); + }); } async function setNextSeasonJob(pvpConfig: PVPConfigType) { if (!!seasonRefreshTimeJobId) { seasonRefreshTimeJobId.cancel(); } - //定时开启新赛季,比seasonEndTime多定一分钟,保证定时器时间没错 - seasonRefreshTimeJobId = scheduleJob('seasonRefreshTimeJobId', (pvpConfig.seasonEndTime) * 1000, setPvpSeasonJob); + if(!pvpConfig || pvpConfig.seasonStartTime < nowSeconds()) { + pvpConfig = await PVPConfigModel.findPVPConfig(pvpConfig? pvpConfig.seasonNum + 1: 1); + if(!pvpConfig) return; + } + console.log('####### setNextSeasonJob', JSON.stringify(pvpConfig)) + + seasonRefreshTimeJobId = scheduleJob('seasonRefreshTimeJobId', pvpConfig.seasonStartTime * 1000, async () => { + console.log('************ setNextSeasonJob *********'); + setPvpSeasonNumToRemote(pvpConfig); + await PVPConfigModel.setNextPvp(pvpConfig.seasonNum); + let nextPvpConfig = await PVPConfigModel.findPVPConfig(pvpConfig.seasonNum + 1); + await setNextSeasonJob(nextPvpConfig); + }); } -/** - * debug接口 - * @param hour - */ -export async function resetPvpSeasonTime(minute: number) { - return await setPvpSeason(false, true, minute); +export async function setPvpSeasonNumToRemote(pvpConfig: PVPConfigType) { + await setPvpSeasonNum(pvpConfig); + await pinus.app.rpc.battle.battleRemote.setPvpSeasonNum.broadcast(pvpConfig); + await pinus.app.rpc.role.roleRemote.setPvpSeasonNum.broadcast(pvpConfig); + await pinus.app.rpc.connector.connectorRemote.setPvpSeasonNum.broadcast(pvpConfig); +} + +export async function setPvpSeasonNum(pvpConfig?: PVPConfigType) { + if(!pvpConfig) { + pvpConfig = await PVPConfigModel.findCurPVPConfig(); + if(!pvpConfig) return; + } + + let now = nowSeconds(); + pinus.app.set('pvpSeasonNum', pvpConfig.seasonNum); + pinus.app.set('pvpSeasonStartTime', pvpConfig.seasonStartTime); + pinus.app.set('pvpSeasonEndTime', pvpConfig.seasonEndTime); + pinus.app.set('pvpSeasonRewardTime', pvpConfig.seasonRewardTime); + if(pvpConfig.seasonEndTime <= now) { // 赛季结束,需要显示下一赛季的倒计时 + let nextPvpConfig = await PVPConfigModel.findPVPConfig(pvpConfig.seasonNum + 1); + if(nextPvpConfig) { + pinus.app.set('pvpSeasonStartTime', nextPvpConfig.seasonStartTime); + } + } +} + +export async function setPvpSettleSeasonNumToRemote(settledPvpConfig?: PVPConfigType) { + setPvpSettleSeasonNum(settledPvpConfig); + await pinus.app.rpc.battle.battleRemote.setPvpSettleSeasonNum.broadcast(settledPvpConfig); + await pinus.app.rpc.role.roleRemote.setPvpSettleSeasonNum.broadcast(settledPvpConfig); + await pinus.app.rpc.connector.connectorRemote.setPvpSettleSeasonNum.broadcast(settledPvpConfig); +} + +export async function setPvpSettleSeasonNum(settledPvpConfig?: PVPConfigType) { + if(!settledPvpConfig) { + settledPvpConfig = await PVPConfigModel.getSettledConfig(); + if(!settledPvpConfig) return; + } + pinus.app.set('pvpSettleSeasonNum', settledPvpConfig.seasonNum); } export async function reportOnlineSchedule() { diff --git a/game-server/test/pvp.test.ts b/game-server/test/pvp.test.ts index b553afa96..d4430cecb 100644 --- a/game-server/test/pvp.test.ts +++ b/game-server/test/pvp.test.ts @@ -399,7 +399,6 @@ function getData(pinusClient, seasonEnd: boolean, cb) { expect(heroScore.hid).to.be.a('number'); expect(heroScore.score).to.be.a('number'); }); - expect(res.data.isFirstEntry).to.be.a('boolean'); if (seasonEnd) { checkSeasonResult(res.data.seasonResult); } diff --git a/gm-server/app/controller/game.ts b/gm-server/app/controller/game.ts index 6c1fdc931..17a911360 100644 --- a/gm-server/app/controller/game.ts +++ b/gm-server/app/controller/game.ts @@ -194,4 +194,11 @@ export default class GameController extends Controller { ctx.body = await ctx.service.game.getServerName(); return } + + public async getPvpConfig() { + const { ctx } = this; + const { page, pageSize, sortField, sortOrder } = ctx.request.body; + ctx.body = await ctx.service.game.getPvpConfig(page, pageSize, sortField, sortOrder); + return + } } diff --git a/gm-server/app/router.ts b/gm-server/app/router.ts index 75c9338cf..ec694274a 100644 --- a/gm-server/app/router.ts +++ b/gm-server/app/router.ts @@ -70,6 +70,7 @@ export default (app: Application) => { router.post('/api/game/getmarqueelist', tokenParser, controller.game.getMarqueeList); router.post('/api/game/updatemarquee', tokenParser, controller.game.updateMarquee); router.post('/api/game/getaccuse', tokenParser, controller.game.getAccuse); + router.post('/api/game/getpvpconfig', controller.game.getPvpConfig); router.post('/api/activity/getactivitylist', tokenParser, controller.activity.getActivityList); router.post('/api/activity/getallactivities', tokenParser, controller.activity.getAllActivities); diff --git a/gm-server/app/service/Game.ts b/gm-server/app/service/Game.ts index 8ef5fe1a0..37bb12813 100644 --- a/gm-server/app/service/Game.ts +++ b/gm-server/app/service/Game.ts @@ -21,6 +21,7 @@ import { UserOrderModel } from '@db/UserOrder'; import { SurveyModel } from '@db/Survery'; import { RedisClient } from 'redis'; import { ChannelInfoModel } from '@db/ChannelInfo'; +import { PVPConfigModel } from '@db/PvpConfig'; /** * Test Service @@ -314,4 +315,13 @@ export default class Game extends Service { }), total }); } + + public async getPvpConfig(page: number, pageSize: number, sortField: string, sortOrder: string) { + const { ctx } = this; + const list = await PVPConfigModel.findByCondition(page, pageSize, sortField, sortOrder); + const total = await PVPConfigModel.countByCondition() + return ctx.service.utils.resResult(STATUS.SUCCESS, { + list, total + }); + } } diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index 2e5b5b88a..f3f478297 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -639,7 +639,8 @@ export enum SHOP_REFRESH_TYPE { DAILY = 1, // 每天刷新 WEEKLY = 2, // 每周 MONTHLY = 3, // 每月 - FOREVER = 4 // 不重置 + FOREVER = 4, // 不重置 + PVP = 5, // pvp赛季 } // 任务的大类 @@ -1154,4 +1155,10 @@ export enum SYSTEM_OPEN_ID { EXPEDITION = 36, // 远征 } -export const DEBUG_PRICE = 0.01; \ No newline at end of file +export const DEBUG_PRICE = 0.01; + +export enum PVP_SEASON_STATUS { + START = 1, // 已开始 + SUMMIT = 2, // 结算中 + WAITING = 3, // 待新赛季 +} \ No newline at end of file diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index 2e6ae89fb..ef4a70152 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -21,6 +21,7 @@ export const STATUS = { ADDRESS_ERR: { code: 17, simStr: '您的版本已停止支持,请前往应用商店下载最新安装包' }, GLOBAL_ERR: { code: 1003, simStr: '服务器内部错误' }, UPDATE_INFO_ERR: {code: 1004, simStr: '热更新配置错误'}, + DEBUG_FUNCTION_ERR: {code: 1005, simStr: '功能逻辑已改,debug接口不再提供'}, // http请求 REQUEST_TIME_OUT: { code: 2000, simStr: '请求超时' }, @@ -177,6 +178,8 @@ export const STATUS = { PVP_SET_ATTACK_CNT_NOT_ENOUGH: { code: 20806, simStr: '设置挑战阵容次数不足' }, PVP_NOT_SET_ATTACK: { code: 20807, simStr: '未设置挑战阵容' }, PVP_BUY_ATTACK_CNT_NOT_ENOUGH: { code: 20808, simStr: '购买挑战阵容次数不足' }, + PVP_SEASON_NOT_OPEN: { code: 20809, simStr: 'pvp赛季未开启' }, + PVP_CAN_NOT_SAVE_DEFENSE: { code: 20810, simStr: '结算期不可保存防守阵容' }, // 军团 20900-20999 GUILD_AUTH_NOT_ENOUGH: { code: 20900, simStr: '权限不足' }, diff --git a/shared/db/PvpConfig.ts b/shared/db/PvpConfig.ts new file mode 100644 index 000000000..a63026d72 --- /dev/null +++ b/shared/db/PvpConfig.ts @@ -0,0 +1,115 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; +import { nowSeconds } from '../pubUtils/timeUtil'; +import { CounterModel } from './Counter'; +import { COUNTER } from '../consts'; + +@index({ isCurrent: 1 }) +@index({ seasonNum: 1 }) +export default class PVPConfig extends BaseModel { + + @prop({ required: true, default: 1 }) + seasonNum: number; // 赛季 + + @prop({ required: true }) + seasonStartTime: number; // 赛季开始时间 + + @prop({ required: true }) + seasonRewardTime: number; // 结算奖励时间 + + @prop({ required: true }) + seasonEndTime: number; // 赛季结束的时间 + + @prop({ required: true }) + hasSettleReward: boolean; // 是否发放奖励 + + @prop({ required: true, type: Number }) + warIds: number[]; // 关卡id + + @prop({ required: true }) + isCurrent: boolean; // 是否是当前赛季 + + public static async findCurPVPConfig() { + let result: PVPConfigType = await PVPConfigModel.findOne({ isCurrent: true }).lean(); + if(!result) { + result = await PVPConfigModel.findOneAndUpdate({ seasonStartTime: { $lte: nowSeconds() } }, { $set: { isCurrent: true }}, { new: true }).sort({ seasonStartTime: -1 }).lean(); + } + return result; + } + + public static async findPVPConfig(seasonNum: number) { + const result: PVPConfigType = await PVPConfigModel.findOne({ seasonNum }).lean(true); + return result; + } + + public static async createPVPConfig(seasonNum: number|'new', params: PVPConfigUpdate, uid: number) { + if(seasonNum == 'new') { + seasonNum = await CounterModel.getNewCounter(COUNTER.PVP_SEASON_NUM); + } + const result: PVPConfigType = await PVPConfigModel.findOneAndUpdate({ seasonNum }, { $set: { ...params, updatedBy: uid }, $setOnInsert: { hasSettleReward: false, isCurrent: false, createdBy: uid } }, { upsert: true, new: true }).lean(true); + return result; + } + + public static async getSettledConfig() { + const result: PVPConfigType = await PVPConfigModel.findOne({ hasSettleReward: true }).sort({ seasonNum: -1}).lean(); + return result; + } + + public static async checkTime(seasonNum: number|'new', seasonStartTime: number, seasonRewardTime: number) { + if(seasonNum == 'new') { + return await PVPConfigModel.exists({ seasonRewardTime: { $gt: seasonStartTime } }) + } else { + return await PVPConfigModel.exists({ + seasonNum: { $ne: seasonNum }, + $or: [ + { seasonNum: { $lt: seasonNum }, seasonRewardTime: { $gt: seasonStartTime } }, + { seasonNum: { $gt: seasonNum }, seasonStartTime: { $lt: seasonRewardTime } } + ] + }) + } + } + + public static async setReward(seasonNum: number) { + const result: PVPConfigType = await PVPConfigModel.findOneAndUpdate({ seasonNum }, { hasSettleReward: true }, { new: true }).lean(true); + return result; + } + + public static async setCurrentPvp() { + await PVPConfigModel.updateMany({ isCurrent: true }, { $set: { isCurrent: false } }); + const result: PVPConfigType = await PVPConfigModel.findOneAndUpdate({ seasonStartTime: { $lte: nowSeconds() } }, { $set: { isCurrent: true }}, {new: true}).sort({ seasonStartTime: -1 }).lean(true); + return result; + } + + public static async setNextPvp(seasonNum: number) { + await PVPConfigModel.updateMany({ isCurrent: true }, { $set: { isCurrent: false } }); + const result: PVPConfigType = await PVPConfigModel.findOneAndUpdate({ seasonNum }, { $set: { isCurrent: true }}, {new: true}).sort({ seasonStartTime: -1 }).lean(true); + return result; + } + + public static async findByCondition(page: number, pageSize: number, sortField: string = 'seasonNum', sortOrder: string = 'descend') { + let sort = {}; + if (sortField && sortOrder) { + if (sortOrder == 'ascend') { + sort[sortField] = 1; + } else if (sortOrder == 'descend') { + sort[sortField] = -1; + } + } + const result: PVPConfigType[] = await PVPConfigModel.find().limit(pageSize).skip((page - 1) * pageSize).sort(sort).lean({ getters: true, virtuals: true }); + return result; + + } + + public static async countByCondition() { + + const result = await PVPConfigModel.count({}); + return result; + } +} + +export const PVPConfigModel = getModelForClass(PVPConfig); + +export interface PVPConfigType extends Pick, keyof PVPConfig> { + id: number; +}; +export type PVPConfigUpdate = Partial; // 将所有字段变成可选项 diff --git a/shared/db/PvpDefense.ts b/shared/db/PvpDefense.ts index 715283cf4..026761f00 100644 --- a/shared/db/PvpDefense.ts +++ b/shared/db/PvpDefense.ts @@ -7,6 +7,7 @@ import { COUNTER } from '../consts'; import { PVP } from '../pubUtils/dicParam'; @index({ roleId: 1 }) +@index({ score: 1 }) export default class PvpDefense extends BaseModel { @prop({ required: true }) serverId: number; // 区 id @@ -17,6 +18,8 @@ export default class PvpDefense extends BaseModel { @prop({ ref: 'Role', type: mongoose.Schema.Types.ObjectId }) role: Ref; @prop({ required: true, default: null, _id: false }) + hasDefense: boolean; + @prop({ required: true, default: null, _id: false }) defense: Defense; @prop({ required: true, default: null, _id: false }) attack: Attack; @@ -58,8 +61,6 @@ export default class PvpDefense extends BaseModel { seasonNum: number; @prop({ required: true, default: 0 }) seasonWinNum: number; // 本赛季胜利次数 - @prop({ required: true, default: true }) - isFirstEntry: boolean; @prop({ required: true, default: 0 }) defenseScoreCnt: number; @@ -129,7 +130,7 @@ export default class PvpDefense extends BaseModel { } public static async findByTeamLv(seasonNum: number, min: number, max: number) { - const result: PvpDefenseType[] = await PvpDefenseModel.find({ seasonNum, 'defense.pLv': { $gte: min, $lte: max } }) + const result: PvpDefenseType[] = await PvpDefenseModel.find({ seasonNum, hasDefense: true, 'defense.pLv': { $gte: min, $lte: max } }) .populate('role', '_id head frame spine heads frames spines topLineupCe roleId roleName lv globalCeAttr title') .populate('heroes.hero') .populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine heads frames spines rankLv pLv title lv defCe heroes warId buff') @@ -137,6 +138,25 @@ export default class PvpDefense extends BaseModel { return result; } + public static async findNeighborByScore(seasonNum: number, score: number) { + const beforeData: PvpDefenseType[] = await PvpDefenseModel.find({ + seasonNum, hasDefense: true, score: { $lt: score } + }).sort({ score: -1 }).limit(10) + .populate('role', '_id head frame spine heads frames spines topLineupCe roleId roleName lv globalCeAttr title') + .populate('heroes.hero') + .populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine heads frames spines rankLv pLv title lv defCe heroes warId buff') + .lean({ getters: true, virtuals: true }); + const afterData: PvpDefenseType[] = await PvpDefenseModel.find({ + seasonNum, hasDefense: true, score: { $gt: score } + }).sort({ score: 1 }).limit(10) + .populate('role', '_id head frame spine heads frames spines topLineupCe roleId roleName lv globalCeAttr title') + .populate('heroes.hero') + .populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine heads frames spines rankLv pLv title lv defCe heroes warId buff') + .lean({ getters: true, virtuals: true }); + + return [...beforeData, ...afterData]; + } + public static async updateInfoAndInclude(roleId: string, update: pvpUpdateInter) { delete update._id; let result: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({roleId}, {$set:update}, {new: true}) @@ -162,14 +182,6 @@ export default class PvpDefense extends BaseModel { return ranks; } - public static async resetScores(roleId: string, newSeasonNum: number, newScore: number, newHeroScores: HeroScore[]) { - let result: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({roleId}, {$set: { seasonNum: newSeasonNum, score: newScore, heroScores: newHeroScores, challengeCnt: PVP.PVP_CHALLENGE_COUNTS, challengeRefTime: 0, winStreakNum: 0 }}, {new: true}) - .populate('role', 'roleId roleName head frame spine heads frames spines title lv vLv') - .populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine heads frames spines rankLv pLv title lv defCe heroes warId buff').lean({ getters: true, virtuals: true }) - .lean(); - return result; - } - public static async deleteHero(roleId: string, hid: number) { let result:PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({roleId}, {$pull:{lineupCe: {hid}, heroScores: {hid}}, $set: {defense: null, attack: null}}, {new: true}).lean(); return result; diff --git a/shared/db/PvpSaveData.ts b/shared/db/PvpSaveData.ts new file mode 100644 index 000000000..4b5a71929 --- /dev/null +++ b/shared/db/PvpSaveData.ts @@ -0,0 +1,36 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; +import { DefenseHeroInSaveData, } from '../domain/battleField/pvp'; + +@index({ roleId: 1 }) +@index({ roleId: 1, warId: 1 }) +export default class PvpSaveData extends BaseModel { + @prop({ required: true }) + roleId: string; // 角色 id + + @prop({ required: true }) + warId: number; // 关卡id + + @prop({ required: true }) + buff: number; // 地图buff + + @prop({ required: true, default: [], _id: false, type: DefenseHeroInSaveData }) + heroes: DefenseHeroInSaveData[]; + + + public static async createSaveData(roleId: string, warId: number, buff: number, heroes: DefenseHeroInSaveData[]) { + const result: PvpSaveDataType = await PvpSaveDataModel.findOneAndUpdate({ roleId, warId }, { $set: { buff, heroes } }, { new: true, upsert: true }).lean(); + return result; + } + + public static async findByRoleId(roleId: string) { + const result: PvpSaveDataType[] = await PvpSaveDataModel.find({ roleId }).lean(); + return result; + } + +} + +export const PvpSaveDataModel = getModelForClass(PvpSaveData); + +export interface PvpSaveDataType extends Pick, keyof PvpSaveData> { }; +export type pvpSaveDataUpdate = Partial; \ No newline at end of file diff --git a/shared/db/PvpSeasonResult.ts b/shared/db/PvpSeasonResult.ts index c93219aea..f20b9118b 100644 --- a/shared/db/PvpSeasonResult.ts +++ b/shared/db/PvpSeasonResult.ts @@ -59,6 +59,10 @@ export default class PvpSeasonResult extends BaseModel { let result: PvpSeasonResultType = await PvpSeasonResultModel.findOne({ roleId, show: true }).lean(); return result; } + + public static async checkResultBySeasonNum(roleId: string, seasonNum: number) { + return await PvpSeasonResultModel.exists({ roleId, seasonNum }); + } } export const PvpSeasonResultModel = getModelForClass(PvpSeasonResult); diff --git a/shared/db/SystemConfig.ts b/shared/db/SystemConfig.ts deleted file mode 100644 index 2fe9746f2..000000000 --- a/shared/db/SystemConfig.ts +++ /dev/null @@ -1,59 +0,0 @@ -import BaseModel from './BaseModel'; -import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; -import { CounterModel } from './Counter'; -import { COUNTER } from '../consts'; - -@index({ id: 1 }) -@index({ seasonNum: 1 }) -export default class PVPConfig extends BaseModel { - - @prop({ required: true, default: 1 }) - seasonNum: number; // 赛季 - - @prop({ required: true }) - seasonStartTime: number; // 赛季开始时间 - - @prop({ required: true }) - seasonRewardTime: number; // 结算奖励时间 - - @prop({ required: true }) - seasonEndTime: number; // 赛季结束的时间 - - @prop({ required: true }) - hasSettleReward: boolean; // 赛季结束的时间 - - - public static async findCurPVPConfig() { - let seasonNum = await CounterModel.getCounter(COUNTER.PVP_SEASON_NUM); - const result: PVPConfigType = await PVPConfigModel.findOne({ seasonNum }).lean(true); - return result; - } - - public static async findPVPConfig(seasonNum: number) { - const result: PVPConfigType = await PVPConfigModel.findOne({ seasonNum }).lean(true); - return result; - } - - public static async createPVPConfig(seasonNum: number, seasonStartTime: number, seasonRewardTime: number, seasonEndTime: number) { - const result: PVPConfigType = await PVPConfigModel.findOneAndUpdate({ seasonNum }, { seasonStartTime, seasonRewardTime, seasonEndTime, hasSettleReward: false }, { upsert: true, new: true }).lean(true); - return result; - } - - public static async setReward(seasonNum: number) { - const result: PVPConfigType = await PVPConfigModel.findOneAndUpdate({ seasonNum }, { hasSettleReward: true }, { new: true }).lean(true); - return result; - } - - public static async setCurPvpConfig(update: PVPConfigUpdate) { - let seasonNum = await CounterModel.getCounter(COUNTER.PVP_SEASON_NUM); - const result: PVPConfigType = await PVPConfigModel.findOneAndUpdate({ seasonNum }, update).lean(true); - return result; - } -} - -export const PVPConfigModel = getModelForClass(PVPConfig); - -export interface PVPConfigType extends Pick, keyof PVPConfig> { - id: number; -}; -export type PVPConfigUpdate = Partial; // 将所有字段变成可选项 diff --git a/shared/db/UserShop.ts b/shared/db/UserShop.ts index 1ddf16ae4..e2d6d6597 100644 --- a/shared/db/UserShop.ts +++ b/shared/db/UserShop.ts @@ -44,7 +44,10 @@ export default class UserShop extends BaseModel { @prop({ required: true }) count: number; // 数量 - private static getRefreshCondition() { + @prop({ required: true }) + seasonNum: number; // 赛季id + + private static getRefreshCondition(seasonNum: number) { let today = getZeroPointD(); let cutWeek = getZeroPointD(SHOP_REFRESH_TYPE.WEEKLY); let curMonth = getZeroPointD(SHOP_REFRESH_TYPE.MONTHLY); @@ -54,38 +57,39 @@ export default class UserShop extends BaseModel { { createdAt: { $gte: cutWeek }, refreshType: SHOP_REFRESH_TYPE.WEEKLY }, { createdAt: { $gte: curMonth }, refreshType: SHOP_REFRESH_TYPE.MONTHLY }, { refreshType: SHOP_REFRESH_TYPE.FOREVER }, + { refreshType: SHOP_REFRESH_TYPE.PVP, seasonNum }, ] } - public static async findByShopType(roleId: string, shop: number, type: number) { - let timeCondition = this.getRefreshCondition(); + public static async findByShopType(roleId: string, shop: number, type: number, seasonNum: number) { + let timeCondition = this.getRefreshCondition(seasonNum); let rec: UserShopType[] = await UserShopModel.find({ shop, type, roleId, $or: timeCondition }).lean(); return rec; } - public static async findByRoleId(roleId: string) { - let timeCondition = this.getRefreshCondition(); + public static async findByRoleId(roleId: string, seasonNum: number) { + let timeCondition = this.getRefreshCondition(seasonNum); let rec: UserShopType[] = await UserShopModel.find({ roleId, $or: timeCondition }).lean(); return rec; } - public static async findByRoleAndItem(roleId: string, activityId: number, dicShopItem: { id: number, shop: number, type: number, createTime?: number }) { - let timeCondition = this.getRefreshCondition(); + public static async findByRoleAndItem(roleId: string, activityId: number, dicShopItem: { id: number, shop: number, type: number, createTime?: number }, seasonNum: number) { + let timeCondition = this.getRefreshCondition(seasonNum); let { id, shop, type, createTime = 0 } = dicShopItem; let rec: UserShopType = await UserShopModel.findOne({ roleId, itemId: id, shop, type, activityId, createTime, $or: timeCondition }).lean(); return rec; } - public static async purchase(roleId: string, roleName: string, activityId: number, dicShopItem: { id: number, goodId: number, refreshType: number, shop: number, type: number, createTime?: number }, inc: number) { + public static async purchase(roleId: string, roleName: string, activityId: number, dicShopItem: { id: number, goodId: number, refreshType: number, shop: number, type: number, createTime?: number }, inc: number, seasonNum: number) { let code = genCode(8); - let timeCondition = this.getRefreshCondition(); + let timeCondition = this.getRefreshCondition(seasonNum); let { id, goodId, refreshType, shop, type, createTime = 0 } = dicShopItem; let rec: UserShopType = await UserShopModel.findOneAndUpdate( { roleId, itemId: id, $or: timeCondition, activityId, shop, type, createTime }, - { $setOnInsert: { roleName, code, goodId, refreshType }, $inc: { count: inc } }, + { $setOnInsert: { roleName, code, goodId, refreshType, seasonNum }, $inc: { count: inc } }, { new: true, upsert: true } ).lean(); return rec; diff --git a/shared/domain/activityField/popUpShopField.ts b/shared/domain/activityField/popUpShopField.ts index 0ee97b3e4..14f11e4e4 100644 --- a/shared/domain/activityField/popUpShopField.ts +++ b/shared/domain/activityField/popUpShopField.ts @@ -6,7 +6,7 @@ import { RewardInter } from "../../pubUtils/interface"; import { parseNumberList } from "../../pubUtils/util"; import { stringWithTypeToRewardInter } from "../../pubUtils/roleUtil"; import { ActivityBase } from './activityField'; -import { PVPConfigModel } from "../../db/SystemConfig"; +import { PVPConfigModel } from "../../db/PvpConfig"; import { getZeroPointOfTimeD, nowSeconds } from "../../pubUtils/timeUtil"; // 数据库格式 diff --git a/shared/domain/backEndField/params.ts b/shared/domain/backEndField/params.ts index 34873368e..20775480e 100644 --- a/shared/domain/backEndField/params.ts +++ b/shared/domain/backEndField/params.ts @@ -3,7 +3,7 @@ import { isArray, isNumber, isString } from 'underscore'; import ServerStategy, { GMMail } from "../../db/ServerStategy"; import { RegionType } from "../../db/Region"; import { RewardInter } from "../../pubUtils/interface"; -import { isTimestamp } from '../../pubUtils/util'; +import { isTimestamp, parseNumberList } from '../../pubUtils/util'; import { isBoolean, isDate } from "util"; export class UpdateMailParams { @@ -438,4 +438,36 @@ export class UpdateChannelParam { if(this.privacyPolicyLink && !isString(this.privacyPolicyLink)) return false; return true; } +} + + +export class CreatePvpConfigParam { + env: string = ''; + seasonNum: number|'new' = 0; + seasonStartTime: number = 0; + seasonEndTime: number = 0; + seasonRewardTime: number = 0; + warIds: string = ''; + + constructor(obj?: any) { + if(obj) { + for(let key in obj) { + this[key] = obj[key]; + } + } + } + + checkParams() { + // console.log('##### createNew', this.env, this.openTime, this.stopRegisterTime, this.hasOpenMail, this.hasCircleMail) + if(this.seasonNum != 'new' && !isNumber(this.seasonNum)) return false; + if(!this.env || !isNumber(this.seasonStartTime) || !isNumber(this.seasonEndTime) || !isNumber(this.seasonRewardTime) || !isString(this.warIds)) { + return false + } + return true; + } + + getUpdateParam() { + let { seasonStartTime, seasonEndTime, seasonRewardTime, warIds } = this; + return { seasonStartTime, seasonEndTime, seasonRewardTime, warIds: parseNumberList(warIds)} + } } \ No newline at end of file diff --git a/shared/domain/battleField/pvp.ts b/shared/domain/battleField/pvp.ts index 20c69415d..336cef067 100644 --- a/shared/domain/battleField/pvp.ts +++ b/shared/domain/battleField/pvp.ts @@ -3,13 +3,13 @@ import { prop, Ref, mongoose } from '@typegoose/typegoose'; import Hero from '../../db/Hero'; import { PvpDefenseType } from '../../db/PvpDefense'; import PvpHistoryOpp from '../../db/PvpHistoryOpp'; +import { PvpSaveDataType } from '../../db/PvpSaveData'; import { PvpSeasonResultType } from '../../db/PvpSeasonResult'; import { getPlvAndScore } from '../../pubUtils/data'; import { RewardInter } from '../../pubUtils/interface'; +import { nowSeconds } from '../../pubUtils/timeUtil'; - -// 防守阵容武将 -export class DefenseHero { +export class DefenseHeroInSaveData { @prop({ required: true }) actorId: number; // 武将id @prop({ required: true }) @@ -18,16 +18,26 @@ export class DefenseHero { dataId: number; @prop({ required: true }) order: number; - @prop({ ref: 'Hero', type: mongoose.Schema.Types.ObjectId }) - hero: Ref; - constructor(param: { actorId: number, ai: number, dataId: number, order: number }, heroId: string) { + constructor(param: { actorId: number, ai: number, dataId: number, order: number }) { this.actorId = param.actorId; this.ai = param.ai; this.dataId = param.dataId; this.order = param.order; + } +} + +// 防守阵容武将 +export class DefenseHero extends DefenseHeroInSaveData { + + @prop({ ref: 'Hero', type: mongoose.Schema.Types.ObjectId }) + hero: Ref; + + constructor(param: { actorId: number, ai: number, dataId: number, order: number }, heroId: string) { + super(param); this.hero = heroId; } + } // 防守阵容 @@ -228,7 +238,9 @@ export class PvpSeasonResultRecord { export class PvpDataReturn { seasonNum: number; + seasonStartTime: number; seasonEndTime: number; + seasonRewardTime: number; myRank: number = 0; oppPlayers: OppPlayerReturn[] = []; defense: DefenseLineupReturn = null; @@ -244,7 +256,7 @@ export class PvpDataReturn { receivedBox: number[] = []; hisScore: number = 0; heroScores: HeroScoreReturn[] = []; - isFirstEntry: boolean = false; + hasSaveDefense: boolean = false; resultRecord: PvpSeasonResultRecord; setPvpDefense(pvpDefense: PvpDefenseType) { @@ -284,10 +296,6 @@ export class PvpDataReturn { return { attackCe, defenseCe }; } - setIsFirstEntry(isFirstEntry: boolean) { - this.isFirstEntry = isFirstEntry; - } - setOppPlayers(oppPlayers: OppPlayerReturn[]) { this.oppPlayers = oppPlayers; } @@ -296,12 +304,53 @@ export class PvpDataReturn { this.myRank = rankLv; } - setPvpConfig(seasonNum: number, seasonEndTime: number) { + setPvpConfig(seasonNum: number, seasonStartTime: number, seasonEndTime: number, seasonRewardTime: number) { this.seasonNum = seasonNum; + this.seasonStartTime = seasonStartTime; this.seasonEndTime = seasonEndTime; + this.seasonRewardTime = seasonRewardTime; } setPvpSeasonResult(pvpSeasonResult: PvpSeasonResultType) { this.resultRecord = new PvpSeasonResultRecord(pvpSeasonResult); } + + getHasSaveDefense() { + if(this.seasonRewardTime < nowSeconds() && this.seasonStartTime > nowSeconds()) { + return true; + } + return !!this.defense; + } + + calHasSaveDefense() { + this.hasSaveDefense = this.getHasSaveDefense(); + return this.hasSaveDefense; + } + + setChallengeCnt(challengeCnt: number) { + return this.challengeCnt = challengeCnt; + } +} + +export class pvpSaveDataReturn { + warId: number; // 地图id + isUsing: boolean = false; // 设置的是否是这张地图 + hasSet: boolean = false; // 玩家是否设置过 + buff: number; // 选择的地图buff,没有设置过不返回 + heroes: DefenseHeroInSaveData[]; // 玩家武将,没有设置不返回 + + constructor(warId: number) { + this.warId = warId; + } + + setUserSaveData(pvpSaveData: PvpSaveDataType) { + if(!pvpSaveData) return; + this.hasSet = true; + this.buff = pvpSaveData.buff; + this.heroes = pvpSaveData.heroes; + } + + setAsUsing() { + this.isUsing = true; + } } \ No newline at end of file diff --git a/shared/resource/jsons/dic_api.json b/shared/resource/jsons/dic_api.json index 3e8968c71..a83f09cee 100644 --- a/shared/resource/jsons/dic_api.json +++ b/shared/resource/jsons/dic_api.json @@ -894,5 +894,19 @@ "name": "开关接口", "module": "sys", "type": "update" + }, + { + "id": 129, + "api": "/api/game/getpvpconfig", + "name": "获取pvp赛季", + "module": "sys", + "type": "find" + }, + { + "id": 130, + "api": "gm.gmServerHandler.savePvpConfig", + "name": "保存pvp赛季", + "module": "sys", + "type": "update" } ] \ No newline at end of file diff --git a/shared/resource/jsons/dic_zyz_shop.json b/shared/resource/jsons/dic_zyz_shop.json index 8dcbc4492..27f2783de 100644 --- a/shared/resource/jsons/dic_zyz_shop.json +++ b/shared/resource/jsons/dic_zyz_shop.json @@ -10,7 +10,7 @@ "lvLimit": 0, "ranklimit": 0, "purchaseLimit": 5, - "refreshType": 1, + "refreshType": 5, "money": 31002, "price": "1&0|2&50|3&100|4&150|5&200", "chosen": 2,