Files
ZYZ/game-server/app/services/auctionService.ts

372 lines
15 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 } from './../db/Dividend';
import { LOT_CODE_LEN, AUCTION_STAGE, AUCTION_TIME, DIVIDEND_CODE_LEN, DIVIDEND_STATUS, LOT_STATUS, MAIL_TYPE, CURRENCY_BY_TYPE, CURRENCY_TYPE, DIVIDENDMAXRATIO, DIVIDENDPOSITIONMAXRATIO, ROLE_RECEIVE_STATUS, AUCTION_BID_STATUS, DEBUG_MAGIC_WORD, AUCTION_SOURCE } from './../consts';
import { DividendRec, ItemReward } from "../domain/dbGeneral";
import { genCode } from '../pubUtils/util';
import { LotModel, LotParam } from '../db/Lot';
import { getCurDay, getTimeFunD, getTimeFunM } from '../pubUtils/timeUtil';
import { gameData, getGoodById } from '../pubUtils/data';
import { DividendParam, DividendType } from '../db/Dividend';
import { sendMailByContent } from './mailService';
import { FrontendOrBackendSession, pinus } from 'pinus';
import { participants } from './guildActivityService';
import { Member } from '../domain/battleField/guildActivity';
import * as dicParam from '../pubUtils/dicParam';
import { RewardInter } from '../pubUtils/interface';
import { pushCurrentTime } from './chatService';
// ! 获取底价,假数据
export function getBasePrice(gid: number, count: number) {
const good = getGoodById(gid);
return (good ? good.quality * 100 : 100) * count;
}
// ! 获取一口价,假数据
export function getMaxPrice(gid: number, count: number) {
const good = getGoodById(gid);
return (good ? good.quality * 200 : 200) * count;
}
export function auctionStage() {
const curTime = new Date().getTime();
if (curTime < todayGuildBegin().getTime()) return AUCTION_STAGE.DEFAULT;
if (curTime < todayWorldBegin().getTime() && curTime > todayGuildBegin().getTime()) return AUCTION_STAGE.GUILD;
if (curTime > todayWorldBegin().getTime() && curTime < todayWorldEnd().getTime()) return AUCTION_STAGE.WORLD;
if (curTime > todayWorldEnd().getTime()) return AUCTION_STAGE.END;
}
export async function debugAuctionLots(session: FrontendOrBackendSession, begin: Date) {
const serverId = session.get('serverId');
const lots = await LotModel.findWorldLotsByBegin(serverId, begin);
return lots;
}
export async function officialAuctionLots(session: FrontendOrBackendSession, begin: Date) {
const serverId = session.get('serverId');
const guildCode = session.get('guildCode');
const stage = auctionStage();
let lots = [];
if (stage === AUCTION_STAGE.DEFAULT || stage === AUCTION_STAGE.GUILD) {
lots = await LotModel.findGuildLotsByBegin(guildCode, begin);
} else if (stage === AUCTION_STAGE.WORLD) {
lots = await LotModel.findWorldLotsByBegin(serverId, begin);
}
return lots;
}
// 拍卖行开始时间 今天20:20
export function auctionBegin() {
let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_OPEN);
return <Date>getTimeFunD().getAfterDayAndSetHour(0, hour, minute);
}
// 军团拍卖行结束时间 20:30
export function guildAuctionEnd() {
let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_CLOSE);
return <Date>getTimeFunD().getAfterDayAndSetHour(0, hour, minute);
}
// 拍卖行结束时间 22:00
export function auctionEnd() {
let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.WORLD_CLOSE);
return <Date>getTimeFunD().getAfterDayAndSetHour(0, hour, minute);
}
// 今天军团拍卖行开始时间 20:20
export function todayGuildBegin() {
let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_OPEN);
return <Date>getTimeFunD().getAfterDayAndSetHour(0, hour, minute);
}
// 明天军团拍卖行开始时间 20:20
export function tomorrowGuildBegin() {
let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_OPEN);
// console.log(hour, minute)
return <Date>getTimeFunD().getAfterDayAndSetHour(1, hour, minute);
}
// 明天军团拍卖行开始时间 20:20
export function tomorrowGuildEnd() {
let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_CLOSE);
// console.log(hour, minute)
return <Date>getTimeFunD().getAfterDayAndSetHour(1, hour, minute);
}
// 昨天军团拍卖行开始时间 20:20
export function yestodayGuildBegin() {
let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_OPEN);
return <Date>getTimeFunD().getAfterDayAndSetHour(-1, hour, minute);
}
// 今天世界拍卖行开始时间 20:40
export function todayWorldBegin() {
let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.WORLD_OPEN);
return <Date>getTimeFunD().getAfterDayAndSetHour(0, hour, minute);
}
// 今天世界拍卖行结束时间 22:00
export function todayWorldEnd() {
let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.WORLD_CLOSE);
return <Date>getTimeFunD().getAfterDayAndSetHour(0, hour, minute);
}
// 拍卖行预览时间 20:00
export function guildAuctionPreview() {
let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_PREVIEW);
return <Date>getTimeFunD().getAfterDayAndSetHour(0, hour, minute);
}
// 演武台。8点以前是今天的8点以后是明天的
export function getBossAuctionBegin() {
if(Date.now() < guildAuctionPreview().getTime()) {
return todayGuildBegin();
} else {
return tomorrowGuildBegin();
}
}
// 演武台。8点以前是今天的8点以后是明天的
export function getBossAuctionEnd() {
if(Date.now() < guildAuctionPreview().getTime()) {
return guildAuctionEnd();
} else {
return tomorrowGuildEnd();
}
}
/**
* @description 生成拍卖数据
* @export
* @param {string} guildCode
* @param {number} sourceType
* @param {string} sourceCode
* @param {number} serverId
* @param {ItemReward[]} rewards
*/
export async function genAuction(guildCode: string, sourceType: number, sourceCode: string, serverId: number, rewards: { goods: RewardInter, basePrice: number, maxPrice: number}[]) {
let begin = auctionBegin();
let end = auctionEnd();
if(sourceType == AUCTION_SOURCE.BOSS) { // 军团boss本
begin = getBossAuctionBegin();
end = getBossAuctionEnd();
}
const guildEnd = guildAuctionEnd();
const lotsData: LotParam[] = rewards.map(({ goods, basePrice, maxPrice }) => {
const { id, count } = goods;
const code = genCode(LOT_CODE_LEN);
return {
auctionStage: AUCTION_STAGE.DEFAULT, sourceType,
sourceCode, serverId, guildCode, code, gid: id, count, begin, end, status: LOT_STATUS.DEFAULT,
maxPrice, curPrice: basePrice,
}
});
const lots = await LotModel.createRecs(lotsData);
const dividendCode = genCode(DIVIDEND_CODE_LEN);
const dividendData: DividendParam = {
guildCode, sourceType, sourceCode, serverId, code: dividendCode, dividends: [], totalPrice: 0, begin, lots: lots.map(lot => {
const { code, gid } = lot;
return { code, gid, price: 0, time: guildEnd, max: false, count: lot.count }
}),
};
const dividend = await DividendModel.createDividend(dividendData);
return { lots, dividend };
}
function posDividend(totalPrice: number, roleRatio: number, totalRatio: number) {
const dividend = Math.floor(totalPrice * roleRatio / totalRatio);
const maxDividend = Math.floor(totalPrice * DIVIDENDMAXRATIO);
return dividend <= maxDividend ? dividend : Math.floor(maxDividend * roleRatio / DIVIDENDPOSITIONMAXRATIO);
}
function weekendDividend(posNum: number, date: Date) {
const day = date.getDay();
return (day === 0 || day === 6) ? Math.floor(posNum * dicParam.GUILD_AUCTION.DIVIDEND_WEEKEND_RATE) : 0;
}
function dividendRate(data: Member) {
return gameData.guildPosition.get(data.job).sellRatio;
}
function totalDividendRatio(participantsData: Member[]) {
const result = participantsData.reduce((sum, data) => {
return sum + dividendRate(data);
}, 0);
return result;
}
export async function calculateDividend(dividend: DividendType) {
if (!dividend) return null;
const { code, guildCode, sourceType, sourceCode, lots, totalPrice, status, begin } = dividend;
if (status === DIVIDEND_STATUS.SENT) return dividend;
const calcuTotalPrice = lots.reduce((acc, lot) => { return acc + lot.price }, 0) * dicParam.GUILD_AUCTION.DIVIDEND_RATE;
if (calcuTotalPrice !== totalPrice) {
await DividendModel.updateDividend(code, { totalPrice: calcuTotalPrice });
// 更新 totalPrice
}
const participantsData = await participants(guildCode, sourceType, sourceCode);
const totalRatio = totalDividendRatio(participantsData);
const dividends: DividendRec[] = participantsData.map(data => {
const { roleId } = data;
const posNum = posDividend(calcuTotalPrice, dividendRate(data), totalRatio);
const weekendNum = weekendDividend(posNum, begin);
return {
roleId,
posNum, // 职位分红
weekendNum, // 额外分红,周末
total: posNum + weekendNum, // 总分红
status: 0, // 0未领取1已领取
};
});
return await DividendModel.updateDividend(code, { dividends });
}
export async function startGuildAuction() {
try {
console.log('schedule startGuildAuction called:', new Date());
const begin = todayGuildBegin();
await LotModel.updateLotsStageByBegin(begin, AUCTION_STAGE.GUILD);
await DividendModel.updateDividendsStatus(begin, DIVIDEND_STATUS.ING);
if(dicParam.SERVER_DEBUG_MODE.CURRENT_TIME == 1) {
let day = getCurDay();
let time = <number>getTimeFunM().getTimeWithWeek(day, 20, 20, 0);
pinus.app.rpc.guild.guildActivityRemote.setCurrentTime.broadcast(time);
}
return true;
} catch (e) {
console.error('startGuildAuction err: ', e);
return false;
}
}
export async function startWorldAuction() {
try {
console.log('schedule startWorldAuction called:', new Date());
const begin = todayGuildBegin();
await LotModel.setLotSoldByBegin(begin);
await LotModel.updateUnSoldLotsStageByBegin(begin, AUCTION_STAGE.WORLD);
await DividendModel.updateDividendsStatus(begin, DIVIDEND_STATUS.END);
if(dicParam.SERVER_DEBUG_MODE.CURRENT_TIME == 1) {
let day = getCurDay();
let time = <number>getTimeFunM().getTimeWithWeek(day, 20, 40, 0);
pinus.app.rpc.guild.guildActivityRemote.setCurrentTime.broadcast(time);
}
return true;
} catch (e) {
console.error('startWorldAuction err: ', e);
return false;
}
}
export async function stopAuction() {
try {
console.log('schedule stopAuction called:', new Date());
const begin = todayGuildBegin();
await LotModel.setLotSoldByBegin(begin);
await LotModel.updateLotsStageByBegin(begin, AUCTION_STAGE.END);
if(dicParam.SERVER_DEBUG_MODE.CURRENT_TIME == 1) {
let day = getCurDay();
let time = <number>getTimeFunM().getTimeWithWeek(day, 22, 0, 0);
pinus.app.rpc.guild.guildActivityRemote.setCurrentTime.broadcast(time);
}
return true;
} catch (e) {
console.error('stopAuction err: ', e);
return false;
}
}
async function debugDividends() {
const begin = yestodayGuildBegin();
const dividends = await DividendModel.findDividendsByBegin(begin);
const todayBegin = todayGuildBegin();
const todayDividends = await DividendModel.findDividendsByBegin(todayBegin);
return [...dividends, ...todayDividends];
}
async function officialDividends() {
const begin = yestodayGuildBegin();
const dividends = await DividendModel.findDividendsByBegin(begin);
return dividends;
}
async function updateDebugDividendsStatus(status: number) {
const begin = yestodayGuildBegin();
await DividendModel.updateDividendsStatus(begin, status);
const todayBegin = todayGuildBegin();
await DividendModel.updateDividendsStatus(todayBegin,status);
}
async function updateOfficialDividendsStatus(status: number) {
const begin = yestodayGuildBegin();
await DividendModel.updateDividendsStatus(begin, status);
}
export async function sendUngotDividendJob() {
try {
return await sendUngotDividend();
} catch (e) {
console.error('sendUngotDividend err: ', e);
return false;
}
}
export function auctionBidStatus(roleId: string, lot: LotParam) {
const { curBuyer, status } = lot;
return curBuyer !== roleId ? AUCTION_BID_STATUS.RETURN : status === LOT_STATUS.SOLD || status === LOT_STATUS.MAX ? AUCTION_BID_STATUS.SUC : AUCTION_BID_STATUS.LEAD;
}
export function guildBidStatus(lot: { max: boolean, gid: number, count: number, price: number, dividendStatus: number }) {
const { max, gid, count, price: lotPrice, dividendStatus } = lot;
return max || lotPrice === getMaxPrice(gid, count) || ((dividendStatus == DIVIDEND_STATUS.END || dividendStatus == DIVIDEND_STATUS.SENT) && lotPrice !== 0)
}
export async function sendUngotDividend(debug = false) {
try {
console.log('schedule sendUngotDividend called:', new Date());
const dividends = debug === true ? await debugDividends() : await officialDividends();
const rewards = new Map<string, number>();
for (let dividend of dividends) {
if (!dividend.dividends || dividend.status === DIVIDEND_STATUS.SENT) continue;
for (let dividendRec of dividend.dividends) {
if (dividendRec.status === ROLE_RECEIVE_STATUS.YES) continue;
const sum = rewards.get(dividendRec.roleId) || 0;
rewards.set(dividendRec.roleId, sum + dividendRec.total);
}
}
for (let [roleId, count] of rewards) {
// TODO: 邮件类型修改
await sendMailByContent(MAIL_TYPE.GUILD_BOSS_REWARD, roleId, {
params: [JSON.stringify(count)],
goods: [{ id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD), count }]
});
}
debug === true ? await updateDebugDividendsStatus(DIVIDEND_STATUS.SENT) : await updateOfficialDividendsStatus(DIVIDEND_STATUS.SENT);
return true;
} catch (e) {
console.error('sendUngotDividend err: ', e);
return false;
}
}
/**
* 获取拍卖行数据
* @param guildCode
* @param session
* @param magicWord
*/
export async function getAuction(guildCode: string, session: FrontendOrBackendSession, magicWord?: string) {
const begin = todayGuildBegin();
let lots = magicWord === DEBUG_MAGIC_WORD ? await debugAuctionLots(session, begin) : await officialAuctionLots(session, begin);
let dividends: DividendType[] = [];
if(guildCode) {
dividends = await DividendModel.findGuildDividendsByBegin(guildCode, begin);
}
return { lots, dividends };
}