1 package net.sourceforge.simplegamenet.framework.transport;
2
3 import java.io.IOException;
4 import java.io.Serializable;
5 import java.util.HashMap;
6 import java.util.Iterator;
7 import java.util.Map;
8 import net.sourceforge.simplegamenet.framework.GameFactoryManager;
9 import net.sourceforge.simplegamenet.framework.model.ChatMessage;
10 import net.sourceforge.simplegamenet.framework.model.ServerEngineImpl;
11 import net.sourceforge.simplegamenet.specs.model.ServerEngine;
12 import net.sourceforge.simplegamenet.specs.to.GameSettings;
13 import net.sourceforge.simplegamenet.specs.to.PlayerSettings;
14
15 public class ServerModem extends Modem {
16
17 private ServerEngineImpl serverEngineImpl;
18 private ClassLoader gamesClassLoader;
19
20 private ServerListener serverListener;
21 private HashMap connectionMap = new HashMap(8);
22
23 private int unprocessedGameEndsAmount = 0;
24
25 public ServerModem(ServerEngineImpl serverEngine, int port) throws IOException {
26 taskQueue = new TaskQueue(false);
27 this.serverEngineImpl = serverEngine;
28 gamesClassLoader = GameFactoryManager.getInstance().getGamesClassLoader();
29 serverListener = new ServerListener(this, port);
30 taskQueue.start();
31 serverListener.start();
32 }
33
34 public void processPacketInServerThread(Integer playerID, Packet packet) {
35 taskQueue.addTask(new ServerPacketTask(this, playerID, packet));
36 }
37
38 public void processPacket(Integer playerID, Packet packet) {
39
40 if (!connectionMap.containsKey(playerID)) {
41 return;
42 }
43 switch (packet.getPacketCode()) {
44
45 case CON_CLIENT_PING:
46
47 break;
48 case CON_CLIENT_PONG:
49
50 break;
51
52 case CHAT_ASK_MESSAGE:
53 if (!(packet.getData() instanceof ChatMessage)) {
54 kickProtocolViolatingPlayer(playerID);
55 return;
56 }
57 ChatMessage chatMessage = (ChatMessage) packet.getData();
58 if (chatMessage.getPlayerID() == null
59 || !playerID.equals(chatMessage.getPlayerID())) {
60 kickProtocolViolatingPlayer(playerID);
61 return;
62 }
63 if (serverEngineImpl.receiveChatMessage(playerID, chatMessage)) {
64 ((ServerConnection) connectionMap.get(playerID)).sendPacket(
65 new Packet(E_CHAT_MESSAGE, null));
66 }
67 break;
68
69 case GAME_CHANGE_GAME_SETTINGS:
70 if (!(packet.getData() instanceof GameSettings)) {
71 kickProtocolViolatingPlayer(playerID);
72 return;
73 }
74 GameSettings gameSettings = (GameSettings) packet.getData();
75 try {
76 serverEngineImpl.changeGameSettings(gameSettings);
77 } catch (IllegalStateException e) {
78 ((ServerConnection) connectionMap.get(playerID)).sendPacket(
79 new Packet(E_GAME_CHANGE_GAME_SETTINGS_GAME_IN_PROGRESS, e));
80 } catch (IllegalArgumentException e) {
81 ((ServerConnection) connectionMap.get(playerID)).sendPacket(
82 new Packet(E_GAME_CHANGE_GAME_SETTINGS_NOT_ACCEPTED, e));
83 }
84 break;
85
86 case GAME_CHANGE_PLAYER_SETTINGS:
87 if (!(packet.getData() instanceof PlayerSettings)) {
88 kickProtocolViolatingPlayer(playerID);
89 return;
90 }
91 PlayerSettings playerSettings = (PlayerSettings) packet.getData();
92 try {
93 if (!playerID.equals(playerSettings.getPlayerID())) {
94 throw new IllegalArgumentException();
95 }
96 serverEngineImpl.changePlayerSettings(playerSettings);
97 } catch (IllegalStateException e) {
98 ((ServerConnection) connectionMap.get(playerID)).sendPacket(
99 new Packet(E_GAME_CHANGE_PLAYER_SETTINGS_GAME_IN_PROGRESS, e));
100 } catch (IllegalArgumentException e) {
101 ((ServerConnection) connectionMap.get(playerID)).sendPacket(
102 new Packet(E_GAME_CHANGE_PLAYER_SETTINGS_NOT_ACCEPTED, e));
103 }
104 break;
105
106 case CON_CLIENT_CON_CLOSE:
107 sendToAllExceptOne(new Packet(CON_REMOVE_PLAYER_BY_LEFT, playerID), playerID);
108 removePlayer(playerID, RemovePlayerType.LEFT);
109 break;
110
111 case GAME_CLIENT_START_GAME:
112 try {
113 serverEngineImpl.startGame();
114 } catch (IllegalStateException e) {
115 ((ServerConnection) connectionMap.get(playerID)).sendPacket(
116 new Packet(E_GAME_CLIENT_START_GAME, e));
117 }
118 break;
119
120 case GAME_CLIENT_SEND_DATA:
121 serverEngineImpl.receiveData(playerID, packet.getData());
122 break;
123
124 case GAME_CLIENT_ABORT_GAME:
125 try {
126 serverEngineImpl.abortGame();
127 } catch (IllegalStateException e) {
128 ((ServerConnection) connectionMap.get(playerID)).sendPacket(
129 new Packet(E_GAME_CLIENT_ABORT_GAME, e));
130 }
131 break;
132
133 case GAME_CLIENT_CONFIRM_GAME_STOPPING:
134 gameEnded(playerID);
135 break;
136
137 case GAME_CLIENT_CONFIRM_GAME_ABORTING:
138 gameEnded(playerID);
139 break;
140
141 case E_CON_SERVER_VIOLATION:
142 sendToAllExceptOne(new Packet(CON_REMOVE_PLAYER_BY_SERVER_VIOLATION, playerID),
143 playerID);
144 removePlayer(playerID, RemovePlayerType.PROTOCOL_VIOLATION_LEFT);
145 break;
146
147 default:
148 kickProtocolViolatingPlayer(playerID);
149 }
150 }
151
152
153
154
155
156
157
158 public void sendChatMessage(Integer playerID, ChatMessage chatMessage) {
159 if (connectionMap.containsKey(playerID)) {
160 ((ServerConnection) connectionMap.get(playerID)).sendPacket(
161 new Packet(CHAT_GRANT_MESSAGE, chatMessage));
162 } else {
163 throw new IllegalArgumentException("Invalid playerID: " + playerID);
164 }
165 }
166
167 public void sendChatMessage(ChatMessage chatMessage) {
168 sendToAll(new Packet(CHAT_GRANT_MESSAGE, chatMessage));
169 }
170
171 public void updateGameSettings(GameSettings gameSettings) {
172 sendToAll(new Packet(GAME_UPDATE_GAME_SETTINGS, gameSettings));
173 }
174
175 public void addNewConnectionInEventThread(NewConnectionData newConnectionData) {
176 taskQueue.addTask(new NewConnectionTask(this, newConnectionData));
177 }
178
179 public void addNewConnection(NewConnectionData newConnectionData) {
180 LoginData loginData = null;
181 try {
182 loginData = serverEngineImpl.createPlayer(PlayerSettings.USER,
183 newConnectionData.getNickname());
184 } catch (IllegalStateException e) {
185 try {
186 newConnectionData.getObjectOutputStream().writeObject(new Packet(E_CON_LOGIN,
187 e));
188 } catch (IOException innerException) {
189 innerException.printStackTrace();
190 }
191 try {
192 newConnectionData.getSocket().close();
193 } catch (IOException innerException) {
194 innerException.printStackTrace();
195 }
196 return;
197 }
198 ServerConnection serverConnection = new ServerConnection(this,
199 loginData.getPlayerID(), newConnectionData.getSocket(),
200 newConnectionData.getObjectInputStream(),
201 newConnectionData.getObjectOutputStream());
202 serverConnection.sendPacket(new Packet(CON_LOGIN_DATA, loginData));
203 serverConnection.start();
204 PlayerSettings newPlayerSettings = null;
205 for (int i = 0; i < loginData.getPlayerSettingsArray().length; i++) {
206 if (loginData.getPlayerID().equals(loginData.getPlayerSettingsArray()[i].getPlayerID())) {
207 newPlayerSettings = loginData.getPlayerSettingsArray()[i];
208 break;
209 }
210 }
211 sendToAll(new Packet(CON_ADD_PLAYER, newPlayerSettings));
212 connectionMap.put(loginData.getPlayerID(), serverConnection);
213 serverEngineImpl.playerAdded(loginData.getPlayerID());
214 }
215
216 public void updatePlayerSettings(PlayerSettings playerSettings) {
217 sendToAll(new Packet(GAME_UPDATE_PLAYER_SETTINGS, playerSettings));
218 }
219
220 public void kickPlayer(Integer playerID) {
221 ((ServerConnection) connectionMap.get(playerID)).sendPacket(new Packet(CON_KICK, null));
222 sendToAllExceptOne(new Packet(CON_REMOVE_PLAYER_BY_KICK, playerID), playerID);
223 removePlayer(playerID, RemovePlayerType.KICKED);
224 }
225
226 public void banPlayer(Integer playerID) {
227 ServerConnection serverConnection = (ServerConnection) connectionMap.get(playerID);
228 serverListener.addBannedInetAddress(serverConnection.getInetAddress());
229 serverConnection.sendPacket(new Packet(CON_BAN, null));
230 sendToAllExceptOne(new Packet(CON_REMOVE_PLAYER_BY_BAN, playerID), playerID);
231 removePlayer(playerID, RemovePlayerType.BANNED);
232 }
233
234 public void kickProtocolViolatingPlayer(Integer playerID) throws IllegalArgumentException {
235 if (connectionMap.containsKey(playerID)) {
236 ((ServerConnection) connectionMap.get(playerID)).sendPacket(
237 new Packet(E_CON_CLIENT_VIOLATION, null));
238 sendToAllExceptOne(new Packet(CON_REMOVE_PLAYER_BY_CLIENT_VIOLATION, playerID),
239 playerID);
240 removePlayer(playerID, RemovePlayerType.PROTOCOL_VIOLATION_KICKED);
241 } else {
242 throw new IllegalArgumentException("Invalid playerID: " + playerID);
243 }
244 }
245
246 public void processDisconnectionInEventThread(Integer playerID) {
247 taskQueue.addTask(new ServerDisconnectionTask(this, playerID));
248 }
249
250 public void processDisconnection(Integer playerID) {
251
252
253 if (!connectionMap.containsKey(playerID)) {
254 return;
255 }
256 sendToAllExceptOne(new Packet(CON_REMOVE_PLAYER_BY_DISCONNECTION, playerID),
257 playerID);
258 removePlayer(playerID, RemovePlayerType.DISCONNECTED);
259 }
260
261 private void removePlayer(Integer playerID, int removePlayerType) {
262 ((ServerConnection) connectionMap.remove(playerID)).close();
263 serverEngineImpl.removePlayer(playerID, removePlayerType);
264 }
265
266 public void gameStarted() {
267 sendToAll(new Packet(GAME_SERVER_GAME_STARTED, null));
268 }
269
270 public void sendData(Integer playerID, Serializable data) throws IllegalArgumentException {
271 if (connectionMap.containsKey(playerID)) {
272 ((ServerConnection) connectionMap.get(playerID)).sendPacket(
273 new Packet(GAME_SERVER_SEND_DATA, data));
274 } else {
275 throw new IllegalArgumentException("Invalid playerID: " + playerID);
276 }
277 }
278
279 public void sendData(Serializable data) {
280 sendToAll(new Packet(GAME_SERVER_SEND_DATA, data));
281 }
282
283 public void gameStopping() {
284 sendGameEndToAll(new Packet(GAME_SERVER_GAME_STOPPING, null));
285 }
286
287 public void gameAborting() {
288 sendGameEndToAll(new Packet(GAME_SERVER_GAME_ABORTING, null));
289 }
290
291 public void gameEnded(Integer playerID) throws ClassCastException {
292 if (connectionMap.containsKey(playerID)) {
293 ((ServerConnection) connectionMap.get(playerID)).setGameEndUnprocessed(false);
294 }
295 unprocessedGameEndsAmount--;
296 if (unprocessedGameEndsAmount <= 0) {
297 serverEngineImpl.gameEnded();
298 sendToAll(new Packet(GAME_SERVER_GAME_ENDED, null));
299 }
300 }
301
302 ServerEngine getServerEngineImpl() {
303 return serverEngineImpl;
304 }
305
306 private void sendToAll(Packet packet) {
307 Iterator iterator = connectionMap.entrySet().iterator();
308 while (iterator.hasNext()) {
309 ((ServerConnection) ((Map.Entry) iterator.next()).getValue())
310 .sendPacket(packet);
311 }
312 }
313
314 private void sendToAllExceptOne(Packet packet, Integer playerID) {
315 Iterator iterator = connectionMap.entrySet().iterator();
316 while (iterator.hasNext()) {
317 Map.Entry mapEntry = (Map.Entry) iterator.next();
318 if (!playerID.equals((Integer) mapEntry.getKey())) {
319 ((ServerConnection) mapEntry.getValue()).sendPacket(packet);
320 }
321 }
322 }
323
324 private void sendGameEndToAll(Packet packet) {
325 unprocessedGameEndsAmount = connectionMap.size();
326 Iterator iterator = connectionMap.entrySet().iterator();
327 while (iterator.hasNext()) {
328 ServerConnection serverConnection =
329 (ServerConnection) ((Map.Entry) iterator.next()).getValue();
330 serverConnection.setGameEndUnprocessed(true);
331 serverConnection.sendPacket(packet);
332 }
333 }
334
335 public void closeServerInServerThread() {
336 taskQueue.addTask(new Runnable() {
337 public void run() {
338 closeServer();
339 }
340 });
341 }
342
343 public void closeServer() {
344 serverListener.close();
345 taskQueue.close();
346 for (Iterator it = connectionMap.entrySet().iterator(); it.hasNext();) {
347 ServerConnection serverConnection =
348 (ServerConnection) ((Map.Entry) it.next()).getValue();
349 serverConnection.sendPacket(new Packet(CON_SERVER_CON_CLOSE, null));
350 serverConnection.close();
351 }
352 serverEngineImpl.hostedGameQuit();
353 }
354
355 }