View Javadoc

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          // Do not process packets (received from the taskQueue) of players already removed
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 //   void ping(Integer playerID) {
153 //   }
154 //
155 //   void ping() {
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         // Do not process disconnections (received from the taskQueue) of players already
252         // removed
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 }