Lag compensation in multiplayer games uses client-side prediction to make player movements feel responsive by immediately updating the local player's position when input is received, then reconciling with the server's authoritative state when updates arrive; this is implemented using a rollback synchronizer that tracks both state properties (position, velocity) and input properties, allowing the system to rewind and replay inputs when discrepancies are detected, thereby eliminating the perceptible delay between player input and visual response even under network latency conditions.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Godot Multiplayer Lag Compensation with NetfoxAdded:
You hit forward on the keyboard and it takes a full second for the player to move. With the demo just launched, you need to figure out what's going on with this delay. It worked fine all year when testing locally. You know, those late nights, cold coffee vibe code, cold sweats, networking, authoritative governor servers. And when you finally saved up enough to deploy it somewhere, it's completely unplayable.
Latency.
So, the first thing you want to do is clone or download my Godot intro to multiplayer project. As this is going to be our starting point for this video because it does not have lag compensation and it's an easy project to work on and demonstrate the implementation of lag compensation. Make sure you have the latest version of Godot and once you have the project open, just run it really quick to make sure that it works. Great, everything looks to be okay. So, go ahead and close that. And as a best practice, I like to keep editor upgrades on its own commit.
And as part of this commit, I'm going to quickly remove this send test message functionality as I think we're way past that.
And then let's go over to the asset lib and let's search for Net Fox.
And there's a few things that show up when you search for Net Fox.
So, select the Net Fox asset, click install.
I am going to install Net Fox extras so you can introduce latency into your game just testing locally, which is a really cool feature.
Once installed, head over to the project settings and under the plugins tab, make sure they're both enabled.
If we take a quick peek at the globals tab, you can see there's some new auto loads that have been added as part of the Net Fox install like network time, network rollback, and events. So, just run a quick test to make sure that nothing broke. If you do get an error, just go ahead and restart your Godot editor and it should clear up any errors that you see there.
And just like with editor updates, I also like creating separate commits for when I upgrade or install libraries. So, commit the Netfox install. So, now we want to demo some latency, but I don't want to have to deploy this somewhere to the cloud or get a friend to participate in this test. So, I need to just be able to do this locally. Fortunately, there's a way to do that with the Netfox extras plugin.
So, open up the main menu script.
So, the way we can introduce some latency is with this network simulator tool. And basically, what we're going to do is hook into the server created and client connected hooks, which are going to call to these respective functions.
So, I've wired up the network simulator signals to create a server and connect a client to these two functions down here respectively.
And what that's going to do is automatically start a server and client for us. So, we're not actually going to be using our on host pressed or joined buttons. So, in order to enable this, go to the project settings, scroll down to Netfox, and then select auto connect, and then hit this enable checkbox.
I'm going to change the port to 8,000.
And the simulated latency, we can do something like 400 milliseconds, which should be noticeable. Close that. So, if you haven't already, you need to enable an extra debug client. Go to the debug menu, custom run instances, check this enable multiple instances, and then hit this up arrow so you get two.
Let's run the game. And did you notice that we didn't have to click any buttons? It just automatically put in both our server and client ships. Yeah, that's what I'm talking about. So, if you don't want that, again, you can adjust the ready function to not do this when the network simulator is disabled.
Oh, and if you get an error down here, I actually talked to the developers. This is just part of the setup when it's trying to establish the server and client. Just ignore that. It's just the way that it goes and detects if there's a connection made. You can just basically ignore this error. So, this is our server peer, and this is our client peer.
And this is my untouched multiplayer project demo without any lag compensation or anything. So, what you'll see is when I click the movement keys, there's going to be a difference between when I click it and the player actually moves on the screen. Now, let's look at the client or player two.
Here, I'll put the microphone close to the keyboard so you can hear the click.
Let's break down what's happening here.
Right now, when I hit the keyboard, my ship moves on the host first, then on my client. That's the naive setup. The authoritative host receives your input, applies them as movement, then sends the result back to the client.
Because of that round trip, you get a noticeable delay, input lag. Keep in mind, this lag is the problem we're about to fix. Once prediction is on, you won't see the host move first anymore.
That's where Netfox comes in using client-side prediction and server reconciliation, what it implements under the hood as rollback. Your ship moves immediately on the screen the moment you press a key. The round trip still happens in the background, but here's the trick. When an authoritative update arrives from the server, Netfox rewinds your ship to that point, snaps it to the server state, and quickly re-plays all your inputs since then to catch back up to the present. If your prediction was already correct, you won't notice anything at all. Now, that's a gross simplification, but I'll drop some links below if you want to dig deeper.
So, I went ahead and added a wrapper for you so that you can test this out easily.
So, in order to turn it off, let's just go back over to project project settings, auto connect, and just click this enable checkbox.
And if we run it again, it should not hit this code, which means we should be able to use our normal on host and on join buttons. And as you can see, it didn't kick us into the game. Great.
Let's just run a sanity check.
Perfect.
If you wanted to run that again, go into the project settings and check that check box, and then it will it'll automatically run this simulated latency test for you. So, I'm going to leave that there for you guys if you want to play around with the latency.
And I'm going to add those network simulator changes as its own commit.
Open up the player script and the player input script, so we just have them ready to go.
And with the player scene open, add a rollback synchronizer. If you try to add it to the player scene and it's not showing up, check the output tab.
There's probably some errors there. The way that I cleared this up was just to restart the Godot editor. And just so you know, there is some good tutorials and documentation over on the Netfox site, and this responsive player movement guide is actually the one I'm following today.
If you'd like to do a deeper dive, I'd recommend reading through the tutorials and concept and guide sections, as they provide some pretty good information to help you a better understand what they're actually doing behind the scenes. So, why are we using this rollback synchronizer node? Well, when developing out your game, there's some properties on maybe various objects in your game that need to be compensated for the latency that it is experiencing that represent the state of the objects that you're moving around in the game.
Maybe you have a player, in this case we're using a ship, and it's a very simple implementation, right? We're just using X and Y coordinates to move the ship around in a 2D plane, and the state is just position and maybe velocity. But maybe you have a 3D game, and at that point you'd probably want to use the transform property because you'd have things like rotation as well as movement within the 3D space. And the other side is to look at the inputs from the player, but we're going to look at that in a second. And if you open the rollback synchronizer, here's where we can capture the state properties. And if you look at where we currently are from the previous tutorial, we were just using the multiplayer synchronizer to pass position between the clients to show the movement of the ships. Well, that's not going to work as soon as you introduce latency. As part of the upgrade for handling lag compensation, we need to remove the old ways of synchronizing these properties. So, let's go ahead and remove the position property from the synchronizer. And then head back over to the rollback synchronizer, open the state properties section, and enter in position. And make sure you put a colon in front of the position property as that indicates to the rollback synchronizer that it's a property of the player. So, after position, we also need to capture the velocity. So, the velocity defined here in the player script is going to be underscore velocity, and it's a property that we're independently tracking. And the reason why we need to track velocity is because sometimes our current velocity calculation relies on what the value of the velocity was in the previous tick, as you can see here with this move toward call. So, in the event that NetFox does a rollback, it would restore to the correct position, but it may not get the correct velocity because we didn't track it. So, there may be a gap or a jump in your ship or player's movement if you didn't track that property along with its position because it can't correctly calculate the position without the velocity because we're actually using the velocity from a previous tick to calculate the next velocity to apply to the position with our translate function. Hope that all makes sense. So, in this case, we need to track the velocity.
So, the next thing we need to do is handle the inputs from the player. And currently right now, we're doing that over in the player input script, but you can see here there's another drop down where we can add the input properties.
Open up the player input script. You could see that the input direction property is what we use to transfer the inputs that the player pushes on their keyboard. So, because this is how a player currently controls the movement of their ship, we need to add that property over here under this input properties tab. Add a new element in input player input colon input direction. So, with these two properties, the position or location of the ship, and then the inputs that the player uses to move that ship, with this client-side prediction and server reconciliation technique that Netfox has implemented, you're able to see your ship move immediately on your local machine without waiting for the server authoritative round trip of sending out your input, moving the ship on the server, and then sending that update back. They handle this in a really graceful way, which smooths out and gives a much more responsive feel when you're moving your ship or character around in your game.
And as a quick tangent, definitely check out this authoritative servers post here. It's a good breakdown between the naive replication implementation that we currently had from the first tutorial versus what we're trying to do today with the Netfox client-side prediction and server reconciliation.
And if we look back at the responsive player tutorial, I'm just looking at how they want us to capture the input properties, and you can see right here there's this gather function, and it looks like we have to register the gather function with network time before tick loop. So, it looks like they're not relying on physics process anymore to gather the inputs. I guess they're using the gather function. So, let's head over to the player input script. In the ready function, let's set both process and physics process to false, so those don't run anymore cuz we don't really need it.
And let's change the physics process function to gather. And to keep in style with the Netfox implementation, let's just remove this authority check out of this conditional here, and just add a new one above and kick out anything that's not the authority.
And as a reminder, in this context, the authority is actually the player. So, the player has authority over their keyboard and mouse and pushing those buttons. So, we don't want anybody else to interfere with capturing those specific inputs from that player.
So, we kick out everybody else when they're not the authority over this player input object. If you want to do a deeper dive on the authority concepts and player inputs, I have a whole video on that. Check that out if you're still struggling with some of the authority concepts. So, now we need to register gather with the network time.
So, in the ready function, let's do network time before tick loop and then just register or connect the gather function.
Great. And if you check back with the docs, it wants us to change out the process or physics process with rollback tick. So, let's head back to the player script.
So, in the ready function, set the physics process to false unless you're using it for something else. But in this example, I'm only using it to gather the player inputs and apply it to the ship's position.
So, we'll set that to false and then update it to rollback tick.
And then go ahead and update the function signature with the correct parameters.
And you can see that here in the documentation. And we've confirmed our player's authority over their inputs and we've upgraded the player script to use the rollback tick, which is part of the Net Fox suite. We don't need to include this authority check here anymore. Net Fox will handle that for us. So, let's remove that from this conditional.
And if we look back at what the doc says about implementing the rollback tick, you can see here that they want you to wrap move and slide with these two velocity adjustments. If you are using a character body 3D or 2D, that makes sense you would want to do this.
However, if you look back at our player script, we're using a node 2D and not a character body 2D.
So, we don't have access to that move and slide function. So, instead we use this translate function to move our player on the screen based on velocity times the delta. So, because we're using translate in this situation, we don't need to compensate for the difference in the frame rates between the physics process and Godot's internal tick rate.
So, we can just leave it as is. If you want to learn more about what's going on here, check out the caveats section and you can read more about the character body velocity problem here.
So I think we're all set with the rollback tick function. The next thing I want to do is pull out the input synchronizers because we're no longer going to be using that to synchronize the player's input. We're relying on the rollback synchronizer for that. So remove the references from the input synchronizer from our ready function and our export declaration at the top and then delete it from underneath the player input script. If you run a quick test, you may notice a little bit of jittery and you may or may not depending, you know, if you're running it locally, you may not notice that, but there's a way to smooth it out if you are. And the way that we're going to do that is with this node called tick interpolator.
So let's go ahead and add this to our player scene.
And under the properties, let's put in position.
And that should help smooth out the movement of the ship.
If we follow up with the docs under the smooth motion section, they touch on a technique to help smooth out the motion using the tick interpolator and you're welcome to read more about that here. And there's even a section on the tick interpolator itself.
And this will smoothly interpolate the ship's visual position between the ticks. And before our demo, I noticed an issue. I forgot to put the player input name in front of the input direction. As it stands right now, it's assumed that it's going to be a property of the player script, but it is not. It is a property of the player input. So we need to say player input in front of this.
Now let's do a demo without any latency enabled.
Yep, everything looks good. We didn't break anything. We can move on both clients or peers successfully.
I think the missile size is a little too large, so let me just fix that really quick.
Good, much better size. Sorry for the detour. So now that we have the lag compensation enabled, I think we're ready for a real test with network latency. Let's go back to the NetFox configuration and check the enabled button.
So, now when we run it, we should have about 400 ms of latency.
But, you'll notice or I noticed that the response was immediate. There was no lag here. So, let's try the client here though.
Yes, so before this being peer number two or the client, there would be a lag between when I push the keyboard and when this would move.
But, now it's immediate.
Here, let me let me move the mic close to the keyboard.
I mean, I guess I could be faking this in post, but you're just going to have to take my word for it.
It's almost immediate. And it's immediate on the peer itself, right?
It's on your machine. If this is your machine, you don't see your ship moving on the other person's computer, right?
So, there's always going to be a little bit of a lag there because it has to travel through space and time. But, on your machine, you want to immediately see your ship move without it going to the server and then coming back again and then synchronizing. So, with this lag compensation implementation with NetFox, you can immediately move your ship and have that nice responsiveness. And that's the 400 ms of latency.
Let's change the latency to something a little bit more reasonable, maybe 100 ms. I mean, it's it's bare it's I feels like it's very acceptable. This is a 100 ms lag. I think that's very acceptable if you're trying to build a serious game.
And maybe, you know, up to 400, that's about like you're you're reaching your limits there on what's acceptable in terms of millisecond compensation or latency compensation here. But, I am noticing a little bit of lag or delay from when I hit the space bar to when the actual ships missile fires and I want to address that in a separate video because NetFox actually has another tool called network weapon and I think that's really powerful. So, let's fix that in another video. So, anyways, we've got our latency compensation wrapped up. You can deploy this anywhere. You can deploy this on some dedicated server, in the cloud, or wherever you want to host it and have your friends join and connect to it. You can do a client host peer-to-peer setup where you or one of your friends become the host and all your friends join to you. And I know the guys from NetFox have a tool called Norway and that'll allow you to get those connections up and running.
And also, you can use NoHub, which is another tool that they make, which is kind of a matchmaking thing and it's really lightweight and simple and and we did a video on that a little while back as a just like a general talk about it.
So, check those out if you're looking for a free to get started solution.
Otherwise, it's this should be supported on Steam if you want to do like a client host setup on Steam. I think they're called Steam multiplayer peer and they rolled them into the main proper baseline. I'm pretty sure this NetFox stuff will work with that. I don't know if it's officially supported, but I've tested it before and it's worked great.
So, anyways, you guys are good to go.
You have a great starting point for your latency compensation. You can play with your friends and not have to worry about input lag. And I want to wrap up this series with one more video on the network weapon and how to use that and that will basically take care of the latency issues with firing a projectile across the screen. If there's anything else you guys want to see, please let me know down in the comments. Drop by the Discord. Check out my new game. Stay connected. Thanks for watching.
Related Videos
OpenHuman VS Hermes AI: Who Wins?
JulianGoldieSEO
285 viewsβ’2026-05-29
Long-Running Agents β Build an Agent That Never Forgets with Google ADK
suryakunju
142 viewsβ’2026-05-30
This computer is made from real human brain cells. And you can buy it.
Talktmsmedia
3K viewsβ’2026-05-28
BREAKING: Microsoftβs New Image Generating Model Beat Out GPT 1.5 and Nano Banana 2
aimmediahouse
122 viewsβ’2026-06-03
I Made the Same Anime Fight Scene in Every AI Video Generator
NobleGooseAnime
295 viewsβ’2026-05-30
Nvidia Bets Big On AI PCs | New Chip To Power Windows Laptops | Technology | AI Updates | N18S
cnnnews18
3K viewsβ’2026-06-01
I Tested NEW Opus 4.8 on Four Projects (Updated LLM Leaderboard)
AICodingDaily
298 viewsβ’2026-05-29
3D Platformer Update - NO CAPES
SolarLune
294 viewsβ’2026-05-30











