wiki:ProtocolOne

Version 33 (modified by jherwitz, 13 years ago) (diff)

--

ProtocolOne

ProtocolOne is the Java API which abstracts the Quagents game engine to a simple Java interface. The underlying clientside structure maintains data transmission, reception, and storage, while providing an API for Quagent actions and queries. Named for its level of abstraction, ProtocolOne builds on ProtocolZero, allowing easy access to its hooks through a functional interface. The interface aims to provide the user easy access to Quagent commands, while handling all client/server interaction, data formatting, and data storage, internally.

For API code documentation, see the Javadoc. This wiki will focus mainly on the usage of ProtocolOne (intended for users, rather than developers), while the Javadoc will provide a comprehensive specification of the ProtocolOne API.

Overview

An atomic Quagents scenario contains two phases of execution, an Initial Phase? and a Live Phase?. During the Initial Phase?, users may specify pre-spawn attributes (e.g., initial spawn position or the Quagent's in-game name). The user may not call Quagent actions or queries during this stage. During the Live Phase?, Quagents are spawned and active in the scenario. All Quagent actions and queries are unlocked for the user to utilize. The API contains two distinct function types, which correspond to the aforementioned phases. These phases are disjoint - a "Live Command" may not be used during the "Initial Phase", and vice-versa. These are:

Flow of Execution

To create a Quagent, simply instantiate a new client using the Client constructor. The constructor takes one argument, which must specify the IP address of the Quagents server.

Example:

Client quagent = new Client("127.0.0.1");

Now, before the bot spawns, you may use initial commands to specify certain static parameters. These are optional. When you have completed these modifications, call the ready() function to initiate the live section of the session.

Example:

quagent.ready();

During the live section, you are free to call any ProtocolZero or ProtocolOne functions you wish (with the exception of initial commands).

Example:

//this will make the Quagent face and shoot at the user. 
while(true){
    quagent.faceEntityDirection(0,1);
    quagent.fireWeapon(1);
}

Command Structure

ProtocolOne provides the user two ways of executing Quagent commands. Both of these adhere to a distinct programming paradigm - one method is Object-Oriented while the other is Functional. These methods are (approximately) equivalent in usability and accessibility, so the user may choose to use whichever paradigm is preferred. The user may choose to execute commands by either explicitly instantiating the command objects or calling a relevant function. Internally, all commands are represented as command-specific objects. These objects handle writing the specified command to the server, automatically update data fields with any relevant server data response, and maintain auxiliary data related to the command, such as command exitcode? and runtime. To execute a command explicitly using the object, simply call the member function run(). Function calls automatically instantiate, run, and return the relevant object. It is important to note that all Commands are implemented as TimerTasks, so a user may easily implement an application involving high-level scheduling or planning using Timers (this is actually how the periodic execution is implemented). It is recommended that users new to Quagents use the command functions, as these provide a more intuitive command interface and also allow the client to record any results in its command history (although this may be moved into the Command class to ensure identical functionality between both methods of execution). Command objects may be reused an arbitrary number of times, to reexecute the same command.

Example The following two code blocks are functionally identical. Functional

client.fireWeapon();

Object-Oriented

FireWeapon fw = new FireWeapon(2, client.qid, client.getWriter());
fw.run();

Retrieving Data

Client/Server? data response in Quagents 3 is asynchronous. Thus, the object-oriented and functional methods of execution do not directly return related data. Instead, the user gets a reference to the related command object. This object automatically updates data specific to itself as it is read from the socket. The user must poll this object using object query functions to gain access to data. It is important to note that these object poll functions block for a response from the server. The following example illustrates the interaction.

Example The following code blocks are functionally identical. The functionality of the code is to access the Quagent's current health.

client.currentHealth().getCurrentHealth();
CurrentHealth ch = new CurrentHealth(1, client.qid, client.getWriter());
ch.getCurrentHealth();
CurrentHealth ch = client.currentHealth();
ch.getCurrentHealth();

Periodic Commands

The clientside structure has built-in support for periodic commands. Simply add an integer parameter to the end of any command function or constructor and the client will automatically execute the command systematically using the integer as the period. These commands are useful when it is desired

Example The following illustrates the usage of a periodic command.

CurrentArmor updatedarmor = client.currentArmor(1000);

//arbitrary code

//now, we can call this whenever we want the Quagent's current armor,
from the nearest second.
updatedarmor.getCurrentArmor(); 

Multiple Quagents

Using multiple quagents is as simple as creating multiple Client objects, and following the same steps as above for each.

Example

		Client client = new Client("127.0.0.1");
		Client client2 = new Client("127.0.0.1");
		Client client3 = new Client("127.0.0.1");
		client.name("Bo");
		client2.name("Luke");
		client3.name("Daisy");
		client.ready();
		client2.ready();
		client2.moveForever();
		client2.followEntity(client.qid);
		client3.ready();
		client3.switchWeapon(weapon.SHOTGUN);
		client3.say("Y'all get back here!");

Example behaviors

  • These assume that the Client object (which represents a Quagent) has been instantiated as "client".

Take an depthmap of the player.

client.faceEntityDirection(0,1);
client.showImage(1);