Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix item_name component not work; Improve display of custom effects and shulker box tooltips for item names #5255

Merged
merged 7 commits into from
Jan 5, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,17 @@ public void setItemInFrame(EntityMetadata<ItemStack, ?> entityMetadata) {
NbtMapBuilder builder = NbtMap.builder();
builder.putByte("Count", (byte) itemData.getCount());
NbtMap itemDataTag = itemData.getTag();
if (itemData.getTag() != null) {
if (itemDataTag != null) {
// Remove custom name that Geyser sets for items due to translating non-"custom_name" components
String customName = ItemTranslator.getCustomName(session, heldItem.getDataComponents(),
session.getItemMappings().getMapping(heldItem), 'f', true, false);
if (customName == null) {
// No custom name found, must modify tag if custom name exists
NbtMapBuilder copy = itemDataTag.toBuilder();
copy.remove("display"); // Also removes lore, but, should not matter
itemDataTag = copy.build();
}

builder.put("tag", itemDataTag);
}
builder.putShort("Damage", (short) itemData.getDamage());
Expand Down
13 changes: 0 additions & 13 deletions core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@
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;
Expand Down Expand Up @@ -70,17 +68,6 @@ public ItemData.Builder translateToBedrock(GeyserSession session, int count, Dat
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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
import org.geysermc.geyser.translator.item.CustomItemTranslator;
import org.geysermc.geyser.translator.item.ItemTranslator;
Expand Down Expand Up @@ -98,8 +99,12 @@ public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNul

// Only the display name is what we have interest in, so just translate that if relevant
if (boxComponents != null) {
String customName = ItemTranslator.getCustomName(session, boxComponents, boxMapping, '7', true);
String customName = ItemTranslator.getCustomName(session, boxComponents, boxMapping, '7', false, true);
if (customName != null) {
// Fix count display (e.g., x16) with incorrect color due to some items with colored names
if (customName.contains("" + ChatColor.ESCAPE)) {
customName += ChatColor.RESET + ChatColor.GRAY;
}
boxItemNbt.putCompound("tag", NbtMap.builder()
.putCompound("display", NbtMap.builder()
.putString("Name", customName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,12 @@

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;
Expand All @@ -60,15 +57,4 @@ public ItemData.Builder translateToBedrock(GeyserSession session, int count, Dat
}
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.item.Potion;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.components.Rarity;
import org.geysermc.geyser.item.type.Item;
Expand Down Expand Up @@ -70,6 +71,7 @@
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 org.geysermc.mcprotocollib.protocol.data.game.item.component.WrittenBookContent;

import java.text.DecimalFormat;
import java.util.ArrayList;
Expand Down Expand Up @@ -163,18 +165,25 @@ public static ItemData translateToBedrock(GeyserSession session, ItemStack stack
.build();
}

public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents components) {
public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents customComponents) {
BedrockItemBuilder nbtBuilder = new BedrockItemBuilder();

// Populates default components that aren't sent over the network
components = javaItem.gatherComponents(components);
DataComponents components = javaItem.gatherComponents(customComponents);

// Translate item-specific components
javaItem.translateComponentsToBedrock(session, components, nbtBuilder);

Rarity rarity = Rarity.fromId(components.getOrDefault(DataComponentType.RARITY, 0));
String customName = getCustomName(session, components, bedrockItem, rarity.getColor(), false);
String customName = getCustomName(session, customComponents, bedrockItem, rarity.getColor(), false, false);
if (customName != null) {
PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS);
// Make custom effect information visible
// Ignore when item have "hide_additional_tooltip" component
if (potionContents != null && components.get(DataComponentType.HIDE_ADDITIONAL_TOOLTIP) == null) {
customName += getPotionEffectInfo(potionContents, session.locale());
}

nbtBuilder.setCustomName(customName);
}

Expand Down Expand Up @@ -336,7 +345,8 @@ private static String attributeToLore(GeyserSession session, int attribute, Item
Effect.INFESTED
);

public static void addPotionEffectLore(PotionContents contents, BedrockItemBuilder builder, String language) {
public static String getPotionEffectInfo(PotionContents contents, String language) {
StringBuilder finalText = new StringBuilder();
List<MobEffectInstance> effectInstanceList = contents.getCustomEffects();
for (MobEffectInstance effectInstance : effectInstanceList) {
Effect effect = effectInstance.getEffect();
Expand Down Expand Up @@ -372,8 +382,40 @@ public static void addPotionEffectLore(PotionContents contents, BedrockItemBuild
.color((negativeEffectList.contains(effect)) ? NamedTextColor.RED : NamedTextColor.BLUE)
.append(appendTranslatable)
.build();
builder.getOrCreateLore().add(MessageTranslator.convertMessage(component, language));
// Bedrock supports wrap lines with '\n' in a single string in custom name
finalText.append('\n').append(MessageTranslator.convertMessage(component, language));
}
return finalText.toString();
}

public static String getPotionName(PotionContents contents, ItemMapping mapping, boolean hideAdditionalTooltip, String language) {
String customPotionName = contents.getCustomName();
Potion potion = Potion.getByJavaId(contents.getPotionId());

if (customPotionName != null) {
// "custom_name" tag in "potion_contents" component
return MessageTranslator.convertMessage(
Component.translatable(mapping.getJavaItem().translationKey() + ".effect." + customPotionName),
language);
}
if (!hideAdditionalTooltip && !contents.getCustomEffects().isEmpty()) {
// Make a name when has custom effects
String potionName;
if (potion != null) {
potionName = potion.toString().toLowerCase(Locale.ROOT);
if (potionName.startsWith("strong_")) {
potionName = potionName.substring(6);
} else if (potionName.startsWith("long_")) {
potionName = potionName.substring(4);
}
} else {
potionName = "empty";
}
return MessageTranslator.convertMessage(
Component.translatable(mapping.getJavaItem().translationKey() + ".effect." + potionName),
language);
}
return null;
}

private static void addAdvancedTooltips(@Nullable DataComponents components, BedrockItemBuilder builder, Item item, String language) {
Expand Down Expand Up @@ -493,31 +535,34 @@ public static ItemDefinition getBedrockItemDefinition(GeyserSession session, @No
* @param translationColor if this item is not available on Java, the color that the new name should be.
* Normally, this should just be white, but for shulker boxes this should be gray.
*/
public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping, char translationColor, boolean includeDefault) {
public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping, char translationColor, boolean customNameOnly, boolean includeAll) {
if (components != null) {
// ItemStack#getHoverName as of 1.20.5
Component customName = components.get(DataComponentType.CUSTOM_NAME);
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());
if (!customNameOnly) {
PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS);
if (potionContents != null) {
String potionName = getPotionName(potionContents, mapping, components.get(DataComponentType.HIDE_ADDITIONAL_TOOLTIP) != null, session.locale());
if (potionName != null) {
return ChatColor.RESET + ChatColor.ESCAPE + translationColor + potionName;
}
}
if (includeAll) {
// Fix book title display in tooltips of shulker box
WrittenBookContent bookContent = components.get(DataComponentType.WRITTEN_BOOK_CONTENT);
if (bookContent != null) {
return ChatColor.RESET + ChatColor.ESCAPE + translationColor + bookContent.getTitle().getRaw();
}
}
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
// behavior as of 1.21
return ChatColor.RESET + ChatColor.ESCAPE + translationColor + MessageTranslator.convertMessage(customName, session.locale());
}
}
customName = components.get(DataComponentType.ITEM_NAME);
if (customName != null && includeDefault) {
// Get the translated name and prefix it with a reset char to prevent italics - matches Java Edition
// behavior as of 1.21
return ChatColor.RESET + ChatColor.ESCAPE + translationColor + MessageTranslator.convertMessage(customName, session.locale());
}
}

Expand Down
Loading