From 64b078801243fadbac529cfc5c4092ac5b105b4f Mon Sep 17 00:00:00 2001 From: Redned Date: Sat, 4 Sep 2021 12:36:09 -0500 Subject: [PATCH] Use an array for java blocks and replace rarely used map in BlockMappings --- ...BedrockInventoryTransactionTranslator.java | 6 +- .../connector/registry/ArrayRegistry.java | 151 ++++++++++++++++++ .../connector/registry/BlockRegistries.java | 5 +- .../geysermc/connector/registry/Registry.java | 13 +- .../loader/CollisionRegistryLoader.java | 9 +- .../populator/BlockRegistryPopulator.java | 18 ++- .../registry/type/BlockMappings.java | 9 +- 7 files changed, 185 insertions(+), 26 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/registry/ArrayRegistry.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 45135d90c..1f909806b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -232,11 +232,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator= 2 && session.getGameMode() == GameMode.CREATIVE) { // Otherwise insufficient permissions - int blockState = session.getBlockMappings().getJavaBlockState(packet.getBlockRuntimeId()); - String blockName = BlockRegistries.JAVA_IDENTIFIERS.get().getOrDefault(blockState, ""); - // In the future this can be used for structure blocks too, however not all elements - // are available in each GUI - if (blockName.contains("jigsaw")) { + if (session.getBlockMappings().getJigsawStateIds().contains(packet.getBlockRuntimeId())) { ContainerOpenPacket openPacket = new ContainerOpenPacket(); openPacket.setBlockPosition(packet.getBlockPosition()); openPacket.setId((byte) 1); diff --git a/connector/src/main/java/org/geysermc/connector/registry/ArrayRegistry.java b/connector/src/main/java/org/geysermc/connector/registry/ArrayRegistry.java new file mode 100644 index 000000000..bb97ddb12 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/ArrayRegistry.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry; + +import org.geysermc.connector.registry.loader.RegistryLoader; + +import javax.annotation.Nullable; +import java.util.function.Supplier; + +/** + * An array registry that stores mappings as an array defined by {@link M}. + * The M represents the value that is to be stored as part of this array. + * + * @param the mapping type + */ +public class ArrayRegistry extends Registry { + + /** + * Creates a new array registry of this class with the given input and + * {@link RegistryLoader}. The input specified is what the registry + * loader needs to take in. + * + * @param input the input + * @param registryLoader the registry loader + */ + protected ArrayRegistry(I input, RegistryLoader registryLoader) { + super(input, registryLoader); + } + + /** + * Returns the value registered by the given index. + * + * @param index the index + * @return the value registered by the given index. + */ + @Nullable + public M get(int index) { + if (index >= this.mappings.length) { + return null; + } + + return this.mappings[index]; + } + + /** + * Returns the value registered by the given index or the default value + * specified if null. + * + * @param index the index + * @param defaultValue the default value + * @return the value registered by the given key or the default value + * specified if null. + */ + public M getOrDefault(int index, M defaultValue) { + M value = this.get(index); + if (value == null) { + return defaultValue; + } + + return value; + } + + /** + * Registers a new value into this registry with the given index. + * + * @param index the index + * @param value the value + * @return a new value into this registry with the given index. + */ + public M register(int index, M value) { + return this.mappings[index] = value; + } + + /** + * Creates a new array registry with the given {@link RegistryLoader} supplier. The + * input type is not specified here, meaning the loader return type is either + * predefined, or the registry is populated at a later point. + * + * @param registryLoader the registry loader supplier + * @param the input type + * @param the returned mappings type + * @return a new registry with the given RegistryLoader supplier + */ + public static ArrayRegistry create(Supplier> registryLoader) { + return new ArrayRegistry<>(null, registryLoader.get()); + } + + /** + * Creates a new array registry with the given {@link RegistryLoader} supplier + * and input. + * + * @param input the input + * @param registryLoader the registry loader supplier + * @param the input type + * @param the returned mappings type + * @return a new registry with the given RegistryLoader supplier + */ + public static ArrayRegistry create(I input, Supplier> registryLoader) { + return new ArrayRegistry<>(input, registryLoader.get()); + } + + /** + * Creates a new array registry with the given {@link RegistryLoader}. The + * input type is not specified here, meaning the loader return type is either + * predefined, or the registry is populated at a later point. + * + * @param registryLoader the registry loader + * @param the input type + * @param the returned mappings type + * @return a new registry with the given RegistryLoader supplier + */ + public static ArrayRegistry create(RegistryLoader registryLoader) { + return new ArrayRegistry<>(null, registryLoader); + } + + /** + * Creates a new array registry with the given {@link RegistryLoader} and input. + * + * @param input the input + * @param registryLoader the registry loader + * @param the input type + * @param the returned mappings type + * @return a new registry with the given RegistryLoader supplier + */ + public static ArrayRegistry create(I input, RegistryLoader registryLoader) { + return new ArrayRegistry<>(input, registryLoader); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/registry/BlockRegistries.java b/connector/src/main/java/org/geysermc/connector/registry/BlockRegistries.java index 09069eb5a..275353300 100644 --- a/connector/src/main/java/org/geysermc/connector/registry/BlockRegistries.java +++ b/connector/src/main/java/org/geysermc/connector/registry/BlockRegistries.java @@ -25,7 +25,6 @@ package org.geysermc.connector.registry; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; @@ -52,10 +51,10 @@ public class BlockRegistries { public static final SimpleMappedRegistry JAVA_TO_BEDROCK_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); /** - * A mapped registry which stores Java IDs to {@link BlockMapping}, containing miscellaneous information about + * A registry which stores Java IDs to {@link BlockMapping}, containing miscellaneous information about * blocks and their behavior in many cases. */ - public static final MappedRegistry> JAVA_BLOCKS = MappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + public static final ArrayRegistry JAVA_BLOCKS = ArrayRegistry.create(RegistryLoaders.empty(() -> new BlockMapping[] {})); /** * A (bi)mapped registry containing the Java IDs to identifiers. diff --git a/connector/src/main/java/org/geysermc/connector/registry/Registry.java b/connector/src/main/java/org/geysermc/connector/registry/Registry.java index 135e94342..dfa0e3397 100644 --- a/connector/src/main/java/org/geysermc/connector/registry/Registry.java +++ b/connector/src/main/java/org/geysermc/connector/registry/Registry.java @@ -64,7 +64,7 @@ import java.util.function.Consumer; * @param the value being held by the registry */ public abstract class Registry { - protected final M mappings; + protected M mappings; /** * Creates a new instance of this class with the given input and @@ -88,6 +88,17 @@ public abstract class Registry { return this.mappings; } + /** + * Sets the underlying value held by this registry. + * Clears any existing data associated with the previous + * value. + * + * @param mappings the underlying value held by this registry + */ + public void set(M mappings) { + this.mappings = mappings; + } + /** * Registers what is specified in the given * {@link Consumer} into the underlying value. diff --git a/connector/src/main/java/org/geysermc/connector/registry/loader/CollisionRegistryLoader.java b/connector/src/main/java/org/geysermc/connector/registry/loader/CollisionRegistryLoader.java index 049f1d726..49ccfd831 100644 --- a/connector/src/main/java/org/geysermc/connector/registry/loader/CollisionRegistryLoader.java +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/CollisionRegistryLoader.java @@ -75,12 +75,13 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader blockMap = BlockRegistries.JAVA_BLOCKS.get(); + BlockMapping[] blockMappings = BlockRegistries.JAVA_BLOCKS.get(); // Map of unique collisions to its instance Map collisionInstances = new Object2ObjectOpenHashMap<>(); - for (Int2ObjectMap.Entry entry : blockMap.int2ObjectEntrySet()) { - BlockCollision newCollision = instantiateCollision(entry.getValue(), annotationMap, collisionList); + for (int i = 0; i < blockMappings.length; i++) { + BlockMapping blockMapping = blockMappings[i]; + BlockCollision newCollision = instantiateCollision(blockMapping, annotationMap, collisionList); if (newCollision != null) { // If there's an existing instance equal to this one, use that instead @@ -92,7 +93,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader stateMapper = STATE_MAPPER.getOrDefault(palette.getKey(), (i, s) -> null); IntList javaToBedrockBlockMap = new IntArrayList(); - Int2IntMap bedrockToJavaBlockMap = new Int2IntOpenHashMap(); Map flowerPotBlocks = new Object2ObjectOpenHashMap<>(); Object2IntMap itemFrames = new Object2IntOpenHashMap<>(); + IntSet jigsawStateIds = new IntOpenHashSet(); + BlockMappings.BlockMappingsBuilder builder = BlockMappings.builder(); while (blocksIterator.hasNext()) { javaRuntimeId++; @@ -169,15 +170,16 @@ public class BlockRegistryPopulator { break; } + if (javaId.contains("jigsaw")) { + jigsawStateIds.add(bedrockRuntimeId); + } + boolean waterlogged = entry.getKey().contains("waterlogged=true") || javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass"); if (waterlogged) { - bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId | 1 << 31, javaRuntimeId); int finalJavaRuntimeId = javaRuntimeId; BlockRegistries.WATERLOGGED.register(set -> set.add(finalJavaRuntimeId)); - } else { - bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId, javaRuntimeId); } String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(entry.getKey()); @@ -221,10 +223,10 @@ public class BlockRegistryPopulator { BlockRegistries.BLOCKS.register(PALETTE_VERSIONS.getInt(palette.getKey()), builder.blockStateVersion(stateVersion) .emptyChunkSection(new ChunkSection(new BlockStorage[]{new BlockStorage(airRuntimeId)})) .javaToBedrockBlockMap(javaToBedrockBlockMap.toIntArray()) - .bedrockToJavaBlockMap(bedrockToJavaBlockMap) .javaIdentifierToBedrockTag(javaIdentifierToBedrockTag) .itemFrames(itemFrames) .flowerPotBlocks(flowerPotBlocks) + .jigsawStateIds(jigsawStateIds) .build()); } } @@ -239,6 +241,8 @@ public class BlockRegistryPopulator { throw new AssertionError("Unable to load Java block mappings", e); } + BlockRegistries.JAVA_BLOCKS.set(new BlockMapping[blocksJson.size()]); // Set array size to number of blockstates + Set cleanIdentifiers = new HashSet<>(); int javaRuntimeId = -1; diff --git a/connector/src/main/java/org/geysermc/connector/registry/type/BlockMappings.java b/connector/src/main/java/org/geysermc/connector/registry/type/BlockMappings.java index 09b3db08e..6fb28d7ab 100644 --- a/connector/src/main/java/org/geysermc/connector/registry/type/BlockMappings.java +++ b/connector/src/main/java/org/geysermc/connector/registry/type/BlockMappings.java @@ -27,7 +27,7 @@ package org.geysermc.connector.registry.type; import com.nukkitx.nbt.NbtList; import com.nukkitx.nbt.NbtMap; -import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.Builder; import lombok.Value; @@ -46,7 +46,6 @@ public class BlockMappings { ChunkSection emptyChunkSection; int[] javaToBedrockBlockMap; - Int2IntMap bedrockToJavaBlockMap; NbtList bedrockBlockStates; @@ -61,6 +60,8 @@ public class BlockMappings { Object2IntMap itemFrames; Map flowerPotBlocks; + IntSet jigsawStateIds; + public int getBedrockBlockId(int state) { if (state >= this.javaToBedrockBlockMap.length) { return bedrockAirId; @@ -68,10 +69,6 @@ public class BlockMappings { return this.javaToBedrockBlockMap[state]; } - public int getJavaBlockState(int bedrockId) { - return this.bedrockToJavaBlockMap.get(bedrockId); - } - public int getItemFrame(NbtMap tag) { return this.itemFrames.getOrDefault(tag, -1); }