Initial commit

This commit is contained in:
GuiNerd
2019-11-27 18:42:43 -03:00
commit 5fd7176543
1714 changed files with 171249 additions and 0 deletions

View File

@ -0,0 +1,279 @@
package com.mycompany.mavenproject1;
/*
* AffectEngine.java
*
* Copyright (c) 2005, 2006, 2007, 2008, Patrick Gebhard, DFKI GmbH
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* - Neither the name of the DFKI GmbH nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
import de.affect.emotion.Emotion;
import de.affect.emotion.EmotionType;
import de.affect.manage.AffectManager;
import de.affect.manage.event.AffectUpdateEvent;
import de.affect.manage.event.AffectUpdateListener;
import de.affect.mood.Mood;
import de.affect.xml.AffectOutputDocument;
import de.affect.xml.AffectInputDocument.AffectInput;
import de.affect.xml.AffectInputDocument.AffectInput.Character;
import de.affect.xml.AffectInputDocument.AffectInput.BasicEEC;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Provides the basic interface between Pogamut and ALMA.
*
* This code is based on the AffectEngine.java class provided with ALMA as an example
* implementation.
*
* @author Patrick Gebhard, Michal Bida
*/
public class ALMA implements AffectUpdateListener {
/** The agent this PogamutALMA instance is for. */
public EmotionalBot myAgent;
/** The ALMA Java implementation */
public static AffectManager fAM = null;
/** ALMA affect computation definition file */
private static String sALMACOMP = "./conf/AffectComputation.aml";
/** ALMA character definition file */
private static String sALMADEF = "./conf/CharacterDefinition.aml";
/** Current level time in seconds (contains also milliseconds after dot) */
public double currentTime;
/* ALMA mode:
false - output on console
true - graphical user interface CharacterBuilder
NOTE: No runtime windows (defined in AffectComputation or
AffectDefinition will be displayed!) */
private static final boolean sGUIMode = false;
/** Console logging */
public static Logger log = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
/**
* The constructor that sets up ALMA engine.
*
* @param agent
*/
public ALMA(EmotionalBot agent) {
// Starting the ALMA affect engine
myAgent = agent;
try {
//fAM = new AffectManager(sALMACOMP, sALMADEF, sGUIMode);
fAM = new AffectManager(ALMA.class.getClassLoader().getResourceAsStream(sALMACOMP), ALMA.class.getClassLoader().getResourceAsStream(sALMADEF), sGUIMode);
//disable alma logging
fAM.log.setLevel(Level.OFF);
fAM.addAffectUpdateListener(this);
} catch (IOException io) {
log.info("Error during ALMA initialisation");
io.printStackTrace();
System.exit(-1);
} catch (Exception xmle) {
log.info("Error in ALMA configuration");
xmle.printStackTrace();
System.exit(-1);
}
}
/**
* Listens to affect updates computed by ALMA. This implements the AffectUpdateListener.
*
* Called each time something in ALMA is changed. In ALMA the affects are changing
* very often resulting in this method getting called very often as well.
*
* @param event
*/
public synchronized void update(AffectUpdateEvent event) {
AffectOutputDocument aod = event.getUpdate();
//nothing for now, logging?
}
/**
* Returns current mood for target agent.
*
* @param agentName
* @return
*/
public Mood getCurrentMood(String agentName) {
return fAM.getCharacterByName(agentName).getCurrentMood();
}
/**
* Gets all emotions for target agent, that are felt toward the elicitor provided.
*
* @param agentName
* @param elicitor
* @return
*/
public List<Emotion> getAllEmotionsForElicitor(String agentName, String elicitor) {
ArrayList<Emotion> emotionList = new ArrayList<Emotion>();
Emotion tempEm = null;
for (int j = 0; j < EmotionType.values().length; j++) {
//we get emotions one by one from ALMA history
tempEm = fAM.getCharacterByName(agentName).getEmotionHistory().getEmotionByElicitor(EmotionType.values()[j], elicitor);
if (tempEm != null) {
emotionList.add(tempEm);
}
}
return emotionList;
}
/**
* Gets emotion for target agent name of input type and for input elicitor.
*
* @param agentName
* @param elicitor
* @param type
* @return
*/
public Emotion getEmotionForElicitor(String agentName, String elicitor, EmotionType type) {
return fAM.getCharacterByName(agentName).getEmotionHistory().getEmotionByElicitor(type, elicitor);
}
/**
* Gets dominant emotion for the input agent.
*
* @param agentName
* @return
*/
public Emotion getDominantEmotion(String agentName){
return fAM.getCharacterByName(agentName).getCurrentEmotions().getDominantEmotion();
}
/**
* Gets the ALMA current emotions (in characters focus) for target agent.
*
* @param agentName
* @return
*/
public List<Emotion> getCurrentEmotions(String agentName) {
if (fAM.getCharacterByName(agentName) != null) {
return fAM.getCharacterByName(agentName).getCurrentEmotions().getEmotions();
} else {
return new ArrayList<Emotion>();
}
}
/**
* Creates an AffectInput document containing an BasicEEC Element and returns a AffectInput object
*
* @param actor
* @param desirability
* @param agency
* @param praiseworthiness
* @param appealingness
* @param liking
* @param likelihood
* @param elicitor
* @param realization
* @return
*/
public AffectInput createAffectInputBasicEEC(String actor,
double desirability, double praiseworthiness, double appealingness, double likelihood,
double liking, double realization, String elicitor, String agency) {
AffectInput aiInput = AffectInput.Factory.newInstance();
// Building the Character element
Character perfCharacter = Character.Factory.newInstance();
perfCharacter.setName(actor);
BasicEEC eec = BasicEEC.Factory.newInstance();
eec.setDesirability(desirability);
eec.setPraiseworthiness(praiseworthiness);
eec.setAppealingness(appealingness);
eec.setLikelihood(likelihood);
eec.setLiking(liking);
eec.setRealization(realization);
eec.setAgency((agency.toLowerCase() == "self") ? BasicEEC.Agency.SELF : BasicEEC.Agency.OTHER);
eec.setElicitor(elicitor);
aiInput.setCharacter(perfCharacter);
aiInput.setBasicEEC(eec);
return aiInput;
}
/**
* Creates an AffectInput document containing an BasicEEC Element and returns a AffectInput object
* This type eec element is constructed elsewhere
* @param actor
* @param eec
* @return
*/
public AffectInput createAffectInput(String actor, BasicEEC eec) {
AffectInput aiInput = AffectInput.Factory.newInstance();
// Building the Character element
Character perfCharacter = Character.Factory.newInstance();
perfCharacter.setName(actor);
aiInput.setCharacter(perfCharacter);
aiInput.setBasicEEC(eec);
return aiInput;
}
/**
* The <code>processAffectInput</code> passes instance of AffectInput to AffectManager
* event string is here just for logging
* @param ai
* @param event
*/
public void processAffectInput(AffectInput ai, String event) {
myAgent.getLog().warning("Name: " + ai.getCharacter().getName() + " Event: " + event + " ${symbol_escape}n" + myAgent.currentTime +
" Vars: D: " + ai.getBasicEEC().getDesirability() + "; P: " + ai.getBasicEEC().getPraiseworthiness() +
"; A: " + ai.getBasicEEC().getAppealingness() + "; Lh: " + ai.getBasicEEC().getLikelihood() +
"; Li: " + ai.getBasicEEC().getLiking() + "; R: " + ai.getBasicEEC().getRealization() +
"; Ag: " + ai.getBasicEEC().getAgency() + "; El.: " + ai.getBasicEEC().getElicitor());
fAM.processSignal(ai);
}
}

View File

@ -0,0 +1,534 @@
package com.mycompany.mavenproject1;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import cz.cuni.amis.pogamut.base.agent.navigation.IPathExecutorState;
import cz.cuni.amis.pogamut.base.agent.navigation.PathExecutorState;
import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
import cz.cuni.amis.pogamut.ut2004.agent.module.utils.TabooSet;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004PathAutoFixer;
import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004BotModuleController;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Initialize;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotKilled;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ConfigChange;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ControlMessage;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.InitedMessage;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
import cz.cuni.amis.pogamut.ut2004.hideandseek.bot.UT2004BotHSController;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.HSBotState;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.HSScoreChangeReason;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSAssignSeeker;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSBotStateChanged;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSPlayerScoreChanged;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRoundEnd;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRoundStart;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRoundState;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRunnerCaptured;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRunnerFouled;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRunnerSafe;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRunnerSpotted;
import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRunnerSurvived;
import cz.cuni.amis.pogamut.ut2004.hideandseek.server.UT2004HSServer;
import cz.cuni.amis.pogamut.ut2004.utils.UT2004BotRunner;
import cz.cuni.amis.utils.IFilter;
import cz.cuni.amis.utils.collections.MyCollections;
import cz.cuni.amis.utils.exception.PogamutException;
import cz.cuni.amis.utils.flag.FlagListener;
/**
* Example of the bot playing HIDE-AND-SEEK-GAME according to {@link ControlMessage}s from {@link UT2004HSServer}.
*
* @author Jakub Gemrot aka Jimmy
*/
@AgentScoped
public class HideAndSeekBot extends UT2004BotHSController<UT2004Bot> {
private static String[] names = new String[]{"Peter", "James", "Johnny", "Craig", "Jimmy", "Steve", "Ronnie", "Bobby"};
static {
List<String> n = MyCollections.toList(names);
Collections.shuffle(n);
names = n.toArray(new String[n.size()]);
}
/**
* Just for the numbering of bots.
*/
private static int number = 0;
/**
* Taboo set is working as "black-list", that is you might add some
* NavPoints to it for a certain time, marking them as "unavailable".
*/
protected TabooSet<NavPoint> tabooNavPoints;
/**
* Path auto fixer watches for navigation failures and if some navigation
* link is found to be unwalkable, it removes it from underlying navigation
* graph.
*
* Note that UT2004 navigation graphs are some times VERY stupid or contains
* VERY HARD TO FOLLOW links...
*/
protected UT2004PathAutoFixer autoFixer;
/**
* Here we can modify initializing command for our bot.
*
* @return
*/
@Override
public Initialize getInitializeCommand() {
return new Initialize().setName(names[(++number) % names.length]);
}
/**
* The bot is initialized in the environment - a physical representation of
* the bot is present in the game.
*
* @param config information about configuration
* @param init information about configuration
*/
@SuppressWarnings("unchecked")
@Override
public void botInitialized(GameInfo gameInfo, ConfigChange config, InitedMessage init) {
// initialize taboo set where we store temporarily unavailable navpoints
tabooNavPoints = new TabooSet<NavPoint>(bot);
// auto-removes wrong navigation links between navpoints
autoFixer = new UT2004PathAutoFixer(bot, navigation.getPathExecutor(), fwMap, aStar, navBuilder);
// IMPORTANT
// adds a listener to the path executor for its state changes, it will allow you to
// react on stuff like "PATH TARGET REACHED" or "BOT STUCK"
navigation.getPathExecutor().getState().addStrongListener(new FlagListener<IPathExecutorState>() {
@Override
public void flagChanged(IPathExecutorState changedValue) {
pathExecutorStateChange(changedValue.getState());
}
});
navigation.getLog().setLevel(Level.INFO);
// ((SocketConnection)bot.getEventBus().getComponent(SocketConnection.COMPONENT_ID)).setLogMessages(true);
// bot.getLogger().getCategory(SocketConnection.COMPONENT_ID.getToken()).setLevel(Level.ALL);
// bot.getLogger().getCategory(YylexParser.COMPONENT_ID.getToken()).setLevel(Level.ALL);
}
/**
* The bot is initialized in the environment - a physical representation of
* the bot is present in the game.
*
* @param config information about configuration
* @param init information about configuration
*/
@Override
public void botFirstSpawn(GameInfo gameInfo, ConfigChange config, InitedMessage init, Self self) {
// change to ALL to receive logs from the navigation so you can get a grasp on how it is working
navigation.getPathExecutor().getLog().setLevel(Level.WARNING);
}
// --------------------
// ====================
// HIDE AND SEEK EVENTS
// ====================
// --------------------
/**
* Some RUNNER has just survived the round.
* <p><p>
* This event is triggered at the end of the round for every RUNNER that has not been FOULED, CAPTURED and did not make it to SAFE area.
*
* @param event
*/
@Override
protected void hsRunnerSurvived(HSRunnerSurvived event, boolean me) {
}
/**
* Some RUNNER has just been spotted by the SEEKER.
* @param event
*/
@Override
protected void hsRunnerSpotted(HSRunnerSpotted event, boolean me) {
}
/**
* Some RUNNER has just made it to the safe-area.
* @param event
*/
@Override
protected void hsRunnerSafe(HSRunnerSafe event, boolean me) {
}
/**
* Some RUNNER has just been fouled-out because it stepped into the restricted-area while it was activated.
* @param event
* @param me whether this event speaks about your bot
*/
@Override
protected void hsRunnerFouled(HSRunnerFouled event, boolean me) {
}
/**
* Some RUNNER has just been captured by the SEEKER, i.e., seeker has spotted the runner and made it to the safe-area before
* the runner.
*
* @param event
* @param me whether this event speaks about your bot
*/
@Override
protected void hsRunnerCaptured(HSRunnerCaptured event, boolean me) {
}
/**
* Round state update has been received.
* @param event
*/
@Override
protected void hsRoundState(HSRoundState event) {
}
/**
* New round has just started, you may use this event to initialize your data-structures.
* @param event
*/
@Override
protected void hsRoundStart(HSRoundStart event) {
hideNavPoint = null;
targetNavPoint = null;
goingToFoul = random.nextInt(6) == 5; // 1/6 probability that the RUNNER will perform FOUL BEHAVIOR, will remain in restricted area instead of hiding
tabooNavPoints.clear();
navigation.stopNavigation(); // prevent commands from previous round to be still effective
}
/**
* Round has just ended, you may use this event to cleanup your data-structures.
* @param event
*/
@Override
protected void hsRoundEnd(HSRoundEnd event) {
}
/**
* Some player (runner/seeker) score has just changed, you may examine the reason within {@link HSPlayerScoreChanged${symbol_pound}getScoreChangeReason()}, see
* {@link HSScoreChangeReason}.
*
* @param event
* @param me whether this event speaks about your bot
*/
@Override
protected void hsPlayerScoreChanged(HSPlayerScoreChanged event, boolean me) {
}
/**
* Some bot {@link HSBotState} has been updated.
* @param event
* @param me whether this event speaks about your bot
*/
protected void hsBotStateChanged(HSBotStateChanged event, boolean me) {
}
/**
* SEEKER role has been just assigned to some bot.
* @param event
* @param me whether this event speaks about your bot
*/
@Override
protected void hsAssignSeeker(HSAssignSeeker event, boolean me) {
}
// -----
// =====
// LOGIC
// =====
// -----
/**
* This method is called only once right before actual logic() method is
* called for the first time.
*/
@Override
public void beforeFirstLogic() {
}
/**
* Main method that controls the bot - makes decisions what to do next. It
* is called iteratively by Pogamut engine every time a synchronous batch
* from the environment is received. This is usually 4 times per second - it
* is affected by visionTime variable, that can be adjusted in GameBots ini
* file in UT2004/System folder.
*/
@Override
public void logic() {
// mark that another logic iteration has began
log.info("====== LOGIC ITERATION ======");
// UNCOMMENT TO GET DETAIL INFO DURING RUN-TIME
// logState();
if (!hide.isRoundRunning()) return;
if (!hide.isMeAlive()) return;
switch(hide.getMyState()) {
case RUNNER:
logicRunner();
break;
case RUNNER_SPOTTED:
logicRunnerSpotted();
break;
case SEEKER:
logicSeeker();
break;
default:
// SHOULD NOT REACH HERE, BUT LET'S PLAY SAFE...
return;
}
}
private void logState() {
log.info("------ STATE ------");
log.info("Game state: " + hide.getGameState());
log.info("Game running: " + hide.isGameRunning());
if (!hide.isGameRunning()) return;
log.info("Round running: " + hide.isRoundRunning());
if (!hide.isRoundRunning()) return;
log.info("Me: " + hide.getMyState());
log.info("Me spawned? " + hide.isMeAlive());
log.info("Hiding time left: " + hide.getRemainingHidingTime());
log.info("Restricted area time left: " + hide.getRemainingRestrictedAreaTime());
log.info("Round time left: " + hide.getRemainingRoundTime());
log.info("Distance to safe-area: " + hide.getMySafeAreaDistance());
log.info("Distance to restricted-area: " + hide.getMyRestrictedAreaDistance());
}
// ------------
// ============
// LOGIC RUNNER
// ============
// ------------
NavPoint hideNavPoint;
Boolean goingToFoul = null;
private void logicRunner() {
log.info("------ RUNNER ------");
if (hide.isHidingTime()) {
if (goingToFoul) {
log.info("GOING TO FOUL! Standing-stil...");
return;
}
log.info("HIDING!");
if (hideNavPoint == null) {
hideNavPoint = chooseHideNavPoint();
if (hideNavPoint == null) {
log.warning("THERE IS NO SUITABLE HIDE-POINT TO RUN TO!");
return;
}
}
if (info.isAtLocation(hideNavPoint)) {
if (navigation.isNavigating()) {
navigation.stopNavigation();
}
log.info("HIDDEN!");
move.turnHorizontal(30);
return;
}
navigation.navigate(hideNavPoint);
return;
}
if (hide.isRestrictedAreaActivated()) {
log.info("RESTRICTED AREA ACTIVE, standing still!");
return;
}
runToSafePoint();
}
private NavPoint chooseHideNavPoint() {
if (visibility.isInitialized()) {
// WE HAVE VISIBILITY INFORMATION!
// => lets get smarty!
return
MyCollections.getRandomFiltered(
visibility.getCoverNavPointsFrom(hide.getSafeArea()),
new IFilter<NavPoint>() {
@Override
public boolean isAccepted(NavPoint object) {
return !hide.isInRestrictedArea(object, 50);
}
}
);
}
// NO VISIBILITY INFORMATION PROVIDED, CHOOSE RANDOM SUITABLE
return
MyCollections.getRandomFiltered(
navPoints.getNavPoints().values(),
new IFilter<NavPoint>() {
@Override
public boolean isAccepted(NavPoint object) {
return !hide.isInRestrictedArea(object, 50);
}
}
);
}
// --------------------
// ====================
// LOGIC RUNNER SPOTTED
// ====================
// --------------------
private void logicRunnerSpotted() {
runToSafePoint();
}
private void runToSafePoint() {
log.info("RUNNING TO SAFE POINT");
navigation.navigate(hide.getSafeArea());
}
// ------------
// ============
// LOGIC SEEKER
// ============
// ------------
private void logicSeeker() {
log.info("------ SEEKER ------");
if (hide.canCaptureRunner()) {
log.info("CAN CAPTURE RUNNER!");
runToSafePoint();
} else {
if (players.canSeePlayers()) {
targetNavPoint = null;
handlePlayerNavigation(players.getNearestVisiblePlayer());
} else {
handleNavPointNavigation();
}
}
}
private NavPoint targetNavPoint;
private void handleNavPointNavigation() {
if (navigation.isNavigatingToNavPoint()) {
// IS TARGET CLOSE & NEXT TARGET NOT SPECIFIED?
while (navigation.getContinueTo() == null && navigation.getRemainingDistance() < 400) {
// YES, THERE IS NO "next-target" SET AND WE'RE ABOUT TO REACH OUR TARGET!
navigation.setContinueTo(getRandomNavPoint());
// note that it is WHILE because navigation may immediately eat up "next target" and next target may be actually still too close!
}
// WE'RE NAVIGATING TO SOME NAVPOINT
return;
}
// NAVIGATION HAS STOPPED ...
// => we need to choose another navpoint to navigate to
// => possibly follow some players ...
targetNavPoint = getRandomNavPoint();
if (targetNavPoint == null) {
log.severe("COULD NOT CHOOSE ANY NAVIGATION POINT TO RUN TO!!!");
if (world.getAll(NavPoint.class).size() == 0) {
log.severe("world.getAll(NavPoint.class).size() == 0, there are no navigation ponits to choose from! Is exporting of nav points enabled in GameBots2004.ini inside UT2004?");
}
config.setName("NavigationBot [CRASHED]");
return;
}
navigation.navigate(targetNavPoint);
}
private void handlePlayerNavigation(Player player) {
if (navigation.isNavigating() && navigation.getCurrentTargetPlayer() == player) {
// WE'RE NAVIGATING TO SOME PLAYER
return;
}
// START THE NAVIGATION
navigation.navigate(player);
}
/**
* Called each time our bot die. Good for reseting all bot state dependent
* variables.
*
* @param event
*/
@Override
public void botKilled(BotKilled event) {
navigation.stopNavigation();
}
/**
* Path executor has changed its state (note that {@link UT2004BotModuleController${symbol_pound}getPathExecutor()}
* is internally used by
* {@link UT2004BotModuleController${symbol_pound}getNavigation()} as well!).
*
* @param state
*/
protected void pathExecutorStateChange(PathExecutorState state) {
switch (state) {
case PATH_COMPUTATION_FAILED:
// if path computation fails to whatever reason, just try another navpoint
// taboo bad navpoint for 10 seconds
tabooNavPoints.add(targetNavPoint, 10);
break;
case TARGET_REACHED:
// taboo reached navpoint for 10 seconds
tabooNavPoints.add(targetNavPoint, 10);
break;
case STUCK:
// the bot has stuck! ... target nav point is unavailable currently
tabooNavPoints.add(targetNavPoint, 30);
break;
case STOPPED:
// path execution has stopped
targetNavPoint = null;
break;
}
}
/**
* Randomly picks some navigation point to head to.
*
* @return randomly choosed navpoint
*/
protected NavPoint getRandomNavPoint() {
log.info("Picking new target navpoint.");
// choose one feasible navpoint (== not belonging to tabooNavPoints) randomly
NavPoint chosen = MyCollections.getRandomFiltered(navPoints.getNavPoints().values(), tabooNavPoints);
if (chosen != null) {
return chosen;
}
log.warning("All navpoints are tabooized at this moment, choosing navpoint randomly!");
// ok, all navpoints have been visited probably, try to pick one at random
return MyCollections.getRandom(navPoints.getNavPoints().values());
}
public static void main(String args[]) throws PogamutException {
// Starts 1 bot
// If you want to execute the whole Hide&Seek game/match, execute {@link HideAndSeekGame}.
new UT2004BotRunner(HideAndSeekBot.class, "HSBot").setMain(true).setLogLevel(Level.WARNING).startAgents(1);
}
}

View File

@ -0,0 +1,282 @@
package com.mycompany.mavenproject1;
import java.util.Set;
import java.util.logging.Level;
import cz.cuni.amis.pogamut.base.agent.navigation.IPathExecutorState;
import cz.cuni.amis.pogamut.base.agent.navigation.PathExecutorState;
import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
import cz.cuni.amis.pogamut.base.utils.math.DistanceUtils;
import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.visibility.Visibility;
import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.visibility.VisibilityCreator;
import cz.cuni.amis.pogamut.ut2004.agent.module.utils.TabooSet;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004PathAutoFixer;
import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004BotModuleController;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Initialize;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotKilled;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ConfigChange;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.InitedMessage;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
import cz.cuni.amis.pogamut.ut2004.utils.UT2004BotRunner;
import cz.cuni.amis.utils.Cooldown;
import cz.cuni.amis.utils.Heatup;
import cz.cuni.amis.utils.collections.MyCollections;
import cz.cuni.amis.utils.exception.PogamutException;
import cz.cuni.amis.utils.flag.FlagListener;
/**
* Example of Pogamut Bot that is utilizing {@link Visibility} module.
*
* Must be run on DM-1on1-Albatross. If you want to use different map
* read javadoc for {@link Visibility} and {@link VisibilityCreator}.
*
* @author Jakub Gemrot aka Jimmy
*/
@AgentScoped
public class HideBot extends UT2004BotModuleController {
/**
* Taboo set is working as "black-list", that is you might add some
* NavPoints to it for a certain time, marking them as "unavailable".
*/
protected TabooSet<NavPoint> tabooNavPoints;
/**
* Used for autofixing navpoints.
*/
protected UT2004PathAutoFixer autoFixer;
/**
* Here we can modify initializing command for our bot.
*
* @return
*/
@Override
public Initialize getInitializeCommand() {
return new Initialize().setName("HideBot");
}
/**
* The bot is initialized in the environment - a physical representation of
* the bot is present in the game.
*
* @param config information about configuration
* @param init information about configuration
*/
@SuppressWarnings("unchecked")
@Override
public void botInitialized(GameInfo gameInfo, ConfigChange config, InitedMessage init) {
// initialize taboo set where we store temporarily unavailable navpoints
tabooNavPoints = new TabooSet<NavPoint>(bot);
// auto-removes wrong navigation links between navpoints
autoFixer = new UT2004PathAutoFixer(bot, navigation.getPathExecutor(), fwMap, aStar, navBuilder);
// IMPORTANT
// adds a listener to the path executor for its state changes, it will allow you to
// react on stuff like "PATH TARGET REACHED" or "BOT STUCK"
navigation.getPathExecutor().getState().addStrongListener(new FlagListener<IPathExecutorState>() {
@Override
public void flagChanged(IPathExecutorState changedValue) {
pathExecutorStateChange(changedValue.getState());
}
});
}
Player hidingFrom;
Heatup hiding = new Heatup(10000);
Cooldown turning = new Cooldown(1200);
NavPoint targetNavPoint;
Cooldown changeNavPoint = new Cooldown(2000);
@Override
public void logic() {
if (!visibility.isInitialized()) {
log.warning("Could not use VISIBILITY module :-(");
return;
}
Player visible = players.getNearestVisiblePlayer();
if (hidingFrom != null) {
if (visible != hidingFrom) {
if (!hidingFrom.isVisible()) {
// SWITCH ATTENTION
startRunningAwayFrom(visible);
return;
}
if (info.getLocation().getDistance(visible.getLocation()) < info.getLocation().getDistance(hidingFrom.getLocation())) {
// SWITCH ATTENTION
startRunningAwayFrom(hidingFrom);
return;
}
}
continueRunningAwayFrom();
return;
}
if (visible != null) {
startRunningAwayFrom(visible);
return;
}
if (navigation.isNavigating()) {
navigation.stopNavigation();
navigation.setFocus(null);
}
if (turning.tryUse()) {
move.turnHorizontal(110);
}
}
private void startRunningAwayFrom(Player enemy) {
this.hidingFrom = enemy;
NavPoint cover = getCoverNavPoint(enemy);
if (cover == null) {
log.warning("No suitable navpoint, standing still... :-(");
return;
}
navigation.setFocus(enemy);
runTo(cover);
}
private NavPoint getCoverNavPoint(ILocated enemy) {
Set<NavPoint> navPoints = visibility.getCoverNavPointsFrom(enemy);
NavPoint cover = DistanceUtils.getNearestFiltered(navPoints, info.getLocation(), tabooNavPoints);
if (cover != null) return cover;
log.warning("Could not use any navpoint as cover... trying random one.");
return getRandomNavPoint();
}
private void continueRunningAwayFrom() {
if (hidingFrom == null) {
log.warning("hidingFrom == null ???");
return;
}
if (navigation.isNavigating()) {
NavPoint suitableNavPoint = getCoverNavPoint(hidingFrom);
if (targetNavPoint != suitableNavPoint) {
if (changeNavPoint.tryUse()) {
runTo(suitableNavPoint);
}
}
return;
}
// NOT NAVIGATING!
if (targetNavPoint != null) {
tabooNavPoints.add(targetNavPoint, 30);
}
if (hidingFrom.isVisible()) {
startRunningAwayFrom(hidingFrom);
return;
}
// NOT NAVIGATING! Player not visible...
this.hidingFrom = null;
}
private void runTo(NavPoint navPoint) {
log.info("Running to: " + navPoint);
targetNavPoint = navPoint;
navigation.navigate(targetNavPoint);
}
/**
* Called each time our bot die. Good for reseting all bot state dependent variables.
*
* @param event
*/
@Override
public void botKilled(BotKilled event) {
navigation.stopNavigation();
targetNavPoint = null;
hidingFrom = null;
hiding.clear();
turning.clear();
changeNavPoint.clear();
}
/**
* Path executor has changed its state (note that {@link UT2004BotModuleController${symbol_pound}getPathExecutor()}
* is internally used by
* {@link UT2004BotModuleController${symbol_pound}getNavigation()} as well!).
*
* @param state
*/
protected void pathExecutorStateChange(PathExecutorState state) {
switch (state) {
case PATH_COMPUTATION_FAILED:
// if path computation fails to whatever reason, just try another navpoint
// taboo bad navpoint for 3 minutes
tabooNavPoints.add(targetNavPoint, 180);
break;
case TARGET_REACHED:
tabooNavPoints.add(targetNavPoint, 5);
break;
case STUCK:
// the bot has stuck! ... target nav point is unavailable currently
tabooNavPoints.add(targetNavPoint, 60);
break;
case STOPPED:
// path execution has stopped
targetNavPoint = null;
break;
}
}
/**
* Randomly picks some navigation point to head to.
*
* @return randomly choosed navpoint
*/
protected NavPoint getRandomNavPoint() {
log.info("Picking new target navpoint.");
// choose one feasible navpoint (== not belonging to tabooNavPoints) randomly
NavPoint chosen = MyCollections.getRandomFiltered(getWorldView().getAll(NavPoint.class).values(), tabooNavPoints);
if (chosen != null) {
return chosen;
}
log.warning("All navpoints are tabooized at this moment, choosing navpoint randomly!");
// ok, all navpoints have been visited probably, try to pick one at random
return MyCollections.getRandom(getWorldView().getAll(NavPoint.class).values());
}
public static void main(String args[]) throws PogamutException {
// wrapped logic for bots executions, suitable to run single bot in single JVM
// we're forcingly setting logging to aggressive level FINER so you can see (almost) all logs
// that describes decision making behind movement of the bot as well as incoming environment events
new UT2004BotRunner(HideBot.class, "HideBot").setMain(true).setLogLevel(Level.INFO).startAgent();
}
}

View File

@ -0,0 +1,414 @@
package com.mycompany.mavenproject1;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import cz.cuni.amis.introspection.java.JProp;
import cz.cuni.amis.pogamut.base.agent.navigation.IPathExecutorState;
import cz.cuni.amis.pogamut.base.communication.worldview.listener.annotation.EventListener;
import cz.cuni.amis.pogamut.base.utils.Pogamut;
import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
import cz.cuni.amis.pogamut.base.utils.math.DistanceUtils;
import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
import cz.cuni.amis.pogamut.ut2004.agent.module.utils.TabooSet;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.NavigationState;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004PathAutoFixer;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.stuckdetector.UT2004DistanceStuckDetector;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.stuckdetector.UT2004PositionStuckDetector;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.stuckdetector.UT2004TimeStuckDetector;
import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004BotModuleController;
import cz.cuni.amis.pogamut.ut2004.communication.messages.ItemType;
import cz.cuni.amis.pogamut.ut2004.communication.messages.UT2004ItemType;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Initialize;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Move;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Rotate;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Stop;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.StopShooting;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotDamaged;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotKilled;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Item;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerDamaged;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerKilled;
import cz.cuni.amis.pogamut.ut2004.utils.UT2004BotRunner;
import cz.cuni.amis.utils.collections.MyCollections;
import cz.cuni.amis.utils.exception.PogamutException;
import cz.cuni.amis.utils.flag.FlagListener;
/**
* Example of Simple Pogamut bot, that randomly walks around the map searching
* for preys shooting at everything that is in its way.
*
* @author Rudolf Kadlec aka ik
* @author Jimmy
*/
@AgentScoped
public class HunterBot extends UT2004BotModuleController<UT2004Bot> {
/**
* boolean switch to activate engage behavior
*/
@JProp
public boolean shouldEngage = true;
/**
* boolean switch to activate pursue behavior
*/
@JProp
public boolean shouldPursue = true;
/**
* boolean switch to activate rearm behavior
*/
@JProp
public boolean shouldRearm = true;
/**
* boolean switch to activate collect health behavior
*/
@JProp
public boolean shouldCollectHealth = true;
/**
* how low the health level should be to start collecting health items
*/
@JProp
public int healthLevel = 75;
/**
* how many bot the hunter killed other bots (i.e., bot has fragged them /
* got point for killing somebody)
*/
@JProp
public int frags = 0;
/**
* how many times the hunter died
*/
@JProp
public int deaths = 0;
/**
* {@link PlayerKilled} listener that provides "frag" counting + is switches
* the state of the hunter.
*
* @param event
*/
@EventListener(eventClass = PlayerKilled.class)
public void playerKilled(PlayerKilled event) {
if (event.getKiller().equals(info.getId())) {
++frags;
}
if (enemy == null) {
return;
}
if (enemy.getId().equals(event.getId())) {
enemy = null;
}
}
/**
* Used internally to maintain the information about the bot we're currently
* hunting, i.e., should be firing at.
*/
protected Player enemy = null;
/**
* Item we're running for.
*/
protected Item item = null;
/**
* Taboo list of items that are forbidden for some time.
*/
protected TabooSet<Item> tabooItems = null;
private UT2004PathAutoFixer autoFixer;
private static int instanceCount = 0;
/**
* Bot's preparation - called before the bot is connected to GB2004 and
* launched into UT2004.
*/
@Override
public void prepareBot(UT2004Bot bot) {
tabooItems = new TabooSet<Item>(bot);
autoFixer = new UT2004PathAutoFixer(bot, navigation.getPathExecutor(), fwMap, aStar, navBuilder); // auto-removes wrong navigation links between navpoints
// listeners
navigation.getState().addListener(new FlagListener<NavigationState>() {
@Override
public void flagChanged(NavigationState changedValue) {
switch (changedValue) {
case PATH_COMPUTATION_FAILED:
case STUCK:
if (item != null) {
tabooItems.add(item, 10);
}
reset();
break;
case TARGET_REACHED:
reset();
break;
}
}
});
// DEFINE WEAPON PREFERENCES
weaponPrefs.addGeneralPref(UT2004ItemType.LIGHTNING_GUN, true);
weaponPrefs.addGeneralPref(UT2004ItemType.SHOCK_RIFLE, true);
weaponPrefs.addGeneralPref(UT2004ItemType.MINIGUN, false);
weaponPrefs.addGeneralPref(UT2004ItemType.FLAK_CANNON, true);
weaponPrefs.addGeneralPref(UT2004ItemType.ROCKET_LAUNCHER, true);
weaponPrefs.addGeneralPref(UT2004ItemType.LINK_GUN, true);
weaponPrefs.addGeneralPref(UT2004ItemType.ASSAULT_RIFLE, true);
weaponPrefs.addGeneralPref(UT2004ItemType.BIO_RIFLE, true);
}
/**
* Here we can modify initializing command for our bot.
*
* @return
*/
@Override
public Initialize getInitializeCommand() {
// just set the name of the bot and his skill level, 1 is the lowest, 7 is the highest
// skill level affects how well will the bot aim
return new Initialize().setName("Hunter-" + (++instanceCount)).setDesiredSkill(5);
}
/**
* Resets the state of the Hunter.
*/
protected void reset() {
item = null;
enemy = null;
navigation.stopNavigation();
itemsToRunAround = null;
}
@EventListener(eventClass=PlayerDamaged.class)
public void playerDamaged(PlayerDamaged event) {
log.info("I have just hurt other bot for: " + event.getDamageType() + "[" + event.getDamage() + "]");
}
@EventListener(eventClass=BotDamaged.class)
public void botDamaged(BotDamaged event) {
log.info("I have just been hurt by other bot for: " + event.getDamageType() + "[" + event.getDamage() + "]");
}
/**
* Main method that controls the bot - makes decisions what to do next. It
* is called iteratively by Pogamut engine every time a synchronous batch
* from the environment is received. This is usually 4 times per second - it
* is affected by visionTime variable, that can be adjusted in GameBots ini
* file in UT2004/System folder.
*
* @throws cz.cuni.amis.pogamut.base.exceptions.PogamutException
*/
@Override
public void logic() {
// 1) do you see enemy? -> go to PURSUE (start shooting / hunt the enemy)
if (shouldEngage && players.canSeeEnemies() && weaponry.hasLoadedWeapon()) {
stateEngage();
return;
}
// 2) are you shooting? -> stop shooting, you've lost your target
if (info.isShooting() || info.isSecondaryShooting()) {
getAct().act(new StopShooting());
}
// 3) are you being shot? -> go to HIT (turn around - try to find your enemy)
if (senses.isBeingDamaged()) {
this.stateHit();
return;
}
// 4) have you got enemy to pursue? -> go to the last position of enemy
if (enemy != null && shouldPursue && weaponry.hasLoadedWeapon()) { // !enemy.isVisible() because of 2)
this.statePursue();
return;
}
// 5) are you hurt? -> get yourself some medKit
if (shouldCollectHealth && info.getHealth() < healthLevel) {
this.stateMedKit();
return;
}
// 6) if nothing ... run around items
stateRunAroundItems();
}
//////////////////
// STATE ENGAGE //
//////////////////
protected boolean runningToPlayer = false;
/**
* Fired when bot see any enemy. <ol> <li> if enemy that was attacked last
* time is not visible than choose new enemy <li> if enemy is reachable and the bot is far - run to him
* <li> otherwise - stand still (kind a silly, right? :-)
* </ol>
*/
protected void stateEngage() {
//log.info("Decision is: ENGAGE");
//config.setName("Hunter [ENGAGE]");
boolean shooting = false;
double distance = Double.MAX_VALUE;
pursueCount = 0;
// 1) pick new enemy if the old one has been lost
if (enemy == null || !enemy.isVisible()) {
// pick new enemy
enemy = players.getNearestVisiblePlayer(players.getVisibleEnemies().values());
if (enemy == null) {
log.info("Can't see any enemies... ???");
return;
}
}
// 2) stop shooting if enemy is not visible
if (!enemy.isVisible()) {
if (info.isShooting() || info.isSecondaryShooting()) {
// stop shooting
getAct().act(new StopShooting());
}
runningToPlayer = false;
} else {
// 2) or shoot on enemy if it is visible
distance = info.getLocation().getDistance(enemy.getLocation());
if (shoot.shoot(weaponPrefs, enemy) != null) {
log.info("Shooting at enemy!!!");
shooting = true;
}
}
// 3) if enemy is far or not visible - run to him
int decentDistance = Math.round(random.nextFloat() * 800) + 200;
if (!enemy.isVisible() || !shooting || decentDistance < distance) {
if (!runningToPlayer) {
navigation.navigate(enemy);
runningToPlayer = true;
}
} else {
runningToPlayer = false;
navigation.stopNavigation();
}
item = null;
}
///////////////
// STATE HIT //
///////////////
protected void stateHit() {
//log.info("Decision is: HIT");
bot.getBotName().setInfo("HIT");
if (navigation.isNavigating()) {
navigation.stopNavigation();
item = null;
}
getAct().act(new Rotate().setAmount(32000));
}
//////////////////
// STATE PURSUE //
//////////////////
/**
* State pursue is for pursuing enemy who was for example lost behind a
* corner. How it works?: <ol> <li> initialize properties <li> obtain path
* to the enemy <li> follow the path - if it reaches the end - set lastEnemy
* to null - bot would have seen him before or lost him once for all </ol>
*/
protected void statePursue() {
//log.info("Decision is: PURSUE");
++pursueCount;
if (pursueCount > 30) {
reset();
}
if (enemy != null) {
bot.getBotName().setInfo("PURSUE");
navigation.navigate(enemy);
item = null;
} else {
reset();
}
}
protected int pursueCount = 0;
//////////////////
// STATE MEDKIT //
//////////////////
protected void stateMedKit() {
//log.info("Decision is: MEDKIT");
Item item = items.getPathNearestSpawnedItem(ItemType.Category.HEALTH);
if (item == null) {
log.warning("NO HEALTH ITEM TO RUN TO => ITEMS");
stateRunAroundItems();
} else {
bot.getBotName().setInfo("MEDKIT");
navigation.navigate(item);
this.item = item;
}
}
////////////////////////////
// STATE RUN AROUND ITEMS //
////////////////////////////
protected List<Item> itemsToRunAround = null;
protected void stateRunAroundItems() {
//log.info("Decision is: ITEMS");
//config.setName("Hunter [ITEMS]");
if (navigation.isNavigatingToItem()) return;
List<Item> interesting = new ArrayList<Item>();
// ADD WEAPONS
for (ItemType itemType : ItemType.Category.WEAPON.getTypes()) {
if (!weaponry.hasLoadedWeapon(itemType)) interesting.addAll(items.getSpawnedItems(itemType).values());
}
// ADD ARMORS
for (ItemType itemType : ItemType.Category.ARMOR.getTypes()) {
interesting.addAll(items.getSpawnedItems(itemType).values());
}
// ADD QUADS
interesting.addAll(items.getSpawnedItems(UT2004ItemType.U_DAMAGE_PACK).values());
// ADD HEALTHS
if (info.getHealth() < 100) {
interesting.addAll(items.getSpawnedItems(UT2004ItemType.HEALTH_PACK).values());
}
Item item = MyCollections.getRandom(tabooItems.filter(interesting));
if (item == null) {
log.warning("NO ITEM TO RUN FOR!");
if (navigation.isNavigating()) return;
bot.getBotName().setInfo("RANDOM NAV");
navigation.navigate(navPoints.getRandomNavPoint());
} else {
this.item = item;
log.info("RUNNING FOR: " + item.getType().getName());
bot.getBotName().setInfo("ITEM: " + item.getType().getName() + "");
navigation.navigate(item);
}
}
////////////////
// BOT KILLED //
////////////////
@Override
public void botKilled(BotKilled event) {
reset();
}
///////////////////////////////////
public static void main(String args[]) throws PogamutException {
// starts 3 Hunters at once
// note that this is the most easy way to get a bunch of (the same) bots running at the same time
new UT2004BotRunner(HunterBot.class, "Hunter").setMain(true).setLogLevel(Level.INFO).startAgents(2);
}
}

View File

@ -0,0 +1,602 @@
package com.mycompany.mavenproject1;
import java.util.logging.Level;
import cz.cuni.amis.introspection.java.JProp;
import cz.cuni.amis.pogamut.base.agent.navigation.IPathExecutorState;
import cz.cuni.amis.pogamut.base.agent.navigation.PathExecutorState;
import cz.cuni.amis.pogamut.base.communication.worldview.listener.annotation.EventListener;
import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.NavPoints;
import cz.cuni.amis.pogamut.ut2004.agent.module.utils.TabooSet;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.IUT2004Navigation;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004Navigation;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004PathAutoFixer;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004PathExecutorStuckState;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.astar.UT2004AStar;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.floydwarshall.FloydWarshallMap;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.navmesh.NavMeshModule;
import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004BotModuleController;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Initialize;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotKilled;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ConfigChange;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.InitedMessage;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Item;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ItemPickedUp;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
import cz.cuni.amis.pogamut.ut2004.utils.UT2004BotRunner;
import cz.cuni.amis.utils.collections.MyCollections;
import cz.cuni.amis.utils.exception.PogamutException;
import cz.cuni.amis.utils.flag.FlagListener;
/**
* Example of Simple Pogamut bot, that randomly walks around the map.
*
* <p><p>
* Bot is able to handle movers as well as teleporters.
*
* <p><p>
* It also implements player-following, that is, if it sees a player,
* it will start to navigate to it.
*
* <p><p>
* We recommend you to try it on map DM-1on1-Albatross or CTF-LostFaith or DM-Flux2.
*
* <p><p>
* This bot also contains an example of {@link TabooSet} usage.
*
* <p><p>
* Bot also instantiates {@link UT2004PathAutoFixer} that automatically removes bad-edges
* from navigation graph of UT2004. Note that Pogamut bot's cannot achieve 100% safe navigation
* inside UT2004 maps mainly due to edges that does not contain enough information on how
* to travel them, we're trying our best, but some edges inside navigation graph exported
* from UT2004 cannot be traveled with our current implementation.
*
* <p><p>
* You may control the way the bot informs you about its decisions via {@link ${symbol_pound}shouldLog} and {@link ${symbol_pound}shouldSpeak} flags.
*
* <p><p>
* We advise to change chat settings within UT2004 via ESCAPE -> Settings -> HUD -> Max. Chat Count -> set to 8 (max).
*
* @author Rudolf Kadlec aka ik
* @author Jakub Gemrot aka Jimmy
*/
@AgentScoped
public class NavigationBot extends UT2004BotModuleController {
/**
* Taboo set is working as "black-list", that is you might add some
* NavPoints to it for a certain time, marking them as "unavailable".
*/
protected TabooSet<NavPoint> tabooNavPoints;
/**
* Current navigation point we're navigating to.
*/
protected NavPoint targetNavPoint;
/**
* Path auto fixer watches for navigation failures and if some navigation
* link is found to be unwalkable, it removes it from underlying navigation
* graph.
*
* Note that UT2004 navigation graphs are some times VERY stupid or contains
* VERY HARD TO FOLLOW links...
*/
protected UT2004PathAutoFixer autoFixer;
/**
* Standard {@link UT2004BotModuleController${symbol_pound}getNavigation()} is using {@link FloydWarshallMap} to find the path.
* <p><p>
* This {@link UT2004Navigation} is initialized using {@link UT2004BotModuleController${symbol_pound}getAStar()} and can be used to confirm, that
* {@link UT2004AStar} is working in the map.
*/
protected UT2004Navigation navigationAStar;
/**
* {@link NavigationBot${symbol_pound}talking} state.
*/
protected int talking;
/**
* Whether to use {@link ${symbol_pound}navigationAStar} and {@link UT2004AStar} (== true).
* <p><p>
* Can be configured from NetBeans plugin during runtime.
*/
@JProp
public boolean useAStar = false;
/**
* Whether to use {@link ${symbol_pound}nmNav} or standard {@link UT2004BotModuleController${symbol_pound}getNavigation()}.
* <p><p>
* Can be configured from NetBeans plugin during runtime.
* <p><p>
* Note that you must have corresponding .navmesh file for a current played map within directory ./navmesh, more info available at {@link NavMeshModule}.
* <p><p>
* Note that navigation bot comes with only three navmeshes DM-TrainingDay, DM-1on1-Albatross and DM-Flux2 (see ./navmesh folder within the project folder).
*/
@JProp
public boolean useNavMesh = false;
/**
* Whether we should draw the navmesh before we start running using {@link ${symbol_pound}nmNav} or standard {@link UT2004BotModuleController${symbol_pound}getNavigation()}.
* <p><p>
* Can be configured from NetBeans plugin during runtime.
*/
@JProp
public boolean drawNavMesh = true;
/**
* Whether we should speak using in game communication within {@link ${symbol_pound}say(String)}.
*/
public boolean shouldSpeak = true;
/**
* Whether to LOG messages within {@link ${symbol_pound}say(String)}.
*/
public boolean shouldLog = false;
/**
* What log level to use.
*/
public Level navigationLogLevel = Level.WARNING;
/**
* Here we will store either {@link UT2004BotModuleController${symbol_pound}getNavigation()} or {@link ${symbol_pound}navigationAStar} according to {@link ${symbol_pound}useAStar}.
*/
protected IUT2004Navigation navigationToUse;
private boolean navMeshDrawn = false;
private int waitForMesh;
private double waitingForMesh;
private boolean offMeshLinksDrawn = false;
private int waitForOffMeshLinks;
private double waitingForOffMeshLinks;
/**
* Here we can modify initializing command for our bot.
*
* @return
*/
@Override
public Initialize getInitializeCommand() {
return new Initialize().setName("NavigationBot");
}
@Override
public void mapInfoObtained() {
// YOU CAN USE navBuilder IN HERE
// IN WHICH CASE YOU SHOULD UNCOMMENT FOLLOWING LINE AFTER EVERY CHANGE
navMeshModule.setReloadNavMesh(true); // tells NavMesh to reconstruct OffMeshPoints
}
/**
* The bot is initialized in the environment - a physical representation of
* the bot is present in the game.
*
* @param config information about configuration
* @param init information about configuration
*/
@SuppressWarnings("unchecked")
@Override
public void botInitialized(GameInfo gameInfo, ConfigChange config, InitedMessage init) {
// initialize taboo set where we store temporarily unavailable navpoints
tabooNavPoints = new TabooSet<NavPoint>(bot);
// auto-removes wrong navigation links between navpoints
autoFixer = new UT2004PathAutoFixer(bot, navigation.getPathExecutor(), fwMap, aStar, navBuilder);
// IMPORTANT
// adds a listener to the path executor for its state changes, it will allow you to
// react on stuff like "PATH TARGET REACHED" or "BOT STUCK"
navigation.getPathExecutor().getState().addStrongListener(new FlagListener<IPathExecutorState>() {
@Override
public void flagChanged(IPathExecutorState changedValue) {
pathExecutorStateChange(changedValue);
}
});
nmNav.getPathExecutor().getState().addStrongListener(new FlagListener<IPathExecutorState>() {
@Override
public void flagChanged(IPathExecutorState changedValue) {
pathExecutorStateChange(changedValue);
}
});
navigationAStar = new UT2004Navigation(bot, navigation.getPathExecutor(), aStar, navigation.getBackToNavGraph(), navigation.getRunStraight());
navigationAStar.getLog().setLevel(navigationLogLevel);
navigation.getLog().setLevel(navigationLogLevel);
nmNav.setLogLevel(navigationLogLevel);
}
/**
* The bot is initialized in the environment - a physical representation of
* the bot is present in the game.
*
* @param config information about configuration
* @param init information about configuration
*/
@Override
public void botFirstSpawn(GameInfo gameInfo, ConfigChange config, InitedMessage init, Self self) {
// receive logs from the navigation so you can get a grasp on how it is working
//navigation.getPathExecutor().getLog().setLevel(Level.ALL);
//nmNav.setLogLevel(Level.ALL);
//navigationAStar.getPathExecutor().getLog().setLevel(Level.ALL);
}
/**
* This method is called only once right before actual logic() method is
* called for the first time.
*/
@Override
public void beforeFirstLogic() {
}
/**
* Main method that controls the bot - makes decisions what to do next. It
* is called iteratively by Pogamut engine every time a synchronous batch
* from the environment is received. This is usually 4 times per second - it
* is affected by visionTime variable, that can be adjusted in GameBots ini
* file in UT2004/System folder.
*/
@Override
public void logic() {
// mark that another logic iteration has began
say("--- Logic iteration ---");
// decide which navigation to use
chooseNavigationToUse();
if (navigationToUse == nmNav && drawNavMesh) {
if (!drawNavMesh()) return;
if (!drawOffMeshLinks()) return;
}
if (players.canSeePlayers() || navigationToUse.getCurrentTargetPlayer() != null) {
// we can see some player / is navigating to some point where we lost the player from sight
// => navigate to player
handlePlayerNavigation();
} else {
// no player can be seen
// => navigate to navpoint
handleNavPointNavigation();
}
}
private void chooseNavigationToUse() {
if (useAStar) {
if (navigationToUse != navigationAStar) {
say("Using UT2004AStar to find path.");
if (navigationToUse != null) navigationToUse.stopNavigation();
navigationToUse = navigationAStar;
info.getBotName().setInfo("UT2004-ASTAR");
}
} else
if (useNavMesh) {
if (nmNav.isAvailable()) {
if (navigationToUse != nmNav) {
say("Using NavMesh for navigation.");
if (navigationToUse != null) navigationToUse.stopNavigation();
navigationToUse = nmNav;
info.getBotName().setInfo("NAVMESH");
}
} else {
log.warning("NavMesh not available! See startup log for more details.");
}
}
if (navigationToUse == null || (!useAStar && !useNavMesh)) {
if (navigationToUse != navigation) {
say("Using FloydWarshallMap to find path.");
if (navigationToUse != null) navigationToUse.stopNavigation();
navigationToUse = navigation;
info.getBotName().setInfo("FW");
}
}
}
private void handlePlayerNavigation() {
if (navigationToUse.isNavigating() && navigationToUse.getCurrentTargetPlayer() != null) {
// WE'RE NAVIGATING TO SOME PLAYER
logNavigation();
return;
}
// NAVIGATION HAS STOPPED ...
// => we need to choose another player to navigate to
Player player = players.getNearestVisiblePlayer();
if (player == null) {
// NO PLAYERS AT SIGHT
// => navigate to random navpoint
handleNavPointNavigation();
return;
}
// CHECK DISTANCE TO THE PLAYER ...
if (info.getLocation().getDistance(player.getLocation()) < UT2004Navigation.AT_PLAYER) {
// PLAYER IS NEXT TO US...
// => talk to player
talkTo(player);
return;
}
navigationToUse.navigate(player);
logNavigation();
}
private void handleNavPointNavigation() {
if (navigationToUse.isNavigatingToNavPoint()) {
// IS TARGET CLOSE & NEXT TARGET NOT SPECIFIED?
while (navigationToUse.getContinueTo() == null && navigationToUse.getRemainingDistance() < 400) {
// YES, THERE IS NO "next-target" SET AND WE'RE ABOUT TO REACH OUR TARGET!
NavPoint nextNavPoint = getRandomNavPoint();
say("EXTENDING THE PATH: " + NavPoints.describe(nextNavPoint));
navigationToUse.setContinueTo(nextNavPoint);
// note that it is WHILE because navigation may immediately eat up "next target" and next target may be actually still too close!
}
// WE'RE NAVIGATING TO SOME NAVPOINT
logNavigation();
return;
}
// NAVIGATION HAS STOPPED ...
// => we need to choose another navpoint to navigate to
// => possibly follow some players ...
targetNavPoint = getRandomNavPoint();
if (targetNavPoint == null) {
log.severe("COULD NOT CHOOSE ANY NAVIGATION POINT TO RUN TO!!!");
if (world.getAll(NavPoint.class).size() == 0) {
log.severe("world.getAll(NavPoint.class).size() == 0, there are no navigation ponits to choose from! Is exporting of nav points enabled in GameBots2004.ini inside UT2004?");
}
config.setName("NavigationBot [CRASHED]");
return;
}
talking = 0;
say("CHOOSING FIRST NAVPOINT TO RUN TO: " + NavPoints.describe(targetNavPoint));
navigationToUse.navigate(targetNavPoint);
logNavigation();
}
private void logNavigation() {
// log how many navpoints & items the bot knows about and which is visible
if (navigationToUse.getCurrentTargetPlayer() != null) {
say("-> " + NavPoints.describe(navigationToUse.getCurrentTargetPlayer()));
} else {
say("-> " + NavPoints.describe(navigationToUse.getCurrentTarget()));
}
int pathLeftSize = navigationToUse.getPathExecutor().getPath() == null ? 0 : navigationToUse.getPathExecutor().getPath().size() - navigationToUse.getPathExecutor().getPathElementIndex();
say("Path points left: " + pathLeftSize);
say("Remaining distance: " + navigationToUse.getRemainingDistance());
say("Visible navpoints: " + world.getAllVisible(NavPoint.class).size() + " / " + world.getAll(NavPoint.class).size());
say("Visible items: " + items.getVisibleItems().values() + " / " + world.getAll(Item.class).size());
say("Visible players: " + players.getVisiblePlayers().size());
}
private void talkTo(Player player) {
// FACE THE PLAYER
move.turnTo(player);
// SEND MESSAGES
switch (talking) {
case 0:
say("Hi!");
break;
case 4:
say("Howdy!");
break;
case 10:
say("I'm NavigationBot made to fool around and test Pogamut's navigation stuff!");
break;
case 18:
say("My work is extremely important.");
break;
case 24:
say("So do not interrupt me, ok?");
break;
case 26:
if (random.nextDouble() > 0.5) {
move.jump();
}
break;
case 40:
say(getRandomLogoutMessage());
break;
}
++talking;
if (talking > 40) {
talking = 25;
}
}
private String getRandomLogoutMessage() {
switch (random.nextInt(8)) {
case 0:
return "I would appriciate if you log out or switch to SPECTATE mode.";
case 1:
return "Would you please log out or switch to SPECTATE mode.";
case 2:
return "Just log out, will ya?";
case 3:
return "As I've said, I'M SOMEONE, so log out, ok?";
case 4:
return "I can see you don't get it... LOGOUT! OK!";
case 5:
return "I hate when humans are so clueless... just press ESCAPE key and press Spectate button, that's all I want!";
case 6:
return "I guess you do not know how to switch to spectate mode, right? Just press ESCAPE key and press Spectate button";
default:
return "AHAHAHAYYYAAAA!";
}
}
private boolean drawNavMesh() {
if (!navMeshDrawn) {
navMeshDrawn = true;
say("Drawing NavMesh...");
navMeshModule.getNavMeshDraw().clearAll();
navMeshModule.getNavMeshDraw().draw(true, false);
say("Okey, drawing commands issued, now we have to wait a bit till it gets drawn completely...");
waitForMesh = navMeshModule.getNavMesh().getPolys().size() / 35;
waitingForMesh = -info.getTimeDelta();
}
if (waitForMesh > 0) {
waitForMesh -= info.getTimeDelta();
waitingForMesh += info.getTimeDelta();
if (waitingForMesh > 2) {
waitingForMesh = 0;
say(((int)Math.round(waitForMesh)) + "s...");
}
if (waitForMesh > 0) {
return false;
}
}
return true;
}
private boolean drawOffMeshLinks() {
if (!offMeshLinksDrawn) {
offMeshLinksDrawn = true;
if (navMeshModule.getNavMesh().getOffMeshPoints().size() == 0) {
say("Ha! There are no off-mesh points / links within this map!");
return true;
}
say("Drawing OffMesh Links...");
navMeshModule.getNavMeshDraw().draw(false, true);
say("Okey, drawing commands issued, now we have to wait a bit till it gets drawn completely...");
waitForOffMeshLinks = navMeshModule.getNavMesh().getOffMeshPoints().size() / 10;
waitingForOffMeshLinks = -info.getTimeDelta();
}
if (waitForOffMeshLinks > 0) {
waitForOffMeshLinks -= info.getTimeDelta();
waitingForOffMeshLinks += info.getTimeDelta();
if (waitingForOffMeshLinks > 2) {
waitingForOffMeshLinks = 0;
say(((int)Math.round(waitForOffMeshLinks)) + "s...");
}
if (waitForOffMeshLinks > 0) {
return false;
}
}
return true;
}
private void say(String text) {
if (shouldSpeak) {
body.getCommunication().sendGlobalTextMessage(text);
}
if (shouldLog) {
say(text);
}
}
/**
* Called each time our bot die. Good for reseting all bot state dependent
* variables.
*
* @param event
*/
@Override
public void botKilled(BotKilled event) {
navigation.stopNavigation();
}
/**
* Path executor has changed its state (note that {@link UT2004BotModuleController${symbol_pound}getPathExecutor()}
* is internally used by
* {@link UT2004BotModuleController${symbol_pound}getNavigation()} as well!).
*
* @param event
*/
protected void pathExecutorStateChange(IPathExecutorState event) {
switch (event.getState()) {
case PATH_COMPUTATION_FAILED:
// if path computation fails to whatever reason, just try another navpoint
// taboo bad navpoint for 3 minutes
tabooNavPoints.add(targetNavPoint, 180);
break;
case TARGET_REACHED:
// taboo reached navpoint for 3 minutes
tabooNavPoints.add(targetNavPoint, 180);
break;
case STUCK:
UT2004PathExecutorStuckState stuck = (UT2004PathExecutorStuckState)event;
if (stuck.isGlobalTimeout()) {
say("UT2004PathExecutor GLOBAL TIMEOUT!");
} else {
say(stuck.getStuckDetector() + " reported STUCK!");
}
if (stuck.getLink() == null) {
say("STUCK LINK is NOT AVAILABLE!");
} else {
say("Bot has stuck while running from " + stuck.getLink().getFromNavPoint().getId() + " -> " + stuck.getLink().getToNavPoint().getId());
}
// the bot has stuck! ... target nav point is unavailable currently
tabooNavPoints.add(targetNavPoint, 60);
break;
case STOPPED:
// path execution has stopped
targetNavPoint = null;
break;
}
}
/**
* Randomly picks some navigation point to head to.
*
* @return randomly choosed navpoint
*/
protected NavPoint getRandomNavPoint() {
say("Picking new target navpoint.");
// choose one feasible navpoint (== not belonging to tabooNavPoints) randomly
NavPoint chosen = MyCollections.getRandomFiltered(getWorldView().getAll(NavPoint.class).values(), tabooNavPoints);
if (chosen != null) {
return chosen;
}
log.warning("All navpoints are tabooized at this moment, choosing navpoint randomly!");
// ok, all navpoints have been visited probably, try to pick one at random
return MyCollections.getRandom(getWorldView().getAll(NavPoint.class).values());
}
public static void main(String args[]) throws PogamutException {
// wrapped logic for bots executions, suitable to run single bot in single JVM
// you can set the log level to FINER to see (almost) all logs
// that describes decision making behind movement of the bot as well as incoming environment events
// however note that in NetBeans this will cause your bot to lag heavilly (in Eclipse it is ok)
new UT2004BotRunner(NavigationBot.class, "NavigationBot").setMain(true).setLogLevel(Level.WARNING).startAgent();
}
}

View File

@ -0,0 +1,272 @@
package com.mycompany.mavenproject1;
import javax.vecmath.Vector3d;
import cz.cuni.amis.introspection.java.JProp;
import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
import cz.cuni.amis.pogamut.ut2004.agent.navigation.navmesh.LevelGeometryModule;
import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004BotModuleController;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Configuration;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.RemoveRay;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.AutoTraceRay;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ConfigChange;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.InitedMessage;
import cz.cuni.amis.pogamut.ut2004.utils.UT2004BotRunner;
import cz.cuni.amis.pogamut.ut2004.utils.UnrealUtils;
import cz.cuni.amis.utils.exception.PogamutException;
import cz.cuni.amis.utils.flag.FlagListener;
/**
* Example of Simple Pogamut bot, that randomly walks around the map. Bot is
* incapable of handling movers so far.
*
* <p><p>
* The crucial method to read
* through is {@link RaycastingBot${symbol_pound}botInitialized(GameInfo, ConfigChange, InitedMessage)},
* it will show you how to set up ray-casting.
*
* <p><p>
* We recommend you to try this bot on DM-TrainingDay or DM-Albatross or DM-Flux2.
*
* <p><p>
* Note that this is a bit deprecated way to do raycasting as we have more advanced approach via "geometry-at-client", see {@link LevelGeometryModule}
* and checkout svn://artemis.ms.mff.cuni.cz/pogamut/trunk/project/Main/PogamutUT2004Examples/35-ManualBot that contains hints how to do raycasting client-side.
*
*
* @author Ondrej Burkert
* @author Rudolf Kadlec aka ik
* @author Jakub Gemrot aka Jimmy
*/
@AgentScoped
@Deprecated
public class RaycastingBot extends UT2004BotModuleController {
// Constants for rays' ids. It is allways better to store such values
// in constants instead of using directly strings on multiple places of your
// source code
protected static final String FRONT = "frontRay";
protected static final String LEFT45 = "left45Ray";
protected static final String LEFT90 = "left90Ray";
protected static final String RIGHT45 = "right45Ray";
protected static final String RIGHT90 = "right90Ray";
private AutoTraceRay left, front, right;
/**
* Flag indicating that the bot has been just executed.
*/
private boolean first = true;
private boolean raysInitialized = false;
/**
* Whether the left45 sensor signalizes the collision. (Computed in the
* doLogic()) <p><p> Using {@link RaycastingBot${symbol_pound}LEFT45} as the key for the
* ray.
*/
@JProp
private boolean sensorLeft45 = false;
/**
* Whether the right45 sensor signalizes the collision. (Computed in the
* doLogic()) <p><p> Using {@link RaycastingBot${symbol_pound}RIGHT45} as the key for the
* ray.
*/
@JProp
private boolean sensorRight45 = false;
/**
* Whether the front sensor signalizes the collision. (Computed in the
* doLogic()) <p><p> Using {@link RaycastingBot${symbol_pound}FRONT} as the key for the
* ray.
*/
@JProp
private boolean sensorFront = false;
/**
* Whether the bot is moving. (Computed in the doLogic())
*/
@JProp
private boolean moving = false;
/**
* Whether any of the sensor signalize the collision. (Computed in the
* doLogic())
*/
@JProp
private boolean sensor = false;
/**
* How much time should we wait for the rotation to finish (milliseconds).
*/
@JProp
private int turnSleep = 250;
/**
* How fast should we move? Interval <0, 1>.
*/
private float moveSpeed = 0.6f;
/**
* Small rotation (degrees).
*/
@JProp
private int smallTurn = 30;
/**
* Big rotation (degrees).
*/
@JProp
private int bigTurn = 90;
/**
* The bot is initialized in the environment - a physical representation of
* the bot is present in the game.
*
* @param config information about configuration
* @param init information about configuration
*/
@Override
public void botInitialized(GameInfo info, ConfigChange currentConfig, InitedMessage init) {
// initialize rays for raycasting
final int rayLength = (int) (UnrealUtils.CHARACTER_COLLISION_RADIUS * 10);
// settings for the rays
boolean fastTrace = true; // perform only fast trace == we just need true/false information
boolean floorCorrection = false; // provide floor-angle correction for the ray (when the bot is running on the skewed floor, the ray gets rotated to match the skew)
boolean traceActor = false; // whether the ray should collid with other actors == bots/players as well
// 1. remove all previous rays, each bot starts by default with three
// rays, for educational purposes we will set them manually
getAct().act(new RemoveRay("All"));
// 2. create new rays
raycasting.createRay(LEFT45, new Vector3d(1, -1, 0), rayLength, fastTrace, floorCorrection, traceActor);
raycasting.createRay(FRONT, new Vector3d(1, 0, 0), rayLength, fastTrace, floorCorrection, traceActor);
raycasting.createRay(RIGHT45, new Vector3d(1, 1, 0), rayLength, fastTrace, floorCorrection, traceActor);
// note that we will use only three of them, so feel free to experiment with LEFT90 and RIGHT90 for yourself
raycasting.createRay(LEFT90, new Vector3d(0, -1, 0), rayLength, fastTrace, floorCorrection, traceActor);
raycasting.createRay(RIGHT90, new Vector3d(0, 1, 0), rayLength, fastTrace, floorCorrection, traceActor);
// register listener called when all rays are set up in the UT engine
raycasting.getAllRaysInitialized().addListener(new FlagListener<Boolean>() {
public void flagChanged(Boolean changedValue) {
// once all rays were initialized store the AutoTraceRay objects
// that will come in response in local variables, it is just
// for convenience
left = raycasting.getRay(LEFT45);
front = raycasting.getRay(FRONT);
right = raycasting.getRay(RIGHT45);
}
});
// have you noticed the FlagListener interface? The Pogamut is often using {@link Flag} objects that
// wraps some iteresting values that user might respond to, i.e., whenever the flag value is changed,
// all its listeners are informed
// 3. declare that we are not going to setup any other rays, so the 'raycasting' object may know what "all" is
raycasting.endRayInitSequence();
// change bot's default speed
config.setSpeedMultiplier(moveSpeed);
// IMPORTANT:
// The most important thing is this line that ENABLES AUTO TRACE functionality,
// without ".setAutoTrace(true)" the AddRay command would be useless as the bot won't get
// trace-lines feature activated
getAct().act(new Configuration().setDrawTraceLines(true).setAutoTrace(true));
// FINAL NOTE: the ray initialization must be done inside botInitialized method or later on inside
// botSpawned method or anytime during doLogic method
}
/**
* Main method that controls the bot.
*
* @throws cz.cuni.amis.pogamut.base.exceptions.PogamutException
*/
@Override
public void logic() throws PogamutException {
// mark that another logic iteration has began
log.info("--- Logic iteration ---");
// if the rays are not initialized yet, do nothing and wait for their initialization
if (!raycasting.getAllRaysInitialized().getFlag()) {
return;
}
// once the rays are up and running, move according to them
sensorFront = front.isResult();
sensorLeft45 = left.isResult();
sensorRight45 = right.isResult();
// is any of the sensor signalig?
sensor = sensorFront || sensorLeft45 || sensorRight45;
if (!sensor) {
// no sensor are signalizes - just proceed with forward movement
goForward();
return;
}
// some sensor/s is/are signaling
// if we're moving
if (moving) {
// stop it, we have to turn probably
move.stopMovement();
moving = false;
}
// according to the signals, take action...
// 8 cases that might happen follows
if (sensorFront) {
if (sensorLeft45) {
if (sensorRight45) {
// LEFT45, RIGHT45, FRONT are signaling
move.turnHorizontal(bigTurn);
} else {
// LEFT45, FRONT45 are signaling
move.turnHorizontal(smallTurn);
}
} else {
if (sensorRight45) {
// RIGHT45, FRONT are signaling
move.turnHorizontal(-smallTurn);
} else {
// FRONT is signaling
move.turnHorizontal(smallTurn);
}
}
} else {
if (sensorLeft45) {
if (sensorRight45) {
// LEFT45, RIGHT45 are signaling
goForward();
} else {
// LEFT45 is signaling
move.turnHorizontal(smallTurn);
}
} else {
if (sensorRight45) {
// RIGHT45 is signaling
move.turnHorizontal(-smallTurn);
} else {
// no sensor is signaling
goForward();
}
}
}
// HOMEWORK FOR YOU GUYS:
// Try to utilize LEFT90 and RIGHT90 sensors and implement wall-following behavior!
}
/**
* Simple method that starts continuous movement forward + marking the
* situation (i.e., setting {@link RaycastingBot${symbol_pound}moving} to true, which
* might be utilized later by the logic).
*/
protected void goForward() {
move.moveContinuos();
moving = true;
}
public static void main(String args[]) throws PogamutException {
// wrapped logic for bots executions, suitable to run single bot in single JVM
new UT2004BotRunner(RaycastingBot.class, "RaycastingBot").setMain(true).startAgent();
}
}

View File

@ -0,0 +1,384 @@
package com.mycompany.mavenproject1;
import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEvent;
import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
import cz.cuni.amis.pogamut.base.communication.worldview.listener.annotation.AnnotationListenerRegistrator;
import cz.cuni.amis.pogamut.base.communication.worldview.listener.annotation.EventListener;
import cz.cuni.amis.pogamut.base.communication.worldview.listener.annotation.ObjectClassEventListener;
import cz.cuni.amis.pogamut.base.communication.worldview.listener.annotation.ObjectClassListener;
import cz.cuni.amis.pogamut.base.communication.worldview.listener.annotation.ObjectEventListener;
import cz.cuni.amis.pogamut.base.communication.worldview.listener.annotation.ObjectListener;
import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObject;
import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectDestroyedEvent;
import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectFirstEncounteredEvent;
import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
import cz.cuni.amis.pogamut.base.utils.math.DistanceUtils;
import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
import cz.cuni.amis.pogamut.base3d.worldview.object.event.WorldObjectAppearedEvent;
import cz.cuni.amis.pogamut.base3d.worldview.object.event.WorldObjectDisappearedEvent;
import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004BotModuleController;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Initialize;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotDamaged;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotKilled;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Bumped;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ConfigChange;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.EndMessage;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.InitedMessage;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
import cz.cuni.amis.pogamut.ut2004.utils.UT2004BotRunner;
import cz.cuni.amis.pogamut.ut2004.utils.UnrealUtils;
import cz.cuni.amis.utils.exception.PogamutException;
/**
* Example of Simple Pogamut bot, that can listen to some events coming from
* the game engine and respond to them appropriately. The logic of the bot is
* completely event driven.
*
* <p><p>
* Notice that we're using a special annotations
* for various methods, i.e., for the method {@link ResponsiveBot${symbol_pound}bumped(Bumped)}
* the annotation {@link EventListener}, for the method {@link ResponsiveBot${symbol_pound}playerAppeared(WorldObjectAppearedEvent)}
* we're using {@link ObjectClassEventListener}, etc. You may perceive is as a bit magic as
* some methods are called as a response to some event, e.g., the method {@link ResponsiveBot${symbol_pound}bumped(Bumped)}
* is called whenever GameBots2004 sends a message {@link Bumped} to the bot.
*
* <p><p>
* How is this possible?
*
* <p><p>
* Well, the {@link UT2004BotModuleController}
* is using {@link AnnotationListenerRegistrator} that introspects (via Java
* Reflection API) the methods declared by the {@link ResponsiveBot} looking for
* annotations: {@link EventListener}, {@link ObjectClassEventListener},
* {@link ObjectClassListener}, {@link ObjectEventListener} or {@link ObjectListener}
* (I recommend you to read javadoc for all of them) automatically registering a
* listener inside {@link ResponsiveBot${symbol_pound}getWorldView()} using one of the
* "addListener" methods (e.g. {@link EventListener} annotated method is recalled
* from listener added via {@link IWorldView${symbol_pound}addEventListener(java.lang.Class, cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener)}.
* It provides you with a simple way how to create methods that reacts on certain events inside the game.
*
* <p><p>
* WARNING: these annotations works only in THIS class only. If you want other of your classes to have the
* same option, you will have to instantiate {@link AnnotationListenerRegistrator} for yourself
* within that class.
*
* <p><p>
* We advise you to read through all comments carefully and try to understand
* when {@link EventListener} suffices and when you need to use one
* of {@link ObjectClassEventListener} /
* {@link ObjectClassListener} / {@link ObjectEventListener} / {@link ObjectListener}s.
*
* <p><p>
* The trick is that some messages from GB2004 are {@link IWorldEvent}s only and some of them are {@link IWorldObject}s as well.
* For listening {@link IWorldEvent}s only you must use {@link EventListener}, for listening to object updates,
* you must use one of {@link ObjectClassEventListener} / {@link ObjectClassListener} / {@link ObjectEventListener} / {@link ObjectListener}s.
*
* <p><p>
* We recommend you to run the bot on DM-TrainingDay map.
*
* <p><p>
* Start the bot and run to it. Note that whenever the bot sees you (you enter bot's field of view}
* {@link ResponsiveBot${symbol_pound}playerAppeared(cz.cuni.amis.pogamut.base3d.worldview.object.event.WorldObjectAppearedEvent)} will be triggered
* and the bot will greet you.
*
* <p><p>
* Then try to approach very close to the bot and it will ask you "what do you want". See {@link ResponsiveBot${symbol_pound}playerUpdated(cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent) }
* event listener method.
*
* <p><p>
* Check out comments inside {@link ResponsiveBot${symbol_pound}gb2004BatchEnd(cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.EndMessage)} message.
*
* @author Rudolf Kadlec aka ik
* @author Jakub Gemrot aka Jimmy
*/
@AgentScoped
public class ResponsiveBot extends UT2004BotModuleController {
/**
* Listener called when someone/something bumps into the bot. The bot
* responds by moving in the opposite direction than the bump come from.
*
* <p><p>
* We're using {@link EventListener} here that is registered by the {@link AnnotationListenerRegistrator}
* to listen for {@link Bumped} events.
*
* <p><p>
* Notice that {@link Bumped} is {@link IWorldEvent} only, it's not {@link IWorldObject},
* thus we're using {@link EventListener}.
*/
@EventListener(eventClass = Bumped.class)
protected void bumped(Bumped event) {
// schema of the vector computations
//
// e<->a<------>t
// | | v |
// | | target - bot will be heading there
// | getLocation()
// event.getLocation()
Location v = event.getLocation().sub(bot.getLocation()).scale(5);
Location target = bot.getLocation().sub(v);
// make the bot to go to the computed location while facing the bump source
move.strafeTo(target, event.getLocation());
}
/**
* Listener called when a player appears.
*
* <p><p>
* We're using {@link ObjectClassEventListener} here that is registered by the {@link AnnotationListenerRegistrator} to
* listen on all {@link WorldObjectAppearedEvent} that happens on any object
* of the class {@link Player}.
*
* <p><p>
* I.e., whenever the GameBots2004 sends an
* update about arbitrary {@link Player} object in the game notifying us that the
* player has become visible (it's {@link Player${symbol_pound}isVisible()} is switched to
* true and the {@link WorldObjectAppearedEvent} is generated), this method
* is called.
*
* <p><p>
* Notice that {@link Player} implements {@link IWorldObject} thus you CANNOT use
* {@link EventListener} to catch events that updates {@link Player} objects.
*/
@ObjectClassEventListener(eventClass = WorldObjectAppearedEvent.class, objectClass = Player.class)
protected void playerAppeared(WorldObjectAppearedEvent<Player> event) {
// greet player when he appears
body.getCommunication().sendGlobalTextMessage("Hello " + event.getObject().getName() + "!");
}
/**
* Flag indicating whether the player was also close to the bot last time it
* was updated.
*/
protected boolean wasCloseBefore = false;
/**
* Listener called each time a player is updated.
*
* <p><p>
* Again, we're using {@link ObjectClassEventListener}
* that is registered by the {@link AnnotationListenerRegistrator} to listen
* on all {@link WorldObjectUpdatedEvent} that happens on any object of the
* class {@link Player}.
*
* <p><p>
* I.e., whenever the GameBots2004 sends an update
* about arbitrary {@link Player} in the game notifying us that some
* information about the player has changed (the {@link WorldObjectUpdatedEvent}
* is generated), this method is called.
*
* <p><p>
* Again, {@link Player} implements {@link IWorldObject}, thus you CANNOT use
* {@link EventListener} annotation to check for events regarding {@link Player}
* objects.
*/
@ObjectClassEventListener(eventClass = WorldObjectUpdatedEvent.class, objectClass = Player.class)
protected void playerUpdated(WorldObjectUpdatedEvent<Player> event) {
// Check whether the player is closer than 5 bot diameters.
// Notice the use of the UnrealUtils class.
// It contains many auxiliary constants and methods.
Player player = event.getObject();
// First player objects are received in HandShake - at that time we don't have Self message yet or players location!!
if (player.getLocation() == null || info.getLocation() == null) {
return;
}
if (player.getLocation().getDistance(info.getLocation()) < (UnrealUtils.CHARACTER_COLLISION_RADIUS * 10)) {
// If the player wasn't close enough the last time this listener was called,
// then ask him what does he want.
if (!wasCloseBefore) {
body.getCommunication().sendGlobalTextMessage("What do you want " + player.getName() + "?");
// Set proximity flag to true.
wasCloseBefore = true;
}
} else {
// Otherwise set the proximity flag to false.
wasCloseBefore = false;
}
}
/**
* Listener that is manually created and manually hooked to the {@link ResponsiveBot${symbol_pound}getWorldView()}
* via {@link IWorldView${symbol_pound}addEventListener(Class, IWorldEventListener)}
* method inside {@link ResponsiveBot${symbol_pound}prepareBot(UT2004Bot)}.
*
* <p><p>
* Note, that this is old/manual way how to add listeners on various events that are rised
* within the {@link IWorldView} (obtainable from {@link UT2004Bot${symbol_pound}getWorldView()} via
* <code>bot.getWorldView()</code> or simply accessing {@link UT2004BotModuleController${symbol_pound}world} field).
*
* <p><p>
* Such event listener MUST BE registered via some method of {@link IWorldView} offers.
* This particular listener is registered inside {@link ResponsiveBot${symbol_pound}prepareBot(cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot)}.
* Note that you can add/remove any listener during runtime.
*/
IWorldEventListener<BotDamaged> botDamagedListener = new IWorldEventListener<BotDamaged>() {
@Override
public void notify(BotDamaged event) {
// the bot was injured - let's move around the level and hope that we will find a health pack
// note that we have to acquire "SECOND" nearest navpoint, as the first one is the navpoint we're standing at
NavPoint secondNav = DistanceUtils.getSecondNearest(getWorldView().getAll(NavPoint.class).values(), info.getLocation());
// always check even for improbable conditions
if (secondNav == null) {
// try to locate some navpoint
move.turnVertical(30);
} else {
// move to it
move.moveTo(secondNav);
}
}
};
/**
* Example usage of {@link ObjectListener} that will listen on every change
* / event that will be raised on the concrete {@link IWorldObject}, in this
* case on the {@link GameInfo}.
*
* <p><p>
* Notice that we have to specify which ID
* class the world object is using and have explicit representation of it's
* id - note that this is totally unsuitable for any dynamic IDs, such as
* NavPoint ids, etc... you will probably never use this annotation.
*
* <p><p>
* See implementations of {@link IWorldObjectEvent}, which are
* {@link WorldObjectFirstEncounteredEvent}, {@link WorldObjectAppearedEvent},
* {@link WorldObjectUpdatedEvent}, {@link WorldObjectDisappearedEvent}
* and {@link WorldObjectDestroyedEvent}. All such events may be possibly
* caught by this {@link ObjectListener} annotated method.
*
* @param info
*/
@ObjectListener(idClass = UnrealId.class, objectId = "GameInfoId")
public void gameInfo1(IWorldObjectEvent<GameInfo> gameInfoEvent) {
log.warning("GAME INFO EVENT =1=: " + gameInfoEvent);
}
/**
* Example usage of {@link ObjectEventListener} that will listen on SPECIFIC
* event that is raised on the concrete {@link IWorldObject}. As is the case
* of {@link ResponsiveBot${symbol_pound}gameInfo1(IWorldObjectEvent)}, you will probably
* never use this.
*
* @param gameInfoEvent
*/
@ObjectEventListener(idClass = UnrealId.class, objectId = "GameInfoId", eventClass = WorldObjectUpdatedEvent.class)
public void gameInfo2(WorldObjectUpdatedEvent<GameInfo> gameInfoEvent) {
log.warning("GAME INFO EVENT =2=: " + gameInfoEvent);
}
/**
* Example usage of {@link ObjectClassListener} notice the difference
* between this listener and {@link ObjectClassEventListener} that is used
* on {@link ResponsiveBot${symbol_pound}playerAppeared(WorldObjectAppearedEvent)}.
*
* <p><p>
* This method will receive ALL events that are raised on any {@link Player}
* object whereas {@link ResponsiveBot${symbol_pound}playerAppeared(WorldObjectAppearedEvent)}
* will receive only {@link WorldObjectAppearedEvent}.
*
* <p><p>
* See implementations of {@link IWorldObjectEvent}, which are
* {@link WorldObjectFirstEncounteredEvent}, {@link WorldObjectAppearedEvent},
* {@link WorldObjectUpdatedEvent}, {@link WorldObjectDisappearedEvent}
* and {@link WorldObjectDestroyedEvent}. All such events may be possibly
* caught by this {@link ObjectListener} annotated method.
*
* @param playerEvent
*/
@ObjectClassListener(objectClass = Player.class)
public void playerEvent(IWorldObjectEvent<Player> playerEvent) {
log.warning("PLAYER EVENT: " + playerEvent);
}
/**
* If you uncomment {@link EventListener} annotation below this comment, this message
* will be triggered every time the GB2004 sends EndMessage to you. It will (more-less)
* act the same way as {@link ResponsiveBot${symbol_pound}logic()} method.
* @param event
*/
//@EventListener(eventClass=EndMessage.class)
public void gb2004BatchEnd(EndMessage event) {
log.info("EndMessage received!");
}
/**
* Initialize all necessary variables here, before the bot actually receives
* anything from the environment + hook up your custom listener.
*/
@Override
public void prepareBot(UT2004Bot bot) {
// register the botDamagedListener that we have previously created
getWorldView().addEventListener(BotDamaged.class, botDamagedListener);
}
/**
* Here we can modify initialize command for our bot if we want to.
*
* @return
*/
@Override
public Initialize getInitializeCommand() {
return new Initialize();
}
/**
* The bot is initialized in the environment - a physical representation of
* the bot is present in the game.
*
* @param config information about configuration
* @param init information about configuration
*/
@Override
public void botFirstSpawn(GameInfo gameInfo, ConfigChange config, InitedMessage init, Self self) {
// notify the world (i.e., send message to UT2004) that the bot is up and running
body.getCommunication().sendGlobalTextMessage("I am alive!");
}
/**
* This method is called only once right before actual logic() method is
* called for the first time. Similar to {@link ResponsiveBot${symbol_pound}botFirstSpawn(cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo, cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ConfigChange, cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.InitedMessage, cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self)}.
*/
@Override
public void beforeFirstLogic() {
}
/**
* Main method that controls the bot - makes decisions what to do next.
* <p><p> Notice that the method is empty as this bot is completely
* event-driven.
*/
@Override
public void logic() throws PogamutException {
}
/**
* Called each time our bot die. Good for reseting all bot state dependent
* variables.
*
* @param event
*/
@Override
public void botKilled(BotKilled event) {
}
/**
* This method is called when the bot is started either from IDE or from
* command line.
*
* @param args
*/
public static void main(String args[]) throws PogamutException {
// wrapped logic for bots executions, suitable to run single bot in single JVM
new UT2004BotRunner(ResponsiveBot.class, "ResponsiveBot").setMain(true).startAgent();
}
}