diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildTools.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildTools.java index 0c951e1..b67307c 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildTools.java +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildTools.java @@ -23,11 +23,11 @@ import com.skcraft.launcher.auth.Session; import com.skcraft.launcher.builder.BuilderConfig; import com.skcraft.launcher.builder.BuilderOptions; import com.skcraft.launcher.builder.FnPatternList; -import com.skcraft.launcher.buildtools.build.*; -import com.skcraft.launcher.buildtools.build.BuildDialog.BuildOptions; +import com.skcraft.launcher.buildtools.compile.*; +import com.skcraft.launcher.buildtools.compile.BuildDialog.BuildOptions; import com.skcraft.launcher.buildtools.project.BuilderConfigDialog; import com.skcraft.launcher.buildtools.http.LocalHttpServerBuilder; -import com.skcraft.launcher.buildtools.build.DeployServerDialog.DeployOptions; +import com.skcraft.launcher.buildtools.compile.DeployServerDialog.DeployOptions; import com.skcraft.launcher.dialog.ConfigurationDialog; import com.skcraft.launcher.dialog.ConsoleFrame; import com.skcraft.launcher.dialog.ProgressDialog; diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/BuildDialog.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/BuildDialog.java new file mode 100644 index 0000000..0ff94a6 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/BuildDialog.java @@ -0,0 +1,118 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.compile; + +import com.skcraft.launcher.swing.DirectoryField; +import com.skcraft.launcher.swing.SwingHelper; +import lombok.Data; +import lombok.Getter; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; + +public class BuildDialog extends JDialog { + + private final DirectoryField destDirField = new DirectoryField(); + private final JTextField versionText = new JTextField(20); + private final JTextField manifestFilenameText = new JTextField(30); + private final JCheckBox cleanCheck = new JCheckBox("Delete previously generated files first"); + @Getter + private BuildOptions options; + + public BuildDialog(Window parent) { + super(parent, "Build Release", ModalityType.DOCUMENT_MODAL); + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + initComponents(); + setResizable(false); + pack(); + setLocationRelativeTo(parent); + } + + private void initComponents() { + JPanel container = new JPanel(); + container.setLayout(new MigLayout("insets dialog")); + + container.add(new JLabel("Version:")); + container.add(versionText, "span"); + + container.add(new JLabel("Manifest Filename:")); + container.add(manifestFilenameText, "span"); + + container.add(new JLabel("Output Directory:")); + container.add(destDirField, "span"); + + container.add(cleanCheck, "span, gapbottom unrel"); + + JButton buildButton = new JButton("Build..."); + JButton cancelButton = new JButton("Cancel"); + + container.add(buildButton, "tag ok, span, split 2, sizegroup bttn"); + container.add(cancelButton, "tag cancel, sizegroup bttn"); + + add(container, BorderLayout.CENTER); + + buildButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + returnValue(); + } + }); + + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + } + + private void returnValue() { + String version = versionText.getText().trim(); + String manifestFilename = manifestFilenameText.getText().trim(); + + if (version.isEmpty()) { + SwingHelper.showErrorDialog(this, "A version string must be entered.", "Error"); + return; + } + + if (manifestFilename.isEmpty()) { + SwingHelper.showErrorDialog(this, "A manifest filename must be entered.", "Error"); + return; + } + + if (destDirField.getPath().isEmpty()) { + SwingHelper.showErrorDialog(this, "A destination directory must be entered.", "Error"); + return; + } + + options = new BuildOptions(version, manifestFilename, cleanCheck.isSelected(), new File(destDirField.getPath())); + dispose(); + } + + public static BuildOptions showBuildDialog(Window parent, String version, String manifestName, File destDir) { + BuildDialog dialog = new BuildDialog(parent); + dialog.versionText.setText(version); + dialog.manifestFilenameText.setText(manifestName); + dialog.destDirField.setPath(destDir.getAbsolutePath()); + dialog.setVisible(true); + return dialog.getOptions(); + } + + @Data + public static class BuildOptions { + private final String version; + private final String manifestFilename; + private final boolean clean; + private final File destDir; + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/DeployServerDialog.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/DeployServerDialog.java new file mode 100644 index 0000000..3836a9b --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/DeployServerDialog.java @@ -0,0 +1,103 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.compile; + +import com.skcraft.launcher.swing.DirectoryField; +import com.skcraft.launcher.swing.SwingHelper; +import lombok.Data; +import lombok.Getter; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; + +public class DeployServerDialog extends JDialog { + + private final DirectoryField destDirField = new DirectoryField(); + private final JCheckBox cleanModsCheck = new JCheckBox("Delete \"mods/\" folder before deploying"); + @Getter + private DeployOptions options; + + public DeployServerDialog(Window parent) { + super(parent, "Deploy Server Files", ModalityType.DOCUMENT_MODAL); + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + initComponents(); + setResizable(false); + pack(); + setLocationRelativeTo(parent); + + cleanModsCheck.setSelected(true); + } + + private void initComponents() { + JPanel container = new JPanel(); + container.setLayout(new MigLayout("insets dialog")); + + container.add(new JLabel("Output Directory:")); + container.add(destDirField, "span"); + + container.add(cleanModsCheck, "span, gapbottom unrel"); + + JButton buildButton = new JButton("Deploy..."); + JButton cancelButton = new JButton("Cancel"); + + container.add(buildButton, "tag ok, span, split 2, sizegroup bttn"); + container.add(cancelButton, "tag cancel, sizegroup bttn"); + + add(container, BorderLayout.CENTER); + + buildButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + returnValue(); + } + }); + + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + } + + private void returnValue() { + String dir = destDirField.getPath(); + + if (dir.isEmpty()) { + SwingHelper.showErrorDialog(this, "A directory must be entered.", "Error"); + return; + } + + File dirFile = new File(dir); + + if (!dirFile.isDirectory()) { + SwingHelper.showErrorDialog(this, "The selected path is not a directory that exists.", "Error"); + return; + } + + options = new DeployOptions(dirFile,cleanModsCheck.isSelected()); + dispose(); + } + + public static DeployOptions showDeployDialog(Window parent) { + DeployServerDialog dialog = new DeployServerDialog(parent); + dialog.setVisible(true); + return dialog.getOptions(); + } + + @Data + public static class DeployOptions { + private final File destDir; + private final boolean cleanMods; + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ModpackBuilder.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ModpackBuilder.java new file mode 100644 index 0000000..272a315 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ModpackBuilder.java @@ -0,0 +1,76 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.compile; + +import com.skcraft.concurrency.ProgressObservable; +import com.skcraft.launcher.LauncherException; +import com.skcraft.launcher.LauncherUtils; +import com.skcraft.launcher.builder.PackageBuilder; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +public class ModpackBuilder implements Callable, ProgressObservable { + + private final File inputDir; + private final File outputDir; + private final String version; + private final String manifestFilename; + private final boolean clean; + + public ModpackBuilder(File inputDir, File outputDir, String version, String manifestFilename, boolean clean) { + this.inputDir = inputDir; + this.outputDir = outputDir; + this.version = version; + this.manifestFilename = manifestFilename; + this.clean = clean; + } + + @Override + public ModpackBuilder call() throws Exception { + if (clean) { + List failures = new ArrayList(); + + try { + LauncherUtils.interruptibleDelete(outputDir, failures); + } catch (IOException e) { + Thread.sleep(1000); + LauncherUtils.interruptibleDelete(outputDir, failures); + } + + if (failures.size() > 0) { + throw new LauncherException(failures.size() + " failed to delete", "There were " + failures.size() + " failures during cleaning."); + } + } + + //noinspection ResultOfMethodCallIgnored + outputDir.mkdirs(); + + String[] args = { + "--version", version, + "--manifest-dest", new File(outputDir, manifestFilename).getAbsolutePath(), + "-i", inputDir.getAbsolutePath(), + "-o", outputDir.getAbsolutePath() + }; + PackageBuilder.main(args); + + return this; + } + + @Override + public double getProgress() { + return -1; + } + + @Override + public String getStatus() { + return "Building modpack..."; + } +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/Problem.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/Problem.java new file mode 100644 index 0000000..a2227ce --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/Problem.java @@ -0,0 +1,27 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.compile; + +import lombok.Data; + +@Data +public class Problem { + + private final String title; + private final String explanation; + + public Problem(String title, String explanation) { + this.title = title; + this.explanation = explanation; + } + + @Override + public String toString() { + return title; + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemChecker.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemChecker.java new file mode 100644 index 0000000..0719036 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemChecker.java @@ -0,0 +1,94 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.compile; + +import com.beust.jcommander.internal.Lists; +import com.skcraft.concurrency.ProgressObservable; +import com.skcraft.launcher.builder.BuilderOptions; +import com.skcraft.launcher.buildtools.BuildTools; + +import java.io.File; +import java.util.List; +import java.util.concurrent.Callable; + +public class ProblemChecker implements Callable>, ProgressObservable { + + private final BuildTools buildTools; + private String status = "Checking for problems..."; + + public ProblemChecker(BuildTools buildTools) { + this.buildTools = buildTools; + } + + @Override + public List call() throws Exception { + List problems = Lists.newArrayList(); + + File inputDir = buildTools.getInputDir(); + File srcDir = buildTools.getSrcDir(); + File loadersDir = new File(inputDir, BuilderOptions.DEFAULT_LOADERS_DIRNAME); + File modsDir = new File(srcDir, "mods"); + boolean hasLoaders = hasFiles(loadersDir); + boolean hasMods = hasFiles(modsDir); + + String[] files; + + if (new File(inputDir, "_CLIENT").exists()) { + problems.add(new Problem("Root _CLIENT", "There's a _CLIENT folder that's not in " + + "the src/ folder. Only files that are in src/ will actually appear in the " + + "modpack, so you probably intended to put _CLIENT in src/.")); + } + + if (new File(inputDir, "_SERVER").exists()) { + problems.add(new Problem("Root _SERVER", "There's a _SERVER folder that's not in " + + "the src/ folder. Only files that are in src/ will actually appear in the " + + "modpack, so you probably intended to put _SERVER in src/.")); + } + + if (new File(inputDir, "mods").exists()) { + problems.add(new Problem("Root mods", "There's a mods folder that's not in " + + "the src/ folder. Only files that are in src/ will actually appear in the " + + "modpack.")); + } + + if (new File(inputDir, "config").exists()) { + problems.add(new Problem("Root mods", "There's a config folder that's not in " + + "the src/ folder. Only files that are in src/ will actually appear in the " + + "modpack.")); + } + + if (new File(inputDir, "version.json").exists()) { + problems.add(new Problem("Legacy version.json", "There's a version.json file in the " + + "project directory. If you are upgrading your modpack from an old version " + + "of the launcher, then you should be able to delete version.json as it is " + + "no longer needed to create a modpack. If you are intentionally overriding the " + + "Minecraft version manifest, then ignore this warning.")); + } + + if (hasMods && !hasLoaders) { + problems.add(new Problem("No Loaders", "There appears to be a mods/ folder but there's no mod loaders in loaders/.")); + } + + return problems; + } + + @Override + public double getProgress() { + return -1; + } + + @Override + public String getStatus() { + return status; + } + + private static boolean hasFiles(File dir) { + String[] contents = dir.list(); + return contents != null && contents.length > 0; + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTable.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTable.java new file mode 100644 index 0000000..d73f442 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTable.java @@ -0,0 +1,34 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.compile; + +import javax.swing.*; +import javax.swing.table.TableModel; +import java.awt.*; + +class ProblemTable extends JTable { + + public ProblemTable() { + setShowGrid(false); + setRowHeight((int) (Math.max(getRowHeight(), new JCheckBox().getPreferredSize().getHeight() - 2))); + setIntercellSpacing(new Dimension(0, 0)); + setFillsViewportHeight(true); + setTableHeader(null); + setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + } + + @Override + public void setModel(TableModel dataModel) { + super.setModel(dataModel); + try { + getColumnModel().getColumn(0).setMaxWidth(20); + } catch (ArrayIndexOutOfBoundsException ignored) { + } + } + + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTableModel.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTableModel.java new file mode 100644 index 0000000..3d290ab --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTableModel.java @@ -0,0 +1,88 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.compile; + +import com.skcraft.launcher.swing.SwingHelper; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import java.util.List; + +class ProblemTableModel extends AbstractTableModel { + + private static final ImageIcon WARNING_ICON; + + static { + WARNING_ICON = SwingHelper.readImageIcon(ProblemTableModel.class, "warning_icon.png"); + } + + private final List problems; + + public ProblemTableModel(List problems) { + this.problems = problems; + } + + @Override + public String getColumnName(int columnIndex) { + switch (columnIndex) { + case 0: + return ""; + case 1: + return "Problem"; + default: + return null; + } + } + + @Override + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case 0: + return ImageIcon.class; + case 1: + return Problem.class; + default: + return null; + } + } + + @Override + public void setValueAt(Object value, int rowIndex, int columnIndex) { + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + @Override + public int getRowCount() { + return problems.size(); + } + + @Override + public int getColumnCount() { + return 2; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + switch (columnIndex) { + case 0: + return WARNING_ICON; + case 1: + return problems.get(rowIndex); + default: + return null; + } + } + + public Problem getProblem(int index) { + return problems.get(index); + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemViewer.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemViewer.java new file mode 100644 index 0000000..d20bcca --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemViewer.java @@ -0,0 +1,79 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.compile; + +import com.skcraft.launcher.swing.SwingHelper; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +public class ProblemViewer extends JDialog { + + private static final String DEFAULT_EXPLANATION = "Select a problem on the left to see the explanation here."; + private final ProblemTable problemTable = new ProblemTable(); + private final ProblemTableModel problemTableModel; + private final JTextArea explanationText = new JTextArea(DEFAULT_EXPLANATION); + + public ProblemViewer(Window parent, List problems) { + super(parent, "Potential Problems", ModalityType.DOCUMENT_MODAL); + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + initComponents(); + pack(); + setLocationRelativeTo(parent); + + problemTableModel = new ProblemTableModel(problems); + problemTable.setModel(problemTableModel); + } + + private void initComponents() { + explanationText.setFont(new JTextField().getFont()); + explanationText.setEditable(false); + explanationText.setLineWrap(true); + explanationText.setWrapStyleWord(true); + + JPanel container = new JPanel(); + container.setLayout(new MigLayout("fill, insets dialog")); + + JSplitPane splitPane = new JSplitPane( + JSplitPane.HORIZONTAL_SPLIT, + SwingHelper.wrapScrollPane(problemTable), SwingHelper. + wrapScrollPane(explanationText)); + splitPane.setDividerLocation(180); + SwingHelper.flattenJSplitPane(splitPane); + + container.add(splitPane, "grow, w 220:500, h 240, wrap"); + + JButton closeButton = new JButton("Close"); + container.add(closeButton, "tag cancel, gaptop unrel"); + + add(container, BorderLayout.CENTER); + + problemTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + Problem selected = problemTableModel.getProblem(problemTable.getSelectedRow()); + if (selected != null) { + SwingHelper.setTextAndResetCaret(explanationText, selected.getExplanation()); + } + } + }); + + closeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + } +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ServerDeployer.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ServerDeployer.java new file mode 100644 index 0000000..a3aeec5 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ServerDeployer.java @@ -0,0 +1,69 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.compile; + +import com.skcraft.concurrency.ProgressObservable; +import com.skcraft.launcher.LauncherException; +import com.skcraft.launcher.LauncherUtils; +import com.skcraft.launcher.builder.ServerCopyExport; +import com.skcraft.launcher.buildtools.compile.DeployServerDialog.DeployOptions; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +public class ServerDeployer implements Callable, ProgressObservable { + + private final File srcDir; + private final DeployOptions options; + + public ServerDeployer(File srcDir, DeployOptions options) { + this.srcDir = srcDir; + this.options = options; + } + + @Override + public ServerDeployer call() throws Exception { + File modsDir = new File(options.getDestDir(), "mods"); + + if (options.isCleanMods() && modsDir.isDirectory()) { + List failures = new ArrayList(); + + try { + LauncherUtils.interruptibleDelete(modsDir, failures); + } catch (IOException e) { + Thread.sleep(1000); + LauncherUtils.interruptibleDelete(modsDir, failures); + } + + if (failures.size() > 0) { + throw new LauncherException(failures.size() + " failed to delete", "There were " + failures.size() + " failures during cleaning."); + } + } + + String[] args = { + "--source", srcDir.getAbsolutePath(), + "--dest", options.getDestDir().getAbsolutePath() + }; + ServerCopyExport.main(args); + + return this; + } + + @Override + public double getProgress() { + return -1; + } + + @Override + public String getStatus() { + return "Deploying server files..."; + } + +} diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/compile/warning_icon.png b/build-tools/src/main/resources/com/skcraft/launcher/buildtools/compile/warning_icon.png new file mode 100644 index 0000000..209b290 Binary files /dev/null and b/build-tools/src/main/resources/com/skcraft/launcher/buildtools/compile/warning_icon.png differ