🎉 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!

Fighting Game Over Network

Started by
14 comments, last by NetworkDev19 4 years, 9 months ago

Hello!
I want to make an online game using libGDX and kryonet. For the last two days I have been studying all sorts of concepts for creating online games. Server reconcillation, Interpolation between two states on the client side are understandable to me now. But there are two things that I don’t understand to the end.

The first is the lag condensation. To quote Gabriel Gambett https://www.gabrielgambetta.com/lag-compensation.html:

  • When you shoot, client sends this event to the server with full information: the exact timestamp of your shot, and the exact aim of the weapon.

  • Here’s the crucial step. Since the server gets all the input with timestamps, it can authoritatively reconstruct the world at any instant in the past. In particular, it can reconstruct the world exactly as it looked like to any client at any point in time.

  • This means the server can know exactly what was on your weapon’s sights the instant you shot. It was the past position of your enemy’s head, but the server knows it was the position of his head in your present.

  • The server processes the shot at that point in time, and updates the clients.

Ok, basically everything is clear. But this moment: "Since the server gets all the input with timestamps, it can authoritatively reconstruct the world at any instant in the past. In particular, it can reconstruct the world exactly as it looked like to any client at any point in time.". I do not understand how to implement this. Clients send timestamps to our server along with events. But after all, clients clocks are not synchronized. How can I understand from a given timestamp what state I should roll back the world to? I can only roll back that particular client, right?

Ok, my second question is how to implement animation over the network? My game will use regular sprite animation (Animation class from libGDX). It is clear that it is impossible to synchronize it between two clients. But how do I interpolate the animation of another client? What data should be transmitted over the network for this?

Thanks.

Advertisement

Another problem occurred to me:
Suppose player 1 fires a fireball at player 2 and locally player 1 detects a collision of a fireball with player 2. Should I in this case play an animation in which player 2 flies off? Suddenly, the server decides that there was no collision with the fireball? Then I will have to abruptly stop the animation of player 2 flying off and make everything as if there was nothing, right? This cannot be avoided, can it?

Maybe I don't need to send timestamp from client but rather calculate this timestamp based on current ping? This is approximation of course. It look like this:

received_input_timestamp = curr_server_time - ping / 2

Then I will have a globally ordered events. But this way I can't perform batching of events and only allowed to send one input :/

I will have a frequency of updates on the server and a certain number of snapshots (the more - the more accurate, let's say I keep 30 global snapshots in memory for the last second), ordered by server time when they were made. Then, if I get another input from the player, I can find the closest snapshot for this event and apply this event in the context of this snapshot. This will solve the lag condensation problem I think. The biggest problem is of course

Quote

find the closest snapshot for this event

Please tell me how to do this. Or maybe there is a better solution?

On this link:

Source-LagCompensation

There is such formula:

Command Execution Time = Current Server Time - Packet Latency - Client View Interpolation

Can you explain me please what is Client View Interpolation? Is this some constant tunable in Source Engine? I mean, if our server do 30 snapshots a second and sends them to clients, then Client View Interpolation will be 1000 / 30 = 33.333ms, cause client interpolates other players states within this interval, right?

The GGPO implementation of server-authoritative time with replay on clients, works great for fighting games, because fighting games always have wind-up animations, and don't have "hitscan" weapons (like sniper rifles with raycast bullets.) Also, fighting games generally have cheap physics, just two skeletal characters, and thus can easily run X frames of simulation per visible frame.

For hitscan weapons, you need to know the round-trip time to each player, and calculate the position of each "foreign" entity at the time the client shot, as well as the position of the "client" entity that's doing the shooting -- the "foreign" entities run at time T-DELAY when the client runs at time T+DELAY. (Delay is the one-way delay in each direction -- on some kinds of internet the downstream delay is different from the upstream delay. Sadly, it's very hard to measure this difference, so you typically end up with RTT/2 as an estimate.)

 

enum Bool { True, False, FileNotFound };
37 minutes ago, hplus0603 said:

The GGPO implementation of server-authoritative time with replay on clients, works great for fighting games, because fighting games always have wind-up animations, and don't have "hitscan" weapons (like sniper rifles with raycast bullets.) Also, fighting games generally have cheap physics, just two skeletal characters, and thus can easily run X frames of simulation per visible frame.

For hitscan weapons, you need to know the round-trip time to each player, and calculate the position of each "foreign" entity at the time the client shot, as well as the position of the "client" entity that's doing the shooting -- the "foreign" entities run at time T-DELAY when the client runs at time T+DELAY. (Delay is the one-way delay in each direction -- on some kinds of internet the downstream delay is different from the upstream delay. Sadly, it's very hard to measure this difference, so you typically end up with RTT/2 as an estimate.)

 

Thank you for answer! Yeah, I already read your post about GGPO, but didn’t understand what it is, what architecture it has. Maybe there are some examples?

The more I think about how to implement this game, the more I want to give up :(

I was just thinking about a problem like event ordering. Most online games don’t send every event to the server, right? Instead, they collect a batch of events and send it in single packet. But how does the server understand in which order to execute the events of two users when calculating a new snapshot? I mean, there can be a causal connection between the events of two players. Everything would be so simple if it was possible to synchronize the clocks of clients :(

Maybe you can somehow use the logical clocks?
I also wanted to ask how accurately it is practically possible to synchronize the clocks of two players? And constantly adjust them according to server time and ping? 50ms? 100ms?

hplus0603 Don't you know whether it is possible somehow to introduce global order (or at least causal order) on the events coming to the server from the players? By causal order, I mean that if the action of player 1 somehow affects player 2, then on the server this action must be processed earlier. Thanks.

I apologize for this endless stream of questions, just for me it's all very new. I have experience creating single games, but multiplayer is a completely different matter.
I did come to some kind of model. Firstly, I am going to synchronize the clocks of two players as described in this thread (I hope this will give me about 100ms accuracy):


Thank god Kryonet provides an opportunity to know RTT.
All local updates on the client, such as client-side-prediction and another player state interpolation I will do in the main game loop using:


Gdx.graphics.getDeltaTime()

Which returns me number of seconds (float) elapsed since the last frame was drawn.

The player also collects all keyboard events, processes them and attaches a label to each of them when this event occurred. Once in a while (say 10 times per second), the client sends all these events to the server (asynchronously).

The server collects all these event batches from all the players and puts them in an ordered collection (BST). Once in a while (probably it should be 10 times per second, as in client, right?) It runs throughout the collection in order of events and applies them to the previous snapshot of the system. After he ran the entire collection, he swaps this snapshot with the previous (since we don’t have hitskan weapons, we don’t need to store previous snapshots, right? Punching is not considered a hitskan attack, right?). After that, he sends a snapshot to each of the players and attaches this same time stamp. And when the player receives this snapshot, he again corrects his time, corrects his state (server side reconcillation), interpolates another player state and everything repeats in a circle.

Please tell me if I think correctly?

This topic is closed to new replies.

Advertisement