How long do your attacks *really* take?


Arcanaville

 

Posted

The original thread seems to have been purged, and I've been asked to repost this, so I'm reposting in the Guides section so it doesn't get purged again. This is a copy of the original post: I haven't edited it in any way (so if the original had typos or minor errors, this one might as well - sorry, don't have enough time to proof it better at the moment).

Although I will say that since this article was first published, a number of posters have used these basic calculations to attempt to predict their damage output under a variety of circumstances where its possible to measure actual damage output reasonably accurately. So far as I'm aware, the time calculation model presented here seems to be consistent with all of those tests to within a high degree of accuracy. So I believe its safe to say that the model has been independently confirmed by multiple posters.

I'm also told that this model is increasingly being referred to as "ArcanaTime." Kind of like Bullet Time, but with more math I suppose. Nevertheless, I preserved the original title of the post, since I think its more descriptive. I also decided against calling it "Guide to X" for the same reason.

Also: Power Slice still be slow.


-----[Guide follows below]-----

How long does this attack chain take:

Nimble Slash -> Ablating Strike -> Power Slice -> One Thousand Cuts

Simple question, right? Nope. The answer to this question has *major* repercussions for anyone attempting to quantify how much damage any powerset can do. I've been looking at aspects of this one question in a sense for over a year now, and I've been focused on a specific aspect of it that no one has ever really investigated in any detail until now (I doubt even the original or current dev team has thought about it much). Its a bit complicated, so I'm going to start at the beginning, and hopefully get to the end before too long.

The cast times for those powers are:

Nimble Slash: 1.03s
Ablating Strike: 1.03s
Power Slice: 1.03s
One Thousand Cuts: 3.3s

So naturally that chain should take 1.03 + 1.03 + 1.03 + 3.3 = 6.39 seconds, right?

Actually, if you time it, you'll probably get something closer to 7.39 seconds. But that's just lag, isn't is?

If you mean network lag, its not. But first, how do you measure the duration of that attack chain as precisely as possible? The methodology I've used for years now is to use demorecords. When you demorecord a sequence of events, the demorecord file has (in a differential form) timing information that says when each event happens, and it has millisecond precision. Its actually possible to record a sequence and know it took exactly 7392 milliseconds, if you know how to read the demorecord files.

But are demorecord files accurate? Suppose they only record when the *client* sees something happen? If that were the case, then all that millisecond precision would be somewhat worthless, because network lag would cause different events to be delayed by different amounts, and make the measurements unreliable.

As it turns out, demorecord timings appear to encapsulate when the *server* thinks something should happen. If you record the same events from two different computers, logged in to two different characters, the demorecord timings tend to be identical (they are sometimes off by one millisecond for some events, which might be round-off error). This is true even if the two computers are connected to two different networks, with two different paths to the game servers, and with two different amounts of network lag. So the demorecord timing information appears to be reliable *and* a window into what the *server* sees and does. If the demorecord says a sequence of events takes 7392 milliseconds, that is exactly how long it takes according to the game.

Even so, network lag can still cause problems. When I push a button, it takes some time for that event to get sent to the servers. There is a difference between when I do something, and when the servers *know* I did something. That could still cause a delay between when an attack *should* go off, and when it actually *does* go off.

That delay can be eliminated with attack queueing. If you queue an attack (tell the server to fire it, while you are still executing a different attack) that message gets sent to the server *immediately*. Even if it takes 300 milliseconds to get to the servers from your computer, as long as you send it 300ms before the attack *could* fire, that command will be waiting on the servers for the moment when the attack can actually be fired. Queueing attacks (if you do it fast enough) eliminates network lag. The server basically has a queue of attacks, and fires them off as fast as possible. So if you queue that attack chain above, the amount of time it takes should be the *fastest* that the game servers can possible execute them, which is another way of saying that's how long that attack chain theoretically takes.

Is an attack chain the sum of its cast times? For years now I've measured attack chains using the demorecord method and queued attacks. I do it so that I can measure what I call the "attack time" of an attack: the amount of time it takes up in an attack chain. I've always assumed in the past that this was a way to measure the cast time of the power, plus or minus a certain margin of error. It turns out that this method never seems to get any closer than about 180ms (0.18s) from the "published" cast times. Why is that?

As it turns out, there are *two* things that have to happen before you can fire off an attack. One: the cast time for the previous attack must have expired. Basically, when you cast an attack, you have to wait the cast time before you can use another attack. Two: the Rooted time of the animation of the attack must also be completed.

When an attack is executed, it causes you to perform an animation - a sequence of moves that visually represent the motions of the attack. Most attack animations are flagged with a special flag called CANTMOVE. This basically means that while that animation is playing, the player cannot perform any character movement, and cannot activate any other powers. It basically locks you out of doing anything until the animation of the attack finishes.

This is important. If a power has a cast time of one second, but it plays a rooted animation that lasts for two seconds, then for two seconds you can't attack again. You basically have to obey whichever one is [u]higher[u].

BackAlleyBrawler has been working to clean up a lot of discrepancies between cast times and rooted times, because if they are different, the cast time will be misleading to players (especially now that the Real Numbers system displays cast time). There's no trivially easy way to display "Rooted Time" so the players will have no idea their attack is actually slower than it is documented to be.

Some attacks still have discrepancies, though (the vast majority of the one's I've identified have been fixed by BaB). One of the powers that *hasn't* been fixed yet is actually Power Slice. Back in beta I measured PS to be about 1.4 seconds in duration, plus or minus. However, its documented cast time was actually 1.03 seconds. That's *far* outside my margin of error: there is no way for my method to be off by 0.4 seconds, ever.

However, I'm not measuring cast time: I'm actually always measuring the *higher* of cast time or rooted time. Clearly, the rooted time of the power must be higher than the cast time, and that was what caused by I11beta measurements to be "off." In fact, Power Slice's animation roots the player for exactly 41 frames of animation, or about 1.37 seconds, and that's what my I11beta measurement was actually measuring: the *true* time that attack "takes."

However, the rooted times for all the other attacks are equal or less than the cast time, so only Power Slice actually takes longer to animate (and root the player) than its cast time takes to expire. The attack chain should then execute in:

1.03s + 1.03s + 1.37s + 3.3s = 6.73 seconds. That's still quite far from 7.39 seconds, and still way outside of my margin of error.

Time to back up a bit. I didn't *actually* measure PS to be 1.4s. I actually made an educated guess that it was 1.4s, based on my actual measurements. I actually measured PS to be closer to about 1.6 seconds long. But I applied a correction factor. I also measured the "attack time" of brawl during my measurements. Its my reference measurement: Brawl (back then) had a 0.67 cast time, and I could use that to calilbrate my measurements for other systematic errors. Based on my measurements of Brawl, my I11beta measurements appeared to have about 175ms of "extra time" in them. I therefore corrected all my measurements downward by about 175ms to calibrate them to Brawl. My 1.6s PS became about 1.4s as a result.

Where was this 175ms "error" coming from? That has been a long standing question of mine, going back over three years in fact (ever since I invented the measurement technique). I finally decided to determine once and for all what this error was, and whether it was something that was special to me and my setup, or something more fundamental.

My typical lag during measurements is about 220ms according to /netgraph. There's no way it could be responsible for a 175ms delay between attacks. Moreover, if I'm queueing the attacks, network lag shouldn't factor in at all (tests confirm that if you queue an attack, that message is sent immediately, and no further signal from the client is required to execute the attack: it'll go off even if you disconnect). So why was I measuring attacks to take 175ms longer than they should have been taking?


I had a suspicion that what I was seeing had something to do with the game server processing loops. It doesn't matter if something is "supposed" to happen exactly 1030ms later: the server can't literally execute an attack when its supposed to, because it can only fire attacks off at some maximum speed. Most game systems (and real time and pseudo-real time systems like game servers) use a processing loop that is executed so many times per second, each time checking to see if something is supposed to "happen." In a complex system, there might be many different execution loops going on. The time interval from the start of one loop to the start of the next loop is often referred to as the processing quantum or the tick interval. I was guessing that even if I had a queued attack, it could only fire when the next tick interval came up.

But 175ms seemed to be quite a long time for the tick interval to be, and its an odd number. If I'm seeing 175ms, its more likely the clock quantum was something like 250ms (one quarter of a second), and that seemed *way* too long.

As it turns out, based on conversations with the devs, two things are causing my rather longish measurement for the clock quantum. First, my guess that powers could only fire aligned to a server "combat clock" were correct. However, what I *didn't* anticipate was another feature of the combat engine. The game doesn't "check" to see if all the conditions needed to fire an attack existed on the fly: that would take too long when making attack decisions. Instead, every combat clock, the game checks to see if the character is in the "Ready to Shoot" state (that's just what I call it). If it is, it executes the queued attack. If its not, it doesn't. *After* that, the game engine checks all characters to see if they meet all the conditions necessary to be allowed to fire an attack: if so, its *then* flagged "Ready to Shoot."

See the problem? When an attack is running, the character is not in the correct state to fire another attack. It has to wait. When the attack finishes, and the (rooted) animation is over, and the cast time is over, its *still* not ready to shoot. It has to be *flagged* to be ready. But by then its too late to fire during that clock tick. It has to wait for the *next* clock tick to actually fire.


This is the anatomy of an attack sequence:

Ready --> Activate --> Animate/CastTime --> Completed --> Flagged Completed --> Activate Next Attack

From the moment the power is Activated, an *integer number* of clock ticks must happen before it can be flagged completed, and then *one more* has to happen before the next power can activate. So its not just what the power's cast time is, or even its rooted time, that determines the powers' "attack time." Its *real attack time* is actually always going to be:

[RoundUp(CastTime / ClockInterval) + 1] * ClockInterval

In other words, it will take a whole number of clock ticks, rounded upward, plus one.

So what's the clock interval. The answer is: I'm not 100% certain. I *believe* its about 132ms. Where does that number come from? Two sources: its a reasonable fit for all of my measurements, and it agrees with what I've been told about the game engine, which is this (and this is only necessarily true for attack processing: other things might run on different clocks): the game is designed to *simultaneously* process one combat loop every 125ms, but *also* not to do anything until the next *animation* clock (and once again, that's what I'm calling it, not what its actually called, since I don't know what its called).

There's a 30 tick per second clock that is used to sync up certain game events, and its probably specifically intended to sync the server with the game client. So after the combat clock ticks 125ms, the 30clock has only ticked 3.8 times: it has to wait until 30clock tick #4, which happens at about 132ms-133ms (33 * 4 = 132, 33.33 * 4 = 133.32). So the game engine only checks on the status of attacks about every 132ms.

That means a power that has a cast time of 1.03 seconds - 1030ms - takes 1030/132 = 7.8 combat clock ticks to execute. The game won't *know* that attack is "done" until tick #8 (8*132 = 1056ms = 1.056s). It won't be able to execute the next attack in the queue until tick #9 (9*132 = 1188ms = 1.188s). So a power with a cast time of 1.03 seconds (and a rooted time of about the same value) will actually "burn up" 1.188seconds of time, not 1.03 seconds of time, in any attack chain. That's the *minimum* amoutn of time that attack will burn up: nothing you do can make it go faster. Even if you patched your computer directly to the game servers to eliminate all possible lag, and kicked everyone else off that server so its full processing power was focused only on you, Nimble Slash is *never* running any faster.

So long as you queue your attacks and the server isn't overloaded, its never running *slower* than that either. Network lag is totally irrelevant as long as you queue attacks. So this time - 1.188 seconds - is actually the best estimate for the attack's "true" duration.

Nimble Slash and Ablating Strike actually both take 1188ms according to this theory. Power Slice takes 1584ms. OTC takes 3432ms. Add them up, and you get 7392ms, or about 7.4 seconds. And that turns out to be very close to the actual measured time for that chain (in fact, I tend to measure that chain to be about 7420ms on average, plus or minus 100ms).

So far, I've tested the theory against Dual Blades, Martial Arts, and Energy Blast, plus some other assorted attacks. The theory matches measurement usually to within 30ms, and often to within 20ms (less than one visual frame of animation). That's pretty good: I'm currently examining the question of whether there is another source of systematic error that can account for even *that* discrepancy, or if its simply an artifact of averaging dozens instead of thousands of attack chains to average out the jitter intrinsic to all of these measurements (when the server decides to do something every 132ms, that doesn't mean *everything* will be done instantly: it could happen anywhere within that 132ms window, which causes "jitter" in the measurements that can be partially averaged out).


What does this mean? Well, it means everything actually takes longer than we think it does, by an average of about 198ms, plus or minus (for complex reasons, its actually slightly lower than that). And that value isn't constant: it depends on the actual cast time (and rooted) time of the individual power: the value can be anywhere from about 132 to 232ms (that's nearly a quarter of a second). And most importantly, this will affect different sets differently. I say "affect" but of course, all powers and powersets have been living under these conditions since the very beginning of time. What I mean are the on-paper calculations of how much damage a powerset does. Faster attack chains will be hurt more than slower ones. Low cast time powers will be hit proportionately harder than high cast time powers.


If you are a DPS fanatic, it also means a few other things. It means whenever you are not queueing attacks, you are taking a substantial penalty in damage over time. Just the act of switching targets when one dies and re-activating the attack (instead of switching targets *before* it dies and queueing the next attack, assuming it dies) costs more in damage over time than the difference between the best and worst single target attack sets in any archetype. And it means ironically very short cast time attacks (i.e. 0.83 seconds) aren't necessarily as good as they appear, because its surprisingly difficult to keep such attacks queued ahead of time. They are not bad, but difficult to *make work* as fast as they could be.


If BaB makes a change to an animation, sometimes that change will have no impact on DPS at all, because it won't affect the actual DPA of the attack in true terms. Sometimes it will have a higher impact than you might expect. It really depends.


And finally, it means one should always be careful about trusting paper calculations. They are only as good as the input numbers to them. I myself am a strong proponent of good analysis, and even good analysis can be incomplete due the availability of the facts. But I also believe all numbers and all anaysis should be questioned. We're given cast times now, and lots of other numerical information about our powers. That information is presumed to be "authoritative" and so there is a greater acceptance of calculations based on those numbers. But the way the game processes those numbers can sometimes be more complex than it first seems. There's no substitute for testing things carefully.

That doesn't mean I believe anecdotes are stronger than analysis: anecdotes can be poisoned by all sorts of observer problems to a higher degree than paper calculations can be. But I am saying that in spite of the access to raw data we have now, and maybe even because of it, rigorous testing is more important now than its ever been. Especially since much more faith is placed on numerical calculations now than it ever has been in the past.


Basically, fast is never as fast as it looks on paper. At least not without this modification to attack time.


[Guide to Defense] [Scrapper Secondaries Comparison] [Archetype Popularity Analysis]

In one little corner of the universe, there's nothing more irritating than a misfile...
(Please support the best webcomic about a cosmic universal realignment by impaired angelic interference resulting in identity crisis angst. Or I release the pigmy water thieves.)

 

Posted

Fascinating read, Arcanaville.

Good Work! (as always)


Regards,
4


I've been rich, and I've been poor. Rich is definitely better.
Light is faster than sound - that's why some people look smart until they speak.
For every seller who leaves the market dirty stinkin' rich,
there's a buyer who leaves the market dirty stinkin' IOed. - Obitus.

 

Posted

Well, well. This rather neatly defenestrates all my attack chain calculations.

Thanks for the info, Arcanaville.


 

Posted

That anatomy of an attack sequence makes perfect sense from the age-old Nettrek originated quote (I think?): "Don't trust the client; it is in the hands of the enemy!"

Back when I was writing combat systems for MUSHes, I'd implemented something similar, though not quite that convoluted.

I have to wonder just a little bit, if MMOs might do well with a model that doesn't hide the numbers part of the game engine. A MMO engine can't be more complex than something like the Linux or BSD kernels. Leave the producing companies to design the numbers on powersets and the art and stories that make up the game.


 

Posted

[ QUOTE ]
Well, well. This rather neatly defenestrates all my attack chain calculations.

[/ QUOTE ]

On the flip side, its made Werner the God of Attack Chains.


[Guide to Defense] [Scrapper Secondaries Comparison] [Archetype Popularity Analysis]

In one little corner of the universe, there's nothing more irritating than a misfile...
(Please support the best webcomic about a cosmic universal realignment by impaired angelic interference resulting in identity crisis angst. Or I release the pigmy water thieves.)