diff --git a/game-server/app.ts b/game-server/app.ts index 47ca14431..6d6d941b0 100644 --- a/game-server/app.ts +++ b/game-server/app.ts @@ -22,6 +22,7 @@ import * as redLockService from './app/services/redLockService'; import _pinus = require('pinus'); import { updateTeamStatus } from './app/services/comBattleService'; import { init } from './app/pubUtils/gmData/gmDataUtil'; +import { addActive } from './app/services/guildService'; const filePath = (_pinus as any).FILEPATH; filePath.MASTER = '/config/master'; filePath.SERVER = '/config/servers'; diff --git a/game-server/app/servers/guild/handler/gateActivityHandler.ts b/game-server/app/servers/guild/handler/gateActivityHandler.ts index 95f9e2108..1bf1ee15e 100644 --- a/game-server/app/servers/guild/handler/gateActivityHandler.ts +++ b/game-server/app/servers/guild/handler/gateActivityHandler.ts @@ -1,11 +1,11 @@ import { Application, BackendSession, ChannelService } from "pinus"; -import { setMedianCe, getMedianCe, getGuildActivityStatus, getRecordScore } from "../../../services/guildActivityService"; +import { setMedianCe, getMedianCe, getGuildActivityStatus, getRecordScore, getGuildActivityObj } from "../../../services/guildActivityService"; import { resResult } from "../../../pubUtils/util"; -import { STATUS, GUILD_ACTIVITY_TYPE } from "../../../consts"; +import { STATUS, GUILD_ACTIVITY_TYPE, GUILD_POINT_WAYS, ENEMIES_TYPE, GET_POINT_WAYS } from "../../../consts"; import { GameModel } from "../../../db/Game"; import { ServerlistModel } from "../../../db/Serverlist"; import { UserGuildActivityRecModel, Record } from "../../../db/UserGuildActivityRec"; -import { UserGuildModel } from "../../../db/UserGuild"; +import { GateMembersRec } from "../../../domain/battleField/guildActivity"; import { GUILDACTIVITY } from "../../../pubUtils/dicParam"; import { GuildActivityRecordModel } from "../../../db/GuildActivityRec"; import { RoleModel, RoleType } from "../../../db/Role"; @@ -13,6 +13,8 @@ import { GuildModel } from "../../../db/Guild"; import { RankParam, GuildRankParam } from "../../../domain/rank"; import { setRank, getGuildKeyName, getRankScore, getRank, getUnionRank } from "../../../services/redisService"; import { REDIS_KEY } from "../../../consts"; +import { addActive } from "../../../services/guildService"; +import { gameData } from "../../../pubUtils/data"; export default function (app: Application) { return new GateActivityHandler(app); @@ -24,8 +26,6 @@ export class GateActivityHandler { this.channelService = app.get('channelService'); } - private gateHp: Map = new Map(); // 城门血条,每个军团有一条血条 - private members: Map> = new Map(); // 每个军团参与的成员 private aid = GUILD_ACTIVITY_TYPE.GATE_ACTIVITY; // 蛮夷入侵id // 进入蛮夷入侵界面 @@ -86,8 +86,13 @@ export class GateActivityHandler { const guildCode = session.get('guildCode'); if(!guildCode) return resResult(STATUS.GUILD_AUTH_NOT_ENOUGH); + let gateHp = getGuildActivityObj(this.aid).getGateHpAndInc(guildCode); + if(gateHp <= 0) return resResult(STATUS.GATE_HP_IS_ZERO); + let statusResult = getGuildActivityStatus(this.aid); if(!statusResult) return resResult(STATUS.DIC_DATA_NOT_FOUND); + // TODO 测试完成后去掉这条判断 + // if(!statusResult.isOpen) return resResult(STATUS.GUILD_ACTIVITY_NOT_OPEN); let guildActivityRec = await GuildActivityRecordModel.getRecord(guildCode, serverId, this.aid); if(!guildActivityRec) return resResult(STATUS.INTERNAL_ERR); @@ -96,11 +101,12 @@ export class GateActivityHandler { let myGuildActivityRec = await UserGuildActivityRecModel.getRecord(roleId, roleName, guildCode, serverId, sourceCode, heroes, this.aid); let { code, challengeCnt } = myGuildActivityRec; + // 更新公会参与的玩家 + getGuildActivityObj(this.aid).pushMembers(guildCode, roleId); + // 返回当前军团总军功 let guildScore = await getRankScore(REDIS_KEY.GUILD_ACTIVITY, serverId, guildCode); - // 城门血条 - let gateHp = this.gateHp.get(guildCode)||GUILDACTIVITY.GATEACTIVITY_GATEHP; // 前一天中位数战力 let medianCe = await getMedianCe(serverId); @@ -126,27 +132,32 @@ export class GateActivityHandler { let statusResult = getGuildActivityStatus(this.aid); if(!statusResult) return resResult(STATUS.DIC_DATA_NOT_FOUND); + // TODO 测试完成后去掉这条判断 + // if(!statusResult.isOpen) return resResult(STATUS.GUILD_ACTIVITY_NOT_OPEN); + + let gateHp = getGuildActivityObj(this.aid).getGateHpAndInc(guildCode); + if(gateHp <= 0) return resResult(STATUS.GATE_HP_IS_ZERO); // 计算record内得分 - // TODO 防刷分,应加入记录玩家操作 - let scoreResult = getRecordScore(this.aid, record); + let memberRecord = getGuildActivityObj(this.aid).getMemberRecord(code, roleId); + let scoreResult = getRecordScore(this.aid, record, memberRecord); if(!scoreResult) return resResult(STATUS.DIC_DATA_NOT_FOUND); - let { score, newRecords } = scoreResult; + let { score, newRecords, memberRecord: newMemberRecord } = scoreResult; + getGuildActivityObj(this.aid).setMemberRecord(code, memberRecord); // 更新redis数据 let role = await RoleModel.findByRoleId(roleId); let { lv, vLv, head, frame, spine, title } = role; let userParam = new RankParam(roleName, lv, vLv, head, frame, spine, title); - let myScore = await setRank(getGuildKeyName(REDIS_KEY.USER_GUILD_ACTIVITY, guildCode), serverId, guildCode, score, Date.now(), userParam); + let myScore = await setRank(getGuildKeyName(REDIS_KEY.USER_GUILD_ACTIVITY, guildCode), serverId, roleId, score, Date.now(), userParam); let guild = await GuildModel.findByCode(guildCode, serverId); let leader = guild.leader; let params = new GuildRankParam(guild.icon, guild.name, guild.lv, leader); - let guildScore = await setRank(REDIS_KEY.GUILD_ACTIVITY, serverId, guild.code, 0, Date.now(), params, true); + let guildScore = await setRank(REDIS_KEY.GUILD_ACTIVITY, serverId, guild.code, score, Date.now(), params, true); // 更新数据库 let rec = await UserGuildActivityRecModel.pushRecord(code, newRecords); - let gateHp = this.gateHp.get(guildCode)||GUILDACTIVITY.GATEACTIVITY_GATEHP; return resResult(STATUS.SUCCESS, { code: rec.code, @@ -158,13 +169,105 @@ export class GateActivityHandler { } // 上报敌军攻打城门情况 - async hitGate(msg: {}, session: BackendSession) { + async hitGate(msg: { code: string, damage: number }, session: BackendSession) { + let roleId = session.get('roleId'); + let guildCode = session.get('guildCode'); + let serverId = session.get('serverId'); + let { code, damage } = msg; + let gateHp = getGuildActivityObj(this.aid).getGateHpAndInc(guildCode); + if(gateHp <= 0) return resResult(STATUS.GATE_HP_IS_ZERO); + + let statusResult = getGuildActivityStatus(this.aid); + if(!statusResult) return resResult(STATUS.DIC_DATA_NOT_FOUND); + // TODO 测试完成后去掉这条判断 + // if(!statusResult.isOpen) return resResult(STATUS.GUILD_ACTIVITY_NOT_OPEN); + + gateHp = getGuildActivityObj(this.aid).getGateHpAndInc(guildCode, -1 * damage); + if(gateHp <= 0) { + // TODO 推送 停止活动 + } + // TODO 推送 城门血量 + + // 返回当前军团总军功 + let guildScore = await getRankScore(REDIS_KEY.GUILD_ACTIVITY, serverId, guildCode); + let myScore = await getRankScore(getGuildKeyName(REDIS_KEY.USER_GUILD_ACTIVITY, guildCode), serverId, roleId, true); + + return resResult(STATUS.SUCCESS, { + code, + ...statusResult, + guildScore, + myScore, + gateHp + }) } // 结束挑战 - async battleEnd(msg: { count: number }, session: BackendSession) { + async battleEnd(msg: { code: string, isSuccess: boolean }, session: BackendSession) { + let roleId = session.get('roleId'); + let roleName = session.get('roleName'); + let guildCode = session.get('guildCode'); + let serverId = session.get('serverId'); + let { code, isSuccess } = msg; + + let statusResult = getGuildActivityStatus(this.aid); + if(!statusResult) return resResult(STATUS.DIC_DATA_NOT_FOUND); + + // 更新userGuildActivityRecord + let myGuildActivityRec = await UserGuildActivityRecModel.updateInfo(code, { isSuccess, isCompleted: true }); + if(!myGuildActivityRec) return resResult(STATUS.INTERNAL_ERR); + + // 功劳簿计算 + let { record } = myGuildActivityRec; + let round = 0, enemyCnt = 0, littleBossCnt = 0, bossCnt = 0; + for(let { enemyType, round: r } of record) { + if(r > round) round = r; + if(enemyType == ENEMIES_TYPE.ENEMY) { + enemyCnt ++; + } else if (enemyType == ENEMIES_TYPE.LITTLE_BOSS) { + littleBossCnt ++; + } else if (enemyType == ENEMIES_TYPE.BOSS) { + bossCnt ++; + } + } + + if(isSuccess) { + let score = gameData.gateActivityPoint.get(GET_POINT_WAYS.DEFENSE_SUCCESS); + // 更新redis数据 + let role = await RoleModel.findByRoleId(roleId); + let { lv, vLv, head, frame, spine, title } = role; + let userParam = new RankParam(roleName, lv, vLv, head, frame, spine, title); + await setRank(getGuildKeyName(REDIS_KEY.USER_GUILD_ACTIVITY, guildCode), serverId, guildCode, score, Date.now(), userParam); + + let guild = await GuildModel.findByCode(guildCode, serverId); + let leader = guild.leader; + let params = new GuildRankParam(guild.icon, guild.name, guild.lv, leader); + await setRank(REDIS_KEY.GUILD_ACTIVITY, serverId, guild.code, score, Date.now(), params, true); + } + + // 发放活跃 + await addActive(roleId, serverId, GUILD_POINT_WAYS.ACTIVITY); //获得活跃值 + // 返回当前军团总军功 + let guildScore = await getRankScore(REDIS_KEY.GUILD_ACTIVITY, serverId, guildCode); + let myScore = await getRankScore(getGuildKeyName(REDIS_KEY.USER_GUILD_ACTIVITY, guildCode), serverId, roleId, true); + let gateHp = getGuildActivityObj(this.aid).getGateHpAndInc(guildCode); + + getGuildActivityObj(this.aid).delMemberRecord(code); + let info = { + round, + enemyCnt, littleBossCnt, bossCnt, + isSuccess + } + + return resResult(STATUS.SUCCESS, { + code, + ...statusResult, + guildScore, + myScore, + gateHp, + info + }) } @@ -177,6 +280,12 @@ export class GateActivityHandler { } } + async debugGetPrivate(msg: { }, session: BackendSession) { + let guildCode = session.get('guildCode'); + let res = getGuildActivityObj(this.aid).getObj(guildCode); + return resResult(STATUS.SUCCESS, res) + } + async test() { let result = await setMedianCe(); diff --git a/game-server/app/services/guildActivityService.ts b/game-server/app/services/guildActivityService.ts index 5f9f6c73c..f90fdee00 100644 --- a/game-server/app/services/guildActivityService.ts +++ b/game-server/app/services/guildActivityService.ts @@ -4,8 +4,19 @@ import { reduceCe } from "../pubUtils/util"; import { GUILDACTIVITY } from "../pubUtils/dicParam"; import { gameData } from "../pubUtils/data"; import { getCurHourPoint, getCutDay, nowSeconds } from "../pubUtils/timeUtil"; -import { GUILD_ACTIVITY_STATUS } from "../consts"; +import { GUILD_ACTIVITY_STATUS, GET_POINT_WAYS, GUILD_ACTIVITY_TYPE } from "../consts"; import { Record } from "../db/UserGuildActivityRec"; +import { GateMembersRec, GateActivityObject } from "../domain/battleField/guildActivity"; + +let gateActivityObj: GateActivityObject; +export function getGuildActivityObj(aid: number) { + if(aid == GUILD_ACTIVITY_TYPE.GATE_ACTIVITY) { + if(!gateActivityObj) { + gateActivityObj = new GateActivityObject() + } + return gateActivityObj; + } +} /** * 定时任务,获得前一天的活跃玩家中位数武将战力 @@ -75,32 +86,38 @@ export function getGuildActivityStatus(id: number) { } } -export function getRecordScore(aid: number, record: { round: number, dataId: number }[]) { +/** + * 根据每回合上报数据判断军功 + * @param aid + * @param record + * @param memberRecord + */ +export function getRecordScore(aid: number, record: { round: number, dataId: number }[], memberRecord: GateMembersRec) { let dicGuildActivity = gameData.guildActivity.get(aid); - console.log('xxxx', dicGuildActivity.warid) if(!dicGuildActivity) return false; let dicWarJson = gameData.warJson.get(dicGuildActivity.warid); if(!dicWarJson) return false; - let curRound = record[0]?.round; - let sum = 0, newRecords = new Array() + let { round: curRound, enemies: historyEnemies} = memberRecord; + let sum = 0, newRecords = new Array(); for(let {round, dataId} of record) { - let enemy = dicWarJson.find(cur => cur.dataId == dataId); - console.log('yyyy', enemy.enemyType); - let enemyType = enemy.enemyType; - let score = gameData.gateActivityPoint.get(enemyType); - newRecords.push({ round, dataId, score}); - sum += score; - console.log('***%*****', sum, score) - if(round != curRound) { // 每回合开始得10分 - sum += gameData.gateActivityPoint.get(1); - console.log('***%%*****', sum) - curRound = round; + if(!historyEnemies.includes(dataId)) { + + let enemy = dicWarJson.find(cur => cur.dataId == dataId); + let enemyType = enemy.enemyType; + let score = gameData.gateActivityPoint.get(enemyType); + newRecords.push({ round, dataId, score, enemyType}); + sum += score; + if(round > curRound) { // 每回合开始得10分 + sum += gameData.gateActivityPoint.get(GET_POINT_WAYS.ROUND_START); + curRound = round; + } + + historyEnemies.push(dataId); } } - console.log('***&**', sum) - return { score: sum, newRecords } + return { score: sum, newRecords, memberRecord } } \ No newline at end of file diff --git a/game-server/app/services/redisService.ts b/game-server/app/services/redisService.ts index 8d8bacdd9..67e39400b 100644 --- a/game-server/app/services/redisService.ts +++ b/game-server/app/services/redisService.ts @@ -628,8 +628,18 @@ export async function getMyUnionRank(key: string, serverId: number, roleId: stri return myRank + 1; } -export async function getRankScore(key: string, serverId: number, field: string) { +/** + * 获取拼接得分的排行榜的某一个人的得分 + * @param key REDIS_KEY中配置的 + * @param serverId 分服 + * @param field 查询的人 + */ +export async function getRankScore(key: string, serverId: number, field: string, needDecode = false) { let score = await redisClient().zscoreAsync(getKeyName(key, serverId), field); + if(!score) score = 0; + if(needDecode) { + score = decodeScoreWithTime(score.toString()); + } return score; } diff --git a/shared/consts/constModules/guildConst.ts b/shared/consts/constModules/guildConst.ts index 2c8563cd0..489628ebc 100644 --- a/shared/consts/constModules/guildConst.ts +++ b/shared/consts/constModules/guildConst.ts @@ -148,4 +148,20 @@ export enum GUILD_ACTIVITY_STATUS { WAITING = 0, START = 1, END = 2 +} + +// 积分获取类型 +export enum GET_POINT_WAYS { + ROUND_START = 1, + ENEMY = 2, // 小兵 + LITTLE_BOSS = 3, // 小boss + BOSS = 4, // 大boss + DEFENSE_SUCCESS = 5 +} + +// 敌军类型,和上面的相对应 +export enum ENEMIES_TYPE { + ENEMY = 2, // 小兵 + LITTLE_BOSS = 3, // 小boss + BOSS = 4, // 大boss } \ No newline at end of file diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index 4c96a884f..772152f9c 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -197,6 +197,7 @@ export const STATUS = { // 军团活动 21100-21199 GUILD_ACTIVITY_NOT_OPEN: { code: 21100, simStr: '活动未开放' }, + GATE_HP_IS_ZERO: { code: 21101, simStr: '城门已被击破' }, // 通用 30000 - 30099 DIC_DATA_NOT_FOUND: { code: 30000, simStr: '数据表未找到' }, diff --git a/shared/db/UserGuildActivityRec.ts b/shared/db/UserGuildActivityRec.ts index 491802455..402b19375 100644 --- a/shared/db/UserGuildActivityRec.ts +++ b/shared/db/UserGuildActivityRec.ts @@ -10,8 +10,12 @@ export class Record { @prop({ required: true }) dataId: number; // 出兵表上的dataId + @prop({ required: true }) + enemyType: number; // 敌人类型 2-小兵 3-小boss 4-大boss + @prop({ required: true }) score: number; // 得分 + } @index({ code: 1 }) @@ -55,9 +59,6 @@ export default class UserGuildActivityRec extends BaseModel { @prop({ required: true, type: Number }) heroes: number[]; // 使用的武将 - @prop({ required: true }) - round: number; // 坚持回合数 - @prop({ required: true }) score: number; // 个人总军功 @@ -76,7 +77,7 @@ export default class UserGuildActivityRec extends BaseModel { { $setOnInsert: update }, {new: true, upsert: true}).lean(); if(heroes.length > 0 && rec) { - rec = await UserGuildActivityRecModel.findOneAndUpdate( { code: rec.code}, { $push: { heroes: { $each: heroes}}}, {new: true}).lean(); + rec = await UserGuildActivityRecModel.findOneAndUpdate( { code: rec.code}, { $push: { heroes: { $each: heroes}}, $inc: { challengeCnt: 1 }}, {new: true}).lean(); } return rec; } @@ -89,6 +90,11 @@ export default class UserGuildActivityRec extends BaseModel { ).lean(); return rec; } + + public static async updateInfo(code: string, update: UserGuildActivityRecUpdateParam) { + let rec: UserGuildActivityRec = await UserGuildActivityRecModel.findOneAndUpdate({ code }, { $set: update }, { new: true }).lean(); + return rec; + } } export const UserGuildActivityRecModel = getModelForClass(UserGuildActivityRec); diff --git a/shared/domain/battleField/guildActivity.ts b/shared/domain/battleField/guildActivity.ts new file mode 100644 index 000000000..cbfe0beba --- /dev/null +++ b/shared/domain/battleField/guildActivity.ts @@ -0,0 +1,58 @@ +import { GUILDACTIVITY } from "../../pubUtils/dicParam"; + +export class GateMembersRec { + roleId: string; + round: number = 0; + enemies: number[] = []; + constructor(roleId: string) { + this.roleId = roleId; + } +} + +export class GateActivityObject { + private gateHp: Map = new Map(); // 城门血条,每个军团有一条血条 + private members: Map> = new Map(); // 每个军团参与的成员 + private membersRecord: Map = new Map(); // 每个成员的回合数和敌军数,防刷 + + public getObj(guildCode: string) { + return { + gateHp: this.getGateHpAndInc(guildCode), + members: this.members.get(guildCode), + memberesRecord: this.membersRecord.get(guildCode) + } + } + + public getGateHpAndInc(guildCode: string, inc: number = 0) { + let gateHp = this.gateHp.get(guildCode); + if(!this.gateHp.has(guildCode)) { + gateHp = GUILDACTIVITY.GATEACTIVITY_GATEHP; + } + if(inc != 0) { + gateHp += inc; + this.gateHp.set(guildCode, gateHp); + } + if(gateHp <= 0) gateHp = 0; + return gateHp + } + + public pushMembers(guildCode: string, roleId: string) { + + if(this.members.has(guildCode)) { + this.members.get(guildCode).push(roleId); + } else { + this.members.set(guildCode, [roleId]); + } + } + + public getMemberRecord(code: string, roleId: string) { + return this.membersRecord.get(code)||new GateMembersRec(roleId) + } + + public setMemberRecord(code: string, newMemberRecord: GateMembersRec) { + this.membersRecord.set(code, newMemberRecord); + } + + public delMemberRecord(code: string) { + this.membersRecord.delete(code); + } +} \ No newline at end of file diff --git a/shared/pubUtils/dictionary/DicGuildActiveWays.ts b/shared/pubUtils/dictionary/DicGuildActiveWays.ts index 66b50bda4..ee65f7590 100644 --- a/shared/pubUtils/dictionary/DicGuildActiveWays.ts +++ b/shared/pubUtils/dictionary/DicGuildActiveWays.ts @@ -20,6 +20,7 @@ export const dicGuildActiveWays = new Map(); arr.forEach(o => { o.activePoint = decodeIdCntArrayStr(o.activePoint, 1); + if(!o.count) o.count = o.cout; dicGuildActiveWays.set(o.id, o); }); arr = undefined; \ No newline at end of file