This tutorial can be applied to PogamutUT2004 and will mostly hold for PogamutUDK examples.
Purpose of this first tutorial is to get you familiar with basic concepts which will be needed in further tutorials. We will show how to create a simple bot that will just stands in the environment talking about wether forecast. It is a Pogamut's analogy of the "Hello world !" program - a simple program used to demonstrate basics of given technology.
This example is installed by Pogamut UT2004 installer. In NetBeans click New Project -> Maven -> Project From Archetype -> Local Archetypes Catalog and select 00-empty-bot-archetype project. Moreover, as Pogamut 3 has been fully mavenized, you can try and run this example even without installing the Pogamut NetBeans plugin. However in that case you won't be able to use visualization as this is a part of Pogamut NetBeans plugin. To set up this example follow up the steps in Pogamut 3 with Maven Quickstart Tutorial and in the last step fill up following information into Maven Archetype dialog:
For UT2004 example:
cz.cuni.amis.pogamut.ut2004.examples
00-empty-bot-archetype
3.3.0
http://diana.ms.mff.cuni.cz:8081/artifactory/repo
For UDK example only change
to cz.cuni.amis.pogamut.udk.examples and 3.2.5-SNAPSHOT . The rest remains the same. You will find up-to-date list of available archetypes inAfter setting up the example according to the section above, a new project named "00-empty-bot" will be opened in the Projects tab, open project's Source Packages sub folder and then the package present in this folder
Note that sometimes instead of "00-empty-bot" you get a project with the name "badly formed maven project". In this case simply right click the project and select
option. The project should reappear normally. If the project is reporting some bugs right click it and select the option again. The bugs are reported probably because Maven has not yet downloaded all dependencies (Clean and Build option assures that). If the Javadoc of the project is missing (help does not show up), right click the folder and select option.Finally double click EmptyBot.java
file
containing the source code of your first bot
Notice that the project's node in Projects tab is in bold, this means that the (F6) and (Ctrl + F5) buttons are linked to this project. Before we start your first bot, we have to launch the Unreal Tournament dedicated server - an environment simulator that Pogamut and the bot will connect to. You have two options how to start the server:
First way - start standalone server
execute the server by running
startGamebotsDMServer.bat
, wait until
START MATCH
string appears
in the console, now the server is ready to receive bot
connections. Shortcut to bat file startGamebotsDMServer.bat
can be found
in the start menu under Pogamut folder. File startGamebotsDMServer.bat
can
be found in /UT2004/System/ directory.
let the server console window opened and return back to Netbeans, switch to Services tab (Ctrl + 5 or → ), right click UT2004 Servers node and select action
in the dialog that will appear you can optionally
assign Server name, e.g..
Local UT
and you have to specify
server's complete URI (first delete the
[not set]
string and then
type the URI), in this case
localhost:3001
then press
button (if localhost does not work, try 127.0.0.1:3001 instead).
just created Local UT server will appear under the UT2004 Servers node, you will have to create this server only once, it will remain registered in the IDE
Second way - start server through UT2004 GUI.
Start UT2004 game through shortcut in the start menu or by running UT2004.exe in UT2004/System/ directory.
In the UT2004 game menu click
In the next menu select
tab and select some of the GameBots2004 game types.After you finished setting up the server, click listen button located in lower right. The server will be started and you will be connected to it as a player.
Connect to server from NetBeans the same way as shown above.
Now the server is running and the IDE knows how to connect to it. You can start the bot by pressing F6 ( ). Alternatively, you can simply right click the main bot class and select or select the project and click . If everything works fine, the bot will connect to the server and begin execution. After starting, the bot will appear under the Local UT node in Pogamut bots folder. It will be represented by a node named EmptyBot. If you select the bot's node, you will see some additional information about the bot in Properties window ( → ). Agent3D section shows properties defining bot's position in the space, Agent configuration section enables you to change bot's behavior/abilities (e.g. if the bot will be able to use raycasting, if it will automatically pick up items etc.). You will see that the bot is standing still, no movement, no rotation, after all, that's what it was designed for.
To see how the bot is doing in the game you will have to start the Unreal Tournament (UT) client, you can:
Start the UT directly from Netbeans
Right click Local UT server node and select action, the UT2004 will start in the spectate mode and it will be automatically connected to the selected server.
Start UT in a standard way
You can either use
When starting the UT for the first time it will open in a full screen mode, when developing bots you will often want to see both the Netbeans window and the UT. You have two options - use two monitors or configure UT to start in windowed mode, you can do this from main menu of UT Resolution panel → uncheck the checkbox.
→ tab →Inspecting the bot directly in UT is a very handy debugging tool. You can see, where the bot exactly is, whether it has stuck etc. Gamebots, Pogamut's extension of the Unreal Tournament, also adds some in game visualization features that can be useful when observing the bot.
Once the UT has connected to the game, press the left mouse button to view the bot. Also notice the green text in the upper half of the screen labeled GAMEBOTS 2004 HUD HELP (press ALT + H to trigger HUD help on and off). You can try some of the listed functions, but we will address them later on.
If the UT window seems to be not reacting to your key presses, try to press ALT key again - sometimes when switching between windows through ALT + TAB, the ALT button is left hanging in UT2004 with UT2004 thinking you are still pressing it even if you are not.
Now return back to the Netbeans (if UT was in full screen mode use ALT + TAB). We will go through bot's source code in order to describe its basics.
The EmptyBot extends UT2004BotModuleController
class,
this is declared by line:
public class EmptyBot extends UT2004BotModuleController
UT2004BotModuleController
is a base bot class that will
suit most situations. UT2004BotModuleController
class has
several methods that have to be overridden by the EmptyBot and
by any other bot extending this class.
These methods are:
logic()
- method called
periodically by an internal thread associated with the bot. It
enables the bot to be proactive, that is to act "on his own"
without any external stimuli.
botKilled(BotKilled event)
- called
each time the bot has died
botInitialized(GameInfo info, ConfigChange config,
InitedMessage init)
- called when the bot received INITED message from the server. This
means that the INIT command succeeded, the handshake between bot and server is over and the bot is ready to receive other commands. Note that this does not mean the bot is already spawned in the environment! If it is set bAutoSpawn=False in GameBots ini file, the bot won't be spawned automatically and user needs to issue command Respawn
to spawn the bot. Then botInitialized()
method would be the right place to send first Respawn
command. Now briefly about method parameters. info
object holds information about the game
type, map etc. config
object holding information about bot current configuration - his vision time delay, autotracing setting, spawn setting etc. init
object holds information about bot variables such as his speed in the environment, maximum possible health etc.
botFirstSpawn(GameInfo gameInfo, ConfigChange config, InitedMessage init, Self self)
- called when the bot is spawned in the game for the first time. This means that the bot graphical represantation is visible in the game and Self
object was received from the environment holding information about bot location and current state. This is the last place to do some preparations before logic()
method will be called periodically.
getInitializeCommand()
- used
for setting initial properties of the agent such as it's
name, starting location etc. This method is used by Pogamut to get the initialize command for the bot.
prepareBot(UT2004Bot bot)
- called before the
bot connects to the environment, but after UT2004Bot is constructed. This is the right place to initialize Pogamut bot modules (but about them later)!
Sequence of calling these methods is:
prepareBot(UT2004Bot bot)
getInitializeCommand()
botInitialized(GameInfo info, ConfigChange config,
InitedMessage init)
botFirstSpawn(GameInfo gameInfo, ConfigChange config, InitedMessage init, Self self)
logic()
- called N times. Note that between
two logic iterations, botKilled(BotKilled event)
method
may be called notifying about bot death.
Let's explore methods implemented in this example. First
is getInitializeCommand()
:
public Initialize getInitializeCommand() { return new Initialize().setName("EmptyBot"); }
In this method an Initialize
object is
created, a bot's name is set and the initialized object is
returned to the rest of Pogamut platform. Note that all setters in all Pogamut commands
always return the same object, so you may chain the setters calls.
new Initialize().setName("EmptyBot").setTeam(0);
Second method is botFirstSpawn(GameInfo gameInfo, ConfigChange config, InitedMessage init, Self self)
:
public void botFirstSpawn(GameInfo gameInfo, ConfigChange config, InitedMessage init, Self self) { // Display a welcome message in the game engine // right in the time when the bot appears in the environment, i.e., his body has been just spawned // into the UT2004 for the first time. body.getCommunication().sendGlobalTextMessage("Hello world! I am alive!"); // alternatively, you may use getAct() method for issuing arbitrary {@link CommandMessage} for the bot getAct().act(new SendMessage().setGlobal(true).setText("And I can speak! Hurray!")); }
The "Hello world!" message is printed there. Note that the body
is the
gateway for the most commands you may issue to the bot to Unreal Tournament.
These commands are grouped together in several categories, like body.getCommunication()
.
All commands are well documented, so you can receive contextual help in NetBeans while
coding.
Alternatively you can use the basic command interface accessed through
getAct()
method to issue commands. The getAct()
method returns object
implementing IAct
interface that defines
act(CommandMessage command)
method. The
act()
method is the gateway for issuing actions
represented by CommandMessage
objects.
SendMessage
is a command sending message to a
global chat channel - the constructor. Notice that the object is created
and it's name property is set in only one line. The
setText()
method returns the instance on which
it has been called, so more properties can be set in a chain e.g.
new SendMessage().setGlobal(true).setText("And I can speak! Hurray!")
.
To see all command objects you can use in your bot, open
CommandMessage
class definition. To do it as
quickly as possible press Ctrl + O and type name of
the class for search. In this case, type
CommandMessage
. Once the source opens in the
central window press Alt + F12 to open
Hierarchy browser. Now you can see list of all
classes extending the CommandMessage
which
are commands provided by the PogamutUT2004.
Last method we will describe in this section is
main()
. This is the first method called when
you execute the bot program (like in any other Java program). This
method is responsible for instantiating the bot and connecting it to the
environment. Bot runner class facilitates bot execution:
public static void main(String args[]) throws PogamutException { // wrapped logic for bots executions, suitable to run single bot in single JVM new UT2004BotRunner(EmptyBot.class, "EmptyBot").setMain(true).startAgent(); }
Note that setMain(true)
is setter that should be used
only in global main methods (i.e., public static void main(String args[])
)
so the Pogamut platform correctly terminates itself after the end of the bot run. Otherwise
the JVM should not exit itself ... blame the JMX guys! Not us :-) So the rule of thumb,
you're in main method, use setMain(true)
, you're starting the agent from different method,
do not use it.
The logic()
method will be described in
the next section.
Two features that you will find handy during parameterization and evaluation of the bot are logging and introspection.
Logging is a mechanism for tracing program's execution by printing messages - it can be used both for debugging (multi threaded applications are often hard or impossible to debug using breakpoints) and evaluation (you can process logs of bot's activity and utilize some statistical software).
Introspection is designed to ease the bot's parameterization. It is often needed to adjust multiple behavior parameters at runtime and you will probably end up creating your own GUI (graphical user interface) for this purpose. In introspection, you just annotate desired variables with @JProp annotation and they will be accessible via the Netbeans GUI.
Let's look how logging and introspection works in EmptyBot
example. First start the bot (F6), then have a look on
it's source code. In the initial section several variables annotated
with the @JProp
are defined.
@JProp public String stringProp = "Hello bot example"; @JProp public boolean boolProp = true; @JProp public int intProp = 2; @JProp public double doubleProp = 1.0;
Now expand bot's node
under the UT server node (in Services tab), you
will see two new nodes - Logs and
Introspection. After selecting the
Introspection node the annotated variables will be
shown in the Properties (Ctrl + Shift +
7) window. Note that the intProp
variable is
being continuously updated. New values of variables can be also set in
this window.
Last non-empty method is logic()
. There a simple
follow player behavior is specified. The bot first checks whether he sees someone
and if yes he tries to go to that player location and if not and he remembers some player
he was following before, he goes to the last known spot of the player using advanced
map navigation object pathExecutor.
public void logic() throws PogamutException { if (players.canSeePlayers()) { lastPlayer = players.getNearestVisiblePlayer(); move.moveTo(players.getNearestVisiblePlayer()); } else { if (lastPlayer == null) { //we don't see any player and we don't even remeber lastPlayer - we will turn around move.turnHorizontal(30); } else { if (lastPlayer.getLocation().getDistance(info.getLocation()) < 200) { //if we are close we will turn to the spot and forget the lastPlayer move.turnTo(lastPlayer.getLocation()); if (info.isFacing(lastPlayer.getLocation())) { lastPlayer = null; } } else { //if we are not closed we tell pathExecutor we want to go there - if //we are not going there already if (this.pathExecutor.isExecuting()) { // WAIT TILL WE GET THERE } else { this.pathExecutor.followPath( this.pathPlanner.computePath( info.getLocation(), lastPlayer.getLocation())); } } } } }
Note that you can observer Pogamut logs accesible by getLog()
method under bot's
Logs node.