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