// GameServer v1.0 Java Application // Implements GSP/1.0 // Coded by: Andrew T. Graham // Based on an idea by: Bryan E. Beyer // // One Server, One Protocol, MultiGame, MultiPlayer // Classes included: GameServer, Game, and Player // import java.net.*; import java.io.*; import java.util.*; class GameServer extends Thread { public final static int DEFAULT_PORT = 7779; int myPort = 0; int GameId = 0; int PlayerId = 0; Vector Games = new Vector(1); Vector AllPlayers = new Vector(10); Game chatRoom = addGame("Chat Room"); protected ServerSocket serverSock; Game getChatRoom() { return chatRoom; } public String getVersion() { return "GameServer v0.1"; } GameServer(int port) { if(port == 0) port = DEFAULT_PORT; myPort = port; try { serverSock = new ServerSocket(port, 12); } catch (Exception e) { System.out.println("Exception caught creating server socket. " +e); System.exit(1); } System.out.println("GameServer: Listening on port "+port); this.start(); } public static void main(String [] args) { int port = 0; if(args.length == 1) { try { port = Integer.parseInt(args[0]); } catch (NumberFormatException e) { port = 0; } } new GameServer(port); } public void run() { while(true) { try { while(true) { Socket playerSock = serverSock.accept(); Player p = new Player(PlayerId++, playerSock, this); System.out.println("Connect from "+ playerSock.toString()); // playerSock.getInetAddress().getHostAddress()); } } catch (Exception e) { System.out.println("Caught error on server socket accept."); System.out.println(" "+e); e.printStackTrace(); System.out.println("Ignoring."); } } } public synchronized Game addGame(String name, int MaxPlayers, String type) { Game G = new Game(GameId++, name, type, MaxPlayers, this); Games.addElement(G); return G; } public synchronized void removeGame(Game g) { if(Games.contains(g)) { Games.removeElement(g); g.endGame(); } } public synchronized Game addGame(String name) { return addGame(name, -1, null); } public synchronized Game addGame(String name, String type) { return addGame(name, -1, type); } public synchronized void addGame(Player p, String name, String type, int MaxPlayers) { Game G = addGame(name, MaxPlayers, type); if(G != null) { G.setOwner(p); sendMessage(G.genericData("CREATED")); } else { p.sendMessage("FAILED\tCREATE"); } } public synchronized void addPlayerToGame(Player p, Game g) { g.addPlayer(p); } public synchronized void listGames(Player p) { listGames(p,p.getGameType()); } public synchronized void listGames(Player p, String gametype) { int i; Game g; for(i = 0; i < Games.size(); i++) { g = (Game) Games.elementAt(i); if(g.getGameType() == null || g.getGameType().equals("null") || g.getGameType().equals(gametype)) { p.sendMessage(g.getListStr()); } } } public synchronized void purgeGamesOwnedBy(Player p) { int i; Game g; for(i = 0; i < Games.size(); i++) { g = (Game) Games.elementAt(i); if(g.getOwner() == p) removeGame(g); } } public synchronized Game getGame(String GameId) { int i; boolean Found = false; Game g = null; i = Games.size(); if(i > 0) while((i-- > 0) && !Found) { g = (Game) Games.elementAt(i); Found = g.getID().equals(GameId); } if(Found) { return g; } return null; } public synchronized boolean addPlayerToGame(Player p, String GameId) { Game g = getGame(GameId); if(g != null) { addPlayerToGame(p,g); return true; } return false; } public synchronized void removePlayerFromGame(Player p) { int i; boolean Found = false; Game g; if((g = p.getGame()) != null) { g.removePlayer(p); if(g != chatRoom) chatRoom.addPlayer(p); else p.disconnect(); } } public synchronized void addPlayer(Player p) { if(!AllPlayers.contains(p)) AllPlayers.addElement(p); } public synchronized void removePlayer(Player p) { if(AllPlayers.contains(p)) AllPlayers.removeElement(p); if(p.getGame() != null) p.getGame().removePlayer(p); // if(p.getGame() == chatRoom) p.getGame().removePlayer(p); purgeGamesOwnedBy(p); } public synchronized void listPlayers(Player p) { int i; Player pl; i = AllPlayers.size(); if(i > 0) while(i-- > 0) { pl = (Player) AllPlayers.elementAt(i); p.sendMessage(pl.getListStr()); } } public synchronized void sendMessage(String msg) { int i; Game g; i = Games.size(); if(i > 0 ) while(i-- > 0) { g = (Game) Games.elementAt(i); g.sendMessage(msg); } } } ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// class Game extends Object { private Vector Players = new Vector(0); private boolean started = false; private Player owner; private Player whoseTurn; private String gameName; private String gameID; private int maxPlayers; private String gameType; private GameServer gameServer; // constructor Game(int GameId, String name, String typ, int MaxPlay, GameServer server) { gameID = ""+GameId; gameName = name; gameType = typ; maxPlayers = MaxPlay; gameServer = server; whoseTurn = null; } public String getName() { return gameName; } public String getID() { return gameID; } public boolean setOwner(Player p) { if(owner == null) { owner = p; return true; } return false; } public Player getOwner() { return owner; } public boolean isStarted() { return started; } public boolean setStarted() { if(!started) { started = true; sendMessage("STARTGAME"); return true; } return false; } public int getMaxPlayers() { return maxPlayers; } public String getGameType() { return gameType; } public String genericData(String cmd) { return cmd+"\t"+getGameType()+"\t"+ getID()+"\t"+ getMaxPlayers()+"\t"+ isStarted()+"\t"+ getName()+"\t"+(getOwner() != null ? (getOwner().getID()) : "null"); } public String getListStr() { return genericData("GAME"); } public String getIdent() { return getName()+"<"+getID()+">"; } // add a player to the game and inform other threads of the addition public synchronized void addPlayer(Player p) { if(!Players.contains(p) && !isStarted()) { if(p.getGame() != null) p.getGame().removePlayer(p); Players.addElement(p); p.setGame(this); p.sendMessage(getListStr()); sendMessage("JOINED\t"+p.getID()+"\t"+getID()); return; } p.sendMessage("FAILED\tJOIN"); } public synchronized void removePlayer(Player p) { if(Players.contains(p)) { p.setGame(null); Players.removeElement(p); sendMessage("PLAYERQUIT\t"+p.getID()+"\t"+getID()); // if(p.getGame() == null) { // gameServer.addPlayerToGame(p,gameServer.getChatRoom()); // } if(isStarted() || p == owner) endGame(); } } public synchronized void sendMessage(String msg) { int i; Player p; i = Players.size(); if(i > 0) while(i-- > 0) { p = (Player) Players.elementAt(i); p.sendMessage(msg); } } public synchronized Player findPlayer(String pid) { int i; Player p; i = Players.size(); if(i > 0) while(i-- > 0) { p = (Player) Players.elementAt(i); if(p.getID() == pid) return p; } return null; } public synchronized void sendToMaster(String pid, String msg) { getOwner().sendMessage("TOMASTER\t"+pid+"\t"+msg); } public synchronized void sendToClient(String pid, String msg) { Player p = findPlayer(pid); if(p == null) return; p.sendMessage("FROMMASTER\t"+msg); } public synchronized void listPlayers(Player p) { int i; Player pl; i = Players.size(); if(i > 0) while(i-- > 0) { pl = (Player) Players.elementAt(i); p.sendMessage(pl.getListStr()); } } public synchronized void endGame() { int i; Player p; i = Players.size(); if(i > 0) while(i-- > 0) { p = (Player) Players.elementAt(i); if(isStarted()) p.sendMessage("GAMEOVER"); Players.removeElement(p); gameServer.removePlayerFromGame(p); } gameServer.sendMessage("DESTROYED\t"+getID()); gameServer.removeGame(this); } } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// class Player extends Object implements Runnable { private String name; private String gameType; private String playerID; private Socket playerSock; private DataInputStream inSock; private PrintStream outSock; private Game myGame; private GameServer gameServer; private Thread mainThread; private Thread readerThread; private Thread writerThread; private int State = 0; Player(int PlayerId, Socket sock, GameServer gs) { playerSock = sock; gameServer = gs; playerID = ""+PlayerId; try { inSock = new DataInputStream(playerSock.getInputStream()); outSock = new PrintStream(playerSock.getOutputStream()); } catch (Exception e) { try { playerSock.close(); } catch(Exception e2) { } print("Error getting socket streams. "+e); return; } mainThread = new Thread(this, "Player("+getID()+")"); mainThread.start(); } public void disconnect() { print("Disconnected"); sendMessage("DISCONNECTED"); try { playerSock.close(); } catch (Exception e) { }; gameServer.removePlayer(this); gameServer.sendMessage("PLAYERLEFT\t"+getID()); } public void setName(String n) { name = n; } public String getName() { return name; } public String getID() { return playerID; } public String getIdent() { return getName()+"<"+getID()+">"; } public Game getGame() { return myGame; } public void setGame(Game g) { myGame = g; } public void setGameType(String GT) { gameType = GT; } public String getGameType() { return gameType; } public String getListStr() { String gid; if(myGame == null) gid = "0"; else gid = myGame.getID(); return "PLAYER\t"+getID()+"\t"+getName()+"\t"+gid; } public void sendMessage(String s) { outSock.println(s); } public void print(String msg) { System.out.println(getIdent()+" "+msg); } public void sendError(String err) { sendMessage("FAILED\t"+err); } public String readLine() throws IOException { return inSock.readLine(); } public void run() { String str; gameServer.addPlayer(this); sendMessage("GSP/1.0\t" + getID()); State = 0; try { boolean done = false; while (!done) { str = readLine(); print("< "+str); done = parseInput(str); } disconnect(); } catch (Exception e) { print("Caught "+e+" in run()"); e.printStackTrace(); disconnect(); } } int toInt(String s) { int number = -1; try { number = Integer.parseInt(s); } catch (NumberFormatException e) { number = -1; } return number; } public boolean parseInput(String s) { if(s == null) { return true; } StringTokenizer ST = new StringTokenizer(s,"\t"); String token; int len = ST.countTokens(); if(len == 0) { return false; } if(State == 0) { if(len < 3) { return true; } String proto = ST.nextToken(); String gametype = ST.nextToken(); String name = ST.nextToken(); if(proto.equals("GSP/1.0")) { setName(name); setGameType(gametype); State = 1; gameServer.sendMessage(getListStr()); gameServer.addPlayerToGame(this,gameServer.getChatRoom()); return false; } sendError(s); return true; } String tok = ST.nextToken(); if(tok.equals("BYE!") && !ST.hasMoreTokens()) { sendMessage("BYE!"); return true; } if(tok.equals("LIST") && ST.hasMoreTokens()) { String tok2 = ST.nextToken(); if(tok2.equals("GAMES")) { if(!ST.hasMoreTokens()) { gameServer.listGames(this); } else { gameServer.listGames(this,ST.nextToken()); } return false; } else if(tok2.equals("PLAYERS")) { if(!ST.hasMoreTokens()) { gameServer.listPlayers(this); return false; } else { Game g = gameServer.getGame(ST.nextToken()); if(g != null) { g.listPlayers(this); return false; } } } else if(tok2.equals("ALL")) { gameServer.listPlayers(this); gameServer.listGames(this); } } if(tok.equals("MSG") && ST.hasMoreTokens()) { myGame.sendMessage("MSG\t"+getIdent()+"\t"+ST.nextToken()); return false; } if(tok.equals("CREATE")) { int maxplayers = -1; if(ST.hasMoreTokens()) maxplayers = toInt(ST.nextToken()); //String gamename = ST.nextToken(); //gameServer.addGame(this,gamename,getGameType(),-1); gameServer.addGame(this,getName(),getGameType(),maxplayers); return false; } if(tok.equals("JOIN") && ST.hasMoreTokens()) { gameServer.addPlayerToGame(this,ST.nextToken()); return false; } if(tok.equals("STARTGAME") && !ST.hasMoreTokens()) { if((myGame != null) && (myGame.getOwner() == this)) { if(myGame.setStarted()) return false; } } if(tok.equals("DESTROY") && ST.hasMoreTokens()) { Game G = gameServer.getGame(ST.nextToken()); if(G != null && G.getOwner() == this) { G.endGame(); } } if(tok.equals("SENDTOMASTER") && ST.hasMoreTokens()) { // SENDTOMASTER xx xxx xxx xxx xxx String msg = ST.nextToken(); while(ST.hasMoreTokens()) msg += "\t" + ST.nextToken(); myGame.sendToMaster(getID(), msg); return false; } if(tok.equals("SENDTOCLIENT") && ST.hasMoreTokens()) { // SENDTOCLIENT xx xxx xxx xxx xxx String pid = ST.nextToken(); if(ST.hasMoreTokens()) { String msg = ST.nextToken(); while(ST.hasMoreTokens()) msg += "\t" + ST.nextToken(); myGame.sendToClient(getID(), msg); return false; } } if(tok.equals("TOALL")) { myGame.sendMessage(s); // just send the thing verbatim... return false; } sendError(tok); return false; } }