Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9e0a101
Fix Some Sentry Issues
lowercasebtw Sep 2, 2026
1d1f305
Merge branch 'Polyfrost:v1' into v1
lowercasebtw Sep 2, 2026
2c6e315
Update minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/…
lowercasebtw Sep 2, 2026
4d89381
Update minecraft/src/main/java/org/polyfrost/oneconfig/internal/OneCo…
lowercasebtw Sep 2, 2026
dfd800e
Update minecraft/src/main/java/org/polyfrost/oneconfig/internal/OneCo…
lowercasebtw Sep 2, 2026
fb22bdf
Update minecraft/src/main/java/org/polyfrost/oneconfig/internal/OneCo…
lowercasebtw Sep 2, 2026
22d354c
Update modules/config-impl/src/main/java/org/polyfrost/oneconfig/api/…
lowercasebtw Sep 2, 2026
ddf6ff8
Update modules/config-impl/src/main/java/org/polyfrost/oneconfig/api/…
lowercasebtw Sep 2, 2026
16192ae
Add missing imports
lowercasebtw Sep 2, 2026
da5c383
Fix
lowercasebtw Sep 2, 2026
a6cfad9
rewrite skyblocker compat fixes
Wyvest Sep 3, 2026
1ff17eb
Merge upstream Polyfrost/OneConfig v1 into PR #1026
lowercasebtw Sep 8, 2026
337297e
chore: update hud api dump
lowercasebtw Sep 8, 2026
87a57d2
Fix Conflicts & Requested Changes
lowercasebtw Sep 8, 2026
241332e
Merge pull request #1 from lowercasebtw/pr1026-merge
lowercasebtw Sep 8, 2026
5c639da
Fix Sentry Issues
lowercasebtw Sep 10, 2026
4108a73
Merge remote-tracking branch 'origin/v1' into v1
lowercasebtw Sep 10, 2026
c464572
Fix merge conflict issue
lowercasebtw Sep 10, 2026
0f824fb
Merge branch 'v1' into pr/1026
Wyvest Sep 10, 2026
1cc922d
fix stuff
Wyvest Sep 10, 2026
b713356
even more fixes
Wyvest Sep 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public class CompatibilityPlatformImpl implements CompatibilityPlatform {

@Override
public void displayChatMessage(Component text) {
Minecraft minecraft = Minecraft.getInstance();
if (!minecraft.isSameThread()) {
minecraft.execute(() -> displayChatMessage(text));
return;
}
//? if >=1.21.4 {
MinecraftClientAudiences.of().audience().sendMessage(text);
//?} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,18 @@
import kotlin.Unit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
//todo import org.polyfrost.oneconfig.internal.generated.RelocatedMixins;
//? moul_compat {
import org.polyfrost.oneconfig.internal.generated.RelocatedMixins;
//? }
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
Expand Down Expand Up @@ -65,7 +69,6 @@ public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
public List<String> getMixins() {
List<String> mixins = new ArrayList<>();


//? moul_compat {
RelocatedMixins.INSTANCE.register(e -> {
mixins.add(e);
Expand Down Expand Up @@ -126,7 +129,12 @@ public List<String> getMixins() {
*///? }

//? skyblocker_compat {
mixins.add("compat.skyblocker.Mixin_SkyblockerFancyStatusBars");
Boolean skyblockerSingleton = declaresStaticMethod("de.hysky.skyblocker.skyblock.fancybars.FancyStatusBars", "initStatic");
if (skyblockerSingleton != null) {
mixins.add(skyblockerSingleton
? "compat.skyblocker.Mixin_SkyblockerFancyStatusBarsInstance"
: "compat.skyblocker.Mixin_SkyblockerFancyStatusBarsStatic");
}
mixins.add("compat.skyblocker.Mixin_SkyblockerWidgetManager");
//? }

Expand Down Expand Up @@ -227,6 +235,23 @@ private static boolean isClassPresent(String className) {
}
}

private static Boolean declaresStaticMethod(String className, String methodName) {
try (InputStream in = OneConfigMixinInit.class.getClassLoader()
.getResourceAsStream(className.replace('.', '/') + ".class")) {
if (in == null) return null;
ClassNode node = new ClassNode();
new ClassReader(in).accept(node, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
for (MethodNode method : node.methods) {
if (method.name.equals(methodName) && (method.access & Opcodes.ACC_STATIC) != 0) return Boolean.TRUE;
}
return Boolean.FALSE;
} catch (Throwable t) {
LogManager.getLogger(OneConfigMixinInit.class)
.warn("could not read {} to pick a mixin shape, skipping the mixins that depend on it", className, t);
return null;
}
}

@Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,19 @@

@Pseudo
@Mixin(FancyStatusBars.class)
public class Mixin_SkyblockerFancyStatusBars {
public class Mixin_SkyblockerFancyStatusBarsInstance {

//? if skyblocker_hud_v2 {
@Inject(method = "initStatic", at = @At("TAIL"), require = 0)
private static void oneconfig$registerHudCompat(CallbackInfo ci) {
SkyblockerCompat.initialize();
}

@Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true, require = 0)
private void oneconfig$suppressWhileEditing(CallbackInfoReturnable<Boolean> cir) {
if (CompatOverlayRenderer.oneConfigScreenOpen() && !SkyblockerCompat.isRedrawing()) {
cir.setReturnValue(false);
}
}
//?} else {
/*@Inject(method = "init", at = @At("TAIL"), require = 0)
@Inject(method = "initStatic", at = @At("TAIL"), require = 0, expect = 0)
private static void oneconfig$registerHudCompat(CallbackInfo ci) {
SkyblockerCompat.initialize();
}

//~ if >= 26.1 'render' -> 'extractRenderState'
@Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true, require = 0)
private static void oneconfig$suppressWhileEditing(CallbackInfoReturnable<Boolean> cir) {
if (CompatOverlayRenderer.oneConfigScreenOpen() && !SkyblockerCompat.isRedrawing()) {
@Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true, require = 0, expect = 0)
private void oneconfig$suppressWhileEditing(CallbackInfoReturnable<Boolean> cir) {
if (CompatOverlayRenderer.oneConfigScreenOpen() && !SkyblockerCompat.isRedrawing() && SkyblockerCompat.isActive()) {
cir.setReturnValue(false);
}
}
*///?}
}
//? }
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.polyfrost.oneconfig.internal.mixin.compat.skyblocker;

//? skyblocker_compat {
import de.hysky.skyblocker.skyblock.fancybars.FancyStatusBars;
import org.polyfrost.oneconfig.internal.compat.SkyblockerCompat;
import org.polyfrost.oneconfig.internal.ui.hud.CompatOverlayRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Pseudo
@Mixin(FancyStatusBars.class)
public class Mixin_SkyblockerFancyStatusBarsStatic {

@Inject(method = "init", at = @At("TAIL"), require = 0, expect = 0)
private static void oneconfig$registerHudCompat(CallbackInfo ci) {
SkyblockerCompat.initialize();
}

//~ if >= 26.1 'render' -> 'extractRenderState'
@Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true, require = 0, expect = 0)
private static void oneconfig$suppressWhileEditing(CallbackInfoReturnable<Boolean> cir) {
if (CompatOverlayRenderer.oneConfigScreenOpen() && !SkyblockerCompat.isRedrawing() && SkyblockerCompat.isActive()) {
cir.setReturnValue(false);
}
}
}
//? }
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import org.polyfrost.oneconfig.api.hud.v1.OneConfigHudWrapper
import org.polyfrost.oneconfig.api.hud.v1.events.HudEditorToggleEvent
import org.polyfrost.oneconfig.internal.ui.hud.CompatOverlayRenderer
import java.awt.Color
import java.lang.reflect.Field
import java.lang.reflect.Method
import java.util.function.Consumer
import kotlin.math.abs

Expand All @@ -33,47 +35,101 @@ object SkyblockerCompat {

private var initialized = false
private var dirty = false
private var barsUnavailable = false

@Volatile
private var redrawing = false

@Volatile
private var dragged: StatusBar? = null

//? if skyblocker_hud_v2 {
private fun statusBars(): Map<StatusBarType, StatusBar> = FancyStatusBars.INSTANCE.statusBars
private val cls = FancyStatusBars::class.java

private fun positioner(): BarPositioner = FancyStatusBars.INSTANCE.barPositioner
private val NO_INSTANCE = Any()

private fun saveBars() = FancyStatusBars.INSTANCE.saveBarConfig()
@Volatile
private var selfCache: Any? = null

private fun self(): Any? {
selfCache?.let { return if (it === NO_INSTANCE) null else it }
val found = runCatching { cls.getField("INSTANCE").get(null) }.getOrNull()
?: runCatching { cls.getMethod("getInstance").invoke(null) }.getOrNull()
if (found == null && !barsReady) return null
selfCache = found ?: NO_INSTANCE
return found
}

private fun placeBars() = FancyStatusBars.INSTANCE.placeBarsInPositioner()
private fun field(name: String): Field? = runCatching {
cls.getDeclaredField(name).apply { isAccessible = true }
}.onFailure { LOGGER.warn("Skyblocker FancyStatusBars.{} is unavailable", name, it) }.getOrNull()

private fun method(name: String, vararg params: Class<*>): Method? = runCatching {
cls.getDeclaredMethod(name, *params).apply { isAccessible = true }
}.onFailure { LOGGER.warn("Skyblocker FancyStatusBars.{}() is unavailable", name, it) }.getOrNull()

private val statusBarsField by lazy { field("statusBars") }
private val barPositionerField by lazy { field("barPositioner") }
private val saveBarConfigMethod by lazy { method("saveBarConfig") }
private val placeBarsMethod by lazy { method("placeBarsInPositioner") }
private val updatePositionsMethod by lazy { method("updatePositions", java.lang.Boolean.TYPE) }
private val healthFancyBarMethod by lazy { method("isHealthFancyBarEnabled") }
private val renderBarsMethod by lazy {
//~ if >= 26.1 'render' -> 'extractRenderState'
method("extractRenderState", GuiGraphicsExtractor::class.java, Minecraft::class.java)
}

private fun updatePositions(ignoreVisibility: Boolean) = FancyStatusBars.INSTANCE.updatePositions(ignoreVisibility)
private val handlesResolved: Boolean by lazy {
val ok = listOf(renderBarsMethod, saveBarConfigMethod, updatePositionsMethod, barPositionerField, statusBarsField)
.all { it != null }
if (!ok) LOGGER.warn("Skyblocker status bar compat is off: FancyStatusBars has an unrecognised shape")
ok
}

private fun healthFancyBarEnabled(): Boolean = FancyStatusBars.INSTANCE.isHealthFancyBarEnabled()
@Volatile
private var barsReady = false

private fun renderStatusBars(ctx: GuiGraphicsExtractor, mc: Minecraft) {
FancyStatusBars.INSTANCE.extractRenderState(ctx, mc)
@JvmStatic
fun isActive(): Boolean {
if (barsReady) return true
if (!handlesResolved) return false
if (runCatching { statusBarsField?.get(self()) }.getOrNull() == null) return false
barsReady = true
return true
}
//?} else {
/*private fun statusBars(): Map<StatusBarType, StatusBar> = FancyStatusBars.statusBars

private fun positioner(): BarPositioner = FancyStatusBars.barPositioner
private fun noStatusBars(error: Throwable?): Map<StatusBarType, StatusBar> {
if (!barsUnavailable) {
barsUnavailable = true
LOGGER.warn("Skyblocker's status bar API is unavailable, its bars will be left out of the OneConfig HUD editor", error)
}
return emptyMap()
}

@Suppress("UNCHECKED_CAST")
private fun statusBars(): Map<StatusBarType, StatusBar> =
runCatching { statusBarsField?.get(self()) as? Map<StatusBarType, StatusBar> }
.getOrElse { noStatusBars(it) } ?: noStatusBars(null)

private fun positioner(): BarPositioner =
checkNotNull(barPositionerField?.get(self()) as? BarPositioner) { "Skyblocker barPositioner is unavailable" }

private fun saveBars() = FancyStatusBars.saveBarConfig()
private fun saveBars() {
saveBarConfigMethod?.invoke(self())
}

private fun placeBars() = FancyStatusBars.placeBarsInPositioner()
private fun placeBars() {
placeBarsMethod?.invoke(self())
}

private fun updatePositions(ignoreVisibility: Boolean) = FancyStatusBars.updatePositions(ignoreVisibility)
private fun updatePositions(ignoreVisibility: Boolean) {
updatePositionsMethod?.invoke(self(), ignoreVisibility)
}

private fun healthFancyBarEnabled(): Boolean = FancyStatusBars.isHealthFancyBarEnabled()
private fun healthFancyBarEnabled(): Boolean = healthFancyBarMethod?.invoke(self()) as? Boolean == true

private fun renderStatusBars(ctx: GuiGraphicsExtractor, mc: Minecraft) {
//~ if >= 26.1 'render' -> 'extractRenderState'
FancyStatusBars.extractRenderState(ctx, mc)
renderBarsMethod?.invoke(self(), ctx, mc)
}
*///?}

@JvmStatic
fun isRedrawing(): Boolean = redrawing
Expand All @@ -86,6 +142,7 @@ object SkyblockerCompat {
}

private fun register() {
if (!handlesResolved) return
var count = 0
for (type in StatusBarType.values()) {
runCatching {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,21 +269,23 @@ object StellaCompat {
if (!element.isEnabled()) return@forEach

ctx.pose().pushMatrix()
ctx.pose().translate(element.x, element.y)
ctx.pose().scale(element.scale, element.scale)

val custom = customRenderers[element.id]
if (custom != null) custom(ctx)
else {
if (element.width == 0 && element.height == 0) {
element.width = element.text.width() + 4
element.height = element.text.height() + 6
try {
ctx.pose().translate(element.x, element.y)
ctx.pose().scale(element.scale, element.scale)

val custom = customRenderers[element.id]
if (custom != null) custom(ctx)
else {
if (element.width == 0 && element.height == 0) {
element.width = element.text.width() + 4
element.height = element.text.height() + 6
}

Render2D.drawString(ctx, element.text, 2, 3, shadow = false)
}

Render2D.drawString(ctx, element.text, 2, 3, shadow = false)
} finally {
ctx.pose().popMatrix()
}

ctx.pose().popMatrix()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ class MinecraftItemCatalogService : ItemCatalogService {
}

private fun renderPendingBatch() {
if (Minecraft.getInstance().player == null) {
retryRenderLater()
return
}
val guiWidth = Platform.screen().guiWidth()
val guiHeight = Platform.screen().guiHeight()
val windowWidth = Platform.screen().windowWidth()
Expand Down Expand Up @@ -585,6 +589,18 @@ class MinecraftItemCatalogService : ItemCatalogService {
}
}

private fun retryRenderLater() {
val retry = synchronized(requestLock) {
if (waiting.isEmpty()) {
renderScheduled = false
false
} else {
true
}
}
if (retry) scheduleRender()
}

private fun markRenderFinished() {
var scheduleNext = false
synchronized(requestLock) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,11 @@ private class PlatformImpl : PlatformContext {
}

fun resetPointerIcon() {
applyPointerIcon(PointerIcon.Default)
//? if >= 26.3 {
/*SDL_SetCursor(SDL_GetDefaultCursor())
*///?} else {
glfwSetCursor(handle, 0L)
//?}
}

private fun applyPointerIcon(pointerIcon: PointerIcon) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ abstract class ComposeScreen(

//? >= 1.21.10 {
override fun charTyped(event: CharacterEvent): Boolean {
val char = Char(event.codepoint)
val char = if (Character.isBmpCodePoint(event.codepoint)) Char(event.codepoint) else Char(0)
val codepoint = event.codepoint
//? >= 26.1 {
val modifiers = 0 //dropped from the event in 26.1 because glfw no longer passes them
Expand Down Expand Up @@ -824,6 +824,18 @@ abstract class ComposeScreen(
}

private fun sendCharacterEvent(char: Char, codePoint: Int, modifiers: Int): Boolean {
if (!Character.isBmpCodePoint(codePoint)) {
var handled = false
for (part in Character.toChars(codePoint)) {
handled = sendCharKeyEvent(part, codePoint, modifiers) || handled
}
return handled
}
if (char == KeyEvent.CHAR_UNDEFINED) return false
return sendCharKeyEvent(char, codePoint, modifiers)
}

private fun sendCharKeyEvent(char: Char, codePoint: Int, modifiers: Int): Boolean {
return sendKeyEventSafely {
androidx.compose.ui.input.key.KeyEvent(
key = Key(KeyEvent.VK_UNDEFINED),
Expand Down
Loading
Loading