• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Tonyyyyyyy

Authoritative Server-side Input

7 posts in this topic

After hours of googling and countless re-reads of Valve's networking documentation, I simply can't get it to work. [img]http://public.gamedev.net//public/style_emoticons/default/sad.png[/img]
I implement prediction in my game as follows (I'm probably doing something extremely stupid):

[CODE]
struct InputPacket
{
private byte _id = 0;
bool forward; // > 0
bool forward_zero; // == 0
bool right; // > 0
bool right_zero; // == 0
float pitch;
float yaw;
public InputPacket(byte id, int forward, int strafe, float pitch, float yaw, bool jumpDown)
{
_id = id;
this.forward = forward > 0;
this.forward_zero = forward == 0;
this.right = strafe > 0;
this.right_zero = strafe == 0;
this.jumping = jumpDown;
this.pitch = pitch;
this.yaw = yaw;
}
public Packet CreatePacket()
{
// creates a packet...
}
}
vector3 pastpositions[256];
mainLoop() // 60 FPS
{
if(shouldUpdate) // input is sampled at 30 FPS
{
input.sample();
int forward = 0;
int right = 0;
if(input.forward.down)
forward++;
if(input.back.down)
forward--;
if(input.strafe_right.down)
strafe++;
if(input.strafe_left.down)
strafe--;

// set player input
playerObj.Forward = forward;
playerObj.Strafe = right;
// set player direction
playerObj.Yaw = camera.yaw;
playerObj.Pitch = camera.pitch;
playerObj.ForwardMove = camera.forwardmove;
playerObj.RightMove = camera.rightmove;
}
// goes before because some values may be changed
if(shouldUpdate)
sendMessage(new InputPacket(...).CreatePacket());
// exact same code as the server
playerObj.Update(elapsedTime);
if(shouldUpdate)
{
pastpositions[counter++] = playerObj.Position;
}
}
receivePos(byte id, Vector3 pos)
{
if(pastpositions[id] != pos)
{
// client will interpolate position to match this
playerObj.ServerPos = pos;
}
}
[/CODE]

This works [b]pretty well[/b], except every single time, the prediction is off from 0 to at most, 1 (units). The error increases with ping, and I get around 0.3 units off at 50ms.

After reading the Valve documentation though, it seems that they have it right most of the time. I strongly suspect that what's causing the error for me is that the timing on the server/client may be different.

For example, say the client starts moving at time t = 0, and stops moving at time t = 1. The client thinks it has moved for 1t, and advances the position as it should. However, due to network latency, the first packet may arrive at t=1, and the packet that says "I stopped moving" may arrive at t = 2.25. In the server's eyes, the client moved 1.25 seconds, and thus an error has been produced.

I noticed that Valve includes a duration in their packet, but wouldn't this make the prediction off if the FPS is variable? Seeing as many players don't have a constant FPS, it boggles my mind as to how they rarely get prediction errors.

Even if I were to use the time of the last frame (as Valve states they do), how could I split that time between the player updates? As you can see, my update is sampled at 30 FPS, and my player is updated at 60 FPS, and therefore, I have to somehow intelligently split the time between the extra frames. I guess what worries me the most is that a changing FPS will royally screw over all my guesswork.

Thanks in advance! Edited by Tonyyyyyyy
0

Share this post


Link to post
Share on other sites
Hmm, I am sorry but I am not really getting your implementation.
Are you receiving the position from the client and assuming it is right?
Also, how are you calculating the position? Are you calculating the position assuming the client has a set FPS?

I believe you should be using a time difference approach, this way the FPS would not affect the math at all. I always use something like this:

nextX = currentPos.fX + (cos(angle) * moveSpeed * timeElapsed);
nextY = currentPos.fY + (sin(angle) * moveSpeed * timeElapsed);

This way, assuming the latency is nearly constant, the amount of time you move should nearly the same and you will be in about the same position (a small error is OK). Edited by KnolanCross
0

Share this post


Link to post
Share on other sites
[quote name='KnolanCross' timestamp='1351612582' post='4995458']
Hmm, I am sorry but I am not really getting your implementation.
Are you receiving the position from the client and assuming it is right?
Also, how are you calculating the position? Are you calculating the position assuming the client has a set FPS?

I believe you should be using a time difference approach, this way the FPS would not affect the math at all. I always use something like this:

nextX = currentPos.fX + (cos(angle) * moveSpeed * timeElapsed);
nextY = currentPos.fY + (sin(angle) * moveSpeed * timeElapsed);

This way, assuming the latency is nearly constant, the amount of time you move should nearly the same and you will be in about the same position (a small error is OK).
[/quote]

Hi, Knolan, thanks for the reply!

For input, the server sends [b]only[/b] the keyboard state to the server.
On the client, I multiply the movement vector by the time elapsed since the last frame, and do the same on the server.
Unfortunately, this is where I think the error comes in; the timing on the server and the client may not be exact, and therefore this causes a discrepancy.
0

Share this post


Link to post
Share on other sites
This may be similar to a problem that I had encountered. I noticed that when remote testing over the internet, [i]local[/i] clients were working correctly, however the remote players were experiencing large prediction errors. It became evident that a factor was affecting the simulation. For me, I wasn't easily able to "rewind" physics simulations. For example, prior to becoming aware of the bug, I was simulating inputs in real time as they were received. The problem here is that the upstream latency will shift the inputs on server and client. The client stores them immediately as the current tick, whereas the server may receive and store them several later, resulting in a discrepancy. For me, as I don't have full exposure of the physics system, fixing this involves forward predicting when the inputs will be received by the server, on the client. So that If the upstream latency is 5 game ticks, the client predicts the results of those inputs and stores them on the current tick + latency (5 ticks). For you, as you're working in C++, one can presume that you've more control over the physics steps, you'd send the intended tick number with the input packet, and the server would "rewind" to that state, and simulate for the time step. This would account for any latency.
0

Share this post


Link to post
Share on other sites
[quote name='Angus Hollands' timestamp='1351712706' post='4995921']
This may be similar to a problem that I had encountered. I noticed that when remote testing over the internet, [i]local[/i] clients were working correctly, however the remote players were experiencing large prediction errors. It became evident that a factor was affecting the simulation. For me, I wasn't easily able to "rewind" physics simulations. For example, prior to becoming aware of the bug, I was simulating inputs in real time as they were received. The problem here is that the upstream latency will shift the inputs on server and client. The client stores them immediately as the current tick, whereas the server may receive and store them several later, resulting in a discrepancy. For me, as I don't have full exposure of the physics system, fixing this involves forward predicting when the inputs will be received by the server, on the client. So that If the upstream latency is 5 game ticks, the client predicts the results of those inputs and stores them on the current tick + latency (5 ticks). For you, as you're working in C++, one can presume that you've more control over the physics steps, you'd send the intended tick number with the input packet, and the server would "rewind" to that state, and simulate for the time step. This would account for any latency.
[/quote]

Sorry for this late reply!
It mostly works now, except I get some floating-point issues. In order to make my server frame-rate agnostic, the client sends the "simulation time", which is basically the time that the client used to multiply the movement velocity (V*t) to the server. The server then subtracts 0.166667 from this value each frame (the server runs at 60 FPS) or the remaining value if it is less that 0.166667. Unfortunately, this causes some small floating point precision errors. Add in packet drops (if packet #2 was dropped, when I receive packet #3 i just process #2 with the information from packet #1 and then process packet #3), and the client will slowly become inaccurate.

Is there something I'm doing wrong here? Is it necessary for the client to also send its predicted position, and have the server decide whether the error is ok, and then reset its position to the client's position? Or should the server just be the absolute decider?

Each of my input packets is currently 10 bytes and 5 bits, and adding the predicted position would cause it to be 22 bytes and 5 bits, effectively doubling the original size.
Just for movement, I'd be sending out 5.4kbits/second.

Thanks! Edited by Tonyyyyyyy
0

Share this post


Link to post
Share on other sites
In some respect, I don't know if i can understand entirely the problem, but let me dump my information at you!
Firstly, because I can't rewind physics, i forward store the prediction locally. You may be able to perform rewind physics, in which case that should be prefferable.
Another thing i noticed was a prediction error that I couldn't find the cause for. Essentially, it came from the fact that the client was running at a lower frame rate. It only sampled input every other tick, so when the events were processed back to back on the server, half the displacement was missing (because it moved the clients at the server displacement per tick, rather than the clients. My solution is the scale the displacement factor by the number of ticks between each client packet. This again is sub optimal, but I am forced to use it for various reasons. You may be able to rewind, which again would allow you to avoid this!

Next point.
I don't use delta time in my simultion. I set a standard of ticks. There are game ticks and network ticks. The game ticks are determined from a uniform frame rate (I use the server framerate for obvious reasons). The client and the server both use these to determine when a state was intended for. The network tick rate runs off this, and is basically the frequency at which an event should be sent. Edited by Angus Hollands
0

Share this post


Link to post
Share on other sites
Got a small example (under 1000 lines of code).

needs [url="http://sourceforge.net/projects/glfw/files/glfw/2.7.7/glfw-2.7.7.bin.WIN32.zip/download"]glfw[/url], controls are WSAD, or a X360 controller.

Nothing special, just a client / server app, where the client runs some prediction ahead, the server is authoritative over updates. The server has a small perturbation area that the client is unaware of, thus forcing the client to correct his prediction when receiving server updates in the vicinity of the perturbation.

run the application twice (once for server, once for client).
0

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  
Followers 0