View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.teamcomm.bot;
2   
3   import java.io.Serializable;
4   import java.net.InetSocketAddress;
5   import java.util.ArrayList;
6   import java.util.Collections;
7   import java.util.HashSet;
8   import java.util.List;
9   import java.util.Set;
10  
11  import cz.cuni.amis.pogamut.base.agent.module.SensomotoricModule;
12  import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
13  import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
14  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
15  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
16  import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
17  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
18  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BeginMessage;
19  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.EndMessage;
20  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
21  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
22  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.client.TCMinaClient;
23  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.client.TCMinaClient.RequestFuture;
24  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.client.messages.TCRequestCreateChannel;
25  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.client.messages.TCRequestDestroyChannel;
26  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.client.messages.TCRequestGetStatus;
27  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.client.messages.TCRequestJoinChannel;
28  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.client.messages.TCRequestLeaveChannel;
29  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.messages.TCMessage;
30  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.messages.TCMessageData;
31  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.messages.TCRequestMessage;
32  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.model.TCChannel;
33  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.model.TCTeam;
34  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.server.TCMinaServer;
35  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.server.messages.TCInfoStatus;
36  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.server.messages.TCInfoTeamChannelBotJoined;
37  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.server.messages.TCInfoTeamChannelBotLeft;
38  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.server.messages.TCInfoTeamChannelCreated;
39  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.server.messages.TCInfoTeamChannelDestroyed;
40  import cz.cuni.amis.pogamut.ut2004.teamcomm.server.protocol.TCControlMessagesTranslator;
41  import cz.cuni.amis.pogamut.ut2004.teamcomm.server.protocol.messages.TCControlServerAlive;
42  import cz.cuni.amis.utils.exception.PogamutException;
43  import cz.cuni.amis.utils.flag.Flag;
44  import cz.cuni.amis.utils.future.FutureWithListeners;
45  import cz.cuni.amis.utils.maps.HashMapMap;
46  import cz.cuni.amis.utils.token.IToken;
47  
48  public class UT2004TCClient extends SensomotoricModule<UT2004Bot> {
49  	
50  	private UT2004Bot bot;
51  	
52  	private IWorldView botWorldView;
53  	
54  	private IWorldView teamWorldView;
55  	
56  	private IWorldObjectEventListener<Self, WorldObjectUpdatedEvent<Self>> selfListener = new IWorldObjectEventListener<Self, WorldObjectUpdatedEvent<Self>>() {
57  		
58  		@Override
59  		public void notify(WorldObjectUpdatedEvent<Self> event) {
60  			selfUpdate(event);
61  		}
62  	};
63  	
64  	private IWorldEventListener<BeginMessage> beginMessageListener = new IWorldEventListener<BeginMessage>() {
65  		
66  		@Override
67  		public void notify(BeginMessage event) {
68  			beginMessage(event);
69  		}
70  	};
71  	
72  	private IWorldEventListener<EndMessage> endMessageListener = new IWorldEventListener<EndMessage>() {
73  		
74  		@Override
75  		public void notify(EndMessage event) {
76  			endMessage(event);
77  		}
78  	};
79  	
80  	private IWorldEventListener<TCMessage> tcMessageListener = new IWorldEventListener<TCMessage>() {
81  
82  		@Override
83  		public void notify(TCMessage event) {
84  			tcMessage(event);
85  		}
86  		
87  	};
88  	
89  	private List<TCMessage> current = new ArrayList<TCMessage>();
90  	
91  	private List<TCMessage> incoming = new ArrayList<TCMessage>();
92  	
93  	private TCControlMessagesTranslator tcTranslator;
94  	
95  	private TCEvents tcEvents;
96  	
97  	private Self self;
98  	
99  	private long simTime;
100 	
101 	private TCMinaClient minaClient = null;
102 	
103 	public UT2004TCClient(UT2004Bot bot, IWorldView teamWorldView) {
104 		super(bot);
105 		
106 		this.botWorldView = bot.getWorldView();
107 		this.teamWorldView = teamWorldView;
108 				
109 		tcTranslator = new TCControlMessagesTranslator(botWorldView, false);
110 		tcTranslator.enable();
111 		
112 		tcEvents = new TCEvents(agent.getWorldView()) {
113 			@Override
114 			public void tcControlServerAlive(TCControlServerAlive event) {
115 				UT2004TCClient.this.tcControlServerAlive(event);
116 			}
117 		};
118 		tcEvents.enableTCEvents();
119 		
120 		bot.getWorldView().addObjectListener(Self.class, WorldObjectUpdatedEvent.class, selfListener);		
121 		bot.getWorldView().addEventListener(BeginMessage.class, beginMessageListener);
122 		bot.getWorldView().addEventListener(EndMessage.class, endMessageListener);
123 		
124 		this.teamWorldView.addEventListener(TCMessage.class, tcMessageListener);
125 	}
126 			
127 	// =========================
128 	// PUBLIC INTERFACE - STATUS
129 	// =========================
130 	
131 	/**
132 	 * Whether your bot is connected to the TC server.
133 	 * @return
134 	 */
135 	public boolean isConnected() {
136 		TCMinaClient mClient = minaClient;
137 		if (mClient == null) return false;
138 		return mClient.getConnected().getFlag();
139 	}
140 	
141 	public Flag<Boolean> getConnectedFlag() {
142 		TCMinaClient mClient = minaClient;
143 		if (mClient == null) return null;
144 		return mClient.getConnected();
145 	}
146 	
147 	public boolean isConnected(UnrealId botId) {
148 		TCMinaClient mClient = minaClient;
149 		if (mClient == null) return false;
150 		return mClient.isConnected(botId);		
151 	}
152 	
153 	public boolean isConnected(Player bot) {
154 		TCMinaClient mClient = minaClient;
155 		if (mClient == null) return false;
156 		return mClient.isConnected(bot);
157 	}
158 	
159 	public boolean isConnectedToMyTeam(UnrealId botId) {
160 		TCMinaClient mClient = minaClient;
161 		if (mClient == null) return false;
162 		return mClient.isConnectedToMyTeam(botId);
163 	}
164 	
165 	public boolean isConnectedToMyTeam(Player bot) {
166 		TCMinaClient mClient = minaClient;
167 		if (mClient == null) return false;
168 		return mClient.isConnectedToMyTeam(bot);
169 	}
170 	
171 	public boolean isConnectedToChannel(UnrealId botId, int channelId) {
172 		TCMinaClient mClient = minaClient;
173 		if (mClient == null) return false;
174 		return mClient.isConnectedToChannel(botId, channelId);
175 	}
176 	
177 	public boolean isConnectedToChannel(Player bot, int channelId) {
178 		TCMinaClient mClient = minaClient;
179 		if (mClient == null) return false;
180 		return mClient.isConnectedToChannel(bot, channelId);
181 	}
182 	
183 	public boolean isChannelExist(int channelId) {
184 		TCMinaClient mClient = minaClient;
185 		if (mClient == null) return false;
186 		return mClient.isChannelExist(channelId);
187 	}
188 	
189 	/**
190 	 * Returns set of all bots connected to the same TC server.
191 	 * @return READ-ONLY!
192 	 */
193 	public Set<UnrealId> getConnectedAllBots() {
194 		TCMinaClient mClient = minaClient;
195 		if (mClient == null) return new HashSet<UnrealId>();
196 		return mClient.getConnectedAllBots();
197 	}
198 	
199 	/**
200 	 * Returns set of bots of the same team connected to the same TC server.
201 	 * @return READ-ONLY!
202 	 */
203 	public Set<UnrealId> getConnectedTeamBots() {
204 		TCMinaClient mClient = minaClient;
205 		if (mClient == null) return new HashSet<UnrealId>();
206 		return mClient.getConnectedTeamBots();
207 	}
208 	
209 	/**
210 	 * Returns set of bots connected to the channel of 'channelId' of the same TC server.
211 	 * @return READ-ONLY!
212 	 */
213 	public Set<UnrealId> getConnectedChannelBots(int channelId) {
214 		TCMinaClient mClient = minaClient;
215 		if (mClient == null) return new HashSet<UnrealId>();
216 		return mClient.getConnectedChannelBots(channelId);
217 	}
218 	
219 	/**
220 	 * Returns details about bots/channels connected to the team.
221 	 * 
222 	 * Returns NULL if not connected!
223 	 * 
224 	 * @return READ-ONLY!
225 	 */
226 	public TCTeam getTeam() {		
227 		TCMinaClient mClient = minaClient;
228 		if (mClient == null) return null;
229 		return mClient.getTeam();
230 	}
231 	
232 	/**
233 	 * Returns details about bots/channels connected to the team.
234 	 * 
235 	 * Returns NULL if not connected or non-existing channel!
236 	 * 
237 	 * @return READ-ONLY!
238 	 */
239 	public TCChannel getChannel(int channelId) {		
240 		TCMinaClient mClient = minaClient;
241 		if (mClient == null) return null;
242 		return mClient.getChannel(channelId);
243 	}
244 	
245 	// ===========================
246 	// PUBLIC INTERFACE - REQUESTS
247 	// ===========================
248 		
249 	/**
250 	 * Request to create a new channel, the channel will gets channelId assigned by {@link TCMinaServer}.
251 	 * 
252 	 * When created, you will be automatically added to it as its creator.
253 	 * 
254 	 * @return 
255 	 */
256 	public RequestFuture<TCInfoTeamChannelCreated> requestCreateChannel() {
257 		TCMinaClient mClient = minaClient;
258 		if (mClient == null) return null;
259 		return mClient.requestCreateChannel();		
260 	}
261 	
262 	/**
263 	 * Request to destroy an existing channel. Note that you must be channel's creator in able to do this!
264 	 * @param channelId
265 	 * @return 
266 	 */
267 	public RequestFuture<TCInfoTeamChannelDestroyed> requestDestroyChannel(int channelId) {
268 		TCMinaClient mClient = minaClient;
269 		if (mClient == null) return null;
270 		return mClient.requestDestroyChannel(channelId);
271 	}
272 	
273 	/**
274 	 * Request {@link TCInfoStatus} update from {@link TCMinaServer}.
275 	 * @return request future or NULL if not connected
276 	 */
277 	public RequestFuture<TCInfoStatus> requestGetStatus() {
278 		TCMinaClient mClient = minaClient;
279 		if (mClient == null) return null;
280 		return mClient.requestGetStatus();
281 	}
282 	
283 	/**
284 	 * Request to join an existing channel.
285 	 * @param channelId
286 	 * @return 
287 	 */
288 	public RequestFuture<TCInfoTeamChannelBotJoined> requestJoinChannel(int channelId) {
289 		TCMinaClient mClient = minaClient;
290 		if (mClient == null) return null;
291 		return mClient.requestJoinChannel(channelId);
292 	}
293 	
294 	/**
295 	 * Request to leave an existing channel. Leaving a channel you have created will NOT destroy it.
296 	 * @param channelId
297 	 * @return
298 	 */
299 	public RequestFuture<TCInfoTeamChannelBotLeft> requestLeaveChannel(int channelId) {
300 		TCMinaClient mClient = minaClient;
301 		if (mClient == null) return null;
302 		return mClient.requestLeaveChannel(channelId);
303 	}
304 	
305 	// ================================
306 	// PUBLIC INTERFACE - COMMUNICATION
307 	// ================================	
308 	
309 	public boolean sendToAll(IToken messageType, Serializable data) {
310 		if (minaClient == null) {
311 			log.warning("minaClient is NULL, cannot sendToAll: " + data);
312 			return false;
313 		}
314 		if (!minaClient.getConnected().getFlag()) {
315 			log.warning("minaClient is NOT connected, cannot sendToAll: " + data);
316 			return false;
317 		}
318 		return minaClient.sendToAll(messageType, data);
319 	}
320 	
321 	public boolean sendToAll(TCMessageData data) {
322 		data.setSimTime(getSimTime());
323 		return sendToAll(data.getMessageType(), data);
324 	}
325 	
326 	public boolean sendToTeam(IToken messageType, Serializable data) {
327 		if (minaClient == null) {
328 			log.warning("minaClient is NULL, cannot sendToTeam: " + data);
329 			return false;
330 		}
331 		if (!minaClient.getConnected().getFlag()) {
332 			log.warning("minaClient is NOT connected, cannot sendToTeam: " + data);
333 			return false;
334 		}
335 		return minaClient.sendToTeam(messageType, data);
336 	}
337 	
338 	public boolean sendToTeam(TCMessageData data) {
339 		data.setSimTime(getSimTime());
340 		return sendToTeam(data.getMessageType(), data);
341 	}
342 	
343 	public boolean sendToChannel(int channelId, IToken messageType, Serializable data) {
344 		if (minaClient == null) {
345 			log.warning("minaClient is NULL, cannot sendToChannel(" + channelId + "): " + data);
346 			return false;
347 		}
348 		if (!minaClient.getConnected().getFlag()) {
349 			log.warning("minaClient is NOT connected, cannot sendToChannel(" + channelId + "): " + data);
350 			return false;
351 		}
352 		return minaClient.sendToChannel(channelId, messageType, data);
353 	}
354 	
355 	public boolean sendToChannel(int channelId, TCMessageData data) {
356 		data.setSimTime(getSimTime());
357 		return sendToChannel(channelId, data.getMessageType(), data);
358 	}
359 	
360 	public boolean sendToBot(UnrealId bot, IToken messageType, Serializable data) {
361 		if (minaClient == null) {
362 			log.warning("minaClient is NULL, cannot sendToBot(" + bot.getStringId() + "): " + data);
363 			return false;
364 		}
365 		if (!minaClient.getConnected().getFlag()) {
366 			log.warning("minaClient is NOT connected, cannot sendToBot(" + bot.getStringId() + "): " + data);
367 			return false;
368 		}
369 		return minaClient.sendPrivate(bot, messageType, data);
370 	}
371 	
372 	public boolean sendToBot(UnrealId bot, TCMessageData data) {
373 		data.setSimTime(getSimTime());
374 		return sendToBot(bot, data.getMessageType(), data);
375 	}
376 
377 	/**
378 	 * {@link TCMessage}s that came since the last {@link EndMessage}, i.e., since the last update, i.e., since the last logic() iteration.
379 	 * <p><p>
380 	 * This list is auto-emptied every {@link EndMessage}.
381 	 *  
382 	 * @return
383 	 */
384 	public List<TCMessage> getMessages() {
385 		return this.current;
386 	}
387 	
388 	// ========================
389 	// PUBLIC INTERFACE - UTILS
390 	// ========================
391 	
392 	public UnrealId getBotId() {
393 		if (self == null) {
394 			throw new PogamutException("Could not retrieve BotId, self is NULL.", log, this);
395 		}
396 		return self.getBotId();
397 	}
398 	
399 	public int getBotTeam() {
400 		if (self == null) {
401 			throw new PogamutException("Could not retrieve bot Team, self is NULL.", log, this);
402 		}
403 		return self.getTeam();
404 	}
405 	
406 	public long getSimTime() {
407 		return simTime;
408 	}
409 
410 	// =====================
411 	// UT2004 EVENT HANDLERS
412 	// =====================
413 	
414 	protected void selfUpdate(WorldObjectUpdatedEvent<Self> event) {
415 		this.self = event.getObject();
416 		if (minaClient == null) return;
417 		if (minaClient.getConnected().getFlag()) return;
418 		if (minaClient.getConnecting().getFlag()) return;
419 		minaClient.connect();
420 	}
421 	
422 	protected void beginMessage(BeginMessage event) {
423 		this.simTime = event.getSimTime();
424 	}
425 	
426 	protected void endMessage(EndMessage event) {
427 		this.current.clear();
428 		List<TCMessage> temp = this.current;
429 		this.current = incoming;
430 		this.incoming = temp;
431 	}
432 	
433 	protected void tcControlServerAlive(TCControlServerAlive event) {
434 		if (minaClient == null) {
435 			if (this.self != null) {
436 				minaClient = new TCMinaClient(this, new InetSocketAddress(event.getHost(), event.getPort()), teamWorldView, log);
437 				if (minaClient.getConnected().getFlag()) return;
438 				if (minaClient.getConnecting().getFlag()) return;
439 				minaClient.connect();
440 			}
441 		} else {
442 			if (!event.getHost().equals(minaClient.getHost()) || event.getPort() != minaClient.getPort()) {
443 				log.warning("There are multiple TC server connected to the UT2004, currently using " + minaClient.getHost() + ":" + minaClient.getPort() + ", the other server is listening at " + event.getHost() + ":" + event.getPort());
444 				return;
445 			}
446 		}
447 	}	
448 	
449 	protected void tcMessage(TCMessage event) {
450 		incoming.add(event);
451 	}
452 	
453 	// ================
454 	// MODULE LIFECYCLE
455 	// ================
456 	
457 	@Override
458 	protected void cleanUp() {
459 		if (minaClient != null) {
460 			minaClient.stop();
461 			minaClient = null;
462 			self = null;
463 			simTime = -1;
464 		}
465 		
466 		super.cleanUp();
467 		
468 	}
469 
470 	
471 
472 }