import { Application, BackendSession, pinus } from 'pinus'; import { resResult } from '../../../pubUtils/util'; import { STATUS } from '../../../consts/statusCode'; import { getRoleOnlineInfo, redisClient, updateUserInfo } from '../../../services/redisService'; import { addItems } from '../../../services/role/rewardService'; import { RewardInter } from '../../../pubUtils/interface'; import { gameData, getExpByLv, getHeroExpByLv, getHeroLvByExp, getLvByExp, getEquipByJobClassAndEPlace } from '../../../pubUtils/data'; import { RoleModel, RoleType, WarStar } from '../../../db/Role'; import { BLOCK_TYPE, DEFAULT_HEROES, GUILD_AUTH, GUILD_DISMISS_WAY, GUILD_JOB, GUILD_MASTER_CHANGE_WAY, GUILD_STATUS, GUILD_STRUCTURE, HERO_SYSTEM_TYPE, ITEM_CHANGE_REASON, MAIL_TYPE, MEMORY_LOG_TYPE, PUSH_ROUTE, REDIS_KEY, TA_EVENT, WAR_TYPE } from '../../../consts'; import { GuildFormParam, SetHeroParam } from '../../../domain/backEndField/params'; import { GuildModel, GuildUpdateParam } from '../../../db/Guild'; import { Rank } from '../../../services/rankService'; import { UserGuildModel } from '../../../db/UserGuild'; import { UserGuildApplyModel } from '../../../db/UserGuildApply'; import { reportTAEvent } from '../../../services/sdkService'; import { sendMailByContent } from '../../../services/mailService'; import { GuildLeader } from '../../../domain/rank'; import { HeroModel } from '../../../db/Hero'; import { SkinModel } from '../../../db/Skin'; import { PvpDefenseModel } from '../../../db/PvpDefense'; import { createHeroes } from '../../../services/role/createHero'; import { calculateCeWithHero, calculateCeWithRole } from '../../../services/playerCeService'; import { pushChangeGuildLeader, pushGuildDismiss, pushGuildInfoUpdate } from '../../../services/guildService'; import { sendMessageToUserWithSuc } from '../../../services/pushService'; import { RScriptRecordModel } from '../../../db/RScriptRecord'; import { DicWar } from '../../../pubUtils/dictionary/DicWar'; import { SchoolModel } from '../../../db/School'; import { JewelModel } from '../../../db/Jewel'; import { RoleCeModel } from '../../../db/RoleCe'; import { setTrainLv } from '../../../services/gmService'; import { ArtifactModel } from '../../../db/Artifact'; import { roleLeave } from '../../../services/redisService'; import { KeyName } from '../../../domain/rank'; import { LadderMatchModel } from '../../../db/LadderMatch'; let timer: NodeJS.Timer; export default function (app: Application) { return new GmRoleHandler(app); } export class GmRoleHandler { constructor(private app: Application) { } async addItems(msg: { roleId: string, roleName: string, serverId: number, values: { reward: RewardInter[], heroes: number[], lv: number, expInc: number, fixedIpLocation: string }}, session: BackendSession) { let { roleId, roleName, serverId, values } = msg; let { reward, heroes, lv, expInc = 0, fixedIpLocation } = values; let connect = await getRoleOnlineInfo(roleId); let sid = connect.isOnline?connect.sid: null; if(reward &&reward.length > 0) { await addItems(roleId, roleName, sid, values.reward, ITEM_CHANGE_REASON.DEBUG); } if(heroes && heroes.length > 0) { await createHeroes(roleId, roleName, sid, serverId, heroes.map(hid => { return { hid, count: 1 }})) } if(lv && lv > 0) { let exp = getExpByLv(lv - 1)?.sum||0; exp += expInc; let newLv = getLvByExp(exp); let role = await RoleModel.updateRoleInfo(roleId, { lv: newLv, exp }) let r = new Rank(REDIS_KEY.USER_LV, { serverId: serverId }); await r.setRankWithRoleInfo(roleId, newLv, Date.now(), role); sendMessageToUserWithSuc(roleId, PUSH_ROUTE.PLAYER_EXP_CHANGE, { isLvUp: false, lv: newLv, exp }, sid); } if(fixedIpLocation != undefined) { await RoleModel.updateRoleInfo(roleId, { fixedIpLocation }) } return resResult(STATUS.SUCCESS); } async handleBlock(msg: { roleId: string, blockType: BLOCK_TYPE, blockReason: string }, session: BackendSession) { let { roleId, blockType, blockReason } = msg; if(roleId == undefined || blockType == undefined || blockReason == undefined) return resResult(STATUS.WRONG_PARMS); let role = await RoleModel.updateRoleInfo(roleId, { blockType, blockReason }); if(!role) return resResult(STATUS.ROLE_NOT_FOUND); let { isOnline, sid } = await getRoleOnlineInfo(roleId); if(isOnline) { await this.app.rpc.connector.connectorRemote.setOtherUserSession.toServer(sid,[{ roleId, blockType }]); if(blockType == BLOCK_TYPE.BLOCK) { // 踢走 await this.app.rpc.connector.connectorRemote.remoteLogin.toServer(sid, roleId, STATUS.BLOCKED); await roleLeave(roleId); } } return resResult(STATUS.SUCCESS); } async setHero(msg: { roleId: string, hid: number, param: SetHeroParam }, session: BackendSession) { let { roleId, hid } = msg; let param = new SetHeroParam(msg.param); if(!param.checkParams()) return resResult(STATUS.WRONG_PARMS); let hero = await HeroModel.findByHidAndRole(hid, roleId); if(!hero) return resResult(STATUS.HERO_NOT_FIND); let { sid } = await getRoleOnlineInfo(roleId); if(param.lv && param.lv > 0) { let exp = getHeroExpByLv(param.lv - 1)||0; exp += (param.expInc||0); let newLv = getHeroLvByExp(exp); param.lv = newLv; param['exp'] = exp; } await calculateCeWithHero(HERO_SYSTEM_TYPE.INIT, roleId, hero.serverId, sid, hid, {...hero, ...param}); // if(param.job > 0) { // await calculateCe(HERO_SYSTEM_TYPE.STAGEUP, roleId, hero.serverId, sid, param, {}, { hid }); // hero = await calPlayerCeAndSave(HERO_SYSTEM_TYPE.STAGEUP, sid, roleId, hero, { job: param.job, jobStage: 0 }); // } // if (hero.star != param.star) { // await calAllHeroCe(HERO_SYSTEM_TYPE.STAR, sid, roleId, {}, [hid, 1]); // 升星可能影响到百家学院全局加成 // } return resResult(STATUS.SUCCESS); } /** * 升级英雄装备至限制内的最高级 * * @param {{ roleId: string, hid: number }} msg * @param {BackendSession} session * @return {*} * @memberof GmRoleHandler */ async upgradeHeroEPlace(msg: { roleId: string, hid: number }, session: BackendSession) { let { roleId, hid } = msg; let hero = await HeroModel.findByHidAndRole(hid, roleId); if (!hero) return resResult(STATUS.HERO_NOT_FIND); /* * 通过 * dic_zyz_equipQuality.json * dic_zyz_equipStar.json * dic_zyz_equipStrength.json * dic_zyz_artifactQuality.json * 配置文件得出: * maxLevel: 100 * maxQuality: 5 (金) * maxStar: 12 * * 限制: * 装备等级不能超过hero等级 * maxQuality限制等级最大值: 金 最大lv 100 * * 装备信息: * dic_zyz_equip.json */ const MAX_STAR = 12; const MAX_QUALITY = 5; // EPLACE_ID 分别代表4个部位 const EPLACE_IDS = [1, 2, 3, 4]; // 装备升级、升星、升品(注意升级限制) // 装备未满 - 补全 - 并升至满级 let doNotGetEPlaceIds = new Set(EPLACE_IDS); hero.ePlace.forEach((ePlaceItem) => { doNotGetEPlaceIds.delete(ePlaceItem.id); // 该装备已拥有 - 升级、品、星 // 升级 - 最大等级100 ePlaceItem.lv = hero.lv; // 英雄等级肯定小于MAX_LV // 升品 - 金 ePlaceItem.quality = MAX_QUALITY; ePlaceItem.qualityStage = 0; // 生星 - 最高12 ePlaceItem.star = MAX_STAR; ePlaceItem.starStage = 0; }); // 装备补全 let dicHero = gameData.hero.get(hero.skinId); doNotGetEPlaceIds.forEach((ePlaceId) => { let dicEquip = getEquipByJobClassAndEPlace(dicHero?.jobClass, ePlaceId); if (dicEquip) { hero.ePlace.push({ lv: hero.lv, quality: MAX_QUALITY, qualityStage: 0, star: MAX_STAR, starStage: 0, jewel: 0, id: ePlaceId, equipId: dicEquip.id, stones: [ { id: 1, stone: 0 }, { id: 2, stone: 0 }, { id: 3, stone: 0 } ] }) } }) // 更新装备信息 await HeroModel.updateHeroInfo(roleId, hid, { ePlace: hero.ePlace }); // 获取战力重算需要的数据 let role = await RoleModel.findByRoleId(roleId); let schools = await SchoolModel.findByRoleId(roleId); let jewels = await JewelModel.findbyRole(roleId); let heroes = await HeroModel.findByRole(roleId); let skins = await SkinModel.findbyRole(roleId); let artifacts = await ArtifactModel.findbyRole(roleId); // 所有战力重算 await calculateCeWithRole(HERO_SYSTEM_TYPE.RE_CAL, roleId, role.serverId, null, {}, { role, schools, jewels, heroes, skins, artifacts }); // 获取更新装备的英雄 hero = await HeroModel.findByHidAndRole(hid, roleId); // 返回强化,升星,升品后的hero数据 return resResult(STATUS.SUCCESS, { curHero: hero }); } async deleteHero(msg: { roleId: string, hid: number }, session: BackendSession) { let { roleId, hid } = msg; let hero = await HeroModel.findByHidAndRole(hid, roleId); if (!hero) return resResult(STATUS.HERO_NOT_FIND); await HeroModel.deleteHero(roleId, hid); await SkinModel.deleteByHero(roleId, hid); let role = await RoleModel.findByRoleId(roleId); await PvpDefenseModel.deleteHero(roleId, hid); await RoleCeModel.deleteHero(roleId, hid); await RoleModel.updateRoleInfo(roleId, { topLineup: role.topLineup.filter(cur => cur.hid != hid), topLineupCe: role.topLineupCe - hero.ce, ce: role.ce - hero.ce }); await JewelModel.updateMany({ hid }, { $set: { hid: 0}}); return resResult(STATUS.SUCCESS); } async updateGuild(msg: GuildFormParam, session: BackendSession ) { const uid = session.get('uid'); let params = new GuildFormParam(msg); if(!params.checkParams()) return resResult(STATUS.WRONG_PARMS); let guild = await GuildModel.findByCode(params.code, null, '+members'); let structure = guild.structure||[]; let updateParams: GuildUpdateParam = { code: params.code }; if(params.name && guild.name != params.name) updateParams.name = params.name; if(params.fund != undefined && guild.fund != params.fund) updateParams.fund = params.fund; if(params.notice && guild.notice != params.notice) updateParams.notice = params.notice; if(params.lv && guild.lv != params.lv) updateParams.lv = params.lv; for(let id = GUILD_STRUCTURE.START; id < GUILD_STRUCTURE.END; id ++) { let curStructure = structure.find(cur => cur.id == id); let lv = params.lv; switch(id) { case GUILD_STRUCTURE.ARMY_CENTER: lv = params.lv; break; case GUILD_STRUCTURE.EQUIP_PRODUCE: lv = params.equipProduce; break; case GUILD_STRUCTURE.BOSS: lv = params.boss; break; case GUILD_STRUCTURE.TRAIN: lv = params.train; break; case GUILD_STRUCTURE.DONATE: lv = params.donate; break; case GUILD_STRUCTURE.WISH_POOL: lv = params.wishPool; break; case GUILD_STRUCTURE.STORE: lv = params.store; break; } if(curStructure) { curStructure.lv = lv; } else { structure.push({ id, lv }); } } updateParams.structure = structure; await pushGuildInfoUpdate(params.code, updateParams); // 设置玩家名 if(updateParams.name != undefined || updateParams.lv != undefined) { let arr = []; if(updateParams.name != undefined) { arr.push({ field: 'name', value: updateParams.name }); for(let roleId of guild.members) { await updateUserInfo(REDIS_KEY.USER_INFO, roleId, [{ field: 'guildName', value: updateParams.name }]); } } if(updateParams.lv != undefined) arr.push({ field: 'lv', value: updateParams.lv }); await updateUserInfo(REDIS_KEY.GUILD_INFO, params.code, arr); } if (updateParams.lv != undefined) { let r = new Rank(REDIS_KEY.GUILD_LV_RANK, { serverId: guild.serverId }); await r.setRankWithGuildInfo2(guild.code, updateParams.lv, guild.activeWeekly, guild.lvUpdateTime, guild); } guild = await GuildModel.updateInfo(params.code, updateParams); if(params.trainLv) { await setTrainLv(params.code, params.trainLv); } return resResult(STATUS.SUCCESS); } async dismissGuild(msg: { code: string }, session: BackendSession) { const { code } = msg; let guild = await GuildModel.findByCode(code, null, '+serverId'); if(!guild) return resResult(STATUS.GUILD_NOT_FOUND); if(guild.status == GUILD_STATUS.DISMISSED) return resResult(STATUS.GUILD_DELETE_ERROR); let serverId = guild.serverId; guild = await GuildModel.dismiss(code, serverId); if (!guild) return resResult(STATUS.GUILD_DELETE_ERROR); await UserGuildModel.dismiss(code); const { members } = guild; await RoleModel.dissmissGuild(members); await UserGuildApplyModel.deleteApplyByGuild(code); await this.app.rpc.connector.connectorRemote.setOtherUserGuildSession.broadcast(members.map(roleId => { return { roleId, userGuild: null } })); // 更新session // 删除channel await pushGuildDismiss(code); let r = new Rank(REDIS_KEY.GUILD_ACTIVE_RANK, { serverId }); await r.removeFromRank({ guildCode: code }); let r2 = new Rank(REDIS_KEY.GUILD_LV_RANK, { serverId }); await r2.removeFromRank({ guildCode: code }); let leader = guild.leader; reportTAEvent(leader.roleId, TA_EVENT.GUILD_DISMISS, { name: guild.name, way: GUILD_DISMISS_WAY.BACKEND }); return resResult(STATUS.SUCCESS, { code, status: guild.status }); } async setGuildLeader(msg: { code: string, roleId: string }, session: BackendSession) { const { code, roleId } = msg; let guild = await GuildModel.findByCode(code, null, '+serverId'); if(!guild) return resResult(STATUS.GUILD_NOT_FOUND); if(guild.status == GUILD_STATUS.DISMISSED) return resResult(STATUS.GUILD_DELETE_ERROR); let role = await RoleModel.findByRoleId(roleId); if(!role) return resResult(STATUS.ROLE_NOT_FOUND); let userGuild = await UserGuildModel.getMyGuild(roleId); if(!userGuild || userGuild.guildCode != code) return resResult(STATUS.GUILD_KICK_ERROR); if(userGuild.auth == GUILD_AUTH.LEADER) return resResult(STATUS.GUILD_USER_IS_LEADER); let leader = guild.leader; // 交换 let oldLeaderUserGuild = await UserGuildModel.updateInfo(leader.roleId, { auth: GUILD_AUTH.MEMBER, job: GUILD_JOB.SHIBING }, {}, 'auth'); // 团长撤 await this.app.rpc.connector.connectorRemote.setOtherUserGuildSession.broadcast([{ roleId: leader.roleId, userGuild: oldLeaderUserGuild }]); // 更新session let newLeaderUserGuild = await UserGuildModel.updateInfo(roleId, { auth: GUILD_AUTH.LEADER, job: GUILD_JOB.DAJIANGJUN }, {}, 'auth'); // 最高功勋人升 await this.app.rpc.connector.connectorRemote.setOtherUserGuildSession.broadcast([{ roleId: roleId, userGuild: newLeaderUserGuild }]); // 更新session let managerCntInc = userGuild.auth == GUILD_AUTH.MANAGER ? -1 : 0; // 管理人数 guild = await GuildModel.updateInfo(code, { leader: role._id }, { managerCnt: managerCntInc }, 'managerCnt name'); // 如果有转让团长设置leader // 添加动态 await pushChangeGuildLeader(code, guild.managerCnt, role, leader.roleId); await sendMailByContent(MAIL_TYPE.GUILD_BE_IMPEACH, leader.roleId, { params: [guild.name] }); await sendMailByContent(MAIL_TYPE.GUILD_BE_SET_LEADER, roleId, { params: [guild.name] }); await updateUserInfo(REDIS_KEY.GUILD_INFO, code, [{ field: 'leader', value: new GuildLeader(role) }]); reportTAEvent(roleId, TA_EVENT.GUILD_MASTER_CHANGE, { way: GUILD_MASTER_CHANGE_WAY.BACKEND, change_id_after: roleId }) return resResult(STATUS.SUCCESS, { code }); } async skipEpilogue(msg: { roleId: string, roleName: string }, session: BackendSession) { const { roleId, roleName } = msg; let role = await RoleModel.findByRoleId(roleId); if(!role) return resResult(STATUS.ROLE_NOT_FOUND); if(role.hasInit) return resResult(STATUS.ROLE_HAS_INIT); let checkName = await RoleModel.checkName(roleName, role.serverId); if (checkName) return resResult(STATUS.NAME_HAS_USED); let warStars: WarStar[] = []; let insertParams: DicWar[] = []; let exp = 0; for(let i = 101; i <= 103; i++) { let dicWar = gameData.war.get(i); insertParams.push(dicWar); warStars.push({ id: dicWar.war_id, warType: dicWar.warType, star: 0, stars: [] }); exp += dicWar.kingExp; } let lv = getLvByExp(exp); await RScriptRecordModel.deleteByWarType(roleId, WAR_TYPE.NORMAL); await RScriptRecordModel.insertScripts(roleId, insertParams); let onlineUser = await getRoleOnlineInfo(roleId); await createHeroes(roleId, roleName, onlineUser?.sid, role.serverId, DEFAULT_HEROES.map(hid => ({hid, count: 1})), { roleName, hasInit: true, title: role.title, teraphs: role.teraphs, lv, exp, warStar: warStars }); return resResult(STATUS.SUCCESS); } async reCalCe(msg: { roleId: string }, session: BackendSession) { const { roleId } = msg; let role = await RoleModel.findByRoleId(roleId); let schools = await SchoolModel.findByRoleId(roleId); let jewels = await JewelModel.findbyRole(roleId); let heroes = await HeroModel.findByRole(roleId); let skins = await SkinModel.findbyRole(roleId); let artifacts = await ArtifactModel.findbyRole(roleId); await calculateCeWithRole(HERO_SYSTEM_TYPE.RE_CAL, roleId, role.serverId, null, {}, { role, schools, jewels, heroes, skins, artifacts }); return resResult(STATUS.SUCCESS); } async clearRank(msg: { roleId: string }, session: BackendSession) { let { roleId } = msg; let role = await RoleModel.findByRoleId(roleId); if(!role) return resResult(STATUS.WRONG_PARMS); if(role.blockType != 2) return resResult(STATUS.GM_CANNOT_CLEAR_RANK) let { serverId } = role; await redisClient().zremAsync(new KeyName(REDIS_KEY.TOWER_RANK, { serverId }).getName(), roleId); await redisClient().zremAsync(new KeyName(REDIS_KEY.LADDER, { serverId }).getName(), roleId); await LadderMatchModel.updateByRoleId(roleId, { rank: 0 }); await redisClient().zremAsync(new KeyName(REDIS_KEY.TOP_LINEUP_RANK, { serverId }).getName(), roleId); await redisClient().zremAsync(new KeyName(REDIS_KEY.TOP_HERO_RANK, { serverId }).getName(), roleId); await redisClient().zremAsync(new KeyName(REDIS_KEY.HERO_NUM_RANK, { serverId }).getName(), roleId); await redisClient().zremAsync(new KeyName(REDIS_KEY.SUM_CE_RANK, { serverId }).getName(), roleId); await redisClient().zremAsync(new KeyName(REDIS_KEY.USER_LV, { serverId }).getName(), roleId); await redisClient().zremAsync(new KeyName(REDIS_KEY.MAIN_RANK, { serverId }).getName(), roleId); await redisClient().zremAsync(new KeyName(REDIS_KEY.MAIN_ELITE_RANK, { serverId }).getName(), roleId); let keys = await redisClient().keysAsync(REDIS_KEY.PVP_RANK); for(let key of keys) await redisClient().zremAsync(key, roleId); return resResult(STATUS.SUCCESS); } }