Skip to content

Spell batching

magey edited this page Aug 8, 2019 · 23 revisions

Official statements from Blizzard

Source: https://web.archive.org/web/20140619092137/us.battle.net/wow/en/forum/topic/13087818929?page=6#114

Any action that one unit takes on another different unit used to be processed in batches every 400ms. Some very attentive people may have noticed that healing yourself would give you the health instantly (minus client/server latency), whereas healing another unit would incur a delay of between 0ms and 400ms (again, on top of client/server latency). Same with damaging, applying auras, interrupting, knocking back, etc.

Source: https://eu.forums.blizzard.com/en/wow/t/spell-batching-in-classic/39542

For WoW Classic, we’re moving spell casts to a low-priority loop that will cause them to be processed at the frequency that best fits how the game actually played in version 1.12. Two mages will be able to Polymorph each other somewhat reliably, resulting in two sheep nervously pacing around at range. Two warriors will be able to Charge one another, and the end result will be both warriors standing stunned in each other’s original location.

Observations from the beta

The key takeaway from Blizzard's statements regarding spell batching is "Any action that one unit takes on another different unit used to be processed in batches every 400ms". What does this mean in practice? first of all it means that any action that you take on yourself (healing yourself, buffing yourself, etc.) is instant; only actions taken on other units, be it players or mobs, are batched.

It's important to note that only the application of damage or healing and buffs/debuffs resulting from an attack, cast or use of an ability are delayed until the next batch processing window; the calculations which determine if the attack hit or missed and if it triggered any procs happen immediately when the cast finishes, and the player can immediately start casting another spell or use another ability before the damage of the previous one has even been applied (you can find an example of this below involving Frostbolt).

Auto attacks

When you're auto attacking a target the combat log will show you a SWING_DAMAGE message if you hit the target or a SWING_MISSED message if you missed or were avoided at the interval of your swing speed, i.e. if you're using a 3.6 speed weapon then these messages will show up every 3.6 seconds. But these messages are only one part of the equation; they signal when the attack table roll happens and damage calculations are performed but the actual damage of your auto attack is not applied to the target until the next batch is processed by the server. When this happens, and advanced combat logging is enabled in the client, the combat log will show a SWING_DAMAGE_LANDED message signaling the actual application of the damage on the target. Example (edited for brevity):

6/8 11:38:15.866  SWING_DAMAGE (Glance for 125)
6/8 11:38:15.967  SWING_DAMAGE_LANDED (Glance for 125)
6/8 11:38:19.480  SWING_DAMAGE (Glance for 107)
6/8 11:38:19.589  SWING_DAMAGE_LANDED (Glance for 107)
6/8 11:38:23.089  SWING_MISSED (Miss)
6/8 11:38:26.684  SWING_MISSED (Miss)
6/8 11:38:30.290  SWING_DAMAGE (Hit for 134)
6/8 11:38:30.528  SWING_DAMAGE_LANDED (Hit for 134)
6/8 11:38:33.887  SWING_MISSED (Parry)
6/8 11:38:37.409  SWING_DAMAGE (Crit for 258)
6/8 11:38:37.814  SWING_DAMAGE_LANDED (Crit for 258)

If you look at the time difference between the different SWING_DAMAGE and SWING_MISSED messages you will see they align with a 3.6 weapon swing timer.

Instant melee attacks

Lets use a Hamstring as an example. When you cast Hamstring the server checks the requirements for using the skill (having enough rage, having a weapon equipped, etc.), and if the requirement check is not passed a SPELL_CAST_FAILED event will show up in the combat log detailing the reason why.

If the server decides that you can use the skill it will immediately perform the steps involved in a melee special attack such as the attack table roll, weapon damage calculation, armor reduction, etc. This shows up in the combat log as the SPELL_CAST_SUCCESS message. If your Hamstring failed the attack table roll (parry, dodge, miss, immune, etc.) a SPELL_MISSED message will immediately follow.

When your Hamstring passes the attack table roll and is about to hit the target spell batching kicks in. Your Hamstring's movement speed debuff and damage are added into the batch processing queue but will not be applied to your target until the next batch is processed by the server (which occurs every 400ms). When this happens the combat log will show you the SPELL_AURA_APPLLIED message for the application of the movement speed debuff and the SPELL_DAMAGE message for the damage being done to the target. Example:

6/8 11:33:24.535  SPELL_CAST_SUCCESS (Hamstring)
6/8 11:33:24.535  SPELL_MISSED (Hamstring, Parry)
6/8 11:33:26.050  SPELL_CAST_SUCCESS (Hamstring)
6/8 11:33:26.050  SWING_DAMAGE (Auto attack for 133)
6/8 11:33:26.200  SPELL_DAMAGE (Hamstring damaged target for 11)
6/8 11:33:26.200  SPELL_AURA_APPLIED (Hamstring slow applied to target)
6/8 11:33:26.200  SWING_DAMAGE_LANDED (Auto attack for 133 damage applied)

Here we can see the attacker attempting to use Hamstring and getting parried by the target; SPELL_CAST_SUCCESS immediately followed by SPELL_MISSED. He then uses Hamstring again 1.5s later (GCD) and this time it connects. He also happens to auto attack at this time as we can see by the SWING_DAMAGE message. The application of the Hamstring damage and slow and the auto attack damage all happen at the edge of the batch window which occurs at 11:33:26.200.

Instant cast spells

Instant cast spells are handled much like instant melee attacks, which makes sense since instant melee attacks are really spells with a physical school where the server tries its best to make them appear like regular melee attacks. The sequence of events that happens when using an instant cast spell such as Fire Blast or Arcane Explosion is nearly identical to the one described for Hamstring above, only instead of the melee attack table the spell hit table is used and damage calculations use bonus spell damage and target resists. Example:

7/12 19:22:08.258  SPELL_CAST_SUCCESS (Arcane Explosion)
7/12 19:22:08.258  SPELL_MISSED (Son of Flame, Resist)
7/12 19:22:08.258  SPELL_MISSED (Son of Flame, Resist)
7/12 19:22:08.258  SPELL_MISSED (Son of Flame, Resist)
7/12 19:22:08.258  SPELL_MISSED (Son of Flame, Resist)
7/12 19:22:08.258  SPELL_MISSED (Son of Flame, Resist)
7/12 19:22:09.887  SPELL_CAST_SUCCESS (Arcane Explosion)
7/12 19:22:09.887  SPELL_MISSED (Son of Flame, Resist)
7/12 19:22:09.887  SPELL_MISSED (Son of Flame, Resist)
7/12 19:22:09.887  SPELL_MISSED (Son of Flame, Resist)
7/12 19:22:10.268  SPELL_DAMAGE (Son of Flame, 39 damage, 117 resisted)

Here we can see a poor soul trying to cast Arcane Explosion on a bunch of Sons of Flame. His first cast is fully resisted by all of them which we can tell by the SPELL_MISSED messages immediately following the SPELL_CAST_SUCCESS (same timestamp). He then attempts a second cast and doesn't fare all that better; this cast is fully resisted by 3 of them and the 4th one receives 39 damage. We can see the SPELL_DAMAGE event has a different timestamp than the SPELL_CAST_SUCCESS and SPELL_MISSED events; this is spell batching at work.

Spells with a cast time

Plain old spells with a cast time are similar overall in their sequence of events to instant melee attacks and instant cast spells, but they have the addition of the SPELL_CAST_START message which is sent when the server approves the client's request to start casting the spell (after checking for example if the caster has enough mana). When the spell finishes casting the SPELL_CAST_SUCCESS message is sent and from here on out it behaves like the other attacks above do. Example:

6/15 12:20:15.508  SPELL_CAST_START (Frostbolt)
6/15 12:20:18.496  SPELL_CAST_SUCCESS (Frostbolt)
6/15 12:20:18.496  SPELL_CAST_START (Frostbolt)
6/15 12:20:18.921  SPELL_AURA_APPLIED (Frostbolt slow debuff applied to target)
6/15 12:20:18.921  SPELL_DAMAGE (Frostbolt damaged target)
6/15 12:20:21.515  SPELL_CAST_SUCCESS (Frostbolt)
6/15 12:20:21.643  SPELL_AURA_REFRESH (Frostbolt slow debuff refreshed on target)
6/15 12:20:21.643  SPELL_DAMAGE (Frostbolt damaged target)

In this log sample we can see Frostbolt starting to be cast (SPELL_CAST_START) and the cast finishing ~3 seconds later (SPELL_CAST_SUCCESS). One interesting thing to note is that Frostbolt is being chain cast here, and because of the spell queue mechanism present in the modern client the caster does not lose any casting time due to lag; you can see the second cast of Frostbolt starting immediately when the first cast finishes at 12:20:18.496. The actual damage and slow debuff from the first cast are applied at the edge of the batch window which occurs at 12:20:18.921 (after the second cast starts) as we can see by the SPELL_AURA_APPLIED and SPELL_DAMAGE messages. The damage and slow debuff from the second cast are applied during the batch processing which occurs at 12:20:21.643.

Healing

With regards to spell batching, healing is treated much like damaging spells with a cast time. Note that healing yourself happens instantly, but the effects of healing others are delayed until the next batch processing window occurs. Example:

6/6 15:27:23.246  SPELL_CAST_START (Healing Wave)
6/6 15:27:25.746  SPELL_HEAL (Healing Wave, Roska)
6/6 15:27:25.746  SPELL_CAST_SUCCESS (Healing Wave, Roska)
6/6 15:27:25.746  SPELL_CAST_START (Healing Wave)
6/6 15:27:28.246  SPELL_CAST_SUCCESS (Healing Wave, Vannock)
6/6 15:27:28.246  SPELL_CAST_START (Healing Wave)
6/6 15:27:28.413  SPELL_HEAL (Healing Wave, Vannock)
6/6 15:27:30.746  SPELL_CAST_SUCCESS (Healing Wave, Colty)
6/6 15:27:30.846  SPELL_HEAL (Healing Wave, Colty)

Here we can see Roska starting to cast a Healing Wave on himself at 15:27:23.246 with the SPELL_CAST_START message, which completes 2.5 seconds later and immediately heals him at 15:27:25.746; we can see the SPELL_HEAL and SPELL_CAST_SUCCESS happening at the same timestamp. He then starts casting another Healing Wave right away on Vannock, which doesn't suffer any delay due to lag thanks to the spell queue system. The heal on Vannock finishes its cast at 15:27:28.246 and Roska being casting another heal on Colty, but the effects of the heal on Vannock are not applied until the next batch window at 15:27:28.413 noted by the SPELL_HEAL message. The same thing happens with the heal cast on Colty which finishes at 15:27:30.746 but is only applied at 15:27:30.846.

Buffing

When you buff yourself the buff is applied instantly, however when you buff other people the buff will only be applied on them in the next batch window. Example:

6/6 15:25:35.353  SWING_DAMAGE (Skit-ClassicBetaPvP, Scarlet Guardsman)
6/6 15:25:35.403  SPELL_AURA_APPLIED (Vannock-ClassicBetaPvP, Battle Shout)
6/6 15:25:35.403  SPELL_CAST_SUCCESS (Vannock-ClassicBetaPvP, Battle Shout)
6/6 15:25:35.515  PARTY_KILL (Skit-ClassicBetaPvP, Scarlet Guardsman)
6/6 15:25:35.515  SWING_DAMAGE_LANDED (Skit-ClassicBetaPvP, Scarlet Guardsman)
6/6 15:25:35.515  SPELL_AURA_APPLIED (Colty-ClassicBetaPvP, Battle Shout)
6/6 15:25:35.515  SPELL_AURA_APPLIED (Skit-ClassicBetaPvP, Battle Shout)
6/6 15:25:35.515  SPELL_AURA_APPLIED (Puffymuffins-ClassicBetaPvP, Battle Shout)

This log excerpt begins with Skit auto attacking the Scarlet Guardsman. Shortly after, Vannock decides to cast Battle Shout and as can be seen the buff is applied to him immediately. The next batch processing occurs at 15:25:35.515 where we can see several actions taking place: Skit's auto attack swing lands which causes the Scarlet Guardsman to die from the damage, and the Battle Shout cast by Vannock earlier is finally applied to the other party members.

Illustration

batching_v3

In this awesome infographic made by Beanna (right-click and open in new tab to see in full resolution) we see a Warrior swinging a 2.90 speed weapon and using various abilities. The sequence of events helps illustrate batching interactions as described in the section above:

  • The warrior swings his weapon at time 0 (SWING_DAMAGE) but the actual damage from his auto attack doesn't land until the next batch window (SWING_DAMAGE_LANDED).
  • Later, more than halfway into the batch window, he uses Hamstring (SPELL_CAST_SUCCESS) which doesn't apply its slow and damage components until the next batch window.
  • While the GCD triggered by Hamstring is cooling the Warrior queues an Heroic Strike and shortly after uses his Earthstrike. Due to the trinket usage being a self-cast, which is not affected by spell batching, he gains the AP buff immediately.
  • When the GCD is done cooling he uses Bloodthirst, which applies its damage component at the next batch window.
  • Finally at time 2.9 his swing timer is finished and he attacks again, but this time he has Heroic Strike queued so it gets cast instead of a regular melee swing (SPELL_CAST_SUCCESS). The damage from Heroic Strike is applied at the next batch window.