From fd7e62b2a92031d1e3bb3da4c8030fdf1a96fa01 Mon Sep 17 00:00:00 2001 From: Sergey Shatunov Date: Wed, 10 Jan 2024 05:04:08 +0800 Subject: [PATCH] Add ClientTooltipComponentRegistry for custom tooltips (#463) Signed-off-by: Sergey Shatunov --- .../gui/ClientTooltipComponentRegistry.java | 50 ++++++++++++++ .../ClientTooltipComponentRegistryImpl.java | 43 ++++++++++++ .../event/forge/EventHandlerImplClient.java | 11 ++++ .../ClientTooltipComponentRegistryImpl.java | 58 +++++++++++++++++ .../java/dev/architectury/test/TestMod.java | 3 + .../test/registry/TestRegistries.java | 4 ++ .../registry/objects/ItemWithTooltip.java | 65 +++++++++++++++++++ 7 files changed, 234 insertions(+) create mode 100644 common/src/main/java/dev/architectury/registry/client/gui/ClientTooltipComponentRegistry.java create mode 100644 fabric/src/main/java/dev/architectury/registry/client/gui/fabric/ClientTooltipComponentRegistryImpl.java create mode 100644 forge/src/main/java/dev/architectury/registry/client/gui/forge/ClientTooltipComponentRegistryImpl.java create mode 100644 testmod-common/src/main/java/dev/architectury/test/registry/objects/ItemWithTooltip.java diff --git a/common/src/main/java/dev/architectury/registry/client/gui/ClientTooltipComponentRegistry.java b/common/src/main/java/dev/architectury/registry/client/gui/ClientTooltipComponentRegistry.java new file mode 100644 index 00000000..b7e9a798 --- /dev/null +++ b/common/src/main/java/dev/architectury/registry/client/gui/ClientTooltipComponentRegistry.java @@ -0,0 +1,50 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021, 2022 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.registry.client.gui; + +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.world.inventory.tooltip.TooltipComponent; + +import java.util.function.Function; + +/** + * Registry for {@link ClientTooltipComponent} factories + */ +@Environment(EnvType.CLIENT) +public final class ClientTooltipComponentRegistry { + private ClientTooltipComponentRegistry() { + } + + /** + * Allows users to register custom {@link ClientTooltipComponent} + * factories for their {@link TooltipComponent} types. + * + * @param clazz class of {@link T} + * @param factory factory to create instances of {@link ClientTooltipComponent} from {@link T} + * @param the type of {@link TooltipComponent} factory + */ + @ExpectPlatform + public static void register(Class clazz, Function factory) { + throw new AssertionError(); + } +} diff --git a/fabric/src/main/java/dev/architectury/registry/client/gui/fabric/ClientTooltipComponentRegistryImpl.java b/fabric/src/main/java/dev/architectury/registry/client/gui/fabric/ClientTooltipComponentRegistryImpl.java new file mode 100644 index 00000000..5f07c2d2 --- /dev/null +++ b/fabric/src/main/java/dev/architectury/registry/client/gui/fabric/ClientTooltipComponentRegistryImpl.java @@ -0,0 +1,43 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021, 2022 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.registry.client.gui.fabric; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.rendering.v1.TooltipComponentCallback; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.world.inventory.tooltip.TooltipComponent; +import org.jetbrains.annotations.ApiStatus; + +import java.util.function.Function; + +@Environment(EnvType.CLIENT) +@ApiStatus.Internal +public class ClientTooltipComponentRegistryImpl { + + public static void register(Class clazz, Function factory) { + TooltipComponentCallback.EVENT.register((tooltipComponent) -> { + if (clazz.isInstance(tooltipComponent)) { + return factory.apply(clazz.cast(tooltipComponent)); + } + return null; + }); + } +} diff --git a/forge/src/main/java/dev/architectury/event/forge/EventHandlerImplClient.java b/forge/src/main/java/dev/architectury/event/forge/EventHandlerImplClient.java index ab6cca72..8cc9b6c8 100644 --- a/forge/src/main/java/dev/architectury/event/forge/EventHandlerImplClient.java +++ b/forge/src/main/java/dev/architectury/event/forge/EventHandlerImplClient.java @@ -28,11 +28,13 @@ import dev.architectury.hooks.forgelike.ForgeLikeClientHooks; import dev.architectury.impl.ScreenAccessImpl; import dev.architectury.impl.TooltipEventColorContextImpl; import dev.architectury.impl.TooltipEventPositionContextImpl; +import dev.architectury.registry.client.gui.forge.ClientTooltipComponentRegistryImpl; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.network.chat.Component; +import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.event.*; @@ -336,5 +338,14 @@ public class EventHandlerImplClient { public static void event(RegisterShadersEvent event) { ClientReloadShadersEvent.EVENT.invoker().reload(event.getResourceProvider(), event::registerShader); } + + @SubscribeEvent(priority = EventPriority.HIGH) + public static void event(RegisterClientTooltipComponentFactoriesEvent event) { + ClientTooltipComponentRegistryImpl.consume(factory -> registerTooltipComponent(factory, event)); + } + + private static void registerTooltipComponent(ClientTooltipComponentRegistryImpl.Factory factory, RegisterClientTooltipComponentFactoriesEvent event) { + event.register(factory.clazz(), factory.factory()); + } } } diff --git a/forge/src/main/java/dev/architectury/registry/client/gui/forge/ClientTooltipComponentRegistryImpl.java b/forge/src/main/java/dev/architectury/registry/client/gui/forge/ClientTooltipComponentRegistryImpl.java new file mode 100644 index 00000000..be405e51 --- /dev/null +++ b/forge/src/main/java/dev/architectury/registry/client/gui/forge/ClientTooltipComponentRegistryImpl.java @@ -0,0 +1,58 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021, 2022 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.registry.client.gui.forge; + +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.world.inventory.tooltip.TooltipComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +@OnlyIn(Dist.CLIENT) +@ApiStatus.Internal +public class ClientTooltipComponentRegistryImpl { + @Nullable + private static List> FACTORIES = new ArrayList<>(); + + public static void consume(Consumer> consumer) { + if (FACTORIES != null) { + FACTORIES.forEach(consumer); + FACTORIES = null; + } + } + + public static void register(Class clazz, Function factory) { + if (FACTORIES == null) { + throw new IllegalStateException("Cannot register ClientTooltipComponent factory when factories are already aggregated!"); + } + FACTORIES.add(new Factory<>(clazz, factory)); + } + + public record Factory( + Class clazz, Function factory + ) { + } +} diff --git a/testmod-common/src/main/java/dev/architectury/test/TestMod.java b/testmod-common/src/main/java/dev/architectury/test/TestMod.java index 009bcf22..5829979b 100644 --- a/testmod-common/src/main/java/dev/architectury/test/TestMod.java +++ b/testmod-common/src/main/java/dev/architectury/test/TestMod.java @@ -20,6 +20,7 @@ package dev.architectury.test; import dev.architectury.event.events.client.ClientLifecycleEvent; +import dev.architectury.registry.client.gui.ClientTooltipComponentRegistry; import dev.architectury.registry.client.level.entity.EntityRendererRegistry; import dev.architectury.test.debug.ConsoleMessageSink; import dev.architectury.test.debug.MessageSink; @@ -33,6 +34,7 @@ import dev.architectury.test.networking.TestModNet; import dev.architectury.test.particle.TestParticles; import dev.architectury.test.registry.TestRegistries; import dev.architectury.test.registry.client.TestKeybinds; +import dev.architectury.test.registry.objects.ItemWithTooltip; import dev.architectury.test.tags.TestTags; import dev.architectury.test.trade.TestTrades; import dev.architectury.test.worldgen.TestWorldGeneration; @@ -72,6 +74,7 @@ public class TestMod { TestModNet.initializeClient(); EntityRendererRegistry.register(TestRegistries.TEST_ENTITY, CowRenderer::new); EntityRendererRegistry.register(TestRegistries.TEST_ENTITY_2, CowRenderer::new); + ClientTooltipComponentRegistry.register(ItemWithTooltip.MyTooltipComponent.class, ItemWithTooltip.MyClientTooltipComponent::new); } } } diff --git a/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java b/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java index 2aec687f..bd72bc84 100644 --- a/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java +++ b/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java @@ -35,6 +35,7 @@ import dev.architectury.test.TestMod; import dev.architectury.test.entity.TestEntity; import dev.architectury.test.recipes.TestRecipeSerializer; import dev.architectury.test.registry.objects.EquippableTickingItem; +import dev.architectury.test.registry.objects.ItemWithTooltip; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; @@ -135,6 +136,9 @@ public class TestRegistries { } }); + public static final RegistrySupplier TEST_TOOLTIP = ITEMS.register("test_tooltip", + () -> new ItemWithTooltip(new Item.Properties().arch$tab(TestRegistries.TEST_TAB))); + public static final RegistrySupplier TEST_BLOCK = BLOCKS.register("test_block", () -> new Block(BlockBehaviour.Properties.ofLegacyCopy(Blocks.STONE))); public static final RegistrySupplier COLLISION_BLOCK = BLOCKS.register("collision_block", () -> diff --git a/testmod-common/src/main/java/dev/architectury/test/registry/objects/ItemWithTooltip.java b/testmod-common/src/main/java/dev/architectury/test/registry/objects/ItemWithTooltip.java new file mode 100644 index 00000000..6183c92a --- /dev/null +++ b/testmod-common/src/main/java/dev/architectury/test/registry/objects/ItemWithTooltip.java @@ -0,0 +1,65 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021, 2022 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.test.registry.objects; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.world.inventory.tooltip.TooltipComponent; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +public class ItemWithTooltip extends Item { + public ItemWithTooltip(Properties properties) { + super(properties); + } + + @Override + public @NotNull Optional getTooltipImage(ItemStack itemStack) { + return Optional.of(new MyTooltipComponent(itemStack.getCount())); + } + + public record MyTooltipComponent(int count) implements TooltipComponent { + + } + + @Environment(EnvType.CLIENT) + public record MyClientTooltipComponent(MyTooltipComponent component) implements ClientTooltipComponent { + @Override + public int getHeight() { + return 100; + } + + @Override + public int getWidth(Font font) { + return 100; + } + + @Override + public void renderImage(Font font, int x, int y, GuiGraphics guiGraphics) { + guiGraphics.drawString(font, "Count: " + component.count, x + getWidth(font) / 2, y + (getHeight() - font.lineHeight) / 2, 0xFF00FF00); + } + } +}