How to deal with lag in a network game.

Blitz3D Forums/Blitz3D Programming/How to deal with lag in a network game.

WERDNA(Posted 2009) [#1]
Hey everyone!

Things are going pretty good in WERDNA WORLD right now, having
finally made my first online game :)

I have one question though.
How do I account for lag?

The game played perfectly when my 2 play testers played it locally
on their LAN network with each other, but as soon as I started
hosting it, they could join just fine but there were massive lag spikes
every 30 seconds or so.

Changing the code so the network updated every 5th loop, instead
of every single loop seemed to fix most of it, but it was still there
to some extent.

Currently I pack player data into a string, and send it through
sendnetmsg like this.
Function PackPlayerMsg$( p.Player )
Return LSet$( Int(p\x),6 )+LSet$( Int(p\y),6 )+LSet$( Int(p\r),6 )+LSet$( Int(p\typ),6 )+LSet$( Int(p\Pos),6 )+LSet$( Int(p\T),6 )+LSet$( Int(BallNum),6)+LSet$( Int(Ball1X),6 )+LSet$( Int(Ball1Y),6 )
End Function


And then Unpack player data through this.
Function UnpackPlayerMsg( msg$,p.Player )
x=Mid$( msg$,1,6 )
y=Mid$( msg$,7,6 )
r=Mid$( msg$,13,6 )
typ=Mid$( msg$,19,6 )
pos=Mid$( msg$,25,6 )
T=Mid$( msg$,31,6 )
NewBNum=Mid$( msg$,37,6 )
B1X=Mid$( msg$,43,6 )
B1Y=Mid$( msg$,49,6 )
p\dx=(x-p\x)/smoothing
p\dy=(y-p\y)/smoothing
p\dr=(r-p\r)/smoothing
p\typ = typ
p\Pos = Pos
p\T = T
If P\T = False
BallNum=NewBNum
Ball1X = B1X
Ball1Y = B1Y
End If
End Function


Should I split up the data transfers throughout the code, so not
too much at once is being sent?

Thanks,


jfk EO-11110(Posted 2009) [#2]
Do I get this right, SentNetMsg is part of the DirectPlay Network Command Set? I think you maybe better use plain TCP or UDP instead. Spikes, as you described, shouldn't be there unless the connection was interrupted by the provider, or a defect cable etc. Maybe try one of the existing TCP or UDP solutions. Sending packets of a certain size is ok, because if they are too small then there's a handling-overhead. But basicly data should be reduced to the min, of course.

Then there is the Lag of non-LAN connections, around the world. However, Lags are often handled with "dead reckoning" algorithms. So they don't send the players coordinates, but their direction and speed, so each computer can "continue" an other players motion in the most likely way, when there is a lag, and try to display everyones position in realtime. Then, frequently, the positions and esp. the actions are updated, using the players real position and current action/speed etc. But this kind of Lag-fight shouldn't be an issue in LAN only games.


WERDNA(Posted 2009) [#3]
However, Lags are often handled with "dead reckoning" algorithms.


Thats what I was looking for!

Someone came up with a really useful method, similar to what you describe
for dealing with framerate speeds.

And yes, SendNetMsg is part of the DirectPlay Network Command Set.
I might try using TCP, or UDP instead, although I'll play test a tad more
first :)


Thanks a bundle jfk!

And if anyone else has anything to add to his advice, it would be much
appreciated :D


RifRaf(Posted 2009) [#4]
I dont recommend dead reckoning just based off my own attempts with various methods.

I also recommend UDP. there are libraries out there that already handle it very well. Bplay pro 2.0 (2.2 has gnet bugs that can crash randomly), Rottnett (Free), a few others including some DLL libraries that I havent tried.

I recommend sending only position orientation packets and interpolating them. using this you know the players are always in sync and in the correct position across the network. Other methods ive tried were more complicated to sync up.

If you want to see how this method works download my game and try it.

A few tips


1.
if possible cluster your packets.. for example if you have a server-client setup, when the server receives a group of messages.. wait until you check all the messages in that loop and lump all similar together and rebroadcast that rather than rebroadcasting each one as you pass it in the loop.
example of this is to add a byte to your master packet indicating how many
packets were added to the cluster, after you read that loop through the rest of the packet accordingly.
code example
;pseudo netmessage cluster recieve code  
Case movementpack%
 numberof=BP_StrToInt(Mid$(msg\msgdata,1,2))
 offset=3
 For i=1 To numberof
   miscdata=Int(Mid$(msg\msgdata,offset,1))
    offset=offset+1
   pitch#=BP_StrToFloat(Mid$(msg\msgdata,offset,4))
    offset=offset+4
   roll#=BP_StrToFloat(Mid$(msg\msgdata,offset,4))
    offset=offset+4
   yaw#=BP_StrToFloat(Mid$(msg\msgdata,offset,4))	
    offset=offset+4
   y#=BP_StrToFloat(Mid$(msg\msgdata,offset,4))
    offset=offset+4
   x#=BP_StrToFloat(Mid$(msg\msgdata,offset,4))				
    offset=offset+4
   z#=BP_StrToFloat(Mid$(msg\msgdata,offset,4))				
    offset=offset+4
   pid=Asc(Mid$(msg\msgdata,offset,1))
    offset=offset+1
   p.player=FindPlayer_ByNetID.player(PID)
   If p<>Null Then do_somthing here
Next

2.
If you have a twitch game like an fps. You can get away with 5 orientation updates per second (in my testing), but I think if your game is slower you could do between one and three per second, turn based you can send only when actions are taken.

3.
Put a local client check on actions that send data.. For example if a client can only fire when hes not reloading , dont allow the client to send the network command to fire to the server. Even if the server will double check this as well, theres no need to even get to the servers check if you are still reloading. Also add some sort of delay for repeatable actions that require packets sent out. One example could be chat, have a spam check so that players cannot packet flood the server intentionally

4.
Dependable packets should have some sort of resend limit.. dont resend them indefinatly. Kick players that dont send a confirmation packet after x tries.

5.
Compress your packets .. blitzplay lite and rottnett have examples of this. with BP_INTTOSTR() BP_FLOATTOSTR(). in your example you are using six characters per coordinate.. if your coords are always positive you can use two characters, if not you can use four.
If all of you data is positive it would reduce a single packet to only 18 bytes
6.
Dont send everything dependable. Just critical data.


WERDNA(Posted 2009) [#5]
Thanks a lot RifRaf!

That advice was invaluable :)

I'll check out Bplay pro 2.0, and rottnett, but will probably attempt to
write my own.(Not because it would be better, but because it would
broaden my knowledge of network code. I just want to have a solid
understanding of how it all works)


Thanks a bundle!


Rroff(Posted 2009) [#6]
As above you deff. wanna be using UDP - and get to grips with interpolation and extrapolation - typically with network games the clients will be running upto 1 frame behind the most current one they have and intepolating between the latest one and the previous set of data.


RifRaf(Posted 2009) [#7]
a good article that may help you.. if you are using Blitz3D you may want to consider what you can afford to do and what you cannot , since Blitz3D is not as fast as C++, or Bmax. using all the listed techniques might be too costly.

http://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking


WERDNA(Posted 2009) [#8]
Thanks once again RifRaf!(And Rroff)

I'll check this out in a bet, going to be working on my blender lessons right now :)

I just used the DirectPlay commands because they were the easiest
ones to learn. I'll work on both the UDP, and ICP commands next.

Thanks a bundle!


Blitzplotter(Posted 2009) [#9]
a good article that may help you.. if you are using Blitz3D you may want to consider what you can afford to do and what you cannot , since Blitz3D is not as fast as C++, or Bmax. using all the listed techniques might be too costly.


Hmm, I wonder if there has ever been an attempt at a true comparison between apps (i.e.B3D, BMax with miniB3D, C/C++ with how many libs to achieve what can be done with relative ease within Blitz products? etc) performing similar networked functionality. I made some progress with network code within B3D, however the math of trying to correlate vehicles at varying speeds in 2 separate worlds on computers with vastly different hardware eluded me. I opted for a Server/Client variant in B3D messing about at the byte level with 512 byte packets.