From 0930d2661d47d595607f9e719d64123062d1764c Mon Sep 17 00:00:00 2001 From: TheMrEngMan <68214507+TheMrEngMan@users.noreply.github.com> Date: Sun, 14 Aug 2022 02:36:01 -0400 Subject: [PATCH 1/2] Added text of signs placed on all blocks that provide tabs to the tab tooltips. The sign must be placed directly on the chest/barrel/shulker box etc. to show up in the tooltip. Text color applied with dyes and custom formatting is also applied to tooltip text. This works for double chests and chests identified with item frames as well. --- .../tabs/render/TabRenderer.java | 2 +- .../tabs/tab/SimpleBlockTab.java | 8 ++ .../com/kqp/inventorytabs/tabs/tab/Tab.java | 17 ++- .../com/kqp/inventorytabs/util/BlockUtil.java | 122 ++++++++++++++++++ 4 files changed, 147 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/kqp/inventorytabs/tabs/render/TabRenderer.java b/src/main/java/com/kqp/inventorytabs/tabs/render/TabRenderer.java index 6d340fd..414abe0 100644 --- a/src/main/java/com/kqp/inventorytabs/tabs/render/TabRenderer.java +++ b/src/main/java/com/kqp/inventorytabs/tabs/render/TabRenderer.java @@ -164,7 +164,7 @@ public void renderHoverTooltips(MatrixStack matrices, double mouseX, double mous Rectangle itemRec = new Rectangle(tabRenderInfo.itemX, tabRenderInfo.itemY, 16, 16); if (itemRec.contains(mouseX, mouseY)) { - tabManager.getCurrentScreen().renderTooltip(matrices, tabRenderInfo.tabReference.getHoverText(), + tabManager.getCurrentScreen().renderTooltip(matrices, tabRenderInfo.tabReference.getFullHoverText(), (int) mouseX, (int) mouseY); } } diff --git a/src/main/java/com/kqp/inventorytabs/tabs/tab/SimpleBlockTab.java b/src/main/java/com/kqp/inventorytabs/tabs/tab/SimpleBlockTab.java index 7963fcc..003c1bb 100644 --- a/src/main/java/com/kqp/inventorytabs/tabs/tab/SimpleBlockTab.java +++ b/src/main/java/com/kqp/inventorytabs/tabs/tab/SimpleBlockTab.java @@ -1,5 +1,6 @@ package com.kqp.inventorytabs.tabs.tab; +import java.util.List; import java.util.Objects; import com.kqp.inventorytabs.init.InventoryTabs; @@ -98,6 +99,13 @@ public Text getHoverText() { } + @Override + public List getFullHoverText() { + List hoverTexts = super.getFullHoverText(); + hoverTexts.addAll(BlockUtil.getSignText(blockPos, true)); + return hoverTexts; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/src/main/java/com/kqp/inventorytabs/tabs/tab/Tab.java b/src/main/java/com/kqp/inventorytabs/tabs/tab/Tab.java index c7f6079..78025e3 100644 --- a/src/main/java/com/kqp/inventorytabs/tabs/tab/Tab.java +++ b/src/main/java/com/kqp/inventorytabs/tabs/tab/Tab.java @@ -12,6 +12,9 @@ import net.minecraft.item.ItemStack; import net.minecraft.text.Text; +import java.util.ArrayList; +import java.util.List; + /** * Base interface for tabs. */ @@ -37,12 +40,24 @@ protected Tab(ItemStack renderItemStack) { public abstract boolean shouldBeRemoved(); /** - * Returns the text that's displayed when hovering over the tab. + * Returns the first line of text that's displayed when hovering over the tab. * * @return */ public abstract Text getHoverText(); + /** + * Returns the full text that's displayed when hovering over the tab, + * this includes the text of a sign that is attached to the container. + * + * @return + */ + public List getFullHoverText() { + ArrayList firstHoverText = new ArrayList<>(1); + firstHoverText.add(getHoverText()); + return firstHoverText; + } + /** * Called when the screen associated with the tab is closed. */ diff --git a/src/main/java/com/kqp/inventorytabs/util/BlockUtil.java b/src/main/java/com/kqp/inventorytabs/util/BlockUtil.java index 01ef340..406479b 100644 --- a/src/main/java/com/kqp/inventorytabs/util/BlockUtil.java +++ b/src/main/java/com/kqp/inventorytabs/util/BlockUtil.java @@ -1,15 +1,29 @@ package com.kqp.inventorytabs.util; import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.SignBlockEntity; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.state.property.Properties; +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.DyeColor; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; import net.minecraft.world.RaycastContext; import net.minecraft.world.World; +import java.util.ArrayList; +import java.util.List; + +import static com.kqp.inventorytabs.util.ChestUtil.getOtherChestBlockPos; + public class BlockUtil { public static boolean inRange(BlockPos pos, PlayerEntity player, double distance) { double distanceSquared = distance * distance; @@ -65,6 +79,114 @@ private static BlockHitResult getBlockHitResult(Vec3d playerHead, Vec3d blockVec return null; } + public static List getSignText(BlockPos blockPos) { + return getSignText(blockPos, false); + } + + public static List getSignText(BlockPos blockPos, boolean isChest) { + World world = MinecraftClient.getInstance().player.world; + ArrayList signTextLines = new ArrayList<>(); + + // If the dye color of the sign should be used to format the label + // True by default unless the sign has custom formatting applied to it (via commands) + // If false, the sign's custom formatting is used instead + boolean applySignDyeColor = true; + + // Check if this is a double chest + boolean isDoubleChest = isChest && ChestUtil.isDouble(world, blockPos); + BlockPos doubleChestPos = isDoubleChest ? getOtherChestBlockPos(world, blockPos) : blockPos; + + // Positions to check around the container + ArrayList positionsToCheck = new ArrayList<>(); + positionsToCheck.add(blockPos.add(1, 0, 0)); + positionsToCheck.add(blockPos.add(0, 0, 1)); + positionsToCheck.add(blockPos.add(-1, 0, 0)); + positionsToCheck.add(blockPos.add(0, 0, -1)); + + // If this is a double chest, also check positions around the other side of the chest + // (and don't check positions inside the chests) + if(isDoubleChest) { + positionsToCheck.add(doubleChestPos.add(1, 0, 0)); + positionsToCheck.add(doubleChestPos.add(0, 0, 1)); + positionsToCheck.add(doubleChestPos.add(-1, 0, 0)); + positionsToCheck.add(doubleChestPos.add(0, 0, -1)); + positionsToCheck.remove(doubleChestPos); + positionsToCheck.remove(blockPos); + } + + // Check each position needed + BlockEntity blockEntity = null; + int positionToCheckIndex = -1; + for(BlockPos positionToCheck : positionsToCheck) { + blockEntity = world.getBlockEntity(positionToCheck); + + // Keep track of which position is being checked + // if this is a double chest, the other chest position needs to be used for the comparison + // after all three sides of the first chest were checked + positionToCheckIndex++; + + // If a sign was found around the container + if(blockEntity instanceof SignBlockEntity) { + + // Check if it is a sign that could be attached to the container + BlockState blockState = world.getBlockState(positionToCheck); + if (blockState.contains(Properties.HORIZONTAL_FACING)) { + Direction direction = blockState.get(Properties.HORIZONTAL_FACING); + + // If the block this sign is attached to sign is the container, then use it as the label for this container + if(positionToCheck.add(direction.getOpposite().getVector()).equals(positionToCheckIndex < 3 ? blockPos : doubleChestPos)) { + break; + } + } + } + } + + // If a suitable sign was found, read the NBT data from it + if (blockEntity != null) { + NbtCompound tag = new NbtCompound(); + blockEntity.writeNbt(tag); + + // Check all 4 lines of text + for (int lineNumber = 1; lineNumber <= 4; lineNumber++) { + + // If the current line is not empty + if(!tag.getString("Text" + lineNumber).equals("{\"text\":\"\"}")) { + + // Get the text on this line and add it to the list of texts to be processed + MutableText currentLineText = Text.Serializer.fromJson(tag.getString("Text" + lineNumber)); + if(currentLineText == null) { continue; } + signTextLines.add(currentLineText); + + // Check if this line contains any custom formatting (determine if the dye color should be used or not) + // For some reason Text.getStyle().isEmpty() always seems to return false + // even on simple un-formatted signs so this had to be done instead + if (currentLineText.getStyle() != null) { + if (currentLineText.getStyle().isBold() || + currentLineText.getStyle().isItalic() || + currentLineText.getStyle().isObfuscated() || + currentLineText.getStyle().isStrikethrough() || + currentLineText.getStyle().isUnderlined() || + currentLineText.getStyle().getColor() != null) { + applySignDyeColor = false; + } + } + } + } + + // Apply the dye color if need be, replacing the default text on signs with a gray so the tooltip is visible + if(applySignDyeColor) { + String signDyeColorToUse = tag.getString("Color").equals("black") ? "gray" : tag.getString("Color"); + for (int currentLineInxed = 0; currentLineInxed < signTextLines.size(); currentLineInxed++) { + MutableText currentText = ((MutableText) signTextLines.get(currentLineInxed)); + signTextLines.set(currentLineInxed, currentText.setStyle(Style.EMPTY.withColor(DyeColor.byName(signDyeColorToUse, DyeColor.GRAY).getSignColor()))); + } + } + + } + + return signTextLines; + } + private static final Vec3d[] SIGHT_OFFSETS = { // Center new Vec3d(0.5D, 0.5D, 0.5D), From d970f6847411fb56ba08fde3e2f3786675009ca0 Mon Sep 17 00:00:00 2001 From: TheMrEngMan <68214507+TheMrEngMan@users.noreply.github.com> Date: Thu, 18 Aug 2022 16:31:50 -0400 Subject: [PATCH 2/2] Fix all tabs being processed as chests for getting the sign texts --- .../java/com/kqp/inventorytabs/tabs/tab/SimpleBlockTab.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/kqp/inventorytabs/tabs/tab/SimpleBlockTab.java b/src/main/java/com/kqp/inventorytabs/tabs/tab/SimpleBlockTab.java index 003c1bb..935793b 100644 --- a/src/main/java/com/kqp/inventorytabs/tabs/tab/SimpleBlockTab.java +++ b/src/main/java/com/kqp/inventorytabs/tabs/tab/SimpleBlockTab.java @@ -8,6 +8,7 @@ import com.kqp.inventorytabs.util.BlockUtil; import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.ChestBlockEntity; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.command.argument.EntityAnchorArgumentType; @@ -102,7 +103,10 @@ public Text getHoverText() { @Override public List getFullHoverText() { List hoverTexts = super.getFullHoverText(); - hoverTexts.addAll(BlockUtil.getSignText(blockPos, true)); + World world = MinecraftClient.getInstance().player.world; + BlockEntity blockEntity = world.getBlockEntity(blockPos); + boolean isChest = blockEntity instanceof ChestBlockEntity; + hoverTexts.addAll(BlockUtil.getSignText(blockPos, isChest)); return hoverTexts; }