From 6b5bae9beed0f831dfb323a2a2668dddf8447681 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Mon, 13 May 2024 20:26:47 -0400 Subject: [PATCH] Cache block and biome wrapper deserialization values --- .../common/wrappers/block/BiomeWrapper.java | 110 ++++++----- .../wrappers/block/BlockStateWrapper.java | 179 ++++++++++-------- 2 files changed, 164 insertions(+), 125 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BiomeWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BiomeWrapper.java index 2d5f95ca8..fcb59ad9a 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BiomeWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BiomeWrapper.java @@ -64,6 +64,8 @@ public class BiomeWrapper implements IBiomeWrapper public static final ConcurrentMap, BiomeWrapper> WRAPPER_BY_BIOME = new ConcurrentHashMap<>(); #endif + public static final ConcurrentHashMap WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>(); + public static final String EMPTY_BIOME_STRING = "EMPTY"; public static final BiomeWrapper EMPTY_WRAPPER = new BiomeWrapper(null, null); @@ -267,62 +269,78 @@ public class BiomeWrapper implements IBiomeWrapper return EMPTY_WRAPPER; } - - - // parse the resource location - int separatorIndex = resourceLocationString.indexOf(":"); - if (separatorIndex == -1) + if (WRAPPER_BY_RESOURCE_LOCATION.containsKey(resourceLocationString)) { - throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "]."); + return WRAPPER_BY_RESOURCE_LOCATION.get(resourceLocationString); } - ResourceLocation resourceLocation; + + + // if no wrapper is found, default to the empty wrapper + BiomeWrapper foundWrapper = EMPTY_WRAPPER; try { - resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1)); - } - catch (Exception e) - { - throw new IOException("No Resource Location found for the string: [" + resourceLocationString + "] Error: ["+e.getMessage()+"]."); - } - - - try - { - Level level = (Level)levelWrapper.getWrappedMcObject(); - net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); - - boolean success; - #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 - Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation); - success = (biome != null); - #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2 - Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation); - success = (unwrappedBiome != null); - Holder biome = new Holder.Direct<>(unwrappedBiome); - #else - Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation); - success = (unwrappedBiome != null); - Holder biome = new Holder.Direct<>(unwrappedBiome); - #endif - - - - if (!success) + // parse the resource location + int separatorIndex = resourceLocationString.indexOf(":"); + if (separatorIndex == -1) { - if (!brokenResourceLocationStrings.contains(resourceLocationString)) - { - brokenResourceLocationStrings.add(resourceLocationString); - LOGGER.warn("Unable to deserialize biome from string: [" + resourceLocationString + "]"); - } - return EMPTY_WRAPPER; + throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "]."); } - return getBiomeWrapper(biome, levelWrapper); + ResourceLocation resourceLocation; + try + { + resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1)); + } + catch (Exception e) + { + throw new IOException("No Resource Location found for the string: [" + resourceLocationString + "] Error: [" + e.getMessage() + "]."); + } + + + try + { + Level level = (Level) levelWrapper.getWrappedMcObject(); + net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); + + boolean success; + #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 + Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation); + success = (biome != null); + #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2 + Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation); + success = (unwrappedBiome != null); + Holder biome = new Holder.Direct<>(unwrappedBiome); + #else + Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation); + success = (unwrappedBiome != null); + Holder biome = new Holder.Direct<>(unwrappedBiome); + #endif + + + + if (!success) + { + if (!brokenResourceLocationStrings.contains(resourceLocationString)) + { + brokenResourceLocationStrings.add(resourceLocationString); + LOGGER.warn("Unable to deserialize biome from string: [" + resourceLocationString + "]"); + } + return EMPTY_WRAPPER; + } + + + foundWrapper = (BiomeWrapper) getBiomeWrapper(biome, levelWrapper); + return foundWrapper; + } + catch (Exception e) + { + throw new IOException("Failed to deserialize the string [" + resourceLocationString + "] into a BiomeWrapper: " + e.getMessage(), e); + } } - catch (Exception e) + finally { - throw new IOException("Failed to deserialize the string [" + resourceLocationString + "] into a BiomeWrapper: " + e.getMessage(), e); + WRAPPER_BY_RESOURCE_LOCATION.putIfAbsent(resourceLocationString, foundWrapper); } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java index 5e5fca6b1..75004f474 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java @@ -65,6 +65,7 @@ public class BlockStateWrapper implements IBlockStateWrapper private static final Logger LOGGER = DhLoggerBuilder.getLogger(); public static final ConcurrentHashMap WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>(); + public static final ConcurrentHashMap WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>(); public static final String AIR_STRING = "AIR"; public static final BlockStateWrapper AIR = new BlockStateWrapper(null, null); @@ -336,7 +337,6 @@ public class BlockStateWrapper implements IBlockStateWrapper } - // TODO would it be worth while to cache these objects in a ConcurrentHashMap? /** will only work if a level is currently loaded */ public static IBlockStateWrapper deserialize(String resourceStateString, ILevelWrapper levelWrapper) throws IOException { @@ -345,106 +345,127 @@ public class BlockStateWrapper implements IBlockStateWrapper return AIR; } - - - // try to parse out the BlockState - String blockStatePropertiesString = null; // will be null if no properties were included - int stateSeparatorIndex = resourceStateString.indexOf(STATE_STRING_SEPARATOR); - if (stateSeparatorIndex != -1) + // attempt to use the existing wrapper + if (WRAPPER_BY_RESOURCE_LOCATION.containsKey(resourceStateString)) { - // blockstate properties found - blockStatePropertiesString = resourceStateString.substring(stateSeparatorIndex + STATE_STRING_SEPARATOR.length()); - resourceStateString = resourceStateString.substring(0, stateSeparatorIndex); + return WRAPPER_BY_RESOURCE_LOCATION.get(resourceStateString); } - // parse the resource location - int separatorIndex = resourceStateString.indexOf(RESOURCE_LOCATION_SEPARATOR); - if (separatorIndex == -1) - { - throw new IOException("Unable to parse Resource Location out of string: [" + resourceStateString + "]."); - } - ResourceLocation resourceLocation; + + // if no wrapper is found, default to air + BlockStateWrapper foundWrapper = AIR; try { - resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1)); - } - catch (Exception e) - { - throw new IOException("No Resource Location found for the string: [" + resourceStateString + "] Error: ["+e.getMessage()+"]."); - } - - - // attempt to get the BlockState from all possible BlockStates - try - { - - #if MC_VER > MC_1_17_1 - // use the given level if possible, otherwise try using the currently loaded one - Level level = (levelWrapper != null ? (Level)levelWrapper.getWrappedMcObject() : null); - level = (level == null ? Minecraft.getInstance().level : level); - #endif - - Block block; - #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 - block = Registry.BLOCK.get(resourceLocation); - #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2 - net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); - block = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).get(resourceLocation); - #else - net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); - block = registryAccess.registryOrThrow(Registries.BLOCK).get(resourceLocation); - #endif - - - if (block == null) + // try to parse out the BlockState + String blockStatePropertiesString = null; // will be null if no properties were included + int stateSeparatorIndex = resourceStateString.indexOf(STATE_STRING_SEPARATOR); + if (stateSeparatorIndex != -1) { - // shouldn't normally happen, but here to make the compiler happy - if (!BrokenResourceLocations.contains(resourceLocation)) - { - BrokenResourceLocations.add(resourceLocation); - LOGGER.warn("Unable to find BlockState with the resourceLocation [" + resourceLocation + "] and properties: [" + blockStatePropertiesString + "]. Air will be used instead, some data may be lost."); - } - return AIR; + // blockstate properties found + blockStatePropertiesString = resourceStateString.substring(stateSeparatorIndex + STATE_STRING_SEPARATOR.length()); + resourceStateString = resourceStateString.substring(0, stateSeparatorIndex); + } + + // parse the resource location + int separatorIndex = resourceStateString.indexOf(RESOURCE_LOCATION_SEPARATOR); + if (separatorIndex == -1) + { + throw new IOException("Unable to parse Resource Location out of string: [" + resourceStateString + "]."); + } + + ResourceLocation resourceLocation; + try + { + resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1)); + } + catch (Exception e) + { + throw new IOException("No Resource Location found for the string: [" + resourceStateString + "] Error: [" + e.getMessage() + "]."); } - // attempt to find the blockstate from all possibilities - BlockState foundState = null; - if (blockStatePropertiesString != null) - { - List possibleStateList = block.getStateDefinition().getPossibleStates(); - for (BlockState possibleState : possibleStateList) - { - String possibleStatePropertiesString = serializeBlockStateProperties(possibleState); - if (possibleStatePropertiesString.equals(blockStatePropertiesString)) - { - foundState = possibleState; - break; - } - } - } - // use the default if no state was found or given - if (foundState == null) + // attempt to get the BlockState from all possible BlockStates + try { - if (blockStatePropertiesString != null) + + #if MC_VER > MC_1_17_1 + // use the given level if possible, otherwise try using the currently loaded one + Level level = (levelWrapper != null ? (Level) levelWrapper.getWrappedMcObject() : null); + level = (level == null ? Minecraft.getInstance().level : level); + #endif + + Block block; + #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 + block = Registry.BLOCK.get(resourceLocation); + #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2 + net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); + block = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).get(resourceLocation); + #else + net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); + block = registryAccess.registryOrThrow(Registries.BLOCK).get(resourceLocation); + #endif + + + if (block == null) { - // we should have found a blockstate, but didn't + // shouldn't normally happen, but here to make the compiler happy if (!BrokenResourceLocations.contains(resourceLocation)) { BrokenResourceLocations.add(resourceLocation); - LOGGER.warn("Unable to find BlockState for Block [" + resourceLocation + "] with properties: [" + blockStatePropertiesString + "]. Using the default block state."); + LOGGER.warn("Unable to find BlockState with the resourceLocation [" + resourceLocation + "] and properties: [" + blockStatePropertiesString + "]. Air will be used instead, some data may be lost."); + } + + return AIR; + } + + + // attempt to find the blockstate from all possibilities + BlockState foundState = null; + if (blockStatePropertiesString != null) + { + List possibleStateList = block.getStateDefinition().getPossibleStates(); + for (BlockState possibleState : possibleStateList) + { + String possibleStatePropertiesString = serializeBlockStateProperties(possibleState); + if (possibleStatePropertiesString.equals(blockStatePropertiesString)) + { + foundState = possibleState; + break; + } } } - foundState = block.defaultBlockState(); + // use the default if no state was found or given + if (foundState == null) + { + if (blockStatePropertiesString != null) + { + // we should have found a blockstate, but didn't + if (!BrokenResourceLocations.contains(resourceLocation)) + { + BrokenResourceLocations.add(resourceLocation); + LOGGER.warn("Unable to find BlockState for Block [" + resourceLocation + "] with properties: [" + blockStatePropertiesString + "]. Using the default block state."); + } + } + + foundState = block.defaultBlockState(); + } + + foundWrapper = new BlockStateWrapper(foundState, levelWrapper); + return foundWrapper; + } + catch (Exception e) + { + throw new IOException("Failed to deserialize the string [" + resourceStateString + "] into a BlockStateWrapper: " + e.getMessage(), e); } - return new BlockStateWrapper(foundState, levelWrapper); } - catch (Exception e) + finally { - throw new IOException("Failed to deserialize the string [" + resourceStateString + "] into a BlockStateWrapper: " + e.getMessage(), e); + // put if absent in case two threads deserialize at the same time + // unfortunately we can't put everything in a computeIfAbsent() since we also throw exceptions + WRAPPER_BY_RESOURCE_LOCATION.putIfAbsent(resourceStateString, foundWrapper); } }