diff --git a/src/client/java/tobinio/bettersnowcoverage/BetterSnowChecker.java b/src/client/java/tobinio/bettersnowcoverage/BetterSnowChecker.java index 574dde6..9ce82d6 100644 --- a/src/client/java/tobinio/bettersnowcoverage/BetterSnowChecker.java +++ b/src/client/java/tobinio/bettersnowcoverage/BetterSnowChecker.java @@ -1,46 +1,61 @@ package tobinio.bettersnowcoverage; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; +import net.minecraft.block.*; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.world.ClientWorld; import net.minecraft.registry.tag.BlockTags; import net.minecraft.registry.tag.TagKey; +import net.minecraft.state.property.Properties; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.BlockRenderView; import tobinio.bettersnowcoverage.config.Config; -import java.util.logging.Logger; - /** * Created: 02.08.24 * * @author Tobias Frischmann */ public class BetterSnowChecker { - public static boolean shouldHaveSnow(BlockState state, BlockPos pos, BlockRenderView world) { + + public static BlockState getSnowState(BlockState state) { + if (state.getBlock() instanceof SnowyBlock) { + return state.with(Properties.SNOWY, true); + } + return state; + } + + public enum SnowState { + NONE, WITH_LAYER, WITHOUT_LAYER, + } + + public static SnowState shouldHaveSnow(BlockPos pos, BlockRenderView world) { ClientPlayerEntity player = MinecraftClient.getInstance().player; if (player == null) { BetterSnowCoverage.LOGGER.warn("no player found"); - return false; + return SnowState.NONE; } - if (state.isSideSolidFullSquare(world, pos, Direction.DOWN)) { - return false; + var state = world.getBlockState(pos); + + if (state.isSideSolidFullSquare(world, pos, Direction.DOWN) || state.getBlock() == Blocks.AIR) { + return SnowState.NONE; } if (!world.getBlockState(pos.down()).isFullCube(world, pos.down())) { - return false; + return SnowState.NONE; } - if (isExcludedBlock(state)) { - return false; + if (hasSnowNeighbor(pos, world)) { + if (isExcludedBlock(state)) { + return SnowState.WITHOUT_LAYER; + } + + return SnowState.WITH_LAYER; } - return hasSnowNeighbor(pos, world); + return SnowState.NONE; } private static boolean isExcludedBlock(BlockState state) { diff --git a/src/client/java/tobinio/bettersnowcoverage/mixin/client/SectionBuilderMixin.java b/src/client/java/tobinio/bettersnowcoverage/mixin/client/SectionBuilderMixin.java index 2c3a931..1f03bdf 100644 --- a/src/client/java/tobinio/bettersnowcoverage/mixin/client/SectionBuilderMixin.java +++ b/src/client/java/tobinio/bettersnowcoverage/mixin/client/SectionBuilderMixin.java @@ -4,7 +4,6 @@ import com.llamalad7.mixinextras.sugar.Local; import com.mojang.blaze3d.systems.VertexSorter; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; -import net.minecraft.block.FlowerBlock; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.block.BlockRenderManager; import net.minecraft.client.render.chunk.BlockBufferAllocatorStorage; @@ -17,8 +16,10 @@ import net.minecraft.util.math.random.Random; 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.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import tobinio.bettersnowcoverage.BetterSnowChecker; @@ -38,8 +39,26 @@ public class SectionBuilderMixin { BlockBufferAllocatorStorage allocatorStorage, CallbackInfoReturnable cir, @Local BlockState blockState, @Local (ordinal = 2) BlockPos blockPos, @Local MatrixStack matrixStack, @Local BufferBuilder bufferBuilder, @Local Random random) { - if (BetterSnowChecker.shouldHaveSnow(blockState, blockPos, renderRegion)) { - blockRenderManager.renderBlock(Blocks.SNOW.getDefaultState(), blockPos, renderRegion, matrixStack, bufferBuilder, true, random); + + var snowState = BetterSnowChecker.shouldHaveSnow(blockPos.up(), renderRegion); + + if (snowState == BetterSnowChecker.SnowState.WITH_LAYER) { + matrixStack.push(); + matrixStack.translate(0, 1, 0); + blockRenderManager.renderBlock(Blocks.SNOW.getDefaultState(), blockPos.up(), renderRegion, matrixStack, bufferBuilder, true, random); + matrixStack.pop(); } } + + @ModifyVariable (method = "build", at = @At ("STORE"), ordinal = 0) + private BlockState setGrassState(BlockState state, @Local (ordinal = 2) BlockPos blockPos, + @Local (argsOnly = true) ChunkRendererRegion renderRegion) { + var snowState = BetterSnowChecker.shouldHaveSnow(blockPos.up(), renderRegion); + + if (snowState != BetterSnowChecker.SnowState.NONE) { + return BetterSnowChecker.getSnowState(state); + } + + return state; + } } diff --git a/src/client/java/tobinio/bettersnowcoverage/mixin/client/sodium/ChunkBuilderMeshingTaskMixin.java b/src/client/java/tobinio/bettersnowcoverage/mixin/client/sodium/ChunkBuilderMeshingTaskMixin.java index 6c0a535..b7b3962 100644 --- a/src/client/java/tobinio/bettersnowcoverage/mixin/client/sodium/ChunkBuilderMeshingTaskMixin.java +++ b/src/client/java/tobinio/bettersnowcoverage/mixin/client/sodium/ChunkBuilderMeshingTaskMixin.java @@ -11,10 +11,7 @@ import me.jellysquid.mods.sodium.client.util.task.CancellationToken; import me.jellysquid.mods.sodium.client.world.WorldSlice; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; -import net.minecraft.block.FlowerBlock; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import org.joml.Vector3f; import org.joml.Vector3fc; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -32,17 +29,22 @@ public class ChunkBuilderMeshingTaskMixin { @Inject (method = "execute(Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext;Lme/jellysquid/mods/sodium/client/util/task/CancellationToken;)Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput;", at = @At (value = "INVOKE", target = "Lme/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer;renderModel(Lme/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext;Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers;)V", remap = false), remap = false) private void execute(ChunkBuildContext buildContext, CancellationToken cancellationToken, CallbackInfoReturnable cir, @Local BlockRenderContext ctx, - @Local ChunkBuildBuffers buffers, @Local BlockRenderCache cache, @Local WorldSlice slice) { - if (BetterSnowChecker.shouldHaveSnow(ctx.state(), ctx.pos(), ctx.world())) { - Vector3fc origin = ctx.origin(); + @Local ChunkBuildBuffers buffers, @Local BlockRenderCache cache, @Local WorldSlice slice, + @Local (ordinal = 1) BlockPos.Mutable modelOffset) { + BetterSnowChecker.SnowState snowState = BetterSnowChecker.shouldHaveSnow(ctx.pos().up(), ctx.world()); + if (snowState != BetterSnowChecker.SnowState.NONE) { + var newState = BetterSnowChecker.getSnowState(ctx.state()); + ctx.update(ctx.pos(), modelOffset, newState, cache.getBlockModels().getModel(newState), ctx.seed()); + } + + if (snowState == BetterSnowChecker.SnowState.WITH_LAYER) { BlockRenderContext context = new BlockRenderContext(slice); BlockState snow = Blocks.SNOW.getDefaultState(); - var model = cache.getBlockModels() - .getModel(snow); + var model = cache.getBlockModels().getModel(snow); - context.update(ctx.pos(), new BlockPos((int) origin.x(), (int) origin.y(), (int) origin.z()), snow, model, ctx.seed()); + context.update(ctx.pos().up(), modelOffset.up(), snow, model, ctx.seed()); cache.getBlockRenderer().renderModel(context, buffers); }