Files
ZYZ/game-server/app/servers/guild/handler/auctionHandler.ts

400 lines
18 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 { DividendModel, DividendType } from './../../../db/Dividend';
import { Application, BackendSession, ChannelService, HandlerService, pinus, } from "pinus";
import { AUCTION_STAGE, DEBUG_MAGIC_WORD, STATUS, CURRENCY_BY_TYPE, CURRENCY_TYPE, DATA_NAME, LOT_STATUS, CHANNEL_PREFIX, MAIL_TYPE, ITEM_CHANGE_REASON, TA_EVENT, ROLE_RECEIVE_STATUS, PUSH_ROUTE, AUCTION_BID_EXTEND_TIME } from "../../../consts";
import { LotModel, LotParam } from "../../../db/Lot";
import { ItemReward } from "../../../domain/dbGeneral";
import { genCode, resResult } from "../../../pubUtils/util";
import { auctionStage, calculateDividend, genAuction, sendUngotDividend, startGuildAuction, startWorldAuction, stopAuction, todayGuildBegin, getBasePrice, debugAuctionLots, officialAuctionLots, auctionBidStatus, getMaxPrice, guildBidStatus, getAuction, pushAuctionOver, pushAuctionUpdate, processDividendFormat, processSingleDividendFormat, tomorrowGuildBegin, processLotsFormat, processSingleLotFormat, getAuctionRewardByPoolId, getLotStatus, extendLotTime } from "../../../services/auctionService";
import { addItems, getGoldObject, handleCost } from '../../../services/role/rewardService';
import { getSimpleRoleInfo } from '../../../services/roleService';
import { getRoleOnlineInfo } from '../../../services/redisService';
import { lockData } from '../../../services/redLockService';
import { GuildModel } from '../../../db/Guild';
import { RoleModel, RoleType } from '../../../db/Role';
import { openGuildRefine } from '../../../services/guildRefineService';
import { unlockTrain } from '../../../services/guildTrainService';
import { UserGuildModel } from '../../../db/UserGuild';
import { UserGuildApplyModel } from '../../../db/UserGuildApply';
import * as dicParam from '../../../pubUtils/dicParam';
import { gameData } from '../../../pubUtils/data';
import { sendMailByContent } from '../../../services/mailService';
import { reportTAEvent } from '../../../services/sdkService';
import { sendMessageToGuildWithSuc, sendMessageToServerWithSuc } from '../../../services/pushService';
import { LOTS_KEEP_TO_WORLD_CNT } from '../../../consts';
export default function (app: Application) {
new HandlerService(app, {});
return new AuctionHandler(app);
}
export class AuctionHandler {
channelService: ChannelService;
constructor(private app: Application) {
this.channelService = app.get('channelService');
}
async getAuction(msg: { magicWord: string }, session: BackendSession) {
const { magicWord } = msg;
const guildCode = session.get('guildCode');
let result = await getAuction(guildCode, session, magicWord);
return resResult(STATUS.SUCCESS, result);
}
async leaveAuction(msg: {}, session: BackendSession) {
return resResult(STATUS.SUCCESS);
}
async offer(msg: { code: string, max: boolean, auctionStage: number, magicWord: string }, session: BackendSession) {
const { code, max, auctionStage, magicWord } = msg;
const roleId = session.get('roleId');
const sid = session.get('sid');
const serverId = session.get('serverId');
const guildCode = session.get('guildCode');
const ip = session.get('ip');
let res: any = await lockData(serverId, DATA_NAME.AUCTION_LOT, '');// 加锁
try {
if (!!res.err) {
return resResult(STATUS.REDLOCK_ERR);
}
const lot = await LotModel.findLot(code);
if (!lot) {
res.releaseCallback();
return resResult(STATUS.GUILD_LOT_NOT_FOUND);
}
if (lot.status === LOT_STATUS.SOLD || lot.status === LOT_STATUS.MAX) {
res.releaseCallback();
return resResult(STATUS.GUILD_LOT_HAS_SOLD);
}
if (auctionStage === AUCTION_STAGE.GUILD && lot.guildCode !== guildCode) {
res.releaseCallback();
return resResult(STATUS.AUCTION_GUILD_MEMBER_ONLY);
}
let { curBuyer, curPrice, prePrice, maxPrice, gid, count, bidRoles, watchingRoles, seq, begin, auctionStage: lotAuctionStage } = lot;
if (auctionStage != lotAuctionStage) {
res.releaseCallback();
return resResult(STATUS.AUCITON_STAGE_ERR);
}
if (curBuyer === roleId && !max) {
res.releaseCallback();
return resResult(STATUS.LOT_OFFER_SERIAL);
}
let newPrice = Math.floor(curPrice * dicParam.GUILD_AUCTION.AUCTION_PRICE_RISE);
let maxFlag = max;
if (maxFlag) {
curPrice = maxPrice;
}
if (curPrice >= maxPrice) {
curPrice = maxPrice;
newPrice = maxPrice;
maxFlag = true;
}
if(newPrice > maxPrice) {
newPrice = maxPrice;
}
const costRes = await handleCost(roleId, sid, [{ id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD), count: curPrice }], ITEM_CHANGE_REASON.AUCTION_OFFER);
if (!costRes) {
res.releaseCallback();
return resResult(STATUS.ROLE_COIN_NOT_ENOUGH);
}
bidRoles.push({ roleId, price: newPrice, time: new Date() });
let lotStatus = await getLotStatus(auctionStage, max, maxFlag)
let update: LotParam = { code, curBuyer: roleId, curPrice: newPrice, auctionStage, prePrice: curPrice, bidRoles, status: lotStatus, watchingRoles: Array.from(new Set([...watchingRoles, roleId])), seq: 0 };
if(lotStatus == LOT_STATUS.BIDDING) update.end = new Date(Date.now() + AUCTION_BID_EXTEND_TIME * 1000);
const newLot = await LotModel.updateLot(update);
if(!newLot) {
// 如果拍卖行状态不对那回退handleCost
if (curBuyer && prePrice > 0) {
await sendMailByContent(MAIL_TYPE.AUCTION_OVER, roleId, { goods: [getGoldObject(curPrice)] });
}
res.releaseCallback();
return resResult(STATUS.GUILD_LOT_HAS_SOLD);
} else {
if (curBuyer && prePrice > 0) {
await sendMailByContent(MAIL_TYPE.AUCTION_OVER, curBuyer, { goods: [getGoldObject(prePrice)] });
}
if (maxFlag) {
newPrice = maxPrice;
await sendMailByContent(MAIL_TYPE.AUTION_REWARD, roleId, { goods: [{ id: gid, count }] });
let dicGoods = gameData.goods.get(gid);
reportTAEvent(roleId, TA_EVENT.AUCTION_ITEM_GET, { item_name: dicGoods?.name, item_count: count, deel_price: newPrice }, ip);
}
}
await extendLotTime(newLot);
if(seq <= LOTS_KEEP_TO_WORLD_CNT && seq > 0) await LotModel.updateOne({ begin, gid, count, status: LOT_STATUS.DEFAULT, serverId, seq: { $gt: LOTS_KEEP_TO_WORLD_CNT } }, { $set: { seq }});
await pushAuctionOver(newLot); // 推送竞价超过标志
res.releaseCallback();
const incPrice = curPrice - prePrice > 0? prePrice: 0;
let newDividend: DividendType = null;
if (auctionStage === AUCTION_STAGE.GUILD) {
const dividend = await DividendModel.updateLot(code, gid, curPrice, incPrice, max);
newDividend = await calculateDividend(dividend);
await sendMessageToGuildWithSuc(guildCode, PUSH_ROUTE.DIVIDEND_UPDATE, { dividends: processDividendFormat([newDividend]) })
}
let newLotResult = processSingleLotFormat(newLot);
return resResult(STATUS.SUCCESS, { lot: newLotResult, dividend: processSingleDividendFormat(newDividend) });
} catch (e) {
console.log('offer got err:', e);
res.releaseCallback();
return resResult(STATUS.INTERNAL_ERR);
}
}
async watchLot(msg: { code: string }, session: BackendSession) {
const roleId = session.get('roleId');
const { code } = msg;
const lot = await LotModel.watchLot(code, roleId);
if (!lot) return resResult(STATUS.WRONG_PARMS);
return resResult(STATUS.SUCCESS, { lot: processSingleLotFormat(lot) });
}
async unWatchLot(msg: { code: string }, session: BackendSession) {
const roleId = session.get('roleId');
const { code } = msg;
const lot = await LotModel.unWatchLot(code, roleId);
if (!lot) return resResult(STATUS.WRONG_PARMS);
return resResult(STATUS.SUCCESS, { lot: processSingleLotFormat(lot) });
}
async checkDividend(msg: {}, session: BackendSession) {
const begin = await todayGuildBegin();
const tomorrowBegin = await tomorrowGuildBegin();
const guildCode = session.get('guildCode');
if(guildCode) {
const dividends = await DividendModel.findGuildDividendsByBegin(guildCode, [begin, tomorrowBegin]);
return resResult(STATUS.SUCCESS, { dividends: processDividendFormat(dividends) });
} else {
let roleId = session.get('roleId');
const dividends = await DividendModel.findDividendByRoleAndBegin(roleId, [begin, tomorrowBegin]);
return resResult(STATUS.SUCCESS, { dividends: processDividendFormat(dividends) });
}
}
async getDividend(msg: { code: string }, session: BackendSession) {
const roleId = session.get('roleId');
const sid = session.get('sid');
const roleName = session.get('roleName');
const { code } = msg;
const dividendData = await DividendModel.findReadyDividend(code);
if (!dividendData) return resResult(STATUS.DIVIDEND_NOT_READY);
const { dividends } = dividendData;
const dividend = dividends.find(item => { return item.roleId === roleId });
if (!dividend || dividend.status == ROLE_RECEIVE_STATUS.YES) return resResult(STATUS.DIVIDEND_GUILD_PLAYER_ONLY);
let goods = await addItems(roleId, roleName, sid, [{ id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD), count: dividend.total }], ITEM_CHANGE_REASON.AUCTION_DIVIDEND);
await DividendModel.updateReceiveStatus(dividendData.code, roleId);
dividend.status = ROLE_RECEIVE_STATUS.YES;
return resResult(STATUS.SUCCESS, { dividend, goods });
}
async myWatching(msg: {}, session: BackendSession) {
const roleId = session.get('roleId');
const serverId = session.get('serverId');
const begin = await todayGuildBegin();
const lots = await LotModel.watchingLotsByBegin(serverId, roleId, begin);
const stage = await auctionStage();
let newLots = await processLotsFormat(lots);
return resResult(STATUS.SUCCESS, { lots: stage === AUCTION_STAGE.END ? [] : newLots });
}
async offerRecs(msg: { count: number }, session: BackendSession) {
const roleId = session.get('roleId');
const serverId = session.get('serverId');
const lotsData = await LotModel.recentBidLots(serverId, roleId, msg.count);
const bidRecs = lotsData.map(lot => {
const bidRec = lot.bidRoles.find(role => { return role.roleId === roleId });
const { gid } = lot;
return { ...bidRec, gid, status: auctionBidStatus(roleId, lot) };
}).sort((a,b) => b.time.getTime() - a.time.getTime());
return resResult(STATUS.SUCCESS, { bidRecs });
}
async guildLotRecs(msg: { count: number }, session: BackendSession) {
const guildCode = session.get('guildCode');
const dividends = await DividendModel.findDividendsByGuild(guildCode, msg.count);
let lotsData = [];
dividends.forEach(dividend => {
const lots = dividend.lots.map(lot => {
return { ...lot, sourceType: dividend.sourceType, dividendStatus: dividend.status };
})
lotsData = [...lotsData, ...lots];
});
const lotRecs = lotsData.map(lot => {
const { gid, count, price: lotPrice } = lot;
// const price = lotPrice === 0 ? getBasePrice(gid, count) : lotPrice;
const sold = guildBidStatus(lot);
return { ...lot, price: lotPrice, sold };
}).sort((a,b) => b.time.getTime() - a.time.getTime());;
return resResult(STATUS.SUCCESS, { lotRecs });
}
// ! 测试接口
async debugSetDividendStatus(msg: { magicWord: string, sourceType: number, status: number }, session: BackendSession) {
const { magicWord, sourceType, status } = msg;
if (magicWord !== DEBUG_MAGIC_WORD) {
return resResult(STATUS.TOKEN_ERR);
}
const guildCode: string = session.get('guildCode');
if (!guildCode) return resResult(STATUS.GUILD_NOT_FOUND)
const dividend = await DividendModel.updateDividendStatus(guildCode, sourceType, status);
return resResult(STATUS.SUCCESS, { dividend });
}
// ! 测试接口
async debugSetLotStage(msg: { magicWord: string, code: string, auctionStage: number }, session: BackendSession) {
const { magicWord, code, auctionStage } = msg;
if (magicWord !== DEBUG_MAGIC_WORD) {
return resResult(STATUS.TOKEN_ERR);
}
const lot = await LotModel.updateLotStage(code, auctionStage);
return resResult(STATUS.SUCCESS, { lot });
}
// ! 测试接口
async debugAddLots(msg: { magicWord: string, sourceType: number, sourceCode: string, poolId: number }, session: BackendSession) {
const { magicWord, sourceType, sourceCode, poolId } = msg;
if (magicWord !== DEBUG_MAGIC_WORD) {
return resResult(STATUS.TOKEN_ERR);
}
let guildCode: string = session.get('guildCode');
const serverId: number = session.get('serverId');
if (!guildCode) {//创建公会
const roleId = session.get('roleId');
const role: RoleType = await RoleModel.findByRoleId(roleId);
// 创建公会
const name = '测试公会'
const icon = 1
const notice = '测试公会'
const guild = await GuildModel.createGuild({ guildCode: genCode(6), name, icon, notice }, role, serverId);
if (!guild) return resResult(STATUS.GUILD_CREATE_ERROR);
guild.leader = <RoleType>guild.leader;
//创建科技树
await openGuildRefine(guild.code);
await unlockTrain(guild.code, 1);
const userGuild = await UserGuildModel.createUserGuild(guild.code, role, true);
if (!userGuild) return resResult(STATUS.GUILD_CREATE_ERROR);
await RoleModel.joinGuild(roleId, guild.code, guild.name, true);
await UserGuildApplyModel.deleteApply(roleId); // 删除玩家所有对其他公会的申请
guildCode = guild.code;
session.set('guildCode', guildCode);
session.push('guildCode', () => {});
}
let rewards = getAuctionRewardByPoolId(poolId);
if(!rewards) return resResult(STATUS.WRONG_PARMS);
const result = await genAuction(guildCode, sourceType, magicWord, serverId, rewards);
if (!result) {
return resResult(STATUS.WRONG_PARMS);
}
return resResult(STATUS.SUCCESS, result);
}
// ! 测试接口
async debugScheduleStartGuild(msg: { magicWord: string }, session: BackendSession) {
const { magicWord } = msg;
if (magicWord !== DEBUG_MAGIC_WORD) {
return resResult(STATUS.TOKEN_ERR);
}
const result = await startGuildAuction();
if (result === true) {
return resResult(STATUS.SUCCESS);
}
return resResult(STATUS.INTERNAL_ERR);
}
// ! 测试接口
async debugScheduleStartWorld(msg: { magicWord: string }, session: BackendSession) {
const { magicWord } = msg;
if (magicWord !== DEBUG_MAGIC_WORD) {
return resResult(STATUS.TOKEN_ERR);
}
const result = await startWorldAuction();
if (result === true) {
return resResult(STATUS.SUCCESS);
}
return resResult(STATUS.INTERNAL_ERR);
}
// ! 测试接口
async debugScheduleStopAuction(msg: { magicWord: string }, session: BackendSession) {
const { magicWord } = msg;
if (magicWord !== DEBUG_MAGIC_WORD) {
return resResult(STATUS.TOKEN_ERR);
}
const result = await stopAuction();
if (result === true) {
return resResult(STATUS.SUCCESS);
}
return resResult(STATUS.INTERNAL_ERR);
}
// ! 测试接口
async debugScheduleSendUngotDividend(msg: { magicWord: string }, session: BackendSession) {
const { magicWord } = msg;
if (magicWord !== DEBUG_MAGIC_WORD) {
return resResult(STATUS.TOKEN_ERR);
}
const result = await sendUngotDividend(true);
if (result === true) {
return resResult(STATUS.SUCCESS);
}
return resResult(STATUS.INTERNAL_ERR);
}
async debugSetPlayTime(msg: { magicWord: string, time: string }, session: BackendSession) {
const { magicWord, time } = msg;
if (magicWord !== DEBUG_MAGIC_WORD) {
return resResult(STATUS.TOKEN_ERR);
}
let serverId = session.get('serverId');
await sendMessageToServerWithSuc(serverId, PUSH_ROUTE.PUSH_CURRENT_TIME, { time: new Date(time).getTime() });
return resResult(STATUS.SUCCESS);
}
// ! 测试接口
/**
* 领取分红之前,修改分红数据信息,确保领取分红接口能正常跑通
* debugSetDividendStatus 和 debugSetDividendStatusV2 区别
* debugSetDividendStatus: 修改 DividendModel.status
* debugSetDividendStatus: 修改 DividendModel.status 和 DividendModel.dividends.status
*
* @param {{ magicWord: string, sourceType: number, status: number }} msg
* @param {BackendSession} session
* @return {*}
* @memberof AuctionHandler
*/
async debugSetDividendStatusV2(msg: { magicWord: string, sourceType: number, status: number }, session: BackendSession) {
const { magicWord, sourceType, status } = msg;
if (magicWord !== DEBUG_MAGIC_WORD) {
return resResult(STATUS.TOKEN_ERR);
}
const guildCode: string = session.get('guildCode');
if (!guildCode) return resResult(STATUS.GUILD_NOT_FOUND)
let dividend = await DividendModel.updateDividendStatus(guildCode, sourceType, status);
dividend.dividends.forEach(item => {
item.status = ROLE_RECEIVE_STATUS.NO
});
dividend = await DividendModel.updateDividend(dividend.code, { dividends: dividend.dividends })
return resResult(STATUS.SUCCESS, { dividend });
}
}