New method for determining control object state dirty checked in
by Mark Frohnmayer · in Torque Game Engine · 03/26/2002 (3:36 pm) · 2 replies
Hi all... I just checked some changes to the way that GameConnection determines when to send new control object data (via the control object's writePacketData/readPacketData pair). Previously, the client and the server versions of the object were required to call the setControlDirty() method on ShapeBase whenever the object was acted upon by forces that the other side of the connection was not aware of.
This had several noticable problems... first, there were a bunch of places this had to be called, and not all of them were obvious. Second, there was (and still is) a bug somewhere, either due to math rounding differences, imprecise object positions or something, that was causing the client and server player position computation to get desynched. To fix this in T2, I introduced a lame hack fix - in GameConnection I forced update of the control object state once every 16 packets (ControlStateSkipAmount = 16) even if it wasn't dirty.
The initial solution I hit upon was to have the client send the full state of the control object to the server with every packet, after it had done its move computation, and if this differed from the server's version after applying the move list, the server would update the client with the correct control object state. However, given that the client can transmit up to 32 packets per second to the server, and that the vehicle control object state is upwards of 100 bytes, this would be an unacceptable burden on the client's upstream bandwidth.
To get to the point... what I added was a getPacketDataChecksum() method to GameBase. When the client sends a packet to the server, it sends a 32-bit control object checksum. The server, before it sends a packet to the client, check's the server object's checksum against the last one it received from the client. If the two differ, the server sends the full control object state back to the client.
This may affect your control object code! I've added a version of getPacketDataChecksum() to ShapeBase that XORs the position x,y,z and mount information, but it's possible that that may not be enough. As I was typing this I also realized that it is possible for the server to send the client an update packet before it processes the moves it received from the client, and in those cases it would always report an error, so I'm going to fix that. (This problem can also cause the server to seem to lag badly when firing instantaneous projectiles).
If anyone feels like a challenge, try tracking down why the server and client get desynched in the first place...
This had several noticable problems... first, there were a bunch of places this had to be called, and not all of them were obvious. Second, there was (and still is) a bug somewhere, either due to math rounding differences, imprecise object positions or something, that was causing the client and server player position computation to get desynched. To fix this in T2, I introduced a lame hack fix - in GameConnection I forced update of the control object state once every 16 packets (ControlStateSkipAmount = 16) even if it wasn't dirty.
The initial solution I hit upon was to have the client send the full state of the control object to the server with every packet, after it had done its move computation, and if this differed from the server's version after applying the move list, the server would update the client with the correct control object state. However, given that the client can transmit up to 32 packets per second to the server, and that the vehicle control object state is upwards of 100 bytes, this would be an unacceptable burden on the client's upstream bandwidth.
To get to the point... what I added was a getPacketDataChecksum() method to GameBase. When the client sends a packet to the server, it sends a 32-bit control object checksum. The server, before it sends a packet to the client, check's the server object's checksum against the last one it received from the client. If the two differ, the server sends the full control object state back to the client.
This may affect your control object code! I've added a version of getPacketDataChecksum() to ShapeBase that XORs the position x,y,z and mount information, but it's possible that that may not be enough. As I was typing this I also realized that it is possible for the server to send the client an update packet before it processes the moves it received from the client, and in those cases it would always report an error, so I'm going to fix that. (This problem can also cause the server to seem to lag badly when firing instantaneous projectiles).
If anyone feels like a challenge, try tracking down why the server and client get desynched in the first place...
About the author
#2
setControlDirty is still used (haven't cleaned it out yet), but in ShapeBase it stubs out to nothing.
In other news, I just checked in another fairly major change to the network processing that actually ended up pretty completely getting rid of the desynching problem. The server and client now will only send packets after a tick has occurred. This should also have the effect of decreasing the percieved latency when doing things like firing weapons, since before the server could receive a packet with a trigger and send a packet back to the client before the trigger was processed and a projectile created.
If you see any major problems with this, please let me know.
03/26/2002 (6:59 pm)
Yup, kinda, yup and yup.setControlDirty is still used (haven't cleaned it out yet), but in ShapeBase it stubs out to nothing.
In other news, I just checked in another fairly major change to the network processing that actually ended up pretty completely getting rid of the desynching problem. The server and client now will only send packets after a tick has occurred. This should also have the effect of decreasing the percieved latency when doing things like firing weapons, since before the server could receive a packet with a trigger and send a packet back to the client before the trigger was processed and a projectile created.
If you see any major problems with this, please let me know.
Torque 3D Owner Joel Baxter
Seems like we will likely need to create more specific getPacketDataChecksum functions for our control object classes... for example, if there was a rotating turret that could be player-controlled, we'd need to include rotation angle in that class's checksum.