aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/anthonyhilyard/iceberg
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/anthonyhilyard/iceberg')
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/events/GatherComponentsExtEvent.java21
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/events/RenderTooltipExtEvent.java38
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/mixin/TextColorMixin.java36
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/util/ItemColor.java2
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/util/Selectors.java91
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/util/Tooltips.java87
6 files changed, 228 insertions, 47 deletions
diff --git a/src/main/java/com/anthonyhilyard/iceberg/events/GatherComponentsExtEvent.java b/src/main/java/com/anthonyhilyard/iceberg/events/GatherComponentsExtEvent.java
new file mode 100644
index 0000000..753c7c0
--- /dev/null
+++ b/src/main/java/com/anthonyhilyard/iceberg/events/GatherComponentsExtEvent.java
@@ -0,0 +1,21 @@
+package com.anthonyhilyard.iceberg.events;
+
+import java.util.List;
+
+import com.mojang.datafixers.util.Either;
+
+import net.minecraft.network.chat.FormattedText;
+import net.minecraft.world.inventory.tooltip.TooltipComponent;
+import net.minecraft.world.item.ItemStack;
+import net.minecraftforge.client.event.RenderTooltipEvent.GatherComponents;
+
+public class GatherComponentsExtEvent extends GatherComponents
+{
+ private final int index;
+ public GatherComponentsExtEvent(ItemStack itemStack, int screenWidth, int screenHeight, List<Either<FormattedText, TooltipComponent>> tooltipElements, int maxWidth, int index)
+ {
+ super(itemStack, screenWidth, screenHeight, tooltipElements, maxWidth);
+ this.index = index;
+ }
+ public int getIndex() { return index; }
+}
diff --git a/src/main/java/com/anthonyhilyard/iceberg/events/RenderTooltipExtEvent.java b/src/main/java/com/anthonyhilyard/iceberg/events/RenderTooltipExtEvent.java
index 98f01a6..febe70f 100644
--- a/src/main/java/com/anthonyhilyard/iceberg/events/RenderTooltipExtEvent.java
+++ b/src/main/java/com/anthonyhilyard/iceberg/events/RenderTooltipExtEvent.java
@@ -14,30 +14,45 @@ public class RenderTooltipExtEvent
public static class Pre extends RenderTooltipEvent.Pre
{
private final boolean comparisonTooltip;
+ private final int index;
- public Pre(ItemStack stack, PoseStack PoseStack, int x, int y, int screenWidth, int screenHeight, Font font, List<ClientTooltipComponent> components, boolean comparison)
+ public Pre(ItemStack stack, PoseStack PoseStack, int x, int y, int screenWidth, int screenHeight, Font font, List<ClientTooltipComponent> components, boolean comparison, int index)
{
super(stack, PoseStack, x, y, screenWidth, screenHeight, font, components);
- comparisonTooltip = comparison;
+ this.comparisonTooltip = comparison;
+ this.index = index;
+ }
+
+ public Pre(ItemStack stack, PoseStack PoseStack, int x, int y, int screenWidth, int screenHeight, Font font, List<ClientTooltipComponent> components, boolean comparison)
+ {
+ this(stack, PoseStack, x, y, screenWidth, screenHeight, font, components, comparison, 0);
}
public boolean isComparison() { return comparisonTooltip; }
+ public int getIndex() { return index; }
}
public static class Post extends RenderTooltipEvent
{
private final boolean comparisonTooltip;
+ private final int index;
private final int width;
private final int height;
- public Post(ItemStack stack, PoseStack PoseStack, int x, int y, Font font, int width, int height, List<ClientTooltipComponent> components, boolean comparison)
+ public Post(ItemStack stack, PoseStack PoseStack, int x, int y, Font font, int width, int height, List<ClientTooltipComponent> components, boolean comparison, int index)
{
super(stack, PoseStack, x, y, font, components);
this.width = width;
this.height = height;
+ this.comparisonTooltip = comparison;
+ this.index = index;
+ }
- comparisonTooltip = comparison;
+ public Post(ItemStack stack, PoseStack PoseStack, int x, int y, Font font, int width, int height, List<ClientTooltipComponent> components, boolean comparison)
+ {
+ this(stack, PoseStack, x, y, font, width, height, components, comparison, 0);
}
public boolean isComparison() { return comparisonTooltip; }
+ public int getIndex() { return index; }
public int getWidth() { return width; }
public int getHeight() { return height; }
}
@@ -45,18 +60,25 @@ public class RenderTooltipExtEvent
public static class Color extends RenderTooltipEvent.Color
{
private final boolean comparisonTooltip;
+ private final int index;
- public Color(ItemStack stack, PoseStack PoseStack, int x, int y, Font font, int background, int borderStart, int borderEnd, List<ClientTooltipComponent> components, boolean comparison)
+ public Color(ItemStack stack, PoseStack PoseStack, int x, int y, Font font, int background, int borderStart, int borderEnd, List<ClientTooltipComponent> components, boolean comparison, int index)
{
super(stack, PoseStack, x, y, font, background, borderStart, borderEnd, components);
- comparisonTooltip = comparison;
+ this.comparisonTooltip = comparison;
+ this.index = index;
+ }
+ public Color(ItemStack stack, PoseStack PoseStack, int x, int y, Font font, int background, int borderStart, int borderEnd, List<ClientTooltipComponent> components, boolean comparison)
+ {
+ this(stack, PoseStack, x, y, font, background, borderStart, borderEnd, components, comparison, 0);
}
- public Color(ItemStack stack, PoseStack PoseStack, int x, int y, Font font, int backgroundStart, int backgroundEnd, int borderStart, int borderEnd, List<ClientTooltipComponent> components, boolean comparison)
+ public Color(ItemStack stack, PoseStack PoseStack, int x, int y, Font font, int backgroundStart, int backgroundEnd, int borderStart, int borderEnd, List<ClientTooltipComponent> components, boolean comparison, int index)
{
- this(stack, PoseStack, x, y, font, backgroundStart, borderStart, borderEnd, components, comparison);
+ this(stack, PoseStack, x, y, font, backgroundStart, borderStart, borderEnd, components, comparison, index);
setBackgroundStart(backgroundStart);
setBackgroundEnd(backgroundEnd);
}
public boolean isComparison() { return comparisonTooltip; }
+ public int getIndex() { return index; }
}
}
diff --git a/src/main/java/com/anthonyhilyard/iceberg/mixin/TextColorMixin.java b/src/main/java/com/anthonyhilyard/iceberg/mixin/TextColorMixin.java
new file mode 100644
index 0000000..2bd40ba
--- /dev/null
+++ b/src/main/java/com/anthonyhilyard/iceberg/mixin/TextColorMixin.java
@@ -0,0 +1,36 @@
+package com.anthonyhilyard.iceberg.mixin;
+
+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.CallbackInfoReturnable;
+
+import net.minecraft.network.chat.TextColor;
+
+@Mixin(TextColor.class)
+public class TextColorMixin
+{
+ /**
+ * Fix an issue in TextColor parsing that makes it so only alpha values up to 0x7F are supported.
+ */
+ @Inject(method = "parseColor", at = @At("HEAD"), cancellable = true)
+ private static boolean parseColor(String colorString, CallbackInfoReturnable<TextColor> info)
+ {
+ if (!colorString.startsWith("#"))
+ {
+ return false;
+ }
+
+ try
+ {
+ int i = Integer.parseUnsignedInt(colorString.substring(1), 16);
+ info.setReturnValue(TextColor.fromRgb(i));
+ return true;
+ }
+ catch (NumberFormatException numberformatexception)
+ {
+ info.setReturnValue(null);
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/com/anthonyhilyard/iceberg/util/ItemColor.java b/src/main/java/com/anthonyhilyard/iceberg/util/ItemColor.java
index 3714681..6b614c5 100644
--- a/src/main/java/com/anthonyhilyard/iceberg/util/ItemColor.java
+++ b/src/main/java/com/anthonyhilyard/iceberg/util/ItemColor.java
@@ -40,7 +40,7 @@ public class ItemColor
try
{
ChatFormatting format = ChatFormatting.getByCode(rawTitle.charAt(i + 1));
- if (format.isColor())
+ if (format != null && format.isColor())
{
return TextColor.fromLegacyFormat(format);
}
diff --git a/src/main/java/com/anthonyhilyard/iceberg/util/Selectors.java b/src/main/java/com/anthonyhilyard/iceberg/util/Selectors.java
index 6f450f1..5099644 100644
--- a/src/main/java/com/anthonyhilyard/iceberg/util/Selectors.java
+++ b/src/main/java/com/anthonyhilyard/iceberg/util/Selectors.java
@@ -2,6 +2,7 @@ package com.anthonyhilyard.iceberg.util;
import net.minecraft.world.item.ItemStack;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiPredicate;
@@ -12,6 +13,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NumericTag;
import net.minecraft.nbt.Tag;
+import net.minecraft.nbt.ListTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextColor;
import net.minecraft.resources.ResourceLocation;
@@ -72,6 +74,25 @@ public class Selectors
});
}};
+ public static record SelectorDocumentation(String name, String description, List<String> examples)
+ {
+ public SelectorDocumentation(String name, String description, String... examples) { this(name, description, Arrays.asList(examples)); }
+ }
+
+ public static List<SelectorDocumentation> selectorDocumentation()
+ {
+ return Arrays.asList(
+ new SelectorDocumentation("Item name", "Use item name for vanilla items or include mod name for modded items.", "minecraft:stick", "iron_ore"),
+ new SelectorDocumentation("Tag", "$ followed by tag name.", "$forge:stone", "$planks"),
+ new SelectorDocumentation("Mod name", "@ followed by mod identifier.", "@spoiledeggs"),
+ new SelectorDocumentation("Rarity", "! followed by item's rarity. This is ONLY vanilla rarities.", "!uncommon", "!rare", "!epic"),
+ new SelectorDocumentation("Item name color", "# followed by color hex code, the hex code must match exactly.", "#23F632"),
+ new SelectorDocumentation("Display name", "% followed by any text. Will match any item with this text in its tooltip display name.", "%Netherite", "%[Uncommon]"),
+ new SelectorDocumentation("Tooltip text", "Will match any item with this text anywhere in the tooltip text (besides the name).", "^Legendary"),
+ new SelectorDocumentation("NBT tag", "& followed by tag name and optional comparator (=, >, <, or !=) and value, in the format <tag><comparator><value> or just <tag>.", "&Damage=0", "&Tier>1", "&map!=128", "&Enchantments")
+ );
+ }
+
/**
* Returns true if this selector is syntactically valid.
* @param value The selector.
@@ -212,24 +233,8 @@ public class Selectors
}
}
- // Look for a tag matching the given name.
- Tag matchedTag = getSubtag(item.getTag(), tagName);
- if (matchedTag != null)
- {
- // A tag value of null means that we are just looking for the presence of this tag.
- if (tagValue == null)
- {
- return true;
- }
- // Otherwise, we will use the provided comparator.
- else
- {
- if (valueChecker != null)
- {
- return valueChecker.test(matchedTag, tagValue);
- }
- }
- }
+ // Look for a tag matching the given name and value.
+ return findMatchingSubtag(item.getTag(), tagName, tagValue, valueChecker);
}
return false;
@@ -238,31 +243,59 @@ public class Selectors
/**
* Retrieves the first inner tag with the given key, or null if there is no match.
*/
- private static Tag getSubtag(CompoundTag tag, String key)
+ private static boolean findMatchingSubtag(Tag tag, String key, String value, BiPredicate<Tag, String> valueChecker)
{
if (tag == null)
{
- return null;
+ return false;
}
- if (tag.contains(key))
+ if (tag.getId() == Tag.TAG_COMPOUND)
{
- return tag.get(key);
+ CompoundTag compoundTag = (CompoundTag)tag;
+
+ if (compoundTag.contains(key))
+ {
+ // Just checking presence.
+ if (value == null && valueChecker == null)
+ {
+ return true;
+ }
+ // Otherwise, we will use the provided comparator.
+ else
+ {
+ return valueChecker.test(compoundTag.get(key), value);
+ }
+ }
+ else
+ {
+ for (String innerKey : compoundTag.getAllKeys())
+ {
+ if (compoundTag.getTagType(innerKey) == Tag.TAG_LIST || compoundTag.getTagType(innerKey) == Tag.TAG_COMPOUND)
+ {
+ if (findMatchingSubtag(compoundTag.get(innerKey), key, value, valueChecker))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
- else
+ else if (tag.getId() == Tag.TAG_LIST)
{
- for (String innerKey : tag.getAllKeys())
+ ListTag listTag = (ListTag)tag;
+ for (Tag innerTag : listTag)
{
- if (tag.getTagType(innerKey) == Tag.TAG_COMPOUND)
+ if (innerTag.getId() == Tag.TAG_LIST || innerTag.getId() == Tag.TAG_COMPOUND)
{
- Tag innerTag = getSubtag(tag.getCompound(innerKey), key);
- if (innerTag != null)
+ if (findMatchingSubtag(innerTag, key, value, valueChecker))
{
- return innerTag;
+ return true;
}
}
}
- return null;
}
+ return false;
}
} \ No newline at end of file
diff --git a/src/main/java/com/anthonyhilyard/iceberg/util/Tooltips.java b/src/main/java/com/anthonyhilyard/iceberg/util/Tooltips.java
index 1673815..467604b 100644
--- a/src/main/java/com/anthonyhilyard/iceberg/util/Tooltips.java
+++ b/src/main/java/com/anthonyhilyard/iceberg/util/Tooltips.java
@@ -10,6 +10,7 @@ import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import com.anthonyhilyard.iceberg.events.GatherComponentsExtEvent;
import com.anthonyhilyard.iceberg.events.RenderTooltipExtEvent;
import com.mojang.blaze3d.vertex.PoseStack;
@@ -23,6 +24,8 @@ import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.locale.Language;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FormattedText;
+import net.minecraft.network.chat.Style;
+import net.minecraft.util.FormattedCharSequence;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.datafixers.util.Either;
@@ -93,12 +96,13 @@ public class Tooltips
Rect2i rect, int screenWidth, int screenHeight,
int backgroundColor, int borderColorStart, int borderColorEnd, boolean comparison, boolean constrain)
{
- renderItemTooltip(stack, poseStack, info, rect, screenWidth, screenHeight, backgroundColor, backgroundColor, borderColorStart, borderColorEnd, comparison, constrain);
+ renderItemTooltip(stack, poseStack, info, rect, screenWidth, screenHeight, backgroundColor, backgroundColor, borderColorStart, borderColorEnd, comparison, constrain, false, 0);
}
public static void renderItemTooltip(@Nonnull final ItemStack stack, PoseStack poseStack, TooltipInfo info,
- Rect2i rect, int screenWidth, int screenHeight,
- int backgroundColorStart, int backgroundColorEnd, int borderColorStart, int borderColorEnd, boolean comparison, boolean constrain)
+ Rect2i rect, int screenWidth, int screenHeight,
+ int backgroundColorStart, int backgroundColorEnd, int borderColorStart, int borderColorEnd,
+ boolean comparison, boolean constrain, boolean centeredTitle, int index)
{
if (info.getComponents().isEmpty())
{
@@ -111,10 +115,16 @@ public class Tooltips
itemRenderer = Minecraft.getInstance().getItemRenderer();
}
+ // Center the title now if needed.
+ if (centeredTitle)
+ {
+ info = new TooltipInfo(centerTitle(info.getComponents(), info.getFont(), rect.getWidth()), info.getFont());
+ }
+
int rectX = rect.getX() + 4;
int rectY = rect.getY() + 4;
- RenderTooltipExtEvent.Pre preEvent = new RenderTooltipExtEvent.Pre(stack, poseStack, rectX, rectY, screenWidth, screenHeight, info.getFont(), info.getComponents(), comparison);
+ RenderTooltipExtEvent.Pre preEvent = new RenderTooltipExtEvent.Pre(stack, poseStack, rectX, rectY, screenWidth, screenHeight, info.getFont(), info.getComponents(), comparison, index);
if (MinecraftForge.EVENT_BUS.post(preEvent))
{
return;
@@ -133,7 +143,7 @@ public class Tooltips
itemRenderer.blitOffset = zLevel;
Matrix4f mat = poseStack.last().pose();
- RenderTooltipExtEvent.Color colorEvent = new RenderTooltipExtEvent.Color(stack, poseStack, rectX, rectY, info.getFont(), backgroundColorStart, backgroundColorEnd, borderColorStart, borderColorEnd, info.getComponents(), comparison);
+ RenderTooltipExtEvent.Color colorEvent = new RenderTooltipExtEvent.Color(stack, poseStack, rectX, rectY, info.getFont(), backgroundColorStart, backgroundColorEnd, borderColorStart, borderColorEnd, info.getComponents(), comparison, index);
MinecraftForge.EVENT_BUS.post(colorEvent);
backgroundColorStart = colorEvent.getBackgroundStart();
@@ -176,12 +186,18 @@ public class Tooltips
itemRenderer.blitOffset = f;
- RenderTooltipExtEvent.Post postEvent = new RenderTooltipExtEvent.Post(stack, poseStack, rectX, rectY, info.getFont(), rect.getWidth(), rect.getHeight(), info.getComponents(), comparison);
+ RenderTooltipExtEvent.Post postEvent = new RenderTooltipExtEvent.Post(stack, poseStack, rectX, rectY, info.getFont(), rect.getWidth(), rect.getHeight(), info.getComponents(), comparison, index);
MinecraftForge.EVENT_BUS.post(postEvent);
}
public static List<ClientTooltipComponent> gatherTooltipComponents(ItemStack stack, List<? extends FormattedText> textElements, Optional<TooltipComponent> itemComponent,
- int mouseX, int screenWidth, int screenHeight, @Nullable Font forcedFont, Font fallbackFont, int maxWidth)
+ int mouseX, int screenWidth, int screenHeight, @Nullable Font forcedFont, Font fallbackFont, int maxWidth)
+ {
+ return gatherTooltipComponents(stack, textElements, itemComponent, mouseX, screenWidth, screenHeight, forcedFont, fallbackFont, maxWidth, 0);
+ }
+
+ public static List<ClientTooltipComponent> gatherTooltipComponents(ItemStack stack, List<? extends FormattedText> textElements, Optional<TooltipComponent> itemComponent,
+ int mouseX, int screenWidth, int screenHeight, @Nullable Font forcedFont, Font fallbackFont, int maxWidth, int index)
{
Font font = ForgeHooksClient.getTooltipFont(forcedFont, stack, fallbackFont);
List<Either<FormattedText, TooltipComponent>> elements = textElements.stream()
@@ -190,7 +206,7 @@ public class Tooltips
itemComponent.ifPresent(c -> elements.add(1, Either.right(c)));
- var event = new RenderTooltipEvent.GatherComponents(stack, screenWidth, screenHeight, elements, maxWidth);
+ var event = new GatherComponentsExtEvent(stack, screenWidth, screenHeight, elements, maxWidth, index);
if (MinecraftForge.EVENT_BUS.post(event))
{
return List.of();
@@ -244,6 +260,12 @@ public class Tooltips
public static Rect2i calculateRect(final ItemStack stack, PoseStack poseStack, List<ClientTooltipComponent> components,
int mouseX, int mouseY,int screenWidth, int screenHeight, int maxTextWidth, Font font)
{
+ return calculateRect(stack, poseStack, components, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth, font, 0, false);
+ }
+
+ public static Rect2i calculateRect(final ItemStack stack, PoseStack poseStack, List<ClientTooltipComponent> components,
+ int mouseX, int mouseY,int screenWidth, int screenHeight, int maxTextWidth, Font font, int minWidth, boolean centeredTitle)
+ {
Rect2i rect = new Rect2i(0, 0, 0, 0);
if (components == null || components.isEmpty() || stack == null)
{
@@ -263,9 +285,14 @@ public class Tooltips
screenHeight = event.getScreenHeight();
font = event.getFont();
- int tooltipTextWidth = 0;
+ int tooltipTextWidth = minWidth;
int tooltipHeight = components.size() == 1 ? -2 : 0;
+ if (centeredTitle)
+ {
+ components = centerTitle(components, font, minWidth);
+ }
+
for (ClientTooltipComponent component : components)
{
int componentWidth = component.getWidth(event.getFont());
@@ -292,4 +319,46 @@ public class Tooltips
rect = new Rect2i(tooltipX - 2, tooltipY - 4, tooltipTextWidth, tooltipHeight);
return rect;
}
+
+ public static List<ClientTooltipComponent> centerTitle(List<ClientTooltipComponent> components, Font font, int minWidth)
+ {
+ // Calculate tooltip width first.
+ int tooltipWidth = minWidth;
+
+ for (ClientTooltipComponent clienttooltipcomponent : components)
+ {
+ if (clienttooltipcomponent == null)
+ {
+ return components;
+ }
+ int componentWidth = clienttooltipcomponent.getWidth(font);
+ if (componentWidth > tooltipWidth)
+ {
+ tooltipWidth = componentWidth;
+ }
+ }
+
+ // TODO: If the title is multiple lines, we need to extend this for each one.
+
+ List<FormattedText> recomposedLines = StringRecomposer.recompose(List.of(components.get(0)));
+ if (recomposedLines.isEmpty())
+ {
+ return components;
+ }
+
+ List<ClientTooltipComponent> result = new ArrayList<>(components);
+
+ FormattedCharSequence title = Language.getInstance().getVisualOrder(recomposedLines.get(0));
+ FormattedCharSequence space = FormattedCharSequence.forward(" ", Style.EMPTY);
+ while (result.get(0).getWidth(font) < tooltipWidth)
+ {
+ title = FormattedCharSequence.fromList(List.of(space, title, space));
+ if (title == null)
+ {
+ break;
+ }
+ result.set(0, ClientTooltipComponent.create(title));
+ }
+ return result;
+ }
}