From fab64d84774865216ce26533a1460a28e98097ce Mon Sep 17 00:00:00 2001 From: Ran <43445785+Ran-Mewo@users.noreply.github.com> Date: Mon, 7 Apr 2025 13:47:42 +1000 Subject: [PATCH] Fix white foliage issue --- .../block/TintWithoutLevelOverrider.java | 73 +++++++++++++------ 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelOverrider.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelOverrider.java index 754281608..56143aa6d 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelOverrider.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelOverrider.java @@ -19,19 +19,16 @@ package com.seibel.distanthorizons.common.wrappers.block; -import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.*; import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.material.FluidState; -import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,46 +43,74 @@ public class TintWithoutLevelOverrider implements BlockAndTintGetter * but {@link Nullable} is there just in case. */ @Nullable - private final Biome biome; - - + #if MC_VER >= MC_1_18_2 + public final Holder biome; + #else + public final Biome biome; + #endif + /** + * Constructs the TintWithoutLevelOverrider, storing the provided Biome Holder for late-binding access. + * + *

Previously, this class might have immediately unwrapped the Holder like this:

+ *
{@code
+	 * // Inside constructor (OLD WAY - PROBLEMATIC):
+	 * Holder biomeHolder = getTheHolderFromSomewhere();
+	 * this.biome = biomeHolder.value(); // <-- PROBLEM HERE
+	 * }
+ * + *

This approach is problematic because the {@link net.minecraft.core.Holder} system, + * particularly {@code Holder.Reference}, is designed for late binding. Here's why storing + * the Holder itself is now necessary:

+ *
    + *
  1. A {@code Holder.Reference} might be created initially just with a + * {@link net.minecraft.resources.ResourceKey} (like {@code minecraft:plains}), but its actual + * {@link net.minecraft.core.Holder#value() value()} (the {@code Biome} object itself) might be {@code null} + * at construction time.
  2. + *
  3. Later, during game loading, registry population, or potentially due to modifications by other mods + * (e.g., Polytone), the system calls internal binding methods (like {@code bindValue(Biome)}) + * on the {@code Holder} instance. This sets or updates the internal reference to the + * actual {@code Biome} object.
  4. + *
  5. Crucially, the binding process might assign a completely new {@code Biome} object + * instance to the {@code Holder} reference, replacing any previous one.
  6. + *
+ * + *

If we unwrapped the {@code Holder} using {@code .value()} within the constructor (the old way), + * our class's internal {@code biome} field would permanently store a reference to whatever {@code Biome} + * object the {@code Holder} pointed to *at that exact moment*. It would have no link back to the + * {@code Holder} and would be unaware if the {@code Holder} was later updated to point to a different + * (or the initially missing) {@code Biome} object. This would lead to using stale or even {@code null} data.

+ * + *

By storing the {@code Holder} itself, this class can call {@link net.minecraft.core.Holder#value()} + * whenever the biome information is needed, ensuring it always retrieves the most current {@code Biome} + * instance associated with the holder at that time.

+ */ public TintWithoutLevelOverrider(BiomeWrapper biomeWrapper, IClientLevelWrapper clientLevelWrapper) { - // try to get the wrapped biome - Biome unwrappedBiome = null; - if (biomeWrapper.biome != null) + #if MC_VER >= MC_1_18_2 Holder #else Biome #endif biome = biomeWrapper.biome; + if (biome == null) // We are looking at the empty biome wrapper { - unwrappedBiome = unwrap(biomeWrapper.biome); - } - - if(unwrappedBiome == null) - { - // we are looking at the empty biome wrapper, try using plains as a backup BiomeWrapper plainsBiomeWrapper = ((BiomeWrapper) clientLevelWrapper.getPlainsBiomeWrapper()); if (plainsBiomeWrapper != null) { - unwrappedBiome = unwrap(plainsBiomeWrapper.biome); + biome = plainsBiomeWrapper.biome; } } - this.biome = unwrappedBiome; + this.biome = biome; } @Override - public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver) - { - if (this.biome != null) - { - return colorResolver.getColor(this.biome, blockPos.getX(), blockPos.getZ()); - } - else + public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver) + { + if (this.biome == null) { // hopefully unneeded debug color return ColorUtil.CYAN; } + return colorResolver.getColor(unwrap(biome), blockPos.getX(), blockPos.getZ()); } private static Biome unwrap(#if MC_VER >= MC_1_18_2 Holder #else Biome #endif biome)