132 lines
6.3 KiB
TypeScript
132 lines
6.3 KiB
TypeScript
import BaseModel from './BaseModel';
|
||
import { index, getModelForClass, prop, DocumentType, mongoose, Ref } from '@typegoose/typegoose';
|
||
import { LadderDefense, LadderOppPlayerInDB, LadderOppPlayerInfo } from '../domain/battleField/ladder';
|
||
import Role from './Role';
|
||
|
||
@index({ roleId: 1 })
|
||
export default class LadderMatch extends BaseModel {
|
||
@prop({ required: true, default: 0 })
|
||
serverId: number; // 角色 id
|
||
@prop({ required: true, default: '' })
|
||
roleId: string; // 角色 id
|
||
@prop({ ref: 'Role', type: mongoose.Schema.Types.ObjectId })
|
||
role: Ref<Role>;
|
||
@prop({ required: true, default: 0 })
|
||
rank: number; // 排名
|
||
@prop({ required: true, default: 0 })
|
||
oldRank: number; // 交换前排名
|
||
@prop({ required: true, default: 0 })
|
||
historyRank: number; // 历史最高排名
|
||
|
||
@prop({ required: true, default: 0 })
|
||
locked: number; // 是否被挑战
|
||
|
||
@prop({ required: true, default: null, _id: false })
|
||
defense: LadderDefense;
|
||
|
||
@prop({ required: true, type: LadderOppPlayerInDB, default: [], _id: false })
|
||
oppPlayers: LadderOppPlayerInDB[];
|
||
|
||
@prop({ required: true, default: () => { return new Date() } })
|
||
refDaily: Date; // 每日刷新,控制refOppCnt和setAttackCnt
|
||
@prop({ required: true, default: 0 })
|
||
challengeCnt: number; // 挑战次数
|
||
@prop({ required: true, default: 0 })
|
||
buyCnt: number; // 购买次数
|
||
@prop({ required: true, default: 0 })
|
||
refOppCnt: number; // 刷新对手次数
|
||
|
||
public static async findByRoleId(roleId: string) {
|
||
const result: LadderMatchType = await LadderMatchModel.findOne({ roleId }).lean();
|
||
return result;
|
||
}
|
||
|
||
public static async checkByRank(rank: number) {
|
||
const result = await LadderMatchModel.exists({ rank });
|
||
return result;
|
||
}
|
||
|
||
public static async findByRoleIdAndInclude(roleId: string) {
|
||
const result: LadderMatchType = await LadderMatchModel.findOne({ roleId })
|
||
.populate('role', 'roleId roleName head frame spine heads frames spines title lv updatedAt')
|
||
.populate('defense.hero', 'hid skinId quality star colorStar lv')
|
||
.lean();
|
||
return result;
|
||
}
|
||
|
||
public static async createLadder(params: LadderUpdateInter) {
|
||
const doc = new LadderMatchModel();
|
||
|
||
const update = Object.assign(doc.toJSON(), params);
|
||
const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ roleId: params.roleId }, { $set: update}, { upsert: true, new: true }).lean();
|
||
return defense;
|
||
|
||
}
|
||
|
||
public static async updateByRoleId(roleId: string, params: LadderUpdateInter) {
|
||
const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ roleId }, { $set: params}, { new: true }).lean();
|
||
return defense;
|
||
}
|
||
|
||
public static async updateByRoleIdAndInclude(roleId: string, params: LadderUpdateInter) {
|
||
const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ roleId }, { $set: params}, { new: true })
|
||
.populate('role', 'roleId roleName head frame spine heads frames spines title lv updatedAt')
|
||
.populate('defense.hero', 'hid skinId quality star colorStar lv')
|
||
.lean();
|
||
return defense;
|
||
}
|
||
public static async findAll(serverId: number) {
|
||
let result: LadderMatchType[] = [], latestTime = new Date();
|
||
while(latestTime) {
|
||
let ladderMatch = await LadderMatchModel.find({ serverId, rank: { $gt: 0 }, createdAt: { $lt: latestTime } })
|
||
.sort({ createdAt: -1 })
|
||
.populate('role', 'roleId roleName head frame spine heads frames spines title lv updatedAt')
|
||
.limit(1000);
|
||
result.push(...ladderMatch);
|
||
latestTime = ladderMatch[ladderMatch.length - 1]?.createdAt;
|
||
}
|
||
return result
|
||
}
|
||
|
||
public static async lock(roleId: string, rank: number) {
|
||
const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ roleId, rank, locked: 0 }, { $set: { locked: 1 }}, { new: true }).lean();
|
||
return defense;
|
||
}
|
||
|
||
public static async changeRank(isSuccess: boolean, attackInfo: LadderOppPlayerInfo, defenseInfo: LadderOppPlayerInfo, times = 0) {
|
||
if(times > 10) return { isChange: false }
|
||
const session = await mongoose.connection.startSession();
|
||
session.startTransaction()
|
||
|
||
try {
|
||
|
||
let atkLadderMatch: LadderMatchType, defLadderMatch: LadderMatchType, isChange = false;
|
||
if(defenseInfo.isRobot) {
|
||
atkLadderMatch = await LadderMatchModel.findOne({ roleId: attackInfo.roleId }).lean();
|
||
if(isSuccess && atkLadderMatch && atkLadderMatch.rank > defenseInfo.oldRank) {
|
||
atkLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: attackInfo.roleId }, { $set: { rank: defenseInfo.oldRank, oldRank: atkLadderMatch.rank } }, { new: true }).lean();
|
||
isChange = true;
|
||
}
|
||
} else {
|
||
atkLadderMatch = await LadderMatchModel.findOne({ roleId: attackInfo.roleId }).lean();
|
||
defLadderMatch = await LadderMatchModel.findOne({ roleId: defenseInfo.roleId }).lean();
|
||
if(isSuccess && atkLadderMatch && defLadderMatch && atkLadderMatch.rank > defLadderMatch.rank) {
|
||
atkLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: attackInfo.roleId }, { $set: { rank: defLadderMatch.rank, oldRank: atkLadderMatch.rank } }, { new: true }).lean();
|
||
defLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: defenseInfo.roleId }, { $set: { rank: atkLadderMatch.rank, oldRank: defLadderMatch.rank } }, { new: true }).lean();
|
||
isChange = true;
|
||
}
|
||
}
|
||
await session.commitTransaction()
|
||
return { isChange, atkLadderMatch, defLadderMatch }
|
||
} catch(e) {
|
||
return await this.changeRank(isSuccess, attackInfo, defenseInfo, times + 1);
|
||
} finally {
|
||
session.endSession()
|
||
}
|
||
}
|
||
}
|
||
|
||
export const LadderMatchModel = getModelForClass(LadderMatch);
|
||
|
||
export interface LadderMatchType extends Pick<DocumentType<LadderMatch>, keyof LadderMatch> { };
|
||
export type LadderUpdateInter = Partial<LadderMatchType>; |