Added functional servers list to launcher.
This commit is contained in:
parent
ee6d7a00cb
commit
dec56be4af
|
@ -4,6 +4,6 @@ jpackage^
|
|||
--name "Ace-of-Shades"^
|
||||
--description "Top-down 2D shooter game inspired by Ace of Spades."^
|
||||
--module-path "aos-client-3.1.jar;../../core/target/aos-core-3.1.jar"^
|
||||
--module aos_client/nl.andrewlalis.aos_client.Client^
|
||||
--module aos_client/nl.andrewlalis.aos_client.launcher.Launcher^
|
||||
--win-shortcut^
|
||||
--win-dir-chooser
|
|
@ -1,6 +1,5 @@
|
|||
package nl.andrewlalis.aos_client;
|
||||
|
||||
import nl.andrewlalis.aos_client.view.ConnectDialog;
|
||||
import nl.andrewlalis.aos_client.view.GameFrame;
|
||||
import nl.andrewlalis.aos_client.view.GamePanel;
|
||||
import nl.andrewlalis.aos_core.model.Player;
|
||||
|
@ -122,11 +121,4 @@ public class Client {
|
|||
System.out.println("Sound manager closed.");
|
||||
this.frame.dispose();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
ConnectDialog dialog = new ConnectDialog();
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,26 @@
|
|||
package nl.andrewlalis.aos_client.launcher;
|
||||
|
||||
import nl.andrewlalis.aos_client.Client;
|
||||
import nl.andrewlalis.aos_client.launcher.servers.ServerInfo;
|
||||
import nl.andrewlalis.aos_client.launcher.servers.ServerInfoCellRenderer;
|
||||
import nl.andrewlalis.aos_client.launcher.servers.ServerInfoListModel;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Launcher application for starting the game. Because the client is only
|
||||
* actually started when connecting to a server, this user interface serves as
|
||||
* the menu that the user interacts with before joining a game.
|
||||
*/
|
||||
public class Launcher extends JFrame {
|
||||
private static final Pattern addressPattern = Pattern.compile("(.+):(\\d+)");
|
||||
|
||||
|
@ -18,6 +28,7 @@ public class Launcher extends JFrame {
|
|||
super("Ace of Shades - Launcher");
|
||||
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
this.setContentPane(this.buildContent());
|
||||
this.setPreferredSize(new Dimension(400, 500));
|
||||
this.pack();
|
||||
this.setLocationRelativeTo(null);
|
||||
}
|
||||
|
@ -25,12 +36,10 @@ public class Launcher extends JFrame {
|
|||
private Container buildContent() {
|
||||
JTabbedPane mainPanel = new JTabbedPane(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
|
||||
mainPanel.addTab("Connect", null, this.getConnectPanel(), "Connect to a server and play.");
|
||||
|
||||
JPanel serversPanel = new JPanel();
|
||||
mainPanel.addTab("Servers", null, serversPanel, "View a list of available servers.");
|
||||
|
||||
JPanel settingsPanel = new JPanel();
|
||||
mainPanel.addTab("Settings", null, settingsPanel, "Change game settings.");
|
||||
mainPanel.addTab("Servers", null, this.getServersPanel(), "View a list of available servers.");
|
||||
//
|
||||
// JPanel settingsPanel = new JPanel();
|
||||
// mainPanel.addTab("Settings", null, settingsPanel, "Change game settings.");
|
||||
|
||||
return mainPanel;
|
||||
}
|
||||
|
@ -58,7 +67,7 @@ public class Launcher extends JFrame {
|
|||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
if (validateInput(addressField, usernameField)) {
|
||||
if (validateConnectInput(addressField, usernameField)) {
|
||||
connect(addressField, usernameField);
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +81,7 @@ public class Launcher extends JFrame {
|
|||
cancelButton.addActionListener(e -> this.dispose());
|
||||
JButton connectButton = new JButton("Connect");
|
||||
connectButton.addActionListener(e -> {
|
||||
if (validateInput(addressField, usernameField)) {
|
||||
if (validateConnectInput(addressField, usernameField)) {
|
||||
connect(addressField, usernameField);
|
||||
}
|
||||
});
|
||||
|
@ -80,12 +89,72 @@ public class Launcher extends JFrame {
|
|||
buttonPanel.add(connectButton);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout());
|
||||
mainPanel.add(new JLabel("Directly connect to a server and play."), BorderLayout.NORTH);
|
||||
mainPanel.add(inputPanel, BorderLayout.CENTER);
|
||||
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
private boolean validateInput(JTextField addressField, JTextField usernameField) {
|
||||
private Container getServersPanel() {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
|
||||
ServerInfoListModel listModel = new ServerInfoListModel();
|
||||
listModel.add(new ServerInfo("one", "localhost:8035", "andrew"));
|
||||
listModel.add(new ServerInfo("two", "localhost:25565", null));
|
||||
JList<ServerInfo> serversList = new JList<>(listModel);
|
||||
serversList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
serversList.setCellRenderer(new ServerInfoCellRenderer());
|
||||
JScrollPane scrollPane = new JScrollPane(serversList, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
panel.add(scrollPane, BorderLayout.CENTER);
|
||||
|
||||
serversList.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (SwingUtilities.isRightMouseButton(e)) {
|
||||
serversList.setSelectedIndex(serversList.locationToIndex(e.getPoint()));
|
||||
ServerInfo server = serversList.getSelectedValue();
|
||||
if (server == null) return;
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
JMenuItem connectItem = new JMenuItem("Connect");
|
||||
connectItem.addActionListener(a -> connect(server));
|
||||
menu.add(connectItem);
|
||||
JMenuItem editItem = new JMenuItem("Edit");
|
||||
editItem.addActionListener(a -> {
|
||||
// TODO: Open edit dialog.
|
||||
listModel.serverEdited();
|
||||
});
|
||||
menu.add(editItem);
|
||||
JMenuItem removeItem = new JMenuItem("Remove");
|
||||
removeItem.addActionListener(a -> {
|
||||
int choice = JOptionPane.showConfirmDialog(panel, "Are you sure you want to remove this server?", "Confirm Server Removal", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
if (choice == JOptionPane.OK_OPTION) {
|
||||
listModel.remove(serversList.getSelectedValue());
|
||||
}
|
||||
});
|
||||
menu.add(removeItem);
|
||||
menu.show(serversList, e.getX(), e.getY());
|
||||
} else if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
|
||||
serversList.setSelectedIndex(serversList.locationToIndex(e.getPoint()));
|
||||
ServerInfo server = serversList.getSelectedValue();
|
||||
if (server == null) return;
|
||||
connect(server);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JPanel buttonPanel = new JPanel();
|
||||
JButton addServerButton = new JButton("Add Server");
|
||||
addServerButton.addActionListener(e -> {
|
||||
// TODO: Add server dialog.
|
||||
});
|
||||
buttonPanel.add(addServerButton);
|
||||
|
||||
panel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
private boolean validateConnectInput(JTextField addressField, JTextField usernameField) {
|
||||
List<String> warnings = new ArrayList<>();
|
||||
if (addressField.getText() == null || addressField.getText().isBlank()) {
|
||||
warnings.add("Address must not be empty.");
|
||||
|
@ -124,6 +193,20 @@ public class Launcher extends JFrame {
|
|||
}
|
||||
}
|
||||
|
||||
private void connect(ServerInfo serverInfo) {
|
||||
String username = serverInfo.getUsername();
|
||||
if (username == null) {
|
||||
username = JOptionPane.showInputDialog(this, "Enter a username.", "Username", JOptionPane.PLAIN_MESSAGE);
|
||||
if (username == null || username.isBlank()) return;
|
||||
}
|
||||
try {
|
||||
new Client(serverInfo.getHostAddress(), serverInfo.getHostPort(), username);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
JOptionPane.showMessageDialog(this, "Could not connect:\n" + e.getMessage(), "Connection Error", JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
Launcher launcher = new Launcher();
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package nl.andrewlalis.aos_client.launcher.servers;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ServerInfo implements Comparable<ServerInfo> {
|
||||
private String name;
|
||||
private String host;
|
||||
private String username;
|
||||
|
||||
public ServerInfo(String name, String host, String username) {
|
||||
this.name = name;
|
||||
this.host = host;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getHostAddress() {
|
||||
return this.host.split(":")[0];
|
||||
}
|
||||
|
||||
public int getHostPort() {
|
||||
String[] parts = this.host.split(":");
|
||||
if (parts.length < 2) return 8035;
|
||||
return Integer.parseInt(parts[1]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ServerInfo that = (ServerInfo) o;
|
||||
return getName().equals(that.getName()) && getHost().equals(that.getHost()) && Objects.equals(getUsername(), that.getUsername());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getName(), getHost(), getUsername());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ServerInfo o) {
|
||||
return this.name.compareTo(o.name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package nl.andrewlalis.aos_client.launcher.servers;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
public class ServerInfoCellRenderer implements ListCellRenderer<ServerInfo> {
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<? extends ServerInfo> list, ServerInfo value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createTitledBorder(value.getName()));
|
||||
JTextField hostField = new JTextField(value.getHost());
|
||||
hostField.setEditable(false);
|
||||
panel.add(hostField, BorderLayout.CENTER);
|
||||
if (value.getUsername() != null) {
|
||||
panel.add(new JLabel("Username: " + value.getUsername()), BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
if (isSelected) {
|
||||
panel.setBackground(list.getSelectionBackground());
|
||||
panel.setForeground(list.getSelectionForeground());
|
||||
} else {
|
||||
panel.setBackground(list.getBackground());
|
||||
panel.setForeground(list.getForeground());
|
||||
}
|
||||
|
||||
return panel;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package nl.andrewlalis.aos_client.launcher.servers;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class ServerInfoListModel extends AbstractListModel<ServerInfo> {
|
||||
private final List<ServerInfo> servers;
|
||||
|
||||
public ServerInfoListModel() {
|
||||
this.servers = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void add(ServerInfo server) {
|
||||
if (this.servers.contains(server)) return;
|
||||
this.servers.add(server);
|
||||
this.servers.sort(Comparator.naturalOrder());
|
||||
this.fireContentsChanged(this, 0, this.getSize());
|
||||
}
|
||||
|
||||
public void remove(ServerInfo server) {
|
||||
int index = this.servers.indexOf(server);
|
||||
if (index == -1) return;
|
||||
this.servers.remove(index);
|
||||
this.fireIntervalRemoved(this, index, index);
|
||||
}
|
||||
|
||||
public void serverEdited() {
|
||||
this.fireContentsChanged(this, 0, this.getSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return this.servers.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerInfo getElementAt(int index) {
|
||||
return this.servers.get(index);
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
package nl.andrewlalis.aos_client.view;
|
||||
|
||||
import nl.andrewlalis.aos_client.Client;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ConnectDialog extends JDialog {
|
||||
private static final Pattern addressPattern = Pattern.compile("(.+):(\\d+)");
|
||||
|
||||
public ConnectDialog() {
|
||||
super((Frame) null, "Connect to Server", false);
|
||||
JPanel inputPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 0;
|
||||
inputPanel.add(new JLabel("Address"), c);
|
||||
JTextField addressField = new JTextField(20);
|
||||
c.gridx = 1;
|
||||
inputPanel.add(addressField, c);
|
||||
|
||||
c.gridy = 1;
|
||||
c.gridx = 0;
|
||||
inputPanel.add(new JLabel("Username"), c);
|
||||
JTextField usernameField = new JTextField(20);
|
||||
c.gridx = 1;
|
||||
inputPanel.add(usernameField, c);
|
||||
|
||||
var enterListener = new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
if (validateInput(addressField, usernameField)) {
|
||||
connect(addressField, usernameField);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
addressField.addKeyListener(enterListener);
|
||||
usernameField.addKeyListener(enterListener);
|
||||
|
||||
JPanel buttonPanel = new JPanel(new FlowLayout());
|
||||
JButton cancelButton = new JButton("Cancel");
|
||||
cancelButton.addActionListener(e -> this.dispose());
|
||||
JButton connectButton = new JButton("Connect");
|
||||
connectButton.addActionListener(e -> {
|
||||
if (validateInput(addressField, usernameField)) {
|
||||
connect(addressField, usernameField);
|
||||
}
|
||||
});
|
||||
buttonPanel.add(cancelButton);
|
||||
buttonPanel.add(connectButton);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout());
|
||||
mainPanel.add(inputPanel, BorderLayout.CENTER);
|
||||
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
|
||||
this.setContentPane(mainPanel);
|
||||
this.pack();
|
||||
this.setLocationRelativeTo(null);
|
||||
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
}
|
||||
|
||||
private boolean validateInput(JTextField addressField, JTextField usernameField) {
|
||||
List<String> warnings = new ArrayList<>();
|
||||
if (addressField.getText() == null || addressField.getText().isBlank()) {
|
||||
warnings.add("Address must not be empty.");
|
||||
}
|
||||
if (usernameField.getText() == null || usernameField.getText().isBlank()) {
|
||||
warnings.add("Username must not be empty.");
|
||||
}
|
||||
if (usernameField.getText() != null && usernameField.getText().length() > 16) {
|
||||
warnings.add("Username is too long.");
|
||||
}
|
||||
if (addressField.getText() != null && !addressPattern.matcher(addressField.getText()).matches()) {
|
||||
warnings.add("Address must be in the form HOST:PORT.");
|
||||
}
|
||||
if (!warnings.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(
|
||||
this,
|
||||
String.join("\n", warnings),
|
||||
"Invalid Input",
|
||||
JOptionPane.WARNING_MESSAGE
|
||||
);
|
||||
}
|
||||
return warnings.isEmpty();
|
||||
}
|
||||
|
||||
private void connect(JTextField addressField, JTextField usernameField) {
|
||||
String hostAndPort = addressField.getText();
|
||||
String[] parts = hostAndPort.split(":");
|
||||
String host = parts[0].trim();
|
||||
int port = Integer.parseInt(parts[1]);
|
||||
String username = usernameField.getText();
|
||||
try {
|
||||
new Client(host, port, username);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
JOptionPane.showMessageDialog(null, "Could not connect:\n" + ex.getMessage(), "Connection Error", JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue