Some optimizations

- Fix recipe registry not using an int key-based map
- Versioned registries now use Fastutil more effectively
- Replace uses of String#split for block identifier manipulation with #indexOf and #substring
- Reuse Patterns in collision loader
This commit is contained in:
Camotoy 2021-07-15 18:03:41 -04:00
parent ba4e0cf5b9
commit 25edf41329
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
7 changed files with 62 additions and 40 deletions

View file

@ -36,20 +36,12 @@ import com.nukkitx.protocol.bedrock.data.inventory.PotionMixData;
import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.Pair;
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 it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import org.geysermc.connector.network.translators.collision.translators.BlockCollision; import org.geysermc.connector.network.translators.collision.translators.BlockCollision;
import org.geysermc.connector.network.translators.effect.Effect; import org.geysermc.connector.network.translators.effect.Effect;
import org.geysermc.connector.network.translators.sound.SoundHandler; import org.geysermc.connector.network.translators.sound.SoundHandler;
import org.geysermc.connector.network.translators.sound.SoundInteractionHandler; import org.geysermc.connector.network.translators.sound.SoundInteractionHandler;
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
import org.geysermc.connector.registry.loader.BlockEntityRegistryLoader; import org.geysermc.connector.registry.loader.*;
import org.geysermc.connector.registry.loader.CollisionRegistryLoader;
import org.geysermc.connector.registry.loader.ParticleTypesRegistryLoader;
import org.geysermc.connector.registry.loader.PotionMixRegistryLoader;
import org.geysermc.connector.registry.loader.RegistryLoaders;
import org.geysermc.connector.registry.loader.SoundEffectsRegistryLoader;
import org.geysermc.connector.registry.loader.SoundHandlerRegistryLoader;
import org.geysermc.connector.registry.loader.SoundRegistryLoader;
import org.geysermc.connector.registry.populator.ItemRegistryPopulator; import org.geysermc.connector.registry.populator.ItemRegistryPopulator;
import org.geysermc.connector.registry.populator.RecipeRegistryPopulator; import org.geysermc.connector.registry.populator.RecipeRegistryPopulator;
import org.geysermc.connector.registry.type.ItemMappings; import org.geysermc.connector.registry.type.ItemMappings;
@ -67,7 +59,7 @@ public class Registries {
public static final SimpleMappedRegistry<Integer, BlockCollision> COLLISIONS = SimpleMappedRegistry.create(Pair.of("org.geysermc.connector.network.translators.collision.translators", "mappings/collision.json"), CollisionRegistryLoader::new); public static final SimpleMappedRegistry<Integer, BlockCollision> COLLISIONS = SimpleMappedRegistry.create(Pair.of("org.geysermc.connector.network.translators.collision.translators", "mappings/collision.json"), CollisionRegistryLoader::new);
public static final VersionedRegistry<Map<RecipeType, List<CraftingData>>> CRAFTING_DATA = VersionedRegistry.create(RegistryLoaders.empty(Object2ObjectLinkedOpenHashMap::new)); public static final VersionedRegistry<Map<RecipeType, List<CraftingData>>> CRAFTING_DATA = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
public static final SimpleRegistry<NbtMap> ENTITY_IDENTIFIERS = SimpleRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT); public static final SimpleRegistry<NbtMap> ENTITY_IDENTIFIERS = SimpleRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT);

View file

@ -25,23 +25,23 @@
package org.geysermc.connector.registry; package org.geysermc.connector.registry;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import org.geysermc.connector.registry.loader.RegistryLoader; import org.geysermc.connector.registry.loader.RegistryLoader;
import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
public class VersionedRegistry<V> extends AbstractMappedRegistry<Integer, V, Map<Integer, V>> { public class VersionedRegistry<V> extends AbstractMappedRegistry<Integer, V, Int2ObjectMap<V>> {
protected <I> VersionedRegistry(I input, RegistryLoader<I, Map<Integer, V>> registryLoader) { protected <I> VersionedRegistry(I input, RegistryLoader<I, Int2ObjectMap<V>> registryLoader) {
super(input, registryLoader); super(input, registryLoader);
} }
public V forVersion(int version) { public V forVersion(int version) {
V value = null; V value = null;
for (Map.Entry<Integer, V> entry : this.mappings.entrySet()) { for (Int2ObjectMap.Entry<V> entry : this.mappings.int2ObjectEntrySet()) {
if (version < entry.getKey()) { if (version < entry.getIntKey()) {
continue; continue;
} }
if (version == entry.getKey()) { if (version == entry.getIntKey()) {
return entry.getValue(); return entry.getValue();
} }
value = entry.getValue(); value = entry.getValue();
@ -49,19 +49,19 @@ public class VersionedRegistry<V> extends AbstractMappedRegistry<Integer, V, Map
return value; return value;
} }
public static <I, V> VersionedRegistry<V> create(RegistryLoader<I, Map<Integer, V>> registryLoader) { public static <I, V> VersionedRegistry<V> create(RegistryLoader<I, Int2ObjectMap<V>> registryLoader) {
return new VersionedRegistry<>(null, registryLoader); return new VersionedRegistry<>(null, registryLoader);
} }
public static <I, V> VersionedRegistry<V> create(I input, RegistryLoader<I, Map<Integer, V>> registryLoader) { public static <I, V> VersionedRegistry<V> create(I input, RegistryLoader<I, Int2ObjectMap<V>> registryLoader) {
return new VersionedRegistry<>(input, registryLoader); return new VersionedRegistry<>(input, registryLoader);
} }
public static <I, V> VersionedRegistry< V> create(Supplier<RegistryLoader<I, Map<Integer, V>>> registryLoader) { public static <I, V> VersionedRegistry< V> create(Supplier<RegistryLoader<I, Int2ObjectMap<V>>> registryLoader) {
return new VersionedRegistry<>(null, registryLoader.get()); return new VersionedRegistry<>(null, registryLoader.get());
} }
public static <I, V> VersionedRegistry< V> create(I input, Supplier<RegistryLoader<I, Map<Integer, V>>> registryLoader) { public static <I, V> VersionedRegistry< V> create(I input, Supplier<RegistryLoader<I, Int2ObjectMap<V>>> registryLoader) {
return new VersionedRegistry<>(input, registryLoader.get()); return new VersionedRegistry<>(input, registryLoader.get());
} }
} }

View file

@ -30,6 +30,7 @@ import com.google.common.collect.BiMap;
import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.Pair;
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 lombok.AllArgsConstructor;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.translators.collision.BoundingBox; import org.geysermc.connector.network.translators.collision.BoundingBox;
import org.geysermc.connector.network.translators.collision.CollisionRemapper; import org.geysermc.connector.network.translators.collision.CollisionRemapper;
@ -43,9 +44,7 @@ import org.reflections.Reflections;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -55,14 +54,13 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
public Map<Integer, BlockCollision> load(Pair<String, String> input) { public Map<Integer, BlockCollision> load(Pair<String, String> input) {
Int2ObjectMap<BlockCollision> collisions = new Int2ObjectOpenHashMap<>(); Int2ObjectMap<BlockCollision> collisions = new Int2ObjectOpenHashMap<>();
List<Class<?>> collisionTypes = new ArrayList<>(); Map<Class<?>, CollisionInfo> annotationMap = new HashMap<>();
Map<Class<?>, CollisionRemapper> annotationMap = new HashMap<>();
Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections(input.key()) : new Reflections(input.key()); Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections(input.key()) : new Reflections(input.key());
for (Class<?> clazz : ref.getTypesAnnotatedWith(CollisionRemapper.class)) { for (Class<?> clazz : ref.getTypesAnnotatedWith(CollisionRemapper.class)) {
GeyserConnector.getInstance().getLogger().debug("Found annotated collision translator: " + clazz.getCanonicalName()); GeyserConnector.getInstance().getLogger().debug("Found annotated collision translator: " + clazz.getCanonicalName());
collisionTypes.add(clazz); CollisionRemapper collisionRemapper = clazz.getAnnotation(CollisionRemapper.class);
annotationMap.put(clazz, clazz.getAnnotation(CollisionRemapper.class)); annotationMap.put(clazz, new CollisionInfo(collisionRemapper, Pattern.compile(collisionRemapper.regex()), Pattern.compile(collisionRemapper.paramRegex())));
} }
// Load collision mappings file // Load collision mappings file
@ -80,7 +78,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
// Map of classes that don't change based on parameters that have already been created // Map of classes that don't change based on parameters that have already been created
Map<Class<?>, BlockCollision> instantiatedCollision = new HashMap<>(); Map<Class<?>, BlockCollision> instantiatedCollision = new HashMap<>();
for (Map.Entry<String, Integer> entry : javaIdBlockMap.entrySet()) { for (Map.Entry<String, Integer> entry : javaIdBlockMap.entrySet()) {
BlockCollision newCollision = instantiateCollision(entry.getKey(), entry.getValue(), collisionTypes, annotationMap, instantiatedCollision, collisionList); BlockCollision newCollision = instantiateCollision(entry.getKey(), entry.getValue(), annotationMap, instantiatedCollision, collisionList);
if (newCollision != null) { if (newCollision != null) {
instantiatedCollision.put(newCollision.getClass(), newCollision); instantiatedCollision.put(newCollision.getClass(), newCollision);
} }
@ -89,22 +87,21 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
return collisions; return collisions;
} }
private BlockCollision instantiateCollision(String blockID, int numericBlockID, List<Class<?>> collisionTypes, Map<Class<?>, CollisionRemapper> annotationMap, Map<Class<?>, BlockCollision> instantiatedCollision, ArrayNode collisionList) { private BlockCollision instantiateCollision(String blockID, int numericBlockID, Map<Class<?>, CollisionInfo> annotationMap, Map<Class<?>, BlockCollision> instantiatedCollision, ArrayNode collisionList) {
String[] blockIdParts = blockID.split("\\[");
String blockName = blockID.split("\\[")[0].replace("minecraft:", ""); String blockName = blockIdParts[0].replace("minecraft:", "");
String params = ""; String params = "";
if (blockID.contains("[")) { if (blockID.contains("[")) {
params = "[" + blockID.split("\\[")[1]; params = "[" + blockIdParts[1];
} }
int collisionIndex = BlockRegistries.JAVA_BLOCKS.get(numericBlockID).getCollisionIndex(); int collisionIndex = BlockRegistries.JAVA_BLOCKS.get(numericBlockID).getCollisionIndex();
for (Class<?> type : collisionTypes) { for (Map.Entry<Class<?>, CollisionInfo> collisionRemappers : annotationMap.entrySet()) {
CollisionRemapper annotation = annotationMap.get(type); Class<?> type = collisionRemappers.getKey();
CollisionInfo collisionInfo = collisionRemappers.getValue();
CollisionRemapper annotation = collisionInfo.collisionRemapper;
Pattern pattern = Pattern.compile(annotation.regex()); if (collisionInfo.pattern.matcher(blockName).find() && collisionInfo.paramsPattern.matcher(params).find()) {
Pattern paramsPattern = Pattern.compile(annotation.paramRegex());
if (pattern.matcher(blockName).find() && paramsPattern.matcher(params).find()) {
try { try {
if (!annotation.usesParams() && instantiatedCollision.containsKey(type)) { if (!annotation.usesParams() && instantiatedCollision.containsKey(type)) {
return instantiatedCollision.get(type); return instantiatedCollision.get(type);
@ -168,4 +165,14 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
return collision; return collision;
} }
/**
* Used to prevent patterns from being compiled more than needed
*/
@AllArgsConstructor
public static class CollisionInfo {
private final CollisionRemapper collisionRemapper;
private final Pattern pattern;
private final Pattern paramsPattern;
}
} }

View file

@ -42,6 +42,7 @@ import org.geysermc.connector.network.translators.world.chunk.ChunkSection;
import org.geysermc.connector.registry.BlockRegistries; import org.geysermc.connector.registry.BlockRegistries;
import org.geysermc.connector.registry.type.BlockMapping; import org.geysermc.connector.registry.type.BlockMapping;
import org.geysermc.connector.registry.type.BlockMappings; import org.geysermc.connector.registry.type.BlockMappings;
import org.geysermc.connector.utils.BlockUtils;
import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.FileUtils;
import java.io.DataInputStream; import java.io.DataInputStream;
@ -165,7 +166,7 @@ public class BlockRegistryPopulator {
bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId, javaRuntimeId); bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId, javaRuntimeId);
} }
String cleanJavaIdentifier = entry.getKey().split("\\[")[0]; String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(entry.getKey());
// 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) {

View file

@ -49,6 +49,7 @@ import org.geysermc.connector.network.translators.item.StoredItemMappings;
import org.geysermc.connector.registry.BlockRegistries; import org.geysermc.connector.registry.BlockRegistries;
import org.geysermc.connector.registry.Registries; import org.geysermc.connector.registry.Registries;
import org.geysermc.connector.registry.type.*; import org.geysermc.connector.registry.type.*;
import org.geysermc.connector.utils.BlockUtils;
import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.FileUtils;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -282,7 +283,8 @@ public class ItemRegistryPopulator {
String correctBedrockIdentifier = blockMappings.getBedrockBlockStates().get(aValidBedrockBlockId).getString("name"); String correctBedrockIdentifier = blockMappings.getBedrockBlockStates().get(aValidBedrockBlockId).getString("name");
boolean firstPass = true; boolean firstPass = true;
for (Map.Entry<String, Integer> blockEntry : BlockRegistries.JAVA_IDENTIFIERS.get().entrySet()) { for (Map.Entry<String, Integer> blockEntry : BlockRegistries.JAVA_IDENTIFIERS.get().entrySet()) {
if (blockEntry.getKey().split("\\[")[0].equals(javaBlockIdentifier)) { String aBlockIdentifier = BlockUtils.getCleanIdentifier(blockEntry.getKey());
if (aBlockIdentifier.equals(javaBlockIdentifier)) {
int bedrockBlockRuntimeId = blockMappings.getBedrockBlockId(blockEntry.getValue()); int bedrockBlockRuntimeId = blockMappings.getBedrockBlockId(blockEntry.getValue());
NbtMap blockTag = blockMappings.getBedrockBlockStates().get(bedrockBlockRuntimeId); NbtMap blockTag = blockMappings.getBedrockBlockStates().get(bedrockBlockRuntimeId);
String bedrockName = blockTag.getString("name"); String bedrockName = blockTag.getString("name");

View file

@ -27,6 +27,7 @@ package org.geysermc.connector.registry.type;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import org.geysermc.connector.utils.BlockUtils;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -54,7 +55,7 @@ public class BlockMapping {
* @return the identifier without the additional block states * @return the identifier without the additional block states
*/ */
public String getCleanJavaIdentifier() { public String getCleanJavaIdentifier() {
return javaIdentifier.split("\\[")[0]; return BlockUtils.getCleanIdentifier(javaIdentifier);
} }
/** /**

View file

@ -225,6 +225,25 @@ public class BlockUtils {
return blockPos; return blockPos;
} }
/**
* Taking in a complete Java block state identifier, output just the block ID of this block state without the states.
* Examples:
* minecraft:oak_log[axis=x] -> minecraft:oak_log
* minecraft:stone_brick_wall[east=low,north=tall,south=none,up=true,waterlogged=false,west=tall] -> minecraft:stone_brick_wall
* minecraft:stone -> minecraft:stone
*
* @param fullJavaIdentifier a full Java block identifier, with possible block states.
* @return a clean identifier in the format of minecraft:block
*/
public static String getCleanIdentifier(String fullJavaIdentifier) {
int stateIndex = fullJavaIdentifier.indexOf('[');
if (stateIndex == -1) {
// Identical to its clean variation
return fullJavaIdentifier;
}
return fullJavaIdentifier.substring(0, stateIndex);
}
// Note: these reuse classes, so don't try to store more than once instance or coordinates will get overwritten // Note: these reuse classes, so don't try to store more than once instance or coordinates will get overwritten
public static BlockCollision getCollision(int blockId, int x, int y, int z) { public static BlockCollision getCollision(int blockId, int x, int y, int z) {
BlockCollision collision = Registries.COLLISIONS.get(blockId); BlockCollision collision = Registries.COLLISIONS.get(blockId);