Convert Biome/Block wrapper serialization methods to use ResourceLocations

This commit is contained in:
James Seibel
2023-08-05 11:12:46 -05:00
parent 5cd6111e92
commit c895dff2c8
2 changed files with 154 additions and 33 deletions
@@ -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<Biome> #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);
}
}
@@ -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<BlockState, BlockStateWrapper> 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<BlockState> 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<net.minecraft.world.level.block.state.properties.Property<?>> blockPropertyCollection = blockState.getProperties();
// alphabetically sort the list so they are always in the same order
List<net.minecraft.world.level.block.state.properties.Property<?>> 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)
{