From 92d5df7d14f8b29bc786542c6287e9441fa8576c Mon Sep 17 00:00:00 2001 From: deirn Date: Tue, 13 Feb 2024 17:49:23 +0700 Subject: [PATCH] add harvest plugin (#248) * harvestability * pass 2 * pass 3 * pass 4 * pass 5 (cherry picked from commit 1e6ff7263d92be242b4be3f697b7d0dce8d3246a) (cherry picked from commit f69de06aba4bdf85e709ceae0ef897db6c3137f1) --- build.gradle.kts | 7 +- buildSrc/src/main/kotlin/PlatformConfig.kt | 2 +- .../mobius/waila/fabric/FabricApiService.java | 17 ++ .../mcp/mobius/waila/fabric/FabricWaila.java | 2 + ....mobius.waila.api.__internal__.IApiService | 2 +- .../src/main/resources/waila_plugins.json | 6 + .../mobius/waila/forge/ForgeApiService.java | 17 ++ .../mcp/mobius/waila/forge/ForgeWaila.java | 6 + .../src/main/resources/waila_plugins.json | 6 + .../waila/plugin/forge/WailaPluginForge.java | 43 ++++ platform/quilt/build.gradle.kts | 1 + .../mobius/waila/quilt/QuiltApiService.java | 17 ++ ....mobius.waila.api.__internal__.IApiService | 2 +- .../quilt/src/main/resources/quilt.mod.json | 2 +- .../src/main/resources/waila_plugins.json | 6 + .../plugin/textile/WailaPluginTextile.java | 45 ++++ .../java/mcp/mobius/waila/api/IRegistrar.java | 13 ++ .../java/mcp/mobius/waila/api/IToolType.java | 78 +++++++ .../waila/api/__internal__/IApiService.java | 10 + .../api/__internal__/IHarvestService.java | 19 ++ src/main/java/mcp/mobius/waila/Waila.java | 5 + .../mcp/mobius/waila/service/ApiService.java | 29 ++- .../mcp/mobius/waila/mixed/IShearable.java | 8 + .../waila/mixin/ShearableBlocksMixin.java | 26 +++ .../plugin/harvest/WailaPluginHarvest.java | 21 ++ .../harvest/component/ToolComponent.java | 69 ++++++ .../harvest/config/HarvestDisplayMode.java | 7 + .../waila/plugin/harvest/config/Options.java | 16 ++ .../harvest/provider/HarvestProvider.java | 211 ++++++++++++++++++ .../harvest/service/HarvestService.java | 27 +++ .../waila/plugin/harvest/tool/ToolTier.java | 59 +++++ .../waila/plugin/harvest/tool/ToolType.java | 126 +++++++++++ ...ius.waila.api.__internal__.IHarvestService | 1 + .../resources/assets/waila/lang/en_us.json | 38 +++- .../assets/waila/textures/components.png | Bin 631 -> 704 bytes src/resources/resources/wthit.mixins.json | 3 +- 36 files changed, 933 insertions(+), 14 deletions(-) create mode 100644 platform/fabric/src/main/java/mcp/mobius/waila/fabric/FabricApiService.java create mode 100644 platform/quilt/src/main/java/mcp/mobius/waila/quilt/QuiltApiService.java create mode 100644 src/api/java/mcp/mobius/waila/api/IToolType.java create mode 100644 src/api/java/mcp/mobius/waila/api/__internal__/IHarvestService.java create mode 100644 src/mixin/java/mcp/mobius/waila/mixed/IShearable.java create mode 100644 src/mixin/java/mcp/mobius/waila/mixin/ShearableBlocksMixin.java create mode 100644 src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/WailaPluginHarvest.java create mode 100644 src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/component/ToolComponent.java create mode 100644 src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/config/HarvestDisplayMode.java create mode 100644 src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/config/Options.java create mode 100644 src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/provider/HarvestProvider.java create mode 100644 src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/service/HarvestService.java create mode 100644 src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/tool/ToolTier.java create mode 100644 src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/tool/ToolType.java create mode 100644 src/resources/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IHarvestService diff --git a/build.gradle.kts b/build.gradle.kts index 5c9d2d777..1cae35b65 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -106,16 +106,17 @@ sourceSets { val mixin by creating val pluginCore by creating val pluginExtra by creating + val pluginHarvest by creating val pluginVanilla by creating val pluginTest by creating - listOf(api, buildConst, mixin, pluginCore, pluginExtra, pluginVanilla, pluginTest).applyEach { + listOf(api, buildConst, mixin, pluginCore, pluginExtra, pluginHarvest, pluginVanilla, pluginTest).applyEach { compileClasspath += main.compileClasspath } - listOf(api, main, mixin, pluginCore, pluginExtra, pluginVanilla, pluginTest).applyEach { + listOf(api, main, mixin, pluginCore, pluginExtra, pluginHarvest, pluginVanilla, pluginTest).applyEach { compileClasspath += buildConst.output } - listOf(main, pluginCore, pluginExtra, pluginVanilla, pluginTest).applyEach { + listOf(main, pluginCore, pluginExtra, pluginHarvest, pluginVanilla, pluginTest).applyEach { compileClasspath += api.output + mixin.output } mixin.apply { diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index c2602ebac..ae4df3fd9 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -18,7 +18,7 @@ fun Project.setupPlatform() { } listOf(plugin, main).applyEach { - compileClasspath += api.output + compileClasspath += api.output + rootSourceSets["mixin"].output } main.apply { diff --git a/platform/fabric/src/main/java/mcp/mobius/waila/fabric/FabricApiService.java b/platform/fabric/src/main/java/mcp/mobius/waila/fabric/FabricApiService.java new file mode 100644 index 000000000..a292f5d52 --- /dev/null +++ b/platform/fabric/src/main/java/mcp/mobius/waila/fabric/FabricApiService.java @@ -0,0 +1,17 @@ +package mcp.mobius.waila.fabric; + +import mcp.mobius.waila.service.ApiService; +import net.fabricmc.fabric.api.mininglevel.v1.MiningLevelManager; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Tier; +import net.minecraft.world.level.block.Block; +import org.jetbrains.annotations.Nullable; + +public class FabricApiService extends ApiService { + + @Override + public @Nullable TagKey getTierTag(Tier tier) { + return tier.getLevel() == 0 ? null : MiningLevelManager.getBlockTag(tier.getLevel()); + } + +} diff --git a/platform/fabric/src/main/java/mcp/mobius/waila/fabric/FabricWaila.java b/platform/fabric/src/main/java/mcp/mobius/waila/fabric/FabricWaila.java index 4640bee07..9d7e148f0 100644 --- a/platform/fabric/src/main/java/mcp/mobius/waila/fabric/FabricWaila.java +++ b/platform/fabric/src/main/java/mcp/mobius/waila/fabric/FabricWaila.java @@ -8,6 +8,7 @@ import mcp.mobius.waila.util.ModInfo; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; @@ -26,6 +27,7 @@ public void onInitialize() { ServerLifecycleEvents.SERVER_STARTING.register(server -> PluginConfig.reload()); ServerLifecycleEvents.SERVER_STOPPED.register(server -> onServerStopped()); + CommonLifecycleEvents.TAGS_LOADED.register((registries, client) -> onTagReload()); ModInfo.register(new ModInfo(false, "c", "Common", "0")); diff --git a/platform/fabric/src/main/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IApiService b/platform/fabric/src/main/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IApiService index b26e09a4e..f440c9574 100644 --- a/platform/fabric/src/main/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IApiService +++ b/platform/fabric/src/main/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IApiService @@ -1 +1 @@ -mcp.mobius.waila.service.ApiService +mcp.mobius.waila.fabric.FabricApiService diff --git a/platform/fabric/src/main/resources/waila_plugins.json b/platform/fabric/src/main/resources/waila_plugins.json index 04d2f6493..043905e95 100644 --- a/platform/fabric/src/main/resources/waila_plugins.json +++ b/platform/fabric/src/main/resources/waila_plugins.json @@ -11,6 +11,12 @@ "required" : ["minecraft"] }, + "waila:harvest" : { + "initializer": "mcp.mobius.waila.plugin.harvest.WailaPluginHarvest", + "side" : "*", + "required" : [] + }, + "waila:extra" : { "initializer": "mcp.mobius.waila.plugin.extra.WailaPluginExtra", "side" : "*", diff --git a/platform/forge/src/main/java/mcp/mobius/waila/forge/ForgeApiService.java b/platform/forge/src/main/java/mcp/mobius/waila/forge/ForgeApiService.java index 258c272fe..744ab64c5 100644 --- a/platform/forge/src/main/java/mcp/mobius/waila/forge/ForgeApiService.java +++ b/platform/forge/src/main/java/mcp/mobius/waila/forge/ForgeApiService.java @@ -1,9 +1,16 @@ package mcp.mobius.waila.forge; +import java.util.List; + import mcp.mobius.waila.api.IModInfo; import mcp.mobius.waila.service.ApiService; import mcp.mobius.waila.util.ModInfo; +import net.minecraft.tags.TagKey; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Tier; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.common.TierSortingRegistry; +import org.jetbrains.annotations.Nullable; public class ForgeApiService extends ApiService { @@ -17,4 +24,14 @@ public String getDefaultEnergyUnit() { return "FE"; } + @Override + public @Nullable TagKey getTierTag(Tier tier) { + return tier.getTag(); + } + + @Override + public List getTiers() { + return TierSortingRegistry.getSortedTiers(); + } + } diff --git a/platform/forge/src/main/java/mcp/mobius/waila/forge/ForgeWaila.java b/platform/forge/src/main/java/mcp/mobius/waila/forge/ForgeWaila.java index eb7641052..e0c918b67 100644 --- a/platform/forge/src/main/java/mcp/mobius/waila/forge/ForgeWaila.java +++ b/platform/forge/src/main/java/mcp/mobius/waila/forge/ForgeWaila.java @@ -7,6 +7,7 @@ import mcp.mobius.waila.debug.DumpGenerator; import mcp.mobius.waila.network.Packets; import net.minecraftforge.event.RegisterCommandsEvent; +import net.minecraftforge.event.TagsUpdatedEvent; import net.minecraftforge.event.server.ServerStartingEvent; import net.minecraftforge.event.server.ServerStoppedEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -52,6 +53,11 @@ static void serverStopped(ServerStoppedEvent event) { onServerStopped(); } + @SubscribeEvent + static void tagReload(TagsUpdatedEvent event) { + onTagReload(); + } + @SubscribeEvent static void registerCommands(RegisterCommandsEvent event) { ServerCommand.register(event.getDispatcher()); diff --git a/platform/forge/src/main/resources/waila_plugins.json b/platform/forge/src/main/resources/waila_plugins.json index 01e1543b8..dda9a52a1 100644 --- a/platform/forge/src/main/resources/waila_plugins.json +++ b/platform/forge/src/main/resources/waila_plugins.json @@ -11,6 +11,12 @@ "required" : ["minecraft"] }, + "waila:harvest" : { + "initializer": "mcp.mobius.waila.plugin.harvest.WailaPluginHarvest", + "side" : "*", + "required" : [] + }, + "waila:extra" : { "initializer": "mcp.mobius.waila.plugin.extra.WailaPluginExtra", "side" : "*", diff --git a/platform/forge/src/plugin/java/mcp/mobius/waila/plugin/forge/WailaPluginForge.java b/platform/forge/src/plugin/java/mcp/mobius/waila/plugin/forge/WailaPluginForge.java index 82c210906..c4cf73aed 100644 --- a/platform/forge/src/plugin/java/mcp/mobius/waila/plugin/forge/WailaPluginForge.java +++ b/platform/forge/src/plugin/java/mcp/mobius/waila/plugin/forge/WailaPluginForge.java @@ -1,14 +1,21 @@ package mcp.mobius.waila.plugin.forge; import mcp.mobius.waila.api.IRegistrar; +import mcp.mobius.waila.api.IToolType; import mcp.mobius.waila.api.IWailaPlugin; import mcp.mobius.waila.api.data.FluidData; import mcp.mobius.waila.plugin.forge.fluid.ForgeFluidDescriptor; import mcp.mobius.waila.plugin.forge.provider.EnergyCapabilityProvider; import mcp.mobius.waila.plugin.forge.provider.FluidCapabilityProvider; import mcp.mobius.waila.plugin.forge.provider.ItemCapabilityProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.DoublePlantBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.material.Fluid; +import net.minecraftforge.common.IForgeShearable; +import net.minecraftforge.common.ToolActions; public class WailaPluginForge implements IWailaPlugin { @@ -18,6 +25,42 @@ public void register(IRegistrar registrar) { registrar.addBlockData(EnergyCapabilityProvider.INSTANCE, BlockEntity.class, 2000); registrar.addBlockData(ItemCapabilityProvider.INSTANCE, BlockEntity.class, 2000); registrar.addBlockData(FluidCapabilityProvider.INSTANCE, BlockEntity.class, 2000); + + registrar.addToolType(new ResourceLocation("pickaxe"), IToolType.builder() + .lowestTierItem(Items.WOODEN_PICKAXE) + .blockTag(BlockTags.MINEABLE_WITH_PICKAXE) + .itemPredicate(it -> it.canPerformAction(ToolActions.PICKAXE_DIG)) + .build()); + + registrar.addToolType(new ResourceLocation("shovel"), IToolType.builder() + .lowestTierItem(Items.WOODEN_SHOVEL) + .blockTag(BlockTags.MINEABLE_WITH_SHOVEL) + .itemPredicate(it -> it.canPerformAction(ToolActions.SHOVEL_DIG)) + .build()); + + registrar.addToolType(new ResourceLocation("axe"), IToolType.builder() + .lowestTierItem(Items.WOODEN_AXE) + .blockTag(BlockTags.MINEABLE_WITH_AXE) + .itemPredicate(it -> it.canPerformAction(ToolActions.AXE_DIG)) + .build()); + + registrar.addToolType(new ResourceLocation("hoe"), IToolType.builder() + .lowestTierItem(Items.WOODEN_HOE) + .blockTag(BlockTags.MINEABLE_WITH_HOE) + .itemPredicate(it -> it.canPerformAction(ToolActions.HOE_DIG)) + .build()); + + registrar.addToolType(new ResourceLocation("sword"), IToolType.builder() + .lowestTierItem(Items.WOODEN_SWORD) + .blockTag(new ResourceLocation("forge:mineable/sword")) + .itemPredicate(it -> it.canPerformAction(ToolActions.SWORD_DIG)) + .build()); + + registrar.addToolType(new ResourceLocation("shears"), IToolType.builder() + .lowestTierItem(Items.SHEARS) + .blockPredicate(it -> it.getBlock() instanceof IForgeShearable || it.getBlock() instanceof DoublePlantBlock) + .itemPredicate(it -> it.canPerformAction(ToolActions.SHEARS_DIG)) + .build()); } } diff --git a/platform/quilt/build.gradle.kts b/platform/quilt/build.gradle.kts index d81d51d45..d6a99776e 100644 --- a/platform/quilt/build.gradle.kts +++ b/platform/quilt/build.gradle.kts @@ -14,6 +14,7 @@ dependencies { modCompileRuntime("org.quiltmc:qsl:${rootProp["qsl"]}") modCompileRuntime("org.quiltmc.quilted-fabric-api:fabric-key-binding-api-v1:${rootProp["qfapi"]}") modCompileRuntime("org.quiltmc.quilted-fabric-api:fabric-rendering-v1:${rootProp["qfapi"]}") + modCompileRuntime("org.quiltmc.quilted-fabric-api:fabric-mining-level-api-v1:${rootProp["qfapi"]}") modCompileRuntime("com.terraformersmc:modmenu:${rootProp["modMenu"]}") diff --git a/platform/quilt/src/main/java/mcp/mobius/waila/quilt/QuiltApiService.java b/platform/quilt/src/main/java/mcp/mobius/waila/quilt/QuiltApiService.java new file mode 100644 index 000000000..0583d4927 --- /dev/null +++ b/platform/quilt/src/main/java/mcp/mobius/waila/quilt/QuiltApiService.java @@ -0,0 +1,17 @@ +package mcp.mobius.waila.quilt; + +import mcp.mobius.waila.service.ApiService; +import net.fabricmc.fabric.api.mininglevel.v1.MiningLevelManager; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Tier; +import net.minecraft.world.level.block.Block; +import org.jetbrains.annotations.Nullable; + +public class QuiltApiService extends ApiService { + + @Override + public @Nullable TagKey getTierTag(Tier tier) { + return tier.getLevel() == 0 ? null : MiningLevelManager.getBlockTag(tier.getLevel()); + } + +} diff --git a/platform/quilt/src/main/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IApiService b/platform/quilt/src/main/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IApiService index b26e09a4e..961aaf340 100644 --- a/platform/quilt/src/main/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IApiService +++ b/platform/quilt/src/main/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IApiService @@ -1 +1 @@ -mcp.mobius.waila.service.ApiService +mcp.mobius.waila.quilt.QuiltApiService diff --git a/platform/quilt/src/main/resources/quilt.mod.json b/platform/quilt/src/main/resources/quilt.mod.json index 51f474a29..0279bdc7c 100644 --- a/platform/quilt/src/main/resources/quilt.mod.json +++ b/platform/quilt/src/main/resources/quilt.mod.json @@ -49,7 +49,7 @@ }, { "id" : "badpackets", - "versions": ">=0.4.1" + "versions": ">=0.5.6" } ] }, diff --git a/platform/quilt/src/main/resources/waila_plugins.json b/platform/quilt/src/main/resources/waila_plugins.json index addfde8d6..c3b215b0c 100644 --- a/platform/quilt/src/main/resources/waila_plugins.json +++ b/platform/quilt/src/main/resources/waila_plugins.json @@ -11,6 +11,12 @@ "required" : ["minecraft"] }, + "waila:harvest" : { + "initializer": "mcp.mobius.waila.plugin.harvest.WailaPluginHarvest", + "side" : "*", + "required" : [] + }, + "waila:extra" : { "initializer": "mcp.mobius.waila.plugin.extra.WailaPluginExtra", "side" : "*", diff --git a/platform/textile/src/plugin/java/mcp/mobius/waila/plugin/textile/WailaPluginTextile.java b/platform/textile/src/plugin/java/mcp/mobius/waila/plugin/textile/WailaPluginTextile.java index f754e2819..da67c2f5b 100644 --- a/platform/textile/src/plugin/java/mcp/mobius/waila/plugin/textile/WailaPluginTextile.java +++ b/platform/textile/src/plugin/java/mcp/mobius/waila/plugin/textile/WailaPluginTextile.java @@ -1,12 +1,21 @@ package mcp.mobius.waila.plugin.textile; import mcp.mobius.waila.api.IRegistrar; +import mcp.mobius.waila.api.IToolType; import mcp.mobius.waila.api.IWailaPlugin; import mcp.mobius.waila.api.data.FluidData; +import mcp.mobius.waila.mixed.IShearable; import mcp.mobius.waila.plugin.textile.fluid.TextileFluidDescriptor; import mcp.mobius.waila.plugin.textile.provider.FluidStorageProvider; import mcp.mobius.waila.plugin.textile.provider.ItemStorageProvider; +import net.fabricmc.fabric.api.mininglevel.v1.FabricMineableTags; +import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.item.Items; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.DoublePlantBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.material.Fluid; @@ -18,6 +27,42 @@ public void register(IRegistrar registrar) { FluidData.describeCauldron(Block.class, TextileFluidDescriptor.INSTANCE); registrar.addBlockData(ItemStorageProvider.INSTANCE, BlockEntity.class, 2000); registrar.addBlockData(FluidStorageProvider.INSTANCE, BlockEntity.class, 2000); + + registrar.addToolType(new ResourceLocation("pickaxe"), IToolType.builder() + .lowestTierItem(Items.WOODEN_PICKAXE) + .blockTag(BlockTags.MINEABLE_WITH_PICKAXE) + .itemTag(ItemTags.PICKAXES) + .build()); + + registrar.addToolType(new ResourceLocation("shovel"), IToolType.builder() + .lowestTierItem(Items.WOODEN_SHOVEL) + .blockTag(BlockTags.MINEABLE_WITH_SHOVEL) + .itemTag(ItemTags.SHOVELS) + .build()); + + registrar.addToolType(new ResourceLocation("axe"), IToolType.builder() + .lowestTierItem(Items.WOODEN_AXE) + .blockTag(BlockTags.MINEABLE_WITH_AXE) + .itemTag(ItemTags.AXES) + .build()); + + registrar.addToolType(new ResourceLocation("hoe"), IToolType.builder() + .lowestTierItem(Items.WOODEN_HOE) + .blockTag(BlockTags.MINEABLE_WITH_HOE) + .itemTag(ItemTags.HOES) + .build()); + + registrar.addToolType(new ResourceLocation("sword"), IToolType.builder() + .lowestTierItem(Items.WOODEN_SWORD) + .blockTag(FabricMineableTags.SWORD_MINEABLE) + .itemTag(ItemTags.SWORDS) + .build()); + + registrar.addToolType(new ResourceLocation("shears"), IToolType.builder() + .lowestTierItem(Items.SHEARS) + .blockPredicate(it -> it.is(FabricMineableTags.SHEARS_MINEABLE) || it.getBlock() instanceof IShearable || it.getBlock() instanceof DoublePlantBlock) + .itemTag(ConventionalItemTags.SHEARS) + .build()); } } diff --git a/src/api/java/mcp/mobius/waila/api/IRegistrar.java b/src/api/java/mcp/mobius/waila/api/IRegistrar.java index 05b959347..0303ab367 100644 --- a/src/api/java/mcp/mobius/waila/api/IRegistrar.java +++ b/src/api/java/mcp/mobius/waila/api/IRegistrar.java @@ -3,6 +3,7 @@ import java.nio.file.Path; import mcp.mobius.waila.api.__internal__.ApiSide; +import mcp.mobius.waila.api.__internal__.IHarvestService; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; @@ -597,6 +598,18 @@ default void addRayCastVector(IRayCastVectorProvider provider) { addRayCastVector(provider, DEFAULT_PRIORITY); } + /** + * Registers a tool type, to be used for the harvestability tooltip. + * + * @param id the tool type id, also used as the translation key as {@code tooltip.waila.harvest.tool.[namespace].[path]} + * @param toolType the tool type + */ + @ApiSide.ClientOnly + @ApiStatus.Experimental + default void addToolType(ResourceLocation id, IToolType toolType) { + IHarvestService.INSTANCE.addToolType(id, toolType); + } + // ----------------------------------------------------------------------------------------------------------------------------------------------- // TODO: Remove diff --git a/src/api/java/mcp/mobius/waila/api/IToolType.java b/src/api/java/mcp/mobius/waila/api/IToolType.java new file mode 100644 index 000000000..7dea3aff4 --- /dev/null +++ b/src/api/java/mcp/mobius/waila/api/IToolType.java @@ -0,0 +1,78 @@ +package mcp.mobius.waila.api; + +import java.util.function.Predicate; + +import mcp.mobius.waila.api.__internal__.IHarvestService; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Tiers; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.NonExtendable +@ApiStatus.Experimental +public interface IToolType { + + static Builder0 builder() { + return IHarvestService.INSTANCE.createToolTypeBuilder(); + } + + interface Builder0 { + + /** + * The wooden stack, or any stack of the type that has its {@linkplain ItemStack#getDestroySpeed(BlockState) destroy speed} + * the same as or higher than {@linkplain Tiers#WOOD wood}. + */ + Builder1 lowestTierStack(ItemStack stack); + + /** + * The wooden item, or any item of the type that has its {@linkplain Item#getDestroySpeed(ItemStack, BlockState) destroy speed} + * the same as or higher than {@linkplain Tiers#WOOD wood} + */ + Builder1 lowestTierItem(ItemLike item); + + } + + interface Builder1 { + + /** + * The block state predicate, used to check if the current block can be mined by the tool. + */ + Builder2 blockPredicate(Predicate predicate); + + /** + * The block tag, used to check if the current block can be mined by the tool. + */ + Builder2 blockTag(TagKey tag); + + Builder2 blockTag(ResourceLocation tag); + + } + + interface Builder2 { + + /** + * The stack predicate, used to check if the current stack is valid for the tool type. + */ + Builder3 itemPredicate(Predicate predicate); + + /** + * The item tag, used to check if the current stack is valid for the tool type. + */ + Builder3 itemTag(TagKey tag); + + Builder3 itemTag(ResourceLocation tag); + + } + + interface Builder3 { + + IToolType build(); + + } + +} diff --git a/src/api/java/mcp/mobius/waila/api/__internal__/IApiService.java b/src/api/java/mcp/mobius/waila/api/__internal__/IApiService.java index b85cf277d..de929259c 100644 --- a/src/api/java/mcp/mobius/waila/api/__internal__/IApiService.java +++ b/src/api/java/mcp/mobius/waila/api/__internal__/IApiService.java @@ -2,6 +2,7 @@ import java.nio.file.Path; import java.util.Collection; +import java.util.List; import com.mojang.blaze3d.vertex.BufferBuilder; import mcp.mobius.waila.api.IBlacklistConfig; @@ -18,8 +19,12 @@ import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Tier; +import net.minecraft.world.level.block.Block; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; /** @hidden */ @@ -68,4 +73,9 @@ public interface IApiService { IInstanceRegistry createInstanceRegistry(boolean reversed); + @Nullable + TagKey getTierTag(Tier tier); + + List getTiers(); + } diff --git a/src/api/java/mcp/mobius/waila/api/__internal__/IHarvestService.java b/src/api/java/mcp/mobius/waila/api/__internal__/IHarvestService.java new file mode 100644 index 000000000..5c9844b65 --- /dev/null +++ b/src/api/java/mcp/mobius/waila/api/__internal__/IHarvestService.java @@ -0,0 +1,19 @@ +package mcp.mobius.waila.api.__internal__; + +import mcp.mobius.waila.api.IToolType; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; + +/** @hidden */ +@ApiStatus.Internal +public interface IHarvestService { + + IHarvestService INSTANCE = Internals.loadService(IHarvestService.class); + + void addToolType(ResourceLocation id, IToolType toolType); + + IToolType.Builder0 createToolTypeBuilder(); + + void resetCache(); + +} diff --git a/src/main/java/mcp/mobius/waila/Waila.java b/src/main/java/mcp/mobius/waila/Waila.java index 8c4efc1d6..aed9e7ef0 100644 --- a/src/main/java/mcp/mobius/waila/Waila.java +++ b/src/main/java/mcp/mobius/waila/Waila.java @@ -6,6 +6,7 @@ import mcp.mobius.waila.api.IJsonConfig; import mcp.mobius.waila.api.IPluginInfo; import mcp.mobius.waila.api.WailaConstants; +import mcp.mobius.waila.api.__internal__.IHarvestService; import mcp.mobius.waila.config.BlacklistConfig; import mcp.mobius.waila.config.WailaConfig; import mcp.mobius.waila.gui.hud.theme.ThemeDefinition; @@ -57,6 +58,10 @@ protected static void onServerStopped() { RegistryFilter.attach(null); } + protected static void onTagReload() { + IHarvestService.INSTANCE.resetCache(); + } + protected static void unsupportedPlatform(String platformName, String loaderName, String clazz) { try { Class.forName(clazz); diff --git a/src/main/java/mcp/mobius/waila/service/ApiService.java b/src/main/java/mcp/mobius/waila/service/ApiService.java index 5dc09bff9..809e1ed36 100644 --- a/src/main/java/mcp/mobius/waila/service/ApiService.java +++ b/src/main/java/mcp/mobius/waila/service/ApiService.java @@ -2,7 +2,13 @@ import java.nio.file.Path; import java.util.Collection; +import java.util.Comparator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.function.Supplier; +import com.google.common.base.Suppliers; +import com.google.common.collect.Streams; import com.mojang.blaze3d.vertex.BufferBuilder; import mcp.mobius.waila.Waila; import mcp.mobius.waila.api.IBlacklistConfig; @@ -34,11 +40,14 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.PotionItem; import net.minecraft.world.item.SpawnEggItem; +import net.minecraft.world.item.Tier; +import net.minecraft.world.item.TieredItem; +import net.minecraft.world.item.Tiers; import net.minecraft.world.item.TippedArrowItem; import net.minecraft.world.item.alchemy.PotionUtils; import org.joml.Matrix4f; -public class ApiService implements IApiService { +public abstract class ApiService implements IApiService { @Override public IModInfo getModInfo(ItemStack stack) { @@ -164,4 +173,22 @@ public IInstanceRegistry createInstanceRegistry(boolean reversed) { return registry; } + public static final Supplier> TIERS = Suppliers.memoize(() -> { + var vanilla = List.of(Tiers.values()); + var custom = new LinkedHashSet(); + + for (var item : BuiltInRegistries.ITEM) { + if (item instanceof TieredItem tiered && !(tiered.getTier() instanceof Tiers)) { + custom.add(tiered.getTier()); + } + } + + return Streams.concat(vanilla.stream(), custom.stream()).sorted(Comparator.comparingInt(Tier::getLevel)).toList(); + }); + + @Override + public List getTiers() { + return TIERS.get(); + } + } diff --git a/src/mixin/java/mcp/mobius/waila/mixed/IShearable.java b/src/mixin/java/mcp/mobius/waila/mixed/IShearable.java new file mode 100644 index 000000000..abf5144a1 --- /dev/null +++ b/src/mixin/java/mcp/mobius/waila/mixed/IShearable.java @@ -0,0 +1,8 @@ +package mcp.mobius.waila.mixed; + +/** + * A copy of Forge IForgeShearable interface, as Fabric doesn't have anything similar. + */ +public interface IShearable { + +} diff --git a/src/mixin/java/mcp/mobius/waila/mixin/ShearableBlocksMixin.java b/src/mixin/java/mcp/mobius/waila/mixin/ShearableBlocksMixin.java new file mode 100644 index 000000000..724ec7878 --- /dev/null +++ b/src/mixin/java/mcp/mobius/waila/mixin/ShearableBlocksMixin.java @@ -0,0 +1,26 @@ +package mcp.mobius.waila.mixin; + +import mcp.mobius.waila.mixed.IShearable; +import net.minecraft.world.level.block.CherryLeavesBlock; +import net.minecraft.world.level.block.DeadBushBlock; +import net.minecraft.world.level.block.LeavesBlock; +import net.minecraft.world.level.block.MangroveLeavesBlock; +import net.minecraft.world.level.block.SeagrassBlock; +import net.minecraft.world.level.block.TallGrassBlock; +import net.minecraft.world.level.block.VineBlock; +import net.minecraft.world.level.block.WebBlock; +import org.spongepowered.asm.mixin.Mixin; + + +@Mixin({ + CherryLeavesBlock.class, + DeadBushBlock.class, + LeavesBlock.class, + MangroveLeavesBlock.class, + SeagrassBlock.class, + TallGrassBlock.class, + VineBlock.class, + WebBlock.class}) +public class ShearableBlocksMixin implements IShearable { + +} diff --git a/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/WailaPluginHarvest.java b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/WailaPluginHarvest.java new file mode 100644 index 000000000..3d3254ff6 --- /dev/null +++ b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/WailaPluginHarvest.java @@ -0,0 +1,21 @@ +package mcp.mobius.waila.plugin.harvest; + +import mcp.mobius.waila.api.IRegistrar; +import mcp.mobius.waila.api.IWailaPlugin; +import mcp.mobius.waila.api.TooltipPosition; +import mcp.mobius.waila.plugin.harvest.config.HarvestDisplayMode; +import mcp.mobius.waila.plugin.harvest.config.Options; +import mcp.mobius.waila.plugin.harvest.provider.HarvestProvider; +import net.minecraft.world.level.block.Block; + +public class WailaPluginHarvest implements IWailaPlugin { + + @Override + public void register(IRegistrar registrar) { + registrar.addFeatureConfig(Options.ENABLED, true); + registrar.addConfig(Options.DISPLAY_MODE, HarvestDisplayMode.MODERN); + registrar.addComponent(HarvestProvider.INSTANCE, TooltipPosition.BODY, Block.class); + registrar.addEventListener(HarvestProvider.INSTANCE, 3000); + } + +} diff --git a/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/component/ToolComponent.java b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/component/ToolComponent.java new file mode 100644 index 000000000..ba92ee199 --- /dev/null +++ b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/component/ToolComponent.java @@ -0,0 +1,69 @@ +package mcp.mobius.waila.plugin.harvest.component; + +import mcp.mobius.waila.api.ITooltipComponent; +import mcp.mobius.waila.api.WailaConstants; +import mcp.mobius.waila.api.__internal__.ApiSide; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +@ApiSide.ClientOnly +public class ToolComponent implements ITooltipComponent { + + private final @Nullable ItemStack icon; + + private final int v0; + private final int width; + private final int xo; + + private int x; + + public ToolComponent(@Nullable ItemStack icon, @Nullable Boolean matches) { + this.icon = icon; + + if (matches != null) v0 = matches ? 7 : 0; + else v0 = -1; + + if (icon == null) { + width = 6; + xo = 0; + } else { + width = 9; + xo = 3; + } + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return 9; + } + + @Override + public void render(GuiGraphics ctx, int x, int y, float delta) { + this.x = x; + } + + public void actuallyRender(GuiGraphics ctx, int y) { + if (icon != null) { + ctx.pose().pushPose(); + ctx.pose().translate(-2, -2, 0); + ctx.pose().scale(0.85f, 0.85f, 1f); + ctx.pose().translate(x / 0.85f, y / 0.85f, 0); + ctx.renderItem(icon, 0, 0); + ctx.pose().popPose(); + } + + if (v0 == -1) return; + ctx.pose().pushPose(); + ctx.pose().translate(0, 0, ItemRenderer.ITEM_COUNT_BLIT_OFFSET); + ctx.blit(WailaConstants.COMPONENT_TEXTURE, x + xo, y + 3, 122, v0, 7, 7); + ctx.pose().popPose(); + } + +} diff --git a/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/config/HarvestDisplayMode.java b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/config/HarvestDisplayMode.java new file mode 100644 index 000000000..66ea2fbd1 --- /dev/null +++ b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/config/HarvestDisplayMode.java @@ -0,0 +1,7 @@ +package mcp.mobius.waila.plugin.harvest.config; + +public enum HarvestDisplayMode { + MODERN, + CLASSIC, + CLASSIC_MINIMAL +} diff --git a/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/config/Options.java b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/config/Options.java new file mode 100644 index 000000000..ee75518f2 --- /dev/null +++ b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/config/Options.java @@ -0,0 +1,16 @@ +package mcp.mobius.waila.plugin.harvest.config; + +import net.minecraft.resources.ResourceLocation; + +public class Options { + + // @formatter:off + public static final ResourceLocation ENABLED = rl("enabled"); + public static final ResourceLocation DISPLAY_MODE = rl("display_mode"); + // @formatter:on + + public static ResourceLocation rl(String path) { + return new ResourceLocation("harvest", path); + } + +} diff --git a/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/provider/HarvestProvider.java b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/provider/HarvestProvider.java new file mode 100644 index 000000000..d8a9a500b --- /dev/null +++ b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/provider/HarvestProvider.java @@ -0,0 +1,211 @@ +package mcp.mobius.waila.plugin.harvest.provider; + +import java.awt.Rectangle; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; +import mcp.mobius.waila.api.IBlockAccessor; +import mcp.mobius.waila.api.IBlockComponentProvider; +import mcp.mobius.waila.api.ICommonAccessor; +import mcp.mobius.waila.api.IEventListener; +import mcp.mobius.waila.api.IPluginConfig; +import mcp.mobius.waila.api.ITooltip; +import mcp.mobius.waila.api.component.GrowingComponent; +import mcp.mobius.waila.api.component.PairComponent; +import mcp.mobius.waila.buildconst.Tl; +import mcp.mobius.waila.plugin.harvest.component.ToolComponent; +import mcp.mobius.waila.plugin.harvest.config.HarvestDisplayMode; +import mcp.mobius.waila.plugin.harvest.config.Options; +import mcp.mobius.waila.plugin.harvest.tool.ToolTier; +import mcp.mobius.waila.plugin.harvest.tool.ToolType; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TieredItem; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; + +public enum HarvestProvider implements IBlockComponentProvider, IEventListener { + + INSTANCE; + + private static final ToolType UNBREAKABLE = new ToolType(); + + public final Map> toolsCache = new Reference2ObjectOpenHashMap<>(); + public final Map tierCache = new Reference2ObjectOpenHashMap<>(); + + private int updateId = 0; + private BlockState state; + + private final List toolComponents = new ArrayList<>(); + private boolean renderComponents = false; + + @Override + public void appendBody(ITooltip tooltip, IBlockAccessor accessor, IPluginConfig config) { + if (!config.getBoolean(Options.ENABLED)) return; + + updateId = accessor.getUpdateId(); + state = accessor.getBlockState(); + + var unbreakable = state.getDestroySpeed(accessor.getWorld(), accessor.getPosition()) < 0; + + var tools = toolsCache.get(state); + if (tools == null) { + tools = new ArrayList<>(); + + if (unbreakable) { + tools.add(UNBREAKABLE); + } else { + for (var tool : ToolType.all()) { + if (tool.blockPredicate.test(state)) { + tools.add(tool); + } + } + if (tools.isEmpty()) tools = List.of(); + } + toolsCache.put(state, tools); + } + + var highestTier = tierCache.get(state); + if (highestTier == null) { + highestTier = ToolTier.NONE; + for (var tier : ToolTier.all()) { + if (tier.tag != null && state.is(tier.tag)) { + highestTier = tier; + } + } + tierCache.put(state, highestTier); + } + + HarvestDisplayMode displayMode = config.getEnum(Options.DISPLAY_MODE); + if (displayMode == HarvestDisplayMode.MODERN) return; + + var heldStack = accessor.getPlayer().getInventory().getSelected(); + + if (displayMode == HarvestDisplayMode.CLASSIC) { + tooltip.addLine(Component.empty() + .append(getHarvestableSymbol(accessor, unbreakable)) + .append(" ") + .append(Component.translatable(Tl.Tooltip.Harvest.HARVESTABLE))); + + if (!tools.isEmpty() && !unbreakable) tooltip.addLine(new PairComponent( + Component.translatable(Tl.Tooltip.Harvest.EFFECTIVE_TOOL), + getToolText(tools, heldStack))); + + if (highestTier != ToolTier.NONE) tooltip.addLine(new PairComponent( + Component.translatable(Tl.Tooltip.Harvest.LEVEL), + getTierText(highestTier, heldStack))); + } else if (displayMode == HarvestDisplayMode.CLASSIC_MINIMAL) { + var text = Component.empty(); + text.append(getHarvestableSymbol(accessor, unbreakable)); + + if (!tools.isEmpty() && !unbreakable) { + text.append(" | ").append(getToolText(tools, heldStack)); + if (highestTier != ToolTier.NONE) { + text.append(" | "); + } + } + + if (highestTier != ToolTier.NONE) { + text.append(getTierText(highestTier, heldStack)); + } + + tooltip.addLine(text); + } + } + + @Override + public void onHandleTooltip(ITooltip tooltip, ICommonAccessor accessor, IPluginConfig config) { + renderComponents = false; + + if (!config.getBoolean(Options.ENABLED)) return; + + HarvestDisplayMode displayMode = config.getEnum(Options.DISPLAY_MODE); + if (displayMode != HarvestDisplayMode.MODERN) return; + + if (updateId != accessor.getUpdateId()) return; + + var tools = toolsCache.get(state); + var highestTier = tierCache.get(state); + if (tools == null || highestTier == null || tools.isEmpty()) return; + + var heldStack = accessor.getPlayer().getInventory().getSelected(); + + var line = tooltip.getLine(tooltip.getLineCount() - 1); + line.with(GrowingComponent.INSTANCE); + + toolComponents.clear(); + for (var tool : tools) { + ToolComponent component; + if (tool == UNBREAKABLE) { + component = new ToolComponent(null, false); + } else { + var icon = tool.getIcon(highestTier); + Boolean matches = null; + if (state.requiresCorrectToolForDrops()) { + matches = tool.itemPredicate.test(heldStack); + if (highestTier != ToolTier.NONE && heldStack.getItem() instanceof TieredItem tiered) { + var heldTier = ToolTier.get(tiered.getTier()); + matches = matches && heldTier.index >= highestTier.index; + } + } + component = new ToolComponent(icon, matches); + } + line.with(component); + toolComponents.add(component); + } + + renderComponents = true; + } + + @Override + public void onAfterTooltipRender(GuiGraphics ctx, Rectangle rect, ICommonAccessor accessor, IPluginConfig config) { + if (!renderComponents) return; + + for (var component : toolComponents) { + component.actuallyRender(ctx, rect.y + rect.height - 13); + } + } + + @NotNull + @SuppressWarnings("UnnecessaryUnicodeEscape") + private MutableComponent getHarvestableSymbol(IBlockAccessor accessor, boolean unbreakable) { + return unbreakable || !accessor.getPlayer().hasCorrectToolForDrops(state) + ? Component.literal("\u2718").withStyle(ChatFormatting.RED) + : Component.literal("\u2714").withStyle(ChatFormatting.GREEN); + } + + @NotNull + private static MutableComponent getToolText(List tools, ItemStack heldStack) { + var toolText = Component.empty(); + var toolIter = tools.iterator(); + while (toolIter.hasNext()) { + var tool = toolIter.next(); + if (tool == UNBREAKABLE) continue; + + toolText.append(tool.text.copy().withStyle(tool.itemPredicate.test(heldStack) ? ChatFormatting.GREEN : ChatFormatting.RED)); + if (toolIter.hasNext()) toolText.append(", "); + } + return toolText; + } + + @NotNull + private static MutableComponent getTierText(ToolTier highestTier, ItemStack heldStack) { + var tierText = I18n.exists(highestTier.tlKey) + ? Component.translatable(highestTier.tlKey) + : Component.literal(String.valueOf(highestTier.index)); + if (heldStack.getItem() instanceof TieredItem tiered) { + var heldTier = ToolTier.get(tiered.getTier()); + tierText.withStyle(heldTier.index >= highestTier.index ? ChatFormatting.GREEN : ChatFormatting.RED); + } else { + tierText.withStyle(ChatFormatting.RED); + } + return tierText; + } + +} diff --git a/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/service/HarvestService.java b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/service/HarvestService.java new file mode 100644 index 000000000..119e71ab7 --- /dev/null +++ b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/service/HarvestService.java @@ -0,0 +1,27 @@ +package mcp.mobius.waila.plugin.harvest.service; + +import mcp.mobius.waila.api.IToolType; +import mcp.mobius.waila.api.__internal__.IHarvestService; +import mcp.mobius.waila.plugin.harvest.provider.HarvestProvider; +import mcp.mobius.waila.plugin.harvest.tool.ToolType; +import net.minecraft.resources.ResourceLocation; + +public class HarvestService implements IHarvestService { + + @Override + public void addToolType(ResourceLocation id, IToolType toolType) { + ((ToolType) toolType).bind(id); + } + + @Override + public IToolType.Builder0 createToolTypeBuilder() { + return new ToolType(); + } + + @Override + public void resetCache() { + HarvestProvider.INSTANCE.toolsCache.clear(); + HarvestProvider.INSTANCE.tierCache.clear(); + } + +} diff --git a/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/tool/ToolTier.java b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/tool/ToolTier.java new file mode 100644 index 000000000..f4f7d597d --- /dev/null +++ b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/tool/ToolTier.java @@ -0,0 +1,59 @@ +package mcp.mobius.waila.plugin.harvest.tool; + +import java.util.Collection; +import java.util.Locale; +import java.util.Map; +import java.util.function.Supplier; + +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableMap; +import mcp.mobius.waila.api.__internal__.IApiService; +import mcp.mobius.waila.api.__internal__.Internals; +import mcp.mobius.waila.buildconst.Tl; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Tier; +import net.minecraft.world.item.Tiers; +import net.minecraft.world.level.block.Block; +import org.jetbrains.annotations.Nullable; + +public final class ToolTier { + + public static final ToolTier NONE = Internals.unsafeAlloc(ToolTier.class); + + private static final Supplier> TIERS = Suppliers.memoize(() -> { + var builder = ImmutableMap.builder(); + var tiers = IApiService.INSTANCE.getTiers(); + for (var i = 0; i < tiers.size(); i++) { + var tier = tiers.get(i); + builder.put(tier, new ToolTier(tier, i)); + } + return builder.build(); + }); + + public final Tier tier; + public final int index; + public final @Nullable TagKey tag; + public final String tlKey; + + public ToolTier(Tier tier, int index) { + this.tier = tier; + this.index = index; + this.tag = IApiService.INSTANCE.getTierTag(tier); + + if (tier instanceof Tiers vanilla) + this.tlKey = Tl.Tooltip.Harvest.TIER + "." + vanilla.name().toLowerCase(Locale.ROOT); + else if (tag != null) + this.tlKey = Tl.Tooltip.Harvest.TIER + "." + tag.location().toLanguageKey(); + else + this.tlKey = Tl.Tooltip.Harvest.TIER + "." + tier.getLevel(); + } + + public static Collection all() { + return TIERS.get().values(); + } + + public static ToolTier get(Tier tier) { + return TIERS.get().get(tier); + } + +} diff --git a/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/tool/ToolType.java b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/tool/ToolType.java new file mode 100644 index 000000000..6465555e3 --- /dev/null +++ b/src/pluginHarvest/java/mcp/mobius/waila/plugin/harvest/tool/ToolType.java @@ -0,0 +1,126 @@ +package mcp.mobius.waila.plugin.harvest.tool; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import com.google.common.base.Suppliers; +import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; +import mcp.mobius.waila.api.IToolType; +import mcp.mobius.waila.buildconst.Tl; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TieredItem; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +public class ToolType implements IToolType, IToolType.Builder0, IToolType.Builder1, IToolType.Builder2, IToolType.Builder3 { + + private static final Map MAP = new LinkedHashMap<>(); + + public ResourceLocation id; + public ItemStack lowestTierStack; + public Predicate blockPredicate; + public Predicate itemPredicate; + public Component text; + + private final Supplier> icons = Suppliers.memoize(() -> { + var tiers = ToolTier.all(); + var map = new Reference2ObjectOpenHashMap(); + + for (var item : BuiltInRegistries.ITEM) { + var stack = item.getDefaultInstance(); + if (itemPredicate.test(stack)) { + for (var tier : tiers) { + if (!map.containsKey(tier) && item instanceof TieredItem tiered && tiered.getTier() == tier.tier) { + map.put(tier, stack); + } + } + } + } + + if (map.size() < tiers.size()) { + for (var tier : tiers) { + map.putIfAbsent(tier, lowestTierStack); + } + } + + return map; + }); + + public ItemStack getIcon(ToolTier tier) { + if (tier == ToolTier.NONE) return lowestTierStack; + else return icons.get().get(tier); + } + + public void bind(ResourceLocation id) { + this.id = id; + this.text = Component.translatable(Tl.Tooltip.Harvest.TOOL + "." + id.toLanguageKey()); + + MAP.put(id, this); + } + + public static Collection all() { + return MAP.values(); + } + + @Override + public Builder1 lowestTierStack(ItemStack stack) { + lowestTierStack = stack; + return this; + } + + @Override + public Builder1 lowestTierItem(ItemLike item) { + lowestTierStack = new ItemStack(item); + return this; + } + + @Override + public Builder2 blockPredicate(Predicate predicate) { + blockPredicate = predicate; + return this; + } + + @Override + public Builder2 blockTag(TagKey tag) { + blockPredicate = state -> state.is(tag); + return this; + } + + @Override + public Builder2 blockTag(ResourceLocation tag) { + return blockTag(TagKey.create(Registries.BLOCK, tag)); + } + + @Override + public Builder3 itemPredicate(Predicate predicate) { + itemPredicate = predicate; + return this; + } + + @Override + public Builder3 itemTag(TagKey tag) { + itemPredicate = stack -> stack.is(tag); + return this; + } + + @Override + public Builder3 itemTag(ResourceLocation tag) { + return itemTag(TagKey.create(Registries.ITEM, tag)); + } + + @Override + public IToolType build() { + return this; + } + +} diff --git a/src/resources/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IHarvestService b/src/resources/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IHarvestService new file mode 100644 index 000000000..d5bed02d8 --- /dev/null +++ b/src/resources/resources/META-INF/services/mcp.mobius.waila.api.__internal__.IHarvestService @@ -0,0 +1 @@ +mcp.mobius.waila.plugin.harvest.service.HarvestService diff --git a/src/resources/resources/assets/waila/lang/en_us.json b/src/resources/resources/assets/waila/lang/en_us.json index 44a59c10c..e090ea687 100644 --- a/src/resources/resources/assets/waila/lang/en_us.json +++ b/src/resources/resources/assets/waila/lang/en_us.json @@ -29,6 +29,8 @@ "tooltip.waila.panda.personality" : "Personality", "tooltip.waila.panda.traits" : "Traits", + + "tooltip.waila.panda.gene" : "_DO_NOT_TRANSLATE_", "tooltip.waila.panda.gene.normal" : "Normal", "tooltip.waila.panda.gene.lazy" : "Lazy", "tooltip.waila.panda.gene.worried" : "Worried", @@ -37,6 +39,7 @@ "tooltip.waila.panda.gene.weak" : "Weak", "tooltip.waila.panda.gene.aggressive" : "Aggressive", + "tooltip.waila.instrument" : "_DO_NOT_TRANSLATE_", "tooltip.waila.instrument.harp" : "Harp", "tooltip.waila.instrument.basedrum" : "Bass Drum", "tooltip.waila.instrument.snare" : "Snare Drum", @@ -64,6 +67,26 @@ "tooltip.waila.extra.energy" : "Energy", "tooltip.waila.extra.unknown_fluid" : "Unknown Fluid", + "tooltip.waila.harvest.harvestable" : "Currently Harvestable", + "tooltip.waila.harvest.effective_tool" : "Effective Tool", + "tooltip.waila.harvest.level" : "Harvest Level", + + "tooltip.waila.harvest.tool" : "_DO_NOT_TRANSLATE_", + "tooltip.waila.harvest.tool.minecraft.pickaxe" : "Pickaxe", + "tooltip.waila.harvest.tool.minecraft.shovel" : "Shovel", + "tooltip.waila.harvest.tool.minecraft.axe" : "Axe", + "tooltip.waila.harvest.tool.minecraft.hoe" : "Hoe", + "tooltip.waila.harvest.tool.minecraft.sword" : "Sword", + "tooltip.waila.harvest.tool.minecraft.shears" : "Shears", + + "tooltip.waila.harvest.tier" : "_DO_NOT_TRANSLATE_", + "tooltip.waila.harvest.tier.wood" : "Wood", + "tooltip.waila.harvest.tier.stone" : "Stone", + "tooltip.waila.harvest.tier.iron" : "Iron", + "tooltip.waila.harvest.tier.gold" : "Gold", + "tooltip.waila.harvest.tier.diamond" : "Diamond", + "tooltip.waila.harvest.tier.netherite" : "Netherite", + "gui.waila.configuration" : "%s Configuration", "gui.waila.waila_settings" : "%s Settings", "gui.waila.plugin_settings" : "Plugin Settings", @@ -193,6 +216,8 @@ "key.waila.show_recipe_input" : "Show Recipe Usage", "key.waila.show_recipe_output" : "Show Recipe", + "config.waila.plugin_" : "_DO_NOT_TRANSLATE_", + "config.waila.plugin_minecraft" : "Minecraft", "config.waila.plugin_minecraft.item_entity" : "Show Item Entity", "config.waila.plugin_minecraft.breaking_progress" : "Breaking Progress", @@ -280,6 +305,13 @@ "config.waila.plugin_waila.icon_position_middle" : "Middle", "config.waila.plugin_waila.icon_position_bottom" : "Bottom", + "config.waila.plugin_harvest" : "Harvest", + "config.waila.plugin_harvest.enabled" : "Show Harvestability", + "config.waila.plugin_harvest.display_mode" : "Display Mode", + "config.waila.plugin_harvest.display_mode_modern" : "Modern", + "config.waila.plugin_harvest.display_mode_classic" : "Classic", + "config.waila.plugin_harvest.display_mode_classic_minimal" : "Classic Minimal", + "config.waila.plugin_wailax" : "Waila Extra", "config.waila.plugin_wailax.energy" : "Energy", "config.waila.plugin_wailax.energy.enabled_block" : "Show Block Energy", @@ -326,9 +358,5 @@ "theme.waila.plugin_waila.nine_patch.regionRight" : "Region: Right", "theme.waila.plugin_waila.nine_patch.mode" : "Draw Mode", "theme.waila.plugin_waila.nine_patch.mode_stretch" : "Stretch", - "theme.waila.plugin_waila.nine_patch.mode_tile" : "Tile", - - "tooltip.waila.instrument" : "_DO_NOT_TRANSLATE_", - "tooltip.waila.panda.gene" : "_DO_NOT_TRANSLATE_", - "config.waila.plugin_" : "_DO_NOT_TRANSLATE_" + "theme.waila.plugin_waila.nine_patch.mode_tile" : "Tile" } diff --git a/src/resources/resources/assets/waila/textures/components.png b/src/resources/resources/assets/waila/textures/components.png index 5cc130ce1c0fc36111864441bf472483f7f86540..1f94b268243b0f6eff5989e9f5cc2ffd6c6eda69 100644 GIT binary patch delta 447 zcmV;w0YLuu1i%H5F@JhVL_t(|obB7ejp9HM1<>jhnGgVHGQt561pz=hT-IkIsyXaf zJ3AQ7%H0TBe(z!lgoR}N?{eENu~24aDWyF6e!t)6(tXq3?{SP0ad*5jBIiD59X2&T z{;33Rw_DBbX=JzCMTsci!!G>%s@*|mI@5PzDuD>$=a1?Fh<{K5J(-&XSg$4p5TOKm zF@=Ac1X#Cb1rVVG-rd(TzY-uKV$(XbKP?RM8gpa6%K@5B027nI`*{@d;z+I9Qwm@h zhG*;+Xl%1ItmpH2_VZyF;&QnZ4+3={BcmAq*KF~@pBwY1@JDzO@ZF5#SndL^09Y!& zIUEiG--G;I`F~G$0I2Xk;m^#xUax8U+U>swMFH?v^&;Tcv7Zi=4F9Iq7=vR|Rft3LCsoA>#N&xz^coqLq z;E%_nI|I;(@{BXL5`aED<#k|}1JH-36o3f;`d|$JRvWD81R(s-mu3YZ{Lr5!1t9#; pr|JR_epn&5`jdeH-xvTo@d5l47jUVOFS`H$002ovPDHLkV1l$D(BuFB delta 377 zcmV-<0fzp-1@{DyF@G^hL_t(|obB7ejlwVx1yFlMCltV$jz|GiK>^SXC(cylJt3`D zAXfHd$tdq#B7v|Xh54~3PA#2UYpvE=Uwyyd?_2NK#Jk;YFRvBrwHf*GyAZhF?<2z# zWVhRW`V?5Guh9WoYwq-r)NlZlA_O3-kN_w}2tY<*0Z@t%fPZW@(M9{NF$gS2=nUY& zOaOA2B><*rnqycX*rvBw&*$^g&!=fBm&>Kv2n5U5y;grV&3_bsDRu%bjh%pmYQG!~ z2L%sn@t5Lnt+ng*+8jT7{O|t;c?>rJe@^>>T!sQb@k4Ii0igIHzwQ9oZnu%=0eryF z65wF(mcD){5^=*a*iQRldG3jxSsme+wT z2Ox)80>BIaa?k^S6$_mKD1OK#EC3Wg