Skip to content

Commit

Permalink
Merge pull request wowsims#3884 from vigo2/vigo/resource-tasks
Browse files Browse the repository at this point in the history
vigo/resource-tasks
  • Loading branch information
vigo2 authored Oct 19, 2023
2 parents a7624c6 + 84c81f0 commit f5e24b3
Show file tree
Hide file tree
Showing 18 changed files with 2,008 additions and 2,079 deletions.
2 changes: 1 addition & 1 deletion sim/core/aura.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ func (at *auraTracker) reset(sim *Simulation) {
}

func (at *auraTracker) advance(sim *Simulation) time.Duration {
if at.minExpires > sim.CurrentTime {
if sim.CurrentTime < at.minExpires {
return at.minExpires
}

Expand Down
57 changes: 29 additions & 28 deletions sim/core/energy.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ type energyBar struct {
cumulativeEnergyDecisionThresholds []int

onEnergyGain func(*Simulation, bool)
tickAction *PendingAction

nextEnergyTick time.Duration

// Multiplies energy regen from ticks.
EnergyTickMultiplier float64
Expand Down Expand Up @@ -149,7 +150,7 @@ func (eb *energyBar) CurrentEnergy() float64 {
}

func (eb *energyBar) NextEnergyTickAt() time.Duration {
return eb.tickAction.NextActionAt
return eb.nextEnergyTick
}

func (eb *energyBar) addEnergyInternal(sim *Simulation, amount float64, metrics *ResourceMetrics) bool {
Expand Down Expand Up @@ -201,7 +202,8 @@ func (eb *energyBar) ResetEnergyTick(sim *Simulation) {
crossedThreshold := eb.addEnergyInternal(sim, partialTickAmount, eb.regenMetrics)
eb.onEnergyGain(sim, crossedThreshold)

eb.newTickAction(sim, false, sim.CurrentTime)
eb.nextEnergyTick = sim.CurrentTime + EnergyTickDuration
sim.RescheduleTask(eb.nextEnergyTick)
}

func (eb *energyBar) AddComboPoints(sim *Simulation, pointsToAdd int32, metrics *ResourceMetrics) {
Expand All @@ -223,29 +225,16 @@ func (eb *energyBar) SpendComboPoints(sim *Simulation, metrics *ResourceMetrics)
eb.comboPoints = 0
}

func (eb *energyBar) newTickAction(sim *Simulation, randomTickTime bool, startAt time.Duration) {
if eb.tickAction != nil {
eb.tickAction.Cancel(sim)
}

nextTickDuration := EnergyTickDuration
if randomTickTime {
nextTickDuration = time.Duration(sim.RandomFloat("Energy Tick") * float64(EnergyTickDuration))
func (eb *energyBar) RunTask(sim *Simulation) time.Duration {
if sim.CurrentTime < eb.nextEnergyTick {
return eb.nextEnergyTick
}

pa := &PendingAction{
NextActionAt: startAt + nextTickDuration,
Priority: ActionPriorityRegen,
}
pa.OnAction = func(sim *Simulation) {
crossedThreshold := eb.addEnergyInternal(sim, EnergyPerTick*eb.EnergyTickMultiplier, eb.regenMetrics)
eb.onEnergyGain(sim, crossedThreshold)
crossedThreshold := eb.addEnergyInternal(sim, EnergyPerTick*eb.EnergyTickMultiplier, eb.regenMetrics)
eb.onEnergyGain(sim, crossedThreshold)

pa.NextActionAt = sim.CurrentTime + EnergyTickDuration
sim.AddPendingAction(pa)
}
eb.tickAction = pa
sim.AddPendingAction(pa)
eb.nextEnergyTick = sim.CurrentTime + EnergyTickDuration
return eb.nextEnergyTick
}

func (eb *energyBar) reset(sim *Simulation) {
Expand All @@ -255,13 +244,27 @@ func (eb *energyBar) reset(sim *Simulation) {

eb.currentEnergy = eb.maxEnergy
eb.comboPoints = 0
eb.newTickAction(sim, true, sim.Environment.PrepullStartTime())

if eb.unit.Type != PetUnit {
eb.enable(sim, sim.Environment.PrepullStartTime())
}
}

func (eb *energyBar) enable(sim *Simulation, startAt time.Duration) {
sim.AddTask(eb)
eb.nextEnergyTick = startAt + time.Duration(sim.RandomFloat("Energy Tick")*float64(EnergyTickDuration))
sim.RescheduleTask(eb.nextEnergyTick)

if eb.cumulativeEnergyDecisionThresholds != nil && sim.Log != nil {
eb.unit.Log(sim, "[DEBUG] APL Energy decision thresholds: %v", eb.energyDecisionThresholds)
}
}

func (eb *energyBar) disable(sim *Simulation) {
eb.nextEnergyTick = NeverExpires
sim.RemoveTask(eb)
}

type EnergyCostOptions struct {
Cost float64

Expand Down Expand Up @@ -293,13 +296,11 @@ func (ec *EnergyCost) MeetsRequirement(spell *Spell) bool {
spell.CurCast.Cost = spell.ApplyCostModifiers(spell.CurCast.Cost)
return spell.Unit.CurrentEnergy() >= spell.CurCast.Cost
}
func (ec *EnergyCost) CostFailureReason(sim *Simulation, spell *Spell) string {
func (ec *EnergyCost) CostFailureReason(_ *Simulation, spell *Spell) string {
return fmt.Sprintf("not enough energy (Current Energy = %0.03f, Energy Cost = %0.03f)", spell.Unit.CurrentEnergy(), spell.CurCast.Cost)
}
func (ec *EnergyCost) SpendCost(sim *Simulation, spell *Spell) {
if spell.CurCast.Cost > 0 {
spell.Unit.SpendEnergy(sim, spell.CurCast.Cost, ec.ResourceMetrics)
}
spell.Unit.SpendEnergy(sim, spell.CurCast.Cost, ec.ResourceMetrics)
}
func (ec *EnergyCost) IssueRefund(sim *Simulation, spell *Spell) {
if ec.Refund > 0 {
Expand Down
72 changes: 46 additions & 26 deletions sim/core/focus.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,20 @@ type focusBar struct {
currentFocus float64

onFocusGain OnFocusGain
tickAction *PendingAction

nextFocusTick time.Duration

regenMetrics *ResourceMetrics
refundMetrics *ResourceMetrics
}

func (unit *Unit) EnableFocusBar(regenMultiplier float64, onFocusGain OnFocusGain) {
unit.focusBar = focusBar{
unit: unit,
focusPerTick: BaseFocusPerTick * regenMultiplier,
onFocusGain: onFocusGain,
unit: unit,
focusPerTick: BaseFocusPerTick * regenMultiplier,
onFocusGain: onFocusGain,
regenMetrics: unit.NewEnergyMetrics(ActionID{OtherID: proto.OtherAction_OtherActionFocusRegen}),
refundMetrics: unit.NewEnergyMetrics(ActionID{OtherID: proto.OtherAction_OtherActionRefund}),
}
}

Expand All @@ -42,15 +48,16 @@ func (fb *focusBar) CurrentFocus() float64 {
return fb.currentFocus
}

func (fb *focusBar) AddFocus(sim *Simulation, amount float64, actionID ActionID) {
func (fb *focusBar) AddFocus(sim *Simulation, amount float64, metrics *ResourceMetrics) {
if amount < 0 {
panic("Trying to add negative focus!")
}

newFocus := min(fb.currentFocus+amount, MaxFocus)
metrics.AddEvent(amount, newFocus-fb.currentFocus)

if sim.Log != nil {
fb.unit.Log(sim, "Gained %0.3f focus from %s (%0.3f --> %0.3f).", amount, actionID, fb.currentFocus, newFocus)
fb.unit.Log(sim, "Gained %0.3f focus from %s (%0.3f --> %0.3f).", amount, metrics.ActionID, fb.currentFocus, newFocus)
}

fb.currentFocus = newFocus
Expand Down Expand Up @@ -82,39 +89,53 @@ func (fb *focusBar) reset(sim *Simulation) {

fb.currentFocus = MaxFocus

pa := &PendingAction{
Priority: ActionPriorityRegen,
NextActionAt: tickDuration,
if fb.unit.Type != PetUnit {
fb.enable(sim)
}
pa.OnAction = func(sim *Simulation) {
fb.AddFocus(sim, fb.focusPerTick, ActionID{OtherID: proto.OtherAction_OtherActionFocusRegen})
}

pa.NextActionAt = sim.CurrentTime + tickDuration
sim.AddPendingAction(pa)
}
fb.tickAction = pa
sim.AddPendingAction(pa)
func (fb *focusBar) enable(sim *Simulation) {
sim.AddTask(fb)
fb.nextFocusTick = sim.CurrentTime + tickDuration
sim.RescheduleTask(fb.nextFocusTick)
}

func (fb *focusBar) Cancel(sim *Simulation) {
if fb.tickAction != nil {
fb.tickAction.Cancel(sim)
fb.tickAction = nil
func (fb *focusBar) disable(sim *Simulation) {
fb.nextFocusTick = NeverExpires
sim.RemoveTask(fb)
}

func (fb *focusBar) RunTask(sim *Simulation) time.Duration {
if sim.CurrentTime < fb.nextFocusTick {
return fb.nextFocusTick
}

fb.AddFocus(sim, fb.focusPerTick, fb.regenMetrics)

fb.nextFocusTick = sim.CurrentTime + tickDuration
return fb.nextFocusTick
}

type FocusCostOptions struct {
Cost float64

Refund float64
RefundMetrics *ResourceMetrics // Optional, will default to unit.FocusRefundMetrics if not supplied
}
type FocusCost struct {
Refund float64
RefundMetrics *ResourceMetrics
ResourceMetrics *ResourceMetrics
}

func newFocusCost(spell *Spell, options FocusCostOptions) *FocusCost {
spell.DefaultCast.Cost = options.Cost

if options.Refund > 0 && options.RefundMetrics == nil {
options.RefundMetrics = spell.Unit.refundMetrics
}
return &FocusCost{
Refund: options.Refund,
RefundMetrics: options.RefundMetrics,
ResourceMetrics: spell.Unit.NewFocusMetrics(spell.ActionID),
}
}
Expand All @@ -123,15 +144,14 @@ func (fc *FocusCost) MeetsRequirement(spell *Spell) bool {
spell.CurCast.Cost = max(0, spell.CurCast.Cost*spell.Unit.PseudoStats.CostMultiplier)
return spell.Unit.CurrentFocus() >= spell.CurCast.Cost
}
func (fc *FocusCost) CostFailureReason(sim *Simulation, spell *Spell) string {
func (fc *FocusCost) CostFailureReason(_ *Simulation, spell *Spell) string {
return fmt.Sprintf("not enough focus (Current Focus = %0.03f, Focus Cost = %0.03f)", spell.Unit.CurrentFocus(), spell.CurCast.Cost)
}
func (fc *FocusCost) SpendCost(sim *Simulation, spell *Spell) {
spell.Unit.SpendFocus(sim, spell.CurCast.Cost, fc.ResourceMetrics)
}
func (fc *FocusCost) IssueRefund(sim *Simulation, spell *Spell) {
}

func (spell *Spell) FocusMetrics() *ResourceMetrics {
return spell.Cost.(*FocusCost).ResourceMetrics
if fc.Refund > 0 {
spell.Unit.AddFocus(sim, fc.Refund*spell.CurCast.Cost, fc.RefundMetrics)
}
}
2 changes: 2 additions & 0 deletions sim/core/pending_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const (

// DOTs need to be higher than anything else so that dots can properly expire before we take other actions.
ActionPriorityDOT ActionPriority = 3

ActionPriorityPrePull ActionPriority = 10
)

type PendingAction struct {
Expand Down
6 changes: 5 additions & 1 deletion sim/core/pet.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ func (pet *Pet) Enable(sim *Simulation, petAgent PetAgent) {
}

sim.addTracker(&pet.auraTracker)

if pet.HasFocusBar() {
pet.focusBar.enable(sim)
}
}

// Helper for enabling a pet that will expire after a certain duration.
Expand Down Expand Up @@ -230,7 +234,7 @@ func (pet *Pet) Disable(sim *Simulation) {
}

pet.CancelGCDTimer(sim)
pet.focusBar.Cancel(sim)
pet.focusBar.disable(sim)
pet.AutoAttacks.CancelAutoSwing(sim)
pet.enabled = false
pet.DoNothing() // mark it is as doing nothing now.
Expand Down
Loading

0 comments on commit f5e24b3

Please sign in to comment.