Cached Minecraft jars

This commit is contained in:
huangyuhui 2018-01-27 14:05:39 +08:00
parent 1a572be52e
commit 418be689f2
17 changed files with 133 additions and 38 deletions

View File

@ -69,10 +69,10 @@ public class HMCLGameDownloadTask extends Task {
dependencies.add(new FileDownloadTask(
NetworkUtils.toURL(profile.getDependency().getDownloadProvider().injectURL(version.getDownloadInfo().getUrl())),
jar,
cache,
profile.getDependency().getProxy(),
version.getDownloadInfo().getSha1()
));
).then(Task.of(v -> FileUtils.copyFile(cache, jar))));
}
}

View File

@ -22,6 +22,7 @@ import com.google.gson.GsonBuilder;
import org.jackhuang.hmcl.event.EventBus;
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
import org.jackhuang.hmcl.event.RefreshingVersionsEvent;
import org.jackhuang.hmcl.setting.EnumGameDirectory;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.setting.VersionSetting;
@ -63,7 +64,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
@Override
public File getRunDirectory(String id) {
if (beingModpackVersions.contains(id))
if (beingModpackVersions.contains(id) || isModpack(id))
return getVersionRoot(id);
else {
VersionSetting vs = profile.getVersionSetting(id);
@ -155,7 +156,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
if (!hasVersion(id))
return null;
if (versionSettings.containsKey(id))
return versionSettings.get(id);
return getVersionSetting(id);
else
return initVersionSetting(id, new VersionSetting());
}
@ -176,7 +177,10 @@ public class HMCLGameRepository extends DefaultGameRepository {
public VersionSetting getVersionSetting(String id) {
if (!versionSettings.containsKey(id))
loadVersionSetting(id);
return versionSettings.get(id);
VersionSetting setting = versionSettings.get(id);
if (setting != null && isModpack(id))
setting.setGameDirType(EnumGameDirectory.VERSION_FOLDER);
return setting;
}
public File getVersionIcon(String id) {
@ -195,7 +199,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
@Override
public File getModpackConfiguration(String version) {
return new File(getRunDirectory(version), "modpack.cfg");
return new File(getVersionRoot(version), "modpack.cfg");
}
public void markVersionAsModpack(String id) {

View File

@ -115,6 +115,11 @@ public final class LauncherHelper {
launchingStepsPane.setProgress(1.0 * finished.get() / executor.getRunningTasks());
});
}
@Override
public void onTerminate() {
Controllers.closeDialog();
}
});
executor.start();

View File

@ -44,7 +44,6 @@ public final class MultiMCInstallVersionSettingTask extends Task {
@Override
public void execute() {
profile.getRepository().refreshVersions();
VersionSetting vs = Objects.requireNonNull(profile.specializeVersionSetting(version));
ModpackHelper.toVersionSetting(manifest, vs);
}

View File

@ -426,11 +426,9 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza
}
public JFXDialog showDialog(Region content) {
if (dialog.getContent() != content) {
dialog.setContent(content);
if (!dialogShown)
dialog.show();
}
dialog.setContent(content);
if (!dialogShown)
dialog.show();
return dialog;
}

View File

@ -18,7 +18,9 @@
package org.jackhuang.hmcl.ui;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXListView;
import com.jfoenix.controls.JFXMasonryPane;
import com.jfoenix.controls.JFXPopup;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
@ -26,6 +28,7 @@ import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.StackPane;
import javafx.stage.FileChooser;
import org.jackhuang.hmcl.Main;
@ -61,6 +64,9 @@ public final class MainPage extends StackPane implements DecoratorPage {
private final StringProperty title = new SimpleStringProperty(this, "title", Main.i18n("main_page"));
private Profile profile;
private String rightClickedVersion;
@FXML
private JFXButton btnRefresh;
@ -70,6 +76,11 @@ public final class MainPage extends StackPane implements DecoratorPage {
@FXML
private JFXMasonryPane masonryPane;
@FXML
private JFXListView versionList;
private JFXPopup versionPopup;
{
FXUtils.loadFXML(this, "/assets/fxml/main.fxml");
@ -77,6 +88,9 @@ public final class MainPage extends StackPane implements DecoratorPage {
EventBus.EVENT_BUS.channel(ProfileLoadingEvent.class).register(this::onProfilesLoading);
EventBus.EVENT_BUS.channel(ProfileChangedEvent.class).register(this::onProfileChanged);
versionPopup = new JFXPopup(versionList);
getChildren().remove(versionList);
btnAdd.setOnMouseClicked(e -> Controllers.getDecorator().startWizard(new DownloadWizardProvider(), Main.i18n("install")));
FXUtils.installTooltip(btnAdd, 0, 5000, 0, new Tooltip(Main.i18n("install")));
btnRefresh.setOnMouseClicked(e -> Settings.INSTANCE.getSelectedProfile().getRepository().refreshVersionsAsync().start());
@ -136,6 +150,13 @@ public final class MainPage extends StackPane implements DecoratorPage {
}
}
});
item.setOnMouseClicked(event -> {
if (event.getButton() == MouseButton.SECONDARY) {
rightClickedVersion = version;
versionList.getSelectionModel().select(-1);
versionPopup.show(item, JFXPopup.PopupVPosition.TOP, JFXPopup.PopupHPosition.LEFT, event.getX(), event.getY());
}
});
File iconFile = profile.getRepository().getVersionIcon(version);
if (iconFile.exists())
item.setImage(new Image("file:" + iconFile.getAbsolutePath()));
@ -155,6 +176,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
}
private void loadVersions(Profile profile) {
this.profile = profile;
List<Node> children = new LinkedList<>();
for (Version version : profile.getRepository().getVersions()) {
children.add(buildNode(profile, version.getId(), Lang.nonNull(GameVersion.minecraftVersion(profile.getRepository().getVersionJar(version.getId())), "Unknown")));
@ -162,6 +184,21 @@ public final class MainPage extends StackPane implements DecoratorPage {
FXUtils.resetChildren(masonryPane, children);
}
public void onVersionManagement() {
versionPopup.hide();
switch (versionList.getSelectionModel().getSelectedIndex()) {
case 0:
VersionPage.renameVersion(profile, rightClickedVersion);
break;
case 1:
VersionPage.deleteVersion(profile, rightClickedVersion);
break;
case 2:
VersionPage.exportVersion(profile, rightClickedVersion);
break;
}
}
public String getTitle() {
return title.get();
}

View File

@ -36,6 +36,7 @@ import org.jackhuang.hmcl.ui.wizard.DecoratorPage;
import org.jackhuang.hmcl.util.FileUtils;
import java.io.File;
import java.lang.reflect.Proxy;
import java.util.Optional;
public final class VersionPage extends StackPane implements DecoratorPage {
@ -112,16 +113,11 @@ public final class VersionPage extends StackPane implements DecoratorPage {
}
public void onDelete() {
Controllers.confirmDialog(Main.i18n("version.manage.remove.confirm", version), Main.i18n("message.confirm"), () -> {
if (profile.getRepository().removeVersionFromDisk(version)) {
profile.getRepository().refreshVersionsAsync().start();
Controllers.navigate(null);
}
}, null);
deleteVersion(profile, version);
}
public void onExport() {
Controllers.getDecorator().startWizard(new ExportWizardProvider(profile, version), Main.i18n("modpack.wizard"));
exportVersion(profile, version);
}
public void onBrowse() {
@ -157,16 +153,10 @@ public final class VersionPage extends StackPane implements DecoratorPage {
public void onManagement() {
switch (managementList.getSelectionModel().getSelectedIndex()) {
case 0: // rename a version
Optional<String> res = FXUtils.inputDialog("Input", Main.i18n("version.manage.rename.message"), null, version);
if (res.isPresent()) {
if (profile.getRepository().renameVersion(version, res.get())) {
profile.getRepository().refreshVersionsAsync().start();
Controllers.navigate(null);
}
}
renameVersion(profile, version);
break;
case 1: // remove a version
onDelete();
deleteVersion(profile, version);
break;
case 2: // redownload asset index
new GameAssetIndexDownloadTask(profile.getDependency(), profile.getRepository().getVersion(version).resolve(profile.getRepository())).start();
@ -191,4 +181,26 @@ public final class VersionPage extends StackPane implements DecoratorPage {
public void setTitle(String title) {
this.title.set(title);
}
public static void deleteVersion(Profile profile, String version) {
Controllers.confirmDialog(Main.i18n("version.manage.remove.confirm", version), Main.i18n("message.confirm"), () -> {
if (profile.getRepository().removeVersionFromDisk(version)) {
profile.getRepository().refreshVersionsAsync().start();
Controllers.navigate(null);
}
}, null);
}
public static void renameVersion(Profile profile, String version) {
Controllers.inputDialog(Main.i18n("version.manage.rename.message"), res -> {
if (profile.getRepository().renameVersion(version, res)) {
profile.getRepository().refreshVersionsAsync().start();
Controllers.navigate(null);
}
});
}
public static void exportVersion(Profile profile, String version) {
Controllers.getDecorator().startWizard(new ExportWizardProvider(profile, version), Main.i18n("modpack.wizard"));
}
}

View File

@ -126,6 +126,8 @@ public final class VersionSettingsController {
this.profile = profile;
this.versionId = versionId;
gameDirItem.setDisable(profile.getRepository().isModpack(versionId));
if (lastVersionSetting != null) {
lastVersionSetting.widthProperty().unbind();
lastVersionSetting.heightProperty().unbind();

View File

@ -92,6 +92,9 @@ public final class TransitionHandler implements AnimationHandler {
} else
previousNode = NULL;
if (previousNode == currentNode)
previousNode = NULL;
currentNode = newView;
view.getChildren().setAll(previousNode, currentNode);

View File

@ -78,7 +78,7 @@ public final class DownloadWizardProvider implements WizardProvider {
profile.getRepository().markVersionAsModpack(name);
Task finalizeTask = Task.of(() -> {
profile.getRepository().refreshVersionsAsync().start();
profile.getRepository().refreshVersions();
VersionSetting vs = profile.specializeVersionSetting(name);
profile.getRepository().undoMark(name);
if (vs != null)
@ -87,14 +87,14 @@ public final class DownloadWizardProvider implements WizardProvider {
if (modpack.getManifest() instanceof CurseManifest)
return new CurseInstallTask(profile.getDependency(), selected, ((CurseManifest) modpack.getManifest()), name)
.with(finalizeTask);
.finalized(finalizeTask);
else if (modpack.getManifest() instanceof HMCLModpackManifest)
return new HMCLModpackInstallTask(profile, selected, modpack, name)
.with(finalizeTask);
.finalized(finalizeTask);
else if (modpack.getManifest() instanceof MultiMCInstanceConfiguration)
return new MultiMCModpackInstallTask(profile.getDependency(), selected, ((MultiMCInstanceConfiguration) modpack.getManifest()), name)
.with(new MultiMCInstallVersionSettingTask(profile, ((MultiMCInstanceConfiguration) modpack.getManifest()), name))
.with(finalizeTask);
.finalized(finalizeTask)
.with(new MultiMCInstallVersionSettingTask(profile, ((MultiMCInstanceConfiguration) modpack.getManifest()), name));
else throw new IllegalStateException("Unrecognized modpack: " + modpack);
}

View File

@ -77,7 +77,7 @@ public final class ModpackPage extends StackPane implements WizardPage {
chooser.setTitle(Main.i18n("modpack.choose"));
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(Main.i18n("modpack"), "*.zip"));
File selectedFile = chooser.showOpenDialog(Controllers.getStage());
if (selectedFile == null) Platform.runLater(controller::onFinish);
if (selectedFile == null) Platform.runLater(() -> Controllers.navigate(null));
else {
// TODO: original HMCL modpack support.
controller.getSettings().put(MODPACK_FILE, selectedFile);

View File

@ -5,6 +5,8 @@
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import com.jfoenix.controls.JFXListView?>
<?import javafx.scene.control.Label?>
<fx:root
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
type="StackPane" pickOnBounds="false"
@ -28,4 +30,11 @@
</JFXButton>
</VBox>
<JFXListView fx:id="versionList" styleClass="option-list-view" onMouseClicked="#onVersionManagement"
maxWidth="150.0" minWidth="150.0">
<Label text="%version.manage.rename"/>
<Label text="%version.manage.remove"/>
<Label text="%modpack.export"/>
</JFXListView>
</fx:root>

View File

@ -18,7 +18,7 @@
<Label fx:id="content" wrapText="true" />
</body>
<actions>
<HBox fx:id="actions">
<HBox fx:id="actions" alignment="CENTER_RIGHT">
<JFXButton fx:id="acceptButton" styleClass="dialog-accept" text="%button.ok" />
<JFXButton fx:id="cancelButton" visible="false" styleClass="dialog-cancel" text="%button.cancel" />
</HBox>

View File

@ -311,7 +311,7 @@ public class DefaultGameRepository implements GameRepository {
}
public File getModpackConfiguration(String version) {
return new File(getRunDirectory(version), "modpack.json");
return new File(getVersionRoot(version), "modpack.json");
}
public boolean isModpack(String version) {

View File

@ -34,6 +34,7 @@ import java.util.function.Function;
final class CoupleTask<P extends Task> extends Task {
private final boolean relyingOnDependents;
private final boolean failIfDependentsFail;
private final Collection<Task> dependents;
private final List<Task> dependencies = new LinkedList<>();
private final ExceptionalFunction<AutoTypingMap<String>, Task, ?> succ;
@ -45,10 +46,11 @@ final class CoupleTask<P extends Task> extends Task {
* @param succ a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred.
* @param relyingOnDependents true if this task chain will be broken when task pred fails.
*/
public CoupleTask(P pred, ExceptionalFunction<AutoTypingMap<String>, Task, ?> succ, boolean relyingOnDependents) {
public CoupleTask(P pred, ExceptionalFunction<AutoTypingMap<String>, Task, ?> succ, boolean relyingOnDependents, boolean failIfDependentsFail) {
this.dependents = Collections.singleton(pred);
this.succ = succ;
this.relyingOnDependents = relyingOnDependents;
this.failIfDependentsFail = failIfDependentsFail;
setSignificance(TaskSignificance.MODERATE);
}
@ -58,6 +60,9 @@ final class CoupleTask<P extends Task> extends Task {
Task task = succ.apply(getVariables());
if (task != null)
dependencies.add(task);
if (failIfDependentsFail && !isDependentsSucceeded())
throw new SilentException();
}
@Override

View File

@ -69,6 +69,16 @@ public abstract class Task {
return Schedulers.defaultScheduler();
}
private boolean dependentsSucceeded = false;
public boolean isDependentsSucceeded() {
return dependentsSucceeded;
}
void setDependentsSucceeded() {
dependentsSucceeded = true;
}
/**
* True if requires all {@link #getDependents} finishing successfully.
* <p>
@ -239,7 +249,7 @@ public abstract class Task {
}
public final Task then(ExceptionalFunction<AutoTypingMap<String>, Task, ?> b) {
return new CoupleTask<>(this, b, true);
return new CoupleTask<>(this, b, true, false);
}
public final Task with(Task b) {
@ -247,7 +257,15 @@ public abstract class Task {
}
public final Task with(ExceptionalFunction<AutoTypingMap<String>, Task, ?> b) {
return new CoupleTask<>(this, b, false);
return new CoupleTask<>(this, b, false, false);
}
public final Task finalized(Task b) {
return finalized(s -> b);
}
public final Task finalized(ExceptionalFunction<AutoTypingMap<String>, Task, ?> b) {
return new CoupleTask<>(this, b, false, true);
}
public static Task empty() {

View File

@ -159,6 +159,9 @@ public final class TaskExecutor {
if (!doDependentsSucceeded && task.isRelyingOnDependents() || canceled)
throw new SilentException();
if (doDependentsSucceeded)
task.setDependentsSucceeded();
task.setVariables(variables);
task.execute();