Yeet NbtItemStackTranslator

This commit is contained in:
Camotoy 2023-04-08 12:45:13 -04:00
parent 503296a9cf
commit 60de3187c6
43 changed files with 1670 additions and 1896 deletions

View File

@ -1,5 +1,4 @@
org.geysermc.geyser.processor.BlockEntityProcessor
org.geysermc.geyser.processor.CollisionRemapperProcessor
org.geysermc.geyser.processor.ItemRemapperProcessor
org.geysermc.geyser.processor.PacketTranslatorProcessor
org.geysermc.geyser.processor.SoundHandlerProcessor

View File

@ -195,7 +195,6 @@ public class GeyserImpl implements GeyserApi {
/* Initialize translators */
EntityDefinitions.init();
ItemTranslator.init();
MessageTranslator.init();
// Download the latest asset list and cache it

View File

@ -51,7 +51,7 @@ public class AbstractFishEntity extends WaterEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (EntityUtils.attemptToBucket(session, itemInHand)) {
if (EntityUtils.attemptToBucket(itemInHand)) {
return InteractionResult.SUCCESS;
} else {
return super.mobInteract(hand, itemInHand);

View File

@ -77,7 +77,7 @@ public class AxolotlEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (EntityUtils.attemptToBucket(session, itemInHand)) {
if (EntityUtils.attemptToBucket(itemInHand)) {
return InteractionResult.SUCCESS;
} else {
return super.mobInteract(hand, itemInHand);

View File

@ -32,6 +32,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.FlowerItem;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
@ -76,7 +77,7 @@ public class MooshroomEntity extends AnimalEntity {
} else if (!isBaby && isAlive() && itemInHand.asItem() == Items.SHEARS) {
// Shear items
return InteractionResult.SUCCESS;
} else if (isBrown && session.getTagCache().isSmallFlower(itemInHand) && itemInHand.getMapping(session).isHasSuspiciousStewEffect()) {
} else if (isBrown && session.getTagCache().isSmallFlower(itemInHand) && itemInHand.asItem() instanceof FlowerItem) {
// ?
return InteractionResult.SUCCESS;
}

View File

@ -27,6 +27,8 @@ package org.geysermc.geyser.inventory;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import lombok.AccessLevel;
import lombok.Getter;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import lombok.Data;
import org.geysermc.geyser.item.type.Item;
@ -107,6 +109,7 @@ public class GeyserItemStack {
return session.getItemMappings().getMapping(this.javaId);
}
@Getter(AccessLevel.NONE)
private Item item; //TODO
public Item asItem() {

View File

@ -43,34 +43,26 @@ public class StoredItemMappings {
private final ItemMapping bamboo;
private final ItemMapping banner;
private final ItemMapping barrier;
private final ItemMapping bucket;
private final ItemMapping compass;
private final ItemMapping crossbow;
private final ItemMapping frogspawn;
private final ItemMapping glassBottle;
private final ItemMapping lilyPad;
private final ItemMapping milkBucket;
private final ItemMapping powderSnowBucket;
private final ItemMapping egg;
private final ItemMapping shield;
private final ItemMapping waterBucket;
private final ItemMapping wheat;
public StoredItemMappings(Map<Item, ItemMapping> itemMappings) {
this.bamboo = load(itemMappings, Items.BAMBOO);
this.banner = load(itemMappings, Items.WHITE_BANNER); // As of 1.17.10, all banners have the same Bedrock ID
this.barrier = load(itemMappings, Items.BARRIER);
this.bucket = load(itemMappings, Items.BUCKET);
this.compass = load(itemMappings, Items.COMPASS);
this.crossbow = load(itemMappings, Items.CROSSBOW);
this.frogspawn = load(itemMappings, Items.FROGSPAWN);
this.glassBottle = load(itemMappings, Items.GLASS_BOTTLE);
this.lilyPad = load(itemMappings, Items.LILY_PAD);
this.milkBucket = load(itemMappings, Items.MILK_BUCKET);
this.powderSnowBucket = load(itemMappings, Items.POWDER_SNOW_BUCKET);
this.egg = load(itemMappings, Items.EGG);
this.shield = load(itemMappings, Items.SHIELD);
this.waterBucket = load(itemMappings, Items.WATER_BUCKET);
this.wheat = load(itemMappings, Items.WHEAT);
}

View File

@ -27,22 +27,24 @@ package org.geysermc.geyser.item;
import org.geysermc.geyser.item.type.Item;
import java.util.function.Supplier;
public enum ArmorMaterial {
LEATHER(Items.LEATHER),
CHAIN(Items.IRON_INGOT),
IRON(Items.IRON_INGOT),
GOLD(Items.GOLD_INGOT),
DIAMOND(Items.DIAMOND),
TURTLE(Items.SCUTE),
NETHERITE(Items.NETHERITE_INGOT);
LEATHER(() -> Items.LEATHER),
CHAIN(() -> Items.IRON_INGOT),
IRON(() -> Items.IRON_INGOT),
GOLD(() -> Items.GOLD_INGOT),
DIAMOND(() -> Items.DIAMOND),
TURTLE(() -> Items.SCUTE),
NETHERITE(() -> Items.NETHERITE_INGOT);
private final Item repairIngredient;
private final Supplier<Item> repairIngredient;
ArmorMaterial(Item repairIngredient) {
ArmorMaterial(Supplier<Item> repairIngredient) {
this.repairIngredient = repairIngredient;
}
public Item getRepairIngredient() {
return repairIngredient;
return repairIngredient.get();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,53 +23,34 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
import java.util.List;
public interface DyeableLeatherItem {
@ItemRemapper
public class LeatherArmorTranslator extends NbtItemStackTranslator {
private static final List<Item> ITEMS = List.of(Items.LEATHER_HELMET, Items.LEATHER_CHESTPLATE,
Items.LEATHER_LEGGINGS, Items.LEATHER_BOOTS, Items.LEATHER_HORSE_ARMOR);
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
CompoundTag displayTag = itemTag.get("display");
static void translateNbtToBedrock(CompoundTag tag) {
CompoundTag displayTag = tag.get("display");
if (displayTag == null) {
return;
}
IntTag color = displayTag.remove("color");
if (color != null) {
itemTag.put(new IntTag("customColor", color.getValue()));
tag.put(new IntTag("customColor", color.getValue()));
}
}
@Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
IntTag color = itemTag.get("customColor");
static void translateNbtToJava(CompoundTag tag) {
IntTag color = tag.get("customColor");
if (color == null) {
return;
}
CompoundTag displayTag = itemTag.get("display");
CompoundTag displayTag = tag.get("display");
if (displayTag == null) {
displayTag = new CompoundTag("display");
}
displayTag.put(color);
itemTag.remove("customColor");
}
@Override
public boolean acceptItem(Item item) {
return ITEMS.contains(item);
tag.remove("customColor");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,35 +23,31 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
import org.jetbrains.annotations.NotNull;
@ItemRemapper
public class AxolotlBucketTranslator extends NbtItemStackTranslator {
public class AxolotlBucketItem extends Item {
public AxolotlBucketItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
public void translateNbtToBedrock(@NotNull GeyserSession session, @NotNull CompoundTag tag, @NotNull ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
// Bedrock Edition displays the properties of the axolotl. Java does not.
// To work around this, set the custom name to the Axolotl translation and it's displayed correctly
itemTag.put(new ByteTag("AppendCustomName", (byte) 1));
itemTag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.axolotl", session.locale())));
tag.put(new ByteTag("AppendCustomName", (byte) 1));
tag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.axolotl", session.locale())));
// Boilerplate required so the nametag does not appear as "Bucket of "
itemTag.put(new StringTag("ColorID", ""));
itemTag.put(new StringTag("BodyID", ""));
}
@Override
public boolean acceptItem(Item item) {
return item == Items.AXOLOTL_BUCKET;
tag.put(new StringTag("ColorID", ""));
tag.put(new StringTag("BodyID", ""));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,30 +23,26 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.*;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.geysermc.erosion.util.BannerUtils.getJavaPatternTag;
@ItemRemapper
public class BannerTranslator extends NbtItemStackTranslator {
public class BannerItem extends BlockItem {
/**
* Holds what a Java ominous banner pattern looks like.
*
@ -56,8 +52,6 @@ public class BannerTranslator extends NbtItemStackTranslator {
*/
public static final ListTag OMINOUS_BANNER_PATTERN;
private final List<Item> appliedItems;
static {
OMINOUS_BANNER_PATTERN = new ListTag("Patterns");
// Construct what an ominous banner is supposed to look like
@ -71,12 +65,6 @@ public class BannerTranslator extends NbtItemStackTranslator {
OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("bo", 15));
}
public BannerTranslator() {
appliedItems = Registries.JAVA_ITEMS.get().stream()
.filter(entry -> entry.javaIdentifier().endsWith("banner"))
.collect(Collectors.toList());
}
/**
* Convert a list of patterns from Java nbt to Bedrock nbt
*
@ -128,42 +116,44 @@ public class BannerTranslator extends NbtItemStackTranslator {
}
}
public BannerItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
CompoundTag blockEntityTag = itemTag.get("BlockEntityTag");
public void translateNbtToBedrock(@NotNull GeyserSession session, @NotNull CompoundTag tag, @NotNull ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
CompoundTag blockEntityTag = tag.remove("BlockEntityTag");
if (blockEntityTag != null && blockEntityTag.get("Patterns") instanceof ListTag patterns) {
if (patterns.equals(OMINOUS_BANNER_PATTERN)) {
// Remove the current patterns and set the ominous banner type
itemTag.put(new IntTag("Type", 1));
tag.put(new IntTag("Type", 1));
} else {
invertBannerColors(patterns);
itemTag.put(patterns);
tag.put(patterns);
}
itemTag.remove("BlockEntityTag");
}
}
@Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
if (itemTag.get("Type") instanceof IntTag type && type.getValue() == 1) {
public void translateNbtToJava(@NotNull CompoundTag tag, @NotNull ItemMapping mapping) {
super.translateNbtToJava(tag, mapping);
if (tag.get("Type") instanceof IntTag type && type.getValue() == 1) {
// Ominous banner pattern
itemTag.remove("Type");
tag.remove("Type");
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
blockEntityTag.put(OMINOUS_BANNER_PATTERN);
itemTag.put(blockEntityTag);
} else if (itemTag.get("Patterns") instanceof ListTag patterns) {
tag.put(blockEntityTag);
} else if (tag.get("Patterns") instanceof ListTag patterns) {
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
invertBannerColors(patterns);
blockEntityTag.put(patterns);
itemTag.put(blockEntityTag);
itemTag.remove("Patterns"); // Remove the old Bedrock patterns list
tag.put(blockEntityTag);
tag.remove("Patterns"); // Remove the old Bedrock patterns list
}
}
@Override
public boolean acceptItem(Item item) {
return appliedItems.contains(item);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,12 +23,10 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item;
package org.geysermc.geyser.item.type;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(value = RetentionPolicy.RUNTIME)
public @interface ItemRemapper {
int priority() default 0;
public class BoatItem extends Item {
public BoatItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
}

View File

@ -28,10 +28,12 @@ package org.geysermc.geyser.item.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.session.GeyserSession;
public class CompassItem extends Item {
public CompassItem(String javaIdentifier, Builder builder) {
@ -41,7 +43,6 @@ public class CompassItem extends Item {
@Override
public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
if (isLodestoneCompass(itemStack.getNbt())) {
// NBT will be translated in nbt/LodestoneCompassTranslator if applicable
return super.translateToBedrock(itemStack, mappings.getLodestoneCompass(), mappings);
}
return super.translateToBedrock(itemStack, mapping, mappings);
@ -55,6 +56,18 @@ public class CompassItem extends Item {
return super.toBedrockDefinition(nbt, mappings);
}
@Override
public void translateNbtToBedrock(GeyserSession session, CompoundTag tag, ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
Tag lodestoneTag = tag.get("LodestoneTracked");
if (lodestoneTag instanceof ByteTag) {
int trackId = session.getLodestoneCache().store(tag);
// Set the bedrock tracking id - will return 0 if invalid
tag.put(new IntTag("trackingHandle", trackId));
}
}
private boolean isLodestoneCompass(CompoundTag nbt) {
if (nbt != null) {
Tag lodestoneTag = nbt.get("LodestoneTracked");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,33 +23,34 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.*;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
@ItemRemapper
public class CrossbowTranslator extends NbtItemStackTranslator {
public class CrossbowItem extends Item {
public CrossbowItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
ListTag chargedProjectiles = itemTag.get("ChargedProjectiles");
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
ListTag chargedProjectiles = tag.get("ChargedProjectiles");
if (chargedProjectiles != null) {
if (!chargedProjectiles.getValue().isEmpty()) {
CompoundTag projectile = (CompoundTag) chargedProjectiles.getValue().get(0);
ItemMapping projectileMapping = session.getItemMappings().getMapping((String) projectile.get("id").getValue());
if (projectileMapping == null) return;
CompoundTag tag = projectile.get("tag");
ItemStack itemStack = new ItemStack(mapping.getJavaItem().javaId(), (byte) projectile.get("Count").getValue(), tag);
CompoundTag projectileTag = projectile.get("tag");
ItemStack itemStack = new ItemStack(mapping.getJavaItem().javaId(), (byte) projectile.get("Count").getValue(), projectileTag);
ItemData itemData = ItemTranslator.translateToBedrock(session, itemStack);
CompoundTag newProjectile = new CompoundTag("chargedItem");
@ -58,15 +59,17 @@ public class CrossbowTranslator extends NbtItemStackTranslator {
newProjectile.put(new ShortTag("Damage", (short) itemData.getDamage()));
itemTag.put(newProjectile);
projectileTag.put(newProjectile);
}
}
}
@Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
if (itemTag.get("chargedItem") != null) {
CompoundTag chargedItem = itemTag.get("chargedItem");
public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToJava(tag, mapping);
if (tag.get("chargedItem") != null) {
CompoundTag chargedItem = tag.get("chargedItem");
CompoundTag newProjectile = new CompoundTag("");
newProjectile.put(new ByteTag("Count", (byte) chargedItem.get("Count").getValue()));
@ -75,12 +78,7 @@ public class CrossbowTranslator extends NbtItemStackTranslator {
ListTag chargedProjectiles = new ListTag("ChargedProjectiles");
chargedProjectiles.add(newProjectile);
itemTag.put(chargedProjectiles);
tag.put(chargedProjectiles);
}
}
@Override
public boolean acceptItem(Item item) {
return item == Items.CROSSBOW;
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.item.ArmorMaterial;
import org.geysermc.geyser.item.DyeableLeatherItem;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
public class DyeableArmorItem extends ArmorItem implements DyeableLeatherItem {
public DyeableArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) {
super(javaIdentifier, material, builder);
}
@Override
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
DyeableLeatherItem.translateNbtToBedrock(tag);
}
@Override
public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToJava(tag, mapping);
DyeableLeatherItem.translateNbtToJava(tag);
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.item.DyeableLeatherItem;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
public class DyeableHorseArmorItem extends Item implements DyeableLeatherItem {
public DyeableHorseArmorItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
DyeableLeatherItem.translateNbtToBedrock(tag);
}
@Override
public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToJava(tag, mapping);
DyeableLeatherItem.translateNbtToJava(tag);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,49 +23,40 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
@ItemRemapper(priority = 1)
public class EnchantedBookTranslator extends NbtItemStackTranslator {
import java.util.ArrayList;
import java.util.List;
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
if (!itemTag.contains("StoredEnchantments")) {
return;
}
Tag enchTag = itemTag.get("StoredEnchantments");
if (enchTag instanceof ListTag) {
enchTag = new ListTag("Enchantments", ((ListTag) enchTag).getValue());
itemTag.remove("StoredEnchantments");
itemTag.put(enchTag);
}
public class EnchantedBookItem extends Item {
public EnchantedBookItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
if (!itemTag.contains("Enchantments")) {
return;
}
Tag enchTag = itemTag.get("Enchantments");
if (enchTag instanceof ListTag) {
enchTag = new ListTag("StoredEnchantments", ((ListTag) enchTag).getValue());
itemTag.remove("Enchantments");
itemTag.put(enchTag);
}
}
public void translateNbtToBedrock(GeyserSession session, CompoundTag tag, ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
@Override
public boolean acceptItem(Item item) {
return item == Items.ENCHANTED_BOOK;
List<Tag> newTags = new ArrayList<>();
Tag enchantmentTag = tag.remove("StoredEnchantments");
if (enchantmentTag instanceof ListTag listTag) {
for (Tag subTag : listTag.getValue()) {
if (!(subTag instanceof CompoundTag)) continue;
CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) subTag, tag);
if (bedrockTag != null) {
newTags.add(bedrockTag);
}
}
}
if (!newTags.isEmpty()) {
tag.put(new ListTag("ench", newTags));
}
}
}

View File

@ -28,6 +28,7 @@ package org.geysermc.geyser.item.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings;
@ -41,7 +42,10 @@ public class FilledMapItem extends MapItem {
public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
ItemData.Builder builder = super.translateToBedrock(itemStack, mapping, mappings);
CompoundTag nbt = itemStack.getNbt();
if (nbt != null && nbt.get("display") instanceof CompoundTag display) {
if (nbt == null) {
// This is a fallback for maps with no nbt (Change added back in June 2020; is it needed in 2023?)
return builder.tag(NbtMap.builder().putInt("map", 0).build());
} else if (nbt.get("display") instanceof CompoundTag display) {
// Note: damage 5 treasure map, 6 ???
Tag mapColor = display.get("MapColor");
if (mapColor != null && mapColor.getValue() instanceof Number color) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,22 +23,52 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag;
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
import com.github.steveice10.opennbt.tag.builtin.*;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.level.FireworkColor;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.MathUtils;
/**
* Stores common code for firework rockets and firework stars.
*/
public abstract class FireworkBaseTranslator extends NbtItemStackTranslator {
public class FireworkRocketItem extends Item {
public FireworkRocketItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
protected CompoundTag translateExplosionToBedrock(CompoundTag explosion, String newName) {
@Override
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
CompoundTag fireworks = tag.get("Fireworks");
if (fireworks == null) {
return;
}
if (fireworks.get("Flight") != null) {
fireworks.put(new ByteTag("Flight", MathUtils.getNbtByte(fireworks.get("Flight").getValue())));
}
ListTag explosions = fireworks.get("Explosions");
if (explosions == null) {
return;
}
for (Tag effect : explosions.getValue()) {
CompoundTag effectData = (CompoundTag) effect;
CompoundTag newEffectData = translateExplosionToBedrock(effectData, "");
explosions.remove(effectData);
explosions.add(newEffectData);
}
}
@Override
public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToJava(tag, mapping);
}
static CompoundTag translateExplosionToBedrock(CompoundTag explosion, String newName) {
CompoundTag newExplosionData = new CompoundTag(newName);
if (explosion.get("Type") != null) {
@ -80,7 +110,7 @@ public abstract class FireworkBaseTranslator extends NbtItemStackTranslator {
return newExplosionData;
}
protected CompoundTag translateExplosionToJava(CompoundTag explosion, String newName) {
static CompoundTag translateExplosionToJava(CompoundTag explosion, String newName) {
CompoundTag newExplosionData = new CompoundTag(newName);
if (explosion.get("FireworkType") != null) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,28 +23,29 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
@ItemRemapper
public class FireworkStarTranslator extends FireworkBaseTranslator {
public class FireworkStarItem extends Item {
public FireworkStarItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
Tag explosion = itemTag.get("Explosion");
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
Tag explosion = tag.remove("Explosion");
if (explosion instanceof CompoundTag) {
CompoundTag newExplosion = translateExplosionToBedrock((CompoundTag) explosion, "FireworksItem");
itemTag.remove("Explosion");
itemTag.put(newExplosion);
CompoundTag newExplosion = FireworkRocketItem.translateExplosionToBedrock((CompoundTag) explosion, "FireworksItem");
tag.put(newExplosion);
Tag color = ((CompoundTag) explosion).get("Colors");
if (color instanceof IntArrayTag) {
// Determine the custom color, if any.
@ -74,25 +75,21 @@ public class FireworkStarTranslator extends FireworkBaseTranslator {
finalColor = r << 16 | g << 8 | b;
}
itemTag.put(new IntTag("customColor", finalColor));
tag.put(new IntTag("customColor", finalColor));
}
}
}
@Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
Tag explosion = itemTag.get("FireworksItem");
public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToJava(tag, mapping);
Tag explosion = tag.remove("FireworksItem");
if (explosion instanceof CompoundTag) {
CompoundTag newExplosion = translateExplosionToJava((CompoundTag) explosion, "Explosion");
itemTag.remove("FireworksItem");
itemTag.put(newExplosion);
CompoundTag newExplosion = FireworkRocketItem.translateExplosionToJava((CompoundTag) explosion, "Explosion");
tag.put(newExplosion);
}
// Remove custom color, if any, since this only exists on Bedrock
itemTag.remove("customColor");
}
@Override
public boolean acceptItem(Item item) {
return item == Items.FIREWORK_STAR;
tag.remove("customColor");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,38 +23,32 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
@ItemRemapper
public class LodestoneCompassTranslator extends NbtItemStackTranslator {
public class FishingRodItem extends Item {
public FishingRodItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
Tag lodestoneTag = itemTag.get("LodestoneTracked");
if (lodestoneTag instanceof ByteTag) {
int trackId = session.getLodestoneCache().store(itemTag);
// Set the bedrock tracking id - will return 0 if invalid
itemTag.put(new IntTag("trackingHandle", trackId));
public void translateNbtToBedrock(GeyserSession session, CompoundTag tag, ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
// Fix damage inconsistency
Tag damage = tag.get("Damage");
if (damage instanceof IntTag) {
int originalDurability = ((IntTag) damage).getValue();
tag.put(new IntTag("Damage", getBedrockDamage(originalDurability)));
}
}
// NBT does not need to be translated from Bedrock Edition to Java Edition.
// translateToJava is called in three places: extra recipe loading, creative menu, and stonecutters
// Lodestone compasses cannot be touched in any of those places.
@Override
public boolean acceptItem(Item item) {
return item == Items.COMPASS;
public static int getBedrockDamage(int javaDamage) {
return javaDamage * 6;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,16 +23,11 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.processor;
package org.geysermc.geyser.item.type;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_16)
public class ItemRemapperProcessor extends ClassProcessor {
public ItemRemapperProcessor() {
super("org.geysermc.geyser.translator.inventory.item.ItemRemapper");
// If blocks are implemented, then this class is not needed.
public class FlowerItem extends BlockItem {
public FlowerItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
}

View File

@ -27,11 +27,22 @@ package org.geysermc.geyser.item.type;
import com.github.steveice10.mc.protocol.data.game.Identifier;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.*;
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.Enchantment;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
import org.geysermc.geyser.translator.text.MessageTranslator;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class Item {
private final String javaIdentifier;
@ -39,14 +50,12 @@ public class Item {
private final int stackSize;
private final String toolType;
private final int maxDamage;
private final boolean hasSuspiciousStewEffect;
public Item(String javaIdentifier, Builder builder) {
this.javaIdentifier = Identifier.formalize(javaIdentifier).intern();
this.stackSize = builder.stackSize;
this.toolType = builder.toolType;
this.maxDamage = builder.maxDamage;
this.hasSuspiciousStewEffect = builder.hasSuspiciousStewEffect;
}
public String javaIdentifier() {
@ -102,13 +111,151 @@ public class Item {
return mappings.getMapping(javaId);
}
/**
* Takes NBT from Java Edition and converts any value that Bedrock parses differently.
*/
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
if (tag.get("display") instanceof CompoundTag displayTag) {
if (displayTag.get("Lore") instanceof ListTag listTag) {
List<Tag> lore = new ArrayList<>();
for (Tag subTag : listTag.getValue()) {
if (!(subTag instanceof StringTag)) continue;
lore.add(new StringTag("", MessageTranslator.convertMessageLenient(((StringTag) subTag).getValue(), session.locale())));
}
displayTag.put(new ListTag("Lore", lore));
}
}
List<Tag> newTags = new ArrayList<>();
Tag enchantmentTag = tag.remove("Enchantments");
if (enchantmentTag instanceof ListTag listTag) {
for (Tag subTag : listTag.getValue()) {
if (!(subTag instanceof CompoundTag)) continue;
CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) subTag, tag);
if (bedrockTag != null) {
newTags.add(bedrockTag);
}
}
}
if (!newTags.isEmpty()) {
tag.put(new ListTag("ench", newTags));
}
}
/**
* Takes NBT from Java Edition and converts any value that Bedrock parses differently. <br />
* Do note that this method is, these days, only called in three places (as of 2023/~1.19):
* <ul>
* <li>Extra recipe loading</li>
* <li>Creative menu</li>
* <li>Stonecutters</li>
* </ul>
* Therefore, if translation cannot be achieved for a certain item, it is not necessarily bad.
*/
public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
CompoundTag displayTag = tag.get("display");
if (displayTag != null) {
if (displayTag.contains("Name")) {
StringTag nameTag = displayTag.get("Name");
displayTag.put(new StringTag("Name", MessageTranslator.convertToJavaMessage(nameTag.getValue())));
}
if (displayTag.contains("Lore")) {
ListTag loreTag = displayTag.get("Lore");
List<Tag> lore = new ArrayList<>();
for (Tag subTag : loreTag.getValue()) {
if (!(subTag instanceof StringTag)) continue;
lore.add(new StringTag("", MessageTranslator.convertToJavaMessage(((StringTag) subTag).getValue())));
}
displayTag.put(new ListTag("Lore", lore));
}
}
ListTag enchantmentTag = tag.remove("ench");
if (enchantmentTag != null) {
List<Tag> enchantments = new ArrayList<>();
for (Tag value : enchantmentTag.getValue()) {
if (!(value instanceof CompoundTag tagValue))
continue;
ShortTag bedrockId = tagValue.get("id");
if (bedrockId == null) continue;
Enchantment enchantment = Enchantment.getByBedrockId(bedrockId.getValue());
if (enchantment != null) {
CompoundTag javaTag = new CompoundTag("");
Map<String, Tag> javaValue = javaTag.getValue();
javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier()));
ShortTag levelTag = tagValue.get("lvl");
javaValue.put("lvl", new IntTag("lvl", levelTag != null ? levelTag.getValue() : 1));
javaTag.setValue(javaValue);
enchantments.add(javaTag);
} else {
GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId);
}
}
if (!enchantments.isEmpty()) {
tag.put(new ListTag("Enchantments", enchantments));
}
}
}
protected final CompoundTag remapEnchantment(GeyserSession session, CompoundTag tag, CompoundTag rootTag) {
Tag javaEnchId = tag.get("id");
if (!(javaEnchId instanceof StringTag))
return null;
Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue());
if (enchantment == null) {
if (Identifier.formalize((String) javaEnchId.getValue()).equals("minecraft:sweeping")) {
Tag javaEnchLvl = tag.get("lvl");
int sweepingLvl = javaEnchLvl != null && javaEnchLvl.getValue() instanceof Number lvl ? lvl.intValue() : 0;
addSweeping(session, rootTag, sweepingLvl);
return null;
}
GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment while NBT item translating: " + javaEnchId.getValue());
return null;
}
Tag javaEnchLvl = tag.get("lvl");
CompoundTag bedrockTag = new CompoundTag("");
bedrockTag.put(new ShortTag("id", (short) enchantment.ordinal()));
// If the tag cannot parse, Java Edition 1.18.2 sets to 0
bedrockTag.put(new ShortTag("lvl", javaEnchLvl != null && javaEnchLvl.getValue() instanceof Number lvl ? lvl.shortValue() : (short) 0));
return bedrockTag;
}
private void addSweeping(GeyserSession session, CompoundTag itemTag, int level) {
CompoundTag displayTag = itemTag.get("display");
if (displayTag == null) {
displayTag = new CompoundTag("display");
itemTag.put(displayTag);
}
ListTag loreTag = displayTag.get("Lore");
if (loreTag == null) {
loreTag = new ListTag("Lore");
displayTag.put(loreTag);
}
String sweepingTranslation = MinecraftLocale.getLocaleString("enchantment.minecraft.sweeping", session.locale());
String lvlTranslation = MinecraftLocale.getLocaleString("enchantment.level." + level, session.locale());
loreTag.add(new StringTag("", ChatColor.RESET + ChatColor.GRAY + sweepingTranslation + " " + lvlTranslation));
}
/* Translation methods end */
public ItemStack newItemStack(int count, CompoundTag tag) {
return new ItemStack(this.javaId, count, tag);
}
public void setJavaId(int javaId) { // TODO like this?
if (this.javaId != -1) { // ID has already been set.
throw new RuntimeException();
if (this.javaId != -1) {
throw new RuntimeException("Item ID has already been set!");
}
this.javaId = javaId;
}
@ -129,7 +276,6 @@ public class Item {
private int stackSize = 64;
private String toolType;
private int maxDamage;
private boolean hasSuspiciousStewEffect;
public Builder stackSize(int stackSize) {
this.stackSize = stackSize;
@ -146,11 +292,6 @@ public class Item {
return this;
}
public Builder setHasSuspiciousStewEffect(boolean hasSuspiciousStewEffect) {
this.hasSuspiciousStewEffect = hasSuspiciousStewEffect;
return this;
}
private Builder() {
}
}

View File

@ -25,8 +25,37 @@
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.*;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
public class MapItem extends Item {
public MapItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateNbtToBedrock(GeyserSession session, CompoundTag tag, ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
Tag mapId = tag.remove("map");
if (mapId == null || !(mapId.getValue() instanceof Number number)) return;
int mapValue = number.intValue();
tag.put(new LongTag("map_uuid", mapValue));
tag.put(new IntTag("map_name_index", mapValue));
tag.put(new ByteTag("map_display_players", (byte) 1));
}
@Override
public void translateNbtToJava(CompoundTag tag, ItemMapping mapping) {
super.translateNbtToJava(tag, mapping);
IntTag mapNameIndex = tag.remove("map_name_index");
if (mapNameIndex != null) {
tag.put(new IntTag("map", mapNameIndex.getValue()));
tag.remove("map_uuid");
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,29 +23,31 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
@ItemRemapper
public class PlayerHeadTranslator extends NbtItemStackTranslator {
public class PlayerHeadItem extends Item {
public PlayerHeadItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
if (!itemTag.contains("display") || !((CompoundTag) itemTag.get("display")).contains("Name")) {
if (itemTag.contains("SkullOwner")) {
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
Tag display = tag.get("display");
if (!(display instanceof CompoundTag) || !((CompoundTag) display).contains("Name")) {
Tag skullOwner = tag.get("SkullOwner");
if (skullOwner != null) {
StringTag name;
Tag skullOwner = itemTag.get("SkullOwner");
if (skullOwner instanceof StringTag) {
name = (StringTag) skullOwner;
} else {
@ -53,23 +55,18 @@ public class PlayerHeadTranslator extends NbtItemStackTranslator {
if (skullOwner instanceof CompoundTag && (skullName = ((CompoundTag) skullOwner).get("Name")) != null) {
name = skullName;
} else {
session.getGeyser().getLogger().debug("Not sure how to handle skull head item display. " + itemTag);
session.getGeyser().getLogger().debug("Not sure how to handle skull head item display. " + tag);
return;
}
}
// Add correct name of player skull
// TODO: It's always yellow, even with a custom name. Handle?
String displayName = ChatColor.RESET + ChatColor.YELLOW + MinecraftLocale.getLocaleString("block.minecraft.player_head.named", session.locale()).replace("%s", name.getValue());
if (!itemTag.contains("display")) {
itemTag.put(new CompoundTag("display"));
if (!(display instanceof CompoundTag)) {
tag.put(display = new CompoundTag("display"));
}
((CompoundTag) itemTag.get("display")).put(new StringTag("Name", displayName));
((CompoundTag) display).put(new StringTag("Name", displayName));
}
}
}
@Override
public boolean acceptItem(Item item) {
return item == Items.PLAYER_HEAD;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,33 +23,39 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
import org.geysermc.geyser.translator.text.MessageTranslator;
import java.util.ArrayList;
import java.util.List;
@ItemRemapper
public class BookPagesTranslator extends NbtItemStackTranslator {
/**
* Encapsulates written books and writable books. Customly named class to share common code.
*/
public class ReadableBookItem extends Item {
public ReadableBookItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
if (!itemTag.contains("pages")) {
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
ListTag pagesTag = tag.remove("pages");
if (pagesTag == null) {
return;
}
List<Tag> pages = new ArrayList<>();
ListTag pagesTag = itemTag.get("pages");
for (Tag tag : pagesTag.getValue()) {
if (!(tag instanceof StringTag textTag))
for (Tag subTag : pagesTag.getValue()) {
if (!(subTag instanceof StringTag textTag))
continue;
CompoundTag pageTag = new CompoundTag("");
@ -58,25 +64,26 @@ public class BookPagesTranslator extends NbtItemStackTranslator {
pages.add(pageTag);
}
itemTag.remove("pages");
itemTag.put(new ListTag("pages", pages));
tag.put(new ListTag("pages", pages));
}
@Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
if (!itemTag.contains("pages")) {
public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToJava(tag, mapping);
if (!tag.contains("pages")) {
return;
}
List<Tag> pages = new ArrayList<>();
ListTag pagesTag = itemTag.get("pages");
for (Tag tag : pagesTag.getValue()) {
if (!(tag instanceof CompoundTag pageTag))
ListTag pagesTag = tag.get("pages");
for (Tag subTag : pagesTag.getValue()) {
if (!(subTag instanceof CompoundTag pageTag))
continue;
StringTag textTag = pageTag.get("text");
pages.add(new StringTag("", textTag.getValue()));
}
itemTag.remove("pages");
itemTag.put(new ListTag("pages", pages));
tag.remove("pages");
tag.put(new ListTag("pages", pages));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,26 +23,30 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item.type;
import com.github.steveice10.mc.protocol.data.game.Identifier;
import com.github.steveice10.opennbt.tag.builtin.*;
import org.geysermc.geyser.item.type.Item;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
import org.geysermc.geyser.util.MathUtils;
@ItemRemapper
public class ShulkerBoxItemTranslator extends NbtItemStackTranslator {
public class ShulkerBoxItem extends BlockItem {
public ShulkerBoxItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
if (!itemTag.contains("BlockEntityTag")) return; // Empty shulker box
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
CompoundTag blockEntityTag = itemTag.get("BlockEntityTag");
CompoundTag blockEntityTag = tag.get("BlockEntityTag");
if (blockEntityTag == null) {
// Empty shulker box
return;
}
if (blockEntityTag.get("Items") == null) return;
ListTag itemsList = new ListTag("Items");
for (Tag item : (ListTag) blockEntityTag.get("Items")) {
@ -72,21 +76,17 @@ public class ShulkerBoxItemTranslator extends NbtItemStackTranslator {
itemsList.add(boxItemTag);
}
itemTag.put(itemsList);
tag.put(itemsList);
// Don't actually bother with removing the block entity tag. Too risky to translate
// if the user is on creative and messing with a shulker box
//itemTag.remove("BlockEntityTag");
}
@Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
if (itemTag.contains("Items")) { // Remove any extraneous Bedrock tag and don't touch the Java one
itemTag.remove("Items");
}
}
public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToJava(tag, mapping);
@Override
public boolean acceptItem(Item item) {
return item.javaIdentifier().contains("shulker_box");
// Remove any extraneous Bedrock tag and don't touch the Java one
tag.remove("Items");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,43 +23,44 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.*;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextDecoration;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.entity.type.living.animal.TropicalFishEntity;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
import org.geysermc.geyser.translator.text.MessageTranslator;
import java.util.ArrayList;
import java.util.List;
@ItemRemapper
public class TropicalFishBucketTranslator extends NbtItemStackTranslator {
public class TropicalFishBucketItem extends Item {
private static final Style LORE_STYLE = Style.style(NamedTextColor.GRAY, TextDecoration.ITALIC);
public TropicalFishBucketItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
super.translateNbtToBedrock(session, tag, mapping);
// Prevent name from appearing as "Bucket of"
itemTag.put(new ByteTag("AppendCustomName", (byte) 1));
itemTag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.locale())));
tag.put(new ByteTag("AppendCustomName", (byte) 1));
tag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.locale())));
// Add Java's client side lore tag
Tag bucketVariantTag = itemTag.get("BucketVariantTag");
Tag bucketVariantTag = tag.get("BucketVariantTag");
if (bucketVariantTag instanceof IntTag) {
CompoundTag displayTag = itemTag.get("display");
CompoundTag displayTag = tag.get("display");
if (displayTag == null) {
displayTag = new CompoundTag("display");
itemTag.put(displayTag);
tag.put(displayTag);
}
List<Tag> lore = new ArrayList<>();
@ -90,9 +91,4 @@ public class TropicalFishBucketTranslator extends NbtItemStackTranslator {
displayTag.put(new ListTag("Lore", lore));
}
}
@Override
public boolean acceptItem(Item item) {
return item == Items.TROPICAL_FISH_BUCKET;
}
}

View File

@ -149,7 +149,6 @@ public class CustomItemRegistryPopulator {
.toolType(customItemData.toolType())
.toolTier(customItemData.toolTier())
.translationString(customItemData.translationString())
.hasSuspiciousStewEffect(false)
.customItemOptions(Collections.emptyList())
.javaItem(item)
.build();

View File

@ -138,7 +138,6 @@ public class ItemRegistryPopulator {
Object2ObjectMap<String, BlockDefinition> bedrockBlockIdOverrides = new Object2ObjectOpenHashMap<>();
Object2IntMap<String> blacklistedIdentifiers = new Object2IntOpenHashMap<>();
List<ItemDefinition> boats = new ObjectArrayList<>();
List<ItemDefinition> buckets = new ObjectArrayList<>();
List<ItemData> carpets = new ObjectArrayList<>();
@ -339,7 +338,6 @@ public class ItemRegistryPopulator {
.bedrockDefinition(definition)
.bedrockData(mappingItem.getBedrockData())
.bedrockBlockDefinition(bedrockBlock)
.hasSuspiciousStewEffect(mappingItem.isHasSuspiciousStewEffect())
.javaItem(javaItem);
if (mappingItem.getToolType() != null) {
@ -394,12 +392,9 @@ public class ItemRegistryPopulator {
ItemMapping mapping = mappingBuilder.build();
/*
if (javaIdentifier.contains("boat")) {
boats.add(definition);
} else if (javaIdentifier.contains("bucket") && !javaIdentifier.contains("milk")) {
if (javaItem.javaIdentifier().contains("bucket") && !javaItem.javaIdentifier().contains("milk")) {
buckets.add(definition);
} else if (javaIdentifier.contains("_carpet") && !javaIdentifier.contains("moss")) {
} else if (javaItem.javaIdentifier().contains("_carpet") && !javaItem.javaIdentifier().contains("moss")) {
// This should be the numerical order Java sends as an integer value for llamas
carpets.add(ItemData.builder()
.definition(definition)
@ -407,12 +402,11 @@ public class ItemRegistryPopulator {
.count(1)
.blockDefinition(mapping.getBedrockBlockDefinition())
.build());
} else if (javaIdentifier.startsWith("minecraft:music_disc_")) {
} else if (javaItem.javaIdentifier().startsWith("minecraft:music_disc_")) {
// The Java record level event uses the item ID as the "key" to play the record
Registries.RECORDS.register(javaItem.javaId(), SoundEvent.valueOf("RECORD_" +
javaIdentifier.replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH)));
javaItem.javaIdentifier().replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH)));
}
*/
mappings.add(mapping);
javaItemToMapping.put(javaItem, mapping);
@ -495,7 +489,6 @@ public class ItemRegistryPopulator {
.storedItems(new StoredItemMappings(javaItemToMapping))
.javaOnlyItems(javaOnlyItems)
.buckets(buckets)
.boats(boats)
.carpets(carpets)
.componentItemData(componentItemData)
.lodestoneCompass(lodestoneEntry)

View File

@ -28,8 +28,6 @@ package org.geysermc.geyser.registry.type;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* Represents Geyser's own serialized item information before being processed per-version
*/
@ -45,9 +43,6 @@ public class GeyserMappingItem {
@JsonProperty("armor_type") String armorType;
@JsonProperty("protection_value") int protectionValue;
@JsonProperty("max_damage") int maxDamage = 0;
@JsonProperty("repair_materials") List<String> repairMaterials;
@JsonProperty("has_suspicious_stew_effect") boolean hasSuspiciousStewEffect = false;
@JsonProperty("dye_color") int dyeColor = -1;
@JsonProperty("is_edible") boolean edible = false;
@JsonProperty("is_entity_placer") boolean entityPlacer = false;
}

View File

@ -52,7 +52,6 @@ public class ItemMapping {
null,
null,
Collections.emptyList(),
false,
Items.AIR
);
@ -74,8 +73,6 @@ public class ItemMapping {
@NonNull
List<Pair<CustomItemOptions, ItemDefinition>> customItemOptions;
boolean hasSuspiciousStewEffect;
@NonNull
Item javaItem;

View File

@ -46,9 +46,9 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.SlotType;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.item.type.BannerItem;
import org.geysermc.geyser.item.type.DyeItem;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator;
import java.util.Collections;
import java.util.List;
@ -158,7 +158,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
inputCopy.setNbt(new CompoundTag(""));
}
CompoundTag blockEntityTag = inputCopy.getNbt().get("BlockEntityTag");
CompoundTag javaBannerPattern = BannerTranslator.getJavaBannerPattern(pattern);
CompoundTag javaBannerPattern = BannerItem.getJavaBannerPattern(pattern);
if (blockEntityTag != null) {
ListTag patternsList = blockEntityTag.get("Patterns");

View File

@ -37,9 +37,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries;
@ -49,44 +47,16 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.FileUtils;
import javax.annotation.Nonnull;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public final class ItemTranslator {
private static final List<NbtItemStackTranslator> NBT_TRANSLATORS;
private ItemTranslator() {
}
public static void init() {
// no-op
}
static {
/* Load item translators */
Map<NbtItemStackTranslator, Integer> loadedNbtItemTranslators = new HashMap<>();
for (Class<?> clazz : FileUtils.getGeneratedClassesForAnnotation(ItemRemapper.class)) {
int priority = clazz.getAnnotation(ItemRemapper.class).priority();
GeyserImpl.getInstance().getLogger().debug("Found annotated item translator: " + clazz.getCanonicalName());
try {
if (NbtItemStackTranslator.class.isAssignableFrom(clazz)) {
NbtItemStackTranslator nbtItemTranslator = (NbtItemStackTranslator) clazz.getDeclaredConstructor().newInstance();
loadedNbtItemTranslators.put(nbtItemTranslator, priority);
}
} catch (InstantiationException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
GeyserImpl.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName());
}
}
NBT_TRANSLATORS = loadedNbtItemTranslators.keySet().stream().sorted(Comparator.comparingInt(loadedNbtItemTranslators::get)).collect(Collectors.toList());
}
/**
* @param mappings item mappings to use while translating. This can't just be a Geyser session as this method is used
* when loading recipes.
@ -102,11 +72,7 @@ public final class ItemTranslator {
ItemStack itemStack = javaItem.translateToJava(data, bedrockItem, mappings);
if (itemStack != null && itemStack.getNbt() != null) {
for (NbtItemStackTranslator translator : NBT_TRANSLATORS) {
if (translator.acceptItem(javaItem)) {
translator.translateToJava(itemStack.getNbt(), bedrockItem);
}
}
javaItem.translateNbtToJava(itemStack.getNbt(), bedrockItem);
if (itemStack.getNbt().isEmpty()) {
// Otherwise, seems to cause issues with villagers accepting books, and I don't see how this will break anything else. - Camotoy
itemStack = new ItemStack(itemStack.getId(), itemStack.getAmount(), null);
@ -145,18 +111,8 @@ public final class ItemTranslator {
private static ItemData.Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, CompoundTag tag) {
CompoundTag nbt = tag != null ? tag.clone() : null;
// This is a fallback for maps with no nbt
if (nbt == null && javaItem == Items.FILLED_MAP) {
nbt = new CompoundTag("");
nbt.put(new IntTag("map", 0));
}
if (nbt != null) {
for (NbtItemStackTranslator translator : NBT_TRANSLATORS) {
if (translator.acceptItem(javaItem)) {
translator.translateToBedrock(session, nbt, bedrockItem);
}
}
javaItem.translateNbtToBedrock(session, nbt, bedrockItem);
}
nbt = translateDisplayProperties(session, nbt, bedrockItem);

View File

@ -1,90 +0,0 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
import com.github.steveice10.opennbt.tag.builtin.*;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.ItemUtils;
import java.util.ArrayList;
import java.util.List;
@ItemRemapper(priority = -1)
public class BasicItemTranslator extends NbtItemStackTranslator {
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
Tag damage = itemTag.get("Damage");
if (damage instanceof IntTag) {
int originalDurability = ((IntTag) damage).getValue();
int durability = ItemUtils.getCorrectBedrockDurability(mapping.getJavaItem(), originalDurability);
if (durability != originalDurability) {
// Fix damage tag inconsistencies
itemTag.put(new IntTag("Damage", durability));
}
}
if (!(itemTag.get("display") instanceof CompoundTag displayTag)) {
return;
}
if (displayTag.get("Lore") instanceof ListTag listTag) {
List<Tag> lore = new ArrayList<>();
for (Tag tag : listTag.getValue()) {
if (!(tag instanceof StringTag)) continue;
lore.add(new StringTag("", MessageTranslator.convertMessageLenient(((StringTag) tag).getValue(), session.locale())));
}
displayTag.put(new ListTag("Lore", lore));
}
}
@Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
CompoundTag displayTag = itemTag.get("display");
if (displayTag == null) {
return;
}
if (displayTag.contains("Name")) {
StringTag nameTag = displayTag.get("Name");
displayTag.put(new StringTag("Name", MessageTranslator.convertToJavaMessage(nameTag.getValue())));
}
if (displayTag.contains("Lore")) {
ListTag loreTag = displayTag.get("Lore");
List<Tag> lore = new ArrayList<>();
for (Tag tag : loreTag.getValue()) {
if (!(tag instanceof StringTag)) continue;
lore.add(new StringTag("", MessageTranslator.convertToJavaMessage(((StringTag) tag).getValue())));
}
displayTag.put(new ListTag("Lore", lore));
}
}
}

View File

@ -1,168 +0,0 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
import com.github.steveice10.mc.protocol.data.game.Identifier;
import com.github.steveice10.opennbt.tag.builtin.*;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.item.Enchantment;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ItemRemapper
public class EnchantmentTranslator extends NbtItemStackTranslator {
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
List<Tag> newTags = new ArrayList<>();
Tag enchantmentTag = itemTag.remove("Enchantments");
if (enchantmentTag instanceof ListTag listTag) {
for (Tag tag : listTag.getValue()) {
if (!(tag instanceof CompoundTag)) continue;
CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) tag, itemTag);
if (bedrockTag != null) {
newTags.add(bedrockTag);
}
}
}
// TODO consolidate this into EnchantedBookTranslator
enchantmentTag = itemTag.remove("StoredEnchantments");
if (enchantmentTag instanceof ListTag listTag) {
for (Tag tag : listTag.getValue()) {
if (!(tag instanceof CompoundTag)) continue;
CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) tag, itemTag);
if (bedrockTag != null) {
newTags.add(bedrockTag);
}
}
}
if (!newTags.isEmpty()) {
itemTag.put(new ListTag("ench", newTags));
}
}
@Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
if (!itemTag.contains("ench")) {
return;
}
ListTag enchantmentTag = itemTag.get("ench");
List<Tag> enchantments = new ArrayList<>();
List<Tag> storedEnchantments = new ArrayList<>();
for (Tag value : enchantmentTag.getValue()) {
if (!(value instanceof CompoundTag tagValue))
continue;
ShortTag bedrockId = tagValue.get("id");
if (bedrockId == null) continue;
ShortTag geyserStoredEnchantmentTag = tagValue.get("GeyserStoredEnchantment");
Enchantment enchantment = Enchantment.getByBedrockId(bedrockId.getValue());
if (enchantment != null) {
CompoundTag javaTag = new CompoundTag("");
Map<String, Tag> javaValue = javaTag.getValue();
javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier()));
ShortTag levelTag = tagValue.get("lvl");
javaValue.put("lvl", new IntTag("lvl", levelTag != null ? levelTag.getValue() : 1));
javaTag.setValue(javaValue);
if (geyserStoredEnchantmentTag != null) {
tagValue.remove("GeyserStoredEnchantment");
storedEnchantments.add(javaTag);
} else {
enchantments.add(javaTag);
}
} else {
GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId);
}
}
if (!enchantments.isEmpty()) {
itemTag.put(new ListTag("Enchantments", enchantments));
}
if (!storedEnchantments.isEmpty()) {
itemTag.put(new ListTag("StoredEnchantments", storedEnchantments));
}
itemTag.remove("ench");
}
private CompoundTag remapEnchantment(GeyserSession session, CompoundTag tag, CompoundTag rootTag) {
Tag javaEnchId = tag.get("id");
if (!(javaEnchId instanceof StringTag))
return null;
Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue());
if (enchantment == null) {
if (Identifier.formalize((String) javaEnchId.getValue()).equals("minecraft:sweeping")) {
Tag javaEnchLvl = tag.get("lvl");
int sweepingLvl = javaEnchLvl != null && javaEnchLvl.getValue() instanceof Number lvl ? lvl.intValue() : 0;
addSweeping(session, rootTag, sweepingLvl);
return null;
}
GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment while NBT item translating: " + javaEnchId.getValue());
return null;
}
Tag javaEnchLvl = tag.get("lvl");
CompoundTag bedrockTag = new CompoundTag("");
bedrockTag.put(new ShortTag("id", (short) enchantment.ordinal()));
// If the tag cannot parse, Java Edition 1.18.2 sets to 0
bedrockTag.put(new ShortTag("lvl", javaEnchLvl != null && javaEnchLvl.getValue() instanceof Number lvl ? lvl.shortValue() : (short) 0));
return bedrockTag;
}
private void addSweeping(GeyserSession session, CompoundTag itemTag, int level) {
CompoundTag displayTag = itemTag.get("display");
if (displayTag == null) {
displayTag = new CompoundTag("display");
itemTag.put(displayTag);
}
ListTag loreTag = displayTag.get("Lore");
if (loreTag == null) {
loreTag = new ListTag("Lore");
displayTag.put(loreTag);
}
String sweepingTranslation = MinecraftLocale.getLocaleString("enchantment.minecraft.sweeping", session.locale());
String lvlTranslation = MinecraftLocale.getLocaleString("enchantment.level." + level, session.locale());
loreTag.add(new StringTag("", ChatColor.RESET + ChatColor.GRAY + sweepingTranslation + " " + lvlTranslation));
}
}

View File

@ -1,94 +0,0 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.util.MathUtils;
@ItemRemapper
public class FireworkRocketTranslator extends FireworkBaseTranslator {
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
CompoundTag fireworks = itemTag.get("Fireworks");
if (fireworks == null) {
return;
}
if (fireworks.get("Flight") != null) {
fireworks.put(new ByteTag("Flight", MathUtils.getNbtByte(fireworks.get("Flight").getValue())));
}
ListTag explosions = fireworks.get("Explosions");
if (explosions == null) {
return;
}
for (Tag effect : explosions.getValue()) {
CompoundTag effectData = (CompoundTag) effect;
CompoundTag newEffectData = translateExplosionToBedrock(effectData, "");
explosions.remove(effectData);
explosions.add(newEffectData);
}
}
@Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
CompoundTag fireworks = itemTag.get("Fireworks");
if (fireworks == null) {
return;
}
if (fireworks.contains("Flight")) {
fireworks.put(new ByteTag("Flight", MathUtils.getNbtByte(fireworks.get("Flight").getValue())));
}
ListTag explosions = fireworks.get("Explosions");
if (explosions == null) {
return;
}
for (Tag effect : explosions.getValue()) {
CompoundTag effectData = (CompoundTag) effect;
CompoundTag newEffectData = translateExplosionToJava(effectData, "");
explosions.remove(effect);
explosions.add(newEffectData);
}
}
@Override
public boolean acceptItem(Item item) {
return item == Items.FIREWORK_ROCKET;
}
}

View File

@ -1,73 +0,0 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.inventory.item.nbt;
import com.github.steveice10.opennbt.tag.builtin.*;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
@ItemRemapper
public class MapItemTranslator extends NbtItemStackTranslator {
@Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
// Can be either an IntTag or ShortTag
Tag mapId = itemTag.get("map");
if (mapId == null) return;
int mapValue;
if (mapId.getValue() instanceof Short) {
// Convert to int if necessary
mapValue = (int) (short) mapId.getValue();
} else {
mapValue = (int) mapId.getValue();
}
itemTag.put(new LongTag("map_uuid", mapValue));
itemTag.put(new IntTag("map_name_index", mapValue));
itemTag.put(new ByteTag("map_display_players", (byte) 1));
itemTag.remove("map");
}
@Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
IntTag tag = itemTag.get("map_name_index");
if (tag != null) {
itemTag.put(new IntTag("map", tag.getValue()));
itemTag.remove("map_name_index");
itemTag.remove("map_uuid");
}
}
@Override
public boolean acceptItem(Item item) {
return item == Items.FILLED_MAP;
}
}

View File

@ -30,8 +30,8 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.item.type.BannerItem;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator;
@BlockEntity(type = BlockEntityType.BANNER)
public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@ -47,12 +47,12 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement
}
if (tag.get("Patterns") instanceof ListTag patterns) {
if (patterns.equals(BannerTranslator.OMINOUS_BANNER_PATTERN)) {
if (patterns.equals(BannerItem.OMINOUS_BANNER_PATTERN)) {
// This is an ominous banner; don't try to translate the raw patterns (it doesn't translate correctly)
// and tell the Bedrock client that this is an ominous banner
builder.putInt("Type", 1);
} else {
builder.put("Patterns", BannerTranslator.convertBannerPattern(patterns));
builder.put("Patterns", BannerItem.convertBannerPattern(patterns));
}
}

View File

@ -57,10 +57,12 @@ import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.click.Click;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.BlockItem;
import org.geysermc.geyser.item.type.BoatItem;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.item.type.SpawnEggItem;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.registry.BlockRegistries;
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.inventory.InventoryTranslator;
@ -274,15 +276,14 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(blockPacket);
Item item = session.getPlayerInventory().getItemInHand().asItem();
if (packet.getItemInHand() != null) {
ItemDefinition definition = packet.getItemInHand().getDefinition();
int blockState = session.getGeyser().getWorldManager().getBlockAt(session, packet.getBlockPosition());
// Otherwise boats will not be able to be placed in survival and buckets, lily pads, frogspawn, and glass bottles won't work on mobile
if (session.getItemMappings().getBoats().contains(definition) ||
definition == session.getItemMappings().getStoredItems().lilyPad().getBedrockDefinition() ||
definition == session.getItemMappings().getStoredItems().frogspawn().getBedrockDefinition()) {
if (item instanceof BoatItem || item == Items.LILY_PAD || item == Items.FROGSPAWN) {
useItem(session, packet, blockState);
} else if (definition == session.getItemMappings().getStoredItems().glassBottle().getBedrockDefinition()) {
} else if (item == Items.GLASS_BOTTLE) {
if (!session.isSneaking() && BlockStateValues.isCauldron(blockState) && !BlockStateValues.isNonWaterCauldron(blockState)) {
// ServerboundUseItemPacket is not sent for water cauldrons and glass bottles
return;
@ -315,10 +316,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
}
}
}
ItemMapping handItem = session.getPlayerInventory().getItemInHand().getMapping(session);
if (handItem.isBlock()) {
if (item instanceof BlockItem) {
session.setLastBlockPlacePosition(blockPos);
session.setLastBlockPlacedId(handItem.getJavaItem().javaIdentifier());
session.setLastBlockPlacedId(item.javaIdentifier());
}
session.setInteracting(true);
}
@ -526,9 +526,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
Inventory playerInventory = session.getPlayerInventory();
int heldItemSlot = playerInventory.getOffsetForHotbar(packet.getHotbarSlot());
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, playerInventory, heldItemSlot);
if (playerInventory.getItem(heldItemSlot).getAmount() > 1) {
if (packet.getItemInHand().getDefinition() == session.getItemMappings().getStoredItems().bucket().getBedrockDefinition() ||
packet.getItemInHand().getDefinition() == session.getItemMappings().getStoredItems().glassBottle().getBedrockDefinition()) {
GeyserItemStack itemStack = playerInventory.getItem(heldItemSlot);
if (itemStack.getAmount() > 1) {
if (itemStack.asItem() == Items.BUCKET || itemStack.asItem() == Items.GLASS_BOTTLE) {
// Using a stack of buckets or glass bottles will result in an item being added to the first empty slot.
// We need to revert the item in case the interaction fails. The order goes from left to right in the
// hotbar. Then left to right and top to bottom in the inventory.

View File

@ -38,7 +38,6 @@ import org.geysermc.geyser.entity.type.living.ArmorStandEntity;
import org.geysermc.geyser.entity.type.living.animal.AnimalEntity;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import java.util.Locale;
@ -217,7 +216,7 @@ public final class EntityUtils {
/**
* Determine if an action would result in a successful bucketing of the given entity.
*/
public static boolean attemptToBucket(GeyserSession session, GeyserItemStack itemInHand) {
public static boolean attemptToBucket(GeyserItemStack itemInHand) {
return itemInHand.asItem() == Items.WATER_BUCKET;
}

View File

@ -30,6 +30,7 @@ import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.FishingRodItem;
import org.geysermc.geyser.item.type.Item;
import javax.annotation.Nullable;
@ -64,7 +65,7 @@ public class ItemUtils {
// Java durability: 64
// Bedrock durability : 384
// 384 / 64 = 6
return original * 6;
return FishingRodItem.getBedrockDamage(original);
}
return original;
}