From a23e48b087252995f8a42212bd77f3d0d8126578 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Tue, 11 Jul 2023 13:30:44 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BB=BB=E5=8A=A1=20task=20?= =?UTF-8?q?=E5=8C=85=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/task/errors.go | 14 +++ game/task/events.go | 41 +++++---- game/task/options.go | 80 ++++++++++++++-- game/task/state.go | 8 +- game/task/task.go | 211 +++++++++++++++++++++++++++++++++++-------- utils/maths/math.go | 1 + 6 files changed, 289 insertions(+), 66 deletions(-) create mode 100644 game/task/errors.go diff --git a/game/task/errors.go b/game/task/errors.go new file mode 100644 index 0000000..a0c6230 --- /dev/null +++ b/game/task/errors.go @@ -0,0 +1,14 @@ +package task + +import "errors" + +var ( + // ErrTaskNotFinish 任务未完成 + ErrTaskNotFinish = errors.New("task not finish") + // ErrTaskRewardReceived 任务奖励已领取 + ErrTaskRewardReceived = errors.New("task reward received") + // ErrTaskNotStart 任务未开始 + ErrTaskNotStart = errors.New("task not start") + // ErrTaskFail 任务失败 + ErrTaskFail = errors.New("task fail") +) diff --git a/game/task/events.go b/game/task/events.go index 00dd3eb..c3925ff 100644 --- a/game/task/events.go +++ b/game/task/events.go @@ -1,32 +1,35 @@ package task type ( - TaskDoneEventHandle func(eventId int64, task *Task) + RefreshTaskCountEvent func(taskType int, increase int64) + RefreshTaskChildCountEvent func(taskType int, key any, increase int64) ) -var taskDoneEventHandles = make(map[int64]map[int64]TaskDoneEventHandle) +var ( + refreshTaskCountEventHandles = make(map[int]RefreshTaskCountEvent) + refreshTaskChildCountEventHandles = make(map[int]RefreshTaskChildCountEvent) +) -// RegTaskDoneEvent 注册任务完成事件 -func RegTaskDoneEvent(id int64, eventId int64, handle TaskDoneEventHandle) { - events, exist := taskDoneEventHandles[id] - if !exist { - events = map[int64]TaskDoneEventHandle{} - taskDoneEventHandles[id] = events - } - events[eventId] = handle +// RegRefreshTaskCount 注册任务计数刷新事件 +func RegRefreshTaskCount(taskType int, handler RefreshTaskCountEvent) { + refreshTaskCountEventHandles[taskType] = handler } -// UnRegTaskDoneEvent 取消注册任务完成事件 -func UnRegTaskDoneEvent(id int64, eventId int64) { - events, exist := taskDoneEventHandles[id] - if exist { - delete(events, eventId) +// OnRefreshTaskCount 触发任务计数刷新事件 +func OnRefreshTaskCount(taskType int, increase int64) { + if handler, ok := refreshTaskCountEventHandles[taskType]; ok { + handler(taskType, increase) } } -// OnTaskDoneEvent 任务完成事件 -func OnTaskDoneEvent(task *Task) { - for eventId, handle := range taskDoneEventHandles[task.id] { - handle(eventId, task) +// RegRefreshTaskChildCount 注册任务子计数刷新事件 +func RegRefreshTaskChildCount(taskType int, handler RefreshTaskChildCountEvent) { + refreshTaskChildCountEventHandles[taskType] = handler +} + +// OnRefreshTaskChildCount 触发任务子计数刷新事件 +func OnRefreshTaskChildCount(taskType int, key any, increase int64) { + if handler, ok := refreshTaskChildCountEventHandles[taskType]; ok { + handler(taskType, key, increase) } } diff --git a/game/task/options.go b/game/task/options.go index 16d949e..2182ae2 100644 --- a/game/task/options.go +++ b/game/task/options.go @@ -1,17 +1,85 @@ package task +import ( + "github.com/kercylan98/minotaur/utils/offset" + "time" +) + type Option func(task *Task) -// WithInitCount 通过初始化计数的方式创建任务 -func WithInitCount(count int) Option { +// WithChildCount 通过初始化子计数的方式创建任务 +func WithChildCount(key any, childCount int64) Option { return func(task *Task) { - task.count = count + if task.childCount == nil { + task.childCount = make(map[any]int64) + } + if task.childCondition == nil { + task.childCondition = make(map[any]int64) + } + task.childCount[key] = childCount } } -// WithDone 通过指定任务完成计数的方式创建任务 -func WithDone(done int) Option { +// WithChild 通过指定子计数的方式创建任务 +// - 只有当子计数与主计数均达到条件时,任务才会完成 +// - 通常用于多条件的任务 +func WithChild(key any, childCondition int64) Option { return func(task *Task) { - task.done = done + if task.childCount == nil { + task.childCount = make(map[any]int64) + } + if task.childCondition == nil { + task.childCondition = make(map[any]int64) + } + task.childCondition[key] = childCondition + } +} + +// WithDisableNotStartGetReward 禁止未开始的任务领取奖励 +func WithDisableNotStartGetReward() Option { + return func(task *Task) { + task.disableNotStartGetReward = true + } +} + +// WithCount 通过初始化计数的方式创建任务 +func WithCount(count int64) Option { + return func(task *Task) { + task.SetCount(count) + } +} + +// WithStartTime 通过指定开始时间的方式创建任务 +// - 只有当时间在开始时间之后,任务才会开始计数 +func WithStartTime(startTime time.Time) Option { + return func(task *Task) { + task.start = startTime + } +} + +// WithOffsetTime 通过指定偏移时间的方式创建任务 +func WithOffsetTime(offset *offset.Time) Option { + return func(task *Task) { + task.offset = offset + } +} + +// WithLimitedTime 通过限时的方式创建任务 +func WithLimitedTime(limitTime time.Duration) Option { + return func(task *Task) { + task.limitTime = limitTime + } +} + +// WithFront 通过指定任务前置任务的方式创建任务 +// - 当前置任务未完成时,当前任务不会开始计数 +func WithFront(fronts ...*Task) Option { + return func(task *Task) { + if task.fronts == nil { + task.fronts = make(map[int64]*Task) + } + for _, front := range fronts { + task.fronts[front.GetID()] = front + } } } diff --git a/game/task/state.go b/game/task/state.go index 75d6d07..f2a8807 100644 --- a/game/task/state.go +++ b/game/task/state.go @@ -1,10 +1,10 @@ package task const ( - StateDoing State = iota // 进行中 - StateDone // 已完成 + StateAccept State = iota // 已接受 + StateFinish // 已完成 StateReward // 已领取 + StateFail // 已失败 ) -// State 任务状态 -type State byte +type State uint16 diff --git a/game/task/task.go b/game/task/task.go index 361b245..2130942 100644 --- a/game/task/task.go +++ b/game/task/task.go @@ -1,67 +1,204 @@ package task -// NewTask 新建任务 -func NewTask(id int64, options ...Option) *Task { +import ( + "github.com/kercylan98/minotaur/utils/hash" + "github.com/kercylan98/minotaur/utils/offset" + "time" +) + +// NewTask 创建任务 +func NewTask(id int64, taskType int, condition int64, options ...Option) *Task { task := &Task{ - id: id, + id: id, + condition: condition, + state: StateAccept, } for _, option := range options { option(task) } - if task.count > task.done { - task.count = task.done + if task.start.IsZero() { + if task.offset != nil { + task.start = task.offset.Now() + } else { + task.start = time.Now() + } + } + for key := range task.childCount { + if !hash.Exist(task.childCondition, key) { + delete(task.childCount, key) + } + } + if task.count == task.condition { + task.state = StateFinish } - task.Add(0) return task } +// Task 通用任务数据结构 type Task struct { - id int64 // 任务ID - count int // 任务计数 - done int // 任务完成计数 - reward bool // 是否已领取奖励 + id int64 // 任务ID + taskType int // 任务类型 + count int64 // 任务主计数 + condition int64 // 任务完成需要的计数条件 + childCount map[any]int64 // 任务子计数 + childCondition map[any]int64 // 任务子计数条件 + state State // 任务状态 + start time.Time // 任务开始时间 + limitTime time.Duration // 任务限时 + fronts map[int64]*Task // 任务前置任务 + disableNotStartGetReward bool // 禁止未开始的任务领取奖励 + + offset *offset.Time // 任务偏移时间 +} + +// GetID 获取任务ID +func (slf *Task) GetID() int64 { + return slf.id +} + +// GetType 获取任务类型 +func (slf *Task) GetType() int { + return slf.taskType } // Reset 重置任务 func (slf *Task) Reset() { slf.count = 0 - slf.reward = false - switch slf.GetState() { - case StateDone: - OnTaskDoneEvent(slf) + slf.state = StateAccept + for key := range slf.childCount { + delete(slf.childCount, key) } } -// Add 增加任务计数 -func (slf *Task) Add(count int) { - if count != 0 { - slf.count += count - if slf.count < 0 { - slf.count = 0 - } else if slf.count > slf.done { - slf.count = slf.done +// GetFronts 获取前置任务 +func (slf *Task) GetFronts() map[int64]*Task { + return slf.fronts +} + +// GetFrontsWithState 获取特定状态的前置任务 +func (slf *Task) GetFrontsWithState(state State) map[int64]*Task { + fronts := make(map[int64]*Task) + for id, front := range slf.fronts { + if front.GetState() == state { + fronts[id] = front } } - switch slf.GetState() { - case StateDone: - OnTaskDoneEvent(slf) + return fronts +} + +// FrontsIsFinish 判断前置任务是否完成 +func (slf *Task) FrontsIsFinish() bool { + for _, front := range slf.fronts { + state := front.GetState() + if state == StateAccept || state == StateFail { + return false + } } + return true +} + +// GetReward 获取任务奖励 +// - 当任务状态为 StateFinish 时,调用 rewardHandle 函数 +// - 当任务状态不为 StateFinish 或奖励函数发生错误时,返回错误 +func (slf *Task) GetReward(rewardHandle func() error) error { + if !slf.IsStart() { + return ErrTaskNotStart + } + switch slf.GetState() { + case StateAccept: + return ErrTaskNotFinish + case StateReward: + return ErrTaskRewardReceived + case StateFail: + return ErrTaskFail + } + if err := rewardHandle(); err != nil { + return err + } + slf.state = StateReward + return nil } // GetState 获取任务状态 func (slf *Task) GetState() State { - if slf.count >= slf.done { - if slf.reward { - return StateReward - } - return StateDone - } - return StateDoing + return slf.state } -// Reward 返回是否领取过奖励,并且设置任务为领取过奖励的状态 -func (slf *Task) Reward() bool { - reward := slf.reward - slf.reward = true - return reward +// IsStart 判断任务是否开始 +func (slf *Task) IsStart() bool { + var current time.Time + if slf.offset != nil { + current = slf.offset.Now() + } else { + current = time.Now() + } + if current.Before(slf.start) { + return false + } else if slf.limitTime > 0 && current.Sub(slf.start) >= slf.limitTime { + return false + } + return true +} + +// SetCount 设置计数 +func (slf *Task) SetCount(count int64) { + if !slf.IsStart() || !slf.FrontsIsFinish() { + return + } + slf.count = count + if slf.count >= slf.condition { + slf.count = slf.condition + } else if slf.count < 0 { + slf.count = 0 + } + slf.refreshState() +} + +// AddCount 增加计数 +func (slf *Task) AddCount(count int64) { + slf.SetCount(slf.count + count) +} + +// GetCount 获取计数 +func (slf *Task) GetCount() int64 { + return slf.count +} + +// GetCondition 获取计数条件 +func (slf *Task) GetCondition() int64 { + return slf.condition +} + +// SetChildCount 设置子计数 +func (slf *Task) SetChildCount(key any, count int64) { + if !slf.IsStart() || !slf.FrontsIsFinish() || !hash.Exist(slf.childCondition, key) { + return + } + if condition := slf.childCondition[key]; count > condition { + count = condition + } else if count < 0 { + count = 0 + } + slf.childCount[key] = count + slf.refreshState() +} + +// AddChildCount 增加子计数 +func (slf *Task) AddChildCount(key any, count int64) { + slf.SetChildCount(key, slf.childCount[key]+count) +} + +// refreshState 刷新任务状态 +func (slf *Task) refreshState() { + slf.state = StateFinish + if slf.count != slf.condition { + slf.state = StateAccept + return + } + for key, condition := range slf.childCondition { + if slf.childCount[key] != condition { + slf.state = StateAccept + return + } + } } diff --git a/utils/maths/math.go b/utils/maths/math.go index 6fb118e..03ef7f4 100644 --- a/utils/maths/math.go +++ b/utils/maths/math.go @@ -8,6 +8,7 @@ import ( const ( DefaultTolerance = 0.0001 // 默认误差范围 + Zero = 0 // 零 ) // GetDefaultTolerance 获取默认误差范围