From 76b93874b1e225161e70e71d0f5d70ffedb44b3f Mon Sep 17 00:00:00 2001 From: robotum1 <333931377+robotum1@users.noreply.github.com> Date: Fri, 25 Sep 2026 18:29:34 +0100 Subject: [PATCH 1/6] Update to 26.3 --- gradle/libs.versions.toml | 14 +++++++------- .../commands/commands/NotebotCommand.java | 5 +++-- .../meteorclient/gui/screens/CommitsScreen.java | 11 ++++++----- .../meteorclient/mixin/ClientLevelMixin.java | 4 ++-- .../systems/accounts/MicrosoftLogin.java | 5 +++-- .../systems/modules/misc/DiscordPresence.java | 5 +++-- .../systems/modules/misc/swarm/Swarm.java | 6 ++++-- 7 files changed, 28 insertions(+), 22 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0f922fa956b..42b965e1970 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,9 +1,9 @@ [versions] # Fabric (https://fabricmc.net/develop) jdk = "25" -minecraft = "26.3-pre-1" -fabric-loader = "0.19.3" -fabric-api = "0.159.1+26.3" +minecraft = "26.3" +fabric-loader = "0.19.5" +fabric-api = "0.161.0+26.3" # Plugins # Loom (https://github.com/FabricMC/fabric-loom) @@ -13,13 +13,13 @@ loom = "1.17-SNAPSHOT" # Baritone (https://github.com/MeteorDevelopment/baritone) baritone = "26.1-SNAPSHOT" # Sodium (https://github.com/CaffeineMC/sodium-fabric) -sodium = "mc26.2-0.9.1-fabric" +sodium = "mc26.3-0.9.2-fabric" # Lithium (https://github.com/CaffeineMC/lithium-fabric) -lithium = "mc26.2-0.25.2-fabric" +lithium = "mc26.3-0.26.1-fabric" # Iris (https://github.com/IrisShaders/Iris) -iris = "1.11.2+26.2-fabric" +iris = "1.11.6+26.3-fabric" # ModMenu (https://github.com/TerraformersMC/ModMenu) -modmenu = "20.0.1" +modmenu = "21.0.0" # Orbit (https://github.com/MeteorDevelopment/orbit) orbit = "0.2.4" # Starscript (https://github.com/MeteorDevelopment/starscript) diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java index 6f3bb0350b3..cc13cedf45f 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java @@ -5,6 +5,7 @@ package meteordevelopment.meteorclient.commands.commands; +import com.mojang.blaze3d.Blaze3D; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; @@ -24,11 +25,11 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.sounds.SoundEvent; -import net.minecraft.util.Util; import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; import java.io.FileWriter; import java.io.IOException; +import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -48,7 +49,7 @@ public NotebotCommand() { @Override public void build(LiteralArgumentBuilder builder) { builder.then(literal("help").executes(_ -> { - Util.getPlatform().openUri("https://github.com/MeteorDevelopment/meteor-client/wiki/Notebot-Guide"); + Blaze3D.openUri(URI.create("https://github.com/MeteorDevelopment/meteor-client/wiki/Notebot-Guide")); return SINGLE_SUCCESS; })); diff --git a/src/main/java/meteordevelopment/meteorclient/gui/screens/CommitsScreen.java b/src/main/java/meteordevelopment/meteorclient/gui/screens/CommitsScreen.java index b045d95641a..c0c6243a6ca 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/screens/CommitsScreen.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/screens/CommitsScreen.java @@ -5,6 +5,7 @@ package meteordevelopment.meteorclient.gui.screens; +import com.mojang.blaze3d.Blaze3D; import meteordevelopment.meteorclient.addons.GithubRepo; import meteordevelopment.meteorclient.addons.MeteorAddon; import meteordevelopment.meteorclient.gui.GuiTheme; @@ -13,8 +14,8 @@ import meteordevelopment.meteorclient.gui.widgets.containers.WTable; import meteordevelopment.meteorclient.utils.network.Http; import meteordevelopment.meteorclient.utils.network.MeteorExecutor; -import net.minecraft.util.Util; +import java.net.URI; import java.net.http.HttpResponse; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; @@ -66,11 +67,11 @@ private void populateHeader(String headerMessage) { l.add(theme.label(headerMessage)).expandX(); String website = addon.getWebsite(); - if (website != null) l.add(theme.button("Website")).widget().action = () -> Util.getPlatform().openUri(website); + if (website != null) l.add(theme.button("Website")).widget().action = () -> Blaze3D.openUri(URI.create(website)); l.add(theme.button("GitHub")).widget().action = () -> { GithubRepo repo = addon.getRepo(); - Util.getPlatform().openUri(String.format("https://github.com/%s/tree/%s", repo.getOwnerName(), repo.branch())); + Blaze3D.openUri(URI.create(String.format("https://github.com/%s/tree/%s", repo.getOwnerName(), repo.branch()))); }; } @@ -91,7 +92,7 @@ private void populateError() { l.add(theme.label("Consider using an authentication token: ")).expandX(); l.add(theme.button("Authorization Guide")).widget().action = () -> { - Util.getPlatform().openUri("https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens"); + Blaze3D.openUri(URI.create("https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens")); }; } @@ -115,7 +116,7 @@ private void populateCommits() { String date = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(commit.commit.committer.date)); t.add(theme.label(date)).top().right().widget().color = theme.textSecondaryColor(); - t.add(theme.label(getMessage(commit))).widget().action = () -> Util.getPlatform().openUri(String.format("https://github.com/%s/commit/%s", addon.getRepo().getOwnerName(), commit.sha)); + t.add(theme.label(getMessage(commit))).widget().action = () -> Blaze3D.openUri(URI.create(String.format("https://github.com/%s/commit/%s", addon.getRepo().getOwnerName(), commit.sha))); t.row(); } } diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/ClientLevelMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/ClientLevelMixin.java index 9f0135be996..f779a7e8374 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/ClientLevelMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/ClientLevelMixin.java @@ -64,8 +64,8 @@ private void onAddDestroyBlockEffect(BlockPos pos, BlockState blockState, Callba if (Modules.get().get(NoRender.class).noParticle(ParticleTypes.BLOCK)) ci.cancel(); } - @Inject(method = "addBreakingBlockEffect", at = @At("HEAD"), cancellable = true) - private void onAddBlockBreakingParticles(BlockPos pos, Direction direction, CallbackInfo ci) { + @Inject(method = "addBreakingParticles", at = @At("HEAD"), cancellable = true) + private void onAddBlockBreakingParticles(BlockPos pos, Direction direction, BlockState state, CallbackInfo ci) { if (Modules.get().get(NoRender.class).noParticle(ParticleTypes.BLOCK)) ci.cancel(); } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/accounts/MicrosoftLogin.java b/src/main/java/meteordevelopment/meteorclient/systems/accounts/MicrosoftLogin.java index e32fe1e561b..3e5254e09eb 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/accounts/MicrosoftLogin.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/accounts/MicrosoftLogin.java @@ -5,9 +5,9 @@ package meteordevelopment.meteorclient.systems.accounts; +import com.mojang.blaze3d.Blaze3D; import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.utils.network.MeteorExecutor; -import net.minecraft.util.Util; import net.raphimc.minecraftauth.MinecraftAuth; import net.raphimc.minecraftauth.java.JavaAuthManager; import net.raphimc.minecraftauth.java.model.MinecraftProfile; @@ -19,6 +19,7 @@ import net.raphimc.minecraftauth.msa.service.impl.DeviceCodeMsaAuthService; import org.jspecify.annotations.Nullable; +import java.net.URI; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -54,7 +55,7 @@ public static String getRefreshToken(Consumer callback) { .login(DeviceCodeMsaAuthService::new, (Consumer) deviceCode -> { String urlString = deviceCode.getDirectVerificationUri(); urlFuture.complete(urlString); - Util.getPlatform().openUri(urlString); + Blaze3D.openUri(URI.create(urlString)); }); MsaToken msaToken = authManager.getMsaToken().getUpToDate(); diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/DiscordPresence.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/DiscordPresence.java index a8dda6dab0d..01de40a4f28 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/DiscordPresence.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/DiscordPresence.java @@ -7,6 +7,7 @@ //Created by squidoodly +import com.mojang.blaze3d.Blaze3D; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import meteordevelopment.discordipc.DiscordIPC; import meteordevelopment.discordipc.RichPresence; @@ -34,9 +35,9 @@ import net.minecraft.client.gui.screens.worldselection.EditWorldScreen; import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen; import net.minecraft.realms.RealmsScreen; -import net.minecraft.util.Util; import org.meteordev.starscript.Script; +import java.net.URI; import java.util.ArrayList; import java.util.List; @@ -288,7 +289,7 @@ private void onOpenScreen(OpenScreenEvent event) { @Override public WWidget getWidget(GuiTheme theme) { WButton help = theme.button("Open documentation."); - help.action = () -> Util.getPlatform().openUri("https://github.com/MeteorDevelopment/meteor-client/wiki/Starscript"); + help.action = () -> Blaze3D.openUri(URI.create("https://github.com/MeteorDevelopment/meteor-client/wiki/Starscript")); return help; } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/Swarm.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/Swarm.java index c3c5317c5f3..ef06a936e79 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/Swarm.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/Swarm.java @@ -5,6 +5,7 @@ package meteordevelopment.meteorclient.systems.modules.misc.swarm; +import com.mojang.blaze3d.Blaze3D; import meteordevelopment.meteorclient.events.game.GameJoinedEvent; import meteordevelopment.meteorclient.events.game.GameLeftEvent; import meteordevelopment.meteorclient.events.world.TickEvent; @@ -17,7 +18,8 @@ import meteordevelopment.meteorclient.systems.modules.Categories; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.orbit.EventHandler; -import net.minecraft.util.Util; + +import java.net.URI; public class Swarm extends Module { private final SettingGroup sgGeneral = settings.getDefaultGroup(); @@ -72,7 +74,7 @@ public WWidget getWidget(GuiTheme theme) { stop.action = this::close; WButton guide = list.add(theme.button("Guide")).expandX().widget(); - guide.action = () -> Util.getPlatform().openUri("https://github.com/MeteorDevelopment/meteor-client/wiki/Swarm-Guide"); + guide.action = () -> Blaze3D.openUri(URI.create("https://github.com/MeteorDevelopment/meteor-client/wiki/Swarm-Guide")); return list; } From 007f64158b6d087b80bafcf046c06c71bed55c28 Mon Sep 17 00:00:00 2001 From: robotum1 <333931377+robotum1@users.noreply.github.com> Date: Fri, 25 Sep 2026 19:41:57 +0100 Subject: [PATCH 2/6] Fix crash when a key is pressed while the game is starting 26.3 pumps input events during Minecraft's constructor, before Meteor has initialized, so ScreenMixin#onKeyPressed hit a null Modules instance. --- .../java/meteordevelopment/meteorclient/mixin/ScreenMixin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/ScreenMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/ScreenMixin.java index dd8385b0d85..5e5127110ca 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/ScreenMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/ScreenMixin.java @@ -61,7 +61,8 @@ private static void onDefaultHandleClickEvent(ClickEvent event, Minecraft minecr @Inject(method = "keyPressed", at = @At("HEAD"), cancellable = true) private void onKeyPressed(KeyEvent event, CallbackInfoReturnable cir) { - if ((Object) (this) instanceof ChatScreen) return; + // Input events are pumped while the game is still starting, before Meteor has initialized + if ((Object) (this) instanceof ChatScreen || Modules.get() == null) return; GUIMove guiMove = Modules.get().get(GUIMove.class); if ((guiMove.disableArrows() && meteor$isArray(event.key())) || (guiMove.disableSpace() && event.key() == KEY_SPACE)) { cir.setReturnValue(true); From e1c2ec0a21d7f4697401a82a32dc56a76bac8b1c Mon Sep 17 00:00:00 2001 From: robotum1 <333931377+robotum1@users.noreply.github.com> Date: Fri, 25 Sep 2026 20:28:34 +0100 Subject: [PATCH 3/6] Fix typing in text boxes SDL only delivers typed characters while text input is enabled, and vanilla enables it from EditBox#setFocused. WTextBox never did, so Meteor's text boxes received key presses but no characters. --- .../meteorclient/gui/widgets/input/WTextBox.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/meteordevelopment/meteorclient/gui/widgets/input/WTextBox.java b/src/main/java/meteordevelopment/meteorclient/gui/widgets/input/WTextBox.java index 0f10db85ffb..91a674d6980 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/widgets/input/WTextBox.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/widgets/input/WTextBox.java @@ -716,6 +716,9 @@ public void setFocused(boolean focused) { this.focused = focused; + // SDL only delivers typed characters while text input is enabled + mc.textInputManager().onTextInputFocusChange(this, focused); + resetSelection(); if (wasJustFocused) onCursorChanged(); From 53d71d0cd623d3e6a9155669c3be3491c9a37016 Mon Sep 17 00:00:00 2001 From: robotum1 <333931377+robotum1@users.noreply.github.com> Date: Fri, 25 Sep 2026 20:28:34 +0100 Subject: [PATCH 4/6] Fix migrating keybinds saved in the legacy format Legacy keybinds store raw GLFW key codes, mouse buttons and modifier bits, but input is SDL based now, so they were loaded as the wrong keys (e.g. the grave accent key became keypad 8). Translate them through the key names, which are the same for both. --- .../meteorclient/utils/misc/Keybind.java | 94 ++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/Keybind.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/Keybind.java index 61fa056d20c..05cfa022e81 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/misc/Keybind.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/Keybind.java @@ -251,17 +251,105 @@ public Keybind fromTag(CompoundTag tag) { } catch (IllegalArgumentException ignored) {} } } else { - // Legacy format: raw ints (GLFW) + // Legacy format: raw GLFW key codes, mouse buttons and modifier bits. + // Input is SDL based now, so translate them through the key names, which stayed the same. boolean isKey = tag.getBooleanOr("isKey", true); - int value = tag.getIntOr("value", InputConstants.UNKNOWN.getValue()); + int value = tag.getIntOr("value", -1); int mods = tag.getIntOr("modifiers", 0); - set(isKey ? keyboard(value) : mouse(value), isKey ? Modifier.fromRawValue(mods) : Set.of()); + set(isKey ? legacyKeyboard(value) : legacyMouse(value), isKey ? legacyModifiers(mods) : Set.of()); } return this; } + private static InputConstants.Key legacyKeyboard(int glfwKey) { + String name = switch (glfwKey) { + case 32 -> "space"; + case 39 -> "apostrophe"; + case 44 -> "comma"; + case 45 -> "minus"; + case 46 -> "period"; + case 47 -> "slash"; + case 59 -> "semicolon"; + case 61 -> "equal"; + case 91 -> "left.bracket"; + case 92 -> "backslash"; + case 93 -> "right.bracket"; + case 96 -> "grave.accent"; + case 161 -> "world.1"; + case 162 -> "world.2"; + case 256 -> "escape"; + case 257 -> "enter"; + case 258 -> "tab"; + case 259 -> "backspace"; + case 260 -> "insert"; + case 261 -> "delete"; + case 262 -> "right"; + case 263 -> "left"; + case 264 -> "down"; + case 265 -> "up"; + case 266 -> "page.up"; + case 267 -> "page.down"; + case 268 -> "home"; + case 269 -> "end"; + case 280 -> "caps.lock"; + case 281 -> "scroll.lock"; + case 282 -> "num.lock"; + case 283 -> "print.screen"; + case 284 -> "pause"; + case 330 -> "keypad.decimal"; + case 331 -> "keypad.divide"; + case 332 -> "keypad.multiply"; + case 333 -> "keypad.subtract"; + case 334 -> "keypad.add"; + case 335 -> "keypad.enter"; + case 336 -> "keypad.equal"; + case 340 -> "left.shift"; + case 341 -> "left.control"; + case 342 -> "left.alt"; + case 343 -> "left.win"; + case 344 -> "right.shift"; + case 345 -> "right.control"; + case 346 -> "right.alt"; + case 347 -> "right.win"; + case 348 -> "menu"; + default -> { + if (glfwKey >= 48 && glfwKey <= 57) yield String.valueOf((char) glfwKey); // 0-9 + if (glfwKey >= 65 && glfwKey <= 90) yield String.valueOf((char) (glfwKey + 32)); // a-z + if (glfwKey >= 290 && glfwKey <= 313) yield "f" + (glfwKey - 289); // F1-F24 + if (glfwKey >= 320 && glfwKey <= 329) yield "keypad." + (glfwKey - 320); // keypad 0-9 + yield null; + } + }; + + return name == null ? InputConstants.UNKNOWN : InputConstants.getKey("key.keyboard." + name); + } + + private static InputConstants.Key legacyMouse(int glfwButton) { + String name = switch (glfwButton) { + case 0 -> "left"; + case 1 -> "right"; + case 2 -> "middle"; + default -> String.valueOf(glfwButton + 1); + }; + + return glfwButton < 0 ? InputConstants.UNKNOWN : InputConstants.getKey("key.mouse." + name); + } + + private static Set legacyModifiers(int glfwMods) { + Set result = EnumSet.noneOf(Modifier.class); + + if ((glfwMods & 0x01) != 0) result.add(Modifier.SHIFT); + if ((glfwMods & 0x02) != 0) result.add(Modifier.CONTROL); + if ((glfwMods & 0x04) != 0) result.add(Modifier.ALT); + if ((glfwMods & 0x08) != 0) result.add(Modifier.SUPER); + if ((glfwMods & 0x10) != 0) result.add(Modifier.CAPS_LOCK); + if ((glfwMods & 0x20) != 0) result.add(Modifier.NUM_LOCK); + + return result; + } + private static InputConstants.Key keyboard(int key) { return InputConstants.Type.KEYBOARD.getOrCreate(key); } From d91a1f18b1beb7a43968d4feb382f04edfd0b69e Mon Sep 17 00:00:00 2001 From: robotum1 <333931377+robotum1@users.noreply.github.com> Date: Fri, 25 Sep 2026 20:41:35 +0100 Subject: [PATCH 5/6] Fix crash when hovering items with Meteor tooltips in container screens 26.3 container screens set tooltips through the Component list overload of setTooltipForNextFrame, which the mixin didn't cover, so MeteorTooltipData went through ClientTooltipComponent.create() and added a null line. --- .../mixin/GuiGraphicsExtractorMixin.java | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/GuiGraphicsExtractorMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/GuiGraphicsExtractorMixin.java index d5c7469ec0c..f2c8c76eec9 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/GuiGraphicsExtractorMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/GuiGraphicsExtractorMixin.java @@ -8,18 +8,11 @@ import com.llamalad7.mixinextras.injector.ModifyReceiver; import com.llamalad7.mixinextras.sugar.Local; import meteordevelopment.meteorclient.utils.tooltip.MeteorTooltipData; -import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; -import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipPositioner; -import net.minecraft.resources.Identifier; -import net.minecraft.util.FormattedCharSequence; import net.minecraft.world.inventory.tooltip.TooltipComponent; -import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.List; import java.util.Optional; @@ -27,15 +20,18 @@ @Mixin(value = GuiGraphicsExtractor.class) public abstract class GuiGraphicsExtractorMixin { - @Inject(method = "setTooltipForNextFrame(Lnet/minecraft/client/gui/Font;Ljava/util/List;Ljava/util/Optional;Lnet/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipPositioner;IIZLnet/minecraft/resources/Identifier;)V", at = @At(value = "INVOKE", target = "Ljava/util/Optional;ifPresent(Ljava/util/function/Consumer;)V", shift = At.Shift.BEFORE)) - private void onDrawTooltip(Font font, List tooltip, Optional component, ClientTooltipPositioner positioner, int xo, int yo, boolean replaceExisting, @Nullable Identifier style, CallbackInfo ci, @Local(name = "components") List components) { - if (component.isPresent() && component.get() instanceof MeteorTooltipData meteorTooltipData) + // Both overloads convert the tooltip image with ClientTooltipComponent.create(), which returns null for MeteorTooltipData, + // so add Meteor's own component instead and skip the vanilla conversion + @ModifyReceiver(method = { + "setTooltipForNextFrame(Lnet/minecraft/client/gui/Font;Ljava/util/List;Ljava/util/Optional;Lnet/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipPositioner;IIZLnet/minecraft/resources/Identifier;)V", + "setTooltipForNextFrame(Lnet/minecraft/client/gui/Font;Ljava/util/List;Ljava/util/Optional;IILnet/minecraft/resources/Identifier;Z)V" + }, at = @At(value = "INVOKE", target = "Ljava/util/Optional;ifPresent(Ljava/util/function/Consumer;)V")) + private Optional onDrawTooltip(Optional data, Consumer action, @Local(name = "components") List components) { + if (data.isPresent() && data.get() instanceof MeteorTooltipData meteorTooltipData) { components.add(meteorTooltipData.getComponent()); - } + return Optional.empty(); + } - @ModifyReceiver(method = "setTooltipForNextFrame(Lnet/minecraft/client/gui/Font;Ljava/util/List;Ljava/util/Optional;Lnet/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipPositioner;IIZLnet/minecraft/resources/Identifier;)V", at = @At(value = "INVOKE", target = "Ljava/util/Optional;ifPresent(Ljava/util/function/Consumer;)V")) - private Optional onDrawTooltip_modifyIfPresentReceiver(Optional data, Consumer action) { - if (data.isPresent() && data.get() instanceof MeteorTooltipData) return Optional.empty(); return data; } } From 9a9600699248bb4f34be5f05b93e42ff5c695e22 Mon Sep 17 00:00:00 2001 From: robotum1 <333931377+robotum1@users.noreply.github.com> Date: Fri, 25 Sep 2026 21:04:18 +0100 Subject: [PATCH 6/6] Don't call LevelRenderer#executeOutline for entity shaders Other mods inject into executeOutline expecting it to only run inside the main pass, e.g. Litematica draws schematics there and crashed with "Cannot dereference handle with no underlying resource" when called from submitEntities. Run the same outline pass directly instead. --- .../mixin/LevelRendererMixin.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/LevelRendererMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/LevelRendererMixin.java index d48a6a501e9..81a87334234 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/LevelRendererMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/LevelRendererMixin.java @@ -9,8 +9,10 @@ import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.resource.GraphicsResourceAllocator; import com.mojang.blaze3d.resource.ResourceHandle; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.renderpearl.api.buffers.GpuBufferSlice; +import com.mojang.renderpearl.api.commands.RenderPass; import it.unimi.dsi.fastutil.Stack; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import meteordevelopment.meteorclient.mixininterface.IEntityRenderState; @@ -33,12 +35,15 @@ import net.minecraft.client.renderer.state.level.LevelRenderState; import net.minecraft.world.entity.Entity; import org.joml.Vector4f; +import org.joml.Vector4fc; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.Optional; +import java.util.OptionalDouble; import java.util.function.Function; import static meteordevelopment.meteorclient.MeteorClient.mc; @@ -124,7 +129,7 @@ private void draw(LevelRenderState worldState, PoseStack matrices, EntityShader meteor$pushEntityOutlineFramebuffer(shader.framebuffer); try { try (var frame = renderDispatcher.prepareFrame(outlineRenderCommandQueue)) { - executeOutline(frame); + meteor$executeOutline(frame); } } finally { outlineRenderCommandQueue.submitsPerOrder.clear(); @@ -132,6 +137,17 @@ private void draw(LevelRenderState worldState, PoseStack matrices, EntityShader } } + // Same as executeOutline(), but without going through it, since other mods inject into it expecting to be inside the main pass + @Unique + private void meteor$executeOutline(FeatureRenderDispatcher.PreparedFrame frame) { + if (!currentFrameRendersEntityOutline) return; + + try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(() -> "Meteor entity outline", entityOutlineTarget.getColorTextureView(), Optional.of(ZERO_CLEAR_COLOR), null, OptionalDouble.empty())) { + RenderSystem.bindDefaultUniforms(pass); + frame.executeOutline(pass); + } + } + @Inject(method = "lambda$addMainPass$0", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;executeOutline(Lnet/minecraft/client/renderer/feature/FeatureRenderDispatcher$PreparedFrame;)V", shift = At.Shift.AFTER)) private void addMainPass$submitEntityVertices(CallbackInfo ci) { PostProcessShaders.submitEntityVertices(); @@ -161,7 +177,11 @@ private void onResize(int width, int height, CallbackInfo ci) { private RenderBuffers renderBuffers; @Shadow - protected abstract void executeOutline(FeatureRenderDispatcher.PreparedFrame featureFrame); + private boolean currentFrameRendersEntityOutline; + + @Shadow + @Final + private static Vector4fc ZERO_CLEAR_COLOR; @Unique private Stack framebufferStack;