APLCheck - WoWAnalyzer/WoWAnalyzer GitHub Wiki
The APL checker is a tool to automatically generate useful analysis from a basic Action Priority List. Currently, this tool can generate a Checklist section and Timeline annotations, as well as structured output that can (in theory) be used in other analysis.
Once you understand the concept of an APL, writing them is fairly straightforward. An example is likely the most useful way to get moving. Below is the APL for Brewmaster Monk as of Patch 9.1.
export const apl = build([
SPELLS.BONEDUST_BREW_CAST,
{ spell: SPELLS.KEG_SMASH, condition: buffPresent(SPELLS.WEAPONS_OF_ORDER_BUFF_AND_HEAL) },
{ spell: SPELLS.BREATH_OF_FIRE, condition: hasLegendary(SPELLS.CHARRED_PASSIONS) },
SPELLS.KEG_SMASH,
SPELLS.BLACKOUT_KICK_BRM,
SPELLS.FAELINE_STOMP_CAST,
SPELLS.BREATH_OF_FIRE,
{
spell: SPELLS.RUSHING_JADE_WIND_TALENT,
condition: buffMissing(SPELLS.RUSHING_JADE_WIND_TALENT, {
timeRemaining: 2000,
duration: 6000,
}),
},
{ spell: SPELLS.SPINNING_CRANE_KICK_BRM, condition: buffPresent(SPELLS.CHARRED_PASSIONS_BUFF) },
SPELLS.CHI_WAVE_TALENT,
SPELLS.CHI_BURST_TALENT,
{
spell: SPELLS.SPINNING_CRANE_KICK_BRM,
condition: optional(
hasConduit(SPELLS.WALK_WITH_THE_OX),
<>
It is worthwhile to cast <SpellLink id={SPELLS.SPINNING_CRANE_KICK_BRM.id} /> over{' '}
<SpellLink id={SPELLS.TIGER_PALM.id} /> when using this conduit <em>if</em> doing so would
get you an extra cast of <SpellLink id={SPELLS.INVOKE_NIUZAO_THE_BLACK_OX.id} /> that lines
up with incoming damage. We cannot check this automatically, and be warned that it is a
small defensive loss due to the loss of Brew cooldown reduction.
</>,
),
},
SPELLS.TIGER_PALM,
]);
An APL is just a list of Rule
s. Each rule is a Spell
(e.g. SPELLS.BONEDUST_BREW_CAST
) that may have a condition
attached to it. All available conditions can be found in parser/shared/metrics/apl/conditions/
.
The checker runs through the list of rules from top to bottom and finds the first one that applies. Specifically:
- The spell must be known (i.e. in the
Abilities
module for the spec) - The spell must have at least 1 charge off cooldown or be the current spell cast
- The
condition
for the rule must apply (thevalidate
function of the condition object should returntrue
)
If the spell attached to the rule matches the current spell being cast, then it is marked as a success. Otherwise it is a violation of the rule, and marked as such.
Spells that are not in the APL are excluded from this processing. This means that you don't need to worry about utility spells clogging up the violation list.
The simplest way to annotate the timeline is to use an empty functional suggestion:
import { WIPSuggestionFactory } from 'parser/core/CombatLogParser';
import aplCheck, { build } from 'parser/shared/metrics/apl';
import annotateTimeline from 'parser/shared/metrics/apl/annotate';
export const apl = build([ ... ]);
export const check = aplCheck(apl);
const suggestion = (): WIPSuggestionFactory => (events, info) => {
const { violations } = check(events, info);
annotateTimeline(violations);
return undefined;
};
export default suggestion;
The annotateTimeline
function actually does the work of attaching timeline annotations. Note that this will overwrite any existing annotations!
In order to have WoWAnalyzer call this function, it needs to be added to the suggestions
list on your CombatLogParser
:
import AplCheck from './path/to/AplCheck';
// ...
class CombatLogParser extendss CoreCombatLogParser {
// ...
static suggestions = [...CoreCombatLogParser.suggestions, AplCheck()];
}
Most Checklists are split into two files: Component
and Module
. Adding the APL check results to the checklist requires modifying both.
First, in the Module
file, import your apl
and the check
function. Then, as part of the render
method, compute the check results:
import { apl, check as aplCheck } from '../../path/to/AplCheck';
// ...
class Checklist extends BaseChecklist {
// ...
render() {
const checkResults = aplCheck(this.owner.eventHistory, this.owner.info);
return (
<Component
apl={apl}
checkResults={checkResults}
// other properties...
/>
);
}
}
Then, modify the Component
file to pass the new properties to an AplRule
. If the Component
is a .js
file instead of a .tsx
file, then don't import or use the AplRuleProps
type.
import AplRule, { AplRuleProps } from 'parser/shared/metrics/apl/ChecklistRule';
// ...
const Component = (props: ChecklistProps & AplRuleProps) => {
// ...
return (
<Checklist>
<AplRule {...props} cooldowns={[ ... ]} />
// ...
</Checklist>
};
Add any relevant cooldowns to the cooldowns
list (see the next section for the reasons not to put cooldowns in the APL itself).
This will produce a Checklist rule that looks something like this (the name and description of this are customized---which you can do with the name
and description
properties of the AplRule
):
Writing APLs for automatic checking in WoWAnalyzer is not quite the same as writing an APL for simc
. Real fights have a lot of factors to consider that can break APLs that are ported from simc
without adjustments. For example: it is often correct to hold a cooldown when you know there is upcoming downtime, a priority add, or a burn phase. A simc
APL will include that cooldown and a simple port would mark every cast with that cooldown available as a violation if it were included in the WoWAnalyzer APL. (Some specs like Brewmaster also have a lot of simc
rules that are specific to the simulation itself.) As a result, it is better to think of this as automating Wowhead or Icy-Veins than as applying simc
to a log.
My process for building the APLs for Brewmaster and Protection Paladin was basically as follows:
- Start with the rotation as described on Wowhead / Icy-Veins.
- Remove major cooldowns (anything that would be at or near the top of the APL that might be correct to delay).
- Write the APL out from top to bottom.
- Check the timeline annotations to ensure they look reasonable. A small number of incorrectly-marked violations is okay as long as it is actually a small number.
In particular, there are a couple of simple rules that I would strongly recommend people follow when using this tool:
- Do not include cooldowns in the APL
- Wrap conditions that are difficult or impossible to accurately check with the
optional
condition. - Do not include defensive, healing, or utility buttons even if they are in the
simc
APL (many specs have a kick in their rotation due to Sephuz' Secret).
The WoWAnalyzer discord is the best place to go for help. @emallson
is the primary author of this tool and is usually around to answer questions or help with implementation.