GTK: Memory Settings
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details

This commit is contained in:
Johannes Frohnmeyer 2023-01-29 12:39:46 +01:00
parent 5c9ce78ebf
commit eb9601d6cf
Signed by: Johannes
GPG Key ID: E76429612C2929F4
6 changed files with 156 additions and 24 deletions

View File

@ -5,8 +5,7 @@ import org.gtk.gtk.*;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.PropertyKey; import org.jetbrains.annotations.PropertyKey;
import java.util.function.Consumer; import java.util.function.*;
import java.util.function.IntConsumer;
public class IRow extends Box { public class IRow extends Box {
public IRow(@PropertyKey(resourceBundle = I18n.BUNDLE) String title, @PropertyKey(resourceBundle = I18n.BUNDLE) @Nullable String subtitle, Object... args) { public IRow(@PropertyKey(resourceBundle = I18n.BUNDLE) String title, @PropertyKey(resourceBundle = I18n.BUNDLE) @Nullable String subtitle, Object... args) {
@ -30,51 +29,58 @@ public class IRow extends Box {
append(head); append(head);
} }
public void setButton(@PropertyKey(resourceBundle = I18n.BUNDLE) String text, Button.Clicked action) { public Button setButton(@PropertyKey(resourceBundle = I18n.BUNDLE) String text, Button.Clicked action) {
firstChild.hexpand = true;
Button btn = Button.newWithLabel(I18n.get(text)); Button btn = Button.newWithLabel(I18n.get(text));
btn.valign = Align.CENTER; packSmallEnd(btn);
btn.halign = Align.END;
btn.onClicked(action); btn.onClicked(action);
append(btn); return btn;
} }
public DropDown setDropdown(String[] options, int defaultIndex, IntConsumer changed) { public DropDown setDropdown(String[] options, int defaultIndex, IntConsumer changed) {
firstChild.hexpand = true;
DropDown btn = new DropDown(new StringList(options), null); DropDown btn = new DropDown(new StringList(options), null);
btn.valign = Align.CENTER; packSmallEnd(btn);
btn.halign = Align.END;
btn.selected = defaultIndex; btn.selected = defaultIndex;
btn.onNotify("selected", pspec -> { btn.onNotify("selected", pspec -> {
changed.accept(btn.selected); changed.accept(btn.selected);
}); });
btn.expression = new PropertyExpression(StringObject.type, null, "string"); btn.expression = new PropertyExpression(StringObject.type, null, "string");
append(btn);
return btn; return btn;
} }
public Switch setCheckbox(boolean value, Consumer<Boolean> changed) { public Switch setSwitch(boolean value, Consumer<Boolean> changed) {
firstChild.hexpand = true;
Switch btn = new Switch(); Switch btn = new Switch();
btn.valign = Align.CENTER; packSmallEnd(btn);
btn.halign = Align.END;
btn.active = value; btn.active = value;
btn.onStateSet(state -> { btn.onStateSet(state -> {
changed.accept(state); changed.accept(state);
return false; return false;
}); });
append(btn);
return btn; return btn;
} }
public Entry setEntry(String value, Consumer<String> onChanged) { public SpinButton setSpinButton(double value, double min, double max, double step, DoubleConsumer changed) {
SpinButton btn = SpinButton.newWithRange(min, max, step);
packSmallEnd(btn);
btn.value = value;
btn.onValueChanged(() -> changed.accept(btn.value));
return btn;
}
public Entry setEntry(String value, Consumer<String> changed) {
Entry entry = new Entry(); Entry entry = new Entry();
entry.text = value == null ? "" : value; entry.text = value == null ? "" : value;
entry.hexpand = true; entry.hexpand = true;
entry.valign = Align.CENTER; entry.valign = Align.CENTER;
entry.halign = Align.FILL; entry.halign = Align.FILL;
entry.onChanged(() -> onChanged.accept(entry.text)); entry.onChanged(() -> changed.accept(entry.text));
append(entry); append(entry);
return entry; return entry;
} }
private void packSmallEnd(Widget widget) {
firstChild.hexpand = true;
widget.valign = Align.CENTER;
widget.halign = Align.END;
append(widget);
}
} }

View File

@ -0,0 +1,103 @@
package io.gitlab.jfronny.inceptum.gtk.util;
import io.gitlab.jfronny.commons.LazySupplier;
import io.gitlab.jfronny.commons.OSUtils;
import io.gitlab.jfronny.inceptum.common.Utils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
public class Memory {
public static final long KB = 1024;
public static final long MB = KB * 1024;
public static final long GB = MB * 1024;
private static final MI impl = switch (OSUtils.TYPE) {
case LINUX -> new LinuxMI();
case WINDOWS -> new WindowsMI();
case MAC_OS -> new MacOsMI();
};
private static final LazySupplier<Long> totalMemory = new LazySupplier<>(impl::getTotalMemory);
public static long getMaxMBForInstance() {
return Math.max(totalMemory.get() / MB - 1024, 1024);
}
private interface MI {
long getTotalMemory();
}
private static class LinuxMI implements MI {
@Override
public long getTotalMemory() {
try (Stream<String> stream = Files.lines(Path.of("/proc/meminfo"))) {
var memTotal = stream
.filter(s -> s.startsWith("MemTotal:"))
.map(s -> s.substring("MemTotal:".length()))
.map(String::trim)
.findFirst();
if (memTotal.isPresent()) {
return parseDecimalMemorySizeToBinary(memTotal.get());
} else {
Utils.LOGGER.error("Could not find total memory");
return 32 * GB;
}
} catch (IOException e) {
Utils.LOGGER.error("Could not get total memory", e);
return 32 * GB;
}
}
// Taken from oshi
private static final Pattern BYTES_PATTERN = Pattern.compile("(\\d+) ?([kKMGT]?B?).*");
private static final Pattern WHITESPACES = Pattern.compile("\\s+");
private static long parseDecimalMemorySizeToBinary(String size) {
String[] mem = WHITESPACES.split(size);
if (mem.length < 2) {
// If no spaces, use regexp
Matcher matcher = BYTES_PATTERN.matcher(size.trim());
if (matcher.find() && matcher.groupCount() == 2) {
mem = new String[2];
mem[0] = matcher.group(1);
mem[1] = matcher.group(2);
}
}
long capacity = parseLongOrDefault(mem[0], 0L);
if (mem.length == 2 && mem[1].length() > 1) {
switch (mem[1].charAt(0)) {
case 'T' -> capacity <<= 40;
case 'G' -> capacity <<= 30;
case 'M' -> capacity <<= 20;
case 'K', 'k' -> capacity <<= 10;
default -> {}
}
}
return capacity;
}
private static long parseLongOrDefault(String s, long defaultLong) {
try {
return Long.parseLong(s);
} catch (NumberFormatException e) {
return defaultLong;
}
}
}
private static class WindowsMI implements MI {
@Override
public long getTotalMemory() {
return 32 * GB; // This is currently unsupported, but any implementations by Windows user using panama are welcome
}
}
private static class MacOsMI implements MI {
@Override
public long getTotalMemory() {
return 32 * GB; // This is currently unsupported, but any implementations by MacOS user using panama are welcome
}
}
}

View File

@ -23,7 +23,7 @@ public class LauncherSettingsWindow extends Window {
{ {
IRow row = new IRow("settings.snapshots", "settings.snapshots.subtitle"); IRow row = new IRow("settings.snapshots", "settings.snapshots.subtitle");
listBox.append(row); listBox.append(row);
row.setCheckbox(InceptumConfig.snapshots, b -> { row.setSwitch(InceptumConfig.snapshots, b -> {
InceptumConfig.snapshots = b; InceptumConfig.snapshots = b;
InceptumConfig.saveConfig(); InceptumConfig.saveConfig();
}); });

View File

@ -2,11 +2,11 @@ package io.gitlab.jfronny.inceptum.gtk.window.edit;
import io.github.jwharm.javagi.GErrorException; import io.github.jwharm.javagi.GErrorException;
import io.gitlab.jfronny.commons.ArgumentsTokenizer; import io.gitlab.jfronny.commons.ArgumentsTokenizer;
import io.gitlab.jfronny.commons.OSUtils;
import io.gitlab.jfronny.commons.io.JFiles; import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.inceptum.common.*; import io.gitlab.jfronny.inceptum.common.*;
import io.gitlab.jfronny.inceptum.gtk.control.ILabel; import io.gitlab.jfronny.inceptum.gtk.control.ILabel;
import io.gitlab.jfronny.inceptum.gtk.util.I18n; import io.gitlab.jfronny.inceptum.gtk.util.I18n;
import io.gitlab.jfronny.inceptum.gtk.util.Memory;
import io.gitlab.jfronny.inceptum.gtk.window.InstanceSettingsWindow; import io.gitlab.jfronny.inceptum.gtk.window.InstanceSettingsWindow;
import io.gitlab.jfronny.inceptum.launcher.api.FabricMetaApi; import io.gitlab.jfronny.inceptum.launcher.api.FabricMetaApi;
import io.gitlab.jfronny.inceptum.launcher.api.McApi; import io.gitlab.jfronny.inceptum.launcher.api.McApi;
@ -78,7 +78,7 @@ public class GeneralTab extends SettingsTab {
var fabricRow = section.row("instance.settings.general.game.fabric.enabled", "instance.settings.general.game.fabric.enabled.subtitle"); var fabricRow = section.row("instance.settings.general.game.fabric.enabled", "instance.settings.general.game.fabric.enabled.subtitle");
var loaderRow = section.row("instance.settings.general.game.fabric.version", "instance.settings.general.game.fabric.version.subtitle"); var loaderRow = section.row("instance.settings.general.game.fabric.version", "instance.settings.general.game.fabric.version.subtitle");
loaderRow.visible = instance.isFabric; loaderRow.visible = instance.isFabric;
ref.fabricEnabled = fabricRow.setCheckbox(instance.isFabric, bl -> { ref.fabricEnabled = fabricRow.setSwitch(instance.isFabric, bl -> {
if (bl) { if (bl) {
if (ref.fabricVersions != null && ref.fabricVersions.length != 0 && ref.defaultFabric != null) { if (ref.fabricVersions != null && ref.fabricVersions.length != 0 && ref.defaultFabric != null) {
instance.meta.gameVersion = GameVersionParser.createVersionWithFabric(instance.gameVersion, ref.defaultFabric); instance.meta.gameVersion = GameVersionParser.createVersionWithFabric(instance.gameVersion, ref.defaultFabric);
@ -151,7 +151,22 @@ public class GeneralTab extends SettingsTab {
}); });
row.append(btn); row.append(btn);
} }
//TODO minMem/maxMem (slider?) {
var row = section.row("instance.settings.general.game.memory.min", "instance.settings.general.game.memory.min.subtitle");
row.setSpinButton(instance.meta.minMem == null ? 512 : instance.meta.minMem / Memory.MB, 512, Memory.maxMBForInstance, 128, v -> {
instance.meta.minMem = (long) (v * Memory.MB);
if (instance.meta.minMem == Memory.GB / 2) instance.meta.minMem = null;
instance.writeMeta();
});
}
{
var row = section.row("instance.settings.general.game.memory.max", "instance.settings.general.game.memory.max.subtitle");
row.setSpinButton(instance.meta.maxMem == null ? 1024 : instance.meta.maxMem / Memory.MB, 1024, Memory.maxMBForInstance, 128, v -> {
instance.meta.maxMem = (long) (v * Memory.MB);
if (instance.meta.maxMem == Memory.GB) instance.meta.maxMem = null;
instance.writeMeta();
});
}
}); });
section("instance.settings.general.args", section -> { section("instance.settings.general.args", section -> {
if (instance.meta.arguments == null) instance.meta.arguments = new InstanceMeta.Arguments(List.of(), List.of(), List.of()); if (instance.meta.arguments == null) instance.meta.arguments = new InstanceMeta.Arguments(List.of(), List.of(), List.of());

View File

@ -90,4 +90,8 @@ instance.settings.general.game.fabric.enabled.subtitle=Whether the Fabric Loader
instance.settings.general.game.fabric.version=Fabric Version instance.settings.general.game.fabric.version=Fabric Version
instance.settings.general.game.fabric.version.subtitle=Version of the Fabric Loader to use instance.settings.general.game.fabric.version.subtitle=Version of the Fabric Loader to use
instance.settings.general.game.java=Java instance.settings.general.game.java=Java
instance.settings.general.game.java.subtitle=The path of the custom Java binary to use (or empty for default) instance.settings.general.game.java.subtitle=The path of the custom Java binary to use (or empty for default)
instance.settings.general.game.memory.min=Minimum Memory
instance.settings.general.game.memory.min.subtitle=The minimum amount of Memory Minecraft will allocate (in MiB)
instance.settings.general.game.memory.max=Maximum Memory
instance.settings.general.game.memory.max.subtitle=The maximum amount of Memory Minecraft will allocate (in MiB)

View File

@ -90,4 +90,8 @@ instance.settings.general.game.fabric.enabled.subtitle=Ob Fabric-Loader f
instance.settings.general.game.fabric.version=Fabric-Version instance.settings.general.game.fabric.version=Fabric-Version
instance.settings.general.game.fabric.version.subtitle=Zu verwendende Version des Fabric-Loaders instance.settings.general.game.fabric.version.subtitle=Zu verwendende Version des Fabric-Loaders
instance.settings.general.game.java=Java instance.settings.general.game.java=Java
instance.settings.general.game.java.subtitle=Pfad der Java-Binärdatei, die diese Instanz verwenden soll. Leer lassen um die Standard-Binärdatei zu nutzen. instance.settings.general.game.java.subtitle=Pfad der Java-Binärdatei, die diese Instanz verwenden soll. Leer lassen um die Standard-Binärdatei zu nutzen.
instance.settings.general.game.memory.min=Minimale Speichernutzung
instance.settings.general.game.memory.min.subtitle=Die minimale Speichernutzung dieser Instanz (in MiB)
instance.settings.general.game.memory.max=Maximale Speichernutzung
instance.settings.general.game.memory.max.subtitle=Die maximale Speichernutzung dieser Instanz (in MiB)