From d956354b7f401664de7103228bc4f7ec5213802b Mon Sep 17 00:00:00 2001 From: BugTeaON <99161186+BUGTeas@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:03:09 +0800 Subject: [PATCH] =?UTF-8?q?Feature=EF=BC=9AMake=20custom=20effect=20inform?= =?UTF-8?q?ation=20visible=20&=20Support=20for=20customizing=20item=20name?= =?UTF-8?q?=20via=20'custom=5Fname'=20tag=20in=20'potion=5Fcontents'=20com?= =?UTF-8?q?ponent=20(new=20feature=20since=201.21.2)=20(#5176)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make custom effect information visible * Support for customizing item name via 'custom_name' tag in 'potion_contents' component * A little optimization of custom effect information * The effect information should appear in front of the custom lore --- .../geysermc/geyser/item/type/PotionItem.java | 13 ++++ .../geyser/item/type/TippedArrowItem.java | 14 ++++ .../translator/item/ItemTranslator.java | 78 +++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java index 89e60b325..4cc3756cd 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java @@ -34,7 +34,9 @@ import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.CustomItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; @@ -68,6 +70,17 @@ public class PotionItem extends Item { return super.translateToBedrock(session, count, components, mapping, mappings); } + @Override + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { + // Make custom effect information visible + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + ItemTranslator.addPotionEffectLore(potionContents, builder, session.locale()); + } + + super.translateComponentsToBedrock(session, components, builder); + } + @Override public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { Potion potion = Potion.getByBedrockId(itemData.getDamage()); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TippedArrowItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TippedArrowItem.java index 09e4ee21f..9e212ebef 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/TippedArrowItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/TippedArrowItem.java @@ -25,12 +25,15 @@ package org.geysermc.geyser.item.type; +import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; @@ -57,4 +60,15 @@ public class TippedArrowItem extends ArrowItem { } return super.translateToBedrock(session, count, components, mapping, mappings); } + + @Override + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { + // Make custom effect information visible + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + ItemTranslator.addPotionEffectLore(potionContents, builder, session.locale()); + } + + super.translateComponentsToBedrock(session, components, builder); + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java index 3cfd00233..97cb3df2f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.translator.item; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -55,6 +56,7 @@ import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.auth.GameProfile.Texture; import org.geysermc.mcprotocollib.auth.GameProfile.TextureType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; @@ -63,12 +65,16 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemAttributeModifiers; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectDetails; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectInstance; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; public final class ItemTranslator { @@ -324,6 +330,65 @@ public final class ItemTranslator { return MessageTranslator.convertMessage(attributeComponent, language); } + private static final List negativeEffectList = List.of( + Effect.SLOWNESS, + Effect.MINING_FATIGUE, + Effect.INSTANT_DAMAGE, + Effect.NAUSEA, + Effect.BLINDNESS, + Effect.HUNGER, + Effect.WEAKNESS, + Effect.POISON, + Effect.WITHER, + Effect.LEVITATION, + Effect.UNLUCK, + Effect.DARKNESS, + Effect.WIND_CHARGED, + Effect.WEAVING, + Effect.OOZING, + Effect.INFESTED + ); + + public static void addPotionEffectLore(PotionContents contents, BedrockItemBuilder builder, String language) { + List effectInstanceList = contents.getCustomEffects(); + for (MobEffectInstance effectInstance : effectInstanceList) { + Effect effect = effectInstance.getEffect(); + MobEffectDetails details = effectInstance.getDetails(); + int amplifier = details.getAmplifier(); + int durations = details.getDuration(); + TranslatableComponent appendTranslatable = Component.translatable("effect.minecraft." + effect.toString().toLowerCase(Locale.ROOT)); + if (amplifier != 0) { + appendTranslatable = Component.translatable("potion.withAmplifier", + appendTranslatable, + Component.translatable("potion.potency." + amplifier)); + } + if (durations > 20) { + int seconds = durations / 20; + int secondsFormat = seconds % 60; + int minutes = seconds / 60; + int minutesFormat = minutes % 60; + int hours = minutes / 60; + String text = ((minutesFormat > 9) ? "" : "0") + minutesFormat + ":" + ((secondsFormat > 9) ? "" : "0") + secondsFormat; + if (minutes >= 60) { + text = ((hours > 9) ? "" : "0") + hours + ":" + text; + } + appendTranslatable = Component.translatable("potion.withDuration", + appendTranslatable, + Component.text(text)); + } else if (durations == -1) { + appendTranslatable = Component.translatable("potion.withDuration", + appendTranslatable, + Component.translatable("effect.duration.infinite")); + } + Component component = Component.text() + .resetStyle() + .color((negativeEffectList.contains(effect)) ? NamedTextColor.RED : NamedTextColor.BLUE) + .append(appendTranslatable) + .build(); + builder.getOrCreateLore().add(MessageTranslator.convertMessage(component, language)); + } + } + private static void addAdvancedTooltips(@Nullable DataComponents components, BedrockItemBuilder builder, Item item, String language) { int maxDurability = item.maxDamage(); @@ -448,6 +513,19 @@ public final class ItemTranslator { if (customName != null) { return MessageTranslator.convertMessage(customName, session.locale()); } + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + // "custom_name" tag in "potion_contents" component + String customPotionName = potionContents.getCustomName(); + if (customPotionName != null) { + Component component = Component.text() + .resetStyle() + .color(NamedTextColor.WHITE) + .append(Component.translatable(mapping.getJavaItem().translationKey() + ".effect." + customPotionName)) + .build(); + return MessageTranslator.convertMessage(component, session.locale()); + } + } customName = components.get(DataComponentType.ITEM_NAME); if (customName != null) { // Get the translated name and prefix it with a reset char to prevent italics - matches Java Edition