Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vigo/resource-tasks #3884

Merged
merged 11 commits into from
Oct 19, 2023
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
Loading