Skip to content
Draft
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
124 changes: 97 additions & 27 deletions src/main/java/dev/aoqia/leaf/installer/Handler.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
Expand Down Expand Up @@ -72,6 +75,9 @@ public abstract class Handler implements InstallerProgress {
public JComboBox<String> loaderVersionComboBox;
public JCheckBox createConfigCheckbox;
private JPanel pane;
private JTextArea launchArguments;
private String proxyJarName;
private LoaderVersion customLoaderVersion;

protected static Component createSpacer() {
return Box.createRigidArea(new Dimension(4, 0));
Expand All @@ -92,6 +98,10 @@ public void setupPane1(JPanel pane, GridBagConstraints c, InstallerGui installer
public void setupPane2(JPanel pane, GridBagConstraints c, InstallerGui installerGui) {
}

protected Component makeLaunchOptionsPanel(JPanel manualPanel) {
return manualPanel;
}

public JPanel makePanel(InstallerGui installerGui) {
pane = new JPanel(new GridBagLayout());
pane.setBorder(new EmptyBorder(4, 4, 4, 4));
Expand Down Expand Up @@ -134,6 +144,7 @@ public JPanel makePanel(InstallerGui installerGui) {
if (!selected && Main.LOADER_META.isComplete()) {
updateLoaderVersions(Main.LOADER_META.getVersions());
}
updateLaunchArguments();
});

addRow(pane, c, "prompt.loader.version", loaderVersionComboBox, createSpacer(), loaderProxyCheckbox);
Expand All @@ -153,35 +164,15 @@ public JPanel makePanel(InstallerGui installerGui) {
createConfigCheckbox.setEnabled(false);
addRow(pane, c, null, createConfigCheckbox);

addRow(pane, c, null, statusLabel = new JLabel());
statusLabel.setText(Utils.BUNDLE.getString("prompt.loading.versions"));
statusLabel = new JLabel(Utils.BUNDLE.getString("prompt.loading.versions"));

launchArguments = new JTextArea();
launchArguments.setEditable(false);

copyArgButton = new JButton(Utils.BUNDLE.getString("prompt.copy.arg"));
copyArgButton.setEnabled(false);
copyArgButton.addActionListener(e -> {
StringSelection s;
if (loaderProxyCheckbox.isSelected()) {
try {
String fmt = "";

if (OperatingSystem.CURRENT == OperatingSystem.WINDOWS) {
String tag = Main.LATEST_PROXY_NATIVE_TAG;
fmt += String.format("-agentlib:.leaf/lib/native-%s.dll",
tag.startsWith("v") ? tag.substring(1) : tag);
fmt += " ";
}

fmt += String.format("-javaagent:.leaf/lib/%s", Utils.getLatestLoaderProxy().getJarName());

s = new StringSelection(fmt);
} catch (IOException exc) {
error(exc);
return;
}
} else {
s = new StringSelection(String.format("-pzexeconfig leaf-%s-%s.json",
queryLoaderVersion().name, gameVersionComboBox.getSelectedItem()));
}

StringSelection s = new StringSelection(launchArguments.getText().replace('\n', ' '));
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(s, null);
});

Expand All @@ -191,13 +182,89 @@ public JPanel makePanel(InstallerGui installerGui) {
install(loaderProxyCheckbox.isEnabled() && loaderProxyCheckbox.isSelected());
});

addLastRow(pane, c, null, buttonInstall, copyArgButton);
JPanel manualPanel = new JPanel(new GridBagLayout());
GridBagConstraints manualConstraints = new GridBagConstraints();
manualConstraints.gridx = manualConstraints.gridy = 0;
manualConstraints.insets = c.insets;
addRow(manualPanel, manualConstraints, null,
new JLabel(Utils.BUNDLE.getString("prompt.launch.arguments")));
JPanel argumentsPanel = new JPanel();
argumentsPanel.setOpaque(false);
argumentsPanel.setBorder(UIManager.getBorder("TextField.border"));
argumentsPanel.add(launchArguments);
argumentsPanel.add(copyArgButton);
addRow(manualPanel, manualConstraints, null, argumentsPanel);
addRow(pane, c, null, makeLaunchOptionsPanel(manualPanel));
c.gridwidth = 2;
c.fill = GridBagConstraints.HORIZONTAL;
pane.add(new JSeparator(), c);
c.gridy++;
addRow(pane, c, null, statusLabel);
c.insets = new Insets(VERTICAL_SPACING, HORIZONTAL_SPACING, 10, HORIZONTAL_SPACING);
addLastRow(pane, c, null, buttonInstall);

gameVersionComboBox.addActionListener(e -> updateLaunchArguments());
loaderVersionComboBox.addActionListener(e -> {
if (SELECT_CUSTOM_ITEM.equals(loaderVersionComboBox.getSelectedItem())) {
customLoaderVersion = null;
customLoaderVersion = queryLoaderVersion();
}
updateLaunchArguments();
});
updateLaunchArguments();
new Thread(() -> {
try {
String jarName;
synchronized (Utils.class) {
jarName = Utils.getLatestLoaderProxy().getJarName();
}
SwingUtilities.invokeLater(() -> {
proxyJarName = jarName;
updateLaunchArguments();
});
} catch (IOException e) {
SwingUtilities.invokeLater(() -> error(e));
}
}).start();

installerGui.updateSize(true);

return pane;
}

private void updateLaunchArguments() {
if (launchArguments == null) {
return;
}

String arguments = "";
if (loaderProxyCheckbox.isSelected()) {
if (proxyJarName != null) {
if (OperatingSystem.CURRENT == OperatingSystem.WINDOWS && Main.LATEST_PROXY_NATIVE_TAG != null) {
String tag = Main.LATEST_PROXY_NATIVE_TAG;
arguments = String.format("-agentpath:.leaf/lib/native-%s.dll\n",
tag.startsWith("v") ? tag.substring(1) : tag);
}
arguments += String.format("-javaagent:.leaf/lib/%s", proxyJarName);
arguments += " --";
}
} else if (loaderVersionComboBox.getSelectedItem() != null && gameVersionComboBox.getSelectedItem() != null) {
String version = (String) loaderVersionComboBox.getSelectedItem();
if (SELECT_CUSTOM_ITEM.equals(version)) {
version = customLoaderVersion == null ? null : customLoaderVersion.name;
}
if (version != null) {
arguments = String.format("-pzexeconfig leaf-%s-%s.json",
version, gameVersionComboBox.getSelectedItem());
}
}
launchArguments.setText(arguments);
copyArgButton.setEnabled(true);
if (InstallerGui.instance != null) {
InstallerGui.instance.updateSize(false);
}
}

private void updateGameVersions(List<GameMetaHandler.Version> versions) {
gameVersionComboBox.removeAllItems();

Expand Down Expand Up @@ -234,6 +301,9 @@ protected LoaderVersion queryLoaderVersion() {
if (!ret.equals(SELECT_CUSTOM_ITEM)) {
return new LoaderVersion(ret);
} else {
if (customLoaderVersion != null) {
return customLoaderVersion;
}
// ask user for loader jar

JFileChooser chooser = new JFileChooser();
Expand Down
63 changes: 57 additions & 6 deletions src/main/java/dev/aoqia/leaf/installer/client/ClientHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@
package dev.aoqia.leaf.installer.client;

import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.event.HyperlinkEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.GridBagConstraints;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.FileNotFoundException;
Expand All @@ -39,9 +44,35 @@
import dev.aoqia.leaf.installer.util.ArgumentParser;
import dev.aoqia.leaf.installer.util.InstallerProgress;
import dev.aoqia.leaf.installer.util.NoopCaret;
import dev.aoqia.leaf.installer.util.OperatingSystem;
import dev.aoqia.leaf.installer.util.SteamLaunchOptions;
import dev.aoqia.leaf.installer.util.Utils;

public class ClientHandler extends Handler {
private JTabbedPane launchOptionsTabs;
private JCheckBox steamLaunchOptionsCheckbox;
private JCheckBox alternateLaunchCheckbox;

@Override
protected Component makeLaunchOptionsPanel(JPanel manualPanel) {
steamLaunchOptionsCheckbox = new JCheckBox(Utils.BUNDLE.getString("option.steam.launch.options"), true);
alternateLaunchCheckbox = new JCheckBox(Utils.BUNDLE.getString("option.alternate.launch"), true);
alternateLaunchCheckbox.setEnabled(OperatingSystem.CURRENT == OperatingSystem.WINDOWS);
JPanel automaticPanel = new JPanel(new GridLayout(0, 1));
automaticPanel.add(steamLaunchOptionsCheckbox);
automaticPanel.add(alternateLaunchCheckbox);
JLabel closeSteamNotice = new JLabel(Utils.BUNDLE.getString("prompt.close.steam"));
automaticPanel.add(closeSteamNotice);
steamLaunchOptionsCheckbox.addItemListener(e -> {
closeSteamNotice.setVisible(steamLaunchOptionsCheckbox.isSelected());
InstallerGui.instance.updateSize(false);
});
launchOptionsTabs = new JTabbedPane();
launchOptionsTabs.addTab(Utils.BUNDLE.getString("tab.automatic"), automaticPanel);
launchOptionsTabs.addTab(Utils.BUNDLE.getString("tab.manual"), manualPanel);
return launchOptionsTabs;
}

@Override
public String name() {
return Utils.BUNDLE.getString("tab.client");
Expand Down Expand Up @@ -95,7 +126,21 @@ public void setupPane2(JPanel pane, GridBagConstraints c, InstallerGui installer

private void installInternal(boolean proxy) {
String gameVersion = (String) gameVersionComboBox.getSelectedItem();
boolean createConfig = createConfigCheckbox.isEnabled() && createConfigCheckbox.isSelected();
boolean automatic = launchOptionsTabs.getSelectedIndex() == 0;
boolean steamLaunchOptions = automatic && steamLaunchOptionsCheckbox.isSelected();
boolean alternateLaunch = automatic && alternateLaunchCheckbox.isEnabled()
&& alternateLaunchCheckbox.isSelected();
boolean createConfig = !proxy && (createConfigCheckbox.isSelected() || steamLaunchOptions);
String installDirectory = installLocation.getText();
if (steamLaunchOptions) {
try {
SteamLaunchOptions.checkSteamClosed();
} catch (IOException e) {
error(e);
buttonInstall.setEnabled(true);
return;
}
}

final LoaderVersion loaderVersion;
if (!proxy) {
Expand All @@ -105,25 +150,31 @@ private void installInternal(boolean proxy) {
loaderVersion = new LoaderVersion(Utils.getLatestLoaderProxy().version);
} catch (IOException exc) {
error(exc);
buttonInstall.setEnabled(true);
return;
}
}
if (loaderVersion == null) {
buttonInstall.setEnabled(true);
return;
}

System.out.println("Installing");

new Thread(() -> {
try {
Path pzPath = Utils.normaliseClientGamePath(Paths.get(installLocation.getText())).toAbsolutePath();
if (!Files.exists(pzPath)) {
Path gamePath = Utils.normaliseClientGamePath(Paths.get(installDirectory)).toAbsolutePath();
if (!Files.exists(gamePath)) {
throw new RuntimeException(Utils.BUNDLE.getString("progress.exception.no.launcher.directory"));
}

new ClientInstaller(pzPath, gameVersion, loaderVersion, this).install(proxy, createConfig);
new ClientInstaller(gamePath, gameVersion, loaderVersion, this)
.install(proxy, createConfig, steamLaunchOptions, alternateLaunch);
SwingUtilities.invokeLater(() -> showInstalledMessage(proxy, loaderVersion, gameVersion));
} catch (Exception e) {
error(e);
SwingUtilities.invokeLater(() -> error(e));
} finally {
buttonInstall.setEnabled(true);
SwingUtilities.invokeLater(() -> buttonInstall.setEnabled(true));
}
}).start();
}
Expand Down
34 changes: 32 additions & 2 deletions src/main/java/dev/aoqia/leaf/installer/client/ClientInstaller.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@
import org.apache.commons.collections4.iterators.IteratorChain;

import dev.aoqia.leaf.installer.LoaderVersion;
import dev.aoqia.leaf.installer.util.ClientLaunchOptions;
import dev.aoqia.leaf.installer.util.InstallerProgress;
import dev.aoqia.leaf.installer.util.LaunchConfigUtil;
import dev.aoqia.leaf.installer.util.LeafService;
import dev.aoqia.leaf.installer.util.Library;
import dev.aoqia.leaf.installer.util.OperatingSystem;
import dev.aoqia.leaf.installer.util.Reference;
import dev.aoqia.leaf.installer.util.SteamLaunchOptions;
import dev.aoqia.leaf.installer.util.Utils;
import dev.aoqia.leaf.installer.util.json.LoaderJson;

Expand All @@ -49,6 +51,15 @@ public ClientInstaller(Path gameDir, String gameVersion, LoaderVersion loaderVer
}

public void install(boolean proxy, boolean createConfig) throws IOException {
install(proxy, createConfig, false, false);
}

public void install(boolean proxy, boolean createConfig, boolean steamLaunchOptions, boolean alternateLaunch)
throws IOException
{
if (steamLaunchOptions) {
SteamLaunchOptions.checkSteamClosed();
}
if (proxy) {
System.out.printf("Installing leaf-loader-proxy for %s%n", gameVersion);
} else {
Expand All @@ -61,6 +72,7 @@ public void install(boolean proxy, boolean createConfig) throws IOException {
var proxyLib = Utils.getLatestLoaderProxy();

String configName = String.format("leaf-%s-%s", proxy ? proxyLib.version : loaderVersion.name, gameVersion);
String mainClass = null;

if (Files.exists(this.leafLibDir)) {
Utils.deleteDirectory(this.leafLibDir);
Expand All @@ -83,7 +95,7 @@ public void install(boolean proxy, boolean createConfig) throws IOException {
LoaderJson loaderVersionJson = LeafService.queryMetaJson(
"dist/loader/%s.json".formatted(loaderVersion.name), LoaderJson.class);
LoaderJson.Libraries libsJson = loaderVersionJson.libraries();
String mainClass = loaderVersionJson.mainClass().client();
mainClass = loaderVersionJson.mainClass().client();
String mainClassInternal = mainClass.replace(".", "/");

// Putting loader dependency into the libs list for later download.
Expand All @@ -109,12 +121,30 @@ public void install(boolean proxy, boolean createConfig) throws IOException {
}
});

if (createConfig) {
if (createConfig || steamLaunchOptions) {
var launchConfigUtil = new LaunchConfigUtil(gameDir);
launchConfigUtil.createConfig(configName, mainClassInternal);
}
}

String agents = String.format("-javaagent:.leaf/lib/%s", proxyLib.getJarName());
if (proxy && (steamLaunchOptions || alternateLaunch) && OperatingSystem.CURRENT == OperatingSystem.WINDOWS) {
try (var files = Files.list(leafLibDir)) {
String nativeName = files.filter(Files::isRegularFile).map(path -> path.getFileName().toString())
.filter(name -> name.startsWith("native-") && name.endsWith(".dll"))
.findFirst().orElseThrow(() -> new IOException("No installed loader proxy native library found."));
agents = "-agentpath:.leaf/lib/" + nativeName + " " + agents;
}
}
if (alternateLaunch) {
progress.updateProgress(Utils.BUNDLE.getString("progress.patch.alternate.launch"));
ClientLaunchOptions.patchAlternateLauncher(gameDir, proxy ? agents : "", mainClass);
}
if (steamLaunchOptions) {
progress.updateProgress(Utils.BUNDLE.getString("progress.patch.steam.launch.options"));
SteamLaunchOptions.update(gameDir, proxy ? agents + " --" : "-pzexeconfig " + configName + ".json");
}

progress.updateProgress(Utils.BUNDLE.getString("progress.done"));
}
}
Loading
Loading