mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-17 07:47:57 -04:00
Cached Minecraft jars
This commit is contained in:
parent
1a572be52e
commit
418be689f2
@ -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))));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -115,6 +115,11 @@ public final class LauncherHelper {
|
||||
launchingStepsPane.setProgress(1.0 * finished.get() / executor.getRunningTasks());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTerminate() {
|
||||
Controllers.closeDialog();
|
||||
}
|
||||
});
|
||||
|
||||
executor.start();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user