== 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 [[sy|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. See [[botfiles]] for a list of options. FIXME: problem loading bot models? * 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: ([[AtomicActions|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 * Basic Actions ([[AtomicActions|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 ([[AtomicActions|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|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. * ''[[fo]]'' - "Follow" Takes no arguments * Complex Sensors ([[AtomicActions|atomic]]) * ''[[rb|rb]]'' - "Rangefinder, Batch". Takes eight arguments. * int mode * int range * float starting_yaw * float starting_pitch * int width * int height * float pixel_delta_yaw * float pixel_delta_pitch * Command Queue Management ([[AtomicActions|atomic]]) * ''[[po]]'' - "POp". Takes no arguments. * ''[[pa]]'' - "PAuse". Takes no arguments. * ''[[fa]]'' - "Forget All tasks". Takes no arguments. * ''[[fm]]'' - "Forget Most tasks". Takes no arguments. * ''[[sk]]'' - "SKip". Takes no arguments. * ''[[pk]]'' - "PeeK". Takes one argument. * int depth '''LIVE PHASE (EVENT CHANNEL)''' '''LIVE PHASE (DIRECTOR CHANNEL)''' Currently, all god actions print to the game console instead of sending messages back through the socket. * God Actions * ''wiki:sh'' - "Set Health". Takes two arguments: * long botid * int newhealth * ''wiki:sg'' - "Set Gravity". Takes one argument: * float gravity * ''wiki:sa;; - "Set Armor". Takes two arguments: * long botid * int newarmor * God Queries * ''wiki:gh'' - "Get Health". Takes one argument: * long botid * ''wiki:ga'' - "Get Armor". Takes one argument: * long botid * ''wiki:gg;; - "Get Gravity". Takes no arguments. * ''wiki:gp'' - "Get Position". Takes one argument: * long botid * ''wiki:fd'' - "Find Distance". Takes six arguments: * double x1 * double y1 * double z1 * double x2 * double y2 * double z2 * ''wiki:li'' - "LIsten". Takes two arguments: * double x * double y == Not Yet Implemented Commands == (for URCS Quagents team reference) '''LIVE COMMANDS''' * Basic robot-like functions for users who want low-level fine control. (Implement first) * get [ENTITYID] - picks up an item from the environment * drop [ENTITYID] - drops an item from inventory - maybe not entity but itemtype? Hm. * look [...] - sends an image over the socket back to the user representing what the agent can see - may be zoomed or variable-resolution? Use OpenGL. * lookdepth [...] - like look, but sends the OpenGL Zbuffer not framebuffer back over the socket. '''GOD''' * getPositions [VOID] - returns list of all Quagent positions. * setGravity [GRAVITY] - sets global gravity. * slomo [SLOW_FACTOR] - slows down all game actions by SLOW_FACTOR. * speedup [SPEED_FACTOR] - speeds up all game actions by SPEED_FACTOR. * drop[ITEM,LOCATION] - places ITEM at LOCATION. * move[BOT,LOCATION] - moves specified Quagent to specified LOCATION. * look[POSITION,DIRECTION] - produces a snapshot taken from POSITION facing DIRECTION. * findDist [POSITION1, POSITION2] - returns the distance between two points. * setHealth [BOT,HEALTH] - sets Quagent's health to HEALTH. * setArmor [BOT,ARMOR] - sets Quagent's armor to ARMOR. * isWithin [BOT,SPACE] - determines if Quagent is within the specified SPACE. * listen [POSITION] - listens for Quagent communications at the given POSITION. * pause [VOID] - global pause. calling this while paused acts as a resume.