Architecture
The overall architecture of the system should be simple, adhere to the DRY principle and be very flexible. The mantra I would suggest is flexibility above design. Because while you are developing a game, anything can happen.
The following diagram shows the current model we aim for. The model only have very few methods mentioned. The actual implementation will drive the details.

Network
We have to decide some network model, here's a list of some models to consider.
Attention, Update. We are going for the Carmac Q3 Model.
Q3 Model
The server stores all changes in the game world, i.e. anything that changes the course of the simulation. This usually only includes input from connected clients, because if on-one does anything, the world will always simulate the same. These changes are stored in a list ordered by time of occurrence. Functioning communication goes as follows:
- Server sends all changes to client which have not been received yet. (When the client first connects, this includes a CreateObject change for all game objects in vicinity.)
- Client executes changes and now has a correct state of current local world (that what is in vicinity) and starts extrapolating simulation until next packet arrives. Client sends an ACK for received packet. (Actually the ACK will be pickybacked as the last received change simulation step number on the change ships controls request).
- Server now knows exactly which timestep client is at. On next transmission, server sends all changes to the world from this timestamp and up to current timestamp.
- Repeat from 2.
- As this loop continues the client continuously sends (every x ms) input events, which are registered as changes on the server.
- Step 2 is a little more complicated. When an ACK is lost, the server will resend old changes along with the newest ones. Therefore, the client will have to ignore any changes which are older then its current timestamp.
- The server need not worry about lost ACKs. Should an ACK not arrive, it will just resend the previous content as well as any new changes.
Client has One Copy of the world, that is confirmed from the server, the rest is simulated using dead reckoning.
See quake network model.
Pros:
- All clients fixed to servers time.
- Good network usage.
Cons:
- Needs a detailed create/change/delete handling for all objects.
Packet design
The packet design should be optimized for network bandwidth, while still be quite flexible, as the actual primitives we would like to sent will change. One packet can contain multiple primitives for the game, and will all be identified be a Header (H) and the actual data (D)
On an abstract level, the info that can be exchanged is the following:
- client connects / disconnects, this might include the player specifying some login info and the server assigning the player a unique id.
- players world influence, basically what the player would like to do with his ship. Perhaps even chat.
- General world changes, enemies spawn, bullets are created, a player dies etc.
- Admin request, it should be possible to do send non game data also, such as restarting the server, or issuing a world save…
- Player ID, in Quake3, experience showed that a unique ID was required since some crappy routers swapped players port behind the same router. An unique ID solved the problem of identifying packages with changing port number.
All packages will look like this
[ID|T|D<T|D>]
- ID is 24 bit identifying the client (either as destination or sender) 24 bits allows more than 16 millions, which is more than enough while 16 bit only allow 65 thousand users, which definitively is to few :)
- T is 8 bit identifying the data, the message type
- D is data of arbitrary length, from T the packet unpacking and packing details are known.
//TODO, Update, this is not the case anymore.
T is split into two groups. Because when using groups, the code detecting whether a primitive will be more simple, for example, the actual handling of the updates can be separated from connection logic, by a few lines of code.
we will use a single byte and let the first 4 bits define the message type, and the last 4 bits some refinement on this. Player world influence and general world influence will be fused.
From this we have restricted ourself to 4^2 (16) message types. Each message type can be refined by 4^2 (16) sub groups.
namespace MESSAGE { // The first 4 bits are the message group. const sf::Uint8 GROUP_BITS = 0xF0; // The next 4 bits are the details refining the message type. const sf::Uint8 DETAILS_BITS = 0x0F; namespace TYPE { const sf::Uint8 CONNECT = 0x00; const sf::Uint8 WORLD_UPDATE = 0x10; const sf::Uint8 ADMIN = 0x20; } namespace CONNECT { const sf::Uint8 CONNECT = 0x00; const sf::Uint8 DISCONNECT = 0x01; } namespace WORLD_UPDATE { // Type field, use logical && with CLASS_FIELD to extract and compare. const sf::Uint8 CREATE_OBJ = 0x00; const sf::Uint8 DESTROY_OBJ = 0x01; const sf::Uint8 SHIP_CONTROL = 0x02; } namespace ADMIN { const sf::Uint8 RESTART = 0x00; const sf::Uint8 SHUTDOWN = 0x01; const sf::Uint8 KICK = 0x02; const sf::Uint8 ETC = 0x03; } }
Model 1
- Server constantly streams the entire (Unreliable communications via UDP) world to all clients. Alternatively the server just sends the world that is visible.
- Clients stream keyboard commands to the server.
Pros:
- Simple implementation.
Cons:
- Lots of network traffic.
- Have to take into account package loss when using unreliable communication (Lower probability by sending many times?, objects auto die after lack of updates??)
Model 2
- Server sends a minimal information about the objects in the players vicinity (Via TCP). (something like [Position, ID])
- Server Streams requested information to clients
- Clients request updates about objects in their vicinity (Stream)
- Clients stream keyboard commands to the server.
Pros:
- Less network usage.
Cons:
- More complicated implementation than model 1




Comments
We need your feedback
Hi Cromozon. I haven't a clue who you are but if you're a friend of u9, you're a friend of mine.
@u9, cool IRC chat!
— hartnell
I think model two is probably the best way to go. :)
I think the Quake 3 model is the one :) I myself am strongly against TCP, while Cromozon is is a little pro-TCP
Yep, I agree. I will make some suggestive packet design.
sounds good.
I'm gonna learn a lot from how you guys make SB, so make sure to include detailed documentation. I'm considering makinga c++ server for an MMO, but the client is a game maker client… that makes things tricky. Anyway, I'm gonna look at what methods you guys use for general communication. No matter what language you are using, some basic principals stilll apply.
By the way, how's SB coming?
Coming along slowly but nicely. We are working only one day a week. We have completely rewritten the network part and hopefully on Thursday we will be able to connect clients again… this time without any limits like we had last time :)
So, how's it going so far? I know it's been a while and we've all been insanely busy…but I hope some progress has been made.
Last week we started changing the packet design so the type not is part of the header, this increases flexibility, but it does take up some more bandwidth, I am really looking forward to se how everything is performing though.
Furthermore we have implemented far more connection states in client and server. ~{CONNECTING, SYNCHRONIZING, SYNCHRONIZED, PLAYING}
The transmission pattern (I have to call it something), is more clean, so reception and transmission is separated. This means that what is transmitted is defined by the state, and not a reaction to a incoming message.
I will soon upload some details about the client<->server connection sequence.
Interesting, if I could understand a bit more about what it meant. :P
Looking forward to the next build, keep up the great work. :)