package controller; import common.ApplicationLock; import common.Log; import controller.action.ActionBoard; import controller.net.GameControlReturnDataReceiver; import controller.net.SPLCoachMessageReceiver; import controller.net.Sender; import controller.ui.GUI; import controller.ui.KeyboardListener; import controller.ui.StartInput; import data.AdvancedData; import data.GameControlData; import data.Rules; import data.Teams; import java.io.File; import java.io.IOException; import java.net.Inet4Address; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Enumeration; import javax.swing.*; /** * @author Michel Bartsch * * The programm starts in this class. * The main components are initialised here. */ public class GameController { /** * The version of the GameController. * Actually there are no dependencies, but this should be the first thing * to be written into the log file. */ public static final String version = "GC2 1.3"; /** Relative directory of where logs are stored */ private final static String LOG_DIRECTORY = "logs"; private static final String HELP_TEMPLATE = "Usage: java -jar GameController.jar {options}" + "\n (-h | --help) display help" + "\n (-i | --interface) <interface> set network interface (default is a connected IPv4 interface)" + "\n (-l | --league) %s%sselect league (default is spl)" + "\n (-w | --window) select window mode (default is fullscreen)" + "\n"; private static final String COMMAND_INTERFACE = "--interface"; private static final String COMMAND_INTERFACE_SHORT = "-i"; private static final String COMMAND_LEAGUE = "--league"; private static final String COMMAND_LEAGUE_SHORT = "-l"; private static final String COMMAND_WINDOW = "--window"; private static final String COMMAND_WINDOW_SHORT = "-w"; /** * The program starts here. * * @param args This is ignored. */ public static void main(String[] args) { System.out.println("OVERRIDE"); // Do not just System.exit(0) on Macs when selecting GameController/Quit System.setProperty("apple.eawt.quitStrategy", "CLOSE_ALL_WINDOWS"); //commands String interfaceName = ""; boolean windowMode = false; parsing: for (int i=0; i<args.length; i++) { if ((args.length > i+1) && ((args[i].equalsIgnoreCase(COMMAND_INTERFACE_SHORT)) || (args[i].equalsIgnoreCase(COMMAND_INTERFACE)))) { interfaceName = args[++i]; continue parsing; } else if ((args.length > i+1) && ((args[i].equalsIgnoreCase(COMMAND_LEAGUE_SHORT)) || (args[i].equalsIgnoreCase(COMMAND_LEAGUE))) ) { i++; for (int j=0; j < Rules.LEAGUES.length; j++) { if (Rules.LEAGUES[j].leagueDirectory.equals(args[i])) { Rules.league = Rules.LEAGUES[j]; continue parsing; } } } else if (args[i].equals(COMMAND_WINDOW_SHORT) || args[i].equals(COMMAND_WINDOW)) { windowMode = true; continue parsing; } String leagues = ""; for (Rules rules : Rules.LEAGUES) { leagues += (leagues.equals("") ? "" : " | ") + rules.leagueDirectory; } if (leagues.contains("|")) { leagues = "(" + leagues + ")"; } System.out.printf(HELP_TEMPLATE, leagues, leagues.length() < 17 ? " ".substring(leagues.length()) : "\n "); System.exit(0); } //application-lock final ApplicationLock applicationLock = new ApplicationLock("GameController"); try { if (!applicationLock.acquire()) { JOptionPane.showMessageDialog(null, "An instance of GameController already exists.", "Multiple instances", JOptionPane.WARNING_MESSAGE); System.exit(0); } } catch (Exception e) { JOptionPane.showMessageDialog(null, "Error while trying to acquire the application lock.", "IOError", JOptionPane.ERROR_MESSAGE); System.exit(-1); } //collect the start parameters and put them into the first data. StartInput input = new StartInput(!windowMode); while (!input.finished) { try { Thread.sleep(100); } catch (InterruptedException e) { System.exit(0); } } AdvancedData data = new AdvancedData(); for (int i=0; i<2; i++) { data.team[i].teamNumber = (byte)input.outTeam[i]; } data.team[0].teamColor = input.outTeamColor[0]; data.team[1].teamColor = input.outTeamColor[1]; data.kickOffTeam = (byte)input.outTeam[0]; data.colorChangeAuto = input.outAutoColorChange; data.gameType = Rules.league.dropInPlayerMode ? GameControlData.GAME_DROPIN : input.outFulltime ? GameControlData.GAME_PLAYOFF : GameControlData.GAME_ROUNDROBIN; InterfaceAddress localAddress = null; try { NetworkInterface networkInterface = NetworkInterface.getByName(interfaceName); if (networkInterface == null || !networkInterface.isUp()) { Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces(); if (interfaceName.isEmpty()) { while (nifs.hasMoreElements()) { NetworkInterface nif = nifs.nextElement(); if (!nif.isUp() || nif.isLoopback()) { continue; } for(InterfaceAddress ifAddress : nif.getInterfaceAddresses()) { if (ifAddress.getAddress().isLoopbackAddress()) { // ignore loopback during automatic interface lookup continue; } else if (ifAddress.getAddress() instanceof Inet4Address) { networkInterface = nif; localAddress = ifAddress; } } } } else { System.err.printf("The specified interface \"%s\" is not available%n", interfaceName); System.err.print("List of known and up interfaces: "); while (nifs.hasMoreElements()) { NetworkInterface nif = nifs.nextElement(); if (nif.isUp()) { System.err.printf("%s (%s)",nif.getName(), nif.getDisplayName()); if (nifs.hasMoreElements()) { System.err.print(", "); } } } System.err.println(); Log.error("fatal: " + String.format("The specified interface \"%s\" is not available", interfaceName)); System.exit(-1); } } else { for (InterfaceAddress ifAddress : networkInterface.getInterfaceAddresses()) { if (ifAddress.getAddress() instanceof Inet4Address) { localAddress = ifAddress; } } if (localAddress == null) { System.err.printf("The specified interface \"%s\" has no IPv4 address assigned%n", interfaceName); Log.error("fatal: " + String.format("The specified interface \"%s\" has no IPv4 address assigned", interfaceName)); System.exit(-1); } } //sender Sender.initialize(localAddress.getBroadcast() == null ? localAddress.getAddress() : localAddress.getBroadcast()); Sender sender = Sender.getInstance(); sender.send(data); sender.start(); //event-handler EventHandler.getInstance().data = data; //receiver GameControlReturnDataReceiver.initialize(localAddress.getAddress()); GameControlReturnDataReceiver receiver = GameControlReturnDataReceiver.getInstance(); receiver.start(); if (Rules.league.isCoachAvailable) { SPLCoachMessageReceiver spl = SPLCoachMessageReceiver.getInstance(); spl.start(); } } catch (Exception e) { JOptionPane.showMessageDialog(null, "Error while setting up GameController on port: " + GameControlData.GAMECONTROLLER_RETURNDATA_PORT + ".", "Error on configured port", JOptionPane.ERROR_MESSAGE); Log.error("fatal: " + e.getMessage()); System.exit(-1); } //log SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss-S"); final File logDir = new File(LOG_DIRECTORY); if (!logDir.exists() && !logDir.mkdirs()) { Log.init("log_"+df.format(new Date(System.currentTimeMillis()))+".txt"); } else { final File logFile = new File(logDir, "log_"+df.format(new Date(System.currentTimeMillis()))+".txt"); Log.init(logFile.getPath()); } Log.toFile("League = "+Rules.league.leagueName); Log.toFile("Game type = "+ (data.gameType == GameControlData.GAME_ROUNDROBIN ? "round robin" : data.gameType == GameControlData.GAME_PLAYOFF ? "play-off" : "drop-in")); Log.toFile("Auto color change = "+data.colorChangeAuto); Log.toFile("Using broadcast address " + (localAddress.getBroadcast() == null ? localAddress.getAddress() : localAddress.getBroadcast())); Log.toFile("Listening on address " + (Rules.league.dropBroadcastMessages ? localAddress.getAddress() : "0.0.0.0")); //ui ActionBoard.init(); Log.state(data, Teams.getNames(false)[data.team[0].teamNumber] + " (" + Rules.league.teamColorName[data.team[0].teamColor] + ") vs " + Teams.getNames(false)[data.team[1].teamNumber] + " (" + Rules.league.teamColorName[data.team[1].teamColor] + ")"); GUI gui = new GUI(input.outFullscreen, data); new KeyboardListener(); EventHandler.getInstance().setGUI(gui); gui.update(data); //input dispose input.dispose(); //clock runs until window is closed Clock.getInstance().start(); // shutdown Log.toFile("Shutdown GameController"); try { applicationLock.release(); } catch (IOException e) { Log.error("Error while trying to release the application lock."); } Sender.getInstance().interrupt(); GameControlReturnDataReceiver.getInstance().interrupt(); SPLCoachMessageReceiver.getInstance().interrupt(); Thread.interrupted(); // clean interrupted status try { Sender.getInstance().join(); GameControlReturnDataReceiver.getInstance().join(); SPLCoachMessageReceiver.getInstance().join(); } catch (InterruptedException e) { Log.error("Waiting for threads to shutdown was interrupted."); } try { Log.close(); } catch (IOException e) { Log.error("Error while trying to close the log."); } gui.dispose(); System.exit(0); } }