diff --git a/src/main/java/net/qzimyion/cellulose/mixin/snowing/LeafBlocksMixin.java b/src/main/java/net/qzimyion/cellulose/mixin/snowing/LeafBlocksMixin.java new file mode 100644 index 0000000..aec7950 --- /dev/null +++ b/src/main/java/net/qzimyion/cellulose/mixin/snowing/LeafBlocksMixin.java @@ -0,0 +1,91 @@ +package net.qzimyion.cellulose.mixin.snowing; + +import net.minecraft.core.BlockPos; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LeavesBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.levelgen.Heightmap; +import net.qzimyion.cellulose.util.ISnow; +import net.qzimyion.cellulose.util.TintManager; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(LeavesBlock.class) +public class LeafBlocksMixin extends Block implements ISnow { + + @Shadow + @Final + public static BooleanProperty PERSISTENT; + + @Unique + private boolean isSnowing = false; + @Unique + private long lastUpdateTime = 0; + + public LeafBlocksMixin(Properties properties) { + super(properties); + } + + @Override + public boolean isSnowy(Level level, BlockPos pos) { + return updateSnow(level, pos); + } + + @Unique + private boolean updateSnow(Level level, BlockPos pos) { + if (level.getBiome(pos).value().warmEnoughToRain(pos)) return false; + + int topY = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, pos).getY(); + if (topY > pos.getY()) { + BlockPos checkPos = pos.above(); + for (int i = 0; i < topY - pos.getY(); i++) { + if (level.getBrightness(LightLayer.SKY, checkPos) == 15) return true; + + Block block = level.getBlockState(checkPos).getBlock(); + if (!(block instanceof LeavesBlock) && !block.equals(Blocks.AIR) && !block.equals(Blocks.SNOW) && !block.equals(Blocks.SNOW_BLOCK)) { + return false; + } + checkPos = checkPos.above(); + } + } + return true; + } + + @Inject(method = "animateTick", at = @At("HEAD")) + public void animateTick( + BlockState state, + Level level, + BlockPos pos, + RandomSource random, + CallbackInfo ci + ) { + if (level.getBiome(pos).value().warmEnoughToRain(pos)) return; + + boolean isCurrentlySnowing = level.isRaining(); + if (isCurrentlySnowing != isSnowing) { + isSnowing = isCurrentlySnowing; + lastUpdateTime = level.getGameTime(); + TintManager.updateTint(); + } + + if (level.getGameTime() - lastUpdateTime > 400) return; + + boolean persistent = state.getValue(PERSISTENT); +// if (persistent != isSnowing) { +// level.setBlock(pos, state.setValue(PERSISTENT, isSnowing), 2); +// } + level.setBlockAndUpdate(pos, state.setValue(PERSISTENT, !persistent)); + level.setBlockAndUpdate(pos, state.setValue(PERSISTENT, persistent)); + } + +} diff --git a/src/main/java/net/qzimyion/cellulose/mixin/snowing/LeafRender.java b/src/main/java/net/qzimyion/cellulose/mixin/snowing/LeafRender.java new file mode 100644 index 0000000..c74ff8e --- /dev/null +++ b/src/main/java/net/qzimyion/cellulose/mixin/snowing/LeafRender.java @@ -0,0 +1,51 @@ +package net.qzimyion.cellulose.mixin.snowing; + + +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.LeavesBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.qzimyion.cellulose.util.TintManager; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(BlockColors.class) +public class LeafRender { + + @Unique + private int adjustColor(int baseColor, float gradient) { + int red = (baseColor >> 16) & 0xFF; + int green = (baseColor >> 8) & 0xFF; + int blue = baseColor & 0xFF; + + red += (int) (gradient * (255 - red)); + green += (int) (gradient * (255 - green)); + blue += (int) (gradient * (255 - blue)); + + return (red << 16) | (green << 8) | blue; + } + + @Inject( + method = "getColor(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/core/BlockPos;I)I", + at = @At("RETURN"), + cancellable = true + ) + public void getColor( + BlockState state, + net.minecraft.world.level.BlockAndTintGetter tintGetter, + BlockPos pos, + int tintIndex, + CallbackInfoReturnable cir + ) { + if (pos == null || !(state.getBlock() instanceof LeavesBlock)) return; + + int baseColor = cir.getReturnValue(); + float gradient = TintManager.getGradient(); + cir.setReturnValue(adjustColor(baseColor, gradient)); + } +} diff --git a/src/main/java/net/qzimyion/cellulose/util/ISnow.java b/src/main/java/net/qzimyion/cellulose/util/ISnow.java new file mode 100644 index 0000000..6225239 --- /dev/null +++ b/src/main/java/net/qzimyion/cellulose/util/ISnow.java @@ -0,0 +1,8 @@ +package net.qzimyion.cellulose.util; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; + +public interface ISnow { + boolean isSnowy(Level level, BlockPos pos); +} diff --git a/src/main/java/net/qzimyion/cellulose/util/TintManager.java b/src/main/java/net/qzimyion/cellulose/util/TintManager.java new file mode 100644 index 0000000..cee4221 --- /dev/null +++ b/src/main/java/net/qzimyion/cellulose/util/TintManager.java @@ -0,0 +1,44 @@ +package net.qzimyion.cellulose.util; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.util.Mth; + +import java.util.Objects; + +public class TintManager { + private static float gradient = 0; + private static long lastUpdateTime = 0; + + public static void updateTint() { + Minecraft client = Minecraft.getInstance(); + ClientLevel clientLevel = client.level; + if (clientLevel == null) return; + + long currentTime = clientLevel.getGameTime(); + boolean isSnowing = clientLevel.isRaining() && + !clientLevel.getBiome(Objects.requireNonNull(client.player).blockPosition()) + .value() + .warmEnoughToRain(client.player.blockPosition()); + + if (isSnowing) { + gradient += (currentTime - lastUpdateTime) / 300.0f; + } else { + gradient -= (currentTime - lastUpdateTime) / 300.0f; + } + + gradient = Mth.clamp(gradient, 0, 1); + lastUpdateTime = currentTime; + updateChunks(clientLevel); + } + + public static void updateChunks(ClientLevel level) { + if (level != null) { + Minecraft.getInstance().levelRenderer.allChanged(); + } + } + + public static float getGradient() { + return gradient; + } +}