-
Notifications
You must be signed in to change notification settings - Fork 9
Spell batching
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.
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).
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.
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 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.
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
.
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
.
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.
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.