sigsegvMost people don't really know how this sort of stuff works. And worse, many people speak authoritatively about it when they actually have no idea what they're talking about. So here's a little case study on client-side interpolation and the weird effects it can have on gameplay. I hope you learned something new today.
My recommendations on how to configure your interp for Team Fortress 2 (or basically any Source game): ==================================================================================================== 1. Set cl_interp to 0 (so that the game will look at cl_interp_ratio instead). 2. Set cl_interp_ratio to 2, unless you have a very good reason to use a different value. (Bump it up to 3 if your net connection is bad enough that you're still having problems at 2. Drop it down to 1 _only_ if you actually know what you're doing and why you're doing it.)
An interp ratio of 2 enables the game to compensate for 1 consecutive dropped packet. A ratio of 3 enables the game to compensate for 2 consecutive dropped packets, and a ratio of 4 allows for up to 3 consecutive dropped packets, and so forth.
Lowering the ratio to 1 (the effective minimum) can be desirable, particularly when playing non-hitscan classes, because it reduces the artificial interpolation lag you experience from 30 ms down to 15 ms. But it comes at a big cost, because you remove the ability for the game to cope with even small amounts of jitter or packet loss without resorting to extrapolation. (It is possible to set up your game configuration to use different interp ratios when you play different classes. But that's beyond the scope of this wall-of-text; Google is your friend.)
Extrapolation is what your game client does when it doesn't know how everything is supposed to be moving because it missed information from the server _and_ also doesn't have enough interpolation history to figure out "average" values that would serve as reasonable stand-ins for the missing data. So instead, the game does the least horrendous thing it can: it assumes that all objects will just continue moving in a perfectly straight line in the same direction that they're currently going. Needless to say, this very rarely matches reality, and it also leads to sudden jerks when the next server update _does_ arrive and objects jump to the location where they were _actually_ supposed to be.
When extrapolation isn't an option, the game client more-or-less throws its hands up in the air and just freezes everything in place while it waits for data to start arriving again from the server telling it what to do. Once a proper server update does arrive, then everything un-freezes, and the positions/velocities/states of all the entities in the game suddenly jump to their actual correct values for the current time. This sudden-stop-and-freeze-up, then wait, then suddenly-jump-and-resume-everything phenomenon is very jarring, which is why interpolation is so important.
Client-side interpolation (interp) in TF2 and related gamessigsegv2017-04-18 | Most people don't really know how this sort of stuff works. And worse, many people speak authoritatively about it when they actually have no idea what they're talking about. So here's a little case study on client-side interpolation and the weird effects it can have on gameplay. I hope you learned something new today.
My recommendations on how to configure your interp for Team Fortress 2 (or basically any Source game): ==================================================================================================== 1. Set cl_interp to 0 (so that the game will look at cl_interp_ratio instead). 2. Set cl_interp_ratio to 2, unless you have a very good reason to use a different value. (Bump it up to 3 if your net connection is bad enough that you're still having problems at 2. Drop it down to 1 _only_ if you actually know what you're doing and why you're doing it.)
An interp ratio of 2 enables the game to compensate for 1 consecutive dropped packet. A ratio of 3 enables the game to compensate for 2 consecutive dropped packets, and a ratio of 4 allows for up to 3 consecutive dropped packets, and so forth.
Lowering the ratio to 1 (the effective minimum) can be desirable, particularly when playing non-hitscan classes, because it reduces the artificial interpolation lag you experience from 30 ms down to 15 ms. But it comes at a big cost, because you remove the ability for the game to cope with even small amounts of jitter or packet loss without resorting to extrapolation. (It is possible to set up your game configuration to use different interp ratios when you play different classes. But that's beyond the scope of this wall-of-text; Google is your friend.)
Extrapolation is what your game client does when it doesn't know how everything is supposed to be moving because it missed information from the server _and_ also doesn't have enough interpolation history to figure out "average" values that would serve as reasonable stand-ins for the missing data. So instead, the game does the least horrendous thing it can: it assumes that all objects will just continue moving in a perfectly straight line in the same direction that they're currently going. Needless to say, this very rarely matches reality, and it also leads to sudden jerks when the next server update _does_ arrive and objects jump to the location where they were _actually_ supposed to be.
When extrapolation isn't an option, the game client more-or-less throws its hands up in the air and just freezes everything in place while it waits for data to start arriving again from the server telling it what to do. Once a proper server update does arrive, then everything un-freezes, and the positions/velocities/states of all the entities in the game suddenly jump to their actual correct values for the current time. This sudden-stop-and-freeze-up, then wait, then suddenly-jump-and-resume-everything phenomenon is very jarring, which is why interpolation is so important.
This clip shows what I believe to be basically the final iteration of the fully-custom AI behavior mod, now featuring custom enemy target identification, target selection, pathfinding, intentionally forcing the bots' vision system to ignore any entities that are not stickybombs, and finally, actually shooting the damn things.
Unfortunately, the target selection code was a bit dumb and just chose known stickies randomly, so the bot kinda goes crazy aiming in different random directions, rather than going sticky-by-sticky in a more effective manner. (Could have been implemented, as a distance-to-sticky and difference-of-viewangles optimization heuristic.)
Also there was apparently some kind of weird issue where occasionally the bot would choose a particular sticky, and would become unable to see it for whatever reason; and then it would just stay fixated on that one stickybomb it couldn't shoot in stupid fashion. (I believe this was mitigated somewhat in the code later by adding a 5-second automatic-retarget mechanism, but that's a bit of a kludge.)
This clip is from a couple days after the first clip, and I believe that at this point I had started work on the actual fully-custom AI behavior mod itself. It may look pretty boring, but this video demonstrates that I could get bots to choose targets (enemy stickybombs) and path toward them reliably.
I believe this clip shows an early attempt that mostly just used the existing TFBot AlwaysAttack pop attribute and SeekAndDestroy action to make the bots hold down +mouse1 and chase down enemies, respectively. Then on top of that, I believe I wrote a little bit of custom code that altered the bots' enemy determination code to make them consider stickybombs to be enemies rather than players. (Something like that... it's been a long time, and this wasn't all documented super-well.)
The code for final(ish) version of this mod: github.com/sigsegv-mvm/sigsegv-mvm/blob/dfe7f0d35edef3a8e040f266415751cd5d7b1355/src/mod/pop/extattr/targetstickies.cppClueless cheater randomly joins MvM test server, gets owned by bots, ragequits.sigsegv2018-04-10 | [Read the video description for commentary.] This guy randomly joined an empty server for a MvM map test event I was hosting; I discovered this gem while going through the SourceTV demo files. Basically, he has no idea what gamemode he's in, or how to operate his cheats, or what he's doing in general; and he ends up getting killed by bots twice and then ragequits. (And is subsequently VAC banned mere hours later.)
[For anyone curious about the MvM map you see in this video, it's called Quetzal, and it's made by my friend Dayal; you can find more information about it here: tf2maps.net/threads/quetzal.35707]
Presumably he'd just set up this account for cheating, and picked a server at random from the server browser to cheat on. Of all places, he happened to end up on this empty MvM map-testing server of mine, where there are no enemy players to abuse, only bots.
He doesn't appear to grasp the concept of MvM upgrade stations, making it clear that he doesn't comprehend the gamemode he's playing.
He seems unable to figure out how to disable his cheat's chat-advertisement-spam feature: he says "STOP" in chat at 0:59 (as if that will do anything), and then spends until around 2:09 apparently fiddling around with the cheat settings until he finally finds whatever checkbox or button disables that crap.
After that, it takes him until about 2:29 to notice the "press F4 to ready up" text on his screen (again, presumably he thinks he's in a normal TF2 PvP server). In the meantime, he fires some shots at the bomb path marker holograms, apparently unsure whether they are enemy players.
Once the bots start spawning around 2:45, he enables "aimbot like an idiot" mode, getting some sweet headshots on bots who still have spawn zone invulnerability. But then he's unexpectedly ambushed by a notoriously daunting bot, the GRU heavy.
After his cheats successfully dispatch this extremely dangerous foe without any actual skill on his own part, our cheater proceeds to get rushed by a small group of shotgun heavy bots and dies at 3:12. His incompetence runs so deep that he doesn't think to use his cheats to aimbot-headshot the bots, choosing instead to use his cheat-aim on his SMG.
[NOTE: At 3:22, I tried to go into third-person view; but the guy's player model wouldn't draw due to a glitch with the demo playback. So ignore that little graphical goof.]
Obviously annoyed at dying to bots, he stops at 3:26 to keyboard-mash an unintelligible message of frustration into chat.
Engaging the bots once more at 3:38, he again switches to his tried-and-true SMG aimbot tactic, followed by swinging his melee uselessly at the air, and is killed a second time by shotgun heavies. He immediately ragequits.
Now, for the fun part. This fellow's Steam profile was set up on April 4 2018. He played on my server on April 6 2018. I checked his Steam ID on April 9, and found "1 VAC ban on record; 3 day(s) since last ban". So this means he was banned by Valve within literally hours of incompetently attempting to use cheats on my MvM server. (And if you're wondering, yes, I checked: his disconnection from my server was a bona fide ragequit, not a VAC ban kick.)
Kids, don't use cheats. You don't want to turn out like this.Improved TFBot kart locomotionsigsegv2017-10-08 | Normally, if you put a TFBot into a kart, it won't move very effectively, because they try to strafe, but the strafing keys (A/D) are actually rotation keys when in a kart. I wrote a quick mod to make them use WASD more intelligently while in karts. (Why? I don't know.)
Normally, bots use W/S and A/D independently to move or strafe in whichever direction they're trying to go. The mod makes them (a) only go forward, and never go backward; (b) not attempt to strafe; (c) only press W if they are facing roughly the direction they want to go; and (d) press A or D appropriately if they aren't facing roughly the direction they want to go, depending on which way the angular error is.
(The sound in this video may be slightly out-of-sync; I'm not really sure what that was caused by.)
The Sandman ball projectile sticks around for a short while after hitting the ground (and also after successfully hitting a player), and it can be picked up by any Sandman-using scout of either team whose ball is recharging.
What's interesting about the particular case shown in this video is that the very same ball responsible for stunning you can also refill your ammo at the same time, due to the fact that both the stun effect and the ammo pickup are accomplished by touching the ball projectile.
Ideally, the game probably shouldn't allow the ball projectile to be picked up until after it's hit the ground. (Not that this is a huge deal by any means.)
It's not... terribly useful... but it is kinda interesting and peculiar.
Credit to Deathrowboat for pointing out this quirk to me.Fun with breakmodelssigsegv2017-05-08 | There's a rare bug that can sometimes cause a deflected rocket to spew forth multiple dud rocket breakmodels instead of just one. Today I thought it'd be a fun exercise to intentionally write a mod to make this sort of thing happen. As hoped, much fun was had.
I could probably improve this quite a bit with a companion client-side mod: this would allow me to alter the speed and trajectory of the rocket duds (to make them spew farther/wider), as well as mess with the breakmodel fade time, and more. But really, I should probably be working on other things...What goes up, must come down [flares]sigsegv2017-02-18 | Reaches a maximum height of about 8400 HU before it reaches its apex and falls back down. Other flare variants (detonator, scorch shot) are essentially identical to this demonstration.What goes up, must come down [huntsman arrows]sigsegv2017-02-18 | Only feasible up to about ~60% charge, given 16384 HU of vertical space to work with (the height of the skybox on this map relative to the ground). Kinda funny that the arrow model falls down backwards (contrary to how the drag would work out in real life).Falling 16384 Hammer Units in TF2sigsegv2017-02-18 | If you've ever wondered what it's like to freefall vertically from a height of ~16384 HU above the ground in TF2... well, now you know. (Probably not the most unique video ever.) Note that velocity caps out at 3500 HU/s.Pose parameter hitbox bug example: engineer robotsigsegv2017-02-14 | One of the more egregious cases. I found this one amusing, as different incorrect things happen depending on the particular direction the player is moving.
Both of the engie bot model's arms flail around in a stupid manner even in the absence of game glitches; the model is just simply that bad. (It's even worse of an inconsistent, rushed mess than the other MvM player models, if you can believe that.)
Also, despite the human engie player model having its missing pelvis hitbox fixed, the robot engie still lacks it.Pose parameter hitbox bug example: giant scout robotsigsegv2017-02-14 | One of the more typical/tame examples, at first glance: the hitboxes simply don't budge when the scout is on the move. But notice how much the scout's head visibly rises when he's running, compared to how low its hitbox stays in reality due to the bug.TF2 class change pose parameter bug [dedicated server]sigsegv2017-02-14 | Before recording, I initially spawned as soldier. When I then switch to scout, heavy, or sniper, the pose parameters are not updated properly. (The animations are also simply out-of-sync; they _were_ properly in sync at first, but after spectating and un-spec'ing, they de-sync'd.)Shortstop shove third-person animations (20% speed)sigsegv2017-02-07 | The animations themselves aren't new, but what is new is that they actually work now in third person (7 months after the shove mechanic itself was introduced). Presented in "stunning" 720p60, because I was too lazy to fire up my 1080p-hacked version of the model viewer.tf_nav_show_bomb_target_distance 1sigsegv2017-02-05 | Used for determining where MvM engineer bots should/shouldn't teleport in, depending on where the bomb is relative to the bomb hatch. The values are precomputed in the nav mesh based on path distance from the nav area to the bomb hatch.
An extensive writeup I did regarding the logic that MvM engineer bots use to decide where to teleport in: gist.github.com/sigsegv-mvm/a1f103ae79bbb0a5c5ff7dcd4a378958That pyro healing debuff thing added in MYM is very screwed upsigsegv2017-01-19 | Remember that "flamethrowers reduce medigun healing by 25%" thing added in Meet Your Match? No? Well, pretend you do, as I take you on a tour of the various arbitrary, decidedly-non-75% heal rates that it produces depending on the particular situation you're in.
And just think, I haven't even tested the Vaccinator resists yet to see if those work correctly with this stupid thing...Why its occasionally possible to outright kill Sentry Busterssigsegv2017-01-05 | You aren't supposed to be able to kill sentry busters; if you damage a buster enough to kill it, the game forces it to stay at 1 HP and starts its detonation sequence instead. But due to a bug, it IS possible to kill busters in rare cases; continue reading for more on the specifics.
The short version is this: if a sentry buster has X HP, and you do anywhere between approximately (X-0.001) and (X-0.500) damage to it (e.g. if it has 100 HP, that would mean anywhere between ~99.500 and ~99.999 damage), then the buster will lose 100 HP, be left with 0 HP, and therefore die; and the game will not intervene to keep it alive at 1 HP as it should.
The root of the problem involves the fact that entities in the Source engine (such as player entities, which includes sentry busters) store their current health value as an integer; whereas damage values in the Source engine are represented as floating-point numbers. (For non-programmers: essentially, floating-point numbers are simply numbers that aren't limited to just storing integer values; they can have fractional parts: stuff to the right of the decimal point, so to speak. But they have other tradeoffs, like precision limitations.)
When the game checks whether the damage would hypothetically be enough to kill the buster, what it actually does is it subtracts the damage amount from the bot's current health and checks whether the result is less than or equal to zero; naturally, if a player's health drops to 0 or less, then they have been killed. (Side note: the bot's HP value is implicitly converted from int to float for this comparison, but that's of no particular relevance and doesn't affect anything.)
The important thing to take away from the paragraph above is that the game is checking whether the health would drop below 0.000000 to determine whether the bot would die. But since HP values are stored as integers, when the damage is finally actually applied (by subtracting it from the bot's health), some sort of rounding MUST occur; and for fractional amounts of damage that are inflicted on players, Team Fortress 2 rounds to the nearest integer (e.g. if you do 149.7 damage to an enemy player, they will lose 150 HP).
Most damage amounts in TF2 are actually not whole numbers, even if your HUD damage text leads you to believe that they are. Factors like distance falloff and percentage-based damage multipliers/resistances will constantly result in damage amounts not being integral. And that's not inherently problematic.
But what IS problematic, is that in many cases (not just with sentry busters), the game does hypothetical comparisons like the one described earlier, which fail to properly account for the fact that you can't just subtract a damage value from an HP value and assume that a naked floating point comparison will result in an accurate prediction of the post-damage HP value.
^ That code is from the March 2008 leak; however, I've confirmed that the exact same methodology is still being used in the most recent TF2 version: http://i.cubeupload.com/reNlP9.pngBugginess involving abandoned MvM engiebot buildingssigsegv2016-12-02 | For reasons that make no sense whatsoever, if you destroy an unowned engiebot building (one whose builder has died), then the game causes all other buildings of the same type that are also unowned to be destroyed simultaneously.
This occurs even if zero bots are alive at the time you destroy the building (as is the case in this video demonstration). The fact that I happen to be an engineer in the video isn't relevant to the demonstration; destroying the building by *any means* will trigger the cascade.
This apparently deliberate but impossibly-intentional behavior has been around since the day MvM engineer bots were introduced with the Mecha Update, released on December 20, 2012.
(I can only assume that with Mike Booth gone from the company by the time this stuff was in development, no one completely knew what they were doing with TFBot development any longer?)MvM bug: Accumulation of engiebot TeleportWhere entriessigsegv2016-12-01 | Player slots are re-used for "different" bots in waves of Mann vs Machine mode. Everything *should* be reset, so weirdness occurs if things persist across deaths. This is one example of something that should not persist across what are ostensibly different bots, but which does.
Engineer bot spawners have a "TeleportWhere" keyvalue that tells the game which bot spawn point(s) should be linked up to the engineer's teleporter exit when it goes active. If the engineer bot's spawner has no TeleportWhere keyvalue, then the engie will not build a teleporter at all.
Due to a coding oversight, each player slot's list of "TeleportWhere" entries is only added to with each bot spawn; the previous entries from past bot lives on the same player slot are not cleared out.
As a result, if engiebots *with* TeleportWhere entries spawn, and then die, and then later on, engiebots *without* TeleportWhere entries (not intended to build teleporter exits) spawn and happen to reuse the same player slots as were used for the first group of engies, the second group of engies will inherit the TeleportWhere entries from the earlier bots that occupied their same player slots.
The accumulation continues essentially forever over the course of one MvM mission. Since most official Valve MvM missions only feature one type of engiebot (tele-building or non-tele-building), usually the bug doesn't manifest in any noticeable way.
The only official Valve mission I can think of where both tele-building and non-tele-building engiebots are present is the Mecha Engine tour's Disintegration mission: on all of the waves prior to the boss wave, the engiebots are set to build teleporters; but on the boss wave with Major Bomber, the bot spawners are set up so that the engies will only build sentries. But because so many tele-building engies will have already spawned and died over the course of the mission, leaving behind an accumulation of TeleportWhere entries on those player slots, many of the engiebots on the last wave actually do build teleporters.Spy backstab detection mechanics illustratedsigsegv2016-10-18 | Whether or not a particular knife attack is a backstab is determined by the result of three vector dot products. This video should help show visually how all of this stuff operates, even for people who don't know what a "vector" or "dot product" is.
In the first video segment, the yellow vector is the horizontal part of the spy's aim direction ("SpyView"); the magenta vector is the horizontal part of the heavy's aim direction ("VictimView"); and the cyan vector is the horizontal part of the vector pointing from the middle of the spy's hull/bbox to the heavy's ("DeltaPosition").
The threshold between being considered "behind" or "in front of" the victim is when you're standing side-by-side, directly to the right or left of the victim (as if you're standing centered on a line extending out from the middle of the victim, perpendicular to their aim direction).
One curious finding is that as long as you're behind (see definition above) the victim, you can actually be facing slightly to their rear (17.5 degrees past perpendicular) and still score a backstab. This is best demonstrated in the beginning of the third video clip (at 3:20).
Since the vertical component of all the vectors involved is ignored, arguably-stupid things like backstabbing people while on top of them are possible. Because of the "behind" rule, it's only possible on the back half of their hull; and the other requirements become slightly more constraining than when you're on the ground beside the victim.
Yes, I know, it looks like the spy is trying to take a dump on the heavy's head in the fourth video clip. That's just what the duck animations do when you start and stop moving. Deal with it and leave your stupid comments to yourself.
Here's another very good analysis of spy backstab mechanics that's worth reading if you haven't seen it before. It's not 100% accurate about everything (e.g. the spy's aim direction does actually matter, and there's a hard 107.5 degree limit on reverse-direction stabs) but it's still largely correct and has some good diagrams and explanations: http://technofovea.com/blog/archives/278
And here's what the actual code for backstab determination looks like: gist.github.com/sigsegv-mvm/bda5c53af428878af6889635cd787332MvM Bug: RandomSpawn + teleporter = no sound, no ubersigsegv2016-10-15 | The pyros in this video are from a normal wavespawn. The soldiers are from an almost identical wavespawn; the only difference is that the soldiers have "RandomSpawn 1". CWaveSpawnPopulator::Update entirely skips calling OnBotTeleported in the latter case due to a bug.
OnBotTeleported is the function responsible for emitting the "MvM.Robot_Teleporter_Deliver" sound and adding 5 seconds of post-spawn invulnerability to the bots, among a couple of other minor things.
This bug has been in the game since the day the Mecha Update came out (when teleporters were first added to MvM).Sentry buster detonation-while-ubered is still glitchedsigsegv2016-10-07 | The sentry buster "beep boop" idle sound loop and the wave status icon don't get stopped/removed if the buster doesn't properly kill itself. This bug was partially fixed in the July 14 update, but it's still a problem for busters that are invulnerable when they det.
Note that sentry busters do not appear shiny when ubered because their model lacks the skins for it. I have a mod to fix that but wasn't using it for this particular video.Minigun spun-up resistance doesnt work how you think it doessigsegv2016-10-01 | The MYM patch notes said "20% damage resistance now only applies when spun up and below 50% max health." Turns out, the actual situation is more complicated than that, and it leads to some counterintuitive (and arguably outright wrong) results.
(Sorry about the short video + wall-of-text description; ideally I'd find a way to work more of this into the video itself, but that takes a lot of time and effort, and I'd rather put the information out in some form than not at all.)
The main thing you probably didn't realize about the MYM changes to the Natascha and Brass Beast spun-up resistance, is that the 50% health check is NOT based on the heavy's "current" health before the damage is taken. Instead, it's actually based on whether the heavy's health WOULD be below 50%, if he were to hypothetically take full damage from the current attack.
So obviously, if a heavy is below 50% health, he gets the spun-up resistance. But even if a spun-up heavy is ABOVE 50% health (up to any level, including fully-healed or even overhealed), and he takes enough damage from one hit that he would *theoretically* be taken down below 50% health by that damage, then the game applies the "below 50% health" spun-up resistance to the damage.
This appears to be an intentional mechanic, and it could arguably be considered to be a good thing. What's most problematic is that it was never explained clearly in the update notes or the weapon description, both of which are ambiguous (stating "when below 50% max health" without further explanation). Furthermore, it's effectively "biased" against weapons like the sniper rifle that apply damage in single large hits.
Second, there's an outright falsehood in the update notes and weapon attribute description: both use the phrase "below 50% max health", which is just plain wrong. The game actually applies the resistance when the heavy's health is less than OR EQUAL TO 50%. This might seem nitpicky, until you realize that by implication, a heavy with full 300 hp is eligible for the spun-up damage resistance when hit by a "quickscope" headshot (because 300 - 150 = 150, and 150 is exactly equal to, not less than, 50% of heavy's max health). That's just silly, and it wouldn't be the case if the game's functionality actually matched the description.
Finally, I'll briefly explain why the damage in this video is only reduced by 30, rather than by 90 as you might expect (since 90 is 20% of 450). Most resistances in TF2, including the minigun spun-up resistance, only apply to the non-critical portion of the damage being done. Critical hits (including headshots) triple the overall damage amount; but only the original damage amount is affected by resistance or vulnerability multipliers (in *most* cases). So with a fully-charged headshot, the "base" damage is 150, and the additional "crit" damage (due to it being a headshot) is 300, adding up to 450 total. When we reduce the base damage by 20%, the 150 goes down to 120, but the 300 is still 300, so the total damage is therefore 420.Flamethrower + impulse 101 = ughsigsegv2016-09-21 | Command "impulse 101" refills your health and ammo. It also fills your rage meter; on non-phlogistinator FTs, this means you end up with this annoying particle effect on your viewmodel that you can't get rid of by any means other than respawning. Very annoying when testing stuff.
Basically, the flamethrower code doesn't bother to check whether it's actually a rage-utilizing FT (i.e. the phlogistinator) when deciding whether it should display a "fully charged" particle effect on the muzzle of the weapon.Moonwalking giant + knockback rage = flying?sigsegv2016-09-19 | Was curious if a groundstalled (moonwalking / FL_ONGROUND-glitched) giant would go flying the way that already-airborne robots tend to when raged. Verdict: No. He does go flying for a couple very brief moments when popped up (I believe he jumps at 0:31), but for the most part, he just does the standard walk-backwards thing.
Thanks to itsgalf for assistance with testing this.
Incidentally, I'm now not totally sure that moonwalking animations are 100% correlated with the player being FL_ONGROUND-glitched/groundstalled, so I'll be looking into that...[Raw: 2/2] Airblast-vs-Players: Vectors + Cone (essay in description)sigsegv2016-09-19 | This is some raw footage from a visualization mod I coded up and was messing around with the other day. It draws the vectors related to player airblast detection and the impulse imparted, plus the detection cone. (Read the rest of this video description for much more detailed info.)
For airblast versus enemy players to occur, the pyro's aim/crosshair vector (cyan) must point within ~37 degrees of the vector pointing from the pyro's WSC (hull middle) to the victim's WSC (magenta). It's actually slightly more complicated than this due to the fact that the pyro's "aim" vector is treated as if it comes out of his WSC rather than his head (where you'd expect your aim to come from), but effectively it boils down to "you must aim in a direction within 37 degrees of the middle of the enemy's bounding box".
Why 37 degrees in particular? Because that's the arccosine of 0.8, and what the game actually does in mathematical terms is to check whether the dot product of the cyan and magenta vectors is greater than or equal to 0.8.
The mod shown in this video draws a cone 37 degrees wide, which represents the valid set of directions that the magenta vector can point where the airblast-push will be allowed to happen. The depth of the cone drawn does not accurately depict the effective range of player airblast; the actual limits are determined by the box shown in my projectile airblast detection box video: youtu.be/W1g2x4b_Byg
"Impulse" is a physics term that refers to a change in momentum; basically, for objects with constant mass, it's just a change in velocity (speed and/or direction); and mathematically, it's the integral of force with respect to time. As far as the Source engine is concerned, impulse is essentially just an instantaneous change to the velocity vector of the entity in question.
It's important to note that the way airblast modifies the velocity of the players it affects is very unrealistic: instead of adding the impulse vector to the entity's existing momentum vector, resulting in a *relative* change in motion that preserves some aspects of the entity's previous motion, the game instead first *completely zeroes out* the affected player's velocity vector (cancelling all of their velocity, no matter how fast or in what direction), and then applies the airblast push impulse. This zeroing-of-velocity before the push impulse is applied gives the pyro increased "control" over the airblasted player, which can be a good thing for the pyro; however it also tends to result in an infuriating feeling for the airblast victim, whose movement is suddenly interrupted and then adjusted in an unrealistic manner that they don't have *any* control over.
In most normal situations, the pyro will be aiming somewhat horizontally at a player next to them, so the red vector will accordingly be horizontal as well. When combined with the vertical green vector, this will result in a diagonal yellow total force vector, at roughly a 45 degree angle upward.
At 2:45, you can see what happens when you airblast a player directly above you: the red vector now points straight up, since that's the direction from the pyro to the victim, and it has the same magnitude as before. And the green vector still points straight up with the same magnitude it had before (completely unchanged). So when these vectors are added, you get a total force vector that points upward, but which has in the neighborhood of ~1.4 times the magnitude of the regular diagonal airblast.
And at 3:00, you can see what happens when you airblast a player directly below you: the red vector now points straight down with the same magnitude as before. And the green vector still points straight up with the same magnitude it had before. Since these vectors point in opposite directions with approximately equal magnitude, their sum (the yellow vector) is very small, almost to the point that they cancel out. However, you probably noticed in the video that the airblast victim still gets pushed up a bit. There's a reason for this, and it has to do with Valve's fix for the groundstall situation that once affected the game. (See comments for explanation of this.)[Raw: 1/2] Airblast-vs-Players: Vectors (essay in description)sigsegv2016-09-19 | This is some raw footage from a visualization mod I coded up and was messing around with the other day. It draws the vectors related to player airblast detection and the impulse imparted. (Read the rest of this video description for much more detailed info.)
The magenta vector (labeled "delta-WSC") shows the direction from the pyro's World Space Center to the victim player's World Space Center. A player's WSC is simply the middle point of their bounding box (or "hull"). The length of this vector doesn't have any particular meaning; only the direction is relevant.
The cyan vector (labeled "xhair") shows the pyro's aim/crosshair direction. Note that the vector comes out of the pyro's WSC (the middle of his bounding box), instead of coming out of his head (specifically his eye position) as you might expect. The length of this vector doesn't have any particular meaning; only the direction is relevant.
The red vector (labeled "Delta-WSC Impulse") shows the magnitude and direction of the primary component of the force (technically impulse) imparted on the airblasted player. Notably, it *always* points from the pyro's WSC to the victim player's WSC; the actual direction that the pyro is aiming with his crosshair does not determine the direction of the impulse. All that matters is that he's aiming close enough toward the player (within ~37 degrees of the delta-WSC vector) for the detection check to pass; then the actual direction of the impulse is determined entirely by the two players' positions.
The green vector (labeled "Vertical Impulse") shows the magnitude and direction of the secondary component of the force (technically impulse) imparted on the airblasted player. Basically, no matter what direction you airblast a player, the game always adds a fixed amount of directly-upward "oomph", determined by the value of hidden console variable tf_flamethrower_burst_zvelocity (default 350).
The yellow vector (labeled "Vector Sum") shows the sum of the red and green vectors, which is the magnitude and direction of the total/overall force applied by the airblast on the victim; in other words, the yellow arrow shows the final, actual direction that the airblast pushes the player.Valve broke MvM again because they dont do any regression testingsigsegv2016-09-14 | Previously, CTFPlayer::IsAllowedToPickUpFlag only checked attribute "cannot_pick_up_intelligence" (used by items, e.g. sticky jumper). Now, it also requires that the player not be in TF_COND_GHOST_MODE (77), as well as not in TF_COND_STUNNED (15).
Notable sources of stun (i.e., ways in which players may end up in TF_COND_STUNNED): - MvM: robo sapper (even at +0 upgrade ticks) - MvM: rocket specialist upgrade (even on rocket jumper) - MvM: jarate/milk slowdown upgrade - MvM: explosive headshot upgrade - MvM: medigun shield touch (from red-player shields only) - MvM: Mannhattan gate capture "radio wave" effect - MvM: heavy's knockback rage upgrade - Sandman's stun effect (doesn't have to be a full moonshot) - Natascha's slowdown effect (only when within effective movement stun range) - Force-a-Nature's knockback - Loose Cannon's double-donk - Scorch Shot's airblast-on-hit effect - Flamethrower's airblast deflection versus players - Various taunt attacks (e.g. the initial thrusts of the Ubersaw and Huntsman taunts, except against giant MvM bots) - Item attribute "damage blast push" - Item attribute "stun enemies wielding same weapon" - Various Halloween-event-related things (involving bosses, minigames, karts, etc)
(Even that list is not 100% comprehensive; there are yet more things that can cause players to gain condition TF_COND_STUNNED.)
On a somewhat related note, if you've ever noticed that you were able to get a cleaver crit combo on a player that you hadn't hit with the sandman, this is why: any of the effects listed above are capable of applying TF_COND_STUNNED to the enemy player; all the cleaver does is check whether the victim has TF_COND_STUNNED when deciding whether to do critical damage.
Oh, and the best part of all of this? The devs actually didn't even need to change CTFPlayer::IsAllowedToPickUpFlag at all in the first place; they could have put the new condition checks into CTFPasstimeLogic::BCanPlayerPickUpBall instead, where they actually belong, and then those changes would have only affected Passtime, instead of causing game-breaking regressions to capture flags in other game modes.
(By the way, the particular conditions that are checked for, combined with the timing of the update, leads me to believe that this year's Halloween event map may well be a Passtime map. I can't think of any other particularly good reason why there would need to be an ostensibly Passtime-specific check for TF_COND_GHOST_MODE... can anyone else?)Teleporter + Cow Mangler + Sapper = Bugssigsegv2016-08-14 | The Cow Mangler's plasma-disable ability screws with sappers in a lot of ways. In the cases where only one teleporter is sapped, an engineer on the non-sapped end of the tele cannot remove the sapper on the sapped end by hitting his end with the wrench. (Nor can a homewrecker pyro.)
Thanks to Botspan and Jakapoa for helping out as the soldier and spy in this video.The teleporter/sapper situation is a complete clusterfuck.sigsegv2016-08-14 | I did two tweaks here for ease of demonstration: (a) made the wrench able to one-hit-remove sappers; and (b) increased the "disable building after sapper removed" time from 0.5 sec to 5.0 sec. Nothing makes sense and the whole thing is an absolute clusterfuck; there's no other way to put it.
So back in the December 17, 2015 Tough Break update, Valve thought it would be a good idea to make the following change: "After removing a Sapper from a sentry, there is now a 0.5s delay before the sentry is active again."
Famously, the disable duration was actually 5.0 seconds, not 0.5, due to apparently not testing anything. This had to be fixed with an update the next day.
Incidentally, the Tough Break patch notes are misleading: the 0.5 second disabled period after un-sapping actually applies to all buildings, not just sentries.
For the new post-sapper-removal activation delay, the Valve devs reused the same "plasma disabled" mechanism that the Cow Mangler 5000's charged shot applies to buildings it hits (in the CM5k's case, the "plasma disabled" duration is 4 seconds).
Before the Cow Mangler existed, CBaseObject::HasSapper returned true if the building was sapped and false if not. But once the Cow Mangler's plasma disable mechanism was introduced, CBaseObject::HasSapper was changed to return true if the building was either sapped OR plasma-disabled. In some senses this is reasonable: for example, TFBots call HasSapper to know if a sentry is a threat to them, and a plasma-disabled sentry is not a threat in the same way that a sapped sentry is not a threat.
But there are certainly respects in which making CBaseObject::HasSapper return true for buildings that are plasma-disabled-but-not-actually-sapped was a horrendously bad idea. Because, believe it or not, there are areas of the game code that call HasSapper and expect the result of that function to tell them if the building, you know, has a sapper, in the actual sense of having a sapper attached to it.
In particular, when applying a sapper to a teleporter, the game code checks if the matching teleporter HasSapper(), and only applies a sapper to the other end of the teleporter if it returned false (this is done in CTFWeaponBuilder::PrimaryAttack). This means that sapping one end of a teleporter when the other end is plasma-disabled will result in only the close end of the teleporter being sapped. The HasSapper check in this case was meant to prevent double-sapping the other end of the teleporter; but because of the screwed-up semantics of HasSapper, it also prevents properly sapping both ends of a tele if the remote end is plasma-disabled.
When this situation occurs, it's impossible to remove the sapper if you're hitting the non-sapped end. Essentially, when you successfully apply damage to a sapper, the sapper will check if it's on a teleporter that has a matching partner, and if so, the sapper will propagate the damage it just took to the sapper on the other end (this happens in CObjectSapper::OnTakeDamage). Hitting the non-sapped end doesn't damage a sapper (because there isn't any sapper there), so the propagate-damage-to-the-other-tele's-sapper logic doesn't happen.
Also, it's not possible to remove sappers from a building when that building is plasma-disabled. This may or may not be intentional; I have no idea. But it manages to make sapper-spamming situations even more obnoxious to deal with than before.
Basically, this is an area of the game that is badly in need of some serious refactoring. What a mess.Most legit airblast reflections eversigsegv2016-08-13 | This player DoctorDrai definitely didn't have his "auto-airblast projectiles" cheat toggled on. Nope. Pure skill.
This guy is so good, he can airblast Loch-N-Load pills behind his back with perfect consistency. He doesn't even have to think about it; you might even say it's practically automatic to him at this point!
(Unfortunately his cheats didn't provide him with infinite ammo, so he didn't have enough to reflect my last shot. I love these little moments when cheaters expose their own lack of actual strategy or skill because their cheats suddenly lose their ability to bail them out.)
vacstat.us/u/76561198138861879How to fix the Short Circuit lag compensation bugsigsegv2016-08-12 | The Short Circuit has had a problem since July 7th (MYM update). If you use its alt-fire, and it doesn't hit anyone, it will cause certain enemy players to experience horrific rubber-banding. This video demonstrates the cause of the bug and its resolution.
This bug was previously demonstrated in this video by D3M1G0D: youtu.be/LztPob22GwI
I've already emailed information about this bug to Valve so they can fix it.
Weapons in games like TF2 are lag compensated. Note that "lag compensation" is a distinct thing from interpolation, extrapolation, client-side prediction, and clock correction; all of these are mechanisms designed to reduce the impact of network latency but they're all separate things that shouldn't be conflated with each other.
Lag compensation works like this: when the server simulates a player taking a shot with a weapon, it will temporarily "rewind" the other players' locations to where they were at the time when you hit the mouse button to take the shot. So if the latency between your computer and the server is 100 milliseconds, then the server will determine whether your shot is a hit based on where the other players were located 100 milliseconds in the past, not where they are at the "present time" on the server. This way, the server can determine whether you were aiming at the other player on your screen at the time you took the shot, regardless of how long it may have taken for the "I fired my weapon" command to reach the server.
Here's how the Source engine does lag compensation: 1. When the server wants to start lag compensation, the engine saves a backup of the players' locations/orientations/etc, then actually *overwrites* the player's location/orientation/etc with the "back in time" values 2. Then the server does the weapon hit detection 3. And then to finish up the lag compensation process, the engine restores the backed-up values back into the players, so that they're located at the proper places for the present time
Now, imagine that someone at Valve goofed up and made it so that, under some circumstances, step #3 accidentally doesn't happen. Well, now, instead of "temporarily" overwriting those players' locations with the back-in-time values, you've now *permanently* overwritten them. So the players are actually warped back to where they were a fraction of a second ago, and that becomes their new authoritative position as far as the server is concerned. And since the client isn't expecting to get warped like that, the affected players will experience a horrible client-side prediction error, as the client suddenly realizes "the server says I'm supposed to be over there, not here".
Now you're probably thinking that no one in their right mind would make lag compensation work in such a fragile, easy-to-screw-up way. But it's true, the Source engine really does overwrite players' locations, and then un-overwrite them afterwards (provided that you actually make the right call in the code). That's how the code works.
Here's a quote from developer.valvesoftware.com/wiki/Source_Multiplayer_Networking#Lag_compensation "Then the server moves all other players - only players - back to where they were at the command execution time. The user command is executed and the hit is detected correctly. After the user command has been processed, the players revert to their original positions."
If the developer makes a mistake and forgets to call lagcompensation->FinishLagCompensation, then that whole "reverting the players back to their original positions" part just doesn't happen. Yeah.
In this particular instance, it looks like it was due to a new optimization they added, where they exit the CTFMechanicalArm::ShockAttack function early if the list of entities in the alt-fire effect box is empty and don't call FinishLagCompensation in the early-return case. You'd think they'd have come up with some kind of RAII class/macro to make sure that lag compensation would be reliably finished when going out of scope (as is common practice for stuff like dynamic memory allocation or holding mutex locks), but nope. We're cowboy coders around these parts.
It's worth noting that the engine doesn't revert *every* player on the server when it does lag compensation. It won't revert teammates of the attacking player, and it will only revert enemies who are either (a) close to the attacker, or (b) within a 45-degree cone of the attacker's crosshair.
Thanks to Ronald Railgun for playing the role of the non-engineer player in this video.Enhanced sentry rocket explosionssigsegv2016-08-06 | Attribute "use large smoke explosion" works on sentry rockets. Isn't it great? (The attribute can be on the engineer himself or any of his weapons and it'll work.)
This works for very similar reasons as why "rocket specialist" works on sentry rockets. Video of that: youtube.com/watch?v=XjKIS78VT64
The Rocket Jumper also happens to be compatible with the "use large smoke explosion" attribute. Which makes for some humorous juxtaposition with its toned-down sound effects and lack of actual damage.
The short version: it works on all grenade launchers and it works on all rocket launchers except the Cow Mangler; but it doesn't work on stickybomb launchers or most other things.Valve: CTraceFilterDeflection NEEDS to ignore enemy playerssigsegv2016-07-29 | From a real game just now. The deflection trace line terminates on the bounding box of the cloaked enemy spy standing in front of me. And since that termination point is "forward" of the rocket's position at the time of airblast, it's deflected toward me.
Valve mostly fixed deflection angles recently, but the angles can still go wrong if you're aiming at a nearby enemy player. I've been emailing them asking them to address this oversight.Iron Bomber fuse time reduction in MYM makes jumping easiersigsegv2016-07-26 | The MYM update reduced the fuse time on the Iron Bomber from 2.0 seconds down to 1.4. Most people probably didn't pick up on the fact that this makes doing pipe-jumps with it much less awkward. (And jumping is ostensibly one of the main points of this weapon.)
Before, you sort of had to wait around awkwardly for about a second before jumping over the pipe if you wanted to execute a jump. Or you'd have to fire the pipe pretty far out in front of you so that you'd reach it just as the fuse timer had finally run down enough, which takes a lot of practice to get just right.
Now, it's much less awkward to do Iron Bomber pipe jumps: you no longer have to stand there like an idiot waiting for the thing to detonate; and timing your jump is considerably easier since there's less guesswork involved in estimating when the moment of detonation will happen.Server mod: custom engiebot AI behavior for Wranglersigsegv2016-07-25 | This is a fully functional custom TFBot AI behavior which enables engineer bots to use the Wrangler with their sentry. It's not 100% complete with all the features I'd ideally like it to have, but it essentially works.
Mostly I just liked the idea of having an engineer bot taunt you by saying "this thing ain't on autopilot, son", when by definition the engineer bot himself is on autopilot. Bit ironic, wouldn't you say?
There's an annoying bug in the game that causes engineer robots who use the Wrangler to have two laser beams at once: one coming from the sentry like usual, and another coming out of their eyes, as if they're a sniper robot. So I had to do a client-side mod to make that go away.
If I was more creative, I would have built some sort of cheeky laundry-chute style contraption into an existing map, and then made a video of unsuspecting players getting bombarded by stickies sliding out of the chute. But my time right now is demanded by more pressing matters, such as figuring out how to make the "nemesis" particle show up over bots who are dominating you.
The large stickybomb is an essential part of this map.Server mod: enabling domination/revenge in MvM modesigsegv2016-07-24 | By request. Still need to work out how to get the above-the-head icons to show up (it may be a client-side thing for all I know).
This one's only in 720p because I was too lazy to re-launch TF2 at a higher resolution. Just changing the resolution without re-launching screws up the entire HUD.Teleporter exit detonation bugsigsegv2016-07-23 | If a tele thinks it's about to get a player get stuck in something near the exit by sending them, then it aborts the teleport and destroys the exit. Unfortunately, this is based on an obnoxiously coarse bounding box check, which fails horrendously for diagonal stuff like this.
Ideally, in cases like this, they would do a follow-up check after finding that the boxes overlap by doing enginetrace->ClipRayToCollideable; this would determine if the safety box around the exit *actually* overlaps with the actual solid parts of the func_brush. But nope, no one ever bothered to implement such a thing.
Many players on mvm_bigrock have noticed this problem and generally figured that it had something to do with two-way teleporters. It doesn't. All you have to do is teleport such that the teleporter you exit from overlaps this bug ugly red box.
TF2Maps thread on this topic: http://tf2maps.net/threads/bug-teleporters-dont-work-when-inside-solid-func_lods-or-func_brushes.24683Bot spawn glitch not fixed, hopefully really fixed next timesigsegv2016-07-22 | Sigh. Valve fixed the bug but they fixed it a bit wrong. Here's a clip of me debugging the problem, with one of my fancy over-engineered realtime text overlays. Bot #16 is the troublemaker. Part of the video is at 1/4x speed.
Previous video from before this bug was "fixed": youtube.com/watch?v=CY0o9MPpgkYFlamethrower Mojo Investigation: Part 4 of 4sigsegv2016-07-18 | Part 4 shows a non-flame-related hitreg bug with the same root cause. Server-side clock correction can cause close-range crossbow bolts aimed at teammates to miss them completely. Shots against enemies don't suffer from the problem. (Read on for why.)
Timestamps: 0:05 Clip 1: no clock correction: CollideWithTeammatesThink consistently occurs immediately after firing 0:28 Clip 2: with clock correction: CollideWithTeammatesThink becomes inconsistent and is frequently very, very late 1:03 Clip 3: point-blank crossbow tests with a teammate 1:48 Clip 4: point-blank crossbow tests with an enemy
Q: What is CollideWithTeammatesThink? A: Projectiles use CollideWithTeammatesThink as a timer. You know how rockets or grenades will pass through teammates if fired from close range, but will actually hit teammates from long range? That's controlled by this. When the projectile spawns, it sets the CollideWithTeammatesThink to occur in the future, after a certain number of milliseconds. Prior to the Think, the projectile will ignore teammate collisions; after the Think, the projectile will not ignore them.
Q: So why does the crossbow have trouble hitting close-range teammates? A: CTFProjectile_HealingBolt::GetCollideWithTeammatesDelay returns 0.0, which means that crossbow projectiles should be able to collide with teammates right away, instead of having an initial delay where they won't hit teammates like other projectiles. What this actually means is that when the projectile spawns, it requests that the CollideWithTeammatesThink occur at the current time + 0.0 seconds. But because of server-side clock correction, the "current time" it's seeing may actually be in the future. So in actuality, CollideWithTeammatesThink doesn't happen until tens of milliseconds after the bolt is fired; as a result, the bolt ignores teammate collisions for that initial interval. And ignoring teammate collisions means that the bolt won't detect if it hits a teammate and should apply healing.
Q: Why is hit registration against enemies unaffected? A: Projectiles always detect hits against enemies, no matter what. It's only hit detection against teammates that critically depends on the timing of when a Think (specifically CollideWithTeammatesThink) happens.
Q: How is this different from the flame situation? A: Unlike flame entities, crossbow bolts don't do basic stuff like hit detection in a Think routine; they let the game engine do it the normal way, for the most part, and so it's not as if the projectile is completely non-functional if it's not thinking. But since projectiles do use a Think as a timer to change their "should I collide with teammates" flag, they are still affected by the underlying clock-correction issue, just in a different way.
Q: Why does this matter? What was the point of showing crossbow stuff in a video series ostensibly about Flamethrower Mojo? A: The point is to demonstrate that the underlying issue behind Flamethrower Mojo has the potential to be screwing up all sorts of other things, many of which we probably aren't even aware of. The actual core problem is this: many entities (primarily weapon entities) are simulated on the server in a player's clock-corrected context; and these entities often spawn other entities (e.g. projectiles); and when these other entities are spawned, they set up various things (timestamps, SetNextThink times, etc) based on the clock-corrected value of gpGlobals->curtime. Then, when these secondary entities are themselves simulated, they are no longer in a clock-corrected context, and so any time-based logic (be it Think times or timestamp comparisons or whatever else) will fundamentally be "off" by a non-insignificant time interval.
Q: That sounds like a pretty wide-reaching problem. Are there ways to fix this? A: Yes, I've come up with some potentially workable solutions, and I've emailed what I've come up with to Valve (along with all the other information about the problem). They may also find their own ways to work around it beyond what I was able to suggest. So don't get the impression that this is a huge, fundamentally unfixable problem. It can be solved. Most likely, none of the developers ever really considered this particular set of circumstances when implementing clock correction for player simulation.Flamethrower Mojo Investigation: Part 3 of 4sigsegv2016-07-18 | Part 3 demonstrates that missing FlameThinks results in poor hit registration with nearby enemies near a wall (or floor or other solid object). If the flame has already reached the wall by the time it does its first FlameThink, it will remove itself and register no hits.
Timestamps: 0:05 Clip 1: no clock correction: perfect hit detection 0:47 Clip 2: lag + clock correction: plummets to ~50% hit rate
Q: Why are the flame entities coming out of your head, when the muzzle of your flamethrower is way out in front of you? A: Because that's how the game actually works. With few exceptions, weapons fire from your head, not your gun. Even the heavyweapons guy's $200 custom-tooled cartridges come out of his noggin, not Sasha's barrel.
Q: What do the colored and/or white lines between the pyro's head and the flame entity boxes represent? A: Those are visualizations of the trace lines (ray casts) that the FlameThink is doing for hit detection. My code draws them in white if the flame believes it hit a wall and decided to remove itself. It draws them in the same color as the flame entity box if the flame did not hit a wall. If the trace hit the enemy pyro, then it also draws "HIT" in the color of the flame entity; if the trace hit the wall, then it draws "HIT WALL" in white, and additionally draws a small sphere at the point of impact with the wall.
Q: Why doesn't the flame "catch up" and ignite the entities it's passed through, even if the first trace does hits a wall? A: Because that's how Valve setup up the flame code to work. When FlameThink does the trace, it if hits a wall, the flame removes itself and doesn't handle any other hit detection, end of story. On the other hand, in the absence of a wall, a few missed FlameThinks at the beginning aren't a problem and can be "caught up" on, because when the first FlameThink does occur, the trace line it generates will pass all the way from the pyro's head to the current location of the flame entity, and will ignite any enemies that are located in between.
Q: Why is the clock-corrected long-term hit rate roughly 50% rather than, say, 0%? Why 50% in particular? A: For these tests, the network connection had constant jitter, which means that the latency (ping) was constantly jumping up and down (with the settings used, it could vary anywhere between 100 ms and 300 ms). So about half of the time, packets would arrive early, so the server-side clock correction would adjust the clock into the future, and the FlameThinks would be delayed, messing up the hit detection. But the other half of the time, packets would arrive late, so the server-side clock correction would adjust the clock into the past; and in this "time-travel-to-the-past" case, the first FlameThink is requested X ms in the past, so it ends up executing immediately ("normally", more-or-less). So the flame acts *mostly* normal 50% of the time. (It's worth noting, however, that the flame's expiration time would still be erroneously short in this case, because that's determined by a different timestamp that is influenced by clock correction.)
Q: Why did you turn hitsounds off for this video? A: At 200 ping, hitsounds are (a) delayed, and (b) tend to batch up into 200 ms groups. Accordingly, the hitsounds weren't really lining up with the hits and misses and giving an accurate impression of which flames were or were not hitting. And as the hit ratio is the main point this video is trying to convey, it made sense to remove the hitsound, to prevent giving viewers false impressions unintentionally.Flamethrower Mojo Investigation: Part 2 of 4sigsegv2016-07-18 | Part 2 shows how server-side clock correction causes flame entities to miss their first several FlameThinks. Since flame physics and collision detection are done in FlameThink, this has dramatic deleterious effects on their trajectory and behavior.
Timestamps: 0:05 Clip 1: no clock correction: normal FlameThinks 1:03 Clip 2: with clock correction: missed FlameThinks 2:49 Clip 3: full-speed comparison of #1 and #2 3:25 Clip 4: higher float: flames don't rise until they think 4:13 Clip 5: 100% drag: flames stop moving on their first think
In the clips with tf_flamethrower convars shown, ones that have non-default values are highlighted in yellow.
It's worth noting that missed FlameThinks are not the sole cause of increased flamethrower range. Server-side clock correction also causes the flames' "time-to-live" value to be a bit farther in the future than it ought to be, so the flames last longer than they should.
Q: What is a "Think"? A: It's a bit of code that an entity runs on the server to do simulation-type stuff. Some Thinks run repeatedly at an interval; other Thinks are used essentially as a one-shot timer. Flame entities have a FlameThink, which runs every server tick (66 times per second). Flames do all of their physics, collision detection, and removing-themselves-when-expired stuff in their FlameThink.
Q: What the heck is going on in clips 4 and 5? A: I tweaked a couple of the flamethrower parameters to make it slightly easier to visually see what's going on. In clip 4, I increased the "float" factor, so when flames do their FlameThink, they will rise vertically more dramatically. Flames that aren't running their FlameThink will keep going horizontally. Likewise, in clip 5, I set the "drag" factor to zero, meaning that when FlameThink runs, it will immediately slow the flame's velocity down to zero. So flames that aren't running their FlameThink will move horizontally, and then stop as soon as they finally do run a FlameThink. (In both cases, I also set the "vecrand" parameter to zero, which removes the slight speed/direction variation that the flamethrower normally imparts on the flame entities).
Q: Why does the flame entity not show up immediately in sync with the animation/sound/particle in clips 1 and 2? A: Because the connection is laggy, of course. Also, the game is running in slow motion, which exaggerates the effect. The animation/sound/particle show up immediately when the client sees that I pressed +attack. But the colored flame entity boxes are drawn by the server, so they don't show up until the command from the client to fire the flamethrower has made it all the way across the laggy connection to the server.
Q: Why did you disable the flamethrower particle effect for clips 4 and 5? A: Because it's misleading and was just getting in the way. The particle effect (the graphical flames shown coming out of the flamethrower on the client) is completely unconnected to the flame entities themselves. The flame particles are only on the client side, and the flame entities are only on the server side. The two don't communicate at all. The flamethrower particle effect was just made to look like it roughly matches up with where the flame entities approximately usually go. So when I make tweaks to the actual flame entity parameters on the server side, the client-side particle effect doesn't change at all (it still shows flames coming out the usual way).
Incidentally, this is a good general explanation for why the visual flame particles frequently do not match up with the actual effects that your flamethrower is having. (For example, the flame entities themselves do subtle things like integrating some of the pyro's movement into their own velocity; the particle effect doesn't really convey that, because it's a simplistic system that just spits out particles in a certain manner; it doesn't account for any of the physics stuff that the flame entities are actually doing.) To make the two match up would require the client to do prediction with its own local, "virtual" copies of the flame entities, where it attempts to mimic the simulation that the server would be doing with them. (This is necessary because getting the actual information back from the server would take too long; prediction is what makes it possible for your game client to speculatively do things like movement and weapon actions on your screen *immediately*, before it's even possible to get confirmation that those actions did actually take place on the server.) This might be a possible thing for Valve to implement in the future, depending on how big of an issue they consider the mismatch between the visual particle and the flame entities to be. But keep in mind that a feature like this might ultimately be performance-prohibitive; it's hard for me to say.Flamethrower Mojo Investigation: Part 1 of 4sigsegv2016-07-18 | Part 1 establishes that "Flamethrower Mojo" is a real phenomenon: under the right circumstances, flamethrower range can deviate tremendously from the distance intended. Varying lag and server-side clock correction are the necessary preconditions.
Timestamps: 0:05 Clip 1: no clock correction + no lag: normal flame distance 0:30 Clip 2: no clock correction + adding lag: still normal 0:59 Clip 3: clock correction + lag swings = abnormal distance 1:45 Clip 4: clock correction + lag jitter = abnormal distance
If you'd like to watch a simpler explanation video than my technical ones, check out Whistling Pyro's video: youtube.com/watch?v=WDUXMoALnu4
Q: What do the white boxes represent? A: These are "ghost" boxes showing where flame entities died. The number shown on them is the distance they traveled from the firing position (in Hammer Units). Statistics on these distance figures are shown in the upper-right corner. The statistics are sampled from the last 44 flames (equivalent to 2.0 seconds' worth of flames).
Q: What is server-side clock correction? A: If a player's client-side clock is getting out of sync with the server-side clock (due to short-term changes in ping, for example), then when the server does simulation for that player (AND their weapons), it will "fudge" the clock values (gpGlobals->curtime) to try to make things line up the way they were meant to.
Q: Why is server-side clock correction problematic in this case? A: The flame entities are spawned by the flamethrower entity during its entity simulation, meaning that clock-correction is in effect, so any timestamps or timers or SetNextThink's that the flame entity's Spawn function does will be based on the "corrected" clock, which may actually be set to a time in the future. Then, when the flame entities themselves simulate, they see the real, un-corrected clock. So when, for example, the flame entity spawns and says "I'd like my first FlameThink to happen immediately, please", and it does SetNextThink(gpGlobals->curtime), it's *actually* requesting for the think to take place as much as, say, 60 milliseconds in the future, depending on how much clock-correction is in effect at the time.
Q: Would fixing this be as simple as disabling server-side clock correction (i.e. setting sv_clockcorrection_msecs 0 as the default)? A: Almost certainly not. There are good reasons to have clock correction. And there are some potential ways that this problem could be addressed without affecting other parts of the game.
Q: Were net_fakelag and net_fakejitter being used on the server, the client, or both? A: Only on the server side.
Q: Is this a listen server? A: No. It says it right there in the video, bonehead.
Q: If it's not a listen server, then how are you able to draw debug overlays from the server and make them show up on the client? A: I wrote my own code to make this possible. I spent a lot of time on it, and it's an invaluable tool for debugging. On the server, I have a mod that intercepts calls to NDebugOverlay functions. It serializes the parameters and sends the information over the network to the client. On the client, I have another mod, which receives the network data, deserializes it, and then forwards the calls on to the IVDebugOverlay interface. (Because this is a client mod, I have to run the game with "-insecure", i.e. VAC-disabled mode, for it to get loaded. But who cares, this is just for debugging purposes anyway.) In the past, I did the network transmission via custom usermessages, but the Source engine was not particularly happy about me sending multiple megabits-per-second of data over its main connection. I couldn't figure out a good way to overcome Source's stupid MTU and throughput limits, so now I just send everything via a separate UDP socket, with 65000 byte jumbo frame packets. ("And blackjack, and hookers.")
Q: So what exactly was the test setup, then? A: These demonstrations were done with a Linux dedicated server and a Windows client. The video recordings are from the Windows client. The server and client were running on the same machine, though the client was running in a virtual machine.
Q: Why the hell do you run your game client in a virtual machine? A: Because I am a crazy, crazy man with (a) too much time on my hands, and (b) access to two graphics cards, an IOMMU, and the power of QEMU, KVM, and VFIO.medicgun_beam_machinerysigsegv2016-07-16 | This curious white medigun beam particle effect has been in the game files for a long time. Turns out there's still code in the client to use it when healing a CBaseObject (i.e. a building). All I had to do for this video was mod the medigun to allow buildings as heal targets.
A client code reference to this particle effect (to use it when healing buildings) appeared around April 17 2013, then went away around April 30 2013, then came back in the July 10 2013 update, and remains in the codebase to this day.
About the particle files themselves: as far as I can tell they weren't in the game between October 10 2013 and November 21 2013, and then they've been in the game files since. (Nov 21 2013 was the Two Cities update). I'm pretty sure they weren't in existence at all before October 10 2013, but I can't personally prove it (I need to expand my archive of old TF2 files a bit more).
Is this particle effect new? No. Is it something that was meant for MvM robots to use? Probably not.
Based on the time when this stuff showed up (in the run-up to the Two Cities update, when Valve was looking for ways to buff medic in MvM), my best guess is that they were experimenting with giving medics the ability (probably via an upgrade) to heal teammates' buildings. And they went so far as to put together a new particle effect for it. But that idea was probably scrapped in favor of the tons of other changes they made instead.
Strictly speaking, nothing here conclusively proves that this particle effect had anything to do with MvM at all. Maybe Valve was thinking about making a new medigun that could heal buildings for use in PvP. Who knows.
Another remote possibility is that this beam particle was intended to be used when healing MvM Reanimators; at the time, early in development, they could have been CBaseObjects, I suppose. But it's very unlikely, it's very speculative, and it doesn't really explain why the beam would have mechanical looking stuff in it.Welcome to the new TF2 pub experiencesigsegv2016-07-13 | Votekicking is no longer possible. Nor is spectating. So cheaters now possess an unprecedented ability to ruin players' games. They know that even if they're super-obvious and everyone wants them out of the server, no one can actually do a damn thing about it.
Cheaters are an ever-present problem, and VAC isn't enough by itself: it can't always keep up with the latest cheats, and by design it doesn't ban players immediately. So there needs to be a way to deal with the immediate problem of games being ruined by cheaters who haven't been banned yet.
Previously, on Valve servers, you could votekick cheaters, which was acceptable because at the very least you could get them out of your game and make them go somewhere else. But with Casual Matchmaking (as it currently exists), cheaters are free to do whatever the hell they want and players are powerless to do anything about it.
Here's this particular cheater's Steam ID info: vacstat.us/u/76561198260389462 (Incidentally, VacStatus is a great site to use for tracking players that you think are cheating; you can add them to a personal list and then the site will notify you if/when they get banned.)New MvM-related sound file in the Meet Your Match updatesigsegv2016-07-09 | This will only be interesting to people who obsess over possible future MvM content updates. Basically: Valve added this new, unused sound file in the update, and the most likely purpose of it is to be used in a (speculative) new MvM map in the future. More info below.
We've already found out in other recent TF2 updates that Valve added some hidden new MvM-related features, such as adding various pieces of functionality to enable bots to use the BASE Jumper parachute item.
This new effect sounds like an air raid siren. Air raid sirens are used to warn people about an incoming air raid. An air raid which maybe, just maybe, could involve EVIL ROBOTS who parachute down from the sky to invade Mann Co... and then probably just plant a bomb that they could have dropped directly from a bomber in the first place.
Obviously this is pretty much just gratuitous speculation. But it's fun to try to figure out what new, possibly idiotic gimmicks Valve are currently in the process of thinking up.
Also: if we are lucky, maybe they will jump out of blimps.
(The blimp thing is an obscure mvm_mannhattan reference.)Engiebot model still has no pelvis hitboxsigsegv2016-07-08 | Valve literally never updates the MvM robot models. Ever.Exploit: instant medic revive in MvMsigsegv2016-07-08 | CTFReviveMarker::m_iMaxHealth is initially 0, and it isn't set until the first CTFReviveMarker::ReviveThink, ~100ms after spawning. So by healing during the first 100ms, CTFReviveMarker::AddMarkerHealth will see that its health exceeds its max health and will immediately revive.