/******************************************************************************* * Copyright (c) 2015 * <p> * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * <p> * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * <p> * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. *******************************************************************************/ package jsettlers.main.swing.menu.joinpanel; import java.awt.BorderLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.event.ActionListener; import java.util.Arrays; import java.util.List; import java.util.Vector; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import jsettlers.common.ai.EPlayerType; import jsettlers.common.menu.ENetworkMessage; import jsettlers.common.menu.EProgressState; import jsettlers.common.menu.IChatMessageListener; import jsettlers.common.menu.IJoinPhaseMultiplayerGameConnector; import jsettlers.common.menu.IJoiningGame; import jsettlers.common.menu.IJoiningGameListener; import jsettlers.common.menu.IMultiplayerConnector; import jsettlers.common.menu.IMultiplayerListener; import jsettlers.common.menu.IMultiplayerPlayer; import jsettlers.common.menu.IStartingGame; import jsettlers.common.utils.collections.ChangingList; import jsettlers.graphics.localization.Labels; import jsettlers.graphics.startscreen.SettingsManager; import jsettlers.logic.map.loading.EMapStartResources; import jsettlers.logic.map.loading.MapLoader; import jsettlers.logic.player.PlayerSetting; import jsettlers.main.JSettlersGame; import jsettlers.main.swing.JSettlersFrame; import jsettlers.main.swing.JSettlersSwingUtil; import jsettlers.main.swing.lookandfeel.ELFStyle; import jsettlers.main.swing.lookandfeel.components.BackgroundPanel; import jsettlers.main.swing.menu.joinpanel.slots.PlayerSlot; import jsettlers.main.swing.menu.joinpanel.slots.SlotToggleGroup; import jsettlers.main.swing.menu.joinpanel.slots.factories.ClientOfMultiplayerPlayerSlotFactory; import jsettlers.main.swing.menu.joinpanel.slots.factories.HostOfMultiplayerPlayerSlotFactory; import jsettlers.main.swing.menu.joinpanel.slots.factories.IPlayerSlotFactory; import jsettlers.main.swing.menu.joinpanel.slots.factories.SinglePlayerSlotFactory; /** * @author codingberlin */ public class JoinGamePanel extends BackgroundPanel { private static final long serialVersionUID = -1186791399814385303L; private final JSettlersFrame settlersFrame; private final JLabel titleLabel = new JLabel(); private final JPanel contentPanel = new JPanel(); private final JPanel westPanel = new JPanel(); private final JPanel mapPanel = new JPanel(); private final JPanel settingsPanel = new JPanel(); private final JPanel centerPanel = new JPanel(); private final JLabel mapNameLabel = new JLabel(); private final JLabel mapImage = new JLabel(); private final JLabel numberOfPlayersLabel = new JLabel(); private final JComboBox<Integer> numberOfPlayersComboBox = new JComboBox<>(); private final JLabel peaceTimeLabel = new JLabel(); private final JComboBox<EPeaceTime> peaceTimeComboBox = new JComboBox<>(); private final JLabel startResourcesLabel = new JLabel(); private final JComboBox<MapStartResourcesUIWrapper> startResourcesComboBox = new JComboBox<>(); private final JPanel playerSlotsPanel = new JPanel(); private final JButton cancelButton = new JButton(); private final JButton startGameButton = new JButton(); private final JLabel slotsHeadlinePlayerNameLabel = new JLabel(); private final JLabel slotsHeadlineCivilisation = new JLabel(); private final JLabel slotsHeadlineType = new JLabel(); private final JLabel slotsHeadlineMapSlot = new JLabel(); private final JLabel slotsHeadlineTeam = new JLabel(); private final JTextField chatInputField = new JTextField(); private final JTextArea chatArea = new JTextArea(); private final JButton sendChatMessageButton = new JButton(); private MapLoader mapLoader; private final List<PlayerSlot> playerSlots = new Vector<>(); private IPlayerSlotFactory playerSlotFactory; public JoinGamePanel(JSettlersFrame settlersFrame) { this.settlersFrame = settlersFrame; createStructure(); setStyle(); localize(); addListener(); } private void createStructure() { add(contentPanel); contentPanel.setLayout(new BorderLayout(30, 30)); JPanel titleLabelWrapper = new JPanel(); contentPanel.add(titleLabelWrapper, BorderLayout.NORTH); titleLabelWrapper.add(titleLabel); titleLabel.setHorizontalAlignment(SwingConstants.CENTER); contentPanel.add(westPanel, BorderLayout.WEST); contentPanel.add(centerPanel, BorderLayout.CENTER); westPanel.setLayout(new BorderLayout()); westPanel.add(mapPanel, BorderLayout.NORTH); JPanel settingsPanelWrapper = new JPanel(); westPanel.add(settingsPanelWrapper, BorderLayout.CENTER); settingsPanelWrapper.add(settingsPanel); settingsPanel.setLayout(new GridLayout(0, 2, 20, 20)); mapPanel.setLayout(new BorderLayout()); JPanel mapNameLabelWrapper = new JPanel(); mapPanel.add(mapNameLabelWrapper, BorderLayout.NORTH); mapNameLabelWrapper.add(mapNameLabel); mapNameLabel.setHorizontalAlignment(SwingConstants.CENTER); mapPanel.add(mapImage, BorderLayout.CENTER); mapImage.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); settingsPanel.add(numberOfPlayersLabel); settingsPanel.add(numberOfPlayersComboBox); settingsPanel.add(startResourcesLabel); settingsPanel.add(startResourcesComboBox); settingsPanel.add(peaceTimeLabel); settingsPanel.add(peaceTimeComboBox); centerPanel.setLayout(new BorderLayout(0, 30)); sendChatMessageButton.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 15)); JPanel chatPanel = new JPanel(); chatPanel.setLayout(new BorderLayout(0, 10)); JPanel chatInputPanel = new JPanel(); chatInputPanel.setLayout(new BorderLayout(10, 0)); chatPanel.add(chatArea, BorderLayout.CENTER); chatPanel.add(chatInputPanel, BorderLayout.SOUTH); chatInputPanel.add(chatInputField, BorderLayout.CENTER); chatInputPanel.add(sendChatMessageButton, BorderLayout.EAST); centerPanel.add(chatPanel, BorderLayout.CENTER); GridBagConstraints constraints = new GridBagConstraints(); constraints.gridx = 0; constraints.gridy = 0; constraints.fill = GridBagConstraints.HORIZONTAL; playerSlotsPanel.setLayout(new GridBagLayout()); JScrollPane playerSlotPanelWrapper = new JScrollPane(playerSlotsPanel); playerSlotsPanel.setBorder(new EmptyBorder(20, 25, 20, 20)); centerPanel.add(playerSlotPanelWrapper, BorderLayout.NORTH); JPanel southPanelWrapper = new JPanel(); contentPanel.add(southPanelWrapper, BorderLayout.SOUTH); JPanel southPanel = new JPanel(); southPanel.setLayout(new GridLayout(0, 3, 20, 20)); southPanelWrapper.add(southPanel); cancelButton.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 15)); southPanel.add(cancelButton); startGameButton.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 15)); southPanel.add(startGameButton); } private void setStyle() { mapNameLabel.putClientProperty(ELFStyle.KEY, ELFStyle.LABEL_LONG); numberOfPlayersLabel.putClientProperty(ELFStyle.KEY, ELFStyle.LABEL_SHORT); startResourcesLabel.putClientProperty(ELFStyle.KEY, ELFStyle.LABEL_SHORT); peaceTimeLabel.putClientProperty(ELFStyle.KEY, ELFStyle.LABEL_SHORT); titleLabel.putClientProperty(ELFStyle.KEY, ELFStyle.LABEL_HEADER); cancelButton.putClientProperty(ELFStyle.KEY, ELFStyle.BUTTON_MENU); startGameButton.putClientProperty(ELFStyle.KEY, ELFStyle.BUTTON_MENU); slotsHeadlinePlayerNameLabel.putClientProperty(ELFStyle.KEY, ELFStyle.LABEL_DYNAMIC); slotsHeadlineCivilisation.putClientProperty(ELFStyle.KEY, ELFStyle.LABEL_DYNAMIC); slotsHeadlineType.putClientProperty(ELFStyle.KEY, ELFStyle.LABEL_DYNAMIC); slotsHeadlineMapSlot.putClientProperty(ELFStyle.KEY, ELFStyle.LABEL_DYNAMIC); slotsHeadlineTeam.putClientProperty(ELFStyle.KEY, ELFStyle.LABEL_DYNAMIC); sendChatMessageButton.putClientProperty(ELFStyle.KEY, ELFStyle.BUTTON_MENU); chatInputField.putClientProperty(ELFStyle.KEY, ELFStyle.TEXT_DEFAULT); chatArea.putClientProperty(ELFStyle.KEY, ELFStyle.PANEL_DARK); startResourcesComboBox.putClientProperty(ELFStyle.KEY, ELFStyle.COMBOBOX); numberOfPlayersComboBox.putClientProperty(ELFStyle.KEY, ELFStyle.COMBOBOX); peaceTimeComboBox.putClientProperty(ELFStyle.KEY, ELFStyle.COMBOBOX); chatArea.putClientProperty(ELFStyle.KEY, ELFStyle.TEXT_DEFAULT); SwingUtilities.updateComponentTreeUI(this); } private void localize() { numberOfPlayersLabel.setText(Labels.getString("join-game-panel-number-of-players")); startResourcesLabel.setText(Labels.getString("join-game-panel-start-resources")); cancelButton.setText(Labels.getString("join-game-panel-cancel")); startGameButton.setText(Labels.getString("join-game-panel-start")); peaceTimeLabel.setText(Labels.getString("join-game-panel-peace-time")); slotsHeadlinePlayerNameLabel.setText(Labels.getString("join-game-panel-player-name")); slotsHeadlineCivilisation.setText(Labels.getString("join-game-panel-civilisation")); slotsHeadlineType.setText(Labels.getString("join-game-panel-player-type")); slotsHeadlineMapSlot.setText(Labels.getString("join-game-panel-map-slot")); slotsHeadlineTeam.setText(Labels.getString("join-game-panel-team")); sendChatMessageButton.setText(Labels.getString("join-game-panel-send-chat-message")); } private void addListener() { numberOfPlayersComboBox.addActionListener(e -> updateNumberOfPlayerSlots()); } public void setSinglePlayerMap(MapLoader mapLoader) { this.playerSlotFactory = new SinglePlayerSlotFactory(); titleLabel.setText(Labels.getString("join-game-panel-new-single-player-game-title")); numberOfPlayersComboBox.setEnabled(true); peaceTimeComboBox.setEnabled(true); startResourcesComboBox.setEnabled(true); startGameButton.setVisible(true); setChatVisible(false); cancelButton.addActionListener(e -> settlersFrame.showMainMenu()); setStartButtonActionListener(e -> { long randomSeed = System.currentTimeMillis(); PlayerSetting[] playerSettings = playerSlots.stream() .sorted((playerSlot, otherPlayerSlot) -> playerSlot.getSlot() - otherPlayerSlot.getSlot()) .map(playerSlot -> { if (playerSlot.isAvailable()) { return new PlayerSetting(playerSlot.getPlayerType(), playerSlot.getCivilisation(), playerSlot.getTeam()); } else { return new PlayerSetting(); } }) .toArray(PlayerSetting[]::new); JSettlersGame game = new JSettlersGame(mapLoader, randomSeed, playerSlots.get(0).getSlot(), playerSettings); IStartingGame startingGame = game.start(); settlersFrame.showStartingGamePanel(startingGame); }); setCancelButtonActionListener(e -> { settlersFrame.showMainMenu(); }); prepareUiFor(mapLoader); } public void setNewMultiPlayerMap(MapLoader mapLoader, IMultiplayerConnector connector) { this.playerSlotFactory = new HostOfMultiplayerPlayerSlotFactory(); titleLabel.setText(Labels.getString("join-game-panel-new-multi-player-game-title")); numberOfPlayersComboBox.setEnabled(false); peaceTimeComboBox.setEnabled(false); startResourcesComboBox.setEnabled(false); startGameButton.setVisible(true); setChatVisible(true); setStartButtonActionListener(e -> { }); IJoiningGame joiningGame = connector.openNewMultiplayerGame(new OpenMultiPlayerGameInfo(mapLoader)); joiningGame.setListener(new IJoiningGameListener() { @Override public void joinProgressChanged(EProgressState state, float progress) { } @Override public void gameJoined(IJoinPhaseMultiplayerGameConnector connector) { SwingUtilities.invokeLater(() -> { initializeChatFor(connector); setStartButtonActionListener(e -> { connector.startGame(); }); connector.getPlayers().setListener(changingPlayers -> onPlayersChanges(changingPlayers, connector)); connector.setMultiplayerListener(new IMultiplayerListener() { @Override public void gameIsStarting(IStartingGame game) { settlersFrame.showStartingGamePanel(game); } @Override public void gameAborted() { settlersFrame.showMainMenu(); } }); onPlayersChanges(connector.getPlayers(), connector); // init the UI with the players }); } }); setCancelButtonActionListener(e -> { joiningGame.abort(); settlersFrame.showMainMenu(); }); prepareUiFor(mapLoader); } public void setJoinMultiPlayerMap(IJoinPhaseMultiplayerGameConnector joinMultiPlayerMap, MapLoader mapLoader) { playerSlotFactory = new ClientOfMultiplayerPlayerSlotFactory(); titleLabel.setText(Labels.getString("join-game-panel-join-multi-player-game-title")); numberOfPlayersComboBox.setEnabled(false); peaceTimeComboBox.setEnabled(false); startResourcesComboBox.setEnabled(false); setChatVisible(true); cancelButton.addActionListener(e -> { settlersFrame.showMainMenu(); }); startGameButton.setVisible(false); prepareUiFor(mapLoader); joinMultiPlayerMap.getPlayers().setListener(changingPlayers -> { onPlayersChanges(changingPlayers, joinMultiPlayerMap); }); joinMultiPlayerMap.setMultiplayerListener(new IMultiplayerListener() { @Override public void gameIsStarting(IStartingGame game) { settlersFrame.showStartingGamePanel(game); } @Override public void gameAborted() { settlersFrame.showMainMenu(); } }); initializeChatFor(joinMultiPlayerMap); onPlayersChanges(joinMultiPlayerMap.getPlayers(), joinMultiPlayerMap); // init the UI with the players } private void initializeChatFor(IJoinPhaseMultiplayerGameConnector joinMultiPlayerMap) { joinMultiPlayerMap.setChatListener(new IChatMessageListener() { @Override public void chatMessageReceived(String authorId, String message) { chatArea.append(authorId + ": " + message + "\n"); } @Override public void systemMessageReceived(IMultiplayerPlayer author, ENetworkMessage message) { chatArea.append(Labels.getString("network-message-" + message.name()) + "\n"); } }); ActionListener sendChatMessage = e -> { String message = chatInputField.getText(); if (!message.equals("")) { joinMultiPlayerMap.sendChatMessage(message); chatInputField.setText(""); } }; Arrays.asList(sendChatMessageButton.getActionListeners()).stream().forEach(sendChatMessageButton::removeActionListener); Arrays.asList(chatInputField.getActionListeners()).stream().forEach(chatInputField::removeActionListener); sendChatMessageButton.addActionListener(sendChatMessage); chatInputField.addActionListener(sendChatMessage); } private void setChatVisible(boolean isVisible) { chatArea.setVisible(isVisible); chatInputField.setVisible(isVisible); sendChatMessageButton.setVisible(isVisible); chatArea.setText(""); chatInputField.setText(""); } private void onPlayersChanges(ChangingList<? extends IMultiplayerPlayer> changingPlayers, IJoinPhaseMultiplayerGameConnector joinMultiPlayerMap) { SwingUtilities.invokeLater(() -> { List<? extends IMultiplayerPlayer> players = changingPlayers.getItems(); String myId = SettingsManager.getInstance().get(SettingsManager.SETTING_UUID); for (int i = 0; i < players.size(); i++) { PlayerSlot playerSlot = playerSlots.get(i); IMultiplayerPlayer player = players.get(i); playerSlot.setPlayerName(player.getName()); playerSlot.setReady(player.isReady()); if (player.getId().equals(myId)) { playerSlot.setReadyButtonEnabled(true); playerSlot.informGameAboutReady(joinMultiPlayerMap); } else { playerSlot.setReadyButtonEnabled(false); } } for (int i = players.size(); i < playerSlots.size(); i++) { playerSlots.get(i).setPlayerType(EPlayerType.AI_VERY_HARD, false); } setCancelButtonActionListener(e -> { joinMultiPlayerMap.abort(); settlersFrame.showMainMenu(); }); }); } ; private void prepareUiFor(MapLoader mapLoader) { this.mapLoader = mapLoader; mapNameLabel.setText(mapLoader.getMapName()); mapImage.setIcon(new ImageIcon(JSettlersSwingUtil.createBufferedImageFrom(mapLoader))); peaceTimeComboBox.removeAllItems(); peaceTimeComboBox.addItem(EPeaceTime.WITHOUT); startResourcesComboBox.removeAllItems(); Arrays.asList(EMapStartResources.values()).stream() .map(MapStartResourcesUIWrapper::new) .forEach(startResourcesComboBox::addItem); startResourcesComboBox.setSelectedIndex(EMapStartResources.HIGH_GOODS.value - 1); resetNumberOfPlayersComboBox(); buildPlayerSlots(); updateNumberOfPlayerSlots(); } private void buildPlayerSlots() { int maximumNumberOfPlayers = this.mapLoader.getMaxPlayers(); playerSlots.clear(); for (byte i = 0; i < maximumNumberOfPlayers; i++) { PlayerSlot playerSlot = playerSlotFactory.createPlayerSlot(i, this.mapLoader); playerSlots.add(playerSlot); } PlayerSetting[] playerSettings = mapLoader.getFileHeader().getPlayerSettings(); for (byte i = 0; i < playerSlots.size(); i++) { PlayerSlot playerSlot = playerSlots.get(i); PlayerSetting playerSetting = playerSettings[i]; playerSlot.setSlot(i); if (playerSetting.getTeamId() != null) { playerSlot.setTeam(playerSetting.getTeamId(), false); } else { playerSlot.setTeam(i); } if (playerSetting.getCivilisation() != null) { playerSlot.setCivilisation(playerSetting.getCivilisation(), false); } if (playerSetting.getPlayerType() != null) { playerSlot.setPlayerType(playerSetting.getPlayerType(), false); } } } private void setStartButtonActionListener(ActionListener actionListener) { ActionListener[] actionListeners = startGameButton.getActionListeners(); Arrays.asList(actionListeners).stream().forEach(startGameButton::removeActionListener); startGameButton.addActionListener(actionListener); } private void setCancelButtonActionListener(ActionListener actionListener) { ActionListener[] actionListeners = cancelButton.getActionListeners(); Arrays.asList(actionListeners).stream().forEach(cancelButton::removeActionListener); cancelButton.addActionListener(actionListener); } private void resetNumberOfPlayersComboBox() { numberOfPlayersComboBox.removeAllItems(); for (int i = 1; i < mapLoader.getMaxPlayers() + 1; i++) { numberOfPlayersComboBox.addItem(i); } numberOfPlayersComboBox.setSelectedIndex(mapLoader.getMaxPlayers() - 1); } private void updateNumberOfPlayerSlots() { if (playerSlotFactory == null || numberOfPlayersComboBox.getSelectedItem() == null) { return; } playerSlotsPanel.removeAll(); addPlayerSlotHeadline(); for (int i = 0; i < playerSlots.size(); i++) { if (i < (int) numberOfPlayersComboBox.getSelectedItem()) { playerSlots.get(i).addTo(playerSlotsPanel, i + 1); } else { playerSlots.get(i).setAvailable(false); } } SwingUtilities.updateComponentTreeUI(playerSlotsPanel); SlotToggleGroup slotToggleGroup = new SlotToggleGroup(); playerSlots.stream().forEach(slotToggleGroup::add); } private void addPlayerSlotHeadline() { GridBagConstraints constraints = new GridBagConstraints(); constraints.gridx = 1; constraints.gridy = 0; constraints.gridwidth = 4; constraints.fill = GridBagConstraints.HORIZONTAL; playerSlotsPanel.add(slotsHeadlinePlayerNameLabel, constraints); constraints.gridx = 5; constraints.gridy = 0; constraints.gridwidth = 2; constraints.fill = GridBagConstraints.HORIZONTAL; playerSlotsPanel.add(slotsHeadlineCivilisation, constraints); constraints = new GridBagConstraints(); constraints.gridx = 7; constraints.gridy = 0; constraints.gridwidth = 4; constraints.fill = GridBagConstraints.HORIZONTAL; playerSlotsPanel.add(slotsHeadlineType, constraints); constraints = new GridBagConstraints(); constraints.gridx = 11; constraints.gridy = 0; constraints.gridwidth = 1; constraints.fill = GridBagConstraints.HORIZONTAL; playerSlotsPanel.add(slotsHeadlineMapSlot, constraints); constraints = new GridBagConstraints(); constraints.gridx = 12; constraints.gridy = 0; constraints.gridwidth = 1; constraints.fill = GridBagConstraints.HORIZONTAL; playerSlotsPanel.add(slotsHeadlineTeam, constraints); } private enum EPeaceTime { WITHOUT; @Override public String toString() { return Labels.getString("peace-time-" + name()); } } }