Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RenderTooltipEvent #81

Merged
merged 8 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ usesMixins = true
separateMixinSourceSet =

# Adds some debug arguments like verbose output and class export.
usesMixinDebug = false
usesMixinDebug = true

# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
mixinPlugin =
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pluginManagement {
}

plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.27'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.30'
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package com.gtnewhorizon.gtnhlib.client.event;

import java.util.List;
import java.util.function.Consumer;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;

import cpw.mods.fml.common.eventhandler.Cancelable;
import cpw.mods.fml.common.eventhandler.Event;

/**
* RenderTooltipEvent is fired when a tooltip is about to be rendered. With this event you can modify colors,
* coordinates, font or replace the renderer completely. To stop the tooltip from rendering at all, you can
* {@link Event#setCanceled(boolean) cancel} it.
* <p>
* <b>Note:</b> Use {@link ItemTooltipEvent} to modify the text being displayed.
* <p>
* This event is fired on the {@link MinecraftForge#EVENT_BUS} (client-side only).
*
* @since 0.6.0
* @author glowredman
* @see ItemTooltipEvent
*/
@Cancelable
public class RenderTooltipEvent extends Event {

public static final int ORIGINAL_BG_START = 0xF0100010;
public static final int ORIGINAL_BG_END = 0xF0100010;
public static final int ORIGINAL_BORDER_START = 0x505000FF;
public static final int ORIGINAL_BORDER_END = (ORIGINAL_BORDER_START & 0xFEFEFE) >> 1
| ORIGINAL_BORDER_START & 0xFF000000;

/**
* The ItemStack of which the tooltip is being displayed
*/
@Nonnull
public final ItemStack itemStack;

/**
* The GUI in which the tooltip is being rendered
*/
@Nonnull
public final GuiScreen gui;

/**
* The upper background color in ARGB format
* <p>
* Default value: {@code 0xF0100010}
*/
public int backgroundStart;

/**
* The lower background color in ARGB format
* <p>
* Default value: {@code 0xF0100010}
*/
public int backgroundEnd;

/**
* The upper border color in ARGB format
* <p>
* Default value: {@code 0x505000FF}
*/
public int borderStart;

/**
* The lower border color in ARGB format
* <p>
* Default value: {@code 0x5028007F}
*/
public int borderEnd;

/**
* The X coordinate of the mouse cursor
*/
public int x;

/**
* The Y coordinate of the mouse cursor
*/
public int y;

/**
* The FontRenderer used to render the tooltip's text
* <p>
* Default value: {@link GuiScreen#fontRendererObj} or {@link Item#getFontRenderer(ItemStack)} (if that method
* doesn't return {@code null})
*/
@Nonnull
public FontRenderer font;

/**
* Optional hook to completely replace the rendering code. Will be used instead of the vanilla code if no
* {@code null}. The provided argument is the text to render.
* <p>
* <b>Note:</b> The usage may break compat with other mods, for example AppleCore!
* <p>
* Default value: {@code null}
*
* @apiNote The following GL states will be disabled before calling this hook: {@link GL12#GL_RESCALE_NORMAL},
* {@link GL11#GL_LIGHTING}, {@link GL11#GL_LIGHT0}, {@link GL11#GL_LIGHT1},
* {@link GL11#GL_COLOR_MATERIAL}, {@link GL11#GL_DEPTH_TEST}. They will be re-enabled after the hook is
* called. {@link Gui#zLevel GuiScreen.zLevel} and {@link RenderItem#zLevel GuiScreen.itemRender.zLevel}
* must be set/reset by the hook! An <a
* href=https://forge.gemwire.uk/wiki/Access_Transformers>AccessTransformer</a> may be needed for this.
*/
@Nullable
YannickMG marked this conversation as resolved.
Show resolved Hide resolved
public Consumer<List<String>> alternativeRenderer;

public RenderTooltipEvent(ItemStack itemStack, GuiScreen gui, int backgroundStart, int backgroundEnd,
int borderStart, int borderEnd, int x, int y, FontRenderer font) {
this.itemStack = itemStack;
this.gui = gui;
this.backgroundStart = backgroundStart;
this.backgroundEnd = backgroundEnd;
this.borderStart = borderStart;
this.borderEnd = borderEnd;
this.x = x;
this.y = y;
this.font = font;
}

/**
* Convenience method to set both background {@link #backgroundStart start}/{@link #backgroundEnd end} color to the
* same value (the default background does not have a gradient)
*
* @param background The background color in ARGB format
*/
public void setBackground(int background) {
this.backgroundStart = background;
this.backgroundEnd = background;
}

/**
* Calculates {@link #borderEnd} based on {@link #borderStart} using the vanilla algorithm
*/
public void calculateBorderEnd() {
this.borderEnd = (this.borderStart & 0xFEFEFE) >> 1 | this.borderStart & 0xFF000000;
}
}
2 changes: 2 additions & 0 deletions src/main/java/com/gtnewhorizon/gtnhlib/mixins/Mixins.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public enum Mixins {
.setPhase(Phase.EARLY).addMixinClasses("fml.MixinGuiModList")),
EVENT_BUS_ACCESSOR(new Builder("EventBusAccessor").addTargetedMod(TargetedMod.VANILLA).setSide(Side.BOTH)
.setPhase(Phase.EARLY).addMixinClasses("fml.EventBusAccessor", "fml.EnumHolderAccessor")),
TOOLTIP_RENDER(new Builder("TooltipRenderer").addMixinClasses("MixinGuiScreen").addTargetedMod(TargetedMod.VANILLA)
.setApplyIf(() -> true).setPhase(Phase.EARLY).setSide(Side.CLIENT)),
DEBUG_TEXTURES(new Builder("Dump textures sizes").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
.setPhase(Phase.EARLY)
.setApplyIf(() -> Boolean.parseBoolean(System.getProperty("gtnhlib.debugtextures", "false")))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package com.gtnewhorizon.gtnhlib.mixins.early;

import static com.gtnewhorizon.gtnhlib.client.event.RenderTooltipEvent.*;

import java.util.List;

import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
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;

import com.gtnewhorizon.gtnhlib.client.event.RenderTooltipEvent;

// This mixin must run before AppleCore's GuiScreenMixin because we're using an @Overwrite
@Mixin(priority = 999, value = GuiScreen.class)
public class MixinGuiScreen extends Gui {

@Unique
private ItemStack gtnhlib$currentStack;

@Shadow
protected static RenderItem itemRender;
@Shadow
public int width;
@Shadow
public int height;

@Inject(at = @At("HEAD"), method = "renderToolTip")
private void preRenderToolTip(ItemStack itemIn, int x, int y, CallbackInfo ci) {
this.gtnhlib$currentStack = itemIn;
}

@Inject(at = @At("TAIL"), method = "renderToolTip")
private void postRenderToolTip(CallbackInfo ci) {
this.gtnhlib$currentStack = null;
}

/**
* @author glowredman
* @reason Add RenderTooltipEvent
*/
@Overwrite(remap = false)
protected void drawHoveringText(List<String> textLines, int mouseX, int mouseY, FontRenderer font) {
YannickMG marked this conversation as resolved.
Show resolved Hide resolved
if (!textLines.isEmpty()) {
// spotless:off
/***************************************************************************************************************************************
* IMPORTANT NOTE: *
* The int variables width, lineWidth, x, y and height must stay in this order and no other int variables may be inserted before them. *
* This due to compat with AppleCore. *
* *
* The potentially conflicting mixin can be found here: *
* https://github.com/GTNewHorizons/AppleCore/blob/master/src/main/java/squeek/applecore/mixins/early/minecraft/GuiScreenMixin.java *
***************************************************************************************************************************************/
// spotless:on

// create event
RenderTooltipEvent event = new RenderTooltipEvent(
this.gtnhlib$currentStack,
(GuiScreen) (Object) this,
ORIGINAL_BG_START,
ORIGINAL_BG_END,
ORIGINAL_BORDER_START,
ORIGINAL_BORDER_END,
mouseX,
mouseY,
font);

// post event if called from renderToolTip
if (this.gtnhlib$currentStack != null) {
MinecraftForge.EVENT_BUS.post(event);
if (event.isCanceled()) {
// skip all rendering
return;
}
}

// set GL states
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
RenderHelper.disableStandardItemLighting();
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_DEPTH_TEST);

if (event.alternativeRenderer == null) {
// re-assign variables because they might have been modified by an event handler
mouseX = event.x;
mouseY = event.y;
font = event.font;

// determine max line width
int width = 0;
for (String s : textLines) {
int lineWidth = font.getStringWidth(s);
if (lineWidth > width) {
width = lineWidth;
}
}

// calculate coordinates
int x = mouseX + 12;
int y = mouseY - 12;
int height = 8;

if (textLines.size() > 1) {
height += 2 + (textLines.size() - 1) * 10;
}

if (x + width > this.width) {
x -= 28 + width;
}

if (y + height + 6 > this.height) {
y = this.height - height - 6;
}

// set Z level
this.zLevel = 300.0F;
itemRender.zLevel = 300.0F;

int backgroundStart = event.backgroundStart;
int backgroundEnd = event.backgroundEnd;
int borderStart = event.borderStart;
int borderEnd = event.borderEnd;

// spotless:off
// draw background
this.drawGradientRect(x - 3, y - 4, x + width + 3, y - 3, backgroundStart, backgroundStart); // top
this.drawGradientRect(x - 3, y + height + 3, x + width + 3, y + height + 4, backgroundEnd, backgroundEnd); // bottom
this.drawGradientRect(x - 3, y - 3, x + width + 3, y + height + 3, backgroundStart, backgroundEnd); // middle
this.drawGradientRect(x - 4, y - 3, x - 3, y + height + 3, backgroundStart, backgroundEnd); // left
this.drawGradientRect(x + width + 3, y - 3, x + width + 4, y + height + 3, backgroundStart, backgroundEnd); // right
// draw inner border
this.drawGradientRect(x - 3, y - 2, x - 2, y + height + 2, borderStart, borderEnd); // left
this.drawGradientRect(x + width + 2, y - 2, x + width + 3, y + height + 2, borderStart, borderEnd); // right
this.drawGradientRect(x - 3, y - 3, x + width + 3, y - 2, borderStart, borderStart); // top
this.drawGradientRect(x - 3, y + height + 2, x + width + 3, y + height + 3, borderEnd, borderEnd); // bottom
// spotless:on

// draw text
for (int i = 0; i < textLines.size(); i++) {
String s = textLines.get(i);
font.drawStringWithShadow(s, x, y, -1);

// increase Y coordinate
if (i == 0) {
y += 2;
}
y += 10;
}

// reset Z level
this.zLevel = 0.0F;
itemRender.zLevel = 0.0F;
} else {
event.alternativeRenderer.accept(textLines);
}

// reset GL states
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
}
}

}
Loading