Use an array for java blocks and replace rarely used map in BlockMappings

This commit is contained in:
Redned 2021-09-04 12:36:09 -05:00 committed by RednedEpic
parent 206368e448
commit 64b0788012
7 changed files with 185 additions and 26 deletions

View file

@ -232,11 +232,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
int blockState = session.getBlockMappings().getJavaBlockState(packet.getBlockRuntimeId()); if (session.getBlockMappings().getJigsawStateIds().contains(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")) {
ContainerOpenPacket openPacket = new ContainerOpenPacket(); ContainerOpenPacket openPacket = new ContainerOpenPacket();
openPacket.setBlockPosition(packet.getBlockPosition()); openPacket.setBlockPosition(packet.getBlockPosition());
openPacket.setId((byte) 1); openPacket.setId((byte) 1);

View file

@ -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 <M> the mapping type
*/
public class ArrayRegistry<M> extends Registry<M[]> {
/**
* 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 <I> ArrayRegistry(I input, RegistryLoader<I, M[]> 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 <I> the input type
* @param <M> the returned mappings type
* @return a new registry with the given RegistryLoader supplier
*/
public static <I, M> ArrayRegistry<M> create(Supplier<RegistryLoader<I, M[]>> 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 <I> the input type
* @param <M> the returned mappings type
* @return a new registry with the given RegistryLoader supplier
*/
public static <I, M> ArrayRegistry<M> create(I input, Supplier<RegistryLoader<I, M[]>> 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 <I> the input type
* @param <M> the returned mappings type
* @return a new registry with the given RegistryLoader supplier
*/
public static <I, M> ArrayRegistry<M> create(RegistryLoader<I, M[]> 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 <I> the input type
* @param <M> the returned mappings type
* @return a new registry with the given RegistryLoader supplier
*/
public static <I, M> ArrayRegistry<M> create(I input, RegistryLoader<I, M[]> registryLoader) {
return new ArrayRegistry<>(input, registryLoader);
}
}

View file

@ -25,7 +25,6 @@
package org.geysermc.connector.registry; 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.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
@ -52,10 +51,10 @@ public class BlockRegistries {
public static final SimpleMappedRegistry<String, String> JAVA_TO_BEDROCK_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); public static final SimpleMappedRegistry<String, String> 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. * blocks and their behavior in many cases.
*/ */
public static final MappedRegistry<Integer, BlockMapping, Int2ObjectMap<BlockMapping>> JAVA_BLOCKS = MappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); public static final ArrayRegistry<BlockMapping> JAVA_BLOCKS = ArrayRegistry.create(RegistryLoaders.empty(() -> new BlockMapping[] {}));
/** /**
* A (bi)mapped registry containing the Java IDs to identifiers. * A (bi)mapped registry containing the Java IDs to identifiers.

View file

@ -64,7 +64,7 @@ import java.util.function.Consumer;
* @param <M> the value being held by the registry * @param <M> the value being held by the registry
*/ */
public abstract class Registry<M> { public abstract class Registry<M> {
protected final M mappings; protected M mappings;
/** /**
* Creates a new instance of this class with the given input and * Creates a new instance of this class with the given input and
@ -88,6 +88,17 @@ public abstract class Registry<M> {
return this.mappings; 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 * Registers what is specified in the given
* {@link Consumer} into the underlying value. * {@link Consumer} into the underlying value.

View file

@ -75,12 +75,13 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
throw new AssertionError("Unable to load collision data", e); throw new AssertionError("Unable to load collision data", e);
} }
Int2ObjectMap<BlockMapping> blockMap = BlockRegistries.JAVA_BLOCKS.get(); BlockMapping[] blockMappings = BlockRegistries.JAVA_BLOCKS.get();
// Map of unique collisions to its instance // Map of unique collisions to its instance
Map<BlockCollision, BlockCollision> collisionInstances = new Object2ObjectOpenHashMap<>(); Map<BlockCollision, BlockCollision> collisionInstances = new Object2ObjectOpenHashMap<>();
for (Int2ObjectMap.Entry<BlockMapping> entry : blockMap.int2ObjectEntrySet()) { for (int i = 0; i < blockMappings.length; i++) {
BlockCollision newCollision = instantiateCollision(entry.getValue(), annotationMap, collisionList); BlockMapping blockMapping = blockMappings[i];
BlockCollision newCollision = instantiateCollision(blockMapping, annotationMap, collisionList);
if (newCollision != null) { if (newCollision != null) {
// If there's an existing instance equal to this one, use that instead // If there's an existing instance equal to this one, use that instead
@ -92,7 +93,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
} }
} }
collisions.put(entry.getIntKey(), newCollision); collisions.put(i, newCollision);
} }
return collisions; return collisions;
} }

View file

@ -30,10 +30,10 @@ import com.google.common.collect.ImmutableMap;
import com.nukkitx.nbt.*; import com.nukkitx.nbt.*;
import com.nukkitx.protocol.bedrock.v440.Bedrock_v440; import com.nukkitx.protocol.bedrock.v440.Bedrock_v440;
import com.nukkitx.protocol.bedrock.v448.Bedrock_v448; import com.nukkitx.protocol.bedrock.v448.Bedrock_v448;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
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.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
@ -140,11 +140,12 @@ public class BlockRegistryPopulator {
BiFunction<String, NbtMapBuilder, String> stateMapper = STATE_MAPPER.getOrDefault(palette.getKey(), (i, s) -> null); BiFunction<String, NbtMapBuilder, String> stateMapper = STATE_MAPPER.getOrDefault(palette.getKey(), (i, s) -> null);
IntList javaToBedrockBlockMap = new IntArrayList(); IntList javaToBedrockBlockMap = new IntArrayList();
Int2IntMap bedrockToJavaBlockMap = new Int2IntOpenHashMap();
Map<String, NbtMap> flowerPotBlocks = new Object2ObjectOpenHashMap<>(); Map<String, NbtMap> flowerPotBlocks = new Object2ObjectOpenHashMap<>();
Object2IntMap<NbtMap> itemFrames = new Object2IntOpenHashMap<>(); Object2IntMap<NbtMap> itemFrames = new Object2IntOpenHashMap<>();
IntSet jigsawStateIds = new IntOpenHashSet();
BlockMappings.BlockMappingsBuilder builder = BlockMappings.builder(); BlockMappings.BlockMappingsBuilder builder = BlockMappings.builder();
while (blocksIterator.hasNext()) { while (blocksIterator.hasNext()) {
javaRuntimeId++; javaRuntimeId++;
@ -169,15 +170,16 @@ public class BlockRegistryPopulator {
break; break;
} }
if (javaId.contains("jigsaw")) {
jigsawStateIds.add(bedrockRuntimeId);
}
boolean waterlogged = entry.getKey().contains("waterlogged=true") boolean waterlogged = entry.getKey().contains("waterlogged=true")
|| javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass"); || javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass");
if (waterlogged) { if (waterlogged) {
bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId | 1 << 31, javaRuntimeId);
int finalJavaRuntimeId = javaRuntimeId; int finalJavaRuntimeId = javaRuntimeId;
BlockRegistries.WATERLOGGED.register(set -> set.add(finalJavaRuntimeId)); BlockRegistries.WATERLOGGED.register(set -> set.add(finalJavaRuntimeId));
} else {
bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId, javaRuntimeId);
} }
String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(entry.getKey()); String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(entry.getKey());
@ -221,10 +223,10 @@ public class BlockRegistryPopulator {
BlockRegistries.BLOCKS.register(PALETTE_VERSIONS.getInt(palette.getKey()), builder.blockStateVersion(stateVersion) BlockRegistries.BLOCKS.register(PALETTE_VERSIONS.getInt(palette.getKey()), builder.blockStateVersion(stateVersion)
.emptyChunkSection(new ChunkSection(new BlockStorage[]{new BlockStorage(airRuntimeId)})) .emptyChunkSection(new ChunkSection(new BlockStorage[]{new BlockStorage(airRuntimeId)}))
.javaToBedrockBlockMap(javaToBedrockBlockMap.toIntArray()) .javaToBedrockBlockMap(javaToBedrockBlockMap.toIntArray())
.bedrockToJavaBlockMap(bedrockToJavaBlockMap)
.javaIdentifierToBedrockTag(javaIdentifierToBedrockTag) .javaIdentifierToBedrockTag(javaIdentifierToBedrockTag)
.itemFrames(itemFrames) .itemFrames(itemFrames)
.flowerPotBlocks(flowerPotBlocks) .flowerPotBlocks(flowerPotBlocks)
.jigsawStateIds(jigsawStateIds)
.build()); .build());
} }
} }
@ -239,6 +241,8 @@ public class BlockRegistryPopulator {
throw new AssertionError("Unable to load Java block mappings", e); 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<String> cleanIdentifiers = new HashSet<>(); Set<String> cleanIdentifiers = new HashSet<>();
int javaRuntimeId = -1; int javaRuntimeId = -1;

View file

@ -27,7 +27,7 @@ package org.geysermc.connector.registry.type;
import com.nukkitx.nbt.NbtList; import com.nukkitx.nbt.NbtList;
import com.nukkitx.nbt.NbtMap; 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 it.unimi.dsi.fastutil.objects.Object2IntMap;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
@ -46,7 +46,6 @@ public class BlockMappings {
ChunkSection emptyChunkSection; ChunkSection emptyChunkSection;
int[] javaToBedrockBlockMap; int[] javaToBedrockBlockMap;
Int2IntMap bedrockToJavaBlockMap;
NbtList<NbtMap> bedrockBlockStates; NbtList<NbtMap> bedrockBlockStates;
@ -61,6 +60,8 @@ public class BlockMappings {
Object2IntMap<NbtMap> itemFrames; Object2IntMap<NbtMap> itemFrames;
Map<String, NbtMap> flowerPotBlocks; Map<String, NbtMap> flowerPotBlocks;
IntSet jigsawStateIds;
public int getBedrockBlockId(int state) { public int getBedrockBlockId(int state) {
if (state >= this.javaToBedrockBlockMap.length) { if (state >= this.javaToBedrockBlockMap.length) {
return bedrockAirId; return bedrockAirId;
@ -68,10 +69,6 @@ public class BlockMappings {
return this.javaToBedrockBlockMap[state]; return this.javaToBedrockBlockMap[state];
} }
public int getJavaBlockState(int bedrockId) {
return this.bedrockToJavaBlockMap.get(bedrockId);
}
public int getItemFrame(NbtMap tag) { public int getItemFrame(NbtMap tag) {
return this.itemFrames.getOrDefault(tag, -1); return this.itemFrames.getOrDefault(tag, -1);
} }