diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 41c60758c..357292dae 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -33,9 +33,9 @@ build: - MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1"] script: # this both runs the unit tests and assembles the code - - ./gradlew clean -PmcVer="${MC_VER}" --gradle-user-home cache/; - - ./gradlew build -PmcVer="${MC_VER}" --gradle-user-home cache/; - - ./gradlew mergeJars -PmcVer="${MC_VER}" --gradle-user-home cache/; + - ./gradlew clean -PmcVer="${MC_VER}" -PgitMainBranch="${CI_COMMIT_BRANCH}" -PgitMainCommit="${CI_COMMIT_SHA}" -PgitCoreCommit="Unavailable (built by Gitlab CI)" --gradle-user-home cache/; + - ./gradlew build -PmcVer="${MC_VER}" -PgitMainBranch="${CI_COMMIT_BRANCH}" -PgitMainCommit="${CI_COMMIT_SHA}" -PgitCoreCommit="Unavailable (built by Gitlab CI)" --gradle-user-home cache/; + - ./gradlew mergeJars -PmcVer="${MC_VER}" -PgitMainBranch="${CI_COMMIT_BRANCH}" -PgitMainCommit="${CI_COMMIT_SHA}" -PgitCoreCommit="Unavailable (built by Gitlab CI)" --gradle-user-home cache/; artifacts: name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}" paths: diff --git a/Readme.md b/Readme.md index 2566023d5..6875690be 100644 --- a/Readme.md +++ b/Readme.md @@ -20,7 +20,7 @@ If you want to see a quick demo, check out a video covering the mod here: ### This branch supports the following versions of Minecraft: -#### 1.20.1, 1.20 +#### 1.20.1, 1.20 (Default) Fabric: 0.14.21\ Fabric API: 0.85.0+1.20.1\ Forge: 45.1.0\ @@ -41,21 +41,21 @@ Forge: 43.2.14\ Parchment: 1.19.2:2022.11.27\ Modmenu: 4.2.0-beta.2 -#### 1.18.2 (Default) +#### 1.18.2 Fabric: 0.14.21\ Fabric API: 0.76.0+1.18.2\ Forge: 40.2.10\ Parchment: 1.18.2:2022.11.06\ Modmenu: 3.2.5 -#### 1.17.1, 1.17 (BROKE) +#### 1.17.1, 1.17 Fabric: 0.14.21\ Fabric API: 0.46.1+1.17\ Forge: 37.1.1\ Parchment: 1.17.1:2021.12.12\ Modmenu: 2.0.14 -#### 1.16.5, 1.16.4 (BROKE) +#### 1.16.5, 1.16.4 Fabric: 0.14.21\ Fabric API: 0.42.0+1.16\ Forge: 36.2.39\ @@ -196,5 +196,5 @@ https://github.com/TheElectronWill/night-config SVG Salamander for SVG support\ https://github.com/blackears/svgSalamander -FlatLaf for theming (for development testing, may remove later)\ +FlatLaf for Java Swing theming (for development testing, may remove later, and not included in compiled jars)\ https://www.formdev.com/flatlaf/ diff --git a/build.gradle b/build.gradle index 2e97bc4c4..14f0cc074 100644 --- a/build.gradle +++ b/build.gradle @@ -363,11 +363,23 @@ subprojects { p -> def git_main_commit = "Git_not_found" def git_core_commit = "Git_not_found" def git_main_branch = "Git_not_found" + // These "hasProperty"'s are so that they can be passed through the cli (ie in the CI) try { - "git rev-parse --is-inside-work-tree".execute() // If git doesnt exist, or this isnt cloned from git, then this wont work - git_main_commit = 'git rev-parse --verify HEAD'.execute().text.trim() - git_core_commit = 'git ls-tree --object-only HEAD ../coreSubProjects'.execute().text.trim() // TODO: is there a way to do this universally - git_main_branch = 'git symbolic-ref --short HEAD'.execute().text.trim() +// "git rev-parse --is-inside-work-tree".execute() // If git doesnt exist, or this isnt cloned from git, then this wont work + if (gitMainCommit != "null") + git_main_commit = gitMainCommit + else + git_main_commit = 'git rev-parse --verify HEAD'.execute().text.trim() + + if (gitCoreCommit != "null") + git_core_commit = gitCoreCommit + else + git_core_commit = 'git ls-tree --object-only HEAD ../coreSubProjects'.execute().text.trim() // TODO: is there a way to do this universally + + if (gitMainBranch != "null") + git_main_branch = gitMainBranch + else + git_main_branch = 'git symbolic-ref --short HEAD'.execute().text.trim() } catch (Exception e) { println "Git or Git project not found" } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java index c33eefce0..01bcf52f7 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java @@ -23,6 +23,8 @@ import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiW import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; +import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; +import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.level.IDhServerLevel; @@ -32,11 +34,14 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.chunk.ChunkAccess; import java.io.IOException; -import java.util.HashMap; +import java.util.HashSet; /** * This handles creating abstract wrapper objects. @@ -74,7 +79,7 @@ public class WrapperFactory implements IWrapperFactory public IBlockStateWrapper getAirBlockStateWrapper() { return BlockStateWrapper.AIR; } @Override - public HashMap getRendererIgnoredBlocks() { return BlockStateWrapper.RENDERER_IGNORED_BLOCKS; } + public HashSet getRendererIgnoredBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredBlocks(levelWrapper); } /** @@ -114,15 +119,34 @@ public class WrapperFactory implements IWrapperFactory } ChunkAccess chunk = (ChunkAccess) objectArray[0]; - // light source - if (!(objectArray[1] instanceof LevelReader)) + // level / light source + if (!(objectArray[1] instanceof Level)) { throw new ClassCastException(createChunkWrapperErrorMessage(objectArray)); } - LevelReader lightSource = (LevelReader) objectArray[1]; + // the level is needed for the DH level wrapper... + Level level = (Level) objectArray[1]; + // ...the LevelReader is needed for chunk lighting + LevelReader lightSource = level; - return new ChunkWrapper(chunk, lightSource, /*A DH wrapped level isn't necessary*/null); + // level wrapper + ILevelWrapper levelWrapper; + if (level instanceof ServerLevel) + { + levelWrapper = ServerLevelWrapper.getWrapper((ServerLevel)level); + } + else if (level instanceof ClientLevel) + { + levelWrapper = ClientLevelWrapper.getWrapper((ClientLevel)level); + } + else + { + throw new ClassCastException(createChunkWrapperErrorMessage(objectArray)); + } + + + return new ChunkWrapper(chunk, lightSource, levelWrapper); } // incorrect number of parameters from the API else @@ -153,7 +177,7 @@ public class WrapperFactory implements IWrapperFactory // MC 1.16, 1.18, 1.19, 1.20 #if POST_MC_1_17_1 || MC_1_16_5 message.append("[" + ChunkAccess.class.getName() + "], \n"); - message.append("[" + LevelReader.class.getName() + "]. \n"); + message.append("[" + ServerLevel.class.getName() + "] or [" + ClientLevel.class.getName() + "]. \n"); #else // See preprocessor comment in createChunkWrapper() for full documentation not implemented for this version of Minecraft! 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 096a4b9dc..aee4951ca 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,40 +19,44 @@ package com.seibel.distanthorizons.common.wrappers.block; -import com.seibel.distanthorizons.core.config.Config; -import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; -import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; -import com.seibel.distanthorizons.coreapi.ModInfo; -import net.minecraft.core.Holder; -import net.minecraft.core.RegistryAccess; -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.ILevelWrapper; +import net.minecraft.world.level.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +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 #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; +import net.minecraft.core.RegistryAccess; +import net.minecraft.data.BuiltinRegistries; #else +import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; #endif +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; #endif @@ -60,135 +64,208 @@ import net.minecraft.core.registries.Registries; 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; #else public static final ConcurrentMap, BiomeWrapper> biomeWrapperMap = new ConcurrentHashMap<>(); + #endif + + public static final String EMPTY_STRING = "EMPTY"; + public static final BiomeWrapper EMPTY_WRAPPER = new BiomeWrapper(null, null); + + + + // properties // + + #if PRE_MC_1_18_2 + public final Biome biome; + #else public final Holder biome; #endif - - private final ILevelWrapper levelWrapper; - - /** - * 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; - + + /** technically final, but since it requires a method call to generate it can't be marked as such */ + private String serialString = null; + + + //==============// // constructors // //==============// - - static public IBiomeWrapper getBiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder #endif biome, ILevelWrapper levelWrapper) { - Objects.requireNonNull(#if PRE_MC_1_18_2 biome #else biome.value() #endif); - return biomeWrapperMap.computeIfAbsent(biome, biomeHolder -> new BiomeWrapper(biomeHolder, levelWrapper)); + + static public IBiomeWrapper getBiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder #endif biome, ILevelWrapper levelWrapper) + { + if (biome == null) + { + return EMPTY_WRAPPER; + } + + return biomeWrapperMap.computeIfAbsent(biome, newBiome -> new BiomeWrapper(newBiome, levelWrapper)); } - - private BiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder #endif biome, ILevelWrapper levelWrapper) { + + private BiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder #endif biome, ILevelWrapper levelWrapper) + { this.biome = biome; - this.levelWrapper = levelWrapper; + this.serialString = this.serialize(levelWrapper); + LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]"); } - + + + //=========// // methods // //=========// - + @Override - public String getName() { + public String getName() + { + if (this == EMPTY_WRAPPER) + { + return EMPTY_STRING; + } + #if PRE_MC_1_18_2 return biome.toString(); #else return this.biome.unwrapKey().orElse(Biomes.THE_VOID).registry().toString(); #endif } - + @Override - public boolean equals(Object obj) { - if (this == obj) { + public boolean equals(Object obj) + { + if (this == obj) + { return true; - } else if (obj == null || this.getClass() != obj.getClass()) { + } + 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()); + return Objects.equals(this.getSerialString(), that.getSerialString()); } - + @Override - public int hashCode() { - return Objects.hash(this.serialize()); - } - + public int hashCode() { return Objects.hash(this.getSerialString()); } + @Override - public String serialize() + public String getSerialString() { return this.serialString; } + + @Override + public Object getWrappedMcObject() { return this.biome; } + + @Override + public String toString() { return this.getSerialString(); } + + + + //=======================// + // serialization methods // + //=======================// + + public String serialize(ILevelWrapper levelWrapper) { - // the result can be quickly used as a semi-stable hashing method, so it's going to be cached - if (this.serializationResult != null) - return this.serializationResult; + if (levelWrapper == null) + { + return EMPTY_STRING; + } - 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 - Objects.requireNonNull(resourceLocation); + if (this.serialString == null) + { + 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) + { + String biomeName; + #if MC_1_16_5 || MC_1_17_1 + biomeName = this.biome.toString(); + #else + biomeName = this.biome.value().toString(); + #endif + + LOGGER.warn("unable to serialize: " + biomeName); + // shouldn't normally happen, but just in case + this.serialString = ""; + } + else + { + this.serialString = resourceLocation.getNamespace() + ":" + resourceLocation.getPath(); + } + } - this.serializationResult = resourceLocation.getNamespace() + ":" + resourceLocation.getPath(); - return this.serializationResult; + return this.serialString; } - - @Override - public ILevelWrapper getLevelWrapper() { - return levelWrapper; - } - - public static IBiomeWrapper deserialize(String resourceLocationString, ILevelWrapper levelWrapper) throws IOException { + + public static IBiomeWrapper deserialize(String resourceLocationString, ILevelWrapper levelWrapper) throws IOException + { + if (resourceLocationString.equals(EMPTY_STRING)) + { + LOGGER.warn("["+EMPTY_STRING+"] biome string deserialized. This may mean there was a file saving error or a biome saving error."); + return EMPTY_WRAPPER; + } + else if (resourceLocationString.trim().isEmpty() || resourceLocationString.equals("")) + { + LOGGER.warn("Null biome string deserialized."); + return EMPTY_WRAPPER; + } + + + // parse the resource location int separatorIndex = resourceLocationString.indexOf(":"); - if (separatorIndex == -1) { + 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 + { + Level level = (Level)levelWrapper.getWrappedMcObject(); + net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); + boolean success; #if MC_1_16_5 || MC_1_17_1 Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation); + success = (biome != null); #elif MC_1_18_2 || 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); - assert unwrappedBiome != null; - + success = (unwrappedBiome != null); Holder biome = new Holder.Direct<>(unwrappedBiome); #endif - + + + + if (!success) + { + LOGGER.warn("Unable to deserialize biome from string: [" + resourceLocationString + "]"); + return EMPTY_WRAPPER; + } + return getBiomeWrapper(biome, levelWrapper); - } 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 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 e5f87c95b..4923b9441 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 @@ -4,10 +4,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; -import net.minecraft.core.RegistryAccess; -import net.minecraft.core.registries.BuiltInRegistries; 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.Logger; @@ -18,22 +15,24 @@ import java.util.concurrent.ConcurrentHashMap; #if MC_1_16_5 || MC_1_17_1 import net.minecraft.core.Registry; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.EmptyBlockGetter; #elif MC_1_18_2 || MC_1_19_2 +import net.minecraft.client.Minecraft; +import net.minecraft.world.level.Level; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; #else +import net.minecraft.client.Minecraft; +import net.minecraft.world.level.Level; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.world.level.EmptyBlockGetter; -import org.jetbrains.annotations.NotNull; - -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; #endif public class BlockStateWrapper implements IBlockStateWrapper { - /** example "minecraft:plains" */ + /** example "minecraft:water" */ public static final String RESOURCE_LOCATION_SEPARATOR = ":"; /** example "minecraft:water_STATE_{level:0}" */ public static final String STATE_STRING_SEPARATOR = "_STATE_"; @@ -42,111 +41,102 @@ public class BlockStateWrapper implements IBlockStateWrapper // must be defined before AIR, otherwise a null pointer will be thrown private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - public static final ConcurrentHashMap cache = new ConcurrentHashMap<>(); - public static final BlockStateWrapper AIR = fromBlockState(BuiltInRegistries.BLOCK.get(ResourceLocation.tryParse("minecraft:air")).defaultBlockState(), null, false); - public static final String[] RENDERER_IGNORED_BLOCKS_RESOURCE_LOCATIONS = {"minecraft:air", "minecraft:barrier", "minecraft:structure_void", "minecraft:light"}; - public static final HashMap RENDERER_IGNORED_BLOCKS_INTERNAL = getRendererIgnoredBlocksInternal(RENDERER_IGNORED_BLOCKS_RESOURCE_LOCATIONS); - public static final HashMap RENDERER_IGNORED_BLOCKS = getRendererIgnoredBlocks(RENDERER_IGNORED_BLOCKS_INTERNAL); + public static final ConcurrentHashMap WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>(); + + public static final String AIR_STRING = "AIR"; + public static final BlockStateWrapper AIR = new BlockStateWrapper(null, null); + + public static final String[] RENDERER_IGNORED_BLOCKS_RESOURCE_LOCATIONS = { AIR_STRING, "minecraft:barrier", "minecraft:structure_void", "minecraft:light" }; + + public static HashSet rendererIgnoredBlocks = null; + + + + // properties // + + public final BlockState blockState; + /** technically final, but since it requires a method call to generate it can't be marked as such */ + private String serialString; - /** - * 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 // //==============// - public static BlockStateWrapper fromBlockState(BlockState blockState, @NotNull ILevelWrapper levelWrapper) + public static BlockStateWrapper fromBlockState(BlockState blockState, ILevelWrapper levelWrapper) { - return fromBlockState(blockState, levelWrapper, true); - } - - private static BlockStateWrapper fromBlockState(BlockState blockState, @Nullable ILevelWrapper levelWrapper, boolean nullCheck) - { - if (Objects.requireNonNull(blockState).isAir() && AIR != null) + if (blockState == null || blockState.isAir()) + { return AIR; - - return cache.computeIfAbsent(blockState, blockState1 -> new BlockStateWrapper(blockState1, levelWrapper, nullCheck)); - } - - /** - * Only meant for use in the {@code RENDERER_IGNORED_BLOCKS_INTERNAL} list. Do not use elsewhere, since the {@code levelWrapper} parameter of each {@code IBlockStateWrapper} will be {@code null}, causing issues. - * @param resourceLocations The resource location(s) of the block(s) that should be ignored by the renderer, may only contain {@code [a-z0-9/._-)} characters. - * @return The default blockstate(s) of the block(s), paired with the serialized resource location(s) of the block(s), which should be passed into the {@code RENDERER_IGNORED_BLOCKS_INTERNAL} map and the {@code getRendererIgnoredBlocks} method. - */ - @SuppressWarnings("SameParameterValue") - private static @NotNull HashMap getRendererIgnoredBlocksInternal(String @NotNull ... resourceLocations) - { - HashMap blockStates = new HashMap<>(); - - for (String resourceLocation : resourceLocations) - { - ResourceLocation fetchedResourceLocation = Objects.requireNonNull(ResourceLocation.tryParse(resourceLocation), String.format("Supplied a resource location that couldn't be parsed by Minecraft: %s", resourceLocation)); - var splitResourceLocation = resourceLocation.split(":"); - - if (splitResourceLocation.length == 0) { - LOGGER.warn("A resource location that should be ignored by the renderer was in an invalid format: {}", resourceLocation); - continue; - } - - blockStates.put(BuiltInRegistries.BLOCK.get(fetchedResourceLocation).defaultBlockState(), splitResourceLocation[1].toUpperCase(Locale.ROOT)); } - return blockStates; + return WRAPPER_BY_BLOCK_STATE.computeIfAbsent(blockState, newBlockState -> new BlockStateWrapper(newBlockState, levelWrapper)); } - /** - * Only meant for use in the {@code RENDERER_IGNORED_BLOCKS} list. Do not use elsewhere, since the {@code levelWrapper} parameter of each {@code IBlockStateWrapper} will be {@code null}, causing issues. - * @param rendererIgnoredBlocks A map containing the blockstate(s) of the block(s), paired with the resource location(s) of the block(s) that should be ignored by the renderer. - * @return The blockstate wrapper(s) of the blockstate(s), which should be passed into the {@code RENDERER_IGNORED_BLOCKS} list. - */ - @SuppressWarnings("SameParameterValue") - private static @NotNull HashMap getRendererIgnoredBlocks(@NotNull Map rendererIgnoredBlocks) + private BlockStateWrapper(BlockState blockState, ILevelWrapper levelWrapper) { - HashMap blockStateWrappers = new HashMap<>(); - - for (Map.Entry blockStateResourceLocations : rendererIgnoredBlocks.entrySet()) - { - blockStateWrappers.put(blockStateResourceLocations.getValue(), fromBlockState(blockStateResourceLocations.getKey(), null, false)); - } - - return blockStateWrappers; - } - - public final BlockState blockState; - @CheckForNull - public final ILevelWrapper levelWrapper; - - BlockStateWrapper(BlockState blockState, @Nullable ILevelWrapper levelWrapper) - { - this(blockState, levelWrapper, true); - } - - private BlockStateWrapper(BlockState blockState, @Nullable ILevelWrapper levelWrapper, boolean nullCheck) { this.blockState = blockState; - - if (nullCheck) - { - this.levelWrapper = RENDERER_IGNORED_BLOCKS_INTERNAL.containsKey(blockState) - ? null - : Objects.requireNonNull(levelWrapper); - } - else - { - this.levelWrapper = levelWrapper; - } - - LOGGER.trace("Created BlockStateWrapper for [{}]", blockState); + this.serialString = this.serialize(levelWrapper); + LOGGER.trace("Created BlockStateWrapper ["+this.serialString+"] for ["+blockState+"]"); } - //=========// - // methods // - //=========// + //================// + // helper methods // + //================// + + /** + * Requires a {@link ILevelWrapper} since {@link BlockStateWrapper#deserialize(String,ILevelWrapper)} also requires one. + * This way the method won't accidentally be called before the deserialization can be completed. + */ + public static HashSet getRendererIgnoredBlocks(ILevelWrapper levelWrapper) + { + // use the cached version if possible + if (rendererIgnoredBlocks != null) + { + return rendererIgnoredBlocks; + } + + + // deserialize each of the given resource locations + HashSet blockStateWrappers = new HashSet<>(); + for (String blockResourceLocation : RENDERER_IGNORED_BLOCKS_RESOURCE_LOCATIONS) + { + try + { + BlockStateWrapper DefaultBlockStateToIgnore = (BlockStateWrapper) deserialize(blockResourceLocation, levelWrapper); + blockStateWrappers.add(DefaultBlockStateToIgnore); + + if (DefaultBlockStateToIgnore == AIR) + { + continue; + } + + // add all possible blockstates (to account for light blocks with different light values and such) + List blockStatesToIgnore = DefaultBlockStateToIgnore.blockState.getBlock().getStateDefinition().getPossibleStates(); + for (BlockState blockState : blockStatesToIgnore) + { + BlockStateWrapper newBlockToIgnore = BlockStateWrapper.fromBlockState(blockState, levelWrapper); + blockStateWrappers.add(newBlockToIgnore); + } + } + catch (IOException e) + { + LOGGER.warn("Unable to deserialize rendererIgnoredBlock with the resource location: ["+blockResourceLocation+"]. Error: "+e.getMessage(), e); + } + } + + rendererIgnoredBlocks = blockStateWrappers; + return rendererIgnoredBlocks; + } + + + + //=================// + // wrapper methods // + //=================// @Override public int getOpacity() @@ -168,134 +158,7 @@ public class BlockStateWrapper implements IBlockStateWrapper public int getLightEmission() { return (this.blockState != null) ? this.blockState.getLightEmission() : 0; } @Override - public String serialize() - { - // the result can be quickly used as a semi-stable hashing method, so it's going to be cached - if (this.serializationResult != null) - return this.serializationResult; - - if (RENDERER_IGNORED_BLOCKS_INTERNAL.containsKey(this.blockState)) - return this.serializationResult = RENDERER_IGNORED_BLOCKS_INTERNAL.get(this.blockState); - - Objects.requireNonNull(levelWrapper); - RegistryAccess registryAccess = ((Level) levelWrapper.getWrappedMcObject()).registryAccess(); - - 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 - resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(this.blockState.getBlock()); - #else - resourceLocation = registryAccess.registryOrThrow(Registries.BLOCK).getKey(this.blockState.getBlock()); - #endif - Objects.requireNonNull(resourceLocation); - - this.serializationResult = resourceLocation.getNamespace() + RESOURCE_LOCATION_SEPARATOR + resourceLocation.getPath() - + STATE_STRING_SEPARATOR + serializeBlockStateProperties(this.blockState); - - return this.serializationResult; - } - - @Override - @Nullable - public ILevelWrapper getLevelWrapper() { - return levelWrapper; - } - - public static IBlockStateWrapper deserialize(String resourceStateString, ILevelWrapper levelWrapper) throws IOException - { - if (resourceStateString.isEmpty()) - throw new IOException("resourceStateString is empty"); - - if (RENDERER_IGNORED_BLOCKS_INTERNAL.containsValue(resourceStateString)) - return RENDERER_IGNORED_BLOCKS.get(resourceStateString); - - // 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 - { - Block block; - #if MC_1_16_5 || MC_1_17_1 - block = Registry.BLOCK.get(resourceLocation); - #elif MC_1_18_2 || MC_1_19_2 - net.minecraft.core.RegistryAccess registryAccess = ((Level)levelWrapper.getWrappedMcObject()).registryAccess(); - block = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).get(resourceLocation); - #else - net.minecraft.core.RegistryAccess registryAccess = ((Level)levelWrapper.getWrappedMcObject()).registryAccess(); - block = registryAccess.registryOrThrow(Registries.BLOCK).get(resourceLocation); - #endif - - - - BlockState foundState = null; - List possibleStateList = block.getStateDefinition().getPossibleStates(); - for (BlockState possibleState : possibleStateList) - { - String possibleStatePropertiesString = serializeBlockStateProperties(possibleState); - if (possibleStatePropertiesString.equals(blockStatePropertiesString)) - { - foundState = possibleState; - break; - } - } - - Objects.requireNonNull(foundState); - return new BlockStateWrapper(foundState, levelWrapper); - } - catch (Exception 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(); - } - + public String getSerialString() { return this.serialString; } @Override public boolean equals(Object obj) @@ -310,16 +173,15 @@ public class BlockStateWrapper implements IBlockStateWrapper return false; } - BlockStateWrapper that = (BlockStateWrapper) 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(this.serialize()); + BlockStateWrapper that = (BlockStateWrapper) obj; + // the serialized value is used so we can test the contents instead of the references + return Objects.equals(this.getSerialString(), that.getSerialString()); } + @Override + public int hashCode() { return Objects.hash(this.getSerialString()); } + + @Override public Object getWrappedMcObject() { return this.blockState; } @@ -353,8 +215,178 @@ public class BlockStateWrapper implements IBlockStateWrapper } @Override - public String toString() { - return this.serialize(); + public String toString() { return this.getSerialString(); } + + + + //=======================// + // serialization methods // + //=======================// + + private String serialize(ILevelWrapper levelWrapper) + { + if (this.blockState == null) + { + return AIR_STRING; + } + + + + // older versions of MC have a static registry + #if !(MC_1_16_5 || MC_1_17_1) + Level level = (Level)levelWrapper.getWrappedMcObject(); + net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); + #endif + + 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 + resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(this.blockState.getBlock()); + #else + resourceLocation = registryAccess.registryOrThrow(Registries.BLOCK).getKey(this.blockState.getBlock()); + #endif + + + + if (resourceLocation == null) + { + LOGGER.warn("No ResourceLocation found, unable to serialize: " + this.blockState); + return AIR_STRING; + } + + this.serialString = resourceLocation.getNamespace() + RESOURCE_LOCATION_SEPARATOR + resourceLocation.getPath() + + STATE_STRING_SEPARATOR + serializeBlockStateProperties(this.blockState); + + return this.serialString; } - + + + /** will only work if a level is currently loaded */ + public static IBlockStateWrapper deserialize(String resourceStateString, ILevelWrapper levelWrapper) throws IOException + { + if (resourceStateString.equals(AIR_STRING) || resourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case + { + 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) + { + // blockstate properties found + 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 + { + + #if !(MC_1_16_5 || 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_1_16_5 || MC_1_17_1 + block = Registry.BLOCK.get(resourceLocation); + #elif MC_1_18_2 || 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) + { + // shouldn't normally happen, but here to make the compiler happy + 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; + } + } + } + + // 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 + LOGGER.warn("Unable to find BlockState for Block [" + resourceLocation + "] with properties: [" + blockStatePropertiesString + "]. Using the default block state."); + } + + foundState = block.defaultBlockState(); + } + return new BlockStateWrapper(foundState, levelWrapper); + } + catch (Exception 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(); + } + + + } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java index c184a959e..b9d335944 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java @@ -29,7 +29,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; -import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import net.minecraft.client.multiplayer.ClientChunkCache; import net.minecraft.client.multiplayer.ClientLevel; @@ -95,8 +94,8 @@ public class ChunkWrapper implements IChunkWrapper //=============// // constructor // //=============// - private String stackTraceElements = Arrays.toString(Thread.currentThread().getStackTrace()); - public ChunkWrapper(ChunkAccess chunk, LevelReader lightSource, @Nullable ILevelWrapper wrappedLevel) + + public ChunkWrapper(ChunkAccess chunk, LevelReader lightSource, ILevelWrapper wrappedLevel) { this.chunk = chunk; this.lightSource = lightSource; @@ -157,20 +156,23 @@ public class ChunkWrapper implements IChunkWrapper @Override public IBiomeWrapper getBiome(int relX, int relY, int relZ) { - //if (wrappedLevel != null) return wrappedLevel.getBiome(new DhBlockPos(x + getMinX(), y, z + getMinZ())); - #if PRE_MC_1_17_1 return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome( - relX >> 2, relY >> 2, relZ >> 2)); + relX >> 2, relY >> 2, relZ >> 2), + this.wrappedLevel); #elif PRE_MC_1_18_2 return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome( - QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ))); + QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)), + this.wrappedLevel); #elif PRE_MC_1_18_2 return BiomeWrapper.getBiomeWrapper(this.chunk.getNoiseBiome( - QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ))); - #else //Now returns a Holder instead of Biome + QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)), + this.wrappedLevel); + #else + //Now returns a Holder instead of Biome return BiomeWrapper.getBiomeWrapper(this.chunk.getNoiseBiome( - QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)), wrappedLevel); + QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)), + this.wrappedLevel); #endif } @@ -214,7 +216,7 @@ public class ChunkWrapper implements IChunkWrapper if (this.chunk instanceof LevelChunk) { LevelChunk levelChunk = (LevelChunk) this.chunk; - if (this.wrappedLevel instanceof IClientLevelWrapper) + if (levelChunk.getLevel().isClientSide()) { weakMapLock.readLock().lock(); boolean fixedIsClientLightReady = chunksToUpdateClientLightReady.get(this.chunk); @@ -368,12 +370,11 @@ public class ChunkWrapper implements IChunkWrapper @Override public IBlockStateWrapper getBlockState(int relX, int relY, int relZ) { - //if (wrappedLevel != null) return wrappedLevel.getBlockState(new DhBlockPos(x + getMinX(), y, z + getMinZ())); - return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(new BlockPos(relX, relY, relZ)), wrappedLevel); + return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(new BlockPos(relX, relY, relZ)), this.wrappedLevel); } @Override - public boolean isStillValid() { return this.wrappedLevel == null || this.wrappedLevel.tryGetChunk(this.chunkPos) == this; } + public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; } #if POST_MC_1_20_1 private static boolean checkLightSectionsOnChunk(LevelChunk chunk, LevelLightEngine engine) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/ClassicConfigGUI.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/ClassicConfigGUI.java index cd0b35ab2..ca0f10490 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/ClassicConfigGUI.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/ClassicConfigGUI.java @@ -385,9 +385,15 @@ public class ClassicConfigGUI DhDrawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title - // If the update is pending, display this message to inform the user that it will apply when the game restarts - if (SelfUpdater.deleteOldOnClose) - DhDrawString(matrices, font, Translatable(configBase.modID + ".updater.waitingForClose"), 4, height - 38, 0xFFFFFF); + if (this.configBase.modID == "distanthorizons") + { + // Display version + DhDrawString(matrices, font, TextOrLiteral(ModInfo.VERSION), 2, height - 10, 0xAAAAAA); + + // If the update is pending, display this message to inform the user that it will apply when the game restarts + if (SelfUpdater.deleteOldOnClose) + DhDrawString(matrices, font, Translatable(configBase.modID + ".updater.waitingForClose"), 4, height - 38, 0xFFFFFF); + } // Render the tooltip only if it can find a tooltip in the language file diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java index 5f67a8d75..0cd35bbda 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java @@ -165,7 +165,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper @Override public IBlockStateWrapper getBlockState(DhBlockPos pos) { - return BlockStateWrapper.fromBlockState(this.level.getBlockState(McObjectConverter.Convert(pos)), getWrapper(level)); + return BlockStateWrapper.fromBlockState(this.level.getBlockState(McObjectConverter.Convert(pos)), this); } @Override diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java index b10dcdc50..18dbc08f0 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java @@ -140,7 +140,7 @@ public class ServerLevelWrapper implements IServerLevelWrapper public IChunkWrapper tryGetChunk(DhChunkPos pos) { if (!level.hasChunk(pos.x, pos.z)) return null; - ChunkAccess chunk = level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false); + ChunkAccess chunk = level.getChunk(pos.x, pos.z, ChunkStatus.EMPTY, false); if (chunk == null) return null; return new ChunkWrapper(chunk, level, this); } @@ -156,7 +156,7 @@ public class ServerLevelWrapper implements IServerLevelWrapper @Override public IBlockStateWrapper getBlockState(DhBlockPos pos) { - return BlockStateWrapper.fromBlockState(level.getBlockState(McObjectConverter.Convert(pos)), getWrapper(level)); + return BlockStateWrapper.fromBlockState(level.getBlockState(McObjectConverter.Convert(pos)), this); } @Override diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 5859fbb75..e54490bbb 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -484,7 +484,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv ChunkAccess chunk = totalChunks.get(x, z); if (chunk != null) { - chunkWrapperList.set(x, z, new ChunkWrapper(chunk, region, this.serverlevel.getServerLevelWrapper())); + chunkWrapperList.set(x, z, new ChunkWrapper(chunk, region, serverlevel.getLevelWrapper())); } }); diff --git a/coreSubProjects b/coreSubProjects index c5abc22c5..517925a20 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit c5abc22c58e6a70d1a6311e92937d76ffa67127b +Subproject commit 517925a20705d54771a4285331afedee070f49c7 diff --git a/fabric/build.gradle b/fabric/build.gradle index 464bbd074..824cedccd 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -12,7 +12,9 @@ loom { setConfigName("Fabric Client") ideConfigGenerated(false) runDir("run/client") - +<<<<<<< Updated upstream +======= +>>>>>>> Stashed changes } server { server() diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkMap.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkMap.java index 565b5aeb7..6ac075501 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkMap.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkMap.java @@ -31,6 +31,18 @@ public class MixinChunkMap @Inject(method = "save", at = @At(value = "INVOKE", target = CHUNK_SERIALIZER_WRITE)) private void onChunkSave(ChunkAccess chunk, CallbackInfoReturnable ci) { + // corrupt/incomplete chunk validation + #if MC_1_18_2 + // MC 1.18.2 has the tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks) + // this should prevent that from happening + if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect()) + { + return; + } + #endif + + + // biome validation #if MC_1_16_5 || MC_1_17_1 if (chunk.getBiomes() == null) { diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/BCLibAccessor.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/BCLibAccessor.java index 2b7b642db..968a98086 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/BCLibAccessor.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/BCLibAccessor.java @@ -1,8 +1,8 @@ package com.seibel.distanthorizons.fabric.wrappers.modAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IBCLibAccessor; -#if MC_1_16_5 -#elif PRE_MC_1_19_2 +#if MC_1_16_5 || MC_1_17_1 +#elif MC_1_18_2 import ru.bclib.config.ClientConfig; import ru.bclib.config.Configs; #else @@ -17,8 +17,8 @@ public class BCLibAccessor implements IBCLibAccessor public void setRenderCustomFog(boolean newValue) { - #if MC_1_16_5 || MC_1_17_1 - #elif PRE_MC_1_19_2 + #if !(MC_1_16_5 || MC_1_17_1) // 1.16 and 1.17 don't have "ClientConfig.CUSTOM_FOG_RENDERING" + // Change the value of CUSTOM_FOG_RENDERING in the bclib client config // This disabled fog from rendering within bclib Configs.CLIENT_CONFIG.set(ClientConfig.CUSTOM_FOG_RENDERING, newValue); diff --git a/fabric/src/main/resources/DistantHorizons.fabric.mixins.json b/fabric/src/main/resources/DistantHorizons.fabric.mixins.json index 0c7244db8..d306798af 100644 --- a/fabric/src/main/resources/DistantHorizons.fabric.mixins.json +++ b/fabric/src/main/resources/DistantHorizons.fabric.mixins.json @@ -1,30 +1,29 @@ { - "required": true, - "minVersion": "0.8", - "package": "com.seibel.distanthorizons.fabric.mixins", - "mixins": [ - "server.unsafe.MixinThreadingDetector", - "server.MixinChunkGenerator", - "server.MixinChunkMap", - "server.MixinUtilBackgroundThread" - ], - "client": [ - "client.MixinClientLevel", - "client.MixinClientPacketListener", - "client.MixinDebugScreenOverlay", - "client.MixinFogRenderer", - "client.MixinGameRenderer", - "client.MixinLevelRenderer", - "client.MixinLightmap", - "client.MixinOptionsScreen", - "client.MixinMinecraft", - "client.MixinTextureUtil", - - "mods.sodium.MixinSodiumRenderer" - ], - "server": [], - "injectors": { - "defaultRequire": 1 - }, - "plugin": "com.seibel.distanthorizons.fabric.mixins.FabricMixinPlugin" + "required": true, + "minVersion": "0.8", + "package": "com.seibel.distanthorizons.fabric.mixins", + "mixins": [ + "server.unsafe.MixinThreadingDetector", + "server.MixinChunkGenerator", + "server.MixinChunkMap", + "server.MixinUtilBackgroundThread" + ], + "client": [ + "client.MixinClientLevel", + "client.MixinClientPacketListener", + "client.MixinDebugScreenOverlay", + "client.MixinFogRenderer", + "client.MixinGameRenderer", + "client.MixinLevelRenderer", + "client.MixinLightmap", + "client.MixinOptionsScreen", + "client.MixinMinecraft", + "client.MixinTextureUtil", + "mods.sodium.MixinSodiumRenderer" + ], + "server": [], + "injectors": { + "defaultRequire": 1 + }, + "plugin": "com.seibel.distanthorizons.fabric.mixins.FabricMixinPlugin" } diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 7e6907fd7..01ab3fbf9 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -1,56 +1,59 @@ { - "schemaVersion": 1, - "id": "distanthorizons", - "version": "${version}", - - "name": "${mod_name}", - "description": "${description}", - "authors": $authors, - - "contact": { - "homepage": "${homepage}", - "sources": "${source}", - "issues": "${issues}" - }, - - "license": "LGPL-3", - "icon": "icon.png", - - "accessWidener": "distanthorizons.accesswidener", - - "environment": "*", - "entrypoints": { - "client": [ - "com.seibel.distanthorizons.fabric.FabricClientMain" + "schemaVersion": 1, + "id": "distanthorizons", + "version": "${version}", + + "name": "${mod_name}", + "description": "${description}", + "authors": $authors, + + "contact": { + "homepage": "${homepage}", + "sources": "${source}", + "issues": "${issues}" + }, + + "license": "LGPL-3", + "icon": "icon.png", + + "accessWidener": "distanthorizons.accesswidener", + + "environment": "*", + "entrypoints": { + "client": [ + "com.seibel.distanthorizons.fabric.FabricClientMain" + ], + "server": [ + "com.seibel.distanthorizons.fabric.FabricDedicatedServerMain" + ], + "modmenu": [ + "com.seibel.distanthorizons.fabric.wrappers.config.ModMenuIntegration" + ] + }, + + "mixins": [ + "DistantHorizons.fabric.mixins.json" ], - "server": [ - "com.seibel.distanthorizons.fabric.FabricDedicatedServerMain" - ], - - "modmenu": [ - "com.seibel.distanthorizons.fabric.wrappers.config.ModMenuIntegration" - ] - }, - - "mixins": [ - "DistantHorizons.fabric.mixins.json" - ], - - "depends": { - "fabricloader": "*", - "fabric-api-base": "*", - "fabric-lifecycle-events-v1": "*", - "fabric-key-binding-api-v1": "*", - "fabric-resource-loader-v0": "*", - "minecraft": $compatible_minecraft_versions, - "java": ">=${java_version}" - }, - - "custom": { - "modmenu": { - "links": { - "modmenu.discord": "${discord}" - } + + "depends": { + "fabricloader": "*", + "fabric-api-base": "*", + "fabric-lifecycle-events-v1": "*", + "fabric-key-binding-api-v1": "*", + "fabric-resource-loader-v0": "*", + "minecraft": $compatible_minecraft_versions, + "java": ">=${java_version}" + }, + + "custom": { + "modmenu": { + "links": { + "modmenu.discord": "${discord}" + } + } + }, + + "suggests": { + "blendium": "*" } - } } diff --git a/forge/src/main/resources/DistantHorizons.mixins.json b/forge/src/main/resources/DistantHorizons.mixins.json index 83bfe64e2..4d03828c3 100644 --- a/forge/src/main/resources/DistantHorizons.mixins.json +++ b/forge/src/main/resources/DistantHorizons.mixins.json @@ -1,23 +1,23 @@ { - "required": true, - "minVersion": "0.8", - "package": "com.seibel.distanthorizons.forge.mixins", - "mixins": [ - "server.unsafe.MixinThreadingDetector", - "server.MixinUtilBackgroundThread", - "server.MixinChunkGenerator", - "server.MixinTFChunkGenerator" - ], - "client": [ - "client.MixinClientPacketListener", - "client.MixinDebugScreenOverlay", - "client.MixinFogRenderer", - "client.MixinGameRenderer", - "client.MixinLevelRenderer", - "client.MixinLightmap", - "client.MixinOptionsScreen", - "client.MixinTextureUtil" - ], - "server": [], - "plugin": "com.seibel.distanthorizons.forge.mixins.ForgeMixinPlugin" + "required": true, + "minVersion": "0.8", + "package": "com.seibel.distanthorizons.forge.mixins", + "mixins": [ + "server.unsafe.MixinThreadingDetector", + "server.MixinUtilBackgroundThread", + "server.MixinChunkGenerator", + "server.MixinTFChunkGenerator" + ], + "client": [ + "client.MixinClientPacketListener", + "client.MixinDebugScreenOverlay", + "client.MixinFogRenderer", + "client.MixinGameRenderer", + "client.MixinLevelRenderer", + "client.MixinLightmap", + "client.MixinOptionsScreen", + "client.MixinTextureUtil" + ], + "server": [], + "plugin": "com.seibel.distanthorizons.forge.mixins.ForgeMixinPlugin" } diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml index a9dccfc67..30f586289 100644 --- a/forge/src/main/resources/META-INF/mods.toml +++ b/forge/src/main/resources/META-INF/mods.toml @@ -1,33 +1,32 @@ - -modLoader="javafml" #//mandatory -loaderVersion="*" # // mandatory. Allow all forge versions as we are definding what Minecraft versions we requre later on -license="LGPL" -issueTrackerURL="${issues}" +modLoader = "javafml" #//mandatory +loaderVersion = "*" # // mandatory. Allow all forge versions as we are definding what Minecraft versions we requre later on +license = "LGPL" +issueTrackerURL = "${issues}" [[mods]] #//mandatory - modId="distanthorizons" #//mandatory - version= "${version}" #//mandatory, gets the version number from jar populated by the build.gradle script - displayName="${mod_name}" #//mandatory - authors=["James Seibel", "Leonardo Amato", "Cola", "coolGi", "Ran", "Leetom"] - #//updateJSONURL="https://change.me.example.invalid/updates.json" # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ - displayURL="${homepage}" - description= "${description}" #//mandatory. The description text for the mod - logoFile="logo.png" - catalogueImageIcon="icon.png" - credits="Massive thanks to: Leonardo, Cola, Ran, CoolGi, and Leetom. For their hard work to bring Distant Horizons to where it is today. - James" - #// if not set defaults to "false" - clientSideOnly="true" - #// if not set side defaults to "BOTH" - #// TODO change to "BOTH" when we add server support - side="CLIENT" - #// Allow any version to be present (or not) on the server - acceptableRemoteVersions="*" + modId = "distanthorizons" #//mandatory + version = "${version}" #//mandatory, gets the version number from jar populated by the build.gradle script + displayName = "${mod_name}" #//mandatory + authors = ["James Seibel", "Leonardo Amato", "Cola", "coolGi", "Ran", "Leetom"] + #//updateJSONURL="https://change.me.example.invalid/updates.json" # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ + displayURL = "${homepage}" + description = "${description}" #//mandatory. The description text for the mod + logoFile = "logo.png" + catalogueImageIcon = "icon.png" + credits = "Massive thanks to: Leonardo, Cola, Ran, CoolGi, and Leetom. For their hard work to bring Distant Horizons to where it is today. - James" + #// if not set defaults to "false" + clientSideOnly = "true" + #// if not set side defaults to "BOTH" + #// TODO change to "BOTH" when we add server support + side = "CLIENT" + #// Allow any version to be present (or not) on the server + acceptableRemoteVersions = "*" [[dependencies.distanthorizons]] - modId="minecraft" - mandatory=true - versionRange="${compatible_forgemc_versions}" # Where we set what version of mc it is avalible for - ordering="NONE" - side="BOTH" \ No newline at end of file + modId = "minecraft" + mandatory = true + versionRange = "${compatible_forgemc_versions}" # Where we set what version of mc it is avalible for + ordering = "NONE" + side = "BOTH" \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 3516d29bd..1eb3e376a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -30,6 +30,14 @@ netty_version=4.1.94.Final lwjgl_version=3.2.3 joml_version=1.10.2 + +# These are here so they can be changed with cmd arguments +# If they are null, they would be automatically set +# (This is mainly used for the CI) +gitMainCommit=null +gitCoreCommit=null +gitMainBranch=null + # Internal Properties (These are set at runtime for Forgix to merge jar's) versionStr=