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 c9ada074e..880d14419 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 @@ -24,19 +24,36 @@ import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import com.google.gson.JsonParser; -import com.mojang.serialization.JsonOps; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import net.minecraft.client.Minecraft; +#if POST_MC_1_17 import net.minecraft.core.Holder; +import net.minecraft.resources.RegistryOps; +#endif + #if POST_MC_1_19_2 import net.minecraft.data.worldgen.biome.EndBiomes; import net.minecraft.data.worldgen.biome.NetherBiomes; #endif -import net.minecraft.resources.RegistryOps; + + +#if MC_1_16_5 +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.data.BuiltinRegistries; +import net.minecraft.resources.RegistryReadOps; +import net.minecraft.resources.RegistryWriteOps; +#else +import net.minecraft.resources.RegistryReadOps; +#endif + +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.state.BlockState; +#if !PRE_MC_1_18_2 import net.minecraft.world.level.biome.Biomes; +#endif /** This class wraps the minecraft BlockPos.Mutable (and BlockPos) class */ @@ -70,14 +87,6 @@ public class BiomeWrapper implements IBiomeWrapper #endif } - @Override - public String serialize() { - //FIXME: Pass in a level obj - String data = Biome.CODEC.encodeStart(RegistryOps.create(JsonOps.INSTANCE, Minecraft.getInstance().level.registryAccess()), - biome).get().orThrow().toString(); - return data; - } - @Override public boolean equals(Object o) { if (this == o) return true; @@ -91,19 +100,50 @@ public class BiomeWrapper implements IBiomeWrapper return Objects.hash(biome); } - public static IBiomeWrapper deserialize(String str) throws IOException + @Override + public String serialize() // FIXME pass in level to prevent null pointers (or maybe just RegistryAccess?) { + net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess(); + ResourceLocation resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome); + if (resourceLocation == null) + { + // shouldn't normally happen, but just in case + return ""; + } + else + { + String resourceLocationString = resourceLocation.getNamespace()+":"+resourceLocation.getPath(); + return resourceLocationString; + } + } + + public static IBiomeWrapper deserialize(String resourceLocationString) throws IOException // FIXME pass in level to prevent null pointers (or maybe just RegistryAccess?) + { + if (resourceLocationString.trim().isEmpty() || resourceLocationString.equals("")) + { + // shouldn't normally happen, but just in case + new ResourceLocation("minecraft", "the_void"); // just "void" in MC 1.12 through 1.9 (inclusive) + } + + + // parse the resource location + int separatorIndex = resourceLocationString.indexOf(":"); + if (separatorIndex == -1) + { + throw new IOException("Unable to parse resource location string: ["+resourceLocationString+"]."); + } + ResourceLocation resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex+1)); + + try { - #if PRE_MC_1_18_2 Biome #else - Holder #endif - biome = Biome.CODEC.decode(RegistryOps.create(JsonOps.INSTANCE, Minecraft.getInstance().level.registryAccess()), - JsonParser.parseString(str)).get().orThrow().getFirst(); + net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess(); + Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation); return getBiomeWrapper(biome); } catch (Exception e) { - throw new IOException("Failed to deserialize the string ["+str+"] into a BiomeWrapper: "+e.getMessage(), e); + throw new IOException("Failed to deserialize the string ["+resourceLocationString+"] into a BiomeWrapper: "+e.getMessage(), e); } } 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 b1fbf7c26..15445031b 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 @@ -1,29 +1,35 @@ package com.seibel.distanthorizons.common.wrappers.block; -import com.google.gson.JsonParser; -import com.mojang.serialization.JsonOps; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; -import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; -import net.minecraft.client.resources.model.Material; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockGetter; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import org.apache.logging.log4j.Logger; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; public class BlockStateWrapper implements IBlockStateWrapper { - private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - public static final BlockStateWrapper AIR = new BlockStateWrapper(null); + /** example "minecraft:plains" */ + public static final String RESOURCE_LOCATION_SEPARATOR = ":"; + /** example "minecraft:water_state_{level:0}" */ + public static final String STATE_STRING_SEPARATOR = "_STATE_"; + public static final BlockStateWrapper AIR = new BlockStateWrapper(null); + + + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + public static ConcurrentHashMap cache = new ConcurrentHashMap<>(); + //==============// // constructors // //==============// @@ -79,27 +85,102 @@ public class BlockStateWrapper implements IBlockStateWrapper return "AIR"; } - return BlockState.CODEC.encodeStart(JsonOps.INSTANCE, this.blockState).get().orThrow().toString(); + ResourceLocation resourceLocation = Registry.BLOCK.getKey(this.blockState.getBlock()); + String resourceStateString = resourceLocation.getNamespace() + RESOURCE_LOCATION_SEPARATOR + resourceLocation.getPath() + + STATE_STRING_SEPARATOR + serializeBlockStateProperties(this.blockState); + return resourceStateString; } - public static BlockStateWrapper deserialize(String str) throws IOException + public static BlockStateWrapper deserialize(String resourceStateString) throws IOException { - if (str.equals("AIR")) + if (resourceStateString.equals("AIR") || resourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case { return AIR; } + + + + // parse the BlockState + int stateSeparatorIndex = resourceStateString.indexOf(STATE_STRING_SEPARATOR); + if (stateSeparatorIndex == -1) + { + throw new IOException("Unable to parse BlockState out of string: ["+resourceStateString+"]."); + } + String blockStatePropertiesString = resourceStateString.substring(stateSeparatorIndex+STATE_STRING_SEPARATOR.length()); + resourceStateString = resourceStateString.substring(0, stateSeparatorIndex); + + // parse the resource location + int resourceSeparatorIndex = resourceStateString.indexOf(RESOURCE_LOCATION_SEPARATOR); + if (resourceSeparatorIndex == -1) + { + throw new IOException("Unable to parse Resource Location out of string: ["+resourceStateString+"]."); + } + ResourceLocation resourceLocation = new ResourceLocation(resourceStateString.substring(0, resourceSeparatorIndex), resourceStateString.substring(resourceSeparatorIndex+1)); + + + + // attempt to get the BlockState from all possible BlockStates try { - return new BlockStateWrapper( - BlockState.CODEC.decode(JsonOps.INSTANCE, JsonParser.parseString(str)).get().orThrow().getFirst() - ); + Block block = Registry.BLOCK.get(resourceLocation); + + BlockState foundState = 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 + if (foundState == null) + { + LOGGER.debug("Unable to find BlockState for Block ["+resourceLocation+"] with properties: ["+blockStatePropertiesString+"]."); + foundState = block.defaultBlockState(); + } + return new BlockStateWrapper(foundState); } catch (Exception e) { - throw new IOException("Failed to deserialize the string ["+str+"] into a BlockStateWrapper: "+e.getMessage(), e); + throw new IOException("Failed to deserialize the string ["+resourceStateString+"] into a BlockStateWrapper: "+e.getMessage(), e); } } - + + /** used to compare and save BlockStates based on their properties */ + private static String serializeBlockStateProperties(BlockState blockState) + { + // get the property list for this block (doesn't contain this block state's values, just the names and possible values) + java.util.Collection> blockPropertyCollection = blockState.getProperties(); + + // alphabetically sort the list so they are always in the same order + List> sortedBlockPropteryList = new ArrayList<>(blockPropertyCollection); + sortedBlockPropteryList.sort((a,b) -> a.getName().compareTo(b.getName())); + + + StringBuilder stringBuilder = new StringBuilder(); + for (net.minecraft.world.level.block.state.properties.Property property : sortedBlockPropteryList) + { + String propertyName = property.getName(); + + String value = "NULL"; + if (blockState.hasProperty(property)) + { + value = blockState.getValue(property).toString(); + } + + stringBuilder.append("{"); + stringBuilder.append(propertyName).append(RESOURCE_LOCATION_SEPARATOR).append(value); + stringBuilder.append("}"); + } + + return stringBuilder.toString(); + } + + @Override public boolean equals(Object obj) {