View Javadoc

1   /**
2    * Emohawk Bot, an implementation of the environment interface standard that 
3    * facilitates the connection between GOAL and Emohawk. 
4    * 
5    * Copyright (C) 2012 Emohawk Bot authors.
6    * 
7    * This program is free software: you can redistribute it and/or modify it under
8    * the terms of the GNU General Public License as published by the Free Software
9    * Foundation, either version 3 of the License, or (at your option) any later
10   * version.
11   * 
12   * This program is distributed in the hope that it will be useful, but WITHOUT
13   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15   * details.
16   * 
17   * You should have received a copy of the GNU General Public License along with
18   * this program. If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  package nl.tudelft.goal.emohawk.agent;
22  
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collection;
26  import java.util.List;
27  import java.util.concurrent.Semaphore;
28  import java.util.concurrent.TimeUnit;
29  import java.util.concurrent.locks.Lock;
30  import java.util.concurrent.locks.ReentrantLock;
31  
32  import nl.tudelft.goal.EIS2Java.annotation.AsAction;
33  import nl.tudelft.goal.EIS2Java.annotation.AsPercept;
34  import nl.tudelft.goal.EIS2Java.handlers.AsynchronousEntity;
35  import nl.tudelft.goal.EIS2Java.translation.Filter.Type;
36  import nl.tudelft.goal.emohawk.translators.UnrealIdOrLocation;
37  import nl.tudelft.goal.emohawk.translators.UnrealIdOrLocationTranslator;
38  import nl.tudelft.goal.unreal.messages.BotParameters;
39  import nl.tudelft.goal.unreal.messages.Parameters;
40  import SteeringProperties.ObstacleAvoidanceProperties;
41  import SteeringProperties.WalkAlongProperties;
42  import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
43  import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
44  import cz.cuni.amis.pogamut.emohawk.agent.module.sensomotoric.EmoticonType;
45  import cz.cuni.amis.pogamut.emohawk.agent.module.sensomotoric.Place;
46  import cz.cuni.amis.pogamut.emohawk.bot.impl.EmohawkBotController;
47  import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.AgentInfo;
48  import cz.cuni.amis.pogamut.ut2004.agent.params.UT2004AgentParameters;
49  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
50  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Initialize;
51  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
52  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
53  import cz.cuni.amis.utils.exception.PogamutException;
54  import eis.exceptions.ActException;
55  
56  public class EmohawkBotBehavior extends EmohawkBotController<UT2004Bot> implements AsynchronousEntity {
57  
58  	private Semaphore logic = new Semaphore(0, true);
59  
60  	private WalkAlongProperties walkAlongProperties;
61  
62  	private BotParameters parameters;
63  
64  	@SuppressWarnings("rawtypes")
65  	public void initializeController(UT2004Bot bot) {
66  		super.initializeController(bot);
67  
68  		// Setup parameters
69  		IAgentLogger logger = bot.getLogger();
70  		UT2004AgentParameters parameters = bot.getParams();
71  		if ((parameters instanceof BotParameters)) {
72  			this.parameters = (BotParameters) parameters;
73  		} else {
74  			log.warning("Provided parameters were not a subclass of UnrealGoalParameters, using defaults.");
75  			this.parameters = new BotParameters(logger);
76  		}
77  		Parameters defaults = BotParameters.getDefaults(logger);
78  		this.parameters.assignDefaults(defaults);
79  	}
80  
81  	protected void initializeModules(UT2004Bot bot) {
82  		super.initializeModules(bot);
83  
84  		steering.addObstacleAvoidanceSteering(new ObstacleAvoidanceProperties());
85  		walkAlongProperties = new WalkAlongProperties();
86  		walkAlongProperties.setDistanceFromThePartner(200);
87  		walkAlongProperties.setGiveWayToPartner(false);
88  		steering.addWalkAlongSteering(new WalkAlongProperties());
89  	}
90  
91  	/**
92  	 * Prepares the initialization message for Gamebots using the
93  	 * {@link BotParameters} provided to the {@link UT2004BotRunner}.
94  	 * 
95  	 */
96  	@Override
97  	public Initialize getInitializeCommand() {
98  		assert parameters != null;
99  
100 		// Prepare init command
101 		Initialize init = super.getInitializeCommand();
102 		init.setDesiredSkill(parameters.getSkill());
103 		init.setSkin(parameters.getSkin().getUnrealName());
104 		init.setTeam(parameters.getTeam());
105 		init.setShouldLeadTarget(parameters.shouldLeadTarget());
106 		init.setLocation(parameters.getStartLocation());
107 		init.setRotation(parameters.getStartRotation());
108 		// Set log level.
109 		bot.getLogger().setLevel(this.parameters.getLogLevel());
110 
111 		return init;
112 	}
113 
114 	@Override
115 	public void logic() throws PogamutException {
116 		super.logic();
117 		
118 		// Mark that another logic iteration has began
119 		log.fine("--- Logic iteration ---");
120 
121 		// 1. We release a permit for the actions to be executed.
122 		logic.release();
123 
124 		// 2. So actions are executed in this window.
125 
126 		// 3. After which we retract the permit and end the logic.
127 		try {
128 			logic.acquire();
129 		} catch (InterruptedException e) {
130 			throw new PogamutException("Logic was interupted while aquiring a permit.", e);
131 		}
132 
133 	}
134 
135 	@Override
136 	public void botShutdown() {
137 		super.botShutdown();
138 
139 		/*
140 		 * The bot has stopped so we can release a permit.
141 		 * 
142 		 * TODO: This should not be required as it implies that actions and
143 		 * percepts are requested after the environment has been killed. However
144 		 * EIS currently allows different threads to manipulate the environment
145 		 * at the same time. Thus it may be possible for one thread to be
146 		 * waiting to acquire this agent while another shuts down the
147 		 * environment.
148 		 */
149 		logic.release();
150 	}
151 
152 	@Override
153 	public void acquire() throws InterruptedException {
154 		/*
155 		 * As an extra permit is released in botShutdown the attempt to acquire
156 		 * should never timeout.
157 		 */
158 		if (!logic.tryAcquire(10, TimeUnit.SECONDS)) {
159 			throw new InterruptedException("Could not aquire a permit within the timeout.");
160 		}
161 	}
162 
163 	@Override
164 	public void release() {
165 		logic.release();
166 	}
167 
168 	//
169 	// ============
170 	// EIS Percepts
171 	// ============
172 	//
173 
174 	@AsPercept(name = "navigation")
175 	public String navigation() {
176 
177 		if (steering.isNavigating()) {
178 			return "following";
179 			// FIXME: Would like to uss navigator.isExecuting here but it does
180 			// not consider all it's components. traveling.
181 		} else if (pathExecutor.isExecuting() || getBackToNavGraph.isExecuting() || runStraight.isExecuting()) {
182 			return "traveling";
183 		} else if (pathExecutor.isStuck()) {
184 			return "stuck";
185 		} else if (pathExecutor.isPathUnavailable()) {
186 			return "path_unavailable";
187 		} else if (pathExecutor.isTargetReached()) {
188 			return "destination_reached";
189 
190 		} else {
191 			return "waiting";
192 		}
193 	}
194 
195 	@AsPercept(name = "navPoint", multiplePercepts = true, filter = Type.ONCE)
196 	public Collection<NavPoint> perceptNavPoints() {
197 		return getWorld().getAll(NavPoint.class).values();
198 	}
199 
200 	// TODO: Because EIS2Java assumes objects returned are unchanging, which is
201 	// not the case with pogamut we can't use any other filters but ALWAYS
202 	// (default) and ONCE.
203 	@AsPercept(name = "person", multiplePercepts = true)
204 	public Collection<Player> person() {
205 		return getPlayers().getVisiblePlayers().values();
206 	}
207 
208 	@AsPercept(name = "self")
209 	public AgentInfo self() {
210 		return getInfo();
211 	}
212 
213 	@AsPercept(name = "emoticon", multiplePercepts = true, filter = Type.ONCE)
214 	public Collection<EmoticonType> emoticon() {
215 		return Arrays.asList(EmoticonType.values());
216 	}
217 
218 	// @AsPercept(name = "animation", multiplePercepts = true, filter =
219 	// Type.ONCE)
220 	// public Set<AnimType> animation() {
221 	// return animations.getAvailableAnimations();
222 	// }
223 
224 	@AsPercept(name = "place", multiplePercepts = true, filter = Type.ONCE)
225 	public Collection<Place> place() {
226 		return places.getPlaces();
227 	}
228 
229 	//
230 	// =============
231 	// EIS ACTIONS
232 	// =============
233 	//
234 	@AsAction(name = "stop")
235 	public void stop() {
236 		steering.stopNavigation();
237 		navigation.stopNavigation();
238 	}
239 	
240 	@AsAction(name = "runTo")
241 	public void runTo(UnrealIdOrLocation destination) {
242 		ILocated location = getLocation(destination);
243 
244 		steering.stopNavigation();
245 		if (!move.isRunning())
246 			move.setRun();
247 		navigation.navigate(location);
248 	}
249 
250 
251 	@AsAction(name = "walkTo")
252 	public void walkTo(UnrealIdOrLocation destination) {
253 		ILocated location = getLocation(destination);
254 
255 		steering.stopNavigation();
256 		if (move.isRunning())
257 			move.setWalk();
258 		navigation.navigate(location);
259 	}
260 	
261 
262 	private ILocated getLocation(UnrealIdOrLocation destination) {
263 		ILocated location;
264 		if (destination.isLocation()) {
265 			location = destination.getLocation();
266 		} else {
267 			// Assuming ID's were passed properly this must be a player or
268 			// navpoint.
269 			location = (ILocated) world.get(destination.getId());
270 		}
271 		return location;
272 	}
273 
274 
275 	@AsAction(name = "walkAlong")
276 	public void walkAlong(Player partner) throws ActException {
277 		navigation.stopNavigation();
278 		if (!move.isRunning())
279 			move.setRun();
280 		walkAlongProperties.setPartnerName(partner.getName());
281 		steering.setWalkAlongSteering(walkAlongProperties);
282 		steering.startNavigation();
283 	}
284 
285 	@AsAction(name = "emote")
286 	public void emote(EmoticonType left, EmoticonType center, EmoticonType right) throws ActException {
287 		emoticons.clearEmoticons();
288 
289 		if (left == EmoticonType.NONE && center == EmoticonType.NONE && right == EmoticonType.NONE) {
290 			return;
291 		}
292 
293 		if (left == EmoticonType.NONE && center != EmoticonType.NONE && right == EmoticonType.NONE) {
294 			emoticons.setCenterEmoticonType(center);
295 			return;
296 		}
297 
298 		if (left != EmoticonType.NONE && center == EmoticonType.NONE && right != EmoticonType.NONE) {
299 			emoticons.setDoubleEmoticon(left, right);
300 			return;
301 		}
302 
303 		emoticons.setTripleEmoticon(left, center, right);
304 
305 	}
306 
307 	// @AsAction(name = "animate")
308 	// public void animate(AnimType animation, boolean loop) throws ActException
309 	// {
310 	// animations.stopAnimation();
311 	// animations.playAnimation(animation, loop);
312 	// }
313 
314 	@AsAction(name = "turn")
315 	public void turn(int amount) throws ActException {
316 		move.turnHorizontal(amount);
317 	}
318 
319 	@AsAction(name = "turnTo")
320 	public void turnTo(ILocated location) throws ActException {
321 		move.turnTo(location);
322 	}
323 
324 	@AsAction(name = "jump")
325 	public void jump() throws ActException {
326 		move.jump();
327 	}
328 
329 	@AsAction(name = "skip")
330 	public void skip() throws ActException {
331 		// Does nothing.
332 	}
333 }