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 665ddfd56..4729789b3 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 @@ -33,8 +33,6 @@ 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 @@ -54,12 +52,17 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.biome.Biome; #if !PRE_MC_1_18_2 import net.minecraft.world.level.biome.Biomes; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; #endif /** This class wraps the minecraft BlockPos.Mutable (and BlockPos) class */ public class BiomeWrapper implements IBiomeWrapper { + private static final Logger LOGGER = LogManager.getLogger(); + + #if PRE_MC_1_18_2 public static final ConcurrentMap biomeWrapperMap = new ConcurrentHashMap<>(); public final Biome biome; @@ -67,7 +70,19 @@ public class BiomeWrapper implements IBiomeWrapper public static final ConcurrentMap, BiomeWrapper> biomeWrapperMap = new ConcurrentHashMap<>(); public final Holder biome; #endif - + + /** + * Cached so it can be quickly used as a semi-stable hashing method.
+ * This may also fix the issue where we can serialize and save after a level has been shut down. + */ + private String serializationResult = null; + + + + //==============// + // constructors // + //==============// + static public IBiomeWrapper getBiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder #endif biome) { return biomeWrapperMap.computeIfAbsent(biome, BiomeWrapper::new); @@ -77,61 +92,80 @@ public class BiomeWrapper implements IBiomeWrapper { this.biome = biome; } - - @Override + + + + //=========// + // methods // + //=========// + + @Override public String getName() { #if PRE_MC_1_18_2 return biome.toString(); #else - return biome.unwrapKey().orElse(Biomes.THE_VOID).registry().toString(); + return this.biome.unwrapKey().orElse(Biomes.THE_VOID).registry().toString(); #endif } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - BiomeWrapper that = (BiomeWrapper) o; - return Objects.equals(biome, that.biome); + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (obj == null || this.getClass() != obj.getClass()) + { + return false; + } + + BiomeWrapper that = (BiomeWrapper) obj; + // the serialized value is used so we can test the contents instead of the references + return Objects.equals(this.serialize(), that.serialize()); } @Override - public int hashCode() { - return Objects.hash(biome); - } + public int hashCode() { return Objects.hash(this.serialize()); } @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; - #if MC_1_16_5 || MC_1_17_1 - resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome); - #elif MC_1_18_2 || MC_1_19_2 - resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value()); - #else - resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value()); - #endif - - if (resourceLocation == null) + if (this.serializationResult == null) { - // shouldn't normally happen, but just in case - return ""; - } - else - { - String resourceLocationString = resourceLocation.getNamespace()+":"+resourceLocation.getPath(); - return resourceLocationString; + net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess(); + + ResourceLocation resourceLocation; + #if MC_1_16_5 || MC_1_17_1 + resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome); + #elif MC_1_18_2 || MC_1_19_2 + resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value()); + #else + resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value()); + #endif + + if (resourceLocation == null) + { + LOGGER.warn("unable to serialize: "+this.biome.value()); + // shouldn't normally happen, but just in case + this.serializationResult = ""; + } + else + { + this.serializationResult = resourceLocation.getNamespace()+":"+resourceLocation.getPath(); + } } + + return this.serializationResult; } 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("")) { + LOGGER.warn("null biome string deserialized"); + // shouldn't normally happen, but just in case new ResourceLocation("minecraft", "the_void"); // just "void" in MC 1.12 through 1.9 (inclusive) } @@ -157,6 +191,10 @@ public class BiomeWrapper implements IBiomeWrapper Holder biome = new Holder.Direct<>(unwrappedBiome); #else Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation); + if (unwrappedBiome == null) + { + LOGGER.warn("null biome string deserialized from string: "+resourceLocationString); + } Holder biome = new Holder.Direct<>(unwrappedBiome); #endif @@ -172,4 +210,7 @@ public class BiomeWrapper implements IBiomeWrapper @Override public Object getWrappedMcObject() { return this.biome; } + @Override + public String toString() { return this.serialize(); } + } 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 2b0cb4ba0..6a1c5f430 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 @@ -6,6 +6,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe 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.LogManager; import org.apache.logging.log4j.Logger; import java.io.IOException; @@ -39,10 +40,13 @@ public class BlockStateWrapper implements IBlockStateWrapper private static final Logger LOGGER = DhLoggerBuilder.getLogger(); public static final BlockStateWrapper AIR = new BlockStateWrapper(null); + public static final ConcurrentHashMap cache = new ConcurrentHashMap<>(); - - public static ConcurrentHashMap cache = new ConcurrentHashMap<>(); - + /** + * Cached so it can be quickly used as a semi-stable hashing method.
+ * This may also fix the issue where we can serialize and save after a level has been shut down. + */ + private String serializationResult = null; //==============// @@ -95,25 +99,36 @@ public class BlockStateWrapper implements IBlockStateWrapper @Override public String serialize() // FIXME pass in level to prevent null pointers (or maybe just RegistryAccess?) { - if (this.blockState == null) + // cache the serialization result so it can be quickly used as a semi-stable hashing method + if (this.serializationResult == null) { - return "AIR"; + if (this.blockState == null) + { + return "AIR"; + } + + ResourceLocation resourceLocation; + #if MC_1_16_5 || MC_1_17_1 + resourceLocation = Registry.BLOCK.getKey(this.blockState.getBlock()); + #elif MC_1_18_2 || MC_1_19_2 + net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess(); + resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(this.blockState.getBlock()); + #else + net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess(); + resourceLocation = registryAccess.registryOrThrow(Registries.BLOCK).getKey(this.blockState.getBlock()); + #endif + + if (resourceLocation == null) + { + LOGGER.warn("unable to serialize: "+this.blockState); + } + + this.serializationResult = resourceLocation.getNamespace() + RESOURCE_LOCATION_SEPARATOR + resourceLocation.getPath() + + STATE_STRING_SEPARATOR + serializeBlockStateProperties(this.blockState); } - ResourceLocation resourceLocation; - #if MC_1_16_5 || MC_1_17_1 - resourceLocation = Registry.BLOCK.getKey(this.blockState.getBlock()); - #elif MC_1_18_2 || MC_1_19_2 - net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess(); - resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(this.blockState.getBlock()); - #else - net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess(); - resourceLocation = registryAccess.registryOrThrow(Registries.BLOCK).getKey(this.blockState.getBlock()); - #endif - String resourceStateString = resourceLocation.getNamespace() + RESOURCE_LOCATION_SEPARATOR + resourceLocation.getPath() - + STATE_STRING_SEPARATOR + serializeBlockStateProperties(this.blockState); - return resourceStateString; + return this.serializationResult; } public static BlockStateWrapper deserialize(String resourceStateString) throws IOException // FIXME pass in level to prevent null pointers (or maybe just RegistryAccess?) @@ -175,7 +190,7 @@ public class BlockStateWrapper implements IBlockStateWrapper // use the default if no state was found if (foundState == null) { - LOGGER.debug("Unable to find BlockState for Block ["+resourceLocation+"] with properties: ["+blockStatePropertiesString+"]."); + LOGGER.warn("Unable to find BlockState for Block ["+resourceLocation+"] with properties: ["+blockStatePropertiesString+"]."); foundState = block.defaultBlockState(); } return new BlockStateWrapper(foundState); @@ -231,11 +246,12 @@ public class BlockStateWrapper implements IBlockStateWrapper } BlockStateWrapper that = (BlockStateWrapper) obj; - return Objects.equals(this.blockState, that.blockState); + // the serialized value is used so we can test the contents instead of the references + return Objects.equals(this.serialize(), that.serialize()); } @Override - public int hashCode() { return Objects.hash(this.blockState); } + public int hashCode() { return Objects.hash(this.serialize()); } @Override @@ -270,4 +286,7 @@ public class BlockStateWrapper implements IBlockStateWrapper #endif } + @Override + public String toString() { return this.serialize(); } + } diff --git a/coreSubProjects b/coreSubProjects index c2f7ca8f3..d3cf47ccd 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit c2f7ca8f38eac1fe370f8cd1d153dabcd866a0a9 +Subproject commit d3cf47ccd78afcec88504b3769f0de3e5b2b09b0