diff --git a/game-server/app/servers/chat/remote/chatRemote.ts b/game-server/app/servers/chat/remote/chatRemote.ts index 20f1540bc..72c07a62a 100644 --- a/game-server/app/servers/chat/remote/chatRemote.ts +++ b/game-server/app/servers/chat/remote/chatRemote.ts @@ -10,6 +10,7 @@ import { reloadResources } from '../../../pubUtils/data'; import { GeneralRankParam } from '../../../domain/rank'; import { getAllGuildActivityStatus } from '../../../services/guildActivityService'; import { MailParam } from '../../../domain/roleField/mail'; +import { RankFirstType } from '../../../db/RankFirst'; export default function (app: Application) { new HandlerService(app, {}); @@ -188,12 +189,12 @@ export class ChatRemote { * @description 全服推送排行榜更新信息 * @param serverId */ - public async sendRankTopUpdated(serverId: number, rank: GeneralRankParam & { general: number }) { + public async sendRankTopUpdated(serverId: number, ranks: (RankFirstType & {status: number})[]) { let roomId = groupRoomId(CHANNEL_PREFIX.WORLD, serverId); let channel = this.channelService.getChannel(roomId, false); if (!channel) return; - channel.pushMessage(this.RANK_TOP_UPDATE, resResult(STATUS.SUCCESS, { rank })); + channel.pushMessage(this.RANK_TOP_UPDATE, resResult(STATUS.SUCCESS, { ranks })); } /** diff --git a/game-server/app/servers/guild/handler/guildHandler.ts b/game-server/app/servers/guild/handler/guildHandler.ts index 6aa789977..e3e0da254 100644 --- a/game-server/app/servers/guild/handler/guildHandler.ts +++ b/game-server/app/servers/guild/handler/guildHandler.ts @@ -697,7 +697,7 @@ export class GuildHandler { const sid = session.get('sid'); const { code, id } = msg; - const guild = await GuildModel.findByCode(code, serverId, 'lv structure'); + const guild = await GuildModel.findByCode(code, serverId, 'lv structure activeWeekly lvUpdateTime'); if (!guild) { return resResult(STATUS.GUILD_NOT_FOUND); } @@ -717,13 +717,13 @@ export class GuildHandler { } const cost = getStructureConsume(id, curStructure.lv); - const result = await GuildModel.upStructure(code, id, cost, 'code fund structure lv name'); + const result = await GuildModel.upStructure(code, id, cost, 'code fund structure lv activeWeekly lvUpdateTime name'); if (!result) { return resResult(STATUS.GUILD_FUND_NOT_ENOUGH); } if (id == GUILD_STRUCTURE.ARMY_CENTER) { let r = new Rank(REDIS_KEY.GUILD_LV_RANK, { serverId }); - await r.setRankWithGuildInfo2(code, guild.lv, guild.activeWeekly, guild.lvUpdateTime, guild); + await r.setRankWithGuildInfo2(code, result.lv, result.activeWeekly, result.lvUpdateTime, result); } const resultStructure = result.structure.find(cur => cur.id == id); diff --git a/game-server/app/servers/role/handler/rankHandler.ts b/game-server/app/servers/role/handler/rankHandler.ts index c97cf436b..3b7d576c7 100644 --- a/game-server/app/servers/role/handler/rankHandler.ts +++ b/game-server/app/servers/role/handler/rankHandler.ts @@ -4,7 +4,7 @@ import { STATUS, RANK_TYPE_TO_KEY, ROLE_SELECT, RANK_TYPE, HERO_SELECT, GUILD_SE import { RoleModel } from "../../../db/Role"; import { UserGuildModel } from "../../../db/UserGuild"; import { GuildModel } from "../../../db/Guild"; -import { Rank, getGeneralRank } from "../../../services/rankService"; +import { Rank, getGeneralRank, getRankFirstReward } from "../../../services/rankService"; import { nowSeconds } from "../../../pubUtils/timeUtil"; import { gameData } from "../../../pubUtils/data"; import { addItems } from "../../../services/rewardService"; @@ -34,6 +34,20 @@ export class RoleHandler { return resResult(STATUS.SUCCESS, { ranks }); } + + async getRankReward(msg: {}, session: BackendSession) { + let roleId = session.get('roleId'); + let roleName = session.get('roleName'); + let serverId = session.get('serverId'); + + let role = await RoleModel.findByRoleId(roleId, 'rankReceived'); + if (!role) return resResult(STATUS.WRONG_PARMS); + + let ranks = await getRankFirstReward(role, serverId); + + return resResult(STATUS.SUCCESS, { ranks }); + } + async getRank(msg: { type: number }, session: BackendSession) { let roleId = session.get('roleId'); let serverId = session.get('serverId'); diff --git a/game-server/app/servers/role/handler/roleHandler.ts b/game-server/app/servers/role/handler/roleHandler.ts index 8e7cb436e..41ff0ce3b 100644 --- a/game-server/app/servers/role/handler/roleHandler.ts +++ b/game-server/app/servers/role/handler/roleHandler.ts @@ -58,7 +58,9 @@ export class RoleHandler { } await createHero.createWithInitInfo(infos, initInfos.figureInfo); await createHero.pushMessage(pinus, sid); + console.log('updateRedisRank before', Date.now()) await createHero.updateRedisRank(Rank); + console.log('updateRedisRank after', Date.now()) let heroes = createHero.getResultHeroes(); console.log('****** createHeroes after', Date.now()) diff --git a/game-server/app/servers/role/remote/roleRemote.ts b/game-server/app/servers/role/remote/roleRemote.ts index 57f89393b..1dd738fcf 100644 --- a/game-server/app/servers/role/remote/roleRemote.ts +++ b/game-server/app/servers/role/remote/roleRemote.ts @@ -4,6 +4,7 @@ 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 { getInitRoleInfo } from '../../../pubUtils/roleUtil'; import { DEFAULT_HEROES } from '../../../consts'; import { Figure } from '../../../domain/dbGeneral'; @@ -18,12 +19,35 @@ export class RoleRemote { this.app = app; this.channelService = app.get('channelService'); this.setInitRole(); + this.loadRankFirst(); } private channelService: ChannelService; private initHeroes: Map = new Map(); // hid => hero private initRole: RoleUpdate = {}; private initSkins: Map = new Map(); // hid => skin private figureInfo: {heads: Figure[], frames: Figure[], spines: Figure[]}; + private rankFirstRewards: Map> = new Map(); + + private async loadRankFirst() { + let rankFirstRewards = await RankFirstModel.findAllRankRewards(); + for(let rank of rankFirstRewards) { + if(!this.rankFirstRewards.has(rank.serverId)) { + this.rankFirstRewards.set(rank.serverId, new Map()); + } + this.rankFirstRewards.get(rank.serverId).set(rank.id, rank); + } + } + + public setRankFirst(rank: RankFirstType) { + if(!this.rankFirstRewards.has(rank.serverId)) { + this.rankFirstRewards.set(rank.serverId, new Map()); + } + this.rankFirstRewards.get(rank.serverId).set(rank.id, rank); + } + + public getRankFirstById(serverId: number, id: number) { + return this.rankFirstRewards.get(serverId)?.get(id); + } public setInitRole() { let result = getInitRoleInfo(); diff --git a/game-server/app/services/connectorService.ts b/game-server/app/services/connectorService.ts index 0767085ca..7483f9655 100644 --- a/game-server/app/services/connectorService.ts +++ b/game-server/app/services/connectorService.ts @@ -10,7 +10,7 @@ import { FrontendOrBackendSession, pinus } from 'pinus'; import { resResult } from '../pubUtils/util'; import { STATUS, PUSH_BATCH, PUSH_INTERVAL, CONSUME_TYPE } from '../consts'; import { getAllShopList } from './shopService'; -import { getGeneralRank } from './rankService'; +import { getGeneralRank, getRankFirstReward } from './rankService'; import { getFriendList, getApplyList } from './friendService'; import { getDailyBattleList } from './dailyBattleService'; import { getExpeditionStatus } from './expeditionService'; @@ -77,7 +77,8 @@ async function getModuleData(type: string, data: { role: RoleType, session: Fron case 'shop': // 商店 return await getAllShopList(roleId); case 'rank': // 排名 - return await getGeneralRank(role, serverId); + const rewards = await getRankFirstReward(role, serverId); + return { rewards } case 'mail': // 邮件 return await getMails(roleId, serverId); case 'friend': // 好友 diff --git a/game-server/app/services/rankService.ts b/game-server/app/services/rankService.ts index bef87b172..4dbc230f0 100644 --- a/game-server/app/services/rankService.ts +++ b/game-server/app/services/rankService.ts @@ -10,6 +10,9 @@ import { gameData } from "../pubUtils/data"; import { nowSeconds } from "../pubUtils/timeUtil"; import { getWorldChannelSid } from "./chatChannelService"; import { pinus } from "pinus"; +import ts = require("typescript"); +import { RankFirstModel, RankFirstType, RankFirstUpdateParam } from "../db/RankFirst"; +import { getRandSingleEelm } from "../pubUtils/util"; /** @@ -61,8 +64,7 @@ export class Rank { case REDIS_KEY.GUILD_LV_RANK: this.valueConfig = [ new ValueConfig(true, 'lv', 0, false, false), - new ValueConfig(false, 'active', 5, false, false), - new ValueConfig(false, 'time', 10, true, true) + new ValueConfig(false, 'active', 5, false, false) ]; break; default: @@ -844,22 +846,45 @@ export class Rank { } private async checkMyRankAndPush(myId: myIdInter, oldScore: number, newScore: number) { - if (this.isInit) return; + let ts = this; + if (ts.isInit) return; let myRank = await this.getMyRank(myId); + console.log('*******', ts.key, myRank, newScore, oldScore); if (myRank == 1 && newScore > oldScore) { let serverId = this.keyName.serverId; let sid = await getWorldChannelSid(serverId); - for (let { id, general } of gameData.rank) { + let dicRank = gameData.rank.find(({ id }) => { let redisKey = RANK_TYPE_TO_KEY.get(id); - if (redisKey == this.key) { - let r = new Rank(redisKey, { serverId }, false, 1); - let ranks = await r.getRankByRange(); - if (ranks.length > 0) { - let param = new GeneralRankParam(id, ranks[0] || new RoleRankInfo({}, false), general); - pinus.app.rpc.chat.chatRemote.sendRankTopUpdated.toServer(sid, serverId, { ...param, general }); + return redisKey == ts.key + }); + console.log('*******', dicRank); + if(dicRank) { + let r = new Rank(ts.key, { serverId }, false, 1); + let ranks = await r.getRankByRange(); + let rankFirstRecs: (RankFirstType & { status: number })[] = []; + if(ranks.length > 0 && ranks[0]) { + let userInfo: RankParam, guildInfo: GuildRankParam; + if(ranks[0] instanceof RoleRankInfo) { + userInfo = ranks[0]; + } + if(ranks[0] instanceof GuildRankInfo) { + guildInfo = ranks[0]; } - break; + for(let [id, { rankId, condition }] of gameData.generalRankReward) { + console.log(rankId, dicRank.id, oldScore, condition, newScore); + if(dicRank.id == rankId && oldScore < condition && newScore >= condition) { + let rankFirstRec = await RankFirstModel.createRankFirst(serverId, id, rankId, { userInfo, guildInfo }); + let roleServers = pinus.app.getServersByType('role'); + for(let server of roleServers) { + pinus.app.rpc.role.roleRemote.setRankFirst.toServer(server.id, rankFirstRec); + } + rankFirstRecs.push({ ... rankFirstRec, status: 1}); + } + } + } + if(rankFirstRecs.length > 0) { + pinus.app.rpc.chat.chatRemote.sendRankTopUpdated.toServer(sid, serverId, rankFirstRecs); } } } @@ -1017,4 +1042,31 @@ export async function getGeneralRank(role: RoleType & { rankReceived: number[] } } } return result; +} + +/** + * 获取排行榜总览 + * @param role 玩家数据 + * @param serverId 所在服务器 + */ + export async function getRankFirstReward(role: RoleType & { rankReceived: number[] }, serverId: number) { + let { rankReceived = [] } = role; + + let result: (RankFirstUpdateParam & {status: number})[] = []; + + for (let [id, { rankId: type } ] of gameData.generalRankReward) { + let roleServers = pinus.app.getServersByType('role'); + let curServer = roleServers.find(cur => cur.id == pinus.app.getServerId()); + if(!curServer) { + curServer = getRandSingleEelm(roleServers); + } + let rankFirst = await pinus.app.rpc.role.roleRemote.getRankFirstById.toServer(curServer.id, serverId, id); + if(rankFirst) { + let status = rankReceived.includes(id)?2: 1; + result.push({...rankFirst, status}); + } else { + result.push({ id, type, status: 0 }); + } + } + return result; } \ No newline at end of file diff --git a/gm-server/app/service/users.ts b/gm-server/app/service/users.ts index 32cd056f5..c724de431 100644 --- a/gm-server/app/service/users.ts +++ b/gm-server/app/service/users.ts @@ -283,15 +283,17 @@ export default class GMUsers extends Service { await GroupMailModel.deleteMany({ roleId }); await GroupMailModel.deleteMany({ targetRoleId: roleId }); let userGuild = await UserGuildModel.getMyGuild(roleId); - if(userGuild.auth == 1) { - const guild = await GuildModel.dismiss(userGuild.guildCode, role.serverId); - await UserGuildModel.dismiss(userGuild.guildCode); - const { members } = guild; - await RoleModel.dissmissGuild(members); - await UserGuildApplyModel.deleteApplyByGuild(userGuild.guildCode); - - } else { - await GuildModel.update({ members: { $in: [roleId] } }, { $pull: { members: roleId }, $inc: { memberCnt: -1, managerCnt: userGuild.auth == 2? -1: 0, guildCe: -role.ce }, $set: { isMemberMax: false } }) + if(userGuild) { + if(userGuild.auth == 1) { + const guild = await GuildModel.dismiss(userGuild.guildCode, role.serverId); + await UserGuildModel.dismiss(userGuild.guildCode); + const { members } = guild; + await RoleModel.dissmissGuild(members); + await UserGuildApplyModel.deleteApplyByGuild(userGuild.guildCode); + + } else { + await GuildModel.update({ members: { $in: [roleId] } }, { $pull: { members: roleId }, $inc: { memberCnt: -1, managerCnt: userGuild.auth == 2? -1: 0, guildCe: -role.ce }, $set: { isMemberMax: false } }) + } } await GuildModel.updateMany({ invitedMembers: { $in: [roleId] } }, { $pull: { invitedMembers: roleId } }); await GuildRecModel.deleteMany({ roleId }); diff --git a/shared/db/RankFirst.ts b/shared/db/RankFirst.ts new file mode 100644 index 000000000..48ee5fbbe --- /dev/null +++ b/shared/db/RankFirst.ts @@ -0,0 +1,40 @@ +/** + * 秘境首通 + */ + import BaseModel from './BaseModel'; + import { getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; + import { RankParam, GuildRankParam } from '../domain/rank'; + + export default class RankFirst extends BaseModel { + + @prop({ required: true }) + serverId: number; // 服务器id + + @prop({ required: true }) + id: number; // 奖励表id + + @prop({ required: true }) + type: number; // 排行榜id + + @prop({ required: true, type: () => RankParam, _id: false }) + userInfo: RankParam; // 玩家信息 + + @prop({ required: true, type: () => GuildRankParam, _id: false }) + guildInfo: GuildRankParam; // 军团信息 + + public static async createRankFirst(serverId: number, id: number, type: number, update: RankFirstUpdateParam) { + const rec: RankFirstType = await RankFirstModel.findOneAndUpdate({ serverId, id, type}, { $setOnInsert: update }, { new: true, upsert: true }).lean(); + return rec; + } + + public static async findAllRankRewards() { + let rewards: RankFirstType[] = await RankFirstModel.find({}, { _id: false }).select('serverId id type userInfo guildInfo').lean(); + return rewards; + } + } + + export const RankFirstModel = getModelForClass(RankFirst); + + export interface RankFirstType extends Pick, keyof RankFirst>{} + export type RankFirstUpdateParam = Partial; // 将所有字段变成可选项 + \ No newline at end of file diff --git a/shared/domain/rank.ts b/shared/domain/rank.ts index 78d6952dc..a68858d8a 100644 --- a/shared/domain/rank.ts +++ b/shared/domain/rank.ts @@ -66,6 +66,69 @@ export class RankParam { } } +export class GuildLeader { + @prop({ required: true }) + roleId: string; + + @prop({ required: true }) + roleName: string; + + @prop({ required: true }) + title: number; + + @prop({ required: true }) + lv: number; + + @prop({ required: true }) + head: number; + + @prop({ required: true }) + frame: number; + + @prop({ required: true }) + spine: number; + + constructor(leader: { roleId: string, roleName: string, title: number, lv: number, head: number, frame: number, spine: number}) { + this.roleId = leader.roleId; + this.roleName = leader.roleName; + this.title = leader.title; + this.lv = leader.lv; + this.head = leader.head; + this.frame = leader.frame; + this.spine = leader.spine; + } +} + +// 排行榜返回玩家值 +export class LineupParam { + @prop({ required: true }) + hid: number; + + @prop({ required: true }) + star: number; + + @prop({ required: true }) + colorStar: number; + + @prop({ required: true }) + lv: number; + + @prop({ required: true }) + quality: number; + + @prop({ required: true }) + job: number; + + constructor(hero: HeroType) { + this.hid = hero.hid; + this.star = hero.star; + this.colorStar = hero.colorStar; + this.lv = hero.lv; + this.quality = hero.quality; + this.job = hero.job; + } +} + export class RoleRankInfo extends RankParam { rank: number = 1; roleId: string = ""; @@ -94,23 +157,24 @@ export class RoleRankInfo extends RankParam { } } - - // 公会排行榜返回值 export class GuildRankParam { + @prop({ required: true }) icon: number; + + @prop({ required: true }) name: string; + + @prop({ required: true }) lv: number; + + @prop({ required: true }) memberCnt: number; - leader: { - roleId: string; - roleName: string; - title: number; - lv: number; - head: number; - frame: number; - spine: number; - }; + + @prop({ required: true, _id: false }) + leader: GuildLeader; + + @prop({ required: true }) guildCe: number; constructor(guild: GuildUpdateParam) { @@ -186,56 +250,6 @@ export class RoleAndGuildRankInfo { } } -export class GuildLeader { - roleId: string; - roleName: string; - title: number; - lv: number; - head: number; - frame: number; - spine: number; - - constructor(leader: { roleId: string, roleName: string, title: number, lv: number, head: number, frame: number, spine: number}) { - this.roleId = leader.roleId; - this.roleName = leader.roleName; - this.title = leader.title; - this.lv = leader.lv; - this.head = leader.head; - this.frame = leader.frame; - this.spine = leader.spine; - } -} - -// 排行榜返回玩家值 -export class LineupParam { - @prop({ required: true }) - hid: number; - - @prop({ required: true }) - star: number; - - @prop({ required: true }) - colorStar: number; - - @prop({ required: true }) - lv: number; - - @prop({ required: true }) - quality: number; - - @prop({ required: true }) - job: number; - - constructor(hero: HeroType) { - this.hid = hero.hid; - this.star = hero.star; - this.colorStar = hero.colorStar; - this.lv = hero.lv; - this.quality = hero.quality; - this.job = hero.job; - } -} - export class SimpleGuildRankParam { rank: number = 0; code: string = ""; @@ -366,4 +380,4 @@ export class GeneralRankParam { this.num = rankInfo.num; this.received = received; } -} \ No newline at end of file +} diff --git a/shared/pubUtils/roleUtil.ts b/shared/pubUtils/roleUtil.ts index 85dad4f87..46afa7c7a 100644 --- a/shared/pubUtils/roleUtil.ts +++ b/shared/pubUtils/roleUtil.ts @@ -72,7 +72,7 @@ export class UpdateHeroes { funcs: number[] = []; incHeroNum: number = 0; incRoleCe: number = 0; - pushHeroes: {hid: number, incHeroCe: number, ce: number}[] = []; + pushHeroes: {hid: number, incHeroCe: number, ce: number, hero: HeroUpdate}[] = []; roleUpdate: RoleUpdate; role: RoleType; guild: GuildType; @@ -104,7 +104,7 @@ export class UpdateHeroes { if(isCreate) this.incHeroNum ++; if(heroInfo != originCe) this.incRoleCe += heroInfo.ce - originCe; this.addRoleUpdateParam(await calculatetopLineup(role, heroInfo.hid, heroInfo.ce, heroInfo._id )); - this.pushHeroes.push({ hid: heroInfo.hid, incHeroCe: heroInfo.ce - originCe, ce: heroInfo.ce }); + this.pushHeroes.push({ hid: heroInfo.hid, incHeroCe: heroInfo.ce - originCe, ce: heroInfo.ce, hero: heroInfo }); } // 更新战力相关的各个表 @@ -127,37 +127,50 @@ export class UpdateHeroes { public async updateRedisRank(Rank: any) { let role = await this.getRole(); let { serverId, roleId, pushHeroes } = this; + console.log('******** guildInfo before', Date.now()); // 更新军团信息 if(this.guild) { let r = new Rank(REDIS_KEY.GUILD_INFO, { code: this.guild.code }); await r.generParamAndSet(REDIS_KEY.GUILD_INFO, { guildCode: this.guild.code }, { guild: this.guild }); } + console.log('******** guildInfo after', Date.now()); + console.log('******** heroNum before', Date.now()); // 武将数量 if(this.incHeroNum > 0) { let r = new Rank(REDIS_KEY.HERO_NUM_RANK, { serverId }); await r.setRankWithRoleInfo(roleId, role.heroNum, role.heroNumUpdatedAt, role); } + console.log('******** heroNum after', Date.now()); + console.log('******** topLineup before', Date.now()); // 最强阵容 let r = new Rank(REDIS_KEY.TOP_LINEUP_RANK, { serverId }); await r.setRankWithRoleInfo(roleId, reduceCe(role.topLineupCe), 0, role); + console.log('******** topLineup after', Date.now()); + console.log('******** hero before', Date.now()); // 最强武将 - for(let { hid, ce } of pushHeroes) { + for(let { hid, ce, hero } of pushHeroes) { + console.log('******** hero before', hid, Date.now()); let r2 = new Rank(REDIS_KEY.TOP_HERO_RANK, { serverId }); - await r2.setRankWithHeroInfo(roleId, hid, ce, 0); + await r2.setRankWithHeroInfo(roleId, hid, ce, 0, hero); let r4 = new Rank(REDIS_KEY.HERO_RANK, { serverId, hid }); - await r4.setRankWithHeroInfo(roleId, hid, ce, 0); + await r4.setRankWithHeroInfo(roleId, hid, ce, 0, hero); + console.log('******** hero after', hid, Date.now()); } - + console.log('******** hero after', Date.now()); + console.log('******** sumCe before', Date.now()); // 总战力 let r3 = new Rank(REDIS_KEY.SUM_CE_RANK, { serverId }); await r3.setRankWithRoleInfo(roleId, reduceCe(role.ce), 0, role); + console.log('******** sumCe after', Date.now()); + console.log('******** lineup info before', Date.now()); // 更新最强五人阵容信息 let r5 = new Rank(REDIS_KEY.TOP_LINEUP_INFO, { serverId }); await r5.generParamAndSet(REDIS_KEY.TOP_LINEUP_INFO, { roleId }, { role }); + console.log('******** lineup info after', Date.now()); } public async pushMessage(pinus: any, sid: string) {