diff options
Diffstat (limited to 'src/main/java/com/anthonyhilyard/iceberg/mixin/GuiGraphicsMixin.java')
-rw-r--r-- | src/main/java/com/anthonyhilyard/iceberg/mixin/GuiGraphicsMixin.java | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/src/main/java/com/anthonyhilyard/iceberg/mixin/GuiGraphicsMixin.java b/src/main/java/com/anthonyhilyard/iceberg/mixin/GuiGraphicsMixin.java new file mode 100644 index 0000000..30babf4 --- /dev/null +++ b/src/main/java/com/anthonyhilyard/iceberg/mixin/GuiGraphicsMixin.java @@ -0,0 +1,257 @@ +package com.anthonyhilyard.iceberg.mixin; + +import java.util.List; +import java.util.Optional; + +import com.anthonyhilyard.iceberg.events.RenderTooltipEvents; +import com.anthonyhilyard.iceberg.events.RenderTooltipEvents.ColorExtResult; +import com.anthonyhilyard.iceberg.events.RenderTooltipEvents.PreExtResult; +import com.anthonyhilyard.iceberg.util.Tooltips; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; + +import org.joml.Vector2ic; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Group; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipPositioner; +import net.minecraft.client.gui.screens.inventory.tooltip.TooltipRenderUtil; +import net.minecraft.client.renderer.Rect2i; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextColor; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.inventory.tooltip.TooltipComponent; +import net.minecraft.world.item.ItemStack; + +@Mixin(GuiGraphics.class) +public class GuiGraphicsMixin +{ + @Shadow + @Final + private Minecraft minecraft; + + private static ItemStack tooltipStack = ItemStack.EMPTY; + + private int storedTooltipWidth, storedTooltipHeight; + private Vector2ic storedPostPos; + + @Shadow + private void renderTooltipInternal(Font font, List<ClientTooltipComponent> list, int i, int j, ClientTooltipPositioner clientTooltipPositioner) {} + + @Inject(method = "renderTooltip(Lnet/minecraft/client/gui/Font;Lnet/minecraft/world/item/ItemStack;II)V", at = @At(value = "HEAD")) + protected void renderTooltipHead(Font font, ItemStack itemStack, int x, int y, CallbackInfo info) + { + tooltipStack = itemStack; + } + + @Inject(method = "renderTooltip(Lnet/minecraft/client/gui/Font;Lnet/minecraft/world/item/ItemStack;II)V", at = @At(value = "TAIL")) + protected void renderTooltipTail(Font font, ItemStack itemStack, int x, int y, CallbackInfo info) + { + tooltipStack = ItemStack.EMPTY; + } + + @Inject(method = "renderTooltip(Lnet/minecraft/client/gui/Font;Ljava/util/List;Ljava/util/Optional;II)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;renderTooltipInternal(Lnet/minecraft/client/gui/Font;Ljava/util/List;IILnet/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipPositioner;)V", + shift = Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILEXCEPTION) + public void renderTooltip(Font font, List<Component> textComponents, Optional<TooltipComponent> itemComponent, int x, int y, CallbackInfo info, List<ClientTooltipComponent> components) + { + Screen currentScreen = minecraft.screen; + + if (currentScreen != null && currentScreen instanceof AbstractContainerScreen<?> containerScreen) + { + Slot hoveredSlot = containerScreen.hoveredSlot; + + // If the tooltip stack is empty, try to get the stack from the slot under the mouse. + // This is needed for the creative inventory screen, which doesn't set the tooltip stack. + if (tooltipStack.isEmpty() && hoveredSlot != null) + { + tooltipStack = hoveredSlot.getItem(); + } + } + + List<ClientTooltipComponent> newComponents = Tooltips.gatherTooltipComponents(tooltipStack, textComponents, itemComponent, x, currentScreen.width, currentScreen.height, null, font, -1); + if (newComponents != null && !newComponents.isEmpty()) + { + components.clear(); + components.addAll(newComponents); + } + } + + private int xChange = 0, yChange = 0; + + @Inject(method = "renderTooltipInternal", at = @At(value = "HEAD"), cancellable = true) + private void preRenderTooltipInternal(Font font, List<ClientTooltipComponent> components, int x, int y, ClientTooltipPositioner positioner, CallbackInfo info) + { + GuiGraphics self = (GuiGraphics)(Object)this; + Screen currentScreen = minecraft.screen; + + int width = minecraft.getWindow().getGuiScaledWidth(); + int height = minecraft.getWindow().getGuiScaledHeight(); + + if (currentScreen != null) + { + width = currentScreen.width; + height = currentScreen.height; + } + else + { + if (FabricLoader.getInstance().isModLoaded("andromeda") && tooltipStack != null && !tooltipStack.isEmpty()) + { + List<ClientTooltipComponent> newComponents = Tooltips.gatherTooltipComponents(tooltipStack, Screen.getTooltipFromItem(minecraft, tooltipStack), tooltipStack.getTooltipImage(), x, width, height, null, font, -1); + if (newComponents != null && !newComponents.isEmpty()) + { + int oldWidth = 0, oldHeight = 0; + + for (ClientTooltipComponent tooltipComponent : components) + { + oldHeight += tooltipComponent.getHeight(); + int thisWidth = tooltipComponent.getWidth(font); + if (thisWidth > oldWidth) + { + oldWidth = thisWidth; + } + } + + components.clear(); + components.addAll(newComponents); + Rect2i newRect = Tooltips.calculateRect(tooltipStack, self, positioner, components, x, y, width, height, width, font, 0, true); + + if (tooltipStack == minecraft.player.getMainHandItem()) + { + PoseStack poseStack = RenderSystem.getModelViewStack(); + xChange = (oldWidth - newRect.getWidth()) / 2; + yChange = oldHeight - newRect.getHeight(); + + poseStack.translate(xChange, yChange, 0); + RenderSystem.applyModelViewMatrix(); + } + } + } + } + + if (!components.isEmpty()) + { + PreExtResult eventResult = null; + InteractionResult result = InteractionResult.PASS; + + eventResult = RenderTooltipEvents.PREEXT.invoker().onPre(tooltipStack, self, x, y, width, height, font, components, positioner, false, 0); + result = eventResult.result(); + + if (result != InteractionResult.PASS) + { + info.cancel(); + } + } + } + + @Inject(method = "renderTooltipInternal", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;drawManaged(Ljava/lang/Runnable;)V", + ordinal = 0, shift = Shift.BEFORE)) + private void preFillGradient(Font font, List<ClientTooltipComponent> components, int x, int y, ClientTooltipPositioner positioner, CallbackInfo info) + { + GuiGraphics self = (GuiGraphics)(Object)this; + Screen currentScreen = minecraft.screen; + ItemStack containerStack = ItemStack.EMPTY; + if (currentScreen != null && currentScreen instanceof AbstractContainerScreen<?> containerScreen) + { + Slot hoveredSlot = containerScreen.hoveredSlot; + if (hoveredSlot != null) + { + containerStack = hoveredSlot.getItem(); + } + } + + if (containerStack.isEmpty()) + { + containerStack = tooltipStack; + } + + if (!containerStack.isEmpty()) + { + int background = TooltipRenderUtil.BACKGROUND_COLOR; + int backgroundEnd = background; + int borderStart = TooltipRenderUtil.BORDER_COLOR_TOP; + int borderEnd = TooltipRenderUtil.BORDER_COLOR_BOTTOM; + + // Do colors now, sure why not. + ColorExtResult result = RenderTooltipEvents.COLOREXT.invoker().onColor(containerStack, self, x, y, font, background, backgroundEnd, borderStart, borderEnd, components, false, 0); + if (result != null) + { + background = result.backgroundStart(); + backgroundEnd = result.backgroundEnd(); + borderStart = result.borderStart(); + borderEnd = result.borderEnd(); + } + + Tooltips.currentColors = new Tooltips.TooltipColors(TextColor.fromRgb(background), TextColor.fromRgb(backgroundEnd), TextColor.fromRgb(borderStart), TextColor.fromRgb(borderEnd)); + } + } + + @Group(name = "storeLocals", min = 1, max = 1) + @Inject(method = "renderTooltipInternal", at = @At(value = "INVOKE", target = "Lorg/joml/Vector2ic;x()I", shift = Shift.BEFORE, remap = false), locals = LocalCapture.CAPTURE_FAILSOFT) + private void storeLocals(Font font, List<ClientTooltipComponent> components, int x, int y, ClientTooltipPositioner positioner, CallbackInfo info, int tooltipWidth, int tooltipHeight, int tooltipWidth2, int tooltipHeight2, Vector2ic postPos) + { + storedTooltipWidth = tooltipWidth2; + storedTooltipHeight = tooltipHeight2; + storedPostPos = postPos; + } + + @Group(name = "storeLocals", min = 1, max = 1) + @Inject(method = "renderTooltipInternal", at = @At(value = "INVOKE", target = "Lorg/joml/Vector2ic;x()I", shift = Shift.BEFORE, remap = false), locals = LocalCapture.CAPTURE_FAILSOFT) + private void storeLocalsOptifine(Font font, List<ClientTooltipComponent> components, int x, int y, ClientTooltipPositioner positioner, CallbackInfo info, Object preEvent, int tooltipWidth, int tooltipHeight, int tooltipWidth2, int tooltipHeight2, Vector2ic postPos) + { + storeLocals(font, components, x, y, positioner, info, tooltipWidth, tooltipHeight, tooltipWidth2, tooltipHeight2, postPos); + } + + @Inject(method = "renderTooltipInternal", at = @At(value = "TAIL")) + private void renderTooltipInternalTail(Font font, List<ClientTooltipComponent> components, int x, int y, ClientTooltipPositioner positioner, CallbackInfo info) + { + GuiGraphics self = (GuiGraphics)(Object)this; + Screen currentScreen = minecraft.screen; + ItemStack containerStack = ItemStack.EMPTY; + if (currentScreen != null && currentScreen instanceof AbstractContainerScreen<?> containerScreen) + { + Slot hoveredSlot = containerScreen.hoveredSlot; + if (hoveredSlot != null) + { + containerStack = hoveredSlot.getItem(); + } + } + + if (containerStack.isEmpty()) + { + containerStack = tooltipStack; + } + + if (!containerStack.isEmpty() && !components.isEmpty()) + { + RenderTooltipEvents.POSTEXT.invoker().onPost(containerStack, self, storedPostPos.x(), storedPostPos.y(), font, storedTooltipWidth, storedTooltipHeight, components, false, 0); + } + + if (FabricLoader.getInstance().isModLoaded("andromeda") && tooltipStack == minecraft.player.getMainHandItem()) + { + PoseStack poseStack = RenderSystem.getModelViewStack(); + poseStack.translate(-xChange, -yChange, 0); + RenderSystem.applyModelViewMatrix(); + } + + tooltipStack = ItemStack.EMPTY; + xChange = 0; + yChange = 0; + } +} |