Compare commits

...

11 Commits

Author SHA1 Message Date
s809 f69800dfe3 Move max generation distance check functionality to render distance config 2025-06-10 00:29:06 +05:00
James Seibel cc251e46b0 Add Api Before/After Text Create events 2025-06-09 07:50:25 -05:00
James Seibel 7aa0bfefec Fix hash collisions in FullDataPointIdMap 2025-06-06 07:43:44 -05:00
James Seibel 9bdad5e4f1 Fix 1.21.5 compiling 2025-06-06 07:36:00 -05:00
James Seibel baebb7323d Close #776 (fix Polytone client biome colors) 2025-06-05 07:53:23 -05:00
James Seibel 8a3175f345 Mark Polytone as incompatible 2025-06-04 07:49:15 -05:00
James Seibel dc58efb301 Handle nulls in ChunkLoader
Should fix WorldPainter worlds
2025-06-04 07:28:51 -05:00
James Seibel c9ac4b2ada Fix GLMC.glDeleteTextures() calls 2025-06-04 07:07:51 -05:00
s809 6e1ec476ed Check LOD timestamps in file handler threads 2025-06-03 23:41:51 +05:00
James Seibel d1aa5a524b Remove line ending from editorconfig
Done to fix some issues with some devs on linux
2025-05-17 11:47:06 -05:00
James Seibel 5c661a3a76 yaml indent 2 -> 4
for consistency
2025-05-17 11:25:37 -05:00
18 changed files with 329 additions and 216 deletions
+1 -2
View File
@@ -5,7 +5,6 @@ root = true
[*] [*]
charset = utf-8 charset = utf-8
end_of_line = crlf
indent_size = 4 indent_size = 4
indent_style = space indent_style = space
insert_final_newline = false insert_final_newline = false
@@ -688,7 +687,7 @@ ij_markdown_wrap_text_inside_blockquotes = true
ij_toml_keep_indents_on_empty_lines = false ij_toml_keep_indents_on_empty_lines = false
[{*.yaml,*.yml}] [{*.yaml,*.yml}]
indent_size = 2 indent_size = 4
ij_yaml_align_values_properties = do_not_align ij_yaml_align_values_properties = do_not_align
ij_yaml_autoinsert_sequence_marker = true ij_yaml_autoinsert_sequence_marker = true
ij_yaml_block_mapping_on_new_line = false ij_yaml_block_mapping_on_new_line = false
@@ -47,6 +47,7 @@ import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.biome.Biomes;
#endif #endif
@@ -130,14 +131,6 @@ public class BiomeWrapper implements IBiomeWrapper
//LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]"); //LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]");
} }
/** should only be used to create {@link BiomeWrapper#EMPTY_WRAPPER} */
private BiomeWrapper()
{
this.biome = null;
this.serialString = EMPTY_BIOME_STRING;
this.hashCode = Objects.hash(this.serialString);
}
//=========// //=========//
@@ -286,64 +279,16 @@ public class BiomeWrapper implements IBiomeWrapper
BiomeWrapper foundWrapper = EMPTY_WRAPPER; BiomeWrapper foundWrapper = EMPTY_WRAPPER;
try try
{ {
// parse the resource location
int separatorIndex = resourceLocationString.indexOf(":");
if (separatorIndex == -1)
{
throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
}
ResourceLocation resourceLocation;
try
{
#if MC_VER < MC_1_21_1
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
#else
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
#endif
}
catch (Exception e)
{
throw new IOException("No Resource Location found for the string: [" + resourceLocationString + "] Error: [" + e.getMessage() + "].");
}
try try
{ {
Level level = (Level) levelWrapper.getWrappedMcObject(); Level level = (Level) levelWrapper.getWrappedMcObject();
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess(); net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
boolean success; BiomeDeserializeResult deserializeResult = deserializeBiome(resourceLocationString, registryAccess);
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
success = (biome != null);
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
success = (unwrappedBiome != null);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
#elif MC_VER < MC_1_21_3
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
success = (unwrappedBiome != null);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
#else
Holder<Biome> biome;
Optional<Holder.Reference<Biome>> optionalBiomeHolder = registryAccess.lookupOrThrow(Registries.BIOME).get(resourceLocation);
if (optionalBiomeHolder.isPresent())
{
Biome unwrappedBiome = optionalBiomeHolder.get().value();
success = (unwrappedBiome != null);
biome = new Holder.Direct<>(unwrappedBiome);
}
else
{
success = false;
biome = null;
}
#endif
if (!success) if (!deserializeResult.success)
{ {
if (!brokenResourceLocationStrings.contains(resourceLocationString)) if (!brokenResourceLocationStrings.contains(resourceLocationString))
{ {
@@ -354,7 +299,7 @@ public class BiomeWrapper implements IBiomeWrapper
} }
foundWrapper = (BiomeWrapper) getBiomeWrapper(biome, levelWrapper); foundWrapper = (BiomeWrapper) getBiomeWrapper(deserializeResult.biome, levelWrapper);
return foundWrapper; return foundWrapper;
} }
catch (Exception e) catch (Exception e)
@@ -368,4 +313,82 @@ public class BiomeWrapper implements IBiomeWrapper
} }
} }
public static BiomeDeserializeResult deserializeBiome(String resourceLocationString, net.minecraft.core.RegistryAccess registryAccess) throws IOException
{
// parse the resource location
int separatorIndex = resourceLocationString.indexOf(":");
if (separatorIndex == -1)
{
throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
}
ResourceLocation resourceLocation;
try
{
#if MC_VER < MC_1_21_1
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
#else
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
#endif
}
catch (Exception e)
{
throw new IOException("No Resource Location found for the string: [" + resourceLocationString + "] Error: [" + e.getMessage() + "].");
}
boolean success;
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
success = (biome != null);
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
success = (unwrappedBiome != null);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
#elif MC_VER < MC_1_21_3
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
success = (unwrappedBiome != null);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
#else
Holder<Biome> biome;
Optional<Holder.Reference<Biome>> optionalBiomeHolder = registryAccess.lookupOrThrow(Registries.BIOME).get(resourceLocation);
if (optionalBiomeHolder.isPresent())
{
Biome unwrappedBiome = optionalBiomeHolder.get().value();
success = (unwrappedBiome != null);
biome = new Holder.Direct<>(unwrappedBiome);
}
else
{
success = false;
biome = null;
}
#endif
return new BiomeDeserializeResult(success, biome);
}
//================//
// helper classes //
//================//
public static class BiomeDeserializeResult
{
public final boolean success;
#if MC_VER < MC_1_18_2
public final Biome biome;
#else
public final Holder<Biome> biome;
#endif
public BiomeDeserializeResult(boolean success, #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome)
{
this.success = success;
this.biome = biome;
}
}
} }
@@ -91,7 +91,7 @@ public class ClientBlockStateColorCache
private static final RandomSource RANDOM = RandomSource.create(); private static final RandomSource RANDOM = RandomSource.create();
#endif #endif
private final IClientLevelWrapper levelWrapper; private final IClientLevelWrapper clientLevelWrapper;
private final BlockState blockState; private final BlockState blockState;
private final LevelReader level; private final LevelReader level;
@@ -174,7 +174,7 @@ public class ClientBlockStateColorCache
public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper samplingLevel) public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper samplingLevel)
{ {
this.blockState = blockState; this.blockState = blockState;
this.levelWrapper = samplingLevel; this.clientLevelWrapper = samplingLevel;
this.level = (LevelReader) samplingLevel.getWrappedMcObject(); this.level = (LevelReader) samplingLevel.getWrappedMcObject();
this.resolveColors(); this.resolveColors();
} }
@@ -471,7 +471,7 @@ public class ClientBlockStateColorCache
try try
{ {
tintColor = Minecraft.getInstance().getBlockColors() tintColor = Minecraft.getInstance().getBlockColors()
.getColor(this.blockState, new TintWithoutLevelOverrider(biome, this.levelWrapper), McObjectConverter.Convert(pos), this.tintIndex); .getColor(this.blockState, new TintWithoutLevelOverrider(biome, this.clientLevelWrapper), McObjectConverter.Convert(pos), this.tintIndex);
} }
catch (UnsupportedOperationException e) catch (UnsupportedOperationException e)
{ {
@@ -19,8 +19,10 @@
package com.seibel.distanthorizons.common.wrappers.block; package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.level.*; import net.minecraft.world.level.*;
@@ -29,6 +31,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.FluidState;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -36,22 +39,64 @@ import org.jetbrains.annotations.Nullable;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
#endif #endif
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class TintWithoutLevelOverrider implements BlockAndTintGetter public class TintWithoutLevelOverrider implements BlockAndTintGetter
{ {
/** private static final Logger LOGGER = DhLoggerBuilder.getLogger();
* This will only ever be null if there was an issue with {@link IClientLevelWrapper#getPlainsBiomeWrapper()}
* but {@link Nullable} is there just in case. #if MC_VER < MC_1_18_2
*/ public static final ConcurrentMap<String, Biome> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
@Nullable
#if MC_VER >= MC_1_18_2
public final Holder<Biome> biome;
#else #else
public final Biome biome; public static final ConcurrentMap<String, Holder<Biome>> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
#endif #endif
@NotNull
private final BiomeWrapper biomeWrapper;
//=============//
// constructor //
//=============//
public TintWithoutLevelOverrider(@NotNull BiomeWrapper biomeWrapper, IClientLevelWrapper clientLevelWrapper)
{ this.biomeWrapper = biomeWrapper; }
//=========//
// methods //
//=========//
@Override
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
{
String biomeString = this.biomeWrapper.getSerialString();
if (biomeString == null
|| biomeString.isEmpty()
|| biomeString.equals(BiomeWrapper.EMPTY_BIOME_STRING))
{
// default to "plains" for empty/invalid biomes
biomeString = "minecraft:plains";
}
return colorResolver.getColor(unwrap(getClientBiome(biomeString)), blockPos.getX(), blockPos.getZ());
}
private static Biome unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
{
#if MC_VER >= MC_1_18_2
return biome.value();
#else
return biome;
#endif
}
/** /**
* Constructs the TintWithoutLevelOverrider, storing the provided Biome Holder for late-binding access.
*
* <p>Previously, this class might have immediately unwrapped the Holder like this:</p> * <p>Previously, this class might have immediately unwrapped the Holder like this:</p>
* <pre>{@code * <pre>{@code
* // Inside constructor (OLD WAY - PROBLEMATIC): * // Inside constructor (OLD WAY - PROBLEMATIC):
@@ -85,41 +130,52 @@ public class TintWithoutLevelOverrider implements BlockAndTintGetter
* whenever the biome information is needed, ensuring it always retrieves the most current {@code Biome} * whenever the biome information is needed, ensuring it always retrieves the most current {@code Biome}
* instance associated with the holder at that time.</p> * instance associated with the holder at that time.</p>
*/ */
public TintWithoutLevelOverrider(BiomeWrapper biomeWrapper, IClientLevelWrapper clientLevelWrapper) private static #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif getClientBiome(String biomeResourceString)
{ {
#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome = biomeWrapper.biome; // cache the client biomes so we don't have to re-parse the resource location every time
if (biome == null) // We are looking at the empty biome wrapper return BIOME_BY_RESOURCE_STRING.compute(biomeResourceString,
{ (resourceString, existingBiome) ->
BiomeWrapper plainsBiomeWrapper = ((BiomeWrapper) clientLevelWrapper.getPlainsBiomeWrapper()); {
if (plainsBiomeWrapper != null) if (existingBiome != null)
{ {
biome = plainsBiomeWrapper.biome; return existingBiome;
} }
}
ClientLevel clientLevel = Minecraft.getInstance().level;
this.biome = biome; if (clientLevel == null)
} {
// shouldn't happen, but just in case
throw new IllegalStateException("Attempted to get client biome when no client level was loaded.");
}
@Override
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver) BiomeWrapper.BiomeDeserializeResult result;
{ try
if (this.biome == null) {
{ result = BiomeWrapper.deserializeBiome(resourceString, clientLevel.registryAccess());
// hopefully unneeded debug color }
return ColorUtil.CYAN; catch (Exception e)
} {
return colorResolver.getColor(unwrap(biome), blockPos.getX(), blockPos.getZ()); LOGGER.warn("Unable to deserialize client biome ["+resourceString+"], using fallback...");
}
try
private static Biome unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome) {
{ result = BiomeWrapper.deserializeBiome("minecraft:plains", clientLevel.registryAccess());
#if MC_VER >= MC_1_18_2 }
return biome.value(); catch (IOException ex)
#else {
return biome; // should never happen, if it does this log will explode, but just in case
#endif LOGGER.error("Unable to deserialize fallback client biome [minecraft:plains], returning NULL.");
return null;
}
}
if (result.success)
{
existingBiome = result.biome;
}
return existingBiome;
});
} }
@@ -179,20 +179,24 @@ public class ChunkLoader
//================== Read params for making the LevelChunk ================== //================== Read params for making the LevelChunk ==================
UpgradeData upgradeData; UpgradeData upgradeData = UpgradeData.EMPTY;
#if MC_VER < MC_1_17_1 // commented out 2025-06-04 as a test to see if the upgrade data
upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10) // is actually necessary for DH or if it can be ignored
? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA)) // (if it can't be ignored we'll need to handle null responses from tagGetCompoundTag())
: UpgradeData.EMPTY; //
#elif MC_VER < MC_1_21_5 //#if MC_VER < MC_1_17_1
upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10) //upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level) // ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA))
: UpgradeData.EMPTY; // : UpgradeData.EMPTY;
#else //#elif MC_VER < MC_1_21_5
upgradeData = tagLevel.contains(TAG_UPGRADE_DATA) //upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level) // ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level)
: UpgradeData.EMPTY; // : UpgradeData.EMPTY;
#endif //#else
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA)
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level)
// : UpgradeData.EMPTY;
//#endif
boolean isLightOn = tagGetBoolean(tagLevel, "isLightOn"); boolean isLightOn = tagGetBoolean(tagLevel, "isLightOn");
@@ -242,7 +246,7 @@ public class ChunkLoader
// Set some states after object creation // Set some states after object creation
chunk.setLightCorrect(isLightOn); chunk.setLightCorrect(isLightOn);
readHeightmaps(chunk, chunkData); readHeightmaps(chunk, chunkData);
readPostPocessings(chunk, chunkData); //readPostPocessings(chunk, chunkData);
return chunk; return chunk;
} }
private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData) private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
@@ -285,48 +289,54 @@ public class ChunkLoader
for (int j = 0; j < tagSections.size(); ++j) for (int j = 0; j < tagSections.size(); ++j)
{ {
CompoundTag tagSection = tagGetCompoundTag(tagSections, j); CompoundTag tagSection = tagGetCompoundTag(tagSections, j);
int sectionYPos = tagGetByte(tagSection, "Y"); if (tagSection == null)
{
continue;
}
final int sectionYPos = tagGetByte(tagSection, "Y");
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12)) if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12))
{ {
LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4); LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4);
levelChunkSection.getStates().read(tagSection.getList("Palette", 10), levelChunkSection.getStates().read(tagSection.getList("Palette", 10),
tagSection.getLongArray("BlockStates")); tagSection.getLongArray("BlockStates"));
levelChunkSection.recalcBlockCounts(); levelChunkSection.recalcBlockCounts();
if (!levelChunkSection.isEmpty()) if (!levelChunkSection.isEmpty())
chunkSections[#if MC_VER < MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif ] chunkSections[#if MC_VER < MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif ]
= levelChunkSection; = levelChunkSection;
} }
#else #else
int sectionId = level.getSectionIndexFromSectionY(sectionYPos); int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
if (sectionId >= 0 && sectionId < chunkSections.length) if (sectionId >= 0 && sectionId < chunkSections.length)
{ {
PalettedContainer<BlockState> blockStateContainer; PalettedContainer<BlockState> blockStateContainer;
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
PalettedContainer<Biome> biomeContainer; PalettedContainer<Biome> biomeContainer;
#else #else
PalettedContainer<Holder<Biome>> biomeContainer; PalettedContainer<Holder<Biome>> biomeContainer;
#endif #endif
boolean containsBlockStates; boolean containsBlockStates;
#if MC_VER < MC_1_21_5 #if MC_VER < MC_1_21_5
containsBlockStates = tagSection.contains("block_states", 10); containsBlockStates = tagSection.contains("block_states", 10);
#else #else
containsBlockStates = tagSection.contains("block_states"); containsBlockStates = tagSection.contains("block_states");
#endif #endif
if (containsBlockStates) if (containsBlockStates)
{ {
#if MC_VER < MC_1_20_6 #if MC_VER < MC_1_20_6
blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states")) blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states"))
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
.getOrThrow(false, (message) -> logParsingWarningOnce(message)); .getOrThrow(false, (message) -> logParsingWarningOnce(message));
#else #else
blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states")) blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states"))
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
.getOrThrow((message) -> logErrorAndReturnException(message)); .getOrThrow((message) -> logErrorAndReturnException(message));
#endif #endif
} }
else else
{ {
@@ -334,31 +344,31 @@ public class ChunkLoader
} }
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
biomeContainer = tagSection.contains("biomes", 10) biomeContainer = tagSection.contains("biomes", 10)
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, (message) -> logWarningOnce(message)) ? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, (message) -> logWarningOnce(message))
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); : new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#else #else
boolean containsBiomes; boolean containsBiomes;
#if MC_VER < MC_1_21_5 #if MC_VER < MC_1_21_5
containsBiomes = tagSection.contains("biomes", 10); containsBiomes = tagSection.contains("biomes", 10);
#else #else
containsBiomes = tagSection.contains("biomes"); containsBiomes = tagSection.contains("biomes");
#endif #endif
if (containsBiomes) if (containsBiomes)
{ {
#if MC_VER < MC_1_20_6 #if MC_VER < MC_1_20_6
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes")) biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes"))
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
.getOrThrow(false, (message) -> logParsingWarningOnce(message)); .getOrThrow(false, (message) -> logParsingWarningOnce(message));
#else #else
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes")) biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes"))
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
.getOrThrow((message) -> logErrorAndReturnException(message)); .getOrThrow((message) -> logErrorAndReturnException(message));
#endif #endif
} }
else else
{ {
@@ -371,15 +381,15 @@ public class ChunkLoader
PalettedContainer.Strategy.SECTION_BIOMES); PalettedContainer.Strategy.SECTION_BIOMES);
} }
#endif #endif
#if MC_VER < MC_1_20_1 #if MC_VER < MC_1_20_1
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer); chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
#else #else
chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer); chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
#endif #endif
} }
#endif #endif
} }
} }
@@ -391,10 +401,14 @@ public class ChunkLoader
#else ChunkType #endif #else ChunkType #endif
readChunkType(CompoundTag tagLevel) readChunkType(CompoundTag tagLevel)
{ {
ChunkStatus chunkStatus = ChunkStatus.byName(tagGetString(tagLevel,"Status")); String statusString = tagGetString(tagLevel,"Status");
if (chunkStatus != null) if (statusString != null)
{ {
return chunkStatus.getChunkType(); ChunkStatus chunkStatus = ChunkStatus.byName(statusString);
if (chunkStatus != null)
{
return chunkStatus.getChunkType();
}
} }
#if MC_VER <= MC_1_20_4 #if MC_VER <= MC_1_20_4
@@ -406,43 +420,52 @@ public class ChunkLoader
private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData) private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
{ {
CompoundTag tagHeightmaps = tagGetCompoundTag(chunkData, "Heightmaps"); CompoundTag tagHeightmaps = tagGetCompoundTag(chunkData, "Heightmaps");
for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter()) if (tagHeightmaps != null)
{ {
String heightmap = type.getSerializationKey(); for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
#if MC_VER < MC_1_21_5
if (tagHeightmaps.contains(heightmap, 12))
{ {
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap)); String heightmap = type.getSerializationKey();
} #if MC_VER < MC_1_21_5
#else if (tagHeightmaps.contains(heightmap, 12))
if (tagHeightmaps.contains(heightmap))
{
Optional<long[]> optionalHeightmap = tagHeightmaps.getLongArray(heightmap);
if (optionalHeightmap.isPresent())
{ {
chunk.setHeightmap(type, optionalHeightmap.get()); chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
} }
}
#endif
}
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
}
private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
{
ListTag tagPostProcessings = tagGetListTag(chunkData,"PostProcessing", 9);
for (int i = 0; i < tagPostProcessings.size(); ++i)
{
ListTag listTag3 = tagGetListTag(tagPostProcessings, i);
for (int j = 0; j < listTag3.size(); ++j)
{
#if MC_VER < MC_1_21_3
chunk.addPackedPostProcess(listTag3.getShort(j), i);
#else #else
chunk.addPackedPostProcess(ShortList.of(tagGetShort(listTag3, j)), i); if (tagHeightmaps.contains(heightmap))
{
Optional<long[]> optionalHeightmap = tagHeightmaps.getLongArray(heightmap);
if (optionalHeightmap.isPresent())
{
chunk.setHeightmap(type, optionalHeightmap.get());
}
}
#endif #endif
} }
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
} }
} }
// commented out as a test as of 2025-06-04 to see if this is actually necessary for DH
// DH probably doesn't need any chunk post-processing data
//private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
//{
// ListTag tagPostProcessings = tagGetListTag(chunkData,"PostProcessing", 9);
// if (tagPostProcessings != null)
// {
// for (int i = 0; i < tagPostProcessings.size(); ++i)
// {
// ListTag listTag3 = tagGetListTag(tagPostProcessings, i);
// for (int j = 0; j < listTag3.size(); ++j)
// {
// #if MC_VER < MC_1_21_3
// chunk.addPackedPostProcess(listTag3.getShort(j), i);
// #else
// chunk.addPackedPostProcess(ShortList.of(tagGetShort(listTag3, j)), i);
// #endif
// }
// }
// }
//}
#if MC_VER >= MC_1_18_2 #if MC_VER >= MC_1_18_2
private static BlendingData readBlendingData(CompoundTag chunkData) private static BlendingData readBlendingData(CompoundTag chunkData)
{ {
@@ -728,6 +751,7 @@ public class ChunkLoader
/** defaults to null if the tag isn't present */ /** defaults to null if the tag isn't present */
@Nullable
private static String tagGetString(CompoundTag tag, String key) private static String tagGetString(CompoundTag tag, String key)
{ {
#if MC_VER < MC_1_21_5 #if MC_VER < MC_1_21_5
@@ -738,6 +762,7 @@ public class ChunkLoader
} }
/** defaults to null if the tag isn't present */ /** defaults to null if the tag isn't present */
@Nullable
private static byte[] tagGetByteArray(CompoundTag tag, String key) private static byte[] tagGetByteArray(CompoundTag tag, String key)
{ {
#if MC_VER < MC_1_21_5 #if MC_VER < MC_1_21_5
+1
View File
@@ -24,6 +24,7 @@ fabric_api_version=0.42.0+1.16
immersive_portals_version= immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API
fabric_incompatibility_list={ "iris": "*" } fabric_incompatibility_list={ "iris": "*" }
fabric_recommend_list={} fabric_recommend_list={}
+1
View File
@@ -24,6 +24,7 @@ fabric_api_version=0.46.1+1.17
immersive_portals_version= immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API
fabric_incompatibility_list={ "iris": "*" } fabric_incompatibility_list={ "iris": "*" }
fabric_recommend_list={} fabric_recommend_list={}
+1
View File
@@ -25,6 +25,7 @@ fabric_api_version=0.76.0+1.18.2
immersive_portals_version=v1.4.11-1.18 immersive_portals_version=v1.4.11-1.18
canvas_version=mc118:1.0.2616 canvas_version=mc118:1.0.2616
# iris - needs 1.7.4+ to support the DH API
fabric_incompatibility_list={ "iris": "*" } fabric_incompatibility_list={ "iris": "*" }
fabric_recommend_list={} fabric_recommend_list={}
+1
View File
@@ -24,6 +24,7 @@ fabric_api_version=0.76.1+1.19.2
immersive_portals_version= immersive_portals_version=
canvas_version=mc119-1.0.2480 canvas_version=mc119-1.0.2480
# iris - needs 1.7.4+ to support the DH API
fabric_incompatibility_list={ "iris": "*" } fabric_incompatibility_list={ "iris": "*" }
fabric_recommend_list={} fabric_recommend_list={}
+2 -1
View File
@@ -22,7 +22,8 @@ fabric_api_version=0.87.1+1.19.4
bclib_version=2.3.3 bclib_version=2.3.3
immersive_portals_version= immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API
fabric_incompatibility_list={ "iris": "*" } fabric_incompatibility_list={ "iris": "*" }
fabric_recommend_list={} fabric_recommend_list={}
+2 -1
View File
@@ -22,7 +22,8 @@ fabric_api_version=0.90.4+1.20.1
bclib_version=3.0.13 bclib_version=3.0.13
immersive_portals_version= immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API
fabric_incompatibility_list={ "iris": "<=1.7.4" } fabric_incompatibility_list={ "iris": "<=1.7.4" }
fabric_recommend_list={} fabric_recommend_list={}
+2 -1
View File
@@ -22,7 +22,8 @@ fabric_api_version=0.90.4+1.20.2
bclib_version=3.0.13 bclib_version=3.0.13
immersive_portals_version= immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API
fabric_incompatibility_list={ "iris": "<=1.7.4" } fabric_incompatibility_list={ "iris": "<=1.7.4" }
fabric_recommend_list={} fabric_recommend_list={}
+2 -1
View File
@@ -23,7 +23,8 @@ fabric_api_version=0.91.2+1.20.4
bclib_version= bclib_version=
immersive_portals_version= immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API
fabric_incompatibility_list={ "iris": "<=1.7.4" } fabric_incompatibility_list={ "iris": "<=1.7.4" }
fabric_recommend_list={} fabric_recommend_list={}
+2 -1
View File
@@ -23,7 +23,8 @@ fabric_api_version=0.97.8+1.20.6
bclib_version= bclib_version=
immersive_portals_version= immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API
fabric_incompatibility_list={ "iris": "<=1.7.4" } fabric_incompatibility_list={ "iris": "<=1.7.4" }
fabric_recommend_list={} fabric_recommend_list={}
+2 -1
View File
@@ -23,7 +23,8 @@ fabric_api_version=0.115.0+1.21.1
bclib_version= bclib_version=
immersive_portals_version= immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API
fabric_incompatibility_list={ "iris": "<=1.7.4" } fabric_incompatibility_list={ "iris": "<=1.7.4" }
fabric_recommend_list={} fabric_recommend_list={}
+1 -1
View File
@@ -23,7 +23,7 @@ fabric_api_version=0.110.5+1.21.4
bclib_version= bclib_version=
immersive_portals_version= immersive_portals_version=
canvas_version= canvas_version=
fabric_incompatibility_list={ } fabric_incompatibility_list={ }
fabric_recommend_list={} fabric_recommend_list={}
+1 -1
View File
@@ -23,7 +23,7 @@ fabric_api_version=0.119.5+1.21.5
immersive_portals_version= immersive_portals_version=
canvas_version= canvas_version=
# some versions of 1.8.11 nightly builds may not work, but the ones after 2025-03-30 should # Iris - some versions of 1.8.11 nightly builds may not work, but the ones after 2025-03-30 should
fabric_incompatibility_list={ "iris": "<=1.8.10" } fabric_incompatibility_list={ "iris": "<=1.8.10" }
fabric_recommend_list={} fabric_recommend_list={}