                        QuakeBot C/S Specifications

                          The Bot Smith's Handbook

                                   V0.95

                                  Jim Rorie

                              jfrorie@uncc.edu

----------------------------------------------------------------------------

1.0 Introduction

This document is a description of the architecture of a development project
known as QuakeBot C/S, a client/server bot for use with Quake, by id
software. It's purpose to give individuals a insight into the project and to
generate feedback for future development paths. It is accurate with the
possible exception of typographical errors and has been used as a basis for
a simple bot. But it is not complete, hence the current version level. I
will not reach V1.0 until the project reaches a beta stage.

I intend that in time, this will be an accurate, informative document that
can serve as a handbook for future QuakeBot C/S developers and others
wishing to design their own bots. Currently though, it is a hack. You can
get enough information to establish a connection and piddle a little bit.
But that is about it. If you use this and find out something new, EMAIL ME.
I will include it and along with appropriate credit.

Also included is a comprehensive treatment of the communication protocol
between Quake client and server systems. This is not a proposal, rather the
examination of the current protocol as best it can be determined. All steps
have been taken to verify accuracy but it is based on manually decoding raw
data streams in the C/S environment and its reliability should be taken with
a grain of salt at this time. This is just provided to fill in the gaps that
you might have or to stimulate thinking about parts not fully described.

With recent revisions, I have included information from id software on their
internals. I would like to thank id for their continued and totally amazing
support for their products. J. William Pelzer of the Quake Stomping Grounds
has been a great resource, finding all kinds of cool stuff to contribute.
Oliver T. De Guzman has added his considerable knowledge of the
client-server protocol, smoothing out my rough edges. In addition, Oliver
Montanuy, another bot developer and author of the Unofficial Quake
Specifications, has spotted my many errors and contributed ideas about the
bot's grand vision.

2.0 Client/Server Bot Architecture

The operating environment for Quake is based on the Client/Server model.
This arrangement consists of a central server running the game and
performing game housekeeping, collision detection, and player
synchronization. The client is burdened with task of updating the screen
based on information supplied by the server and displaying it in real time.
One single system, the client and server run locally on the same system and
appear to be one functional unit.

In the network environment, things change slightly as they become separated.
The server executes on a remote system arbitrating the players, while the
client executes on the local system giving runtime feedback to the gamer. On
a system running on the server's local network with minimal traffic, the
game should appear to execute faster, since the local machine is no longer
burdened with the server process.

The idea of a Client/Server QuakeBot is to replace the Quake client with a
custom program that communicates with the server. This client can perform a
number of tasks depending on the implementation. The idea of a peer client
allows it to used on any server, no matter what mods they are running. Thus,
you need nothing special, just boot it up.

The question of fairness arises. A C/S QuakeBot would be as fair as the
server since it is running as a peer client and receives no special
treatment. It does have the advantage of more information than the average
player, but the actual game parameters cannot be changed from the client
side. This is not the case with a QuakeC bot, which requires modification of
the server and can be easily hacked to cheat. I have done this, I know it is
possible.

2.1 Packet Information

The Quake packet starts with a 4 byte header. This head contains two bytes
of flag information, followed by the a 2 byte packet length, including
header. This is shown below:

struct ControlHeader {
char Flag1;
char Flag2;
short PacketLen; // Big Endian or network byte order
};

For the assignment of the header flags, the following have been identified:

{0x80, 0x00} - Control Packet
{0x00, 0x01} - Packet Fragment
{0x00, 0x09} - Final Packet Fragment or Complete Packet
{0x00, 0x02} - Acknowledgment
{0x00, 0x10} - Runtime Game Data Packet (Update)

Certain packets contain the NET_PROTOCOL_VERSION tag. This value exists for
backward compatibility with other versions of Quake Client/Server software.
Currently, this value is three.

#define NET_PROTOCOL_VERSION 0x03

2.2 Control Packets

Control packets are used for the communication of specific requests of the
server. Among these are Query, Connect, Player Information and Rule
Information. Each control packet has a specific protocol associated with it
as shown in the following section.

2.2.1 Server Information

The client transmits a broadcast packet to determine what servers are on the
span. This is responded to with a directed broadcast response from the
server giving current game parameters. It also contains the initialization
port for initial connection.

struct ClientBroadcast {
        struct Header                           // { 0x80, 0x00, 0x00, 0x0c };
        char OP_CODE                            // 0x02, This is CCREQ_SERVER_INFO
        char Data [ ] = { 0x51, 0x55, 0x41, 0x4b, 0x45, 0x00} // "QUAKE", 0x00
        byte net_protocol_version NET_PROTOCOL_VERSION; // 0x03
}

0000: 80 00 00 0c 02 51 55 41 4b 45 00 03                       | .....QUAKE..

struct ServerResponse {
        struct Header;                          //{ 0x80, 0x00, 0x00, 0x2e}
        char OP_Code;                           // 0x83 CCREP_SERVER_INFO
        char Data[];                            // IP:Port
        char Name[];                            // pentium-120
        char Map[];                             // e1m1
        byte current_players                    // 01
        byte max_players                        // 04
        byte net_protocal_version               // NET_PROTOCOL_VERSION
};

0000: 80 00 00 2e 83 31 30 30 2e 31 30 30 2e 31 30 30           | .....100.100.100
0010: 2e 35 30 3a 32 36 30 30 30 00 70 65 6e 74 69 75           | .50:26000.pentiu
0020: 6d 2d 31 32 30 00 65 31 6d 31 00 01 04 03                 | m-120.e1m1....

2.2.2 Player Information

The client transmits a directed packet to determine information on a given
player. This is responded to with a player info packet giving the
information on the requested player. The player number ranges from 0 to
current_players-1. Bad player numbers get no response. The formula for color
is (shirt *16 + pants). "Colors, frags, and connect_time are in
little-endian ordering. Colors use only one byte of the four bytes in the
packet. connect_time is in seconds, frags is a signed number." (O.DG.)

struct ClientPlayerInfo {
        struct Header;
        char OP_CODE; // 0x03, This is CCREQ_PLAYER_INFO
        byte player_number
};

NO EXAMPLE

struct ServerPlayerInfo {
        struct Header;
        char OP_Code; // 0x84 CCREP_PLAYER_INFO
        byte player_number;
        char Name[];
        long colors;
        long frags;
        long connect_time
        char Address[]
};

NO EXAMPLE

2.2.3 Rule Information

This request can give information on any of the variables set in the Quake
server environment. The following rules are currently supported: fraglimit,
timelimit, teamplay, noexit, sv_friction, sv_gravity, sv_maxspeed. The
client sends the RuleInfo packet to the server. The server responds with a
rule and value. Continued querying is performed by sending the last string
received form the server until a packet is return that has no data. No rule,
no value. It will have a packet length of 5.

struct ClientRuleInfo {
        struct Header;
        char OP_CODE; // 0x04, This is CCREQ_RULE_INFO
        char Rule[]; // 0x00 for the first request, the previously receive rule for the next.
}

NO EXAMPLE

struct ServerPlayerInfo {
        struct Header;
        char OP_Code;                  // 0x85 CCREP_RULE_INFO
        char rule[];
        char Value[];
};

NO EXAMPLE

2.2.4 Connection Request

The client transmits a directed packet to the server with a connect request.
The server responds with an Ack and a new port to connect to for all future
communications.

struct ClientConnect {
        struct Header ;                        //{ 0x80, 0x00, 0x00, 0x0c}
        char OP_Code                           // 0x01
        char Data [ ] = { 0x51, 0x55, 0x41, 0x4b, 0x45, 0x00} // "QUAKE", 0x00
        byte net_protocol_version NET_PROTOCOL_VERSION; // 0x03
};

0000: 80 00 00 0c 01 51 55 41 4b 45 00 03                       | .....QUAKE..

struct ServerConnect Response {
        struct Header;                          // { 0x80, 0x00, 0x00, 0x09 }
        char OP_Code;                    // 0x81 This is CCREP_ACCEPT
        short Port;                      // This is your port assigned
                                        // by the server
        char Unknown[ 2] = {0x00, 0x00 };    // The packet header shows these two byte
                                                // to be valid data, I dunno what, tho.
};

0000: 80 00 00 09 81 0a 04 00 00 20 20 20 20 20 20 20   | .........
0010: 20 20                                                     |

Below would be a reject response:

struct ServerConnect Response {
        struct Header;
        char OP_Code; /./ 0x82 This is CCREP_REJECT
        char Data[]; // A string telling you why;
};

NO EXAMPLE

2.3 Reliable Packets

Packet Fragment and Final Packet Fragment are basically the same packet
format with an additional flag set. Messages transmitted using this mode can
appear during game initialization and runtime. These are reliable packets
and receipt must be confirmed with an appropriate acknowledgment. Large
messages use the packet fragment flag to split data over several packets to
prevent overloading of the socket protocol. If packets are fragmented, the
final packet will modify the header to reflect this fact.

2.4 Acknowledgment Packets

Acknowledgments are responses to reliable transmissions. The acknowledgment
consists of nothing more that a sequence to differentiate it from other
packets that might have change order. Acknowledgments are required for all
full packet and packet fragment transmissions.

struct ClientAcknowledge {
        struct Header; {0x00, 0x20, 0x00, 0x08}
        long Sequence; // Big endian order
};

0000: 00 02 00 08 00 00 00 03 | ........

2.5 Runtime Packets

Runtime packets are used for the transmission of unreliable data. These
packet usually appear only during game runtime and do not require an
acknowledgment. They are more fully explained in the runtime section of the
protocol specification.

3.0 Game Initialization Protocol

The protocol as is currently decoded, is shown below. For some packets,
there are DEM commands parsed from the data stream. Below each packet
structure, there is a Ethernet packet dump from an actual game. The format
for server packets is a packet header followed by a series of DEM format
commands. For those unaware, the DEM format is a series of commands used to
store demo's of Quake sessions for playback at a later time. Therefore, they
are capable of describing fully the entire process of the game. Most of
these structures are more fully explained in the Unofficial DEM File Format
Specifications. I will not list the message formats here, since this spec
has very good treatment of the material. WARNING!! Look at the code
fragments, not the specification write up for data types. This threw me way
off.

3.1 Overview

This is a listing of the steps involved in initializing a Quake session.

  1. Client sends a connect control packet. Server responds
  2. Server sends a series of reliable precache packets and a signon 1
     command. Client acknowledges each. ( Server may transmit each packet
     more that once!!!)
  3. Client sends a NO-OP. Server acknowledges.
  4. Client sends a prespawn console command. Server acknowledges.
  5. Server sends series of entity initialization packets and a signon 2
     command. Client acknowledges each.
  6. Client sends its player parameters and a spawn console command.
  7. Server sends lighting and player information with a signon 3 command.
  8. Client sends a begin console command.

Note that step 7 sometimes appears after step 8. They are not cause-effect
related.

3.2 Precache Initialization Phase

This phase contains the names of the level and other resources used in the
games. This is initiated by the server, transmitting a continuous stream of
filenames and embedded ASCII data in a variable number of packets. The final
DEM command in the stream is a Signon command to instruct the client to the
prespawn phase. The following are an example of the DEM format messages
received when parsing these packets. Notice the partial message statement.
The packets are transmitted fracturing the complete DEM message, so you will
need to reassemble them.

Command: print
Message:
VERSION 1.03 SERVER (51103 CRC)

Command: serverinfo
String = maps/e1m1.bsp
String = *1
String = *2

[truncated for space]

String = *55
String = *56
String = *57
String = progs/player.mdl
String = progs/eyes.mdl
String = progs/h_player.mdl
String = progs/gib1.mdl
[truncated for space]
String = progs/g_nail.mdl
String = maps/b_rock0.bsp
String = maps/b_shell1.bsp

Partial Message, getting more....

String = progs/invulner.mdl
String = progs/suit.mdl
String = maps/b_explob.bsp

Sound Precache
String = weapons/r_exp3.wav
String = weapons/rocket1i.wav
String = weapons/sgun1.wav
String = weapons/guncock.wav

[truncated for space]

String = items/suit2.wav
String = misc/secret.wav
String = ambience/comp1.wav
String = ambience/drone6.wav
String =

Command: CD Track
Range 6 - 6

Command: Setview
Entity: 1

Command: Signon
Action: 1

0000: 00 01 04 08 00 00 00 00 0b 0f 00 00 00 04 01 74 | ...............t
0010: 68 65 20 53 6c 69 70 67 61 74 65 20 43 6f 6d 70 | he Slipgate Comp
0020: 6c 65 78 00 6d 61 70 73 2f 65 31 6d 31 2e 62 73 | lex.maps/e1m1.bs
0030: 70 00 2a 31 00 2a 32 00 2a 33 00 2a 34 00 2a 35 | p.*1.*2.*3.*4.*5
0040: 00 2a 36 00 2a 37 00 2a 38 00 2a 39 00 2a 31 30 | .*6.*7.*8.*9.*10
0050: 00 2a 31 31 00 2a 31 32 00 2a 31 33 00 2a 31 34 | .*11.*12.*13.*14
0060: 00 2a 31 35 00 2a 31 36 00 2a 31 37 00 2a 31 38 | .*15.*16.*17.*18
0070: 00 2a 31 39 00 2a 32 30 00 2a 32 31 00 2a 32 32 | .*19.*20.*21.*22
0080: 00 2a 32 33 00 2a 32 34 00 2a 32 35 00 2a 32 36 | .*23.*24.*25.*26
0090: 00 2a 32 37 00 2a 32 38 00 2a 32 39 00 2a 33 30 | .*27.*28.*29.*30
00a0: 00 2a 33 31 00 2a 33 32 00 2a 33 33 00 2a 33 34 | .*31.*32.*33.*34
00b0: 00 2a 33 35 00 2a 33 36 00 2a 33 37 00 2a 33 38 | .*35.*36.*37.*38
00c0: 00 2a 33 39 00 2a 34 30 00 2a 34 31 00 2a 34 32 | .*39.*40.*41.*42
00d0: 00 2a 34 33 00 2a 34 34 00 2a 34 35 00 2a 34 36 | .*43.*44.*45.*46
00e0: 00 2a 34 37 00 2a 34 38 00 2a 34 39 00 2a 35 30 | .*47.*48.*49.*50
00f0: 00 2a 35 31 00 2a 35 32 00 2a 35 33 00 2a 35 34 | .*51.*52.*53.*54
0100: 00 2a 35 35 00 2a 35 36 00 2a 35 37 00 70 72 6f | .*55.*56.*57.pro
0110: 67 73 2f 70 6c 61 79 65 72 2e 6d 64 6c 00 70 72 | gs/player.mdl.pr
0120: 6f 67 73 2f 65 79 65 73 2e 6d 64 6c 00 70 72 6f | ogs/eyes.mdl.pro
0130: 67 73 2f 68 5f 70 6c 61 79 65 72 2e 6d 64 6c 00 | gs/h_player.mdl.
0140: 70 72 6f 67 73 2f 67 69 62 31 2e 6d 64 6c 00 70 | progs/gib1.mdl.p
0150: 72 6f 67 73 2f 67 69 62 32 2e 6d 64 6c 00 70 72 | rogs/gib2.mdl.pr
0160: 6f 67 73 2f 67 69 62 33 2e 6d 64 6c 00 70 72 6f | ogs/gib3.mdl.pro
0170: 67 73 2f 73 5f 62 75 62 62 6c 65 2e 73 70 72 00 | gs/s_bubble.spr.
0180: 70 72 6f 67 73 2f 73 5f 65 78 70 6c 6f 64 2e 73 | progs/s_explod.s
0190: 70 72 00 70 72 6f 67 73 2f 76 5f 61 78 65 2e 6d | pr.progs/v_axe.m
01a0: 64 6c 00 70 72 6f 67 73 2f 76 5f 73 68 6f 74 2e | dl.progs/v_shot.
01b0: 6d 64 6c 00 70 72 6f 67 73 2f 76 5f 6e 61 69 6c | mdl.progs/v_nail
01c0: 2e 6d 64 6c 00 70 72 6f 67 73 2f 76 5f 72 6f 63 | .mdl.progs/v_roc
01d0: 6b 2e 6d 64 6c 00 70 72 6f 67 73 2f 76 5f 73 68 | k.mdl.progs/v_sh
01e0: 6f 74 32 2e 6d 64 6c 00 70 72 6f 67 73 2f 76 5f | ot2.mdl.progs/v_
01f0: 6e 61 69 6c 32 2e 6d 64 6c 00 70 72 6f 67 73 2f | nail2.mdl.progs/
0200: 76 5f 72 6f 63 6b 32 2e 6d 64 6c 00 70 72 6f 67 | v_rock2.mdl.prog
0210: 73 2f 62 6f 6c 74 2e 6d 64 6c 00 70 72 6f 67 73 | s/bolt.mdl.progs
0220: 2f 62 6f 6c 74 32 2e 6d 64 6c 00 70 72 6f 67 73 | /bolt2.mdl.progs
0230: 2f 62 6f 6c 74 33 2e 6d 64 6c 00 70 72 6f 67 73 | /bolt3.mdl.progs
0240: 2f 6c 61 76 61 62 61 6c 6c 2e 6d 64 6c 00 70 72 | /lavaball.mdl.pr
0250: 6f 67 73 2f 6d 69 73 73 69 6c 65 2e 6d 64 6c 00 | ogs/missile.mdl.
0260: 70 72 6f 67 73 2f 67 72 65 6e 61 64 65 2e 6d 64 | progs/grenade.md
0270: 6c 00 70 72 6f 67 73 2f 73 70 69 6b 65 2e 6d 64 | l.progs/spike.md
0280: 6c 00 70 72 6f 67 73 2f 73 5f 73 70 69 6b 65 2e | l.progs/s_spike.
0290: 6d 64 6c 00 70 72 6f 67 73 2f 62 61 63 6b 70 61 | mdl.progs/backpa
02a0: 63 6b 2e 6d 64 6c 00 70 72 6f 67 73 2f 7a 6f 6d | ck.mdl.progs/zom
02b0: 5f 67 69 62 2e 6d 64 6c 00 70 72 6f 67 73 2f 76 | _gib.mdl.progs/v
02c0: 5f 6c 69 67 68 74 2e 6d 64 6c 00 70 72 6f 67 73 | _light.mdl.progs
02d0: 2f 61 72 6d 6f 72 2e 6d 64 6c 00 6d 61 70 73 2f | /armor.mdl.maps/
02e0: 62 5f 6e 61 69 6c 30 2e 62 73 70 00 70 72 6f 67 | b_nail0.bsp.prog
02f0: 73 2f 71 75 61 64 64 61 6d 61 2e 6d 64 6c 00 6d | s/quaddama.mdl.m
0300: 61 70 73 2f 62 5f 62 68 31 30 30 2e 62 73 70 00 | aps/b_bh100.bsp.
0310: 70 72 6f 67 73 2f 67 5f 72 6f 63 6b 32 2e 6d 64 | progs/g_rock2.md
0320: 6c 00 70 72 6f 67 73 2f 67 5f 72 6f 63 6b 2e 6d | l.progs/g_rock.m
0330: 64 6c 00 6d 61 70 73 2f 62 5f 72 6f 63 6b 31 2e | dl.maps/b_rock1.
0340: 62 73 70 00 70 72 6f 67 73 2f 67 5f 6e 61 69 6c | bsp.progs/g_nail
0350: 32 2e 6d 64 6c 00 70 72 6f 67 73 2f 67 5f 73 68 | 2.mdl.progs/g_sh
0360: 6f 74 2e 6d 64 6c 00 6d 61 70 73 2f 62 5f 73 68 | ot.mdl.maps/b_sh
0370: 65 6c 6c 30 2e 62 73 70 00 6d 61 70 73 2f 62 5f | ell0.bsp.maps/b_
0380: 62 68 31 30 2e 62 73 70 00 6d 61 70 73 2f 62 5f | bh10.bsp.maps/b_
0390: 62 68 32 35 2e 62 73 70 00 6d 61 70 73 2f 62 5f | bh25.bsp.maps/b_
03a0: 6e 61 69 6c 31 2e 62 73 70 00 70 72 6f 67 73 2f | nail1.bsp.progs/
03b0: 67 5f 6e 61 69 6c 2e 6d 64 6c 00 6d 61 70 73 2f | g_nail.mdl.maps/
03c0: 62 5f 72 6f 63 6b 30 2e 62 73 70 00 6d 61 70 73 | b_rock0.bsp.maps
03d0: 2f 62 5f 73 68 65 6c 6c 31 2e 62 73 70 00 70 72 | /b_shell1.bsp.pr
03e0: 6f 67 73 2f 69 6e 76 75 6c 6e 65 72 2e 6d 64 6c | ogs/invulner.mdl
03f0: 00 70 72 6f 67 73 2f 73 75 69 74 2e 6d 64 6c 00 | .progs/suit.mdl.
0400: 6d 61 70 73 2f 62 5f 65 | maps/b_e

3.3 Sync Phase

This appears to be a synchronization phase. The first packet transmitted is
a no-op, the second is a prespawn console command. These are transmitted
from the client and acknowledged by the server.

struct ClientPacket{
        struct Header;
        struct Sequence;
        char Data = 0x01;
};

0000: 00 09 00 09 00 00 00 00 01 | .........

struct ClientPrespawn{
        struct Header;
        struct Sequence;
        char RuleByte;          // I am making an assumption here
        char Prespawn[] = "prespawn"
};

0000: 00 09 00 12 00 00 00 01 04 70 72 65 73 70 61 77 | .........prespaw
0010: 6e 00 | n.

3.4 Entity Initialization Phase

The section consists of numerous spawns, creating the entities for use the
in the game. A signon 2 command is appended to move the client into the next
phase. Below is a sample DEM parse session from the data stream. Again, the
packets split the DEM message in the middle so you must reassemble.

Command: spawnstaticsound
Command: spawnstaticsound
Command: spawnstaticsound
Command: spawnstaticsound

{ Truncated]

Command: spawnstaticsound
Command: spawnstaticsound
Command: spawnstaticsound
Command: spawnstaticsound
Command: Spawn Baseline
Command: Spawn Baseline
Command: Spawn Baseline
Command: Spawn Baseline

{ Truncated]

Command: Spawn Baseline
Command: Spawn Baseline
Command: Spawn Baseline
Command: Spawn Baseline

Partial Message, getting more....

Command: Spawn Baseline
Command: Spawn Baseline
Command: Spawn Baseline
Command: Spawn Baseline

{ Truncated]

Command: Spawn Baseline
Command: Spawn Baseline
Command: Spawn Baseline
Command: Spawn Baseline
Command: Signon
Action: 2

0000: 00 01 04 08 00 00 00 03 1d 80 15 00 06 80 02 3e | ...............>
0010: 7f c0 1d 80 12 00 11 c0 02 44 7f c0 1d 80 05 80 | .........D......
0020: 36 40 fb 44 7f c0 1d 80 02 80 36 40 fb 44 7f c0 | 6@.D......6@.D..
0030: 1d 00 0d 80 40 80 fc 44 7f c0 1d 00 0d 80 3d 80 | ....@..D......=.
0040: fc 44 7f c0 1d c0 0a 40 45 40 fd 3e 7f c0 1d 40 | .D.....@E@.>...@
0050: f1 80 40 40 fd 44 7f c0 1d 00 29 00 22 80 f4 51 | ..@@.D....)."..Q
0060: 7f c0 1d d0 07 10 06 40 02 5d ff c0 1d 50 16 10 | .......@.]...P..
0070: 06 40 02 5d ff c0 1d 90 13 50 40 c0 fc 5d ff c0 | .@.].....P@..]..
0080: 1d 90 0e 90 45 c0 fc 5d ff c0 1d 10 29 10 0e c0 | ....E..]....)...
0090: f9 5e 7f c0 16 00 00 01 00 00 00 00 00 00 00 00 | .^..............
00a0: 00 00 00 00 16 01 00 3b 00 01 00 00 00 00 00 00 | .......;........
00b0: 00 00 00 00 16 02 00 3b 00 02 00 00 00 00 00 00 | .......;........
00c0: 00 00 00 00 16 03 00 3b 00 03 00 00 00 00 00 00 | .......;........
00d0: 00 00 00 00 16 04 00 3b 00 04 00 00 00 00 00 00 | .......;........
00e0: 00 00 00 00 16 0b 00 02 00 00 00 00 00 00 00 00 | ................
00f0: 00 00 00 00 16 0c 00 03 00 00 00 00 00 00 00 00 | ................
0100: 00 00 00 00 16 0e 00 55 00 00 00 80 15 00 00 0f | .......U........
0110: 00 80 02 00 16 0f 00 04 00 00 00 00 00 00 00 00 | ................
0120: 00 00 00 00 16 10 00 05 00 00 00 00 00 00 00 00 | ................
0130: 00 00 00 00 16 11 00 06 00 00 00 00 00 00 00 00 | ................
0140: 00 00 00 00 16 12 00 07 00 00 00 00 00 00 00 00 | ................
0150: 00 00 00 00 16 19 00 08 00 00 00 00 00 00 00 00 | ................
0160: 00 40 fb 00 16 1b 00 09 00 00 00 00 00 00 80 f8 | .@..............
0170: 00 00 00 00 16 1c 00 0a 00 00 00 00 00 00 00 00 | ................
0180: 00 00 00 00 16 22 00 0b 00 00 00 00 00 00 00 00 | ....."..........
0190: 00 00 00 00 16 24 00 56 00 00 00 80 08 00 80 49 | .....$.V.......I
01a0: 00 00 02 00 16 2a 00 0e 00 00 00 00 00 00 00 00 | .....*..........
01b0: 00 00 00 00 16 2b 00 0f 00 00 00 00 00 00 00 00 | .....+..........
01c0: 00 00 00 00 16 2c 00 10 00 00 00 00 00 00 00 00 | .....,..........
01d0: 00 f0 fd 00 16 2e 00 57 00 00 00 00 11 00 80 4d | .......W.......M
01e0: 00 40 fd 00 16 2f 00 14 00 00 00 00 00 00 00 00 | .@.../..........
01f0: 00 00 00 00 16 31 00 16 00 00 00 00 00 00 00 00 | .....1..........
0200: 00 00 00 00 16 32 00 17 00 00 00 00 00 00 00 00 | .....2..........
0210: 00 80 f3 00 16 34 00 18 00 00 00 00 00 00 00 00 | .....4..........
0220: 00 00 00 00 16 36 00 58 00 00 00 80 1d 00 80 1f | .....6.X........
0230: 00 80 f7 00 16 37 00 59 00 00 00 80 04 00 80 49 | .....7.Y.......I
0240: 00 80 00 00 16 38 00 5a 00 00 00 00 26 00 80 20 | .....8.Z....&..
0250: 00 80 f2 00 16 39 00 5b 00 00 00 80 2b 00 00 20 | .....9.[....+..
0260: 00 80 f2 00 16 3b 00 5c 00 00 00 00 1a 00 80 4c | .....;.\.......L
0270: 00 80 f4 00 16 3c 00 5d 00 00 00 00 04 00 00 26 | .....<.].......&
0280: 00 80 f9 00 16 3d 00 5e 00 00 00 40 09 00 c0 42 | .....=.^...@...B
0290: 00 00 fa 00 16 3e 00 5f 00 00 00 80 2c 00 40 1c | .....>._....,.@.
02a0: 00 80 f2 00 16 3f 00 60 00 00 00 00 2b 00 40 19 | .....?.`....+.@.
02b0: 00 80 f2 00 16 40 00 60 00 00 00 c0 24 00 40 1d | .....@.`....$.@.
02c0: 00 80 f2 00 16 46 00 23 00 00 00 00 00 00 00 00 | .....F.#........
02d0: 00 80 ff 00 16 47 00 24 00 00 00 00 00 00 00 00 | .....G.$........
02e0: 00 80 ff 00 16 48 00 25 00 00 00 00 00 00 00 00 | .....H.%........
02f0: 00 80 ff 00 16 49 00 26 00 00 00 00 00 00 00 00 | .....I.&........
0300: 00 80 ff 00 16 4b 00 61 00 00 00 00 2b 00 00 20 | .....K.a....+..
0310: 00 80 f7 00 16 4c 00 60 00 00 00 00 25 00 00 1f | .....L.`....%...
0320: 00 80 f7 00 16 4d 00 5f 00 00 00 00 2b 00 c0 1a | .....M._....+...
0330: 00 80 f7 00 16 4e 00 5f 00 00 00 40 27 00 40 35 | .....N._...@'.@5
0340: 00 80 f2 00 16 53 00 62 00 00 00 00 0f 00 00 12 | .....S.b........
0350: 00 00 00 00 16 54 00 61 00 00 00 80 0e 00 c0 16 | ....T.a........
0360: 00 00 02 00 16 55 00 60 00 00 00 40 0a 00 80 1a | .....U.`...@....
0370: 00 00 f9 00 16 56 00 60 00 00 00 c0 0a 00 c0 1c | .....V.`........
0380: 00 00 f9 00 16 57 00 5f 00 00 00 80 ff 00 80 40 | .....W._.......@
0390: 00 80 f9 00 16 58 00 63 00 00 00 00 f1 00 00 46 | .....X.c.......F
03a0: 00 00 fb 00 16 59 00 64 00 00 00 00 fd 00 c0 4c | .....Y.d.......L
03b0: 00 80 00 00 16 5a 00 5b 00 00 00 c0 fc 00 40 45 | .....Z.[......@E
03c0: 00 80 00 00 16 5b 00 65 00 00 00 00 08 00 80 38 | .....[.e.......8
03d0: 00 c0 fe 00 16 5c 00 66 00 00 00 40 16 00 c0 3f | .....\.f...@...?
03e0: 40 40 f3 00 16 5d 00 5b 00 00 00 80 29 00 40 4f | @@...].[....).@O
03f0: 00 80 ef 00 16 5e 00 58 00 00 00 a0 1c 00 80 4b | .....^.X.......K
0400: 00 c0 fb 00 16 62 00 2a | .....b.*

0000: 00 09 00 c6 00 00 00 04 00 00 00 00 00 00 00 00   | ................
0010: 00 00 00 00 16 63 00 5d 00 00 00 c0 f4 00 00 5b   | .....c.].......[
0020: 00 80 fd 00 16 65 00 5e 00 00 00 80 10 00 80 16   | .....e.^........
0030: 00 80 02 00 16 72 00 5f 00 00 00 40 f4 00 40 35   | .....r._...@..@5
0040: 00 00 f9 00 16 73 00 2c 00 00 00 00 00 00 00 00   | .....s.,........
0050: 00 00 00 00 16 74 00 5e 00 00 00 00 15 00 c0 fe   | .....t.^........
0060: 00 80 01 00 16 7b 00 5f 00 00 00 c0 12 00 c0 44   | .....{._.......D
0070: 00 00 fc 00 16 7c 00 67 00 00 00 40 02 00 40 40   | .....|.g...@..@@
0080: 00 81 f9 00 16 7e 00 5f 00 00 00 40 26 00 00 4d   | .....~._...@&..M
0090: 00 80 f6 00 16 80 00 55 00 00 01 00 29 00 c0 20   | .......U....)..
00a0: 00 80 f2 00 16 8c 00 39 00 00 00 00 00 00 00 00   | .......9........
00b0: 00 00 00 00 16 8d 00 3a 00 00 00 00 00 00 00 00   | .......:........
00c0: 00 00 00 00 19 02                                 | ......



3.5 Client Parameter Transfer

The client transmits the name, color and other local parameters to the
server. Each parameter is preceded with a 0x04 which is a console command.
The final command is a spawn, which indicates that the client is initialized
and ready to go to runtime. The server will respond with an ack.



struct ClientPlayerData {
        struct Header; // { 0x00, 0x09, 0x00, 0x31}
        struct Sequence; { 0x00, 0x00, 0x00, 0x02 }
        const char tag1[] = "\0x04name ";
        char Name[] // ASCII name
        const char tail1[] = { 0x0a, 0x00};
        const char tag2[] = "\0x04color ";
        char fgcolor[] = // ASCII color number
        const char tag3 = " ";
        char bgcolor[] = // ASCII color number
        char tail3[] = {0x0a, 0x00, 0x04, "spawn ", 0x00};
};

0000: 00 09 00 31 00 00 00 02 04 6e 61 6d 65 20 42 69   | ...1.....name Bi
0010: 67 5f 42 61 64 5f 6a 69 6d 0a 00 04 63 6f 6c 6f   | g_Bad_jim...colo
0020: 72 20 31 33 20 31 33 0a 00 04 73 70 61 77 6e 20   | r 13 13...spawn
0030: 00                                                | .

3.6 Client Sync

The client now instructs the server that it has initialized and is ready to
begin the game.

struct ClientBegin {
        struct Header; // { 0x00, 0x09, 0x00, 0x0f }
        struct Sequence; // {0x00, 0x00, 0x00, 0x03 };
        char Data[7] = { 0x04, "begin", 0x00 };
};

0000: 00 09 00 0f 00 00 00 03 04 62 65 67 69 6e 00                     | .........begin.

3.7 Server Parameter Transfer Phase

This packet transmits the current parameters for all the player on the
server as well as additional lighting information. The final command
instructs the client to advance to sign on state 3, Runtime.

struct ServerParameterPacket {   // length Varies
        struct Header;                 // {0x00 0x10 0x00 0x6f}
        struct Sequence;                // Most significant byte of the packet ordering
        struct DEMTimeStamp          // Some type of time stamp
        struct DEMUpdateClientParamters;
        struct DEMUpdateEntity;
        // There is usually more data appended at this point.

};

Example DEM parsing:

Command: Time
Time = 1183438817.000000
Command: Update Client Data
Health: 100, Ammo: 25, Armour: 0, Weapon: 1
Shells: 25, Nails: 0, Rockets: 0, Cells: 0
Command: Update Entity (ce)
Mask: 4E, Entity: 1, ModelIndex: 0, Frame: 14, Map: 0, Skin: 0, State: 0
Command: Update Entity (80)
Mask: 0, Entity: 15, ModelIndex: 0, Frame: 0, Map: 0, Skin: 0, State: 0
Command: Update Entity (80)
Mask: 0, Entity: 16, ModelIndex: 0, Frame: 0, Map: 0, Skin: 0, State: 0
Command: Update Entity (80)
Mask: 0, Entity: 18, ModelIndex: 0, Frame: 0, Map: 0, Skin: 0, State: 0

[Truncated]

Command: Update Entity (80)
Mask: 0, Entity: 119, ModelIndex: 0, Frame: 0, Map: 0, Skin: 0, State: 0
Command: Update Entity (80)
Mask: 0, Entity: 120, ModelIndex: 0, Frame: 0, Map: 0, Skin: 0, State: 0
Command: Temp Entity
Command: Update Name
player # = 0
Player Name = QuakeBot
Command: Update Frags
Player # = 0
Frags # = 0

Command: Update Colors
Command: Update Name
player # = 1
Player Name =

Command: Update Frags
Player # = 1
Frags # = 0

Command: Update Colors
Command: lightstyle
Light style = 0
Effect String = m
New offset: 69
Command: lightstyle
Light style = 1
Effect String = mmnmmommommnonmmonqnmmo
New offset: 83
Command: lightstyle
Light style = 2
Effect String = abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba

[Truncated]

Command: Update Stat
PlayerState[11] = 6
Command: Update Stat
PlayerState[12] = 0
Command: Update Stat
PlayerState[13] = 0
Command: Update Stat
PlayerState[14] = 0
Command: Set Angle
Vector 0.000000, 90.000000, 0.000000
Command: Set Angle
Vector 0.000000, 90.000000, 0.000000
Command: Update Client Data
Health: 100, Ammo: 25, Armor: 0, Weapon: 1
Shells: 25, Nails: 0, Rockets: 0, Cells: 0
Command: Signon
Action: 3

0000: 00 10 00 6f 00 00 00 14 07 1f 60 91 45 0f 00 46   | ...o......`.E..F
0010: 01 11 00 00 44 64 00 19 19 00 00 00 01 ce 02 0c   | ....Dd..........
0020: 80 f7 80 5b 41 fe df 0c 05 3b 45 01 00 fc ff 49   | ...[A....;E....I
0030: 45 c0 01 9f 0e 06 3d 02 58 ff c5 53 7b 81 fd 01   | E.....=.X..S{...
0040: 9f 0e 07 3d 02 0e f8 41 5a 0f 81 fd fb df 0c 08   | ...=...AZ.......
0050: 3b 3c 01 96 fc 7f 5d b9 41 fe 80 19 84 1b 00 00   | ;<....].A.......
0060: c4 1c 01 e1 ff 80 58 80 5a 80 62 84 63 0c 5b      | ......X.Z.b.c.[

4.0 Runtime Phase

The game has now begun. The server sends out a packet of data every 50 or so
milliseconds that gives the current parameters for everyone on the system.
The client responds with a complementary packet giving the current state of
the system. The client system appears to work by way of digital sampling.
That is, the current state of the machine is frozen and transmitted to the
remote system as opposed to transmitting every little change. Of interest at
this point are the Packet Sequence bytes. These bytes appear to be counters
that increment sequentially with each transmitted packet. This is prevents
packets that follow different routes from getting out of order.

4.1 Keep Alive

This packet's function is to let the destination know that the source is
still present, but is not presently transmitting data. This packet can be
sent by either the server or the client, during either runtime or game
initialization.

struct RuntimeKeepAlivePacket { //
        struct Header; // {0x00 0x10 0x00 0x09}
        long Sequence;  // Network byte order
        char Command;   // 0x01 for keep alive
};

4.2 Disconnect

This packet is transmitted by the client to inform the server that is the
client is ending its session. It is very important for the client to
transmit this packet and not to simply end the connection. Doing so will
confuse the server and require multiple attempts from the next client to
establish connection.

struct RuntimeDisconnectPacket { //
        struct Header; // {0x00 0x10 0x00 0x09}
        long Sequence;  // Network byte order
        char Command;   // 0x02 for Disconnect
};

4.3 Client Movement

The client to server movement packet is of fixed length and contains the
information shown in the structure below. The action byte is a bit mapped
value that represents the state of key presses on the client side. Fire and
Jump have been determined in this area. The run key is not reflected in here
as it is conveyed by an increased value in the inline and lateral velocity.

struct RuntimeClientMovementPacket { // length 24 bytes
        struct Header; // {0x00 0x10 0x00 0x18}
        long Sequence;  // Network byte order
        char Command;   // 0x03 for movement
        float TimeStamp; // Some type of time stamp
        char Roll;
        char Rotation; // Absolute Rotation
        char ViewAngle; // 00: Horizontal, Positive down, negative up
        short InlineSpeed; // Speed in forward/reverse
        short LateralSpeed; // Speed, side to side
        short VerticleSpeed;
        char Impulse; // 01=Fire, 02 Jump
};

0000: 00 10 00 18 00 00 00 00 03 3b 59 91 45 00 00 00   | .........;Y.E...
0010: 00 00 00 00 00 00 00 00                           | ....

4.4 Console Command

This packet is transmitted by the client to instruct the server to perform a
command. The most common use for this function is the say command. The
character string supplied must be terminated by 0x0 and formatted exactly as
the command would be typed in the server console.

struct RuntmeConsoleCommandPacket { //
        struct Header; // {0x00 0x10, 0x??, 0x??}
        long Sequence;  // Network byte order
        char Command;   // 0x04 for Commands
        char String[]; //  The command to send to the server.
};

4.5 Server Packet

The server packet is not several large structures, but a series of
concatenated smaller structures. These packets are buffered and transmitted
all at once to reduce network packet overhead. This was documented in A.
Oliver's Unofficial Quake Network Protocol. It gives reference to the
Unofficial DEM File Format Specifications as the structure for the server
packet. The DEM specs can be misleading. One should follow the code, not the
text descriptions. The type specifications are different and will result in
a mess.

Positioning appears to work in absolute coordinates. For reference, on
start.map, facing the three hallways from the platform, forward is in the
Y-axis direction. Additionally, the rotation value is 0x40 for that
direction, where 0x00 is directly to the right and 0x80 is to the left.

Messages and collisions are sent as DEM messages and will either be
contained in the runtime packet or transmitted in their own packet. Both
have been observed.

struct RuntimeServerPacket {   // length Varies
        struct Header;                 // {0x00 0x10 0x00 0x6f}
        struct Sequence;                // Most significant byte of the packet ordering
        struct DEMTimeStamp          // Some type of time stamp
        struct DEMUpdateClientParamters;
        struct DEMUpdateEntity;
        // There is usually more data appended at this point.
};

Example DEM parsing:

Command: Time
Time = 1183438817.000000
Command: Update Client Data
Health: 100, Ammo: 25, Armour: 0, Weapon: 1
Shells: 25, Nails: 0, Rockets: 0, Cells: 0
Command: Update Entity (ce)
Mask: 4E, Entity: 1, ModelIndex: 0, Frame: 14, Map: 0, Skin: 0, State: 0
Command: Update Entity (80)
Mask: 0, Entity: 15, ModelIndex: 0, Frame: 0, Map: 0, Skin: 0, State: 0
Command: Update Entity (80)
Mask: 0, Entity: 16, ModelIndex: 0, Frame: 0, Map: 0, Skin: 0, State: 0
Command: Update Entity (80)
Mask: 0, Entity: 18, ModelIndex: 0, Frame: 0, Map: 0, Skin: 0, State: 0
Command: Update Entity (80)
Mask: 0, Entity: 119, ModelIndex: 0, Frame: 0, Map: 0, Skin: 0, State: 0
Command: Update Entity (80)
Mask: 0, Entity: 120, ModelIndex: 0, Frame: 0, Map: 0, Skin: 0, State: 0

NO EXAMPLE



5.0 Data Interpretation

The largest problem facing the Bot designer is interpreting the data that is
received. Although you have a lot of information at your disposal, what to
do with it becomes a major concern. In order to fully interact in the game,
several key pieces of information need to be extract form the data at hand.
I will list how I resolved some of these problem. These are not necessarily
the best solutions but they have worked to some limited extent. I am open to
all suggestions if someone comes up with something better.

Some of the information that is needed:

   * Current client status.
   * Identification of your Bot and other players in the server data stream.
   * Location of objects of interest.
   * Navigation.

5.1 Client Statistics

Information on your client is transmitted via the Update Client command.
This command summarizes all information about your current state, including
weapons, armor, orientation and health. It is important to maintain a these
parameters between transmissions since the DEM format only updates
information that changes between updates. Most information contained in the
DEM specs on the Update Client command is self explanatory.

5.2 Player Identification

Well, you know who you are, but how do you find out who the server thinks
you are? This becomes important for determining your absolute coordinates in
the level. Also, you need to find out who else is playing and their
respective statistics.

Each player and any other moveable object in the level are represented by
dynamic entities. These entities are used by the server to encapsulate
information about any given object. They are communicated to the client
through the use of the spawn baseline and update entity commands.

The spawn baseline command creates a dynamic entity. This command is
received once for each new entity at the beginning of the level. Once
created, the entity record is modified through the Update Entity command.
This command is sent to the client for every entity that is in potential
view on every server transmission. Notice the word POTENTIAL. This includes
items that are behind and possibly obscured by other objects. In this way,
the Bot has an advantage in that is knows more about its environment that
the human player does at a given moment.

The QuakeBot's entity can be identified by the Set View command. This
commands specific which entity is the current viewpoint for the camera.
Individual players are identified by their respective names sent through the
Update Name command. This combined with the Update Frags command gives the
most accurate source of player statistics.

The current life/death state of an opponent appears to be obtained through
the model frame value. This value changes for each variation in
representation of an entity. It appears that certain model frames represent
death frames and from this, one can determine the death of a player. Once a
player dies, its entity changes to a death frame. After regeneration, the
body is represented by another entity number > MAXCLIENTS + 1 and the player
entity again represents the opponent.

5.3 Object Identification

Currently, the only way to determine an object in the wad is through mapping
the .mdl files through the precache table to find out what it is. This is a
very grisly approach and will not stand custom modifications. Quake has to
positively identify health packs, weapons, etc. to the game, therefore,
there must be some mechanism to tell the function of the entity. I have
noticed a descriptor in the .MAP file specs that might be of use, but this
gets compiled and I don't know where it goes afterward.

5.4 Navigation

Eeeeek. This is a nasty problem. For simple functional tests, you can
calculate paths as the crow files and pray that nothing is in between you
and your target. Unfortunately, this is rarely the case. Most levels use
insidious transport mechanisms to make getting some objects more difficult.
Combine this with a little gratuitous BSP tree traversal and you have got
yourself an A-1 mess. Just a few of the navigation issues:

  1. Transporters - Easy but requires a little 4th dimensional thinking
  2. Elevators - Single levels aint bad, but multilevel systems are hairy.
     Don't forget the push to activate type!!!
  3. Moving Platforms - A variation on the elevator theme, but more
     possibilities.
  4. Jumps - I can't figure out how to make some of the jumps, but the bot
     might. The question is how to figure out the need to jump to begin
     with.
  5. Water - Probably not really that bad of a problem, but it still gives
     me the creeps.
  6. Traps - The bot can see them better than people, but what to do is
     another issue.
  7. Dynamic Path Changes - Some paths reorient themselves based on a button
     or other gizmo. I don't even want to think about this one. Maybe avoid
     these areas?

6.0 QuakeBot Functional Architecture

The current QuakeBot C/S architecture is divided into the following
sections:

   * Socket Layer
   * Network Services Layer
   * Primitive Command Layer
   * Heuristics Layer

6.1 Socket Layer

This, the lowest level of the QuakeBot C/S architecture, handles basic I/O
between network nodes. Currently, it implements TCP/IP, but will evolve into
IPX in time. Its basic form of communication is a raw packet:

void SocketObj::SendPacket(char *Data, int DataLen) - Sends buffer to IP
specified by object. Data is raw.

int SocketObj::GetMessage() - Receive data from IP specified by object. Data
is raw.

void AddTimeoutHandler(long Timeout, void (*Handler)(void)) - Adds routine
to handle receive time-outs.

6.2 Network Services Layer

This layer is burdened with the task of handling communications between the
Quake server and the QuakeBot Host. It also handles communications between
bots, referred to here as interbot communications.

The server communications functions consist of creating a virtual circuit
through the UDP data stream by interpretation of the Quake packet sequence
numbers and implementing the C/S handshake protocol. This results in a
seamless data stream presented to the command layer. The commands
implemented in the layer are:

void PacketObj::SendMessage() - Sends a packet to the destination specified
by the object. Sequencing, and Packet Length are automatically handled.

int PacketObj::GetMessage() - Receives a packet from a remote system
specified by the object. Out of sequence packets are dropped until next
proper value is received. Returns the number of bytes received.

BotObj::ConnectBot() - Establishes a session with a peer bot.

BotObj::DisconnectBot() - Drops connection.

BotObj::SpawnBot() - Create a new Bot on same machine (if possible, I dunno
yet)

QueryBot(char *IPADDRESS) - Queries unconnected bots.

void BotObj::Message(CommandObj Command) - Sends a message to peer bot
informing of completion of a task.

6.3 Primitive Command Layer

The command layer implements the functions for sending the server movement
and attack commands. It also implements the commands necessary for sending
and receiving of directives to and from peer bots. It would necessarily
implement map traversal and map inventory, including regeneration time for
important entities.

void PlayerObj::SendBroadcastMessage(const char *String) - Sends a message
to server. Greetings, taunts, abuse, etc.

int PlayerObj::Aim(PlayerObj Player) - Changes player command variables to
aim at player. Returns the distance to player.

int PlayerObj::Distance(PlayerObj Player) - Calculates distance to player in
three dimensions.

int PlayerObj::SelectBestWeapon(void) - Selects the most powerful weapon
based on the weapons in inventory and current ammo.

int PlayerObj::Dead(void) - Determines if a player is dead.

int PlayerObj::SelectSafeWeapon(void) - Selects the most powerful weapon
based on the weapons in inventory and current ammo. Rocket and Grenade
launchers are excluded to prevent shooting into a wall and killing your
self.

6.4 Heuristic Command Layer - Preliminary

This is the bot's brains. The QuakeBot C/S specification defines, but does
not include this layer. It is intended to be supplied by the end user. Our
intention is to provide a framework where by individuals with minimal
network programming experience can develop their own heuristic modules that
are functionally compatible with the interface. This module may either
access the lower level routines through DLL calls or program hooks. Both are
to be defined once the command level functionality is in place.

int BotObj::GotoXYZ(struct Coord) - Instructs a peer bot to traverse map to
get to location XYZ. Returns path distance or -1 if the point is
unreachable.

int PlayerObj::Track(PlayerObj Player, int Distance) - Finds Player and
keeps within a specified distance.

void PlayerObj::Evade(PlayerObj Player) - Evades Player.

struct Coord Find(EntityObj Entity) - Returns nearest Entity. Weapon, armor,
health, powerup, etc.

struct Coord FindNext(EntityObj Entity) - Returns next nearest Entity.
Weapon, armor, health, powerup, etc.

int Exist(EntityObj Entity) - Returns the a normalized probability of the
existence of Entity based on last appearance and regeneration times.

6.4.1 Navigation Object

Navigation algorithms should be modular. This would allow a bot to be
upgraded to a new navigation rev if someone comes up with a better
algorithm. The higher heuristic levels would be able to benefit from more
accurate navigation without changing their underlying functions. I would
propose a Navigation object. This object would exist in a separate thread,
operate on the BSP tree directly and encapsulate the following data :

struct Movement - Returned commands would be in the form of vectors to new
locations. The it would be up to the player object to determine how to
complete the move accounting for velocity and acceleration. A Flag would be
necessary to differentiate between a ramp/stair system and the need for a
jump. Also, some way of conveying timing information for the player is
needed for dynamic platforms, elevators and the like. Ex. Entity x at
(0,0,0) then proceed.

struct Movement NavObj::FirstPath(PlayerObject Player, struct Coord) -
Return the first move to get to locations XYZ. Returns path distance or -1
if the point is unreachable.

struct Movement NavObj::NextPath(PlayerObject Player, struct Coord) - Return
the next move to get to locations XYZ. Returns path distance or -1 if the
point is unreachable.

7.0 Bot Communications Language

The Bot Communication Language specification allows bots created by
different authors to communicate through a common interface. The need for
this may not be readily apparent as it should be obvious that a client bot
by itself can be a far superior opponent to a human player. So why
communicate?

There are applications for client bots that exceed the traditional
deathmatch opponent role. They could be used as referees or as intelligent
data collectors. To provide complete coverage of a level, several bots could
be deployed. Each could perform a separate function or cover a section of a
level. Interbot communications could help coordinate this complicated task
by allowing the bots to keep track of each other. For the true cyber
challenge, teams of bots could challenge other teams to find out who is the
better opponent.

Communications via sockets would provide a robust method of transmission.
Sockets allow point to point communications, relieving the burden placed on
a Quake server. The question of fairness arises in this situation since
other players would not be aware of the information exchange between
clients. It should be obvious that interbot communication as a whole is so
completely unfair that it really makes the question irrelevant. IBC should
be reserved for high level functions or bot vs bot team competitions.
Anything else is equivalent to squirrel hunting with a bazooka.

...but sometimes that squirrel is just beggin' for it. ;)

In this case, a bot can display a little diagnostic information that might
give the humans a slightly larger edge.



7.1 Bot Information

The client transmits a broadcast packet to determine what bots are on the
span. This is responded to with a directed broadcast response from a bot
giving current its current parameters. It also contains the initialization
port for initial connection. It is the same format as the QUAKE broadcast
packet but substitute "QUAKEBOT" for the "QUAKE" string). Query port is
27000 by default.

struct BotQuery {
        struct Header                           // { 0x80, 0x00, 0x00, 0x0F };
        char OP_CODE                            //
        char Data [ ] = "QUAKEBOT"
        byte net_protocol_version NET_PROTOCOL_VERSION; // 0x03
}

struct ClientResponse {
        struct Header;                          //{ 0x80, 0x00, 0x00, ....}
        char OP_Code;                           //
        char Name[];                            // Bot Name
        byte VersionID                          //
        char VersionString[];                   // Client Specific Version String
        short Port;                             // This is your IBC port
};



7.2 Bot Connection Request

The client transmits a directed packet to the bot with a connect request.
The bot responds with a new port to connect to for all future
communications. It is similar to a connect packet but has a password, Could
be null for low security set up. Query port is 27000 by default. The bot
returns a runtime port. Once authenicated, the bot will use the runtime port
for all comm. otherwise a reject message.

struct BotConnect {
        struct Header ;                        //{ 0x80, 0x00, 0x00, 0x0c}
        char OP_Code                           // 0x01
        char Data [ ] = "QUAKEBOT"
        char UserID [ ] = "USERID"
        char Password [ ] = "Password"
};

struct BotConnect Response {
        struct Header;                          // { 0x80, 0x00, 0x00, 0x09 }
        char OP_Code;                           // 0x81 This is CCREP_ACCEPT
        short Port;                             // This is your port assigned
                                                // by the server
};

Below would be a reject response:

struct BotConnect Response {
        struct Header;
        char OP_Code;                           // 0x82 This is CCREP_REJECT
        char Data[];                            // A string telling you why;
};



7.3 Bot Runtime Commands

These would be unreliable packets that would combine a series of commands to
be sent to a Client Bot. The format would be a series of appended commands
similar to the DEM commands structure (minus the code compression). Some
commands would server two purposes, such as Set/Report. These functions
would be interpreted differently depending on the mode the bot is in. For
example, a bot running as a master would interpret a Set/Report Location
command as a report while a slave would see it as a set command.



struct BotRuntime {
        struct Header ;                        //{ 0x00, 0x10, 0x00, 0x0c}
        char Command;
        char Data [ ];
        char Command;
        char Data [ ];
        ...
};



7.3.1 0x00 Illegal Instruction

This would be an illegal instruction to catch invalid data



7.3.2 0x01 - No Operation

This command would be used by itself in packet to perfrom a keep alive
function.



7.3.3 0x02 - Disconnect

This would instruct another client that the bot has been disconnected.



7.3.4 0x03 - Update/Report Bot State

This updates a value stored in the Bot Client State

Byte Index
Long Value

7.3.5 0x04 - Get Bot State

This requests an update for a value stored in the Bot Client State

Byte Index

7.3.6 0x08 - Print

This instructs a bot to print a message

char[] String

7.3.7 0x0A - Set/Report Angle

This instructs a slave bot to face in a certain orientation or informs a
master of the bot's orientation

Angle View[0];
Angle View[1];
Angle View[2];

7.3.8 0x0B - Get Angle

This instructs a bot to send its orientation



7.3.9 0x0C - Set/Report Location

This instructs a slave bot to go to a certain location or informs a master
of the bot's location

Coord Map[0];
Coord Map[1];
Coord Map[2];

7.3.10 0x0D - Get Location

This instructs a bot to send its location



7.3.11 0x0E - Report Ownership

This informs player that another player has a certain object

Byte PlayerID
Long ObjectID

7.3.11 0x1B - Kill/Killed Player

This informs a master that a bot has killed an opponent or instructs slave
to attack a certain player. The latter is particularly useful in a two on
two coordinated attack.

byte Player

7.3.11 0x1C - Killed By Player

This informs a master that a bot has been killed by an opponent.

byte Player

8.0 Additional Functions

The following courtesy functions should be implemented to allow server
operators to ban bots. Also, individual players can determine whether they
wish to compete with the bot.

   * "I hate bots" - Player looking for extra challenge. The bot will target
     this player over others.
   * "I love bots" - Player wanting to avoid the bot. Good for newbies. Bot
     should attack if shot, tho.
   * "No bots" - Server command that would instruct the bot to immediately
     log off. Can be issued by other players also.

9.0 Experimentation

So, ya wanna play? Well, you can, sorta. You have enough information here to
establish a connection and move around. Just copy the client side packets
and acknowledge the server packets. You don't have to worry about doing
anything with the server info, just ignore it. The server does all movement
calculations and collisions. Once you have completed initialization, send
the client packet with a continuously increasing sequence and you should see
the results if another player is standing by. I have released a version of
C++ source that will perform this task for you.

8.1 Stupid Client Tricks - Quake Client as a Monitor

One will notice that in cases of extreme network lag, the client will
freeze. It requires a continuous flow of data and updates its display based
on it. It is this point that brings up a interesting characteristic that can
be used to the botsmith's advantage. The earlier problems of DOOM's
synchronization have been eliminated by the client/server protocol in that
the client is operating as a terminal, albeit a pretty damn bright one. Can
this terminal be used for purposes other than a strict Quake player.

The answer: YES. What will this allow me to do you ask? Let says for example
that you have a client/server bot running around the map, but you are
getting tired of chasing it down using another player just to see what it is
doing. Well, chase no more. How about designing a server proxy? It runs on a
separate system and looks like server to all quake clients. Modify it to
take commands from one client and display the results to another. It's very
simple, all you need to do is change the IP address and forward it to the
server and vice versa for the server packets. You also need to add set view
angle commands to reset the spatial orientation of the client. All
communications to the server from the proxy appear as one quake session. It
can take client commands from the bot client and display the results in the
quake client window. Now your bot has eyes. No need to reinvent the wheel.
Not bad, eh?

If you have some problem getting anything to work, drop me a line and I will
check my typing. Good hunting!

----------------------------------------------------------------------------

                        Return to The QuakeBot Page
