Files
ZYZ/game-server/app/servers/gm/handler/gmRoleHandler.ts
2023-08-02 13:33:18 +08:00

437 lines
21 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 = <RoleType>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 = <RoleType>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);
}
}