ProtocolZero
ProtocolZero is the command protocol used for directly talking to quagents. All commands and responses are sent as ASCII text on top of TCP. ProtocolZero is for agent-based communication, not for the experimental control.
The lifecycle of a connection has two phases: an "initial" phase where the user can enter various setup commands, and a "live" phase, where the user is interacting with a bot in the environment.
You should probably read TutorialTelnet before reading this document.
Command Channel vs Event Channel
ProtocolZero communications are split over two different channels (which are implemented by two different sockets). The primary channel is the "command channel". The user sends commands on the command channel and receives responses. The command channel's responses are generally very predictable: every command responds and reports in order of execution, and no unexpected messages should ever arrive. (Though some commands make a variable number of responses, a set of responses is always terminated by a final report when the command ends.) Every quagent is required to have a command channel connection. Any connections to port 6000 while URCS Quagents3 is running will result in a new command channel and (eventually) the creation of a new quagent.
The secondary channel is the "event channel". Use of this channel is optional. It is used for two purposes: first, for event-based data that has nothing to do with any particular command on the command channel (for example, if another bot executes a say command, it will generate an event on all nearby quagents' event channels, even though they had no command tied to that particular event). Like command channels, event channels have a one-to-one mapping to quagents, but they must be setup after the command channel is. To get an event channel connection, connect to port 6001 while URCS Quagents3 is running (you must have a simultaneous connection to port 6000 as well). More on this below.
Client to Server Messages
Commands sent in the initial phase are simply ASCII strings of the form CMD PARAM. The final initial command given is "ready", after which the bot is spawned, and the connection enters the live phase. Live commands are in the format A BB IDNUM PARAM_1 PARAM_2 PARAM_3 PARAM_4... \n
- where A is either a 't', 'r', or 'n' character, for 'then', 'replace', or 'now', specifying scheduling (see below).
- where BB is the opcode of the instruction (always 2 characters).
- where IDNUM is a sequence of numeric characters representing an unsigned 32-bit integer. This code will be stated as part of the command's report, but is otherwise unused.
- where P1... are parameters for the instruction, and may be any length. They are delimited by single spaces. Parameters should be printed in ASCII, so 253 is '2','5','3', not '\253'. Floats are interpreted by the atof() function.
- and \n is a newline. I think carriage returns will work just as well.
Quagents model their behavior in the form of a double-ended queue that has a maximum capacity of 1024 commands. Commands can be pushed onto either the front ("now" commands) or the end ("then" commands). Additionally, the front command can be atomically replaced by a new command ("replace" commands).
Server to Client Messages
In the initial phase of a connection, the server never sends messages back to the client until the final step: when the client issues a "ready" on the command stream, it responds "id X" where X is the entitynum of the quagent that belongs to that command stream. The same is true on the event stream: when the client issues an "identity X" (where X is the entitynum of the quagent), the server will respond "ready" on a successful connection (or give an error message if there is a problem).
In the live phase of a connection, there are four kinds of messages the server sends back over the channel: "er" (system error), "cp" (completion reports, hereafter called "reports"), "rs" (responses), and "ev" (events). The general idea of these messages is:
- "er" only appears if there is a serious problem that will circumvent one or more of the below contracts. For example, if the user issues too many commands to the quagent, the quagent's command queue may fill up which will result in further commands not being added but an "er [opcode] [idnum] queueful" reply.
- "rs" appears when a command asks for information. The information is always carried in an rs, rather than a cp.
- "cp" only appears once a command is completely done sending any information back (so all "rs"s or "ev"s have been sent). Each command will either eventually reply with a "cp" or will never reply because it never completes execution (for example, it is interrupted by some other command that takes infinite time to complete, such as [pa]).
- "ev" only appears in the event channel, and is prompted by the actions of other quagents or the environment.
Following one of the four message type idenfitiers, the opcode of the relevant command will be issued, followed by the idnum provided when the command was issued. Then, any additional data is stated, and the response is terminated by a newline. So messages are of the form: "TY OP IDNUM DATA" (terminated by newline). See below for examples.
Example Quagent Session
All strings here are terminated in a newline. In a program like telnet, this will typically be automatic for you, but if you're writing your own socket code, be sure to separate commands with newlines.
- User connects using telnet to open a connection to socket 6000.
- User types: "name ExampleBot"
- User types: "ready"
- Quake spawns the bot in a spawn location and names it "ExampleBot".
- Quake responds: "id 1"
- User types: "n mi 1 0 0 1"
- ExampleBot starts moving forever directly forward at full speed.
- User types: "n pa 2"
- ExampleBot pauses motion.
- User types: "n hc 3"
- Quake responds: "rs hc 3 100"
- Quake responds: "cp hc 3 done"
- User types "n po 4"
- Quake responds: "cp po 4 done"
- Quake responds: "cp pa 2 popped"
- ExampleBot resumes motion.
List of Commands
INITIAL PHASE (COMMAND CHANNEL)
- name - sets what the name of the bot will be when it spawns. Takes one argument:
- string name
- botfile - sets the botfile of the bot. Among other things, this determines the bot's in-game model, soundset, and various other details. See botfiles for a list of options.
- string filename
- skill - sets the skill level of the bot, which selects subsections from the botfiles.
- integer skill
- team - sets the team of the bot ("red" or "blue") in CTF or team deathmatch mode.
- string team
- password - sets the password of the bot's event channel. If this command is not issued, the password is the empty string. The password should not contain spaces.
- string password
- initialpos - sets the starting location of the bot. If this command is not issued, the game will select a default spawn location from the map. The location should be specified by three coordinates separated by a single space. This has the potential to spawn a quagent inside a floor or wall, so be careful.
- float x
- float y
- float z
- ready - spawns the bot. Takes no arguments. Replies with "id X" where X is the entityid of the bot. An entityid is a unique integer identifier.
INITIAL PHASE (EVENT CHANNEL)
- identity - attempts to link the socket into a live quagent. Takes two arguments (the second is optional, see password above):
- int entityid
- string password
LIVE PHASE (COMMAND CHANNEL)
- Movement: (non-atomic)
- mi - "Move Indefinitely". Takes three arguments:
- int obstacles
- float direction
- float speed
- mf - "Move For". Takes four arguments:
- int obstacles
- float direction
- float speed
- float time
- mb - "Move By". Takes four arguments:
- int obstacles
- float direction
- float speed
- float distance
- mt - "Move To". Takes four arguments:
- int obstacles
- float speed
- float X
- float Y
- ju - "JUmp once". Takes two arguments:
- float direction
- float speed
- ro - "ROtate". Takes two arguments:
- float yaw
- float pitch
- mi - "Move Indefinitely". Takes three arguments:
- Basic Actions (atomic)
- fw - "Fire Weapon". Takes no arguments.
- sw - "Switch Weapon". Takes one argument.
- int weapon
- sc - "Set Crouch". Takes one argument.
- int crouching
- sv - "ShoVe". Takes three argument.
- float strength
- float shoveangle_yaw
- float shoveangle_pitch
- sy - "SaY". Takes two arguments. (See description.)
- float volume
- string message
- pu - "Pick Up". Takes no arguments.
- pd - "Put Down". Takes two arguments.
- int item
- int quantity
- Basic Queries (atomic)
- hc - "Health, Current". Takes no arguments.
- hm - "Health, Maximum". Takes no arguments.
- ac - "Armor, Current". Takes no arguments.
- am - "Armor, Maximum". Takes no arguments.
- lc - "Location, Current". Takes no arguments.
- fc - "Facing, Current". Takes no arguments.
- cs - "Can See". Takes one argument.
- int entityid
- ra - "RAdar". Takes one argument.
- float range
- wi - "What Is". Takes one argument.
- int entityid
- mc - "aMmo, Current". Takes one argument.
- int weapon
- rf - "RangeFinder". Takes four arguments.
- int mode
- int range
- float yaw
- float pitch
- ci - "Check Inventory" Takes no arguments.
- Complex Sensors (atomic)
- Command Queue Management (atomic)
LIVE PHASE (EVENT CHANNEL)
LIVE PHASE (DIRECTOR CHANNEL)
- God Actions
- sh - "Set Health". Takes two arguments:
- int id
- int newhealth
- sa - "Set Armor". Takes two arguments:
- int id
- int newarmor
- sg - "Set Gravity". Takes one argument:
- float gravity
- gm - "set Gametype and Map". Takes two arguments:
- int gametype
- String map
- su - "Speed Up". Takes one argument:
- float factor
- sm - "SlowMo". Takes one argument:
- float factor
- dr - "DRop". Takes five arguments:
- int item
- int quantity
- float x
- float y
- float z
- ps - "Pause". Takes no arguments.
- ss - "ScreenShot". Takes no arguments.
- fo - "Follow". Takes one argument.
- int clientNum
- sh - "Set Health". Takes two arguments:
- God Queries
- gh - "Get Health". Takes one argument:
- int id
- ga - "Get Armor". Takes one argument:
- int id
- gg - "Get Gravity". Takes no arguments.
- gp - "Get Position". Takes one argument:
- int entityid
- fd - "Find Distance". Takes six arguments:
- float x1
- float y1
- float z1
- float x2
- float y2
- float z2
- iw - "Is Within". Takes four arguments:
- int id
- float x1
- float y1
- float z1
- float x2
- float y2
- float z2
- gh - "Get Health". Takes one argument:
- God Events