From bdfe4539190825fbec227850531f4319304653eb Mon Sep 17 00:00:00 2001 From: nextdayy <79922345+nextdayy@users.noreply.github.com> Date: Fri, 10 May 2024 11:24:19 +0100 Subject: [PATCH] fix publishing, add initial update stuff, other bug fixes --- build.gradle.kts | 2 +- gradle.properties | 2 +- gradle/libs.versions.toml | 2 +- modules/config-impl/api/config-impl.api | 4 +- .../api/config/v1/ConfigManager.java | 6 +- .../api/config/v1/ConfigVisualizer.kt | 11 +- .../api/config/v1/visualize/Visualizer.kt | 13 +- modules/hud/api/hud.api | 4 + .../org/polyfrost/oneconfig/api/hud/v1/Hud.kt | 22 ++- .../oneconfig/api/hud/v1/HudManager.kt | 10 +- .../api/hud/v1/internal/HudVisualizer.kt | 32 ++++ .../oneconfig/api/hud/v1/internal/hudpages.kt | 5 +- modules/root.gradle.kts | 64 ++++++++ .../oneconfig/internal/ui/pages/pages.kt | 12 +- modules/utils/api/utils.api | 12 ++ .../api/platform/v1/LoaderPlatform.java | 9 ++ .../oneconfig/api/platform/v1/Platform.java | 27 ++++ .../oneconfig/utils/v1/OneConfigUpdate.java | 152 ++++++++++++++++++ versions/api/platform.api | 2 +- versions/build.gradle.kts | 8 +- .../api/ui/v1/screen/PolyUIScreen.java | 9 +- .../internal/init/OneConfigTweaker.java | 5 +- .../internal/mixin/CrashReportMixin.java | 70 ++++++++ .../internal/platform/v1/PlatformImpl.java | 26 +-- .../src/main/resources/mixins.oneconfig.json | 37 ++--- 25 files changed, 477 insertions(+), 69 deletions(-) create mode 100644 modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/internal/HudVisualizer.kt create mode 100644 modules/utils/src/main/java/org/polyfrost/oneconfig/utils/v1/OneConfigUpdate.java create mode 100644 versions/src/main/java/org/polyfrost/oneconfig/internal/mixin/CrashReportMixin.java diff --git a/build.gradle.kts b/build.gradle.kts index 4e8205364..03bebfe96 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ val modMajor = project.properties["mod_major_version"] val modMinor = project.properties["mod_minor_version"] version = "$modMajor$modMinor" -group = "org.polyfrost" +group = "org.polyfrost.oneconfig" allprojects { apply(plugin = rootProject.libs.plugins.licenser.get().pluginId) diff --git a/gradle.properties b/gradle.properties index 96e7378b9..99b376125 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ mod_name=OneConfig mod_id=oneconfig mod_major_version=1.0.0-alpha -mod_minor_version=-LOCAL +mod_minor_version=1 polyfrost.defaults.loom=2 org.gradle.daemon=true org.gradle.parallel=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bf45dd300..e29d1e274 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ pgt = "0.5.1" shadow = "8.1.1" licenser = "2.0.1" -polyui = "1.1.6" +polyui = "1.1.63" log4j-api = "2.0-beta9" # used because this is the version that 1.8.9 supports, so we have to compile against the same (annoying) log4j-impl = "2.23.1" # unvulnerable version diff --git a/modules/config-impl/api/config-impl.api b/modules/config-impl/api/config-impl.api index 29d26eb68..b3faaa0b9 100644 --- a/modules/config-impl/api/config-impl.api +++ b/modules/config-impl/api/config-impl.api @@ -26,17 +26,20 @@ public final class org/polyfrost/oneconfig/api/config/v1/ConfigManager { public fun gatherAll (Ljava/lang/String;)Ljava/util/Collection; public fun get (Ljava/lang/String;)Lorg/polyfrost/oneconfig/api/config/v1/Tree; public fun getFolder ()Ljava/nio/file/Path; + public static fun internal ()Lorg/polyfrost/oneconfig/api/config/v1/ConfigManager; public static fun openProfile (Ljava/lang/String;)V public fun register (Ljava/lang/Object;Ljava/lang/String;)Lorg/polyfrost/oneconfig/api/config/v1/Tree; public fun register (Lorg/polyfrost/oneconfig/api/config/v1/Tree;)Lorg/polyfrost/oneconfig/api/config/v1/Tree; public static fun registerCollector (Lorg/polyfrost/oneconfig/api/config/v1/collect/PropertyCollector;)V public fun save (Ljava/lang/String;)Z public fun save (Lorg/polyfrost/oneconfig/api/config/v1/Tree;)Z + public fun saveAll ()V public fun trees ()Ljava/util/Collection; } public class org/polyfrost/oneconfig/api/config/v1/ConfigVisualizer { public static final field Companion Lorg/polyfrost/oneconfig/api/config/v1/ConfigVisualizer$Companion; + public static final field INSTANCE Lorg/polyfrost/oneconfig/api/config/v1/ConfigVisualizer; public fun ()V protected fun create (Lorg/polyfrost/oneconfig/api/config/v1/Tree;Ljava/lang/String;)Lorg/polyfrost/polyui/component/Drawable; public static synthetic fun create$default (Lorg/polyfrost/oneconfig/api/config/v1/ConfigVisualizer;Lorg/polyfrost/oneconfig/api/config/v1/Tree;Ljava/lang/String;ILjava/lang/Object;)Lorg/polyfrost/polyui/component/Drawable; @@ -62,7 +65,6 @@ public class org/polyfrost/oneconfig/api/config/v1/ConfigVisualizer { } public final class org/polyfrost/oneconfig/api/config/v1/ConfigVisualizer$Companion { - public final fun getINSTANCE ()Lorg/polyfrost/oneconfig/api/config/v1/ConfigVisualizer; public final fun strv (Ljava/lang/String;)Ljava/lang/String; } diff --git a/modules/config-impl/src/main/java/org/polyfrost/oneconfig/api/config/v1/ConfigManager.java b/modules/config-impl/src/main/java/org/polyfrost/oneconfig/api/config/v1/ConfigManager.java index 2eaaea4eb..b65a762ea 100644 --- a/modules/config-impl/src/main/java/org/polyfrost/oneconfig/api/config/v1/ConfigManager.java +++ b/modules/config-impl/src/main/java/org/polyfrost/oneconfig/api/config/v1/ConfigManager.java @@ -73,7 +73,7 @@ private ConfigManager(Path onto, FileSerializer... serializers) { * Returns a reference to the internal config manager, which is mounted onto the ./OneConfig directory. */ @ApiStatus.Internal - static ConfigManager internal() { + public static ConfigManager internal() { return internal; } @@ -153,6 +153,10 @@ public boolean save(Tree t) { return backend.save(t); } + public void saveAll() { + backend.saveAll(); + } + public Path getFolder() { return backend.folder; } diff --git a/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/ConfigVisualizer.kt b/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/ConfigVisualizer.kt index 1bf250688..5e4922f81 100644 --- a/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/ConfigVisualizer.kt +++ b/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/ConfigVisualizer.kt @@ -42,6 +42,7 @@ import org.polyfrost.polyui.unit.Vec2 import org.polyfrost.polyui.unit.seconds import org.polyfrost.polyui.utils.LinkedList import org.polyfrost.polyui.utils.image +import org.polyfrost.polyui.utils.mapToArray import org.polyfrost.polyui.utils.rgba import kotlin.math.PI @@ -109,13 +110,13 @@ open class ConfigVisualizer { Group( alignment = alignCV, children = - subcategories.map { (header, options) -> + subcategories.mapToArray { (header, options) -> Group( Text(header, fontSize = 22f), *options.toTypedArray(), alignment = alignCV, ) - }.toTypedArray(), + }, ) } } @@ -149,14 +150,13 @@ open class ConfigVisualizer { protected open fun createHeaders(categories: Map): Drawable? { return Group( - children = - categories.map { (category, options) -> + children = categories.mapToArray { (category, options) -> Button(text = category).events { Event.Mouse.Clicked(0) then { parent[0] = options } } - }.toTypedArray(), + }, ) } @@ -252,6 +252,7 @@ open class ConfigVisualizer { } companion object { + @JvmField val INSTANCE = ConfigVisualizer() protected val visCache = HashMap, Visualizer>() diff --git a/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/visualize/Visualizer.kt b/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/visualize/Visualizer.kt index 14cd83b38..23054f4bd 100644 --- a/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/visualize/Visualizer.kt +++ b/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/visualize/Visualizer.kt @@ -33,6 +33,7 @@ import org.polyfrost.polyui.component.events import org.polyfrost.polyui.component.impl.* import org.polyfrost.polyui.event.Event import org.polyfrost.polyui.unit.Vec2 +import org.polyfrost.polyui.utils.mapToArray /** * Visualizers are procedures that take a property, and return a drawable that represents it. @@ -70,10 +71,10 @@ fun interface Visualizer { return Dropdown( padding = 24f, initial = index, - entries = prop.type.enumConstants.map { + entries = prop.type.enumConstants.mapToArray { it as Enum<*> null to (it::class.java.fields[0].get(it) as? String ?: it.name) - }.toTypedArray(), + }, ) } else { require( @@ -83,7 +84,7 @@ fun interface Visualizer { return Dropdown( padding = 24f, initial = prop.getAs(), - entries = options.map { null to it }.toTypedArray(), + entries = options.mapToArray { null to it }, ) } } @@ -133,10 +134,10 @@ fun interface Visualizer { require(options.isEmpty()) { "Radio button ${prop.id} cannot have options when used with enums" } val r = Radiobutton( - entries = prop.type.enumConstants.map { + entries = prop.type.enumConstants.mapToArray { it as Enum<*> null to (it::class.java.fields[0].get(it) as? String ?: it.name) - }.toTypedArray(), + }, initial = prop.type.enumConstants.indexOf(prop.get()), optionLateralPadding = 20f, ).events { @@ -152,7 +153,7 @@ fun interface Visualizer { ) { "Radio buttons ${prop.id} can only be used with enum or integer types (type=${prop.type}" } require(options.size >= 2) { "Radio button ${prop.id} must have at least two options" } return Radiobutton( - entries = options.map { null to it }.toTypedArray(), + entries = options.mapToArray { null to it }, initial = prop.getAs(), optionLateralPadding = 20f, ).events { diff --git a/modules/hud/api/hud.api b/modules/hud/api/hud.api index 9f6f27835..5ebceaa24 100644 --- a/modules/hud/api/hud.api +++ b/modules/hud/api/hud.api @@ -101,6 +101,10 @@ public final class org/polyfrost/oneconfig/api/hud/v1/TextHud$DateTime : org/pol public fun updateFrequency ()J } +public final class org/polyfrost/oneconfig/api/hud/v1/internal/HudVisualizer : org/polyfrost/oneconfig/api/config/v1/ConfigVisualizer { + public fun ()V +} + public final class org/polyfrost/oneconfig/api/hud/v1/internal/Hud_utilsKt { public static final fun build (Lorg/polyfrost/oneconfig/api/hud/v1/Hud;)Lorg/polyfrost/polyui/component/impl/Block; public static final fun buildNew (Lorg/polyfrost/oneconfig/api/hud/v1/Hud;)Lorg/polyfrost/polyui/component/impl/Block; diff --git a/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/Hud.kt b/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/Hud.kt index 93608bd9a..1e0f58607 100644 --- a/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/Hud.kt +++ b/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/Hud.kt @@ -33,10 +33,11 @@ import org.polyfrost.oneconfig.api.config.v1.ConfigManager import org.polyfrost.oneconfig.api.config.v1.Properties.ktProperty import org.polyfrost.oneconfig.api.config.v1.Properties.simple import org.polyfrost.oneconfig.api.config.v1.Tree -import org.polyfrost.oneconfig.utils.v1.StringUtils import org.polyfrost.polyui.color.PolyColor import org.polyfrost.polyui.component.Drawable import org.polyfrost.polyui.unit.Vec2 +import kotlin.io.path.exists +import kotlin.random.Random /** * HUD (Heads Up Display) is a component that is rendered on top of the screen. They are used for displaying information to the user, such as the time, or the player's health. @@ -71,9 +72,11 @@ abstract class Hud : Cloneable, Config("null", null, "null", null) fun make(with: Tree? = null): Hud { if (tree != null) throw IllegalArgumentException("HUD already exists -> can only clone from root HUD object") val out = clone() - val tree = ConfigManager.collect(out, with?.id ?: "huds/${StringUtils.randomString("0123456789", 4)}-${id()}") + val id = with?.id ?: genRid() + val tree = ConfigManager.collect(out, id) tree.title = out.title() tree.addMetadata("category", out.category()) + tree.addMetadata("frontendIgnore", true) tree["x"] = ktProperty(out.hud::x) tree["y"] = ktProperty(out.hud::y) tree["skewX"] = ktProperty(out.hud::skewX) @@ -92,6 +95,21 @@ abstract class Hud : Cloneable, Config("null", null, "null", null) return out } + private fun genRid(): String { + var p = "huds/${Random.Default.nextInt(0, 100)}-${id()}" + val folder = ConfigManager.active().folder + var i = 0 + while (folder.resolve(p).exists()) { + p = "huds/${Random.Default.nextInt(0, 999)}-${id()}" + when (i++) { + 100 -> HudManager.LOGGER.warn("they all say that it gets better") + 500 -> HudManager.LOGGER.warn("yeah they all say that it gets better;; it gets better the more you grow") + 999 -> throw IllegalStateException("... but what if i dont?") + } + } + return p + } + protected open fun addSpecifics(tree: Tree) {} @Transient diff --git a/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/HudManager.kt b/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/HudManager.kt index 013e7cffe..6cba74ca7 100644 --- a/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/HudManager.kt +++ b/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/HudManager.kt @@ -118,6 +118,7 @@ object HudManager { ), Text("oneconfig.hudeditor.title", fontSize = 24f).setFont { medium }.onClick { ColorPicker(rgba(32, 53, 41).toAnimatable().ref(), mutableListOf(), mutableListOf(), polyUI) + true }, hudsPage, size = Vec2(500f, 1048f), @@ -129,8 +130,8 @@ object HudManager { Image("assets/oneconfig/ico/right-arrow.svg".image()).setAlpha(0.1f), size = Vec2(32f, 1048f), alignment = alignC, - ).named("CloseArea").withStates().setPalette( - Colors.Palette( + ).named("CloseArea").withStates().also { + it.palette = Colors.Palette( TRANSPARENT, PolyColor.Gradient( rgba(100, 100, 100, 0.4f), @@ -143,8 +144,8 @@ object HudManager { type = PolyColor.Gradient.Type.LeftToRight, ), TRANSPARENT, - ), - ).events { + ) + }.events { Event.Mouse.Entered then { Fade(this[0], 1f, false, Animations.EaseInOutQuad.create(0.08.seconds)).add() } @@ -218,6 +219,7 @@ object HudManager { private fun editorClose() { toggleHudPicker() + ConfigManager.active().saveAll() panelExists = false } diff --git a/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/internal/HudVisualizer.kt b/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/internal/HudVisualizer.kt new file mode 100644 index 000000000..4031c53d6 --- /dev/null +++ b/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/internal/HudVisualizer.kt @@ -0,0 +1,32 @@ +/* + * This file is part of OneConfig. + * OneConfig - Next Generation Config Library for Minecraft: Java Edition + * Copyright (C) 2021~2024 Polyfrost. + * + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * OneConfig is licensed under the terms of version 3 of the GNU Lesser + * General Public License as published by the Free Software Foundation, AND + * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, + * either version 1.0 of the Additional Terms, 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License. If not, see . You should + * have also received a copy of the Additional Terms Applicable + * to OneConfig, as published by Polyfrost. If not, see + * + */ + +package org.polyfrost.oneconfig.api.hud.v1.internal + +import org.polyfrost.oneconfig.api.config.v1.ConfigVisualizer + +class HudVisualizer : ConfigVisualizer() { +} \ No newline at end of file diff --git a/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/internal/hudpages.kt b/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/internal/hudpages.kt index 35d546965..afb1c944a 100644 --- a/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/internal/hudpages.kt +++ b/modules/hud/src/main/kotlin/org/polyfrost/oneconfig/api/hud/v1/internal/hudpages.kt @@ -40,6 +40,7 @@ import org.polyfrost.polyui.unit.by import org.polyfrost.polyui.unit.seconds import org.polyfrost.polyui.utils.LinkedList import org.polyfrost.polyui.utils.image +import org.polyfrost.polyui.utils.mapToArray import org.polyfrost.polyui.utils.radii import kotlin.math.PI import kotlin.math.atan2 @@ -61,7 +62,7 @@ fun HudsPage(huds: LinkedList>): Drawable { ), if (huds.isNotEmpty()) { Group( - children = huds.map { + children = huds.mapToArray { val preview = it.buildNew() val size = Vec2(if (preview.width > 200f) 452f else 215f, if (preview.height > 70f) 0f else 80f) Block( @@ -69,7 +70,7 @@ fun HudsPage(huds: LinkedList>): Drawable { alignment = alignC, size = size, ).withBoarder().withStates() - }.toTypedArray(), + }, visibleSize = Vec2(452f, 800f), ) } else { diff --git a/modules/root.gradle.kts b/modules/root.gradle.kts index ca9509c4b..e5e48b533 100644 --- a/modules/root.gradle.kts +++ b/modules/root.gradle.kts @@ -1,8 +1,12 @@ +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName + // contains shared logic between all the modules to reduce boilerplate. plugins { java id(libs.plugins.kotlinx.api.validator.get().pluginId) + signing + `maven-publish` } subprojects { @@ -31,13 +35,73 @@ subprojects { } } + tasks.javadoc { + options { + (this as CoreJavadocOptions).addBooleanOption("Xdoclint:none", true) + } + } + + base.archivesName = "${project.name}-api" + version = rootProject.version + group = rootProject.group + java { + withSourcesJar() + withJavadocJar() toolchain { languageVersion.set(JavaLanguageVersion.of(8)) } } } +signing { + sign(publishing.publications) +} + +publishing { + publications { + for(project in subprojects) { + if (project.name == "ui-impl") return@publications + register(project.name) { + groupId = rootProject.group.toString() + artifactId = project.archivesName.get() + version = rootProject.version.toString() + + artifact(project.tasks["jar"]) + artifact(project.tasks["sourcesJar"]) + artifact(project.tasks["javadocJar"]) + } + } + } + + repositories { + maven { + name = "releases" + url = uri("https://repo.polyfrost.org/releases") + credentials(PasswordCredentials::class) + authentication { + create("basic") + } + } + maven { + name = "snapshots" + url = uri("https://repo.polyfrost.org/snapshots") + credentials(PasswordCredentials::class) + authentication { + create("basic") + } + } + maven { + name = "private" + url = uri("https://repo.polyfrost.org/private") + credentials(PasswordCredentials::class) + authentication { + create("basic") + } + } + } +} + apiValidation { ignoredPackages.add("org.polyfrost.oneconfig.internal") ignoredProjects.add("ui-impl") diff --git a/modules/ui-impl/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/pages/pages.kt b/modules/ui-impl/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/pages/pages.kt index 9f5f13cc7..5185a20fb 100644 --- a/modules/ui-impl/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/pages/pages.kt +++ b/modules/ui-impl/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/pages/pages.kt @@ -44,6 +44,7 @@ import org.polyfrost.polyui.unit.Align import org.polyfrost.polyui.unit.Vec2 import org.polyfrost.polyui.unit.seconds import org.polyfrost.polyui.utils.image +import org.polyfrost.polyui.utils.mapToArray import org.polyfrost.polyui.utils.radii import org.polyfrost.polyui.utils.translated @@ -69,7 +70,8 @@ fun ModsPage(trees: Collection): Drawable { size = Vec2(1130f, 0f), visibleSize = Vec2(1130f, 635f), alignment = Align(cross = Align.Cross.Start, padding = Vec2(18f, 18f)), - children = trees.map { + children = trees.mapNotNull { + if (it.getMetadata("frontendIgnore") != null) return@mapNotNull null Group( Block( Image(it.getMetadata("icon")?.image() ?: defaultModImage), @@ -120,7 +122,7 @@ fun ChangelogPage(news: Collection): Drawable { size = Vec2(1130f, 0f), visibleSize = Vec2(1130f, 635f), alignment = Align(cross = Align.Cross.Center, padding = Vec2(60f, 20f)), - children = news.map { + children = news.mapToArray { Group( if (it.image != null) Image(it.image).onInit { image.size.max(325f, 111f) } else null, Group( @@ -153,7 +155,7 @@ fun ChangelogPage(news: Collection): Drawable { alignment = Align(mode = Align.Mode.Vertical), ), ) - }.toTypedArray(), + }, ) } @@ -161,7 +163,7 @@ fun NotificationsPopup(polyUI: PolyUI, notifications: List) { val it = Block( Text("oneconfig.notifications", fontSize = 16f).setFont { medium }, Group( - children = notifications.map { + children = notifications.mapToArray { Group( Group( Image(it.icon).onInit { image.size.resize(24f, 24f) }, @@ -176,7 +178,7 @@ fun NotificationsPopup(polyUI: PolyUI, notifications: List) { ), *it.extras, ) - }.toTypedArray(), + }, ), Group( Group( diff --git a/modules/utils/api/utils.api b/modules/utils/api/utils.api index 29c53e89b..04b364191 100644 --- a/modules/utils/api/utils.api +++ b/modules/utils/api/utils.api @@ -25,6 +25,7 @@ public abstract interface class org/polyfrost/oneconfig/api/platform/v1/I18nPlat } public abstract interface class org/polyfrost/oneconfig/api/platform/v1/LoaderPlatform { + public fun getLoadedMod (Ljava/lang/String;)Lorg/polyfrost/oneconfig/api/platform/v1/LoaderPlatform$ActiveMod; public abstract fun getLoadedMods ()Ljava/util/List; public abstract fun isModLoaded (Ljava/lang/String;)Z public abstract fun toActiveMod (Ljava/lang/Object;)Lorg/polyfrost/oneconfig/api/platform/v1/LoaderPlatform$ActiveMod; @@ -45,6 +46,7 @@ public abstract interface class org/polyfrost/oneconfig/api/platform/v1/Platform public static fun getInstance ()Lorg/polyfrost/oneconfig/api/platform/v1/Platform; public abstract fun getLoader ()Lorg/polyfrost/oneconfig/api/platform/v1/Platform$Loader; public static fun getLoaderPlatform ()Lorg/polyfrost/oneconfig/api/platform/v1/LoaderPlatform; + public fun getLoaderString ()Ljava/lang/String; public abstract fun getMinecraftVersion ()I public abstract fun getPlayerName ()Ljava/lang/String; public static fun getServerPlatform ()Lorg/polyfrost/oneconfig/api/platform/v1/ServerPlatform; @@ -210,6 +212,16 @@ public final class org/polyfrost/oneconfig/utils/v1/NetworkUtils { public static fun setupConnection (Ljava/lang/String;Ljava/lang/String;IZ)Ljava/io/InputStream; } +public final class org/polyfrost/oneconfig/utils/v1/OneConfigUpdate { + public static final field ONECONFIG_REPO Ljava/lang/String; + public final field snapshot Z + public fun hasChecked ()Z + public fun hasUpdate ()Z + public static fun makeUpdateMarker ()V + public static fun release ()Lorg/polyfrost/oneconfig/utils/v1/OneConfigUpdate; + public static fun snapshot ()Lorg/polyfrost/oneconfig/utils/v1/OneConfigUpdate; +} + public final class org/polyfrost/oneconfig/utils/v1/OneImage { public fun (II)V public fun (Ljava/awt/image/BufferedImage;)V diff --git a/modules/utils/src/main/java/org/polyfrost/oneconfig/api/platform/v1/LoaderPlatform.java b/modules/utils/src/main/java/org/polyfrost/oneconfig/api/platform/v1/LoaderPlatform.java index 3bf10edac..6c070fddf 100644 --- a/modules/utils/src/main/java/org/polyfrost/oneconfig/api/platform/v1/LoaderPlatform.java +++ b/modules/utils/src/main/java/org/polyfrost/oneconfig/api/platform/v1/LoaderPlatform.java @@ -44,6 +44,15 @@ public interface LoaderPlatform { @NotNull List getLoadedMods(); + @Nullable + default ActiveMod getLoadedMod(String id) { + for (ActiveMod mod : getLoadedMods()) { + if (mod == null) continue; + if (id.equals(mod.id)) return mod; + } + return null; + } + class ActiveMod { public final String name; public final String id; diff --git a/modules/utils/src/main/java/org/polyfrost/oneconfig/api/platform/v1/Platform.java b/modules/utils/src/main/java/org/polyfrost/oneconfig/api/platform/v1/Platform.java index 919ecd6e9..b5e620b36 100644 --- a/modules/utils/src/main/java/org/polyfrost/oneconfig/api/platform/v1/Platform.java +++ b/modules/utils/src/main/java/org/polyfrost/oneconfig/api/platform/v1/Platform.java @@ -61,8 +61,35 @@ static I18nPlatform getI18nPlatform() { boolean isCallingFromMinecraftThread(); + /** + * return the minecraft version of the current instance, as per the preprocessor standard. + * for example, if the minecraft version is 1.16.5, this will return 11605. + */ int getMinecraftVersion(); + /** + * return a string representing the loader and the minecraft version of the current instance, as per the preprocessor standard. + * for example, if the loader is Forge and the minecraft version is 1.16.5, this will return "1.16.5-forge". + */ + default String getLoaderString() { + char[] ver = String.valueOf(getMinecraftVersion()).toCharArray(); + StringBuilder sb = new StringBuilder(); + sb.append(ver[0]).append('.'); + if(ver[1] == '0') { + sb.append(ver[2]); + } else { + sb.append(ver[1]).append(ver[2]); + } + sb.append('.'); + if(ver[3] == '0') { + sb.append(ver[4]); + } else { + sb.append(ver[3]).append(ver[4]); + } + sb.append('-').append(getLoader().name().toLowerCase()); + return sb.toString(); + } + boolean isDevelopmentEnvironment(); Loader getLoader(); diff --git a/modules/utils/src/main/java/org/polyfrost/oneconfig/utils/v1/OneConfigUpdate.java b/modules/utils/src/main/java/org/polyfrost/oneconfig/utils/v1/OneConfigUpdate.java new file mode 100644 index 000000000..6286c1d52 --- /dev/null +++ b/modules/utils/src/main/java/org/polyfrost/oneconfig/utils/v1/OneConfigUpdate.java @@ -0,0 +1,152 @@ +/* + * This file is part of OneConfig. + * OneConfig - Next Generation Config Library for Minecraft: Java Edition + * Copyright (C) 2021~2024 Polyfrost. + * + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * OneConfig is licensed under the terms of version 3 of the GNU Lesser + * General Public License as published by the Free Software Foundation, AND + * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, + * either version 1.0 of the Additional Terms, 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License. If not, see . You should + * have also received a copy of the Additional Terms Applicable + * to OneConfig, as published by Polyfrost. If not, see + * + */ + +package org.polyfrost.oneconfig.utils.v1; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.ApiStatus; +import org.polyfrost.oneconfig.api.platform.v1.LoaderPlatform; +import org.polyfrost.oneconfig.api.platform.v1.Platform; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; + +public final class OneConfigUpdate { + private static final Logger LOGGER = LogManager.getLogger("OneConfig/Updates"); + public static final String ONECONFIG_REPO = "https://repo.polyfrost.org/"; + private static OneConfigUpdate releases; + private static OneConfigUpdate snapshots; + public final boolean snapshot; + private volatile boolean fin = false; + private volatile boolean hasUpdate = false; + + public static OneConfigUpdate release() { + if (releases == null) releases = new OneConfigUpdate(false); + return releases; + } + + public static OneConfigUpdate snapshot() { + if (snapshots == null) snapshots = new OneConfigUpdate(true); + return snapshots; + } + + private OneConfigUpdate(boolean snapshot) { + this.snapshot = snapshot; + Multithreading.runAsync(this::fetchUpdateStatus); + } + + /** + * Returns true if there is an update available, blocking this thread until done. + */ + public boolean hasUpdate() { + if(!fin) { + while (true) { + if (fin) break; + } + } + return hasUpdate; + } + + /** + * Returns true if the update status has been checked. + *
you can use this method to avoid the blocking behavior of {@link #hasUpdate()}. + */ + public boolean hasChecked() { + return fin; + } + + private synchronized void fetchUpdateStatus() { + LoaderPlatform.ActiveMod self = Platform.getLoaderPlatform().getLoadedMod("oneconfig"); + if (self == null) { + LOGGER.warn("version check failed: failed to determine current version"); + return; + } + + StringBuilder sb = new StringBuilder(96); + sb.append(ONECONFIG_REPO); + if (snapshot) sb.append("snapshot/"); + else sb.append("releases/"); + sb.append("org/polyfrost/oneconfig-"); + sb.append(Platform.getInstance().getLoaderString()); + sb.append("/maven-metadata.xml"); + try (InputStream stream = NetworkUtils.setupConnection(sb.toString(), "OneConfig/1.0.0", 5000, false)) { + if (stream == null) { + LOGGER.warn("version check failed: failed to fetch metadata from {}", sb.toString()); + return; + } + // totally not over-engineered method to help with performance... + // why: no point in reading the entire file, we can progressively read more of it if needed + // but the ... tag should always be in the first 384 bytes + StringBuilder xml = new StringBuilder(384); + String latestVersion = null; + String next; + while ((next = getNext(stream)) != null) { + xml.append(next); + int startTag = xml.indexOf(""); + if (startTag == -1) continue; + int endTag = xml.indexOf("", startTag + 8); + if (endTag == -1) continue; + latestVersion = xml.substring(startTag + 8, endTag); + break; + } + if (latestVersion == null) { + LOGGER.warn("version check failed: failed to find latest version in metadata"); + return; + } + // no bother doing any other checks to see if the version is more - latest will always be more, plus means we can downgrade server-side if needed + if (!latestVersion.equals(self.version)) { + hasUpdate = true; + LOGGER.warn("OneConfig has an update available: {} -> {}", self.version, latestVersion); + } else LOGGER.info("no update found"); + } catch (Exception e) { + LOGGER.error("failed to check for updates! (unknown error)", e); + } finally { + fin = true; + } + } + + private static String getNext(InputStream is) throws IOException { + byte[] bytes = new byte[384]; + int read = is.read(bytes); + if (read == -1) return null; + return new String(bytes, 0, read); + } + + /** + * creates a marker file to indicate to the loader that on next launch, the mod should be updated. + */ + @ApiStatus.Internal + public static void makeUpdateMarker() { + try { + Files.createFile(Paths.get("oneconfig", "UPDATE")); + } catch (IOException e) { + LOGGER.error("failed to create update marker! maybe it already exists"); + } + } +} diff --git a/versions/api/platform.api b/versions/api/platform.api index 7fa29138f..c223888c2 100644 --- a/versions/api/platform.api +++ b/versions/api/platform.api @@ -104,7 +104,7 @@ public class org/polyfrost/oneconfig/api/ui/v1/screen/PolyUIScreen : org/polyfro public fun (Lorg/polyfrost/polyui/property/Settings;Lorg/polyfrost/polyui/event/InputManager;Lorg/polyfrost/polyui/input/Translator;Lorg/polyfrost/polyui/unit/Align;Lorg/polyfrost/polyui/color/Colors;Lorg/polyfrost/polyui/color/PolyColor;Lorg/polyfrost/polyui/unit/Vec2;Lorg/polyfrost/polyui/unit/Vec2;[Lorg/polyfrost/polyui/component/Drawable;)V public fun (Lorg/polyfrost/polyui/unit/Align;Lorg/polyfrost/polyui/unit/Vec2;[Lorg/polyfrost/polyui/component/Drawable;)V public fun ([Lorg/polyfrost/polyui/component/Drawable;)V - protected final fun adjustResolution (FF)V + protected final fun adjustResolution (FFZ)V public final fun closeCallback (Ljava/lang/Runnable;)Lorg/polyfrost/oneconfig/api/ui/v1/screen/PolyUIScreen; @1.12.2-forge,1.8.9-forge public fun doesGuiPauseGame ()Z diff --git a/versions/build.gradle.kts b/versions/build.gradle.kts index ff89fe67f..cb1f226a6 100644 --- a/versions/build.gradle.kts +++ b/versions/build.gradle.kts @@ -32,7 +32,7 @@ val natives = listOf("windows", "windows-arm64", "linux", "macos", "macos-arm64" val tweakClass = "org.polyfrost.oneconfig.internal.init.OneConfigTweaker" base { - archivesName.set("$modId-$platform") + archivesName.set(platform.toString()) } loom { @@ -321,9 +321,13 @@ tasks { } } +signing { + sign(publishing.publications) +} + publishing { publications { - register("$modId-$platform") { + register(platform.toString()) { groupId = group.toString() artifactId = base.archivesName.get() diff --git a/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/screen/PolyUIScreen.java b/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/screen/PolyUIScreen.java index 779381ef9..7a6c75614 100644 --- a/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/screen/PolyUIScreen.java +++ b/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/screen/PolyUIScreen.java @@ -91,6 +91,7 @@ public PolyUIScreen(@Nullable Settings settings, Settings s = settings == null ? new Settings() : settings; s.enableInitCleanup(false); + s.enableForceSettingInitialSize(true); if (drawables == null || drawables.length == 0) { if (inputManager == null) throw new IllegalArgumentException("Must be created with an inputManager or drawables"); this.inputManager = inputManager; @@ -106,7 +107,7 @@ public PolyUIScreen(@Nullable Settings settings, this.polyUI.setWindow(window); this.inputManager = this.polyUI.getInputManager(); this.desiredResolution = desiredResolution; - adjustResolution(width(), height()); + adjustResolution(width(), height(), true); } } @@ -133,7 +134,7 @@ public PolyUIScreen(@NotNull PolyUI polyUI) { polyUI.setWindow(window); } - protected final void adjustResolution(float w, float h) { + protected final void adjustResolution(float w, float h, boolean force) { // asm: normally, a polyui instance is as big as its window and that is it. // however, inside minecraft, the actual content is smaller than the window size, so resizing it directly would just fuck it up. // so instead, the developer specifies a resolution that their UI was designed for, and we resize accordingly. @@ -142,7 +143,7 @@ protected final void adjustResolution(float w, float h) { float sy = h / desiredResolution.getY(); if (sx == 1f && sy == 1f) return; Vec2 size = polyUI.getMaster().getSize(); - polyUI.resize(size.getX() * sx, size.getY() * sy, false); + polyUI.resize(size.getX() * sx, size.getY() * sy, force); } @@ -185,7 +186,7 @@ public final void onResize(Minecraft client, int width, int height) { if (polyUI == null) return; float w = (float) UResolution.getViewportWidth(); float h = (float) UResolution.getViewportHeight(); - adjustResolution(w, h); + adjustResolution(w, h, false); } @Override diff --git a/versions/src/main/java/org/polyfrost/oneconfig/internal/init/OneConfigTweaker.java b/versions/src/main/java/org/polyfrost/oneconfig/internal/init/OneConfigTweaker.java index 68e1ae834..f12247eab 100644 --- a/versions/src/main/java/org/polyfrost/oneconfig/internal/init/OneConfigTweaker.java +++ b/versions/src/main/java/org/polyfrost/oneconfig/internal/init/OneConfigTweaker.java @@ -31,6 +31,7 @@ import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; import net.minecraftforge.fml.relauncher.CoreModManager; +import org.polyfrost.oneconfig.api.platform.v1.Platform; import org.polyfrost.oneconfig.utils.v1.MHUtils; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; @@ -53,7 +54,7 @@ /** * Mixin-related loading code adapted from EssentialGG's EssentialLoader under GPL-3.0 - * https://github.com/EssentialGG/EssentialLoader/blob/master/LICENSE + * here */ @SuppressWarnings("unused") public class OneConfigTweaker implements ITweaker { @@ -72,7 +73,7 @@ public class OneConfigTweaker implements ITweaker { public OneConfigTweaker() { final List sourceFiles = getSourceFiles(); if (sourceFiles.isEmpty()) { - LOGGER.fatal("Not able to jar sources. mixin will NOT work!"); + if (!Platform.getInstance().isDevelopmentEnvironment()) LOGGER.fatal("Not able to detect jar sources. mixin will NOT work!"); return; } for (SourceFile sourceFile : sourceFiles) { diff --git a/versions/src/main/java/org/polyfrost/oneconfig/internal/mixin/CrashReportMixin.java b/versions/src/main/java/org/polyfrost/oneconfig/internal/mixin/CrashReportMixin.java new file mode 100644 index 000000000..0e3069f14 --- /dev/null +++ b/versions/src/main/java/org/polyfrost/oneconfig/internal/mixin/CrashReportMixin.java @@ -0,0 +1,70 @@ +/* + * This file is part of OneConfig. + * OneConfig - Next Generation Config Library for Minecraft: Java Edition + * Copyright (C) 2021~2024 Polyfrost. + * + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * OneConfig is licensed under the terms of version 3 of the GNU Lesser + * General Public License as published by the Free Software Foundation, AND + * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, + * either version 1.0 of the Additional Terms, 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License. If not, see . You should + * have also received a copy of the Additional Terms Applicable + * to OneConfig, as published by Polyfrost. If not, see + * + */ + +package org.polyfrost.oneconfig.internal.mixin; + +import net.minecraft.crash.CrashReport; +import org.polyfrost.oneconfig.api.ui.v1.LwjglManager; +import org.polyfrost.oneconfig.api.ui.v1.TinyFD; +import org.polyfrost.oneconfig.utils.v1.OneConfigUpdate; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(CrashReport.class) +public abstract class CrashReportMixin { + @Inject(method = "", at = @At("RETURN")) + private void ocfg$checkApiIssues(String desc, Throwable cause, CallbackInfo ci) { + if (cause instanceof LinkageError) { + if (cause.getMessage().contains("org.polyfrost.oneconfig")) { + ocfg$apiDeath(true); + return; + } + for (StackTraceElement e : cause.getStackTrace()) { + if (e.getClassName().contains("org.polyfrost.oneconfig")) { + ocfg$apiDeath(true); + return; + } + } + // asm: still show the window in this case: it's a possible error. + ocfg$apiDeath(false); + } + } + + @Unique + private void ocfg$apiDeath(boolean certain) { + if(!OneConfigUpdate.release().hasUpdate()) return; + TinyFD tinyfd = LwjglManager.INSTANCE.getTinyFD(); + String title = certain ? "OneConfig API Error" : "OneConfig API Error (Possibly)"; + String message = "OneConfig has detected an crash that is potentially caused by an outdated version of OneConfig.\nYou can probably fix this by updating OneConfig by pressing OK, and restarting your game."; + boolean upd = tinyfd.showMessageBox(title, message, TinyFD.OK_CANCEL_DIALOG, TinyFD.WARNING_ICON, true); + if (upd) { + OneConfigUpdate.makeUpdateMarker(); + } + } +} diff --git a/versions/src/main/java/org/polyfrost/oneconfig/internal/platform/v1/PlatformImpl.java b/versions/src/main/java/org/polyfrost/oneconfig/internal/platform/v1/PlatformImpl.java index b8ea973cb..6f66a73c8 100644 --- a/versions/src/main/java/org/polyfrost/oneconfig/internal/platform/v1/PlatformImpl.java +++ b/versions/src/main/java/org/polyfrost/oneconfig/internal/platform/v1/PlatformImpl.java @@ -37,20 +37,20 @@ public boolean isCallingFromMinecraftThread() { @Override public int getMinecraftVersion() { - //#if MC>=12000 - //$$ return 12000; - //#elseif MC>=11900 - //$$ return 11900; - //#elseif MC>=11800 - //$$ return 11800; - //#elseif MC>=11700 - //$$ return 11700; - //#elseif MC>=11600 - //$$ return 11600; - //#elseif MC>=11200 - //$$ return 11200; + //#if MC==12004 + //$$ return 12004; + //#elseif MC==11904 + //$$ return 11904; + //#elseif MC==11801 + //$$ return 11801; + //#elseif MC==11701 + //$$ return 11701; + //#elseif MC==11605 + //$$ return 11605; + //#elseif MC==11202 + //$$ return 11202; //#else - return 10800; + return 10809; //#endif } diff --git a/versions/src/main/resources/mixins.oneconfig.json b/versions/src/main/resources/mixins.oneconfig.json index 7613c520d..98a6bf442 100644 --- a/versions/src/main/resources/mixins.oneconfig.json +++ b/versions/src/main/resources/mixins.oneconfig.json @@ -1,20 +1,21 @@ { - "compatibilityLevel": "JAVA_8", - "minVersion": "0.7", - "package": "org.polyfrost.oneconfig.internal.mixin", - "refmap": "mixins.oneconfig.refmap.json", - "plugin": "org.polyfrost.oneconfig.internal.init.OneConfigMixinInit", - "injectors": { - "maxShiftBy": 5 - }, - "verbose": true, - "client": [ - "GuiIngameMixin", - "MinecraftMixin", - "NetworkManagerMixin", - "compat.OptifineConfigMixin", - "ShaderGroupAccessor", - "compat.VigilantCompatMixin", - "WorldClientMixin" - ] + "compatibilityLevel": "JAVA_8", + "minVersion": "0.7", + "package": "org.polyfrost.oneconfig.internal.mixin", + "refmap": "mixins.oneconfig.refmap.json", + "plugin": "org.polyfrost.oneconfig.internal.init.OneConfigMixinInit", + "injectors": { + "maxShiftBy": 5 + }, + "verbose": true, + "client": [ + "CrashReportMixin", + "GuiIngameMixin", + "MinecraftMixin", + "NetworkManagerMixin", + "ShaderGroupAccessor", + "WorldClientMixin", + "compat.OptifineConfigMixin", + "compat.VigilantCompatMixin" + ] } \ No newline at end of file