diff --git a/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java b/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java index c5cbc2311..55bda23df 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java @@ -13,6 +13,9 @@ import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; import net.minecraft.world.item.EnchantedBookItem; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.LingeringPotionItem; +import net.minecraft.world.item.TippedArrowItem; +import net.minecraft.world.item.alchemy.PotionUtils; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.block.Block; @@ -72,6 +75,9 @@ public class ItemDetails { var enchants = getAllEnchants(stack, hideFlags); if (!enchants.isEmpty()) data.put("enchantments", enchants); + var effects = getAllEffects(stack); + if (!effects.isEmpty()) data.put("potionEffects", effects); + if (tag != null && tag.getBoolean("Unbreakable") && (hideFlags & 4) == 0) { data.put("unbreakable", true); } @@ -137,4 +143,41 @@ public class ItemDetails { enchants.add(enchant); } } + + /** + * Retrieve all potions from given stack. + * + * @param stack Stack to analyse. + * @return A filled list that contain all visible potions. + */ + private static List> getAllEffects(ItemStack stack) { + return PotionUtils.getMobEffects(stack).stream().map(p -> { + Map potion = new HashMap<>(4); + potion.put("name", DetailHelpers.getId(RegistryWrappers.MOB_EFFECTS, p.getEffect())); + potion.put("displayName", Component.translatable(p.getDescriptionId()).getString()); + + // Expose the roman numerals (e.g. Instant Health II), rather than the raw amplifier value. + if (p.getAmplifier() > 0) potion.put("potency", p.getAmplifier() + 1); + + if (p.isInfiniteDuration()) { + potion.put("duration", Double.POSITIVE_INFINITY); + } else if (p.getDuration() > 1) { + potion.put("duration", p.getDuration() / 20.0 * getPotionDurationMultiplier(stack)); + } + return potion; + }).toList(); + } + + /** + * Get the potion duration multiplier for an item, to handle items which have a shorter duration than a normal + * potion. + * + * @param stack The current stack. + * @return The duration multiplier. + */ + private static double getPotionDurationMultiplier(ItemStack stack) { + if (stack.getItem() instanceof LingeringPotionItem) return 0.25; + if (stack.getItem() instanceof TippedArrowItem) return 0.125; + return 1.0; + } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/platform/RegistryWrappers.java b/projects/common/src/main/java/dan200/computercraft/shared/platform/RegistryWrappers.java index 7069db974..368230fbc 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/platform/RegistryWrappers.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/platform/RegistryWrappers.java @@ -10,6 +10,7 @@ import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.effect.MobEffect; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.Item; import net.minecraft.world.item.crafting.RecipeSerializer; @@ -31,6 +32,7 @@ public final class RegistryWrappers { public static final RegistryWrapper> BLOCK_ENTITY_TYPES = PlatformHelper.get().wrap(Registries.BLOCK_ENTITY_TYPE); public static final RegistryWrapper FLUIDS = PlatformHelper.get().wrap(Registries.FLUID); public static final RegistryWrapper ENCHANTMENTS = PlatformHelper.get().wrap(Registries.ENCHANTMENT); + public static final RegistryWrapper MOB_EFFECTS = PlatformHelper.get().wrap(Registries.MOB_EFFECT); public static final RegistryWrapper> COMMAND_ARGUMENT_TYPES = PlatformHelper.get().wrap(Registries.COMMAND_ARGUMENT_TYPE); public static final RegistryWrapper> RECIPE_SERIALIZERS = PlatformHelper.get().wrap(Registries.RECIPE_SERIALIZER); public static final RegistryWrapper> MENU = PlatformHelper.get().wrap(Registries.MENU);