diff --git a/.idea/artifacts/TerrarumBuild.xml b/.idea/artifacts/TerrarumBuild.xml index 793cc2b9f..3f1077feb 100644 --- a/.idea/artifacts/TerrarumBuild.xml +++ b/.idea/artifacts/TerrarumBuild.xml @@ -13,6 +13,10 @@ + + + + @@ -72,21 +76,17 @@ - - - - - - - - - - - + + + + - + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/Principii.xml b/.idea/runConfigurations/Principii.xml new file mode 100644 index 000000000..f4fc9b79a --- /dev/null +++ b/.idea/runConfigurations/Principii.xml @@ -0,0 +1,19 @@ + + + + \ No newline at end of file diff --git a/assets/locales/en/terrarum.json b/assets/locales/en/terrarum.json index 08f2dd26a..33bceff7a 100644 --- a/assets/locales/en/terrarum.json +++ b/assets/locales/en/terrarum.json @@ -27,5 +27,8 @@ "MENU_LABEL_IME_TOGGLE": "Toggle IME", "MENU_LABEL_PASTE_FROM_CLIPBOARD": "Paste from Cliboard", "MENU_OPTIONS_PERFORMANCE": "Performance", - "MENU_LABEL_DELETE": "Delete" + "MENU_LABEL_DELETE": "Delete", + "MENU_OPTIONS_JVM_HEAP_MAX": "Max JVM Heap Memory", + "MENU_OPTIONS_AUTOSAVE": "Autosave", + "CONTEXT_TIME_MINUTE_PLURAL": "Minutes" } \ No newline at end of file diff --git a/buildapp/build_app_linux_arm.sh b/buildapp/build_app_linux_arm.sh index 5976f423c..55c4aee96 100755 --- a/buildapp/build_app_linux_arm.sh +++ b/buildapp/build_app_linux_arm.sh @@ -28,7 +28,8 @@ cp -r "../out/$RUNTIME" $DESTDIR/ # Copy over all the assets and a jarfile cp -r "../assets_release" $DESTDIR/ mv $DESTDIR/assets_release $DESTDIR/assets -cp -r "../out/TerrarumBuild.jar" $DESTDIR/assets/ +mkdir $DESTDIR/out +cp "../out/TerrarumBuild.jar" $DESTDIR/out/ # Pack everything to AppImage ARCH=arm_aarch64 "./$APPIMAGETOOL" $DESTDIR "out/$DESTDIR.AppImage" || { echo 'Building AppImage failed' >&2; exit 1; } diff --git a/buildapp/build_app_linux_x86.sh b/buildapp/build_app_linux_x86.sh index 69a498fe2..d824d4d7a 100755 --- a/buildapp/build_app_linux_x86.sh +++ b/buildapp/build_app_linux_x86.sh @@ -28,7 +28,8 @@ cp -r "../out/$RUNTIME" $DESTDIR/ # Copy over all the assets and a jarfile cp -r "../assets_release" $DESTDIR/ mv $DESTDIR/assets_release $DESTDIR/assets -cp -r "../out/TerrarumBuild.jar" $DESTDIR/assets/ +mkdir $DESTDIR/out +cp "../out/TerrarumBuild.jar" $DESTDIR/out/ # Pack everything to AppImage "./$APPIMAGETOOL" $DESTDIR "out/$DESTDIR.AppImage" || { echo 'Building AppImage failed' >&2; exit 1; } diff --git a/buildapp/build_app_mac_arm.sh b/buildapp/build_app_mac_arm.sh index 5c2c55105..08167f837 100755 --- a/buildapp/build_app_mac_arm.sh +++ b/buildapp/build_app_mac_arm.sh @@ -30,6 +30,7 @@ cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/ # Copy over all the assets and a jarfile cp -r "../assets_release" $DESTDIR/Contents/MacOS/ mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets -cp -r "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/assets/ +mkdir $DESTDIR/Contents/MacOS/out +cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/ echo "Build successful: $DESTDIR" diff --git a/buildapp/build_app_mac_x86.sh b/buildapp/build_app_mac_x86.sh index a170ace0c..33c2e60c5 100755 --- a/buildapp/build_app_mac_x86.sh +++ b/buildapp/build_app_mac_x86.sh @@ -30,6 +30,7 @@ cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/ # Copy over all the assets and a jarfile cp -r "../assets_release" $DESTDIR/Contents/MacOS/ mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets -cp -r "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/assets/ +mkdir $DESTDIR/Contents/MacOS/out +cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/ echo "Build successful: $DESTDIR" diff --git a/buildapp/build_app_windows_x86.sh b/buildapp/build_app_windows_x86.sh index d151f0946..4e149501b 100755 --- a/buildapp/build_app_windows_x86.sh +++ b/buildapp/build_app_windows_x86.sh @@ -29,7 +29,8 @@ cp -r "../out/$RUNTIME" $DESTDIR/ # Copy over all the assets and a jarfile cp -r "../assets_release" $DESTDIR/ mv $DESTDIR/assets_release $DESTDIR/assets -cp -r "../out/TerrarumBuild.jar" $DESTDIR/assets/ +mkdir $DESTDIR/out +cp "../out/TerrarumBuild.jar" $DESTDIR/out/ # Temporary solution: zip everything zip -r -9 -l "out/TerrarumWindows.x86.zip" $DESTDIR diff --git a/buildapp/terrarumlinux_arm/AppRun b/buildapp/terrarumlinux_arm/AppRun index 69f74acdd..c0f260628 100755 --- a/buildapp/terrarumlinux_arm/AppRun +++ b/buildapp/terrarumlinux_arm/AppRun @@ -1,3 +1,3 @@ #!/bin/bash cd "${0%/*}" -./runtime-linux-arm/bin/java -Xms1G -Xmx6G -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./assets/TerrarumBuild.jar +./runtime-linux-arm/bin/java -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./out/TerrarumBuild.jar diff --git a/buildapp/terrarumlinux_x86/AppRun b/buildapp/terrarumlinux_x86/AppRun index 353f3ab90..78ce88112 100755 --- a/buildapp/terrarumlinux_x86/AppRun +++ b/buildapp/terrarumlinux_x86/AppRun @@ -1,3 +1,3 @@ #!/bin/bash cd "${0%/*}" -./runtime-linux-x86/bin/java -Xms1G -Xmx6G -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./assets/TerrarumBuild.jar +./runtime-linux-x86/bin/java -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./out/TerrarumBuild.jar diff --git a/buildapp/terrarummac_arm/Terrarum.sh b/buildapp/terrarummac_arm/Terrarum.sh index 8f99418c5..6b067c834 100755 --- a/buildapp/terrarummac_arm/Terrarum.sh +++ b/buildapp/terrarummac_arm/Terrarum.sh @@ -1,3 +1,3 @@ #!/bin/bash cd "${0%/*}" -./runtime-osx-arm/bin/java -XstartOnFirstThread -Xms1G -Xmx6G -jar ./assets/TerrarumBuild.jar +./runtime-osx-arm/bin/java -XstartOnFirstThread -jar ./out/TerrarumBuild.jar diff --git a/buildapp/terrarummac_x86/Terrarum.sh b/buildapp/terrarummac_x86/Terrarum.sh index 5bcf6f94f..2d4341419 100755 --- a/buildapp/terrarummac_x86/Terrarum.sh +++ b/buildapp/terrarummac_x86/Terrarum.sh @@ -1,3 +1,3 @@ #!/bin/bash cd "${0%/*}" -./runtime-osx-x86/bin/java -XstartOnFirstThread -Xms1G -Xmx6G -jar ./assets/TerrarumBuild.jar +./runtime-osx-x86/bin/java -XstartOnFirstThread -jar ./out/TerrarumBuild.jar diff --git a/buildapp/terrarumwindows_x86/Terrarum.c b/buildapp/terrarumwindows_x86/Terrarum.c index a01642dee..61171ddff 100644 --- a/buildapp/terrarumwindows_x86/Terrarum.c +++ b/buildapp/terrarumwindows_x86/Terrarum.c @@ -2,5 +2,5 @@ #include int main() { - return system(".\\runtime-windows-x86\\bin\\java -Xms1G -Xmx6G -jar .\\assets\\TerrarumBuild.jar"); + return system(".\\runtime-windows-x86\\bin\\java -jar .\\out\\TerrarumBuild.jar"); } \ No newline at end of file diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF index d6603425b..92250febb 100644 --- a/src/META-INF/MANIFEST.MF +++ b/src/META-INF/MANIFEST.MF @@ -1,3 +1,3 @@ Manifest-Version: 1.0 -Main-Class: net.torvald.terrarum.App +Main-Class: net.torvald.terrarum.Principii diff --git a/src/net/torvald/terrarum/DefaultConfig.kt b/src/net/torvald/terrarum/DefaultConfig.kt index d29ecc9d2..e3a4de619 100644 --- a/src/net/torvald/terrarum/DefaultConfig.kt +++ b/src/net/torvald/terrarum/DefaultConfig.kt @@ -10,6 +10,7 @@ import com.badlogic.gdx.Input object DefaultConfig { val hashMap = hashMapOf( + "jvm_xmx" to 8, "displayfps" to 0, // 0: no limit, non-zero: limit "displayfpsidle" to 0, // 0: no limit, non-zero: limit "displaycolourdepth" to 8, @@ -21,7 +22,7 @@ object DefaultConfig { "language" to App.getSysLang(), "notificationshowuptime" to 4096, // 4s "selecteditemnameshowuptime" to 4096, // 4s - "autosaveinterval" to 262144, // 4m22s + "autosaveinterval" to 300000, // 5s "multithread" to true, "showhealthmessageonstartup" to true, diff --git a/src/net/torvald/terrarum/ModMgr.kt b/src/net/torvald/terrarum/ModMgr.kt index 5fca49d55..21ec8ca0b 100644 --- a/src/net/torvald/terrarum/ModMgr.kt +++ b/src/net/torvald/terrarum/ModMgr.kt @@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx import com.badlogic.gdx.files.FileHandle import com.badlogic.gdx.utils.JsonValue import net.torvald.terrarum.App.* +import net.torvald.terrarum.App.setToGameConfig import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.WireCodex import net.torvald.terrarum.gameitems.GameItem diff --git a/src/net/torvald/terrarum/Principii.java b/src/net/torvald/terrarum/Principii.java new file mode 100644 index 000000000..07baccd0e --- /dev/null +++ b/src/net/torvald/terrarum/Principii.java @@ -0,0 +1,370 @@ +package net.torvald.terrarum; + +import com.badlogic.gdx.utils.JsonValue; +import net.torvald.terrarum.serialise.WriteConfig; +import net.torvald.terrarum.utils.JsonFetcher; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by minjaesong on 2023-06-22. + */ +public class Principii { + + public static KVHashMap gameConfig = new KVHashMap(); + + public static String OSName = System.getProperty("os.name"); + + public static String operationSystem; + /** %appdata%/Terrarum, without trailing slash */ + public static String defaultDir; + /** defaultDir + "/config.json" */ + public static String configDir; + + + public static void getDefaultDirRoot() { + String OS = OSName.toUpperCase(); + if (OS.contains("WIN")) { + operationSystem = "WINDOWS"; + defaultDir = System.getenv("APPDATA") + "/Terrarum"; + } + else if (OS.contains("OS X") || OS.contains("MACOS")) { // OpenJDK for mac will still report "Mac OS X" with version number "10.16", even on Big Sur and beyond + operationSystem = "OSX"; + defaultDir = System.getProperty("user.home") + "/Library/Application Support/Terrarum"; + } + else if (OS.contains("NUX") || OS.contains("NIX") || OS.contains("BSD")) { + operationSystem = "LINUX"; + defaultDir = System.getProperty("user.home") + "/.Terrarum"; + } + else if (OS.contains("SUNOS")) { + operationSystem = "SOLARIS"; + defaultDir = System.getProperty("user.home") + "/.Terrarum"; + } + else { + operationSystem = "UNKNOWN"; + defaultDir = System.getProperty("user.home") + "/.Terrarum"; + } + } + + + public static void main(String[] args) { + + boolean devMode = false; + + // if -ea flag is set, turn on all the debug prints + try { + assert false; + } + catch (AssertionError e) { + devMode = true; + } + + String runtimeDir = null; + String extracmd = devMode ? " -ea" : ""; + String OS = OSName.toUpperCase(); + String CPUARCH = System.getProperty("os.arch").toUpperCase(); + if (OS.contains("WIN")) { + if (CPUARCH.equals("AMD64")) + runtimeDir = "runtime-windows-x86"; + } + else if (OS.contains("OS X") || OS.contains("MACOS")) { // OpenJDK for mac will still report "Mac OS X" with version number "10.16", even on Big Sur and beyond + extracmd += " -XstartOnFirstThread"; + if (CPUARCH.equals("AMD64")) + runtimeDir = "runtime-osx-x86"; + else if (CPUARCH.equals("AARCH64")) + runtimeDir = "runtime-osx-arm"; + } + else { + extracmd += " -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd"; + if (CPUARCH.equals("AMD64") || CPUARCH.equals("X86")) + runtimeDir = "runtime-linux-x86"; + else if (CPUARCH.equals("AARCH64")) + runtimeDir = "runtime-linux-arm"; + } + + if (runtimeDir == null) { + // TODO show error message of incompatible processor (possibly 32-bit?) + System.exit(1); + } + + + + + getDefaultDirRoot(); + configDir = defaultDir + "/config.json"; + + initialiseConfig(); + readConfigJson(); + + + int xmx = getConfigInt("jvm_xmx"); + + try { + Process proc = Runtime.getRuntime().exec("java"+extracmd+" -Xms1G -Xmx"+xmx+"G -cp ./out/TerrarumBuild.jar net.torvald.terrarum.App"); + + // TODO redirect proc's PrintStream to System.out + int size = 0; + byte[] buffer = new byte[1024]; + while ((size = proc.getInputStream().read(buffer)) != -1) { + System.out.write(buffer, 0, size); + } + + } + catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + + // CONFIG // + + + + /** + * Return config from config set. If the config does not exist, default value will be returned. + * @param key + * * + * @return Config from config set or default config if it does not exist. + * * + * @throws NullPointerException if the specified config simply does not exist. + */ + public static int getConfigInt(String key) { + Object cfg = getConfigMaster(key); + + if (cfg instanceof Integer) return ((int) cfg); + + double value = (double) cfg; + + if (Math.abs(value % 1.0) < 0.00000001) + return (int) Math.round(value); + return ((int) cfg); + } + + + /** + * Return config from config set. If the config does not exist, default value will be returned. + * @param key + * * + * @return Config from config set or default config if it does not exist. + * * + * @throws NullPointerException if the specified config simply does not exist. + */ + public static double getConfigDouble(String key) { + Object cfg = getConfigMaster(key); + return (cfg instanceof Integer) ? (((Integer) cfg) * 1.0) : ((double) (cfg)); + } + + /** + * Return config from config set. If the config does not exist, default value will be returned. + * @param key + * * + * @return Config from config set or default config if it does not exist. + * * + * @throws NullPointerException if the specified config simply does not exist. + */ + public static String getConfigString(String key) { + Object cfg = getConfigMaster(key); + return ((String) cfg); + } + + /** + * Return config from config set. If the config does not exist, default value will be returned. + * @param key + * * + * @return Config from config set or default config if it does not exist. If the default value is undefined, will return false. + */ + public static boolean getConfigBoolean(String key) { + try { + Object cfg = getConfigMaster(key); + return ((boolean) cfg); + } + catch (NullPointerException keyNotFound) { + return false; + } + } + + /*public static int[] getConfigIntArray(String key) { + Object cfg = getConfigMaster(key); + if (cfg instanceof JsonArray) { + JsonArray jsonArray = ((JsonArray) cfg).getAsJsonArray(); + //return IntArray(jsonArray.size(), { i -> jsonArray[i].asInt }) + int[] intArray = new int[jsonArray.size()]; + for (int i = 0; i < jsonArray.size(); i++) { + intArray[i] = jsonArray.get(i).getAsInt(); + } + return intArray; + } + else + return ((int[]) cfg); + }*/ + + public static double[] getConfigDoubleArray(String key) { + Object cfg = getConfigMaster(key); + return ((double[]) cfg); + } + + public static int[] getConfigIntArray(String key) { + double[] a = getConfigDoubleArray(key); + int[] r = new int[a.length]; + for (int i = 0; i < a.length; i++) { + r[i] = ((int) a[i]); + } + return r; + } + + /*public static String[] getConfigStringArray(String key) { + Object cfg = getConfigMaster(key); + if (cfg instanceof JsonArray) { + JsonArray jsonArray = ((JsonArray) cfg).getAsJsonArray(); + //return IntArray(jsonArray.size(), { i -> jsonArray[i].asInt }) + String[] intArray = new String[jsonArray.size()]; + for (int i = 0; i < jsonArray.size(); i++) { + intArray[i] = jsonArray.get(i).getAsString(); + } + return intArray; + } + else + return ((String[]) cfg); + }*/ + + /** + * Get config from config file. If the entry does not exist, get from defaults; if the entry is not in the default, NullPointerException will be thrown + */ + private static HashMap getDefaultConfig() { + return DefaultConfig.INSTANCE.getHashMap(); + } + + private static Object getConfigMaster(String key1) { + String key = key1.toLowerCase(); + + Object config; + try { + config = gameConfig.get(key); + } + catch (NullPointerException e) { + config = null; + } + + Object defaults; + try { + defaults = getDefaultConfig().get(key); + } + catch (NullPointerException e) { + defaults = null; + } + + if (config == null) { + if (defaults == null) { + throw new NullPointerException("key not found: '" + key + "'"); + } + else { + return defaults; + } + } + else { + return config; + } + } + + public static void setConfig(String key, Object value) { + gameConfig.set(key.toLowerCase(), value); + } + + + /** + * + * @return true on successful, false on failure. + */ + private static Boolean readConfigJson() { + System.out.println("Config file: " + configDir); + + + try { + // read from disk and build config from it + JsonValue map = JsonFetcher.INSTANCE.invoke(configDir); + + // make config + for (JsonValue entry = map.child; entry != null; entry = entry.next) { + setToGameConfigForced(entry, null); + } + + return true; + } + catch (IOException e) { + // write default config to game dir. Call th.is method again to read config from it. + try { + createConfigJson(); + } + catch (IOException e1) { + System.out.println("[Bootstrap] Unable to write config.json file"); + e.printStackTrace(); + } + + return false; + } + + } + + + private static void createConfigJson() throws IOException { + File configFile = new File(configDir); + + if (!configFile.exists() || configFile.length() == 0L) { + WriteConfig.INSTANCE.invoke(); + } + } + + /** + * Reads DefaultConfig to populate the gameConfig + */ + private static void initialiseConfig() { + for (Map.Entry entry : DefaultConfig.INSTANCE.getHashMap().entrySet()) { + gameConfig.set(entry.getKey(), entry.getValue()); + } + } + + /** + * Will forcibly overwrite previously loaded config value. + * + * Key naming convention will be 'modName:propertyName'; if modName is null, the key will be just propertyName. + * + * @param value JsonValue (the key-value pair) + * @param modName module name, nullable + */ + public static void setToGameConfigForced(JsonValue value, String modName) { + gameConfig.set((modName == null) ? value.name : modName+":"+value.name, + value.isArray() ? value.asDoubleArray() : + value.isDouble() ? value.asDouble() : + value.isBoolean() ? value.asBoolean() : + value.isLong() ? value.asInt() : + value.asString() + ); + } + + /** + * Will not overwrite previously loaded config value. + * + * Key naming convention will be 'modName:propertyName'; if modName is null, the key will be just propertyName. + * + * @param value JsonValue (the key-value pair) + * @param modName module name, nullable + */ + public static void setToGameConfig(JsonValue value, String modName) { + String key = (modName == null) ? value.name : modName+":"+value.name; + if (gameConfig.get(key) == null) { + gameConfig.set(key, + value.isArray() ? value.asDoubleArray() : + value.isDouble() ? value.asDouble() : + value.isBoolean() ? value.asBoolean() : + value.isLong() ? value.asInt() : + value.asString() + ); + } + } + +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIGraphicsControlPanel.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIGraphicsControlPanel.kt index 9e08433ab..9e77e4410 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIGraphicsControlPanel.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIGraphicsControlPanel.kt @@ -109,7 +109,8 @@ class UIGraphicsControlPanel(remoCon: UIRemoCon?) : UICanvas() { UIItemSpinner(this, x, y, App.getConfigDouble(optionName), arg[1].toDouble(), arg[2].toDouble(), arg[3].toDouble(), spinnerWidth, numberToTextFunction = { "${((it as Double)*100).toInt()}%" }) to { it: UIItem, optionStr: String -> (it as UIItemSpinner).selectionChangeListener = { App.setConfig(optionStr, it) - } } + } + } } else if (args.startsWith("typeinint")) { // val arg = args.split(',') // args: none diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIPerformanceControlPanel.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIPerformanceControlPanel.kt new file mode 100644 index 000000000..ff9c1be5b --- /dev/null +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIPerformanceControlPanel.kt @@ -0,0 +1,219 @@ +package net.torvald.terrarum.modulebasegame.ui + +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.Input +import com.badlogic.gdx.graphics.Camera +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.g2d.SpriteBatch +import net.torvald.terrarum.App +import net.torvald.terrarum.CommonResourcePool +import net.torvald.terrarum.ceilInt +import net.torvald.terrarum.langpack.Lang +import net.torvald.terrarum.ui.* +import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack +import net.torvald.unicode.TIMES + +/** + * Created by minjaesong on 2023-06-22. + */ +class UIPerformanceControlPanel(remoCon: UIRemoCon?) : UICanvas() { + + + private val linegap = 14 + private val panelgap = 20 + + private val rowheight = 20 + linegap + + private val h1MarginTop = 16 + private val h1MarginBottom = 4 + + private val options = arrayOf( + arrayOf("", { Lang["MENU_OPTIONS_GAMEPLAY"] }, "h1"), + arrayOf("autosaveinterval", { Lang["MENU_OPTIONS_AUTOSAVE"] + " (${Lang["CONTEXT_TIME_MINUTE_PLURAL"]})" }, "spinnerimul,5,120,5,60000"), + arrayOf("", { Lang["MENU_OPTIONS_PERFORMANCE"] }, "h1"), + arrayOf("jvm_xmx", { Lang["MENU_OPTIONS_JVM_HEAP_MAX"] + " (GB)" }, "spinner,2,32,1"), + arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"), + ) + + private val optionsYpos = IntArray(options.size + 1) + + init { + CommonResourcePool.addToLoadingList("gui_hrule") { + TextureRegionPack(Gdx.files.internal("assets/graphics/gui/hrule.tga"), 216, 20) + } + CommonResourcePool.loadAll() + + + + var akku = 0 + options.forEachIndexed { index, row -> + val option = row[2] + + if (index > 0 && option == "h1") { + akku += h1MarginTop + } + + optionsYpos[index] = akku + + akku += when (option) { + "h1" -> rowheight + h1MarginBottom + else -> rowheight + } + } + optionsYpos[optionsYpos.lastIndex] = akku + } + override var width = 560 + override var height = optionsYpos.last() + + private val hrule = CommonResourcePool.getAsTextureRegionPack("gui_hrule") + + private val spinnerWidth = 140 + private val drawX = (Toolkit.drawWidth - width) / 2 + private val drawY = (App.scr.height - height) / 2 + + // @return Pair of + private fun makeButton(args: String, x: Int, y: Int, optionName: String): Pair Unit> { + return if (args.startsWith("h1") || args.startsWith("p")) { + (object : UIItem(this, x, y) { + override val width = 1 + override val height = 1 + override fun dispose() {} + }) to { _, _ -> } + } + else if (args.startsWith("toggle")) { + UIItemToggleButton(this, x, y, spinnerWidth, App.getConfigBoolean(optionName)) to { it: UIItem, optionStr: String -> + (it as UIItemToggleButton).clickOnceListener = { _, _ -> + it.toggle() + App.setConfig(optionStr, it.getStatus()) + } + } + } + else if (args.startsWith("spinner,")) { + val arg = args.split(',') + UIItemSpinner(this, x, y, App.getConfigInt(optionName), arg[1].toInt(), arg[2].toInt(), arg[3].toInt(), spinnerWidth, numberToTextFunction = { "${it.toLong()}" }) to { it: UIItem, optionStr: String -> + (it as UIItemSpinner).selectionChangeListener = { + App.setConfig(optionStr, it) + } + } + } + else if (args.startsWith("spinnerd,")) { + val arg = args.split(',') + UIItemSpinner(this, x, y, App.getConfigDouble(optionName), arg[1].toDouble(), arg[2].toDouble(), arg[3].toDouble(), spinnerWidth, numberToTextFunction = { "${((it as Double)*100).toInt()}%" }) to { it: UIItem, optionStr: String -> + (it as UIItemSpinner).selectionChangeListener = { + App.setConfig(optionStr, it) + } + } + } + else if (args.startsWith("spinnerimul,")) { + val arg = args.split(',') + val mult = arg[4].toInt() + UIItemSpinner(this, x, y, App.getConfigInt(optionName) / mult, arg[1].toInt(), arg[2].toInt(), arg[3].toInt(), spinnerWidth, numberToTextFunction = { "${it.toLong()}" }) to { it: UIItem, optionStr: String -> + (it as UIItemSpinner).selectionChangeListener = { + App.setConfig(optionStr, it.toInt() * mult) + } + } + } + else if (args.startsWith("typeinint")) { +// val arg = args.split(',') // args: none + UIItemTextLineInput(this, x, y, spinnerWidth, { "${App.getConfigInt(optionName)}" }, InputLenCap(4, InputLenCap.CharLenUnit.CODEPOINTS), { it.headkey in Input.Keys.NUM_0..Input.Keys.NUM_9 || it.headkey == Input.Keys.BACKSPACE }) to { it: UIItem, optionStr: String -> + (it as UIItemTextLineInput).textCommitListener = { + App.setConfig(optionStr, it.toInt()) // HAXXX!!! + } + } + } + else if (args.startsWith("typeinres")) { + val keyWidth = optionName.substringBefore(',') + val keyHeight = optionName.substringAfter(',') + UIItemTextLineInput(this, x, y, spinnerWidth, { "${App.getConfigInt(keyWidth)}x${App.getConfigInt(keyHeight)}" }, InputLenCap(9, InputLenCap.CharLenUnit.CODEPOINTS), { it.headkey == Input.Keys.ENTER || it.headkey == Input.Keys.BACKSPACE || it.character?.matches(Regex("[0-9xX]")) == true }, UIItemTextButton.Companion.Alignment.CENTRE) to { it: UIItem, optionStr: String -> + (it as UIItemTextLineInput).textCommitListener = { text -> + val text = text.lowercase() + if (text.matches(Regex("""[0-9]+x[0-9]+"""))) { + it.markAsNormal() + val width = text.substringBefore('x').toInt() + val height = text.substringAfter('x').toInt() + App.setConfig(keyWidth, width) + App.setConfig(keyHeight, height) + } + else it.markAsInvalid() + } + } + } + else throw IllegalArgumentException(args) + } + + private val optionControllers: List Unit>> = options.mapIndexed { index, strings -> + makeButton(options[index][2] as String, + drawX + width / 2 + panelgap, + drawY - 2 + optionsYpos[index], + options[index][0] as String + ) + } + + init { + optionControllers.forEachIndexed { i, it -> + it.second.invoke(it.first, options[i][0] as String) + addUIitem(it.first) + } + } + + override fun updateUI(delta: Float) { + uiItems.forEach { it.update(delta) } + } + + override fun renderUI(batch: SpriteBatch, camera: Camera) { + /*batch.color = Toolkit.Theme.COL_INACTIVE + Toolkit.drawBoxBorder(batch, drawX, drawY, width, height) + + batch.color = CELL_COL + Toolkit.fillArea(batch, drawX, drawY, width, height)*/ + + options.forEachIndexed { index, strings -> + val mode = strings[2] + + val font = if (mode == "h1") App.fontUITitle else App.fontGame + + val label = (strings[1] as () -> String).invoke() + val labelWidth = font.getWidth(label) + batch.color = when (mode) { + "h1" -> Toolkit.Theme.COL_MOUSE_UP + "p" -> Color.LIGHT_GRAY + else -> Color.WHITE + } + + val xpos = if (mode == "p" || mode == "h1") + drawX + (width - labelWidth)/2 // centre-aligned + else + drawX + width/2 - panelgap - labelWidth // right aligned at the middle of the panel, offsetted by panelgap + + font.draw(batch, label, xpos.toFloat(), drawY + optionsYpos[index] - 2f) + + // draw hrule + if (mode == "h1") { + val ruleWidth = ((width - 24 - labelWidth) / 2).toFloat() + batch.draw(hrule.get(0,0), xpos - 24f - ruleWidth, drawY + optionsYpos[index].toFloat(), ruleWidth, hrule.tileH.toFloat()) + batch.draw(hrule.get(0,1), xpos + 24f + labelWidth, drawY + optionsYpos[index].toFloat(), ruleWidth, hrule.tileH.toFloat()) + } + } + uiItems.forEach { it.render(batch, camera) } + + if (App.getConfigBoolean("fx_streamerslayout")) { + val xstart = App.scr.width - App.scr.chatWidth + + batch.color = Color(0x00f8ff_40) + Toolkit.fillArea(batch, xstart + 1, 1, App.scr.chatWidth - 2, App.scr.height - 2) + + batch.color = Toolkit.Theme.COL_MOUSE_UP + Toolkit.drawBoxBorder(batch, xstart + 1, 1, App.scr.chatWidth - 2, App.scr.height - 2) + + val overlayResTxt = "${(App.scr.chatWidth * App.scr.magn).ceilInt()}$TIMES${App.scr.windowH}" + + App.fontGame.draw(batch, overlayResTxt, + (xstart + (App.scr.chatWidth - App.fontGame.getWidth(overlayResTxt)) / 2).toFloat(), + ((App.scr.height - App.fontGame.lineHeight) / 2).toFloat() + ) + } + } + + override fun dispose() { + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UITitleRemoConYaml.kt b/src/net/torvald/terrarum/modulebasegame/ui/UITitleRemoConYaml.kt index a1a38addd..25be8b232 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UITitleRemoConYaml.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UITitleRemoConYaml.kt @@ -18,6 +18,7 @@ object UITitleRemoConYaml { - MENU_OPTIONS_CONTROLS : net.torvald.terrarum.modulebasegame.ui.UIKeyboardControlPanel - MENU_LABEL_IME : net.torvald.terrarum.modulebasegame.ui.UIIMEConfig - MENU_LABEL_LANGUAGE : net.torvald.terrarum.modulebasegame.ui.UITitleLanguage + - GAME_GENRE_MISC : net.torvald.terrarum.modulebasegame.ui.UIPerformanceControlPanel - MENU_MODULES : net.torvald.terrarum.ModOptionsHost - MENU_LABEL_RETURN+WRITETOCONFIG - MENU_MODULES : net.torvald.terrarum.modulebasegame.ui.UITitleModules