Add the base files to the Launcher Git.
33
creator-tools/build.gradle
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
plugins {
|
||||
id 'application'
|
||||
id "com.github.johnrengelman.shadow"
|
||||
id 'io.freefair.lombok'
|
||||
}
|
||||
|
||||
version = "2.1.0-SNAPSHOT"
|
||||
|
||||
application {
|
||||
mainClassName = "com.skcraft.launcher.creator.Creator"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(path: ':launcher-builder')
|
||||
implementation 'org.eclipse.jetty:jetty-server:9.3.1.v20150714'
|
||||
implementation 'com.jidesoft:jide-oss:3.6.18'
|
||||
}
|
||||
|
||||
processResources {
|
||||
filesMatching('**/*.properties') {
|
||||
filter {
|
||||
it.replace('${project.version}', project.version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
archiveClassifier.set("")
|
||||
}
|
||||
|
||||
build {
|
||||
dependsOn(shadowJar)
|
||||
}
|
||||
2
creator-tools/lombok.config
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# This file is generated by the 'io.freefair.lombok' Gradle plugin
|
||||
config.stopBubbling = true
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator;
|
||||
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.skcraft.launcher.Launcher;
|
||||
import com.skcraft.launcher.creator.controller.WelcomeController;
|
||||
import com.skcraft.launcher.creator.dialog.WelcomeDialog;
|
||||
import com.skcraft.launcher.creator.model.creator.CreatorConfig;
|
||||
import com.skcraft.launcher.creator.model.creator.RecentEntry;
|
||||
import com.skcraft.launcher.creator.model.creator.Workspace;
|
||||
import com.skcraft.launcher.persistence.Persistence;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import java.io.File;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class Creator {
|
||||
|
||||
@Getter private final File dataDir;
|
||||
@Getter private final CreatorConfig config;
|
||||
@Getter private final ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
|
||||
|
||||
public Creator() {
|
||||
this.dataDir = getAppDataDir();
|
||||
this.config = Persistence.load(new File(dataDir, "config.json"), CreatorConfig.class);
|
||||
|
||||
// Remove deleted workspaces
|
||||
List<RecentEntry> recentEntries = config.getRecentEntries();
|
||||
Iterator<RecentEntry> it = recentEntries.iterator();
|
||||
while (it.hasNext()) {
|
||||
RecentEntry workspace = it.next();
|
||||
if (!Workspace.getWorkspaceFile(workspace.getPath()).exists()) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void showWelcome() {
|
||||
WelcomeDialog dialog = new WelcomeDialog();
|
||||
WelcomeController controller = new WelcomeController(dialog, this);
|
||||
controller.show();
|
||||
}
|
||||
|
||||
private static File getFileChooseDefaultDir() {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
FileSystemView fsv = chooser.getFileSystemView();
|
||||
return fsv.getDefaultDirectory();
|
||||
}
|
||||
|
||||
private static File getAppDataDir() {
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
if (osName.contains("win")) {
|
||||
return new File(getFileChooseDefaultDir(), "SKCraft Modpack Creator");
|
||||
} else {
|
||||
return new File(System.getProperty("user.home"), ".skcraftcreator");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Launcher.setupLogger();
|
||||
System.setProperty("skcraftLauncher.killWithoutConfirm", "true");
|
||||
|
||||
final Creator creator = new Creator();
|
||||
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
SwingHelper.setSwingProperties("Modpack Creator");
|
||||
SwingHelper.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
|
||||
try {
|
||||
creator.showWelcome();
|
||||
} catch (Exception e) {
|
||||
SwingHelper.showErrorDialog(null, "Failed to start the modpack creator program.", "Start Error", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.skcraft.concurrency.Deferred;
|
||||
import com.skcraft.concurrency.Deferreds;
|
||||
import com.skcraft.concurrency.SettableProgress;
|
||||
import com.skcraft.launcher.creator.dialog.GenerateListingDialog;
|
||||
import com.skcraft.launcher.creator.dialog.ManifestEntryDialog;
|
||||
import com.skcraft.launcher.creator.model.creator.ManifestEntry;
|
||||
import com.skcraft.launcher.creator.model.creator.Workspace;
|
||||
import com.skcraft.launcher.creator.model.swing.ListingType;
|
||||
import com.skcraft.launcher.creator.model.swing.ManifestEntryTableModel;
|
||||
import com.skcraft.launcher.dialog.ProgressDialog;
|
||||
import com.skcraft.launcher.persistence.Persistence;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.util.SwingExecutor;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GenerateListingController {
|
||||
|
||||
private final GenerateListingDialog dialog;
|
||||
private final Workspace workspace;
|
||||
private final List<ManifestEntry> manifestEntries;
|
||||
private final ListeningExecutorService executor;
|
||||
private final ManifestEntryTableModel manifestTableModel;
|
||||
|
||||
public GenerateListingController(GenerateListingDialog dialog, Workspace workspace, List<ManifestEntry> manifestEntries, ListeningExecutorService executor) {
|
||||
this.dialog = dialog;
|
||||
this.workspace = workspace;
|
||||
this.manifestEntries = manifestEntries;
|
||||
this.executor = executor;
|
||||
|
||||
this.manifestTableModel = new ManifestEntryTableModel(manifestEntries);
|
||||
dialog.getManifestsTable().setModel(manifestTableModel);
|
||||
dialog.getManifestsTableAdjuster().adjustColumns();
|
||||
|
||||
initListeners();
|
||||
|
||||
setListingType(workspace.getPackageListingType());
|
||||
}
|
||||
|
||||
public void setOutputDir(File dir) {
|
||||
dialog.getDestDirField().setPath(dir.getAbsolutePath());
|
||||
}
|
||||
|
||||
public void setListingType(ListingType type) {
|
||||
dialog.getListingTypeCombo().setSelectedItem(type);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
|
||||
public Optional<ManifestEntry> getManifestFromIndex(int selectedIndex) {
|
||||
if (selectedIndex >= 0) {
|
||||
ManifestEntry manifest = manifestEntries.get(selectedIndex);
|
||||
if (manifest != null) {
|
||||
return Optional.fromNullable(manifest);
|
||||
}
|
||||
}
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
public Optional<ManifestEntry> getSelectedManifest() {
|
||||
JTable table = dialog.getManifestsTable();
|
||||
int selectedIndex = table.getSelectedRow();
|
||||
if (selectedIndex >= 0) {
|
||||
selectedIndex = table.convertRowIndexToModel(selectedIndex);
|
||||
ManifestEntry manifest = manifestEntries.get(selectedIndex);
|
||||
if (manifest != null) {
|
||||
return Optional.fromNullable(manifest);
|
||||
}
|
||||
}
|
||||
|
||||
SwingHelper.showErrorDialog(dialog, "Please select a modpack from the list.", "Error");
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
private void updateManifestEntryInTable(ManifestEntry manifestEntry) {
|
||||
int index = manifestEntries.indexOf(manifestEntry);
|
||||
if (index >= 0) {
|
||||
manifestTableModel.fireTableRowsUpdated(index, index);
|
||||
}
|
||||
}
|
||||
|
||||
private void initListeners() {
|
||||
dialog.getManifestsTable().addMouseListener(new MouseAdapter() {
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
JTable table = (JTable) e.getSource();
|
||||
Point point = e.getPoint();
|
||||
int selectedIndex = table.rowAtPoint(point);
|
||||
if (selectedIndex >= 0) {
|
||||
selectedIndex = table.convertRowIndexToModel(selectedIndex);
|
||||
Optional<ManifestEntry> optional = getManifestFromIndex(selectedIndex);
|
||||
if (optional.isPresent()) {
|
||||
if (showModifyDialog(optional.get())) {
|
||||
updateManifestEntryInTable(optional.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialog.getListingTypeCombo().addItemListener(e -> {
|
||||
ListingType type = (ListingType) e.getItem();
|
||||
dialog.getGameKeyWarning().setVisible(!type.isGameKeyCompatible());
|
||||
});
|
||||
|
||||
dialog.getEditManifestButton().addActionListener(e -> {
|
||||
Optional<ManifestEntry> optional = getSelectedManifest();
|
||||
if (optional.isPresent()) {
|
||||
if (showModifyDialog(optional.get())) {
|
||||
updateManifestEntryInTable(optional.get());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialog.getGenerateButton().addActionListener(e -> tryGenerate());
|
||||
|
||||
dialog.getCancelButton().addActionListener(e -> dialog.dispose());
|
||||
}
|
||||
|
||||
private boolean showModifyDialog(ManifestEntry manifestEntry) {
|
||||
ManifestEntryDialog modifyDialog = new ManifestEntryDialog(dialog);
|
||||
modifyDialog.setTitle("Modify " + manifestEntry.getManifestInfo().getLocation());
|
||||
ManifestEntryController controller = new ManifestEntryController(modifyDialog, manifestEntry);
|
||||
return controller.show();
|
||||
}
|
||||
|
||||
private boolean tryGenerate() {
|
||||
String path = dialog.getDestDirField().getPath().trim();
|
||||
|
||||
if (path.isEmpty()) {
|
||||
SwingHelper.showErrorDialog(dialog, "A directory must be entered.", "Error");
|
||||
return false;
|
||||
}
|
||||
|
||||
List<ManifestEntry> selected = manifestEntries.stream()
|
||||
.filter(ManifestEntry::isSelected)
|
||||
.sorted()
|
||||
.collect(Collectors.toCollection(Lists::newArrayList));
|
||||
|
||||
if (selected.isEmpty()) {
|
||||
SwingHelper.showErrorDialog(dialog, "At least one modpack must be selected to appear in the package list.", "Error");
|
||||
return false;
|
||||
}
|
||||
|
||||
ListingType listingType = (ListingType) dialog.getListingTypeCombo().getSelectedItem();
|
||||
File destDir = new File(path);
|
||||
destDir.mkdirs();
|
||||
File file = new File(destDir, listingType.getFilename());
|
||||
|
||||
workspace.setPackageListingEntries(selected);
|
||||
workspace.setPackageListingType(listingType);
|
||||
Persistence.commitAndForget(workspace);
|
||||
|
||||
SettableProgress progress = new SettableProgress("Generating package listing...", -1);
|
||||
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(() -> listingType.generate(selected)))
|
||||
.thenTap(() -> progress.set("Deleting older package listing files...", -1))
|
||||
.thenApply(input -> {
|
||||
for (ListingType otherListingType : ListingType.values()) {
|
||||
File f = new File(destDir, otherListingType.getFilename());
|
||||
if (f.exists()) {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
})
|
||||
.thenTap(() -> progress.set("Writing package listing to disk...", -1))
|
||||
.thenApply(input -> {
|
||||
try {
|
||||
Files.write(input, file, Charset.forName("UTF-8"));
|
||||
return file;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to write package listing file to disk", e);
|
||||
}
|
||||
})
|
||||
.handleAsync(v -> {
|
||||
if (listingType.isGameKeyCompatible()) {
|
||||
SwingHelper.showMessageDialog(dialog, "Successfully generated package listing.", "Success", null, JOptionPane.INFORMATION_MESSAGE);
|
||||
} else {
|
||||
SwingHelper.showMessageDialog(dialog, "Successfully generated package listing.\n\n" +
|
||||
"Note that any modpacks with game keys set were not added.",
|
||||
"Success", null, JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
dialog.dispose();
|
||||
SwingHelper.browseDir(destDir, dialog);
|
||||
}, ex -> {}, SwingExecutor.INSTANCE);
|
||||
|
||||
ProgressDialog.showProgress(dialog, deferred, progress, "Writing package listing...", "Writing package listing...");
|
||||
SwingHelper.addErrorDialogCallback(dialog, deferred);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller;
|
||||
|
||||
import com.skcraft.launcher.creator.dialog.ManifestEntryDialog;
|
||||
import com.skcraft.launcher.creator.model.creator.ManifestEntry;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
|
||||
public class ManifestEntryController {
|
||||
|
||||
private final ManifestEntryDialog dialog;
|
||||
private final ManifestEntry manifestEntry;
|
||||
|
||||
private boolean save;
|
||||
|
||||
public ManifestEntryController(ManifestEntryDialog dialog, ManifestEntry manifestEntry) {
|
||||
this.dialog = dialog;
|
||||
this.manifestEntry = manifestEntry;
|
||||
|
||||
initListeners();
|
||||
copyFrom();
|
||||
}
|
||||
|
||||
private void copyFrom() {
|
||||
dialog.getIncludeCheck().setSelected(manifestEntry.isSelected());
|
||||
dialog.getPrioritySpinner().setValue(manifestEntry.getManifestInfo().getPriority());
|
||||
SwingHelper.setTextAndResetCaret(dialog.getGameKeysText(), SwingHelper.listToLines(manifestEntry.getGameKeys()));
|
||||
}
|
||||
|
||||
private void copyTo() {
|
||||
manifestEntry.setSelected(dialog.getIncludeCheck().isSelected());
|
||||
manifestEntry.getManifestInfo().setPriority((Integer) dialog.getPrioritySpinner().getValue());
|
||||
manifestEntry.setGameKeys(SwingHelper.linesToList(dialog.getGameKeysText().getText()));
|
||||
}
|
||||
|
||||
public boolean show() {
|
||||
dialog.setVisible(true);
|
||||
return save;
|
||||
}
|
||||
|
||||
private void initListeners() {
|
||||
dialog.getOkButton().addActionListener(e -> {
|
||||
copyTo();
|
||||
save = true;
|
||||
dialog.dispose();
|
||||
});
|
||||
|
||||
dialog.getCancelButton().addActionListener(e -> dialog.dispose());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,862 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.skcraft.concurrency.Deferred;
|
||||
import com.skcraft.concurrency.Deferreds;
|
||||
import com.skcraft.concurrency.SettableProgress;
|
||||
import com.skcraft.launcher.Instance;
|
||||
import com.skcraft.launcher.InstanceList;
|
||||
import com.skcraft.launcher.Launcher;
|
||||
import com.skcraft.launcher.auth.OfflineSession;
|
||||
import com.skcraft.launcher.auth.Session;
|
||||
import com.skcraft.launcher.builder.BuilderConfig;
|
||||
import com.skcraft.launcher.builder.FnPatternList;
|
||||
import com.skcraft.launcher.creator.Creator;
|
||||
import com.skcraft.launcher.creator.controller.task.*;
|
||||
import com.skcraft.launcher.creator.dialog.AboutDialog;
|
||||
import com.skcraft.launcher.creator.dialog.*;
|
||||
import com.skcraft.launcher.creator.dialog.BuildDialog.BuildOptions;
|
||||
import com.skcraft.launcher.creator.dialog.DeployServerDialog.DeployOptions;
|
||||
import com.skcraft.launcher.creator.model.creator.*;
|
||||
import com.skcraft.launcher.creator.model.swing.PackTableModel;
|
||||
import com.skcraft.launcher.creator.server.TestServer;
|
||||
import com.skcraft.launcher.creator.server.TestServerBuilder;
|
||||
import com.skcraft.launcher.creator.swing.PackDirectoryFilter;
|
||||
import com.skcraft.launcher.dialog.*;
|
||||
import com.skcraft.launcher.model.modpack.LaunchModifier;
|
||||
import com.skcraft.launcher.persistence.Persistence;
|
||||
import com.skcraft.launcher.swing.PopupMouseAdapter;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.util.MorePaths;
|
||||
import com.skcraft.launcher.util.SwingExecutor;
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PackManagerController {
|
||||
|
||||
private static final DateFormat VERSION_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
||||
private static final Pattern FILENAME_SANITIZE = Pattern.compile("[^a-z0-9_\\-\\.]+");
|
||||
|
||||
@Getter private final File workspaceDir;
|
||||
@Getter private final Creator creator;
|
||||
@Getter private final File workspaceFile;
|
||||
@Getter private final File dataDir;
|
||||
@Getter private final File distDir;
|
||||
@Getter private final File launcherDir;
|
||||
@Getter private File webRoot;
|
||||
@Getter private Workspace workspace;
|
||||
@Getter private final Launcher launcher;
|
||||
@Getter private final ListeningExecutorService executor;
|
||||
@Getter private final TestServer testServer;
|
||||
|
||||
private File lastServerDestDir;
|
||||
|
||||
private final PackManagerFrame frame;
|
||||
private PackTableModel packTableModel;
|
||||
|
||||
public PackManagerController(PackManagerFrame frame, File workspaceDir, Creator creator) throws IOException {
|
||||
this.workspaceDir = workspaceDir;
|
||||
this.creator = creator;
|
||||
this.dataDir = Workspace.getDataDir(workspaceDir);
|
||||
workspaceFile = Workspace.getWorkspaceFile(workspaceDir);
|
||||
|
||||
this.distDir = new File(workspaceDir, "_upload");
|
||||
launcherDir = new File(dataDir, "staging/launcher");
|
||||
File launcherConfigDir = new File(creator.getDataDir(), "launcher");
|
||||
this.webRoot = new File(dataDir, "staging/www");
|
||||
|
||||
launcherDir.mkdirs();
|
||||
launcherConfigDir.mkdirs();
|
||||
webRoot.mkdirs();
|
||||
|
||||
this.launcher = new Launcher(launcherDir, launcherConfigDir);
|
||||
this.executor = launcher.getExecutor();
|
||||
this.frame = frame;
|
||||
|
||||
TestServerBuilder builder = new TestServerBuilder();
|
||||
builder.setBaseDir(webRoot);
|
||||
builder.setPort(0);
|
||||
testServer = builder.build();
|
||||
}
|
||||
|
||||
public void show() {
|
||||
frame.setVisible(true);
|
||||
frame.setTitle("Modpack Creator - [" + workspaceDir.getAbsolutePath() + "]");
|
||||
|
||||
initListeners();
|
||||
loadWorkspace();
|
||||
|
||||
Deferreds.makeDeferred(executor.submit(() -> {
|
||||
startServer();
|
||||
return null;
|
||||
}))
|
||||
.handle(
|
||||
result -> {
|
||||
},
|
||||
(ex) -> SwingHelper.showErrorDialog(frame, "Failed to start a local web server. You will be unable to test modpacks.", "Error", ex)
|
||||
);
|
||||
}
|
||||
|
||||
private void startServer() throws Exception {
|
||||
testServer.start();
|
||||
|
||||
launcher.getProperties().setProperty("newsUrl", "http://localhost:" + testServer.getLocalPort() + "/news.html");
|
||||
launcher.getProperties().setProperty("packageListUrl", "http://localhost:" + testServer.getLocalPort() + "/packages.json");
|
||||
launcher.getProperties().setProperty("selfUpdateUrl", "http://localhost:" + testServer.getLocalPort() + "/latest.json");
|
||||
}
|
||||
|
||||
private void loadWorkspace() {
|
||||
PackLoader loader = new PackLoader();
|
||||
|
||||
SettableProgress progress = new SettableProgress("Loading workspace...", -1);
|
||||
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(() -> {
|
||||
Workspace workspace = Persistence.load(workspaceFile, Workspace.class);
|
||||
workspace.setDirectory(workspaceDir);
|
||||
workspace.load();
|
||||
if (!workspaceFile.exists()) {
|
||||
Persistence.commitAndForget(workspace);
|
||||
}
|
||||
this.workspace = workspace;
|
||||
return workspace;
|
||||
}))
|
||||
.thenTap(() -> progress.observe(loader))
|
||||
.thenApply(loader)
|
||||
.thenApplyAsync(packs -> {
|
||||
JTable table = frame.getPackTable();
|
||||
packTableModel = new PackTableModel(packs);
|
||||
table.setModel(packTableModel);
|
||||
packTableModel.fireTableDataChanged();
|
||||
table.getRowSorter().toggleSortOrder(1);
|
||||
if (packTableModel.getRowCount() > 0) {
|
||||
table.addRowSelectionInterval(0, 0);
|
||||
}
|
||||
|
||||
return packs;
|
||||
}, SwingExecutor.INSTANCE);
|
||||
|
||||
ProgressDialog.showProgress(frame, deferred, progress, "Loading workspace...", "Loading workspace...");
|
||||
SwingHelper.addErrorDialogCallback(frame, deferred);
|
||||
}
|
||||
|
||||
private boolean checkPackLoaded(Pack pack) {
|
||||
if (pack.isLoaded()) {
|
||||
return true;
|
||||
} else {
|
||||
SwingHelper.showErrorDialog(frame, "The selected pack could not be loaded. You will have to remove it from the workspace or change its location.", "Error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Pack> getPackFromIndex(int selectedIndex, boolean requireLoaded) {
|
||||
if (selectedIndex >= 0) {
|
||||
Pack pack = workspace.getPacks().get(selectedIndex);
|
||||
if (pack != null && (!requireLoaded || checkPackLoaded(pack))) {
|
||||
return Optional.of(pack);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<Pack> getSelectedPack(boolean requireLoaded) {
|
||||
JTable table = frame.getPackTable();
|
||||
int selectedIndex = table.getSelectedRow();
|
||||
if (selectedIndex >= 0) {
|
||||
selectedIndex = table.convertRowIndexToModel(selectedIndex);
|
||||
Pack pack = workspace.getPacks().get(selectedIndex);
|
||||
if (pack != null && (!requireLoaded || checkPackLoaded(pack))) {
|
||||
return Optional.of(pack);
|
||||
}
|
||||
}
|
||||
|
||||
SwingHelper.showErrorDialog(frame, "Please select a modpack from the list.", "Error");
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public boolean writeWorkspace() {
|
||||
try {
|
||||
Persistence.commit(workspace);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
SwingHelper.showErrorDialog(frame, "Failed to write the current state of the workspace to disk. " +
|
||||
"Any recent changes to the list of modpacks may not appear in the workspace on the next load.", "Error", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean writeBuilderConfig(Pack pack, BuilderConfig config) {
|
||||
try {
|
||||
Persistence.write(pack.getConfigFile(), config, Persistence.L2F_LIST_PRETTY_PRINTER);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
SwingHelper.showErrorDialog(frame, "Failed to write modpack.json to disk. Aborting.", "Error", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOfflineEnabled() {
|
||||
CreatorConfig config = creator.getConfig();
|
||||
|
||||
if (config.isOfflineEnabled()) {
|
||||
return true;
|
||||
} else {
|
||||
Session session = AccountSelectDialog.showAccountRequest(frame, launcher);
|
||||
if (session != null) {
|
||||
config.setOfflineEnabled(true);
|
||||
Persistence.commitAndForget(config);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canAddPackDir(File dir) {
|
||||
try {
|
||||
if (dir.exists() && !dir.isDirectory()) {
|
||||
SwingHelper.showErrorDialog(frame, "The selected path is a file that already exists. It must be a directory.", "Error");
|
||||
return false;
|
||||
} else if (dir.getCanonicalPath().equals(workspaceDir.getCanonicalPath())) {
|
||||
SwingHelper.showErrorDialog(frame, "You cannot choose the workspace directory.", "Error");
|
||||
return false;
|
||||
} else if (workspace.hasPack(dir)) {
|
||||
SwingHelper.showErrorDialog(frame, "There is already a modpack in this workspace that uses that directory.", "Error");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
SwingHelper.showErrorDialog(frame, "An unexpected error occurred while checking if the modpack being added can be added.", "Error", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addPackToWorkspace(Pack pack) {
|
||||
pack.load();
|
||||
|
||||
try {
|
||||
File base = workspaceDir;
|
||||
File child = pack.getDirectory();
|
||||
if (MorePaths.isSubDirectory(base, child)) {
|
||||
pack.setLocation(MorePaths.relativize(base, child));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
SwingHelper.showErrorDialog(frame, "An unexpected error occurred that could have been caused by the removal " +
|
||||
"of the workspace or modpack directory.", "Error", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Pack> packs = workspace.getPacks();
|
||||
pack.setWorkspace(workspace);
|
||||
packs.add(pack);
|
||||
packTableModel.fireTableRowsInserted(packs.size() - 1, packs.size() - 1);
|
||||
writeWorkspace();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void updatePackInWorkspace(Pack pack) {
|
||||
List<Pack> packs = workspace.getPacks();
|
||||
pack.load();
|
||||
int index = packs.indexOf(pack);
|
||||
if (index >= 0) {
|
||||
packTableModel.fireTableRowsUpdated(index, index);
|
||||
}
|
||||
writeWorkspace();
|
||||
}
|
||||
|
||||
public boolean removePackFromWorkspace(Pack pack) {
|
||||
if (workspace.getPacks().remove(pack)) {
|
||||
packTableModel.fireTableDataChanged();
|
||||
writeWorkspace();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void addDefaultConfig(BuilderConfig config) {
|
||||
LaunchModifier launchModifier = new LaunchModifier();
|
||||
launchModifier.setFlags(ImmutableList.of("-Dfml.ignoreInvalidMinecraftCertificates=true"));
|
||||
config.setLaunchModifier(launchModifier);
|
||||
|
||||
FnPatternList userFiles = new FnPatternList();
|
||||
userFiles.setInclude(Lists.newArrayList("options.txt", "optionsshaders.txt"));
|
||||
userFiles.setExclude(Lists.<String>newArrayList());
|
||||
config.setUserFiles(userFiles);
|
||||
}
|
||||
|
||||
private void initListeners() {
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosed(WindowEvent e) {
|
||||
try {
|
||||
testServer.stop();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
System.exit(0); // TODO: Proper shutdown
|
||||
}
|
||||
});
|
||||
|
||||
frame.getPackTable().addMouseListener(new MouseAdapter() {
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
JTable table = (JTable) e.getSource();
|
||||
Point point = e.getPoint();
|
||||
int selectedIndex = table.rowAtPoint(point);
|
||||
if (selectedIndex >= 0) {
|
||||
selectedIndex = table.convertRowIndexToModel(selectedIndex);
|
||||
Optional<Pack> optional = getPackFromIndex(selectedIndex, true);
|
||||
if (optional.isPresent()) {
|
||||
if (e.isControlDown()) {
|
||||
SwingHelper.browseDir(optional.get().getDirectory(), frame);
|
||||
} else {
|
||||
startTest(optional.get(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frame.getPackTable().addMouseListener(new PopupMouseAdapter() {
|
||||
@Override
|
||||
protected void showPopup(MouseEvent e) {
|
||||
JTable table = (JTable) e.getSource();
|
||||
Point point = e.getPoint();
|
||||
int selectedIndex = table.rowAtPoint(point);
|
||||
if (selectedIndex >= 0) {
|
||||
table.setRowSelectionInterval(selectedIndex, selectedIndex);
|
||||
Optional<Pack> optional = getSelectedPack(false);
|
||||
if (optional.isPresent()) {
|
||||
popupPackMenu(e.getComponent(), e.getX(), e.getY(), optional.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frame.getNewPackMenuItem().addActionListener(event -> tryAddPackViaDialog());
|
||||
|
||||
frame.getNewPackAtLocationMenuItem().addActionListener(e -> tryAddPackViaDirectory(true));
|
||||
|
||||
frame.getImportPackMenuItem().addActionListener(event -> tryAddPackViaDirectory(false));
|
||||
|
||||
frame.getRemovePackItem().addActionListener(e -> {
|
||||
Optional<Pack> optional = getSelectedPack(false);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
Pack pack = optional.get();
|
||||
|
||||
if (!pack.isLoaded() || SwingHelper.confirmDialog(frame, "Are you sure that you want to remove this modpack? No files will be deleted " +
|
||||
"and you can later re-import the modpack using 'Add Existing'.", "Confirm")) {
|
||||
removePackFromWorkspace(pack);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frame.getDeletePackItem().addActionListener(e -> {
|
||||
Optional<Pack> optional = getSelectedPack(false);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
Pack pack = optional.get();
|
||||
|
||||
String input = JOptionPane.showInputDialog(
|
||||
frame,
|
||||
"Are you sure that you want to delete '" + pack.getDirectory().getAbsolutePath() + "'? " +
|
||||
"If yes, type 'delete' below.",
|
||||
"Confirm",
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
|
||||
if (input != null && input.replaceAll("'", "").equalsIgnoreCase("delete")) {
|
||||
removePackFromWorkspace(pack);
|
||||
|
||||
DirectoryDeleter deleter = new DirectoryDeleter(pack.getDirectory());
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(deleter), executor);
|
||||
ProgressDialog.showProgress(frame, deferred, deleter, "Deleting modpack...", "Deleting modpack...");
|
||||
SwingHelper.addErrorDialogCallback(frame, deferred);
|
||||
} else if (input != null) {
|
||||
SwingHelper.showMessageDialog(frame, "You did not enter the correct word. Nothing was deleted.", "Failure", null, JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frame.getChangePackLocationMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> optional = getSelectedPack(false);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
Pack pack = optional.get();
|
||||
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
chooser.setDialogTitle("Choose New Folder for Pack");
|
||||
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
chooser.setFileFilter(new PackDirectoryFilter());
|
||||
|
||||
File dir = workspaceDir;
|
||||
|
||||
do {
|
||||
chooser.setCurrentDirectory(dir);
|
||||
int returnVal = chooser.showOpenDialog(frame);
|
||||
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
dir = chooser.getSelectedFile();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} while (!canAddPackDir(dir));
|
||||
|
||||
pack.setLocation(dir.getAbsolutePath());
|
||||
updatePackInWorkspace(pack);
|
||||
}
|
||||
});
|
||||
|
||||
frame.getRefreshMenuItem().addActionListener(e -> loadWorkspace());
|
||||
|
||||
frame.getQuitMenuItem().addActionListener(e -> {
|
||||
frame.dispose();
|
||||
});
|
||||
|
||||
frame.getEditConfigMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> optional = getSelectedPack(true);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
Pack pack = optional.get();
|
||||
File file = pack.getConfigFile();
|
||||
BuilderConfig config = Persistence.read(file, BuilderConfig.class);
|
||||
|
||||
if (BuilderConfigDialog.showEditor(frame, config)) {
|
||||
writeBuilderConfig(pack, config);
|
||||
updatePackInWorkspace(pack);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frame.getOpenFolderMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> selectedPack = getSelectedPack(true);
|
||||
|
||||
selectedPack.ifPresent(pack -> SwingHelper.browseDir(pack.getDirectory(), frame));
|
||||
});
|
||||
|
||||
frame.getCheckProblemsMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> optional = getSelectedPack(true);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
ProblemChecker checker = new ProblemChecker(optional.get());
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(checker), executor)
|
||||
.handleAsync(this::showProblems, (ex) -> {
|
||||
}, SwingExecutor.INSTANCE);
|
||||
SwingHelper.addErrorDialogCallback(frame, deferred);
|
||||
}
|
||||
});
|
||||
|
||||
frame.getTestMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> optional = getSelectedPack(true);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
Pack pack = optional.get();
|
||||
startTest(pack, false);
|
||||
}
|
||||
});
|
||||
|
||||
frame.getTestOnlineMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> optional = getSelectedPack(true);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
Pack pack = optional.get();
|
||||
startTest(pack, true);
|
||||
}
|
||||
});
|
||||
|
||||
frame.getOptionsMenuItem().addActionListener(e -> {
|
||||
ConfigurationDialog configDialog = new ConfigurationDialog(frame, launcher);
|
||||
configDialog.setVisible(true);
|
||||
});
|
||||
|
||||
frame.getInstanceOptionsMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> selectedPack = getSelectedPack(true);
|
||||
|
||||
selectedPack.ifPresent(pack -> {
|
||||
InstanceList.Enumerator instanceList = launcher.getInstances().createEnumerator();
|
||||
|
||||
ListenableFuture<InstanceList> future = executor.submit(instanceList);
|
||||
Futures.addCallback(future, new FutureCallback<InstanceList>() {
|
||||
@Override
|
||||
public void onSuccess(InstanceList result) {
|
||||
Instance found = null;
|
||||
|
||||
for (Instance instance : result.getInstances()) {
|
||||
if (instance.getName().equals(pack.getCachedConfig().getName())) {
|
||||
found = instance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == null) {
|
||||
SwingHelper.showErrorDialog(frame, "No instance found for that pack - you need " +
|
||||
"to test the pack first.", "Not Found");
|
||||
return;
|
||||
}
|
||||
|
||||
InstanceSettingsDialog.open(frame, found);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ignored) {
|
||||
}
|
||||
}, SwingExecutor.INSTANCE);
|
||||
|
||||
ProgressDialog.showProgress(frame, future, instanceList, "Enumerating instances...",
|
||||
"Enumerating instances...");
|
||||
SwingHelper.addErrorDialogCallback(frame, future);
|
||||
});
|
||||
});
|
||||
|
||||
frame.getClearInstanceMenuItem().addActionListener(e -> {
|
||||
DirectoryDeleter deleter = new DirectoryDeleter(launcher.getInstancesDir());
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(deleter), executor);
|
||||
ProgressDialog.showProgress(frame, deferred, deleter, "Deleting test instances...", "Deleting test instances...");
|
||||
SwingHelper.addErrorDialogCallback(frame, deferred);
|
||||
});
|
||||
|
||||
frame.getClearWebRootMenuItem().addActionListener(e -> {
|
||||
DirectoryDeleter deleter = new DirectoryDeleter(webRoot);
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(deleter), executor);
|
||||
ProgressDialog.showProgress(frame, deferred, deleter, "Deleting web server files...", "Deleting web server files...");
|
||||
SwingHelper.addErrorDialogCallback(frame, deferred);
|
||||
});
|
||||
|
||||
frame.getBuildMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> optional = getSelectedPack(true);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
Pack pack = optional.get();
|
||||
buildPack(pack);
|
||||
}
|
||||
});
|
||||
|
||||
frame.getDeployServerMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> optional = getSelectedPack(true);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
Pack pack = optional.get();
|
||||
DeployOptions options = DeployServerDialog.showDeployDialog(frame, lastServerDestDir);
|
||||
|
||||
if (options != null) {
|
||||
ConsoleFrame.showMessages();
|
||||
|
||||
File destDir = options.getDestDir();
|
||||
destDir.mkdirs();
|
||||
lastServerDestDir = destDir;
|
||||
|
||||
ServerDeploy deploy = new ServerDeploy(pack.getSourceDir(), options);
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(deploy), executor)
|
||||
.handleAsync(r -> SwingHelper.showMessageDialog(frame, "Server deployment complete!", "Success", null, JOptionPane.INFORMATION_MESSAGE),
|
||||
ex -> {
|
||||
},
|
||||
SwingExecutor.INSTANCE);
|
||||
ProgressDialog.showProgress(frame, deferred, deploy, "Deploying files...", "Deploying server files...");
|
||||
SwingHelper.addErrorDialogCallback(frame, deferred);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frame.getGeneratePackagesMenuItem().addActionListener(e -> {
|
||||
List<ManifestEntry> entries = workspace.getPackageListingEntries();
|
||||
ManifestInfoEnumerator enumerator = new ManifestInfoEnumerator(distDir);
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(() -> enumerator.apply(entries)))
|
||||
.handleAsync(loaded -> {
|
||||
GenerateListingDialog dialog = new GenerateListingDialog(frame);
|
||||
GenerateListingController controller = new GenerateListingController(dialog, workspace, loaded, executor);
|
||||
controller.setOutputDir(distDir);
|
||||
controller.show();
|
||||
}, ex -> {
|
||||
}, SwingExecutor.INSTANCE);
|
||||
ProgressDialog.showProgress(frame, deferred, new SettableProgress("Searching...", -1), "Searching for manifests...", "Searching for manifests...");
|
||||
SwingHelper.addErrorDialogCallback(frame, deferred);
|
||||
});
|
||||
|
||||
frame.getVersionCheckMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> optional = getSelectedPack(true);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
Pack pack = optional.get();
|
||||
|
||||
VersionCheckDialog dialog = new VersionCheckDialog(frame);
|
||||
VersionCheckController controller = new VersionCheckController(dialog, executor);
|
||||
controller.showUpdates(pack.getModsDir(), pack.getCachedConfig().getGameVersion(), frame);
|
||||
}
|
||||
});
|
||||
|
||||
frame.getOpenOutputFolderMenuItem().addActionListener(e -> SwingHelper.browseDir(distDir, frame));
|
||||
|
||||
frame.getOpenWorkspaceFolderMenuItem().addActionListener(e1 -> SwingHelper.browseDir(workspaceDir, frame));
|
||||
|
||||
frame.getOpenLauncherFolderMenuItem().addActionListener(e1 -> SwingHelper.browseDir(launcherDir, frame));
|
||||
|
||||
frame.getOpenWebRootMenuItem().addActionListener(e1 -> SwingHelper.browseDir(webRoot, frame));
|
||||
|
||||
frame.getOpenConsoleMenuItem().addActionListener(e -> {
|
||||
ConsoleFrame.showMessages();
|
||||
});
|
||||
|
||||
frame.getDocsMenuItem().addActionListener(e -> {
|
||||
SwingHelper.openURL("https://github.com/SKCraft/Launcher/wiki", frame);
|
||||
});
|
||||
|
||||
frame.getAboutMenuItem().addActionListener(e -> {
|
||||
AboutDialog.showAboutDialog(frame);
|
||||
});
|
||||
|
||||
SwingHelper.addActionListeners(frame.getNewPackButton(), frame.getNewPackMenuItem().getActionListeners());
|
||||
SwingHelper.addActionListeners(frame.getImportButton(), frame.getImportPackMenuItem().getActionListeners());
|
||||
SwingHelper.addActionListeners(frame.getEditConfigButton(), frame.getEditConfigMenuItem().getActionListeners());
|
||||
SwingHelper.addActionListeners(frame.getOpenFolderButton(), frame.getOpenFolderMenuItem().getActionListeners());
|
||||
SwingHelper.addActionListeners(frame.getCheckProblemsButton(), frame.getCheckProblemsMenuItem().getActionListeners());
|
||||
SwingHelper.addActionListeners(frame.getTestButton(), frame.getTestMenuItem().getActionListeners());
|
||||
SwingHelper.addActionListeners(frame.getBuildButton(), frame.getBuildMenuItem().getActionListeners());
|
||||
}
|
||||
|
||||
private void popupPackMenu(Component component, int x, int y, Pack pack) {
|
||||
JPopupMenu popup = new JPopupMenu();
|
||||
JMenuItem menuItem;
|
||||
|
||||
menuItem = new JMenuItem("Edit modpack.json...");
|
||||
menuItem.addActionListener(e -> frame.getEditConfigMenuItem().doClick());
|
||||
popup.add(menuItem);
|
||||
|
||||
menuItem = new JMenuItem("Open Directory");
|
||||
menuItem.addActionListener(e -> frame.getOpenFolderMenuItem().doClick());
|
||||
popup.add(menuItem);
|
||||
|
||||
menuItem = new JMenuItem("Check for Problems");
|
||||
menuItem.addActionListener(e -> frame.getCheckProblemsMenuItem().doClick());
|
||||
popup.add(menuItem);
|
||||
|
||||
popup.addSeparator();
|
||||
|
||||
menuItem = new JMenuItem("Test");
|
||||
menuItem.addActionListener(e -> frame.getTestMenuItem().doClick());
|
||||
popup.add(menuItem);
|
||||
|
||||
menuItem = new JMenuItem("Test Online");
|
||||
menuItem.addActionListener(e -> frame.getTestOnlineMenuItem().doClick());
|
||||
popup.add(menuItem);
|
||||
|
||||
menuItem = new JMenuItem("Instance settings...");
|
||||
menuItem.addActionListener(e -> frame.getInstanceOptionsMenuItem().doClick());
|
||||
popup.add(menuItem);
|
||||
|
||||
menuItem = new JMenuItem("Build...");
|
||||
menuItem.addActionListener(e -> frame.getBuildMenuItem().doClick());
|
||||
popup.add(menuItem);
|
||||
|
||||
menuItem = new JMenuItem("Deploy Server...");
|
||||
menuItem.addActionListener(e -> frame.getDeployServerMenuItem().doClick());
|
||||
popup.add(menuItem);
|
||||
|
||||
popup.addSeparator();
|
||||
|
||||
menuItem = new JMenuItem("Change Location...");
|
||||
menuItem.addActionListener(e -> frame.getChangePackLocationMenuItem().doClick());
|
||||
popup.add(menuItem);
|
||||
|
||||
menuItem = new JMenuItem("Remove...");
|
||||
menuItem.addActionListener(e -> frame.getRemovePackItem().doClick());
|
||||
popup.add(menuItem);
|
||||
|
||||
menuItem = new JMenuItem("Delete Forever...");
|
||||
menuItem.addActionListener(e -> frame.getDeletePackItem().doClick());
|
||||
popup.add(menuItem);
|
||||
|
||||
popup.show(component, x, y);
|
||||
}
|
||||
|
||||
private void tryAddPackViaDialog() {
|
||||
BuilderConfig config = new BuilderConfig();
|
||||
addDefaultConfig(config);
|
||||
Pack pack = new Pack();
|
||||
File dir;
|
||||
|
||||
do {
|
||||
if (BuilderConfigDialog.showEditor(frame, config)) {
|
||||
dir = new File(workspaceDir, config.getName());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} while (!canAddPackDir(dir));
|
||||
|
||||
pack.setLocation(dir.getAbsolutePath());
|
||||
|
||||
if (pack.getConfigFile().exists()) {
|
||||
if (SwingHelper.confirmDialog(frame, "There's already an existing modpack with that name, though " +
|
||||
"it is not imported into this workspace. Would you like to import it and ignore " +
|
||||
"the new modpack that you just entered?", "Conflict")) {
|
||||
addPackToWorkspace(pack);
|
||||
}
|
||||
} else {
|
||||
if (writeBuilderConfig(pack, config)) {
|
||||
pack.createGuideFolders();
|
||||
addPackToWorkspace(pack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void tryAddPackViaDirectory(boolean createNew) {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
chooser.setDialogTitle("Choose Folder for Pack");
|
||||
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
chooser.setFileFilter(new PackDirectoryFilter());
|
||||
|
||||
File dir = workspaceDir;
|
||||
|
||||
do {
|
||||
chooser.setCurrentDirectory(dir);
|
||||
int returnVal = chooser.showOpenDialog(frame);
|
||||
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
dir = chooser.getSelectedFile();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} while (!canAddPackDir(dir));
|
||||
|
||||
Pack pack = new Pack();
|
||||
pack.setLocation(dir.getAbsolutePath());
|
||||
|
||||
if (pack.getConfigFile().exists()) {
|
||||
if (createNew) {
|
||||
if (SwingHelper.confirmDialog(frame, "There's already a modpack in that directory. Do you want to import it instead?", "Exists Already")) {
|
||||
addPackToWorkspace(pack);
|
||||
}
|
||||
} else {
|
||||
addPackToWorkspace(pack);
|
||||
}
|
||||
} else if (createNew || SwingHelper.confirmDialog(frame, "You've selected a directory that doesn't seem to be a modpack " +
|
||||
"(at least with the directory structure this program expects). Would you like to create the files necessary to turn " +
|
||||
"that folder into a modpack?", "Import Error")) {
|
||||
|
||||
BuilderConfig config = new BuilderConfig();
|
||||
addDefaultConfig(config);
|
||||
|
||||
if (BuilderConfigDialog.showEditor(frame, config)) {
|
||||
if (writeBuilderConfig(pack, config)) {
|
||||
pack.createGuideFolders();
|
||||
addPackToWorkspace(pack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startTest(Pack pack, boolean online) {
|
||||
Session session;
|
||||
|
||||
if (online) {
|
||||
session = AccountSelectDialog.showAccountRequest(frame, launcher);
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!isOfflineEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
session = new OfflineSession("Player");
|
||||
}
|
||||
|
||||
String version = generateVersionFromDate();
|
||||
|
||||
PackBuilder builder = new PackBuilder(pack, webRoot, version, "staging.json", false, false);
|
||||
InstanceList.Enumerator enumerator = launcher.getInstances().createEnumerator();
|
||||
TestLauncher instanceLauncher = new TestLauncher(launcher, frame, pack.getCachedConfig().getName(), session);
|
||||
|
||||
SettableProgress progress = new SettableProgress(builder);
|
||||
|
||||
ConsoleFrame.showMessages();
|
||||
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(builder), executor)
|
||||
.thenTap(() -> progress.set("Loading instance in test launcher...", -1))
|
||||
.thenRun(enumerator)
|
||||
.thenTap(() -> progress.set("Launching", -1))
|
||||
.thenApply(instanceLauncher)
|
||||
.handleAsync(result -> ConsoleFrame.hideMessages(), ex -> {}, SwingExecutor.INSTANCE);
|
||||
|
||||
ProgressDialog.showProgress(frame, deferred, progress, "Setting up test instance...", "Preparing files for launch...");
|
||||
SwingHelper.addErrorDialogCallback(frame, deferred);
|
||||
}
|
||||
|
||||
private void buildPack(Pack pack) {
|
||||
String initialVersion = generateVersionFromDate();
|
||||
BuildOptions options = BuildDialog.showBuildDialog(frame, initialVersion, generateManifestName(pack), distDir);
|
||||
|
||||
if (options != null) {
|
||||
ConsoleFrame.showMessages();
|
||||
PackBuilder builder = new PackBuilder(pack, options.getDestDir(), options.getVersion(), options.getManifestFilename(), false, true);
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(builder), executor)
|
||||
.handleAsync(result -> {
|
||||
ConsoleFrame.hideMessages();
|
||||
SwingHelper.showMessageDialog(frame, "Successfully generated the package files.", "Success", null, JOptionPane.INFORMATION_MESSAGE);
|
||||
}, ex -> {}, SwingExecutor.INSTANCE);
|
||||
ProgressDialog.showProgress(frame, deferred, builder, "Building modpack...", "Building modpack...");
|
||||
SwingHelper.addErrorDialogCallback(frame, deferred);
|
||||
}
|
||||
}
|
||||
|
||||
private void showProblems(List<Problem> problems) {
|
||||
if (problems.isEmpty()) {
|
||||
SwingHelper.showMessageDialog(frame, "No potential problems found!", "Success", null, JOptionPane.INFORMATION_MESSAGE);
|
||||
} else {
|
||||
ProblemViewer viewer = new ProblemViewer(frame, problems);
|
||||
viewer.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
public String generateManifestName(Pack pack) {
|
||||
File file = pack.getConfigFile();
|
||||
if (file.exists()) {
|
||||
BuilderConfig config = Persistence.read(file, BuilderConfig.class, true);
|
||||
if (config != null) {
|
||||
String name = Strings.nullToEmpty(config.getName());
|
||||
name = name.toLowerCase();
|
||||
name = FILENAME_SANITIZE.matcher(name).replaceAll("-");
|
||||
name = name.trim();
|
||||
if (!name.isEmpty()) {
|
||||
return name + ".json";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "my_modpack.json";
|
||||
}
|
||||
|
||||
public static String generateVersionFromDate() {
|
||||
Date today = Calendar.getInstance().getTime();
|
||||
return VERSION_DATE_FORMAT.format(today);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.skcraft.concurrency.Deferred;
|
||||
import com.skcraft.concurrency.Deferreds;
|
||||
import com.skcraft.concurrency.SettableProgress;
|
||||
import com.skcraft.launcher.creator.controller.task.DirectoryWalker;
|
||||
import com.skcraft.launcher.creator.dialog.VersionCheckDialog;
|
||||
import com.skcraft.launcher.creator.model.creator.ModFile;
|
||||
import com.skcraft.launcher.creator.model.swing.ModFileTableModel;
|
||||
import com.skcraft.launcher.creator.util.ModInfoReader;
|
||||
import com.skcraft.launcher.creator.util.ModInfoReader.ModInfo;
|
||||
import com.skcraft.launcher.creator.util.NemModList;
|
||||
import com.skcraft.launcher.creator.util.NemModList.ModEntry;
|
||||
import com.skcraft.launcher.dialog.ProgressDialog;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.util.SwingExecutor;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
public class VersionCheckController {
|
||||
|
||||
private final VersionCheckDialog dialog;
|
||||
private final ListeningExecutorService executor;
|
||||
|
||||
public VersionCheckController(VersionCheckDialog dialog, ListeningExecutorService executor) {
|
||||
this.dialog = dialog;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public void showUpdates(File dir, String gameVersion, Window parentWindow) {
|
||||
initListeners();
|
||||
|
||||
DirectoryWalker walker = new DirectoryWalker(dir);
|
||||
walker.setRecursive(false);
|
||||
walker.setFileFilter(pathname -> pathname.getName().endsWith(".jar"));
|
||||
|
||||
ModInfoReader binaryInspector = new ModInfoReader();
|
||||
NemModList nemModList = new NemModList();
|
||||
|
||||
SettableProgress progress = new SettableProgress("Retrieving mod information...", -1);
|
||||
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(walker), executor)
|
||||
.thenTap(() -> progress.set("Querying NotEnoughMods for version data...", -1))
|
||||
.thenTap(() -> {
|
||||
try {
|
||||
nemModList.load(gameVersion);
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new RuntimeException("Failed to retrieve mod information from NotEnoughMods. Perhaps NEM doesn't support your pack's MC version.", e);
|
||||
}
|
||||
})
|
||||
.thenTap(() -> progress.set("Scanning mod files for manifests...", -1))
|
||||
.thenApply(files -> {
|
||||
List<ModFile> mods = Lists.newArrayList();
|
||||
|
||||
for (File file : files) {
|
||||
ModFile mod = new ModFile();
|
||||
mod.setGameVersion(gameVersion);
|
||||
mod.setFile(file);
|
||||
|
||||
List<? extends ModInfo> infoList = binaryInspector.detectMods(file);
|
||||
if (!infoList.isEmpty()) {
|
||||
ModInfo info = infoList.get(0);
|
||||
mod.setModId(info.getModId());
|
||||
mod.setName(info.getName());
|
||||
mod.setVersion(info.getVersion());
|
||||
|
||||
if (info.getUrl() != null) {
|
||||
mod.setUrl(getFirstUrl(info.getUrl(), "http://" + info.getUrl()));
|
||||
}
|
||||
}
|
||||
|
||||
if (mod.getModId() != null) {
|
||||
ModEntry entry = nemModList.get(mod.getModId());
|
||||
|
||||
if (entry != null) {
|
||||
mod.setLatestVersion(entry.getLatestVersion());
|
||||
mod.setLatestDevVersion(entry.getLatestDevVersion());
|
||||
if (entry.getUrl() != null) {
|
||||
mod.setUrl(entry.getUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mods.add(mod);
|
||||
}
|
||||
|
||||
return mods;
|
||||
})
|
||||
.handleAsync(mods -> {
|
||||
List<ModFile> known = Lists.newArrayList();
|
||||
List<ModFile> unknown = Lists.newArrayList();
|
||||
|
||||
for (ModFile mod : mods) {
|
||||
if (mod.getVersion() != null && mod.getLatestVersion() != null) {
|
||||
if (!mod.getCleanVersion().equals(mod.getLatestVersion()) && !mod.getCleanVersion().equals(mod.getLatestDevVersion())) {
|
||||
known.add(mod);
|
||||
}
|
||||
} else {
|
||||
unknown.add(mod);
|
||||
}
|
||||
}
|
||||
|
||||
dialog.getKnownModsTable().setModel(new ModFileTableModel(known));
|
||||
dialog.getUnknownModsTable().setModel(new ModFileTableModel(unknown));
|
||||
dialog.getKnownModsTable().getRowSorter().toggleSortOrder(1);
|
||||
dialog.getUnknownModsTable().getRowSorter().toggleSortOrder(1);
|
||||
dialog.setVisible(true);
|
||||
}, ex -> {
|
||||
}, SwingExecutor.INSTANCE);
|
||||
|
||||
ProgressDialog.showProgress(parentWindow, deferred, progress, "Checking for mod updates...", "Checking for mod updates...");
|
||||
SwingHelper.addErrorDialogCallback(parentWindow, deferred);
|
||||
}
|
||||
|
||||
private void initListeners() {
|
||||
dialog.getCloseButton().addActionListener(e -> dialog.dispose());
|
||||
|
||||
ModTableMouseListener mouseListener = new ModTableMouseListener();
|
||||
dialog.getKnownModsTable().addMouseListener(mouseListener);
|
||||
dialog.getUnknownModsTable().addMouseListener(mouseListener);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static URL getFirstUrl(String... options) {
|
||||
for (String option : options) {
|
||||
try {
|
||||
return new URL(option);
|
||||
} catch (MalformedURLException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class ModTableMouseListener extends MouseAdapter {
|
||||
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
JTable table = (JTable) e.getSource();
|
||||
Point point = e.getPoint();
|
||||
int selectedIndex = table.rowAtPoint(point);
|
||||
if (selectedIndex >= 0) {
|
||||
selectedIndex = table.convertRowIndexToModel(selectedIndex);
|
||||
ModFile mod = ((ModFileTableModel) table.getModel()).getMod(selectedIndex);
|
||||
if (mod != null && mod.getUrl() != null) {
|
||||
SwingHelper.openURL(mod.getUrl(), dialog);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.skcraft.concurrency.Deferred;
|
||||
import com.skcraft.concurrency.Deferreds;
|
||||
import com.skcraft.concurrency.SettableProgress;
|
||||
import com.skcraft.launcher.creator.Creator;
|
||||
import com.skcraft.launcher.creator.dialog.AboutDialog;
|
||||
import com.skcraft.launcher.creator.dialog.PackManagerFrame;
|
||||
import com.skcraft.launcher.creator.dialog.WelcomeDialog;
|
||||
import com.skcraft.launcher.creator.model.creator.RecentEntry;
|
||||
import com.skcraft.launcher.creator.model.creator.Workspace;
|
||||
import com.skcraft.launcher.creator.model.swing.RecentListModel;
|
||||
import com.skcraft.launcher.creator.swing.WorkspaceDirectoryFilter;
|
||||
import com.skcraft.launcher.dialog.ProgressDialog;
|
||||
import com.skcraft.launcher.persistence.Persistence;
|
||||
import com.skcraft.launcher.swing.PopupMouseAdapter;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.util.MorePaths;
|
||||
import com.skcraft.launcher.util.SwingExecutor;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class WelcomeController {
|
||||
|
||||
private final WelcomeDialog dialog;
|
||||
private final Creator creator;
|
||||
private final RecentListModel recentListModel;
|
||||
|
||||
public WelcomeController(WelcomeDialog dialog, Creator creator) {
|
||||
this.dialog = dialog;
|
||||
this.creator = creator;
|
||||
|
||||
initListeners();
|
||||
|
||||
recentListModel = new RecentListModel(creator.getConfig().getRecentEntries());
|
||||
dialog.getRecentList().setModel(recentListModel);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
|
||||
private boolean openWorkspace(File dir) {
|
||||
ListeningExecutorService executor = creator.getExecutor();
|
||||
PackManagerFrame frame = new PackManagerFrame();
|
||||
Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(() -> {
|
||||
PackManagerController controller = new PackManagerController(frame, dir, creator);
|
||||
addRecentEntry(dir);
|
||||
return controller;
|
||||
}), executor)
|
||||
.handleAsync(PackManagerController::show, ex -> {}, SwingExecutor.INSTANCE);
|
||||
ProgressDialog.showProgress(frame, deferred, new SettableProgress("Loading...", -1), "Loading workspace...", "Loading workspace...");
|
||||
SwingHelper.addErrorDialogCallback(frame, deferred);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addRecentEntry(File dir) {
|
||||
List<RecentEntry> newEntries = creator.getConfig().getRecentEntries()
|
||||
.stream()
|
||||
.filter(entry -> {
|
||||
try {
|
||||
return !MorePaths.isSamePath(entry.getPath(), dir);
|
||||
} catch (IOException ignored) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toCollection(Lists::newArrayList));
|
||||
|
||||
RecentEntry recent = new RecentEntry();
|
||||
recent.setPath(dir);
|
||||
newEntries.add(0, recent);
|
||||
|
||||
creator.getConfig().setRecentEntries(newEntries);
|
||||
|
||||
Persistence.commitAndForget(creator.getConfig());
|
||||
|
||||
recentListModel.fireUpdate();
|
||||
}
|
||||
|
||||
private void removeRecentEntry(RecentEntry entry) {
|
||||
creator.getConfig().getRecentEntries().remove(entry);
|
||||
Persistence.commitAndForget(creator.getConfig());
|
||||
|
||||
recentListModel.fireUpdate();
|
||||
}
|
||||
|
||||
private Optional<RecentEntry> getSelectedRecentEntry() {
|
||||
int selectedIndex = dialog.getRecentList().getSelectedIndex();
|
||||
if (selectedIndex >= 0) {
|
||||
return Optional.fromNullable(creator.getConfig().getRecentEntries().get(selectedIndex));
|
||||
} else {
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<File> getWorkspaceDir() {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
chooser.setDialogTitle("Select Workspace Directory");
|
||||
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
chooser.setFileFilter(new WorkspaceDirectoryFilter());
|
||||
|
||||
int returnVal = chooser.showOpenDialog(dialog);
|
||||
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
return Optional.fromNullable(chooser.getSelectedFile());
|
||||
} else {
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
private void initListeners() {
|
||||
dialog.getRecentList().addMouseListener(new MouseAdapter() {
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
JList<RecentEntry> table = (JList<RecentEntry>) e.getSource();
|
||||
Point point = e.getPoint();
|
||||
int selectedIndex = table.locationToIndex(point);
|
||||
if (selectedIndex >= 0) {
|
||||
table.setSelectedIndex(selectedIndex);
|
||||
Optional<RecentEntry> optional = getSelectedRecentEntry();
|
||||
if (optional.isPresent()) {
|
||||
if (openWorkspace(optional.get().getPath())) {
|
||||
dialog.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialog.getRecentList().addMouseListener(new PopupMouseAdapter() {
|
||||
@Override
|
||||
protected void showPopup(MouseEvent e) {
|
||||
JList<RecentEntry> table = (JList<RecentEntry>) e.getSource();
|
||||
Point point = e.getPoint();
|
||||
int selectedIndex = table.locationToIndex(point);
|
||||
if (selectedIndex >= 0) {
|
||||
table.setSelectedIndex(selectedIndex);
|
||||
Optional<RecentEntry> optional = getSelectedRecentEntry();
|
||||
if (optional.isPresent()) {
|
||||
popupRecentWorkspaceMenu(e.getComponent(), e.getX(), e.getY(), optional.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialog.getNewButton().addActionListener(e -> {
|
||||
Optional<File> optional = getWorkspaceDir();
|
||||
if (optional.isPresent()) {
|
||||
File workspaceFile = Workspace.getWorkspaceFile(optional.get());
|
||||
if (!workspaceFile.exists() || SwingHelper.confirmDialog(dialog, "There is already a workspace there. Do you want to load it?", "Existing")) {
|
||||
if (openWorkspace(optional.get())) {
|
||||
dialog.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialog.getOpenButton().addActionListener(e -> {
|
||||
Optional<File> optional = getWorkspaceDir();
|
||||
if (optional.isPresent()) {
|
||||
File workspaceFile = Workspace.getWorkspaceFile(optional.get());
|
||||
if (workspaceFile.exists() || SwingHelper.confirmDialog(dialog, "Do you want to create a new workspace there?", "Create New")) {
|
||||
if (openWorkspace(optional.get())) {
|
||||
dialog.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialog.getHelpButton().addActionListener(e -> {
|
||||
SwingHelper.openURL("https://github.com/SKCraft/Launcher/wiki", dialog);
|
||||
});
|
||||
|
||||
dialog.getAboutButton().addActionListener(e -> {
|
||||
AboutDialog.showAboutDialog(dialog);
|
||||
});
|
||||
|
||||
dialog.getQuitButton().addActionListener(e -> {
|
||||
dialog.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
private void popupRecentWorkspaceMenu(Component component, int x, int y, RecentEntry entry) {
|
||||
JPopupMenu popup = new JPopupMenu();
|
||||
JMenuItem menuItem;
|
||||
|
||||
menuItem = new JMenuItem("Remove");
|
||||
menuItem.addActionListener(e -> removeRecentEntry(entry));
|
||||
popup.add(menuItem);
|
||||
|
||||
popup.show(component, x, y);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller.task;
|
||||
|
||||
import com.skcraft.concurrency.ProgressObservable;
|
||||
import com.skcraft.launcher.LauncherException;
|
||||
import com.skcraft.launcher.LauncherUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class DirectoryDeleter implements Callable<File>, ProgressObservable {
|
||||
|
||||
private final File dir;
|
||||
|
||||
public DirectoryDeleter(File dir) {
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File call() throws Exception {
|
||||
Thread.sleep(2000);
|
||||
|
||||
List<File> failures = new ArrayList<File>();
|
||||
|
||||
try {
|
||||
LauncherUtils.interruptibleDelete(dir, failures);
|
||||
} catch (IOException e) {
|
||||
Thread.sleep(1000);
|
||||
LauncherUtils.interruptibleDelete(dir, failures);
|
||||
}
|
||||
|
||||
if (failures.size() > 0) {
|
||||
throw new LauncherException(failures.size() + " failed to delete", failures.size() + " file(s) could not be deleted");
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProgress() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatus() {
|
||||
return "Deleting files...";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller.task;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.skcraft.launcher.util.MorePaths;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class DirectoryWalker implements Callable<List<File>> {
|
||||
|
||||
@Getter private final File dir;
|
||||
@Getter @Setter private FileFilter fileFilter = pathname -> true;
|
||||
@Getter @Setter private boolean recursive;
|
||||
|
||||
public DirectoryWalker(File dir) {
|
||||
checkNotNull(dir, "dir");
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<File> call() throws IOException {
|
||||
if (!dir.isDirectory()) {
|
||||
throw new IllegalArgumentException(dir.getAbsolutePath() + " is not a directory");
|
||||
}
|
||||
|
||||
List<File> matched = Lists.newArrayList();
|
||||
Set<String> seen = Sets.newHashSet();
|
||||
|
||||
Queue<File> queue = new LinkedList<>();
|
||||
queue.add(dir);
|
||||
|
||||
File cur;
|
||||
while ((cur = queue.poll()) != null) {
|
||||
String canonical = cur.getCanonicalPath();
|
||||
if (!seen.contains(canonical) && MorePaths.isSubDirectory(dir, cur)) {
|
||||
File[] files = cur.listFiles();
|
||||
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (recursive && file.isDirectory()) {
|
||||
queue.add(file);
|
||||
}
|
||||
|
||||
if (fileFilter.accept(file)) {
|
||||
matched.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller.task;
|
||||
|
||||
import com.skcraft.launcher.creator.model.creator.ManifestEntry;
|
||||
import com.skcraft.launcher.model.modpack.Manifest;
|
||||
import com.skcraft.launcher.model.modpack.ManifestInfo;
|
||||
import com.skcraft.launcher.persistence.Persistence;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ManifestInfoEnumerator implements Function<List<ManifestEntry>, List<ManifestEntry>> {
|
||||
|
||||
private final File searchDir;
|
||||
|
||||
public ManifestInfoEnumerator(File searchDir) {
|
||||
this.searchDir = searchDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ManifestEntry> apply(List<ManifestEntry> entries) {
|
||||
File[] files = searchDir.listFiles(f -> f.isFile() && f.getName().toLowerCase().endsWith(".json") && !f.getName().startsWith("packages."));
|
||||
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
String location = file.getName();
|
||||
Manifest manifest = Persistence.read(file, Manifest.class, true);
|
||||
|
||||
if (manifest != null) {
|
||||
ManifestInfo info = new ManifestInfo();
|
||||
info.setName(manifest.getName());
|
||||
info.setTitle(manifest.getTitle());
|
||||
info.setVersion(manifest.getVersion());
|
||||
info.setPriority(0);
|
||||
info.setLocation(location);
|
||||
|
||||
boolean found = false;
|
||||
|
||||
for (ManifestEntry entry : entries) {
|
||||
if (entry.getManifestInfo().getLocation().equals(location)) {
|
||||
info.setPriority(entry.getManifestInfo().getPriority());
|
||||
entry.setManifestInfo(info);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
ManifestEntry entry = new ManifestEntry();
|
||||
entry.setManifestInfo(info);
|
||||
entries.add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller.task;
|
||||
|
||||
import com.skcraft.concurrency.ProgressObservable;
|
||||
import com.skcraft.launcher.LauncherException;
|
||||
import com.skcraft.launcher.LauncherUtils;
|
||||
import com.skcraft.launcher.builder.PackageBuilder;
|
||||
import com.skcraft.launcher.creator.model.creator.Pack;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class PackBuilder implements Callable<PackBuilder>, ProgressObservable {
|
||||
|
||||
private final Pack pack;
|
||||
private final File outputDir;
|
||||
private final String version;
|
||||
private final String manifestFilename;
|
||||
private final boolean clean;
|
||||
private final boolean downloadUrls;
|
||||
|
||||
public PackBuilder(Pack pack, File outputDir, String version, String manifestFilename, boolean clean, boolean downloadUrls) {
|
||||
this.pack = pack;
|
||||
this.outputDir = outputDir;
|
||||
this.version = version;
|
||||
this.manifestFilename = manifestFilename;
|
||||
this.clean = clean;
|
||||
this.downloadUrls = downloadUrls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackBuilder call() throws Exception {
|
||||
if (clean) {
|
||||
List<File> failures = new ArrayList<File>();
|
||||
|
||||
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();
|
||||
|
||||
System.setProperty("com.skcraft.builder.ignoreURLOverrides", downloadUrls ? "false" : "true");
|
||||
String[] args = {
|
||||
"--version", version,
|
||||
"--manifest-dest", new File(outputDir, manifestFilename).getAbsolutePath(),
|
||||
"-i", pack.getDirectory().getAbsolutePath(),
|
||||
"-o", outputDir.getAbsolutePath()
|
||||
};
|
||||
PackageBuilder.main(args);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProgress() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatus() {
|
||||
return "Building modpack...";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller.task;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.skcraft.concurrency.ProgressObservable;
|
||||
import com.skcraft.launcher.creator.model.creator.Pack;
|
||||
import com.skcraft.launcher.creator.model.creator.Workspace;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PackLoader implements ProgressObservable, Function<Workspace, List<Pack>> {
|
||||
|
||||
private int index;
|
||||
private int size = 0;
|
||||
private Pack lastPack;
|
||||
|
||||
@Override
|
||||
public List<Pack> apply(Workspace workspace) {
|
||||
List<Pack> packs = workspace.getPacks();
|
||||
size = packs.size();
|
||||
|
||||
for (Pack pack : packs) {
|
||||
lastPack = pack;
|
||||
pack.load();
|
||||
index++;
|
||||
}
|
||||
|
||||
lastPack = null;
|
||||
|
||||
return packs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProgress() {
|
||||
if (size == 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return index / (double) size;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatus() {
|
||||
Pack pack = lastPack;
|
||||
if (pack != null) {
|
||||
return "Loading " + pack.getDirectory().getName() + "...";
|
||||
} else {
|
||||
return "Enumerating packs...";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller.task;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.skcraft.concurrency.ProgressObservable;
|
||||
import com.skcraft.launcher.builder.BuilderOptions;
|
||||
import com.skcraft.launcher.creator.model.creator.Pack;
|
||||
import com.skcraft.launcher.creator.model.creator.Problem;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class ProblemChecker implements Callable<List<Problem>>, ProgressObservable {
|
||||
|
||||
private final Pack pack;
|
||||
|
||||
public ProblemChecker(Pack pack) {
|
||||
this.pack = pack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Problem> call() throws Exception {
|
||||
List<Problem> problems = Lists.newArrayList();
|
||||
|
||||
File packDir = pack.getDirectory();
|
||||
File srcDir = pack.getSourceDir();
|
||||
|
||||
File loadersDir = new File(packDir, BuilderOptions.DEFAULT_LOADERS_DIRNAME);
|
||||
File modsDir = new File(srcDir, "mods");
|
||||
boolean hasLoaders = hasFiles(loadersDir);
|
||||
boolean hasMods = hasFiles(modsDir);
|
||||
|
||||
String[] files;
|
||||
|
||||
if (new File(packDir, "_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(packDir, "_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(packDir, "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(packDir, "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(packDir, "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 "Checking for problems...";
|
||||
}
|
||||
|
||||
private static boolean hasFiles(File dir) {
|
||||
String[] contents = dir.list();
|
||||
return contents != null && contents.length > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller.task;
|
||||
|
||||
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.creator.dialog.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 ServerDeploy implements Callable<ServerDeploy>, ProgressObservable {
|
||||
|
||||
private final File srcDir;
|
||||
private final DeployOptions options;
|
||||
|
||||
public ServerDeploy(File srcDir, DeployOptions options) {
|
||||
this.srcDir = srcDir;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerDeploy call() throws Exception {
|
||||
File modsDir = new File(options.getDestDir(), "mods");
|
||||
|
||||
if (options.isCleanMods() && modsDir.isDirectory()) {
|
||||
List<File> failures = new ArrayList<File>();
|
||||
|
||||
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...";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.controller.task;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.skcraft.concurrency.ProgressObservable;
|
||||
import com.skcraft.launcher.Instance;
|
||||
import com.skcraft.launcher.InstanceList;
|
||||
import com.skcraft.launcher.Launcher;
|
||||
import com.skcraft.launcher.auth.Session;
|
||||
import com.skcraft.launcher.launch.LaunchOptions;
|
||||
import com.skcraft.launcher.launch.LaunchOptions.UpdatePolicy;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
public class TestLauncher implements Function<InstanceList, Instance>, ProgressObservable {
|
||||
|
||||
private final Launcher launcher;
|
||||
private final Window window;
|
||||
private final String id;
|
||||
private final Session session;
|
||||
|
||||
public TestLauncher(Launcher launcher, Window window, String id, Session session) {
|
||||
this.launcher = launcher;
|
||||
this.window = window;
|
||||
this.id = id;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
private Optional<Instance> findInstance(List<Instance> instances) {
|
||||
for (Instance instance : instances) {
|
||||
if (instance.getName().equals(id)) {
|
||||
return Optional.fromNullable(instance);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instance apply(InstanceList instanceList) {
|
||||
Optional<Instance> optional = findInstance(instanceList.getInstances());
|
||||
|
||||
if (optional.isPresent()) {
|
||||
LaunchOptions options = new LaunchOptions.Builder()
|
||||
.setInstance(optional.get())
|
||||
.setUpdatePolicy(UpdatePolicy.ALWAYS_UPDATE)
|
||||
.setWindow(window)
|
||||
.setSession(session)
|
||||
.build();
|
||||
|
||||
launcher.getLaunchSupervisor().launch(options);
|
||||
|
||||
return optional.get();
|
||||
} else {
|
||||
SwingHelper.showErrorDialog(window,
|
||||
"After generating the necessary files, it appears the modpack can't be found in the " +
|
||||
"launcher. Did you change modpack.json while the launcher was launching?", "Launch Error");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProgress() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatus() {
|
||||
return "Launching the game...";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.skcraft.launcher.LauncherUtils;
|
||||
import com.skcraft.launcher.creator.Creator;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import lombok.extern.java.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@Log
|
||||
public class AboutDialog extends JDialog {
|
||||
|
||||
private String version;
|
||||
|
||||
public AboutDialog(Window parent) {
|
||||
super(parent, "About", ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
try {
|
||||
Properties properties = LauncherUtils.loadProperties(Creator.class, "creator.properties", "com.skcraft.creator.propertiesFile");
|
||||
version = properties.getProperty("version", "????");
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to get version", e);
|
||||
version = "????";
|
||||
}
|
||||
|
||||
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(SwingHelper.createIcon(Creator.class, "about_header.png")), "dock north");
|
||||
container.add(new JLabel("<html>Version " + version), "wrap");
|
||||
container.add(new JLabel("<html>Licensed under GNU Lesser General Public License, version 3."), "wrap, gapbottom unrel");
|
||||
container.add(new JLabel("<html>Created by the SKCraft team. Visit our website!"), "wrap, gapbottom unrel");
|
||||
|
||||
JButton okButton = new JButton("OK");
|
||||
JButton sourceCodeButton = new JButton("Source Code");
|
||||
JButton skCraftButton = new JButton("Website");
|
||||
|
||||
container.add(sourceCodeButton, "span, split 3, sizegroup bttn");
|
||||
container.add(skCraftButton, "sizegroup bttn");
|
||||
container.add(okButton, "tag ok, sizegroup bttn");
|
||||
|
||||
add(container, BorderLayout.CENTER);
|
||||
|
||||
getRootPane().setDefaultButton(okButton);
|
||||
getRootPane().registerKeyboardAction(e -> okButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
|
||||
okButton.addActionListener(e -> dispose());
|
||||
sourceCodeButton.addActionListener(e -> SwingHelper.openURL("https://github.com/SKCraft/Launcher", this));
|
||||
skCraftButton.addActionListener(e -> SwingHelper.openURL("http://www.skcraft.com", this));
|
||||
}
|
||||
|
||||
public static void showAboutDialog(Window parent) {
|
||||
AboutDialog dialog = new AboutDialog(parent);
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.skcraft.launcher.swing.DirectoryField;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.swing.TextFieldPopupMenu;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
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);
|
||||
@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() {
|
||||
versionText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
manifestFilenameText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
|
||||
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");
|
||||
|
||||
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);
|
||||
|
||||
getRootPane().setDefaultButton(buildButton);
|
||||
getRootPane().registerKeyboardAction(e -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
|
||||
buildButton.addActionListener(e -> returnValue());
|
||||
cancelButton.addActionListener(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, 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 File destDir;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.jidesoft.swing.SearchableUtils;
|
||||
import com.jidesoft.swing.TableSearchable;
|
||||
import com.skcraft.launcher.builder.BuilderConfig;
|
||||
import com.skcraft.launcher.builder.FeaturePattern;
|
||||
import com.skcraft.launcher.builder.FnPatternList;
|
||||
import com.skcraft.launcher.creator.model.swing.FeaturePatternTableModel;
|
||||
import com.skcraft.launcher.model.modpack.LaunchModifier;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.swing.TextFieldPopupMenu;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
public class BuilderConfigDialog extends JDialog {
|
||||
|
||||
private final JTextField nameText = new JTextField(20);
|
||||
private final JTextField titleText = new JTextField(30);
|
||||
private final JTextField gameVersionText = new JTextField(10);
|
||||
private final JTextArea launchFlagsArea = new JTextArea(10, 40);
|
||||
private final JTextArea userFilesIncludeArea = new JTextArea(15, 40);
|
||||
private final JTextArea userFilesExcludeArea = new JTextArea(8, 40);
|
||||
private final FeaturePatternTable featuresTable = new FeaturePatternTable();
|
||||
private FeaturePatternTableModel featuresModel;
|
||||
|
||||
private final BuilderConfig config;
|
||||
private boolean saved = false;
|
||||
|
||||
public BuilderConfigDialog(Window parent, BuilderConfig config) {
|
||||
super(parent, "Modpack Properties", ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
this.config = config;
|
||||
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
initComponents();
|
||||
setResizable(false);
|
||||
pack();
|
||||
setLocationRelativeTo(parent);
|
||||
|
||||
copyFrom();
|
||||
|
||||
nameText.requestFocus();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
nameText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
titleText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
gameVersionText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
launchFlagsArea.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
userFilesIncludeArea.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
|
||||
launchFlagsArea.setFont(nameText.getFont());
|
||||
userFilesIncludeArea.setFont(nameText.getFont());
|
||||
userFilesExcludeArea.setFont(nameText.getFont());
|
||||
|
||||
JTabbedPane tabbedPane = new JTabbedPane();
|
||||
|
||||
JPanel container = new JPanel();
|
||||
container.setLayout(new MigLayout("fill, insets dialog"));
|
||||
|
||||
tabbedPane.addTab("Modpack", null, createMainPanel());
|
||||
tabbedPane.addTab("Launch", null, createLaunchPanel());
|
||||
tabbedPane.addTab("User Files", null, createUserFilesPanel());
|
||||
tabbedPane.addTab("Optional Features", null, createFeaturesPanel());
|
||||
|
||||
container.add(tabbedPane, "span, grow, gapbottom unrel");
|
||||
|
||||
JButton saveButton = new JButton("Save");
|
||||
JButton cancelButton = new JButton("Cancel");
|
||||
|
||||
container.add(saveButton, "tag ok, span, split 2, sizegroup bttn");
|
||||
container.add(cancelButton, "tag cancel, sizegroup bttn");
|
||||
|
||||
getRootPane().setDefaultButton(saveButton);
|
||||
getRootPane().registerKeyboardAction(event -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
|
||||
add(container, BorderLayout.CENTER);
|
||||
|
||||
saveButton.addActionListener(e -> {
|
||||
if (nameText.getText().trim().isEmpty()) {
|
||||
SwingHelper.showErrorDialog(BuilderConfigDialog.this, "The 'Name' field cannot be empty.", "Input Error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameVersionText.getText().trim().isEmpty()) {
|
||||
SwingHelper.showErrorDialog(BuilderConfigDialog.this, "The 'Game Version' field must be a Minecraft version.", "Input Error");
|
||||
return;
|
||||
}
|
||||
|
||||
copyTo();
|
||||
saved = true;
|
||||
dispose();
|
||||
});
|
||||
|
||||
cancelButton.addActionListener(e -> dispose());
|
||||
|
||||
TableSearchable tableSearchable = SearchableUtils.installSearchable(featuresTable);
|
||||
tableSearchable.setMainIndex(-1);
|
||||
}
|
||||
|
||||
private JPanel createMainPanel() {
|
||||
JPanel container = new JPanel();
|
||||
SwingHelper.removeOpaqueness(container);
|
||||
container.setLayout(new MigLayout("insets dialog"));
|
||||
|
||||
container.add(new JLabel("Name:"));
|
||||
container.add(nameText, "span");
|
||||
|
||||
container.add(new JLabel("Title:"));
|
||||
container.add(titleText, "span");
|
||||
|
||||
container.add(new JLabel("Game Version:"));
|
||||
container.add(gameVersionText, "span");
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
private JPanel createLaunchPanel() {
|
||||
JPanel container = new JPanel();
|
||||
SwingHelper.removeOpaqueness(container);
|
||||
container.setLayout(new MigLayout("insets dialog"));
|
||||
|
||||
container.add(new JLabel("Launch Flags:"), "wrap");
|
||||
container.add(SwingHelper.wrapScrollPane(launchFlagsArea), "span");
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
private JPanel createUserFilesPanel() {
|
||||
JPanel container = new JPanel();
|
||||
SwingHelper.removeOpaqueness(container);
|
||||
container.setLayout(new MigLayout("insets dialog"));
|
||||
|
||||
container.add(new JLabel("Include Patterns:"), "wrap");
|
||||
container.add(SwingHelper.wrapScrollPane(userFilesIncludeArea), "span, gapbottom unrel");
|
||||
|
||||
container.add(new JLabel("Exclude Patterns:"), "wrap");
|
||||
container.add(SwingHelper.wrapScrollPane(userFilesExcludeArea), "span");
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
private JPanel createFeaturesPanel() {
|
||||
JPanel container = new JPanel();
|
||||
SwingHelper.removeOpaqueness(container);
|
||||
container.setLayout(new MigLayout("fill, insets dialog"));
|
||||
|
||||
JButton newButton = new JButton("New...");
|
||||
JButton editButton = new JButton("Edit...");
|
||||
JButton deleteButton = new JButton("Delete...");
|
||||
|
||||
container.add(newButton, "span, split 3, sizegroup bttn");
|
||||
container.add(editButton, "sizegroup bttn");
|
||||
container.add(deleteButton, "sizegroup bttn");
|
||||
|
||||
container.add(SwingHelper.wrapScrollPane(featuresTable), "grow, w 10:100:null, gaptop 10");
|
||||
|
||||
newButton.addActionListener(e -> {
|
||||
FeaturePattern pattern = new FeaturePattern();
|
||||
if (FeaturePatternDialog.showEditor(BuilderConfigDialog.this, pattern)) {
|
||||
featuresModel.addFeature(pattern);
|
||||
}
|
||||
});
|
||||
|
||||
editButton.addActionListener(e -> {
|
||||
int index = featuresTable.getSelectedRow();
|
||||
if (index > -1) {
|
||||
FeaturePattern pattern = featuresModel.getFeature(index);
|
||||
FeaturePatternDialog.showEditor(BuilderConfigDialog.this, pattern);
|
||||
featuresModel.fireTableDataChanged();
|
||||
} else {
|
||||
SwingHelper.showErrorDialog(BuilderConfigDialog.this, "Select a feature first.", "No Selection");
|
||||
}
|
||||
});
|
||||
|
||||
deleteButton.addActionListener(e -> {
|
||||
int index = featuresTable.getSelectedRow();
|
||||
if (index > -1) {
|
||||
FeaturePattern pattern = featuresModel.getFeature(index);
|
||||
if (SwingHelper.confirmDialog(BuilderConfigDialog.this, "Are you sure that you want to delete '" + pattern.getFeature().getName() + "'?", "Delete")) {
|
||||
featuresModel.removeFeature(index);
|
||||
}
|
||||
} else {
|
||||
SwingHelper.showErrorDialog(BuilderConfigDialog.this, "Select a feature first.", "No Selection");
|
||||
}
|
||||
});
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
private void copyFrom() {
|
||||
SwingHelper.setTextAndResetCaret(nameText, config.getName());
|
||||
SwingHelper.setTextAndResetCaret(titleText, config.getTitle());
|
||||
SwingHelper.setTextAndResetCaret(gameVersionText, config.getGameVersion());
|
||||
SwingHelper.setTextAndResetCaret(launchFlagsArea, SwingHelper.listToLines(config.getLaunchModifier().getFlags()));
|
||||
SwingHelper.setTextAndResetCaret(userFilesIncludeArea, SwingHelper.listToLines(config.getUserFiles().getInclude()));
|
||||
SwingHelper.setTextAndResetCaret(userFilesExcludeArea, SwingHelper.listToLines(config.getUserFiles().getExclude()));
|
||||
featuresModel = new FeaturePatternTableModel(config.getFeatures());
|
||||
featuresTable.setModel(featuresModel);
|
||||
}
|
||||
|
||||
private void copyTo() {
|
||||
config.setName(nameText.getText().trim());
|
||||
config.setTitle(Strings.emptyToNull(titleText.getText().trim()));
|
||||
config.setGameVersion(gameVersionText.getText().trim());
|
||||
|
||||
LaunchModifier launchModifier = config.getLaunchModifier();
|
||||
FnPatternList userFiles = config.getUserFiles();
|
||||
|
||||
launchModifier.setFlags(SwingHelper.linesToList(launchFlagsArea.getText()));
|
||||
userFiles.setInclude(SwingHelper.linesToList(userFilesIncludeArea.getText()));
|
||||
userFiles.setExclude(SwingHelper.linesToList(userFilesExcludeArea.getText()));
|
||||
}
|
||||
|
||||
public static boolean showEditor(Window window, BuilderConfig config) {
|
||||
BuilderConfigDialog dialog = new BuilderConfigDialog(window, config);
|
||||
dialog.setVisible(true);
|
||||
return dialog.saved;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
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.KeyEvent;
|
||||
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);
|
||||
|
||||
getRootPane().setDefaultButton(buildButton);
|
||||
getRootPane().registerKeyboardAction(e -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
|
||||
buildButton.addActionListener(e -> returnValue());
|
||||
cancelButton.addActionListener(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, File destDir) {
|
||||
DeployServerDialog dialog = new DeployServerDialog(parent);
|
||||
if (destDir != null) {
|
||||
dialog.destDirField.setPath(destDir.getAbsolutePath());
|
||||
}
|
||||
dialog.setVisible(true);
|
||||
return dialog.getOptions();
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class DeployOptions {
|
||||
private final File destDir;
|
||||
private final boolean cleanMods;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.skcraft.launcher.builder.FeaturePattern;
|
||||
import com.skcraft.launcher.builder.FnPatternList;
|
||||
import com.skcraft.launcher.creator.model.swing.RecommendationComboBoxModel;
|
||||
import com.skcraft.launcher.model.modpack.Feature;
|
||||
import com.skcraft.launcher.model.modpack.Feature.Recommendation;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.swing.TextFieldPopupMenu;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
public class FeaturePatternDialog extends JDialog {
|
||||
|
||||
private static final Joiner NEW_LINE_JOINER = Joiner.on("\n");
|
||||
|
||||
private final JTextField nameText = new JTextField(20);
|
||||
private final JTextArea descArea = new JTextArea(3, 40);
|
||||
private final JComboBox recommendationCombo = new JComboBox(new RecommendationComboBoxModel());
|
||||
private final JCheckBox selectedCheck = new JCheckBox("Selected by default");
|
||||
private final JTextArea includeArea = new JTextArea(8, 40);
|
||||
private final JTextArea excludeArea = new JTextArea(3, 40);
|
||||
|
||||
private final FeaturePattern pattern;
|
||||
private boolean saved = false;
|
||||
|
||||
public FeaturePatternDialog(Window parent, FeaturePattern pattern) {
|
||||
super(parent, "Configure Feature", ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
this.pattern = pattern;
|
||||
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
initComponents();
|
||||
setResizable(false);
|
||||
pack();
|
||||
setLocationRelativeTo(parent);
|
||||
|
||||
copyFrom();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
nameText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
descArea.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
includeArea.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
excludeArea.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
|
||||
descArea.setFont(nameText.getFont());
|
||||
includeArea.setFont(nameText.getFont());
|
||||
excludeArea.setFont(nameText.getFont());
|
||||
|
||||
JPanel container = new JPanel();
|
||||
container.setLayout(new MigLayout("insets dialog"));
|
||||
|
||||
container.add(new JLabel("Feature Name:"));
|
||||
container.add(nameText, "span");
|
||||
|
||||
container.add(new JLabel("Recommendation:"));
|
||||
container.add(recommendationCombo, "span");
|
||||
|
||||
container.add(selectedCheck, "span");
|
||||
|
||||
container.add(new JLabel("Description:"), "wrap");
|
||||
container.add(SwingHelper.wrapScrollPane(descArea), "span");
|
||||
|
||||
container.add(new JLabel("Include Patterns:"), "wrap");
|
||||
container.add(SwingHelper.wrapScrollPane(includeArea), "span");
|
||||
|
||||
container.add(new JLabel("Exclude Patterns:"), "wrap");
|
||||
container.add(SwingHelper.wrapScrollPane(excludeArea), "span, gapbottom unrel");
|
||||
|
||||
JButton okButton = new JButton("OK");
|
||||
JButton cancelButton = new JButton("Cancel");
|
||||
|
||||
container.add(okButton, "tag ok, span, split 2, sizegroup bttn");
|
||||
container.add(cancelButton, "tag cancel, sizegroup bttn");
|
||||
|
||||
getRootPane().setDefaultButton(okButton);
|
||||
getRootPane().registerKeyboardAction(e -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
|
||||
add(container, BorderLayout.CENTER);
|
||||
|
||||
okButton.addActionListener(e -> {
|
||||
if (nameText.getText().trim().isEmpty()) {
|
||||
SwingHelper.showErrorDialog(FeaturePatternDialog.this, "The 'Feature Name' field cannot be empty.", "Input Error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (descArea.getText().trim().isEmpty()) {
|
||||
SwingHelper.showErrorDialog(FeaturePatternDialog.this, "The 'Description' field cannot be empty.", "Input Error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (includeArea.getText().trim().isEmpty()) {
|
||||
SwingHelper.showErrorDialog(FeaturePatternDialog.this, "The 'Include Patterns' field cannot be empty.", "Input Error");
|
||||
return;
|
||||
}
|
||||
|
||||
copyTo();
|
||||
saved = true;
|
||||
dispose();
|
||||
});
|
||||
|
||||
cancelButton.addActionListener(e -> dispose());
|
||||
}
|
||||
|
||||
private void copyFrom() {
|
||||
if (pattern.getFeature() == null) {
|
||||
pattern.setFeature(new Feature());
|
||||
}
|
||||
|
||||
if (pattern.getFilePatterns() == null) {
|
||||
pattern.setFilePatterns(new FnPatternList());
|
||||
}
|
||||
|
||||
SwingHelper.setTextAndResetCaret(nameText, pattern.getFeature().getName());
|
||||
SwingHelper.setTextAndResetCaret(descArea, pattern.getFeature().getDescription());
|
||||
recommendationCombo.setSelectedItem(pattern.getFeature().getRecommendation());
|
||||
selectedCheck.setSelected(pattern.getFeature().isSelected());
|
||||
SwingHelper.setTextAndResetCaret(includeArea, NEW_LINE_JOINER.join(pattern.getFilePatterns().getInclude()));
|
||||
SwingHelper.setTextAndResetCaret(excludeArea, NEW_LINE_JOINER.join(pattern.getFilePatterns().getExclude()));
|
||||
}
|
||||
|
||||
private void copyTo() {
|
||||
pattern.getFeature().setName(nameText.getText().trim());
|
||||
pattern.getFeature().setDescription(descArea.getText().trim());
|
||||
pattern.getFeature().setRecommendation((Recommendation) recommendationCombo.getSelectedItem());
|
||||
pattern.getFeature().setSelected(selectedCheck.isSelected());
|
||||
pattern.getFilePatterns().setInclude(SwingHelper.linesToList(includeArea.getText()));
|
||||
pattern.getFilePatterns().setExclude(SwingHelper.linesToList(excludeArea.getText()));
|
||||
}
|
||||
|
||||
public static boolean showEditor(Window window, FeaturePattern pattern) {
|
||||
FeaturePatternDialog dialog = new FeaturePatternDialog(window, pattern);
|
||||
dialog.setVisible(true);
|
||||
return dialog.saved;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.skcraft.launcher.swing.DefaultTable;
|
||||
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
class FeaturePatternTable extends DefaultTable {
|
||||
|
||||
@Override
|
||||
public void setModel(TableModel dataModel) {
|
||||
super.setModel(dataModel);
|
||||
try {
|
||||
getColumnModel().getColumn(1).setMaxWidth(80);
|
||||
getColumnModel().getColumn(2).setMaxWidth(80);
|
||||
} catch (ArrayIndexOutOfBoundsException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.jidesoft.swing.SearchableUtils;
|
||||
import com.jidesoft.swing.TableSearchable;
|
||||
import com.skcraft.launcher.creator.Creator;
|
||||
import com.skcraft.launcher.creator.model.swing.ListingType;
|
||||
import com.skcraft.launcher.creator.model.swing.ListingTypeComboBoxModel;
|
||||
import com.skcraft.launcher.swing.DefaultTable;
|
||||
import com.skcraft.launcher.swing.DirectoryField;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.swing.TableColumnAdjuster;
|
||||
import lombok.Getter;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
public class GenerateListingDialog extends JDialog {
|
||||
|
||||
@Getter private final DirectoryField destDirField = new DirectoryField();
|
||||
@Getter private final JComboBox<ListingType> listingTypeCombo = new JComboBox<>(new ListingTypeComboBoxModel());
|
||||
@Getter private final JTable manifestsTable = new DefaultTable();
|
||||
@Getter private final JLabel gameKeyWarning = new JLabel("Selected listing type won't support adding modpacks using 'game keys'.", SwingHelper.createIcon(Creator.class, "warning_icon.png"), SwingConstants.LEFT);
|
||||
|
||||
@Getter private final JButton editManifestButton = new JButton("Modify...");
|
||||
|
||||
@Getter private final JButton generateButton = new JButton("Generate");
|
||||
@Getter private final JButton cancelButton = new JButton("Cancel");
|
||||
|
||||
@Getter private final TableColumnAdjuster manifestsTableAdjuster = new TableColumnAdjuster(manifestsTable);
|
||||
|
||||
public GenerateListingDialog(Window parent) {
|
||||
super(parent, "Generate Package Listing", ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
initComponents();
|
||||
pack();
|
||||
setLocationRelativeTo(parent);
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
manifestsTableAdjuster.adjustColumns();
|
||||
manifestsTableAdjuster.setDynamicAdjustment(true);
|
||||
|
||||
manifestsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
||||
manifestsTable.setAutoCreateRowSorter(true);
|
||||
|
||||
JPanel container = new JPanel();
|
||||
container.setLayout(new MigLayout("insets dialog, fill", "[grow 0][grow 100]"));
|
||||
|
||||
container.add(new JLabel("Output Directory:"));
|
||||
container.add(destDirField, "span");
|
||||
|
||||
container.add(new JLabel("Package Listing Type:"));
|
||||
container.add(listingTypeCombo, "span");
|
||||
container.add(gameKeyWarning, "span, skip 1, hidemode 3");
|
||||
|
||||
container.add(new JLabel("Modpacks to Include:"), "span, gaptop unrel");
|
||||
container.add(SwingHelper.wrapScrollPane(manifestsTable), "grow, pushy, span, w 500:650, h 170");
|
||||
container.add(editManifestButton, "gapbottom unrel, span, split 2");
|
||||
container.add(new JLabel("<html>Previously-selected modpacks and those in the _upload directory are the available options."), "gapbottom unrel");
|
||||
|
||||
container.add(generateButton, "tag ok, span, split 2, sizegroup bttn");
|
||||
container.add(cancelButton, "tag cancel, sizegroup bttn");
|
||||
|
||||
add(container, BorderLayout.CENTER);
|
||||
|
||||
getRootPane().setDefaultButton(generateButton);
|
||||
getRootPane().registerKeyboardAction(e -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
|
||||
TableSearchable tableSearchable = SearchableUtils.installSearchable(manifestsTable);
|
||||
tableSearchable.setMainIndex(-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.swing.TextFieldPopupMenu;
|
||||
import lombok.Getter;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
public class ManifestEntryDialog extends JDialog {
|
||||
|
||||
@Getter private final JSpinner prioritySpinner = new JSpinner();
|
||||
@Getter private final JTextArea gameKeysText = new JTextArea(5, 30);
|
||||
@Getter private final JCheckBox includeCheck = new JCheckBox("Include in package listing");
|
||||
|
||||
@Getter private final JButton okButton = new JButton("OK");
|
||||
@Getter private final JButton cancelButton = new JButton("Cancel");
|
||||
|
||||
public ManifestEntryDialog(Window parent) {
|
||||
super(parent, "Modpack Entry", ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
initComponents();
|
||||
setResizable(false);
|
||||
pack();
|
||||
setLocationRelativeTo(parent);
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
gameKeysText.setFont(prioritySpinner.getFont());
|
||||
|
||||
prioritySpinner.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
gameKeysText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
|
||||
JPanel container = new JPanel();
|
||||
container.setLayout(new MigLayout("insets dialog"));
|
||||
|
||||
container.add(includeCheck, "span, gapbottom unrel");
|
||||
|
||||
container.add(new JLabel("Priority:"));
|
||||
container.add(prioritySpinner, "span, split 2, w 50");
|
||||
container.add(new JLabel("(Greater is higher)"));
|
||||
|
||||
container.add(new JLabel("Game Keys:"));
|
||||
container.add(SwingHelper.wrapScrollPane(gameKeysText), "span");
|
||||
|
||||
container.add(okButton, "tag ok, span, split 2, sizegroup bttn, gaptop unrel");
|
||||
container.add(cancelButton, "tag cancel, sizegroup bttn");
|
||||
|
||||
add(container, BorderLayout.CENTER);
|
||||
|
||||
getRootPane().setDefaultButton(okButton);
|
||||
getRootPane().registerKeyboardAction(e -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.jidesoft.swing.SearchableUtils;
|
||||
import com.jidesoft.swing.TableSearchable;
|
||||
import com.skcraft.launcher.creator.Creator;
|
||||
import com.skcraft.launcher.swing.DefaultTable;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.swing.TableColumnAdjuster;
|
||||
import lombok.Getter;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
public class PackManagerFrame extends JFrame {
|
||||
|
||||
@Getter private final JButton newPackButton = new JButton("New Pack", SwingHelper.createIcon(Creator.class, "new.png"));
|
||||
@Getter private final JButton importButton = new JButton("Add Existing", SwingHelper.createIcon(Creator.class, "import.png"));
|
||||
@Getter private final JButton editConfigButton = new JButton("Modify", SwingHelper.createIcon(Creator.class, "edit.png"));
|
||||
@Getter private final JButton openFolderButton = new JButton("Open", SwingHelper.createIcon(Creator.class, "open_folder.png"));
|
||||
@Getter private final JButton checkProblemsButton = new JButton("Check", SwingHelper.createIcon(Creator.class, "check.png"));
|
||||
@Getter private final JButton testButton = new JButton("Test", SwingHelper.createIcon(Creator.class, "test.png"));
|
||||
@Getter private final JButton buildButton = new JButton("Build", SwingHelper.createIcon(Creator.class, "build.png"));
|
||||
|
||||
@Getter private final JMenuItem newPackMenuItem = new JMenuItem("New Pack...");
|
||||
@Getter private final JMenuItem newPackAtLocationMenuItem = new JMenuItem("New Pack at Location...");
|
||||
@Getter private final JMenuItem importPackMenuItem = new JMenuItem("Add Existing Pack...");
|
||||
@Getter private final JMenuItem changePackLocationMenuItem = new JMenuItem("Change Pack Location...");
|
||||
@Getter private final JMenuItem refreshMenuItem = new JMenuItem("Reload Workspace");
|
||||
@Getter private final JMenuItem removePackItem = new JMenuItem("Remove Pack...");
|
||||
@Getter private final JMenuItem deletePackItem = new JMenuItem("Delete Pack Forever...");
|
||||
@Getter private final JMenuItem quitMenuItem = new JMenuItem("Exit");
|
||||
@Getter private final JMenuItem editConfigMenuItem = new JMenuItem("Edit modpack.json...");
|
||||
@Getter private final JMenuItem openFolderMenuItem = new JMenuItem("Open Directory");
|
||||
@Getter private final JMenuItem checkProblemsMenuItem = new JMenuItem("Scan for Problems...");
|
||||
@Getter private final JMenuItem testMenuItem = new JMenuItem("Test");
|
||||
@Getter private final JMenuItem testOnlineMenuItem = new JMenuItem("Test Online");
|
||||
@Getter private final JMenuItem optionsMenuItem = new JMenuItem("Test Launcher Options...");
|
||||
@Getter private final JMenuItem instanceOptionsMenuItem = new JMenuItem("Test Instance Options...");
|
||||
@Getter private final JMenuItem clearInstanceMenuItem = new JMenuItem("Delete Test Launcher Instances");
|
||||
@Getter private final JMenuItem clearWebRootMenuItem = new JMenuItem("Empty Test Web Server");
|
||||
@Getter private final JMenuItem buildMenuItem = new JMenuItem("Build Pack...");
|
||||
@Getter private final JMenuItem deployServerMenuItem = new JMenuItem("Deploy Server...");
|
||||
@Getter private final JMenuItem generatePackagesMenuItem = new JMenuItem("Generate packages.json...");
|
||||
@Getter private final JMenuItem openOutputFolderMenuItem = new JMenuItem("Open Upload Folder");
|
||||
@Getter private final JMenuItem versionCheckMenuItem = new JMenuItem("Check for Mod Updates");
|
||||
@Getter private final JMenuItem openWorkspaceFolderMenuItem = new JMenuItem("Open Workspace Folder");
|
||||
@Getter private final JMenuItem openLauncherFolderMenuItem = new JMenuItem("Open Test Launcher Folder");
|
||||
@Getter private final JMenuItem openWebRootMenuItem = new JMenuItem("Open Test Web Server Folder");
|
||||
@Getter private final JMenuItem openConsoleMenuItem = new JMenuItem("Open Console");
|
||||
@Getter private final JMenuItem docsMenuItem = new JMenuItem("Documentation");
|
||||
@Getter private final JMenuItem aboutMenuItem = new JMenuItem("About");
|
||||
|
||||
@Getter private final JTable packTable = new DefaultTable();
|
||||
|
||||
public PackManagerFrame() {
|
||||
super("Modpack Creator");
|
||||
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
initComponents();
|
||||
initMenu();
|
||||
pack();
|
||||
setLocationRelativeTo(null);
|
||||
|
||||
SwingHelper.setFrameIcon(this, Creator.class, "icon.png");
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
TableColumnAdjuster adjuster = new TableColumnAdjuster(packTable);
|
||||
adjuster.adjustColumns();
|
||||
adjuster.setDynamicAdjustment(true);
|
||||
|
||||
packTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
||||
packTable.setAutoCreateRowSorter(true);
|
||||
|
||||
JPanel container = new JPanel();
|
||||
container.setLayout(new MigLayout("fill, wrap 1"));
|
||||
|
||||
container.add(createToolbar(), "dock north");
|
||||
container.add(SwingHelper.wrapScrollPane(packTable), "grow, span, w null:800:null");
|
||||
|
||||
TableSearchable tableSearchable = SearchableUtils.installSearchable(packTable);
|
||||
tableSearchable.setMainIndex(-1);
|
||||
|
||||
add(container, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private JToolBar createToolbar() {
|
||||
JToolBar toolBar = new JToolBar("Toolbar");
|
||||
|
||||
toolBar.setFloatable(false);
|
||||
|
||||
toolBar.add(newPackButton);
|
||||
toolBar.add(importButton);
|
||||
toolBar.addSeparator();
|
||||
toolBar.add(editConfigButton);
|
||||
toolBar.add(openFolderButton);
|
||||
toolBar.add(checkProblemsButton);
|
||||
toolBar.addSeparator();
|
||||
toolBar.add(testButton);
|
||||
toolBar.add(buildButton);
|
||||
|
||||
return toolBar;
|
||||
}
|
||||
|
||||
private void initMenu() {
|
||||
int ctrlKeyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
|
||||
|
||||
newPackMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ctrlKeyMask));
|
||||
newPackAtLocationMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ctrlKeyMask | Event.SHIFT_MASK));
|
||||
editConfigMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, ctrlKeyMask));
|
||||
openFolderMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ctrlKeyMask | Event.SHIFT_MASK));
|
||||
testMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0));
|
||||
testOnlineMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0));
|
||||
buildMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F10, Event.SHIFT_MASK));
|
||||
deployServerMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F9, Event.SHIFT_MASK));
|
||||
docsMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0));
|
||||
|
||||
JMenuBar menuBar;
|
||||
JMenu menu;
|
||||
|
||||
menuBar = new JMenuBar();
|
||||
menuBar.setBorder(BorderFactory.createEmptyBorder());
|
||||
|
||||
Insets menuInset = new Insets(2, 2, 2, 2);
|
||||
|
||||
menu = new JMenu("File");
|
||||
menu.setMargin(menuInset);
|
||||
menu.setMnemonic('f');
|
||||
menuBar.add(menu);
|
||||
menu.add(newPackMenuItem);
|
||||
menu.add(newPackAtLocationMenuItem);
|
||||
menu.add(importPackMenuItem);
|
||||
menu.addSeparator();
|
||||
menu.add(changePackLocationMenuItem);
|
||||
menu.add(removePackItem);
|
||||
menu.add(deletePackItem);
|
||||
menu.addSeparator();
|
||||
menu.add(refreshMenuItem);
|
||||
menu.addSeparator();
|
||||
menu.add(quitMenuItem);
|
||||
|
||||
menu = new JMenu("Edit");
|
||||
menu.setMargin(menuInset);
|
||||
menu.setMnemonic('e');
|
||||
menuBar.add(menu);
|
||||
menu.add(editConfigMenuItem);
|
||||
menu.add(openFolderMenuItem);
|
||||
menu.addSeparator();
|
||||
menu.add(checkProblemsMenuItem);
|
||||
|
||||
menu = new JMenu("Test");
|
||||
menu.setMargin(menuInset);
|
||||
menu.setMnemonic('t');
|
||||
menuBar.add(menu);
|
||||
menu.add(testMenuItem);
|
||||
menu.add(testOnlineMenuItem);
|
||||
menu.addSeparator();
|
||||
menu.add(optionsMenuItem);
|
||||
menu.add(instanceOptionsMenuItem);
|
||||
menu.addSeparator();
|
||||
menu.add(clearInstanceMenuItem);
|
||||
menu.add(clearWebRootMenuItem);
|
||||
|
||||
menu = new JMenu("Build");
|
||||
menu.setMargin(menuInset);
|
||||
menu.setMnemonic('b');
|
||||
menuBar.add(menu);
|
||||
menu.add(buildMenuItem);
|
||||
menu.add(deployServerMenuItem);
|
||||
menu.addSeparator();
|
||||
menu.add(generatePackagesMenuItem);
|
||||
menu.addSeparator();
|
||||
menu.add(openOutputFolderMenuItem);
|
||||
|
||||
menu = new JMenu("Tools");
|
||||
menu.setMargin(menuInset);
|
||||
menu.setMnemonic('t');
|
||||
menuBar.add(menu);
|
||||
menu.add(versionCheckMenuItem);
|
||||
menu.addSeparator();
|
||||
menu.add(openWorkspaceFolderMenuItem);
|
||||
menu.add(openLauncherFolderMenuItem);
|
||||
menu.add(openWebRootMenuItem);
|
||||
menu.addSeparator();
|
||||
menu.add(openConsoleMenuItem);
|
||||
|
||||
menu = new JMenu("Help");
|
||||
menu.setMargin(menuInset);
|
||||
menu.setMnemonic('h');
|
||||
menuBar.add(menu);
|
||||
menu.add(docsMenuItem);
|
||||
menu.addSeparator();
|
||||
menu.add(aboutMenuItem);
|
||||
|
||||
setJMenuBar(menuBar);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.skcraft.launcher.swing.DefaultTable;
|
||||
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
class ProblemTable extends DefaultTable {
|
||||
|
||||
public ProblemTable() {
|
||||
super();
|
||||
setTableHeader(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModel(TableModel dataModel) {
|
||||
super.setModel(dataModel);
|
||||
try {
|
||||
getColumnModel().getColumn(0).setMaxWidth(20);
|
||||
} catch (ArrayIndexOutOfBoundsException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.skcraft.launcher.creator.model.creator.Problem;
|
||||
import com.skcraft.launcher.creator.model.swing.ProblemTableModel;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.swing.TextFieldPopupMenu;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
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<Problem> 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.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
|
||||
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);
|
||||
|
||||
getRootPane().setDefaultButton(closeButton);
|
||||
getRootPane().registerKeyboardAction(e -> closeButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
|
||||
problemTable.getSelectionModel().addListSelectionListener(e -> {
|
||||
Problem selected = problemTableModel.getProblem(problemTable.getSelectedRow());
|
||||
if (selected != null) {
|
||||
SwingHelper.setTextAndResetCaret(explanationText, selected.getExplanation());
|
||||
}
|
||||
});
|
||||
|
||||
closeButton.addActionListener(e -> dispose());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.jidesoft.swing.SearchableUtils;
|
||||
import com.jidesoft.swing.TableSearchable;
|
||||
import com.skcraft.launcher.swing.DefaultTable;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import com.skcraft.launcher.swing.TableColumnAdjuster;
|
||||
import lombok.Getter;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
public class VersionCheckDialog extends JDialog {
|
||||
|
||||
@Getter private final JTable knownModsTable = new DefaultTable();
|
||||
@Getter private final JTable unknownModsTable = new DefaultTable();
|
||||
@Getter private final JButton closeButton = new JButton("Close");
|
||||
private final TableColumnAdjuster updateTableAdjuster = new TableColumnAdjuster(knownModsTable);
|
||||
private final TableColumnAdjuster unknownTableAdjuster = new TableColumnAdjuster(unknownModsTable);
|
||||
|
||||
public VersionCheckDialog(Window parent) {
|
||||
super(parent, "Update Check", ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
initComponents();
|
||||
pack();
|
||||
setLocationRelativeTo(parent);
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
updateTableAdjuster.adjustColumns();
|
||||
updateTableAdjuster.setDynamicAdjustment(true);
|
||||
|
||||
unknownTableAdjuster.adjustColumns();
|
||||
unknownTableAdjuster.setDynamicAdjustment(true);
|
||||
|
||||
knownModsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
||||
knownModsTable.setAutoCreateRowSorter(true);
|
||||
|
||||
unknownModsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
||||
unknownModsTable.setAutoCreateRowSorter(true);
|
||||
|
||||
JPanel container = new JPanel();
|
||||
container.setLayout(new MigLayout("insets dialog, fill"));
|
||||
|
||||
container.add(new JLabel("With Potential Updates:"), "span");
|
||||
container.add(SwingHelper.wrapScrollPane(knownModsTable), "grow, pushy, span, w 500:900, h 230");
|
||||
|
||||
container.add(new JLabel("Unknown Status:"), "span");
|
||||
container.add(SwingHelper.wrapScrollPane(unknownModsTable), "grow, pushy, span, w 500:900, h 150, gapbottom unrel, wrap");
|
||||
|
||||
container.add(new JLabel("Version data is sourced from NotEnoughMods.com."), "");
|
||||
container.add(closeButton, "tag cancel, sizegroup bttn");
|
||||
|
||||
add(container, BorderLayout.CENTER);
|
||||
|
||||
getRootPane().registerKeyboardAction(e -> closeButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
|
||||
TableSearchable tableSearchable;
|
||||
|
||||
tableSearchable = SearchableUtils.installSearchable(knownModsTable);
|
||||
tableSearchable.setMainIndex(-1);
|
||||
|
||||
tableSearchable = SearchableUtils.installSearchable(unknownModsTable);
|
||||
tableSearchable.setMainIndex(-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.dialog;
|
||||
|
||||
import com.skcraft.launcher.creator.Creator;
|
||||
import com.skcraft.launcher.creator.model.creator.RecentEntry;
|
||||
import com.skcraft.launcher.creator.swing.BorderCellRenderer;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
import lombok.Getter;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
public class WelcomeDialog extends JFrame {
|
||||
|
||||
@Getter private final JButton newButton = new JButton("New Workspace...", SwingHelper.createIcon(Creator.class, "new.png"));
|
||||
@Getter private final JButton openButton = new JButton("Open Workspace...", SwingHelper.createIcon(Creator.class, "open_folder.png"));
|
||||
@Getter private final JButton helpButton = new JButton("Help");
|
||||
@Getter private final JButton aboutButton = new JButton("About");
|
||||
@Getter private final JButton quitButton = new JButton("Quit");
|
||||
@Getter private final JList<RecentEntry> recentList = new JList<>();
|
||||
|
||||
public WelcomeDialog() {
|
||||
super("Modpack Creator");
|
||||
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
initComponents();
|
||||
setResizable(false);
|
||||
pack();
|
||||
setLocationRelativeTo(null);
|
||||
|
||||
SwingHelper.setFrameIcon(this, Creator.class, "icon.png");
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
recentList.setCellRenderer(new BorderCellRenderer(BorderFactory.createEmptyBorder(5, 5, 5, 5)));
|
||||
|
||||
JPanel container = new JPanel();
|
||||
container.setLayout(new MigLayout("insets 50 20"));
|
||||
|
||||
container.add(new JLabel(SwingHelper.createIcon(Creator.class, "welcome_logo.png")), "wrap, gap 20 20, gapbottom 30");
|
||||
|
||||
container.add(newButton, "grow, gap 50 50, wrap");
|
||||
container.add(openButton, "grow, gap 50 50, wrap");
|
||||
|
||||
JScrollPane recentScrollPane = new JScrollPane(recentList);
|
||||
recentScrollPane.setBorder(BorderFactory.createMatteBorder(0, 1, 0, 0, Color.LIGHT_GRAY));
|
||||
recentScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
container.add(recentScrollPane, "dock east, w 280, h 390");
|
||||
|
||||
JPanel buttons = new JPanel();
|
||||
buttons.setLayout(new MigLayout("insets 20", "[][]push[]"));
|
||||
buttons.add(helpButton);
|
||||
buttons.add(aboutButton);
|
||||
buttons.add(quitButton);
|
||||
container.add(buttons, "dock south");
|
||||
|
||||
add(container, BorderLayout.CENTER);
|
||||
|
||||
getRootPane().registerKeyboardAction(e -> quitButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.creator;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class CreatorConfig {
|
||||
|
||||
private List<RecentEntry> recentEntries = Lists.newArrayList();
|
||||
private boolean offlineEnabled;
|
||||
|
||||
public void setRecentEntries(List<RecentEntry> recentEntries) {
|
||||
this.recentEntries = recentEntries != null ? recentEntries : Lists.newArrayList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.creator;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.skcraft.launcher.model.modpack.ManifestInfo;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ManifestEntry implements Comparable<ManifestEntry> {
|
||||
|
||||
private boolean selected = false;
|
||||
private ManifestInfo manifestInfo;
|
||||
private List<String> gameKeys = Lists.newArrayList();
|
||||
|
||||
@Override
|
||||
public int compareTo(ManifestEntry o) {
|
||||
return manifestInfo.compareTo(o.getManifestInfo());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.creator;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Data
|
||||
public class ModFile {
|
||||
|
||||
private File file;
|
||||
private String modId;
|
||||
private String name;
|
||||
private String gameVersion;
|
||||
private String version;
|
||||
private String latestVersion;
|
||||
private String latestDevVersion;
|
||||
private URL url;
|
||||
|
||||
@JsonIgnore
|
||||
public String getCleanVersion() {
|
||||
String version = getVersion();
|
||||
return version != null ?
|
||||
version
|
||||
.replaceAll("^" + Pattern.quote(gameVersion) + "\\-", "")
|
||||
.replaceAll("\\-" + Pattern.quote(gameVersion) + "$", "")
|
||||
: null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.creator;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.skcraft.launcher.builder.BuilderConfig;
|
||||
import com.skcraft.launcher.builder.BuilderOptions;
|
||||
import com.skcraft.launcher.persistence.Persistence;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Data
|
||||
public class Pack {
|
||||
|
||||
private String location;
|
||||
@JsonIgnore private Workspace workspace;
|
||||
@JsonIgnore private BuilderConfig cachedConfig;
|
||||
|
||||
@JsonIgnore
|
||||
public File getDirectory() {
|
||||
File path = new File(location);
|
||||
if (path.isAbsolute()) {
|
||||
return path;
|
||||
} else {
|
||||
return new File(workspace.getDirectory(), location);
|
||||
}
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public File getLoadersDir() {
|
||||
return new File(getDirectory(), "loaders");
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public File getSourceDir() {
|
||||
return new File(getDirectory(), "src");
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public File getModsDir() {
|
||||
return new File(getSourceDir(), "mods");
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public File getConfigFile() {
|
||||
return new File(getDirectory(), BuilderOptions.DEFAULT_CONFIG_FILENAME);
|
||||
}
|
||||
|
||||
public void load() {
|
||||
setCachedConfig(Persistence.read(getConfigFile(), BuilderConfig.class, true));
|
||||
getLoadersDir().mkdirs();
|
||||
getSourceDir().mkdirs();
|
||||
}
|
||||
|
||||
public void createGuideFolders() {
|
||||
new File(getSourceDir(), "config").mkdirs();
|
||||
new File(getSourceDir(), "mods").mkdirs();
|
||||
new File(getSourceDir(), "resourcepacks").mkdirs();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean isLoaded() {
|
||||
return cachedConfig != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.creator;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.creator;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Data
|
||||
public class RecentEntry {
|
||||
|
||||
private File path;
|
||||
|
||||
public void setPath(File path) {
|
||||
this.path = path != null ? path : new File(".");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return path.getAbsolutePath();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.creator;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.skcraft.launcher.creator.model.swing.ListingType;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class Workspace {
|
||||
|
||||
public static final String DIR_NAME = ".modpacks";
|
||||
public static final String FILENAME = "workspace.json";
|
||||
|
||||
@JsonIgnore private File directory;
|
||||
private List<Pack> packs = Lists.newArrayList();
|
||||
private List<ManifestEntry> packageListingEntries = Lists.newArrayList();
|
||||
private ListingType packageListingType = ListingType.STATIC;
|
||||
|
||||
public void setPacks(List<Pack> packs) {
|
||||
this.packs = packs != null ? packs : Lists.<Pack>newArrayList();
|
||||
}
|
||||
|
||||
public void setPackageListingEntries(List<ManifestEntry> entries) {
|
||||
this.packageListingEntries = entries != null ? entries : Lists.newArrayList();
|
||||
}
|
||||
|
||||
public void setPackageListingType(ListingType packageListingType) {
|
||||
this.packageListingType = packageListingType != null ? packageListingType : ListingType.STATIC;
|
||||
}
|
||||
|
||||
public boolean hasPack(File dir) {
|
||||
for (Pack pack : packs) {
|
||||
try {
|
||||
if (pack.getDirectory().getCanonicalPath().equals(dir.getCanonicalPath())) {
|
||||
return true;
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void load() {
|
||||
for (Pack pack : getPacks()) {
|
||||
pack.setWorkspace(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
public static File getDataDir(File workspaceDir) {
|
||||
return new File(workspaceDir, DIR_NAME);
|
||||
}
|
||||
|
||||
public static File getWorkspaceFile(File workspaceDir) {
|
||||
return new File(getDataDir(workspaceDir), FILENAME);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.swing;
|
||||
|
||||
import com.skcraft.launcher.builder.FeaturePattern;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import java.util.List;
|
||||
|
||||
public class FeaturePatternTableModel extends AbstractTableModel {
|
||||
|
||||
private final List<FeaturePattern> features;
|
||||
|
||||
public FeaturePatternTableModel(List<FeaturePattern> features) {
|
||||
this.features = features;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return "Feature";
|
||||
case 1:
|
||||
return "Recommendation";
|
||||
case 2:
|
||||
return "Default?";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return String.class;
|
||||
case 1:
|
||||
return String.class;
|
||||
case 2:
|
||||
return String.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 features.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return features.get(rowIndex).getFeature().getName();
|
||||
case 1:
|
||||
return features.get(rowIndex).getFeature().getRecommendation();
|
||||
case 2:
|
||||
return features.get(rowIndex).getFeature().isSelected() ? "Yes" : "";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public FeaturePattern getFeature(int index) {
|
||||
return features.get(index);
|
||||
}
|
||||
|
||||
public void addFeature(FeaturePattern pattern) {
|
||||
features.add(pattern);
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
||||
public void removeFeature(int index) {
|
||||
features.remove(index);
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.swing;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.skcraft.launcher.creator.model.creator.ManifestEntry;
|
||||
import com.skcraft.launcher.model.modpack.ManifestInfo;
|
||||
import com.skcraft.launcher.model.modpack.PackageList;
|
||||
import com.skcraft.launcher.persistence.Persistence;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum ListingType {
|
||||
|
||||
STATIC("packages.json (static)", false, "packages.json") {
|
||||
@Override
|
||||
public String generate(List<ManifestEntry> entries) throws IOException {
|
||||
PackageList list = new PackageList();
|
||||
list.setPackages(Lists.newArrayList());
|
||||
list.setMinimumVersion(PackageList.MIN_VERSION);
|
||||
for (ManifestEntry entry : entries) {
|
||||
if (entry.getGameKeys().isEmpty()) {
|
||||
list.getPackages().add(entry.getManifestInfo());
|
||||
}
|
||||
}
|
||||
return Persistence.writeValueAsString(list, Persistence.L2F_LIST_PRETTY_PRINTER);
|
||||
}
|
||||
},
|
||||
PHP("packages.php (requires PHP on web server) ", true, "packages.php") {
|
||||
@Override
|
||||
public String generate(List<ManifestEntry> entries) throws IOException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<?php\r\n");
|
||||
builder.append("$keys = isset($_GET['key']) ? array_map('trim', explode(',', strtolower($_GET['key']))) : array();\r\n");
|
||||
builder.append("$packages = array();\r\n\r\n");
|
||||
|
||||
for (ManifestEntry entry : entries) {
|
||||
ManifestInfo info = entry.getManifestInfo();
|
||||
List<String> keys = entry.getGameKeys();
|
||||
|
||||
if (!keys.isEmpty()) {
|
||||
builder.append("if (count(array_intersect(array(").append(escapeKeys(keys)).append("), $keys)) > 0)\r\n");
|
||||
}
|
||||
|
||||
builder.append("$packages[] = array(\r\n");
|
||||
builder.append(" 'name' => '").append(escape(info.getName())).append("',\r\n");
|
||||
if (info.getTitle() != null) {
|
||||
builder.append(" 'title' => '").append(escape(info.getTitle())).append("',\r\n");
|
||||
}
|
||||
builder.append(" 'version' => '").append(escape(info.getVersion())).append("',\r\n");
|
||||
builder.append(" 'priority' => ").append(info.getPriority()).append(",\r\n");
|
||||
builder.append(" 'location' => '").append(escape(info.getLocation())).append("',\r\n");
|
||||
builder.append(");\r\n\r\n");
|
||||
}
|
||||
|
||||
builder.append("$out = array('minimumVersion' => ").append(PackageList.MIN_VERSION).append(", 'packages' => $packages);\r\n");
|
||||
builder.append("header('Content-Type: text/plain; charset=utf-8');\r\n");
|
||||
builder.append("echo json_encode($out);\r\n");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String escape(String t) {
|
||||
return t.replaceAll("[\\\\\"']", "\\$0").replace("\r", "\\r").replace("\n", "\\n");
|
||||
}
|
||||
|
||||
private String escapeKeys(List<String> list) {
|
||||
return Joiner.on(", ").join(list.stream().map(s -> "'" + escape(s.toLowerCase()) + "'").collect(Collectors.toList()));
|
||||
}
|
||||
};
|
||||
|
||||
@Getter private final String name;
|
||||
@Getter private final boolean gameKeyCompatible;
|
||||
@Getter private final String filename;
|
||||
|
||||
ListingType(String name, boolean gameKeyCompatible, String filename) {
|
||||
this.name = name;
|
||||
this.gameKeyCompatible = gameKeyCompatible;
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public abstract String generate(List<ManifestEntry> entries) throws IOException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.swing;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class ListingTypeComboBoxModel extends AbstractListModel<ListingType> implements ComboBoxModel<ListingType> {
|
||||
|
||||
private ListingType selection = ListingType.STATIC;
|
||||
|
||||
@Override
|
||||
public void setSelectedItem(Object anItem) {
|
||||
selection = (ListingType) anItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListingType getSelectedItem() {
|
||||
return selection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return ListingType.values().length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListingType getElementAt(int index) {
|
||||
return ListingType.values()[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.swing;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.skcraft.launcher.creator.model.creator.ManifestEntry;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import java.util.List;
|
||||
|
||||
public class ManifestEntryTableModel extends AbstractTableModel {
|
||||
|
||||
private final Joiner GAME_KEY_JOINER = Joiner.on(", ");
|
||||
private final List<ManifestEntry> entries;
|
||||
|
||||
public ManifestEntryTableModel(List<ManifestEntry> entries) {
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return "";
|
||||
case 1:
|
||||
return "Modpack";
|
||||
case 2:
|
||||
return "Version";
|
||||
case 3:
|
||||
return "Priority";
|
||||
case 4:
|
||||
return "Location";
|
||||
case 5:
|
||||
return "Game Keys";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return Boolean.class;
|
||||
case 1:
|
||||
return String.class;
|
||||
case 2:
|
||||
return String.class;
|
||||
case 3:
|
||||
return Integer.class;
|
||||
case 4:
|
||||
return String.class;
|
||||
case 5:
|
||||
return String.class;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void setValueAt(Object value, int rowIndex, int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
entries.get(rowIndex).setSelected((Boolean) value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
ManifestEntry entry = entries.get(rowIndex);
|
||||
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return entry.isSelected();
|
||||
case 1:
|
||||
String title = entry.getManifestInfo().getTitle();
|
||||
if (title != null) {
|
||||
return title;
|
||||
} else {
|
||||
return entry.getManifestInfo().getName();
|
||||
}
|
||||
case 2:
|
||||
return entry.getManifestInfo().getVersion();
|
||||
case 3:
|
||||
return entry.getManifestInfo().getPriority();
|
||||
case 4:
|
||||
return entry.getManifestInfo().getLocation();
|
||||
case 5:
|
||||
List<String> gameKeys = entry.getGameKeys();
|
||||
return gameKeys != null ? GAME_KEY_JOINER.join(gameKeys) : "";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.swing;
|
||||
|
||||
import com.skcraft.launcher.creator.Creator;
|
||||
import com.skcraft.launcher.creator.model.creator.ModFile;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class ModFileTableModel extends AbstractTableModel {
|
||||
|
||||
private static final Icon WWW_ICON;
|
||||
private final List<ModFile> mods;
|
||||
|
||||
static {
|
||||
WWW_ICON = SwingHelper.createIcon(Creator.class, "www_icon.png");
|
||||
}
|
||||
|
||||
public ModFileTableModel(List<ModFile> mods) {
|
||||
checkNotNull(mods, "mods");
|
||||
this.mods = mods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0: return "";
|
||||
case 1: return "Mod";
|
||||
case 2: return "Version";
|
||||
case 3: return "Latest Release";
|
||||
case 4: return "Latest Dev";
|
||||
case 5: return "Mod ID";
|
||||
case 6: return "Filename";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return Icon.class;
|
||||
default:
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
|
||||
@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 mods.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 7;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
@Nullable ModFile mod = mods.get(rowIndex);
|
||||
|
||||
if (mod == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (columnIndex) {
|
||||
case 0: return mod.getUrl() != null ? WWW_ICON : null;
|
||||
case 1: return mod.getName() != null ? mod.getName() : mod.getFile().getName();
|
||||
case 2: return mod.getCleanVersion();
|
||||
case 3: return mod.getLatestVersion();
|
||||
case 4: return mod.getLatestDevVersion();
|
||||
case 5: return mod.getModId();
|
||||
case 6: return mod.getFile().getName();
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ModFile getMod(int index) {
|
||||
return mods.get(index);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.swing;
|
||||
|
||||
import com.skcraft.launcher.builder.BuilderConfig;
|
||||
import com.skcraft.launcher.creator.Creator;
|
||||
import com.skcraft.launcher.creator.model.creator.Pack;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import java.util.List;
|
||||
|
||||
public class PackTableModel extends AbstractTableModel {
|
||||
|
||||
private final Icon instanceIcon;
|
||||
private final Icon warningIcon;
|
||||
private final List<Pack> packs;
|
||||
|
||||
public PackTableModel(List<Pack> packs) {
|
||||
this.packs = packs;
|
||||
|
||||
instanceIcon = SwingHelper.createIcon(Creator.class, "pack_icon.png");
|
||||
warningIcon = SwingHelper.createIcon(Creator.class, "warning_icon.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return "";
|
||||
case 1:
|
||||
return "Name";
|
||||
case 2:
|
||||
return "Title";
|
||||
case 3:
|
||||
return "Game Version";
|
||||
case 4:
|
||||
return "Location";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return Icon.class;
|
||||
default:
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
|
||||
@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 packs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
Pack pack = packs.get(rowIndex);
|
||||
|
||||
BuilderConfig config = pack.getCachedConfig();
|
||||
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return config != null ? instanceIcon : warningIcon;
|
||||
case 1:
|
||||
return config != null ? config.getName() : "<Moved or Deleted>";
|
||||
case 2:
|
||||
return config != null ? config.getTitle() : "?";
|
||||
case 3:
|
||||
return config != null ? config.getGameVersion() : "?";
|
||||
case 4:
|
||||
return pack.getLocation();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.swing;
|
||||
|
||||
import com.skcraft.launcher.creator.Creator;
|
||||
import com.skcraft.launcher.creator.model.creator.Problem;
|
||||
import com.skcraft.launcher.swing.SwingHelper;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import java.util.List;
|
||||
|
||||
public class ProblemTableModel extends AbstractTableModel {
|
||||
|
||||
private static final Icon WARNING_ICON;
|
||||
|
||||
static {
|
||||
WARNING_ICON = SwingHelper.createIcon(Creator.class, "warning_icon.png");
|
||||
}
|
||||
|
||||
private final List<Problem> problems;
|
||||
|
||||
public ProblemTableModel(List<Problem> 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 Icon.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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.swing;
|
||||
|
||||
import com.skcraft.launcher.creator.model.creator.RecentEntry;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.List;
|
||||
|
||||
public class RecentListModel extends AbstractListModel<RecentEntry> {
|
||||
|
||||
private final List<RecentEntry> recentEntries;
|
||||
|
||||
public RecentListModel(List<RecentEntry> recentEntries) {
|
||||
this.recentEntries = recentEntries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return recentEntries.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecentEntry getElementAt(int index) {
|
||||
return recentEntries.get(index);
|
||||
}
|
||||
|
||||
public void fireUpdate() {
|
||||
fireContentsChanged(this, 0, Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.swing;
|
||||
|
||||
import com.skcraft.launcher.model.modpack.Feature.Recommendation;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class RecommendationComboBoxModel extends AbstractListModel implements ComboBoxModel {
|
||||
|
||||
private Recommendation selection;
|
||||
|
||||
@Override
|
||||
public void setSelectedItem(Object anItem) {
|
||||
selection = (Recommendation) anItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSelectedItem() {
|
||||
return selection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return Recommendation.values().length + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int index) {
|
||||
if (index == 0) {
|
||||
return null;
|
||||
} else {
|
||||
return Recommendation.values()[index - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.server;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.skcraft.launcher.selfupdate.LatestVersionInfo;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
class LatestHandler extends AbstractHandler {
|
||||
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
public LatestHandler(ObjectMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
response.setContentType("text/plain; charset=utf-8");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
|
||||
LatestVersionInfo info = new LatestVersionInfo();
|
||||
info.setVersion("0.0.0");
|
||||
info.setUrl(new URL("http://localhost"));
|
||||
mapper.writeValue(response.getWriter(), info);
|
||||
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.server;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
class NewsHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
response.setContentType("text/html; charset=utf-8");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write("<!DOCTYPE html>");
|
||||
writer.write("<html>");
|
||||
writer.write("<head>");
|
||||
writer.write("<title>Staging Tool</title>");
|
||||
writer.write("</head>");
|
||||
writer.write("<body>");
|
||||
writer.write("<p>Welcome to the staging tool!</p>");
|
||||
writer.write("</body>");
|
||||
writer.write("</html>");
|
||||
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.server;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.skcraft.launcher.model.modpack.Manifest;
|
||||
import com.skcraft.launcher.model.modpack.ManifestInfo;
|
||||
import com.skcraft.launcher.model.modpack.PackageList;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
class PackagesHandler extends AbstractHandler {
|
||||
|
||||
private final ObjectMapper mapper;
|
||||
private final File baseDir;
|
||||
|
||||
public PackagesHandler(ObjectMapper mapper, File baseDir) {
|
||||
this.mapper = mapper;
|
||||
this.baseDir = baseDir;
|
||||
}
|
||||
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
response.setContentType("text/plain; charset=utf-8");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
|
||||
List<ManifestInfo> packages = Lists.newArrayList();
|
||||
PackageList packageList = new PackageList();
|
||||
packageList.setPackages(packages);
|
||||
|
||||
File[] files = baseDir.listFiles(new PackageFileFilter());
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
Manifest manifest = mapper.readValue(file, Manifest.class);
|
||||
ManifestInfo info = new ManifestInfo();
|
||||
info.setName(manifest.getName());
|
||||
info.setTitle(manifest.getTitle());
|
||||
info.setVersion(manifest.getVersion());
|
||||
info.setLocation(file.getName());
|
||||
packages.add(info);
|
||||
}
|
||||
}
|
||||
|
||||
mapper.writeValue(response.getWriter(), packageList);
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
|
||||
private static class PackageFileFilter implements FileFilter {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
return pathname.getName().toLowerCase().endsWith(".json");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.server;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
|
||||
public class TestServer {
|
||||
|
||||
@Getter private final Server server;
|
||||
|
||||
public TestServer(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void start() throws Exception {
|
||||
getServer().start();
|
||||
}
|
||||
|
||||
public int getLocalPort() {
|
||||
return ((ServerConnector) server.getConnectors()[0]).getLocalPort();
|
||||
}
|
||||
|
||||
public void stop() throws Exception {
|
||||
getServer().stop();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.server;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.ErrorHandler;
|
||||
import org.eclipse.jetty.server.handler.ResourceHandler;
|
||||
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class TestServerBuilder {
|
||||
|
||||
private File baseDir = new File(".");
|
||||
private int port = 28888;
|
||||
|
||||
public File getBaseDir() {
|
||||
return baseDir;
|
||||
}
|
||||
|
||||
public TestServerBuilder setBaseDir(File baseDir) {
|
||||
this.baseDir = baseDir;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public TestServerBuilder setPort(int port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestServer build() {
|
||||
Server server = new Server(port);
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
ResourceHandler resourceHandler = new ResourceHandler();
|
||||
resourceHandler.setDirectoriesListed(true);
|
||||
resourceHandler.setResourceBase(baseDir.getAbsolutePath());
|
||||
resourceHandler.setMinMemoryMappedContentLength(-1); // Causes file locking on Windows
|
||||
|
||||
ContextHandler rootContext = new ContextHandler();
|
||||
rootContext.setContextPath("/");
|
||||
rootContext.setHandler(resourceHandler);
|
||||
|
||||
ContextHandler packagesContext = new ContextHandler("/packages.json");
|
||||
packagesContext.setAllowNullPathInfo(true);
|
||||
packagesContext.setHandler(new PackagesHandler(mapper, baseDir));
|
||||
|
||||
ContextHandler latestContext = new ContextHandler("/latest.json");
|
||||
latestContext.setAllowNullPathInfo(true);
|
||||
latestContext.setHandler(new LatestHandler(mapper));
|
||||
|
||||
ContextHandler newsContext = new ContextHandler("/news.html");
|
||||
newsContext.setAllowNullPathInfo(true);
|
||||
newsContext.setHandler(new NewsHandler());
|
||||
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
contexts.setHandlers(new Handler[]{packagesContext, latestContext, newsContext, rootContext});
|
||||
|
||||
GzipHandler gzip = new GzipHandler();
|
||||
server.setHandler(gzip);
|
||||
gzip.setHandler(contexts);
|
||||
|
||||
server.addBean(new ErrorHandler());
|
||||
|
||||
return new TestServer(server);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.swing;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import java.awt.*;
|
||||
|
||||
public class BorderCellRenderer implements ListCellRenderer {
|
||||
|
||||
private final Border border;
|
||||
private final DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer();
|
||||
|
||||
public BorderCellRenderer(Border border) {
|
||||
this.border = border;
|
||||
}
|
||||
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
JLabel renderer = (JLabel) defaultRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
renderer.setBorder(border);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.swing;
|
||||
|
||||
import com.skcraft.launcher.creator.model.creator.Workspace;
|
||||
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import java.io.File;
|
||||
|
||||
public class PackDirectoryFilter extends FileFilter {
|
||||
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
return f.isDirectory() && !f.getName().equals(Workspace.DIR_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Directories";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.swing;
|
||||
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import java.io.File;
|
||||
|
||||
public class WorkspaceDirectoryFilter extends FileFilter {
|
||||
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
return f.isDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Directories";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.util;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.common.io.Closer;
|
||||
import lombok.Data;
|
||||
import lombok.extern.java.Log;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* Reads the mod information file from a mod .jar, with support for both Forge
|
||||
* and LiteLoader.
|
||||
*/
|
||||
@Log
|
||||
public class ModInfoReader {
|
||||
|
||||
private static final String FORGE_INFO_FILENAME = "mcmod.info";
|
||||
private static final String LITELOADER_INFO_FILENAME = "litemod.json";
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* Detect the mods listed in the given .jar
|
||||
*
|
||||
* @param file The file
|
||||
* @return A list of detected mods
|
||||
*/
|
||||
public List<? extends ModInfo> detectMods(File file) {
|
||||
Closer closer = Closer.create();
|
||||
|
||||
try {
|
||||
FileInputStream fis = closer.register(new FileInputStream(file));
|
||||
BufferedInputStream bis = closer.register(new BufferedInputStream(fis));
|
||||
ZipInputStream zis = closer.register(new ZipInputStream(bis));
|
||||
|
||||
ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (entry.getName().equalsIgnoreCase(FORGE_INFO_FILENAME)) {
|
||||
List<ForgeModInfo> mods;
|
||||
String content = CharStreams.toString(new InputStreamReader(zis, Charsets.UTF_8));
|
||||
|
||||
try {
|
||||
mods = mapper.readValue(content, ForgeModManifest.class).getMods();
|
||||
} catch (JsonMappingException | JsonParseException e) {
|
||||
mods = mapper.readValue(content, new TypeReference<List<ForgeModInfo>>() {});
|
||||
}
|
||||
|
||||
if (mods != null) {
|
||||
// Ignore "examplemod"
|
||||
return Collections.unmodifiableList(
|
||||
mods.stream()
|
||||
.filter(info -> !info.getModId().equals("examplemod"))
|
||||
.collect(Collectors.toList()));
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
} else if (entry.getName().equalsIgnoreCase(LITELOADER_INFO_FILENAME)) {
|
||||
String content = CharStreams.toString(new InputStreamReader(zis, Charsets.UTF_8));
|
||||
return new ImmutableList.Builder<ModInfo>().add(mapper.readValue(content, LiteLoaderModInfo.class)).build();
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
} catch (JsonMappingException e) {
|
||||
log.log(Level.WARNING, "Unknown format " + FORGE_INFO_FILENAME + " file in " + file.getAbsolutePath(), e);
|
||||
return Collections.emptyList();
|
||||
} catch (JsonParseException e) {
|
||||
log.log(Level.WARNING, "Corrupt " + FORGE_INFO_FILENAME + " file in " + file.getAbsolutePath(), e);
|
||||
return Collections.emptyList();
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to read " + file.getAbsolutePath(), e);
|
||||
return Collections.emptyList();
|
||||
} finally {
|
||||
try {
|
||||
closer.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface ModInfo {
|
||||
|
||||
String getModId();
|
||||
String getName();
|
||||
String getDescription();
|
||||
String getVersion();
|
||||
String getGameVersion();
|
||||
String getUrl();
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
private static class ForgeModInfo implements ModInfo {
|
||||
|
||||
@JsonProperty("modid")
|
||||
private String modId;
|
||||
private String name;
|
||||
private String description;
|
||||
private String version;
|
||||
@JsonProperty("mcversion")
|
||||
private String gameVersion;
|
||||
private String url;
|
||||
private String updateUrl;
|
||||
private List<String> authorList;
|
||||
private String credits;
|
||||
private List<String> dependencies;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
private static class ForgeModManifest {
|
||||
|
||||
@JsonProperty("modListVersion")
|
||||
private int version;
|
||||
@JsonProperty("modList")
|
||||
private List<ForgeModInfo> mods;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
private static class LiteLoaderModInfo implements ModInfo {
|
||||
|
||||
private String name;
|
||||
private String version;
|
||||
@JsonProperty("mcversion")
|
||||
private String gameVersion;
|
||||
private String revision;
|
||||
private String author;
|
||||
private String description;
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public String getModId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.util;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.skcraft.launcher.util.HttpRequest;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class NemModList {
|
||||
|
||||
@Getter
|
||||
private Map<String, ModEntry> mods = ImmutableMap.of();
|
||||
|
||||
public void load(String version) throws IOException, InterruptedException {
|
||||
checkNotNull(version, "version");
|
||||
|
||||
List<ModEntry> mods = HttpRequest.get(HttpRequest.url("https://bot.notenoughmods.com/" + version + ".json"))
|
||||
.execute()
|
||||
.expectResponseCode(200)
|
||||
.returnContent()
|
||||
.asJson(new TypeReference<List<ModEntry>>() {});
|
||||
|
||||
Map<String, ModEntry> index = Maps.newHashMap();
|
||||
|
||||
for (ModEntry entry : mods) {
|
||||
index.put(entry.getModId(), entry);
|
||||
}
|
||||
|
||||
this.mods = Collections.unmodifiableMap(index);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ModEntry get(String modId) {
|
||||
checkNotNull(modId, "modId");
|
||||
return mods.get(modId);
|
||||
}
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class ModEntry {
|
||||
|
||||
@JsonProperty("modid")
|
||||
private String modId;
|
||||
private String name;
|
||||
private List<String> aliases;
|
||||
|
||||
@JsonProperty("version")
|
||||
private String latestVersion;
|
||||
@JsonProperty("dev")
|
||||
private String latestDevVersion;
|
||||
@JsonProperty("prevversion")
|
||||
private String previousVersion;
|
||||
|
||||
private List<String> dependencies;
|
||||
|
||||
@JsonProperty("longurl")
|
||||
private URL url;
|
||||
private List<String> tags;
|
||||
private String comment;
|
||||
private String author;
|
||||
|
||||
private String license;
|
||||
private URL repo;
|
||||
|
||||
@JsonProperty("added_at")
|
||||
private Date addedAt;
|
||||
@JsonProperty("lastupdated")
|
||||
private Date lastUpdated;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 601 B |
|
After Width: | Height: | Size: 861 B |
|
After Width: | Height: | Size: 899 B |
|
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
# SK's Minecraft Launcher
|
||||
# Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
# Please see LICENSE.txt for license information.
|
||||
#
|
||||
|
||||
version=${project.version}
|
||||
|
After Width: | Height: | Size: 620 B |
|
After Width: | Height: | Size: 792 B |
|
After Width: | Height: | Size: 647 B |
|
After Width: | Height: | Size: 540 B |
|
After Width: | Height: | Size: 418 B |
|
After Width: | Height: | Size: 685 B |
|
After Width: | Height: | Size: 431 B |
|
After Width: | Height: | Size: 1 KiB |
|
After Width: | Height: | Size: 577 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 541 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 534 B |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.7 KiB |