diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameDownloadTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameDownloadTask.java index ce34357a3..33935476b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameDownloadTask.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameDownloadTask.java @@ -18,6 +18,7 @@ package org.jackhuang.hmcl.game; import org.jackhuang.hmcl.setting.Profile; +import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.FileDownloadTask.IntegrityCheck; import org.jackhuang.hmcl.task.Task; @@ -29,6 +30,7 @@ import java.io.File; import java.io.IOException; import java.util.LinkedList; import java.util.List; +import java.util.Optional; import java.util.logging.Level; import static org.jackhuang.hmcl.setting.ConfigHolder.CONFIG; @@ -59,7 +61,11 @@ public class HMCLGameDownloadTask extends Task { public void execute() { File jar = profile.getRepository().getVersionJar(version); - File cache = new File(CONFIG.getCommonDirectory(), "jars/" + gameVersion + ".jar"); + // Force using common directory will not affect the behaviour that repository acts + // Since we always copy the downloaded jar to .minecraft/versions// + File cache = new File(Optional.ofNullable(Settings.INSTANCE.getCommonDirectory()) + .orElse(Settings.getDefaultCommonDirectory()), + "jars/" + gameVersion + ".jar"); if (cache.exists()) try { FileUtils.copyFile(cache, jar); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index 2aff2a527..c2a3717c9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -24,6 +24,7 @@ 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; import org.jackhuang.hmcl.util.FileUtils; import org.jackhuang.hmcl.util.Logging; @@ -51,17 +52,16 @@ public class HMCLGameRepository extends DefaultGameRepository { return profile; } - private boolean useSelf(String version, String assetId) { - VersionSetting vs = profile.getVersionSetting(version); - return new File(getBaseDirectory(), "assets/indexes/" + assetId + ".json").exists() || vs.isNoCommon(); + private boolean useSelf(String assetId) { + return new File(getBaseDirectory(), "assets/indexes/" + assetId + ".json").exists(); } @Override public File getAssetDirectory(String version, String assetId) { - if (useSelf(version, assetId)) + if (Settings.INSTANCE.isCommonDirectoryDisabled() || useSelf(assetId)) return super.getAssetDirectory(version, assetId); else - return new File(CONFIG.getCommonDirectory(), "assets"); + return new File(Settings.INSTANCE.getCommonDirectory(), "assets"); } @Override @@ -83,10 +83,10 @@ public class HMCLGameRepository extends DefaultGameRepository { public File getLibraryFile(Version version, Library lib) { VersionSetting vs = profile.getVersionSetting(version.getId()); File self = super.getLibraryFile(version, lib); - if (self.exists() || vs.isNoCommon()) + if (Settings.INSTANCE.isCommonDirectoryDisabled() || self.exists()) return self; else - return new File(CONFIG.getCommonDirectory(), "libraries/" + lib.getPath()); + return new File(Settings.INSTANCE.getCommonDirectory(), "libraries/" + lib.getPath()); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java index b1ab82646..cab85eb9c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java @@ -89,6 +89,9 @@ public final class Config implements Cloneable, Observable { @SerializedName("bgpath") private StringProperty backgroundImage = new SimpleStringProperty(); + @SerializedName("commonDirType") + private ObjectProperty commonDirType = new SimpleObjectProperty<>(EnumCommonDirectory.DEFAULT); + @SerializedName("commonpath") private StringProperty commonDirectory = new SimpleStringProperty(Launcher.MINECRAFT_DIRECTORY.getAbsolutePath()); @@ -146,6 +149,9 @@ public final class Config implements Cloneable, Observable { @SerializedName("authlibInjectorServers") private ObservableList authlibInjectorServers = FXCollections.observableArrayList(); + @SerializedName("_version") + private IntegerProperty configVersion = new SimpleIntegerProperty(0); + private transient ObservableHelper helper = new ObservableHelper(this); public Config() { @@ -225,6 +231,18 @@ public final class Config implements Cloneable, Observable { return backgroundImage; } + public EnumCommonDirectory getCommonDirType() { + return commonDirType.get(); + } + + public ObjectProperty commonDirTypeProperty() { + return commonDirType; + } + + public void setCommonDirType(EnumCommonDirectory commonDirType) { + this.commonDirType.set(commonDirType); + } + public String getCommonDirectory() { return commonDirectory.get(); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/ConfigHolder.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/ConfigHolder.java index 88827939f..c07bf7ec6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/ConfigHolder.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/ConfigHolder.java @@ -24,8 +24,10 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Map; import java.util.logging.Level; +import com.google.gson.Gson; import com.google.gson.JsonParseException; public final class ConfigHolder { @@ -36,15 +38,23 @@ public final class ConfigHolder { public static final Path CONFIG_PATH = Paths.get(CONFIG_FILENAME).toAbsolutePath(); public static final Config CONFIG = initSettings(); + private static Config upgradeSettings(Config deserialized, Map rawJson) { + if (!rawJson.containsKey("commonDirType")) + deserialized.setCommonDirType(deserialized.getCommonDirectory().equals(Settings.getDefaultCommonDirectory()) ? EnumCommonDirectory.DEFAULT : EnumCommonDirectory.CUSTOM); + return deserialized; + } + private static Config initSettings() { Config config = new Config(); if (Files.exists(CONFIG_PATH)) { try { - Config deserialized = Config.fromJson(new String(Files.readAllBytes(CONFIG_PATH), UTF_8)); + String json = new String(Files.readAllBytes(CONFIG_PATH), UTF_8); + Map raw = new Gson().fromJson(json, Map.class); + Config deserialized = Config.fromJson(json); if (deserialized == null) { LOG.finer("Settings file is empty, use the default settings."); } else { - config = deserialized; + config = upgradeSettings(deserialized, raw); } LOG.finest("Initialized settings."); } catch (IOException | JsonParseException e) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumCommonDirectory.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumCommonDirectory.java new file mode 100644 index 000000000..5ca9fd426 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumCommonDirectory.java @@ -0,0 +1,33 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.setting; + +public enum EnumCommonDirectory { + /** + * same to game directory + */ + DISABLED, + /** + * %appdata%/.minecraft or ~/.minecraft + */ + DEFAULT, + /** + * user customized common directory. + */ + CUSTOM +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java index a1b667c2b..1cbc24883 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java @@ -33,6 +33,7 @@ import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.util.*; import org.jackhuang.hmcl.util.i18n.Locales; +import java.io.File; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; @@ -145,6 +146,27 @@ public class Settings { CONFIG.setLogLines(logLines); } + public boolean isCommonDirectoryDisabled() { + return CONFIG.getCommonDirType() == EnumCommonDirectory.DISABLED; + } + + public static String getDefaultCommonDirectory() { + return Launcher.MINECRAFT_DIRECTORY.getAbsolutePath(); + } + + public String getCommonDirectory() { + switch (CONFIG.getCommonDirType()) { + case DISABLED: + return null; + case DEFAULT: + return getDefaultCommonDirectory(); + case CUSTOM: + return CONFIG.getCommonDirectory(); + default: + return null; + } + } + /**************************************** * AUTHLIB INJECTORS * ****************************************/ diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java index d1a6d5e02..761dce2bf 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java @@ -287,23 +287,6 @@ public final class VersionSetting { notCheckGameProperty.set(notCheckGame); } - private final ImmediateBooleanProperty noCommonProperty = new ImmediateBooleanProperty(this, "noCommon", false); - - public ImmediateBooleanProperty noCommonProperty() { - return noCommonProperty; - } - - /** - * True if HMCL does not find/download libraries in/to common path. - */ - public boolean isNoCommon() { - return noCommonProperty.get(); - } - - public void setNoCommon(boolean noCommon) { - noCommonProperty.set(noCommon); - } - private final ImmediateBooleanProperty showLogsProperty = new ImmediateBooleanProperty(this, "showLogs", false); public ImmediateBooleanProperty showLogsProperty() { @@ -504,7 +487,6 @@ public final class VersionSetting { minecraftArgsProperty.addListener(listener); noJVMArgsProperty.addListener(listener); notCheckGameProperty.addListener(listener); - noCommonProperty.addListener(listener); showLogsProperty.addListener(listener); serverIpProperty.addListener(listener); fullscreenProperty.addListener(listener); @@ -569,7 +551,6 @@ public final class VersionSetting { obj.addProperty("fullscreen", src.isFullscreen()); obj.addProperty("noJVMArgs", src.isNoJVMArgs()); obj.addProperty("notCheckGame", src.isNotCheckGame()); - obj.addProperty("noCommon", src.isNoCommon()); obj.addProperty("showLogs", src.isShowLogs()); obj.addProperty("gameDir", src.getGameDir()); obj.addProperty("launcherVisibility", src.getLauncherVisibility().ordinal()); @@ -607,7 +588,6 @@ public final class VersionSetting { vs.setFullscreen(Optional.ofNullable(obj.get("fullscreen")).map(JsonElement::getAsBoolean).orElse(false)); vs.setNoJVMArgs(Optional.ofNullable(obj.get("noJVMArgs")).map(JsonElement::getAsBoolean).orElse(false)); vs.setNotCheckGame(Optional.ofNullable(obj.get("notCheckGame")).map(JsonElement::getAsBoolean).orElse(false)); - vs.setNoCommon(Optional.ofNullable(obj.get("noCommon")).map(JsonElement::getAsBoolean).orElse(false)); vs.setShowLogs(Optional.ofNullable(obj.get("showLogs")).map(JsonElement::getAsBoolean).orElse(false)); vs.setLauncherVisibility(LauncherVisibility.values()[Optional.ofNullable(obj.get("launcherVisibility")).map(JsonElement::getAsInt).orElse(1)]); vs.setGameDirType(EnumGameDirectory.values()[Optional.ofNullable(obj.get("gameDirType")).map(JsonElement::getAsInt).orElse(0)]); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java index 3c1274c44..5acc657cc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java @@ -69,6 +69,7 @@ import org.jackhuang.hmcl.ui.wizard.*; import org.jackhuang.hmcl.util.Lang; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; @@ -227,7 +228,7 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza Bindings.createObjectBinding( () -> { Image image = null; - if (CONFIG.getBackgroundImageType() == EnumBackgroundImage.CUSTOM) { + if (CONFIG.getBackgroundImageType() == EnumBackgroundImage.CUSTOM && CONFIG.getBackgroundImage() != null) { image = tryLoadImage(Paths.get(CONFIG.getBackgroundImage())) .orElse(null); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java index 3b88e0a99..927166f5b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java @@ -20,6 +20,7 @@ package org.jackhuang.hmcl.ui; import com.jfoenix.controls.*; import com.jfoenix.effects.JFXDepthManager; import javafx.application.Platform; +import javafx.beans.binding.Bindings; import javafx.beans.binding.When; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; @@ -50,8 +51,10 @@ import static org.jackhuang.hmcl.setting.ConfigHolder.CONFIG; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import java.net.Proxy; +import java.util.Arrays; import java.util.Collections; import java.util.Objects; +import java.util.Optional; public final class SettingsPage extends StackPane implements DecoratorPage { private final StringProperty title = new SimpleStringProperty(this, "title", i18n("settings.launcher")); @@ -73,7 +76,7 @@ public final class SettingsPage extends StackPane implements DecoratorPage { @FXML private FontComboBox cboFont; @FXML - private FileItem fileCommonLocation; + private MultiFileItem fileCommonLocation; @FXML private Label lblDisplay; @FXML @@ -85,7 +88,7 @@ public final class SettingsPage extends StackPane implements DecoratorPage { @FXML private ScrollPane scroll; @FXML - private MultiFileItem backgroundItem; + private MultiFileItem backgroundItem; @FXML private StackPane themeColorPickerContainer; @FXML @@ -179,7 +182,16 @@ public final class SettingsPage extends StackPane implements DecoratorPage { })); // ==== - fileCommonLocation.pathProperty().bindBidirectional(CONFIG.commonDirectoryProperty()); + fileCommonLocation.loadChildren(Arrays.asList( + fileCommonLocation.createChildren(i18n("launcher.common_directory.disabled"), EnumCommonDirectory.DISABLED), + fileCommonLocation.createChildren(i18n("launcher.common_directory.default"), EnumCommonDirectory.DEFAULT) + ), EnumCommonDirectory.CUSTOM); + fileCommonLocation.selectedDataProperty().bindBidirectional(CONFIG.commonDirTypeProperty()); + fileCommonLocation.customTextProperty().bindBidirectional(CONFIG.commonDirectoryProperty()); + fileCommonLocation.subtitleProperty().bind( + Bindings.createObjectBinding(() -> Optional.ofNullable(Settings.INSTANCE.getCommonDirectory()) + .orElse(i18n("launcher.common_directory.disabled")), + CONFIG.commonDirectoryProperty(), CONFIG.commonDirTypeProperty())); FXUtils.installTooltip(btnUpdate, i18n("update.tooltip")); checkUpdate(); @@ -187,28 +199,11 @@ public final class SettingsPage extends StackPane implements DecoratorPage { // background backgroundItem.loadChildren(Collections.singletonList( backgroundItem.createChildren(i18n("launcher.background.default"), EnumBackgroundImage.DEFAULT) - )); - backgroundItem.setCustomUserData(EnumBackgroundImage.CUSTOM); - backgroundItem.getTxtCustom().textProperty().bindBidirectional(CONFIG.backgroundImageProperty()); - - ObjectProperty backgroundType = new SimpleObjectProperty(EnumBackgroundImage.DEFAULT) { - { - invalidated(); - } - - @Override - protected void invalidated() { - backgroundItem.getGroup().getToggles().stream() - .filter(it -> it.getUserData() == get()) - .findFirst() - .ifPresent(it -> it.setSelected(true)); - } - }; - backgroundItem.getGroup().selectedToggleProperty().addListener((observable, oldValue, newValue) -> backgroundType.set((EnumBackgroundImage) newValue.getUserData())); - backgroundType.bindBidirectional(CONFIG.backgroundImageTypeProperty()); - + ), EnumBackgroundImage.CUSTOM); + backgroundItem.customTextProperty().bindBidirectional(CONFIG.backgroundImageProperty()); + backgroundItem.selectedDataProperty().bindBidirectional(CONFIG.backgroundImageTypeProperty()); backgroundItem.subtitleProperty().bind( - new When(backgroundType.isEqualTo(EnumBackgroundImage.DEFAULT)) + new When(backgroundItem.selectedDataProperty().isEqualTo(EnumBackgroundImage.DEFAULT)) .then(i18n("launcher.background.default")) .otherwise(CONFIG.backgroundImageProperty())); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/VersionSettingsController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/VersionSettingsController.java index d17d04419..aea799b94 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/VersionSettingsController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/VersionSettingsController.java @@ -44,6 +44,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import java.io.File; import java.io.IOException; +import java.nio.file.Paths; import java.util.Arrays; import java.util.List; import java.util.logging.Level; @@ -71,7 +72,6 @@ public final class VersionSettingsController { @FXML private JFXCheckBox chkFullscreen; @FXML private Label lblPhysicalMemory; @FXML private JFXToggleButton chkNoJVMArgs; - @FXML private JFXToggleButton chkNoCommon; @FXML private JFXToggleButton chkNoGameCheck; @FXML private MultiFileItem globalItem; @FXML private MultiFileItem javaItem; @@ -136,7 +136,6 @@ public final class VersionSettingsController { FXUtils.unbindString(txtServerIP, lastVersionSetting.serverIpProperty()); FXUtils.unbindBoolean(chkFullscreen, lastVersionSetting.fullscreenProperty()); FXUtils.unbindBoolean(chkNoGameCheck, lastVersionSetting.notCheckGameProperty()); - FXUtils.unbindBoolean(chkNoCommon, lastVersionSetting.noCommonProperty()); FXUtils.unbindBoolean(chkNoJVMArgs, lastVersionSetting.noJVMArgsProperty()); FXUtils.unbindBoolean(chkShowLogs, lastVersionSetting.showLogsProperty()); FXUtils.unbindEnum(cboLauncherVisibility); @@ -165,7 +164,6 @@ public final class VersionSettingsController { FXUtils.bindString(txtServerIP, versionSetting.serverIpProperty()); FXUtils.bindBoolean(chkFullscreen, versionSetting.fullscreenProperty()); FXUtils.bindBoolean(chkNoGameCheck, versionSetting.notCheckGameProperty()); - FXUtils.bindBoolean(chkNoCommon, versionSetting.noCommonProperty()); FXUtils.bindBoolean(chkNoJVMArgs, versionSetting.noJVMArgsProperty()); FXUtils.bindBoolean(chkShowLogs, versionSetting.showLogsProperty()); FXUtils.bindEnum(cboLauncherVisibility, versionSetting.launcherVisibilityProperty()); @@ -198,7 +196,7 @@ public final class VersionSettingsController { }); gameDirItem.selectedDataProperty().bindBidirectional(versionSetting.gameDirTypeProperty()); - gameDirItem.subtitleProperty().bind(Bindings.createStringBinding(() -> profile.getRepository().getRunDirectory(versionId).getAbsolutePath(), + gameDirItem.subtitleProperty().bind(Bindings.createStringBinding(() -> Paths.get(profile.getRepository().getRunDirectory(versionId).getAbsolutePath()).normalize().toString(), versionSetting.gameDirProperty(), versionSetting.gameDirTypeProperty())); lastVersionSetting = versionSetting; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java index 759bf153b..8bcdf8d80 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java @@ -161,6 +161,11 @@ public class MultiFileItem extends ComponentList { pane.getChildren().add(custom); } + public void loadChildren(Collection list, T customUserData) { + loadChildren(list); + setCustomUserData(customUserData); + } + public ToggleGroup getGroup() { return group; } diff --git a/HMCL/src/main/resources/assets/fxml/setting.fxml b/HMCL/src/main/resources/assets/fxml/setting.fxml index 8b069368f..68c87574b 100644 --- a/HMCL/src/main/resources/assets/fxml/setting.fxml +++ b/HMCL/src/main/resources/assets/fxml/setting.fxml @@ -31,7 +31,7 @@ - + diff --git a/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml b/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml index 7edc20457..8529695fb 100644 --- a/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml +++ b/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml @@ -139,14 +139,6 @@ - - - - - - -