import java.io.*; import java.util.*; import java.net.*; public class BlobWarsServer { public static final int PORT = 38491; private ServerSocket m_socket; private BlobWarsWorld m_world; private Vector m_clientUpdates; private HashMap m_socketToPlayerName; private HashMap m_lastPlayers; private HashMap m_lastShots; public static void main(String[] args) { BlobWarsServer bws = new BlobWarsServer(); bws.mainloop(); } public BlobWarsServer() { m_world = new BlobWarsWorld(); m_clientUpdates = new Vector(); m_socketToPlayerName = new HashMap(); try { m_socket = new ServerSocket(PORT); } catch (Exception e) { e.printStackTrace(); return; } } private class ClientUpdate { public Socket socket; public String message; } public void mainloop() { if (m_socket == null) return; new Thread(new ServerGameLoop()).start(); /* listen loop to accept new connections */ for (;;) { Socket client; try { client = m_socket.accept(); } catch (Exception e) { System.out.println("Socket error!"); e.printStackTrace(); break; } /* handle the client in a separate thread */ Thread t = new Thread(new ClientHandler(client)); t.start(); } } private void processClientUpdate(ClientUpdate cu) { StringTokenizer st = new StringTokenizer(cu.message, ":"); Vector tokens = new Vector(); while (st.hasMoreTokens()) { tokens.add(st.nextToken()); } String[] arr = tokens.toArray(new String[1]); if (arr.length < 2) return; if (arr[0].equals("NAME")) { m_world.addPlayer(arr[1]); m_socketToPlayerName.put(cu.socket, arr[1]); return; } /* the rest of the commands all require a player to be registered */ if (!m_socketToPlayerName.containsKey(cu.socket)) return; String playerName = m_socketToPlayerName.get(cu.socket); if (arr[0].equals("SHOOT")) { m_world.shoot(playerName); } else if (arr[0].equals("UP")) { m_world.moveUp(playerName); } else if (arr[0].equals("DOWN")) { m_world.moveDown(playerName); } else if (arr[0].equals("LEFT")) { m_world.moveLeft(playerName); } else if (arr[0].equals("RIGHT")) { m_world.moveRight(playerName); } } private class ServerGameLoop implements Runnable { public void run() { for (;;) { try { Thread.sleep(45); } catch (InterruptedException ie) { System.out.println("ServerGameLoop: interrupted!"); return; } /* apply changes from clients */ synchronized (m_clientUpdates) { for (ClientUpdate cu : m_clientUpdates) { processClientUpdate(cu); } m_clientUpdates.clear(); } m_world.step(); /* push updates to clients */ HashMap pushPlayers = new HashMap(); HashMap pushShots = new HashMap(); if (m_lastPlayers == null) pushPlayers.putAll(m_world.getPlayers()); else { HashMap players = m_world.getPlayers(); for (String name : players.keySet()) { if (!m_lastPlayers.containsKey(name)) pushPlayers.put(name, players.get(name)); else if (!players.get(name).equals( m_lastPlayers.get(name))) pushPlayers.put(name, players.get(name)); } } if (m_lastShots == null) pushShots.putAll(m_world.getShots()); else { HashMap shots = m_world.getShots(); for (Integer shotid : shots.keySet()) { if (!m_lastShots.containsKey(shotid)) pushShots.put(shotid, shots.get(shotid)); else if (!shots.get(shotid).equals( m_lastShots.get(shotid))) pushShots.put(shotid, shots.get(shotid)); } } /* write updated info to each client */ String sendLine = ""; for (Player p : pushPlayers.values()) { sendLine += "PLAYER:" + p + "\n"; } for (Shot s : pushShots.values()) { sendLine += "SHOT:" + s + "\n"; } synchronized (m_socketToPlayerName) { for (Socket client : m_socketToPlayerName.keySet()) { try { BufferedWriter br = new BufferedWriter( new OutputStreamWriter( client.getOutputStream())); br.write(sendLine, 0, sendLine.length()); } catch (Exception e) { e.printStackTrace(); } } } } } } private class ClientHandler implements Runnable { private Socket m_socket; public ClientHandler(Socket socket) { m_socket = socket; System.out.println("Incoming connection from " + m_socket.getInetAddress().getHostAddress()); } public void run() { BufferedReader br; try { br = new BufferedReader( new InputStreamReader(m_socket.getInputStream())); } catch (IOException ioe) { ioe.printStackTrace(); return; } for (;;) { String line; try { line = br.readLine(); } catch (IOException ioe) { // TODO: remove this line to not print stack trace for // a client that disconnects, and remove socket from // HashMap after for() loop ioe.printStackTrace(); break; } System.out.println("SERVER GOT LINE: " + line); if (line.equals("QUIT")) { synchronized (m_socketToPlayerName) { if (m_socketToPlayerName.containsKey(m_socket)) m_socketToPlayerName.remove(m_socket); try { m_socket.close(); } catch (Exception e) {} } break; } ClientUpdate cu = new ClientUpdate(); cu.socket = m_socket; cu.message = line; synchronized (m_clientUpdates) { m_clientUpdates.add(cu); } } } } }