feat: new memory settings
This commit is contained in:
@@ -296,7 +296,11 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
|||||||
.setProfileName(Metadata.TITLE)
|
.setProfileName(Metadata.TITLE)
|
||||||
.setGameArguments(StringUtils.tokenize(vs.getMinecraftArgs()))
|
.setGameArguments(StringUtils.tokenize(vs.getMinecraftArgs()))
|
||||||
.setJavaArguments(StringUtils.tokenize(vs.getJavaArgs()))
|
.setJavaArguments(StringUtils.tokenize(vs.getJavaArgs()))
|
||||||
.setMaxMemory(vs.getMaxMemory())
|
.setMaxMemory((int)(getAllocatedMemory(
|
||||||
|
vs.getMaxMemory(),
|
||||||
|
OperatingSystem.getPhysicalMemoryStatus().orElse(OperatingSystem.PhysicalMemoryStatus.INVALID).getAvailable(),
|
||||||
|
vs.isAutoMemory()
|
||||||
|
) / 1024 / 1024))
|
||||||
.setMinMemory(vs.getMinMemory())
|
.setMinMemory(vs.getMinMemory())
|
||||||
.setMetaspace(Lang.toIntOrNull(vs.getPermSize()))
|
.setMetaspace(Lang.toIntOrNull(vs.getPermSize()))
|
||||||
.setWidth(vs.getWidth())
|
.setWidth(vs.getWidth())
|
||||||
@@ -400,4 +404,8 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
|||||||
return versions.containsKey(id);
|
return versions.containsKey(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long getAllocatedMemory(long minimum, long available, boolean auto) {
|
||||||
|
return auto ? Math.max(minimum, (long) (available * 0.8)) : minimum;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -237,6 +237,20 @@ public final class VersionSetting implements Cloneable {
|
|||||||
minMemoryProperty.set(minMemory);
|
minMemoryProperty.set(minMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final BooleanProperty autoMemory = new SimpleBooleanProperty(this, "autoMemory", true);
|
||||||
|
|
||||||
|
public boolean isAutoMemory() {
|
||||||
|
return autoMemory.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanProperty autoMemoryProperty() {
|
||||||
|
return autoMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoMemory(boolean autoMemory) {
|
||||||
|
this.autoMemory.set(autoMemory);
|
||||||
|
}
|
||||||
|
|
||||||
private final StringProperty preLaunchCommandProperty = new SimpleStringProperty(this, "precalledCommand", "");
|
private final StringProperty preLaunchCommandProperty = new SimpleStringProperty(this, "precalledCommand", "");
|
||||||
|
|
||||||
public StringProperty preLaunchCommandProperty() {
|
public StringProperty preLaunchCommandProperty() {
|
||||||
@@ -558,6 +572,7 @@ public final class VersionSetting implements Cloneable {
|
|||||||
permSizeProperty.addListener(listener);
|
permSizeProperty.addListener(listener);
|
||||||
maxMemoryProperty.addListener(listener);
|
maxMemoryProperty.addListener(listener);
|
||||||
minMemoryProperty.addListener(listener);
|
minMemoryProperty.addListener(listener);
|
||||||
|
autoMemory.addListener(listener);
|
||||||
preLaunchCommandProperty.addListener(listener);
|
preLaunchCommandProperty.addListener(listener);
|
||||||
javaArgsProperty.addListener(listener);
|
javaArgsProperty.addListener(listener);
|
||||||
minecraftArgsProperty.addListener(listener);
|
minecraftArgsProperty.addListener(listener);
|
||||||
@@ -589,6 +604,7 @@ public final class VersionSetting implements Cloneable {
|
|||||||
versionSetting.setPermSize(getPermSize());
|
versionSetting.setPermSize(getPermSize());
|
||||||
versionSetting.setMaxMemory(getMaxMemory());
|
versionSetting.setMaxMemory(getMaxMemory());
|
||||||
versionSetting.setMinMemory(getMinMemory());
|
versionSetting.setMinMemory(getMinMemory());
|
||||||
|
versionSetting.setAutoMemory(isAutoMemory());
|
||||||
versionSetting.setPreLaunchCommand(getPreLaunchCommand());
|
versionSetting.setPreLaunchCommand(getPreLaunchCommand());
|
||||||
versionSetting.setJavaArgs(getJavaArgs());
|
versionSetting.setJavaArgs(getJavaArgs());
|
||||||
versionSetting.setMinecraftArgs(getMinecraftArgs());
|
versionSetting.setMinecraftArgs(getMinecraftArgs());
|
||||||
@@ -619,6 +635,7 @@ public final class VersionSetting implements Cloneable {
|
|||||||
obj.addProperty("minecraftArgs", src.getMinecraftArgs());
|
obj.addProperty("minecraftArgs", src.getMinecraftArgs());
|
||||||
obj.addProperty("maxMemory", src.getMaxMemory() <= 0 ? OperatingSystem.SUGGESTED_MEMORY : src.getMaxMemory());
|
obj.addProperty("maxMemory", src.getMaxMemory() <= 0 ? OperatingSystem.SUGGESTED_MEMORY : src.getMaxMemory());
|
||||||
obj.addProperty("minMemory", src.getMinMemory());
|
obj.addProperty("minMemory", src.getMinMemory());
|
||||||
|
obj.addProperty("autoMemory", src.isAutoMemory());
|
||||||
obj.addProperty("permSize", src.getPermSize());
|
obj.addProperty("permSize", src.getPermSize());
|
||||||
obj.addProperty("width", src.getWidth());
|
obj.addProperty("width", src.getWidth());
|
||||||
obj.addProperty("height", src.getHeight());
|
obj.addProperty("height", src.getHeight());
|
||||||
@@ -659,6 +676,7 @@ public final class VersionSetting implements Cloneable {
|
|||||||
vs.setMinecraftArgs(Optional.ofNullable(obj.get("minecraftArgs")).map(JsonElement::getAsString).orElse(""));
|
vs.setMinecraftArgs(Optional.ofNullable(obj.get("minecraftArgs")).map(JsonElement::getAsString).orElse(""));
|
||||||
vs.setMaxMemory(maxMemoryN);
|
vs.setMaxMemory(maxMemoryN);
|
||||||
vs.setMinMemory(Optional.ofNullable(obj.get("minMemory")).map(JsonElement::getAsInt).orElse(null));
|
vs.setMinMemory(Optional.ofNullable(obj.get("minMemory")).map(JsonElement::getAsInt).orElse(null));
|
||||||
|
vs.setAutoMemory(Optional.ofNullable(obj.get("autoMemory")).map(JsonElement::getAsBoolean).orElse(true));
|
||||||
vs.setPermSize(Optional.ofNullable(obj.get("permSize")).map(JsonElement::getAsString).orElse(""));
|
vs.setPermSize(Optional.ofNullable(obj.get("permSize")).map(JsonElement::getAsString).orElse(""));
|
||||||
vs.setWidth(Optional.ofNullable(obj.get("width")).map(JsonElement::getAsJsonPrimitive).map(this::parseJsonPrimitive).orElse(0));
|
vs.setWidth(Optional.ofNullable(obj.get("width")).map(JsonElement::getAsJsonPrimitive).map(this::parseJsonPrimitive).orElse(0));
|
||||||
vs.setHeight(Optional.ofNullable(obj.get("height")).map(JsonElement::getAsJsonPrimitive).map(this::parseJsonPrimitive).orElse(0));
|
vs.setHeight(Optional.ofNullable(obj.get("height")).map(JsonElement::getAsJsonPrimitive).map(this::parseJsonPrimitive).orElse(0));
|
||||||
|
|||||||
@@ -21,20 +21,17 @@ import com.jfoenix.controls.*;
|
|||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.InvalidationListener;
|
import javafx.beans.InvalidationListener;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
import javafx.beans.property.*;
|
||||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.*;
|
||||||
import javafx.scene.layout.HBox;
|
|
||||||
import javafx.scene.layout.StackPane;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jackhuang.hmcl.game.GameDirectoryType;
|
import org.jackhuang.hmcl.game.GameDirectoryType;
|
||||||
|
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
||||||
import org.jackhuang.hmcl.game.NativesDirectoryType;
|
import org.jackhuang.hmcl.game.NativesDirectoryType;
|
||||||
import org.jackhuang.hmcl.game.ProcessPriority;
|
import org.jackhuang.hmcl.game.ProcessPriority;
|
||||||
import org.jackhuang.hmcl.setting.LauncherVisibility;
|
import org.jackhuang.hmcl.setting.LauncherVisibility;
|
||||||
@@ -47,8 +44,10 @@ import org.jackhuang.hmcl.ui.Controllers;
|
|||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.construct.*;
|
import org.jackhuang.hmcl.ui.construct.*;
|
||||||
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
||||||
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
import org.jackhuang.hmcl.util.Logging;
|
import org.jackhuang.hmcl.util.Logging;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
|
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
|
||||||
import org.jackhuang.hmcl.util.platform.JavaVersion;
|
import org.jackhuang.hmcl.util.platform.JavaVersion;
|
||||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||||
|
|
||||||
@@ -58,6 +57,7 @@ import java.nio.file.Path;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -76,7 +76,6 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
|||||||
private final VBox rootPane;
|
private final VBox rootPane;
|
||||||
private final JFXTextField txtWidth;
|
private final JFXTextField txtWidth;
|
||||||
private final JFXTextField txtHeight;
|
private final JFXTextField txtHeight;
|
||||||
private final JFXTextField txtMaxMemory;
|
|
||||||
private final JFXTextField txtJVMArgs;
|
private final JFXTextField txtJVMArgs;
|
||||||
private final JFXTextField txtGameArgs;
|
private final JFXTextField txtGameArgs;
|
||||||
private final JFXTextField txtMetaspace;
|
private final JFXTextField txtMetaspace;
|
||||||
@@ -87,8 +86,8 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
|||||||
private final ComponentList componentList;
|
private final ComponentList componentList;
|
||||||
private final ComponentList iconPickerItemWrapper;
|
private final ComponentList iconPickerItemWrapper;
|
||||||
private final JFXComboBox<LauncherVisibility> cboLauncherVisibility;
|
private final JFXComboBox<LauncherVisibility> cboLauncherVisibility;
|
||||||
|
private final JFXCheckBox chkAutoAllocate;
|
||||||
private final JFXCheckBox chkFullscreen;
|
private final JFXCheckBox chkFullscreen;
|
||||||
private final Label lblPhysicalMemory;
|
|
||||||
private final JFXToggleButton chkNoJVMArgs;
|
private final JFXToggleButton chkNoJVMArgs;
|
||||||
private final JFXToggleButton chkNoGameCheck;
|
private final JFXToggleButton chkNoGameCheck;
|
||||||
private final JFXToggleButton chkNoJVMCheck;
|
private final JFXToggleButton chkNoJVMCheck;
|
||||||
@@ -105,6 +104,10 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
|||||||
|
|
||||||
private final InvalidationListener javaListener = any -> initJavaSubtitle();
|
private final InvalidationListener javaListener = any -> initJavaSubtitle();
|
||||||
|
|
||||||
|
private boolean uiVisible = false;
|
||||||
|
private final IntegerProperty maxMemoryProperty = new SimpleIntegerProperty();
|
||||||
|
private final ObjectProperty<OperatingSystem.PhysicalMemoryStatus> memoryStatusProperty = new SimpleObjectProperty<>(OperatingSystem.PhysicalMemoryStatus.INVALID);
|
||||||
|
|
||||||
public VersionSettingsPage() {
|
public VersionSettingsPage() {
|
||||||
ScrollPane scrollPane = new ScrollPane();
|
ScrollPane scrollPane = new ScrollPane();
|
||||||
scrollPane.setFitToHeight(true);
|
scrollPane.setFitToHeight(true);
|
||||||
@@ -163,21 +166,120 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
|||||||
gameDirItem.setCustomText(i18n("settings.custom"));
|
gameDirItem.setCustomText(i18n("settings.custom"));
|
||||||
gameDirItem.setDirectory(true);
|
gameDirItem.setDirectory(true);
|
||||||
|
|
||||||
BorderPane maxMemoryPane = new BorderPane();
|
VBox maxMemoryPane = new VBox(8);
|
||||||
{
|
{
|
||||||
VBox vbox = new VBox();
|
Label title = new Label(i18n("settings.memory"));
|
||||||
maxMemoryPane.setLeft(vbox);
|
VBox.setMargin(title, new Insets(0, 0, 8, 0));
|
||||||
Label maxMemoryLabel = new Label(i18n("settings.max_memory"));
|
|
||||||
lblPhysicalMemory = new Label();
|
|
||||||
lblPhysicalMemory.getStyleClass().add("subtitle-label");
|
|
||||||
vbox.getChildren().setAll(maxMemoryLabel, lblPhysicalMemory);
|
|
||||||
|
|
||||||
txtMaxMemory = new JFXTextField();
|
chkAutoAllocate = new JFXCheckBox(i18n("settings.memory.auto_allocate"));
|
||||||
maxMemoryPane.setRight(txtMaxMemory);
|
VBox.setMargin(chkAutoAllocate, new Insets(0, 0, 8, 5));
|
||||||
BorderPane.setAlignment(txtMaxMemory, Pos.CENTER_RIGHT);
|
|
||||||
FXUtils.setValidateWhileTextChanged(txtMaxMemory, true);
|
HBox lowerBoundPane = new HBox();
|
||||||
FXUtils.setLimitWidth(txtMaxMemory, 300);
|
lowerBoundPane.setAlignment(Pos.CENTER);
|
||||||
txtMaxMemory.setValidators(new NumberValidator(i18n("input.number"), false));
|
VBox.setMargin(lowerBoundPane, new Insets(8, 0, 0, 16));
|
||||||
|
{
|
||||||
|
Label label = new Label();
|
||||||
|
label.textProperty().bind(Bindings.createStringBinding(() -> {
|
||||||
|
if (chkAutoAllocate.isSelected()) {
|
||||||
|
return i18n("settings.memory.lower_bound");
|
||||||
|
} else {
|
||||||
|
return i18n("settings.memory");
|
||||||
|
}
|
||||||
|
}, chkAutoAllocate.selectedProperty()));
|
||||||
|
|
||||||
|
JFXSlider slider = new JFXSlider(0, 1, 0);
|
||||||
|
HBox.setMargin(slider, new Insets(0, 16, 0, 16));
|
||||||
|
HBox.setHgrow(slider, Priority.ALWAYS);
|
||||||
|
slider.setValueFactory(self -> Bindings.createStringBinding(() -> (int)(self.getValue() * 100) + "%", self.valueProperty()));
|
||||||
|
AtomicBoolean changedByTextField = new AtomicBoolean(false);
|
||||||
|
FXUtils.onChangeAndOperate(maxMemoryProperty, maxMemory -> {
|
||||||
|
changedByTextField.set(true);
|
||||||
|
slider.setValue(maxMemory.intValue() * 1.0 / OperatingSystem.TOTAL_MEMORY);
|
||||||
|
changedByTextField.set(false);
|
||||||
|
});
|
||||||
|
slider.valueProperty().addListener((value, oldVal, newVal) -> {
|
||||||
|
if (changedByTextField.get()) return;
|
||||||
|
maxMemoryProperty.set((int)(value.getValue().doubleValue() * OperatingSystem.TOTAL_MEMORY));
|
||||||
|
});
|
||||||
|
|
||||||
|
JFXTextField txtMaxMemory = new JFXTextField();
|
||||||
|
FXUtils.setLimitWidth(txtMaxMemory, 60);
|
||||||
|
FXUtils.setValidateWhileTextChanged(txtMaxMemory, true);
|
||||||
|
txtMaxMemory.textProperty().bindBidirectional(maxMemoryProperty, SafeStringConverter.fromInteger());
|
||||||
|
txtMaxMemory.setValidators(new NumberValidator(i18n("input.number"), false));
|
||||||
|
|
||||||
|
lowerBoundPane.getChildren().setAll(label, slider, txtMaxMemory, new Label("MB"));
|
||||||
|
}
|
||||||
|
|
||||||
|
BorderPane titlePane = new BorderPane();
|
||||||
|
VBox.setMargin(titlePane, new Insets(0, 0, 0, 16));
|
||||||
|
{
|
||||||
|
Label left = new Label(i18n("settings.memory.used_per_total"));
|
||||||
|
left.getStyleClass().add("subtitle-label");
|
||||||
|
titlePane.setLeft(left);
|
||||||
|
|
||||||
|
Label right = new Label();
|
||||||
|
right.textProperty().bind(Bindings.createStringBinding(() -> {
|
||||||
|
if (chkAutoAllocate.isSelected()) {
|
||||||
|
return i18n("settings.memory.allocate.auto");
|
||||||
|
} else {
|
||||||
|
return i18n("settings.memory.allocate.manual");
|
||||||
|
}
|
||||||
|
}, chkAutoAllocate.selectedProperty()));
|
||||||
|
right.getStyleClass().add("subtitle-label");
|
||||||
|
titlePane.setRight(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
StackPane progressBarPane = new StackPane();
|
||||||
|
progressBarPane.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
VBox.setMargin(progressBarPane, new Insets(0, 0, 0, 16));
|
||||||
|
{
|
||||||
|
progressBarPane.setMinHeight(4);
|
||||||
|
progressBarPane.getStyleClass().add("memory-total");
|
||||||
|
|
||||||
|
StackPane usedMemory = new StackPane();
|
||||||
|
usedMemory.getStyleClass().add("memory-used");
|
||||||
|
usedMemory.maxWidthProperty().bind(Bindings.createDoubleBinding(() ->
|
||||||
|
progressBarPane.getWidth() *
|
||||||
|
(memoryStatusProperty.get().getUsed() * 1.0 / memoryStatusProperty.get().getTotal()), progressBarPane.widthProperty(),
|
||||||
|
memoryStatusProperty));
|
||||||
|
StackPane allocateMemory = new StackPane();
|
||||||
|
allocateMemory.getStyleClass().add("memory-allocate");
|
||||||
|
allocateMemory.maxWidthProperty().bind(Bindings.createDoubleBinding(() ->
|
||||||
|
progressBarPane.getWidth() *
|
||||||
|
Math.min(1.0,
|
||||||
|
(double)(HMCLGameRepository.getAllocatedMemory(maxMemoryProperty.get() * 1024L * 1024L, memoryStatusProperty.get().getAvailable(), chkAutoAllocate.isSelected())
|
||||||
|
+ memoryStatusProperty.get().getUsed()) / memoryStatusProperty.get().getTotal()), progressBarPane.widthProperty(),
|
||||||
|
maxMemoryProperty, memoryStatusProperty, chkAutoAllocate.selectedProperty()));
|
||||||
|
|
||||||
|
progressBarPane.getChildren().setAll(allocateMemory, usedMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
BorderPane digitalPane = new BorderPane();
|
||||||
|
VBox.setMargin(digitalPane, new Insets(0, 0, 0, 16));
|
||||||
|
{
|
||||||
|
Label lblPhysicalMemory = new Label();
|
||||||
|
lblPhysicalMemory.getStyleClass().add("memory-label");
|
||||||
|
digitalPane.setLeft(lblPhysicalMemory);
|
||||||
|
lblPhysicalMemory.textProperty().bind(Bindings.createStringBinding(() -> {
|
||||||
|
return i18n("settings.memory.used_per_total.format", memoryStatusProperty.get().getUsedGB(), memoryStatusProperty.get().getTotalGB());
|
||||||
|
}, memoryStatusProperty));
|
||||||
|
|
||||||
|
Label lblAllocateMemory = new Label();
|
||||||
|
lblAllocateMemory.textProperty().bind(Bindings.createStringBinding(() -> {
|
||||||
|
long maxMemory = Lang.parseInt(maxMemoryProperty.get(), 0) * 1024L * 1024L;
|
||||||
|
return i18n(memoryStatusProperty.get().hasAvailable() && maxMemory > memoryStatusProperty.get().getAvailable()
|
||||||
|
? (chkAutoAllocate.isSelected() ? "settings.memory.allocate.format.auto.exceeded" : "settings.memory.allocate.format.manual.exceeded")
|
||||||
|
: (chkAutoAllocate.isSelected() ? "settings.memory.allocate.format.auto" : "settings.memory.allocate.format.manual"),
|
||||||
|
OperatingSystem.PhysicalMemoryStatus.toGigaBytes(maxMemory),
|
||||||
|
OperatingSystem.PhysicalMemoryStatus.toGigaBytes(HMCLGameRepository.getAllocatedMemory(maxMemory, memoryStatusProperty.get().getAvailable(), chkAutoAllocate.isSelected())),
|
||||||
|
OperatingSystem.PhysicalMemoryStatus.toGigaBytes(memoryStatusProperty.get().getAvailable()));
|
||||||
|
}, memoryStatusProperty, maxMemoryProperty, chkAutoAllocate.selectedProperty()));
|
||||||
|
lblAllocateMemory.getStyleClass().add("memory-label");
|
||||||
|
digitalPane.setRight(lblAllocateMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
maxMemoryPane.getChildren().setAll(title, chkAutoAllocate, lowerBoundPane, titlePane, progressBarPane, digitalPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
BorderPane launcherVisibilityPane = new BorderPane();
|
BorderPane launcherVisibilityPane = new BorderPane();
|
||||||
@@ -368,7 +470,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
lblPhysicalMemory.setText(i18n("settings.physical_memory") + ": " + OperatingSystem.TOTAL_MEMORY + "MB");
|
memoryStatusProperty.set(OperatingSystem.getPhysicalMemoryStatus().orElse(OperatingSystem.PhysicalMemoryStatus.INVALID));
|
||||||
|
|
||||||
Task.supplyAsync(JavaVersion::getJavas).thenAcceptAsync(Schedulers.javafx(), list -> {
|
Task.supplyAsync(JavaVersion::getJavas).thenAcceptAsync(Schedulers.javafx(), list -> {
|
||||||
javaItem.loadChildren(list.stream()
|
javaItem.loadChildren(list.stream()
|
||||||
@@ -434,7 +536,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
|||||||
if (lastVersionSetting != null) {
|
if (lastVersionSetting != null) {
|
||||||
FXUtils.unbindInt(txtWidth, lastVersionSetting.widthProperty());
|
FXUtils.unbindInt(txtWidth, lastVersionSetting.widthProperty());
|
||||||
FXUtils.unbindInt(txtHeight, lastVersionSetting.heightProperty());
|
FXUtils.unbindInt(txtHeight, lastVersionSetting.heightProperty());
|
||||||
FXUtils.unbindInt(txtMaxMemory, lastVersionSetting.maxMemoryProperty());
|
maxMemoryProperty.unbindBidirectional(lastVersionSetting.maxMemoryProperty());
|
||||||
FXUtils.unbindString(javaItem.getTxtCustom(), lastVersionSetting.javaDirProperty());
|
FXUtils.unbindString(javaItem.getTxtCustom(), lastVersionSetting.javaDirProperty());
|
||||||
FXUtils.unbindString(gameDirItem.getTxtCustom(), lastVersionSetting.gameDirProperty());
|
FXUtils.unbindString(gameDirItem.getTxtCustom(), lastVersionSetting.gameDirProperty());
|
||||||
FXUtils.unbindString(nativesDirItem.getTxtCustom(), lastVersionSetting.nativesDirProperty());
|
FXUtils.unbindString(nativesDirItem.getTxtCustom(), lastVersionSetting.nativesDirProperty());
|
||||||
@@ -444,6 +546,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
|||||||
FXUtils.unbindString(txtWrapper, lastVersionSetting.wrapperProperty());
|
FXUtils.unbindString(txtWrapper, lastVersionSetting.wrapperProperty());
|
||||||
FXUtils.unbindString(txtPrecallingCommand, lastVersionSetting.preLaunchCommandProperty());
|
FXUtils.unbindString(txtPrecallingCommand, lastVersionSetting.preLaunchCommandProperty());
|
||||||
FXUtils.unbindString(txtServerIP, lastVersionSetting.serverIpProperty());
|
FXUtils.unbindString(txtServerIP, lastVersionSetting.serverIpProperty());
|
||||||
|
FXUtils.unbindBoolean(chkAutoAllocate, lastVersionSetting.autoMemoryProperty());
|
||||||
FXUtils.unbindBoolean(chkFullscreen, lastVersionSetting.fullscreenProperty());
|
FXUtils.unbindBoolean(chkFullscreen, lastVersionSetting.fullscreenProperty());
|
||||||
FXUtils.unbindBoolean(chkNoGameCheck, lastVersionSetting.notCheckGameProperty());
|
FXUtils.unbindBoolean(chkNoGameCheck, lastVersionSetting.notCheckGameProperty());
|
||||||
FXUtils.unbindBoolean(chkNoJVMCheck, lastVersionSetting.notCheckJVMProperty());
|
FXUtils.unbindBoolean(chkNoJVMCheck, lastVersionSetting.notCheckJVMProperty());
|
||||||
@@ -469,7 +572,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
|||||||
// bind new data fields
|
// bind new data fields
|
||||||
FXUtils.bindInt(txtWidth, versionSetting.widthProperty());
|
FXUtils.bindInt(txtWidth, versionSetting.widthProperty());
|
||||||
FXUtils.bindInt(txtHeight, versionSetting.heightProperty());
|
FXUtils.bindInt(txtHeight, versionSetting.heightProperty());
|
||||||
FXUtils.bindInt(txtMaxMemory, versionSetting.maxMemoryProperty());
|
maxMemoryProperty.bindBidirectional(versionSetting.maxMemoryProperty());
|
||||||
FXUtils.bindString(javaItem.getTxtCustom(), versionSetting.javaDirProperty());
|
FXUtils.bindString(javaItem.getTxtCustom(), versionSetting.javaDirProperty());
|
||||||
FXUtils.bindString(gameDirItem.getTxtCustom(), versionSetting.gameDirProperty());
|
FXUtils.bindString(gameDirItem.getTxtCustom(), versionSetting.gameDirProperty());
|
||||||
FXUtils.bindString(nativesDirItem.getTxtCustom(), versionSetting.nativesDirProperty());
|
FXUtils.bindString(nativesDirItem.getTxtCustom(), versionSetting.nativesDirProperty());
|
||||||
@@ -479,6 +582,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
|||||||
FXUtils.bindString(txtWrapper, versionSetting.wrapperProperty());
|
FXUtils.bindString(txtWrapper, versionSetting.wrapperProperty());
|
||||||
FXUtils.bindString(txtPrecallingCommand, versionSetting.preLaunchCommandProperty());
|
FXUtils.bindString(txtPrecallingCommand, versionSetting.preLaunchCommandProperty());
|
||||||
FXUtils.bindString(txtServerIP, versionSetting.serverIpProperty());
|
FXUtils.bindString(txtServerIP, versionSetting.serverIpProperty());
|
||||||
|
FXUtils.bindBoolean(chkAutoAllocate, versionSetting.autoMemoryProperty());
|
||||||
FXUtils.bindBoolean(chkFullscreen, versionSetting.fullscreenProperty());
|
FXUtils.bindBoolean(chkFullscreen, versionSetting.fullscreenProperty());
|
||||||
FXUtils.bindBoolean(chkNoGameCheck, versionSetting.notCheckGameProperty());
|
FXUtils.bindBoolean(chkNoGameCheck, versionSetting.notCheckGameProperty());
|
||||||
FXUtils.bindBoolean(chkNoJVMCheck, versionSetting.notCheckJVMProperty());
|
FXUtils.bindBoolean(chkNoJVMCheck, versionSetting.notCheckJVMProperty());
|
||||||
|
|||||||
@@ -42,6 +42,22 @@
|
|||||||
-fx-text-fill: rgba(0, 0, 0, 0.5);
|
-fx-text-fill: rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.memory-label {
|
||||||
|
-fx-font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memory-used {
|
||||||
|
-fx-background-color: -fx-base-darker-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memory-allocate {
|
||||||
|
-fx-background-color: -fx-base-check-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memory-total {
|
||||||
|
-fx-background-color: -fx-base-rippler-color;
|
||||||
|
}
|
||||||
|
|
||||||
.update-label {
|
.update-label {
|
||||||
-fx-text-fill: red;
|
-fx-text-fill: red;
|
||||||
}
|
}
|
||||||
@@ -530,23 +546,12 @@
|
|||||||
* *
|
* *
|
||||||
*******************************************************/
|
*******************************************************/
|
||||||
|
|
||||||
.jfx-slider-style {
|
.jfx-slider {
|
||||||
-jfx-indicator-position: right;
|
-jfx-indicator-position: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jfx-slider-style > .thumb {
|
.jfx-slider .thumb {
|
||||||
-fx-background-color: #03a9f4;
|
-fx-background-color: -fx-base-color;
|
||||||
}
|
|
||||||
|
|
||||||
.jfx-slider-style .track {
|
|
||||||
-fx-background-color: #ff5252;
|
|
||||||
-fx-pref-height: 5px;
|
|
||||||
-fx-pref-width: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.jfx-slider-style .sliderValue {
|
|
||||||
-fx-stroke: WHITE;
|
|
||||||
-fx-font-size: 10.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|||||||
@@ -520,8 +520,17 @@ settings.launcher.proxy.socks=Socks
|
|||||||
settings.launcher.proxy.username=账户
|
settings.launcher.proxy.username=账户
|
||||||
settings.launcher.theme=主题
|
settings.launcher.theme=主题
|
||||||
|
|
||||||
settings.min_memory=最小内存(MB)
|
settings.memory=游戏内存
|
||||||
settings.max_memory=最大内存(MB)
|
settings.memory.allocate.auto=最低分配 / 实际分配
|
||||||
|
settings.memory.allocate.manual=游戏分配
|
||||||
|
settings.memory.allocate.format.auto=%1$.1f GB / %2$.1f GB
|
||||||
|
settings.memory.allocate.format.auto.exceeded=%1$.1f GB / %2$.1f GB (可用 %3$.1f GB)
|
||||||
|
settings.memory.allocate.format.manual=%1$.1f GB
|
||||||
|
settings.memory.allocate.format.manual.exceeded=%1$.1f GB (可用 %3$.1f GB)
|
||||||
|
settings.memory.auto_allocate=自动分配
|
||||||
|
settings.memory.lower_bound=最低分配
|
||||||
|
settings.memory.used_per_total=已使用 / 总内存
|
||||||
|
settings.memory.used_per_total.format=%1$.1f GB / %2$.1f GB
|
||||||
settings.physical_memory=物理内存大小
|
settings.physical_memory=物理内存大小
|
||||||
settings.show_log=查看日志
|
settings.show_log=查看日志
|
||||||
settings.tabs.installers=自动安装
|
settings.tabs.installers=自动安装
|
||||||
|
|||||||
@@ -17,12 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.util.platform;
|
package org.jackhuang.hmcl.util.platform;
|
||||||
|
|
||||||
import javax.management.JMException;
|
|
||||||
import javax.management.MBeanServer;
|
|
||||||
import javax.management.ObjectName;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.management.ManagementFactory;
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@@ -108,7 +103,8 @@ public enum OperatingSystem {
|
|||||||
else
|
else
|
||||||
CURRENT_OS = UNKNOWN;
|
CURRENT_OS = UNKNOWN;
|
||||||
|
|
||||||
TOTAL_MEMORY = getTotalPhysicalMemorySize()
|
TOTAL_MEMORY = getPhysicalMemoryStatus()
|
||||||
|
.map(PhysicalMemoryStatus::getTotal)
|
||||||
.map(bytes -> (int) (bytes / 1024 / 1024))
|
.map(bytes -> (int) (bytes / 1024 / 1024))
|
||||||
.orElse(1024);
|
.orElse(1024);
|
||||||
|
|
||||||
@@ -133,15 +129,22 @@ public enum OperatingSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Optional<Long> getTotalPhysicalMemorySize() {
|
public static Optional<PhysicalMemoryStatus> getPhysicalMemoryStatus() {
|
||||||
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
|
java.lang.management.OperatingSystemMXBean bean = java.lang.management.ManagementFactory.getOperatingSystemMXBean();
|
||||||
try {
|
if (bean instanceof com.sun.management.OperatingSystemMXBean) {
|
||||||
Object attribute = mBeanServer.getAttribute(new ObjectName("java.lang", "type", "OperatingSystem"), "TotalPhysicalMemorySize");
|
com.sun.management.OperatingSystemMXBean sunBean =
|
||||||
if (attribute instanceof Long) {
|
(com.sun.management.OperatingSystemMXBean)
|
||||||
return Optional.of((Long) attribute);
|
java.lang.management.ManagementFactory.getOperatingSystemMXBean();
|
||||||
|
|
||||||
|
if (CURRENT_OS == LINUX) {
|
||||||
|
// On Linux, real amount of memory that is free for using is "available" size of memory,
|
||||||
|
// which also includes size of memory for caching that can be make use of.
|
||||||
|
// But available size of memory cannot be obtained by OperatingSystemMXBean interface.
|
||||||
|
// So we simply disable reporting free physical memory size on Linux.
|
||||||
|
return Optional.of(new PhysicalMemoryStatus(sunBean.getTotalPhysicalMemorySize(), -1));
|
||||||
}
|
}
|
||||||
} catch (JMException e) {
|
|
||||||
return Optional.empty();
|
return Optional.of(new PhysicalMemoryStatus(sunBean.getTotalPhysicalMemorySize(), sunBean.getFreePhysicalMemorySize()));
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
@@ -203,4 +206,48 @@ public enum OperatingSystem {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class PhysicalMemoryStatus {
|
||||||
|
private final long total;
|
||||||
|
private final long available;
|
||||||
|
|
||||||
|
public PhysicalMemoryStatus(long total, long available) {
|
||||||
|
this.total = total;
|
||||||
|
this.available = available;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotal() {
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTotalGB() {
|
||||||
|
return toGigaBytes(total);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getUsed() {
|
||||||
|
return hasAvailable() ? total - available : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getUsedGB() {
|
||||||
|
return toGigaBytes(getUsed());
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getAvailable() {
|
||||||
|
return available;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getAvailableGB() {
|
||||||
|
return toGigaBytes(available);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAvailable() {
|
||||||
|
return available >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double toGigaBytes(long bytes) {
|
||||||
|
return bytes / 1024. / 1024. / 1024.;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final PhysicalMemoryStatus INVALID = new PhysicalMemoryStatus(0, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user