Networking code

Everything related to the code /
Tout ce qui touche au code
Post Reply
User avatar
AF
Administrateur - Site Admin
Posts: 139
Joined: Thu Dec 28, 2006 8:19 pm
Location: NW UK
Contact:

Networking code

Post by AF » Thu Dec 13, 2007 3:39 pm

Obviously UDP, but for the networking code itself I would suggest we use auswaschbars UDP classes in spring as a starting point. In the last few months the spring network classes have been subject to heavy refactorign and cleaning up by him with the aim that they're portable enough to be moved out into a dedicated server program so autohosts don't have to handle the spring game rendering and simulation and can just handle the traffic itself.

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Thu Dec 13, 2007 5:35 pm

hm interesting, this can be useful indeed.

Currently we only have a working TCP class (which should handle both IPv6 and IPv4) which has been successfully tested on Linux and windows with IPv4.

I'll have a look at Spring's networking classes.

As far as UDP & TCP are concerned, UDP is faster, so it'll be used for time critical stuffs but it's not "reliable" (you don't know if the data you send have been received or not), so for sync critical stuffs, TCP should be better (ie: a unit death cannot be skipped otherwise the game will lose synchronization).

We could use TCP for chat, sync critical events, file transfer, etc... and UDP for normal syncing.
=>;-D Penguin Powered

User avatar
Balthazar
Moderator
Posts: 2055
Joined: Wed Nov 01, 2006 4:31 pm
Location: Russian Federation
Contact:

Post by Balthazar » Thu Dec 13, 2007 6:27 pm

Hmmm... smells like fresh multiplayer support :)

User avatar
AF
Administrateur - Site Admin
Posts: 139
Joined: Thu Dec 28, 2006 8:19 pm
Location: NW UK
Contact:

Post by AF » Thu Dec 13, 2007 9:51 pm

TCP is fine unto you realize that if anyone in the game has a router or uses a network the whole thing falls apart.

Springs UDP classes should also handle packets not arriving.

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Fri Dec 14, 2007 1:15 pm

and there is no routing problems with UDP ?

Also, yes we should handle packets not arriving with UDP.
=>;-D Penguin Powered

User avatar
AF
Administrateur - Site Admin
Posts: 139
Joined: Thu Dec 28, 2006 8:19 pm
Location: NW UK
Contact:

Post by AF » Fri Dec 14, 2007 7:12 pm

Indeed you have similar issues with UDP but there are better solutions.

For when port forwarding and direct connections are not options, hole punching and UPnP are available whereas hole punching is not possible with TCP.

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Fri Dec 14, 2007 8:27 pm

hm, I didn't know that, it could be useful.
=>;-D Penguin Powered

western
Posts: 27
Joined: Tue Mar 06, 2007 8:12 pm
Location: FRANCE, Toulouse

Post by western » Sat Dec 15, 2007 2:40 pm

I disagree to use only UDP protocol for communications. Like I explained in another topic, the UDP packets could be lost and this is a "normal" behaviour. We must guarantee that all important exchanged information is received. We can use UDP for sending some information less important but, except if I missed the topic, we did not define the exchanged information, the architecture (server-client? p2p? etc.). Before the choice of the used communication protocol, we need to define the exchanged data and following the volume of and importance of information, we decide the protocol and the architecture


Best regards,
"same shit, different day" Stephen King's book "Dreamcatcher"

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Sat Dec 15, 2007 2:56 pm

UPnP also works with TCP, so I don't see any problem to use TCP.

I agree that we'll need TCP for things that need to be received (unless we find something better but really I doubt we will).

So what kind of data do we need to send and how ?

Since every client will be running the simulation for its units and weapons, there is no privileged machine that could be a server more than another client.

So I think a p2p network would be better, with the possibility to use a "fast node" to relay data from clients that have low bandwidth.

The data we need to send are exactly what Cire described earlier and the same thing for weapon data.
=>;-D Penguin Powered

User avatar
AF
Administrateur - Site Admin
Posts: 139
Joined: Thu Dec 28, 2006 8:19 pm
Location: NW UK
Contact:

Post by AF » Sat Dec 15, 2007 7:25 pm

A p2p tcp system si worse for NAT issues.

Combined with the fact UPnP is turned off by default in routers for security reasons, and hole punching doesn't work with TCP. That and most games use UDP anyway, and packets that don't arrive can be re-requested, otherwise TCP wouldn't work at all (Afterall they both have the same problem at lower levels of the network stack).

The content of the network itself shouldn't be affected by this though as either way the transport method is rather irrelevant the data will still be the same.

sieistganzfett
Posts: 13
Joined: Wed Nov 21, 2007 2:38 am
Location: America
Contact:

Post by sieistganzfett » Sat Dec 15, 2007 8:48 pm

computer that "hosts" the game that the others join is automatically the server of it in a general sense since they picked a lot of the settings for the game such as map, metal, energy, etc.. easier to program and troubleshoot all the clients if they sync to that 1 computer that started the game than all of them syncing data to all the others like in P2P. its a waste a bandwidth, and wouldn't it be more work to do P2P than client/server? only thing is for players more than 2.
if player that hosted game loses, and quits, "server" must be passed to the next computer (in order of joining? the game)

for data: wouldn't it be just syncing the arrays that already exist from when a game is single player, between all the computers? then add on chat? things i think that must arrive on time are
unit position
unit health
unit location
chat
weapon location (where a emg or laser or rocket, etc. is currently)

things that should arrive but if they didnt arrive wouldnt cause balance problems but simply graphical issues are
unit direction
unit scripting such as turret direction
weapon direction
Last edited by sieistganzfett on Sat Dec 15, 2007 9:06 pm, edited 1 time in total.

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Sat Dec 15, 2007 8:57 pm

western wrote:I disagree to use only UDP protocol for communications. Like I explained in another topic, the UDP packets could be lost and this is a "normal" behaviour. We must guarantee that all important exchanged information is received. We can use UDP for sending some information less important but, except if I missed the topic, we did not define the exchanged information, the architecture (server-client? p2p? etc.). Before the choice of the used communication protocol, we need to define the exchanged data and following the volume of and importance of information, we decide the protocol and the architecture
Best regards,
Please do not take this as an attack against you as its not what I mean, but you obviously have very little knowledge of network programing. As already started UDP traffic isn't guarenteeed, and thus some type of ack would be needed, it is however smarter to use UDP then a straight TCP, because TCP often becomes blocked, and dealing with blocking in code isn't pretty.

Its much more faster/smarter to do something like:

Tick:
dirty units-> distrubute and send data:
client 1, client 2, host

wait:
client 1 sends back ack
host send back ack

host signals that its ready to goto next tick:
we report to host that client 2 hasn't responed to our data sent
host orders us to send again, we do so, in which case:
client can respond or not, if not we could route data through client 1, or host to client 2, once ack is received we move to next tick

now with tcp blocking, it could remain blocked for a very short time, or upto 2 or 3 minutes and thus timing out, once blocked nothing can be sent throught it or read from it, doing so 'locks the thread up', checking constantly if a socket is blocked is slow, and also more steps in the process that aren't needed. There is no way to 'unblock' a socket once blocked except a) closing and reconnecting (often done in browsers and what not but not in a game). b) waiting for it to become unblocked.

Suppose the host says to client 1, and 2 its time for next tick, but client 1s socket is blocked, the game then goes into a wait state for client 1s socket to unblock, or we simply contine the game and hold everything in a buffer to send to client 1 once it becomes unblocked (YUCK!).

TCP traffic for game commication layers using critical data is a BIG BIG BIG mistake that will come back and bite you in the ass.

++Cire.
Females: impossible to live with, most powerful money reducing agent known to man, 99% of the time they drive us insane; yet somehow we desire to have as many as we can.

sieistganzfett
Posts: 13
Joined: Wed Nov 21, 2007 2:38 am
Location: America
Contact:

Post by sieistganzfett » Sat Dec 15, 2007 9:15 pm

its possible to just use UDP to check that the things arrive using a programed ACK back and forth rather than the built in ones from using TCP, if a computer doesn't respond in 10 seconds, its gone from the game. if the computer didnt get any of the data for 10 seconds during a huge base raid, and they come back, half of their units will be dead like magic, but so would half of the other players instantly when connection re-established.

to take it a step further, i think only chat, unit health, and game time need to be verified with an ack. if there are no Acks on those, the other computer is unlikely to have received anything else, but will eventually "catch up" once they receive the new current data.

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Sat Dec 15, 2007 10:24 pm

unit direction (and body orientation) is critical if some event happens like the unit shooting, so I suggest we sync those events from the client that runs the elements that generated them.

For example:
2 clients A & B.

on A a unit is firing, A sends this information to B and also tells B that a WEAPON object has been created by A and gives all required details (weapon type, position, speed, ...). Then B receives the packet, it put the unit in firing position (but don't tell it to fire actually) and create the required WEAPON object with all the required properties.

There should also be the tick counter on packets, so when a client receives a sync packet:
1) the packet is in the future -> tells others to wait, or slow down a bit, then put this information on a stack, it'll use it when it reaches the packet tick
2) the packet is in the past -> simulate the evolution of the data received to reach current tick
=>;-D Penguin Powered

User avatar
AF
Administrateur - Site Admin
Posts: 139
Joined: Thu Dec 28, 2006 8:19 pm
Location: NW UK
Contact:

Post by AF » Sun Dec 16, 2007 12:46 am

syncing the game state can be problematic as it could require bandwidth and thus pauses in game play while the game state is transferred.

Spring hashes the state of units and then compares hashes sent to the server, and then the server tells clients if they aren't synced.

Someone else suggested on the spring forums that instead unit orders be sent and critical events such as unit creation and death.

User avatar
Balthazar
Moderator
Posts: 2055
Joined: Wed Nov 01, 2006 4:31 pm
Location: Russian Federation
Contact:

Post by Balthazar » Sun Dec 16, 2007 9:36 am

Cire - you are awesome as always :) People, hear what this guy say, he know how to do it right!!!

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Sun Dec 16, 2007 11:23 am

The problem with syncing orders given to units is that syncing must be perfect, exactly the same on every client, because a small rounding error could make a unit chose one path over another ... and thus change the whole simulation. Since path are often refreshed, syncing them would require lots of bandwidth. Syncing only required data per unit should be ok.

let's say we have a game running 2000 units and 5 players, each player has 400 units, if you need to send position, speed and health updates for units, you'll send 400 * 7 * sizeof( float ) = 11200 bytes per synced tick if you send floats. Now there are 30 ticks per second ... so we can only sync 10 ticks per second like in TA, and syncing only events for non fully synced ticks. So you need to send 44800 (4 * 11200) bytes per tick if you sync position, speed, and health every 0.1 sec. . We don't need to send what we can compute, so let's say we can compute position and that speed won't change for half of the units (you have buildings, and units moving at full speed ...), and that speed can be computed as 1 float and a short int (speed and direction).

If you do the same for health, then you'll send less than 40 health updates per tick, and you need to send 40 * sizeof( float ) + 200 * ( sizeof( float ) + sizeof( short ) ) = 1360 bytes x 4 = 5440 bytes per tick x 10 = 54Kb/sec.
Unless we can broadcast the sync data to everyone the server will need 54Kb/sec. upload bandwidth, whereas clients will need 5Kb/s.

Of course there are data we'll need to send that are not taken into account here : weapons, events, ...
=>;-D Penguin Powered

User avatar
AF
Administrateur - Site Admin
Posts: 139
Joined: Thu Dec 28, 2006 8:19 pm
Location: NW UK
Contact:

Post by AF » Sun Dec 16, 2007 3:13 pm

you dont need to send all the unit data just a hash representing the units state. This immediately pushes it down to an integer per unit. The check doesnt have to occur every frame. Then we can also just check sync every second or 2 seconds.

The idea is you only resync when the game isn't synced, and rather than continuous resyncing you just check the game states. You don't need to know the exact positions, you only need to know if they're different.

On top of that all simulation should be synced anyway so rounding errors are a bug. This is why tobi went to such effort to deal with this in spring with using streflop and messing with fpu stuff.

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Sun Dec 16, 2007 3:47 pm

well the point is you don't send anything unless it's needed, so for each unit you compute a hash and put it into an integer (we won't use floating point values for the hash, only integer approx) but you do so only if you think others can simulate the data, if something changes (you give an order to one of your units) then you'll need to sync explicitly the data, otherwise you only wait for others to tell you they need to sync because their hash is different.
=>;-D Penguin Powered

Post Reply

Who is online

Users browsing this forum: No registered users and 20 guests