I’m not looking for any code here just some high level discussion. Unless you happen to have a link to an example already.
I’ve taken a look at the shooter game example, which I believe does not do lag compensation on the server when computing shots.
I’ve seen some examples of network movement with client side prediction using UCharacterMovementComponent.
Usually to do lag compensation the server needs to keep a series of snapshot locations. Plus its useful if the server computes the same interpolation between snapshots that the client would use, and rewind to that interpolated state when detecting a shot.
Just using UCharacterMovement only covers the movement with client prediction and reconciliation. We could make the server also record snapshots. However the tricky part is knowing how to properly rewind to snapshots on the server. This is becuase all the movement of other players in the GS.e is hidden behind an abstraction and we don’t really know how the interpolation is done on the client side. I assume it’s using entity interpolation and not ded reckoning.
I was wondering if some light could be shed on this. We would need to provide a timestamp when the shot was fired to the server and know how to properly map that back to a snapshot which matched the client’s state/interpolation when the shot was fired.
I’ve been able to implement this from scratch on unity (I implemented the prediction, reconciliation, interpolation and lag compensation), which we could do here as well. But I was wondering if it would be possible to still leverage the built in networking tools like UCharacterMovement and also have lag compensation shooting.
It’s certainly possible to compensate for the Latency, but depending on how many projectiles you have it can start to eat through memory and performance saving snapshots of all projectiles in the scene. CMC gets away with it because typically you don’t have that many Characters, it might be better to try a different approach depending on how you’re going about it. Additionally, Projectiles typically move so fast and have such short lifespans that is just plain isn’t worth all the hassle, since the end user is likely to see or feel no real difference at all providing the rest of the implementation is solid.
A really good resource for this IMO would be Unreal Tournament, which has implemented a pretty fancy Projectile system that seems to be incredibly reliable (which you can expect, since Pete / Steve are Multiplayer wizards). A brief overview of the system is that the clients spawn a ‘Fake’ projectile, which then blends to the same data as the ‘real’ projectile when the client receives it’s data from the server. The upshot of all this is that the client sees their shots instantly and it looks as if there is no latency, and since the client tells the server where they fired the projectile from and in what direction, there is usually only a minor discrepancy between the real and fake projectile.
Just that system alone merged with ShooterGame should be enough to provide a really good implementation.
If you want to go deeper, UT also they also occasionally bounce a packet from the client to the server and back again, so that each client knows what it’s ‘Prediction Time’ is (essentially half of RTT), and it uses that value to compensate for and offset received data. The prediction time is stored per-player in the Controller/ Player State I believe so that all actors can easily get to it.
To do this in unreal I would probably want to write my own interpolation code (or at least understand/rerun the interpolation done under the hood mh the UCharacterMovementComponent) for how other players move in the world so that when I do rewinding kn the server that I account for the client side interpolation of player positions. And as you said you’ll want to rewind projectiles as well.
I was wondering if that is possible to be able to access that interpolation code and possibly interpolate to specific positions on the server.
An interesting question. Here’s another idea (untested, would love to when I find some time for it) based on the assumption that characters (pawns) are close to accurate using UCharacterMovementComponent and with that basically re-utilizing that data/prediction/interpolation. I am not sure about the additional performance cost on the server though. But it seems to be fairly simple to implement.
On the server you could simply pretend that each player fired their weapon every tick (if they have ammo, have a weapon equipped, etc.) then store the trace hit results but do not apply any damage or other effects yet. After half of RTT seconds have passed (or a little bit more than that just to be safe RTT didn’t suddenly jump up), the results will not be needed anymore and can be removed again because the player did not fire their weapon at that time, otherwise we would have received a function call outlined below.
On the client when the weapon firing is triggered, notify the server about it for example with a function [reliably] replicated to the server (and simulate all effects locally).
On the server when you receive such a function call find the predicted hit results for (current server time - half RTT) and apply damage and effects using those hits now.
Given the initial assumption that characters (pawns) are close to accurate using UCharacterMovementComponent holds, predicted shots should be close to accurate as well. By simulating effects locally when replicating the fire function call effects are also instant for the client. You could send “actual” location/direction of the shot (what the client thinks) with the replicated function and check that against the predicted shot on the server to make sure the difference is small. If it’s not small enough you could do “something special”. If it’s not small enough for most of the time or even always our assumption unfortunately is wrong. But do/should you trust client data? That’s a story for another day
Hi UnrealEverything. That is an interesting approach, to fire a fake shot every server tixk and save state about it, then apply it, if you receive information about a player actually pressing the button in the future.
However, I do see a major flaw in this design. Normally when you rollback to previous snapshots, you don’t actually do it for the shooting player. Note: from the clients perspective when you interpolate other players you see all other players in past locations (maybe 100-200ms delayed) and you are in your present location.
So with your approach you don’t actually know the correct location of the shooting player when you fire the ‘fake shot’. You need to receive their inputs first, move them to the correct location on the server, then fire the weapon (with all other players rolled back to a previous position which reflected where the shooting client was seeing them when the shot was fired)
You should look at UT again. It’s implemented in it.
In fact, they are saving all player position, when you shoot with “lag compensation”, they take the position of all the players at that moment and check for a hit. Be aware that UT is using capsule only collision, so if you want perfect mesh it, you will need to work with another data than just position.
I tried once to save the Physic object so because you can trace against it, but I was not enough aware of how it works to do a proper solution. The saving was too slow and took to much memory. but this was good for a perfect hit compensation approach.
The approach was to check a Capsule collision, followed by a trace on the HitCompoments (Player Mesh Physic bodies). So if you save Position + Bodies, you can have perfect accurate instant fire.
If you found a way to save this object and you are willing to share your findings, it will be a good tutorial for everyone.
For the projectile, UT approach is really good one. it’s really great when you played and the code is rocking solid.