diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..a190fb110 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,19 @@ +**/.git +**/.gitlab +**/.cache + +buildAllJars + +**/_Misc Files +*.bat +*.md +*.sh +*.txt + +coreSubProjects/*.md +coreSubProjects/*.txt + +**/.gitignore +**/.gitattributes +**/.gitlab-cy.yml +**/.gitmodules diff --git a/.gitignore b/.gitignore index 547998298..0fa2bd272 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ run/ out/ *.iml .gradle/ +.gradle-cache/ output/ bin/ libs/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..8df81edfb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM eclipse-temurin:17-jdk + +WORKDIR /home/build/ +COPY ./gradlew . +RUN chmod +x ./gradlew +CMD echo "\r========== [CLEAN: $MC_VER] ==========" && \ + ./gradlew clean -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \ + echo "\r========== [BUILD: $MC_VER] ==========" && \ + ./gradlew build -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \ + echo "\r========== [MERGE: $MC_VER] ==========" && \ + ./gradlew mergeJars -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \ + echo "\r========== [DONE: $MC_VER] ==========" diff --git a/Readme.md b/Readme.md index 737724030..2566023d5 100644 --- a/Readme.md +++ b/Readme.md @@ -109,7 +109,8 @@ If running in an IDE, to ensure the IDE noticed the version change, run any grad >Note: There may be a `java.nio.file.FileSystemException` thrown when running the command after switching versions. To fix it, either restart your IDE (as your IDE is probably locking a file) or use a tool like LockHunter to unlock the linked file(s). (Generally it is a lib file under `common\build\lib`, `forge\build\lib`, or `fabric\build\lib`). \ > If anyone knows how to solve this issue please let us know here: \ > https://gitlab.com/jeseibel/minecraft-lod-mod/-/issues/233 - + +
## Compiling @@ -138,7 +139,16 @@ Run tests with: `./gradlew test` > Example: `./gradlew assemble -PmcVer=1.18.2` -
+
+ +## Compiling with Docker + +`./compile ` + +You can also locally compile the DH jars without a Java environment by using Docker. Where `` is the version of Minecraft to compile for (ie `1.20.1`), or the keyword `all`. See [Versions](#minecraft-and-library-versions) for a list of all supported values. + + +
## Other commands 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 a4cc12d80..9a7b76b2e 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 @@ -19,136 +19,146 @@ package com.seibel.distanthorizons.common.wrappers.block; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; +import net.minecraft.client.Minecraft; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import java.io.IOException; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; - -import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; #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 - - #if MC_1_16_5 || MC_1_17_1 import net.minecraft.core.Registry; #elif MC_1_18_2 || MC_1_19_2 -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; #else import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; #endif -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.biome.Biome; -#if !PRE_MC_1_18_2 -import net.minecraft.world.level.biome.Biomes; -#endif +/** + * This class wraps the minecraft BlockPos.Mutable (and BlockPos) class + */ +public class BiomeWrapper implements IBiomeWrapper { + private static final Logger LOGGER = LogManager.getLogger(); - - -/** This class wraps the minecraft BlockPos.Mutable (and BlockPos) class */ -public class BiomeWrapper implements IBiomeWrapper -{ - #if PRE_MC_1_18_2 - public static final ConcurrentMap biomeWrapperMap = new ConcurrentHashMap<>(); - public final Biome biome; - #else - public static final ConcurrentMap, BiomeWrapper> biomeWrapperMap = new ConcurrentHashMap<>(); - public final Holder biome; + #if PRE_MC_1_18_2 + public static final ConcurrentMap biomeWrapperMap = new ConcurrentHashMap<>(); + public final Biome biome; + #else + public static final ConcurrentMap, BiomeWrapper> biomeWrapperMap = new ConcurrentHashMap<>(); + public final Holder biome; #endif - static public IBiomeWrapper getBiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder #endif biome) - { - return biomeWrapperMap.computeIfAbsent(biome, BiomeWrapper::new); - } + /** + * 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; - private BiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder #endif biome) - { - this.biome = biome; - } + //==============// + // constructors // + //==============// - @Override - public String getName() - { + static public IBiomeWrapper getBiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder #endif biome) { + return biomeWrapperMap.computeIfAbsent(biome, BiomeWrapper::new); + } + + private BiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder #endif biome) { + this.biome = biome; + } + + //=========// + // 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); - } - - @Override - public int hashCode() { - return Objects.hash(biome); - } - - @Override - public String serialize(ILevelWrapper levelWrapper) - { - - net.minecraft.core.RegistryAccess registryAccess = ((Level)levelWrapper.getWrappedMcObject()).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) - { - // shouldn't normally happen, but just in case - return ""; - } - else - { - String resourceLocationString = resourceLocation.getNamespace()+":"+resourceLocation.getPath(); - return resourceLocationString; - } } - - public static IBiomeWrapper deserialize(String resourceLocationString, ILevelWrapper levelWrapper) throws IOException - { - if (resourceLocationString.trim().isEmpty() || resourceLocationString.equals("")) - { + + @Override + 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(Minecraft.getInstance().level)); + } + + @Override + public int hashCode() { + return Objects.hash(this.serialize()); + } + + @Override + public String serialize(ILevelWrapper levelWrapper) { + if (this.serializationResult == null) { + net.minecraft.core.RegistryAccess registryAccess = ((Level) levelWrapper.getWrappedMcObject()).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, ILevelWrapper levelWrapper) throws IOException { + 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) } - - + // parse the resource location int separatorIndex = resourceLocationString.indexOf(":"); - if (separatorIndex == -1) - { - throw new IOException("Unable to parse resource location string: ["+resourceLocationString+"]."); + 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 - { - net.minecraft.core.RegistryAccess registryAccess = ((Level)levelWrapper.getWrappedMcObject()).registryAccess(); + ResourceLocation resourceLocation = new ResourceLocation( + resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1)); + + try { + net.minecraft.core.RegistryAccess registryAccess = ((Level) levelWrapper.getWrappedMcObject()).registryAccess(); #if MC_1_16_5 || MC_1_17_1 Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation); @@ -157,19 +167,24 @@ 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 - + return getBiomeWrapper(biome); - } - catch (Exception e) - { - throw new IOException("Failed to deserialize the string ["+resourceLocationString+"] into a BiomeWrapper: "+e.getMessage(), e); + } catch (Exception e) { + throw new IOException( + "Failed to deserialize the string [" + resourceLocationString + "] into a BiomeWrapper: " + e.getMessage(), e); } } - - - @Override - public Object getWrappedMcObject() { return this.biome; } - + + @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 dd3d66462..673d572fa 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 @@ -8,6 +8,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.Level; 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; @@ -19,8 +20,11 @@ import java.util.concurrent.ConcurrentHashMap; #if MC_1_16_5 || MC_1_17_1 import net.minecraft.core.Registry; #elif MC_1_18_2 || MC_1_19_2 +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; #else +import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.world.level.EmptyBlockGetter; @@ -38,10 +42,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; //==============// @@ -94,25 +101,36 @@ public class BlockStateWrapper implements IBlockStateWrapper @Override public String serialize(ILevelWrapper levelWrapper) { - 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 = ((Level)levelWrapper.getWrappedMcObject()).registryAccess(); + resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(this.blockState.getBlock()); + #else + net.minecraft.core.RegistryAccess registryAccess = ((Level)levelWrapper.getWrappedMcObject()).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 = ((Level)levelWrapper.getWrappedMcObject()).registryAccess(); - resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(this.blockState.getBlock()); - #else - net.minecraft.core.RegistryAccess registryAccess = ((Level)levelWrapper.getWrappedMcObject()).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, ILevelWrapper levelWrapper) throws IOException @@ -174,7 +192,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); @@ -230,11 +248,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 @@ -269,4 +288,7 @@ public class BlockStateWrapper implements IBlockStateWrapper #endif } + @Override + public String toString() { return this.serialize(); } + } diff --git a/compile.sh b/compile.sh new file mode 100644 index 000000000..9cc9a628b --- /dev/null +++ b/compile.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +publish_version() +{ + if [[ "$2" == "all" || "$1" == "$2" ]] + then + docker run --name=dh-build-$1 --rm -v /${PWD}:/home/build -e MC_VER=$1 dh-eclipse-temurin + cp ./fabric/build/libs/*$1.jar ./buildAllJars/fabric/ + cp ./forge/build/libs/*$1.jar ./buildAllJars/forge/ + cp ./Merged/*.jar ./buildAllJars/merged/ + fi +} + + +if [ -z "$1" ] +then + echo "Build target is undefined! [all] [1.20.1] [1.19.4] [1.19.2] [1.18.2] [1.17.1] [1.16.5]" + exit 1 +fi + +docker build --tag=dh-eclipse-temurin -q . + +mkdir -p buildAllJars/fabric +mkdir -p buildAllJars/forge +mkdir -p buildAllJars/merged +publish_version 1.20.1 $1 +publish_version 1.19.4 $1 +publish_version 1.19.2 $1 +publish_version 1.18.2 $1 +publish_version 1.17.1 $1 +publish_version 1.16.5 $1