Evan Todd

Network system description

As promised. :)

First, a small disclaimer. This network system is designed for a very specific task: handling networked physics/gameplay over a LAN network. The structure described here might be useful in other scenarios, but the actual Python code is certainly not fit for much else.

The system follows a modified Model-View-Controller pattern that focuses on two main types of objects: Entities and Controllers. The "View" part is split between the Entity and Controller. Entities handle most of the assets tied to a standard object in the game world: namely, the physics geometry and graphical representation. Each Entity has exactly one Controller, which handles all (and I mean all) actions the Entity can perform. The Entity will not move at all without a Controller.

Two objects manage all the Entities and Controllers: the EntityGroup and the NetManager. There are no separate versions of these classes for client or server mode; they behave similarly in both instances. The advantage of this design is that clients can behave like the server in some ways. Certain Entities, such as a client's player character, are designated as being in "server mode" on the client. So, the player's Controller simulates everything on the client machine, and sends update packets to the server, which then forwards the packets on to all the other clients. The client machine can also spawn Entities if necessary, such as when the client player throws a grenade.

Each Controller has two update functions, one for server and one for client. The server update function accepts a network packet as a parameter, to which it adds its own data. On the server machine, the NetManager calls the server update function on all of the controllers, and broadcasts the resulting data packet only if enough time has elapsed since the last broadcast. (Packets are limited to under 30 FPS.)

Now, the server update function doesn't actually do anything to its Entity. It just packages up its data (which may be different for different types of Entities) and sends it off to the NetManager. So for anything to happen on the server machine, the NetManager must also process its own data packet that it just sent out to the clients, as if it were a client itself. In a way, the server is connected to itself as a client, although it is completely in software.

The client update function accepts a read-only data packet, from which it reads all the Controller data. It handles all client-side effects (for example: lighting, sounds, and sparks from gun shots). The data packet is an optional parameter, though. When a packet is not available, the client update function simulates the Entity to the best of its ability. Of course, on the server, the client update function gets a data packet every single frame.

Client-side prediction is not done at the moment, but all it would take is to advance the physics world a small amount after receiving a server update packet. You can check out the source code here: http://sourceforge.net/projects/stainless/develop. Most of the network functionality can be found in net.py, entities.py, and controllers.py.