Files
ZYZ/shared/db/LadderMatch.ts

159 lines
7.7 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 BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, mongoose, Ref } from '@typegoose/typegoose';
import { LadderDefense, LadderOppPlayerInDB } 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 findByRank(rank: number) {
const result: LadderMatchType = await LadderMatchModel.findOne({ rank }).lean();
return result;
}
public static async isRankExist(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.heroes.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.heroes.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(serverId: number, roleId: string, rank: number) {
const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ serverId, roleId, rank, locked: 0 }, { $set: { locked: 1 }}, { new: true })
.populate('role', 'roleId roleName head frame spine heads frames spines title lv updatedAt')
.populate('defense.heroes.hero', 'hid skinId quality star colorStar lv')
.lean();
return defense;
}
public static async unlock(serverId: number, roleId: string) {
const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ serverId, roleId }, { $set: { locked: 0 }}, { new: true }).lean();
return defense;
}
public static async changeRank(isSuccess: boolean, attackInfo: { roleId: string }, defenseInfo: { isRobot: boolean, roleId: string, oldRank: number }, times = 0) {
if(times > 10) return { isChange: false }
const session = await mongoose.connection.startSession();
session.startTransaction()
try {
let newAtkLadderMatch: LadderMatchType, newDefLadderMatch: LadderMatchType, isChange = false, endTime = Date.now();
if(defenseInfo.isRobot) {
let atkLadderMatch = await LadderMatchModel.findOne({ roleId: attackInfo.roleId }).lean();
if(isSuccess && atkLadderMatch && (atkLadderMatch.rank == 0 || atkLadderMatch.rank > defenseInfo.oldRank)) {
newAtkLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: attackInfo.roleId }, { $set: { rank: defenseInfo.oldRank, oldRank: atkLadderMatch.rank } }, { new: true }).lean();
isChange = true;
endTime = Date.now();
} else {
newAtkLadderMatch = atkLadderMatch;
}
} else {
let atkLadderMatch = await LadderMatchModel.findOne({ roleId: attackInfo.roleId }).lean();
let defLadderMatch = await LadderMatchModel.findOne({ roleId: defenseInfo.roleId }).lean();
if(isSuccess && atkLadderMatch && defLadderMatch && (atkLadderMatch.rank == 0 || atkLadderMatch.rank > defLadderMatch.rank)) {
newAtkLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: attackInfo.roleId }, { $set: { rank: defLadderMatch.rank, oldRank: atkLadderMatch.rank } }, { new: true }).lean();
newDefLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: defenseInfo.roleId }, { $set: { rank: atkLadderMatch.rank, oldRank: defLadderMatch.rank } }, { new: true }).lean();
isChange = true;
endTime = Date.now();
} else {
newAtkLadderMatch = atkLadderMatch;
newDefLadderMatch = defLadderMatch;
}
}
await session.commitTransaction()
return { isChange, atkLadderMatch: newAtkLadderMatch, defLadderMatch: newDefLadderMatch, endTime }
} catch(e) {
return await this.changeRank(isSuccess, attackInfo, defenseInfo, times + 1);
} finally {
session.endSession()
}
}
public static async updateCe(roleId: string, hid: number, ce: number) {
const rec: LadderMatchType = await LadderMatchModel.findOneAndUpdate(
{ roleId, defense: { $exists: false } },
{ $set: { 'defense.heroes.$[t].ce': ce } },
{ arrayFilters: [{"t.actorId": hid}] }).lean();
return rec
}
}
export const LadderMatchModel = getModelForClass(LadderMatch);
export interface LadderMatchType extends Pick<DocumentType<LadderMatch>, keyof LadderMatch> { };
export type LadderUpdateInter = Partial<LadderMatchType>;