Update to latest Protocol changes & cleanup item registry populator

This commit is contained in:
RednedEpic 2022-10-30 11:34:08 -05:00
parent 86ebfbbc6e
commit 3f42d68f4e
16 changed files with 307 additions and 208 deletions

View File

@ -39,7 +39,7 @@ public class FallingBlockEntity extends Entity {
public FallingBlockEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, int javaId) { public FallingBlockEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, int javaId) {
super(session, entityId, geyserId, uuid, EntityDefinitions.FALLING_BLOCK, position, motion, yaw, pitch, headYaw); super(session, entityId, geyserId, uuid, EntityDefinitions.FALLING_BLOCK, position, motion, yaw, pitch, headYaw);
this.dirtyMetadata.put(EntityDataTypes.VARIANT, session.getBlockMappings().getBedrockBlockId(javaId)); this.dirtyMetadata.put(EntityDataTypes.BLOCK, session.getBlockMappings().getBedrockBlock(javaId));
} }
@Override @Override

View File

@ -35,6 +35,7 @@ import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
@ -59,7 +60,7 @@ public class ItemFrameEntity extends Entity {
/** /**
* Specific block 'state' we are emulating in Bedrock. * Specific block 'state' we are emulating in Bedrock.
*/ */
private final int bedrockRuntimeId; private final BlockDefinition blockDefinition;
/** /**
* Rotation of item in frame. * Rotation of item in frame.
*/ */
@ -90,7 +91,7 @@ public class ItemFrameEntity extends Entity {
.putByte("item_frame_photo_bit", (byte) 0); .putByte("item_frame_photo_bit", (byte) 0);
blockBuilder.put("states", statesBuilder.build()); blockBuilder.put("states", statesBuilder.build());
bedrockRuntimeId = session.getBlockMappings().getItemFrame(blockBuilder.build()); blockDefinition = session.getBlockMappings().getItemFrame(blockBuilder.build());
bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ()); bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ());
session.getItemFrameCache().put(bedrockPosition, this); session.getItemFrameCache().put(bedrockPosition, this);
@ -152,7 +153,7 @@ public class ItemFrameEntity extends Entity {
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0); updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(bedrockPosition); updateBlockPacket.setBlockPosition(bedrockPosition);
updateBlockPacket.setRuntimeId(session.getBlockMappings().getBedrockAir().getRuntimeId()); //TODO maybe set this to the world block or another item frame? updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockAir()); //TODO maybe set this to the world block or another item frame?
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
@ -190,7 +191,7 @@ public class ItemFrameEntity extends Entity {
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0); updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(bedrockPosition); updateBlockPacket.setBlockPosition(bedrockPosition);
updateBlockPacket.setRuntimeId(bedrockRuntimeId); updateBlockPacket.setDefinition(blockDefinition);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);

View File

@ -93,7 +93,7 @@ public class BlockInventoryHolder extends InventoryHolder {
UpdateBlockPacket blockPacket = new UpdateBlockPacket(); UpdateBlockPacket blockPacket = new UpdateBlockPacket();
blockPacket.setDataLayer(0); blockPacket.setDataLayer(0);
blockPacket.setBlockPosition(position); blockPacket.setBlockPosition(position);
blockPacket.setRuntimeId(session.getBlockMappings().getBedrockBlockId(defaultJavaBlockState)); blockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(defaultJavaBlockState));
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
session.sendUpstreamPacket(blockPacket); session.sendUpstreamPacket(blockPacket);
inventory.setHolderPosition(position); inventory.setHolderPosition(position);
@ -157,7 +157,7 @@ public class BlockInventoryHolder extends InventoryHolder {
UpdateBlockPacket blockPacket = new UpdateBlockPacket(); UpdateBlockPacket blockPacket = new UpdateBlockPacket();
blockPacket.setDataLayer(0); blockPacket.setDataLayer(0);
blockPacket.setBlockPosition(holderPos); blockPacket.setBlockPosition(holderPos);
blockPacket.setRuntimeId(session.getBlockMappings().getBedrockBlockId(realBlock)); blockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(realBlock));
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
session.sendUpstreamPacket(blockPacket); session.sendUpstreamPacket(blockPacket);
} }

View File

@ -0,0 +1,131 @@
/*
* 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.registry.populator;
import com.fasterxml.jackson.databind.JsonNode;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtUtils;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMappings;
import org.geysermc.geyser.registry.type.ItemMappings;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
public class CreativeItemRegistryPopulator {
private static final List<BiPredicate<String, Integer>> JAVA_ONLY_ITEM_FILTER = List.of(
// Just shows an empty texture; either way it doesn't exist in the creative menu on Java
(identifier, data) -> identifier.equals("minecraft:debug_stick"),
// Bedrock-only as its own item
(identifier, data) -> identifier.equals("minecraft:empty_map") && data == 2,
// Bedrock-only banner patterns
(identifier, data) -> identifier.equals("minecraft:bordure_indented_banner_pattern") || identifier.equals("minecraft:field_masoned_banner_pattern")
);
public static void populate(Map.Entry<String, ItemRegistryPopulator.PaletteVersion> version, Map<String, ItemDefinition> definitions, Consumer<ItemData.Builder> itemConsumer) {
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
// Load creative items
JsonNode creativeItemEntries;
try (InputStream stream = bootstrap.getResource(String.format("bedrock/creative_items.%s.json", version.getKey()))) {
creativeItemEntries = GeyserImpl.JSON_MAPPER.readTree(stream).get("items");
} catch (Exception e) {
throw new AssertionError("Unable to load creative items", e);
}
BlockMappings blockMappings = BlockRegistries.BLOCKS.forVersion(version.getValue().protocolVersion());
for (JsonNode itemNode : creativeItemEntries) {
ItemData.Builder itemBuilder = createItemData(itemNode, blockMappings, definitions);
if (itemBuilder == null) {
continue;
}
itemConsumer.accept(itemBuilder);
}
}
private static ItemData.Builder createItemData(JsonNode itemNode, BlockMappings blockMappings, Map<String, ItemDefinition> definitions) {
int count = 1;
int damage = 0;
int blockRuntimeId = 0;
NbtMap tag = null;
JsonNode damageNode = itemNode.get("damage");
if (damageNode != null) {
damage = damageNode.asInt();
}
JsonNode countNode = itemNode.get("count");
if (countNode != null) {
count = countNode.asInt();
}
JsonNode blockRuntimeIdNode = itemNode.get("blockRuntimeId");
if (blockRuntimeIdNode != null) {
blockRuntimeId = blockRuntimeIdNode.asInt();
}
JsonNode nbtNode = itemNode.get("nbt_b64");
if (nbtNode != null) {
byte[] bytes = Base64.getDecoder().decode(nbtNode.asText());
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
try {
tag = (NbtMap) NbtUtils.createReaderLE(bais).readTag();
} catch (IOException e) {
e.printStackTrace();
}
}
String identifier = itemNode.get("id").textValue();
for (BiPredicate<String, Integer> predicate : JAVA_ONLY_ITEM_FILTER) {
if (predicate.test(identifier, damage)) {
return null;
}
}
ItemDefinition definition = definitions.get(identifier);
if (definition == null) {
GeyserImpl.getInstance().getLogger().debug("Unknown item definition with identifier " + identifier + " when loading creative items!");
return null;
}
return ItemData.builder()
.definition(definition)
.damage(damage)
.count(count)
.tag(tag)
.blockDefinition(blockMappings.getBedrockBlock(blockRuntimeId));
}
}

View File

@ -25,20 +25,24 @@
package org.geysermc.geyser.registry.populator; package org.geysermc.geyser.registry.populator;
import com.google.common.collect.Multimap;
import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType; import com.nukkitx.nbt.NbtType;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
import org.cloudburstmc.protocol.bedrock.packet.StartGamePacket;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemData;
import org.geysermc.geyser.api.item.custom.CustomRenderOffsets; import org.geysermc.geyser.api.item.custom.CustomRenderOffsets;
import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData;
import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.api.util.TriState;
import org.geysermc.geyser.event.type.GeyserDefineCustomItemsEventImpl;
import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.GeyserCustomMappingData;
import org.geysermc.geyser.item.components.ToolBreakSpeedsUtils; import org.geysermc.geyser.item.components.ToolBreakSpeedsUtils;
import org.geysermc.geyser.item.components.WearableSlot; import org.geysermc.geyser.item.components.WearableSlot;
import org.geysermc.geyser.item.mappings.MappingsConfigReader;
import org.geysermc.geyser.registry.type.GeyserMappingItem; import org.geysermc.geyser.registry.type.GeyserMappingItem;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.NonVanillaItemRegistration; import org.geysermc.geyser.registry.type.NonVanillaItemRegistration;
@ -50,6 +54,51 @@ import java.util.Map;
import java.util.OptionalInt; import java.util.OptionalInt;
public class CustomItemRegistryPopulator { public class CustomItemRegistryPopulator {
public static void populate(Map<String, GeyserMappingItem> items, Multimap<String, CustomItemData> customItems, List<NonVanillaCustomItemData> nonVanillaCustomItems) {
MappingsConfigReader mappingsConfigReader = new MappingsConfigReader();
// Load custom items from mappings files
mappingsConfigReader.loadMappingsFromJson((key, item) -> {
if (CustomItemRegistryPopulator.initialCheck(key, item, items)) {
customItems.get(key).add(item);
}
});
GeyserImpl.getInstance().eventBus().fire(new GeyserDefineCustomItemsEventImpl(customItems, nonVanillaCustomItems) {
@Override
public boolean register(@NonNull String identifier, @NonNull CustomItemData customItemData) {
if (CustomItemRegistryPopulator.initialCheck(identifier, customItemData, items)) {
customItems.get(identifier).add(customItemData);
return true;
}
return false;
}
@Override
public boolean register(@NonNull NonVanillaCustomItemData customItemData) {
if (customItemData.identifier().startsWith("minecraft:")) {
GeyserImpl.getInstance().getLogger().error("The custom item " + customItemData.identifier() +
" is attempting to masquerade as a vanilla Minecraft item!");
return false;
}
if (customItemData.javaId() < items.size()) {
// Attempting to overwrite an item that already exists in the protocol
GeyserImpl.getInstance().getLogger().error("The custom item " + customItemData.identifier() +
" is attempting to overwrite a vanilla Minecraft item!");
return false;
}
nonVanillaCustomItems.add(customItemData);
return true;
}
});
int customItemCount = customItems.size() + nonVanillaCustomItems.size();
if (customItemCount > 0) {
GeyserImpl.getInstance().getLogger().info("Registered " + customItemCount + " custom items");
}
}
public static GeyserCustomMappingData registerCustomItem(String customItemName, GeyserMappingItem javaItem, CustomItemData customItemData, int bedrockId) { public static GeyserCustomMappingData registerCustomItem(String customItemName, GeyserMappingItem javaItem, CustomItemData customItemData, int bedrockId) {
ItemDefinition itemDefinition = new ItemDefinition(customItemName, bedrockId, true); ItemDefinition itemDefinition = new ItemDefinition(customItemName, bedrockId, true);
@ -86,7 +135,7 @@ public class CustomItemRegistryPopulator {
.javaId(customItemData.javaId()) .javaId(customItemData.javaId())
.bedrockDefinition(new ItemDefinition(customIdentifier, customItemId, true)) .bedrockDefinition(new ItemDefinition(customIdentifier, customItemId, true))
.bedrockData(0) .bedrockData(0)
.bedrockBlockId(0) .bedrockBlockDefinition(null)
.stackSize(customItemData.stackSize()) .stackSize(customItemData.stackSize())
.toolType(customItemData.toolType()) .toolType(customItemData.toolType())
.toolTier(customItemData.toolTier()) .toolTier(customItemData.toolTier())

View File

@ -26,13 +26,11 @@
package org.geysermc.geyser.registry.populator; package org.geysermc.geyser.registry.populator;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder; import com.google.common.collect.MultimapBuilder;
import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType; import com.nukkitx.nbt.NbtType;
import com.nukkitx.nbt.NbtUtils;
import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@ -45,7 +43,6 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.codec.v527.Bedrock_v527; import org.cloudburstmc.protocol.bedrock.codec.v527.Bedrock_v527;
import org.cloudburstmc.protocol.bedrock.codec.v534.Bedrock_v534; import org.cloudburstmc.protocol.bedrock.codec.v534.Bedrock_v534;
import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544; import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544;
@ -60,10 +57,8 @@ import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemData;
import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.item.custom.CustomItemOptions;
import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData;
import org.geysermc.geyser.event.type.GeyserDefineCustomItemsEventImpl;
import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.inventory.item.StoredItemMappings;
import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.GeyserCustomMappingData;
import org.geysermc.geyser.item.mappings.MappingsConfigReader;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.BlockMappings;
@ -75,24 +70,22 @@ import org.geysermc.geyser.registry.type.PaletteItem;
import org.geysermc.geyser.util.ItemUtils; import org.geysermc.geyser.util.ItemUtils;
import org.geysermc.geyser.util.collection.FixedInt2IntMap; import org.geysermc.geyser.util.collection.FixedInt2IntMap;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Base64;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
/** /**
* Populates the item registries. * Populates the item registries.
*/ */
public class ItemRegistryPopulator { public class ItemRegistryPopulator {
private record PaletteVersion(int protocolVersion, Map<String, String> additionalTranslatedItems) { record PaletteVersion(int protocolVersion, Map<String, String> additionalTranslatedItems) {
} }
public static void populate() { public static void populate() {
@ -120,48 +113,10 @@ public class ItemRegistryPopulator {
// (as of 1.19.2 Java) to replicate some edge cases in Java predicate behavior where it checks from the bottom // (as of 1.19.2 Java) to replicate some edge cases in Java predicate behavior where it checks from the bottom
// of the list first, then ascends. // of the list first, then ascends.
Multimap<String, CustomItemData> customItems = MultimapBuilder.hashKeys().arrayListValues().build(); Multimap<String, CustomItemData> customItems = MultimapBuilder.hashKeys().arrayListValues().build();
List<NonVanillaCustomItemData> nonVanillaCustomItems; List<NonVanillaCustomItemData> nonVanillaCustomItems = customItemsAllowed ? new ObjectArrayList<>() : Collections.emptyList();
MappingsConfigReader mappingsConfigReader = new MappingsConfigReader();
if (customItemsAllowed) { if (customItemsAllowed) {
// Load custom items from mappings files CustomItemRegistryPopulator.populate(items, customItems, nonVanillaCustomItems);
mappingsConfigReader.loadMappingsFromJson((key, item) -> {
if (CustomItemRegistryPopulator.initialCheck(key, item, items)) {
customItems.get(key).add(item);
}
});
nonVanillaCustomItems = new ObjectArrayList<>();
GeyserImpl.getInstance().eventBus().fire(new GeyserDefineCustomItemsEventImpl(customItems, nonVanillaCustomItems) {
@Override
public boolean register(@NonNull String identifier, @NonNull CustomItemData customItemData) {
if (CustomItemRegistryPopulator.initialCheck(identifier, customItemData, items)) {
customItems.get(identifier).add(customItemData);
return true;
}
return false;
}
@Override
public boolean register(@NonNull NonVanillaCustomItemData customItemData) {
if (customItemData.identifier().startsWith("minecraft:")) {
GeyserImpl.getInstance().getLogger().error("The custom item " + customItemData.identifier() +
" is attempting to masquerade as a vanilla Minecraft item!");
return false;
}
if (customItemData.javaId() < items.size()) {
// Attempting to overwrite an item that already exists in the protocol
GeyserImpl.getInstance().getLogger().error("The custom item " + customItemData.identifier() +
" is attempting to overwrite a vanilla Minecraft item!");
return false;
}
nonVanillaCustomItems.add(customItemData);
return true;
}
});
} else {
nonVanillaCustomItems = Collections.emptyList();
} }
int customItemCount = customItems.size() + nonVanillaCustomItems.size(); int customItemCount = customItems.size() + nonVanillaCustomItems.size();
@ -209,15 +164,6 @@ public class ItemRegistryPopulator {
Object2IntMap<String> bedrockBlockIdOverrides = new Object2IntOpenHashMap<>(); Object2IntMap<String> bedrockBlockIdOverrides = new Object2IntOpenHashMap<>();
Object2IntMap<String> blacklistedIdentifiers = new Object2IntOpenHashMap<>(); Object2IntMap<String> blacklistedIdentifiers = new Object2IntOpenHashMap<>();
// Load creative items
// We load this before item mappings to get overridden block runtime ID mappings
JsonNode creativeItemEntries;
try (InputStream stream = bootstrap.getResource(String.format("bedrock/creative_items.%s.json", palette.getKey()))) {
creativeItemEntries = GeyserImpl.JSON_MAPPER.readTree(stream).get("items");
} catch (Exception e) {
throw new AssertionError("Unable to load creative items", e);
}
List<ItemDefinition> boats = new ObjectArrayList<>(); List<ItemDefinition> boats = new ObjectArrayList<>();
List<ItemDefinition> buckets = new ObjectArrayList<>(); List<ItemDefinition> buckets = new ObjectArrayList<>();
List<ItemDefinition> spawnEggs = new ObjectArrayList<>(); List<ItemDefinition> spawnEggs = new ObjectArrayList<>();
@ -225,74 +171,31 @@ public class ItemRegistryPopulator {
List<ItemMapping> mappings = new ObjectArrayList<>(); List<ItemMapping> mappings = new ObjectArrayList<>();
// Temporary mapping to create stored items // Temporary mapping to create stored items
Map<String, ItemMapping> identifierToMapping = new Object2ObjectOpenHashMap<>(); Map<String, ItemMapping> javaIdentifierToMapping = new Object2ObjectOpenHashMap<>();
int netId = 1;
List<ItemData> creativeItems = new ArrayList<>(); List<ItemData> creativeItems = new ArrayList<>();
for (JsonNode itemNode : creativeItemEntries) {
int count = 1;
int damage = 0;
int blockRuntimeId = 0;
NbtMap tag = null;
JsonNode damageNode = itemNode.get("damage");
if (damageNode != null) {
damage = damageNode.asInt();
}
JsonNode countNode = itemNode.get("count");
if (countNode != null) {
count = countNode.asInt();
}
JsonNode blockRuntimeIdNode = itemNode.get("blockRuntimeId");
if (blockRuntimeIdNode != null) {
blockRuntimeId = blockRuntimeIdNode.asInt();
}
JsonNode nbtNode = itemNode.get("nbt_b64");
if (nbtNode != null) {
byte[] bytes = Base64.getDecoder().decode(nbtNode.asText());
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
try {
tag = (NbtMap) NbtUtils.createReaderLE(bais).readTag();
} catch (IOException e) {
e.printStackTrace();
}
}
String identifier = itemNode.get("id").textValue(); AtomicInteger creativeNetId = new AtomicInteger();
if (identifier.equals("minecraft:debug_stick")) { CreativeItemRegistryPopulator.populate(palette, definitions, itemBuilder -> {
// Just shows an empty texture; either way it doesn't exist in the creative menu on Java ItemData item = itemBuilder.netId(creativeNetId.getAndIncrement()).build();
continue; creativeItems.add(item);
} else if (identifier.equals("minecraft:empty_map") && damage == 2) {
// Bedrock-only as its own item
continue;
} else if (identifier.equals("minecraft:bordure_indented_banner_pattern") || identifier.equals("minecraft:field_masoned_banner_pattern")) {
// Bedrock-only banner patterns
continue;
}
ItemDefinition definition = definitions.get(identifier); if (item.getBlockDefinition() != null) {
creativeItems.add(ItemData.builder() String identifier = item.getDefinition().getIdentifier();
.definition(definition)
.damage(damage)
.count(count)
.blockRuntimeId(blockRuntimeId)
.tag(tag)
.netId(netId++)
.build());
if (blockRuntimeId != 0) {
// Add override for item mapping, unless it already exists... then we know multiple states can exist // Add override for item mapping, unless it already exists... then we know multiple states can exist
if (!blacklistedIdentifiers.containsKey(identifier)) { if (!blacklistedIdentifiers.containsKey(identifier)) {
if (bedrockBlockIdOverrides.containsKey(identifier)) { if (bedrockBlockIdOverrides.containsKey(identifier)) {
bedrockBlockIdOverrides.removeInt(identifier); bedrockBlockIdOverrides.removeInt(identifier);
// Save this as a blacklist, but also as knowledge of what the block state name should be // Save this as a blacklist, but also as knowledge of what the block state name should be
blacklistedIdentifiers.put(identifier, blockRuntimeId); blacklistedIdentifiers.put(identifier, item.getBlockDefinition().getRuntimeId());
} else { } else {
// Unless there's multiple possibilities for this one state, let this be // Unless there's multiple possibilities for this one state, let this be
bedrockBlockIdOverrides.put(identifier, blockRuntimeId); bedrockBlockIdOverrides.put(identifier, item.getBlockDefinition().getRuntimeId());
} }
} }
} }
} });
BlockMappings blockMappings = BlockRegistries.BLOCKS.forVersion(palette.getValue().protocolVersion()); BlockMappings blockMappings = BlockRegistries.BLOCKS.forVersion(palette.getValue().protocolVersion());
@ -435,7 +338,7 @@ public class ItemRegistryPopulator {
break; break;
} }
NbtMap states = blockMappings.getBedrockBlockPalette().get(itemData.getBlockRuntimeId()).getCompound("states"); NbtMap states = blockMappings.getBedrockBlockPalette().get(itemData.getBlockDefinition().getRuntimeId()).getCompound("states");
boolean valid = true; boolean valid = true;
for (Map.Entry<String, Object> nbtEntry : requiredBlockStates.entrySet()) { for (Map.Entry<String, Object> nbtEntry : requiredBlockStates.entrySet()) {
if (!states.get(nbtEntry.getKey()).equals(nbtEntry.getValue())) { if (!states.get(nbtEntry.getKey()).equals(nbtEntry.getValue())) {
@ -445,7 +348,7 @@ public class ItemRegistryPopulator {
} }
} }
if (valid) { if (valid) {
creativeItems.set(j, itemData.toBuilder().blockRuntimeId(bedrockBlockId).build()); creativeItems.set(j, itemData.toBuilder().blockDefinition(blockMappings.getBedrockBlock(bedrockBlockId)).build());
break; break;
} }
} }
@ -460,7 +363,7 @@ public class ItemRegistryPopulator {
.bedrockIdentifier(bedrockIdentifier.intern()) .bedrockIdentifier(bedrockIdentifier.intern())
.bedrockDefinition(definition) .bedrockDefinition(definition)
.bedrockData(mappingItem.getBedrockData()) .bedrockData(mappingItem.getBedrockData())
.bedrockBlockId(bedrockBlockId) .bedrockBlockDefinition(blockMappings.getBedrockBlock(bedrockBlockId))
.stackSize(stackSize) .stackSize(stackSize)
.maxDamage(mappingItem.getMaxDamage()) .maxDamage(mappingItem.getMaxDamage())
.hasSuspiciousStewEffect(mappingItem.isHasSuspiciousStewEffect()); .hasSuspiciousStewEffect(mappingItem.isHasSuspiciousStewEffect());
@ -534,7 +437,7 @@ public class ItemRegistryPopulator {
.definition(definition) .definition(definition)
.damage(mapping.getBedrockData()) .damage(mapping.getBedrockData())
.count(1) .count(1)
.blockRuntimeId(mapping.getBedrockBlockId()) .blockDefinition(mapping.getBedrockBlockDefinition())
.build()); .build());
} else if (javaIdentifier.startsWith("minecraft:music_disc_")) { } else if (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
@ -545,7 +448,7 @@ public class ItemRegistryPopulator {
} }
mappings.add(mapping); mappings.add(mapping);
identifierToMapping.put(javaIdentifier, mapping); javaIdentifierToMapping.put(javaIdentifier, mapping);
itemNames.add(javaIdentifier); itemNames.add(javaIdentifier);
@ -570,16 +473,14 @@ public class ItemRegistryPopulator {
.javaId(-1) .javaId(-1)
.bedrockDefinition(lodestoneCompass) .bedrockDefinition(lodestoneCompass)
.bedrockData(0) .bedrockData(0)
.bedrockBlockId(-1) .bedrockBlockDefinition(null)
.stackSize(1) .stackSize(1)
.customItemOptions(Collections.emptyList()) .customItemOptions(Collections.emptyList())
.build(); .build();
if (customItemsAllowed) { if (customItemsAllowed) {
// Add the furnace minecart as a custom item // Add furnace minecart
int furnaceMinecartId = nextFreeBedrockId++; ItemDefinition definition = new ItemDefinition("geysermc:furnace_minecart", nextFreeBedrockId, true);
ItemDefinition definition = new ItemDefinition("geysermc:furnace_minecart", (short) furnaceMinecartId, true);
definitions.put("geysermc:furnace_minecart", definition); definitions.put("geysermc:furnace_minecart", definition);
registry.add(definition); registry.add(definition);
@ -589,49 +490,18 @@ public class ItemRegistryPopulator {
.javaId(javaFurnaceMinecartId) .javaId(javaFurnaceMinecartId)
.bedrockDefinition(definition) .bedrockDefinition(definition)
.bedrockData(0) .bedrockData(0)
.bedrockBlockId(-1) .bedrockBlockDefinition(null)
.stackSize(1) .stackSize(1)
.customItemOptions(Collections.emptyList()) // TODO check for custom items with furnace minecart .customItemOptions(Collections.emptyList()) // TODO check for custom items with furnace minecart
.build()); .build());
creativeItems.add(ItemData.builder() creativeItems.add(ItemData.builder()
.netId(netId++) .netId(creativeNetId.getAndIncrement())
.definition(definition) .definition(definition)
.count(1).build()); .count(1)
NbtMapBuilder builder = NbtMap.builder();
builder.putString("name", "geysermc:furnace_minecart")
.putInt("id", furnaceMinecartId);
NbtMapBuilder itemProperties = NbtMap.builder();
NbtMapBuilder componentBuilder = NbtMap.builder();
// Conveniently, as of 1.16.200, the furnace minecart has a texture AND translation string already.
itemProperties.putCompound("minecraft:icon", NbtMap.builder()
.putString("texture", "minecart_furnace")
.putString("frame", "0.000000")
.putInt("frame_version", 1)
.putString("legacy_id", "").build());
componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", "item.minecartFurnace.name").build());
// Indicate that the arm animation should play on rails
List<NbtMap> useOnTag = Collections.singletonList(NbtMap.builder().putString("tags", "q.any_tag('rail')").build());
componentBuilder.putCompound("minecraft:entity_placer", NbtMap.builder()
.putList("dispense_on", NbtType.COMPOUND, useOnTag)
.putString("entity", "minecraft:minecart")
.putList("use_on", NbtType.COMPOUND, useOnTag)
.build()); .build());
// We always want to allow offhand usage when we can - matches Java Edition registerFurnaceMinecart(nextFreeBedrockId++, componentItemData);
itemProperties.putBoolean("allow_off_hand", true);
itemProperties.putBoolean("hand_equipped", false);
itemProperties.putInt("max_stack_size", 1);
itemProperties.putString("creative_group", "itemGroup.name.minecart");
itemProperties.putInt("creative_category", 4); // 4 - "Items"
componentBuilder.putCompound("item_properties", itemProperties.build());
builder.putCompound("components", componentBuilder.build());
componentItemData.add(new ComponentItemData("geysermc:furnace_minecart", builder.build()));
// Register any completely custom items given to us // Register any completely custom items given to us
IntSet registeredJavaIds = new IntOpenHashSet(); // Used to check for duplicate item java ids IntSet registeredJavaIds = new IntOpenHashSet(); // Used to check for duplicate item java ids
@ -657,8 +527,9 @@ public class ItemRegistryPopulator {
if (customItem.creativeGroup() != null || customItem.creativeCategory().isPresent()) { if (customItem.creativeGroup() != null || customItem.creativeCategory().isPresent()) {
creativeItems.add(ItemData.builder() creativeItems.add(ItemData.builder()
.definition(registration.mapping().getBedrockDefinition()) .definition(registration.mapping().getBedrockDefinition())
.netId(netId++) .netId(creativeNetId.getAndIncrement())
.count(1).build()); .count(1)
.build());
} }
} }
} }
@ -669,7 +540,7 @@ public class ItemRegistryPopulator {
.definitionRegistry(registry.build()) .definitionRegistry(registry.build())
.itemDefinitions(List.copyOf(definitions.values())) .itemDefinitions(List.copyOf(definitions.values()))
.itemNames(itemNames.toArray(new String[0])) .itemNames(itemNames.toArray(new String[0]))
.storedItems(new StoredItemMappings(identifierToMapping)) .storedItems(new StoredItemMappings(javaIdentifierToMapping))
.javaOnlyItems(javaOnlyItems) .javaOnlyItems(javaOnlyItems)
.buckets(buckets) .buckets(buckets)
.boats(boats) .boats(boats)
@ -687,4 +558,40 @@ public class ItemRegistryPopulator {
ItemUtils.setDyeColors(dyeColors); ItemUtils.setDyeColors(dyeColors);
} }
private static void registerFurnaceMinecart(int nextFreeBedrockId, List<ComponentItemData> componentItemData) {
NbtMapBuilder builder = NbtMap.builder();
builder.putString("name", "geysermc:furnace_minecart")
.putInt("id", nextFreeBedrockId);
NbtMapBuilder itemProperties = NbtMap.builder();
NbtMapBuilder componentBuilder = NbtMap.builder();
// Conveniently, as of 1.16.200, the furnace minecart has a texture AND translation string already.
itemProperties.putCompound("minecraft:icon", NbtMap.builder()
.putString("texture", "minecart_furnace")
.putString("frame", "0.000000")
.putInt("frame_version", 1)
.putString("legacy_id", "").build());
componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", "item.minecartFurnace.name").build());
// Indicate that the arm animation should play on rails
List<NbtMap> useOnTag = Collections.singletonList(NbtMap.builder().putString("tags", "q.any_tag('rail')").build());
componentBuilder.putCompound("minecraft:entity_placer", NbtMap.builder()
.putList("dispense_on", NbtType.COMPOUND, useOnTag)
.putString("entity", "minecraft:minecart")
.putList("use_on", NbtType.COMPOUND, useOnTag)
.build());
// We always want to allow offhand usage when we can - matches Java Edition
itemProperties.putBoolean("allow_off_hand", true);
itemProperties.putBoolean("hand_equipped", false);
itemProperties.putInt("max_stack_size", 1);
itemProperties.putString("creative_group", "itemGroup.name.minecart");
itemProperties.putInt("creative_category", 4); // 4 - "Items"
componentBuilder.putCompound("item_properties", itemProperties.build());
builder.putCompound("components", componentBuilder.build());
componentItemData.add(new ComponentItemData("geysermc:furnace_minecart", builder.build()));
}
} }

View File

@ -232,7 +232,7 @@ public class RecipeRegistryPopulator {
.definition(mapping.getBedrockDefinition()) .definition(mapping.getBedrockDefinition())
.damage(damage) .damage(damage)
.count(count) .count(count)
.blockRuntimeId(mapping.isBlock() ? mapping.getBedrockBlockId() : 0) .blockDefinition(mapping.getBedrockBlockDefinition())
.tag(tag) .tag(tag)
.build(); .build();
} }

View File

@ -73,18 +73,11 @@ public class BlockMappings {
return this.javaToBedrockBlocks[state]; return this.javaToBedrockBlocks[state];
} }
public int getItemFrame(NbtMap tag) { public BlockDefinition getItemFrame(NbtMap tag) {
BlockDefinition definition = this.itemFrames.get(tag); return this.itemFrames.get(tag);
return definition == null ? -1 : definition.getRuntimeId();
} }
public boolean isItemFrame(int bedrockBlockRuntimeId) { public boolean isItemFrame(BlockDefinition definition) {
for (Map.Entry<NbtMap, BlockDefinition> entry : this.itemFrames.entrySet()) { return this.itemFrames.containsKey(definition.getState());
if (entry.getValue().getRuntimeId() == bedrockBlockRuntimeId) {
return true;
}
}
return false;
} }
} }

View File

@ -26,11 +26,11 @@
package org.geysermc.geyser.registry.type; package org.geysermc.geyser.registry.type;
import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.objects.ObjectIntPair;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Value; import lombok.Value;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.item.custom.CustomItemOptions;
@ -48,7 +48,7 @@ public class ItemMapping {
0, 0,
ItemDefinition.AIR, ItemDefinition.AIR,
0, 0,
0, // Air is never sent in full over the network for this to serialize. null, // Air is never sent in full over the network for this to serialize.
64, 64,
null, null,
null, null,
@ -69,7 +69,7 @@ public class ItemMapping {
* The Bedrock block runtime ID to render this item with. The specific state *does* matter in how this item is rendered and used as a crafting ingredient. * The Bedrock block runtime ID to render this item with. The specific state *does* matter in how this item is rendered and used as a crafting ingredient.
* Required since 1.16.220. * Required since 1.16.220.
*/ */
int bedrockBlockId; BlockDefinition bedrockBlockDefinition;
int stackSize; int stackSize;
String toolType; String toolType;
@ -92,7 +92,7 @@ public class ItemMapping {
* @return if this item is a block * @return if this item is a block
*/ */
public boolean isBlock() { public boolean isBlock() {
return this.bedrockBlockId != -1; return this.bedrockBlockDefinition != null;
} }
/** /**

View File

@ -127,13 +127,13 @@ public class ItemMappings {
return lodestoneCompass; return lodestoneCompass;
} }
boolean isBlock = data.getBlockRuntimeId() != 0; boolean isBlock = data.getBlockDefinition() != null;
boolean hasDamage = data.getDamage() != 0; boolean hasDamage = data.getDamage() != 0;
for (ItemMapping mapping : this.items) { for (ItemMapping mapping : this.items) {
if (mapping.getBedrockDefinition().equals(definition)) { if (mapping.getBedrockDefinition().equals(definition)) {
if (isBlock && !hasDamage) { // Pre-1.16.220 will not use block runtime IDs at all, so we shouldn't check either if (isBlock && !hasDamage) { // Pre-1.16.220 will not use block runtime IDs at all, so we shouldn't check either
if (data.getBlockRuntimeId() != mapping.getBedrockBlockId()) { if (data.getBlockDefinition() != mapping.getBedrockBlockDefinition()) {
continue; continue;
} }
} else { } else {

View File

@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.inventory.chest;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket; import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket;
@ -82,12 +83,12 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP); Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP);
Vector3i pairPosition = position.add(Vector3i.UNIT_X); Vector3i pairPosition = position.add(Vector3i.UNIT_X);
int bedrockBlockId = session.getBlockMappings().getBedrockBlockId(defaultJavaBlockState); BlockDefinition definition = session.getBlockMappings().getBedrockBlock(defaultJavaBlockState);
UpdateBlockPacket blockPacket = new UpdateBlockPacket(); UpdateBlockPacket blockPacket = new UpdateBlockPacket();
blockPacket.setDataLayer(0); blockPacket.setDataLayer(0);
blockPacket.setBlockPosition(position); blockPacket.setBlockPosition(position);
blockPacket.setRuntimeId(bedrockBlockId); blockPacket.setDefinition(definition);
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
session.sendUpstreamPacket(blockPacket); session.sendUpstreamPacket(blockPacket);
@ -107,7 +108,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
blockPacket = new UpdateBlockPacket(); blockPacket = new UpdateBlockPacket();
blockPacket.setDataLayer(0); blockPacket.setDataLayer(0);
blockPacket.setBlockPosition(pairPosition); blockPacket.setBlockPosition(pairPosition);
blockPacket.setRuntimeId(bedrockBlockId); blockPacket.setDefinition(definition);
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
session.sendUpstreamPacket(blockPacket); session.sendUpstreamPacket(blockPacket);
@ -154,7 +155,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
UpdateBlockPacket blockPacket = new UpdateBlockPacket(); UpdateBlockPacket blockPacket = new UpdateBlockPacket();
blockPacket.setDataLayer(0); blockPacket.setDataLayer(0);
blockPacket.setBlockPosition(holderPos); blockPacket.setBlockPosition(holderPos);
blockPacket.setRuntimeId(session.getBlockMappings().getBedrockBlockId(realBlock)); blockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(realBlock));
session.sendUpstreamPacket(blockPacket); session.sendUpstreamPacket(blockPacket);
holderPos = holderPos.add(Vector3i.UNIT_X); holderPos = holderPos.add(Vector3i.UNIT_X);
@ -162,7 +163,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
blockPacket = new UpdateBlockPacket(); blockPacket = new UpdateBlockPacket();
blockPacket.setDataLayer(0); blockPacket.setDataLayer(0);
blockPacket.setBlockPosition(holderPos); blockPacket.setBlockPosition(holderPos);
blockPacket.setRuntimeId(session.getBlockMappings().getBedrockBlockId(realBlock)); blockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(realBlock));
session.sendUpstreamPacket(blockPacket); session.sendUpstreamPacket(blockPacket);
} }
} }

View File

@ -26,18 +26,30 @@
package org.geysermc.geyser.translator.inventory.item; package org.geysermc.geyser.translator.inventory.item;
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.ByteArrayTag;
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.DoubleTag;
import com.github.steveice10.opennbt.tag.builtin.FloatTag;
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.LongArrayTag;
import com.github.steveice10.opennbt.tag.builtin.LongTag;
import com.github.steveice10.opennbt.tag.builtin.ShortTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.nbt.NbtList; import com.nukkitx.nbt.NbtList;
import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType; import com.nukkitx.nbt.NbtType;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
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 org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
@ -50,7 +62,11 @@ import org.geysermc.geyser.util.FileUtils;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.*; import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public abstract class ItemTranslator { public abstract class ItemTranslator {
@ -169,7 +185,7 @@ public abstract class ItemTranslator {
ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.getOrDefault(bedrockItem.getJavaId(), DEFAULT_TRANSLATOR); ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.getOrDefault(bedrockItem.getJavaId(), DEFAULT_TRANSLATOR);
ItemData.Builder builder = itemStackTranslator.translateToBedrock(itemStack, bedrockItem, session.getItemMappings()); ItemData.Builder builder = itemStackTranslator.translateToBedrock(itemStack, bedrockItem, session.getItemMappings());
if (bedrockItem.isBlock()) { if (bedrockItem.isBlock()) {
builder.blockRuntimeId(bedrockItem.getBedrockBlockId()); builder.blockDefinition(bedrockItem.getBedrockBlockDefinition());
} }
if (nbt != null) { if (nbt != null) {

View File

@ -80,7 +80,7 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity {
BlockEntityUtils.updateBlockEntity(session, tag, position); BlockEntityUtils.updateBlockEntity(session, tag, position);
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0); updateBlockPacket.setDataLayer(0);
updateBlockPacket.setRuntimeId(session.getBlockMappings().getBedrockBlockId(blockState)); updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(blockState));
updateBlockPacket.setBlockPosition(position); updateBlockPacket.setBlockPosition(position);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);

View File

@ -598,7 +598,7 @@ public class PistonBlockEntity {
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
updateBlockPacket.setBlockPosition(newPos); updateBlockPacket.setBlockPosition(newPos);
updateBlockPacket.setRuntimeId(session.getBlockMappings().getBedrockMovingBlock().getRuntimeId()); updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockMovingBlock());
updateBlockPacket.setDataLayer(0); updateBlockPacket.setDataLayer(0);
session.sendUpstreamPacket(updateBlockPacket); session.sendUpstreamPacket(updateBlockPacket);
// Update moving block with correct details // Update moving block with correct details

View File

@ -195,7 +195,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
} }
// Bedrock sends block interact code for a Java entity so we send entity code back to Java // Bedrock sends block interact code for a Java entity so we send entity code back to Java
if (session.getBlockMappings().isItemFrame(packet.getBlockRuntimeId())) { if (session.getBlockMappings().isItemFrame(packet.getBlockDefinition())) {
Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition()); Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition());
if (itemFrameEntity != null) { if (itemFrameEntity != null) {
processEntityInteraction(session, packet, itemFrameEntity); processEntityInteraction(session, packet, itemFrameEntity);
@ -313,7 +313,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
if (packet.getActions().isEmpty()) { if (packet.getActions().isEmpty()) {
if (session.getOpPermissionLevel() >= 2 && session.getGameMode() == GameMode.CREATIVE) { if (session.getOpPermissionLevel() >= 2 && session.getGameMode() == GameMode.CREATIVE) {
// Otherwise insufficient permissions // Otherwise insufficient permissions
if (session.getBlockMappings().getJigsawStates().contains(packet.getBlockRuntimeId())) { if (session.getBlockMappings().getJigsawStates().contains(packet.getBlockDefinition())) {
ContainerOpenPacket openPacket = new ContainerOpenPacket(); ContainerOpenPacket openPacket = new ContainerOpenPacket();
openPacket.setBlockPosition(packet.getBlockPosition()); openPacket.setBlockPosition(packet.getBlockPosition());
openPacket.setId((byte) 1); openPacket.setId((byte) 1);
@ -539,14 +539,14 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0); updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(blockPos); updateBlockPacket.setBlockPosition(blockPos);
updateBlockPacket.setRuntimeId(session.getBlockMappings().getBedrockBlockId(javaBlockState)); updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(javaBlockState));
updateBlockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); updateBlockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
session.sendUpstreamPacket(updateBlockPacket); session.sendUpstreamPacket(updateBlockPacket);
UpdateBlockPacket updateWaterPacket = new UpdateBlockPacket(); UpdateBlockPacket updateWaterPacket = new UpdateBlockPacket();
updateWaterPacket.setDataLayer(1); updateWaterPacket.setDataLayer(1);
updateWaterPacket.setBlockPosition(blockPos); updateWaterPacket.setBlockPosition(blockPos);
updateWaterPacket.setRuntimeId((BlockRegistries.WATERLOGGED.get().contains(javaBlockState) ? session.getBlockMappings().getBedrockWater() : session.getBlockMappings().getBedrockAir()).getRuntimeId()); updateWaterPacket.setDefinition(BlockRegistries.WATERLOGGED.get().contains(javaBlockState) ? session.getBlockMappings().getBedrockWater() : session.getBlockMappings().getBedrockAir());
updateWaterPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); updateWaterPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
session.sendUpstreamPacket(updateWaterPacket); session.sendUpstreamPacket(updateWaterPacket);

View File

@ -27,6 +27,7 @@ package org.geysermc.geyser.util;
import org.cloudburstmc.math.vector.Vector2i; import org.cloudburstmc.math.vector.Vector2i;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket;
import org.cloudburstmc.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket; import org.cloudburstmc.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
@ -133,12 +134,12 @@ public class ChunkUtils {
// Prevent moving_piston from being placed // Prevent moving_piston from being placed
// It's used for extending piston heads, but it isn't needed on Bedrock and causes pistons to flicker // It's used for extending piston heads, but it isn't needed on Bedrock and causes pistons to flicker
if (!BlockStateValues.isMovingPiston(blockState)) { if (!BlockStateValues.isMovingPiston(blockState)) {
int blockId = session.getBlockMappings().getBedrockBlockId(blockState); BlockDefinition definition = session.getBlockMappings().getBedrockBlock(blockState);
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0); updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(position); updateBlockPacket.setBlockPosition(position);
updateBlockPacket.setRuntimeId(blockId); updateBlockPacket.setDefinition(definition);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
session.sendUpstreamPacket(updateBlockPacket); session.sendUpstreamPacket(updateBlockPacket);
@ -147,9 +148,9 @@ public class ChunkUtils {
waterPacket.setDataLayer(1); waterPacket.setDataLayer(1);
waterPacket.setBlockPosition(position); waterPacket.setBlockPosition(position);
if (BlockRegistries.WATERLOGGED.get().contains(blockState)) { if (BlockRegistries.WATERLOGGED.get().contains(blockState)) {
waterPacket.setRuntimeId(session.getBlockMappings().getBedrockWater().getRuntimeId()); waterPacket.setDefinition(session.getBlockMappings().getBedrockWater());
} else { } else {
waterPacket.setRuntimeId(session.getBlockMappings().getBedrockAir().getRuntimeId()); waterPacket.setDefinition(session.getBlockMappings().getBedrockAir());
} }
session.sendUpstreamPacket(waterPacket); session.sendUpstreamPacket(waterPacket);
} }
@ -197,7 +198,7 @@ public class ChunkUtils {
UpdateBlockPacket blockPacket = new UpdateBlockPacket(); UpdateBlockPacket blockPacket = new UpdateBlockPacket();
blockPacket.setBlockPosition(pos); blockPacket.setBlockPosition(pos);
blockPacket.setDataLayer(0); blockPacket.setDataLayer(0);
blockPacket.setRuntimeId(1); blockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(1));
session.sendUpstreamPacket(blockPacket); session.sendUpstreamPacket(blockPacket);
} }
} }