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

Pull in pet/target unit updates from #4118 #4

Merged
merged 2 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion proto/apl.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ message APLListItem {
APLAction action = 3; // The action to be performed.
}

// NextIndex: 19
// NextIndex: 21
message APLAction {
APLValue condition = 1; // If set, action will only execute if value is true or != 0.

Expand Down Expand Up @@ -73,6 +73,9 @@ message APLAction {

// Class or Spec-specific actions
APLActionCatOptimalRotationAction cat_optimal_rotation_action = 19;

// Internal use only, not exposed in UI.
APLActionCustomRotation custom_rotation = 20;
}
}

Expand Down Expand Up @@ -254,6 +257,9 @@ message APLActionMove {
APLValue range_from_target = 1;
}

message APLActionCustomRotation {
}

///////////////////////////////////////////////////////////////////////////
// VALUES
///////////////////////////////////////////////////////////////////////////
Expand Down
6 changes: 1 addition & 5 deletions sim/_shaman/fire_elemental_pet.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (fireElemental *FireElemental) Reset(_ *core.Simulation) {

}

func (fireElemental *FireElemental) OnGCDReady(sim *core.Simulation) {
func (fireElemental *FireElemental) ExecuteCustomRotation(sim *core.Simulation) {
/*
TODO this is a little dirty, can probably clean this up, the rotation might go through some more overhauls,
the random AI is hard to emulate.
Expand Down Expand Up @@ -122,10 +122,6 @@ func (fireElemental *FireElemental) TryCast(sim *core.Simulation, target *core.U
return false
}

if !spell.IsReady(sim) {
return false
}

if !spell.Cast(sim, target) {
return false
}
Expand Down
3 changes: 1 addition & 2 deletions sim/_shaman/spirit_wolves.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ func (spiritWolf *SpiritWolf) Initialize() {
// Nothing
}

func (spiritWolf *SpiritWolf) OnGCDReady(_ *core.Simulation) {
spiritWolf.DoNothing()
func (spiritWolf *SpiritWolf) ExecuteCustomRotation(_ *core.Simulation) {
}

func (spiritWolf *SpiritWolf) Reset(sim *core.Simulation) {
Expand Down
4 changes: 4 additions & 0 deletions sim/core/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ type Agent interface {
// Should return nil when the config doesn't match any custom behaviors.
NewAPLValue(rot *APLRotation, config *proto.APLValue) APLValue
NewAPLAction(rot *APLRotation, config *proto.APLAction) APLActionImpl

// Implements custom rotation behavior. Usually for pets and targets but can be used
// for players too.
ExecuteCustomRotation(sim *Simulation)
}

type ActionID struct {
Expand Down
13 changes: 13 additions & 0 deletions sim/core/apl.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ func (rot *APLRotation) doAndRecordWarnings(warningsList *[]string, isPrepull bo
rot.parsingPrepull = false
}

func (unit *Unit) newCustomRotation() *APLRotation {
return unit.newAPLRotation(&proto.APLRotation{
Type: proto.APLRotation_TypeAPL,
PriorityList: []*proto.APLListItem{
{
Action: &proto.APLAction{
Action: &proto.APLAction_CustomRotation{},
},
},
},
})
}

func (unit *Unit) newAPLRotation(config *proto.APLRotation) *APLRotation {
if config == nil {
return nil
Expand Down
4 changes: 3 additions & 1 deletion sim/core/apl_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func (rot *APLRotation) newAPLActionImpl(config *proto.APLAction) APLActionImpl
return nil
}

customAction := rot.unit.Env.Raid.GetPlayerFromUnit(rot.unit).NewAPLAction(rot, config)
customAction := rot.unit.Env.GetAgentFromUnit(rot.unit).NewAPLAction(rot, config)
if customAction != nil {
return customAction
}
Expand Down Expand Up @@ -179,6 +179,8 @@ func (rot *APLRotation) newAPLActionImpl(config *proto.APLAction) APLActionImpl
return rot.newActionItemSwap(config.GetItemSwap())
case *proto.APLAction_Move:
return rot.newActionMove(config.GetMove())
case *proto.APLAction_CustomRotation:
return rot.newActionCustomRotation(config.GetCustomRotation())
default:
return nil
}
Expand Down
35 changes: 35 additions & 0 deletions sim/core/apl_actions_misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package core

import (
"fmt"
"time"

"github.com/wowsims/sod/sim/core/proto"
)
Expand Down Expand Up @@ -188,3 +189,37 @@ func (action *APLActionMove) Execute(sim *Simulation) {
func (action *APLActionMove) String() string {
return fmt.Sprintf("Move(%s)", action.moveRange)
}

type APLActionCustomRotation struct {
defaultAPLActionImpl
unit *Unit
agent Agent

lastExecutedAt time.Duration
}

func (rot *APLRotation) newActionCustomRotation(config *proto.APLActionCustomRotation) APLActionImpl {
agent := rot.unit.Env.GetAgentFromUnit(rot.unit)
if agent == nil {
panic("Agent not found for custom rotation")
}

return &APLActionCustomRotation{
unit: rot.unit,
agent: agent,
}
}
func (action *APLActionCustomRotation) Reset(sim *Simulation) {
action.lastExecutedAt = -1
}
func (action *APLActionCustomRotation) IsReady(sim *Simulation) bool {
// Prevent infinite loops by only allowing this action to be performed once at each timestamp.
return action.lastExecutedAt != sim.CurrentTime
}
func (action *APLActionCustomRotation) Execute(sim *Simulation) {
action.lastExecutedAt = sim.CurrentTime
action.agent.ExecuteCustomRotation(sim)
}
func (action *APLActionCustomRotation) String() string {
return "Custom Rotation()"
}
2 changes: 1 addition & 1 deletion sim/core/apl_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (rot *APLRotation) newAPLValue(config *proto.APLValue) APLValue {
return nil
}

customValue := rot.unit.Env.Raid.GetPlayerFromUnit(rot.unit).NewAPLValue(rot, config)
customValue := rot.unit.Env.GetAgentFromUnit(rot.unit).NewAPLValue(rot, config)
if customValue != nil {
return customValue
}
Expand Down
26 changes: 12 additions & 14 deletions sim/core/cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,13 @@ func (cast *Cast) EffectiveTime() time.Duration {
type CastFunc func(*Simulation, *Unit)
type CastSuccessFunc func(*Simulation, *Unit) bool

func (spell *Spell) castFailureHelper(sim *Simulation, gracefulFailure bool, message string, vals ...any) bool {
func (spell *Spell) castFailureHelper(sim *Simulation, message string, vals ...any) bool {
if sim.CurrentTime < 0 && spell.Unit.Rotation != nil {
spell.Unit.Rotation.ValidationWarning(fmt.Sprintf(spell.ActionID.String()+" failed to cast: "+message, vals...))
} else if gracefulFailure {
} else {
if sim.Log != nil && !spell.Flags.Matches(SpellFlagNoLogs) {
spell.Unit.Log(sim, fmt.Sprintf(spell.ActionID.String()+" failed to cast: "+message, vals...))
}
} else {
panic(fmt.Sprintf(spell.ActionID.String()+" failed to cast: "+message, vals...))
}
return false
}
Expand Down Expand Up @@ -151,13 +149,13 @@ func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc {

if spell.ExtraCastCondition != nil {
if !spell.ExtraCastCondition(sim, target) {
return spell.castFailureHelper(sim, true, "extra spell condition")
return spell.castFailureHelper(sim, "extra spell condition")
}
}

if spell.Cost != nil {
if !spell.Cost.MeetsRequirement(sim, spell) {
return spell.castFailureHelper(sim, true, spell.Cost.CostFailureReason(sim, spell))
return spell.castFailureHelper(sim, spell.Cost.CostFailureReason(sim, spell))
}
}

Expand All @@ -169,26 +167,26 @@ func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc {
if config.CD.Timer != nil {
// By panicking if spell is on CD, we force each sim to properly check for their own CDs.
if !spell.CD.IsReady(sim) {
return spell.castFailureHelper(sim, false, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime)
return spell.castFailureHelper(sim, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime)
}
spell.CD.Set(sim.CurrentTime + spell.CurCast.CastTime + spell.CD.Duration)
}

if config.SharedCD.Timer != nil {
// By panicking if spell is on CD, we force each sim to properly check for their own CDs.
if !spell.SharedCD.IsReady(sim) {
return spell.castFailureHelper(sim, false, "still on shared cooldown for %s, curTime = %s", spell.SharedCD.TimeToReady(sim), sim.CurrentTime)
return spell.castFailureHelper(sim, "still on shared cooldown for %s, curTime = %s", spell.SharedCD.TimeToReady(sim), sim.CurrentTime)
}
spell.SharedCD.Set(sim.CurrentTime + spell.CurCast.CastTime + spell.SharedCD.Duration)
}

// By panicking if spell is on CD, we force each sim to properly check for their own CDs.
if spell.CurCast.GCD != 0 && !spell.Unit.GCD.IsReady(sim) {
return spell.castFailureHelper(sim, false, "GCD on cooldown for %s, curTime = %s", spell.Unit.GCD.TimeToReady(sim), sim.CurrentTime)
return spell.castFailureHelper(sim, "GCD on cooldown for %s, curTime = %s", spell.Unit.GCD.TimeToReady(sim), sim.CurrentTime)
}

if hc := spell.Unit.Hardcast; hc.Expires > sim.CurrentTime {
return spell.castFailureHelper(sim, false, "casting/channeling %v for %s, curTime = %s", hc.ActionID, hc.Expires-sim.CurrentTime, sim.CurrentTime)
return spell.castFailureHelper(sim, "casting/channeling %v for %s, curTime = %s", hc.ActionID, hc.Expires-sim.CurrentTime, sim.CurrentTime)
}

if effectiveTime := spell.CurCast.EffectiveTime(); effectiveTime != 0 {
Expand All @@ -200,7 +198,7 @@ func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc {
}

if (spell.CurCast.CastTime > 0) && spell.Unit.Moving {
return spell.castFailureHelper(sim, false, "casting/channeling while moving not allowed!")
return spell.castFailureHelper(sim, "casting/channeling while moving not allowed!")
}

// TODO: Fix with removal of ChannelTime?
Expand Down Expand Up @@ -274,14 +272,14 @@ func (spell *Spell) makeCastFuncSimple() CastSuccessFunc {
return func(sim *Simulation, target *Unit) bool {
if spell.ExtraCastCondition != nil {
if !spell.ExtraCastCondition(sim, target) {
return spell.castFailureHelper(sim, true, "extra spell condition")
return spell.castFailureHelper(sim, "extra spell condition")
}
}

if spell.CD.Timer != nil {
// By panicking if spell is on CD, we force each sim to properly check for their own CDs.
if !spell.CD.IsReady(sim) {
return spell.castFailureHelper(sim, false, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime)
return spell.castFailureHelper(sim, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime)
}

spell.CD.Set(sim.CurrentTime + spell.CD.Duration)
Expand All @@ -290,7 +288,7 @@ func (spell *Spell) makeCastFuncSimple() CastSuccessFunc {
if spell.SharedCD.Timer != nil {
// By panicking if spell is on CD, we force each sim to properly check for their own CDs.
if !spell.SharedCD.IsReady(sim) {
return spell.castFailureHelper(sim, false, "still on shared cooldown for %s, curTime = %s", spell.SharedCD.TimeToReady(sim), sim.CurrentTime)
return spell.castFailureHelper(sim, "still on shared cooldown for %s, curTime = %s", spell.SharedCD.TimeToReady(sim), sim.CurrentTime)
}

spell.SharedCD.Set(sim.CurrentTime + spell.SharedCD.Duration)
Expand Down
18 changes: 18 additions & 0 deletions sim/core/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ func (env *Environment) finalize(raidProto *proto.Raid, _ *proto.Encounter, raid

for _, target := range env.Encounter.Targets {
target.finalize()
if target.AI != nil {
target.Rotation = target.newCustomRotation()
}
}

for _, party := range env.Raid.Parties {
Expand All @@ -156,6 +159,7 @@ func (env *Environment) finalize(raidProto *proto.Raid, _ *proto.Encounter, raid
character.Finalize()
for _, pet := range character.Pets {
pet.Finalize()
pet.Rotation = pet.newCustomRotation()
}
}
}
Expand Down Expand Up @@ -264,6 +268,20 @@ func (env *Environment) NextTarget(target *Unit) *Target {
func (env *Environment) NextTargetUnit(target *Unit) *Unit {
return &env.NextTarget(target).Unit
}
func (env *Environment) GetAgentFromUnit(unit *Unit) Agent {
raidAgent := env.Raid.GetPlayerFromUnit(unit)
if raidAgent != nil {
return raidAgent
}

for _, target := range env.Encounter.Targets {
if unit == &target.Unit {
return target
}
}

return nil
}

func (env *Environment) GetUnit(ref *proto.UnitReference, contextUnit *Unit) *Unit {
if ref == nil {
Expand Down
1 change: 1 addition & 0 deletions sim/core/pet.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,4 @@ func (pet *Pet) AddRaidBuffs(_ *proto.RaidBuffs) {}
func (pet *Pet) AddPartyBuffs(_ *proto.PartyBuffs) {}
func (pet *Pet) ApplyTalents() {}
func (pet *Pet) ApplyRunes() {}
func (pet *Pet) OnGCDReady(_ *Simulation) {}
2 changes: 1 addition & 1 deletion sim/core/target_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
type TargetAI interface {
Initialize(*Target, *proto.Target)
Reset(*Simulation)
DoAction(*Simulation)
ExecuteCustomRotation(*Simulation)
}

func (target *Target) initialize(config *proto.Target) {
Expand Down
1 change: 1 addition & 0 deletions sim/core/target_dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ func (td *TargetDummy) ApplyTalents() {}
func (td *TargetDummy) ApplyRunes() {}
func (td *TargetDummy) Initialize() {}
func (td *TargetDummy) Reset(sim *Simulation) {}
func (td *TargetDummy) ExecuteCustomRotation(sim *Simulation) {}
4 changes: 4 additions & 0 deletions sim/core/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,3 +604,7 @@ func (unit *Unit) GetMetadata() *proto.UnitMetadata {

return metadata
}

func (unit *Unit) ExecuteCustomRotation(sim *Simulation) {
panic("Unimplemented ExecuteCustomRotation")
}
2 changes: 1 addition & 1 deletion sim/encounters/default_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (ai *DefaultAI) Reset(sim *core.Simulation) {

}

func (ai *DefaultAI) DoAction(sim *core.Simulation) {
func (ai *DefaultAI) ExecuteCustomRotation(sim *core.Simulation) {
for _, ability := range ai.Abilities {
if sim.CurrentTime < ability.InitialCD {
continue
Expand Down
2 changes: 1 addition & 1 deletion sim/encounters/naxxramas/kelthuzad25_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@ func (ai *KelThuzad25AI) Initialize(target *core.Target, config *proto.Target) {
func (ai *KelThuzad25AI) Reset(*core.Simulation) {
}

func (ai *KelThuzad25AI) DoAction(sim *core.Simulation) {
func (ai *KelThuzad25AI) ExecuteCustomRotation(sim *core.Simulation) {
}
2 changes: 1 addition & 1 deletion sim/encounters/naxxramas/loatheb25_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@ func (ai *Loatheb25AI) Initialize(target *core.Target, config *proto.Target) {
func (ai *Loatheb25AI) Reset(*core.Simulation) {
}

func (ai *Loatheb25AI) DoAction(sim *core.Simulation) {
func (ai *Loatheb25AI) ExecuteCustomRotation(sim *core.Simulation) {
}
2 changes: 1 addition & 1 deletion sim/encounters/naxxramas/patchwerk10_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (ai *Patchwerk10AI) registerFrenzySpell(target *core.Target) {
})
}

func (ai *Patchwerk10AI) DoAction(sim *core.Simulation) {
func (ai *Patchwerk10AI) ExecuteCustomRotation(sim *core.Simulation) {
if ai.Target.CurrentTarget == nil {
return
}
Expand Down
2 changes: 1 addition & 1 deletion sim/encounters/naxxramas/patchwerk25_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func (ai *Patchwerk25AI) registerFrenzySpell(target *core.Target) {
})
}

func (ai *Patchwerk25AI) DoAction(sim *core.Simulation) {
func (ai *Patchwerk25AI) ExecuteCustomRotation(sim *core.Simulation) {
if ai.Target.CurrentTarget == nil {
return
}
Expand Down
2 changes: 1 addition & 1 deletion sim/encounters/naxxramas/thaddius25_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@ func (ai *Thaddius25AI) Initialize(target *core.Target, config *proto.Target) {
func (ai *Thaddius25AI) Reset(*core.Simulation) {
}

func (ai *Thaddius25AI) DoAction(sim *core.Simulation) {
func (ai *Thaddius25AI) ExecuteCustomRotation(sim *core.Simulation) {
}
3 changes: 2 additions & 1 deletion sim/hunter/pet.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func (hp *HunterPet) Reset(_ *core.Simulation) {
hp.uptimePercent = min(1, max(0, hp.hunterOwner.Options.PetUptime))
}

func (hp *HunterPet) OnGCDReady(sim *core.Simulation) {
func (hp *HunterPet) ExecuteCustomRotation(sim *core.Simulation) {
percentRemaining := sim.GetRemainingDurationPercent()
if percentRemaining < 1.0-hp.uptimePercent { // once fight is % completed, disable pet.
hp.Disable(sim)
Expand All @@ -120,6 +120,7 @@ func (hp *HunterPet) OnGCDReady(sim *core.Simulation) {
}

target := hp.CurrentTarget

if hp.focusDump == nil {
hp.specialAbility.Cast(sim, target)
return
Expand Down
Loading
Loading