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.BlockEntityProcessor
org.geysermc.geyser.processor.CollisionRemapperProcessor org.geysermc.geyser.processor.CollisionRemapperProcessor
org.geysermc.geyser.processor.ItemRemapperProcessor
org.geysermc.geyser.processor.PacketTranslatorProcessor org.geysermc.geyser.processor.PacketTranslatorProcessor
org.geysermc.geyser.processor.SoundHandlerProcessor org.geysermc.geyser.processor.SoundHandlerProcessor

View File

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

View File

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

View File

@ -77,7 +77,7 @@ public class AxolotlEntity extends AnimalEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (EntityUtils.attemptToBucket(session, itemInHand)) { if (EntityUtils.attemptToBucket(itemInHand)) {
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} else { } else {
return super.mobInteract(hand, itemInHand); 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.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.FlowerItem;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.geyser.util.InteractiveTag;
@ -76,7 +77,7 @@ public class MooshroomEntity extends AnimalEntity {
} else if (!isBaby && isAlive() && itemInHand.asItem() == Items.SHEARS) { } else if (!isBaby && isAlive() && itemInHand.asItem() == Items.SHEARS) {
// Shear items // Shear items
return InteractionResult.SUCCESS; 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; 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.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import lombok.AccessLevel;
import lombok.Getter;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import lombok.Data; import lombok.Data;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
@ -107,6 +109,7 @@ public class GeyserItemStack {
return session.getItemMappings().getMapping(this.javaId); return session.getItemMappings().getMapping(this.javaId);
} }
@Getter(AccessLevel.NONE)
private Item item; //TODO private Item item; //TODO
public Item asItem() { public Item asItem() {

View File

@ -43,34 +43,26 @@ public class StoredItemMappings {
private final ItemMapping bamboo; private final ItemMapping bamboo;
private final ItemMapping banner; private final ItemMapping banner;
private final ItemMapping barrier; private final ItemMapping barrier;
private final ItemMapping bucket;
private final ItemMapping compass; private final ItemMapping compass;
private final ItemMapping crossbow; private final ItemMapping crossbow;
private final ItemMapping frogspawn;
private final ItemMapping glassBottle; private final ItemMapping glassBottle;
private final ItemMapping lilyPad;
private final ItemMapping milkBucket; private final ItemMapping milkBucket;
private final ItemMapping powderSnowBucket; private final ItemMapping powderSnowBucket;
private final ItemMapping egg; private final ItemMapping egg;
private final ItemMapping shield; private final ItemMapping shield;
private final ItemMapping waterBucket;
private final ItemMapping wheat; private final ItemMapping wheat;
public StoredItemMappings(Map<Item, ItemMapping> itemMappings) { public StoredItemMappings(Map<Item, ItemMapping> itemMappings) {
this.bamboo = load(itemMappings, Items.BAMBOO); 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.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.barrier = load(itemMappings, Items.BARRIER);
this.bucket = load(itemMappings, Items.BUCKET);
this.compass = load(itemMappings, Items.COMPASS); this.compass = load(itemMappings, Items.COMPASS);
this.crossbow = load(itemMappings, Items.CROSSBOW); this.crossbow = load(itemMappings, Items.CROSSBOW);
this.frogspawn = load(itemMappings, Items.FROGSPAWN);
this.glassBottle = load(itemMappings, Items.GLASS_BOTTLE); this.glassBottle = load(itemMappings, Items.GLASS_BOTTLE);
this.lilyPad = load(itemMappings, Items.LILY_PAD);
this.milkBucket = load(itemMappings, Items.MILK_BUCKET); this.milkBucket = load(itemMappings, Items.MILK_BUCKET);
this.powderSnowBucket = load(itemMappings, Items.POWDER_SNOW_BUCKET); this.powderSnowBucket = load(itemMappings, Items.POWDER_SNOW_BUCKET);
this.egg = load(itemMappings, Items.EGG); this.egg = load(itemMappings, Items.EGG);
this.shield = load(itemMappings, Items.SHIELD); this.shield = load(itemMappings, Items.SHIELD);
this.waterBucket = load(itemMappings, Items.WATER_BUCKET);
this.wheat = load(itemMappings, Items.WHEAT); 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 org.geysermc.geyser.item.type.Item;
import java.util.function.Supplier;
public enum ArmorMaterial { public enum ArmorMaterial {
LEATHER(Items.LEATHER), LEATHER(() -> Items.LEATHER),
CHAIN(Items.IRON_INGOT), CHAIN(() -> Items.IRON_INGOT),
IRON(Items.IRON_INGOT), IRON(() -> Items.IRON_INGOT),
GOLD(Items.GOLD_INGOT), GOLD(() -> Items.GOLD_INGOT),
DIAMOND(Items.DIAMOND), DIAMOND(() -> Items.DIAMOND),
TURTLE(Items.SCUTE), TURTLE(() -> Items.SCUTE),
NETHERITE(Items.NETHERITE_INGOT); NETHERITE(() -> Items.NETHERITE_INGOT);
private final Item repairIngredient; private final Supplier<Item> repairIngredient;
ArmorMaterial(Item repairIngredient) { ArmorMaterial(Supplier<Item> repairIngredient) {
this.repairIngredient = repairIngredient; this.repairIngredient = repairIngredient;
} }
public Item getRepairIngredient() { 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,53 +23,34 @@
* @link https://github.com/GeyserMC/Geyser * @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.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag; 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 static void translateNbtToBedrock(CompoundTag tag) {
public class LeatherArmorTranslator extends NbtItemStackTranslator { CompoundTag displayTag = tag.get("display");
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");
if (displayTag == null) { if (displayTag == null) {
return; return;
} }
IntTag color = displayTag.remove("color"); IntTag color = displayTag.remove("color");
if (color != null) { if (color != null) {
itemTag.put(new IntTag("customColor", color.getValue())); tag.put(new IntTag("customColor", color.getValue()));
} }
} }
@Override static void translateNbtToJava(CompoundTag tag) {
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { IntTag color = tag.get("customColor");
IntTag color = itemTag.get("customColor");
if (color == null) { if (color == null) {
return; return;
} }
CompoundTag displayTag = itemTag.get("display"); CompoundTag displayTag = tag.get("display");
if (displayTag == null) { if (displayTag == null) {
displayTag = new CompoundTag("display"); displayTag = new CompoundTag("display");
} }
displayTag.put(color); displayTag.put(color);
itemTag.remove("customColor"); tag.remove("customColor");
}
@Override
public boolean acceptItem(Item item) {
return ITEMS.contains(item);
} }
} }

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

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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,30 +23,26 @@
* @link https://github.com/GeyserMC/Geyser * @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.NbtList;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType; 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.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper; import org.jetbrains.annotations.NotNull;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.geysermc.erosion.util.BannerUtils.getJavaPatternTag; import static org.geysermc.erosion.util.BannerUtils.getJavaPatternTag;
@ItemRemapper public class BannerItem extends BlockItem {
public class BannerTranslator extends NbtItemStackTranslator {
/** /**
* Holds what a Java ominous banner pattern looks like. * 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; public static final ListTag OMINOUS_BANNER_PATTERN;
private final List<Item> appliedItems;
static { static {
OMINOUS_BANNER_PATTERN = new ListTag("Patterns"); OMINOUS_BANNER_PATTERN = new ListTag("Patterns");
// Construct what an ominous banner is supposed to look like // 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)); 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 * 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 @Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToBedrock(@NotNull GeyserSession session, @NotNull CompoundTag tag, @NotNull ItemMapping mapping) {
CompoundTag blockEntityTag = itemTag.get("BlockEntityTag"); super.translateNbtToBedrock(session, tag, mapping);
CompoundTag blockEntityTag = tag.remove("BlockEntityTag");
if (blockEntityTag != null && blockEntityTag.get("Patterns") instanceof ListTag patterns) { if (blockEntityTag != null && blockEntityTag.get("Patterns") instanceof ListTag patterns) {
if (patterns.equals(OMINOUS_BANNER_PATTERN)) { if (patterns.equals(OMINOUS_BANNER_PATTERN)) {
// Remove the current patterns and set the ominous banner type // Remove the current patterns and set the ominous banner type
itemTag.put(new IntTag("Type", 1)); tag.put(new IntTag("Type", 1));
} else { } else {
invertBannerColors(patterns); invertBannerColors(patterns);
itemTag.put(patterns); tag.put(patterns);
} }
itemTag.remove("BlockEntityTag");
} }
} }
@Override @Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToJava(@NotNull CompoundTag tag, @NotNull ItemMapping mapping) {
if (itemTag.get("Type") instanceof IntTag type && type.getValue() == 1) { super.translateNbtToJava(tag, mapping);
if (tag.get("Type") instanceof IntTag type && type.getValue() == 1) {
// Ominous banner pattern // Ominous banner pattern
itemTag.remove("Type"); tag.remove("Type");
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
blockEntityTag.put(OMINOUS_BANNER_PATTERN); blockEntityTag.put(OMINOUS_BANNER_PATTERN);
itemTag.put(blockEntityTag); tag.put(blockEntityTag);
} else if (itemTag.get("Patterns") instanceof ListTag patterns) { } else if (tag.get("Patterns") instanceof ListTag patterns) {
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
invertBannerColors(patterns); invertBannerColors(patterns);
blockEntityTag.put(patterns); blockEntityTag.put(patterns);
itemTag.put(blockEntityTag); tag.put(blockEntityTag);
itemTag.remove("Patterns"); // Remove the old Bedrock patterns list 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,12 +23,10 @@
* @link https://github.com/GeyserMC/Geyser * @link https://github.com/GeyserMC/Geyser
*/ */
package org.geysermc.geyser.translator.inventory.item; package org.geysermc.geyser.item.type;
import java.lang.annotation.Retention; public class BoatItem extends Item {
import java.lang.annotation.RetentionPolicy; public BoatItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
@Retention(value = RetentionPolicy.RUNTIME) }
public @interface ItemRemapper {
int priority() default 0;
} }

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.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.ByteTag; import com.github.steveice10.opennbt.tag.builtin.ByteTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; 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 com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.session.GeyserSession;
public class CompassItem extends Item { public class CompassItem extends Item {
public CompassItem(String javaIdentifier, Builder builder) { public CompassItem(String javaIdentifier, Builder builder) {
@ -41,7 +43,6 @@ public class CompassItem extends Item {
@Override @Override
public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
if (isLodestoneCompass(itemStack.getNbt())) { if (isLodestoneCompass(itemStack.getNbt())) {
// NBT will be translated in nbt/LodestoneCompassTranslator if applicable
return super.translateToBedrock(itemStack, mappings.getLodestoneCompass(), mappings); return super.translateToBedrock(itemStack, mappings.getLodestoneCompass(), mappings);
} }
return super.translateToBedrock(itemStack, mapping, mappings); return super.translateToBedrock(itemStack, mapping, mappings);
@ -55,6 +56,18 @@ public class CompassItem extends Item {
return super.toBedrockDefinition(nbt, mappings); 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) { private boolean isLodestoneCompass(CompoundTag nbt) {
if (nbt != null) { if (nbt != null) {
Tag lodestoneTag = nbt.get("LodestoneTracked"); 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,33 +23,34 @@
* @link https://github.com/GeyserMC/Geyser * @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.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.*; import com.github.steveice10.opennbt.tag.builtin.*;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; 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.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; 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.ItemTranslator;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
@ItemRemapper public class CrossbowItem extends Item {
public class CrossbowTranslator extends NbtItemStackTranslator { public CrossbowItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override @Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
ListTag chargedProjectiles = itemTag.get("ChargedProjectiles"); super.translateNbtToBedrock(session, tag, mapping);
ListTag chargedProjectiles = tag.get("ChargedProjectiles");
if (chargedProjectiles != null) { if (chargedProjectiles != null) {
if (!chargedProjectiles.getValue().isEmpty()) { if (!chargedProjectiles.getValue().isEmpty()) {
CompoundTag projectile = (CompoundTag) chargedProjectiles.getValue().get(0); CompoundTag projectile = (CompoundTag) chargedProjectiles.getValue().get(0);
ItemMapping projectileMapping = session.getItemMappings().getMapping((String) projectile.get("id").getValue()); ItemMapping projectileMapping = session.getItemMappings().getMapping((String) projectile.get("id").getValue());
if (projectileMapping == null) return; if (projectileMapping == null) return;
CompoundTag tag = projectile.get("tag"); CompoundTag projectileTag = projectile.get("tag");
ItemStack itemStack = new ItemStack(mapping.getJavaItem().javaId(), (byte) projectile.get("Count").getValue(), tag); ItemStack itemStack = new ItemStack(mapping.getJavaItem().javaId(), (byte) projectile.get("Count").getValue(), projectileTag);
ItemData itemData = ItemTranslator.translateToBedrock(session, itemStack); ItemData itemData = ItemTranslator.translateToBedrock(session, itemStack);
CompoundTag newProjectile = new CompoundTag("chargedItem"); CompoundTag newProjectile = new CompoundTag("chargedItem");
@ -58,15 +59,17 @@ public class CrossbowTranslator extends NbtItemStackTranslator {
newProjectile.put(new ShortTag("Damage", (short) itemData.getDamage())); newProjectile.put(new ShortTag("Damage", (short) itemData.getDamage()));
itemTag.put(newProjectile); projectileTag.put(newProjectile);
} }
} }
} }
@Override @Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
if (itemTag.get("chargedItem") != null) { super.translateNbtToJava(tag, mapping);
CompoundTag chargedItem = itemTag.get("chargedItem");
if (tag.get("chargedItem") != null) {
CompoundTag chargedItem = tag.get("chargedItem");
CompoundTag newProjectile = new CompoundTag(""); CompoundTag newProjectile = new CompoundTag("");
newProjectile.put(new ByteTag("Count", (byte) chargedItem.get("Count").getValue())); newProjectile.put(new ByteTag("Count", (byte) chargedItem.get("Count").getValue()));
@ -75,12 +78,7 @@ public class CrossbowTranslator extends NbtItemStackTranslator {
ListTag chargedProjectiles = new ListTag("ChargedProjectiles"); ListTag chargedProjectiles = new ListTag("ChargedProjectiles");
chargedProjectiles.add(newProjectile); 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,49 +23,40 @@
* @link https://github.com/GeyserMC/Geyser * @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.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag; 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.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; 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) import java.util.ArrayList;
public class EnchantedBookTranslator extends NbtItemStackTranslator { import java.util.List;
@Override public class EnchantedBookItem extends Item {
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { public EnchantedBookItem(String javaIdentifier, Builder builder) {
if (!itemTag.contains("StoredEnchantments")) { super(javaIdentifier, builder);
return;
}
Tag enchTag = itemTag.get("StoredEnchantments");
if (enchTag instanceof ListTag) {
enchTag = new ListTag("Enchantments", ((ListTag) enchTag).getValue());
itemTag.remove("StoredEnchantments");
itemTag.put(enchTag);
}
} }
@Override @Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToBedrock(GeyserSession session, CompoundTag tag, ItemMapping mapping) {
if (!itemTag.contains("Enchantments")) { super.translateNbtToBedrock(session, tag, mapping);
return;
}
Tag enchTag = itemTag.get("Enchantments");
if (enchTag instanceof ListTag) {
enchTag = new ListTag("StoredEnchantments", ((ListTag) enchTag).getValue());
itemTag.remove("Enchantments");
itemTag.put(enchTag);
}
}
@Override List<Tag> newTags = new ArrayList<>();
public boolean acceptItem(Item item) { Tag enchantmentTag = tag.remove("StoredEnchantments");
return item == Items.ENCHANTED_BOOK; 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.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.Tag; import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings; 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) { public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
ItemData.Builder builder = super.translateToBedrock(itemStack, mapping, mappings); ItemData.Builder builder = super.translateToBedrock(itemStack, mapping, mappings);
CompoundTag nbt = itemStack.getNbt(); 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 ??? // Note: damage 5 treasure map, 6 ???
Tag mapColor = display.get("MapColor"); Tag mapColor = display.get("MapColor");
if (mapColor != null && mapColor.getValue() instanceof Number color) { 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,22 +23,52 @@
* @link https://github.com/GeyserMC/Geyser * @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.*;
import com.github.steveice10.opennbt.tag.builtin.ByteTag; import org.checkerframework.checker.nullness.qual.NonNull;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
import org.geysermc.geyser.level.FireworkColor; 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; import org.geysermc.geyser.util.MathUtils;
/** public class FireworkRocketItem extends Item {
* Stores common code for firework rockets and firework stars. public FireworkRocketItem(String javaIdentifier, Builder builder) {
*/ super(javaIdentifier, builder);
public abstract class FireworkBaseTranslator extends NbtItemStackTranslator { }
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); CompoundTag newExplosionData = new CompoundTag(newName);
if (explosion.get("Type") != null) { if (explosion.get("Type") != null) {
@ -80,7 +110,7 @@ public abstract class FireworkBaseTranslator extends NbtItemStackTranslator {
return newExplosionData; return newExplosionData;
} }
protected CompoundTag translateExplosionToJava(CompoundTag explosion, String newName) { static CompoundTag translateExplosionToJava(CompoundTag explosion, String newName) {
CompoundTag newExplosionData = new CompoundTag(newName); CompoundTag newExplosionData = new CompoundTag(newName);
if (explosion.get("FireworkType") != null) { 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,28 +23,29 @@
* @link https://github.com/GeyserMC/Geyser * @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.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.Tag; import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.geysermc.geyser.item.Items; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
@ItemRemapper public class FireworkStarItem extends Item {
public class FireworkStarTranslator extends FireworkBaseTranslator { public FireworkStarItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override @Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
Tag explosion = itemTag.get("Explosion"); super.translateNbtToBedrock(session, tag, mapping);
Tag explosion = tag.remove("Explosion");
if (explosion instanceof CompoundTag) { if (explosion instanceof CompoundTag) {
CompoundTag newExplosion = translateExplosionToBedrock((CompoundTag) explosion, "FireworksItem"); CompoundTag newExplosion = FireworkRocketItem.translateExplosionToBedrock((CompoundTag) explosion, "FireworksItem");
itemTag.remove("Explosion"); tag.put(newExplosion);
itemTag.put(newExplosion);
Tag color = ((CompoundTag) explosion).get("Colors"); Tag color = ((CompoundTag) explosion).get("Colors");
if (color instanceof IntArrayTag) { if (color instanceof IntArrayTag) {
// Determine the custom color, if any. // Determine the custom color, if any.
@ -74,25 +75,21 @@ public class FireworkStarTranslator extends FireworkBaseTranslator {
finalColor = r << 16 | g << 8 | b; finalColor = r << 16 | g << 8 | b;
} }
itemTag.put(new IntTag("customColor", finalColor)); tag.put(new IntTag("customColor", finalColor));
} }
} }
} }
@Override @Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
Tag explosion = itemTag.get("FireworksItem"); super.translateNbtToJava(tag, mapping);
Tag explosion = tag.remove("FireworksItem");
if (explosion instanceof CompoundTag) { if (explosion instanceof CompoundTag) {
CompoundTag newExplosion = translateExplosionToJava((CompoundTag) explosion, "Explosion"); CompoundTag newExplosion = FireworkRocketItem.translateExplosionToJava((CompoundTag) explosion, "Explosion");
itemTag.remove("FireworksItem"); tag.put(newExplosion);
itemTag.put(newExplosion);
} }
// Remove custom color, if any, since this only exists on Bedrock // Remove custom color, if any, since this only exists on Bedrock
itemTag.remove("customColor"); tag.remove("customColor");
}
@Override
public boolean acceptItem(Item item) {
return item == Items.FIREWORK_STAR;
} }
} }

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

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

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.Identifier;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; 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.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.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings; 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.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 { public class Item {
private final String javaIdentifier; private final String javaIdentifier;
@ -39,14 +50,12 @@ public class Item {
private final int stackSize; private final int stackSize;
private final String toolType; private final String toolType;
private final int maxDamage; private final int maxDamage;
private final boolean hasSuspiciousStewEffect;
public Item(String javaIdentifier, Builder builder) { public Item(String javaIdentifier, Builder builder) {
this.javaIdentifier = Identifier.formalize(javaIdentifier).intern(); this.javaIdentifier = Identifier.formalize(javaIdentifier).intern();
this.stackSize = builder.stackSize; this.stackSize = builder.stackSize;
this.toolType = builder.toolType; this.toolType = builder.toolType;
this.maxDamage = builder.maxDamage; this.maxDamage = builder.maxDamage;
this.hasSuspiciousStewEffect = builder.hasSuspiciousStewEffect;
} }
public String javaIdentifier() { public String javaIdentifier() {
@ -102,13 +111,151 @@ public class Item {
return mappings.getMapping(javaId); 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) { public ItemStack newItemStack(int count, CompoundTag tag) {
return new ItemStack(this.javaId, count, tag); return new ItemStack(this.javaId, count, tag);
} }
public void setJavaId(int javaId) { // TODO like this? public void setJavaId(int javaId) { // TODO like this?
if (this.javaId != -1) { // ID has already been set. if (this.javaId != -1) {
throw new RuntimeException(); throw new RuntimeException("Item ID has already been set!");
} }
this.javaId = javaId; this.javaId = javaId;
} }
@ -129,7 +276,6 @@ public class Item {
private int stackSize = 64; private int stackSize = 64;
private String toolType; private String toolType;
private int maxDamage; private int maxDamage;
private boolean hasSuspiciousStewEffect;
public Builder stackSize(int stackSize) { public Builder stackSize(int stackSize) {
this.stackSize = stackSize; this.stackSize = stackSize;
@ -146,11 +292,6 @@ public class Item {
return this; return this;
} }
public Builder setHasSuspiciousStewEffect(boolean hasSuspiciousStewEffect) {
this.hasSuspiciousStewEffect = hasSuspiciousStewEffect;
return this;
}
private Builder() { private Builder() {
} }
} }

View File

@ -25,8 +25,37 @@
package org.geysermc.geyser.item.type; 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 class MapItem extends Item {
public MapItem(String javaIdentifier, Builder builder) { public MapItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,29 +23,31 @@
* @link https://github.com/GeyserMC/Geyser * @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.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag; import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.geysermc.geyser.item.Items; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.MinecraftLocale; 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 PlayerHeadItem extends Item {
public class PlayerHeadTranslator extends NbtItemStackTranslator { public PlayerHeadItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override @Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
if (!itemTag.contains("display") || !((CompoundTag) itemTag.get("display")).contains("Name")) { super.translateNbtToBedrock(session, tag, mapping);
if (itemTag.contains("SkullOwner")) {
Tag display = tag.get("display");
if (!(display instanceof CompoundTag) || !((CompoundTag) display).contains("Name")) {
Tag skullOwner = tag.get("SkullOwner");
if (skullOwner != null) {
StringTag name; StringTag name;
Tag skullOwner = itemTag.get("SkullOwner");
if (skullOwner instanceof StringTag) { if (skullOwner instanceof StringTag) {
name = (StringTag) skullOwner; name = (StringTag) skullOwner;
} else { } else {
@ -53,23 +55,18 @@ public class PlayerHeadTranslator extends NbtItemStackTranslator {
if (skullOwner instanceof CompoundTag && (skullName = ((CompoundTag) skullOwner).get("Name")) != null) { if (skullOwner instanceof CompoundTag && (skullName = ((CompoundTag) skullOwner).get("Name")) != null) {
name = skullName; name = skullName;
} else { } 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; return;
} }
} }
// Add correct name of player skull // Add correct name of player skull
// TODO: It's always yellow, even with a custom name. Handle? // 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()); String displayName = ChatColor.RESET + ChatColor.YELLOW + MinecraftLocale.getLocaleString("block.minecraft.player_head.named", session.locale()).replace("%s", name.getValue());
if (!itemTag.contains("display")) { if (!(display instanceof CompoundTag)) {
itemTag.put(new CompoundTag("display")); 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,33 +23,39 @@
* @link https://github.com/GeyserMC/Geyser * @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.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag; 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.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; 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.translator.text.MessageTranslator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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 @Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
if (!itemTag.contains("pages")) { super.translateNbtToBedrock(session, tag, mapping);
ListTag pagesTag = tag.remove("pages");
if (pagesTag == null) {
return; return;
} }
List<Tag> pages = new ArrayList<>(); List<Tag> pages = new ArrayList<>();
ListTag pagesTag = itemTag.get("pages"); for (Tag subTag : pagesTag.getValue()) {
for (Tag tag : pagesTag.getValue()) { if (!(subTag instanceof StringTag textTag))
if (!(tag instanceof StringTag textTag))
continue; continue;
CompoundTag pageTag = new CompoundTag(""); CompoundTag pageTag = new CompoundTag("");
@ -58,25 +64,26 @@ public class BookPagesTranslator extends NbtItemStackTranslator {
pages.add(pageTag); pages.add(pageTag);
} }
itemTag.remove("pages"); tag.put(new ListTag("pages", pages));
itemTag.put(new ListTag("pages", pages));
} }
@Override @Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
if (!itemTag.contains("pages")) { super.translateNbtToJava(tag, mapping);
if (!tag.contains("pages")) {
return; return;
} }
List<Tag> pages = new ArrayList<>(); List<Tag> pages = new ArrayList<>();
ListTag pagesTag = itemTag.get("pages"); ListTag pagesTag = tag.get("pages");
for (Tag tag : pagesTag.getValue()) { for (Tag subTag : pagesTag.getValue()) {
if (!(tag instanceof CompoundTag pageTag)) if (!(subTag instanceof CompoundTag pageTag))
continue; continue;
StringTag textTag = pageTag.get("text"); StringTag textTag = pageTag.get("text");
pages.add(new StringTag("", textTag.getValue())); pages.add(new StringTag("", textTag.getValue()));
} }
itemTag.remove("pages"); tag.remove("pages");
itemTag.put(new ListTag("pages", 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,26 +23,30 @@
* @link https://github.com/GeyserMC/Geyser * @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.mc.protocol.data.game.Identifier;
import com.github.steveice10.opennbt.tag.builtin.*; 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.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; 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.ItemTranslator;
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
import org.geysermc.geyser.util.MathUtils; import org.geysermc.geyser.util.MathUtils;
@ItemRemapper public class ShulkerBoxItem extends BlockItem {
public class ShulkerBoxItemTranslator extends NbtItemStackTranslator { public ShulkerBoxItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override @Override
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
if (!itemTag.contains("BlockEntityTag")) return; // Empty shulker box 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; if (blockEntityTag.get("Items") == null) return;
ListTag itemsList = new ListTag("Items"); ListTag itemsList = new ListTag("Items");
for (Tag item : (ListTag) blockEntityTag.get("Items")) { for (Tag item : (ListTag) blockEntityTag.get("Items")) {
@ -72,21 +76,17 @@ public class ShulkerBoxItemTranslator extends NbtItemStackTranslator {
itemsList.add(boxItemTag); itemsList.add(boxItemTag);
} }
itemTag.put(itemsList); tag.put(itemsList);
// Don't actually bother with removing the block entity tag. Too risky to translate // 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 // if the user is on creative and messing with a shulker box
//itemTag.remove("BlockEntityTag"); //itemTag.remove("BlockEntityTag");
} }
@Override @Override
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
if (itemTag.contains("Items")) { // Remove any extraneous Bedrock tag and don't touch the Java one super.translateNbtToJava(tag, mapping);
itemTag.remove("Items");
}
}
@Override // Remove any extraneous Bedrock tag and don't touch the Java one
public boolean acceptItem(Item item) { tag.remove("Items");
return item.javaIdentifier().contains("shulker_box");
} }
} }

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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,43 +23,44 @@
* @link https://github.com/GeyserMC/Geyser * @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.*;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextDecoration; 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.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.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.MinecraftLocale; 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 org.geysermc.geyser.translator.text.MessageTranslator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ItemRemapper public class TropicalFishBucketItem extends Item {
public class TropicalFishBucketTranslator extends NbtItemStackTranslator {
private static final Style LORE_STYLE = Style.style(NamedTextColor.GRAY, TextDecoration.ITALIC); private static final Style LORE_STYLE = Style.style(NamedTextColor.GRAY, TextDecoration.ITALIC);
public TropicalFishBucketItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
@Override @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" // Prevent name from appearing as "Bucket of"
itemTag.put(new ByteTag("AppendCustomName", (byte) 1)); tag.put(new ByteTag("AppendCustomName", (byte) 1));
itemTag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.locale()))); tag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.locale())));
// Add Java's client side lore tag // Add Java's client side lore tag
Tag bucketVariantTag = itemTag.get("BucketVariantTag"); Tag bucketVariantTag = tag.get("BucketVariantTag");
if (bucketVariantTag instanceof IntTag) { if (bucketVariantTag instanceof IntTag) {
CompoundTag displayTag = itemTag.get("display"); CompoundTag displayTag = tag.get("display");
if (displayTag == null) { if (displayTag == null) {
displayTag = new CompoundTag("display"); displayTag = new CompoundTag("display");
itemTag.put(displayTag); tag.put(displayTag);
} }
List<Tag> lore = new ArrayList<>(); List<Tag> lore = new ArrayList<>();
@ -90,9 +91,4 @@ public class TropicalFishBucketTranslator extends NbtItemStackTranslator {
displayTag.put(new ListTag("Lore", lore)); 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()) .toolType(customItemData.toolType())
.toolTier(customItemData.toolTier()) .toolTier(customItemData.toolTier())
.translationString(customItemData.translationString()) .translationString(customItemData.translationString())
.hasSuspiciousStewEffect(false)
.customItemOptions(Collections.emptyList()) .customItemOptions(Collections.emptyList())
.javaItem(item) .javaItem(item)
.build(); .build();

View File

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

View File

@ -28,8 +28,6 @@ package org.geysermc.geyser.registry.type;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import java.util.List;
/** /**
* Represents Geyser's own serialized item information before being processed per-version * 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("armor_type") String armorType;
@JsonProperty("protection_value") int protectionValue; @JsonProperty("protection_value") int protectionValue;
@JsonProperty("max_damage") int maxDamage = 0; @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_edible") boolean edible = false;
@JsonProperty("is_entity_placer") boolean entityPlacer = false; @JsonProperty("is_entity_placer") boolean entityPlacer = false;
} }

View File

@ -52,7 +52,6 @@ public class ItemMapping {
null, null,
null, null,
Collections.emptyList(), Collections.emptyList(),
false,
Items.AIR Items.AIR
); );
@ -74,8 +73,6 @@ public class ItemMapping {
@NonNull @NonNull
List<Pair<CustomItemOptions, ItemDefinition>> customItemOptions; List<Pair<CustomItemOptions, ItemDefinition>> customItemOptions;
boolean hasSuspiciousStewEffect;
@NonNull @NonNull
Item javaItem; 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.Inventory;
import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.inventory.SlotType;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; 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.item.type.DyeItem;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -158,7 +158,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
inputCopy.setNbt(new CompoundTag("")); inputCopy.setNbt(new CompoundTag(""));
} }
CompoundTag blockEntityTag = inputCopy.getNbt().get("BlockEntityTag"); CompoundTag blockEntityTag = inputCopy.getNbt().get("BlockEntityTag");
CompoundTag javaBannerPattern = BannerTranslator.getJavaBannerPattern(pattern); CompoundTag javaBannerPattern = BannerItem.getJavaBannerPattern(pattern);
if (blockEntityTag != null) { if (blockEntityTag != null) {
ListTag patternsList = blockEntityTag.get("Patterns"); ListTag patternsList = blockEntityTag.get("Patterns");

View File

@ -37,9 +37,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries; 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.ChatColor;
import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.FileUtils;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.lang.reflect.InvocationTargetException; import java.util.ArrayList;
import java.util.*; import java.util.List;
import java.util.stream.Collectors; import java.util.Map;
public final class ItemTranslator { public final class ItemTranslator {
private static final List<NbtItemStackTranslator> NBT_TRANSLATORS;
private ItemTranslator() { 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 * @param mappings item mappings to use while translating. This can't just be a Geyser session as this method is used
* when loading recipes. * when loading recipes.
@ -102,11 +72,7 @@ public final class ItemTranslator {
ItemStack itemStack = javaItem.translateToJava(data, bedrockItem, mappings); ItemStack itemStack = javaItem.translateToJava(data, bedrockItem, mappings);
if (itemStack != null && itemStack.getNbt() != null) { if (itemStack != null && itemStack.getNbt() != null) {
for (NbtItemStackTranslator translator : NBT_TRANSLATORS) { javaItem.translateNbtToJava(itemStack.getNbt(), bedrockItem);
if (translator.acceptItem(javaItem)) {
translator.translateToJava(itemStack.getNbt(), bedrockItem);
}
}
if (itemStack.getNbt().isEmpty()) { 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 // 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); 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) { private static ItemData.Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, CompoundTag tag) {
CompoundTag nbt = tag != null ? tag.clone() : null; 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) { if (nbt != null) {
for (NbtItemStackTranslator translator : NBT_TRANSLATORS) { javaItem.translateNbtToBedrock(session, nbt, bedrockItem);
if (translator.acceptItem(javaItem)) {
translator.translateToBedrock(session, nbt, bedrockItem);
}
}
} }
nbt = translateDisplayProperties(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.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag; import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.item.type.BannerItem;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator;
@BlockEntity(type = BlockEntityType.BANNER) @BlockEntity(type = BlockEntityType.BANNER)
public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { 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 (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) // 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 // and tell the Bedrock client that this is an ominous banner
builder.putInt("Type", 1); builder.putInt("Type", 1);
} else { } 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.PlayerInventory;
import org.geysermc.geyser.inventory.click.Click; import org.geysermc.geyser.inventory.click.Click;
import org.geysermc.geyser.item.Items; 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.item.type.SpawnEggItem;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.inventory.InventoryTranslator;
@ -274,15 +276,14 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
session.getWorldCache().nextPredictionSequence()); session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(blockPacket); session.sendDownstreamPacket(blockPacket);
Item item = session.getPlayerInventory().getItemInHand().asItem();
if (packet.getItemInHand() != null) { if (packet.getItemInHand() != null) {
ItemDefinition definition = packet.getItemInHand().getDefinition(); ItemDefinition definition = packet.getItemInHand().getDefinition();
int blockState = session.getGeyser().getWorldManager().getBlockAt(session, packet.getBlockPosition()); 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 // 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) || if (item instanceof BoatItem || item == Items.LILY_PAD || item == Items.FROGSPAWN) {
definition == session.getItemMappings().getStoredItems().lilyPad().getBedrockDefinition() ||
definition == session.getItemMappings().getStoredItems().frogspawn().getBedrockDefinition()) {
useItem(session, packet, blockState); 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)) { if (!session.isSneaking() && BlockStateValues.isCauldron(blockState) && !BlockStateValues.isNonWaterCauldron(blockState)) {
// ServerboundUseItemPacket is not sent for water cauldrons and glass bottles // ServerboundUseItemPacket is not sent for water cauldrons and glass bottles
return; return;
@ -315,10 +316,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
} }
} }
} }
ItemMapping handItem = session.getPlayerInventory().getItemInHand().getMapping(session); if (item instanceof BlockItem) {
if (handItem.isBlock()) {
session.setLastBlockPlacePosition(blockPos); session.setLastBlockPlacePosition(blockPos);
session.setLastBlockPlacedId(handItem.getJavaItem().javaIdentifier()); session.setLastBlockPlacedId(item.javaIdentifier());
} }
session.setInteracting(true); session.setInteracting(true);
} }
@ -526,9 +526,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
Inventory playerInventory = session.getPlayerInventory(); Inventory playerInventory = session.getPlayerInventory();
int heldItemSlot = playerInventory.getOffsetForHotbar(packet.getHotbarSlot()); int heldItemSlot = playerInventory.getOffsetForHotbar(packet.getHotbarSlot());
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, playerInventory, heldItemSlot); InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, playerInventory, heldItemSlot);
if (playerInventory.getItem(heldItemSlot).getAmount() > 1) { GeyserItemStack itemStack = playerInventory.getItem(heldItemSlot);
if (packet.getItemInHand().getDefinition() == session.getItemMappings().getStoredItems().bucket().getBedrockDefinition() || if (itemStack.getAmount() > 1) {
packet.getItemInHand().getDefinition() == session.getItemMappings().getStoredItems().glassBottle().getBedrockDefinition()) { 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. // 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 // 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. // 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.entity.type.living.animal.AnimalEntity;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import java.util.Locale; 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. * 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; 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.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag; import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.FishingRodItem;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -64,7 +65,7 @@ public class ItemUtils {
// Java durability: 64 // Java durability: 64
// Bedrock durability : 384 // Bedrock durability : 384
// 384 / 64 = 6 // 384 / 64 = 6
return original * 6; return FishingRodItem.getBedrockDamage(original);
} }
return original; return original;
} }