Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualTonyyyyyyy

Posted 31 October 2012 - 08:17 PM

After hours of googling and countless re-reads of Valve's networking documentation, I simply can't get it to work. Posted Image
I implement prediction in my game as follows (I'm probably doing something extremely stupid):

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;
}
}

This works pretty well, 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!

#3Tonyyyyyyy

Posted 29 October 2012 - 10:11 PM

After hours of googling and countless re-reads of Valve's networking documentation, I simply can't get it to work. Posted Image
I implement prediction in my game as follows (I'm probably doing something extremely stupid):

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;
}
}

This works pretty well, 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!

#2Tonyyyyyyy

Posted 29 October 2012 - 10:11 PM

After hours of googling and countless re-reads of Valve's networking documentation, I simply can't get it to work. Posted Image
I implement prediction in my game as follows (I'm probably doing something extremely stupid):

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;
}
}

This works pretty well, 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.

Is it really just guess work?

Thanks in advance!

#1Tonyyyyyyy

Posted 29 October 2012 - 10:09 PM

After hours of googling and countless re-reads of Valve's networking documentation, I simply can't get it to work. :(
I implement prediction in my game as follows (I'm probably doing something extremely stupid):

struct InputPacket
{
    private static byte _id = 0;
    bool forward; // > 0
    bool forward_zero; // == 0
    bool right; // > 0
    bool right_zero; // == 0
    float pitch;
    float yaw;
    public InputPacket(int forward, int strafe, float pitch, float yaw, bool jumpDown)
    {
	    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;
}
}

This works pretty well, 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.

Is it really just guess work?

Thanks in advance!

PARTNERS