8 Commits

Author SHA1 Message Date
545e7bacc6 Updates Paper, Vanilla and Waterfall verisions to 1.18
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-11-30 23:28:46 +01:00
b142b6d05e Small fix to use Paper/Travertine/Waterfall's updated API for downloading .jar files
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
Additionally fixes some formatting mistakes
Updates version to 1.4.1
2021-11-24 19:54:59 +01:00
166d63f1b2 Moves the show consoles button to the main control panel
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
Also makes the control servers tab hidden if the servers are not running
2021-10-01 13:56:16 +02:00
8f25fa2796 Fixes the font of the status label
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-10-01 01:26:28 +02:00
3467c900f0 Changes some variable names 2021-10-01 01:09:34 +02:00
9f092a73fe Extracts the control panel tab to its own class, and makes the add server button into a tab button 2021-10-01 00:58:00 +02:00
50b9188229 Makes sure all GUI windows have the same icon
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-09-30 17:47:12 +02:00
b021de5594 Replaces the "Remove server" button with an (X) on the tab itself
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-09-29 13:16:57 +02:00
24 changed files with 474 additions and 271 deletions

View File

@ -1,13 +1,14 @@
# Minecraft-Server-Launcher # Minecraft-Server-Launcher
I originally created this software in 2013 using AutoIt. After learning Java, I recreated it in Java.
The original version can be found at: https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncher/ I originally created this software in 2013 using AutoIt. After learning Java, I recreated it in Java. The original
version can be found at: https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncher/
This version's goal is to do everything the original does, just better. The original is 1595 lines of code repetition This version's goal is to do everything the original does, just better. The original is 1595 lines of code repetition
and dirty code. I had no prior programming experience when I first started working on the original, which is why it and dirty code. I had no prior programming experience when I first started working on the original, which is why it
became such a mess. became such a mess.
The software is in a fully working stage with a functional updater. The software is still in beta because there are still The software is in a fully working stage with a functional updater. The software is still in beta because there are
a lot of things I want to change and small annoyances. The software is fully portable. Make sure to put it in its own still a lot of things I want to change and small annoyances. The software is fully portable. Make sure to put it in its
folder as it will create lots of files. own folder as it will create lots of files.
The updater will move the new version to minecraft-server-launcher.jar, so you should rename the downloaded The updater will move the new version to minecraft-server-launcher.jar, so you should rename the downloaded file to this
file to this if it's named something else to avoid confusion. if it's named something else to avoid confusion.

View File

@ -1,3 +1,3 @@
As this is a personal one-man project, I prefer to stay in charge of the code. As this is a personal one-man project, I prefer to stay in charge of the code. I appreciate code fixing mistakes, or
I appreciate code fixing mistakes, or code improvements, but the software's functionality or purpose, should not be changed. code improvements, but the software's functionality or purpose, should not be changed. I might change anything at any
I might change anything at any time, so you might want to keep that in mind before doing big changes yourself. time, so you might want to keep that in mind before doing big changes yourself.

View File

@ -1,6 +1,7 @@
Fixes # . Fixes # .
Proposed changes: Proposed changes:
- -
- -
- -

View File

@ -141,14 +141,16 @@ public class Profile {
* @param name <p>The name of the collection and its elements</p> * @param name <p>The name of the collection and its elements</p>
*/ */
public void addCollection(String name) throws ConfigurationException { public void addCollection(String name) throws ConfigurationException {
if (name == null) { //If a user cancels or crosses out window //Skip if no name was given
if (name == null) {
return; return;
} }
if (getCollection(name) == null && !name.equals("All") && CommonFunctions.nameIsValid(name)) { if (getCollection(name) == null && !name.equals("All") && CommonFunctions.nameIsValid(name)) {
collections.add(new Collection(name)); collections.add(new Collection(name));
} else { } else {
serverLauncherGui.showError("A server name must my unique and not empty or \"All\"." + serverLauncherGui.showError("A server name must be unique and not empty. " +
"It can't contain any of the characters \"!\", \"?\" or \";\"."); "In addition, a server cannot be named: \"All\". " +
"It cannot contain any of the characters \"!\", \"?\" or \";\".");
} }
} }

View File

@ -379,7 +379,7 @@ public class ServerLauncherController {
* Updates the GUI as necessary to display loaded data * Updates the GUI as necessary to display loaded data
*/ */
private void executeGUILoadingTasks() { private void executeGUILoadingTasks() {
this.serverLauncherGUI.updateProfiles(); this.serverLauncherGUI.getControlPanelTab().updateProfiles();
this.serverLauncherGUI.updateWithSavedProfileData(); this.serverLauncherGUI.updateWithSavedProfileData();
this.currentProfile.updateConsoles(); this.currentProfile.updateConsoles();
if (this.downloadAllJars) { if (this.downloadAllJars) {

View File

@ -1,10 +1,10 @@
package net.knarcraft.minecraftserverlauncher.utility; package net.knarcraft.minecraftserverlauncher.server;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.server.ServerVersionContainer;
import net.knarcraft.minecraftserverlauncher.userinterface.GUI; import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI; import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;

View File

@ -377,7 +377,8 @@ public class Server {
if (Integer.parseInt(serverVersion.split("\\.")[1]) >= 17) { if (Integer.parseInt(serverVersion.split("\\.")[1]) >= 17) {
return controller.getJavaCommand(); return controller.getJavaCommand();
} }
} catch (NumberFormatException ignored) {} } catch (NumberFormatException ignored) {
}
} }
return controller.getOldJavaCommand(); return controller.getOldJavaCommand();
} }

View File

@ -311,7 +311,7 @@ public class ServerVersionContainer {
/** /**
* Sets the current version for a given paper version * Sets the current version for a given paper version
* *
* @param mapKey <p>The version key to set version for</p> * @param mapKey <p>The version key to set version for</p>
* @param newValue <p>The new current version</p> * @param newValue <p>The new current version</p>
*/ */
public void setPaperVersion(String mapKey, String newValue) { public void setPaperVersion(String mapKey, String newValue) {

View File

@ -2,8 +2,8 @@ package net.knarcraft.minecraftserverlauncher.server.servertypes;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.server.JarBuilder;
import net.knarcraft.minecraftserverlauncher.userinterface.GUI; import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
import net.knarcraft.minecraftserverlauncher.utility.JarBuilder;
import java.io.File; import java.io.File;
import java.nio.file.Paths; import java.nio.file.Paths;

View File

@ -50,13 +50,21 @@ public class Waterfall extends AbstractServerType {
public boolean downloadJar(String folder, String version) throws IOException { public boolean downloadJar(String folder, String version) throws IOException {
String file = this.getName() + version + ".jar"; String file = this.getName() + version + ".jar";
File filePath = new File(folder + file); File filePath = new File(folder + file);
String newestVersion = stringBetween(readRemoteFile(versionURL + version), srcStart, srcEnd); String versionFileContents = readRemoteFile(versionURL + version);
String fullURL = downloadURL + version + "/" + newestVersion + "/download"; String[] versions = stringBetween(versionFileContents, srcStart, srcEnd).split(",");
String newestVersion = versions[versions.length - 1];
String oldVersion = oldVersionFunction.apply(version); String oldVersion = oldVersionFunction.apply(version);
//The file is already the newest version //The file is already the newest version
if (filePath.isFile() && newestVersion.equals(oldVersion)) { if (filePath.isFile() && newestVersion.equals(oldVersion)) {
return true; return true;
} }
//Get necessary information for downloading the latest version
String newestVersionInfoURL = versionURL + version + "/builds/" + newestVersion;
String fileName = stringBetween(readRemoteFile(newestVersionInfoURL), "\"name\":\"", "\"");
String fullURL = downloadURL + version + "/builds/" + newestVersion + "/downloads/" + fileName;
//The new jar file could not be downloaded //The new jar file could not be downloaded
if (!downloadFile(fullURL, Paths.get(filePath.toURI()))) { if (!downloadFile(fullURL, Paths.get(filePath.toURI()))) {
return false; return false;
@ -64,4 +72,5 @@ public class Waterfall extends AbstractServerType {
versionUpdateFunction.accept(version, newestVersion); versionUpdateFunction.accept(version, newestVersion);
return true; return true;
} }
} }

View File

@ -2,10 +2,14 @@ package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.utility.BackupUtil; import net.knarcraft.minecraftserverlauncher.utility.BackupUtil;
import javax.imageio.ImageIO;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.io.IOException;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream;
/** /**
* The Backup GUI is used to display backup progress * The Backup GUI is used to display backup progress
@ -33,6 +37,13 @@ public class BackupGUI implements ActionListener {
frame = new JFrame("Running backup..."); frame = new JFrame("Running backup...");
frame.setBounds(100, 100, 500, 140); frame.setBounds(100, 100, 500, 140);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
ImageIcon img;
try {
img = new ImageIcon(ImageIO.read(getResourceAsStream("GUIIcon.png")));
frame.setIconImage(img.getImage());
} catch (IOException ignored) {
}
progressTextArea = new JTextArea(); progressTextArea = new JTextArea();
progressTextArea.setEditable(false); progressTextArea.setEditable(false);
progressBar = new JProgressBar(); progressBar = new JProgressBar();
@ -40,7 +51,7 @@ public class BackupGUI implements ActionListener {
JPanel panel = new JPanel(); JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
panel.add(progressTextArea); panel.add(progressTextArea);
panel.add(Box.createRigidArea(new Dimension(0,5))); panel.add(Box.createRigidArea(new Dimension(0, 5)));
panel.add(progressBar); panel.add(progressBar);
JPanel buttonPane = new JPanel(); JPanel buttonPane = new JPanel();
@ -60,7 +71,7 @@ public class BackupGUI implements ActionListener {
/** /**
* Updates information about the backup progress * Updates information about the backup progress
* *
* @param infoText <p>The text to display</p> * @param infoText <p>The text to display</p>
* @param progressPercent <p>The new percent of the progress bar</p> * @param progressPercent <p>The new percent of the progress bar</p>
*/ */
public static void updateProgress(String infoText, int progressPercent) { public static void updateProgress(String infoText, int progressPercent) {

View File

@ -0,0 +1,48 @@
package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Listener for clicking the close button of a server tab
*/
public class CloseTabActionListener implements ActionListener {
private final String tabName;
private final JTabbedPane tabPane;
/**
* Instantiates a new close tab action listener
*
* @param tabPane <p>The tab pane containing all tabs</p>
* @param tabName <p>The name of the tab connected to this action listener</p>
*/
public CloseTabActionListener(JTabbedPane tabPane, String tabName) {
this.tabName = tabName;
this.tabPane = tabPane;
}
@Override
public void actionPerformed(ActionEvent evt) {
int index = tabPane.indexOfTab(tabName);
if (index >= 0) {
//Abort if the user just mis-clicked
int answer = JOptionPane.showConfirmDialog(null,
String.format("Do you really want to remove the server %s?", tabName), "Remove server",
JOptionPane.YES_NO_OPTION
);
if (answer == JOptionPane.YES_NO_OPTION) {
//Remove the server
ServerLauncherController controller = Main.getController();
controller.getCurrentProfile().removeCollection(tabName);
controller.getGUI().updateWithSavedProfileData();
controller.getCurrentProfile().updateConsoles();
}
}
}
}

View File

@ -0,0 +1,218 @@
package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.server.ServerHandler;
import net.knarcraft.minecraftserverlauncher.utility.BackupUtil;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.concurrent.Executors;
public class ControlPanelTab implements ActionListener {
private JButton startServerButton;
private JButton stopServerButton;
private JButton backupButton;
private JButton addProfileButton;
private JButton showConsolesButton;
private JButton deleteProfileButton;
private JComboBox<String> profiles;
private final JPanel controlPanelPanel;
private final ServerLauncherController controller;
private final JLabel statusLabel = new JLabel("Servers are stopped");
public ControlPanelTab(JPanel controlPanelPanel) {
this.controlPanelPanel = controlPanelPanel;
this.controller = Main.getController();
initialize();
}
/**
* Sets the text of the status label
*
* @param text <p>The new text of the status label</p>
*/
public void setStatusText(String text) {
this.statusLabel.setText(text);
}
/**
* Updates the ServerLauncherGUI components to block a user from doing illegal actions
*
* @param running <p>Whether the servers are currently running</p>
*/
public void updateGUIElementsWhenServersStartOrStop(boolean running) {
boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running.
profiles.setEnabled(stopped);
addProfileButton.setEnabled(stopped);
deleteProfileButton.setEnabled(stopped);
startServerButton.setEnabled(stopped);
stopServerButton.setEnabled(running);
}
/**
* Stops all servers
*/
public void stopServers() {
GUI gui = Main.getController().getGUI();
try {
gui.setStatus("Servers are stopping...");
ServerHandler.stop();
} catch (IOException e1) {
gui.showError("Could not stop server.");
e1.printStackTrace();
} catch (InterruptedException e) {
gui.showError("Could not kill server.");
e.printStackTrace();
}
}
/**
* Gets the currently selected profile
*
* @return <p>The currently selected profile or null</p>
*/
public String getSelectedProfile() {
Object selectedProfile = profiles.getSelectedItem();
if (selectedProfile != null) {
return selectedProfile.toString();
} else {
return null;
}
}
/**
* Updates the profiles combo
*/
public void updateProfiles() {
String selectedProfile = Main.getController().getCurrentProfile().getName();
this.profiles.removeAllItems();
for (String profile : Main.getController().getProfileNames()) {
this.profiles.addItem(profile);
}
this.profiles.setSelectedItem(selectedProfile);
}
/**
* Deletes the selected profile
*/
private void deleteProfile() {
Object selected = profiles.getSelectedItem();
int answer = JOptionPane.showConfirmDialog(null,
String.format("Do you really want to remove the profile %s?", selected), "Remove profile",
JOptionPane.YES_NO_OPTION
);
if (answer == JOptionPane.YES_NO_OPTION) {
if (selected != null) {
controller.removeProfile(selected.toString());
updateProfiles();
}
}
}
/**
* Saves the previous profile and loads data from the new profile
*/
private void changeProfile() {
controller.saveState();
Object current = this.profiles.getSelectedItem();
if (current != null) {
controller.setCurrentProfile(current.toString());
}
controller.getGUI().updateWithSavedProfileData();
controller.getCurrentProfile().updateConsoles();
}
private void initialize() {
SpringLayout springLayout = new SpringLayout();
controlPanelPanel.setLayout(springLayout);
JLabel lblBasicControls = new JLabel("Basic controls");
springLayout.putConstraint(SpringLayout.NORTH, lblBasicControls, 10, SpringLayout.NORTH, controlPanelPanel);
controlPanelPanel.add(lblBasicControls);
startServerButton = new JButton("Start servers");
springLayout.putConstraint(SpringLayout.WEST, lblBasicControls, 0, SpringLayout.WEST, startServerButton);
springLayout.putConstraint(SpringLayout.NORTH, startServerButton, 6, SpringLayout.SOUTH, lblBasicControls);
springLayout.putConstraint(SpringLayout.WEST, startServerButton, 10, SpringLayout.WEST, controlPanelPanel);
controlPanelPanel.add(startServerButton);
startServerButton.addActionListener(this);
stopServerButton = new JButton("Stop servers");
springLayout.putConstraint(SpringLayout.NORTH, stopServerButton, 0, SpringLayout.NORTH, startServerButton);
springLayout.putConstraint(SpringLayout.WEST, stopServerButton, 6, SpringLayout.EAST, startServerButton);
controlPanelPanel.add(stopServerButton);
stopServerButton.addActionListener(this);
showConsolesButton = new JButton("View server consoles");
springLayout.putConstraint(SpringLayout.NORTH, showConsolesButton, 0, SpringLayout.NORTH, stopServerButton);
springLayout.putConstraint(SpringLayout.WEST, showConsolesButton, 6, SpringLayout.EAST, stopServerButton);
controlPanelPanel.add(showConsolesButton);
showConsolesButton.addActionListener(this);
backupButton = new JButton("Backup");
springLayout.putConstraint(SpringLayout.NORTH, backupButton, 0, SpringLayout.NORTH, showConsolesButton);
springLayout.putConstraint(SpringLayout.WEST, backupButton, 6, SpringLayout.EAST, showConsolesButton);
controlPanelPanel.add(backupButton);
backupButton.addActionListener(this);
JLabel profileLabel = new JLabel("Profile");
springLayout.putConstraint(SpringLayout.NORTH, profileLabel, 6, SpringLayout.SOUTH, startServerButton);
springLayout.putConstraint(SpringLayout.WEST, profileLabel, 10, SpringLayout.WEST, controlPanelPanel);
controlPanelPanel.add(profileLabel);
addProfileButton = new JButton("+");
springLayout.putConstraint(SpringLayout.NORTH, addProfileButton, 6, SpringLayout.SOUTH, profileLabel);
springLayout.putConstraint(SpringLayout.WEST, addProfileButton, 10, SpringLayout.WEST, controlPanelPanel);
controlPanelPanel.add(addProfileButton);
addProfileButton.addActionListener(this);
deleteProfileButton = new JButton("-");
springLayout.putConstraint(SpringLayout.NORTH, deleteProfileButton, 0, SpringLayout.NORTH, addProfileButton);
springLayout.putConstraint(SpringLayout.WEST, deleteProfileButton, 6, SpringLayout.EAST, addProfileButton);
controlPanelPanel.add(deleteProfileButton);
deleteProfileButton.addActionListener(this);
profiles = new JComboBox<>();
springLayout.putConstraint(SpringLayout.NORTH, profiles, 0, SpringLayout.NORTH, addProfileButton);
springLayout.putConstraint(SpringLayout.WEST, profiles, 6, SpringLayout.EAST, deleteProfileButton);
springLayout.putConstraint(SpringLayout.EAST, profiles, 124, SpringLayout.EAST, deleteProfileButton);
controlPanelPanel.add(profiles);
profiles.addActionListener(this);
springLayout.putConstraint(SpringLayout.NORTH, statusLabel, 6, SpringLayout.SOUTH, addProfileButton);
springLayout.putConstraint(SpringLayout.SOUTH, statusLabel, -10, SpringLayout.SOUTH, controlPanelPanel);
springLayout.putConstraint(SpringLayout.WEST, statusLabel, 10, SpringLayout.WEST, controlPanelPanel);
springLayout.putConstraint(SpringLayout.EAST, statusLabel, -10, SpringLayout.EAST, controlPanelPanel);
statusLabel.setFont(new Font("", Font.BOLD, 12));
controlPanelPanel.add(statusLabel);
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
Object actionSource = actionEvent.getSource();
if (actionSource == startServerButton) {
controller.saveState();
Executors.newSingleThreadExecutor().execute(ServerHandler::startServers);
} else if (actionSource == stopServerButton) {
stopServers();
} else if (actionSource == backupButton) {
//Run backup in its own thread to prevent locking up
Executors.newSingleThreadExecutor().execute(() -> BackupUtil.backup(controller.getGUI()));
} else if (actionSource == addProfileButton) {
controller.addProfile(JOptionPane.showInputDialog("Profile name: "));
updateProfiles();
} else if (actionSource == deleteProfileButton) {
deleteProfile();
} else if (actionSource == profiles) {
changeProfile();
} else if (actionSource == showConsolesButton) {
ServerConsoles.setAsVisible();
}
}
}

View File

@ -1,7 +1,11 @@
package net.knarcraft.minecraftserverlauncher.userinterface; package net.knarcraft.minecraftserverlauncher.userinterface;
import javax.imageio.ImageIO;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.io.IOException;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream;
/** /**
* This class keeps track of all consoles * This class keeps track of all consoles
@ -31,6 +35,12 @@ public class ServerConsoles {
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
consolesTabbedPane = new JTabbedPane(JTabbedPane.TOP); consolesTabbedPane = new JTabbedPane(JTabbedPane.TOP);
frame.getContentPane().add(consolesTabbedPane, BorderLayout.CENTER); frame.getContentPane().add(consolesTabbedPane, BorderLayout.CENTER);
ImageIcon img;
try {
img = new ImageIcon(ImageIO.read(getResourceAsStream("GUIIcon.png")));
frame.setIconImage(img.getImage());
} catch (IOException ignored) {
}
} }
} }

View File

@ -22,7 +22,6 @@ public class ServerControlTab implements ActionListener {
private JButton customCommandButton; private JButton customCommandButton;
private JButton saveServerButton; private JButton saveServerButton;
private JButton reloadButton; private JButton reloadButton;
private JButton showConsolesButton;
private JTextField customCommandTextField; private JTextField customCommandTextField;
private final ServerLauncherController controller = ServerLauncherController.getInstance(); private final ServerLauncherController controller = ServerLauncherController.getInstance();
@ -134,13 +133,6 @@ public class ServerControlTab implements ActionListener {
springLayout.putConstraint(SpringLayout.EAST, reloadButton, 0, SpringLayout.EAST, opButton); springLayout.putConstraint(SpringLayout.EAST, reloadButton, 0, SpringLayout.EAST, opButton);
controlServers.add(reloadButton); controlServers.add(reloadButton);
reloadButton.addActionListener(this); reloadButton.addActionListener(this);
showConsolesButton = new JButton("View server consoles");
springLayout.putConstraint(SpringLayout.NORTH, showConsolesButton, 0, SpringLayout.NORTH, saveServerButton);
springLayout.putConstraint(SpringLayout.WEST, showConsolesButton, 0, SpringLayout.WEST, lblTargetServer);
springLayout.putConstraint(SpringLayout.EAST, showConsolesButton, 0, SpringLayout.EAST, targetServerCombo);
controlServers.add(showConsolesButton);
showConsolesButton.addActionListener(this);
} }
/** /**
@ -181,9 +173,7 @@ public class ServerControlTab implements ActionListener {
//Registers actions on all commands executed on a specific server //Registers actions on all commands executed on a specific server
handleServerCommands(actionSource, selectedServerValue); handleServerCommands(actionSource, selectedServerValue);
if (actionSource == showConsolesButton) { if (actionSource == targetServerCombo) {
ServerConsoles.setAsVisible();
} else if (actionSource == targetServerCombo) {
updatePlayers(); updatePlayers();
} }
} }

View File

@ -3,12 +3,11 @@ package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.Collection;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.server.ServerHandler;
import net.knarcraft.minecraftserverlauncher.utility.BackupUtil;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import javax.swing.*; import javax.swing.*;
import javax.swing.plaf.basic.BasicButtonUI;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
@ -18,7 +17,6 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Scanner; import java.util.Scanner;
import java.util.concurrent.Executors;
import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE; import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner;
@ -33,25 +31,19 @@ import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getR
*/ */
public class ServerLauncherGUI extends MessageHandler implements ActionListener, GUI { public class ServerLauncherGUI extends MessageHandler implements ActionListener, GUI {
private final JLabel lblStatusLabel = new JLabel("Servers are stopped");
private final ServerLauncherController controller; private final ServerLauncherController controller;
private Map<String, String> textStrings; private Map<String, String> textStrings;
private Tray applicationTray; private Tray applicationTray;
private JFrame frame; private JFrame frame;
private JTabbedPane tabbedPane; private JTabbedPane mainTabbedPane;
private JTabbedPane serversPane; private JTabbedPane serversPane;
private ServerControlTab serverControlTab; private ServerControlTab serverControlTab;
private ControlPanelTab controlPanelTab;
private ServerLauncherMenu serverLauncherMenu; private ServerLauncherMenu serverLauncherMenu;
//Basic controls private JButton addServerTabButton;
private JButton startServerButton; private JButton addServerPaneButton;
private JButton stopServerButton;
private JButton addServerButton;
private JButton backupButton;
private JButton addProfileButton;
private JButton deleteProfileButton;
private JComboBox<String> profiles;
/** /**
* Creates the application window * Creates the application window
@ -99,9 +91,18 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
return this.serversPane; return this.serversPane;
} }
/**
* Gets this GUI's control panel tab
*
* @return <p>The control panel tab for this GUI</p>
*/
public ControlPanelTab getControlPanelTab() {
return this.controlPanelTab;
}
@Override @Override
public void setStatus(String text) { public void setStatus(String text) {
this.lblStatusLabel.setText(text); controlPanelTab.setStatusText(text);
this.logMessage(text); this.logMessage(text);
} }
@ -120,18 +121,6 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
return chooser.getSelectedFile(); return chooser.getSelectedFile();
} }
/**
* Updates the profiles combo
*/
public void updateProfiles() {
String selectedProfile = Main.getController().getCurrentProfile().getName();
this.profiles.removeAllItems();
for (String profile : Main.getController().getProfileNames()) {
this.profiles.addItem(profile);
}
this.profiles.setSelectedItem(selectedProfile);
}
/** /**
* Gets the server control tab used by this GUI * Gets the server control tab used by this GUI
* *
@ -160,7 +149,82 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
serverControlTab.update(); serverControlTab.update();
for (Collection collection : controller.getCurrentProfile().getCollections()) { for (Collection collection : controller.getCurrentProfile().getCollections()) {
serversPane.addTab(collection.getName(), collection.getServerTab().getPanel()); serversPane.addTab(collection.getName(), collection.getServerTab().getPanel());
addCloseButtonToServerTab(collection.getName());
} }
addAddButtonToServerTab();
}
/**
* Adds an add button to the servers tab's tabs
*/
private void addAddButtonToServerTab() {
JPanel tabPanel = new JPanel();
tabPanel.setLayout(new GridLayout());
tabPanel.setOpaque(false);
JPanel tabContentsPanel = new JPanel(new SpringLayout());
serversPane.addTab("Add tab", tabContentsPanel);
addServerTabButton = getAddServerButton(true);
addServerTabButton.addActionListener(this);
addServerPaneButton = getAddServerButton(false);
addServerPaneButton.addActionListener(this);
tabContentsPanel.add(addServerTabButton);
tabPanel.add(addServerPaneButton);
serversPane.setTabComponentAt(serversPane.getTabCount() - 1, tabPanel);
}
/**
* Gets a button for adding a new server
*
* @param displayButtonStyle <p>Whether to show or hide the button's style</p>
* @return <p>A new add server button</p>
*/
private JButton getAddServerButton(boolean displayButtonStyle) {
JButton addButton = new JButton("+ Add server");
if (!displayButtonStyle) {
addButton.setBorder(BorderFactory.createEtchedBorder());
addButton.setFocusable(false);
addButton.setBorderPainted(false);
addButton.setContentAreaFilled(false);
addButton.setRolloverEnabled(true);
addButton.setUI(new BasicButtonUI());
}
return addButton;
}
/**
* @param serverName <p>The name of the server/tab to add a close button to</p>
*/
private void addCloseButtonToServerTab(String serverName) {
int index = serversPane.indexOfTab(serverName);
JPanel tabPanel = new JPanel(new GridBagLayout());
tabPanel.setOpaque(false);
JLabel serverTitleLabel = new JLabel(serverName);
JButton removeServerButton = new JButton("(X)");
removeServerButton.setBorder(BorderFactory.createEtchedBorder());
removeServerButton.setFocusable(false);
removeServerButton.setBorderPainted(false);
removeServerButton.setContentAreaFilled(false);
removeServerButton.setRolloverEnabled(true);
removeServerButton.setPreferredSize(new Dimension(18, 17));
removeServerButton.setUI(new BasicButtonUI());
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.weightx = 1;
tabPanel.add(serverTitleLabel, gridBagConstraints);
gridBagConstraints.gridx++;
gridBagConstraints.weightx = 0;
tabPanel.add(removeServerButton, gridBagConstraints);
serversPane.setTabComponentAt(index, tabPanel);
removeServerButton.addActionListener(new CloseTabActionListener(serversPane, serverName));
} }
/** /**
@ -194,93 +258,30 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
this.serverLauncherMenu = new ServerLauncherMenu(menuBar, this); this.serverLauncherMenu = new ServerLauncherMenu(menuBar, this);
tabbedPane = new JTabbedPane(JTabbedPane.TOP); mainTabbedPane = new JTabbedPane(JTabbedPane.TOP);
frame.getContentPane().add(tabbedPane); frame.getContentPane().add(mainTabbedPane);
JPanel panelBasic = new JPanel(); JPanel controlPanelPanel = new JPanel();
tabbedPane.addTab("Control panel", null, panelBasic, null); mainTabbedPane.addTab("Control panel", null, controlPanelPanel, null);
SpringLayout sl_panel = new SpringLayout(); controlPanelTab = new ControlPanelTab(controlPanelPanel);
panelBasic.setLayout(sl_panel);
JLabel lblBasicControls = new JLabel("Basic controls"); JPanel controlServersPanel = new JPanel();
sl_panel.putConstraint(SpringLayout.NORTH, lblBasicControls, 10, SpringLayout.NORTH, panelBasic); mainTabbedPane.addTab("Control servers", null, controlServersPanel, null);
panelBasic.add(lblBasicControls); serverControlTab = new ServerControlTab(frame, controlServersPanel);
startServerButton = new JButton("Start servers"); JPanel serversPanel = new JPanel();
sl_panel.putConstraint(SpringLayout.WEST, lblBasicControls, 0, SpringLayout.WEST, startServerButton); mainTabbedPane.addTab("Servers", null, serversPanel, null);
sl_panel.putConstraint(SpringLayout.NORTH, startServerButton, 6, SpringLayout.SOUTH, lblBasicControls); SpringLayout serversPanelSpringLayout = new SpringLayout();
sl_panel.putConstraint(SpringLayout.WEST, startServerButton, 10, SpringLayout.WEST, panelBasic); serversPanel.setLayout(serversPanelSpringLayout);
panelBasic.add(startServerButton);
startServerButton.addActionListener(this);
stopServerButton = new JButton("Stop servers"); serversPane = new JTabbedPane(JTabbedPane.TOP);
sl_panel.putConstraint(SpringLayout.NORTH, stopServerButton, 0, SpringLayout.NORTH, startServerButton); serversPanelSpringLayout.putConstraint(SpringLayout.NORTH, serversPane, 0, SpringLayout.NORTH, serversPanel);
sl_panel.putConstraint(SpringLayout.WEST, stopServerButton, 6, SpringLayout.EAST, startServerButton); serversPanelSpringLayout.putConstraint(SpringLayout.WEST, serversPane, 0, SpringLayout.WEST, serversPanel);
panelBasic.add(stopServerButton); serversPanelSpringLayout.putConstraint(SpringLayout.SOUTH, serversPane, 0, SpringLayout.SOUTH, serversPanel);
stopServerButton.addActionListener(this); serversPanelSpringLayout.putConstraint(SpringLayout.EAST, serversPane, 0, SpringLayout.EAST, serversPanel);
serversPanel.add(serversPane);
JLabel lblProfile = new JLabel("Profile"); serversPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
sl_panel.putConstraint(SpringLayout.NORTH, lblProfile, 6, SpringLayout.SOUTH, startServerButton);
sl_panel.putConstraint(SpringLayout.WEST, lblProfile, 10, SpringLayout.WEST, panelBasic);
panelBasic.add(lblProfile);
addProfileButton = new JButton("+");
sl_panel.putConstraint(SpringLayout.NORTH, addProfileButton, 6, SpringLayout.SOUTH, lblProfile);
sl_panel.putConstraint(SpringLayout.WEST, addProfileButton, 10, SpringLayout.WEST, panelBasic);
panelBasic.add(addProfileButton);
addProfileButton.addActionListener(this);
deleteProfileButton = new JButton("-");
sl_panel.putConstraint(SpringLayout.NORTH, deleteProfileButton, 0, SpringLayout.NORTH, addProfileButton);
sl_panel.putConstraint(SpringLayout.WEST, deleteProfileButton, 6, SpringLayout.EAST, addProfileButton);
panelBasic.add(deleteProfileButton);
deleteProfileButton.addActionListener(this);
profiles = new JComboBox<>();
sl_panel.putConstraint(SpringLayout.NORTH, profiles, 0, SpringLayout.NORTH, addProfileButton);
sl_panel.putConstraint(SpringLayout.WEST, profiles, 6, SpringLayout.EAST, deleteProfileButton);
sl_panel.putConstraint(SpringLayout.EAST, profiles, 124, SpringLayout.EAST, deleteProfileButton);
panelBasic.add(profiles);
profiles.addActionListener(this);
sl_panel.putConstraint(SpringLayout.NORTH, lblStatusLabel, 6, SpringLayout.SOUTH, addProfileButton);
sl_panel.putConstraint(SpringLayout.SOUTH, lblStatusLabel, -10, SpringLayout.SOUTH, panelBasic);
sl_panel.putConstraint(SpringLayout.WEST, lblStatusLabel, 10, SpringLayout.WEST, panelBasic);
sl_panel.putConstraint(SpringLayout.EAST, lblStatusLabel, -10, SpringLayout.EAST, panelBasic);
panelBasic.add(lblStatusLabel);
addServerButton = new JButton("Add server");
sl_panel.putConstraint(SpringLayout.NORTH, addServerButton, 0, SpringLayout.NORTH, startServerButton);
sl_panel.putConstraint(SpringLayout.WEST, addServerButton, 6, SpringLayout.EAST, stopServerButton);
panelBasic.add(addServerButton);
addServerButton.addActionListener(this);
backupButton = new JButton("Backup");
sl_panel.putConstraint(SpringLayout.NORTH, backupButton, 0, SpringLayout.NORTH, startServerButton);
sl_panel.putConstraint(SpringLayout.WEST, backupButton, 6, SpringLayout.EAST, addServerButton);
panelBasic.add(backupButton);
backupButton.addActionListener(this);
JPanel controlServers = new JPanel();
tabbedPane.addTab("Control servers", null, controlServers, null);
serverControlTab = new ServerControlTab(frame, controlServers);
JPanel panel_2 = new JPanel();
tabbedPane.addTab("Servers", null, panel_2, null);
SpringLayout sl_panel_2 = new SpringLayout();
panel_2.setLayout(sl_panel_2);
JTabbedPane tabbedPane_1 = new JTabbedPane(JTabbedPane.TOP);
sl_panel_2.putConstraint(SpringLayout.NORTH, tabbedPane_1, 0, SpringLayout.NORTH, panel_2);
sl_panel_2.putConstraint(SpringLayout.WEST, tabbedPane_1, 0, SpringLayout.WEST, panel_2);
sl_panel_2.putConstraint(SpringLayout.SOUTH, tabbedPane_1, 0, SpringLayout.SOUTH, panel_2);
sl_panel_2.putConstraint(SpringLayout.EAST, tabbedPane_1, 0, SpringLayout.EAST, panel_2);
panel_2.add(tabbedPane_1);
this.serversPane = tabbedPane_1;
tabbedPane_1.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
frame.validate(); frame.validate();
frame.pack(); frame.pack();
@ -296,21 +297,6 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
applicationTray.hideToTray(); applicationTray.hideToTray();
} }
/**
* Gets the currently selected profile
*
* @return <p>The currently selected profile or null</p>
*/
public String getSelectedProfile() {
Object selectedProfile = profiles.getSelectedItem();
if (selectedProfile != null) {
return selectedProfile.toString();
} else {
return null;
}
}
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
Object actionSource = e.getSource(); Object actionSource = e.getSource();
@ -325,34 +311,8 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
* @param actionSource <p>The object being interacted with</p> * @param actionSource <p>The object being interacted with</p>
*/ */
private void handleMainTabButtons(Object actionSource) { private void handleMainTabButtons(Object actionSource) {
if (actionSource == startServerButton) { if (actionSource == addServerTabButton || actionSource == addServerPaneButton) {
controller.saveState();
Executors.newSingleThreadExecutor().execute(ServerHandler::startServers);
} else if (actionSource == stopServerButton) {
stopServers();
} else if (actionSource == addServerButton) {
addServer(); addServer();
} else if (actionSource == backupButton) {
//Run backup in its own thread to prevent locking up
Executors.newSingleThreadExecutor().execute(() -> BackupUtil.backup(this));
} else if (actionSource == addProfileButton) {
controller.addProfile(JOptionPane.showInputDialog("Profile name: "));
updateProfiles();
} else if (actionSource == deleteProfileButton) {
deleteProfile();
} else if (actionSource == profiles) {
changeProfile();
}
}
/**
* Deletes the selected profile
*/
private void deleteProfile() {
Object selected = profiles.getSelectedItem();
if (selected != null) {
controller.removeProfile(selected.toString());
updateProfiles();
} }
} }
@ -377,42 +337,9 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
*/ */
public void updateGUIElementsWhenServersStartOrStop(boolean running) { public void updateGUIElementsWhenServersStartOrStop(boolean running) {
boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running. boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running.
profiles.setEnabled(stopped); mainTabbedPane.setEnabledAt(1, !stopped);
addProfileButton.setEnabled(stopped); mainTabbedPane.setEnabledAt(2, stopped);
deleteProfileButton.setEnabled(stopped); controlPanelTab.updateGUIElementsWhenServersStartOrStop(running);
startServerButton.setEnabled(stopped);
addServerButton.setEnabled(stopped);
tabbedPane.setEnabledAt(2, stopped);
stopServerButton.setEnabled(running);
}
/**
* Saves the previous profile and loads data from the new profile
*/
private void changeProfile() {
controller.saveState();
Object current = this.profiles.getSelectedItem();
if (current != null) {
controller.setCurrentProfile(current.toString());
}
this.updateWithSavedProfileData();
controller.getCurrentProfile().updateConsoles();
}
/**
* Stops all servers
*/
public void stopServers() {
try {
setStatus("Servers are stopping...");
ServerHandler.stop();
} catch (IOException e1) {
showError("Could not stop server.");
e1.printStackTrace();
} catch (InterruptedException e) {
showError("Could not kill server.");
e.printStackTrace();
}
} }
/** /**

View File

@ -164,7 +164,7 @@ public class ServerLauncherMenu implements ActionListener {
* Creates a checkbox menu item * Creates a checkbox menu item
* *
* @param itemName <p>The name of the new checkbox item</p> * @param itemName <p>The name of the new checkbox item</p>
* @param parent <p>The parent menu the item belongs to</p> * @param parent <p>The parent menu the item belongs to</p>
* @return <p>The created checkbox menu item</p> * @return <p>The created checkbox menu item</p>
*/ */
private JCheckBoxMenuItem createCheckBoxMenuItem(String itemName, JMenu parent) { private JCheckBoxMenuItem createCheckBoxMenuItem(String itemName, JMenu parent) {
@ -178,7 +178,7 @@ public class ServerLauncherMenu implements ActionListener {
* Creates a menu item * Creates a menu item
* *
* @param itemName <p>The name of the new item</p> * @param itemName <p>The name of the new item</p>
* @param parent <p>The parent menu the item belongs to</p> * @param parent <p>The parent menu the item belongs to</p>
* @return <p>The created menu item</p> * @return <p>The created menu item</p>
*/ */
private JMenuItem createMenuItem(String itemName, JMenu parent) { private JMenuItem createMenuItem(String itemName, JMenu parent) {
@ -190,6 +190,7 @@ public class ServerLauncherMenu implements ActionListener {
/** /**
* Asks the user for the new Java path * Asks the user for the new Java path
*
* @param old <p>Whether asking for the path to the old java version</p> * @param old <p>Whether asking for the path to the old java version</p>
*/ */
private void configureJava(boolean old) { private void configureJava(boolean old) {
@ -237,7 +238,7 @@ public class ServerLauncherMenu implements ActionListener {
* Asks the user for a delay if checked, and sets the value to the current profile * Asks the user for a delay if checked, and sets the value to the current profile
*/ */
private void delay() { private void delay() {
String selectedProfile = serverLauncherGUI.getSelectedProfile(); String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
if (selectedProfile != null) { if (selectedProfile != null) {
Profile profile = controller.getProfileByName(selectedProfile); Profile profile = controller.getProfileByName(selectedProfile);
if (delayStartupCheckBoxMenuItem.isSelected()) { if (delayStartupCheckBoxMenuItem.isSelected()) {
@ -260,7 +261,7 @@ public class ServerLauncherMenu implements ActionListener {
* Saves the runInBackground setting to the current profile * Saves the runInBackground setting to the current profile
*/ */
private void background() { private void background() {
String selectedProfile = serverLauncherGUI.getSelectedProfile(); String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
if (selectedProfile != null) { if (selectedProfile != null) {
Profile profile = controller.getProfileByName(selectedProfile); Profile profile = controller.getProfileByName(selectedProfile);
Objects.requireNonNull(profile).setRunInBackground(runInBackgroundCheckBoxMenuItem.isSelected()); Objects.requireNonNull(profile).setRunInBackground(runInBackgroundCheckBoxMenuItem.isSelected());
@ -273,7 +274,7 @@ public class ServerLauncherMenu implements ActionListener {
* Saves the downloadJars setting to the current profile * Saves the downloadJars setting to the current profile
*/ */
private void downloadJars() { private void downloadJars() {
String selectedProfile = serverLauncherGUI.getSelectedProfile(); String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
if (selectedProfile != null) { if (selectedProfile != null) {
controller.setDownloadAllJars(downloadJarsCheckBoxMenuItem.isSelected()); controller.setDownloadAllJars(downloadJarsCheckBoxMenuItem.isSelected());
} else { } else {

View File

@ -23,11 +23,9 @@ public class ServerTab implements ActionListener {
private final JComboBox<String> serverVersions; private final JComboBox<String> serverVersions;
private final JComboBox<String> maxRam; private final JComboBox<String> maxRam;
private final JCheckBox enabledCheckbox; private final JCheckBox enabledCheckbox;
private final JButton removeServerButton;
private final JButton browseButton; private final JButton browseButton;
private final JTextField directory; private final JTextField directory;
private final JPanel panel; private final JPanel panel;
private final String name;
/** /**
* Initializes a new server tab with the given name * Initializes a new server tab with the given name
@ -36,7 +34,6 @@ public class ServerTab implements ActionListener {
* @throws ConfigurationException <p>If unable to create the new tab</p> * @throws ConfigurationException <p>If unable to create the new tab</p>
*/ */
public ServerTab(String name) throws ConfigurationException { public ServerTab(String name) throws ConfigurationException {
this.name = name;
panel = new JPanel(); panel = new JPanel();
Main.getController().getGUI().getPane().addTab(name, null, panel, null); Main.getController().getGUI().getPane().addTab(name, null, panel, null);
SpringLayout sl_panel_3 = new SpringLayout(); SpringLayout sl_panel_3 = new SpringLayout();
@ -88,14 +85,6 @@ public class ServerTab implements ActionListener {
panel.add(enabledCheckbox); panel.add(enabledCheckbox);
enabledCheckbox.addActionListener(this); enabledCheckbox.addActionListener(this);
removeServerButton = new JButton("Remove server");
sl_panel_3.putConstraint(SpringLayout.NORTH, removeServerButton, 0, SpringLayout.NORTH, serverVersions);
sl_panel_3.putConstraint(SpringLayout.SOUTH, removeServerButton, 0, SpringLayout.SOUTH, serverVersions);
sl_panel_3.putConstraint(SpringLayout.WEST, removeServerButton, 6, SpringLayout.EAST, serverVersions);
sl_panel_3.putConstraint(SpringLayout.EAST, removeServerButton, -10, SpringLayout.EAST, panel);
panel.add(removeServerButton);
removeServerButton.addActionListener(this);
JLabel lblDirectory = new JLabel("Directory"); JLabel lblDirectory = new JLabel("Directory");
sl_panel_3.putConstraint(SpringLayout.WEST, lblDirectory, 6, SpringLayout.EAST, enabledCheckbox); sl_panel_3.putConstraint(SpringLayout.WEST, lblDirectory, 6, SpringLayout.EAST, enabledCheckbox);
panel.add(lblDirectory); panel.add(lblDirectory);
@ -112,7 +101,7 @@ public class ServerTab implements ActionListener {
browseButton = new JButton("Browse"); browseButton = new JButton("Browse");
sl_panel_3.putConstraint(SpringLayout.EAST, directory, -6, SpringLayout.WEST, browseButton); sl_panel_3.putConstraint(SpringLayout.EAST, directory, -6, SpringLayout.WEST, browseButton);
sl_panel_3.putConstraint(SpringLayout.NORTH, browseButton, 3, SpringLayout.SOUTH, removeServerButton); sl_panel_3.putConstraint(SpringLayout.NORTH, browseButton, 3, SpringLayout.SOUTH, serverVersions);
sl_panel_3.putConstraint(SpringLayout.EAST, browseButton, -10, SpringLayout.EAST, panel); sl_panel_3.putConstraint(SpringLayout.EAST, browseButton, -10, SpringLayout.EAST, panel);
sl_panel_3.putConstraint(SpringLayout.SOUTH, directory, 0, SpringLayout.SOUTH, browseButton); sl_panel_3.putConstraint(SpringLayout.SOUTH, directory, 0, SpringLayout.SOUTH, browseButton);
sl_panel_3.putConstraint(SpringLayout.NORTH, directory, 0, SpringLayout.NORTH, browseButton); sl_panel_3.putConstraint(SpringLayout.NORTH, directory, 0, SpringLayout.NORTH, browseButton);
@ -209,9 +198,7 @@ public class ServerTab implements ActionListener {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (e.getSource() == removeServerButton) { if (e.getSource() == browseButton) {
remove();
} else if (e.getSource() == browseButton) {
browse(); browse();
} else if (e.getSource() == serverTypes) { } else if (e.getSource() == serverTypes) {
try { try {
@ -222,15 +209,6 @@ public class ServerTab implements ActionListener {
} }
} }
/**
* Removes the collection containing this ServerTab, and updates everything necessary
*/
private void remove() {
Main.getController().getCurrentProfile().removeCollection(this.name);
Main.getController().getGUI().updateWithSavedProfileData();
Main.getController().getCurrentProfile().updateConsoles();
}
/** /**
* Asks the user for server location and updates the GUI if given a valid value * Asks the user for server location and updates the GUI if given a valid value
*/ */

View File

@ -59,7 +59,7 @@ public class Tray {
trayIcon = new TrayIcon(trayImage, "Minecraft Server Launcher", popup); trayIcon = new TrayIcon(trayImage, "Minecraft Server Launcher", popup);
trayIcon.setImageAutoSize(true); trayIcon.setImageAutoSize(true);
ActionListener exitListener = e -> { ActionListener exitListener = e -> {
serverLauncherGUI.stopServers(); serverLauncherGUI.getControlPanelTab().stopServers();
controller.saveState(); controller.saveState();
System.exit(0); System.exit(0);
}; };
@ -92,7 +92,7 @@ public class Tray {
e1.printStackTrace(); e1.printStackTrace();
} }
} else { } else {
serverLauncherGUI.stopServers(); serverLauncherGUI.getControlPanelTab().stopServers();
controller.saveState(); controller.saveState();
System.exit(0); System.exit(0);
} }
@ -114,7 +114,7 @@ public class Tray {
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
controller.saveState(); controller.saveState();
serverLauncherGUI.stopServers(); serverLauncherGUI.getControlPanelTab().stopServers();
System.exit(0); System.exit(0);
} }
}); });

View File

@ -22,11 +22,15 @@ import java.util.stream.Stream;
/** /**
* A helper class for performing server backup * A helper class for performing server backup
*/ */
public class BackupUtil { public final class BackupUtil {
private static boolean backupAborted; private static boolean backupAborted;
private static boolean backupRunning = false; private static boolean backupRunning = false;
private BackupUtil() {
}
/** /**
* Aborts the currently running backup * Aborts the currently running backup
*/ */
@ -44,7 +48,7 @@ public class BackupUtil {
* @throws IOException <p>If we can't start a file stream</p> * @throws IOException <p>If we can't start a file stream</p>
*/ */
private static long backupFolder(File source, File destination, long backupFileSize, private static long backupFolder(File source, File destination, long backupFileSize,
long alreadyCopied) throws IOException { long alreadyCopied) throws IOException {
if (backupAborted) { if (backupAborted) {
return 0L; return 0L;
} }
@ -136,8 +140,9 @@ public class BackupUtil {
/** /**
* Performs the actual backup after checks have passed and necessary info is available * Performs the actual backup after checks have passed and necessary info is available
* @param gui <p>The GUI to use for informing the user</p> *
* @param serverFolders <p>The folders of the servers to backup</p> * @param gui <p>The GUI to use for informing the user</p>
* @param serverFolders <p>The folders of the servers to backup</p>
* @param backupFileSize <p>The total size of the folders to backup</p> * @param backupFileSize <p>The total size of the folders to backup</p>
*/ */
private static void performBackup(GUI gui, List<List<File>> serverFolders, long backupFileSize) { private static void performBackup(GUI gui, List<List<File>> serverFolders, long backupFileSize) {
@ -164,10 +169,10 @@ public class BackupUtil {
/** /**
* Backs up the files for a single server * Backs up the files for a single server
* *
* @param gui <p>The GUI to use for informing the user</p> * @param gui <p>The GUI to use for informing the user</p>
* @param serverFolder <p>The server's input and output folders</p> * @param serverFolder <p>The server's input and output folders</p>
* @param backupFileSize <p>The total size of the files to backup</p> * @param backupFileSize <p>The total size of the files to backup</p>
* @param alreadyCopied <p>The amount of bytes already copied</p> * @param alreadyCopied <p>The amount of bytes already copied</p>
* @return <p>The new amount of bytes copied</p> * @return <p>The new amount of bytes copied</p>
*/ */
private static long backupServerFiles(GUI gui, List<File> serverFolder, long backupFileSize, long alreadyCopied) { private static long backupServerFiles(GUI gui, List<File> serverFolder, long backupFileSize, long alreadyCopied) {

View File

@ -126,6 +126,7 @@ public final class CommonFunctions {
/** /**
* Gets a buffered writer for writing to a given file * Gets a buffered writer for writing to a given file
*
* @param path <p>The path to the file to write to</p> * @param path <p>The path to the file to write to</p>
* @return <p>A buffered writer for writing to the file</p> * @return <p>A buffered writer for writing to the file</p>
* @throws FileNotFoundException <p>If the file does not exist</p> * @throws FileNotFoundException <p>If the file does not exist</p>
@ -149,8 +150,8 @@ public final class CommonFunctions {
/** /**
* Writes text to a file and adds a trailing newline * Writes text to a file and adds a trailing newline
* *
* @param path <p>The path of the file to write to</p> * @param path <p>The path of the file to write to</p>
* @param text <p>The text to write</p> * @param text <p>The text to write</p>
* @throws IOException <p>If unable to write to the file</p> * @throws IOException <p>If unable to write to the file</p>
*/ */
public static void writeFile(String path, String text) throws IOException { public static void writeFile(String path, String text) throws IOException {
@ -243,7 +244,6 @@ public final class CommonFunctions {
} }
/** /**
* Validates that a name is not empty and does not contain invalid characters * Validates that a name is not empty and does not contain invalid characters
* *
@ -259,7 +259,7 @@ public final class CommonFunctions {
* *
* @param target <p>The folder to delete from</p> * @param target <p>The folder to delete from</p>
*/ */
static void removeFilesRecursively(File target) { public static void removeFilesRecursively(File target) {
File[] oldFiles = target.listFiles(); File[] oldFiles = target.listFiles();
if (oldFiles == null) { if (oldFiles == null) {
throw new IllegalArgumentException("Unable to list files in directory"); throw new IllegalArgumentException("Unable to list files in directory");

View File

@ -1,2 +1,2 @@
beta beta
1.4.0 1.4.2
1 beta
2 1.4.0 1.4.2

View File

@ -1,11 +1,11 @@
Vanilla;Latest,Snapshot,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.9,1.7.10,1.6.4,1.5.2,1.4.7,1.3.2,1.2.5;https://launchermeta.mojang.com/mc/game/version_manifest.json;"release":";";https://s3.amazonaws.com/Minecraft.Download/versions/ Vanilla;Latest,Snapshot,1.18,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.9,1.7.10,1.6.4,1.5.2,1.4.7,1.3.2,1.2.5;https://launchermeta.mojang.com/mc/game/version_manifest.json;"release":";";https://s3.amazonaws.com/Minecraft.Download/versions/
Spigot;Latest,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.9.4,1.8.8,1.7.10,1.6.4-R2.1,1.5.2-R1.1,1.4.7-R1.1;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Spigot/;spigot- Spigot;Latest,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.9.4,1.8.8,1.7.10,1.6.4-R2.1,1.5.2-R1.1,1.4.7-R1.1;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Spigot/;spigot-
Paper;1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.8;https://papermc.io/api/v1/paper/;"latest":;,;https://papermc.io/api/v1/paper/ Paper;1.18,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.8;https://papermc.io/api/v2/projects/paper/versions/;"builds":[;];https://papermc.io/api/v2/projects/paper/versions/
#SpongeVanilla;1.12.2,1.11.2,1.10.2,1.8.9;https://dl-api.spongepowered.org/v1/org.spongepowered/spongevanilla/downloads?type=stable&minecraft=;"version":";",;https://repo.spongepowered.org/maven/org/spongepowered/spongevanilla/;/spongevanilla- #SpongeVanilla;1.12.2,1.11.2,1.10.2,1.8.9;https://dl-api.spongepowered.org/v1/org.spongepowered/spongevanilla/downloads?type=stable&minecraft=;"version":";",;https://repo.spongepowered.org/maven/org/spongepowered/spongevanilla/;/spongevanilla-
Craftbukkit;Latest,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.8,1.7.10-R0.1,1.6.4-R2.0,1.5.2-R1.0,1.4.6-R0.3,1.3.2-R3.0,1.2.5-R2.0,1.1-R6,1.0.1-R1,b1.8.1,b1.7.3;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Bukkit/;craftbukkit- Craftbukkit;Latest,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.8,1.7.10-R0.1,1.6.4-R2.0,1.5.2-R1.0,1.4.6-R0.3,1.3.2-R3.0,1.2.5-R2.0,1.1-R6,1.0.1-R1,b1.8.1,b1.7.3;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Bukkit/;craftbukkit-
#SpongeForge;1.12.2,1.11.2,1.10.2;https://dl-api.spongepowered.org/v1/org.spongepowered/spongeforge/downloads?type=stable&minecraft=;"version":";",;https://repo.spongepowered.org/maven/org/spongepowered/spongeforge/;/spongeforge- #SpongeForge;1.12.2,1.11.2,1.10.2;https://dl-api.spongepowered.org/v1/org.spongepowered/spongeforge/downloads?type=stable&minecraft=;"version":";",;https://repo.spongepowered.org/maven/org/spongepowered/spongeforge/;/spongeforge-
MCPCplus;1.6.4,1.6.2,1.5.2,1.4.7;https://static.knarcraft.net/archive/downloads/minecraftserverjars/MCPC+/;mcpcplus MCPCplus;1.6.4,1.6.2,1.5.2,1.4.7;https://static.knarcraft.net/archive/downloads/minecraftserverjars/MCPC+/;mcpcplus
Bungee;Latest,1.7.10,1.6.4,1.5.2,1.4.7;https://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/;Artifacts of BungeeCord #; ;http://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/BungeeCord.jar;https://static.knarcraft.net/archive/downloads/minecraftserverjars/BungeeCord/;BungeeCord- Bungee;Latest,1.7.10,1.6.4,1.5.2,1.4.7;https://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/;Artifacts of BungeeCord #; ;http://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/BungeeCord.jar;https://static.knarcraft.net/archive/downloads/minecraftserverjars/BungeeCord/;BungeeCord-
Waterfall;1.17,1.16,1.15,1.14,1.13,1.12,1.11;https://papermc.io/api/v1/waterfall/;"latest":;,;https://papermc.io/api/v1/waterfall/ Waterfall;1.18,1.17,1.16,1.15,1.14,1.13,1.12,1.11;https://papermc.io/api/v2/projects/waterfall/versions/;"builds":[;];https://papermc.io/api/v2/projects/waterfall/versions/
Travertine;1.16,1.15,1.14,1.13,1.12;https://papermc.io/api/v1/travertine/;"latest":;,;https://papermc.io/api/v1/travertine/ Travertine;1.16,1.15,1.14,1.13,1.12;https://papermc.io/api/v2/projects/travertine/versions/;"builds":[;];https://papermc.io/api/v2/projects/travertine/versions/
Custom; Custom;
Can't render this file because it contains an unexpected character in line 1 and column 200.

View File

@ -1,8 +1,9 @@
package net.knarcraft.minecraftserverlauncher.utility; package net.knarcraft.minecraftserverlauncher.server;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.userinterface.FakeGUI; import net.knarcraft.minecraftserverlauncher.userinterface.FakeGUI;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;