Sign in to follow this  
PolycountProductions

How should "player A shot box/ground/player B/enemyY" handled in multiplayer game?

Recommended Posts

Hi, I'm working on my multiplayer code, and have currently approached the network issues by having a bit similar idea that Quake 3 uses (http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/Quake3Networking). I use UDP: client are sending inputs to server, server is updating the world and sending packets containing state info to clients - and so far things work pretty nicely. I can adjust health, positions, player classes, carried objects etc. but there's still bit mystery when it comes to shooting stuff. Currently I have class called 'netobject' which state's are put in a packet that's sent to client. Netobject can be things like 'building', 'box', 'player' etc. Anything there is in the world. For health/movement/stuff-mentioned-above I use 'object state'. When object is at position A, and has health N - then it's easy for clients to set up the values after getting state updates from the server. (1) I wonder how shooting objects should be done? Should it be tied somehow into 'user input'? or 'object state'? Or perhaps some sort of 'event message'? Or what? I was considering doing some sort of 'event' messages, that would be put inside packets. In these events one could say that "player A is shooting from location X/Y/Z and hits object 'ground' in location X/Y/Z at time [millisecs]" Then clients could ACK these events, and server would keep sending them until they are ACKed (or perhaps after certain period of time they could be deleted: no point sending info that 'player A shot something 3 seconds ago'.) (2) I haven't decided whether to give client authority over shooting (I'm making a cooperative game, so cheating wouldn't perhaps be that big issue, and it could mean better performance for clients even with slower network), but that's not a big deal. Either I (a) send client input to server, which will tell from which position the client really shot stuff, or (b) I will tell server (when sending input packet) from which location the shot was done, and whether it hit something. Just want to mention this here. (3) What about throwing objects? Or picking up? Would it make sense to do 'throwing event' or 'picking up event' kind of messages as well? Currently I do 'picking up' so that I change the netobject state ('netobject A is attached to netobject B') and when client receives the 'netobject A's state, he can immediately attach the netobject to B if it isn't already attached). Picking up could be handled with events, but not sure if 'events' is reasonable thing to do in a first place. Help me out people. How would you suggest handling shooting (and for example throwing) things? I'm especially concerned on my question #1. (Oh, and my game is not super-fast paced FPS, but rather a top-downish view pretty-fastish done shooting game where you also barricade and pile up stuff - and kill zombies :))

Share this post


Link to post
Share on other sites
I would just use it as a Object State, just update it every time the player shoots, something or someone

I would set the shooting like this

Client: Can I shoot this?
-Sends Packet-
Server: Sorry that's a Wall
-Sends Packet-
Client: Oh ok how about this?
-Sends Packet-
Server: Sure can here is the [XYZ]
-Sends Packet-

Basicly the Server just keeps the Shootable values on the server an the client just asks whether or not it can be shot or thrown at.

Don't get mad at me if this is not what you were looking for or if I completely just screwed up lol, I know the theory behind the thing not how to program it directly =p

~ARC

Share this post


Link to post
Share on other sites
Hmm, I'm afraid this approach would kill the bandwidth. Consider player who is shooting with a machine gun... there would be just too many packets to send (...and anyways, I'm sending max 20 packets per sec)

Thanks for the help though.

Share this post


Link to post
Share on other sites
the way quake3 works on that subject is prediction and server corrections. Clients stack their inputs and send them to the server, who reconstruct the client movement / aim. Then the server can detect if a client accurately shot something or not. if the client movement is invalid (i.e. client bumped into another player), the server sends a correction packet, and the client rewinds his stack and playback the inputs from there.

to combat packet loss, clients send duplicates of inputs. Look at gaffer's article on networked physics.

[Edited by - oliii on October 23, 2008 6:14:11 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by oliii
the way quake3 works on that subject is prediction and server corrections. Clients stack their inputs and send them to the server, who reconstruct the client movement / aim. Then the server can detect if a client accurately shot something or not. if the client movement is invalid (i.e. client bumped into another player), the server sends a correction packet, and the client rewinds his stack and playback the inputs from there.

to combat packet loss, clients send duplicates of inputs. Look at gaffer's article on networked physics.

Thanks oliii.

So everything is input based? State + inputs => new state + inputs => and so on...

I think in Gaffer's article it was mentioned that you will ignore old input / dropped packets. Basically, would this would that if guy who shoots 5 times (like frames 1-5), and 1 packet is dropped, first packet arrives too late, then server will update only the 3 shots?

Still not sure how those '3 shots' should be told to other clients? If server send a world state snapshot, then it means server is not sending state for every frame - but rather for example once per 5 frames (or similar). If client shoots 5 times in 5 frames (and 3 shots are successfully got by the server), then server's snapshot will contain only the latest state ("5th frame", not "frames 1-5") which server broadcasts to clients. <= End result would be that client who shot 5 times could see 5 shots (since it can predict the result), server would simulate 3 shots, but the rest of the players would see only 1 shot since the server's latest state.

Or... would it mean that server also ties 'user input' commands into these state messages, so that the other clients can run the 3 (successfully got) shooting inputs?

Share this post


Link to post
Share on other sites
Quote:
Original post by PolycountProductions
Still not sure how those '3 shots' should be told to other clients? If server send a world state snapshot, then it means server is not sending state for every frame - but rather for example once per 5 frames (or similar). If client shoots 5 times in 5 frames (and 3 shots are successfully got by the server), then server's snapshot will contain only the latest state ("5th frame", not "frames 1-5") which server broadcasts to clients. <= End result would be that client who shot 5 times could see 5 shots (since it can predict the result), server would simulate 3 shots, but the rest of the players would see only 1 shot since the server's latest state.

The state is not whether someone has fired during that frame. That's an instantaneous event, which changes the state. The state itself would include all projectiles in the environment, in this case 3 of them. If the projectiles don't typically live long enough to appear in a state snapshot, either you need to update more often or you just treat them as instantaneous events that need propagating independently.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kylotan
The state is not whether someone has fired during that frame. That's an instantaneous event, which changes the state. The state itself would include all projectiles in the environment, in this case 3 of them. If the projectiles don't typically live long enough to appear in a state snapshot, either you need to update more often or you just treat them as instantaneous events that need propagating independently.


Thanks for the help. I'm not quite sure how those events should be treated on the client side though...

Let's suppose one bullet lives for 1 frame (instant hit), and let's suppose that during 50 millisecs period there's 3 bullets. State update that occurs at 50 millisecs, so basically server does the shooting of those 3 bullets.

Next, in these 'world state snapshots', server would include '3 bullets' ("shots by player A from position P to position T at time N" etc.)

How would client then treat this info? He gets the snapshot, updates the world, and then realizes that "3 bullets were shot within the last 50+lag milliseconds". Would it mean that client would just simply launch all bullets simultaneously from correct positions, meanwhile the player character is running 1 meter (the distance he can move in 50+ milliseconds) away?

(I'm reading source networking over and over but I'm missing something :) - the movement alone sounds understandable, but the moment shooting begins, I start to wonder how it should be done to get those events play correctly.)

Share this post


Link to post
Share on other sites
Quote:
Original post by PolycountProductions

(I'm reading source networking over and over but I'm missing something :) - the movement alone sounds understandable, but the moment shooting begins, I start to wonder how it should be done to get those events play correctly.)


You can't play them correctly since everything has already happened. You try to show something reasonable.

To validate correctness, instead of inplace simulation advancement, server keeps track of past states. So whenever simulation is advanced by one tick, you store old state and keep it around for a while. After all clients have been shown to have advanced past a certain state, you can discard it.

When player's action arrives, you find when that action was triggered, then find matching old state at that time. Then, calculate everything based on that state. If needed, restart entire simulation from that state to update for changes (may lead to warping or other inconsistencies).

Meanwhile, client may choose to simulate actions regardless of whether they are valid or not (showing blood, bullets, etc.), but not getting the results. So shooting something will show damage on screen, but it will take a while until this damage is applied (or it may be simulated, and later compensated/confirmed after server gives its ok).

This model isn't entirely accurate and may not even be entirely fair under certain circumstances, but it's simple and relatively light-weight.

When it comes to displaying other players' actions, one way is to speed up their time to catch up with local view. So if you receive actions from a player that is 200ms behind, you could replay all those actions over 20ms. This isn't accurate, but tends to keep things reasonable.

Sometimes, actions that can be performed are designed with this in mind (time between shots, projectile behavior, etc.).

[Edited by - Antheus on October 24, 2008 8:39:34 AM]

Share this post


Link to post
Share on other sites
The client is just a console, that only send a stream of inputs to the server, who has full authority on everything.

What the client can do is predict events.

1) He thinks he fired 10 bullets, so let the bullet fly on the client, except they will not produce damage, they are just for show. Similarly, he thinks he moved to the right, then let him move to the right instantly.

2) When the server received the command 'move right', he will move the player right if he can. If the player cannot move right (blocked), then a correction packet is sent to re-sync the client.

the case 1) can be demonstrated in Counterstrike. You have a special command that stops client prediction on gun firing. That's what really happens on the server side when you fire your gun. If you allow prediction, your gun will fire normally, *but* what you shoot may not be the same on the server. Hence the glitches such as firing through walls, shooting someone but it's not registering (at least straight away), ect...

The case 2) can also be demonstrated in CS. If you bump into another player, you will see yourself wobble about, this is the server correction kicking in. This is because you cannot predict accurately the position of OTHER players on clients and server.

all this is done via stacking inputs and client-side predictions on the client, sending those inputs and predictions to the server to be verified.

The server re-runs those inputs locally, and compare the predictions with what he calculated.

If there is a mismatch, he sends a correction packet.

Client receives the correction, apply the correction to the offending state, and re-calculate his states stored in his stack from that point forward.

Share this post


Link to post
Share on other sites
Yeh, I'm aware that client is pretty dumb and 'thinks' what occured.

Number #1 is clear, no problem with that...

...but what about if there's server + two players. How can player A know when player B was shooting (think the '3 shots' example above)?

Thanks again!

Share this post


Link to post
Share on other sites
That is done via 'proxies', or if you will, a client-side player 'avatar'. This is outside the realm of the prediction / input system.

What the server does, every tick, is send the state of every players to every other players. The server would probably not sent a proxy state update of yourself to you, as you don't need that (the input prediction correction will take care of your state).

Then, everyone knows what everyone else looks like.

However, these proxies on clients are sort of like cardboard cut-outs, they don't do much apart from looking like they are shooting, jumping, animating. Their real interaction is done on the server one. They do have a purpose on clients,for collision detection (and that arks back to player predictions and corrections).

Their state is interpolated of course, to cover for the low network update rates.

These proxies are very innacurate. It could be that the player shot three times, but it could look like on your machine he shot 4 or 5 times. Most of the times, this doesn't matter so much. It's a 'glitch'. These glitches can usually be fixed ad-hoc, they usually become very application-specific.

Similarly, due to interpolation, latency, simulation 'running behind', the position of the player would be quite innacurate if that player moves fast, and different on the three machines concerned (the shooter, the server, the victim, all positions will be slightly different at a point in time).

This doesn't matter so much as all the damage and aiming and bullet trace is calculated on the server, that has a pretty accurate representation of the game at a given simulation time.

But you can also see those position glitches, when you have to lead your target significantly to do any damage.

Share this post


Link to post
Share on other sites
If the case is that I fire 5 shots in different simulation frames, and one is too late, and one is dropped, then the following will typically happen:

The original player, firing 5 shots, will see five shots firing, will hear five shots firing, and will see blood spattering from 5 shots hitting. These are all local, client-side effects.

However, if there's a health bar or similar, then the actual state of that authoritative data will be updated by the server, and propagated back to the player. Thus, the health bar will be reduced by the impact of 3 shots -- and the display of the health bar will be delayed by one round-trip time.

Any other player will see/hear only three shots firing, and only three impacts. Or less, if the connection from the server to the other players is lossy as well. However, the authoritative state should be eventually consistent in some sense -- the health bar should be made to match the server's idea of the number of hitpoints of the player/target even if individual packets are lost.

Share this post


Link to post
Share on other sites
Sorry if I'm able to express myself clearly, and thanks for help (I really appreciate this), so there's still bit mystery:

Quote:
Any other player will see/hear only three shots firing, and only three impacts. Or less, if the connection from the server to the other players is lossy as well. However, the authoritative state should be eventually consistent in some sense -- the health bar should be made to match the server's idea of the number of hitpoints of the player/target even if individual packets are lost.

I realize that updating player attributes (and then packing this information in the sent tick) is fine: I can adjust player health from 80 to 50 and all the players will get this info at some point.

But in case of 'three shots', how should this info be packed in world state updates? Is it some sort of event that will be done when clients receive the info? What if the latency is close to 100 ms, some players could be able to shoot 2-3 times, and when other clients receive this info it would sound like one player is shooting 3 shots during one frame?

Bottom line is: what kind of information is put in the packet when server broadcasts 'player A shot 3 times during the last 50 ms'? (and how will clients run this info so that it wouldn't sound like player A made 3 shots in one frame, but rather so that player A shoots 3 times - but in different frames)

Share this post


Link to post
Share on other sites
Quote:
Original post by PolycountProductions

Bottom line is: what kind of information is put in the packet when server broadcasts 'player A shot 3 times during the last 50 ms'? (and how will clients run this info so that it wouldn't sound like player A made 3 shots in one frame, but rather so that player A shoots 3 times - but in different frames)


When you replicate an object to client, use some form of dirty value tracking. When any of the shared values change, mark them as dirty for all clients. When you send state to any client, clear the dirty flag.

On each network update tick, search which properties are dirty and send them to client. Depending on the latency, some clients might be receiving more updates than other. For health, one might receive (-10, -10, -10) while another will receive (-30).

For shots, it's similar. Every action confirmed by server is forwarded to all clients (or just subscribed/inside AOI). Just send a message of some form indicating what happened.

Quote:
and when other clients receive this info it would sound like one player is shooting 3 shots during one frame?


Unless you're Marty McFly, you're stuck with accepting that everyone else's world is 100ms in the past and you cannot change it. The article I linked discusses this problem.

You can:
- Play 3 shots simultaneously
- Play others' actions with fixed delay
- Replay the delayed actions in compressed time
- Something else, specific for your particular design

Do whatever will make most sense visually.

Share this post


Link to post
Share on other sites
A simple way would be to serialise the ammo. What's in the gun, and what's in the reserve. Then you can count how many shots you need to fire to reach the same ammunition count. That will probably wont work great when the player picks some up.

Share this post


Link to post
Share on other sites
Quote:
Is it some sort of event that will be done when clients receive the info? What if the latency is close to 100 ms, some players could be able to shoot 2-3 times, and when other clients receive this info it would sound like one player is shooting 3 shots during one frame?


No, because you don't know that there will be another shot when the first shot is fired. You'll just send out the event "one shot fired during tick X." The next shot fired, if it's three ticks later, you'll send out the event "one shot fired during tick X+3." The server will just immediately forward the events to each client when they come in, so again, the server doesn't know there will be any additional shots after the first shot.

My description was of what the aggregate experience would be for the players watching the exchange. At the event level, you just replicate and forward events for the interaction (firing a shot) one at a time, in a reactive fashion.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this