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

Add Wait Until APL action #3605

Merged
merged 1 commit into from
Sep 3, 2023
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
7 changes: 6 additions & 1 deletion proto/apl.proto
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ message APLListItem {
APLAction action = 3; // The action to be performed.
}

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

Expand All @@ -49,6 +49,7 @@ message APLAction {
APLActionCancelAura cancel_aura = 10;
APLActionTriggerICD trigger_icd = 11;
APLActionWait wait = 4;
APLActionWaitUntil wait_until = 14;
}
}

Expand Down Expand Up @@ -188,6 +189,10 @@ message APLActionWait {
APLValue duration = 1;
}

message APLActionWaitUntil {
APLValue condition = 1;
}

///////////////////////////////////////////////////////////////////////////
// VALUES
///////////////////////////////////////////////////////////////////////////
Expand Down
30 changes: 6 additions & 24 deletions sim/core/apl.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ type APLRotation struct {
prepullActions []*APLAction
priorityList []*APLAction

// Current strict sequence
strictSequence *APLAction
// Action currently controlling this rotation (only used for certain actions, such as StrictSequence).
controllingAction APLActionImpl

// Used inside of actions/value to determine whether they will occur during the prepull or regular rotation.
parsingPrepull bool
Expand Down Expand Up @@ -143,7 +143,7 @@ func (rot *APLRotation) allPrepullActions() []*APLAction {
}

func (rot *APLRotation) reset(sim *Simulation) {
rot.strictSequence = nil
rot.controllingAction = nil
rot.inLoop = false
for _, action := range rot.allAPLActions() {
action.impl.Reset(sim)
Expand Down Expand Up @@ -174,37 +174,19 @@ func (apl *APLRotation) DoNextAction(sim *Simulation) {
}

if apl.unit.GCD.IsReady(sim) {
apl.unit.WaitUntil(sim, sim.CurrentTime+time.Millisecond*500)
apl.unit.WaitUntil(sim, sim.CurrentTime+time.Millisecond*50)
} else {
apl.unit.DoNothing()
}
}

func (apl *APLRotation) getNextAction(sim *Simulation) *APLAction {
if sim.CurrentTime < apl.unit.waitUntilTime {
return nil
}

if apl.strictSequence != nil {
ss := apl.strictSequence.impl.(*APLActionStrictSequence)
if ss.actions[ss.curIdx].IsReady(sim) {
return apl.strictSequence
} else if apl.unit.GCD.IsReady(sim) {
// If the GCD is ready when the next subaction isn't, it means the sequence is bad
// so reset and exit the sequence.
ss.curIdx = 0
apl.strictSequence = nil
} else {
// Return nil to wait for the GCD to become ready.
return nil
}
if apl.controllingAction != nil {
return apl.controllingAction.GetNextAction(sim)
}

for _, action := range apl.priorityList {
if action.IsReady(sim) {
if _, ok := action.impl.(*APLActionStrictSequence); ok {
apl.strictSequence = action
}
return action
}
}
Expand Down
14 changes: 10 additions & 4 deletions sim/core/apl_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ type APLActionImpl interface {
// Performs the action.
Execute(*Simulation)

// Called only while this action is controlling the rotation.
GetNextAction(sim *Simulation) *APLAction

// Pretty-print string for debugging.
String() string
}
Expand All @@ -81,10 +84,11 @@ type APLActionImpl interface {
type defaultAPLActionImpl struct {
}

func (impl defaultAPLActionImpl) GetInnerActions() []*APLAction { return nil }
func (impl defaultAPLActionImpl) GetAPLValues() []APLValue { return nil }
func (impl defaultAPLActionImpl) Finalize(*APLRotation) {}
func (impl defaultAPLActionImpl) Reset(*Simulation) {}
func (impl defaultAPLActionImpl) GetInnerActions() []*APLAction { return nil }
func (impl defaultAPLActionImpl) GetAPLValues() []APLValue { return nil }
func (impl defaultAPLActionImpl) Finalize(*APLRotation) {}
func (impl defaultAPLActionImpl) Reset(*Simulation) {}
func (impl defaultAPLActionImpl) GetNextAction(*Simulation) *APLAction { return nil }

func (rot *APLRotation) newAPLAction(config *proto.APLAction) *APLAction {
if config == nil {
Expand Down Expand Up @@ -138,6 +142,8 @@ func (rot *APLRotation) newAPLActionImpl(config *proto.APLAction) APLActionImpl
return rot.newActionTriggerICD(config.GetTriggerIcd())
case *proto.APLAction_Wait:
return rot.newActionWait(config.GetWait())
case *proto.APLAction_WaitUntil:
return rot.newActionWaitUntil(config.GetWaitUntil())
default:
return nil
}
Expand Down
73 changes: 64 additions & 9 deletions sim/core/apl_actions_core.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/wotlk/sim/core/proto"
)
Expand Down Expand Up @@ -208,38 +209,92 @@ type APLActionWait struct {
defaultAPLActionImpl
unit *Unit
duration APLValue

curWaitTime time.Duration
}

func (rot *APLRotation) newActionWait(config *proto.APLActionWait) APLActionImpl {
unit := rot.unit
durationVal := rot.coerceTo(rot.newAPLValue(config.Duration), proto.APLValueType_ValueTypeDuration)
if durationVal == nil {
return nil
}

return &APLActionWait{
unit: unit,
duration: rot.coerceTo(rot.newAPLValue(config.Duration), proto.APLValueType_ValueTypeDuration),
duration: durationVal,
}
}
func (action *APLActionWait) GetAPLValues() []APLValue {
return []APLValue{action.duration}
}
func (action *APLActionWait) IsReady(sim *Simulation) bool {
return action.duration != nil
return true
}

func (action *APLActionWait) Execute(sim *Simulation) {
waitUntilTime := sim.CurrentTime + action.duration.GetDuration(sim)
action.unit.waitUntilTime = waitUntilTime
action.unit.Rotation.controllingAction = action
action.curWaitTime = sim.CurrentTime + action.duration.GetDuration(sim)

if waitUntilTime > action.unit.GCD.ReadyAt() {
action.unit.WaitUntil(sim, waitUntilTime)
return
}
pa := &PendingAction{
Priority: ActionPriorityLow,
OnAction: action.unit.gcdAction.OnAction,
NextActionAt: waitUntilTime,
NextActionAt: action.curWaitTime,
}
sim.AddPendingAction(pa)
}

func (action *APLActionWait) GetNextAction(sim *Simulation) *APLAction {
if sim.CurrentTime >= action.curWaitTime {
action.unit.Rotation.controllingAction = nil
return action.unit.Rotation.getNextAction(sim)
} else {
return nil
}
}

func (action *APLActionWait) String() string {
return fmt.Sprintf("Wait(%s)", action.duration)
}

type APLActionWaitUntil struct {
defaultAPLActionImpl
unit *Unit
condition APLValue
}

func (rot *APLRotation) newActionWaitUntil(config *proto.APLActionWaitUntil) APLActionImpl {
unit := rot.unit
conditionVal := rot.coerceTo(rot.newAPLValue(config.Condition), proto.APLValueType_ValueTypeBool)
if conditionVal == nil {
return nil
}

return &APLActionWaitUntil{
unit: unit,
condition: conditionVal,
}
}
func (action *APLActionWaitUntil) GetAPLValues() []APLValue {
return []APLValue{action.condition}
}
func (action *APLActionWaitUntil) IsReady(sim *Simulation) bool {
return !action.condition.GetBool(sim)
}

func (action *APLActionWaitUntil) Execute(sim *Simulation) {
action.unit.Rotation.controllingAction = action
}

func (action *APLActionWaitUntil) GetNextAction(sim *Simulation) *APLAction {
if action.condition.GetBool(sim) {
action.unit.Rotation.controllingAction = nil
return action.unit.Rotation.getNextAction(sim)
} else {
return nil
}
}

func (action *APLActionWaitUntil) String() string {
return fmt.Sprintf("WaitUntil(%s)", action.condition)
}
24 changes: 20 additions & 4 deletions sim/core/apl_actions_sequences.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,28 @@ func (action *APLActionStrictSequence) IsReady(sim *Simulation) bool {
return true
}
func (action *APLActionStrictSequence) Execute(sim *Simulation) {
action.actions[action.curIdx].Execute(sim)
action.curIdx++
action.unit.Rotation.controllingAction = action
}
func (action *APLActionStrictSequence) GetNextAction(sim *Simulation) *APLAction {
if action.actions[action.curIdx].IsReady(sim) {
nextAction := action.actions[action.curIdx]

if action.curIdx == len(action.actions) {
action.curIdx++
if action.curIdx == len(action.actions) {
action.curIdx = 0
action.unit.Rotation.controllingAction = nil
}

return nextAction
} else if action.unit.GCD.IsReady(sim) {
// If the GCD is ready when the next subaction isn't, it means the sequence is bad
// so reset and exit the sequence.
action.curIdx = 0
action.unit.Rotation.strictSequence = nil
action.unit.Rotation.controllingAction = nil
return action.unit.Rotation.getNextAction(sim)
} else {
// Return nil to wait for the GCD to become ready.
return nil
}
}
func (action *APLActionStrictSequence) String() string {
Expand Down
3 changes: 0 additions & 3 deletions sim/core/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ type Unit struct {
waitingForEnergy float64
waitingForMana float64
waitStartTime time.Duration
waitUntilTime time.Duration

// Cached mana return values per tick.
manaTickWhileCasting float64
Expand Down Expand Up @@ -456,8 +455,6 @@ func (unit *Unit) reset(sim *Simulation, agent Agent) {
if unit.Rotation != nil {
unit.Rotation.reset(sim)
}

unit.waitUntilTime = 0
}

func (unit *Unit) startPull(sim *Simulation) {
Expand Down
4 changes: 2 additions & 2 deletions sim/hunter/TestAPL.results
Original file line number Diff line number Diff line change
Expand Up @@ -810,8 +810,8 @@ dps_results: {
dps_results: {
key: "TestAPL-AllItems-UndeadSlayer'sBlessedArmor"
value: {
dps: 5385.71714
tps: 4633.2316
dps: 5386.46454
tps: 4633.99134
}
}
dps_results: {
Expand Down
2 changes: 1 addition & 1 deletion sim/rogue/TestAssassination.results
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ character_stats_results: {
final_stats: 221
final_stats: 0
final_stats: 5636.84
final_stats: 469.94995
final_stats: 469.94994
final_stats: 2072.9756
final_stats: 221
final_stats: 94
Expand Down
2 changes: 1 addition & 1 deletion sim/rogue/TestCombat.results
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ character_stats_results: {
final_stats: 221
final_stats: 0
final_stats: 5862.3136
final_stats: 469.94995
final_stats: 469.94994
final_stats: 2164.78757
final_stats: 221
final_stats: 94
Expand Down
13 changes: 12 additions & 1 deletion ui/core/components/individual_sim_ui/apl_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
APLActionCancelAura,
APLActionTriggerICD,
APLActionWait,
APLActionWaitUntil,
APLValue,
APLActionMultishield,
} from '../../proto/apl.js';
Expand Down Expand Up @@ -402,7 +403,7 @@ const actionKindFactories: {[f in NonNullable<APLActionKind>]: ActionKindConfig<
['wait']: inputBuilder({
label: 'Wait',
submenu: ['Misc'],
shortDescription: 'Pauses the GCD for a specified amount of time.',
shortDescription: 'Pauses all APL actions for a specified amount of time.',
includeIf: (player: Player<any>, isPrepull: boolean) => !isPrepull,
newValue: () => APLActionWait.create({
duration: {
Expand All @@ -418,6 +419,16 @@ const actionKindFactories: {[f in NonNullable<APLActionKind>]: ActionKindConfig<
AplValues.valueFieldConfig('duration'),
],
}),
['waitUntil']: inputBuilder({
label: 'Wait Until',
submenu: ['Misc'],
shortDescription: 'Pauses all APL actions until the specified condition is <b>True</b>.',
includeIf: (player: Player<any>, isPrepull: boolean) => !isPrepull,
newValue: () => APLActionWaitUntil.create(),
fields: [
AplValues.valueFieldConfig('condition'),
],
}),
['changeTarget']: inputBuilder({
label: 'Change Target',
submenu: ['Misc'],
Expand Down
Loading