The State of Hit Registration
Hi, I’m Kevin Lee, a software engineer on VALORANT’s Game Systems team. Our team is responsible for developing many of the core systems that support VALORANT’s gameplay, including movement, combat and input. In this post, I’ll be going through one of the systems that’s core to FPS gameplay: Hit Registration.
In a game like VALORANT, hit registration is arguably one of the most important systems given that the difference between a win or loss can come down to a single headshot. Our goal as developers is to ensure that when a player fires a shot, the outcome of the shot is clear, feels right, and is above all else, correct.
We’ll sometimes see posts or receive messages from players with clips where hit reg appears broken. We take all of these reports seriously, and go through each video frame-by-frame to validate that the system is working as expected.
That being said, we think hit registration in VALORANT is in a pretty good spot right now. Yes, there may still be edge case bugs out there and we will always take those seriously. We’re constantly looking to improve the quality and clarity of all of our systems.
CORRECTNESS VS CLARITY
In beta patch 0.50, we saw a spike of reports around issues with hit registration. After looking through player reports, videos and extended internal testing, we were able to identify a few edge case bugs with hit registration, but none of them severe enough to explain the amount of reports we received. Upon closer review, the majority of the clips had issues not with correctness, but with clarity. The shots were being properly processed, but the visual feedback of the shot was presenting a misleading outcome to the player. This highlights an important distinction between correctness and clarity.
While both are important in ensuring the “feel” of a shot...
- Correctness refers to the outcome of a shot being wrong (i.e., bullets hit the head but registers as body or enemy players appearing differently on the client compared to the server)
- Clarity refers to the presentation of a shot being hard to read (i.e. bullet hit the shoulder, but visual feedback made it look like the bullet hit the head)
- Correctness bugs are much worse than clarity bugs
We hope this article will shed some light on the system so everyone can look back at their gameplay and understand what’s happening on their screen, with respect to their shots. I’ll go over how the system works at a high level, and explain what happens from the moment the fire button is pressed, to the headshot being displayed.
For a more detailed technical deep dive, check out this article about VALORANT’s netcode on the Riot Tech Blog.
I’ll also go into some common cases we see when it comes to reports of “broken hit reg” and try to explain what’s going on and what we’re doing to improve clarity in those scenarios.
FROM CLICK TO HEADSHOT
Before we dive into what happens when a shot is fired, it’s important to understand how the game simulates what’s happening. VALORANT’s gameplay is simulated twice: once on the server (the authority for how the simulation plays out) and once on your client (predicting server results to make the game feel more responsive).
The game simulation includes everything that makes up the world including all player’s positions, any abilities flying through the air, and any smokes on the battlefield. Each frame, the game takes a snapshot of the simulation and uses that to render a frame on your screen. The server also does this for each of its frames (skipping the render step since there’s no one watching the server).
Ok so, an enemy peeks out from a corner, and with your amazing crosshair placement you’re already locked onto their head, so you hit the left mouse button to fire— What happens?
The moment you press a key, the input is sent to our input system (subject to a small amount of hardware/operating system latency). Each game frame, the input system will process all the inputs it has received since the previous frame. When you fire a shot, that “fire” input is sent to the server alongside a timestamp for what frame in the simulation the shot happened.
It’s important to note that this timestamp is according to what is currently rendered on your screen at the time of the input being received by VALORANT. We now have to follow the shot on two different simulations: the client’s and the server’s.
Let’s start with the client, or your local machine. Immediately after the shot has been sent off to the server, the client starts working on displaying a muzzle flash and tracer for the shot. At the earliest, this will happen one frame after your input has been fired since the game needs to render a new frame to your screen. This is important because it means the frame a shot is processed is NOT the same frame that a tracer is displayed, it's actually at least one frame before.
This can sometimes lead to a failure in shot clarity. The common way this desync could be solved is to delay the bullet. We don’t do this because delaying the bullet adds input latency which we want to minimize in VALORANT. With respect to hit confirms, the client waits until it hears back from the server on the result before displaying a hit-confirm. In order to guarantee consistency across all users and to prevent cheaters from hacking their clients to give false shot results, shot results are entirely server authoritative.
Meanwhile, the server eventually receives a message from the client that a shot has been fired. Due to internet latency, time has passed since this shot has been fired. To ensure the shot is fired against the same simulation that was shown to the player, the server rewinds the simulation to the timestamp given by the client before evaluating hit registration. This includes rewinding player positions and animation poses. It then sends the result of the shot back to the client. For the sake of this example, let’s say it was a headshot!
The client will receive a message from the server with the result of the shot and then plays the VFX and audio that’s appropriate. In this case, it would be headshot VFX and audio. Because the client has to wait for the server to tell it the result of the shot there is a delay between the tracer and the hit effects equal to your connection’s round trip time (i.e. 40 ms to the server = 80 ms delay between tracer and hit VFX), plus a minor amount of processing time. With higher latencies, this delay can become noticeable in real-time.
This is something we’re actively working on improving from a clarity perspective.
CASE STUDY 1: Hitting moving targets
In a lot of reports regarding hit registration, we see that the target of the shot is running. Let’s take a closer look at what visually happens when a shot successfully hits a running target. We see the player gets a successful headshot on the running player. To more easily illustrate this issue in this example, the client is running at 60 FPS. You can see that in the frame before the tracer is fired, their crosshair aligns with the enemy’s head.
However, the frame where the tracer comes out, that is no longer the case.
The second clip shows the same scenario, but with the shot barely missing the target. When you look at the video frame by frame, you can see that the opposite is true: their crosshair is off the head on the frame before the tracer, but on the head the frame the tracer comes out. On first glance, you might think to point to the frame with the tracer and say “See, this was clearly a headshot!” When reviewing video or replays, we actually need to be looking at the frame before the tracer to get an accurate picture of when the shot was fired.
Let’s go back to the example where the shot hit and look at the frame when the hit VFX is rendered. There is a noticeable gap between the player’s current location and the location of the hit VFX due to the delay caused by internet latency. This can be confusing when you’re trying to understand what happened with your shot, since you’ll most likely be focused on the enemy's current location, not their location at the time of the shot. This can also lead to additional confusion in crouching/strafing scenarios (which we will look at in Case Study 2).
This case study illustrates a lack of clarity with the current hit registration system. Ideally, you don’t need to understand all this background information to be able to read the situation clearly. As developers, we acknowledge this and are investigating ways to improve clarity in these cases.
CASE STUDY 2: Crouching into shot VFX
So you’ve entered a gun fight at long range. To your future self’s regret, you hold down left click and spray your gun. At least one of those bullets will be a headshot, right? But no, you hit 3 body shots with your Vandal, dealing 117 damage, before receiving a headshot in return.
Furious, you go to review the footage after the game, certain that bad hit reg was at play. You see the enemy player was spamming crouch in an attempt to dodge your shots. To your surprise, you see a hit VFX right on top of their head while the player is crouching. But your combat report only showed body shots! What gives??
Here’s a link to a real post on reddit titled “Headshots not registering when a player crouches” of the hypothetical.
When our team goes to investigate reports of bad hit reg, situations like this one are the most frequent cause for what appears to be incorrect hit registration. In fact, hit registration is working correctly—shots are going where you're aiming (ignoring spread or movement error) when you press the fire button, and that shot is accurately registering on the server
However, a few different factors cause this particular case to be visually misleading:
- Hit VFX are delayed due to internet latency
- Hit VFX are displayed at the location of the original shot impact
- The target player is moving (most often crouching)
For another example, let’s say the player has 50 ping. The player hits a shoulder shot on the enemy player. Because we need to wait for the server to confirm the hit, it’s 100 ms later when the hit VFX starts to play on the location of the body shot. But during that 100 ms, the enemy player has started to crouch, moving their head right behind the newly spawned hit VFX. At long range and in the heat of a gunfight, a body hit VFX can be confused for a headshot hit VFX.
This was especially bad during beta patch 0.50 when blood was unintentionally disabled for everyone, and our spark VFX has less visual clarity in distinguishing headshots and body shot VFX. We’ve always had separate VFX to indicate body shots vs headshots, but we realize they didn’t always read clearly in combat.
This is a failure in hit registration clarity that we are actively trying to improve. One of the things we’re experimenting with is tying hit VFX to the body part of the character where the hit occurred, so that there is a clear relationship—even with high latency.
Comparison of our current non-blood headshot hit VFX compared to body shot VFX:
PLANNED CLARITY IMPROVEMENTS
The two case studies highlight some areas where our current hit confirm VFX falls short. One of the changes we’re iterating on is to have blood and spark effects spawn on the character’s current position, according to which part of their body got hit, and follow them as they move. This greatly increases the clarity in situations like in case study 2 with crouching enemies, because the visual effect will move with their body movements.
One trade-off to this approach is that it would be possible for hit confirm VFX to move behind cover alongside its attached character. Consider the case of a player with 100 ms of ping shooting at a player jiggle peeking a corner. If they land a shot on the enemy and they immediately move back behind a corner before the hit confirm arrives from the server, the shooter may not be able to see the hit confirm when it spawns.
We’ve considered adding multiple particles, some that follow the character and others that spawn immediately at the hit location, based on the client simulation, to mitigate this issue. However, this in turn can cause confusion if the client and server simulations ever disagree on the outcome of a shot: The effects need to be clear in what they represent so it’s easy to understand the outcome of a shot.
We’re continuing to iterate on this and other improvements to clarity and hope to have a set of clarity updates to share soon, in a future patch.
KEEP SENDING VIDEOS
Hopefully this post has helped you better understand how hit registration works in VALORANT and better understand why shots resolve the way they do. Please keep sending us videos any time you think hit reg is misbehaving, we do try our best to look at all of them.
Even if there’s no issue at hand, it helps us track down hit registration correctness bugs faster when they do happen (my heart rate also jumps each time I see the word “Hit Reg” on a top voted reddit post).