From 2cc2cfa70062efac58335d62ad8e47105c15fdd7 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sun, 20 Jun 2021 23:20:05 +0800 Subject: Properly implement tooltip rendering for bundles --- .../rei/RoughlyEnoughItemsCoreClient.java | 11 +-- .../rei/impl/client/ClientHelperImpl.java | 15 ++++ .../rei/impl/client/gui/ScreenOverlayImpl.java | 27 ++++---- .../rei/impl/client/gui/widget/EntryWidget.java | 4 +- .../client/gui/widget/FavoritesListWidget.java | 4 +- .../rei/impl/client/gui/widget/QueuedTooltip.java | 79 ++++++++++++---------- .../rei/impl/common/entry/AbstractEntryStack.java | 4 +- .../plugin/client/entry/ItemEntryDefinition.java | 15 +++- 8 files changed, 101 insertions(+), 58 deletions(-) (limited to 'runtime/src/main/java/me/shedaniel') diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java index 1985e68b5..dfe241863 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java @@ -35,8 +35,6 @@ import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; -import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; -import me.shedaniel.rei.api.client.gui.Renderer; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; @@ -78,6 +76,7 @@ import net.minecraft.client.gui.components.ImageButton; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.gui.screens.inventory.CraftingScreen; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.client.gui.screens.recipebook.GhostRecipe; import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent; import net.minecraft.client.resources.language.I18n; @@ -95,7 +94,10 @@ import org.apache.commons.lang3.mutable.MutableLong; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.List; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -125,7 +127,8 @@ public class RoughlyEnoughItemsCoreClient { ResourceLocation id = new ResourceLocation(type); return Objects.requireNonNull(Objects.requireNonNull(FavoriteEntryType.registry().get(id)).read(object)); }, "favoriteEntryFromJson"); - ClientInternals.attachInstance((BiFunction<@Nullable Point, Collection, Tooltip>) QueuedTooltip::create, "tooltipProvider"); + ClientInternals.attachInstance((BiFunction<@Nullable Point, Collection, Tooltip>) QueuedTooltip::impl, "tooltipProvider"); + ClientInternals.attachInstance((Function) QueuedTooltip.TooltipEntryImpl::new, "tooltipEntryProvider"); ClientInternals.attachInstance((Function<@Nullable Boolean, ClickArea.Result>) successful -> new ClickArea.Result() { private List> categories = Lists.newArrayList(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientHelperImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientHelperImpl.java index cd488e436..cc834728e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientHelperImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientHelperImpl.java @@ -36,6 +36,7 @@ import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.config.DisplayScreenType; import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.registry.display.DisplayCategory; import me.shedaniel.rei.api.client.view.ViewSearchBuilder; import me.shedaniel.rei.api.common.category.CategoryIdentifier; @@ -43,6 +44,7 @@ import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; import me.shedaniel.rei.api.common.util.EntryStacks; +import me.shedaniel.rei.api.common.util.FormattingUtils; import me.shedaniel.rei.impl.ClientInternals; import me.shedaniel.rei.impl.client.gui.screen.CompositeDisplayViewingScreen; import me.shedaniel.rei.impl.client.gui.screen.DefaultDisplayViewingScreen; @@ -129,6 +131,19 @@ public class ClientHelperImpl implements ClientHelper { return hasPermissionToUsePackets() || Minecraft.getInstance().gameMode.hasInfiniteItems(); } + @Override + public void appendModIdToTooltips(Tooltip components, String modId) { + final String modName = ClientHelper.getInstance().getModFromModId(modId); + boolean alreadyHasMod = false; + for (Tooltip.Entry s : components.entries()) + if (s.isText() && FormattingUtils.stripFormatting(s.getAsText().getString()).equalsIgnoreCase(modName)) { + alreadyHasMod = true; + break; + } + if (!alreadyHasMod) + components.add(ClientHelper.getInstance().getFormattedModFromModId(modId)); + } + @Override public String getModFromModId(String modId) { if (modId == null) diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java index 7a4017e45..fabe48aed 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java @@ -75,6 +75,8 @@ import net.minecraft.client.gui.chat.NarratorChatListener; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTextTooltip; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.PlayerInfo; import net.minecraft.client.renderer.entity.ItemRenderer; @@ -97,6 +99,7 @@ import java.util.*; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; @ApiStatus.Internal public class ScreenOverlayImpl extends ScreenOverlay { @@ -545,26 +548,26 @@ public class ScreenOverlayImpl extends ScreenOverlay { } public void renderTooltip(PoseStack matrices, Tooltip tooltip) { - renderTooltip(matrices, tooltip.getText().stream() - .flatMap(component -> Minecraft.getInstance().font.getSplitter().splitLines(component, 100000, Style.EMPTY).stream()) + renderTooltipInner(matrices, tooltip.entries().stream() + .flatMap(component -> { + if (component.isText()) { + return Minecraft.getInstance().font.getSplitter().splitLines(component.getAsText(), 100000, Style.EMPTY).stream() + .map(Language.getInstance()::getVisualOrder) + .map(ClientTooltipComponent::create); + } else { + return Stream.of(component.getAsComponent()); + } + }) .collect(Collectors.toList()), tooltip.getX(), tooltip.getY()); } - public void renderTooltip(PoseStack matrices, List lines, int mouseX, int mouseY) { - if (lines.isEmpty()) { - return; - } - List orderedTexts = CollectionUtils.map(lines, Language.getInstance()::getVisualOrder); - renderTooltipInner(matrices, orderedTexts, mouseX, mouseY); - } - - public void renderTooltipInner(PoseStack matrices, List lines, int mouseX, int mouseY) { + public void renderTooltipInner(PoseStack matrices, List lines, int mouseX, int mouseY) { if (lines.isEmpty()) { return; } matrices.pushPose(); matrices.translate(0, 0, 500); - minecraft.screen.renderTooltip(matrices, lines, mouseX, mouseY); + minecraft.screen.renderTooltipInternal(matrices, lines, mouseX, mouseY); matrices.popPose(); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java index 781db8d0c..659862c02 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java @@ -312,10 +312,10 @@ public class EntryWidget extends Slot implements DraggableStackProviderWidget { if (interactableFavorites && ConfigObject.getInstance().doDisplayFavoritesTooltip() && !ConfigObject.getInstance().getFavoriteKeyCode().isUnknown()) { String name = ConfigObject.getInstance().getFavoriteKeyCode().getLocalizedName().getString(); if (reverseFavoritesAction()) - tooltip.getText().addAll(Stream.of(I18n.get("text.rei.remove_favorites_tooltip", name).split("\n")) + tooltip.addAllTexts(Stream.of(I18n.get("text.rei.remove_favorites_tooltip", name).split("\n")) .map(TextComponent::new).collect(Collectors.toList())); else - tooltip.getText().addAll(Stream.of(I18n.get("text.rei.favorites_tooltip", name).split("\n")) + tooltip.addAllTexts(Stream.of(I18n.get("text.rei.favorites_tooltip", name).split("\n")) .map(TextComponent::new).collect(Collectors.toList())); } tooltip.queue(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/FavoritesListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/FavoritesListWidget.java index fe195531e..63ca1094e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/FavoritesListWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/FavoritesListWidget.java @@ -1050,8 +1050,8 @@ public class FavoritesListWidget extends WidgetWithBounds implements DraggableSt if (!scrollBounds.contains(point)) return null; Tooltip tooltip = super.getCurrentTooltip(point); if (tooltip != null) { - tooltip.getText().add(ImmutableTextComponent.EMPTY); - tooltip.getText().add(new TranslatableComponent("tooltip.rei.drag_to_add_favorites")); + tooltip.add(ImmutableTextComponent.EMPTY); + tooltip.add(new TranslatableComponent("tooltip.rei.drag_to_add_favorites")); } return tooltip; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/QueuedTooltip.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/QueuedTooltip.java index 6938b16c4..96dff555e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/QueuedTooltip.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/QueuedTooltip.java @@ -25,15 +25,16 @@ package me.shedaniel.rei.impl.client.gui.widget; import com.google.common.collect.Lists; -import dev.architectury.platform.Platform; -import dev.architectury.utils.Env; import me.shedaniel.math.Point; import me.shedaniel.math.impl.PointHelper; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.ApiStatus; -import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -41,66 +42,74 @@ import java.util.List; * @see Tooltip */ @ApiStatus.Internal +@Environment(EnvType.CLIENT) public class QueuedTooltip implements Tooltip { - private Point location; - private List text; + private List components; - private QueuedTooltip(Point location, Collection text) { + private QueuedTooltip(Point location, Collection components) { this.location = location; if (this.location == null) { - if (Platform.getEnvironment() == Env.CLIENT) { - setLocationToMouse(); - } + this.location = PointHelper.ofMouse(); } - this.text = Lists.newArrayList(text); - } - - private void setLocationToMouse() { - this.location = PointHelper.ofMouse(); + this.components = Lists.newArrayList(components); } - public static QueuedTooltip create(Point location, List text) { + public static QueuedTooltip impl(Point location, Collection text) { return new QueuedTooltip(location, text); } - public static QueuedTooltip create(Point location, Collection text) { - return new QueuedTooltip(location, text); - } - - public static QueuedTooltip create(Point location, Component... text) { - return QueuedTooltip.create(location, Arrays.asList(text)); - } - - public static QueuedTooltip create(List text) { - return QueuedTooltip.create(null, text); + @Override + public int getX() { + return location.x; } - public static QueuedTooltip create(Collection text) { - return QueuedTooltip.create(null, text); + @Override + public int getY() { + return location.y; } - public static QueuedTooltip create(Component... text) { - return QueuedTooltip.create(null, text); + @Override + public List getText() { + return CollectionUtils.filterAndMap(components, Tooltip.Entry::isText, Tooltip.Entry::getAsText); } @Override - public int getX() { - return location.x; + public List entries() { + return components; } @Override - public int getY() { - return location.y; + public Tooltip add(Component text) { + components.add(new TooltipEntryImpl(text)); + return this; } @Override - public List getText() { - return text; + public Tooltip add(ClientTooltipComponent component) { + components.add(new TooltipEntryImpl(component)); + return this; } @Override public void queue() { Tooltip.super.queue(); } + + public record TooltipEntryImpl(Object obj) implements Tooltip.Entry { + @Override + public Component getAsText() { + return (Component) obj; + } + + @Override + public boolean isText() { + return obj instanceof Component; + } + + @Override + public ClientTooltipComponent getAsComponent() { + return (ClientTooltipComponent) obj; + } + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java index 20194e7a7..995dbfe5a 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java @@ -158,13 +158,13 @@ public abstract class AbstractEntryStack extends AbstractRenderer implements public Tooltip getTooltip(Point mouse, boolean appendModName) { Mutable tooltip = new MutableObject<>(getRenderer().cast().getTooltip(this, mouse)); if (tooltip.getValue() == null) return null; - tooltip.getValue().getText().addAll(get(Settings.TOOLTIP_APPEND_EXTRA).apply(this)); + tooltip.getValue().addAllTexts(get(Settings.TOOLTIP_APPEND_EXTRA).apply(this)); tooltip.setValue(get(Settings.TOOLTIP_PROCESSOR).apply(this, tooltip.getValue())); if (tooltip.getValue() == null) return null; if (appendModName) { ResourceLocation location = getIdentifier(); if (location != null) { - ClientHelper.getInstance().appendModIdToTooltips(tooltip.getValue().getText(), location.getNamespace()); + ClientHelper.getInstance().appendModIdToTooltips(tooltip.getValue(), location.getNamespace()); } } return tooltip.getValue(); diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java index ba5e0c08f..95dc8b3e4 100644 --- a/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java +++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java @@ -51,6 +51,7 @@ import net.fabricmc.api.Environment; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.client.renderer.texture.OverlayTexture; @@ -63,6 +64,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagCollection; import net.minecraft.tags.TagContainer; +import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; @@ -71,6 +73,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; public class ItemEntryDefinition implements EntryDefinition, EntrySerializer { @Environment(EnvType.CLIENT) @@ -326,7 +329,17 @@ public class ItemEntryDefinition implements EntryDefinition, EntrySer public Tooltip getTooltip(EntryStack entry, Point mouse) { if (entry.isEmpty()) return null; - return Tooltip.create(tryGetItemStackToolTip(entry, entry.getValue(), true)); + Tooltip tooltip = Tooltip.create(); + Optional component = entry.getValue().getTooltipImage(); + List components = tryGetItemStackToolTip(entry, entry.getValue(), true); + if (!components.isEmpty()) { + tooltip.add(components.get(0)); + } + component.ifPresent(tooltipComponent -> tooltip.add(ClientTooltipComponent.create(tooltipComponent))); + for (int i = 1; i < components.size(); i++) { + tooltip.add(components.get(i)); + } + return tooltip; } } } -- cgit