package org.ggp.base.apps.server; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSpinner; import javax.swing.JTabbedPane; import javax.swing.SpinnerNumberModel; import org.ggp.base.apps.server.leaderboard.LeaderboardPanel; import org.ggp.base.apps.server.scheduling.PendingMatch; import org.ggp.base.apps.server.scheduling.Scheduler; import org.ggp.base.apps.server.scheduling.SchedulingPanel; import org.ggp.base.util.crypto.BaseCryptography.EncodedKeyPair; import org.ggp.base.util.game.Game; import org.ggp.base.util.game.GameRepository; import org.ggp.base.util.gdl.grammar.GdlPool; import org.ggp.base.util.presence.PlayerPresence; import org.ggp.base.util.presence.PlayerPresenceManager.InvalidHostportException; import org.ggp.base.util.statemachine.Role; import org.ggp.base.util.statemachine.StateMachine; import org.ggp.base.util.statemachine.implementation.prover.ProverStateMachine; import org.ggp.base.util.ui.GameSelector; import org.ggp.base.util.ui.JLabelBold; import org.ggp.base.util.ui.NativeUI; import org.ggp.base.util.ui.PlayerSelector; @SuppressWarnings("serial") public final class Server extends JPanel implements ActionListener { static void createAndShowGUI(Server serverPanel, String title) { JFrame frame = new JFrame(title); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setPreferredSize(new Dimension(1200, 900)); frame.getContentPane().add(serverPanel); frame.pack(); frame.setVisible(true); } public static void main(String[] args) { NativeUI.setNativeUI(); GdlPool.caseSensitive = false; final Server serverPanel = new Server(); javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() { createAndShowGUI(serverPanel, "Game Server"); } }); } private Game theGame; private final JPanel managerPanel; private final JTabbedPane matchesTabbedPane; private final JPanel gamePanel; private final JPanel playersPanel; private final SchedulingPanel schedulingPanel; private final LeaderboardPanel leaderboardPanel; private final List<JComboBox<String>> playerFields; private final List<JLabel> roleLabels; private final JButton runButton; private final JSpinner startClockSpinner; private final JSpinner playClockSpinner; private final JSpinner repetitionsSpinner; private final JCheckBox shouldScramble; private final JCheckBox shouldQueue; private final JCheckBox shouldDetail; private final JCheckBox shouldPublish; private final JCheckBox shouldSave; private final GameSelector gameSelector; private final PlayerSelector playerSelector; private final JList<String> playerSelectorList; private final Scheduler scheduler; public Server() { super(new GridBagLayout()); runButton = new JButton(runButtonMethod()); startClockSpinner = new JSpinner(new SpinnerNumberModel(30,5,1200,1)); playClockSpinner = new JSpinner(new SpinnerNumberModel(15,5,300,1)); repetitionsSpinner = new JSpinner(new SpinnerNumberModel(1,1,1000,1)); matchesTabbedPane = new JTabbedPane(); managerPanel = new JPanel(new GridBagLayout()); gamePanel = new JPanel(new GridBagLayout()); playersPanel = new JPanel(new GridBagLayout()); roleLabels = new ArrayList<JLabel>(); playerFields = new ArrayList<JComboBox<String>>(); theGame = null; shouldScramble = new JCheckBox("Scramble GDL?", true); shouldQueue = new JCheckBox("Queue match?", true); shouldDetail = new JCheckBox("Show match details?", true); shouldSave = new JCheckBox("Save match to disk?", false); shouldPublish = new JCheckBox("Publish match to the web?", false); runButton.setEnabled(false); gameSelector = new GameSelector(); playerSelector = new PlayerSelector(); playerSelectorList = playerSelector.getPlayerSelectorList(); int nRowCount = 0; gamePanel.add(new JLabelBold("Match Setup"), new GridBagConstraints(0, nRowCount++, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 25, 5, 25), 0, 0)); gamePanel.add(new JLabel("Repository:"), new GridBagConstraints(0, nRowCount, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 1, 5), 5, 5)); gamePanel.add(gameSelector.getRepositoryList(), new GridBagConstraints(1, nRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 1, 5), 5, 5)); gamePanel.add(new JLabel("Game:"), new GridBagConstraints(0, nRowCount, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(1, 5, 5, 5), 5, 5)); gamePanel.add(gameSelector.getGameList(), new GridBagConstraints(1, nRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(1, 5, 5, 5), 5, 5)); gamePanel.add(new JLabel("Start Clock:"), new GridBagConstraints(0, nRowCount, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 1, 5), 5, 5)); gamePanel.add(startClockSpinner, new GridBagConstraints(1, nRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 1, 5), 5, 5)); gamePanel.add(new JLabel("Play Clock:"), new GridBagConstraints(0, nRowCount, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(1, 5, 5, 5), 5, 5)); gamePanel.add(playClockSpinner, new GridBagConstraints(1, nRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(1, 5, 5, 5), 5, 5)); gamePanel.add(new JLabel("Repetitions:"), new GridBagConstraints(0, nRowCount, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(1, 5, 5, 5), 5, 5)); gamePanel.add(repetitionsSpinner, new GridBagConstraints(1, nRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(1, 5, 5, 5), 5, 5)); gamePanel.add(shouldScramble, new GridBagConstraints(1, nRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 5, 0)); gamePanel.add(shouldQueue, new GridBagConstraints(1, nRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 5), 5, 0)); gamePanel.add(shouldDetail, new GridBagConstraints(1, nRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 5), 5, 0)); gamePanel.add(shouldSave, new GridBagConstraints(1, nRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 5), 5, 0)); gamePanel.add(shouldPublish, new GridBagConstraints(1, nRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 5, 5), 5, 0)); gamePanel.add(runButton, new GridBagConstraints(1, nRowCount, 1, 1, 0.0, 1.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); nRowCount = 0; playersPanel.add(new JLabelBold("Player List"), new GridBagConstraints(0, nRowCount++, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 25, 5, 25), 0, 0)); playersPanel.add(new JScrollPane(playerSelectorList), new GridBagConstraints(0, nRowCount++, 3, 1, 1.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 25, 5, 25), 0, 0)); playersPanel.add(new JButton(addPlayerButtonMethod()), new GridBagConstraints(0, nRowCount, 1, 1, 1.0, 1.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); playersPanel.add(new JButton(removePlayerButtonMethod()), new GridBagConstraints(1, nRowCount, 1, 1, 0.0, 1.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); playersPanel.add(new JButton(testPlayerButtonMethod()), new GridBagConstraints(2, nRowCount++, 1, 1, 1.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); nRowCount = 0; managerPanel.add(gamePanel, new GridBagConstraints(0, nRowCount++, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 5, 5)); managerPanel.add(new JSeparator(), new GridBagConstraints(0, nRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 5, 5)); managerPanel.add(playersPanel, new GridBagConstraints(0, nRowCount++, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 5, 5)); this.add(managerPanel, new GridBagConstraints(0, 0, 1, 1, 0.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 5, 5)); this.add(matchesTabbedPane, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 5, 5)); gameSelector.getGameList().addActionListener(this); gameSelector.repopulateGameList(); schedulingPanel = new SchedulingPanel(); leaderboardPanel = new LeaderboardPanel(); matchesTabbedPane.addTab("Overview", new OverviewPanel()); scheduler = new Scheduler(matchesTabbedPane, schedulingPanel, leaderboardPanel); schedulingPanel.setScheduler(scheduler); scheduler.start(); } public void setSigningKeys(EncodedKeyPair keys) { scheduler.signingKeys = keys; } class OverviewPanel extends JPanel { public OverviewPanel() { super(new GridBagLayout()); add(schedulingPanel, new GridBagConstraints(0, 0, 1, 1, 2.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 5, 5)); add(leaderboardPanel, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 5, 5)); } } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == gameSelector.getGameList()) { theGame = gameSelector.getSelectedGame(); for (int i = 0; i < roleLabels.size(); i++) { gamePanel.remove(roleLabels.get(i)); gamePanel.remove(playerFields.get(i)); } roleLabels.clear(); playerFields.clear(); validate(); runButton.setEnabled(false); if (theGame == null) return; StateMachine stateMachine = new ProverStateMachine(); stateMachine.initialize(theGame.getRules()); List<Role> roles = stateMachine.getRoles(); int newRowCount = 11; for (int i = 0; i < roles.size(); i++) { roleLabels.add(new JLabel(roles.get(i).getName().toString() + ":")); playerFields.add(playerSelector.getPlayerSelectorBox()); playerFields.get(i).setSelectedIndex(i%playerFields.get(i).getModel().getSize()); gamePanel.add(roleLabels.get(i), new GridBagConstraints(0, newRowCount, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(1, 5, 1, 5), 5, 5)); gamePanel.add(playerFields.get(i), new GridBagConstraints(1, newRowCount++, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(1, 5, 1, 5), 5, 5)); } gamePanel.add(runButton, new GridBagConstraints(1, newRowCount, 1, 1, 0.0, 1.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); validate(); runButton.setEnabled(true); } } private AbstractAction runButtonMethod() { return new AbstractAction("Start a new match!") { @Override public void actionPerformed(ActionEvent evt) { int startClock = (Integer)startClockSpinner.getValue(); int playClock = (Integer)playClockSpinner.getValue(); List<PlayerPresence> thePlayers = new ArrayList<PlayerPresence>(); for (JComboBox<String> playerField : playerFields) { String name = playerField.getSelectedItem().toString(); thePlayers.add(playerSelector.getPlayerPresence(name)); } synchronized (scheduler) { for (int i = 0; i < (Integer)repetitionsSpinner.getValue(); i++) { scheduler.addPendingMatch(new PendingMatch("Base", theGame, new ArrayList<PlayerPresence>(thePlayers), -1, startClock, playClock, shouldScramble.isSelected(), shouldQueue.isSelected(), shouldDetail.isSelected(), shouldSave.isSelected(), shouldPublish.isSelected())); thePlayers.add(thePlayers.remove(0)); // rotate player roster for repeated matches try { Thread.sleep(10); } catch (InterruptedException ie) { ; } } } } }; } private AbstractAction testPlayerButtonMethod() { return new AbstractAction("Test") { @Override public void actionPerformed(ActionEvent evt) { if (playerSelectorList.getSelectedValue() != null) { Game testGame = GameRepository.getDefaultRepository().getGame("maze"); String playerName = playerSelectorList.getSelectedValue().toString(); List<PlayerPresence> thePlayers = Arrays.asList(new PlayerPresence[]{playerSelector.getPlayerPresence(playerName)}); scheduler.addPendingMatch(new PendingMatch("Test", testGame, thePlayers, -1, 10, 5, shouldScramble.isSelected(), false, shouldDetail.isSelected(), false, false)); } } }; } private AbstractAction addPlayerButtonMethod() { return new AbstractAction("Add") { @Override public void actionPerformed(ActionEvent evt) { String hostport = JOptionPane.showInputDialog(null, "What is the new player's address?\nPlease use the format \"host:port\".", "Add a player", JOptionPane.QUESTION_MESSAGE, null, null, "127.0.0.1:9147").toString(); try { playerSelector.addPlayer(hostport); } catch (InvalidHostportException e) { JOptionPane.showMessageDialog(null, "Could not parse the new player's address! Sorry.", "Error adding player", JOptionPane.ERROR_MESSAGE); } } }; } private AbstractAction removePlayerButtonMethod() { return new AbstractAction("Remove") { @Override public void actionPerformed(ActionEvent evt) { if (playerSelectorList.getSelectedValue() != null) { playerSelector.removePlayer(playerSelectorList.getSelectedValue().toString()); } } }; } }