This wiki was in read-only mode for many years, but can now be edited again. A lot of information will need to be updated.

Network Protocol: Difference between revisions

From BZFlagWiki
Jump to navigation Jump to search
Ts (talk | contribs)
Partial port from http://bzflag.svn.sourceforge.net/viewvccheckout: bzflag/trunk/bzflag/doc/guide/NetworkProtocol.xml
Zehra (talk | contribs)
to rewrite entirely from scratch
 
(7 intermediate revisions by 6 users not shown)
Line 1: Line 1:
{{Inaccurate}}
The following is an overview of the network protocol from version 2.4.x of BZFlag.


= Introduction =


BZFlag uses standard IP (Internet) networking protocols. The code is written to the BSD socket interface, with adjustments for winsock on win32 platforms. Future revisions may centralize the network code into one file behind a single class interface to simplify porting to platforms without the BSD socket API.
Information is directly read from the source code and can be easily referenced:
Most communication is non-blocking. That is, reads and sends return immediately instead of waiting for data to become available or to be sent. That's important since BZFlag is a real time game. It can't afford to get stuck waiting for a packet to come in. (The one exception to this is when BZFlag connects to a server, and this should get fixed someday.)
{|{{Prettytable}}
Communication is multiplexed using the select() call, which notifies the caller which sockets have data pending for read and/or are ready for sends. Instead of checking for incoming data by trying to read every socket and testing for success, we simply ask the system which sockets have data and read on those only. This also means that we use just a single thread for network communication.
|-
BZFlag uses two distinct transport protocols to communicate with the server. Server communication uses TCP/IP for reliability. Live game data communication uses UDP for speed and efficiency. See the other pages for more details.
| {{Hl3}} |'''Location:''' || {{Hl3}} |'''File:'''
|-
| '''/include/''' || '''Protocol.h'''
|-
| '''/include/''' || '''Pack.h'''
|-
|}




= Client/Server Communication =
All packet codes are of the type: '''uint16_t'''. (Protocol.h)
The BZFlag server manages games. It is the judge and arbitrar between clients. It manages game-global resources and information, such as flags and scores. It does not enforce game rules. Clients are trusted to follow the rules, saving the server the trouble of validating kills and client manouvering.
For example, the server is not told of changes to a client's position on the game board. Therefore the server cannot enfore the rule that players can't drive through walls (without the OO or PH flags). This allows each client to run freely. If it had to wait for the server to okay each movement, it would be impossible to play BZFlag except on fast or dedicated networks.
Furthermore, clients inform the server when they've killed another client player. The server doesn't verify the kill was legal beyond checking to see if someone has already claimed a kill on the same player. If more than one player claims a kill or tries to grab a particular flag, the server decides which player gets the kill or the flag.
Client/server communication is mostly limited to those messages that must be successfully delivered. These include, among others, notifications of players coming alive or being killed, notifications of shots being fired, flags coming or going or being grabbed or dropped.
Client/server communication in BZFlag is through TCP/IP. TCP/IP has the advantages of being bidirectional, reliable, and sequential. Bidirectional means each side of the connection can send to the other. Reliable means that each message will be delivered to the destination. Sequential means that messages (on a particular connection) will be received in the order they were sent.
The main disadvantage of TCP/IP is that it's slow. Reliability may require a given message to be sent several times, until the receiver acknowledges its receipt. While delays can cause problems, there really isn't a way around it. Messages between the client and server are specifically those messages that must not be lost. If we didn't use TCP/IP we'd simply have to implement something that did the same thing, and which would necessarily suffer from the same drawbacks.
There are some instances where client/server communication doesn't use TCP/IP. One example is client attempts to locate servers on the network. Clients send broadcast `pings' which the servers listen for and respond to in kind. These messages are not part of normal game communication.


= Client/Client Communication =
BZFlag clients send certain information to other clients during a game. This information includes: status, position, orientation, and linear and angular velocity. This state can change quickly and getting it late is no better than not getting it at all. So client to client packets are sent using UDP, a datagram protocol.
UDP is unreliable, meaning that packets are not guaranteed to be delivered. It's also connectionless, meaning we don't even know if anybody is listening for the message. However, it's also fast because it's so simple. UDP suits our needs because: we need fast delivery; we don't care if a message is lost because another will arrive shortly afterwards; and we don't care if the receiver isn't listening.
BZFlag clients need to send their information to all the other clients. There are several ways to do this. First, each client can send each message to all the other clients. If there are N clients then each message is sent N-1 times. Traffic grows as the square of clients. This is slow and wasteful.
Alternatively, each client can send all messages to one special computer (for example, the server) and that computer can forward the messages to all the other players. This makes life easier on the clients and much harder on the server. It also delays the deliverly of each message. And traffic from the server still grows as N squared (though traffic to the server grows linearly).
Another possibility is to broadcast messages. A broadcast message is sent once and received by all computers on a subnet. This scales linearly and minimizes network traffic but broadcast traffic is never routed outside the subnet, so it means only clients on the same subnet of the same local area network could play together.
BZFlag uses the second technique, using the server as a relay system. The server uses the TCP client/server connection to send client traffic that must be reliable and UDP for information that must be timely but does not need to be reliable.


= Protocol =
Below is taken from '''Protocol.h''':
   --> means from client to server
server communication protocol:
   <-- means from server to client
   --> incoming messages (to server)
   <-- outgoing messages to single player
  <== outgoing messages to all players


All multi-byte data is in network byte order (aka big endian); that is, the most significant byte comes first followed by successively less significant bytes.
==player to server messages:==
All numbers are integers unless otherwise specified. Integers can be 8, 16, or 32 bit signed 2's compliment or unsigned (encoding is the same in regardless of signed status). Values in this document in byte boxes are given in hexadecimal. Values in the text are given in decimal unless otherwise noted.
  MsgEnter      player is joining game
Bitfields are encoded as unsigned integers. All floating point numbers are in standard IEEE-754 single precision format. Multibyte values are *not* necessarily aligned on 2 or 4 byte boundaries.
            --> id, type, team, name, motto
A client normally follows the following sequence during game play: connect to server get the world database join the game send/receive game messages leave game disconnect from server
            <-- MsgReject (if rejected)
common message structures ------------------------- Most messages begin with the length of the message in bytes followed by a 16 bit code. The length is 16 bits and excludes itself and the code, so it's the actual length of the message minus 4.
            <-- MsgAccept (if accepted)
            if accepted, new player is sent (following MsgAccept):
            <-- MsgTeamUpdate (one per team)
            <-- MsgFlagUpdate (one per existing flag)
            <-- MsgAddPlayer (one per already joined player)
            add, finally, sent to all:
            <== MsgAddPlayer (player being accepted)
  MsgExit      player is signing off
            --> /id/
            <== MsgRemovePlayer
  MsgGetWorld      request for playing field database
            --> bytes read so far
            <-- MsgGetWorld
  MsgQueryGame      request for game state
            <-- MsgQueryGame
  MsgQueryPlayers  request for player list
            <-- MsgQueryPlayers
  MsgAlive      player says he's coming alive
            --> /id,
            <== MsgAlive
  MsgKilled    player says he's been killed
            --> /id,/ killer-id, reason, killer-shot-id
            <== MsgKilled
  MsgNewRabbit      player is relinquishing rabbitship
  MsgGrabFlag      player wants to grab flag
            --> /id,/ flag
            <== MsgGrabFlag
  MsgDropFlag      player wants to drop flag
            --> /id,/ position
            <== MsgDropFlag
            <== MsgFlagUpdate
  MsgCaptureFlag    player captured flag
            --> /id,/ team (team flag was taken to)
            <== MsgCaptureFlag
            <== MsgFlagUpdate
  MsgSetVar    <== count/[name/value]*
  MsgShotBegin      player has fired a shot
            --> FiringInfo
            <== MsgShotBegin
  MsgShotEnd        shot has terminated
            --> shooter id, shot number, reason
            <== MsgShotEnd
  MsgTeleport      player has teleported
            --> /id,/ from-teleporter, to-teleporter
            <== MsgTeleport
  MsgMessage        player is sending a message
            --> /id,/ target-id/team-id, message string
            <== MsgMessage
  MsgWantWHash      (player wants md5 of world file
            -->
  MsgNegotiateFlags -->flagCount/[flagabbv]
  MsgPause      -->true or false


==server to player messages:==
  MsgSuperKill      player must disconnect from server
            <== <none>
  MsgTimeUpdate    game time left, if == 0 player is dead and can't restart
            <== time (left, in seconds)
  MsgScoreOver      score limit reached, player is dead and can't restart
            <== id (winner), team (winner)
  MsgAccept    player request is accepted
            <== <none>
  MsgReject    player request is rejected
            <== <none>
  MsgAddPlayer      notification of new tank in game
            <== id, type, team, name, motto
  MsgRemovePlayer  player has exited the server
            <== id
  MsgAdminInfo      update of players' IP addresses
            only sent to players with the PLAYERLIST permission.
            <-- count, [chunklen, id, bitfield, address]*
  MsgPlayerInfo    update of players status
            <-- count, [id, bitfield]*
  MsgFlagUpdate    update of flag info
            <== count, [flag, flag-info]*
  MsgTeamUpdate    update of team info
            <== teamcount, [team, team-info]
  MsgGetWorld      chunk of world database
            <-- bytes left, next 256 byte chunk of world database
  MsgAlive      player is alive
            <== id, position, forward-vector
  MsgKilled    player is dead
            <== id (victim id), killer-id, reason, killer-shot-id
  MsgGrabFlag      notification that flag is grabbed
            <== id (grabber), flag, flag-info
  MsgDropFlag      notification that flag is in air
            <== id (dropper), flag, flag-info
  MsgCaptureFlag    notification that flag has been captured
            <== id (capturer), flag, team
  MsgShotBegin      some player has fired a shot
            <== FiringInfo
  MsgShotEnd        shot has expired
            <== id (shooter id), shot number, reason
  MsgScore      player score has changed
            <== num-scores [id (player id), wins, losses, tks]*n
  MsgTeleport      player has teleported
            <== id, from-teleporter, to-teleporter
  MsgMessage        message to players
            <== from-id, to-id/team-id, message string
  MsgQueryGame      game status
  MsgQueryPlayers  list of players
  MsgWantWHash      md5 digest of world file
            <== temp|perm, digest
  MsgNegotiateFlags <== flagCount/[flagabbv]
  MsgNewRabbit      a new rabbit has been anointed
            <== id
  MsgPause      <== id/true or false


Player identifiers are 1 byte and are used in many messages.
          0 - 243 : Regular Players
        244 - 250 : Special Team Ids
        251 - 252 : Unused IDs
              253 : ServerPlayer (World weapons, etc)
              254 : All Players
              255 : No Player (Invalid Player)
Flag status is common to a few message types:
u16 flag id
u16 status
u16 type
u8 owner id
float position (x)
float position (y)
float position (z)
float launch (x)
float launch (y)
float launch (z)
float landing (x)
float landing (y)
float landing (z)
float flight time
float flight end time
float initial velocity
`Position,' `launch,' `landing,' `flight time,' `flight end,' and `initial velocity' are all floating point numbers. `Flag id' is the type of flag,enumerated in FlagId.
`Status' gives the current location of the flag:
  FlagNoExist  -- the flag is not active (i.e. not in the game)
  FlagOnGround -- the flag is sitting on the ground ready to get picked up
  FlagOnTank  -- the flag is on a player's tank
  FlagInAir    -- the flag is in the air and will fall back down
  FlagComing  -- the flag just appeared and is falling to the ground
  FlagGoing    -- the flag was thrown in the air and is disappearing
`Type' indicates the behavior of the flag: FlagNormal means the flag is permanent and can be dropped normally (e.g. a team flag); FlagUnstable means the flag may disappear after use (e.g. a good super flag); FlagSticky means the flag cannot be dropped normally (e.g. a bad super flag).
`Player id' indicates which player has the flag when `status' is FlagOnTank. It isn't used for any other status.
`Position' is the location of the flag on the ground. It only has meaning when `status' is FlagOnGround. The position of a flag when on a tank is the position of the tank (centered on and at the top of the tank)
`Launch' is the location of the flag where it was thrown in the air. `Landing' is the location where the flag will/would touch ground. These are used when `status' is FlagInAir, FlagComing, and FlagGoing. The client should make the flag follow a reasonable flight path (e.g. a parabolic arc) from `launch' to `landing.'
`Flight time' is the time elapsed since the flag was thrown into the air. `Flight end' the time when the flag will reach the ground. `Initial velocity' gives the vertical (z) velocity of the flag when lanuched. The vertical position of the flag at time t (ranging from 0 to `flight end') is: z = z0 + v * t + 0.5 * g * t * t. z0 = `launch z;' v = `initial velocity;' g = acceleration due to gravity.
== Connecting to a server ==
The [http://bzflag.svn.sourceforge.net/viewvc/*checkout*/bzflag/trunk/bzflag/misc/bzfquery.php bzfquery.php script] is a nice example of how to connect to a server.
At the beginning you need to open a socket. Beginning with protocol 0048 you need to send "BZFLAG\r\n\r\n" in order to get any reply. At that time you unfortunately don't know the protocol, so send it by default or your client will probably freeze.
  -->  connect(server port)
  -->    +----+----+----+----+----+----+----+----+----+----+
| 42 | 5a | 46 | 4C | 41 | 47 | 0D | 0A | 0D | 0A |    BZFLAG\r\n\r\n
+----+----+----+----+----+----+----+----+----+----+
  <--    +----+----+----+----+----+----+----+----+----+
  | 42 | 5a | 46 | 53 | 31 | 39 | 31 | 30 | FF |          BZFS1910        FF
  +----+----+----+----+----+----+----+----+----+
Client should verify the version. In old versions the first four bytes indicates a BZFlag server, the next byte indicates the major version number (as an ascii digit), the two bytes after that are the minor version number (as ascii digits), and the 7th byte is the revision. Major and minor version number changes indicate incompatible protocol changes. Different revisions of a given version are compatible and usually just indicate client user interface changes. A following FF ends the packet. In new versions the protocol is just a number increased by 1 when the protocol changes.
If the reply was a protocol older than 0048 then bzfs will kick the client connecting to it. In this case we recommend a fallback, not sending BZFLAG\r\n\r\n during connection try:
  -->  connect(server port)
  <--    +----+----+----+----+----+----+----+----+----+
  | 42 | 5a | 46 | 53 | 31 | 39 | 31 | 30 | FF |          BZFS1910        FF
  +----+----+----+----+----+----+----+----+----+
Server owners will see something like the following in the logs if their server(s) use a protocol older than 0048:
  Player [0] sent huge packet length (len=16986), possible attack
  Player  [0] removed at 2007-04-11 15:52:55: large packet recvd


[[Category:Development]]
[[Category:Concepts]]
[[Category:Concepts]]

Latest revision as of 03:20, 10 November 2025

The following is an overview of the network protocol from version 2.4.x of BZFlag.


Information is directly read from the source code and can be easily referenced:

Location: File:
/include/ Protocol.h
/include/ Pack.h


All packet codes are of the type: uint16_t. (Protocol.h)


Below is taken from Protocol.h:

server communication protocol:
 --> incoming messages (to server)
 <-- outgoing messages to single player
 <== outgoing messages to all players

player to server messages:

 MsgEnter      player is joining game
           --> id, type, team, name, motto
           <-- MsgReject (if rejected)
           <-- MsgAccept (if accepted)
           if accepted, new player is sent (following MsgAccept):
           <-- MsgTeamUpdate (one per team)
           <-- MsgFlagUpdate (one per existing flag)
           <-- MsgAddPlayer (one per already joined player)
           add, finally, sent to all:
           <== MsgAddPlayer (player being accepted)
 MsgExit       player is signing off
           --> /id/
           <== MsgRemovePlayer
 MsgGetWorld       request for playing field database
           --> bytes read so far
           <-- MsgGetWorld
 MsgQueryGame      request for game state
           <-- MsgQueryGame
 MsgQueryPlayers   request for player list
           <-- MsgQueryPlayers
 MsgAlive      player says he's coming alive
           --> /id,
           <== MsgAlive
 MsgKilled     player says he's been killed
           --> /id,/ killer-id, reason, killer-shot-id
           <== MsgKilled
 MsgNewRabbit      player is relinquishing rabbitship
 MsgGrabFlag       player wants to grab flag
           --> /id,/ flag
           <== MsgGrabFlag
 MsgDropFlag       player wants to drop flag
           --> /id,/ position
           <== MsgDropFlag
           <== MsgFlagUpdate
 MsgCaptureFlag    player captured flag
           --> /id,/ team (team flag was taken to)
           <== MsgCaptureFlag
           <== MsgFlagUpdate
 MsgSetVar     <== count/[name/value]*
 MsgShotBegin      player has fired a shot
           --> FiringInfo
           <== MsgShotBegin
 MsgShotEnd        shot has terminated
           --> shooter id, shot number, reason
           <== MsgShotEnd
 MsgTeleport       player has teleported
           --> /id,/ from-teleporter, to-teleporter
           <== MsgTeleport
 MsgMessage        player is sending a message
           --> /id,/ target-id/team-id, message string
           <== MsgMessage
 MsgWantWHash      (player wants md5 of world file
           -->
 MsgNegotiateFlags -->flagCount/[flagabbv]
 MsgPause      -->true or false

server to player messages:

 MsgSuperKill      player must disconnect from server
           <== <none>
 MsgTimeUpdate     game time left, if == 0 player is dead and can't restart
           <== time (left, in seconds)
 MsgScoreOver      score limit reached, player is dead and can't restart
           <== id (winner), team (winner)
 MsgAccept     player request is accepted
           <== <none>
 MsgReject     player request is rejected
           <== <none>
 MsgAddPlayer      notification of new tank in game
           <== id, type, team, name, motto
 MsgRemovePlayer   player has exited the server
           <== id
 MsgAdminInfo      update of players' IP addresses
           only sent to players with the PLAYERLIST permission.
           <-- count, [chunklen, id, bitfield, address]*
 MsgPlayerInfo     update of players status
           <-- count, [id, bitfield]*
 MsgFlagUpdate     update of flag info
           <== count, [flag, flag-info]*
 MsgTeamUpdate     update of team info
           <== teamcount, [team, team-info]
 MsgGetWorld       chunk of world database
           <-- bytes left, next 256 byte chunk of world database
 MsgAlive      player is alive
           <== id, position, forward-vector
 MsgKilled     player is dead
           <== id (victim id), killer-id, reason, killer-shot-id
 MsgGrabFlag       notification that flag is grabbed
           <== id (grabber), flag, flag-info
 MsgDropFlag       notification that flag is in air
           <== id (dropper), flag, flag-info
 MsgCaptureFlag    notification that flag has been captured
           <== id (capturer), flag, team
 MsgShotBegin      some player has fired a shot
           <== FiringInfo
 MsgShotEnd        shot has expired
           <== id (shooter id), shot number, reason
 MsgScore      player score has changed
           <== num-scores [id (player id), wins, losses, tks]*n
 MsgTeleport       player has teleported
           <== id, from-teleporter, to-teleporter
 MsgMessage        message to players
           <== from-id, to-id/team-id, message string
 MsgQueryGame      game status
 MsgQueryPlayers   list of players
 MsgWantWHash      md5 digest of world file
           <== temp|perm, digest
 MsgNegotiateFlags <== flagCount/[flagabbv]
 MsgNewRabbit      a new rabbit has been anointed
           <== id
 MsgPause      <== id/true or false