diff --git a/game-server/app/servers/chat/remote/chatRemote.ts b/game-server/app/servers/chat/remote/chatRemote.ts index b4fd8d01a..b790b44df 100644 --- a/game-server/app/servers/chat/remote/chatRemote.ts +++ b/game-server/app/servers/chat/remote/chatRemote.ts @@ -5,6 +5,7 @@ import { ON_ADD_CHANNEL_ROUTE, ON_GROUP_MSG_ROUTE, ON_LEAVE_CHANNEL_ROUTE, STATU import { PrivateMessageType } from '../../../db/PrivateMessage'; import { addUserToChannel, getSimpleRoleInfo } from '../../../services/roleService'; import { ChannelUser } from '../../../domain/ChannelUser'; +import { getWorldChannelSid } from '../../../services/chatService'; export default function (app: Application) { return new ChatRemote(app); @@ -29,6 +30,7 @@ export class ChatRemote { } private channelService: ChannelService; + private GUILD_ACTIVITY_END = 'onGuildActivityEnd'; /** * 加入世界频道(分服). @@ -163,4 +165,16 @@ export class ChatRemote { public async sendPrivateMsg(msg: Partial) { } + + + /** + * @description 全服推送活动结束通知 + * @param serverId + */ + public async sendGuildActivityEnd(serverId: number) { + let roomId = await getWorldChannelSid(serverId); + let channel = this.channelService.getChannel(roomId, false); + if (!channel) return; + channel.pushMessage(this.GUILD_ACTIVITY_END, resResult(STATUS.SUCCESS, { })); + } } diff --git a/game-server/app/servers/chat/remote/guildRemote.ts b/game-server/app/servers/chat/remote/guildRemote.ts index f80032a22..56e2e9170 100644 --- a/game-server/app/servers/chat/remote/guildRemote.ts +++ b/game-server/app/servers/chat/remote/guildRemote.ts @@ -5,6 +5,7 @@ import { GuildType } from '../../../db/Guild'; import { RoleType } from '../../../db/Role'; import { GuildRecType } from '../../../db/GuildRec'; import { leaveGuildChannel, groupRoomId } from '../../../services/chatService'; +import { GuildGateRankParam } from '../../../domain/battleField/guildActivity'; export default function (app: Application) { return new GuildRemote(app); @@ -161,7 +162,7 @@ export class GuildRemote { * 向军团推送排行榜名次 * @param guildCode */ - public pushRank(guildCode: string) { - + public pushRank(guildCode: string, msg: GuildGateRankParam) { + this.pushMessage(guildCode, this.GUILD_ACT_RANK, msg); } } \ No newline at end of file diff --git a/game-server/app/servers/guild/handler/gateActivityHandler.ts b/game-server/app/servers/guild/handler/gateActivityHandler.ts index 64906f260..a762185cb 100644 --- a/game-server/app/servers/guild/handler/gateActivityHandler.ts +++ b/game-server/app/servers/guild/handler/gateActivityHandler.ts @@ -1,5 +1,5 @@ import { Application, BackendSession, ChannelService } from "pinus"; -import { setMedianCe, getMedianCe, getGuildActivityStatus, getRecordScore, getGuildActivityObj } from "../../../services/guildActivityService"; +import { setMedianCe, getMedianCe, getGuildActivityStatus, getRecordScore, getGuildActivityObj, getGuildActivityRank } from "../../../services/guildActivityService"; import { resResult } from "../../../pubUtils/util"; import { STATUS, GUILD_ACTIVITY_TYPE, GUILD_POINT_WAYS, ENEMIES_TYPE, GET_POINT_WAYS } from "../../../consts"; import { GameModel } from "../../../db/Game"; @@ -45,33 +45,13 @@ export class GateActivityHandler { let myGuildActivityRec = await UserGuildActivityRecModel.getRecord(roleId, roleName, guildCode, serverId, sourceCode, [], this.aid); let { challengeCnt } = myGuildActivityRec; - // TODO 处理多余字段 - let {ranks: guildRank, myRank: myGuildRank} = await getUnionRank(REDIS_KEY.GUILD_ACTIVITY, serverId, guildCode, 10); - let {ranks: memberRank, myRank: myMemberRank} = await getRank(getGuildKeyName(REDIS_KEY.USER_GUILD_ACTIVITY, guildCode), serverId, roleId); - if(!myGuildRank) { - let guild = await GuildModel.findByCode(guildCode, serverId, 'name'); - myGuildRank = { - rank: 0, - code: guildCode, - name: guild.name, - num: 0 - } - } - if(!myMemberRank) { - myMemberRank = { - rank: 0, - roleId, - roleName, - num: 0 - } - } + let ranks = await getGuildActivityRank(guildCode, serverId, roleId, roleName); return resResult(STATUS.SUCCESS, { ...statusResult, challengeCnt: GUILDACTIVITY.GATEACTIVITY_CHALLENGE_TIMES - challengeCnt, - guildRank, myGuildRank, - memberRank, myMemberRank - }) + ...ranks + }); } // 开启挑战 @@ -101,7 +81,7 @@ export class GateActivityHandler { let { code, challengeCnt } = myGuildActivityRec; // 更新公会参与的玩家 - getGuildActivityObj(this.aid).pushMembers(guildCode, roleId); + getGuildActivityObj(this.aid).pushMembers(guildCode, serverId, roleId); // 返回当前军团总军功 let guildScore = await getRankScore(REDIS_KEY.GUILD_ACTIVITY, serverId, guildCode); diff --git a/game-server/app/servers/guild/remote/guildActivitRemote.ts b/game-server/app/servers/guild/remote/guildActivitRemote.ts new file mode 100644 index 000000000..6fc90833d --- /dev/null +++ b/game-server/app/servers/guild/remote/guildActivitRemote.ts @@ -0,0 +1,30 @@ +import { Application, ChannelService } from 'pinus'; +import { sendAllGuildRanks, sendGuildActEndMsg } from '../../../services/guildActivityService'; + +export default function (app: Application) { + return new GuildActivityRemote(app); +} + +export class GuildActivityRemote { + + constructor(private app: Application) { + this.app = app; + this.channelService = app.get('channelService'); + } + + private channelService: ChannelService; + + /** + * 从systimer服分发到guild各个服,发送排行榜数据 + */ + public async sendRankToGuilds() { + await sendAllGuildRanks(); + } + + /** + * 发送结束活动消息 + */ + public async guildActivityEnd() { + await sendGuildActEndMsg(); + } +} \ No newline at end of file diff --git a/game-server/app/servers/user.rpc.define.ts b/game-server/app/servers/user.rpc.define.ts index e1555523e..c44213e5d 100644 --- a/game-server/app/servers/user.rpc.define.ts +++ b/game-server/app/servers/user.rpc.define.ts @@ -11,6 +11,7 @@ import { SystimerRemote } from './systimer/remote/systimerRemote'; import { GuildRemote } from './chat/remote/guildRemote'; import { GMRemote } from './gm/remote/gmRemote'; import { RoleRemote } from './role/remote/roleRemote'; +import { GuildActivityRemote } from './guild/remote/guildActivitRemote'; declare global { interface UserRpc { chat: { @@ -32,6 +33,9 @@ declare global { }, role: { roleRemote: RemoterClass; + }, + guild: { + guildActivityRemote: RemoterClass; } } } \ No newline at end of file diff --git a/game-server/app/services/chatChannelService.ts b/game-server/app/services/chatChannelService.ts index 7aa70283c..ade3eeaf2 100644 --- a/game-server/app/services/chatChannelService.ts +++ b/game-server/app/services/chatChannelService.ts @@ -63,6 +63,12 @@ export async function leaveGuildChannel(roleId: string, sid: string) { await leaveChannel(roomId, roleId, sid); } +export async function getWorldChannelSid(serverId: number) { + const roomId = groupRoomId(CHANNEL_PREFIX.WORLD, serverId); + const channelSid = await channelServer(roomId); + return channelSid; +} + export async function getGuildChannelSid(guildCode: string) { const roomId = groupRoomId(CHANNEL_PREFIX.GUILD, guildCode); const channelSid = await channelServer(roomId); diff --git a/game-server/app/services/guildActivityService.ts b/game-server/app/services/guildActivityService.ts index f90fdee00..7ce6d9a3b 100644 --- a/game-server/app/services/guildActivityService.ts +++ b/game-server/app/services/guildActivityService.ts @@ -2,11 +2,17 @@ import { ServerlistModel } from "../db/Serverlist"; import { RoleModel } from "../db/Role"; import { reduceCe } from "../pubUtils/util"; import { GUILDACTIVITY } from "../pubUtils/dicParam"; -import { gameData } from "../pubUtils/data"; +import { gameData, getTodayGuildActivity } from "../pubUtils/data"; import { getCurHourPoint, getCutDay, nowSeconds } from "../pubUtils/timeUtil"; -import { GUILD_ACTIVITY_STATUS, GET_POINT_WAYS, GUILD_ACTIVITY_TYPE } from "../consts"; +import { GUILD_ACTIVITY_STATUS, GET_POINT_WAYS, GUILD_ACTIVITY_TYPE, REDIS_KEY } from "../consts"; import { Record } from "../db/UserGuildActivityRec"; import { GateMembersRec, GateActivityObject } from "../domain/battleField/guildActivity"; +import { DicGuildActivity } from "../pubUtils/dictionary/DicGuildActivity"; +import { getUnionRank, getRank, getGuildKeyName } from "./redisService"; +import { GuildModel } from "../db/Guild"; +import { SimpleGuildRankParam, SimpleRoleRankParam } from "../domain/rank"; +import { getGuildChannelSid, getWorldChannelSid } from "./chatChannelService"; +import { pinus } from "pinus"; let gateActivityObj: GateActivityObject; export function getGuildActivityObj(aid: number) { @@ -60,7 +66,11 @@ export async function getMedianCe(serverId: number) { export function getGuildActivityStatus(id: number) { let dicGuildActivity = gameData.guildActivity.get(id); if(!dicGuildActivity) return false; + return getGuildActivityByDic(dicGuildActivity); +} +export function getGuildActivityByDic(dicGuildActivity: DicGuildActivity) { + let startTime = getCurHourPoint(dicGuildActivity.startTime); let countdownTime = getCurHourPoint(dicGuildActivity.countDown); let { duringTime, openDay } = dicGuildActivity; @@ -120,4 +130,72 @@ export function getRecordScore(aid: number, record: { round: number, dataId: num return { score: sum, newRecords, memberRecord } +} + +/** + * 获得军团活动排行榜 + * @param guildCode + * @param serverId + * @param roleId + * @param roleName + */ +export async function getGuildActivityRank(guildCode: string, serverId: number, roleId?: string, roleName?: string) { + + let guildRankResult = await getUnionRank(REDIS_KEY.GUILD_ACTIVITY, serverId, guildCode); + let guildRank = new Array(); + for(let { rank, code, name, num } of guildRankResult.ranks) { + let param = new SimpleGuildRankParam(rank, code, name, num); + guildRank.push(param); + } + let myGuildRank: SimpleGuildRankParam; + if(guildRankResult.myRank) { + let { rank, code, name, num } = guildRankResult.myRank; + myGuildRank = new SimpleGuildRankParam(rank, code, name, num); + } else { + let guild = await GuildModel.findByCode(guildCode, serverId, 'name'); + myGuildRank = new SimpleGuildRankParam(0, guildCode, guild.name, 0); + } + + let memberRankResult = await getRank(getGuildKeyName(REDIS_KEY.USER_GUILD_ACTIVITY, guildCode), serverId, roleId); + let memberRank = new Array(); + for(let { rank, roleId, roleName, num } of memberRankResult.ranks) { + let param = new SimpleRoleRankParam(rank, roleId, roleName, num); + memberRank.push(param) + } + let myMemberRank: SimpleRoleRankParam; + if(roleName) { + if(memberRankResult.myRank) { + let { rank, roleId, roleName, num } = memberRankResult.myRank; + myMemberRank = new SimpleRoleRankParam(rank, roleId, roleName, num); + } else { + myMemberRank = new SimpleRoleRankParam(0, roleId, roleName, 0); + } + } + + return { guildRank, myGuildRank, memberRank, myMemberRank } +} + +/** + * 对这个guild服内所有军团发排行榜信息 + */ +export async function sendAllGuildRanks() { + let obj = getGuildActivityObj(GUILD_ACTIVITY_TYPE.GATE_ACTIVITY); + let guilds = obj.getGuilds(); + for(let [ serverId, guildCodes ] of guilds) { + // TODO 不需要每个军团都排序一次 + for(let guildCode of guildCodes) { + let ranks = await getGuildActivityRank(guildCode, serverId); + let chatSid = await getGuildChannelSid(guildCode); + pinus.app.rpc.chat.guildRemote.pushRank.toServer(chatSid, ranks); + } + } +} + +export async function sendGuildActEndMsg() { + let obj = getGuildActivityObj(GUILD_ACTIVITY_TYPE.GATE_ACTIVITY); + let guilds = obj.getGuilds(); + for(let [ serverId ] of guilds) { + let chatSid = await getWorldChannelSid(serverId); + pinus.app.rpc.chat.chatRemote.sendGuildActivityEnd.toServer(chatSid, serverId); + } } \ No newline at end of file diff --git a/game-server/app/services/timeTaskService.ts b/game-server/app/services/timeTaskService.ts index f51583f38..c3d84d82e 100644 --- a/game-server/app/services/timeTaskService.ts +++ b/game-server/app/services/timeTaskService.ts @@ -4,11 +4,11 @@ import { SystemConfigModel } from '../db/SystemConfig'; import PvpDefenseType,{ PvpDefenseModel } from '../db/PvpDefense'; import { PVP } from '../pubUtils/dicParam'; import { nowSeconds, getTodayZeroPoint, getAge } from '../pubUtils/timeUtil'; -import { getPvpGkWarIds, getPvpRankRewards, getPvpHeroRewards, getResultMaxRank } from '../pubUtils/data'; +import { getPvpGkWarIds, getPvpRankRewards, getPvpHeroRewards, getResultMaxRank, getTodayGuildActivity } from '../pubUtils/data'; import { deepCopy, getRandomArr, resResult, shouldRefresh } from '../pubUtils/util'; import { getLvByScore } from './pvpService'; import { getMyRank, setRank, resetPvpRanks, getAllOnlineRoles } from './redisService'; -import { MAIL_TYPE, REDIS_KEY, ADULT_AGE, GUEST_MAX_TIME, ADDICTION_PREVENTION_CODE } from '../consts'; +import { MAIL_TYPE, REDIS_KEY, ADULT_AGE, GUEST_MAX_TIME, ADDICTION_PREVENTION_CODE, GUILD_ACTIVITY_STATUS, GUILD_ACTIVITY_TYPE } from '../consts'; import { RankParam } from '../domain/rank'; import { RoleModel } from '../db/Role'; import { MailModel, MailType } from '../db/Mail'; @@ -20,15 +20,18 @@ import { STATUS } from '../consts/statusCode'; import { getMailContent, sendMail } from './mailService'; import { reportOnline } from '../pubUtils/httpUtil'; import User, { UserModel } from '../db/User'; +import { getGuildActivityByDic, getGuildActivityRank } from './guildActivityService'; const PER_SECOND = 1 * 1000; const PER_DAY = 24 * 60 * 60; const SETTLE_DIFF = 29 * 60; const pageNum = 500; const PER_MINUTE = 1 * 60; -var seasonJobId; -var warJobId; -var seasonEndTimeJobId; -let guildWeeklyJobId; +var seasonJobId: Job; +var warJobId: Job; +var seasonEndTimeJobId: Job; +let guildWeeklyJobId: Job; +let guildActSecondsJobId: Job; // 军团活动开启后每10(or 1)秒循环的定时任务,到结束活动清除 +let guildActEndJobId: Job; // 军团活动开启后每10(or 1)秒循环的定时任务,到结束活动清除 /** * 服务器启动即开启定时任务,结算时常是23-24点,实际结算的时间点是23:31分钟 */ @@ -61,7 +64,10 @@ export async function init() { // 周功勋结算任务 guildWeeklyJobId = scheduleJob('settleGuildWeekly', '0 0 0 * * 1', settleGuildWeekly); - scheduleJob('reportOnline', '0 0/5 * * * *', reportOnlineSchedule) + // 每5分钟汇报在线玩家在线情况 + scheduleJob('reportOnline', '0 0/5 * * * *', reportOnlineSchedule); + + guildActivitySchedule(); } function setPvpSeasonSchdule() { @@ -319,4 +325,68 @@ export async function reportOneOnline(roleId: string, userCode: string, sid: str } ), [{uid: roleId, sid: sid}]); } } +} + +/** + * 军团活动,每晚8点开启 + */ +async function guildActivitySchedule() { + // 军团晚间活动,每天8点开始 + scheduleJob('guildActivityStart', '0 0 20 * * ?', guildActivityStart); + + let dicGuildActivity = getTodayGuildActivity(); + let statusResult = getGuildActivityByDic(dicGuildActivity); + if(!statusResult) return; + + if(statusResult.status == GUILD_ACTIVITY_STATUS.START) { + if(!guildActSecondsJobId) { + let seconds = 10; // 每10秒下发一次 + if(dicGuildActivity.id == GUILD_ACTIVITY_TYPE.RACE_ACTIVITY) { + seconds = 1; + } + guildActSecondsJobId = scheduleJob('guildActivitySeconds', seconds, guildActivitySeconds); + } + + if(!guildActEndJobId) { + guildActEndJobId = scheduleJob('guildActivityEnd', statusResult.time, guildActivityEnd); + } + } +} + +// 开始军团活动 +export async function guildActivityStart() { + + let dicGuildActivity = getTodayGuildActivity(); + if(!dicGuildActivity) return; + + + let seconds = 10; // 每10秒下发一次 + if(dicGuildActivity.id == GUILD_ACTIVITY_TYPE.RACE_ACTIVITY) { + seconds = 1; + } + guildActSecondsJobId = scheduleJob('guildActivitySeconds', seconds, guildActivitySeconds); + // 结束时间 + guildActEndJobId = scheduleJob('guildActivityEnd', dicGuildActivity.duringTime, guildActivityEnd); +} + +// 结束军团活动 +export async function guildActivityEnd() { + + let servers = pinus.app.getServersByType('guild'); + console.log(servers); + for(let { id } of servers) { + await pinus.app.rpc.guild.guildActivityRemote.guildActivityEnd.toServer(id); + } + + if(guildActSecondsJobId) guildActSecondsJobId.cancel(); + if(guildActEndJobId) guildActEndJobId.cancel(); +} + +// 每10秒下发一次的任务 +export async function guildActivitySeconds() { + let servers = pinus.app.getServersByType('guild'); + console.log(servers); + for(let { id } of servers) { + await pinus.app.rpc.guild.guildActivityRemote.sendRankToGuilds.toServer(id); + } } \ No newline at end of file diff --git a/shared/domain/battleField/guildActivity.ts b/shared/domain/battleField/guildActivity.ts index cbfe0beba..f3ce35530 100644 --- a/shared/domain/battleField/guildActivity.ts +++ b/shared/domain/battleField/guildActivity.ts @@ -1,4 +1,5 @@ import { GUILDACTIVITY } from "../../pubUtils/dicParam"; +import { SimpleGuildRankParam, SimpleRoleRankParam } from '../rank' export class GateMembersRec { roleId: string; @@ -9,10 +10,13 @@ export class GateMembersRec { } } +// 军团活动蛮夷入侵城门血量等数据存储 + export class GateActivityObject { private gateHp: Map = new Map(); // 城门血条,每个军团有一条血条 private members: Map> = new Map(); // 每个军团参与的成员 private membersRecord: Map = new Map(); // 每个成员的回合数和敌军数,防刷 + private guilds: Map = new Map(); // 参加的所有军团 public getObj(guildCode: string) { return { @@ -35,13 +39,24 @@ export class GateActivityObject { return gateHp } - public pushMembers(guildCode: string, roleId: string) { + public getGuilds() { + return this.guilds; + } + + public pushMembers(guildCode: string, serverId: number, roleId: string) { if(this.members.has(guildCode)) { this.members.get(guildCode).push(roleId); } else { this.members.set(guildCode, [roleId]); } + if(this.guilds.has(serverId)) { + this.guilds.set(serverId, []); + } else { + let arr = this.guilds.get(serverId)||[]; + if(!arr.includes(guildCode)) arr.push(guildCode); + this.guilds.set(serverId, arr); + } } public getMemberRecord(code: string, roleId: string) { @@ -55,4 +70,11 @@ export class GateActivityObject { public delMemberRecord(code: string) { this.membersRecord.delete(code); } +} + +export interface GuildGateRankParam { + guildRank: SimpleGuildRankParam[], + myGuildRank: SimpleGuildRankParam, + memberRank: SimpleRoleRankParam[], + myMemberRank?: SimpleRoleRankParam } \ No newline at end of file diff --git a/shared/domain/rank.ts b/shared/domain/rank.ts index 008767cb3..2a13bdd56 100644 --- a/shared/domain/rank.ts +++ b/shared/domain/rank.ts @@ -62,4 +62,32 @@ export class GuildLeader { this.frame = leader.frame; this.spine = leader.spine; } +} + +export class SimpleGuildRankParam { + rank: number; + code: string; + name: string; + num: number; + + constructor(rank: number, code: string, name: string, num: number) { + this.rank = rank; + this.code = code; + this.name = name; + this.num = num; + } +} + +export class SimpleRoleRankParam { + rank: number; + roleId: string; + roleName: string; + num: number; + + constructor(rank: number, roleId: string, roleName: string, num: number) { + this.rank = rank; + this.roleId = roleId; + this.roleName = roleName; + this.num = num; + } } \ No newline at end of file diff --git a/shared/pubUtils/data.ts b/shared/pubUtils/data.ts index 95c40cd26..cf50fc576 100644 --- a/shared/pubUtils/data.ts +++ b/shared/pubUtils/data.ts @@ -58,8 +58,9 @@ import { dicArmyDonate } from '../pubUtils/dictionary/DicArmyDonateBoxReward'; import { dicRoleFriend, DicRoleFriend } from "./dictionary/DicRoleFriend"; import { dicRoleFriendLv } from "./dictionary/DicRoleFriendLv"; import { Attribute } from "../domain/roleField/attribute"; -import { dicGuildActivity } from './dictionary/DicGuildActivity'; +import { dicGuildActivity, DicGuildActivity } from './dictionary/DicGuildActivity'; import { dicGateActivityPoint } from './dictionary/DicGateActivityPoint'; +import { getCutDay } from "./timeUtil"; export const gameData = { blurprtCompose: dicBlueprtCompose, @@ -438,4 +439,20 @@ export function getDicFriendByLv(lv: number) { } return dicFriend; -} \ No newline at end of file +} + + +/** + * @description 获取今天开启的活动的配置 + */ +export function getTodayGuildActivity() { + let today = getCutDay(); + let dic: DicGuildActivity; + for(let [_id, dicGuildActivity] of gameData.guildActivity) { + if(dicGuildActivity.openDay.includes(today)) { + dic = dicGuildActivity; + break; + } + } + return dic; +}