1
2
3
4
5 package spellcast.game;
6
7 import java.beans.PropertyChangeEvent;
8 import java.beans.PropertyChangeListener;
9 import java.util.Iterator;
10
11 import org.apache.log4j.Logger;
12
13 import spellcast.beings.Gender;
14 import spellcast.beings.IWizard;
15 import spellcast.beings.Wizard;
16 import spellcast.event.ConnectionEvent;
17 import spellcast.event.ConnectionRequestEvent;
18 import spellcast.event.DisconnectionEvent;
19 import spellcast.event.DisconnectionRequestEvent;
20 import spellcast.event.GameUpdateEvent;
21 import spellcast.event.MessageEvent;
22 import spellcast.event.OkEvent;
23 import spellcast.model.Id;
24 import spellcast.questions.Question;
25
26 /***
27 * The Game Server class is the control logic for the Game.
28 * It inherits from Game which contains the Data Access methods.
29 *
30 * @author Barrie Treloar
31 */
32 public class Game_Server implements PropertyChangeListener, Runnable {
33 private Game theGame;
34 private IPC ipc;
35 private Thread gameThread;
36 private boolean isRunning;
37
38 /***
39 * When this percentage of wizards have indicated they are ready to start then
40 * the game will commence.
41 */
42 private static final int READY_TO_START_PERCENTAGE = 50;
43
44 private static final Logger logger = Logger.getLogger("game");
45
46 public Game_Server(IPC ipc, String gameName) {
47 this.ipc = ipc;
48 theGame = new Game(gameName, null);
49 }
50
51 public Game getGame() {
52 return theGame;
53 }
54
55 /***
56 * Unless otherwise specified, all property change events are forwarded to all clients
57 */
58 public void propertyChange(PropertyChangeEvent pce) {
59 Id recipient = Id.EVERYONE;
60
61 GameUpdateEvent response = new GameUpdateEvent(pce);
62 if (!recipient.equals(Id.EVERYONE)) {
63 ipc.send(recipient, response);
64 }
65 else {
66 ipc.sendToAll(response);
67 }
68 }
69
70 public void run() {
71 while (isRunning) {
72 processInput();
73 if (!theGame.hasStarted()) {
74 runPreGame();
75 }
76 else {
77 if (!theGame.hasFinished()) {
78 runTurn();
79 }
80 }
81 }
82 }
83
84 /***
85 * Process input from ipc handles.
86 * If the handle is not connected, then we only allow <code>ConnectionRequestEvent</code>s.
87 * If the handle is connected then we process events normally.
88 */
89 private void processInput() {
90 IPCRequest request = ipc.receive();
91
92 if (!request.getHandle().isConnected()) {
93 if (request.getGameEvent() instanceof ConnectionRequestEvent) {
94 processConnectionRequestEvent(request);
95 }
96 }
97 else {
98 if (request.getGameEvent() instanceof DisconnectionRequestEvent) {
99 processDisconnectionRequestEvent(request);
100 }
101 else
102 if (request.getGameEvent() instanceof MessageEvent) {
103 processMessageEvent(request);
104 }
105 else
106 if (request.getGameEvent() instanceof OkEvent) {
107 processOkEvent(request);
108 }
109 else {
110 logger.error(
111 "Unknown Game Event received: " + request.getGameEvent().getClass().getName());
112 }
113 }
114 }
115
116 /***
117 * Process ConnectionRequestEvent.
118 * Checks for duplicate IDs (fatal) and duplicate names (adds a uniquifier)
119 * before adding the wizard to the system.
120 * Sends the ConnectionEvent for this wizard as well as sending one to the
121 * connecting host for every wizard already connected.
122 * The connecting wizard also gets a GameSyncEvent.
123 */
124 private void processConnectionRequestEvent(IPCRequest request) {
125 ConnectionRequestEvent event = (ConnectionRequestEvent) request.getGameEvent();
126
127 Gender gender = Gender.getGender(event.getGender());
128 if (gender == null) {
129 logger.error("Unknown gender specified (" + event.getGender() + ")");
130 return;
131 }
132
133 String originalWizardName = event.getWizardName().trim();
134 String wizardName = originalWizardName;
135 int uniquifier = 1;
136 boolean nameMatched = false;
137 do {
138 nameMatched = false;
139 Iterator wizardIterator = theGame.getWizards().listIterator();
140 while (wizardIterator.hasNext()) {
141 Wizard wiz = (Wizard) wizardIterator.next();
142 if (wiz.getName().equals(wizardName)) {
143 wizardName = originalWizardName + " (" + uniquifier + ")";
144 uniquifier++;
145 nameMatched = true;
146 break;
147 }
148 }
149 }
150 while (nameMatched);
151
152 if (theGame.hasStarted()) {
153 Wizard tmpWiz = new Wizard(Id.createId(), wizardName, gender);
154 ipc.connect(request.getHandle(), tmpWiz.getId());
155 ipc.send(
156 tmpWiz.getId(),
157 new MessageEvent("The game has already started.\nYou have been disconnected.\n"));
158 ipc.send(tmpWiz.getId(), new DisconnectionEvent(tmpWiz));
159 ipc.disconnect(request.getHandle());
160 }
161 else {
162 Wizard newWizard = new Wizard(Id.createId(), wizardName, gender);
163
164 ipc.connect(request.getHandle(), newWizard.getId());
165 ipc.sendToAll(new ConnectionEvent(newWizard));
166 sendMessage2(
167 newWizard.getId(),
168 "You have connected to the server.\n",
169 newWizard.getName() + " has connected to the server.\n");
170 newWizard.addPropertyChangeListener(this);
171 theGame.addWizard(newWizard);
172
173
174 newWizard.setActive(true);
175
176 }
177 }
178
179 /***
180 * Process DisconnectionRequestEvent.
181 */
182 private void processDisconnectionRequestEvent(IPCRequest request) {
183 DisconnectionRequestEvent event =
184 (DisconnectionRequestEvent) request.getGameEvent();
185 IWizard wiz = theGame.getWizard(request.getId());
186 if (wiz != null) {
187 sendMessage2(
188 wiz.getId(),
189 "You have disconnected from the server.\n",
190 wiz.getName() + " has disconnected from the server.\n");
191 ipc.sendToAll(new DisconnectionEvent(wiz));
192 ipc.disconnect(request.getHandle());
193 theGame.removeWizard(wiz);
194 }
195 else {
196 logger.warn("Could not find wizard to remove.");
197 }
198 }
199
200 /***
201 * Process MessageEvent.
202 */
203 private void processMessageEvent(IPCRequest request) {
204 MessageEvent event = (MessageEvent) request.getGameEvent();
205 IWizard wiz = theGame.getWizard(request.getId());
206 sendMessage2(
207 wiz.getId(),
208 "You say: " + event.getMessage() + "\n",
209 wiz.getName() + " says: " + event.getMessage() + "\n");
210 }
211
212 /***
213 * Process OkEvent.
214 */
215 public void processOkEvent(IPCRequest request) {
216 OkEvent event = (OkEvent) request.getGameEvent();
217 IWizard wiz = theGame.getWizard(request.getId());
218 if (wiz.isActive()) {
219 wiz.setLeftHandGesture(event.getLeftHandGesture());
220 wiz.setRightHandGesture(event.getRightHandGesture());
221 }
222 }
223
224 /***
225 * Start the Game Server.
226 * This creates a new thread and starts the thread running.
227 */
228 public void start() {
229 isRunning = true;
230 gameThread = new Thread(this, "GameThread");
231 gameThread.start();
232 }
233
234 /***
235 * Stop the Game Server.
236 * This sets <code>isRunning</code> to false which allows the <code>run</code>
237 * method to terminate. <code>stop</code> will cause the calling thread
238 * to wait until the Game Server Thread has terminated.
239 */
240 public void stop() {
241 isRunning = false;
242 try {
243 gameThread.join();
244 }
245 catch (InterruptedException e) {
246 logger.error("Unexepectedly Interrupted.", e);
247 }
248 }
249
250 /***
251 * Before the game has started we allow wizards to connect to the game.
252 * The game will start when over 50% of the wizards have ended their move
253 * and have answered "Yes" to query "Are you ready to start?".
254 */
255 private void runPreGame() {
256 if (theGame.getWizards().size() == 0) {
257 return;
258 }
259
260 }
261
262 private void beginGame() {
263 theGame.setTurn(new Turn(0, TurnType.NORMAL));
264 theGame.setGameLog(new GameLog());
265 Iterator wizardIterator = theGame.getWizards().iterator();
266 while (wizardIterator.hasNext()) {
267 Wizard wiz = (Wizard) wizardIterator.next();
268 sendMessage2(
269 wiz.getId(),
270 "You advance confidently into the arena. The referee casts the formal Dispel Magic and Anti-Spell on you....\n",
271 wiz.getName()
272 + " strides defiantly into the arena. The referee casts the formal Dispel Magic and Anti-Spell on "
273 + wiz.getGender().pro_him()
274 + "....\n");
275 }
276 }
277
278 private void runTurn() {
279
280 }
281
282 /***
283 * Send a message to everyone.
284 */
285 public void sendMessage(String message) {
286 ipc.sendToAll(new MessageEvent(message));
287 }
288
289 /***
290 * Send a message to one Id and another message to everyone else.
291 */
292 public void sendMessage2(
293 Id id1,
294 String messageForID1,
295 String messageForEveryoneElse) {
296 sendMessage3(id1, messageForID1, null, null, messageForEveryoneElse);
297 }
298
299 /***
300 * Send a message to one Id, a message to another Id, and a message to everyone else.
301 */
302 public void sendMessage3(
303 Id id1,
304 String messageForID1,
305 Id id2,
306 String messageForID2,
307 String messageForEveryoneElse) {
308 MessageEvent id1Event = new MessageEvent(messageForID1);
309 MessageEvent id2Event = new MessageEvent(messageForID2);
310 MessageEvent everyoneElseEvent = new MessageEvent(messageForEveryoneElse);
311
312 Iterator wizardIterator = theGame.getWizards().iterator();
313 while (wizardIterator.hasNext()) {
314 Wizard wiz = (Wizard) wizardIterator.next();
315 if (wiz.getId().equals(id1)) {
316 ipc.send(wiz.getId(), id1Event);
317 }
318 else
319 if (wiz.getId().equals(id2)) {
320 ipc.send(wiz.getId(), id2Event);
321 }
322 else {
323 ipc.send(wiz.getId(), everyoneElseEvent);
324 }
325 }
326 }
327
328 }