Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Download server launcher from installer GUI #130

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 10 additions & 35 deletions src/main/java/net/fabricmc/installer/Handler.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Locale;
Expand All @@ -36,14 +34,12 @@
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileNameExtensionFilter;

import net.fabricmc.installer.util.ArgumentParser;
import net.fabricmc.installer.util.InstallerProgress;
Expand All @@ -54,8 +50,6 @@ public abstract class Handler implements InstallerProgress {
protected static final int HORIZONTAL_SPACING = 4;
protected static final int VERTICAL_SPACING = 6;

private static final String SELECT_CUSTOM_ITEM = "(select custom)";

public JButton buttonInstall;

public JComboBox<String> gameVersionComboBox;
Expand All @@ -81,6 +75,10 @@ public void setupPane1(JPanel pane, GridBagConstraints c, InstallerGui installer

public void setupPane2(JPanel pane, GridBagConstraints c, InstallerGui installerGui) { }

public boolean isLoaderVersionSupported(String version) {
return true;
}

public JPanel makePanel(InstallerGui installerGui) {
pane = new JPanel(new GridBagLayout());
pane.setBorder(new EmptyBorder(4, 4, 4, 4));
Expand Down Expand Up @@ -134,15 +132,18 @@ public JPanel makePanel(InstallerGui installerGui) {

for (int i = 0; i < versions.size(); i++) {
MetaHandler.GameVersion version = versions.get(i);

if (!isLoaderVersionSupported(version.getVersion())) {
continue;
}

loaderVersionComboBox.addItem(version.getVersion());

if (version.isStable()) {
stableIndex = i;
}
}

loaderVersionComboBox.addItem(SELECT_CUSTOM_ITEM);

//If no stable versions are found, default to the latest version
if (stableIndex == -1) {
stableIndex = 0;
Expand Down Expand Up @@ -173,33 +174,7 @@ private void updateGameVersions() {

protected LoaderVersion queryLoaderVersion() {
String ret = (String) loaderVersionComboBox.getSelectedItem();

if (!ret.equals(SELECT_CUSTOM_ITEM)) {
return new LoaderVersion(ret);
} else {
// ask user for loader jar

JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("."));
chooser.setDialogTitle("Select Fabric Loader JAR");
chooser.setFileFilter(new FileNameExtensionFilter("Java Archive", "jar"));
chooser.setAcceptAllFileFilterUsed(false);

if (chooser.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) {
return null;
}

File file = chooser.getSelectedFile();

// determine loader version from fabric.mod.json

try {
return new LoaderVersion(file.toPath());
} catch (IOException e) {
error(e);
return null;
}
}
return new LoaderVersion(ret);
}

@Override
Expand Down
20 changes: 11 additions & 9 deletions src/main/java/net/fabricmc/installer/server/ServerHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import net.fabricmc.installer.InstallerGui;
import net.fabricmc.installer.LoaderVersion;
import net.fabricmc.installer.util.ArgumentParser;
import net.fabricmc.installer.util.FabricService;
import net.fabricmc.installer.util.InstallerProgress;
import net.fabricmc.installer.util.Reference;
import net.fabricmc.installer.util.Utils;
Expand All @@ -55,7 +56,8 @@ public void install() {

new Thread(() -> {
try {
ServerInstaller.install(Paths.get(installLocation.getText()).toAbsolutePath(), loaderVersion, gameVersion, this);
Path launcherJar = Paths.get(installLocation.getText()).resolve(ServerInstaller.DEFAULT_LAUNCH_JAR_NAME);
FabricService.downloadServerLauncher(loaderVersion.name, gameVersion, launcherJar);
ServerPostInstallDialog.show(this);
} catch (Exception e) {
error(e);
Expand All @@ -77,20 +79,15 @@ public void installCli(ArgumentParser args) throws Exception {
String gameVersion = getGameVersion(args);
ServerInstaller.install(dir, loaderVersion, gameVersion, InstallerProgress.CONSOLE);

if (args.has("downloadMinecraft")) {
InstallerProgress.CONSOLE.updateProgress(Utils.BUNDLE.getString("progress.download.minecraft"));
Path serverJar = dir.resolve("server.jar");
MinecraftServerDownloader downloader = new MinecraftServerDownloader(gameVersion);
downloader.downloadMinecraftServer(serverJar);
InstallerProgress.CONSOLE.updateProgress(Utils.BUNDLE.getString("progress.done"));
}
Path launcherJar = dir.resolve(ServerInstaller.DEFAULT_LAUNCH_JAR_NAME);
FabricService.downloadServerLauncher(loaderVersion.name, gameVersion, launcherJar);

InstallerProgress.CONSOLE.updateProgress(new MessageFormat(Utils.BUNDLE.getString("progress.done.start.server")).format(new Object[]{ServerInstaller.DEFAULT_LAUNCH_JAR_NAME}));
}

@Override
public String cliHelp() {
return "-dir <install dir, default current dir> -mcversion <minecraft version, default latest> -loader <loader version, default latest> -downloadMinecraft";
return "-dir <install dir, default current dir> -mcversion <minecraft version, default latest> -loader <loader version, default latest>";
}

@Override
Expand Down Expand Up @@ -119,4 +116,9 @@ public void mouseClicked(MouseEvent e) {
public void setupPane2(JPanel pane, GridBagConstraints c, InstallerGui installerGui) {
installLocation.setText(Paths.get(".").toAbsolutePath().normalize().toString());
}

@Override
public boolean isLoaderVersionSupported(String version) {
return Utils.compareVersions(version, "0.12.0") >= 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,18 @@

package net.fabricmc.installer.server;

import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

import javax.swing.BoxLayout;
import javax.swing.JButton;
Expand All @@ -50,40 +36,27 @@
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import mjson.Json;

import net.fabricmc.installer.InstallerGui;
import net.fabricmc.installer.util.LauncherMeta;
import net.fabricmc.installer.util.Utils;

@SuppressWarnings("serial")
public class ServerPostInstallDialog extends JDialog {
private static final String launchCommand = "java -Xmx2G -jar fabric-server-launch.jar nogui";
private static final int MB = 1000000;

private final JPanel panel = new JPanel();

private final ServerHandler serverHandler;
private final String minecraftVersion;
private final Path installDir;
private final Path minecraftJar;
private final Path minecraftJarTmp;

private JLabel serverJarLabel;
private JButton downloadButton;
private JButton generateButton;

private ServerPostInstallDialog(ServerHandler handler) throws HeadlessException {
super(InstallerGui.instance, true);
this.serverHandler = handler;
this.minecraftVersion = (String) handler.gameVersionComboBox.getSelectedItem();
this.installDir = Paths.get(handler.installLocation.getText());
this.minecraftJar = installDir.resolve("server.jar");
this.minecraftJarTmp = installDir.resolve("server.jar.tmp");

panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
initComponents();
Expand All @@ -94,16 +67,6 @@ private ServerPostInstallDialog(ServerHandler handler) throws HeadlessException
private void initComponents() {
addRow(panel, panel -> panel.add(fontSize(new JLabel(Utils.BUNDLE.getString("progress.done.server")), 20)));

addRow(panel, panel -> panel.add(fontSize(new JLabel(Utils.BUNDLE.getString("prompt.server.info.jar")), 15)));
addRow(panel, panel -> {
updateServerJarLabel();
panel.add(serverJarLabel);

downloadButton = new JButton(Utils.BUNDLE.getString("prompt.server.jar"));
downloadButton.addActionListener(e -> doServerJarDownload());
panel.add(downloadButton);
});

addRow(panel, panel -> panel.add(fontSize(new JLabel(Utils.BUNDLE.getString("prompt.server.info.command")), 15)));
addRow(panel, panel -> {
JTextField textField = new JTextField(launchCommand);
Expand All @@ -128,95 +91,6 @@ private void initComponents() {
});
}

private boolean isValidJarPresent() {
if (!Files.exists(minecraftJar)) {
return false;
}

try (JarFile jarFile = new JarFile(minecraftJar.toFile())) {
JarEntry versionEntry = jarFile.getJarEntry("version.json");

if (versionEntry == null) {
return false;
}

InputStream inputStream = jarFile.getInputStream(versionEntry);

String text;

try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
text = reader.lines().collect(Collectors.joining("\n"));
}

Json json = Json.read(text);
String id = json.at("id").asString();
String name = json.at("name").asString();

return minecraftVersion.equals(id) || minecraftVersion.equals(name);
} catch (IOException e) {
return false;
}
}

private void updateServerJarLabel() {
if (serverJarLabel == null) {
serverJarLabel = new JLabel();
}

if (isValidJarPresent()) {
serverJarLabel.setText(new MessageFormat(Utils.BUNDLE.getString("prompt.server.jar.valid")).format(new Object[]{minecraftVersion}));
color(serverJarLabel, Color.GREEN.darker());
} else {
serverJarLabel.setText(new MessageFormat(Utils.BUNDLE.getString("prompt.server.jar.invalid")).format(new Object[]{minecraftVersion}));
color(serverJarLabel, Color.RED);
}
}

private void doServerJarDownload() {
downloadButton.setEnabled(false);

try {
Files.deleteIfExists(minecraftJar);
Files.deleteIfExists(minecraftJarTmp);
} catch (IOException e) {
color(serverJarLabel, Color.RED).setText(e.getMessage());
serverHandler.error(e);
return;
}

new Thread(() -> {
try {
URL url = new URL(LauncherMeta.getLauncherMeta().getVersion(minecraftVersion).getVersionMeta().downloads.get("server").url);
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
int finalSize = httpConnection.getContentLength();

try (BufferedInputStream inputStream = new BufferedInputStream(httpConnection.getInputStream());
OutputStream outputStream = Files.newOutputStream(minecraftJarTmp)) {
byte[] buffer = new byte[4096];
long downloaded = 0;
int len;

while ((len = inputStream.read(buffer, 0, buffer.length)) >= 0) {
downloaded += len;

final String labelText = new MessageFormat(Utils.BUNDLE.getString("prompt.server.downloading")).format(new Object[] {downloaded / MB, finalSize / MB});
SwingUtilities.invokeLater(() -> color(serverJarLabel, Color.BLUE).setText(labelText));

outputStream.write(buffer, 0, len);
}
}

Files.move(minecraftJarTmp, minecraftJar, StandardCopyOption.REPLACE_EXISTING);

updateServerJarLabel();
downloadButton.setEnabled(true);
} catch (IOException e) {
color(serverJarLabel, Color.RED).setText(e.getMessage());
serverHandler.error(e);
}
}).start();
}

private void generateLaunchScripts() {
Map<Path, String> launchScripts = new HashMap<>();
launchScripts.put(installDir.resolve("start.bat"), launchCommand + "\npause");
Expand All @@ -243,11 +117,6 @@ private JLabel fontSize(JLabel label, int size) {
return label;
}

private JLabel color(JLabel label, Color color) {
label.setForeground(color);
return label;
}

private void addRow(Container parent, Consumer<JPanel> consumer) {
JPanel panel = new JPanel(new FlowLayout());
consumer.accept(panel);
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/net/fabricmc/installer/util/FabricService.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ public static Json queryJsonSubstitutedMaven(String url) throws IOException {
return invokeWithFallbacks((service, arg) -> Json.read(Utils.readString(new URL(service.maven + arg))), path);
}

public static void downloadServerLauncher(String loaderVersion, String minecraftVersion, Path out) throws IOException {
String path = "v2/versions/loader/" + minecraftVersion + "/" + loaderVersion + "/stable/server/jar";

invokeWithFallbacks((service, arg) -> {
Utils.downloadFile(new URL(service.meta + arg), out);
return null;
}, path);
}

/**
* Download url to file, substituting Fabric Maven with fallbacks or overrides.
*/
Expand Down
5 changes: 0 additions & 5 deletions src/main/resources/lang/installer.properties
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,8 @@ prompt.launcher.type.win32=Standalone (Win32)
prompt.game.version=Minecraft Version:
prompt.ready.install=Ready to install
prompt.select.location=Launcher Location:
prompt.server.info.jar=The official Minecraft server jar is required to run fabric
prompt.server.info.command=Use this command to start the server
prompt.server.info.scipt=Or generate launch scripts
prompt.server.jar=Download server jar
prompt.server.jar.valid=Valid {0} server jar found
prompt.server.jar.invalid=No valid {0} server jar found
prompt.server.downloading=Downloading {0}/{1} MB
prompt.server.generate=Generate
prompt.server.overwrite=Are you sure you want to override the existing launch scripts?
prompt.server.launcher=Click here to use the standalone server launcher for an easier setup
Expand Down
4 changes: 0 additions & 4 deletions src/main/resources/lang/installer_ar_AR.properties
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,8 @@ prompt.launcher.open.tile=ماينكرافت لونشر يستعمل حاليا
prompt.game.version=:نسخة اللعبة
prompt.ready.install=جاهز للتثبيث
prompt.select.location=:حدد مكان التثبيث
prompt.server.info.jar=الملف الرسمي للخادم الرسمي إجباري
prompt.server.info.command=إستعمل هذه التعليمة لتشغيل الخادم
prompt.server.info.scipt=أو انتج سكريبت التشغيل
prompt.server.jar=تحميل ملف الخادم
prompt.server.jar.valid=تم العثور على ملف الخادم صالح {0}
prompt.server.jar.invalid={0} لم يتم العثور على ملف الخادم صالح
prompt.server.generate=إنشاء
prompt.server.overwrite=هل أنت متأكد من أنك تريد تجاهل سكريبت التشغيل الحالية؟
prompt.install.successful.title=تم التثبيث بنجاح
Expand Down
Loading
Loading