fix: render issue with water and reframed blocks + missing mixin in mixin config + shading improvement prep

This commit is contained in:
2025-05-14 02:43:46 +02:00
parent b825959626
commit a470724d81
8 changed files with 168 additions and 6 deletions

View File

@@ -135,11 +135,11 @@ public class ReFramed implements ModInitializer {
private static AbstractBlock.Settings cp(Block base) { private static AbstractBlock.Settings cp(Block base) {
return AbstractBlock.Settings.copy(base) return AbstractBlock.Settings.copy(base)
.luminance(state -> state.contains(LIGHT) && state.get(LIGHT) ? 15 : 0) .luminance(state -> state.contains(LIGHT) && state.get(LIGHT) ? 15 : 0)
.nonOpaque()
.sounds(BlockSoundGroup.WOOD) .sounds(BlockSoundGroup.WOOD)
.hardness(0.2f) .hardness(0.2f)
.suffocates((a,b,c) -> false) .suffocates(Blocks::never)
.blockVision((a,b,c) -> false); .solidBlock(Blocks::always)
.blockVision(Blocks::always);
} }
private static <I extends Item> I registerItem(String path, I item) { private static <I extends Item> I registerItem(String path, I item) {

View File

@@ -2,9 +2,11 @@ package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed; import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.util.blocks.BlockHelper; import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import net.minecraft.block.*; import net.minecraft.block.*;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.pathing.NavigationType;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemPlacementContext;
@@ -17,6 +19,7 @@ import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.ItemScatterer; import net.minecraft.util.ItemScatterer;
import net.minecraft.util.collection.DefaultedList; import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.function.BooleanBiFunction;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
@@ -31,6 +34,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY; import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY;
@@ -39,10 +43,26 @@ import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT;
public class ReFramedBlock extends Block implements BlockEntityProvider { public class ReFramedBlock extends Block implements BlockEntityProvider {
public ReFramedBlock(Settings settings) { public ReFramedBlock(Settings settings) {
super(settings); super(settings.dynamicBounds());
setDefaultState(getDefaultState().with(LIGHT, false)); setDefaultState(getDefaultState().with(LIGHT, false));
} }
@Override
@SuppressWarnings("deprecation")
public int getOpacity(BlockState state, BlockView world, BlockPos pos) {
if (state.get(LIGHT)) return 0;
if (!(world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity)
|| frame_entity.getTheme(0).isOpaque())
return world.getMaxLightLevel();
return 0;
}
@Override
@SuppressWarnings("deprecation")
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
return false;
}
@Override @Override
public @Nullable BlockEntity createBlockEntity(BlockPos pos, BlockState state) { public @Nullable BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return ReFramed.REFRAMED_BLOCK_ENTITY.instantiate(pos, state); return ReFramed.REFRAMED_BLOCK_ENTITY.instantiate(pos, state);
@@ -208,4 +228,17 @@ public class ReFramedBlock extends Block implements BlockEntityProvider {
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) { public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
return Map.of(); return Map.of();
} }
public VoxelShape getShadingShape(BlockState state, BlockView world, BlockPos pos) {
if (!(world.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity)) return this.getCollisionShape(state, world, pos, ShapeContext.absent());
AtomicInteger i = new AtomicInteger(1);
return framed_entity.getThemes().stream().map((theme) -> {
int index = i.getAndIncrement();
return theme.isTransparent(world, pos) ? VoxelShapes.empty() : this.getShape(state, index);
}).reduce(
VoxelShapes.empty(),
(prev, current) -> VoxelShapes.combine(prev, current, BooleanBiFunction.OR)
);
}
} }

View File

@@ -24,6 +24,12 @@ public class WaterloggableReFramedBlock extends ReFramedBlock implements Waterlo
super.appendProperties(builder.add(Properties.WATERLOGGED)); super.appendProperties(builder.add(Properties.WATERLOGGED));
} }
@Override
@SuppressWarnings("deprecation")
public boolean hasSidedTransparency(BlockState state) {
return true;
}
@Nullable @Nullable
@Override @Override
public BlockState getPlacementState(ItemPlacementContext ctx) { public BlockState getPlacementState(ItemPlacementContext ctx) {

View File

@@ -51,7 +51,7 @@ public class CamoAppearanceManager {
for(BlendMode blend : BlendMode.values()) { for(BlendMode blend : BlendMode.values()) {
finder.clear().disableDiffuse(false).blendMode(blend); finder.clear().disableDiffuse(false).blendMode(blend);
materials.put(blend, finder.ambientOcclusion(TriState.FALSE).find()); materials.put(blend, finder.ambientOcclusion(TriState.TRUE).find());
ao_materials.put(blend, finder.ambientOcclusion(TriState.DEFAULT).find()); //not "true" since that *forces* AO, i just want to *allow* AO ao_materials.put(blend, finder.ambientOcclusion(TriState.DEFAULT).find()); //not "true" since that *forces* AO, i just want to *allow* AO
} }

View File

@@ -31,6 +31,8 @@ public class CompatMixinPlugin implements IMixinConfigPlugin {
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumNonTerrainBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumNonTerrainBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.BlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1))); CONDITIONS.put("fr.adrien1106.reframed.mixin.render.BlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.FluidRendererMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(2)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.SodiumFluidRendererMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityConnectionPredicateMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityConnectionPredicateMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMQuadTransformMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMQuadTransformMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));

View File

@@ -0,0 +1,62 @@
package fr.adrien1106.reframed.mixin.compat;
import com.llamalad7.mixinextras.sugar.Local;
import fr.adrien1106.reframed.block.ReFramedBlock;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer;
import me.jellysquid.mods.sodium.client.world.WorldSlice;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
import net.minecraft.block.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(FluidRenderer.class)
public abstract class SodiumFluidRendererMixin {
@Redirect(
method = "isSideExposed",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/block/BlockState;isOpaque()Z"
)
)
private boolean isSideOpaqueExposed(BlockState state) {
if (!(state.getBlock() instanceof ReFramedBlock)) return state.isOpaque();
return true; // forces to compute correct shape
}
@Redirect(
method = "isSideExposed",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/block/BlockState;getCullingShape(Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/util/shape/VoxelShape;"
)
)
private VoxelShape isSideShapeExposed(BlockState state, BlockView world, BlockPos pos) {
if (!(state.getBlock() instanceof ReFramedBlock block)) return state.getCullingShape(world, pos);
return block.getShadingShape(state, world, pos);
}
@Redirect(
method = "render",
at = @At(
value = "INVOKE",
target = "Lnet/fabricmc/fabric/api/client/render/fluid/v1/FluidRenderHandlerRegistry;isBlockTransparent(Lnet/minecraft/block/Block;)Z"
)
)
private boolean getThemeState(FluidRenderHandlerRegistry fluid_handler, Block block, @Local(argsOnly = true) WorldSlice world, @Local(ordinal = 2) BlockPos pos, @Local BlockState state, @Local Direction dir) {
if (!(block instanceof ReFramedBlock rfblock && world.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity)) return fluid_handler.isBlockTransparent(block);
return !VoxelShapes.isSideCovered(VoxelShapes.fullCube(), rfblock.getShadingShape(state, world, pos), dir)
&& framed_entity.getThemes().stream()
.anyMatch(s -> s.getBlock() instanceof LeavesBlock
|| s.getBlock() instanceof TranslucentBlock
|| s.getBlock() instanceof AirBlock
);
}
}

View File

@@ -0,0 +1,56 @@
package fr.adrien1106.reframed.mixin.render;
import fr.adrien1106.reframed.block.ReFramedBlock;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import net.minecraft.block.*;
import net.minecraft.client.render.block.FluidRenderer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockRenderView;
import net.minecraft.world.BlockView;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(FluidRenderer.class)
public abstract class FluidRendererMixin {
@Inject(
method = "isSideCovered(Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/Direction;FLnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)Z",
at = @At("HEAD"),
cancellable = true
) // force dynamic water side rendering
private static void isSameSideCovered(BlockView world, Direction direction, float height, BlockPos pos, BlockState state, CallbackInfoReturnable<Boolean> cir) {
if (!(state.getBlock() instanceof ReFramedBlock block)
) return;
boolean is_covered = VoxelShapes.isSideCovered(
VoxelShapes.cuboid(0.0, 0.0, 0.0, 1.0, height, 1.0),
block.getShadingShape(state, world, pos),
direction
);
cir.setReturnValue(is_covered);
}
@Redirect(
method = "render",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/BlockRenderView;getBlockState(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/block/BlockState;",
ordinal = 7
)
)
private BlockState getThemeState(BlockRenderView world, BlockPos pos) {
if (!(world.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity)) return world.getBlockState(pos);
return framed_entity.getThemes().stream()
.anyMatch(state -> state.getBlock() instanceof LeavesBlock
|| state.getBlock() instanceof TranslucentBlock
|| state.getBlock() instanceof AirBlock
)
? Blocks.GLASS.getDefaultState()
: world.getBlockState(pos) ;
}
}

View File

@@ -33,14 +33,17 @@
"compat.IndiumNonTerrainBlockRenderContextMixin", "compat.IndiumNonTerrainBlockRenderContextMixin",
"compat.IndiumTerrainRenderContextMixin", "compat.IndiumTerrainRenderContextMixin",
"compat.SodiumBlockOcclusionCacheMixin", "compat.SodiumBlockOcclusionCacheMixin",
"compat.SodiumFluidRendererMixin",
"model.WeightedBakedModelAccessor", "model.WeightedBakedModelAccessor",
"particles.AccessorParticle", "particles.AccessorParticle",
"particles.AccessorSpriteBillboardParticle", "particles.AccessorSpriteBillboardParticle",
"particles.MixinBlockDustParticle", "particles.MixinBlockDustParticle",
"render.AbstractBlockRenderContextMixin", "render.AbstractBlockRenderContextMixin",
"render.BlockMixin",
"render.BlockModelRendererMixin", "render.BlockModelRendererMixin",
"render.BlockRenderContextMixin", "render.BlockRenderContextMixin",
"render.BlockRenderInfoMixin", "render.BlockRenderInfoMixin",
"render.FluidRendererMixin",
"render.MultipartBakedModelMixin", "render.MultipartBakedModelMixin",
"render.TerrainRenderContextMixin", "render.TerrainRenderContextMixin",
"render.WorldRendererMixin", "render.WorldRendererMixin",