Communication level (protocol.h): Data is exchanged over UDP. The server listens on a port, 5030 or user-specified; clients contact it on this port. Clients allocate a port dynamically; the server learns their address from the incoming packets. Clients communicate only with the server (never direct with each other). There is only one server in a game. So it's a simple star network topology. Each packet contains a checksum (redundant, because IP should already checksum), a packet type, and a gametic (for sequencing). Game negotiation: Clients are pointed to the server and announce themselves with a PKT_INIT. The server is configured at startup with all the game parameters. As each client announces itself, the server replies with a PKT_SETUP which contains all the configuration information for the game. The client then continues through the Doom startup process. When each client is ready to enter the level (enter fullscreen graphics), it signals the server with a PKT_GO. Once the server has a go from all clients, it sends a PKT_GO to all clients to start the game. The clients begin the normal game graphics, and enter the game loop. Game play (client): The server and all clients start at gametic 0. Each client maintains four key values: maketic - the # of the tic being made for this client, based on user input (current mouse & keyboard events are going into this tic) remotesend - the # of the next tic to send to the server remotetic - the # of the tic received from the server, containing player movements from all clients gametic - the tic that the game (on this client) is currently "running" (as all game logic is done locally, this is the tic that all the rest of the code sees, i.e. P_Ticker, the AI, and the rendering) maketic >= remotetic (because the server cannot send us a tic before it knows what _we_ will do in that tic. remotetic >= gametic, because we cannot run the AI for the tic, or display them, before we know what all the players are going in that tic. The client sits in a loop. Every 1/35th of a second, it increments maketic, adds up all the user inputs since the last maketic, and saves this in a ticcmd. If maketic > remotesend, we send all the ticcmds from remotesend onward to the server, and update remotesend. Other than this, the client sits in a loop waiting for tics from the server. When it gets one or more tics, it looks at the gametic they correspond to. If the received data starts at a tic > remotetic, then we have missed some data; it sends a PKT_RETRANS to the server requesting a retransmit starting at remotetic (and discards the out-of-order data). If the received data starts at a tic <= remotetic, the data is buffered, and remotetic increased to the highest tic received. Then, if remotetic > gametic, it runs the new tics for which it has data. It then rerenders the display. Game play (server): The server maintains two values for each client; remoteticfrom and remoteticto. The server does not make tics, or run tics, so it has no need of maketic or gametic. The server sits in a loop. As it receives tics from clients, it updates remoteticfrom and buffers them. If it gets out of sequence data (tics that start at a tic > remoteticfrom) then it discards them and sends back a PKT_RETRANS. The server then goes through all the clients, and works out the number of completed tics that is has: min(remoteticfrom[0 to 3]). Call this lowtic. This is the most recent tic for which the server knows all the player movements. It then goes through all the clients. If remoteticto for the client is less than lowtic, then it sends the necessary tics to that client. Retransmission: If the server receives a PKT_RETRANS, it decreases remoteticto for that client to the specified value (so it will retransmit from that earlier date when it comes to sending). If the client receives a PKT_RETRANS, it decreases remotesend, so it will retransmit all tics from the specified value when it comes to sending). In other words, the retransmission system copes with packet loss by requesting a retransmit when it receives data starting at a later tic than it expected. It will not do clever resequencing of data, and it does not detect lost packets unless some later packets get through (so you kill a network game if you pull the cable out, even if only for a second). Out of band data: Some extra packets are needed for sending extra data, client quits, etc. These are distinguished as different packet types, and are sequenced using the gametic in the packet header. There is no reliability guarantee for these packets - no reliable retransmission as there is for tics. We get away with it, mostly.