增加任务repeat的支持

This commit is contained in:
CounterFire2023 2024-01-09 22:05:48 +08:00
parent a41fb9aa3a
commit 145a5cb06c
8 changed files with 78 additions and 45 deletions

View File

@ -105,6 +105,7 @@ SiweMessage的nonce说明(具体参考例子):
"title": "任务名",
"desc": "任务描述",
"type": 1, //任务类型, 1: 一次性任务, 2: 日常任务
"repeat": 1, // 任务可重复次数
"pretasks": ["task id 1"], //前置任务
"score": 0, // 完成任务可获得的积分
"category": "", // 任务分类

View File

@ -199,6 +199,7 @@
"task": "BurnNft",
"type": 1,
"show": true,
"repeat": 2,
"title": "Hero NFT",
"desc": "Click to burn and redeem Flame",
"category": "CF Pal",
@ -212,6 +213,7 @@
"task": "BurnNft",
"type": 1,
"show": true,
"repeat": 2,
"title": "Candy Badge",
"desc": "Click to burn and redeem Flame",
"category": "CF Pal",
@ -224,6 +226,7 @@
"task": "BurnNft",
"type": 1,
"show": true,
"repeat": 2,
"title": "Explorer Badge",
"desc": "Click to burn and redeem Flame",
"category": "CF Pal",
@ -237,6 +240,7 @@
"task": "BurnNft",
"type": 1,
"show": true,
"repeat": 2,
"title": "Gacha Badge",
"desc": "Click to burn and redeem Flame",
"category": "CF Pal",

View File

@ -96,12 +96,12 @@ export default class TasksController extends BaseController {
return t.id === preTask
});
if (!preTaskData || (preTaskData.status === TaskStatusEnum.NOT_START || preTaskData.status === TaskStatusEnum.RUNNING)) {
throw new ZError(14, 'task previous not end')
throw new ZError(14, 'task previous not finish')
}
}
}
let currentTask = user.taskProgress.find((t: TaskStatus) => t.id === task);
if (currentTask.status === TaskStatusEnum.SUCCESS || currentTask.status === TaskStatusEnum.CLAIMED) {
if (currentTask.status === TaskStatusEnum.PART_SUCCESS || currentTask.status === TaskStatusEnum.SUCCESS || currentTask.status === TaskStatusEnum.CLAIMED) {
throw new ZError(15, 'task already end')
}
if (currentTask.status === TaskStatusEnum.NOT_START) {
@ -126,13 +126,13 @@ export default class TasksController extends BaseController {
if (!currentTask) {
throw new ZError(11, 'task not found')
}
if (currentTask.status === TaskStatusEnum.SUCCESS || currentTask.status === TaskStatusEnum.CLAIMED) {
if (currentTask.status === TaskStatusEnum.CLAIMED) {
return currentTask;
}
if (currentTask.status === TaskStatusEnum.NOT_START) {
throw new ZError(11, 'task not begin');
}
if (currentTask.status === TaskStatusEnum.RUNNING) {
if (currentTask.status === TaskStatusEnum.RUNNING || currentTask.status === TaskStatusEnum.PART_SUCCESS) {
let Task = require('../tasks/' + currentTask.task);
let taskInstance = new Task.default({user, activity});
await taskInstance.execute({task: currentTask});
@ -152,7 +152,7 @@ export default class TasksController extends BaseController {
if (currentTask.status === TaskStatusEnum.CLAIMED) {
throw new ZError(12, 'task already claimed')
}
if (currentTask.status !== TaskStatusEnum.SUCCESS) {
if (currentTask.status !== TaskStatusEnum.SUCCESS && currentTask.status !== TaskStatusEnum.PART_SUCCESS) {
throw new ZError(13, 'task not end')
}

View File

@ -4,7 +4,7 @@ import { dbconn } from 'decorators/dbconn'
import findOrCreate from 'mongoose-findorcreate'
import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'
import { BaseModule } from './Base'
import exp from 'constants'
export enum TaskTypeEnum {
ONCE = 1,
@ -20,6 +20,8 @@ export class TaskCfg {
title: string
@prop({ enum: TaskTypeEnum, default: TaskTypeEnum.ONCE })
type: TaskTypeEnum
@prop({default: 1})
repeat: number
@prop()
desc: string
@prop({ type: mongoose.Schema.Types.Mixed })
@ -76,6 +78,7 @@ class ActivityInfoClass extends BaseModule {
title: task.title,
desc: task.desc,
type: task.type,
repeat: task.repeat,
pretasks: task.pretasks,
score: task.score,
category: task.category,

View File

@ -13,6 +13,7 @@ export enum TaskStatusEnum {
RUNNING = 1,
SUCCESS = 2,
CLAIMED = 3,
PART_SUCCESS = 4,
}
@modelOptions({ schemaOptions: { _id: false }, options: { allowMixed: Severity.ALLOW }})

View File

@ -10,16 +10,12 @@ import { BaseModule } from './Base'
class NftBurnRecordClass extends BaseModule {
@prop({ required: true})
public user: string
@prop()
public chain: number
@prop({ required: true})
public address: string
@prop()
public tokenId: number
public tokenId: string
@prop()
public activity: string
@prop()

View File

@ -21,19 +21,29 @@ export default class BurnNft extends ITask {
const localNft = await NftBurnRecord.find({
user: this.params.user.id,
chain,
address
address,
})
const localNftSet = new Set();
let finishAmount = 0;
let tmpNftSet = new Set();
for (let nft of localNft) {
localNftSet.add(nft.tokenId)
if (nft.activity === this.params.activity.id && nft.task === task.id) {
finishAmount += 1
tmpNftSet.add(nft.tokenId)
}
let finishNft
}
let finishNfts = new Set();
for (let nft of nftList) {
if (!localNftSet.has(nft.tokenId)) {
finishNft = nft.tokenId
finishNfts.add(nft.tokenId)
finishAmount += 1
if (finishAmount >= cfg.repeat) {
break;
}
}
}
for (let finishNft of finishNfts) {
const record = new NftBurnRecord({
user: this.params.user.id,
chain,
@ -43,9 +53,18 @@ export default class BurnNft extends ITask {
task: task.id
})
await record.save()
}
let dataToSave = task.data || {}
dataToSave.tokenId = [...tmpNftSet, ...finishNfts]
dataToSave.finishAmount = finishAmount
task.data = dataToSave
task.markModified('data')
if (finishAmount >= cfg.repeat) {
task.status = TaskStatusEnum.SUCCESS
task.timeFinish = Date.now()
task.data = {tokenId: finishNft}
} else if (finishAmount > 0) {
task.status = TaskStatusEnum.PART_SUCCESS
}
try {
await this.params.user.save()
} catch(err) {
@ -60,5 +79,4 @@ export default class BurnNft extends ITask {
}
return true
}
}

View File

@ -14,17 +14,20 @@ export abstract class ITask {
}
abstract execute(data: any): Promise<boolean>
public async claimReward(task: TaskStatus) {
public async claimReward(task: any) {
const user = this.params.user
const [taskId, dateTag] = task.id.split(':');
const cfg = this.params.activity.tasks.find((t: TaskCfg) => t.id === taskId)
if (!cfg.score) {
return;
}
let claimAmount = task.data.claimAmount || 0
let score = cfg.score
if (user.boost > 1 && Date.now() < user.boostExpire) {
score = Math.floor(score * user.boost)
}
let finishAmount = cfg.repeat > 1 ? task.data.finishAmount || 0 : 1
for (let i = claimAmount; i < Math.min(cfg.repeat, finishAmount); i++) {
await updateRankScore({
user: user.id,
score: score,
@ -36,8 +39,15 @@ export abstract class ITask {
boost: user.boost
}
})
claimAmount += 1
}
task.data.claimAmount = claimAmount
task.markModified('data')
if ((cfg.repeat > 1 && claimAmount >= cfg.repeat)
|| (cfg.repeat === 1 && claimAmount >= 1)) {
task.status = TaskStatusEnum.CLAIMED
task.timeClaim = Date.now()
}
await user.save()
}
}