View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.agent.module.sensor;
2   
3   import java.util.ArrayList;
4   import java.util.HashMap;
5   import java.util.List;
6   import java.util.logging.Level;
7   import java.util.logging.Logger;
8   
9   import javax.vecmath.Vector3d;
10  
11  import cz.cuni.amis.pogamut.base.agent.module.SensorModule;
12  import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
13  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
14  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
15  import cz.cuni.amis.pogamut.base.component.controller.ComponentDependencies;
16  import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
17  import cz.cuni.amis.pogamut.base3d.worldview.object.Rotation;
18  import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
19  import cz.cuni.amis.pogamut.ut2004.agent.navigation.floydwarshall.FloydWarshallMap;
20  import cz.cuni.amis.pogamut.ut2004.bot.IUT2004BotController;
21  import cz.cuni.amis.pogamut.ut2004.bot.IUT2004BotLogicController;
22  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
23  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004BotModuleController;
24  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo;
25  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
26  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPointMessage;
27  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPointNeighbourLink;
28  import cz.cuni.amis.pogamut.ut2004.utils.LinkFlag;
29  import cz.cuni.amis.pogamut.ut2004.utils.UnrealUtils;
30  import cz.cuni.amis.utils.NullCheck;
31  import cz.cuni.amis.utils.exception.PogamutException;
32  
33  /**
34   * This class can be used to manually improve the navigation graph of the UT2004 by manually adding/removing edges from it.
35   * <p><p>
36   * Note that NavigationGraphBuilder is automatically prefixing all navpoint ids with "mapName.", which means, that you do not
37   * need to specify the id of navpoints as (e.g.) "DM-1on1-Albatross.PathNode2", "PathNode2" suffices. If you want to change this behavior
38   * call {@link NavigationGraphBuilder#setAutoPrefix(boolean)} with "false". Autoprefixing is good as it solves the problem with case-sensitivity
39   * of navpoint ids (i.e., you may run map dm-1on1-albatross as well as DM-1on1-Albatross!), it also makes the work faster as you do not have to repeat
40   * yourself.
41   * <p><p>
42   * Note that even if auto-prefixing enabled you may prefix ids of navpoints with map name, the auto-prefixing implemented by {@link NavigationGraphBuilder#autoPrefix(String)} 
43   * will detects that and auto-correct upper/lower case of this existing prefix if needed. Also you may use it as a validation feature because
44   * the {@link NavigationGraphBuilder#autoPrefix(String)} will raise an exception if the prefix does not match the current map name.
45   * <p><p>
46   * As all {@link SensorModule} it should be initialized in {@link IUT2004BotController#prepareBot(UT2004Bot)}. Note
47   * that {@link UT2004BotModuleController} has it auto-initialized inside {@link UT2004BotModuleController#initializeModules(UT2004Bot)}.
48   * <p><p>
49   * Best utilized in {@link IUT2004BotController#botInitialized(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)} method.
50   * 
51   * 
52   * @author Jimmy
53   *
54   */
55  public class NavigationGraphBuilder extends SensorModule<UT2004Bot> {
56  
57  	/**
58  	 * Builder encloses the creation of the new navpoint.
59  	 * <p><p>
60  	 * You must call {@link NewNavPointBuilder#createNavPoint()} after you set it up to truly create the navpoint inside bot's {@link IWorldView}.
61  	 * 
62  	 * @author Jimmy
63  	 */
64  	public class NewNavPointBuilder {
65  		
66  		private String id;
67  		private Location location;
68  		private List<NewNavPointEdgeBuilder> edges = new ArrayList<NewNavPointEdgeBuilder>();
69  
70  		protected NewNavPointBuilder() {			
71  		}
72  		
73  		/**
74  		 * Sets the ID to be used for the new navpoint, corresponds to {@link NavPoint#getId()}.
75  		 * @param id will be auto-prefixed (if enabled, which is default)
76  		 * @return
77  		 */
78  		public NewNavPointBuilder setId(String id) {
79  			NullCheck.check(id, "id");
80  			this.id = autoPrefix(id);
81  			return this;
82  		}
83  		
84  		/**
85  		 * Sets the location of the new navpoint, corresponds to {@link NavPoint#getLocation()}.
86  		 * 
87  		 * @param x
88  		 * @param y
89  		 * @param z
90  		 * @return
91  		 */
92  		public NewNavPointBuilder setLocation(double x, double y, double z) {
93  			this.location = new Location(x,y,z);
94  			return this;
95  		}
96  		
97  		/**
98  		 * Finalizing method that will insert the navpoint into the underlying {@link IWorldView} of the bot.
99  		 * <p><p>
100 		 * You must have ID/Location set via {@link NewNavPointBuilder#setId(String)} and {@link NewNavPointBuilder#setLocation(double, double, double)}
101 		 * otherwise an exception will be thrown.
102 		 * <p><p>
103 		 * WARNING: IF USED INSIDE THE {@link IUT2004BotLogicController#logic()}, THAN THE NEW NAVPOINT WON'T BE ACCESSIBLE IMMEDIATELLY, IT WILL BE ACCESSIBLE FROM THE NEXT LOGIC ITERATION!
104 		 */
105 		public void createNavPoint() {
106 			if (id == null) throw new PogamutException("Could not create navpoint, id is null, you must set it using setId() before calling this method.", this);
107 			if (location == null) throw new PogamutException("Could not create navpoint (" + id + "), location is null, you must set it using setLocation() before calling this method.", this);
108 			NavPoint newNavPoint = 
109 				new NavPointMessage(UnrealId.get(id), location, null, false, null, null, false, false, null, null, false, false, false, false, 255, false, 255, false, false, false, false, false, false, false, false, new Rotation(0,0,0), false, false, null, new HashMap<UnrealId, NavPointNeighbourLink>(), new HashMap<UnrealId, NavPointNeighbourLink>(), null);
110 			
111 			for (NewNavPointEdgeBuilder edge : edges) {
112 				Object np = agent.getWorldView().get(edge.toNavPointId);
113 				if (np == null) {
114 					throw new PogamutException("Could not create navpoint (" + id + ") as the remote end (" + edge.toNavPointId + ") of one of its edges could not be found in the bot's worldview. Warning, id is case-sensitive the upper/lower cases of the id depends on the concrete spelling of the map that was passed to the GB2004 during startup (either from the command line or by the UT2004).", this);
115 				}
116 				if (!(np instanceof NavPoint)) {
117 					throw new PogamutException("Could not create navpoint (" + id + ") as the remote end (" + edge.toNavPointId + ") of one of its edges is not an instance of NavPoint, but " + np.getClass().getSimpleName() + ". Wrong id used?", this);
118 				}
119 				NavPoint toNavPoint = (NavPoint)np; 
120 				NavPointNeighbourLink link = new NavPointNeighbourLink(UnrealId.get(id), edge.flags, edge.collisionR, edge.collisionH, 0, null, false, edge.forceDoubleJump, edge.neededJump, false, false, 0, newNavPoint, toNavPoint);
121 				newNavPoint.getOutgoingEdges().put(link.getToNavPoint().getId(), link);
122 				link.getToNavPoint().getIncomingEdges().put(newNavPoint.getId(), link);
123 			}
124 			
125 			agent.getWorldView().notifyImmediately(newNavPoint);
126 		}
127 		
128 		/**
129 		 * Creates new edge builder for the navpoint you're creating.
130 		 * <p><p>
131 		 * After setting up the edge properties, use {@link NewNavPointEdgeBuilder#createEdge()} to return to this object (and truly creates the edge!).
132 		 * 
133 		 * @return edge builder
134 		 */
135 		public NewNavPointEdgeBuilder<NewNavPointBuilder> newEdge() {
136 			return new NewNavPointEdgeBuilder<NewNavPointBuilder>(this);
137 		}
138 		
139 		/**
140 		 * Creates new edge (to 'navPointId') builder for the navpoint you're creating.
141 		 * <p><p>
142 		 * After setting up the edge properties, use {@link NewNavPointEdgeBuilder#createEdge()} to return to this object (and truly creates the edge!).
143 		 * 
144 		 * @param navPointId will be auto-prefixed
145 		 * @return edge builder
146 		 */
147 		public NewNavPointEdgeBuilder<NewNavPointBuilder> newEdgeTo(String navPointId) {
148 			NullCheck.check(navPointId, "navPointId");
149 			NewNavPointEdgeBuilder<NewNavPointBuilder> edgeBuilder = new NewNavPointEdgeBuilder<NewNavPointBuilder>(this);
150 			edgeBuilder.setTo(navPointId);
151 			return edgeBuilder;
152 		}
153 		
154 		/**
155 		 * Creates simple edge that leads from the navpoint you're currently creating to 'navPointId'
156 		 * @param navPointId will be auto-prefixed (if enabled, which is default)
157 		 */
158 		public void createSimpleEdgeTo(String navPointId) {
159 			NullCheck.check(navPointId, "navPointId");
160 			newEdgeTo(navPointId).createEdge();
161 		}
162 
163 		/**
164 		 * Adds new edge into {@link NewNavPointBuilder#edges}. Their true creation is postponed until {@link NewNavPointBuilder#createNavPoint()}.
165 		 * 
166 		 * @param newNavPointEdgeBuilder
167 		 */
168 		protected void addEdge(NewNavPointEdgeBuilder newNavPointEdgeBuilder) {
169 			this.edges.add(newNavPointEdgeBuilder);
170 		}
171 		
172 	}
173 	
174 	/**
175 	 * Represents the edge of the navpoint you're newly creating.
176 	 * <p><p>
177 	 * WARNING: the created edge is oriented! Its counterpart (from the remote navpoint to newly created one) must be created manually! (If needed.)
178 	 * 
179 	 * @author Jimmy
180 	 */
181 	public class NewNavPointEdgeBuilder<OWNER> {
182 		
183 		protected OWNER owner;
184 		protected UnrealId toNavPointId;
185 		protected int collisionR = (int)UnrealUtils.CHARACTER_COLLISION_RADIUS * 2;
186 		protected int collisionH = (int)UnrealUtils.CHARACTER_HEIGHT_STANDING + 10;
187 		protected boolean forceDoubleJump = false;
188 		protected Vector3d neededJump;
189 		protected int flags = 0;
190 		
191 		protected NewNavPointEdgeBuilder(OWNER owner) {
192 			this.owner = owner;	
193 			NullCheck.check(this.owner, "owner");
194 		}
195 		
196 		/**
197 		 * Sets the remote end of the edge (i.e., navpoint id where the edge is leading to), corresponds to {@link NavPointNeighbourLink#getToNavPoint()}.
198 		 * 
199 		 * @param navPointId will be auto-prefixed (if enabled, which is default)
200 		 * @return
201 		 */
202 		public NewNavPointEdgeBuilder<OWNER> setTo(String navPointId) {
203 			NullCheck.check(navPointId, "navPointId");
204 			this.toNavPointId = UnrealId.get(autoPrefix(navPointId));
205 			return this;
206 		}
207 		
208 		/**
209 		 * Sets the remote end of the edge (i.e., navpoint id where the edge is leading to), corresponds to {@link NavPointNeighbourLink#getToNavPoint()}.
210 		 * 
211 		 * @param navPointId WON'T BE AUTO-PREFIXED AS IT IS ALREADY EXISTING ID!!!
212 		 * @return
213 		 */
214 		public NewNavPointEdgeBuilder<OWNER> setTo(UnrealId navPointId) {
215 			this.toNavPointId = navPointId;
216 			return this;
217 		}
218 		
219 		/**
220 		 * Sets collision radius of the edge, corresponds to {@link NavPointNeighbourLink#getCollisionR()}.
221 		 * 
222 		 * @param collisionRadius
223 		 * @return
224 		 */
225 		public NewNavPointEdgeBuilder<OWNER> setCollisionRadius(int collisionRadius) {
226 			this.collisionR = collisionRadius;
227 			return this;
228 		}
229 		
230 		/**
231 		 * Sets collision height of the edge, corresponds to {@link NavPointNeighbourLink#getCollisionH()}.
232 		 * 
233 		 * @param collisionHeight
234 		 * @return
235 		 */
236 		public NewNavPointEdgeBuilder<OWNER> setCollisionHeight(int collisionHeight) {
237 			this.collisionH = collisionHeight;
238 			return this;
239 		}
240 		
241 		/**
242 		 * Sets the location from where the bot should jump to reach the target, corresponds to {@link NavPointNeighbourLink#getNeededJump()}.
243 		 * 
244 		 * @param x
245 		 * @param y
246 		 * @param z
247 		 * @return
248 		 */
249 		public NewNavPointEdgeBuilder<OWNER> setNeededJump(double x, double y, double z) {
250 			this.neededJump = new Vector3d(x,y,z);
251 			return this;
252 		}
253 		
254 		/**
255 		 * Sets the flag "double jump is needed" to true, corresponds to {@link NavPointNeighbourLink#isForceDoubleJump()}.
256 		 * 
257 		 * @param neededJump
258 		 * @return
259 		 */
260 		public NewNavPointEdgeBuilder<OWNER> setDoubleJump() {
261 			this.forceDoubleJump = true;
262 			return this;
263 		}
264 		
265 		
266 		/**
267 		 * Sets {@link LinkFlag#WALK} flag into {@link NewNavPointEdgeBuilder#flags} of the new navpoint edge,
268 		 * corresponds to {@link NavPointNeighbourLink#getFlags()}.
269 		 * 
270 		 * @return
271 		 */
272 		public NewNavPointEdgeBuilder<OWNER> setWalkFlag() {
273 			flags |= LinkFlag.WALK.get();
274 			return this;
275 		}
276 		
277 		/**
278 		 * Sets {@link LinkFlag#FLY} flag into {@link NewNavPointEdgeBuilder#flags} of the new navpoint edge,
279 		 * corresponds to {@link NavPointNeighbourLink#getFlags()}.
280 		 * 
281 		 * @return
282 		 */
283 		public NewNavPointEdgeBuilder<OWNER> setFlyFlag() {
284 			flags |= LinkFlag.FLY.get();
285 			return this;
286 		}
287 		
288 		/**
289 		 * Sets {@link LinkFlag#SWIM} flag into {@link NewNavPointEdgeBuilder#flags} of the new navpoint edge,
290 		 * corresponds to {@link NavPointNeighbourLink#getFlags()}.
291 		 * 
292 		 * @return
293 		 */
294 		public NewNavPointEdgeBuilder<OWNER> setSwimFlag() {
295 			flags |= LinkFlag.SWIM.get();
296 			return this;
297 		}
298 		
299 		/**
300 		 * Sets {@link LinkFlag#JUMP} flag into {@link NewNavPointEdgeBuilder#flags} of the new navpoint edge,
301 		 * corresponds to {@link NavPointNeighbourLink#getFlags()}.
302 		 * 
303 		 * @return
304 		 */
305 		public NewNavPointEdgeBuilder<OWNER> setJumpFlag() {
306 			flags |= LinkFlag.JUMP.get();
307 			return this;
308 		}
309 		
310 		/**
311 		 * Sets {@link LinkFlag#DOOR} flag into {@link NewNavPointEdgeBuilder#flags} of the new navpoint edge,
312 		 * corresponds to {@link NavPointNeighbourLink#getFlags()}.
313 		 * 
314 		 * @return
315 		 */
316 		public NewNavPointEdgeBuilder<OWNER> setDoorFlag() {
317 			flags |= LinkFlag.DOOR.get();
318 			return this;
319 		}
320 		
321 		/**
322 		 * Sets {@link LinkFlag#SPECIAL} flag into {@link NewNavPointEdgeBuilder#flags} of the new navpoint edge,
323 		 * corresponds to {@link NavPointNeighbourLink#getFlags()}.
324 		 * 
325 		 * @return
326 		 */
327 		public NewNavPointEdgeBuilder<OWNER> setSpecialFlag() {
328 			flags |= LinkFlag.SPECIAL.get();
329 			return this;
330 		}
331 		
332 		/**
333 		 * Sets {@link LinkFlag#LADDER} flag into {@link NewNavPointEdgeBuilder#flags} of the new navpoint edge,
334 		 * corresponds to {@link NavPointNeighbourLink#getFlags()}.
335 		 * 
336 		 * @return
337 		 */
338 		public NewNavPointEdgeBuilder<OWNER> setLadderFlag() {
339 			flags |= LinkFlag.LADDER.get();
340 			return this;
341 		}
342 		
343 		/**
344 		 * Sets {@link LinkFlag#PROSCRIBED} flag into {@link NewNavPointEdgeBuilder#flags} of the new navpoint edge,
345 		 * corresponds to {@link NavPointNeighbourLink#getFlags()}.
346 		 * 
347 		 * @return
348 		 */
349 		public NewNavPointEdgeBuilder<OWNER> setProscribedFlag() {
350 			flags |= LinkFlag.PROSCRIBED.get();
351 			return this;
352 		}
353 		
354 		/**
355 		 * Sets {@link LinkFlag#FORCED} flag into {@link NewNavPointEdgeBuilder#flags} of the new navpoint edge,
356 		 * corresponds to {@link NavPointNeighbourLink#getFlags()}.
357 		 * 
358 		 * @return
359 		 */
360 		public NewNavPointEdgeBuilder<OWNER> setForcedFlag() {
361 			flags |= LinkFlag.FORCED.get();
362 			return this;
363 		}
364 		
365 		/**
366 		 * Sets {@link LinkFlag#PLAYERONLYK} flag into {@link NewNavPointEdgeBuilder#flags} of the new navpoint edge,
367 		 * corresponds to {@link NavPointNeighbourLink#getFlags()}.
368 		 * 
369 		 * @return
370 		 */
371 		public NewNavPointEdgeBuilder<OWNER> setPlayerOnlyFlag() {
372 			flags |= LinkFlag.PLAYERONLY.get();
373 			return this;
374 		}
375 		
376 		/**
377 		 * Finalizes the creation of the edge.
378 		 * <p><p>
379 		 * Edge remote end must be set via {@link NewNavPointEdgeBuilder#setTo(String)} before otherwise an exception is thrown.
380 		 * <p><p>
381 		 * WARNING: the created edge is oriented! Its counterpart (from the remote navpoint to newly created one) must be created manually! (If needed.)
382 		 * 
383 		 * @return nav point the edge is going from (i.e., one you're building)
384 		 */
385 		public OWNER createEdge() {
386 			if (toNavPointId == null) {
387 				throw new PogamutException("Could not create edge - toNavPoint not specified, you must call setTo() with non-null argument (to specify the other end of the edge) before calling this method.", this);
388 			}
389 			((NewNavPointBuilder)owner).addEdge(this);
390 			return ((OWNER)owner);
391 		}
392 
393 	}
394 	
395 	/**
396 	 * Builder that allows you to modify edges of existing navpoint using {@link ExistingNavPointModifier#createEdge()}, 
397 	 * {@link ExistingNavPointModifier#createEdgeTo(String)}, {@link ExistingNavPointModifier#modifyEdgeTo(String)} methods.
398 	 * 
399 	 * @author Jimmy
400 	 */
401 	public class ExistingNavPointModifier {
402 		
403 		private NavPoint navPoint;
404 
405 		protected ExistingNavPointModifier(NavPoint navPoint) {
406 			this.navPoint = navPoint;
407 			NullCheck.check(this.navPoint, "navPoint");
408 		}
409 		
410 		/**
411 		 * Removes edge that is leading from this navpoint to 'navPointId'. Does not do anything if such edge does not exist.
412 		 * <p><p>
413 		 * Removes only one edge, if the edge with opposite direction exists, it leaves it there.
414 		 * 
415 		 * @param navPointId will be auto-prefixed (if enabled, which is default)
416 		 */
417 		public void removeEdgeTo(String navPointId) {
418 			NullCheck.check(navPointId, "navPointId");
419 			navPointId = autoPrefix(navPointId);
420 			UnrealId navPointUnrealId = UnrealId.get(navPointId);
421 			navPoint.getOutgoingEdges().remove(navPointUnrealId);
422 			Object np = agent.getWorldView().get(navPointUnrealId);
423 			if (np != null && (np instanceof NavPoint)) {
424 				((NavPoint)np).getIncomingEdges().remove(navPoint.getId());
425 			}
426 		}
427 		
428 		/**
429 		 * Removes edge that is leading from this navpoint to 'navPointId'. Does not do anything if such edge does not exist.
430 		 * <p><p>
431 		 * Removes both edges, if the edge with opposite direction exists, it is deleted as well.
432 		 * 
433 		 * @param navPointId will be auto-prefixed (if enabled, which is default)
434 		 */
435 		public void removeEdgesBetween(String navPointId) {
436 			NullCheck.check(navPointId, "navPointId");
437 			navPointId = autoPrefix(navPointId);
438 			UnrealId toNavPointUnrealId = UnrealId.get(navPointId);
439 			
440 			Object np = agent.getWorldView().get(toNavPointUnrealId);
441 			NavPoint toNavPoint = null;
442 			if (np != null && (np instanceof NavPoint)) {
443 				toNavPoint = (NavPoint)np;
444 			}
445 			
446 			navPoint.getOutgoingEdges().remove(toNavPointUnrealId);
447 			navPoint.getIncomingEdges().remove(toNavPointUnrealId);
448 			
449 			if (toNavPoint != null) {
450 				toNavPoint.getOutgoingEdges().remove(navPoint.getId());
451 				toNavPoint.getIncomingEdges().remove(navPoint.getId());
452 			}
453 		}
454 		
455 		/**
456 		 * Returns a builder that will allow you to modify properties of the edge that is leading to 'navPointId'.
457 		 * <p><p>
458 		 * If no previous edge (leading to the same navpoint) exists, new one is created automatically.
459 		 * <p><p>
460 		 * Call {@link ExistingNavPointEdgeBuilder#modifyEdge()} when done specifying edge properties.
461 		 * 
462 		 * @param navPointId will be auto-prefixed (if enabled, which is default)
463 		 * @return
464 		 */
465 		public ExistingNavPointEdgeBuilder modifyEdgeTo(String navPointId) {
466 			NullCheck.check(navPointId, "navPointId");
467 			navPointId = autoPrefix(navPointId);
468 			UnrealId navPointUnrealId = UnrealId.get(navPointId);
469 			NavPointNeighbourLink link = navPoint.getOutgoingEdges().get(navPointUnrealId);
470 			if (link != null) {
471 				return new ExistingNavPointEdgeBuilder(this, link);
472 			} else {
473 				return new ExistingNavPointEdgeBuilder(this).setTo(navPointId);
474 			}
475 		}
476 		
477 		/**
478 		 * Returns a builder that will allow you to create new edge that is leading to 'navPointId'. Note that the returned {@link ExistingNavPointEdgeBuilder}
479 		 * will have only {@link ExistingNavPointEdgeBuilder#setTo(String)} filled. It also has different behavior than in the case
480 		 * of {@link ExistingNavPointModifier#modifyEdgeTo(String)} as this new edge builder won't have any properties (except {@link ExistingNavPointEdgeBuilder#setTo(String)}) filled.
481 		 * <p><p>
482 		 * If same edge (leading to the same navpoint) exists, it is replaced automatically.
483 		 * <p><p>
484 		 * Call {@link ExistingNavPointEdgeBuilder#createEdge()} when done specifying edge properties.
485 		 * 
486 		 * @param navPointId will be auto-prefixed (if enabled, which is default)
487 		 * @return
488 		 */
489 		public ExistingNavPointEdgeBuilder createEdgeTo(String navPointId) {
490 			NullCheck.check(navPointId, "navPointId");
491 			navPointId = autoPrefix(navPointId);
492 			ExistingNavPointEdgeBuilder builder = new ExistingNavPointEdgeBuilder(this, null);
493 			builder.setTo(navPointId);
494 			return builder;
495 		}
496 		
497 		/**
498 		 * Returns a builder that will allow you to create new edge. Note that the returned {@link ExistingNavPointEdgeBuilder}
499 		 * is empty, you must set the remote end of the edge manually using {@link ExistingNavPointEdgeBuilder#setTo(String)}.
500 		 * It also has different behavior than in the case
501 		 * of {@link ExistingNavPointModifier#modifyEdgeTo(String)} as this new edge builder won't have any properties (except {@link ExistingNavPointEdgeBuilder#setTo(String)}) filled.
502 		 * <p><p>
503 		 * If same edge (leading to the same navpoint) exists, it is replaced automatically.
504 		 * <p><p>
505 		 * Call {@link ExistingNavPointEdgeBuilder#createEdge()} when done specifying edge properties.
506 		 * 
507 		 * @return
508 		 */
509 		public ExistingNavPointEdgeBuilder createEdge() {
510 			return new ExistingNavPointEdgeBuilder(this, null);
511 		}
512 		
513 		/**
514 		 * Creates simple edge that leads from the navpoint you're currently creating to 'navPointId'.
515 		 * <p><p>
516 		 * If edge exists, it won't be modified.
517 		 * 
518 		 * @param navPointId will be auto-prefixed (if enabled, which is default)
519 		 */
520 		public void createSimpleEdgeTo(String navPointId) {
521 			NullCheck.check(navPointId, "navPointId");
522 			createEdgeTo(navPointId).createEdge();
523 		}
524 		
525 		/**
526 		 * Creates two simple edges between this navpoint and the navpoint with 'navPointId'.
527 		 * <p><p>
528 		 * If any of those two edges exists, it won't be modified.
529 		 * 
530 		 * @param navPointId will be auto-prefixed (if enabled, which is default)
531 		 */
532 		public void createSimpleEdgesBetween(String navPointId) {
533 			NullCheck.check(navPointId, "navPointId");
534 			createEdgeTo(navPointId).createEdge();
535 			modifyNavPoint(navPointId).createSimpleEdgeTo(navPoint.getId().getStringId());
536 		}
537 		
538 	}
539 	
540 	public class ExistingNavPointEdgeBuilder extends NewNavPointEdgeBuilder<ExistingNavPointModifier> {
541 
542 		private NavPointNeighbourLink parentLink;
543 
544 		protected ExistingNavPointEdgeBuilder(ExistingNavPointModifier navPointModifier) {
545 			super(navPointModifier);
546 		}
547 		
548 		protected ExistingNavPointEdgeBuilder(ExistingNavPointModifier navPointModifier, NavPointNeighbourLink parent) {
549 			super(navPointModifier);
550 			this.parentLink = parent;
551 			if (this.parentLink != null) {
552 				this.collisionH = this.parentLink.getCollisionH();
553 				this.collisionR = this.parentLink.getCollisionR();
554 				this.flags = this.parentLink.getFlags();
555 				this.forceDoubleJump = this.parentLink.isForceDoubleJump();
556 				this.neededJump = this.parentLink.getNeededJump();
557 				this.toNavPointId = this.parentLink.getToNavPoint().getId();
558 			}
559 		}
560 		
561 		@Override
562 		public ExistingNavPointEdgeBuilder setTo(String navPointId) {
563 			super.setTo(navPointId);
564 			return this;
565 		}
566 		
567 		@Override
568 		public ExistingNavPointEdgeBuilder setTo(UnrealId navPointId) {
569 			super.setTo(navPointId);
570 			return this;
571 		}
572 		
573 		@Override
574 		public ExistingNavPointEdgeBuilder setCollisionRadius(int collisionRadius) {
575 			super.setCollisionRadius(collisionRadius);
576 			return this;
577 		}
578 		
579 		@Override
580 		public ExistingNavPointEdgeBuilder setCollisionHeight(int collisionHeight) {
581 			super.setCollisionHeight(collisionHeight);
582 			return this;
583 		}
584 		
585 		@Override
586 		public ExistingNavPointEdgeBuilder setNeededJump(double x, double y, double z) {
587 			super.setNeededJump(x, y, z);
588 			return this;
589 		}
590 		
591 		/**
592 		 * Removes "needed jump at location" from the edge.
593 		 * @return
594 		 */
595 		public ExistingNavPointEdgeBuilder removeNeededJump() {
596 			this.neededJump = null;
597 			return this;
598 		}
599 		
600 		@Override
601 		public ExistingNavPointEdgeBuilder setDoubleJump() {
602 			super.setDoubleJump();
603 			return this;
604 		}
605 		
606 		/**
607 		 * Removes "requires double jump" from the edge.
608 		 * @return
609 		 */
610 		public ExistingNavPointEdgeBuilder removeDoubleJump() {
611 			this.forceDoubleJump = false;
612 			return this;
613 		}
614 		
615 		
616 		@Override
617 		public ExistingNavPointEdgeBuilder setWalkFlag() {
618 			super.setWalkFlag();
619 			return this;
620 		}
621 		
622 		/**
623 		 * Removes {@link LinkFlag#WALK} flag from edge flags.
624 		 * 
625 		 * @return
626 		 */
627 		public ExistingNavPointEdgeBuilder removeWalkFlag() {
628 			this.flags = (this.flags | LinkFlag.WALK.get()) ^ LinkFlag.WALK.get(); 
629 			return this;
630 		}
631 		
632 		@Override
633 		public ExistingNavPointEdgeBuilder setFlyFlag() {
634 			super.setFlyFlag();
635 			return this;
636 		}
637 		
638 		/**
639 		 * Removes {@link LinkFlag#FLY} flag from edge flags.
640 		 * 
641 		 * @return
642 		 */
643 		public ExistingNavPointEdgeBuilder removeFlyFlag() {
644 			this.flags = (this.flags | LinkFlag.FLY.get()) ^ LinkFlag.FLY.get(); 
645 			return this;
646 		}
647 		
648 		@Override
649 		public ExistingNavPointEdgeBuilder setSwimFlag() {
650 			super.setSwimFlag();
651 			return this;
652 		}
653 		
654 		/**
655 		 * Removes {@link LinkFlag#SWIM} flag from edge flags.
656 		 * 
657 		 * @return
658 		 */
659 		public ExistingNavPointEdgeBuilder removeSwimFlag() {
660 			this.flags = (this.flags | LinkFlag.SWIM.get()) ^ LinkFlag.SWIM.get(); 
661 			return this;
662 		}
663 		
664 		@Override
665 		public ExistingNavPointEdgeBuilder setJumpFlag() {
666 			super.setJumpFlag();
667 			return this;
668 		}
669 		
670 		/**
671 		 * Removes {@link LinkFlag#JUMP} flag from edge flags.
672 		 * 
673 		 * @return
674 		 */
675 		public ExistingNavPointEdgeBuilder removeJumpFlag() {
676 			this.flags = (this.flags | LinkFlag.JUMP.get()) ^ LinkFlag.JUMP.get(); 
677 			return this;
678 		}
679 		
680 		@Override
681 		public ExistingNavPointEdgeBuilder setDoorFlag() {
682 			super.setDoorFlag();
683 			return this;
684 		}
685 		
686 		/**
687 		 * Removes {@link LinkFlag#DOOR} flag from edge flags.
688 		 * 
689 		 * @return
690 		 */
691 		public ExistingNavPointEdgeBuilder removeDoorFlag() {
692 			this.flags = (this.flags | LinkFlag.DOOR.get()) ^ LinkFlag.DOOR.get(); 
693 			return this;
694 		}
695 		
696 		@Override
697 		public ExistingNavPointEdgeBuilder setSpecialFlag() {
698 			super.setSpecialFlag();
699 			return this;
700 		}
701 		
702 		/**
703 		 * Removes {@link LinkFlag#SPECIAL} flag from edge flags.
704 		 * 
705 		 * @return
706 		 */
707 		public ExistingNavPointEdgeBuilder removeSpecialFlag() {
708 			this.flags = (this.flags | LinkFlag.SPECIAL.get()) ^ LinkFlag.SPECIAL.get(); 
709 			return this;
710 		}
711 		
712 		@Override
713 		public ExistingNavPointEdgeBuilder setLadderFlag() {
714 			super.setLadderFlag();
715 			return this;
716 		}
717 		
718 		/**
719 		 * Removes {@link LinkFlag#LADDER} flag from edge flags.
720 		 * 
721 		 * @return
722 		 */
723 		public ExistingNavPointEdgeBuilder removeLadderFlag() {
724 			this.flags = (this.flags | LinkFlag.LADDER.get()) ^ LinkFlag.LADDER.get(); 
725 			return this;
726 		}
727 		
728 		@Override
729 		public ExistingNavPointEdgeBuilder setProscribedFlag() {
730 			super.setProscribedFlag();
731 			return this;
732 		}
733 		
734 		/**
735 		 * Removes {@link LinkFlag#PROSCRIBED} flag from edge flags.
736 		 * 
737 		 * @return
738 		 */
739 		public ExistingNavPointEdgeBuilder removeProscribedFlag() {
740 			this.flags = (this.flags | LinkFlag.PROSCRIBED.get()) ^ LinkFlag.PROSCRIBED.get(); 
741 			return this;
742 		}
743 		
744 		@Override
745 		public ExistingNavPointEdgeBuilder setForcedFlag() {
746 			super.setForcedFlag();
747 			return this;
748 		}
749 		
750 		/**
751 		 * Removes {@link LinkFlag#FORCED} flag from edge flags.
752 		 * 
753 		 * @return
754 		 */
755 		public ExistingNavPointEdgeBuilder removeForcedFlag() {
756 			this.flags = (this.flags | LinkFlag.FORCED.get()) ^ LinkFlag.FORCED.get(); 
757 			return this;
758 		}
759 		
760 		@Override
761 		public ExistingNavPointEdgeBuilder setPlayerOnlyFlag() {
762 			super.setPlayerOnlyFlag();
763 			return this;
764 		}
765 		
766 		/**
767 		 * Removes {@link LinkFlag#PLAYERONLY} flag from edge flags.
768 		 * 
769 		 * @return
770 		 */
771 		public ExistingNavPointEdgeBuilder removePlayerOnlyFlag() {
772 			this.flags = (this.flags | LinkFlag.PLAYERONLY.get()) ^ LinkFlag.PLAYERONLY.get(); 
773 			return this;
774 		}
775 		
776 		/**
777 		 * Clears all flags to 0.
778 		 * 
779 		 * @return
780 		 */
781 		public ExistingNavPointEdgeBuilder clearFlags() {
782 			this.flags = 0;
783 			return this;
784 		}
785 		
786 		/**
787 		 * Immediately creates a new edge. Checks whether the same edge does not already exist (if so, replaces it).
788 		 * <p><p>
789 		 * WARNING: the created edge is oriented! Its counterpart (from the remote navpoint to one that is being modified) must be created manually! (If needed.)
790 		 *
791 		 * @return previously used navpoint modifier
792 		 */
793 		@Override
794 		public ExistingNavPointModifier createEdge() {
795 			if (toNavPointId == null) {
796 				throw new PogamutException("Could not create/modify edge from navpoint '" + owner.navPoint.getId().getStringId() + "' as toNavPoint not specified, you must call setTo() with non-null argument (to specify the other end of the edge) before calling this method.", this);
797 			}
798 			Object np = agent.getWorldView().get(toNavPointId);
799 			if (np == null) {
800 				throw new PogamutException("Could not create/modify navpoint edge from '" + owner.navPoint.getId().getStringId() + "' as the remote end (" + toNavPointId.getStringId() + ") could not be found in the bot's worldview. Warning, id is case-sensitive the upper/lower cases of the id depends on the concrete spelling of the map that was passed to the GB2004 during startup (either from the command line or by the UT2004).", this);
801 			}
802 			if (!(np instanceof NavPoint)) {
803 				throw new PogamutException("Could not create/modify navpoint edge from '" + owner.navPoint.getId().getStringId() + "' as the remote end '" + toNavPointId.getStringId() + "' is not an instance of NavPoint but " + np.getClass().getSimpleName() + ". Wrong id specified?", this);
804 			}
805 			
806 			NavPoint toNavPoint = (NavPoint)np;
807 			
808 			NavPointNeighbourLink link = null;
809 			
810 			if (parentLink == null) {
811 				link = new NavPointNeighbourLink(owner.navPoint.getId(), flags, collisionR, collisionH, 0, null, false, forceDoubleJump, neededJump, false, false, 0, owner.navPoint, toNavPoint);				
812 			} else {
813 				link = new NavPointNeighbourLink(owner.navPoint.getId(), flags, collisionR, collisionH, parentLink.getTranslocZOffset(), parentLink.getTranslocTargetTag(), parentLink.isOnlyTranslocator(), forceDoubleJump, neededJump, parentLink.isNeverImpactJump(), parentLink.isNoLowGrav(), parentLink.getCalculatedGravityZ(), owner.navPoint, toNavPoint);
814 			}
815 			
816 			owner.navPoint.getOutgoingEdges().put(link.getToNavPoint().getId(), link);
817 			link.getToNavPoint().getIncomingEdges().put(owner.navPoint.getId(), link);
818 			
819 			return owner;
820 		}
821 		
822 		/**
823 		 * Alias for {@link ExistingNavPointEdgeBuilder#createEdge()}. 
824 		 * <p><p>
825 		 * WARNING: the modify edge is oriented! Its counterpart (from the remote navpoint to one that is being modifier) must be modified manually! (If needed.)
826 		 *
827 		 * @return previously used navpoint modifier
828 		 */
829 		public ExistingNavPointModifier modifyEdge() {
830 			return createEdge();
831 		}
832 		
833 	}
834 	
835 	/**
836 	 * GameInfo listener.
837 	 */
838 	private class GameInfoListener implements IWorldObjectEventListener<GameInfo, IWorldObjectEvent<GameInfo>>
839 	{
840 		@Override
841 		public void notify(IWorldObjectEvent<GameInfo> event)
842 		{
843 			lastGameInfo = event.getObject();
844 			if (lastGameInfo.getLevel() == null) {
845 				throw new PogamutException("GameInfo.getLevel() is null!!!", this);
846 			}
847 			mapNameLowerChar = lastGameInfo.getLevel().toLowerCase();
848 		}
849 
850 		/**
851 		 * Constructor. Registers itself on the given WorldView object.
852 		 * @param worldView WorldView object to listent to.
853 		 */
854 		public GameInfoListener(IWorldView worldView)
855 		{
856 			worldView.addObjectListener(GameInfo.class, this);
857 		}
858 	}
859 
860 	/** GameInfo listener */
861 	GameInfoListener gameInfoListener;
862 	
863 	/** Las info about the game the bot is in */
864 	GameInfo lastGameInfo = null;
865 	
866 	String mapNameLowerChar = null;
867 	
868 	public NavigationGraphBuilder(UT2004Bot bot) {
869 		this(bot, null);
870 	}
871 	
872 	public NavigationGraphBuilder(UT2004Bot bot, Logger log) {
873 		this(bot, log, null);
874 	}
875 	
876 	public NavigationGraphBuilder(UT2004Bot bot, Logger log, ComponentDependencies dependencies) {
877 		super(bot, log, dependencies);
878 		gameInfoListener = new GameInfoListener(bot.getWorldView());
879 	}
880 	
881 	@Override
882 	protected void cleanUp() {
883 		super.cleanUp();
884 		lastGameInfo = null;
885 		mapNameLowerChar = null;
886 	}
887 	
888 	/**
889 	 * Returns name of the map the UT2004 is currently running.
890 	 * <p><p>
891 	 * The name is used as a prefix to all IDs in the game. IDs in the world view are case-sensitive!
892 	 * <p><p>
893 	 * Note that NavigationGraphBuilder is automatically prefixing all navpoint ids with "mapName.", which means, that you do not
894 	 * need to specify the id of navpoints as (e.g.) "DM-1on1-Albatross.PathNode2", "PathNode2" suffices. If you want to change this behavior
895 	 * call {@link NavigationGraphBuilder#setAutoPrefix(boolean)} with "false".
896 	 * 
897 	 * @return
898 	 */
899 	public String getMapName() {
900 		if (lastGameInfo == null) return null;
901 		return lastGameInfo.getLevel();
902 	}
903 	
904 	/**
905 	 * Tells, whether the UT2004 is currently running map with name 'name'.
906 	 * @param name
907 	 * @return
908 	 */
909 	public boolean isMapName(String name) {
910 		if (lastGameInfo == null) return false;
911 		if (name == null) return false;
912 		return lastGameInfo.getLevel().toLowerCase().equals(name.toLowerCase());
913 	}
914 	
915 	private boolean autoPrefix = true;
916 
917 	/**
918 	 * Whether this instance has been used to alter the navigation graph.
919 	 */
920 	private boolean used;
921 	
922 	/**
923 	 * Whether {@link NavigationGraphBuilder} is auto prefixing all navpoint ids with current map name.
924 	 * <p><p>
925 	 * As default, auto-prefixing is enabled.
926 	 * <p><p>
927      * Note that even if auto-prefixing enabled you may prefix ids of navpoints with map name, the auto-prefixing implemented by {@link NavigationGraphBuilder#autoPrefix(String)} 
928      * will detects that and auto-correct upper/lower case of this existing prefix if needed. Also you may use it as a validation feature because
929      * the {@link NavigationGraphBuilder#autoPrefix(String)} will raise an exception if the prefix does not match the current map name.
930      * 
931 	 * @return whether auto-prefixing is enabled
932 	 */
933 	public boolean isAutoPrefix() {
934 		return autoPrefix;
935 	}
936 
937 	/**
938 	 * Enables (== true), disables (== false) navpoint ids auto prefixing feature.
939 	 * <p><p>
940 	 * As default, auto-prefixing is enabled.
941 	 * <p><p>
942      * Note that even if auto-prefixing enabled you may prefix ids of navpoints with map name, the auto-prefixing implemented by {@link NavigationGraphBuilder#autoPrefix(String)} 
943      * will detects that and auto-correct upper/lower case of this existing prefix if needed. Also you may use it as a validation feature because
944      * the {@link NavigationGraphBuilder#autoPrefix(String)} will raise an exception if the prefix does not match the current map name.
945      * 
946 	 * @param autoPrefix
947 	 */
948 	public void setAutoPrefix(boolean autoPrefix) {
949 		this.autoPrefix = autoPrefix;
950 	}
951 	
952 	/**
953 	 * It returns 'navPointId' prefixed with "{@link NavigationGraphBuilder#getMapName()}.".
954 	 * <p><p>
955      * Note that you may pass prefixed navPointId into this method, it will detect it that and auto-correct upper/lower case of this existing prefix if needed. 
956      * Also you may use it as a validation feature because
957      * the {@link NavigationGraphBuilder#autoPrefix(String)} will raise an exception if the prefix does not match the current map name.
958 	 * 
959 	 * @param navPointId will be auto-prefixed (if enabled, which is default)
960 	 * @return
961 	 */
962 	public String getPrefixed(String navPointId) {
963 		// auto prefixing is enabled
964 		if (getMapName() == null) {
965 			throw new PogamutException("GameInfo was not received yet, can't auto-prefix name of the navpoint '" + navPointId + "'.", this);
966 		}
967 		if (navPointId.toLowerCase().startsWith(mapNameLowerChar + ".")) {
968 			// already prefixed!
969 			if (!navPointId.startsWith(getMapName())) {
970 				// but wrong upper/lower case detected, replace!
971 				navPointId = getMapName() + navPointId.substring(mapNameLowerChar.length());
972 			}
973 			// correctly prefixed, just return it
974 			return navPointId;
975 		} else {
976 			// not correctly prefixed, check whether there is any prefix at all?
977 			if (navPointId.contains(".")) {
978 				// yes there is -> map name validation fails!
979 				throw new PogamutException("navPointId '" + navPointId + "' is already prefixed with '" + navPointId.substring(0, navPointId.indexOf(".")) + "' which is different from current map name '" + getMapName() + "', map name validation fails!", this);
980 			}
981 			// no there is not ... so prefix it!
982 			return getMapName() + "." + navPointId;
983 		}
984 	}
985 	
986 	/**
987 	 * If {@link NavigationGraphBuilder#isAutoPrefix()} is on (== true), it returns 'navPointId' prefixed with "{@link NavigationGraphBuilder#getMapName()}.".
988 	 * Otherwise it just returns 'navPointId' as is.
989 	 * <p><p>
990      * Uses {@link NavigationGraphBuilder#getPrefixed(String)} for prefixing.
991 	 * 
992 	 * @param navPointId will be auto-prefixed (if enabled, which is default)
993 	 * @return
994 	 */
995 	public String autoPrefix(String navPointId) {
996 		NullCheck.check(navPointId, "navPointId");
997 		if (autoPrefix) {
998 			return getPrefixed(navPointId);
999 		} else {
1000 			// auto prefixing is disabled
1001 			return navPointId;
1002 		}
1003 	}
1004 
1005 	/**
1006 	 * Creates a builder for the specification of the new navpoint you want to create and insert into the worldview.
1007 	 * <p><p>
1008 	 * Use {@link NewNavPointBuilder#createNavPoint()} when done specifying the navpoint.
1009 	 * 
1010 	 * @return navpoint builder
1011 	 */
1012 	public NewNavPointBuilder newNavPoint() {
1013 		used = true;
1014 		return new NewNavPointBuilder();
1015 	}
1016 	
1017 	/**
1018 	 * Creates a builder for the specification of the new navpoint you want to create and insert into the worldview. The builder
1019 	 * will have the id of the navpoint filled (i.e., it calls {@link NewNavPointBuilder#setId(String)} for you.
1020 	 * <p><p>
1021 	 * Use {@link NewNavPointBuilder#createNavPoint()} when done specifying the navpoint.
1022 	 * 
1023 	 * @param navPointId will be auto-prefixed (if enabled, which is default)
1024 	 * @return navpoint builder
1025 	 */
1026 	public NewNavPointBuilder newNavPoint(String navPointId) {
1027 		used = true;
1028 		NullCheck.check(navPointId, "navPointId");
1029 		return new NewNavPointBuilder().setId(navPointId);
1030 	}
1031 	
1032 	/**
1033 	 * Creates a modifier for already existing {@link NavPoint} instance, if navpoint of specified id is not found, an exception is thrown.
1034 	 * <p><p>
1035 	 * The modifier allows you to change existing edges or add new ones.
1036 	 * 
1037 	 * @param navPointId will be auto-prefixed (if enabled, which is default)
1038 	 * @return navpoint modifier for the 'navPointId'
1039 	 */
1040 	public ExistingNavPointModifier modifyNavPoint(String navPointId) {
1041 		used = true;
1042 		NullCheck.check(navPointId, "navPointId");
1043 		navPointId = autoPrefix(navPointId);
1044 		
1045 		Object np = agent.getWorldView().get(UnrealId.get(navPointId));
1046 		if (np == null) {
1047 			throw new PogamutException("Could not modify navpoint '" + navPointId + "' as it was not found in the worldview. No object under this id exists in worldview. Warning, id is case-sensitive the upper/lower cases of the id depends on the concrete spelling of the map that was passed to the GB2004 during startup (either from the command line or by the UT2004).", this);
1048 		}
1049 		if (!(np instanceof NavPoint)) {
1050 			throw new PogamutException("Could not modify navpoint '" + navPointId + "' it does not point to an NavPoint instance but " + np.getClass().getSimpleName() + ". Wrong id specified?", this);
1051 		}
1052 		return new ExistingNavPointModifier((NavPoint)np);
1053 	}
1054 	
1055 	/**
1056 	 * Creates simple (non-altered == no flags == no needed jump, etc.) leading 'fromNavPointId' to 'toNavPointId' (only one edge is created).
1057 	 * <p><p>
1058 	 * If uses {@link ExistingNavPointModifier#modifyEdgeTo(String)} for creation of new edge, so it won't replace an existing edge if such exist.
1059 	 * 
1060 	 * @param fromNavPointId will be auto-prefixed (if enabled, which is default)
1061 	 * @param toNavPointId will be auto-prefixed (if enabled, which is default)
1062 	 */
1063 	public void createSimpleEdge(String fromNavPointId, String toNavPointId) {
1064 		used = true;
1065 		NullCheck.check(fromNavPointId, "fromNavPointId");
1066 		NullCheck.check(toNavPointId, "toNavPointId");
1067 		fromNavPointId = autoPrefix(fromNavPointId);
1068 		toNavPointId = autoPrefix(toNavPointId);
1069 		modifyNavPoint(fromNavPointId).modifyEdgeTo(toNavPointId).createEdge();
1070 	}
1071 	
1072 	/**
1073 	 * Creates simple (non-altered == no flags == no needed jump, etc.) edges between specified navpoints (in both directions).
1074 	 * <p><p>
1075 	 * If uses {@link ExistingNavPointModifier#modifyEdgeTo(String)} for creation of new edge, so it won't replace an existing edge if such exist.
1076 	 * 
1077 	 * @param firstNavPointId will be auto-prefixed (if enabled, which is default)
1078 	 * @param secondNavPointId will be auto-prefixed (if enabled, which is default)
1079 	 */
1080 	public void createSimpleEdgesBetween(String firstNavPointId, String secondNavPointId) {
1081 		used = true;
1082 		NullCheck.check(firstNavPointId, "firstNavPointId");
1083 		NullCheck.check(secondNavPointId, "secondNavPointId");
1084 		firstNavPointId = autoPrefix(firstNavPointId);
1085 		secondNavPointId = autoPrefix(secondNavPointId);
1086 		modifyNavPoint(firstNavPointId).modifyEdgeTo(secondNavPointId).createEdge();
1087 		modifyNavPoint(secondNavPointId).modifyEdgeTo(firstNavPointId).createEdge();
1088 	}
1089 	
1090 	/**
1091 	 * Deletes edge that is leading from 'fromNavPointId' to 'toNavPointId'.
1092 	 * @param fromNavPointId will be auto-prefixed (if enabled, which is default)
1093 	 * @param toNavPointId will be auto-prefixed (if enabled, which is default)
1094 	 */
1095 	public void removeEdge(String fromNavPointId, String toNavPointId) {
1096 		used = true;
1097 		NullCheck.check(fromNavPointId, "fromNavPointId");
1098 		NullCheck.check(toNavPointId, "toNavPointId");
1099 		fromNavPointId = autoPrefix(fromNavPointId);
1100 		toNavPointId = autoPrefix(toNavPointId);
1101 		modifyNavPoint(fromNavPointId).removeEdgeTo(toNavPointId);
1102 	}
1103 	
1104 	/**
1105 	 * Removes both edges between two specified navpoints.
1106 	 * @param firstNavPointId will be auto-prefixed (if enabled, which is default)
1107 	 * @param secondNavPointId will be auto-prefixed (if enabled, which is default)
1108 	 */
1109 	public void removeEdgesBetween(String firstNavPointId, String secondNavPointId) {
1110 		used = true;
1111 		NullCheck.check(firstNavPointId, "firstNavPointId");
1112 		NullCheck.check(secondNavPointId, "secondNavPointId");
1113 		firstNavPointId = autoPrefix(firstNavPointId);
1114 		secondNavPointId = autoPrefix(secondNavPointId);
1115 		modifyNavPoint(firstNavPointId).removeEdgeTo(secondNavPointId);
1116 		modifyNavPoint(secondNavPointId).removeEdgeTo(firstNavPointId);
1117 	}
1118 
1119 	/**
1120 	 * Whether this instance has been used to alter navigation graph. This might interest you in case you're using {@link FloydWarshallMap}
1121 	 * as you will need to {@link FloydWarshallMap#refreshPathMatrix()} after all changes done to the navigation graph.
1122 	 * @return
1123 	 */
1124 	public boolean isUsed() {
1125 		return used;
1126 	}
1127 
1128 	/**
1129 	 * Raises / drops "used" flag, see {@link NavigationGraphBuilder#isUsed()}.
1130 	 * @param used
1131 	 */
1132 	public void setUsed(boolean used) {
1133 		this.used = used;
1134 	}
1135 	
1136 	
1137 	
1138 }
1139