// Server for Nebula Cards
// James Ranson
// July 1999
package net.sf.nebulacards;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.BindException;
import javax.swing.JOptionPane;
import net.sf.nebulacards.comm.ComManager;
import net.sf.nebulacards.comm.GameRunner;
import net.sf.nebulacards.comm.Serv;
import net.sf.nebulacards.main.NebulaUI;
import net.sf.nebulacards.main.Rules;
import net.sf.nebulacards.ui.Gui;
import net.sf.nebulacards.ui.SpadesComp;
/**
* FIXME *01. make setup graphical
* FIXME *02. ensure cards draw appropriately
* FIXME *03. ensure command-line parameters work (and can be used for automation
* FIXME *04. allow saving to config file
*
* @author bcmartin
*/
public class STFront {
public static void main(String[] args) throws Exception {
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
String rulesString = null;
String portString = null;
boolean singlePlayerGame = false;
// parse command line
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-p")) {
try {
portString = args[++i];
} catch (Exception e) {
portString = null;
}
continue;
}
if (args[i].equals("-r")) {
try {
rulesString = args[++i];
} catch (Exception e) {
rulesString = null;
}
continue;
}
if (args[i].equals("-s")) {
singlePlayerGame = true;
}
}
// open rules class
if (rulesString == null) {
System.err.println("Please specify a rule set [Spades]: ");
try {
rulesString = in.readLine();
} catch (IOException e) {}
if (rulesString.equals("")) rulesString = "Spades";
}
if (rulesString.indexOf('.') < 0) {
rulesString = "net.sf.nebulacards.rules." + rulesString;
}
Class ruleSet;
try {
ruleSet = Class.forName(rulesString);
} catch (Exception e) {
System.err.println("Can't open rules: \"" + rulesString + "\"");
try {
Thread.sleep(4000);
} catch (Exception f) {
}
return;
}
// bind socket
int port;
if (portString == null) {
System.err.print("Listening port [8802]: ");
System.err.flush();
String s = null;
try {
s = in.readLine();
} catch (IOException e) {
}
if (s.equals(""))
port = 8802;
else
port = Integer.parseInt(s);
} else {
port = Integer.parseInt(portString);
}
ComManager cm = new ComManager(4);
GameRunner gr = new GameRunner((Rules) ruleSet.newInstance(), cm);
try {
Serv server = new Serv(gr, cm, port);
server.start();
} catch (BindException e) {
crash("Unable to create server at port " + port
+ ": " + e.getMessage());
}
System.err.println("You now have the opportunity to load clients.");
System.err
.println("The game needs 4 clients to start; they can be " +
"loaded");
System.err
.println("from this program, as separate programs, or even on");
System.err
.println("other computers. Loading clients from this program");
System.err.println("will improve the speed of the game.\n\n");
getClients(gr, cm, singlePlayerGame);
System.err.println("Game is over. Waiting for clients to shut down.");
System.err.println("If this takes more than ten seconds, just close " +
"this window.");
}
public static void crash(String message) {
System.err.println(message);
JOptionPane.showMessageDialog(null, message, "Fatal error",
JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
public static void prompt() {
System.err.println("1) Start a human interface.");
System.err.println("2) Start a Spades computer.");
System.err.println("3) Start another client.");
System.err.println("4) Boot a player from the game.");
}
public static void getClients(GameRunner gr, ComManager cm,
boolean singlePlayerGame) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
if (singlePlayerGame) {
startClient(in, "net.sf.nebulacards.ui.Gui", gr, cm);
}
while (gr.isAlive()) {
// TODO z-temporary code
if (gr.howMany() == 4) {
return;
}
if (singlePlayerGame) {
startClient(in, "net.sf.nebulacards.ui.SpadesComp", gr, cm);
continue;
}
prompt();
String ins = null;
try {
ins = in.readLine();
} catch (IOException e) {
break;
}
// If we get an EOF, then the user doesn't want to enter any more
// commands, so we can just join the server thread.
if (ins == null) {
break;
}
if (ins.equals("1")) {
startClient(in, Gui.class.getName(), gr, cm);
}
if (ins.equals("2")) {
startClient(in, SpadesComp.class.getName(), gr, cm);
}
if (ins.equals("3")) {
startClient(in, null, gr, cm);
}
if (ins.equals("4")) {
bootClient(in, gr, cm);
}
}
}
public static void startClient(BufferedReader in, String ifname,
GameRunner gr, ComManager cm) {
String cname = null;
System.err.print("Player's name? ");
System.err.flush();
try {
// FIXME fix names
//cname = in.readLine();
cname = "A";
if (ifname == null) {
System.err.print("Which Client?: ");
System.err.flush();
ifname = in.readLine();
}
} catch (IOException e) {
return;
}
Class UI = null;
try {
UI = Class.forName(ifname);
} catch (ClassNotFoundException e) {
System.err.println("Error: Cannot open interface: " + ifname);
try {
Thread.sleep(3000);
} catch (InterruptedException f) {
}
return;
}
try {
NebulaUI target = (NebulaUI) UI.newInstance();
synchronized (cm) {
int where = cm.add(target);
gr.setName(where, cname);
gr.reconnect(where);
cm.notifyAll();
}
gr.broadcastTable();
System.err.println("Client started.");
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
public static void bootClient(BufferedReader in, GameRunner gr,
ComManager cm) throws IOException {
for (int i = 0; i < 4; i++) {
System.err.print(i);
System.err.println(" - " + gr.getName(i));
}
System.err.print("Boot which player (blank to cancel)? ");
System.err.flush();
String s = in.readLine();
if (s.equals(""))
return;
int who = -1;
for (int i = 0; i < cm.getCapacity(); i++)
if (s.equalsIgnoreCase(gr.getName(i))) {
who = i;
break;
}
if (who == -1) {
try {
who = Integer.parseInt(s);
} catch (NumberFormatException e) {
who = -1;
}
}
if (who < 0 || who > 3) {
System.err.println("cancelled.");
return;
}
System.err.println("Why do you want to boot " + gr.getName(who) + "?");
s = in.readLine();
synchronized (cm) {
cm.getCommunicator(who).booted(s);
cm.remove(who);
cm.notifyAll();
}
}
}