best practice for multiplayer linetrace.

I hope I’m understanding this correctly. If I have a few clients and one listen server and the one client shoots and hits an enemy. Which is the best practice for multiplayer:

  1. I do the line trace on the client, figure out which enemy is hit, and then send the result to the server, where the server can then take off the health or destroy the enemy.
  2. I send my character’s details to the server, and do the line trace and everything else on the server.

For the first one, I wonder if someone can create a hack to just send destroy signals to the server to destroy everything.
For the second, I worry that, on a listen server, there is a slight delay, so the client shoots and hits the enemy on his pc, but on the server, the enemy has moved a fraction, and so the shot misses. I also worry that this is putting more of a load on the server?

100% day one cheats if you use this for shooting.

Never Trust Client Actions or Passed Data in a Multiplayer setting.


Where you see a player on your screen is a position in the past. ALWAYS!!! Even on LAN.

When I input a movement that action happens immediately on my screen. The input is then buffered in a SaveMove along with my current states, location, rotation, velocity. At the start of next Update Send (client → Server update) that move and any other moves, actions, rpc’s etc, that happened in the last update interval are bundled together and sent to the server.

For clarification, ALL client inputs, actions, rpc’s are bundled and sent together at regular intervals. None are sent on input, or when processed. Only at defined update intervals.

Server receives and waits for the next tick start to process the data. Start of tick it simulates the moves, actions etc. Start of next tick it bundles the new moves, states, velocities, actions, RPC’s etc and sends the packet. Net Flush

New packet arrives for other players. Next tick start they process the moves → Game thread, then its passed to the render thread. From there the simulation is rendered to the monitor.

Note: Game Thread is usually 2 frames ahead of the Render Thread.

For this example we are going to use a standard 30/60 model.
Server tick: 30Hz (33.333ms interval)
Client update rate [client → server]: 60Hz (16.667ms interval)

Normal Inherited Delays

  • Waiting on next Send (16.667ms max).
  • 50% of ping to reach server. say I have 50ms ping (25ms travel time to server)
  • Waiting on servers next tick to process (33.333ms)
  • Processing and Simulation (33.333ms)
  • Travel to Opponent. say his ping is 100ms (50ms travel time)
  • Client processing the packet data. Times vary client to client, but lets say 1 client frame.
  • GT is 2 frames ahead of RT… 2* avg frame time
  • Monitor refresh rate delay… varies

Network and server processing delays alone is roughly 141.666ms. At a minimum this is how far behind your view of my character is.

For example If I was to input a jump it would take 141ms +++ before you see the first frame of that jump rendered on your screen.

Now step back a second. We are talking Milliseconds! Average human blink time is between 300-400ms.


Now lets look at a standard multiplayer shooting model. Client-fakey, Server Auth.

Client fires locally for responsiveness. Local trace/projectile, visual fx etc.
Client Trace/Projectile only effects the local simulation. Impact plumes, decals, audio. Nothing is replicated. No damage is calculated, or applied.

Upon firing locally an RPC is executed to have the server fire.

Server steps through logic to determine IF it can fire (has weapon, is equipped, has ammo etc etc etc). If so, it executes its own trace/projectile spawning/pooling based on values it derives.

e.g. Client and Server execute the same function to derive camera Location and Forward vector for the trace. Nothing passed from the client is used.

Server Trace/Projectile determines hits and damage. These are not replicated.

For hitscan the server will Multicast the Trace Start and End vectors. The multicast Event will conditionally check that only Simulated Proxies can execute the rest of the events logic. The condition prevents the server and Owning Client from executing the code. Only the copy of his character (sim proxy) on other clients will execute.

Something like this…

For projectiles you’d send the Aim Vector, or a Projectile Velocity vector, or a Transform depending on the way you use projectiles (Initial Speed or Velocity).

image

Sims trace/projectile hits would apply the impact plumes, decals, audio on all other clients.

This approach replicates the bare minimum of data.

Client RPC’s server to fire. Server does its own localized thing, then Multicasts a few vectors to sims.


Looking back at delays.
With the above model the server should be firing pretty quickly depending on ping. If using hitscan (traces) the shot is an instantaneous hit. So the only delays that are really relevant are Pings. Anything under 100ms there shouldn’t be any issues where the client hits and the Server denies.

If you plan on supporting pings over 100ms you really need to look into Rewind Time Lag Compensation. You’ll have to code this yourself. Lag Comp is not built-in feature.

For Projectiles you either go with Rewind Time or teach your player base to lead shots on moving players if they have a high ping. This is a Ping issue, Not a game issue.

Personally I think anything over 60 ping in a shooter is a high ping. The higher that number gets, the more desync your players will experience. Hits/Death behind cover etc and so forth.

Hope this helps.

2 Likes

Thanks Rev0verDrive. Man, this is probably one of the best replies I’ve ever had. There is just so much info packed into here. I’m going to go through it a few times to make sure that I don’t miss anything. Thanks so much for taking the time to explain. That makes a lot of sense.

2 Likes

:+1:

Glad it was helpful.