Source code: marauroa/game/RPServerManager.java
1 /* $Id: RPServerManager.java,v 1.31 2003/12/12 16:18:24 arianne_rpg Exp $ */
2 /***************************************************************************
3 * (C) Copyright 2003 - Marauroa *
4 ***************************************************************************
5 ***************************************************************************
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 ***************************************************************************/
13 package marauroa.game;
14
15 import java.util.*;
16 import java.io.*;
17 import java.net.*;
18
19 import marauroa.net.*;
20 import marauroa.*;
21
22 /** This class is responsible for adding actions to scheduler, and to build and
23 * sent perceptions */
24 class RPServerManager extends Thread
25 {
26 /** We send 1 TOTAL perception each TOTAL_PERCEPTION_RELATION DELTA perceptions */
27 private final static int TOTAL_PERCEPTION_RELATION=10;
28
29 /** The thread will be running while keepRunning is true */
30 private boolean keepRunning;
31 /** isFinished is true when the thread has really exited. */
32 private boolean isfinished;
33 /** The time elapsed between 2 turns. */
34 private long turnDuration;
35
36 /** The scheduler needed to organize actions */
37 private RPScheduler scheduler;
38 /** The ruleProcessor that the scheduler will use to execute the actions */
39 private RPRuleProcessor ruleProcessor;
40 /** The place where the objects are stored */
41 private RPZone zone;
42
43 /** The networkServerManager so that we can send perceptions */
44 private NetworkServerManager netMan;
45 /** The PlayerEntryContainer so that we know where to send perceptions */
46 private PlayerEntryContainer playerContainer;
47
48
49 /** Constructor
50 * @param netMan the NetworkServerManager so that we can send message */
51 public RPServerManager(NetworkServerManager netMan)
52 {
53 super("RPServerManager");
54
55 marauroad.trace("RPServerManager",">");
56
57 try
58 {
59 keepRunning=true;
60 isfinished=false;
61
62 scheduler=new RPScheduler();
63 playerContainer=PlayerEntryContainer.getContainer();
64 this.netMan=netMan;
65
66 Configuration conf=Configuration.getConfiguration();
67 Class zoneClass=Class.forName(conf.get("rp_RPZoneClass"));
68 zone=(RPZone)zoneClass.newInstance();
69
70 Class ruleProcessorClass=Class.forName(conf.get("rp_RPRuleProcessorClass"));
71 ruleProcessor=(RPRuleProcessor)ruleProcessorClass.newInstance();
72 ruleProcessor.setContext(zone);
73
74 String duration =conf.get("rp_turnDuration");
75 turnDuration = Long.parseLong(duration);
76
77 start();
78 }
79 catch(Exception e)
80 {
81 marauroad.trace("RPServerManager","X",e.getMessage());
82 marauroad.trace("RPServerManager","!","ABORT: Unable to create RPZone and RPRuleProcessor instances");
83 System.exit(-1);
84 }
85 finally
86 {
87 marauroad.trace("RPServerManager","<");
88 }
89 }
90
91 /** Constructor
92 * @param netMan the NetworkServerManager so that we can send message */
93 public RPServerManager(NetworkServerManager netMan, RPZone zone, RPRuleProcessor ruleProcessor, long turnDuration)
94 {
95 super("RPServerManager");
96
97 marauroad.trace("RPServerManager",">");
98
99 try
100 {
101 keepRunning=true;
102 isfinished=false;
103
104 scheduler=new RPScheduler();
105 playerContainer=PlayerEntryContainer.getContainer();
106 this.netMan=netMan;
107 this.zone=zone;
108 this.ruleProcessor=ruleProcessor;
109 this.turnDuration=turnDuration;
110
111 start();
112 }
113 finally
114 {
115 marauroad.trace("RPServerManager","<");
116 }
117 }
118
119 public void finish()
120 {
121 marauroad.trace("RPServerManager::finish",">");
122 keepRunning=false;
123
124 while(isfinished==false)
125 {
126 try
127 {
128 Thread.sleep(1000);
129 }
130 catch(java.lang.InterruptedException e)
131 {
132 }
133 }
134
135 marauroad.trace("RPServerManager::finish","<");
136 }
137
138 public void addRPAction(RPAction action) throws RPScheduler.ActionInvalidException
139 {
140 marauroad.trace("RPServerManager::addRPAction",">");
141 try
142 {
143 marauroad.trace("RPServerManager::addRPAction","D","Added action: "+action.toString());
144 scheduler.addRPAction(action);
145 }
146 finally
147 {
148 marauroad.trace("RPServerManager::addRPAction","<");
149 }
150 }
151
152 public void addRPObject(RPObject object) throws RPZone.RPObjectInvalidException
153 {
154 marauroad.trace("RPServerManager::addRPObject",">");
155 try
156 {
157 marauroad.trace("RPServerManager::addRPObject","D","Added object: "+object.toString());
158 zone.add(object);
159 }
160 finally
161 {
162 marauroad.trace("RPServerManager::addRPObject","<");
163 }
164 }
165
166 public RPObject getRPObject(RPObject.ID id) throws RPZone.RPObjectNotFoundException
167 {
168 marauroad.trace("RPServerManager::getRPObject",">");
169
170 try
171 {
172 return zone.get(id);
173 }
174 finally
175 {
176 marauroad.trace("RPServerManager::getRPObject","<");
177 }
178 }
179
180 public boolean hasRPObject(RPObject.ID id)
181 {
182 marauroad.trace("RPServerManager::hasRPObject",">");
183
184 try
185 {
186 return zone.has(id);
187 }
188 finally
189 {
190 marauroad.trace("RPServerManager::hasRPObject","<");
191 }
192 }
193
194 public RPObject removeRPObject(RPObject.ID id) throws RPZone.RPObjectNotFoundException
195 {
196 marauroad.trace("RPServerManager::removeRPObject",">");
197
198 try
199 {
200 marauroad.trace("RPServerManager::removeRPObject","D","Removed object: "+id.toString());
201 return zone.remove(id);
202 }
203 finally
204 {
205 marauroad.trace("RPServerManager::removeRPObject","<");
206 }
207 }
208
209 private int deltaPerceptionSend=0;
210
211 private void buildPerceptions()
212 {
213 marauroad.trace("RPServerManager::buildPerceptions",">");
214 List playersToRemove=new LinkedList();
215
216 try
217 {
218 playerContainer.getLock().requestReadLock();
219
220 ++deltaPerceptionSend;
221 PlayerEntryContainer.ClientIDIterator it=playerContainer.iterator();
222
223
224 while(it.hasNext())
225 {
226 int clientid=it.next();
227
228 try
229 {
230 if(playerContainer.getRuntimeState(clientid)==playerContainer.STATE_GAME_BEGIN)
231 {
232 InetSocketAddress source=playerContainer.getInetSocketAddress(clientid);
233 RPZone.Perception perception;
234 if(deltaPerceptionSend>TOTAL_PERCEPTION_RELATION)
235 {
236 perception=zone.getPerception(playerContainer.getRPObjectID(clientid),RPZone.Perception.TOTAL);
237 deltaPerceptionSend=0;
238 }
239 else
240 {
241 perception=zone.getPerception(playerContainer.getRPObjectID(clientid),RPZone.Perception.DELTA);
242 }
243
244 Message messages2cPerception=new MessageS2CPerception(source, perception.modifiedList, perception.deletedList);
245 netMan.addMessage(messages2cPerception);
246 }
247
248 if(playerContainer.timedout(clientid))
249 {
250 playersToRemove.add(new Integer(clientid));
251 }
252 }
253 catch(Exception e)
254 {
255 marauroad.trace("RPServerManager::buildPerceptions","X",e.getMessage());
256 }
257 }
258
259 playerContainer.getLock().releaseLock();
260
261 /* Removing the players is a write operation */
262 playerContainer.getLock().requestWriteLock();
263 removeTimedoutPlayers(playersToRemove);
264 playerContainer.getLock().releaseLock();
265 }
266 finally
267 {
268 marauroad.trace("RPServerManager::buildPerceptions","<");
269 }
270 }
271
272 private void removeTimedoutPlayers(List playersToRemove)
273 {
274 marauroad.trace("RPServerManager::removeTimedoutPlayers",">");
275
276 try
277 {
278 Iterator it_removed=playersToRemove.iterator();
279 while(it_removed.hasNext())
280 {
281 int clientid=((Integer)it_removed.next()).intValue();
282
283 RPObject.ID id=playerContainer.getRPObjectID(clientid);
284 RPObject object=removeRPObject(id);
285
286 /* NOTE: Set the Object so that it is stored in Database */
287 playerContainer.setRPObject(clientid,object);
288 playerContainer.removeRuntimePlayer(clientid);
289
290 marauroad.trace("RPServerManager::removeTimedoutPlayers","D","Removed player ("+clientid+")");
291 }
292 }
293 catch(Exception e)
294 {
295 marauroad.trace("RPServerManager::removeTimedoutPlayers","!","Can't remove a player(-not available-) that timedout");
296 System.exit(-1);
297 }
298 finally
299 {
300 marauroad.trace("RPServerManager::removeTimedoutPlayers","<");
301 }
302 }
303
304 public void run()
305 {
306 marauroad.trace("RPServerManager::run",">");
307
308 while(keepRunning)
309 {
310 scheduler.visit(ruleProcessor);
311 buildPerceptions();
312
313 try
314 {
315 Thread.sleep(turnDuration);
316 }
317 catch(InterruptedException e)
318 {
319 }
320
321 scheduler.nextTurn();
322 ruleProcessor.nextTurn();
323 zone.nextTurn();
324 }
325
326 isfinished=true;
327 marauroad.trace("RPServerManager::run","<");
328 }
329 }
330