[ENet-discuss] fps networking

Steve Williams stevewilliams at kromestudios.com
Sun Mar 16 21:05:42 PDT 2008


Games like Unreal and many other FPS games do not generally send inputs over the network.  They send a requested position update, which the server processes, then the server sends back the actual position (after taking into account the requested position updates of all clients and AI characters).  The client takes the actual position, moves its player to that position, and continues.

Client prediction involves the client assuming that the server will agree with what the client thinks might happen, so while the server is processing the requested position update, the client is moving its player to where it thinks it will end up.  When the actual position is received from the server, the client adjusts its players position to match the position the server said it was supposed to be.

This also allows dropped network packets to be handled correctly.  You may see the player jump or snap to the actual position as given by the server after a dropped packet or two, but the positional updates take care of missed packets.

--
Sly


-----Original Message-----
From: enet-discuss-bounces at cubik.org [mailto:enet-discuss-bounces at cubik.org] On Behalf Of Jacky J
Sent: Monday, 17 March 2008 11:56 AM
To: Discussion of the ENet library
Subject: Re: [ENet-discuss] fps networking

Hey Lee i appreciate all the info.  I'm still a bit confused about the
client timestep:

For simplicity, let's say we have a game that has only 8 directions (no
mouse, jumping, etc).

Does the client timestep contain just one move command or does it
contain multiple?  "move command" meaning one of 8 directions that are
applied during a frame.  So for example our game runs at 60 fps, and
we're sending at 20hz. If the server wanted to exactly recreate a
sequence of moves that the client does, it would have to know all of the
directions that were applied at every frame.  That means in our example,
in an ideal world, each client->send() function would send 3 directions
with it. Does this sound right?

Now of course if the client frame rate dropped to 20 fps, it would only
be sending one direction per timestep. But the client wants to be
traveling as much distance as it would if it were running at 60fps, so
locally it would apply some physics update multiple times to make up for
the lost frames.  How does the server account for this?

It seems like in this article they do one move command per timestep:
http://unreal.epicgames.com/Network.htm

Do you have any good examples of source code i could look at?  I looked
a cube but it seems like it was doing the client-side physics method
rather than client/server cosimulation (correct me if i'm wrong).

Thanks again.


Lee Salzman wrote:
> FPS is a spectrum of things you can do, more than a set way. The ways,
> however, are far different from, say, a MMORPG where latency is just
> usually accepted by players: in a twitch FPS game, latency must be
> destroyed at all costs - latency is totally evil, no exceptions. But
> even within the spectrum of FPS networking, each  way comes with its own
> trade-off. They more or less boil down to the following:
>
> Trade-off #1: fixed rate physics, or variable rate physics. You need to
> select a rate at which to run the physics simulation, i.e. 50 Hz, 100
> Hz, etc. Now if  the rendering FPS is higher than the physics rate,
> then you will need to interpolate between two physics steps to have the
> game  not  look all jerky, since if the game is rendering at 100  FPS
> and physics is only simulated at 50 Hz, your view point is only changing
> 50 times a second, so half of those 100 FPS are going to waste. If you
> use variable rate, you still choose a minimum rate at which to run the
> physics, but if the FPS happens to be higher,  then you run physics at a
> higher rate. For example, say, you settle on 50 Hz, meaning each physics
> step is 20 milliseconds. If one frame of rendering took up, say, 102
> milliseconds, then you would do 5 physics steps, and if doing fixed rate
> physics, you would bank those 2 leftover milliseconds for "credit" on
> the next frame. If you are doing variable rate physics, you just go
> ahead and do an extra time step using those leftover 2 milliseconds
> immediately. Fixed rate is probably better if you can just afford to run
> the physics at a high rate these days, and variable rate kinda requires
> the client to be authoritative on physics simulation.
>
> Trade-off #2: co-simulation, totally client-side physics, or lock-step
> simulation.
>
> - In a lock-step simulation, you would just send player input reliably
> to the server, the server would simulate physics, and tell the player
> where everything is at. This is a great evil that should never EVER be
> used in an FPS game because everything requires a silly round-trip that
> destroys twitch gameplay on even modest pings. I only mention it because
> you should NEVER use it. ;)
>
> - Totally client-side physics. Each client just runs its own physics,
> and broadcasts its position at a fixed rate to all other clients (either
> P2P or by sending it through the server which just broadcasts it - the
> server is just a dumb simple broadcaster in this case), i.e. you send
> out your position to other clients say 20 times a second as unreliable
> data. You don't really care if the position gets lost at all, since
> another one is coming behind it right away. On the receiving end, each
> client needs to smooth out the positions it is receiving from other
> clients, since it is much less the rendering FPS. You can do this by
> either buffering one or two steps worth of positions, and interpolating
> between them - i.e. you wait till you've gotten at least two position
> updates from a client, then over some time period (say 50 milliseconds
> if updates are happening at 20 Hz), you interpolate the position between
> them. Another approach is to just send necessary physics simulation data
> (like player velocity), and keep simulating the client locally starting
> from the last position/velocity update you got. These two things can be
> combined, for instance just always simulate the player locally from the
> last time you got an update, however when an update comes in, record the
> different in between the update and the current position (the "snap"),
> and instead of applying the snap immediately, smooth it out over the
> next 50 milliseconds or so. Keep in mind clients are authoritative, so
> you need to take care of cheating by non-technical means (i.e. player
> moderator system).
>
> - Co-simulation. The server and client each run their own corresponding
> loosely coupled simulations. The client runs on the ASSUMPTION its
> simulation is always right i.e. when I shoot, the client assumes I hit
> what I actually did, or if I try to move, the client just moves locally.
> For EACH client time step the client is sending all the input (i.e.
> player movement directions and mouse look) to the server, so the server
> can exactly recreate each time step. This should be done via delta
> compression of an unreliable packet stream to avoid the cost of reliable
> packets. First choose a fixed rate, i.e. 20 Hz. Now every time step is
> numbered, so they form an ever-continuing sequence. So when you send a
> time step to the server, the server knows the sequence number of the
> last time step it got. It sends this sequence number back as a periodic
> ack (unreliable, of course, but best piggy-backed on other
> server->client updates) so the client knows the last sequence number the
> server received (or at least some sequence number less than that in case
> the ack gets lost in transit). Every time the client sends an update to
> the server, it sends all time steps starting at the last sequence number
> the server verified receiving (via that ack the server sent to the
> client), up to the most current time step.  So the client must buffer
> all time steps it is sending to the server, until it has verified the
> server has received them, and is basically just sending this buffer at a
> fixed rate (again i.e. 20 Hz) to the server, removing stuff from the
> front of the buffer as it gets verification the server actually got it.
> If this buffer grows unreasonably large (i.e. some threshold like a few
> KB or more where sending it 20 times a second until the server gets it
> becomes stupidity), you can just "bail out" at the cost of a possible
> round-trip timeout stall by sending the client->server update as a
> reliable packet, and just clearing the buffer (since you know the update
> will get there). You just don't want to use the bail out option on every
> packet, since you want to avoid the latency of reliable traffic at all
> costs. Smart encoding of a time step with a simple run-length scheme and
> you can get the average size of a time step in transit down to only a
> few bits since you may only have one of 8 compass directions, 2D mouse
> coords, and maybe some boolean modifiers like jump/crouch, and certain
> aspects like the direction don't change very fast. Various events like
> shooting , picking up items, etc. should be properly sequenced into this
> same stream as well (but encoded via some exceptional means/special
> prefix since they are uncommon). You just put these in a server-side
> queue for each player, which the server dequeues and runs for each
> player at each of its time steps. If it doesn't have any time step info
> for a client at a particular server time-step, you can either keep the
> client moving in whichever direction he was going, or just have him
> stand there - whatever seems most reasonable, but you give the client a
> "credit" for that time step, so that when more time steps come in over
> the net, you apply them immediately so long as the client has credits.
>
> Now the tricky part. The server then runs its simulation at whatever
> fixed rate you decided along with the client. The server must then send
> out server->client updates on positions/velocities of other clients in
> the world. You can do this by jumping through hoops to do the whole
> delta compression of each other client's input stream to get it from the
> server->client, but this just becomes stupidly complex and hoggish of
> bandwidth (call that Trade-off #3). You are better off just sending out
> the updates from server->client much as you would in the "totally
> client-side" case, i.e. just a simple unreliable update containing the
> positions/velocities of everything, again at some fixed rate like 20 Hz.
> If the update gets lost in transit, you don't care since another one is
> coming soon. However, you want to tag each of these server->client
> updates with a sequence number. So when the client gets an update, it
> knows the sequence number of the last one it got. The client just
> locally moves the physics ahead using its own fixed rate simulation
> (that hopefully works in the same way as the server's, unless the client
> is cheating by modifying it). Now when the client interacts with an
> object, i.e. aims at it and shoots it, it can tell the server ("Okay, I
> shot player Bob, who was at the position stated in server->client update
> #42, from 60 milliseconds had elapsed since that updated, so I had moved
> Bob ahead locally 3 time steps from that position.") The server must
> buffer the results of each time step of its simulation up to a
> reasonable amount of time (say 1 second). So when the server receives
> your shot request, it looks in its buffer for physics update #42 (or if
> this is a time step > 1 second old, just takes the oldest from the
> buffer instead), find Bob's position in this buffered physics update,
> predicts him ahead 60 milliseconds/3 time steps in the SAME EXACT WAY
> the client would have had it got no more updates during those 60
> milliseconds, and then applies your shot to Bob at that position. If you
> are quantizing/truncating numbers to send them from server->client in
> the updates, you must simulate this on the server when pulling Bob's
> position out of the update as well. This way aiming/shooting is
> completely WYSIWYG, no disgusting having-to-lead-your-shots-ahead type
> of gameplay like in various Quakes.
>
> Now there can be some small round-off differences from processor to
> processor, so the simulation between the client and server may drift
> over time. So every  so often the client must either send  what position
> it is at, or the server sends what position it has the client at to the
> client. In either case, you check if they differ by a substantial
> amount, and if so the server sends all the raw/unquantized physics info
> needed to the client for them to sync back up (causing an ugly snap, of
> which the only sane way to hide is interpolation). If you can manage to
> implement the physics entirely without floating point such that there
> will never be any drift and hence no snaps, go for that instead (but
> seems largely impossible in this day and age with more complicated physics).
>
> Hopefully this all adequately confuses you. :)
>
> Lee
>
> Jacky J wrote:
>
>> I'm having a hard time getting my head around some concepts used in
>> first person shooter style games, namely sending user input.  I
>> understand pretty much everything else: client side prediction, object
>> replication, etc.
>>
>> So here are my questions and thoughts:
>>
>> 1. The client continuously sends its input to the server.  This is a
>> packet that might have a bit field for each button or key. For example
>> WASD might take 4 bits, and another few for jump or fire.
>> So how often do i send these packets? Is it on a timer or do i send it
>> as much as the clients presses those buttons?
>>
>> 2.  My biggest concern: What if the client is bogged down to 5 fps,
>> meaning in the best case, the server is receiving those inputs every 200
>> ms.  Surely the server needs to update the client based on the client's
>> own framerate, because if you're moving the player 1 unit per input, the
>> player will move a lot slower if it's updating less per unit time.
>>
>> My initial thought was to send some sort of lastsendtime to scale the
>> player's input, but then it seems like you could cheat and just send
>> really large values to make it seem like you're running at a low fps.
>>
>> What all should i be sending to the server, and what actions should the
>> server be taking based on those inputs?
>>
>> I have a simple techdemo/game setup using enet called godmode.
>> Everything is pretty much set up except for sending client inputs
>> correctly.
>>
>> http://code.google.com/p/godmode/
>>
>> Thanks
>> _______________________________________________
>> ENet-discuss mailing list
>> ENet-discuss at cubik.org
>> http://lists.cubik.org/mailman/listinfo/enet-discuss
>>
>>
>>
>
> _______________________________________________
> ENet-discuss mailing list
> ENet-discuss at cubik.org
> http://lists.cubik.org/mailman/listinfo/enet-discuss
>

_______________________________________________
ENet-discuss mailing list
ENet-discuss at cubik.org
http://lists.cubik.org/mailman/listinfo/enet-discuss




This message and its attachments may contain legally privileged or confidential information. This message is intended for the use of the individual or entity to which it is addressed. If you are not the addressee indicated in this message, or the employee or agent responsible for delivering the message to the intended recipient, you may not copy or deliver this message or its attachments to anyone. Rather, you should permanently delete this message and its attachments and kindly notify the sender by reply e-mail. Any content of this message and its attachments, which does not relate to the official business of the sending company must be taken not to have been sent or endorsed by the sending company or any of its related entities. No warranty is made that the e-mail or attachment(s) are free from computer virus or other defect.



More information about the ENet-discuss mailing list