|
Author Topic:   Networking
Kaeto
Member
posted November 04, 1999 05:42 PM            
Just how the heck is it that you do networking. I have no clue about how to get data from one machine to the other. If you can tell me that, I can write a server to deal with lag.

IP:

Kaeto
Member
posted November 06, 1999 02:00 PM            
Please?

IP:

LDA Seumas
unregistered
posted November 06, 1999 03:49 PM           
Networking is a big topic...

There are two layers to Tread Marks' networking. The lowest layer is a highly encapsulated class I wrote which handles all of the low-level aspects of networking. It uses WinSock 1.1 with UDP datagram packets only, and it handles connections, disconnections, combining multiple mini-packets from the app into larger UDP packets for transmission, prioritization of Unreliable mini-packets, data rate limiting, re-transmission and acknowledgement of Reliable and Ordered Reliable mini-packets, hostname lookups, and boolean version checking through configurable connection challenge keys.

The next layer is intertwined with the game code, and only uses the above class as a low level service provider. The guts of the in-game networking are comprised of a set of BitPacking and BitUnpacking classes, which make it easy to stuff integer and floating point variables into any number of bits you like in one continuous bitstream, and functions for sending or not sending (and prioritizing) Unreliable packets based on their distance in world space from each client player's tank. The latter means that if an Unreliable packet is sent somewhere on the map, it is much more likely to actually get sent to clients who are physically close to it, and much more likely to be dropped for clients that are distant. This is why when playing Tread Marks as a client you'll often see distant tanks pause and then jerk ahead; that's their packets being dropped since they're too far from you.

If you're wondering about the actual implementation with WinSock, it's not too hard. Just initialize WinSock 1.1, create a socket, optionally bind it to a port number (needed if you'll be listening for connections on it), and for UDP, I'd recommend configuring it to be a non-blocking socket and then start using sendto() and recvfrom() to transmit and receive datagrams. For TCP, you'll probably want to spawn a thread to wait for connections, and then spawn more threads (or use select()) to handle each connection.

One thing about ports: A socket's bound port number is the port it receives data on _only_. Any socket on any port can _send_ a packet to any other port on a destination computer. This is with UDP, anyway. In that way I only need a single socket bound to one port on the Server side of Tread Marks, even when handling tens of clients at once. The beauty is that recvfrom() gives you a completely filled out address structure, with IP address and port number, telling you who the packet was from. So to send a reply, all you need to do is send back to that IP and port, and it will go back to the correct recipient regardless of their port number or address.

------------------
-- Seumas McNally, Lead Programmer, Longbow Digital Arts

IP:

Kaeto
Member
posted November 08, 1999 03:18 PM            
thanks. I'll look into it. I had thought winsock was a major pain in the butt but hey, i'll give it a try

IP:

Freeside
New Member
posted November 10, 1999 06:49 PM            
Just curious as to how you handle reliable packets using UDP? Do you just timeout if an ACK isn't received and then resend the packet? Seems like that is a bit of a pain when you also have to have ordered, reliable packets.

I wrote something similar for TCP and wanted to add a UDP implementation.. TCP did use non-blocking and select calls btw..


Also, from your post it didn't sound like you were doing any client side prediction yet?


IP:

LDA Seumas
unregistered
posted November 11, 1999 08:27 PM           
Right. At the moment I use a fixed 1-second timeout on reliable packets, so if an ACK isn't received within 1000 ms, the packet is re-sent. Ordered delivery is a receiver side issue, and it's not that hard; the receiver just has to queue the received packets in a linked list until the "next" packet by sequence number has arrived and can be delivered to the application.

I am doing full client side prediction of tank movement. Notice how even with lag, your tank should respond almost instantly to your control inputs. Opponent tanks are predicted as well, which means that if you aim and fire as if you were on a LAN, you should hit your target. Projectiles are lagged, so they will appear late, and will appear to hit the enemy tanks "where they were", rather than where they are.

------------------
-- Seumas McNally, Lead Programmer, Longbow Digital Arts

IP: