View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.agent.module.sensor.visibility;
2   
3   import java.io.File;
4   import java.util.Map;
5   import java.util.Set;
6   import java.util.Map.Entry;
7   import java.util.logging.Logger;
8   
9   import cz.cuni.amis.pogamut.base.agent.module.SensorModule;
10  import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
11  import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
12  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
13  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
14  import cz.cuni.amis.pogamut.base.utils.Pogamut;
15  import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
16  import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
17  import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.AgentInfo;
18  import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.visibility.model.VisibilityLocation;
19  import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.visibility.model.VisibilityMatrix;
20  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
21  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo;
22  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
23  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPointNeighbourLink;
24  import cz.cuni.amis.pogamut.ut2004.communication.translator.shared.events.MapPointListObtained;
25  import cz.cuni.amis.pogamut.ut2004.utils.PogamutUT2004Property;
26  import cz.cuni.amis.utils.ExceptionToString;
27  import cz.cuni.amis.utils.NullCheck;
28  import cz.cuni.amis.utils.SafeEquals;
29  
30  /**
31   * Module that provides visibility information for the map.
32   * 
33   * The visibility is approximated from {@link VisibilityLocation}s for which we have {@link VisibilityMatrix} built.
34   * 
35   * Note that the module expects "VisibilityMatrix-" + mapName + "-All.bin" file present
36   * in the current directory of the process "." (preferred) or directory specified in PogamutUT2004.properties under 
37   * {@link PogamutUT2004Property#POGAMUT_UT2004_VISIBILITY_DIRECTORY}. This file can be generated utilizing 
38   * {@link VisibilityCreator} and its {@link VisibilityCreator#main(String[])} method.
39   * 
40   * @author Jimmy
41   */
42  public class Visibility extends SensorModule<UT2004Bot>
43  {
44  	/**
45  	 * Tells you whether the module is initialized, e.g., visibility matrix information is available for the level.
46  	 * 
47  	 * See {@link VisibilityCreator} that contains {@link VisibilityCreator#main(String[])} method implemented for quick generation
48  	 * of {@link VisibilityMatrix} that is used for obtaining all visibility information for the level. 
49  	 * 
50  	 * @return
51  	 */
52  	public boolean isInitialized() {
53  		return matrix != null;
54  	}
55  	
56  	/**
57  	 * Returns underlying {@link VisibilityMatrix} that is neede for custom advanced computation.
58  	 * @return
59  	 */
60  	public VisibilityMatrix getMatrix() {
61  		return matrix;
62  	}
63  		
64  	/**
65  	 * Nearest {@link VisibilityLocation} to 'located' present in matrix. 
66  	 * 
67  	 * I.e., nearest {@link VisibilityLocation} we're having visibility information for. 
68  	 * 
69  	 * @param located
70  	 * @return
71  	 */
72  	public VisibilityLocation getNearestVisibilityLocationTo(ILocated located) {
73  		if (!isInitialized()) return null;
74  		return matrix.getNearest(located);
75  	}
76  	
77  	/**
78  	 * Nearest {@link VisibilityLocation} to BOT CURRENT LOCATION. 
79  	 * 
80  	 * I.e., nearest {@link VisibilityLocation} we're having visibility information for.
81  	 * 
82  	 * @return
83  	 */
84  	public VisibilityLocation getNearestVisibilityLocation() {
85  		return getNearestVisibilityLocationTo(info.getLocation());
86  	}
87  	
88  	/**
89  	 * Nearest {@link NavPoint} to 'located' present in the matrix, this should equal (== 99.99%) to nearest navpoint in the map.
90  	 * 
91  	 * @param located
92  	 * @return
93  	 */
94  	public NavPoint getNearestNavPointTo(ILocated located) {
95  		if (!isInitialized()) return null;
96  		return matrix.getNearestNavPoint(located);
97  	}
98  	
99  	/**
100 	 * Nearest {@link NavPoint} to BOT CURRENT LOCATION present in the matrix, this should equal (== 99.99%) to nearest navpoint (to bot) in the map.
101 	 *
102 	 * @return
103 	 */
104 	public NavPoint getNearestNavPopint() {
105 		return getNearestNavPointTo(info.getLocation());
106 	}
107 	
108 	/**
109 	 * Returns whether 'loc1' is visible from 'loc2' (and vice versa == symmetric info).
110 	 * 
111 	 * Note that the information is only approximated from nearest known {@link VisibilityLocation}.
112 	 * The information is accurate for navpoints and very accurate for points on links between navpoints. 
113 	 * 
114 	 * If module is not {@link Visibility#isInitialized()}, returns false.
115 	 * 
116 	 * @param loc1
117 	 * @param loc2
118 	 * @return
119 	 */
120 	public boolean isVisible(ILocated loc1, ILocated loc2) {
121 		if (!isInitialized()) return false;
122 		return matrix.isVisible(loc1, loc2);
123 	}
124 	
125 	/**
126 	 * Returns whether BOT can see 'target' (and vice versa == symmetric info).
127 	 * 
128 	 * Note that the information is only approximated from nearest known {@link VisibilityLocation}.
129 	 * The information is accurate for navpoints and very accurate for points on links between navpoints.
130 	 * 
131 	 * If module is not {@link Visibility#isInitialized()}, returns false.
132 	 * 
133 	 * @param target
134 	 * @return
135 	 */
136 	public boolean isVisible(ILocated target) {
137 		return isVisible(info.getLocation(), target);
138 	}
139 	
140 	/**
141 	 * Returns set of {@link VisibilityLocation} that are not visible from "loc".
142 	 * @param loc
143 	 * @return
144 	 */
145 	public Set<VisibilityLocation> getCoverPointsFrom(ILocated loc) {
146 		if (!isInitialized()) return null;
147 		return matrix.getCoverPoints(loc);
148 	}
149 	
150 	/**
151 	 * Returns set of {@link VisibilityLocation} that are not visible FROM BOT CURRENT LOCATION.
152 	 * @return
153 	 */
154 	public Set<VisibilityLocation> getHiddenPoints() {
155 		return getCoverPointsFrom(info.getLocation());
156 	}
157 	
158 	/**
159 	 * Returns nearest cover point for BOT where to hide from 'enemy'.
160 	 * @param enemy
161 	 * @return
162 	 */
163 	public VisibilityLocation getNearestCoverPointFrom(ILocated enemy) {
164 		if (!isInitialized()) return null;
165 		return matrix.getNearestCoverPoint(info.getLocation(), enemy);
166 	}
167 	
168 	
169 	/**
170 	 * Returns set of {@link VisibilityLocation} that are visible from "loc".
171 	 * 
172 	 * @param loc
173 	 * @return
174 	 */
175 	public Set<VisibilityLocation> getVisiblePointsFrom(ILocated loc) {
176 		if (!isInitialized()) return null;
177 		return matrix.getVisiblePoints(loc);
178 	}
179 	
180 	/**
181 	 * Returns set of {@link VisibilityLocation} that are visible FROM CURRENT BOT LOCATION.
182 	 * @return
183 	 */
184 	public Set<VisibilityLocation> getVisiblePoints() {
185 		return getVisiblePointsFrom(info.getLocation());
186 	}
187 		
188 	/**
189 	 * Returns set of {@link NavPoint} that are not visible from "loc".
190 	 * @param loc
191 	 * @return
192 	 */
193 	public Set<NavPoint> getCoverNavPointsFrom(ILocated loc) {
194 		if (!isInitialized()) return null;
195 		return matrix.getCoverNavPoints(loc);
196 	}
197 	
198 	/**
199 	 * Returns set of {@link NavPoint} that are not visible FROM CURRENT BOT LOCATION.
200 	 * @return
201 	 */
202 	public Set<NavPoint> getHiddenNavPoints() {
203 		return getCoverNavPointsFrom(info.getLocation());
204 	}
205 	
206 	/**
207 	 * Returns nearest cover {@link NavPoint} for BOT where to hide from 'enemy'.
208 	 * @param enemy
209 	 * @return
210 	 */
211 	public NavPoint getNearestCoverNavPointFrom(ILocated enemy) {
212 		if (!isInitialized()) return null;
213 		return matrix.getNearestCoverNavPoint(enemy);
214 	}
215 	
216 	/**
217 	 * Returns set of {@link NavPoint} that are visible from "loc".
218 	 * 
219 	 * @param loc
220 	 * @return
221 	 */
222 	public Set<NavPoint> getVisibleNavPointsFrom(ILocated loc) {
223 		if (!isInitialized()) return null;
224 		return matrix.getVisibleNavPoints(loc);
225 	}
226 	
227 	/**
228 	 * Returns set of {@link NavPoint} that are visible FROM CURRENT BOT LOCATION.
229 	 * @return
230 	 */
231 	public Set<NavPoint> getVisibleNavPoints() {
232 		if (!isInitialized()) return null;
233 		return matrix.getVisibleNavPoints(info.getLocation());
234 	}
235 	
236 	/**
237 	 * Returns set of {@link VisibilityLocation} that are not visible from any 'enemies'.
238 	 * @param enemies
239 	 * @return
240 	 */
241 	public Set<VisibilityLocation> getCoverPointsFromN(ILocated... enemies) {
242 		if (!isInitialized()) return null;
243 		return matrix.getCoverPointsN(enemies);		
244 	}
245 	
246 	/**
247 	 * Returns nearest cover point for 'target' that is hidden from all 'enemies'.
248 	 * @param target
249 	 * @param enemies
250 	 * @return
251 	 */
252 	public VisibilityLocation getNearestCoverPointFromN(ILocated target, ILocated... enemies) {
253 		if (!isInitialized()) return null;
254 		return matrix.getNearestCoverPointN(target, enemies);
255 	}
256 	
257 	/**
258 	 * Returns nearest cover point for BOT that is hidden from all 'enemies'.
259 	 * @param target
260 	 * @param enemies
261 	 * @return
262 	 */
263 	public VisibilityLocation getNearestCoverPointN(ILocated... enemies) {
264 		return getNearestCoverPointFromN(info.getLocation(), enemies);
265 	}
266 	
267 	/**
268 	 * Returns set of {@link NavPoint} that are not visible from any 'enemies'.
269 	 * @param enemies
270 	 * @return
271 	 */
272 	public Set<NavPoint> getCoverNavPointsFromN(ILocated... enemies) {
273 		if (!isInitialized()) return null;
274 		return matrix.getCoverNavPointsN(enemies);
275 	}
276 	
277 	/**
278 	 * Returns nearest cover nav point for 'target' that is hidden from all 'enemies'.
279 	 * @param target
280 	 * @param enemies
281 	 * @return
282 	 */
283 	public NavPoint getNearestCoverNavPointFromN(ILocated target, ILocated... enemies) {
284 		if (!isInitialized()) return null;
285 		return matrix.getNearestCoverNavPointN(target, enemies);
286 	}
287 	
288 	/**
289 	 * Returns nearest cover nav point for BOT that is hidden from all 'enemies'.
290 	 * @param enemies
291 	 * @return
292 	 */
293 	public NavPoint getNearestCoverNavPointN(ILocated... enemies) {
294 		return getNearestCoverNavPointFromN(info.getLocation(), enemies);
295 	}
296 
297 		
298 	//
299 	// =======================================
300 	// LIFECYCLE STUFF
301 	// =======================================
302 	//
303 	
304 	/**
305 	 * GameInfo listener.
306 	 */
307 	private class GameInfoListener implements IWorldObjectEventListener<GameInfo, IWorldObjectEvent<GameInfo>>
308 	{		
309 		@Override
310 		public void notify(IWorldObjectEvent<GameInfo> event)
311 		{
312 			lastGameInfo = event.getObject();
313 		}
314 		
315 		/**
316 		 * Constructor. Registers itself on the given WorldView object.
317 		 * @param worldView WorldView object to listent to.
318 		 */
319 		public GameInfoListener(IWorldView worldView)
320 		{
321 			worldView.addObjectListener(GameInfo.class, this);
322 		}
323 	}
324 	
325 	/**
326 	 * GameInfo listener.
327 	 */
328 	private class MapPointListener implements IWorldEventListener<MapPointListObtained>
329 	{		
330 		@Override
331 		public void notify(MapPointListObtained event)
332 		{
333 			init(lastGameInfo, event);
334 		}
335 		
336 		/**
337 		 * Constructor. Registers itself on the given WorldView object.
338 		 * @param worldView WorldView object to listent to.
339 		 */
340 		public MapPointListener(IWorldView worldView)
341 		{
342 			worldView.addEventListener(MapPointListObtained.class, this);
343 		}
344 	}
345 
346 
347 	GameInfoListener gameInfoListener;
348 
349 	GameInfo lastGameInfo;
350 	
351 	MapPointListener mapPointListener;
352 
353 	/**
354 	 * Underlying instance that is used for all getters. Initialized inside {@link Visibility#init(String)} that is called by
355 	 * {@link MapPointListener} whenever {@link GameInfo} and {@link MapPointListObtained} message is obtained.
356 	 */
357 	VisibilityMatrix matrix = null;
358 
359 	/**
360 	 * Agent info modul needed.
361 	 */
362 	AgentInfo info;
363 	
364 	/**
365 	 * Called from within {@link MapPointListener} whenever {@link GameInfo} and {@link MapPointListObtained} message is obtained.
366 	 * @param gameInfo
367 	 * @param event 
368 	 */
369 	void init(GameInfo gameInfo, MapPointListObtained event) {
370 		if (gameInfo == null || event == null) {
371 			log.warning("Cannot initialize." + (gameInfo == null ? " GameInfo is NULL." : "") + (event == null ? " MapPoints is NULL." : ""));
372 			return;
373 		}
374 		
375 		Map<UnrealId, NavPoint> navPoints = event.getNavPoints();		
376 		if (navPoints == null) {
377 			log.warning("Cannot map visibility locations to NavPoints and Links, nav points not exported by GameBots2004...");
378 			log.warning("Module cannot be initialized.");
379 			return;
380 		}
381 		
382 		String mapName = gameInfo.getLevel();
383 		log.info("Trying to initialize visibility matrix for map: " + mapName);
384 		
385 		File file1 = VisibilityMatrix.getFile_All(new File("."), mapName);
386 		log.info("Looking for file: " + file1.getAbsolutePath());
387 
388 		VisibilityMatrix visibilityMatrix = tryToLoadVisibilityMatrix(new File("."), mapName);
389 		if (visibilityMatrix == null) {
390 			// try property
391 			String dir = Pogamut.getPlatform().getProperty(PogamutUT2004Property.POGAMUT_UT2004_VISIBILITY_DIRECTORY.getKey());
392 			if (dir == null) {
393 				log.warning("Could not load visibility information for " + mapName + ". File from local dir " + file1.getAbsolutePath() + " not found and property " + PogamutUT2004Property.POGAMUT_UT2004_VISIBILITY_DIRECTORY.getKey() + " not set.");
394 			} else {
395 				File dirFile = new File(dir);
396 				if (dirFile.exists() && dirFile.isDirectory()) {
397 					File file2 = VisibilityMatrix.getFile_All(dirFile, mapName);
398 					log.info("Looking for file: " + file2.getAbsolutePath());
399 					visibilityMatrix = tryToLoadVisibilityMatrix(new File("."), mapName);
400 					if (visibilityMatrix == null) {
401 						log.warning("Could not load visibility information for " + mapName + ". File from local dir " + file1.getAbsolutePath() + " not found and file from configured dir " + file2.getAbsolutePath() + " was not found as well.");						
402 					}
403 				} else {
404 					log.warning("Could not load visibility information for " + mapName + ". File from local dir " + file1.getAbsolutePath() + " not found and property " + PogamutUT2004Property.POGAMUT_UT2004_VISIBILITY_DIRECTORY.getKey() + " leads to non-dir " + dirFile.getAbsolutePath() + ".");
405 				}
406 			}
407 		}
408 		
409 		if (visibilityMatrix == null) {
410 			log.warning("Visibility matrix was not loaded, module could not be initialized.");
411 			return;
412 		}
413 		
414 		log.warning("Visibility matrix loaded successfully.");
415 
416 		log.info("Mapping navpoints and links...");
417 		
418 		for (Entry<Integer, VisibilityLocation> vLocEntry : visibilityMatrix.getLocations().entrySet()) {
419 			VisibilityLocation vLoc = vLocEntry.getValue();
420 			if (vLoc.navPoint1Id != null) {
421 				if (vLoc.navPoint2Id != null) {
422 					// search for link
423 					String navPoint1Id = mapName + "." + vLoc.navPoint1Id;
424 					NavPoint np1 = navPoints.get(UnrealId.get(navPoint1Id));
425 					if (np1 == null) {
426 						log.warning("Could not find navpoint (map changed? / old visibility matrix file?): " + navPoint1Id);
427 						continue;
428 					}
429 					String navPoint2Id = mapName + "." + vLoc.navPoint2Id;
430 					NavPoint np2 = navPoints.get(UnrealId.get(navPoint2Id));
431 					if (np2 == null) {
432 						log.warning("Could not find navpoint (map changed? / old visibility matrix file?): " + navPoint2Id);
433 						continue;
434 					}
435 					NavPointNeighbourLink link = np1.getOutgoingEdges().get(np2.getId());
436 					if (link == null) {
437 						link = np2.getOutgoingEdges().get(np1.getId());
438 						log.warning("Could not find navpoint link (map changed? / old visibility matrix file?): " + navPoint1Id + " <-> " + navPoint2Id);
439 						continue;
440 					}
441 					vLoc.link = link;
442 					continue;
443 				} else {
444 					// search for navpoint
445 					String navPointId = mapName + "." + vLoc.navPoint1Id;
446 					vLoc.navPoint = navPoints.get(UnrealId.get(navPointId));
447 					if (vLoc.navPoint == null) {
448 						log.warning("Could not find navpoint (map changed? / old visibility matrix file?): " + navPointId);
449 						continue;
450 					}
451 					continue;
452 				}
453 			} else {
454 				log.warning("Malformed VisibilityLocation under index " + vLocEntry.getKey() + ", it does not have navPoint1Id specified!");
455 			}
456 		}
457 		
458 		this.matrix = visibilityMatrix;
459 		log.warning("Navpoints and links mapped, module is ready to be used.");		
460 	}
461 	
462 	private VisibilityMatrix tryToLoadVisibilityMatrix(File directory, String mapName) {
463 		File file = VisibilityMatrix.getFile_All(directory, mapName);
464 		if (file.exists() && file.isFile()) {
465 			try {
466 				VisibilityMatrix visibilityMatrix = VisibilityMatrix.load(directory, mapName);
467 				if (!SafeEquals.equals(mapName, visibilityMatrix.getMapName())) {
468 					log.warning("Expected to load visibility matrix for map " + mapName + ", but matrix for " + visibilityMatrix.getMapName() + " loaded instead! (Misplaced file?) Module cannot be used.");
469 					return null;
470 				}
471 				return visibilityMatrix;
472 			} catch (Exception e) {		
473 				log.warning(ExceptionToString.process("Failed to load visibility matrix from existing file " + file.getAbsolutePath() + ".", e));
474 			}
475 		}
476 		return null;
477 	}
478 
479 	/*========================================================================*/
480 
481 	/**
482 	 * Constructor. Setups the memory module based on bot's world view.
483 	 * @param bot owner of the module that is using it
484 	 * @param info {@link AgentInfo} module to be used
485 	 */
486 	public Visibility(UT2004Bot bot, AgentInfo info) {
487 		this(bot, info, null);
488 	}
489 	
490 	/**
491 	 * Constructor. Setups the memory module based on bot's world view.
492 	 * @param bot owner of the module that is using it
493 	 * @param info {@link AgentInfo} module to be used
494 	 * @param log Logger to be used for logging runtime/debug info. If <i>null</i>, the module creates its own logger.
495 	 */
496 	public Visibility(UT2004Bot bot, AgentInfo info, Logger log)
497 	{
498 		super(bot, log);
499 
500 		this.info = info;
501 		NullCheck.check(this.info, "agentInfo");
502 		
503 		// create listeners
504 		gameInfoListener = new GameInfoListener(worldView);
505 		mapPointListener = new MapPointListener(worldView);
506 	    
507         cleanUp();
508 	}
509 	
510 	@Override
511 	protected void cleanUp() {
512 		super.cleanUp();
513 		matrix = null;
514 	}
515 	
516 }