🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Predicting Over-Time Skill from Single Input

Started by
4 comments, last by TryBoo 2 days, 4 hours ago

Where I'm at

2D MMO Unity game with client/server networking architecture (server is also a headless Unity instance) containing only basic movement. My early/simple approach has worked thus far:

  • Client and server operating on fixed tick rate
  • Client sends movement input to the server and predicts movement locally
    • Predictions stored as [input → amount moved]
  • Server receives/buffers inputs and processes all on next tick
  • Server uses snapshot approach where it sends entire game state to each client with the client specific last processed input
  • Client receives and performs reconciliation
    • Throws away any predictions before last processed input
    • ‘Replays’ remaining predictions after given server state and checks if the same, if not adjust to server position

Note: No timestamps or ticks are sent from the client yet. Just an input number and the input itself.

What I'm trying to do next (including the problem)

A ‘dash’ skill that lasts several frames from a single input. i.e.

  • Client taps dash skill and begins ‘dashing’ over the next 10 seconds/ x number of ticks
    • On every tick until the skill is complete the client stores a prediction
  • Client sends dash skill input to the server
  • Server receives dash input sometime later and also begins dashing for next 10 seconds
  • Game snapshots being sent out every tick with the current player position
    • Last input received has not changed though since it stemmed from a single ‘dash’ input
  • Client receives updates, but does not know which dash related predictions to throw out

What I've Tried

OK, I've thought of some ways I could solve this if input is locked during the skill

  • Send some sort of ‘dash progress’ info about how much of the dash is complete from the server to client

But, I've lost determinism if another input occurs. i.e.

  • I jump in the middle of the dash which occurred on tick x of the dash
  • Server receives jump input, but if the server and client and even a little out of sync in terms of processing the fixed tick rate, the jump may take place at different point during the dash which would produce a different outcome.

I could also:

  • Include a timestamp in the packet about client dash start time then start the skill on the server at the point where the server believes the client is. But, this feels wrong since the client will snap to a spot on the server if we have a lot of latency. The server will always have a brief ‘catch-up’ since it receives client input late. Is this normal?
  • Syncing server/client tick rates using RTT/2 (the ‘Overwatch’ model I believe). I then store locally the predicted time the dash will be received by the server (client always a but in future). But, this seems overkill for the game I'm trying to create.

What I'm Looking For

Help with resources about how to solve such a problem (or with my problem specifically if I managed to explain clearly enough :P. I'm making a simple Top-Down 2D MMO w/ PVE Only so I don't need advanced rollback for player fairness or anything (yet). I may be overthinking the situation, but can't seem to find any resources about this type of ‘over-time’ prediction.

Advertisement

In almost all theses cases, you end up needing a shared clock of some sort (e g, “game tick number since start of world” or something) and a mapping from “local clock walltime” to “game tick number” for ordering events.

Every ability should then be expressed as “if my state starts at tick X, and it's now tick X+D, here's my evolved state.” For most efficiency, evolution shouldn't involve any other actors/entities, so forward playback is fully deterministic, but if you have to do collision detection against entities, you'll need to simulate one tick at a time.

Some other observations:

  • “MMO” and “Unity for server” aren't a great match-up, as Unity limitations will limit how large your server-side instance can be.
  • “MMO” and “snapshot” isn't a great match-up, either, because many entities times many snapshots means much network choke. You're probably better off baselining and only occasionally correcting.

enum Bool { True, False, FileNotFound };

Thanks for the confirmation that I’ll need a shared/synced clock to accomplish this type of prediction. A follow up concern that I'm unsure how to handle:

  • Client starts the 5 second dash skill’ at Tick X and sends input to server.
    • Client continues predicting movement for next 5 seconds.
  • Server receives dash input at Tick X + (let’s say latency) 5.
    • These inputs will always be received for past ticks?
  • How should the server process the dash given the latency?
    • Should it ‘catch up’ to the client by immediately processing 5 ticks?
      • If we do ‘catch up’ won’t the first 5 ticks of a dash look sped up for remote players even if we’re interpolating? I’m unsure if this is acceptable or what's an acceptable way to handle it.
    • Should I predict based on the average latency the tick that the server will receive the input and mark that as the tick in the packet?
  • What about intermediate inputs? If I get a jump input during the dash? I get I need to timestamp it now, but do I need to retroactively jump on the server at the same past tick and replay to get the same deterministic result?

Also thanks for the additional observations:

  • Ok, for now maybe I’ll diverge from a true MMO approach and just have instances with a max of let’s say 20 players. This involves more learning than I expected so I’ll swap server technologies if I ever make something more robust in the future. Using Unity for server will at least keep that part familiar for now and lessen the learning burden.
  • Interesting note about the snapshot approach. I heard games like Apex Legends use snapshotting so figured it was easier and more efficient than individual packets for every network entity. I guess a true MMO could require magnitudes higher requirements than a battle royale with max 60 players in a game.

There are a couple of “standard” solutions.

The first is to have the client run their local actor simulation at timestep (global time + L) where L is the transmission latency from client to server. This in turn splits into two: Do you show “other objects” also simulated up to client time (e g, predicted and possibly wrong) or do you show other objects in their own time frames (e g, delayed compared to the client.)

The second is to not actually start the physical effects until the server has had time to see it. So, every effect is built with some kind of acknowledgement or wind-up initiation. This is very common in RTS-es – “yes, sir!” – and spell casting (fancy light shows) as well as fighter games (telegraphs/wind-ups.)

enum Bool { True, False, FileNotFound };

Interesting. I believe the compromise I’ll make is for movement (including movement skills) I’ll try to be predictive, but for anything else I wont. It’s fine for me (for now) if a fire skill shows an animation immediately for a client, but doesn’t show damage until the server tells me.

If you wouldn’t mind clarifying the first solution, what would my client to server packets say about my input timing?

  • Is the tick in the input packet the T + L ? So we are predicting what time the server will receive it and the server actually applies it at this time? If it arrives late it just gets processed immediately (or too late It gets thrown out)
  • Is the tick still T and packets always arrive “late” and we somehow adjust? This seems like it would involve some type of rollback and replay on the server to remain deterministic.

Advertisement