Skip to content

Network mechanics

Alexander Grund edited this page Jan 11, 2016 · 6 revisions

Basics

The network code with the GameFrames (GF) and NetWorkFrames (NWF) works like that:

  • GF (happens every n ms):
    • Advance Simulation/Game by one step
      * not directly influenced by user action, e.g. no new building added or new flag set
    • Increase GF number
      later (in the GameLoop):
    • Collect GameCommands (GC)
    • Possibly save game
  • NWF (happens before every nth GF):
    • Wait for GC-Message from all players (happens only when a player lags)
    • Execute 1 GC-Message from each player, record those GCs to replay and discard that Message (Here new buildings etc. are placed)
    • Send all accumulated GCs as new GC-Message to server (which forwards it to all players)
    • Clear list of accumulated GCs to start new collection

So obviously

  1. GCs are executed with a delay of 1-2 NWFs
    (maximum if send right after a NWF -> Wait 1 NWF till it is sent to server and 1 NWF till it is executed)
  2. Each client must send an (empty) GC-Message at the start of the game
    (or the game would wait forever on the next NWF)
  3. The length of a NWF must be at least as long as the ping (round-trip over network) to the "slowest" player
    (the GC-Message must be received within a NWF to avoid having players to wait for others)

Server

The server is in charge for:

  1. Starting the game
  2. Distributing Messages (mostly GC-Messages and Chat)
  3. Executing the AI
  4. Detecting when a player quit or lags to much behind
  5. Detecting asyncs (Game differs between players)

Therefore the general algorithm is like this:

  • Send StartGame-Message
    • Tells players to prepare the map and which NWF length to use
    • Initiates sending the first (empty) GC-Message from each player
  • Send RealStart-Message (actually a special Done-Message)
    • Contains number of first GF to execute
    • Contains length of 1 GF
  • Execute the following in a loop till game is closed:
    1. If time for 1 GF has passed:
      • If it is a NWF:
        • Search for lagging players by checking if a GC-Message (from last NWF) is missing
          If one is found, kick or warn him and skip the rest of step i. (try again a bit later)
        • Compare checksums of all GC-Messages (must be the same, else handle async)
        • Send GCs of AI-players
        • Send a NWF-Done-Message with next GF number to execute
          This message acts as a replacement of the GC-Messages from the AIs as there might be no AIs at all which would make it impossible for the clients to wait for the server. In practice this can (currently) not happen, as the server and 1 client are coupled. So players would at least wait for that client. But this might change in the future (-> Dedicated server...)
      • Run AI for 1 Step
      • Increase GF number
    2. Relay messages

Client

On the clients side it is now pretty straight-forward:

  • When StartGame-Message is received, load map, send empty GC-Message
  • When RealStart-Message is received, set/check first GF# and set GF-Length, then start the game:
  • Repeat the following every n ms according to GF length:
    1. If it is a NWF:
      • Search for lagging players (non GC-Message received)
        Skip the rest if one is found (try again later)
      • Execute the rest of the NWF (see Basics above)
    2. Execute GF (see Basics above)
      • It is checked before this, if the next GF# is smaller than the GF# of the last NWF-Done-Message + the NWF-length. This should however be true in any case (Need confirmation from other devs!)

Attached a visualisation of the messages exchanged by the server (left) and the client (right):

Red boxes are the GFs. The gap between them is the NWF (where e.g. AI commands are send)

I drew some arrows in the next image to show the dependencies of a NWF:

As you can see the NWF-Done-Message influences the second next NWF, NOT the immediately following one.