diff --git a/src/main/java/mcp/mobius/waila/WailaClient.java b/src/main/java/mcp/mobius/waila/WailaClient.java index 0fde3ca08..1411678ef 100644 --- a/src/main/java/mcp/mobius/waila/WailaClient.java +++ b/src/main/java/mcp/mobius/waila/WailaClient.java @@ -95,7 +95,7 @@ protected static void onClientTick() { protected static void onItemTooltip(ItemStack stack, List tooltip) { if (PluginConfig.CLIENT.getBoolean(WailaConstants.CONFIG_SHOW_ITEM_MOD_NAME)) { for (var listener : Registrar.get().eventListeners.get(Object.class)) { - var name = listener.instance().getHoveredItemModName(stack, PluginConfig.CLIENT); + var name = listener.instance().instance().getHoveredItemModName(stack, PluginConfig.CLIENT); if (name != null) { tooltip.add(IWailaConfig.get().getFormatter().modName(name)); return; diff --git a/src/main/java/mcp/mobius/waila/command/ClientCommand.java b/src/main/java/mcp/mobius/waila/command/ClientCommand.java index 134f2e5de..c7b9c6285 100644 --- a/src/main/java/mcp/mobius/waila/command/ClientCommand.java +++ b/src/main/java/mcp/mobius/waila/command/ClientCommand.java @@ -12,6 +12,7 @@ import mcp.mobius.waila.config.ConfigEntry; import mcp.mobius.waila.config.PluginConfig; import mcp.mobius.waila.gui.screen.HomeScreen; +import mcp.mobius.waila.gui.screen.InspectorScreen; import mcp.mobius.waila.plugin.PluginInfo; import mcp.mobius.waila.plugin.PluginLoader; import net.minecraft.client.Minecraft; @@ -158,6 +159,14 @@ protected final void register(ArgumentBuilderBuilder command) { }) .pop("enabled", "showFps") + .then(literal("inspect")) + .executes(context -> { + var client = Minecraft.getInstance(); + client.tell(() -> client.setScreen(new InspectorScreen())); + return 1; + }) + .pop("inspect") + .pop("debug"); } diff --git a/src/main/java/mcp/mobius/waila/gui/hud/ComponentHandler.java b/src/main/java/mcp/mobius/waila/gui/hud/ComponentHandler.java index e86a91b7f..28b09f901 100644 --- a/src/main/java/mcp/mobius/waila/gui/hud/ComponentHandler.java +++ b/src/main/java/mcp/mobius/waila/gui/hud/ComponentHandler.java @@ -71,7 +71,9 @@ private static void handleBlock(ClientAccessor accessor, Tooltip tooltip, Object var registrar = Registrar.get(); var providers = registrar.blockComponent.get(position).get(obj); for (var entry : providers) { - var provider = entry.instance(); + var origin = entry.instance(); + var provider = origin.instance(); + tooltip.origin = origin; try { switch (position) { case HEAD -> provider.appendHead(tooltip, accessor, PluginConfig.CLIENT); @@ -81,6 +83,7 @@ private static void handleBlock(ClientAccessor accessor, Tooltip tooltip, Object } catch (Throwable e) { ExceptionUtil.dump(e, provider.getClass().toString(), tooltip); } + tooltip.origin = null; } } @@ -121,7 +124,9 @@ public static void gatherEntity(Entity entity, ClientAccessor accessor, Tooltip var providers = registrar.entityComponent.get(position).get(entity); for (var entry : providers) { - var provider = entry.instance(); + var origin = entry.instance(); + var provider = origin.instance(); + tooltip.origin = origin; try { switch (position) { case HEAD -> provider.appendHead(tooltip, accessor, PluginConfig.CLIENT); @@ -131,6 +136,7 @@ public static void gatherEntity(Entity entity, ClientAccessor accessor, Tooltip } catch (Throwable e) { ExceptionUtil.dump(e, provider.getClass().toString(), tooltip); } + tooltip.origin = null; } } @@ -142,10 +148,9 @@ public static ITooltipComponent getIcon(HitResult target) { if (target.getType() == HitResult.Type.ENTITY) { var providers = registrar.entityIcon.get(data.getEntity()); for (var provider : providers) { - var icon = provider.instance().getIcon(data, config); - if (icon != null) { - return icon; - } + var origin = provider.instance(); + var icon = InspectComponent.maybeWrap(origin.instance().getIcon(data, config), origin, null); + if (icon != null) return icon; } } else { var state = data.getBlockState(); @@ -155,9 +160,10 @@ public static ITooltipComponent getIcon(HitResult target) { var priority = 0; for (var provider : registrar.blockIcon.get(state.getBlock())) { - var icon = provider.instance().getIcon(ClientAccessor.INSTANCE, PluginConfig.CLIENT); + var origin = provider.instance(); + var icon = origin.instance().getIcon(ClientAccessor.INSTANCE, PluginConfig.CLIENT); if (icon != null) { - result = icon; + result = InspectComponent.maybeWrap(icon, origin, null); priority = provider.priority(); break; } @@ -168,9 +174,10 @@ public static ITooltipComponent getIcon(HitResult target) { for (var provider : registrar.blockIcon.get(blockEntity)) { if (provider.priority() >= priority) break; - var icon = provider.instance().getIcon(ClientAccessor.INSTANCE, PluginConfig.CLIENT); + var origin = provider.instance(); + var icon = origin.instance().getIcon(ClientAccessor.INSTANCE, PluginConfig.CLIENT); if (icon != null) { - result = icon; + result = InspectComponent.maybeWrap(icon, origin, null); break; } } diff --git a/src/main/java/mcp/mobius/waila/gui/hud/ComponentRenderer.java b/src/main/java/mcp/mobius/waila/gui/hud/ComponentRenderer.java new file mode 100644 index 000000000..7ee7010b5 --- /dev/null +++ b/src/main/java/mcp/mobius/waila/gui/hud/ComponentRenderer.java @@ -0,0 +1,73 @@ +package mcp.mobius.waila.gui.hud; + +import java.util.Random; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import mcp.mobius.waila.WailaClient; +import mcp.mobius.waila.api.ITooltipComponent; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.util.Mth; +import org.jetbrains.annotations.Nullable; + +import static mcp.mobius.waila.util.DisplayUtil.renderRectBorder; + +public abstract class ComponentRenderer { + + private static final Random RANDOM = new Random(); + + public abstract void render(PoseStack matrices, ITooltipComponent component, int x, int y, int cw, int ch, float delta); + + private static @Nullable ComponentRenderer current = null; + + public static ComponentRenderer get() { + if (current == null) current = Default.INSTANCE; + return current; + } + + public static void set(@Nullable ComponentRenderer value) { + if (value == null) value = Default.INSTANCE; + current = value; + } + + public static class Default extends ComponentRenderer { + + public static final Default INSTANCE = new Default(); + + @Override + public void render(PoseStack matrices, ITooltipComponent component, int x, int y, int cw, int ch, float delta) { + component.render(matrices, x, y, delta); + + if (WailaClient.showComponentBounds) { + renderBounds(matrices, x, y, cw, ch, 1f); + } + } + + public static void renderBounds(PoseStack matrices, int x, int y, int cw, int ch, float v) { + matrices.pushPose(); + var scale = (float) Minecraft.getInstance().getWindow().getGuiScale(); + matrices.scale(1 / scale, 1 / scale, 1); + + RenderSystem.setShader(GameRenderer::getPositionColorShader); + + var tesselator = Tesselator.getInstance(); + var buf = tesselator.getBuilder(); + buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + var bx = Mth.floor(x * scale + 0.5); + var by = Mth.floor(y * scale + 0.5); + var bw = Mth.floor(cw * scale + 0.5); + var bh = Mth.floor(ch * scale + 0.5); + var color = (0xFF << 24) + Mth.hsvToRgb(RANDOM.nextFloat(), RANDOM.nextFloat(), v); + renderRectBorder(matrices.last().pose(), buf, bx, by, bw, bh, 1, color, color); + tesselator.end(); + + matrices.popPose(); + } + + } + +} diff --git a/src/main/java/mcp/mobius/waila/gui/hud/InspectComponent.java b/src/main/java/mcp/mobius/waila/gui/hud/InspectComponent.java new file mode 100644 index 000000000..7b8f86030 --- /dev/null +++ b/src/main/java/mcp/mobius/waila/gui/hud/InspectComponent.java @@ -0,0 +1,71 @@ +package mcp.mobius.waila.gui.hud; + +import com.mojang.blaze3d.vertex.PoseStack; +import mcp.mobius.waila.api.ITooltipComponent; +import mcp.mobius.waila.registry.PluginAware; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +public class InspectComponent implements ITooltipComponent { + + public static boolean wrap = false; + + public final ITooltipComponent actual; + public final PluginAware origin; + public final ResourceLocation tag; + + private InspectComponent(ITooltipComponent actual, PluginAware origin, ResourceLocation tag) { + this.actual = actual; + this.origin = origin; + this.tag = tag; + } + + public static @Nullable ITooltipComponent maybeWrap(@Nullable ITooltipComponent actual, @Nullable PluginAware origin, @Nullable ResourceLocation tag) { + if (!wrap || actual == null || origin == null || actual instanceof InspectComponent) { + return actual; + } + + if (actual instanceof ITooltipComponent.HorizontalGrowing hg) { + return new InspectComponent.Growing(hg, origin, tag); + } + + return new InspectComponent(actual, origin, tag); + } + + @Override + public int getWidth() { + return actual.getWidth(); + } + + @Override + public int getHeight() { + return actual.getHeight(); + } + + @Override + public void render(PoseStack matrices, int x, int y, float delta) { + actual.render(matrices, x, y, delta); + } + + public static class Growing extends InspectComponent implements HorizontalGrowing { + + public final HorizontalGrowing actual; + + public Growing(HorizontalGrowing actual, PluginAware origin, ResourceLocation tag) { + super(actual, origin, tag); + this.actual = actual; + } + + @Override + public int getMinimalWidth() { + return actual.getMinimalWidth(); + } + + @Override + public void setGrownWidth(int grownWidth) { + actual.setGrownWidth(grownWidth); + } + + } + +} diff --git a/src/main/java/mcp/mobius/waila/gui/hud/Line.java b/src/main/java/mcp/mobius/waila/gui/hud/Line.java index fc84917e8..c910fe1ed 100644 --- a/src/main/java/mcp/mobius/waila/gui/hud/Line.java +++ b/src/main/java/mcp/mobius/waila/gui/hud/Line.java @@ -12,19 +12,20 @@ import mcp.mobius.waila.api.ITooltipComponent.HorizontalGrowing; import mcp.mobius.waila.api.ITooltipLine; import mcp.mobius.waila.api.component.WrappedComponent; -import mcp.mobius.waila.util.DisplayUtil; +import mcp.mobius.waila.registry.PluginAware; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; public class Line implements ITooltipLine { - @Nullable - public final ResourceLocation tag; + public final @Nullable ResourceLocation tag; public final List components = new ArrayList<>(); public final Object2IntOpenHashMap widths = new Object2IntOpenHashMap<>(); public final Object2IntMap heights = new Object2IntOpenHashMap<>(); + public @Nullable PluginAware origin; + private int fixedWidth = -1; private int width = -1; private int height = -1; @@ -38,6 +39,7 @@ public Line(@Nullable ResourceLocation tag) { @Override public Line with(ITooltipComponent component) { + component = InspectComponent.maybeWrap(component, origin, tag); components.add(component); if (component instanceof HorizontalGrowing growing) { growingWeight += growing.getWeight(); @@ -139,7 +141,7 @@ public int getHeight() { return height; } - public void render(PoseStack matrices, int x, int y, float delta) { + public void render(ComponentRenderer renderer, PoseStack matrices, int x, int y, float delta) { Preconditions.checkState(width != -1 && height != -1); var cx = x; @@ -149,7 +151,7 @@ public void render(PoseStack matrices, int x, int y, float delta) { var h = heights.getInt(component); var cy = y + (h < height ? (height - h) / 2 : 0); - DisplayUtil.renderComponent(matrices, component, cx, cy, w, delta); + renderer.render(matrices, component, cx, cy, w, h, delta); cx += w + 1; } } diff --git a/src/main/java/mcp/mobius/waila/gui/hud/Tooltip.java b/src/main/java/mcp/mobius/waila/gui/hud/Tooltip.java index d9fa86867..27477fbc1 100644 --- a/src/main/java/mcp/mobius/waila/gui/hud/Tooltip.java +++ b/src/main/java/mcp/mobius/waila/gui/hud/Tooltip.java @@ -5,11 +5,14 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import mcp.mobius.waila.api.ITooltip; import mcp.mobius.waila.api.ITooltipLine; +import mcp.mobius.waila.registry.PluginAware; import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; public class Tooltip extends ObjectArrayList implements ITooltip { private final Object2IntMap tags = new Object2IntOpenHashMap<>(); + public @Nullable PluginAware origin; public void setLine(ResourceLocation tag, Line line) { if (tags.containsKey(tag)) { @@ -27,12 +30,15 @@ public int getLineCount() { @Override public ITooltipLine getLine(int index) { - return get(index); + var line = get(index); + line.origin = origin; + return line; } @Override public ITooltipLine addLine() { var line = new Line(null); + line.origin = origin; add(line); return line; } @@ -40,6 +46,7 @@ public ITooltipLine addLine() { @Override public ITooltipLine setLine(ResourceLocation tag) { var line = new Line(tag); + line.origin = origin; setLine(tag, line); return line; } diff --git a/src/main/java/mcp/mobius/waila/gui/hud/TooltipHandler.java b/src/main/java/mcp/mobius/waila/gui/hud/TooltipHandler.java index d25e2ac43..5e21386e0 100644 --- a/src/main/java/mcp/mobius/waila/gui/hud/TooltipHandler.java +++ b/src/main/java/mcp/mobius/waila/gui/hud/TooltipHandler.java @@ -17,6 +17,7 @@ import mcp.mobius.waila.pick.PickerAccessor; import mcp.mobius.waila.pick.PickerResults; import mcp.mobius.waila.registry.Registrar; +import mcp.mobius.waila.util.ProfilerUtil; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.ChatScreen; @@ -46,24 +47,38 @@ private enum ProcessResult { } public static void tick() { + tick(STATE, false); + } + + public static boolean tick(TooltipRenderer.State state, boolean inspect) { + try (var ignored = ProfilerUtil.profile("wthit:tick")) { + return _tick(state, inspect); + } + } + + private static boolean _tick(TooltipRenderer.State state, boolean inspect) { STATE.render = false; var client = Minecraft.getInstance(); var config = Waila.CONFIG.get().getGeneral(); - if (client.options.hideGui) return; - if (client.screen != null && !(client.screen instanceof ChatScreen)) return; - if (client.level == null || !config.isDisplayTooltip()) return; - if (config.getDisplayMode() == IWailaConfig.General.DisplayMode.HOLD_KEY && !WailaClient.keyShowOverlay.isDown()) return; - if (config.isHideFromPlayerList() && ((PlayerTabOverlayAccess) client.gui.getTabList()).wthit_isVisible()) return; - if (config.isHideFromDebug() && client.options.renderDebug) return; - if (client.gameMode == null) return; + if (client.level == null) return false; + if (client.gameMode == null) return false; + + if (!inspect) { + if (client.options.hideGui) return false; + if (client.screen != null && !(client.screen instanceof ChatScreen)) return false; + if (!config.isDisplayTooltip()) return false; + if (config.getDisplayMode() == IWailaConfig.General.DisplayMode.HOLD_KEY && !WailaClient.keyShowOverlay.isDown()) return false; + if (config.isHideFromPlayerList() && ((PlayerTabOverlayAccess) client.gui.getTabList()).wthit_isVisible()) return false; + if (config.isHideFromDebug() && client.options.renderDebug) return false; + } Player player = client.player; - if (player == null) return; + if (player == null) return false; var camera = client.cameraEntity; - if (camera == null) return; + if (camera == null) return false; var frameTime = client.getFrameTime(); var pickRange = client.gameMode.getPickRange(); @@ -89,14 +104,16 @@ public static void tick() { } } - if (castOrigin == null) return; + if (castOrigin == null) return false; for (var target : results) { - if (processTarget(target, client, player, castOrigin, castDirection, pickRange, config) == ProcessResult.BREAK) break; + if (processTarget(state, target, client, player, castOrigin, castDirection, pickRange, config) == ProcessResult.BREAK) break; } + + return true; } - private static ProcessResult redirectTarget(HitResult target, TargetRedirector redirector, Minecraft client, Player player, Vec3 castOrigin, Vec3 castDirection, float pickRange, WailaConfig.General config) { + private static ProcessResult redirectTarget(TooltipRenderer.State state, HitResult target, TargetRedirector redirector, Minecraft client, Player player, Vec3 castOrigin, Vec3 castDirection, double pickRange, WailaConfig.General config) { if (redirector.nowhere) return ProcessResult.BREAK; if (redirector.behind) return ProcessResult.CONTINUE; @@ -105,18 +122,18 @@ private static ProcessResult redirectTarget(HitResult target, TargetRedirector r if (redirect.getType() == HitResult.Type.MISS) return ProcessResult.CONTINUE; return processTarget( - redirect, client, player, + state, redirect, client, player, castOrigin.subtract(target.getLocation().subtract(redirect.getLocation())), castDirection, pickRange, config); } - private static ProcessResult processTarget(HitResult target, Minecraft client, Player player, Vec3 castOrigin, Vec3 castDirection, float pickRange, WailaConfig.General config) { + private static ProcessResult processTarget(TooltipRenderer.State state, HitResult target, Minecraft client, Player player, Vec3 castOrigin, Vec3 castDirection, double pickRange, WailaConfig.General config) { var accessor = ClientAccessor.INSTANCE; //noinspection DataFlowIssue accessor.set(client.level, player, target, client.cameraEntity, castOrigin, castDirection, pickRange, client.getFrameTime()); - TooltipRenderer.beginBuild(STATE); + TooltipRenderer.beginBuild(state); if (target.getType() == HitResult.Type.BLOCK) { var block = accessor.getBlock(); @@ -144,7 +161,7 @@ private static ProcessResult processTarget(HitResult target, Minecraft client, P } if (redirectResult != null && !redirector.self) { - return redirectTarget(target, redirector, client, player, castOrigin, castDirection, pickRange, config); + return redirectTarget(state, target, redirector, client, player, castOrigin, castDirection, pickRange, config); } if (block instanceof LiquidBlock) { @@ -153,10 +170,10 @@ private static ProcessResult processTarget(HitResult target, Minecraft client, P return ProcessResult.CONTINUE; } - var state = ComponentHandler.getOverrideBlock(target); - if (state == IBlockComponentProvider.EMPTY_BLOCK_STATE) return ProcessResult.CONTINUE; + var blockState = ComponentHandler.getOverrideBlock(target); + if (blockState == IBlockComponentProvider.EMPTY_BLOCK_STATE) return ProcessResult.CONTINUE; - accessor.setState(state); + accessor.setState(blockState); requestBlockData(accessor); @@ -189,7 +206,7 @@ private static ProcessResult processTarget(HitResult target, Minecraft client, P } if (redirectResult != null && !redirector.self) { - return redirectTarget(target, redirector, client, player, castOrigin, castDirection, pickRange, config); + return redirectTarget(state, target, redirector, client, player, castOrigin, castDirection, pickRange, config); } if (!PluginConfig.CLIENT.getBoolean(WailaConstants.CONFIG_SHOW_ENTITY)) return ProcessResult.CONTINUE; diff --git a/src/main/java/mcp/mobius/waila/gui/hud/TooltipRenderer.java b/src/main/java/mcp/mobius/waila/gui/hud/TooltipRenderer.java index ba419e233..fa28514d8 100644 --- a/src/main/java/mcp/mobius/waila/gui/hud/TooltipRenderer.java +++ b/src/main/java/mcp/mobius/waila/gui/hud/TooltipRenderer.java @@ -1,6 +1,6 @@ package mcp.mobius.waila.gui.hud; -import java.awt.Rectangle; +import java.awt.*; import java.util.Iterator; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; @@ -28,6 +28,7 @@ import mcp.mobius.waila.mixin.GameNarratorAccess; import mcp.mobius.waila.mixin.MinecraftAccess; import mcp.mobius.waila.registry.Registrar; +import mcp.mobius.waila.util.ProfilerUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.screens.ChatScreen; @@ -35,8 +36,6 @@ import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; -import static mcp.mobius.waila.util.DisplayUtil.renderComponent; - public class TooltipRenderer { private static final Tooltip TOOLTIP = new Tooltip(); @@ -85,6 +84,10 @@ public static void add(Line line) { } for (var component : line.components) { + if (component instanceof InspectComponent wrapper) { + component = wrapper.actual; + } + if (component instanceof PairComponent pair) { colonOffset = Math.max(pair.key.getWidth(), colonOffset); break; @@ -99,10 +102,15 @@ public static void setIcon(ITooltipComponent icon) { public static Rectangle endBuild() { Preconditions.checkState(started); + var accessor = ClientAccessor.INSTANCE; if (state.fireEvent()) { - for (var listener : Registrar.get().eventListeners.get(Object.class)) { - listener.instance().onHandleTooltip(TOOLTIP, ClientAccessor.INSTANCE, PluginConfig.CLIENT); + for (var entry : Registrar.get().eventListeners.get(Object.class)) { + var pa = entry.instance(); + var listener = pa.instance(); + TOOLTIP.origin = pa; + listener.onHandleTooltip(TOOLTIP, accessor, PluginConfig.CLIENT); + TOOLTIP.origin = null; } } @@ -178,7 +186,6 @@ public static Rectangle endBuild() { return RECT.get(); } - @SuppressWarnings("DataFlowIssue") public static void resetState() { state = null; } @@ -202,7 +209,7 @@ public static void render(PoseStack matrices, float delta) { // TODO: Figure out why opacity not working properly //noinspection ConstantValue if (true) { - render0(client, matrices, delta); + renderUncached(matrices, delta); return; } @@ -225,7 +232,7 @@ public static void render(PoseStack matrices, float delta) { framebuffer.clear(Minecraft.ON_OSX); framebuffer.bindWrite(true); - render0(client, matrices, delta); + renderUncached(matrices, delta); framebuffer.unbindWrite(); client.getMainRenderTarget().bindWrite(true); lastFrame = now; @@ -255,11 +262,14 @@ public static void render(PoseStack matrices, float delta) { RenderSystem.disableBlend(); } - private static void render0(Minecraft client, PoseStack matrices, float delta) { - var profiler = client.getProfiler(); - - profiler.push("Waila Overlay"); + private static void renderUncached(PoseStack matrices, float delta) { + try (var ignored = ProfilerUtil.profile("wthit:render_uncached")) { + _renderUncached(matrices, delta); + } + } + private static void _renderUncached(PoseStack matrices, float delta) { + var renderer = ComponentRenderer.get(); var scale = state.getScale(); RenderSystem.getModelViewStack().pushPose(); @@ -275,13 +285,12 @@ private static void render0(Minecraft client, PoseStack matrices, float delta) { var canceller = EventCanceller.INSTANCE; canceller.setCanceled(false); for (var listener : Registrar.get().eventListeners.get(Object.class)) { - listener.instance().onBeforeTooltipRender(matrices, rect, ClientAccessor.INSTANCE, PluginConfig.CLIENT, canceller); + listener.instance().instance().onBeforeTooltipRender(matrices, rect, ClientAccessor.INSTANCE, PluginConfig.CLIENT, canceller); if (canceller.isCanceled()) { matrices.popPose(); RenderSystem.enableDepthTest(); RenderSystem.getModelViewStack().popPose(); RenderSystem.applyModelViewMatrix(); - profiler.pop(); return; } } @@ -305,7 +314,7 @@ private static void render0(Minecraft client, PoseStack matrices, float delta) { } for (var line : TOOLTIP) { - line.render(matrices, textX, textY, delta); + line.render(renderer, matrices, textX, textY, delta); textY += line.getHeight() + 1; } @@ -314,7 +323,7 @@ private static void render0(Minecraft client, PoseStack matrices, float delta) { if (state.fireEvent()) { for (var listener : Registrar.get().eventListeners.get(Object.class)) { - listener.instance().onAfterTooltipRender(matrices, rect, ClientAccessor.INSTANCE, PluginConfig.CLIENT); + listener.instance().instance().onAfterTooltipRender(matrices, rect, ClientAccessor.INSTANCE, PluginConfig.CLIENT); } } @@ -323,12 +332,11 @@ private static void render0(Minecraft client, PoseStack matrices, float delta) { if (iconPos == Align.Y.BOTTOM) { iconY++; } - renderComponent(matrices, icon, x + padding.left, iconY, 0, delta); + renderer.render(matrices, icon, x + padding.left, iconY, icon.getWidth(), icon.getHeight(), delta); RenderSystem.enableDepthTest(); RenderSystem.getModelViewStack().popPose(); RenderSystem.applyModelViewMatrix(); - profiler.pop(); } private static void narrateObjectName(Minecraft client) { diff --git a/src/main/java/mcp/mobius/waila/gui/screen/InspectorScreen.java b/src/main/java/mcp/mobius/waila/gui/screen/InspectorScreen.java new file mode 100644 index 000000000..558bb7952 --- /dev/null +++ b/src/main/java/mcp/mobius/waila/gui/screen/InspectorScreen.java @@ -0,0 +1,180 @@ +package mcp.mobius.waila.gui.screen; + +import java.util.ArrayList; +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; +import mcp.mobius.waila.Waila; +import mcp.mobius.waila.api.ITheme; +import mcp.mobius.waila.api.ITooltipComponent; +import mcp.mobius.waila.api.IWailaConfig; +import mcp.mobius.waila.buildconst.Tl; +import mcp.mobius.waila.gui.hud.ComponentRenderer; +import mcp.mobius.waila.gui.hud.InspectComponent; +import mcp.mobius.waila.gui.hud.TooltipHandler; +import mcp.mobius.waila.gui.hud.TooltipRenderer; +import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.NotNull; + +public class InspectorScreen extends YesIAmSureTheClientInstanceIsPresentByTheTimeIUseItScreen { + + private static final String API_COMPONENTS = "mcp.mobius.waila.api.component."; + private static final Component TITLE = Component.translatable(Tl.Gui.Inspector.TITLE); + private static final State STATE = new State(); + + private final Renderer renderer = new Renderer(); + + private boolean tickSuccess = false; + + private final List hoveredComponent = new ArrayList<>(); + + public InspectorScreen() { + super(TITLE); + } + + @Override + protected void init() { + super.init(); + + InspectComponent.wrap = true; + tickSuccess = TooltipHandler.tick(STATE, true); + InspectComponent.wrap = false; + } + + @Override + public void onClose() { + super.onClose(); + TooltipHandler.tick(); + } + + @Override + public void render(@NotNull PoseStack matrices, int mouseX, int mouseY, float tickDelta) { + super.render(matrices, mouseX, mouseY, tickDelta); + + if (!hoveredComponent.isEmpty()) { + var h = minecraft.font.lineHeight + 2; + + var component = hoveredComponent.get(0); + if (component instanceof InspectComponent wrapper) component = wrapper.actual; + var clazz = component.getClass().getName(); + if (clazz.startsWith(API_COMPONENTS)) clazz = clazz.substring(API_COMPONENTS.length()); + drawString(matrices, minecraft.font, Component.literal(clazz), 5, 5, 0xFFFFFF); + + var wrapper = (InspectComponent) hoveredComponent.get(hoveredComponent.size() - 1); + drawString(matrices, minecraft.font, Component.translatable(Tl.Gui.Inspector.TAG, wrapper.tag), 5, 5 + h, 0xFFFFFF); + + var provider = wrapper.origin.instance().getClass().getName(); + drawString(matrices, minecraft.font, Component.translatable(Tl.Gui.Inspector.PROVIDER, provider), 5, 5 + h * 2, 0xFFFFFF); + + var pluginId = wrapper.origin.plugin().getPluginId().toString(); + drawString(matrices, minecraft.font, Component.translatable(Tl.Gui.Inspector.PLUGIN_ID, pluginId), 5, 5 + h * 3, 0xFFFFFF); + + var mod = wrapper.origin.plugin().getModInfo(); + drawString(matrices, minecraft.font, Component.translatable(Tl.Gui.Inspector.MOD, mod.getName(), mod.getId()), 5, 5 + h * 4, 0xFFFFFF); + } + + if (tickSuccess) { + renderer.mouseX = mouseX; + renderer.mouseY = mouseY; + hoveredComponent.clear(); + + ComponentRenderer.set(renderer); + TooltipRenderer.render(matrices, tickDelta); + ComponentRenderer.set(null); + } + } + + private class Renderer extends ComponentRenderer { + + int mouseX, mouseY; + + @Override + public void render(PoseStack matrices, ITooltipComponent component, int x, int y, int cw, int ch, float delta) { + component.render(matrices, x, y, delta); + + var v = 0.3f; + if (x < mouseX && mouseX < (x + cw) && y < mouseY && mouseY < (y + ch)) { + hoveredComponent.add(component); + v = 1f; + } + + ComponentRenderer.Default.renderBounds(matrices, x, y, cw, ch, v); + } + + } + + private static class State implements TooltipRenderer.State { + + @Override + public int getX() { + return 0; + } + + @Override + public int getY() { + return 0; + } + + @Override + public boolean render() { + return true; + } + + @Override + public boolean fireEvent() { + return true; + } + + @Override + public int getFps() { + return 0; + } + + @Override + public float getScale() { + return 1; + } + + @Override + public IWailaConfig.Overlay.Position.Align.X getXAnchor() { + return IWailaConfig.Overlay.Position.Align.X.CENTER; + } + + @Override + public IWailaConfig.Overlay.Position.Align.Y getYAnchor() { + return IWailaConfig.Overlay.Position.Align.Y.MIDDLE; + } + + @Override + public IWailaConfig.Overlay.Position.Align.X getXAlign() { + return IWailaConfig.Overlay.Position.Align.X.CENTER; + } + + @Override + public IWailaConfig.Overlay.Position.Align.Y getYAlign() { + return IWailaConfig.Overlay.Position.Align.Y.MIDDLE; + } + + @Override + public boolean bossBarsOverlap() { + return false; + } + + @Override + public boolean enableTextToSpeech() { + return false; + } + + @Override + public int getBackgroundAlpha() { + return 0xFF; + } + + @Override + public ITheme getTheme() { + return Waila.CONFIG.get().getOverlay().getColor().getTheme(); + } + + } + +} diff --git a/src/main/java/mcp/mobius/waila/registry/PluginAware.java b/src/main/java/mcp/mobius/waila/registry/PluginAware.java new file mode 100644 index 000000000..5231d5bc3 --- /dev/null +++ b/src/main/java/mcp/mobius/waila/registry/PluginAware.java @@ -0,0 +1,7 @@ +package mcp.mobius.waila.registry; + +import mcp.mobius.waila.api.IPluginInfo; + +@SuppressWarnings("deprecation") +public record PluginAware(IPluginInfo plugin, T instance) { +} diff --git a/src/main/java/mcp/mobius/waila/registry/Registrar.java b/src/main/java/mcp/mobius/waila/registry/Registrar.java index 9dc656c5b..910458d32 100644 --- a/src/main/java/mcp/mobius/waila/registry/Registrar.java +++ b/src/main/java/mcp/mobius/waila/registry/Registrar.java @@ -58,10 +58,10 @@ public class Registrar implements ICommonRegistrar, IClientRegistrar, IRegistrar public final InstanceRegistry blockRedirect = new InstanceRegistry<>(); public final InstanceRegistry blockOverride = new InstanceRegistry<>(); - public final InstanceRegistry blockIcon = new InstanceRegistry<>(); + public final InstanceRegistry> blockIcon = new InstanceRegistry<>(); public final InstanceRegistry blockDataCtx = new InstanceRegistry<>(); public final InstanceRegistry> blockData = new InstanceRegistry<>(); - public final Map> blockComponent = Util.make(new EnumMap<>(TooltipPosition.class), map -> { + public final Map>> blockComponent = Util.make(new EnumMap<>(TooltipPosition.class), map -> { for (var key : TooltipPosition.values()) { map.put(key, new InstanceRegistry<>()); } @@ -69,16 +69,16 @@ public class Registrar implements ICommonRegistrar, IClientRegistrar, IRegistrar public final InstanceRegistry entityRedirect = new InstanceRegistry<>(); public final InstanceRegistry entityOverride = new InstanceRegistry<>(); - public final InstanceRegistry entityIcon = new InstanceRegistry<>(); + public final InstanceRegistry> entityIcon = new InstanceRegistry<>(); public final InstanceRegistry entityDataCtx = new InstanceRegistry<>(); public final InstanceRegistry> entityData = new InstanceRegistry<>(); - public final Map> entityComponent = Util.make(new EnumMap<>(TooltipPosition.class), map -> { + public final Map>> entityComponent = Util.make(new EnumMap<>(TooltipPosition.class), map -> { for (var key : TooltipPosition.values()) { map.put(key, new InstanceRegistry<>()); } }); - public final InstanceRegistry eventListeners = Util.make(new InstanceRegistry<>(), InstanceRegistry::reversed); + public final InstanceRegistry> eventListeners = Util.make(new InstanceRegistry<>(), InstanceRegistry::reversed); public final InstanceRegistry raycastVectorProviders = new InstanceRegistry<>(); public final BlacklistConfig blacklist = new BlacklistConfig(); @@ -111,7 +111,6 @@ public void attach(@Nullable IPluginInfo plugin) { this.plugin = plugin; } - @SuppressWarnings("DataFlowIssue") private void addConfig(ResourceLocation key, T defaultValue, T clientOnlyValue, boolean serverRequired, boolean merged, ConfigEntry.Type type) { assertLock(); PluginConfig.addConfig(type.create(plugin, key, defaultValue, clientOnlyValue, serverRequired, merged)); @@ -204,7 +203,7 @@ public void configAlias(ResourceLocation actual, ResourceLocation... aliases) { public void eventListener(IEventListener listener, int priority) { if (skip()) return; assertLock(); - eventListeners.add(Object.class, listener, priority); + eventListeners.add(Object.class, new PluginAware<>(plugin, listener), priority); } @Override @@ -254,7 +253,7 @@ public void icon(IBlockComponentProvider provider, Class clazz, int prior assertLock(); assertPriority(priority); warnTargetClass(provider, clazz); - blockIcon.add(clazz, provider, priority); + blockIcon.add(clazz, new PluginAware<>(plugin, provider), priority); } } @@ -264,7 +263,7 @@ private void component(IBlockComponentProvider provider, TooltipPosition pos assertLock(); assertPriority(priority); warnTargetClass(provider, clazz); - blockComponent.get(position).add(clazz, provider, priority); + blockComponent.get(position).add(clazz, new PluginAware<>(plugin, provider), priority); } } @@ -341,7 +340,7 @@ public void icon(IEntityComponentProvider provider, Class clazz, int prio assertLock(); assertPriority(priority); warnTargetClass(provider, clazz); - entityIcon.add(clazz, provider, priority); + entityIcon.add(clazz, new PluginAware<>(plugin, provider), priority); } } @@ -351,7 +350,7 @@ private void component(IEntityComponentProvider provider, TooltipPosition po assertLock(); assertPriority(priority); warnTargetClass(provider, clazz); - entityComponent.get(position).add(clazz, provider, priority); + entityComponent.get(position).add(clazz, new PluginAware<>(plugin, provider), priority); } } diff --git a/src/main/java/mcp/mobius/waila/service/ClientApiService.java b/src/main/java/mcp/mobius/waila/service/ClientApiService.java index e594e5cb3..fbec2a386 100644 --- a/src/main/java/mcp/mobius/waila/service/ClientApiService.java +++ b/src/main/java/mcp/mobius/waila/service/ClientApiService.java @@ -5,6 +5,7 @@ import com.mojang.math.Matrix4f; import mcp.mobius.waila.api.ITooltipComponent; import mcp.mobius.waila.api.__internal__.IClientApiService; +import mcp.mobius.waila.gui.hud.ComponentRenderer; import mcp.mobius.waila.util.DisplayUtil; import net.minecraft.world.item.ItemStack; @@ -12,7 +13,7 @@ public class ClientApiService implements IClientApiService { @Override public void renderComponent(PoseStack matrices, ITooltipComponent component, int x, int y, float delta) { - DisplayUtil.renderComponent(matrices, component, x, y, 0, delta); + ComponentRenderer.get().render(matrices, component, x, y, component.getWidth(), component.getHeight(), delta); } @Override diff --git a/src/main/java/mcp/mobius/waila/util/DisplayUtil.java b/src/main/java/mcp/mobius/waila/util/DisplayUtil.java index 704aacacd..88dba80d1 100644 --- a/src/main/java/mcp/mobius/waila/util/DisplayUtil.java +++ b/src/main/java/mcp/mobius/waila/util/DisplayUtil.java @@ -1,29 +1,19 @@ package mcp.mobius.waila.util; import java.util.IllegalFormatException; -import java.util.Random; import com.mojang.blaze3d.platform.Lighting; import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.math.Matrix4f; -import mcp.mobius.waila.WailaClient; -import mcp.mobius.waila.api.ITooltipComponent; import mcp.mobius.waila.api.WailaHelper; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.renderer.GameRenderer; import net.minecraft.util.FastColor; -import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; public final class DisplayUtil extends GuiComponent { - private static final Random RANDOM = new Random(); private static final Minecraft CLIENT = Minecraft.getInstance(); @@ -66,33 +56,6 @@ public static void renderRectBorder(Matrix4f matrix, VertexConsumer buf, int x, // @formatter:on } - public static void renderComponent(PoseStack matrices, ITooltipComponent component, int x, int y, int cw, float delta) { - component.render(matrices, x, y, delta); - - if (WailaClient.showComponentBounds) { - matrices.pushPose(); - var scale = (float) Minecraft.getInstance().getWindow().getGuiScale(); - matrices.scale(1 / scale, 1 / scale, 1); - - RenderSystem.disableTexture(); - RenderSystem.setShader(GameRenderer::getPositionColorShader); - - var tesselator = Tesselator.getInstance(); - var buf = tesselator.getBuilder(); - buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - var bx = Mth.floor(x * scale + 0.5); - var by = Mth.floor(y * scale + 0.5); - var bw = Mth.floor((cw == 0 ? component.getWidth() : cw) * scale + 0.5); - var bh = Mth.floor(component.getHeight() * scale + 0.5); - var color = (0xFF << 24) + Mth.hsvToRgb(RANDOM.nextFloat(), RANDOM.nextFloat(), 1f); - renderRectBorder(matrices.last().pose(), buf, bx, by, bw, bh, 1, color, color); - tesselator.end(); - - RenderSystem.enableTexture(); - matrices.popPose(); - } - } - public static void fillGradient(Matrix4f matrix, VertexConsumer buf, int x, int y, int w, int h, int start, int end) { var sa = FastColor.ARGB32.alpha(start) / 255.0F; var sr = FastColor.ARGB32.red(start) / 255.0F; diff --git a/src/main/java/mcp/mobius/waila/util/ProfilerUtil.java b/src/main/java/mcp/mobius/waila/util/ProfilerUtil.java new file mode 100644 index 000000000..fca17735d --- /dev/null +++ b/src/main/java/mcp/mobius/waila/util/ProfilerUtil.java @@ -0,0 +1,29 @@ +package mcp.mobius.waila.util; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.profiling.ProfilerFiller; + +public class ProfilerUtil { + + public static Impl profile(String name) { + return Impl.INSTANCE.start(name); + } + + public enum Impl implements AutoCloseable { + INSTANCE; + + ProfilerFiller profiler; + + private Impl start(String name) { + profiler = Minecraft.getInstance().getProfiler(); + profiler.push(name); + return this; + } + + @Override + public void close() { + profiler.pop(); + } + } + +} diff --git a/src/resources/resources/assets/waila/lang/en_us.json b/src/resources/resources/assets/waila/lang/en_us.json index 6da73b459..4ec5dce0a 100644 --- a/src/resources/resources/assets/waila/lang/en_us.json +++ b/src/resources/resources/assets/waila/lang/en_us.json @@ -106,6 +106,12 @@ "gui.waila.credits.authors" : "Authors", "gui.waila.credits.contributors" : "Contributors", + "gui.waila.inspector.title" : "Inspector", + "gui.waila.inspector.tag" : "Tag: %s", + "gui.waila.inspector.provider" : "Provider: %s", + "gui.waila.inspector.plugin_id" : "Plugin ID: %s", + "gui.waila.inspector.mod" : "Mod: %s (%s)", + "json5.waila.config.default_value" : "Default value: [%s]", "json5.waila.config.available_values" : "Available values: [%s]",