mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Translate CanPlaceOn/CanDestroy NBT (#1253)
* Translate CanPlaceOn/CanDestroy NBT This commit adds support for the translation of the CanPlaceOn/CanDestroy NBT for Bedrock clients. * Remove debug line
This commit is contained in:
parent
9643b208f3
commit
26802e6dab
5 changed files with 79 additions and 25 deletions
|
@ -34,7 +34,6 @@ import com.nukkitx.nbt.NbtMap;
|
||||||
import com.nukkitx.nbt.NbtMapBuilder;
|
import com.nukkitx.nbt.NbtMapBuilder;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket;
|
import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
|
||||||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
@ -102,13 +101,7 @@ public class ItemFrameEntity extends Entity {
|
||||||
ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue());
|
ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue());
|
||||||
NbtMapBuilder builder = NbtMap.builder();
|
NbtMapBuilder builder = NbtMap.builder();
|
||||||
|
|
||||||
String blockName = "";
|
String blockName = ItemRegistry.getBedrockIdentifer(itemEntry);
|
||||||
for (StartGamePacket.ItemEntry startGamePacketItemEntry : ItemRegistry.ITEMS) {
|
|
||||||
if (startGamePacketItemEntry.getId() == (short) itemEntry.getBedrockId()) {
|
|
||||||
blockName = startGamePacketItemEntry.getIdentifier();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.putByte("Count", (byte) itemData.getCount());
|
builder.putByte("Count", (byte) itemData.getCount());
|
||||||
if (itemData.getTag() != null) {
|
if (itemData.getTag() != null) {
|
||||||
|
|
|
@ -221,6 +221,23 @@ public class ItemRegistry {
|
||||||
.stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null));
|
.stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the Bedrock string identifier of an ItemEntry
|
||||||
|
*
|
||||||
|
* @param entry the ItemEntry to search for
|
||||||
|
* @return the Bedrock identifier
|
||||||
|
*/
|
||||||
|
public static String getBedrockIdentifer(ItemEntry entry) {
|
||||||
|
String blockName = "";
|
||||||
|
for (StartGamePacket.ItemEntry startGamePacketItemEntry : ItemRegistry.ITEMS) {
|
||||||
|
if (startGamePacketItemEntry.getId() == (short) entry.getBedrockId()) {
|
||||||
|
blockName = startGamePacketItemEntry.getIdentifier(); // Find the Bedrock string name
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blockName;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a Bedrock {@link ItemData} from a {@link JsonNode}
|
* Gets a Bedrock {@link ItemData} from a {@link JsonNode}
|
||||||
* @param itemNode the JSON node that contains ProxyPass-compatible Bedrock item data
|
* @param itemNode the JSON node that contains ProxyPass-compatible Bedrock item data
|
||||||
|
|
|
@ -41,6 +41,7 @@ import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
import org.geysermc.connector.utils.MessageUtils;
|
import org.geysermc.connector.utils.MessageUtils;
|
||||||
|
@ -154,9 +155,43 @@ public abstract class ItemTranslator {
|
||||||
itemData = DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem);
|
itemData = DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nbt != null) {
|
||||||
|
// Translate the canDestroy and canPlaceOn Java NBT
|
||||||
|
ListTag canDestroy = nbt.get("CanDestroy");
|
||||||
|
String[] canBreak = new String[0];
|
||||||
|
ListTag canPlaceOn = nbt.get("CanPlaceOn");
|
||||||
|
String[] canPlace = new String[0];
|
||||||
|
canBreak = getCanModify(canDestroy, canBreak);
|
||||||
|
canPlace = getCanModify(canPlaceOn, canPlace);
|
||||||
|
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), itemData.getTag(), canPlace, canBreak);
|
||||||
|
}
|
||||||
|
|
||||||
return itemData;
|
return itemData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates the Java NBT of canDestroy and canPlaceOn to its Bedrock counterparts.
|
||||||
|
* In Java, this is treated as normal NBT, but in Bedrock, these arguments are extra parts of the item data itself.
|
||||||
|
* @param canModifyJava the list of items in Java
|
||||||
|
* @param canModifyBedrock the empty list of items in Bedrock
|
||||||
|
* @return the new list of items in Bedrock
|
||||||
|
*/
|
||||||
|
private static String[] getCanModify(ListTag canModifyJava, String[] canModifyBedrock) {
|
||||||
|
if (canModifyJava != null && canModifyJava.size() > 0) {
|
||||||
|
canModifyBedrock = new String[canModifyJava.size()];
|
||||||
|
for (int i = 0; i < canModifyBedrock.length; i++) {
|
||||||
|
// Get the Java identifier of the block that can be placed
|
||||||
|
String block = ((StringTag) canModifyJava.get(i)).getValue();
|
||||||
|
// Sometimes this is done but it's still valid
|
||||||
|
if (!block.startsWith("minecraft:")) block = "minecraft:" + block;
|
||||||
|
// Get the Bedrock identifier of the item and replace it.
|
||||||
|
// This will unfortunately be limited - for example, beds and banners will be translated weirdly
|
||||||
|
canModifyBedrock[i] = BlockTranslator.getBedrockBlockIdentifier(block).replace("minecraft:", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return canModifyBedrock;
|
||||||
|
}
|
||||||
|
|
||||||
private static final ItemTranslator DEFAULT_TRANSLATOR = new ItemTranslator() {
|
private static final ItemTranslator DEFAULT_TRANSLATOR = new ItemTranslator() {
|
||||||
@Override
|
@Override
|
||||||
public List<ItemEntry> getAppliedItems() {
|
public List<ItemEntry> getAppliedItems() {
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
package org.geysermc.connector.network.translators.item.translators.nbt;
|
package org.geysermc.connector.network.translators.item.translators.nbt;
|
||||||
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||||
import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
|
@ -51,13 +50,7 @@ public class ShulkerBoxItemTranslator extends NbtItemStackTranslator {
|
||||||
boxItemTag.put(new ByteTag("WasPickedUp", (byte) 0)); // ???
|
boxItemTag.put(new ByteTag("WasPickedUp", (byte) 0)); // ???
|
||||||
|
|
||||||
ItemEntry boxItemEntry = ItemRegistry.getItemEntry(((StringTag) itemData.get("id")).getValue());
|
ItemEntry boxItemEntry = ItemRegistry.getItemEntry(((StringTag) itemData.get("id")).getValue());
|
||||||
String blockName = "";
|
String blockName = ItemRegistry.getBedrockIdentifer(boxItemEntry);
|
||||||
for (StartGamePacket.ItemEntry startGamePacketItemEntry : ItemRegistry.ITEMS) {
|
|
||||||
if (startGamePacketItemEntry.getId() == (short) boxItemEntry.getBedrockId()) {
|
|
||||||
blockName = startGamePacketItemEntry.getIdentifier(); // Find the Bedrock string name
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boxItemTag.put(new StringTag("Name", blockName));
|
boxItemTag.put(new StringTag("Name", blockName));
|
||||||
boxItemTag.put(new ShortTag("Damage", (short) boxItemEntry.getBedrockData()));
|
boxItemTag.put(new ShortTag("Damage", (short) boxItemEntry.getBedrockData()));
|
||||||
|
|
|
@ -28,15 +28,12 @@ package org.geysermc.connector.network.translators.world.block;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.google.common.collect.BiMap;
|
import com.google.common.collect.BiMap;
|
||||||
import com.google.common.collect.HashBiMap;
|
import com.google.common.collect.HashBiMap;
|
||||||
import com.nukkitx.nbt.NBTInputStream;
|
import com.nukkitx.nbt.*;
|
||||||
import com.nukkitx.nbt.NbtList;
|
|
||||||
import com.nukkitx.nbt.NbtMap;
|
|
||||||
import com.nukkitx.nbt.NbtMapBuilder;
|
|
||||||
import com.nukkitx.nbt.NbtType;
|
|
||||||
import com.nukkitx.nbt.NbtUtils;
|
|
||||||
import it.unimi.dsi.fastutil.ints.*;
|
import it.unimi.dsi.fastutil.ints.*;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.translators.world.block.entity.BlockEntity;
|
import org.geysermc.connector.network.translators.world.block.entity.BlockEntity;
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
|
@ -52,6 +49,11 @@ public class BlockTranslator {
|
||||||
|
|
||||||
private static final Int2IntMap JAVA_TO_BEDROCK_BLOCK_MAP = new Int2IntOpenHashMap();
|
private static final Int2IntMap JAVA_TO_BEDROCK_BLOCK_MAP = new Int2IntOpenHashMap();
|
||||||
private static final Int2IntMap BEDROCK_TO_JAVA_BLOCK_MAP = new Int2IntOpenHashMap();
|
private static final Int2IntMap BEDROCK_TO_JAVA_BLOCK_MAP = new Int2IntOpenHashMap();
|
||||||
|
/**
|
||||||
|
* Stores a list of differences in block identifiers.
|
||||||
|
* Items will not be added to this list if the key and value is the same.
|
||||||
|
*/
|
||||||
|
private static final Object2ObjectMap<String, String> JAVA_TO_BEDROCK_IDENTIFIERS = new Object2ObjectOpenHashMap<>();
|
||||||
private static final BiMap<String, Integer> JAVA_ID_BLOCK_MAP = HashBiMap.create();
|
private static final BiMap<String, Integer> JAVA_ID_BLOCK_MAP = HashBiMap.create();
|
||||||
private static final IntSet WATERLOGGED = new IntOpenHashSet();
|
private static final IntSet WATERLOGGED = new IntOpenHashSet();
|
||||||
private static final Object2IntMap<NbtMap> ITEM_FRAMES = new Object2IntOpenHashMap<>();
|
private static final Object2IntMap<NbtMap> ITEM_FRAMES = new Object2IntOpenHashMap<>();
|
||||||
|
@ -152,11 +154,11 @@ public class BlockTranslator {
|
||||||
|
|
||||||
// Used for adding all "special" Java block states to block state map
|
// Used for adding all "special" Java block states to block state map
|
||||||
String identifier;
|
String identifier;
|
||||||
String bedrock_identifer = entry.getValue().get("bedrock_identifier").asText();
|
String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText();
|
||||||
for (Class<?> clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) {
|
for (Class<?> clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) {
|
||||||
identifier = clazz.getAnnotation(BlockEntity.class).regex();
|
identifier = clazz.getAnnotation(BlockEntity.class).regex();
|
||||||
// Endswith, or else the block bedrock gets picked up for bed
|
// Endswith, or else the block bedrock gets picked up for bed
|
||||||
if (bedrock_identifer.endsWith(identifier) && !identifier.equals("")) {
|
if (bedrockIdentifier.endsWith(identifier) && !identifier.equals("")) {
|
||||||
JAVA_ID_TO_BLOCK_ENTITY_MAP.put(javaRuntimeId, clazz.getAnnotation(BlockEntity.class).name());
|
JAVA_ID_TO_BLOCK_ENTITY_MAP.put(javaRuntimeId, clazz.getAnnotation(BlockEntity.class).name());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -164,9 +166,15 @@ public class BlockTranslator {
|
||||||
|
|
||||||
BlockStateValues.storeBlockStateValues(entry, javaRuntimeId);
|
BlockStateValues.storeBlockStateValues(entry, javaRuntimeId);
|
||||||
|
|
||||||
|
String cleanJavaIdentifier = entry.getKey().split("\\[")[0];
|
||||||
|
|
||||||
|
if (!cleanJavaIdentifier.equals(bedrockIdentifier)) {
|
||||||
|
JAVA_TO_BEDROCK_IDENTIFIERS.put(cleanJavaIdentifier, bedrockIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
// Get the tag needed for non-empty flower pots
|
// Get the tag needed for non-empty flower pots
|
||||||
if (entry.getValue().get("pottable") != null) {
|
if (entry.getValue().get("pottable") != null) {
|
||||||
BlockStateValues.getFlowerPotBlocks().put(entry.getKey().split("\\[")[0], buildBedrockState(entry.getValue()));
|
BlockStateValues.getFlowerPotBlocks().put(cleanJavaIdentifier, buildBedrockState(entry.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("minecraft:water[level=0]".equals(javaId)) {
|
if ("minecraft:water[level=0]".equals(javaId)) {
|
||||||
|
@ -297,6 +305,14 @@ public class BlockTranslator {
|
||||||
return BEDROCK_TO_JAVA_BLOCK_MAP.get(bedrockId);
|
return BEDROCK_TO_JAVA_BLOCK_MAP.get(bedrockId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param javaIdentifier the Java identifier of the block to search for
|
||||||
|
* @return the Bedrock identifier if different, or else the Java identifier
|
||||||
|
*/
|
||||||
|
public static String getBedrockBlockIdentifier(String javaIdentifier) {
|
||||||
|
return JAVA_TO_BEDROCK_IDENTIFIERS.getOrDefault(javaIdentifier, javaIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
public static int getItemFrame(NbtMap tag) {
|
public static int getItemFrame(NbtMap tag) {
|
||||||
return ITEM_FRAMES.getOrDefault(tag, -1);
|
return ITEM_FRAMES.getOrDefault(tag, -1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue