View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.teamcomm.server;
2   
3   import java.net.InetSocketAddress;
4   import java.util.HashSet;
5   import java.util.Map;
6   import java.util.Set;
7   import java.util.logging.Level;
8   
9   import com.google.inject.Inject;
10  
11  import cz.cuni.amis.pogamut.base.communication.command.IAct;
12  import cz.cuni.amis.pogamut.base.communication.connection.impl.socket.SocketConnection;
13  import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
14  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
15  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
16  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
17  import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
18  import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
19  import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
20  import cz.cuni.amis.pogamut.ut2004.agent.params.UT2004AgentParameters;
21  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.SendControlMessage;
22  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.StartPlayers;
23  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BeginMessage;
24  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.EndMessage;
25  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerJoinsGame;
26  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerLeft;
27  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerMessage;
28  import cz.cuni.amis.pogamut.ut2004.communication.worldview.UT2004WorldView;
29  import cz.cuni.amis.pogamut.ut2004.factory.guice.remoteagent.UT2004ServerFactory;
30  import cz.cuni.amis.pogamut.ut2004.server.IUT2004Server;
31  import cz.cuni.amis.pogamut.ut2004.server.impl.UT2004Server;
32  import cz.cuni.amis.pogamut.ut2004.teamcomm.mina.server.TCMinaServer;
33  import cz.cuni.amis.pogamut.ut2004.teamcomm.server.protocol.TCControlMessages;
34  import cz.cuni.amis.pogamut.ut2004.teamcomm.server.protocol.messages.TCControlServerAlive;
35  import cz.cuni.amis.pogamut.ut2004.utils.UT2004ServerRunner;
36  import cz.cuni.amis.utils.maps.LazyMap;
37  
38  public class UT2004TCServer extends UT2004Server implements IUT2004Server {
39  	
40  	public static final UnrealId SERVER_UNREAL_ID = UnrealId.get("TC_CONTROL_SERVER");
41  
42  	private static final double ALIVE_MESSAGE_INTERVAL_SECS = 30;
43  	
44  	 /**
45       * BeginMessage listener - we get current server time here.
46       */
47      private IWorldEventListener<BeginMessage> myBeginMessageListener = new IWorldEventListener<BeginMessage>() {
48          public void notify(BeginMessage event) {
49              timeUpdate(event);
50          }
51      };
52      
53      /**
54       * BeginMessage listener - we get current server time here.
55       */
56      private IWorldEventListener<EndMessage> myEndMessageListener = new IWorldEventListener<EndMessage>() {
57          public void notify(EndMessage event) {
58              batchEnd(event);
59          }
60      };
61      
62      /**
63       * PlayerJoinsGame listener - we get informed that new player/bot has entered the game.
64       */
65      private IWorldEventListener<PlayerJoinsGame> myPlayerJoinsGameMessageListener = new IWorldEventListener<PlayerJoinsGame>() {
66          public void notify(PlayerJoinsGame event) {
67              playerJoinsGame(event);
68          }
69      };
70      
71      /**
72       * PlayerLeft listener - we get informed that new player/bot has entered the game.
73       */
74      private IWorldEventListener<PlayerLeft> myPlayerLeftMessageListener = new IWorldEventListener<PlayerLeft>() {
75          public void notify(PlayerLeft event) {
76              playerLeft(event);
77          }
78      };
79  
80      /**
81       * Player listener - we simply print out all player messages we receive.
82       */
83      private IWorldObjectEventListener<PlayerMessage, WorldObjectUpdatedEvent<PlayerMessage>> myPlayerListener = new IWorldObjectEventListener<PlayerMessage, WorldObjectUpdatedEvent<PlayerMessage>>() {
84          public void notify(WorldObjectUpdatedEvent<PlayerMessage> event) {
85              playerUpdate(event);
86          }
87      };
88      
89      private Object mutex = new Object();
90      
91      private TCControlMessages messages = new TCControlMessages();
92  	
93  	private TCMinaServer minaServer;
94  
95  	private long utSimTime = -1;
96  	
97  	private double utTimeLast = -1;
98  
99  	private double utTimeCurrent = -1;
100 
101 	private double utTimeDelta = -1;
102 	
103 	private Map<UnrealId, BotTCRecord<PlayerMessage>> records = new LazyMap<UnrealId, BotTCRecord<PlayerMessage>>() {
104 
105 		@Override
106 		protected BotTCRecord<PlayerMessage> create(UnrealId key) {
107 			return new BotTCRecord<PlayerMessage>(key);
108 		}
109 		
110 	};
111 	
112 	private Set<UnrealId> leftPlayers = new HashSet<UnrealId>();
113 	
114 	@Inject
115 	public UT2004TCServer(UT2004AgentParameters params, IAgentLogger agentLogger, IComponentBus bus, SocketConnection connection, UT2004WorldView worldView, IAct act) {
116 		super(params, agentLogger, bus, connection, worldView, act);
117 		
118 		minaServer = new TCMinaServer(this, new InetSocketAddress(getParams().getBindHost(), getParams().getBindPort()), getLogger().getCategory("TCMinaServer"));
119 		
120 		getWorldView().addEventListener(BeginMessage.class,    myBeginMessageListener);
121         getWorldView().addEventListener(EndMessage.class,      myEndMessageListener);
122         getWorldView().addEventListener(PlayerJoinsGame.class, myPlayerJoinsGameMessageListener);
123         getWorldView().addEventListener(PlayerLeft.class,      myPlayerLeftMessageListener);
124         getWorldView().addObjectListener(PlayerMessage.class,  WorldObjectUpdatedEvent.class, myPlayerListener);
125 	}
126 
127 	@Override
128 	public UT2004TCServerParams getParams() {
129 		UT2004AgentParameters params = super.getParams();
130 		if (!(params instanceof UT2004TCServerParams)) throw new RuntimeException("Invalid parameters passed, expecting UT2004TCServerParams, got " + params);
131 		return (UT2004TCServerParams) params;
132 	}
133 	
134 	@Override
135     protected void init() {
136     	super.init();
137     	
138     	//getLogger().getCategory(YylexParser.COMPONENT_ID.getToken()).setLevel(Level.ALL);
139     	//getLogger().getCategory(getWorldView()).setLevel(Level.ALL);
140     	
141     	log.setLevel(Level.INFO);
142     	
143     	synchronized(mutex) {
144 	        getAct().act(new StartPlayers(true, true, false));
145     	}
146     }
147 	
148 	@Override
149 	protected void stopAgent() {
150 		synchronized(mutex) {
151 			if (minaServer != null) {
152 				minaServer.stop();
153 				minaServer = null;
154 			}
155 		}
156 		super.stopAgent();
157 	}
158 	
159 	// ================
160 	// PUBLIC INTERFACE
161 	// ================
162 	
163 	public long getSimTime() {
164 		return utSimTime;
165 	}
166 	
167 	public PlayerMessage getPlayer(UnrealId source) {
168 		 
169 		if (!records.containsKey(source)) return null;
170 		
171 		BotTCRecord<PlayerMessage> record = records.get(source);
172 		
173 		if (record == null) return null;
174 		
175 		return record.getPlayer();			
176 	}
177 
178 	
179 	// ===========
180 	// BOT RECORDS
181 	// ===========
182 	
183 	private void deleteRecord(UnrealId id) {
184 		BotTCRecord<PlayerMessage> record = records.remove(id);
185 		
186 		if (record != null) {
187 			minaServer.botLeft(id);
188 		}
189 		
190 		leftPlayers.add(id);
191 	}
192 	
193 	private void ensureRecord(PlayerMessage object) {
194 		records.put(object.getId(), new BotTCRecord<PlayerMessage>(object.getId(), object));
195 	}
196 	
197 	// =====================
198 	// UT2004 EVENT HANDLERS
199 	// =====================
200 	
201 	protected void playerUpdate(IWorldObjectEvent<PlayerMessage> event) {
202 		if (!records.containsKey(event.getId())) {
203 			if (leftPlayers.contains(event.getId())) {
204 				// EATING EXTRA UPDATE FOR NON-EXISTING PLAYER...
205 				leftPlayers.remove(event.getId());
206 				return;
207 			}
208 			log.info(event.getObject().getId().getStringId() + ": First PlayerMessage received.");
209 			sendAlive();
210 		}
211 		ensureRecord(event.getObject());
212 	}
213 
214 	protected void playerLeft(PlayerLeft event) {
215 		log.info(event.getId().getStringId() + ": Player has LEFT the game.");
216 		deleteRecord(event.getId());
217 		minaServer.botLeft(event.getId());
218 	}
219 
220 	protected void playerJoinsGame(PlayerJoinsGame event) {
221 		log.info(event.getId().getStringId() + ": Player has JOINED the game.");
222 	}
223 
224 	protected void batchEnd(EndMessage event) {
225 	}
226 
227 	protected void timeUpdate(BeginMessage event) {
228 		utSimTime = event.getSimTime();
229 		
230 		utTimeLast = utTimeCurrent;
231     	utTimeCurrent = event.getTime();
232     	utTimeDelta = utTimeCurrent - utTimeLast;
233     	
234     	if (utSimTime > 0 && utTimeCurrent > 0 && (lastAlive < 0 || utTimeCurrent - lastAlive > ALIVE_MESSAGE_INTERVAL_SECS)) {
235     		
236     		if (!minaServer.getRunning().getFlag()) {
237     			log.info("Starting MINA SERVER!");
238     			minaServer.start();
239     		}
240     		
241     		sendAlive();
242     	}
243 	}
244 	
245 	// ====================
246 	// CONTROL SERVER UTILS
247 	// ====================
248 	
249 	private double lastAlive = -1;
250 	
251 	private void sendAlive() {
252 		log.fine("Sending ALIVE message");
253 		
254 		lastAlive = utTimeCurrent;
255 		
256 		TCControlServerAlive message = new TCControlServerAlive();
257 		
258 		message.setHost(getParams().getBindHost());
259 		message.setPort(getParams().getBindPort());
260 		
261     	SendControlMessage command = messages.write(message);
262     	command.setSendAll(true);
263     	getAct().act(command);    	
264     }
265 	
266 	public static UT2004TCServer startTCServer() {
267 		return startTCServer("localhost", 3010);
268 	}
269 	
270 	public static UT2004TCServer startTCServer(String bindHost, int bindPort) {
271 		 // START UT2004TagServer
272         UT2004TCServerModule module = new UT2004TCServerModule();
273         UT2004ServerFactory factory = new UT2004ServerFactory(module);
274         UT2004ServerRunner<UT2004Server, UT2004TCServerParams> serverRunner = new UT2004ServerRunner(factory);
275         
276         UT2004TCServerParams params = new UT2004TCServerParams();
277         params.setBindHost("localhost");
278         params.setBindPort(3010);
279          
280         return (UT2004TCServer) serverRunner.setLogLevel(Level.INFO).setMain(false).startAgents(params).get(0);
281 	}
282 	
283 	public static void main(String[] args) {
284 		startTCServer();
285 	}
286 	
287 }