View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.agent.module.sensomotoric;
2   
3   import java.util.HashMap;
4   import java.util.Map;
5   import java.util.UUID;
6   import java.util.Map.Entry;
7   import java.util.concurrent.Future;
8   import java.util.concurrent.TimeUnit;
9   import java.util.logging.Level;
10  import java.util.logging.Logger;
11  
12  import javax.vecmath.Vector3d;
13  
14  import cz.cuni.amis.pogamut.base.agent.module.SensomotoricModule;
15  import cz.cuni.amis.pogamut.base.communication.exception.CommunicationException;
16  import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldObjectUpdateResult;
17  import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldObjectUpdatedEvent;
18  import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldObjectUpdateResult.Result;
19  import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldObjectUpdateResult.WorldObjectUpdateResult;
20  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObject;
21  import cz.cuni.amis.pogamut.base.communication.worldview.object.WorldObjectFuture;
22  import cz.cuni.amis.pogamut.base.communication.worldview.object.WorldObjectId;
23  import cz.cuni.amis.pogamut.ut2004.bot.IUT2004BotController;
24  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
25  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.AddRay;
26  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.RemoveRay;
27  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.AutoTraceRay;
28  import cz.cuni.amis.utils.flag.Flag;
29  
30  /**
31   * Support for creating rays used for raycasting (see {@link AutoTraceRay} that is being utilized).
32   * <p><p>
33   * It is designed to be initialized inside {@link IUT2004BotController#initializeController(UT2004Bot)} method call
34   * and may be used since {@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)}
35   * is called.
36   * @author ik
37   */
38  public class Raycasting extends SensomotoricModule<UT2004Bot> {
39  
40      Map<String, WorldObjectFuture<AutoTraceRay>> rayFutures = new HashMap<String, WorldObjectFuture<AutoTraceRay>>();
41      String idSuffix = null;
42      int counter = 0;
43      int alreadyInitialized = 0;
44      Flag<Boolean> allRaysInitialized = new Flag<Boolean>(false);
45      boolean listening = false;
46  
47      public Flag<Boolean> getAllRaysInitialized() {
48          return allRaysInitialized.getImmutable();
49      }
50  
51      public Raycasting(UT2004Bot bot) {
52          this(bot, null);
53      }
54      
55      public Raycasting(UT2004Bot bot, Logger log) {
56          super(bot, log);
57          idSuffix = "_" + bot.getName() + UUID.randomUUID().toString();
58          
59          cleanUp();
60      }
61      
62      @Override
63      protected void cleanUp() {
64      	super.cleanUp();
65      	for (Entry<String, WorldObjectFuture<AutoTraceRay>> entry : rayFutures.entrySet()) {
66      		final AutoTraceRay ray = entry.getValue().get(0, TimeUnit.MILLISECONDS); 
67      		if (ray != null) {
68      			// LET'S DESTROY THE RAY INSIDE WORLDVIEW - IT WON'T BE ACCESSIBLE AGAIN!
69      			agent.getWorldView().notifyImmediately( 				
70      				new IWorldObjectUpdatedEvent() {
71  						@Override
72  						public WorldObjectId getId() {
73  							return ray.getId();
74  						}
75  						@Override
76  						public IWorldObjectUpdateResult<IWorldObject> update(IWorldObject obj) {
77  							return new WorldObjectUpdateResult<IWorldObject>(Result.DESTROYED, obj);
78  						}
79  						@Override
80  						public long getSimTime() {
81  							return ray.getSimTime();
82  						}
83      				}
84      			);
85      		}
86      		entry.getValue().cancel(false);
87      	}
88      	rayFutures.clear();
89          allRaysInitialized.setFlag(false);
90          alreadyInitialized = 0;
91          listening = false;
92      }
93  
94      /**
95       * Deletes all previous rays and makes this instance ready for setting up
96       * new rays.
97       */
98      public void clear() throws CommunicationException {
99          act.act(new RemoveRay("All"));
100         cleanUp();
101     }
102 
103     /**
104      * Once all rays were initialized using createRay(...) methods, call this
105      * method to start listening for response from UT.
106      */
107     public void endRayInitSequence() {
108         listening = true;
109         checkIfAllInited();
110     }
111 
112     /**
113      * Initializes ray usind AddRay command and returns future that waits for
114      * the first AutoTraceRay message corresponding to this ray.
115      * @param Id
116      * User set Id of the ray, so the ray can be identified.
117      * 
118      * @param Direction
119      * Vector direction of the ray (it will be relative - added to
120      * the vector, where the bot is looking, also takes into
121      * account angle of the floor the bot is standing on).
122      * 
123      * @param Length
124      * Specifies the length of the ray (in UT units).
125      * 
126      * @param FastTrace
127      * True if we want to use FastTrace function instead of Trace
128      * function (a bit faster but less information provided - just
129      * information if we hit something or not).
130      * 
131      * @param FloorCorrection
132      * If we should correct ray directions accoring floor normal. Note: Has issue - we can't set set rays up or down when correction is active.
133 	 * 
134      * @param TraceActors
135      * If we want to trace also actors – bots, monsters, players,
136      * items. False if we want to trace just level geometry.
137 	 * 
138      * @return
139      */
140     public Future<AutoTraceRay> createRay(
141             String Id, Vector3d Direction, int Length, boolean FastTrace, boolean FloorCorrection, boolean TraceActors) throws CommunicationException {
142         AddRay addRay = new AddRay(Id, Direction, Length, FastTrace, FloorCorrection, TraceActors);
143 
144         // create pointer to object that will be created in the future
145         WorldObjectFuture future = new WorldObjectFuture<AutoTraceRay>(worldView, Id, AutoTraceRay.class) {
146 
147             @Override
148             protected void customObjectEncounteredHook(AutoTraceRay obj) {
149                 alreadyInitialized++;
150                 checkIfAllInited();
151             }
152         };
153         rayFutures.put(Id, future);
154 
155         // send ray configuration command
156         act.act(addRay);
157         return future;
158     }
159 
160     /**
161      * Creates ray with system generated id. Note that the ray is not initialized immediately - we have to wait for GB2004 to 
162      * confirm us. Therefore you will not receive actual instance of {@link AutoTraceRay} but its {@link Future}.
163      * Use method {@link Future#isDone()} to check whether the ray was initialized and method {@link Future#get()} to obtain the ray instance.
164      * 
165      * @param Direction
166      * Vector direction of the ray (it will be relative - added to
167      * the vector, where the bot is looking, also takes into
168      * account angle of the floor the bot is standing on).
169 	 * 
170      * @param Length
171      * Specifies the length of the ray (in UT units).
172      * 
173      * @param FastTrace
174      * True if we want to use FastTrace function instead of Trace
175      * function (a bit faster but less information provided - just
176      * information if we hit something or not).
177      * 
178      * @param FloorCorrection
179      * If we should correct ray directions according floor normal. Note: Has issue - we can't set set rays up or down when correction is active.
180      * 
181      * @param TraceActors
182      * If we want to trace also actors, bots, monsters, players,
183      * items. False if we want to trace just level geometry.
184 	 * 
185      * @return ray's future - use method {@link Future#isDone()} to check whether the ray was initialized and method {@link Future#get()} to obtain the ray instance
186      * @throws cz.cuni.amis.pogamut.base.communication.exceptions.CommunicationException
187      */
188     public Future<AutoTraceRay> createRay(
189             Vector3d Direction, int Length, boolean FastTrace, boolean FloorCorrection, boolean TraceActors) throws CommunicationException {
190         String id = counter++ + idSuffix;
191         return createRay(id, Direction, Length, FastTrace, FloorCorrection, TraceActors);
192     }
193 
194     /**
195      * Returns a ray of specified id. If the ray of the specified id does not exist
196      * or was not initialized yet then it returns null.
197      * <p><p>
198      * Note that the {@link AutoTraceRay} instance is self updating - once obtained you may use it every
199      * logic cycle to obtain current readings from the ray.
200      * 
201      * @param rayID
202      * @return
203      */
204     public AutoTraceRay getRay(String rayID) {
205         try {
206         	Future<AutoTraceRay> ray = rayFutures.get(rayID);
207         	if (ray == null) return null;
208         	if (ray.isDone()) return ray.get();
209         	else return null;
210         } catch (Exception ex) {
211             if (log.isLoggable(Level.SEVERE)) log.severe(ex.getMessage());
212             return null;
213         }
214     }
215 
216     /**
217      * Sets {@link Raycasting#allRaysInitialized} flag to true if all rays has been initialized.
218      */
219     protected void checkIfAllInited() {
220         if (listening && rayFutures.size() == alreadyInitialized) {
221             allRaysInitialized.setFlag(true);
222         }
223     }
224     
225     
226 }
227