diff --git a/README.md b/README.md index 7b670aa..7f0f146 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,10 @@ or based on preferences add the person(s) to the project ### What Shapes are planed to be added Currently, the list of shapes to be added is pretty simple as the mod is still under development: -- Wall - Fence -- Pane - Button - Pressure Plate -- Trapdoor -- Door -- Carpet +- Carpet (maybe redundant with Layer) - Post - Half Slab (maybe redundant with Layer) - Slabs Stair (a stair with one end being of a second theme, might be done in multiple blocks) diff --git a/build.gradle b/build.gradle index a9e5d38..43707f3 100755 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ import fr.altarik.CreateTag plugins { id "com.modrinth.minotaur" version "2.+" - id 'fabric-loom' version '1.5-SNAPSHOT' + id 'fabric-loom' version '1.6-SNAPSHOT' id 'maven-publish' } @@ -106,11 +106,11 @@ dependencies { // modRuntimeOnly "maven.modrinth:indium:${project.indium_version}+mc${project.minecraft_version}" // modRuntimeOnly "maven.modrinth:sodium:mc${project.minecraft_version}-${project.sodium_version}" - // Athena for connected texture + // Athena for connected textures modCompileOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}" modRuntimeOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}" - // Continuity for connectedTextures + // Continuity for connected textures modCompileOnly "maven.modrinth:continuity:${project.continuity_version}" modRuntimeOnly "maven.modrinth:continuity:${project.continuity_version}" @@ -200,8 +200,8 @@ publishing { modrinth { token = getEnv("MODRINTH_TOKEN", local.getProperty("modrinth_token")) projectId = project.modrinth_id - versionNumber = project.mod_version - versionName = "${project.archives_base_name} ${project.mod_version}" + versionNumber = "${project.mod_version}-${project.minecraft_version}" + versionName = "${project.archives_base_name} ${project.mod_version}-${project.minecraft_version}" versionType = project.mod_version.endsWith('SNAPSHOT') ? 'beta' : 'release' uploadFile = remapJar gameVersions = [project.minecraft_version] diff --git a/gradle.properties b/gradle.properties index c49b920..93cdd49 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,18 +5,18 @@ org.gradle.jvmargs=-Xmx1G # check these on https://modmuss50.me/fabric.html minecraft_version=1.20.4 yarn_mappings=1.20.4+build.3 -loader_version=0.15.6 +loader_version=0.15.11 # Mod Properties modrinth_id = jCpoCBpn -mod_version = 1.5.8 +mod_version = 1.5.9 maven_group = fr.adrien1106 archives_base_name = ReFramed mod_id = reframed # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.95.4+1.20.4 +fabric_version=0.97.0+1.20.4 git_owner=Altarik git_repo=ReFramed diff --git a/src/main/java/fr/adrien1106/reframed/ReFramed.java b/src/main/java/fr/adrien1106/reframed/ReFramed.java index 532f6e4..3e9b5f9 100644 --- a/src/main/java/fr/adrien1106/reframed/ReFramed.java +++ b/src/main/java/fr/adrien1106/reframed/ReFramed.java @@ -37,7 +37,7 @@ public class ReFramed implements ModInitializer { public static final String MODID = "reframed"; public static final ArrayList BLOCKS = new ArrayList<>(); - public static Block CUBE, SMALL_CUBE, SMALL_CUBES_STEP, STAIR, HALF_STAIR, STAIRS_CUBE, HALF_STAIRS_SLAB, HALF_STAIRS_STAIR, SLAB, SLABS_CUBE, STEP, STEPS_SLAB, LAYER, PILLAR, WALL; + public static Block CUBE, SMALL_CUBE, SMALL_CUBES_STEP, STAIR, HALF_STAIR, STAIRS_CUBE, HALF_STAIRS_SLAB, HALF_STAIRS_STAIR, SLAB, SLABS_CUBE, STEP, STEPS_SLAB, LAYER, PILLAR, PILLARS_WALL, WALL, PANE, TRAPDOOR, DOOR; public static final ArrayList ITEMS = new ArrayList<>(); public static Item HAMMER, SCREWDRIVER, BLUEPRINT, BLUEPRINT_WRITTEN; @@ -65,7 +65,11 @@ public class ReFramed implements ModInitializer { STEP = registerBlock("step" , new ReFramedStepBlock(cp(Blocks.OAK_SLAB))); STEPS_SLAB = registerBlock("steps_slab" , new ReFramedStepsSlabBlock(cp(Blocks.OAK_SLAB))); PILLAR = registerBlock("pillar" , new ReFramedPillarBlock(cp(Blocks.OAK_FENCE))); - WALL = registerBlock("wall" , new ReframedWallBlock(cp(Blocks.OAK_FENCE))); + PILLARS_WALL = registerBlock("pillars_wall" , new ReFramedPillarsWallBlock(cp(Blocks.OAK_FENCE))); + WALL = registerBlock("wall" , new ReFramedWallBlock(cp(Blocks.OAK_FENCE))); + PANE = registerBlock("pane" , new ReFramedPaneBlock(cp(Blocks.OAK_FENCE))); + TRAPDOOR = registerBlock("trapdoor" , new ReFramedTrapdoorBlock(cp(Blocks.OAK_TRAPDOOR))); + DOOR = registerBlock("door" , new ReFramedDoorBlock(cp(Blocks.OAK_DOOR))); HAMMER = registerItem("hammer" , new ReFramedHammerItem(new Item.Settings().maxCount(1))); SCREWDRIVER = registerItem("screwdriver" , new ReFramedScrewdriverItem(new Item.Settings().maxCount(1))); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java index ba53c06..0db4a18 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java @@ -43,18 +43,6 @@ public class ReFramedBlock extends Block implements BlockEntityProvider { setDefaultState(getDefaultState().with(LIGHT, false)); } - /** - * Generates a record for the key so that it replaces the blockstate - * which may have states that returns same models - * @param state - the state_key to generate the key from - * @return a cache key with only relevant properties - */ - public Object getModelCacheKey(BlockState state) { - return ""; - } - - //For addon devs: override this so your blocks don't end up trying to place my block entity, my BlockEntityType only handles blocks internal to the mod - //Just make your own BlockEntityType, it's fine, you can even use the same ReFramedEntity class @Override public @Nullable BlockEntity createBlockEntity(BlockPos pos, BlockState state) { return ReFramed.REFRAMED_BLOCK_ENTITY.instantiate(pos, state); @@ -73,18 +61,13 @@ public class ReFramedBlock extends Block implements BlockEntityProvider { @Override public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { - if (!canUse(world, pos, player)) return superUse(state, world, pos, player, hand, hit); + if (!canUse(world, pos, player)) return ActionResult.PASS; ActionResult result = BlockHelper.useUpgrade(state, world, pos, player, hand); if (result.isAccepted()) return result; return BlockHelper.useCamo(state, world, pos, player, hand, hit, 1); } - // don't like this but might be useful - protected ActionResult superUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { - return super.onUse(state, world, pos, player, hand, hit); - } - protected boolean canUse(World world, BlockPos pos, PlayerEntity player) { return player.canModifyBlocks() && world.canPlayerModifyAt(player, pos); } diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoorBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedDoorBlock.java new file mode 100644 index 0000000..3fd988e --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedDoorBlock.java @@ -0,0 +1,273 @@ +package fr.adrien1106.reframed.block; + +import fr.adrien1106.reframed.util.VoxelHelper; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import net.minecraft.block.*; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.enums.DoorHinge; +import net.minecraft.block.enums.DoubleBlockHalf; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.pathing.NavigationType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.sound.SoundCategory; +import net.minecraft.state.StateManager; +import net.minecraft.util.ActionResult; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import net.minecraft.world.WorldView; +import net.minecraft.world.event.GameEvent; +import net.minecraft.world.explosion.Explosion; +import org.jetbrains.annotations.Nullable; + +import java.util.function.BiConsumer; + +import static net.minecraft.state.property.Properties.*; + +public class ReFramedDoorBlock extends WaterloggableReFramedBlock { + + public static final VoxelShape[] DOOR_VOXELS; + + public ReFramedDoorBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState() + .with(HORIZONTAL_FACING, Direction.NORTH) + .with(DOOR_HINGE, DoorHinge.LEFT) + .with(DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER) + .with(OPEN, false) + .with(POWERED, false) + ); + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(HORIZONTAL_FACING, DOOR_HINGE, DOUBLE_BLOCK_HALF, OPEN, POWERED)); + } + + @Override + public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) { + BlockPos pos_down = pos.down(); + BlockState state_down = world.getBlockState(pos_down); + return state.get(DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER ? !state_down.isAir() : state_down.isOf(this); + } + + @Override + public void neighborUpdate(BlockState state, World world, BlockPos pos, Block source, BlockPos sourcePos, boolean notify) { + if (world.isClient) return; + boolean powered = world.isReceivingRedstonePower(pos) + || world.isReceivingRedstonePower( + state.get(DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER + ? pos.up() + : pos.down() + ); + if (!getDefaultState().isOf(source) && powered != state.get(POWERED)) { + if (state.get(OPEN) != powered) + playToggleSound(null, world, pos, powered); + + world.setBlockState(pos, state.with(POWERED, powered).with(OPEN, powered), 2); + if (state.get(WATERLOGGED)) { + world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world)); + } + } + } + + @Override + public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { + World world = ctx.getWorld(); + BlockPos pos = ctx.getBlockPos(); + Direction facing = ctx.getHorizontalPlayerFacing().getOpposite(); + if (pos.getY() >= world.getTopY() - 1 || !world.getBlockState(pos.up()).canReplace(ctx)) return null; + BlockState state = super.getPlacementState(ctx) + .with(DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER) + .with(HORIZONTAL_FACING, facing); + + if (world.isReceivingRedstonePower(pos) || world.isReceivingRedstonePower(pos.up())) + state = state.with(OPEN, true).with(POWERED, true); + + + return state.with(DOOR_HINGE, getHinge(facing, pos, world, BlockHelper.getRelativePos(ctx.getHitPos(), pos))); + } + + @Override + public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack, BlockState old_state, BlockEntity old_entity) { + world.setBlockState( + pos.up(), + state + .with(DOUBLE_BLOCK_HALF, DoubleBlockHalf.UPPER) + .with(WATERLOGGED, world.getFluidState(pos.up()).isOf(Fluids.WATER)), + 3 + ); + } + + @Override + public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) { + if (!world.isClient() && (player.isCreative() || !player.canHarvest(state))) { + DoubleBlockHalf half = state.get(DOUBLE_BLOCK_HALF); + BlockPos other_pos = half == DoubleBlockHalf.LOWER ? pos.up() : pos.down(); + BlockState other_state = world.getBlockState(other_pos); + if (other_state.isOf(this) && other_state.get(DOUBLE_BLOCK_HALF) != half) { + world.setBlockState(other_pos, other_state.get(WATERLOGGED) ? Blocks.WATER.getDefaultState(): Blocks.AIR.getDefaultState(), 35); + world.syncWorldEvent(player, 2001, other_pos, Block.getRawIdFromState(other_state)); + } + } + + return super.onBreak(world, pos, state, player); + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + super.onStateReplaced(state, world, pos, newState, moved); + + if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos); + } + + @Override + public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState other, WorldAccess world, BlockPos pos, BlockPos moved) { + if (direction.getAxis() == Direction.Axis.Y + && other.isOf(this) + && other.get(DOUBLE_BLOCK_HALF) != state.get(DOUBLE_BLOCK_HALF) + && other.get(OPEN) != state.get(OPEN) + ) return state.cycle(OPEN); + Direction facing = state.get(HORIZONTAL_FACING); + if (direction == ( + state.get(DOOR_HINGE) == DoorHinge.RIGHT + ? facing.rotateYClockwise() + : facing.rotateYCounterclockwise()) + && other.isOf(this) + && other.get(DOUBLE_BLOCK_HALF) == state.get(DOUBLE_BLOCK_HALF) + && other.get(DOOR_HINGE) != state.get(DOOR_HINGE) + && !state.get(POWERED) + ) return state.with(OPEN, other.get(OPEN)); + return super.getStateForNeighborUpdate(state, direction, other, world, pos, moved); + } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + ActionResult result = super.onUse(state, world, pos, player, hand, hit); + if (result.isAccepted()) return result; + flip(state, world, pos, player); + return ActionResult.success(world.isClient); + } + + @Override + public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { + return switch (type) { + case LAND, AIR -> state.get(OPEN); + case WATER -> false; + }; + } + + @Override + public void onExploded(BlockState state, World world, BlockPos pos, Explosion explosion, BiConsumer stack_merger) { + if (explosion.getDestructionType() == Explosion.DestructionType.TRIGGER_BLOCK + && !world.isClient() + && !state.get(POWERED) + ) flip(state, world, pos, null); + + super.onExploded(state, world, pos, explosion, stack_merger); + } + + private void flip(BlockState state, World world, BlockPos pos, @Nullable PlayerEntity player) { + state = state.cycle(OPEN); + world.setBlockState(pos, state, 10); + + this.playToggleSound(player, world, pos, state.get(OPEN)); + } + + protected void playToggleSound(@Nullable PlayerEntity player, World world, BlockPos pos, boolean open) { + world.playSound(player, pos, open ? BlockSetType.OAK.doorOpen() : BlockSetType.OAK.doorClose(), SoundCategory.BLOCKS, 1.0F, world.getRandom().nextFloat() * 0.1F + 0.9F); + world.emitGameEvent(player, open ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pos); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + Direction direction = state.get(HORIZONTAL_FACING); + if (state.get(OPEN)) direction = switch (state.get(DOOR_HINGE)) { + case RIGHT -> direction.rotateYCounterclockwise(); + case LEFT -> direction.rotateYClockwise(); + }; + return DOOR_VOXELS[direction.ordinal() - 2]; + } + + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(HORIZONTAL_FACING, rotation.rotate(state.get(HORIZONTAL_FACING))); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return mirror == BlockMirror.NONE ? state : state.with(HORIZONTAL_FACING, mirror.apply(state.get(HORIZONTAL_FACING))).cycle(DOOR_HINGE); + } + + @Override + public long getRenderingSeed(BlockState state, BlockPos pos) { + return MathHelper.hashCode(pos.getX(), pos.down(state.get(DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER ? 0 : 1).getY(), pos.getZ()); + } + + private DoorHinge getHinge(Direction facing, BlockPos pos, World world, Vec3d hit_pos) { + Direction left = facing.rotateYClockwise(); + BlockPos left_pos = pos.offset(left); + BlockState left_state = world.getBlockState(left_pos); + Direction right = facing.rotateYCounterclockwise(); + BlockPos right_pos = pos.offset(right); + BlockState right_state = world.getBlockState(right_pos); + DoorHinge hinge = null; + + if (left_state.isSideSolidFullSquare(world, left_pos, right)) + hinge = DoorHinge.LEFT; + if (right_state.isSideSolidFullSquare(world, right_pos, left)) + hinge = hinge == DoorHinge.LEFT ? null : DoorHinge.RIGHT; + + if (hinge != null) return hinge; + + if (left_state.isOf(this) + && left_state.get(HORIZONTAL_FACING) == facing + && left_state.get(DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER + && left_state.get(DOOR_HINGE) == DoorHinge.LEFT + ) hinge = DoorHinge.RIGHT; + if (right_state.isOf(this) + && right_state.get(HORIZONTAL_FACING) == facing + && right_state.get(DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER + && right_state.get(DOOR_HINGE) == DoorHinge.RIGHT + ) hinge = hinge == DoorHinge.RIGHT ? null : DoorHinge.LEFT; + + if (hinge != null) return hinge; + + return switch (facing.getAxis()) { + case Z -> { + if (left.getDirection() == Direction.AxisDirection.POSITIVE) + yield hit_pos.getX() < 0.5 ? DoorHinge.RIGHT : DoorHinge.LEFT; + else // left.getDirection() == Direction.AxisDirection.NEGATIVE + yield hit_pos.getX() < 0.5 ? DoorHinge.LEFT : DoorHinge.RIGHT; + } + case X -> { + if (left.getDirection() == Direction.AxisDirection.POSITIVE) + yield hit_pos.getZ() < 0.5 ? DoorHinge.RIGHT : DoorHinge.LEFT; + else // left.getDirection() == Direction.AxisDirection.NEGATIVE + yield hit_pos.getZ() < 0.5 ? DoorHinge.LEFT : DoorHinge.RIGHT; + } + default -> DoorHinge.LEFT; + }; + } + + static { + VoxelShape SHAPE = createCuboidShape(0.0, 0.0, 0.0, 16.0, 16.0, 3.0); + DOOR_VOXELS = VoxelHelper.VoxelListBuilder.create(SHAPE, 4) + .add(VoxelHelper::mirrorZ) + .add(VoxelHelper::rotateY) + .add(VoxelHelper::mirrorX) + .build(); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java index 46bd75a..7f67064 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java @@ -69,17 +69,17 @@ public abstract class ReFramedDoubleBlock extends ReFramedBlock { @Override public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) { - return getCullingShape(state, view, pos); - } - - @Override - public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) { return isGhost(view, pos) ? empty() : fullCube(); } + @Override + public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) { + return getCollisionShape(state, view, pos, ShapeContext.absent()); + } + @Override public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { - if (!canUse(world, pos, player)) return superUse(state, world, pos, player, hand, hit); + if (!canUse(world, pos, player)) return ActionResult.PASS; ActionResult result = BlockHelper.useUpgrade(state, world, pos, player, hand); if (result.isAccepted()) return result; return BlockHelper.useCamo(state, world, pos, player, hand, hit, getHitShape(state, hit)); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairBlock.java index 4f23964..9d2efb7 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairBlock.java @@ -10,6 +10,8 @@ import net.minecraft.block.ShapeContext; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.function.BooleanBiFunction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -29,18 +31,11 @@ public class ReFramedHalfStairBlock extends WaterloggableReFramedBlock { public static final VoxelShape[] HALF_STAIR_VOXELS; - private record ModelCacheKey(Corner corner, int face) {} - public ReFramedHalfStairBlock(Settings settings) { super(settings); setDefaultState(getDefaultState().with(CORNER, NORTH_EAST_DOWN).with(CORNER_FACE, 0)); } - @Override - public Object getModelCacheKey(BlockState state) { - return new ModelCacheKey(state.get(CORNER), state.get(CORNER_FACE)); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(CORNER,CORNER_FACE)); @@ -108,6 +103,20 @@ public class ReFramedHalfStairBlock extends WaterloggableReFramedBlock { return HALF_STAIR_VOXELS[state.get(CORNER_FACE) + state.get(CORNER).getID() * 3]; } + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + Corner corner = state.get(CORNER).rotate(rotation); + Direction face = state.get(CORNER).getDirection(state.get(CORNER_FACE)); + return state.with(CORNER, corner).with(CORNER_FACE, corner.getDirectionIndex(rotation.rotate(face))); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + Corner corner = state.get(CORNER).mirror(mirror); + Direction face = state.get(CORNER).getDirection(state.get(CORNER_FACE)); + return state.with(CORNER, corner).with(CORNER_FACE, corner.getDirectionIndex(mirror.apply(face))); + } + @Override public Map getThemeMap(BlockState state, BlockState new_state) { if (new_state.isOf(ReFramed.HALF_STAIRS_SLAB)) return Map.of(1, 1); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsSlabBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsSlabBlock.java index 85c99b5..18fbb1d 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsSlabBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsSlabBlock.java @@ -7,7 +7,10 @@ import net.minecraft.block.BlockState; import net.minecraft.block.ShapeContext; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; import net.minecraft.world.BlockView; import org.jetbrains.annotations.Nullable; @@ -22,18 +25,11 @@ import static net.minecraft.util.shape.VoxelShapes.empty; public class ReFramedHalfStairsSlabBlock extends WaterloggableReFramedDoubleBlock { - private record ModelCacheKey(Corner corner, int face) {} - public ReFramedHalfStairsSlabBlock(Settings settings) { super(settings); setDefaultState(getDefaultState().with(CORNER, NORTH_EAST_DOWN).with(CORNER_FACE, 0)); } - @Override - public Object getModelCacheKey(BlockState state) { - return new ModelCacheKey(state.get(CORNER), state.get(CORNER_FACE)); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(CORNER,CORNER_FACE)); @@ -48,7 +44,7 @@ public class ReFramedHalfStairsSlabBlock extends WaterloggableReFramedDoubleBloc } @Override - public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) { + public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) { return isGhost(view, pos) ? empty(): getSlabShape(state.get(CORNER).getDirection(state.get(CORNER_FACE))); } @@ -57,6 +53,20 @@ public class ReFramedHalfStairsSlabBlock extends WaterloggableReFramedDoubleBloc return getSlabShape(state.get(CORNER).getDirection(state.get(CORNER_FACE))); } + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + Corner corner = state.get(CORNER).rotate(rotation); + Direction face = state.get(CORNER).getDirection(state.get(CORNER_FACE)); + return state.with(CORNER, corner).with(CORNER_FACE, corner.getDirectionIndex(rotation.rotate(face))); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + Corner corner = state.get(CORNER).mirror(mirror); + Direction face = state.get(CORNER).getDirection(state.get(CORNER_FACE)); + return state.with(CORNER, corner).with(CORNER_FACE, corner.getDirectionIndex(mirror.apply(face))); + } + @Override public VoxelShape getShape(BlockState state, int i) { Corner corner = state.get(CORNER); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsStairBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsStairBlock.java index e4eb07f..6f84264 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsStairBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsStairBlock.java @@ -9,6 +9,8 @@ import net.minecraft.block.BlockState; import net.minecraft.block.ShapeContext; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; @@ -27,11 +29,6 @@ public class ReFramedHalfStairsStairBlock extends WaterloggableReFramedDoubleBlo setDefaultState(getDefaultState().with(EDGE, NORTH_DOWN)); } - @Override - public Object getModelCacheKey(BlockState state) { - return state.get(EDGE); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(EDGE)); @@ -44,7 +41,7 @@ public class ReFramedHalfStairsStairBlock extends WaterloggableReFramedDoubleBlo } @Override - public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) { + public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) { return isGhost(view, pos) ? empty(): getStairShape(state.get(EDGE), StairShape.STRAIGHT); } @@ -53,6 +50,16 @@ public class ReFramedHalfStairsStairBlock extends WaterloggableReFramedDoubleBlo return getStairShape(state.get(EDGE), StairShape.STRAIGHT); } + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(EDGE, state.get(EDGE).rotate(rotation)); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return state.with(EDGE, state.get(EDGE).mirror(mirror)); + } + @Override public VoxelShape getShape(BlockState state, int i) { Edge edge = state.get(EDGE); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedLayerBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedLayerBlock.java index 832183b..a0ab9e9 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedLayerBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedLayerBlock.java @@ -7,8 +7,9 @@ import net.minecraft.block.ShapeContext; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; import net.minecraft.world.BlockView; import org.jetbrains.annotations.Nullable; @@ -20,18 +21,12 @@ import static net.minecraft.state.property.Properties.LAYERS; public class ReFramedLayerBlock extends ReFramedSlabBlock { public static final VoxelShape[] LAYER_VOXELS; - private record ModelCacheKey(Direction face, int layer) {} public ReFramedLayerBlock(Settings settings) { super(settings); setDefaultState(getDefaultState().with(LAYERS, 1)); } - @Override - public Object getModelCacheKey(BlockState state) { - return new ModelCacheKey(state.get(FACING), state.get(LAYERS)); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(LAYERS)); @@ -58,6 +53,16 @@ public class ReFramedLayerBlock extends ReFramedSlabBlock { return previous.with(LAYERS, previous.get(LAYERS) + 1); } + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(FACING, rotation.rotate(state.get(FACING))); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return state.with(FACING, mirror.apply(state.get(FACING))); + } + static { VoxelListBuilder builder = VoxelListBuilder.create(createCuboidShape(0, 0, 0, 16, 2, 16), 48) .add(createCuboidShape(0, 0, 0, 16, 4, 16)) diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedPaneBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedPaneBlock.java new file mode 100644 index 0000000..a800d1c --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedPaneBlock.java @@ -0,0 +1,130 @@ +package fr.adrien1106.reframed.block; + +import fr.adrien1106.reframed.util.VoxelHelper; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.PaneBlock; +import net.minecraft.block.ShapeContext; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.BooleanProperty; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; +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 net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import org.jetbrains.annotations.Nullable; + +import static net.minecraft.state.property.Properties.*; + +public class ReFramedPaneBlock extends WaterloggableReFramedBlock { + + public static final VoxelShape[] PANE_VOXELS; + + public ReFramedPaneBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState() + .with(EAST, false) + .with(NORTH, false) + .with(WEST, false) + .with(SOUTH, false) + ); + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(EAST, NORTH, SOUTH, WEST)); + } + + @Override + public BlockState getStateForNeighborUpdate(BlockState state, Direction dir, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos moved) { + BlockState new_state = super.getStateForNeighborUpdate(state, dir, other_state, world, pos, moved); + if (dir == Direction.DOWN) return new_state; + + for (Direction side: Direction.Type.HORIZONTAL) { + BlockState neighbor = world.getBlockState(pos.offset(side)); + new_state = new_state.with(getPaneProperty(side), connectsTo( + neighbor, + neighbor.isSideSolidFullSquare(world, pos.offset(side), side.getOpposite()) + )); + } + return new_state; + } + + @Override + public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { + BlockState state = super.getPlacementState(ctx); + World world = ctx.getWorld(); + BlockPos pos = ctx.getBlockPos(); + + for (Direction dir: Direction.Type.HORIZONTAL) { + BlockState neighbor = world.getBlockState(pos.offset(dir)); + state = state.with(getPaneProperty(dir), connectsTo( + neighbor, + neighbor.isSideSolidFullSquare(world, pos.offset(dir), dir.getOpposite()) + )); + } + return state; + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + super.onStateReplaced(state, world, pos, newState, moved); + + if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + VoxelShape shape = PANE_VOXELS[0]; + for (Direction dir: Direction.Type.HORIZONTAL) { + if (state.get(getPaneProperty(dir))) + shape = VoxelShapes.union(shape, PANE_VOXELS[dir.ordinal() - 1]); + } + return shape; + } + + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) -> + s.with(getPaneProperty(rotation.rotate(dir)), state.get(getPaneProperty(dir))) + , (prev, next) -> next); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) -> + s.with(getPaneProperty(mirror.apply(dir)), state.get(getPaneProperty(dir))) + , (prev, next) -> next); + } + + public static boolean connectsTo(BlockState state, boolean fs) { + return !cannotConnect(state) && fs || state.getBlock() instanceof PaneBlock || state.isIn(BlockTags.WALLS); + } + + public static BooleanProperty getPaneProperty(Direction dir) { + return switch (dir) { + case NORTH -> NORTH; + case EAST -> EAST; + case SOUTH -> SOUTH; + case WEST -> WEST; + default -> null; + }; + } + + static { + VoxelShape POST = createCuboidShape(7, 0, 7, 9, 16, 9); + VoxelShape SIDE = createCuboidShape(7, 0, 0, 9, 16, 7); + PANE_VOXELS = VoxelHelper.VoxelListBuilder.create(POST, 5) + .add(SIDE) + .add(VoxelHelper::mirrorZ) + .add(VoxelHelper::rotateY) + .add(VoxelHelper::mirrorX) + .build(); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedPillarBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedPillarBlock.java index 6e73175..9b9a379 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedPillarBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedPillarBlock.java @@ -4,17 +4,16 @@ import fr.adrien1106.reframed.util.VoxelHelper; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.ShapeContext; -import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; import net.minecraft.world.BlockView; import org.jetbrains.annotations.Nullable; -import java.util.Map; - import static net.minecraft.state.property.Properties.AXIS; public class ReFramedPillarBlock extends WaterloggableReFramedBlock { @@ -26,30 +25,13 @@ public class ReFramedPillarBlock extends WaterloggableReFramedBlock { setDefaultState(getDefaultState().with(AXIS, Direction.Axis.Y)); } - @Override - public Object getModelCacheKey(BlockState state) { - return state.get(AXIS); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(AXIS)); } - @Override - public boolean canReplace(BlockState state, ItemPlacementContext context) { - return !(context.getPlayer().isSneaking() - || !(context.getStack().getItem() instanceof BlockItem block_item) - || !( - block_item.getBlock() == this - && state.get(AXIS) != context.getSide().getAxis() - ) - ); - } - @Override public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { - // TODO: PILLARS WALL return super.getPlacementState(ctx).with(AXIS, ctx.getSide().getAxis()); } @@ -63,9 +45,13 @@ public class ReFramedPillarBlock extends WaterloggableReFramedBlock { } @Override - public Map getThemeMap(BlockState state, BlockState new_state) { -// if (new_state.getBlock() == ReFramed.PILLARS_WALL) return Map.of(1, 1); // TODO: PILLARS WALL - return super.getThemeMap(state, new_state); + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(AXIS, rotation.rotate(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis()); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return state.with(AXIS, mirror.apply(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis()); } static { diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedPillarsWallBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedPillarsWallBlock.java new file mode 100644 index 0000000..952fc7e --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedPillarsWallBlock.java @@ -0,0 +1,133 @@ +package fr.adrien1106.reframed.block; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.ShapeContext; +import net.minecraft.block.enums.WallShape; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; +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 net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.stream.Collectors; + +import static fr.adrien1106.reframed.block.ReFramedWallBlock.*; +import static net.minecraft.state.property.Properties.*; +import static net.minecraft.util.shape.VoxelShapes.empty; + +public class ReFramedPillarsWallBlock extends WaterloggableReFramedDoubleBlock { + + public ReFramedPillarsWallBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState() + .with(EAST_WALL_SHAPE, WallShape.NONE) + .with(NORTH_WALL_SHAPE, WallShape.NONE) + .with(WEST_WALL_SHAPE, WallShape.NONE) + .with(SOUTH_WALL_SHAPE, WallShape.NONE) + ); + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(EAST_WALL_SHAPE, NORTH_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); + } + + @Override + public BlockState getStateForNeighborUpdate(BlockState state, Direction dir, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos moved) { + BlockState new_state = super.getStateForNeighborUpdate(state, dir, other_state, world, pos, moved); + if (dir == Direction.DOWN) return new_state; + BlockState top_state = dir == Direction.UP? other_state: world.getBlockState(pos.up()); + boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN); + VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN); + Map neighbors = Direction.Type.HORIZONTAL.stream() + .collect(Collectors.toMap(d -> d, d -> { + if (d == dir) return other_state; + return world.getBlockState(pos.offset(d)); + })); + return getWallState(new_state, top_state, neighbors, top_shape, fs, world, pos); + } + + @Override + public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { + BlockState state = super.getPlacementState(ctx); + World world = ctx.getWorld(); + BlockPos pos = ctx.getBlockPos(); + + BlockState top_state = world.getBlockState(pos.up()); + boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN); + VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN); + + Map neighbors = Direction.Type.HORIZONTAL.stream() + .collect(Collectors.toMap(d -> d, d -> world.getBlockState(pos.offset(d)))); + return getWallState(state, top_state, neighbors, top_shape, fs, world, pos); + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + super.onStateReplaced(state, world, pos, newState, moved); + + if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos); + } + + @Override + public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) { + if (isGhost(view, pos)) return empty(); + VoxelShape shape = WALL_VOXELS[9]; + for (Direction dir : Direction.Type.HORIZONTAL) { + if (state.get(getWallShape(dir)) != WallShape.NONE) + shape = VoxelShapes.union(shape, WALL_VOXELS[8 + dir.ordinal()]); + } + return shape; + } + + @Override + public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) { + return isGhost(view, pos) ? empty(): getOutlineShape(state, view, pos, ShapeContext.absent()); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + VoxelShape shape = WALL_VOXELS[0]; + for (Direction dir: Direction.Type.HORIZONTAL) { + WallShape wall_shape = state.get(getWallShape(dir)); + if (wall_shape != WallShape.NONE) + shape = VoxelShapes.union(shape, WALL_VOXELS[1 + (wall_shape.ordinal()-1) * 4 + (dir.ordinal() - 2)]); + } + return shape; + } + + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) -> + s.with(getWallShape(rotation.rotate(dir)), state.get(getWallShape(dir))) + , (prev, next) -> next); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) -> + s.with(getWallShape(mirror.apply(dir)), state.get(getWallShape(dir))) + , (prev, next) -> next); + } + + @Override + public VoxelShape getShape(BlockState state, int i) { + if (i == 1) return WALL_VOXELS[0]; + VoxelShape shape = VoxelShapes.empty(); + for (Direction dir: Direction.Type.HORIZONTAL) { + WallShape wall_shape = state.get(getWallShape(dir)); + if (wall_shape != WallShape.NONE) + shape = VoxelShapes.union(shape, WALL_VOXELS[1 + (wall_shape.ordinal()-1) * 4 + (dir.ordinal() - 2)]); + } + return shape; + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java index 3da8b48..3818508 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java @@ -7,6 +7,8 @@ import net.minecraft.block.ShapeContext; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; @@ -32,11 +34,6 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock { super(settings); setDefaultState(getDefaultState().with(FACING, Direction.DOWN)); } - - @Override - public Object getModelCacheKey(BlockState state) { - return state.get(FACING); - } @Override protected void appendProperties(StateManager.Builder builder) { @@ -77,6 +74,16 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock { return getSlabShape(state.get(FACING)); } + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(FACING, rotation.rotate(state.get(FACING))); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return state.with(FACING, mirror.apply(state.get(FACING))); + } + public static VoxelShape getSlabShape(Direction side) { return switch (side) { case DOWN -> DOWN; diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabsCubeBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabsCubeBlock.java index e148ace..cec5797 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabsCubeBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabsCubeBlock.java @@ -4,11 +4,14 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; import org.jetbrains.annotations.Nullable; import static fr.adrien1106.reframed.block.ReFramedSlabBlock.*; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE; import static net.minecraft.state.property.Properties.AXIS; public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock { @@ -18,11 +21,6 @@ public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock { setDefaultState(getDefaultState().with(AXIS, Direction.Axis.Y)); } - @Override - public Object getModelCacheKey(BlockState state) { - return state.get(AXIS); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(AXIS)); @@ -34,6 +32,16 @@ public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock { return super.getPlacementState(ctx).with(AXIS, ctx.getSide().getAxis()); } + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(AXIS, rotation.rotate(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis()); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return state.with(AXIS, mirror.apply(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis()); + } + @Override public VoxelShape getShape(BlockState state, int i) { return switch (state.get(AXIS)) { diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubeBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubeBlock.java index 892d2c7..a4efbeb 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubeBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubeBlock.java @@ -10,6 +10,8 @@ import net.minecraft.block.ShapeContext; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; @@ -34,11 +36,6 @@ public class ReFramedSmallCubeBlock extends WaterloggableReFramedBlock { setDefaultState(getDefaultState().with(CORNER, NORTH_EAST_DOWN)); } - @Override - public Object getModelCacheKey(BlockState state) { - return state.get(CORNER); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(CORNER)); @@ -130,6 +127,16 @@ public class ReFramedSmallCubeBlock extends WaterloggableReFramedBlock { return SMALL_CUBE_VOXELS[state.get(CORNER).getID()]; } + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(CORNER, state.get(CORNER).rotate(rotation)); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return state.with(CORNER, state.get(CORNER).mirror(mirror)); + } + @Override public Map getThemeMap(BlockState state, BlockState new_state) { if (new_state.isOf(ReFramed.HALF_STAIRS_SLAB)) return Map.of(1, 2); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubesStepBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubesStepBlock.java index 76442e0..7d5b4fb 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubesStepBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubesStepBlock.java @@ -8,6 +8,8 @@ import net.minecraft.block.BlockState; import net.minecraft.block.ShapeContext; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.shape.VoxelShape; import net.minecraft.world.BlockView; @@ -25,11 +27,6 @@ public class ReFramedSmallCubesStepBlock extends WaterloggableReFramedDoubleBloc setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN)); } - @Override - public Object getModelCacheKey(BlockState state) { - return state.get(EDGE); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(EDGE)); @@ -42,7 +39,7 @@ public class ReFramedSmallCubesStepBlock extends WaterloggableReFramedDoubleBloc } @Override - public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) { + public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) { return isGhost(view, pos) ? empty(): getStepShape(state.get(EDGE)); } @@ -51,6 +48,16 @@ public class ReFramedSmallCubesStepBlock extends WaterloggableReFramedDoubleBloc return getStepShape(state.get(EDGE)); } + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(EDGE, state.get(EDGE).rotate(rotation)); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return state.with(EDGE, state.get(EDGE).mirror(mirror)); + } + @Override public VoxelShape getShape(BlockState state, int i) { Edge edge = state.get(EDGE); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedStairBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStairBlock.java index 0340543..c5b1a67 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedStairBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedStairBlock.java @@ -11,6 +11,8 @@ import net.minecraft.block.ShapeContext; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.function.BooleanBiFunction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -31,17 +33,11 @@ import static fr.adrien1106.reframed.util.blocks.StairShape.*; public class ReFramedStairBlock extends WaterloggableReFramedBlock { public static final VoxelShape[] STAIR_VOXELS; - private record ModelCacheKey(Edge edge, StairShape shape) {} public ReFramedStairBlock(Settings settings) { super(settings); setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN).with(STAIR_SHAPE, STRAIGHT)); } - - @Override - public Object getModelCacheKey(BlockState state) { - return new ModelCacheKey(state.get(EDGE), state.get(STAIR_SHAPE)); - } @Override protected void appendProperties(StateManager.Builder builder) { @@ -101,6 +97,31 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock { return getStairShape(state.get(EDGE), state.get(STAIR_SHAPE)); } + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + Edge prev_edge = state.get(EDGE); + Edge edge = prev_edge.rotate(rotation); + if (prev_edge.getAxis() == Direction.Axis.Y) return state.with(EDGE, edge); + + if (prev_edge.getFace().getDirection() == edge.getFace().getDirection()) // 90° rotations + state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).mirror()); + else state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).flip()); + + if (prev_edge.getAxis() == edge.getAxis()) // 180° rotation + state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).mirror()); + + return state.with(EDGE, edge); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + Edge prev_edge = state.get(EDGE); + Edge edge = prev_edge.mirror(mirror); + return state + .with(STAIR_SHAPE, prev_edge == edge ? state.get(STAIR_SHAPE).mirror() : state.get(STAIR_SHAPE).flip()) + .with(EDGE, edge); + } + public static VoxelShape getStairShape(Edge edge, StairShape shape) { return STAIR_VOXELS[edge.getID() * 9 + shape.getID()]; } diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedStairsCubeBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStairsCubeBlock.java index 4605087..b1dcb6f 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedStairsCubeBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedStairsCubeBlock.java @@ -7,6 +7,8 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; @@ -22,18 +24,12 @@ import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE; public class ReFramedStairsCubeBlock extends ReFramedDoubleBlock { private static final VoxelShape[] STAIRS_CUBE_VOXELS = VoxelListBuilder.buildFrom(STAIR_VOXELS); - private record ModelCacheKey(Edge edge, StairShape shape) {} public ReFramedStairsCubeBlock(Settings settings) { super(settings); setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN).with(STAIR_SHAPE, StairShape.STRAIGHT)); } - @Override - public Object getModelCacheKey(BlockState state) { - return new ModelCacheKey(state.get(EDGE), state.get(STAIR_SHAPE)); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(EDGE, STAIR_SHAPE)); @@ -54,6 +50,32 @@ public class ReFramedStairsCubeBlock extends ReFramedDoubleBlock { return super.getPlacementState(ctx).with(EDGE, face).with(STAIR_SHAPE, shape); } + + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + Edge prev_edge = state.get(EDGE); + Edge edge = prev_edge.rotate(rotation); + if (prev_edge.getAxis() == Direction.Axis.Y) return state.with(EDGE, edge); + + if (prev_edge.getFace().getDirection() == edge.getFace().getDirection()) // 90° rotations + state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).mirror()); + else state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).flip()); + + if (prev_edge.getAxis() == edge.getAxis()) // 180° rotation + state = state.with(STAIR_SHAPE, state.get(STAIR_SHAPE).mirror()); + + return state.with(EDGE, edge); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + Edge prev_edge = state.get(EDGE); + Edge edge = prev_edge.mirror(mirror); + return state + .with(STAIR_SHAPE, prev_edge == edge ? state.get(STAIR_SHAPE).mirror() : state.get(STAIR_SHAPE).flip()) + .with(EDGE, edge); + } + @Override public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { super.onStateReplaced(state, world, pos, newState, moved); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java index d706124..607f8d3 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java @@ -10,6 +10,8 @@ import net.minecraft.block.ShapeContext; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; @@ -34,11 +36,6 @@ public class ReFramedStepBlock extends WaterloggableReFramedBlock { setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN)); } - @Override - public Object getModelCacheKey(BlockState state) { - return state.get(EDGE); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(EDGE)); @@ -130,6 +127,16 @@ public class ReFramedStepBlock extends WaterloggableReFramedBlock { return getStepShape(state.get(EDGE)); } + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(EDGE, state.get(EDGE).rotate(rotation)); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return state.with(EDGE, state.get(EDGE).mirror(mirror)); + } + public static VoxelShape getStepShape(Edge edge) { return STEP_VOXELS[edge.getID()]; } diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedStepsSlabBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepsSlabBlock.java index 6cfe71a..82ebc0a 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedStepsSlabBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepsSlabBlock.java @@ -7,6 +7,8 @@ import net.minecraft.block.BlockState; import net.minecraft.block.ShapeContext; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction.Axis; @@ -22,18 +24,12 @@ import static net.minecraft.state.property.Properties.FACING; import static net.minecraft.util.shape.VoxelShapes.empty; public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock { - private record ModelCacheKey(Direction facing, Axis axis) {} public ReFramedStepsSlabBlock(Settings settings) { super(settings); setDefaultState(getDefaultState().with(FACING, Direction.DOWN).with(AXIS, Axis.X)); } - @Override - public Object getModelCacheKey(BlockState state) { - return new ModelCacheKey(state.get(FACING), state.get(AXIS)); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(FACING, AXIS)); @@ -48,7 +44,7 @@ public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock { } @Override - public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) { + public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) { return isGhost(view, pos) ? empty() : getSlabShape(state.get(FACING)); } @@ -57,6 +53,21 @@ public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock { return getSlabShape(state.get(FACING)); } + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state + .with(AXIS, rotation.rotate(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis()) + .with(FACING, rotation.rotate(state.get(FACING))); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + if (state.get(FACING).getAxis() != Axis.Y) + return state.with(FACING, mirror.apply(state.get(FACING))); + + return state; + } + @Override public VoxelShape getShape(BlockState state, int i) { Axis axis = state.get(AXIS); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedTrapdoorBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedTrapdoorBlock.java new file mode 100644 index 0000000..d2a2c09 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedTrapdoorBlock.java @@ -0,0 +1,159 @@ +package fr.adrien1106.reframed.block; + +import fr.adrien1106.reframed.util.VoxelHelper; +import net.minecraft.block.*; +import net.minecraft.block.enums.BlockHalf; +import net.minecraft.entity.ai.pathing.NavigationType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.sound.SoundCategory; +import net.minecraft.state.StateManager; +import net.minecraft.util.ActionResult; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import net.minecraft.world.event.GameEvent; +import net.minecraft.world.explosion.Explosion; +import org.jetbrains.annotations.Nullable; + +import java.util.function.BiConsumer; + +import static net.minecraft.state.property.Properties.*; + +public class ReFramedTrapdoorBlock extends WaterloggableReFramedBlock { + + public static final VoxelShape[] TRAPDOOR_VOXELS; + + public ReFramedTrapdoorBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState() + .with(HORIZONTAL_FACING, Direction.NORTH) + .with(BLOCK_HALF, BlockHalf.BOTTOM) + .with(OPEN, false) + .with(POWERED, false) + ); + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(HORIZONTAL_FACING, BLOCK_HALF, OPEN, POWERED)); + } + + @Override + public void neighborUpdate(BlockState state, World world, BlockPos pos, Block source, BlockPos sourcePos, boolean notify) { + if (world.isClient) return; + boolean powered = world.isReceivingRedstonePower(pos); + if (powered != state.get(POWERED)) { + if (state.get(OPEN) != powered) { + state = state.with(OPEN, powered); + playToggleSound(null, world, pos, powered); + } + + world.setBlockState(pos, state.with(POWERED, powered), 2); + if (state.get(WATERLOGGED)) { + world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world)); + } + } + } + + @Override + public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { + BlockState state = super.getPlacementState(ctx); + World world = ctx.getWorld(); + BlockPos pos = ctx.getBlockPos(); + Direction side = ctx.getSide(); + + if (side.getAxis().isVertical()) state = state + .with(HORIZONTAL_FACING, ctx.getHorizontalPlayerFacing().getOpposite()) + .with(BLOCK_HALF, side == Direction.UP ? BlockHalf.BOTTOM : BlockHalf.TOP); + else state = state + .with(HORIZONTAL_FACING, side) + .with(BLOCK_HALF, ctx.getHitPos().getY() - pos.getY() > 0.5 ? BlockHalf.TOP : BlockHalf.BOTTOM); + + if (world.isReceivingRedstonePower(pos)) state = state.with(OPEN, true).with(POWERED, true); + + return state; + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + super.onStateReplaced(state, world, pos, newState, moved); + + if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos); + } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + ActionResult result = super.onUse(state, world, pos, player, hand, hit); + if (result.isAccepted()) return result; + flip(state, world, pos, player); + return ActionResult.success(world.isClient); + } + + @Override + public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { + return switch (type) { + case LAND, AIR -> state.get(OPEN); + case WATER -> state.get(WATERLOGGED); + }; + } + + @Override + public void onExploded(BlockState state, World world, BlockPos pos, Explosion explosion, BiConsumer stack_merger) { + if (explosion.getDestructionType() == Explosion.DestructionType.TRIGGER_BLOCK + && !world.isClient() + && !state.get(POWERED) + ) flip(state, world, pos, null); + + super.onExploded(state, world, pos, explosion, stack_merger); + } + + private void flip(BlockState state, World world, BlockPos pos, @Nullable PlayerEntity player) { + state = state.cycle(OPEN); + world.setBlockState(pos, state, 2); + + this.playToggleSound(player, world, pos, state.get(OPEN)); + } + + protected void playToggleSound(@Nullable PlayerEntity player, World world, BlockPos pos, boolean open) { + world.playSound(player, pos, open ? BlockSetType.OAK.trapdoorOpen() : BlockSetType.OAK.trapdoorClose(), SoundCategory.BLOCKS, 1.0F, world.getRandom().nextFloat() * 0.1F + 0.9F); + world.emitGameEvent(player, open ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pos); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + int index; + if (!state.get(OPEN)) index = state.get(BLOCK_HALF) == BlockHalf.BOTTOM ? 0 : 1; + else index = state.get(HORIZONTAL_FACING).ordinal(); + return TRAPDOOR_VOXELS[index]; + } + + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(HORIZONTAL_FACING, rotation.rotate(state.get(HORIZONTAL_FACING))); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return state.with(HORIZONTAL_FACING, mirror.apply(state.get(HORIZONTAL_FACING))); + } + + static { + VoxelShape SHAPE = createCuboidShape(0, 0, 0, 16, 3, 16); + TRAPDOOR_VOXELS = VoxelHelper.VoxelListBuilder.create(SHAPE, 6) + .add(VoxelHelper::mirrorY) + .add(VoxelHelper::rotateX) + .add(VoxelHelper::mirrorZ) + .add(VoxelHelper::rotateY) + .add(VoxelHelper::mirrorX) + .build(); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReframedWallBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedWallBlock.java similarity index 72% rename from src/main/java/fr/adrien1106/reframed/block/ReframedWallBlock.java rename to src/main/java/fr/adrien1106/reframed/block/ReFramedWallBlock.java index 581f7db..7fcd9f9 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReframedWallBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedWallBlock.java @@ -7,6 +7,8 @@ import net.minecraft.item.ItemPlacementContext; import net.minecraft.registry.tag.BlockTags; import net.minecraft.state.StateManager; import net.minecraft.state.property.Property; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.function.BooleanBiFunction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -15,19 +17,20 @@ import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.BlockView; import net.minecraft.world.World; import net.minecraft.world.WorldAccess; +import net.minecraft.world.WorldView; import org.jetbrains.annotations.Nullable; +import java.util.Map; +import java.util.stream.Collectors; import java.util.stream.Stream; import static net.minecraft.state.property.Properties.*; -public class ReframedWallBlock extends WaterloggableReFramedBlock { +public class ReFramedWallBlock extends WaterloggableReFramedBlock { public static final VoxelShape[] WALL_VOXELS; - private record ModelCacheKey(boolean up, WallShape east, WallShape north, WallShape west, WallShape south) {} - - public ReframedWallBlock(Settings settings) { + public ReFramedWallBlock(Settings settings) { super(settings); setDefaultState(getDefaultState() .with(UP, true) @@ -38,17 +41,6 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock { ); } - @Override - public Object getModelCacheKey(BlockState state) { - return new ModelCacheKey( - state.get(UP), - state.get(EAST_WALL_SHAPE), - state.get(NORTH_WALL_SHAPE), - state.get(WEST_WALL_SHAPE), - state.get(SOUTH_WALL_SHAPE) - ); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(UP, EAST_WALL_SHAPE, NORTH_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); @@ -61,34 +53,13 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock { BlockState top_state = dir == Direction.UP? other_state: world.getBlockState(pos.up()); boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN); VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN); - if (dir == Direction.UP) { - for (Direction d : Direction.Type.HORIZONTAL) { - Property wall_shape = getWallShape(d); - if (state.get(wall_shape) == WallShape.NONE) continue; - new_state = new_state.with( - wall_shape, - fs - || (top_state.contains(wall_shape) && top_state.get(wall_shape) != WallShape.NONE) - || shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape) - ? WallShape.TALL - : WallShape.LOW - ); - } - return new_state.with(UP, shouldHavePost(new_state, top_state, top_shape)); - } - boolean side_full = other_state.isSideSolidFullSquare(world, moved, dir.getOpposite()); - if (shouldConnectTo(other_state, side_full, dir.getOpposite())) { - Property wall_shape = getWallShape(dir); - new_state = new_state.with( - wall_shape, - fs - || (top_state.contains(wall_shape) && top_state.get(wall_shape) != WallShape.NONE) - || shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape) - ? WallShape.TALL - : WallShape.LOW - ); - } else new_state = new_state.with(getWallShape(dir), WallShape.NONE); + Map neighbors = Direction.Type.HORIZONTAL.stream() + .collect(Collectors.toMap(d -> d, d -> { + if (d == dir) return other_state; + return world.getBlockState(pos.offset(d)); + })); + new_state = getWallState(new_state, top_state, neighbors, top_shape, fs, world, pos); return new_state.with(UP, shouldHavePost(new_state, top_state, top_shape)); } @@ -97,25 +68,14 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock { BlockState state = super.getPlacementState(ctx); World world = ctx.getWorld(); BlockPos pos = ctx.getBlockPos(); + BlockState top_state = world.getBlockState(pos.up()); boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN); VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN); - for (Direction dir : Direction.Type.HORIZONTAL) { - BlockPos offset = pos.offset(dir); - BlockState neighbor = world.getBlockState(offset); - boolean side_full = neighbor.isSideSolidFullSquare(world, offset, dir.getOpposite()); - if (shouldConnectTo(neighbor, side_full, dir.getOpposite())) { - Property wall_shape = getWallShape(dir); - state = state.with( - wall_shape, - fs - || (top_state.contains(wall_shape) && top_state.get(wall_shape) != WallShape.NONE) - || shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape) - ? WallShape.TALL - : WallShape.LOW - ); - } - } + + Map neighbors = Direction.Type.HORIZONTAL.stream() + .collect(Collectors.toMap(d -> d, d -> world.getBlockState(pos.offset(d)))); + state = getWallState(state, top_state, neighbors, top_shape, fs, world, pos); return state.with(UP, shouldHavePost(state, top_state, top_shape)); } @@ -148,9 +108,43 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock { return shape; } - private static boolean shouldHavePost(BlockState state, BlockState top_state, VoxelShape top_shape) { + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) -> + s.with(getWallShape(rotation.rotate(dir)), state.get(getWallShape(dir))) + , (prev, next) -> next); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) -> + s.with(getWallShape(mirror.apply(dir)), state.get(getWallShape(dir))) + , (prev, next) -> next); + } + + public static BlockState getWallState(BlockState state, BlockState top_state, Map neighbors, VoxelShape top_shape, boolean fs, WorldView world, BlockPos pos) { + for (Direction dir : Direction.Type.HORIZONTAL) { + BlockPos offset = pos.offset(dir); + BlockState neighbor = neighbors.get(dir); + boolean side_full = neighbor.isSideSolidFullSquare(world, offset, dir.getOpposite()); + Property wall_shape = getWallShape(dir); + if (shouldConnectTo(neighbor, side_full, dir.getOpposite())) { + state = state.with( + wall_shape, + fs + || (top_state.contains(wall_shape) && top_state.get(wall_shape) != WallShape.NONE) + || shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape) + ? WallShape.TALL + : WallShape.LOW + ); + } else state = state.with(wall_shape, WallShape.NONE); + } + return state; + } + + public static boolean shouldHavePost(BlockState state, BlockState top_state, VoxelShape top_shape) { // above has post - if (top_state.contains(NORTH_WALL_SHAPE) && top_state.get(UP)) return true; + if ((top_state.contains(UP) && top_state.get(UP)) || (!top_state.contains(UP) && top_state.contains(NORTH_WALL_SHAPE))) return true; if (Stream.of(Direction.SOUTH, Direction.EAST) // Opposites are different .anyMatch(dir -> state.get(getWallShape(dir)) != state.get(getWallShape(dir.getOpposite()))) @@ -160,23 +154,22 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock { if (Direction.Type.HORIZONTAL.stream().allMatch(dir -> state.get(getWallShape(dir)) == WallShape.NONE)) return true; - // tall Matching sides + // Matching sides if (Stream.of(Direction.SOUTH, Direction.EAST) .anyMatch(dir -> - state.get(getWallShape(dir)) == WallShape.TALL - && state.get(getWallShape(dir.getOpposite())) == WallShape.TALL + state.get(getWallShape(dir)) == state.get(getWallShape(dir.getOpposite())) )) return false; return top_state.isIn(BlockTags.WALL_POST_OVERRIDE) || top_shape == null || shouldUseTall(WALL_VOXELS[0], top_shape); } - private static boolean shouldConnectTo(BlockState state, boolean side_full, Direction side) { + public static boolean shouldConnectTo(BlockState state, boolean side_full, Direction side) { Block block = state.getBlock(); boolean bl = block instanceof FenceGateBlock && FenceGateBlock.canWallConnect(state, side); return state.isIn(BlockTags.WALLS) || !WallBlock.cannotConnect(state) && side_full || block instanceof PaneBlock || bl; } - private static boolean shouldUseTall(VoxelShape self_shape, VoxelShape other_shape) { + public static boolean shouldUseTall(VoxelShape self_shape, VoxelShape other_shape) { return !VoxelShapes.matchesAnywhere( self_shape, other_shape, @@ -184,7 +177,7 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock { ); } - private static Property getWallShape(Direction dir) { + public static Property getWallShape(Direction dir) { return switch (dir) { case EAST -> EAST_WALL_SHAPE; case NORTH -> NORTH_WALL_SHAPE; diff --git a/src/main/java/fr/adrien1106/reframed/client/ReFramedClient.java b/src/main/java/fr/adrien1106/reframed/client/ReFramedClient.java index 3ea82e9..a4a8520 100644 --- a/src/main/java/fr/adrien1106/reframed/client/ReFramedClient.java +++ b/src/main/java/fr/adrien1106/reframed/client/ReFramedClient.java @@ -14,10 +14,6 @@ import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; import net.minecraft.util.math.ChunkSectionPos; -import static fr.adrien1106.reframed.util.blocks.BlockProperties.*; -import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE; -import static net.minecraft.state.property.Properties.*; - public class ReFramedClient implements ClientModInitializer { public static final ReFramedModelProvider PROVIDER = new ReFramedModelProvider(); @@ -31,92 +27,109 @@ public class ReFramedClient implements ClientModInitializer { BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), ReFramed.BLOCKS.toArray(new Block[0])); // CUBE - HELPER.addReFramedModel("cube" , HELPER.auto(new Identifier("block/cube"), 2)); + HELPER.addReFramedModel("cube" , HELPER.auto(new Identifier("block/cube"))); // SMALL_CUBE - HELPER.addReFramedModel("small_cube" , HELPER.auto(ReFramed.id("block/small_cube/base"), 9, CORNER)); + HELPER.addReFramedModel("small_cube" , HELPER.auto(ReFramed.id("block/small_cube/base"))); // SMALL_CUBES_STEP - HELPER.addReFramedModel("small_cubes_step" , HELPER.autoDouble(ReFramed.id("block/small_cube/base"), ReFramed.id("block/small_cube/step/base"), 9, EDGE)); - HELPER.addReFramedModel("small_cubes_step_reverse" , HELPER.autoDouble(ReFramed.id("block/small_cube/step/base"), ReFramed.id("block/small_cube/base"), 4, EDGE)); + HELPER.addReFramedModel("small_cubes_step" , HELPER.autoDouble(ReFramed.id("block/small_cube/base"), ReFramed.id("block/small_cube/step/base"))); + HELPER.addReFramedModel("small_cubes_step_reverse" , HELPER.autoDouble(ReFramed.id("block/small_cube/step/base"), ReFramed.id("block/small_cube/base"))); // SLAB - HELPER.addReFramedModel("slab" , HELPER.auto(new Identifier("block/slab"), 7, FACING)); + HELPER.addReFramedModel("slab" , HELPER.auto(new Identifier("block/slab"))); // SLAB_CUBE - HELPER.addReFramedModel("double_slab" , HELPER.autoDouble(new Identifier("block/slab"), new Identifier("block/slab_top"), 4, AXIS)); + HELPER.addReFramedModel("double_slab" , HELPER.autoDouble(new Identifier("block/slab"), new Identifier("block/slab_top"))); // STAIR - HELPER.addReFramedModel("stair" , HELPER.auto(ReFramed.id("block/stair/straight"), 13, EDGE)); - HELPER.addReFramedModel("outers_stair" , HELPER.auto(ReFramed.id("block/stair/double_outer"), 24, EDGE, STAIR_SHAPE)); - HELPER.addReFramedModel("inner_stair" , HELPER.auto(ReFramed.id("block/stair/inner"), 24, EDGE, STAIR_SHAPE)); - HELPER.addReFramedModel("outer_stair" , HELPER.auto(ReFramed.id("block/stair/outer"), 16, EDGE, STAIR_SHAPE)); - HELPER.addReFramedModel("outer_side_stair" , HELPER.auto(ReFramed.id("block/stair/outer_side"), 32, EDGE, STAIR_SHAPE)); + HELPER.addReFramedModel("stair" , HELPER.auto(ReFramed.id("block/stair/straight"))); + HELPER.addReFramedModel("outers_stair" , HELPER.auto(ReFramed.id("block/stair/double_outer"))); + HELPER.addReFramedModel("inner_stair" , HELPER.auto(ReFramed.id("block/stair/inner"))); + HELPER.addReFramedModel("outer_stair" , HELPER.auto(ReFramed.id("block/stair/outer"))); + HELPER.addReFramedModel("outer_side_stair" , HELPER.auto(ReFramed.id("block/stair/outer_side"))); // STAIRS_CUBE - HELPER.addReFramedModel("stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/straight"), ReFramed.id("block/stair/cube/straight"), 13, EDGE)); - HELPER.addReFramedModel("outers_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/double_outer"), ReFramed.id("block/stair/cube/double_outer"), 24, EDGE, STAIR_SHAPE)); - HELPER.addReFramedModel("inner_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/inner"), ReFramed.id("block/stair/cube/inner"), 24, EDGE, STAIR_SHAPE)); - HELPER.addReFramedModel("outer_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/outer"), ReFramed.id("block/stair/cube/outer"), 16, EDGE, STAIR_SHAPE)); - HELPER.addReFramedModel("outer_side_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/outer_side"), ReFramed.id("block/stair/cube/outer_side"), 32, EDGE, STAIR_SHAPE)); + HELPER.addReFramedModel("stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/straight"), ReFramed.id("block/stair/cube/straight"))); + HELPER.addReFramedModel("outers_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/double_outer"), ReFramed.id("block/stair/cube/double_outer"))); + HELPER.addReFramedModel("inner_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/inner"), ReFramed.id("block/stair/cube/inner"))); + HELPER.addReFramedModel("outer_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/outer"), ReFramed.id("block/stair/cube/outer"))); + HELPER.addReFramedModel("outer_side_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/outer_side"), ReFramed.id("block/stair/cube/outer_side"))); // HALF_STAIR - HELPER.addReFramedModel("half_stair_down" , HELPER.auto(ReFramed.id("block/half_stair/down"), 9, CORNER, CORNER_FACE)); - HELPER.addReFramedModel("half_stair_side" , HELPER.auto(ReFramed.id("block/half_stair/side"), 16, CORNER, CORNER_FACE)); + HELPER.addReFramedModel("half_stair_down" , HELPER.auto(ReFramed.id("block/half_stair/down"))); + HELPER.addReFramedModel("half_stair_side" , HELPER.auto(ReFramed.id("block/half_stair/side"))); // HALF_STAIRS_SLAB - HELPER.addReFramedModel("half_stairs_slab_down" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/slab/down"), 9, CORNER, CORNER_FACE)); - HELPER.addReFramedModel("half_stairs_slab_side" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/slab/side"), 16, CORNER, CORNER_FACE)); + HELPER.addReFramedModel("half_stairs_slab_down" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/slab/down"))); + HELPER.addReFramedModel("half_stairs_slab_side" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/slab/side"))); // HALF_STAIRS_STAIR - HELPER.addReFramedModel("half_stairs_stair_down" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/stair/down"), 5, EDGE)); - HELPER.addReFramedModel("half_stairs_stair_side" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/stair/side"), 6, EDGE)); - HELPER.addReFramedModel("half_stairs_stair_reverse" , HELPER.autoDouble(ReFramed.id("block/half_stair/stair/side"), ReFramed.id("block/half_stair/side"), 2, EDGE)); + HELPER.addReFramedModel("half_stairs_stair_down" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/stair/down"))); + HELPER.addReFramedModel("half_stairs_stair_side" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/stair/side"))); + HELPER.addReFramedModel("half_stairs_stair_reverse" , HELPER.autoDouble(ReFramed.id("block/half_stair/stair/side"), ReFramed.id("block/half_stair/side"))); // STEP - HELPER.addReFramedModel("step" , HELPER.auto(ReFramed.id("block/step/down"), 13, EDGE)); + HELPER.addReFramedModel("step" , HELPER.auto(ReFramed.id("block/step/down"))); // STEPS_SLAB - HELPER.addReFramedModel("steps_slab" , HELPER.autoDouble(ReFramed.id("block/step/down"), ReFramed.id("block/step/slab/down"), 5, FACING, AXIS)); - HELPER.addReFramedModel("steps_slab_side" , HELPER.autoDouble(ReFramed.id("block/step/side"), ReFramed.id("block/step/slab/side"), 8, FACING, AXIS)); + HELPER.addReFramedModel("steps_slab" , HELPER.autoDouble(ReFramed.id("block/step/down"), ReFramed.id("block/step/slab/down"))); + HELPER.addReFramedModel("steps_slab_side" , HELPER.autoDouble(ReFramed.id("block/step/side"), ReFramed.id("block/step/slab/side"))); // LAYER - HELPER.addReFramedModel("layer_1" , HELPER.auto(new Identifier("block/snow_height2"), 7, FACING)); - HELPER.addReFramedModel("layer_2" , HELPER.auto(new Identifier("block/snow_height4"), 6, FACING)); - HELPER.addReFramedModel("layer_3" , HELPER.auto(new Identifier("block/snow_height6"), 6, FACING)); - HELPER.addReFramedModel("layer_4" , HELPER.auto(new Identifier("block/snow_height8"), 6, FACING)); - HELPER.addReFramedModel("layer_5" , HELPER.auto(new Identifier("block/snow_height10"), 6, FACING)); - HELPER.addReFramedModel("layer_6" , HELPER.auto(new Identifier("block/snow_height12"), 6, FACING)); - HELPER.addReFramedModel("layer_7" , HELPER.auto(new Identifier("block/snow_height14"), 6, FACING)); - HELPER.addReFramedModel("layer_8" , HELPER.auto(new Identifier("block/cube"), 1)); + HELPER.addReFramedModel("layer_1" , HELPER.auto(new Identifier("block/snow_height2"))); + HELPER.addReFramedModel("layer_2" , HELPER.auto(new Identifier("block/snow_height4"))); + HELPER.addReFramedModel("layer_3" , HELPER.auto(new Identifier("block/snow_height6"))); + HELPER.addReFramedModel("layer_4" , HELPER.auto(new Identifier("block/snow_height8"))); + HELPER.addReFramedModel("layer_5" , HELPER.auto(new Identifier("block/snow_height10"))); + HELPER.addReFramedModel("layer_6" , HELPER.auto(new Identifier("block/snow_height12"))); + HELPER.addReFramedModel("layer_7" , HELPER.auto(new Identifier("block/snow_height14"))); + HELPER.addReFramedModel("layer_8" , HELPER.auto(new Identifier("block/cube"))); // PILLAR - HELPER.addReFramedModel("pillar" , HELPER.auto(ReFramed.id("block/pillar"), 4, AXIS)); + HELPER.addReFramedModel("pillar" , HELPER.auto(ReFramed.id("block/pillar"))); // WALL - HELPER.addReFramedModel("wall_inventory" , HELPER.auto(ReFramed.id("block/wall/inventory/default"), 1)); + HELPER.addReFramedModel("wall_inventory" , HELPER.auto(ReFramed.id("block/wall/inventory/default"))); // --------------------- pillar - HELPER.addReFramedModel("wall_core" , HELPER.auto(ReFramed.id("block/wall/pillar/core"), 1, UP)); - HELPER.addReFramedModel("wall_pillar_low" , HELPER.auto(ReFramed.id("block/wall/pillar/low"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_pillar_tall" , HELPER.auto(ReFramed.id("block/wall/pillar/tall"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_pillar_none" , HELPER.auto(ReFramed.id("block/wall/pillar/none"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); + HELPER.addReFramedModel("wall_core" , HELPER.auto(ReFramed.id("block/wall/pillar/core"))); + HELPER.addReFramedModel("wall_pillar_low" , HELPER.auto(ReFramed.id("block/wall/pillar/low"))); + HELPER.addReFramedModel("wall_pillar_tall" , HELPER.auto(ReFramed.id("block/wall/pillar/tall"))); + HELPER.addReFramedModel("wall_pillar_none" , HELPER.auto(ReFramed.id("block/wall/pillar/none"))); // --------------------- side - HELPER.addReFramedModel("wall_side_low" , HELPER.auto(ReFramed.id("block/wall/side/low"), 92, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_side_tall" , HELPER.auto(ReFramed.id("block/wall/side/tall"), 92, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); + HELPER.addReFramedModel("wall_side_low" , HELPER.auto(ReFramed.id("block/wall/side/low"))); + HELPER.addReFramedModel("wall_side_tall" , HELPER.auto(ReFramed.id("block/wall/side/tall"))); // --------------------- junction - HELPER.addReFramedModel("wall_low_e" , HELPER.auto(ReFramed.id("block/wall/junction/low"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_e" , HELPER.auto(ReFramed.id("block/wall/junction/tall"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); + HELPER.addReFramedModel("wall_low_e" , HELPER.auto(ReFramed.id("block/wall/junction/low"))); + HELPER.addReFramedModel("wall_tall_e" , HELPER.auto(ReFramed.id("block/wall/junction/tall"))); // --------------------- junction_i - HELPER.addReFramedModel("wall_low_i" , HELPER.auto(ReFramed.id("block/wall/junction/low_i"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_i" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_low_tall_i" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_i"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); + HELPER.addReFramedModel("wall_low_i" , HELPER.auto(ReFramed.id("block/wall/junction/low_i"))); + HELPER.addReFramedModel("wall_tall_i" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i"))); + HELPER.addReFramedModel("wall_low_tall_i" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_i"))); // --------------------- junction_c - HELPER.addReFramedModel("wall_low_c" , HELPER.auto(ReFramed.id("block/wall/junction/low_c"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_c" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_low_tall_c" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_c"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_low_c" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_c"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); + HELPER.addReFramedModel("wall_low_c" , HELPER.auto(ReFramed.id("block/wall/junction/low_c"))); + HELPER.addReFramedModel("wall_tall_c" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c"))); + HELPER.addReFramedModel("wall_low_tall_c" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_c"))); + HELPER.addReFramedModel("wall_tall_low_c" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_c"))); // --------------------- junction_t - HELPER.addReFramedModel("wall_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_t"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_t"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_low_c_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_c_t"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_i_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i_low_t"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_low_i_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_i_tall_t"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_low_tall_c_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_c_t"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_low_c_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_c_tall_t"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_c_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c_low_t"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); + HELPER.addReFramedModel("wall_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_t"))); + HELPER.addReFramedModel("wall_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_t"))); + HELPER.addReFramedModel("wall_tall_low_c_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_c_t"))); + HELPER.addReFramedModel("wall_tall_i_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i_low_t"))); + HELPER.addReFramedModel("wall_low_i_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_i_tall_t"))); + HELPER.addReFramedModel("wall_low_tall_c_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_c_t"))); + HELPER.addReFramedModel("wall_low_c_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_c_tall_t"))); + HELPER.addReFramedModel("wall_tall_c_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c_low_t"))); // --------------------- junction_x - HELPER.addReFramedModel("wall_low_x" , HELPER.auto(ReFramed.id("block/wall/junction/low_x"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_x"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_i_low_i_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i_low_i_x"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_low_t_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_t_x"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_c_low_c_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c_low_c_x"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); - HELPER.addReFramedModel("wall_tall_t_low_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_t_low_x"), 4, NORTH_WALL_SHAPE, EAST_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE)); + HELPER.addReFramedModel("wall_low_x" , HELPER.auto(ReFramed.id("block/wall/junction/low_x"))); + HELPER.addReFramedModel("wall_tall_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_x"))); + HELPER.addReFramedModel("wall_tall_i_low_i_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i_low_i_x"))); + HELPER.addReFramedModel("wall_tall_low_t_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_t_x"))); + HELPER.addReFramedModel("wall_tall_c_low_c_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c_low_c_x"))); + HELPER.addReFramedModel("wall_tall_t_low_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_t_low_x"))); + // PILLAR WALL + HELPER.addReFramedModel("pillars_wall_inventory" , HELPER.autoDouble(ReFramed.id("block/pillar"), ReFramed.id("block/wall/full/inventory/sides"))); + HELPER.addReFramedModel("pillars_wall_low" , HELPER.autoDouble(ReFramed.id("block/wall/full/pillar/low"), ReFramed.id("block/wall/full/side/low"))); + HELPER.addReFramedModel("pillars_wall_tall" , HELPER.autoDouble(ReFramed.id("block/wall/full/pillar/tall"), ReFramed.id("block/wall/full/side/tall"))); + // PANE + HELPER.addReFramedModel("pane_inventory" , HELPER.auto(ReFramed.id("block/pane"))); + HELPER.addReFramedModel("pane_post" , HELPER.auto(new Identifier("block/glass_pane_post"))); + HELPER.addReFramedModel("pane_side" , HELPER.auto(new Identifier("block/glass_pane_side"))); + HELPER.addReFramedModel("pane_side_alt" , HELPER.auto(new Identifier("block/glass_pane_side_alt"))); + HELPER.addReFramedModel("pane_noside" , HELPER.auto(new Identifier("block/glass_pane_noside"))); + HELPER.addReFramedModel("pane_noside_alt" , HELPER.auto(new Identifier("block/glass_pane_noside_alt"))); + // TRAPDOOR + HELPER.addReFramedModel("trapdoor_open" , HELPER.auto(new Identifier("block/oak_trapdoor_open"))); + HELPER.addReFramedModel("trapdoor_bottom" , HELPER.auto(new Identifier("block/oak_trapdoor_bottom"))); + HELPER.addReFramedModel("trapdoor_top" , HELPER.auto(new Identifier("block/oak_trapdoor_top"))); + // DOOR + HELPER.addReFramedModel("door_inventory" , HELPER.auto(ReFramed.id("block/door"))); //item model assignments (in lieu of models/item/___.json) @@ -134,11 +147,15 @@ public class ReFramedClient implements ClientModInitializer { HELPER.assignItemModel("steps_slab" , ReFramed.STEPS_SLAB); HELPER.assignItemModel("layer_1" , ReFramed.LAYER); HELPER.assignItemModel("pillar" , ReFramed.PILLAR); + HELPER.assignItemModel("pillars_wall_inventory", ReFramed.PILLARS_WALL); HELPER.assignItemModel("wall_inventory" , ReFramed.WALL); + HELPER.assignItemModel("pane_inventory" , ReFramed.PANE); + HELPER.assignItemModel("trapdoor_bottom" , ReFramed.TRAPDOOR); + HELPER.assignItemModel("door_inventory" , ReFramed.DOOR); } private void privateInit() { - //set up some magic to force chunk rerenders when you change a template (see TemplateEntity) + //set up some magic to force chunk re-renders when you change a template (see TemplateEntity) ReFramed.chunkRerenderProxy = (world, pos) -> { if(world == MinecraftClient.getInstance().world) { MinecraftClient.getInstance().worldRenderer.scheduleBlockRender( diff --git a/src/main/java/fr/adrien1106/reframed/client/ReFramedClientHelper.java b/src/main/java/fr/adrien1106/reframed/client/ReFramedClientHelper.java index 547771e..a63b269 100644 --- a/src/main/java/fr/adrien1106/reframed/client/ReFramedClientHelper.java +++ b/src/main/java/fr/adrien1106/reframed/client/ReFramedClientHelper.java @@ -13,7 +13,6 @@ import net.minecraft.client.render.model.UnbakedModel; import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.SpriteIdentifier; import net.minecraft.item.ItemConvertible; -import net.minecraft.state.property.Property; import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; @@ -28,18 +27,18 @@ public class ReFramedClientHelper { private final ReFramedModelProvider prov; - public UnbakedRetexturedModel auto(Identifier parent, int model_count, Property... properties) { - return new UnbakedAutoRetexturedModel(parent, model_count, properties); + public UnbakedRetexturedModel auto(Identifier parent) { + return new UnbakedAutoRetexturedModel(parent); } - public UnbakedRetexturedModel json(Identifier parent, int model_count, Property... properties) { - return new UnbakedJsonRetexturedModel(parent, model_count, properties); + public UnbakedRetexturedModel json(Identifier parent) { + return new UnbakedJsonRetexturedModel(parent); } - public UnbakedModel autoDouble(Identifier first, Identifier second, int model_count, Property... properties) { + public UnbakedModel autoDouble(Identifier first, Identifier second) { return new UnbakedDoubleRetexturedModel( - auto(first, model_count, properties), - auto(second, model_count, properties) + auto(first), + auto(second) ); } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/DoubleRetexturingBakedModel.java b/src/main/java/fr/adrien1106/reframed/client/model/DoubleRetexturingBakedModel.java index a50806c..c700b87 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/DoubleRetexturingBakedModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/DoubleRetexturingBakedModel.java @@ -17,8 +17,8 @@ import java.util.function.Supplier; @Environment(EnvType.CLIENT) public class DoubleRetexturingBakedModel extends ForwardingBakedModel implements MultiRetexturableModel { - private final ForwardingBakedModel model_1, model_2; - public DoubleRetexturingBakedModel(ForwardingBakedModel model_1, ForwardingBakedModel model_2) { + private final RetexturingBakedModel model_1, model_2; + public DoubleRetexturingBakedModel(RetexturingBakedModel model_1, RetexturingBakedModel model_2) { this.wrapped = model_1.getWrappedModel(); this.model_1 = model_1; this.model_2 = model_2; @@ -44,7 +44,7 @@ public class DoubleRetexturingBakedModel extends ForwardingBakedModel implements } @Override - public List models() { + public List models() { return List.of(model_1, model_2); } } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/MultiRetexturableModel.java b/src/main/java/fr/adrien1106/reframed/client/model/MultiRetexturableModel.java index 17ea436..f0e4a95 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/MultiRetexturableModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/MultiRetexturableModel.java @@ -1,10 +1,8 @@ package fr.adrien1106.reframed.client.model; -import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; - import java.util.List; public interface MultiRetexturableModel { - List models(); + List models(); } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/RetexturingBakedModel.java b/src/main/java/fr/adrien1106/reframed/client/model/RetexturingBakedModel.java index 9400b1a..fb1a218 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/RetexturingBakedModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/RetexturingBakedModel.java @@ -20,38 +20,28 @@ import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.ModelBakeSettings; import net.minecraft.client.texture.Sprite; import net.minecraft.item.ItemStack; -import net.minecraft.state.property.Property; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.random.Random; import net.minecraft.world.BlockRenderView; -import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; -import java.util.stream.Stream; public abstract class RetexturingBakedModel extends ForwardingBakedModel { - public RetexturingBakedModel(BakedModel base_model, CamoAppearanceManager tam, int theme_index, ModelBakeSettings settings, BlockState item_state, int model_count, Property... properties) { + public RetexturingBakedModel(BakedModel base_model, CamoAppearanceManager tam, int theme_index, ModelBakeSettings settings, BlockState item_state) { this.wrapped = base_model; //field from the superclass; vanilla getQuads etc. will delegate through to this this.appearance_manager = tam; this.theme_index = theme_index; this.uv_lock = settings.isUvLocked(); this.item_state = item_state; - this.properties = properties; - - BASE_MESH_CACHE = new Object2ObjectLinkedOpenHashMap<>(model_count, 0.25f) { - @Override - protected void rehash(int v) {} - }; } protected final CamoAppearanceManager appearance_manager; protected final int theme_index; protected final boolean uv_lock; protected final BlockState item_state; - protected final Property[] properties; protected record MeshCacheKey(Object state_key, CamoAppearance appearance, int model_id) {} /** cache that store retextured models */ @@ -59,7 +49,11 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel { protected final Cache RETEXTURED_MESH_CACHE = CacheBuilder.newBuilder().maximumSize(256).build(); /** cache that stores the base meshes which has the size of the amount of models */ - protected final Object2ObjectLinkedOpenHashMap BASE_MESH_CACHE; + protected final Object2ObjectLinkedOpenHashMap BASE_MESH_CACHE = + new Object2ObjectLinkedOpenHashMap<>(2, 0.25f) { + @Override + protected void rehash(int v) {} + }; protected static final Direction[] DIRECTIONS_AND_NULL; static { @@ -87,16 +81,19 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel { public Sprite getParticleSprite() { return appearance_manager.getDefaultAppearance(theme_index).getSprites(Direction.UP, 0).get(0).sprite(); } - + + public int getThemeIndex() { + return theme_index; + } + @Override public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { BlockState theme = (world.getBlockEntity(pos) instanceof ThemeableBlockEntity s) ? s.getTheme(theme_index) : null; QuadEmitter quad_emitter = context.getEmitter(); - List model_key = Stream.of(properties).map(state::get).toList(); if(theme == null || theme.isAir()) { getRetexturedMesh( new MeshCacheKey( - model_key, + hashCode(), appearance_manager.getDefaultAppearance(theme_index), 0 ), @@ -112,7 +109,7 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel { if (camo instanceof WeightedComputedAppearance wca) model_id = wca.getAppearanceIndex(seed); int tint = 0xFF000000 | MinecraftClient.getInstance().getBlockColors().getColor(theme, world, pos, 0); - MeshCacheKey key = new MeshCacheKey(model_key, camo, model_id); + MeshCacheKey key = new MeshCacheKey(hashCode(), camo, model_id); // do not clutter the cache with single-use meshes Mesh untintedMesh = camo.hashCode() == -1 ? transformMesh(key, state) : getRetexturedMesh(key, state); @@ -153,7 +150,14 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel { context.popTransform(); } } - + + public boolean useAmbientOcclusion(BlockRenderView view, BlockPos pos) { + if (!(view.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity)) return false; + CamoAppearance appearance = appearance_manager + .getCamoAppearance(view, frame_entity.getTheme(theme_index), pos, theme_index, false); + return appearance.getAO(theme_index); + } + protected Mesh getRetexturedMesh(MeshCacheKey key, BlockState state) { if (RETEXTURED_MESH_CACHE.asMap().containsKey(key)) return RETEXTURED_MESH_CACHE.getIfPresent(key); Mesh mesh = transformMesh(key, state); diff --git a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedAutoRetexturedModel.java b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedAutoRetexturedModel.java index ed0fcc1..3f2daee 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedAutoRetexturedModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedAutoRetexturedModel.java @@ -14,7 +14,6 @@ import net.minecraft.client.render.model.Baker; import net.minecraft.client.render.model.ModelBakeSettings; import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.SpriteIdentifier; -import net.minecraft.state.property.Property; import net.minecraft.util.Identifier; import net.minecraft.util.math.Direction; import net.minecraft.util.math.random.Random; @@ -24,8 +23,8 @@ import java.util.function.Function; public class UnbakedAutoRetexturedModel extends UnbakedRetexturedModel { - public UnbakedAutoRetexturedModel(Identifier parent, int state_count, Property... properties) { - super(parent, state_count, properties); + public UnbakedAutoRetexturedModel(Identifier parent) { + super(parent); item_state = Blocks.AIR.getDefaultState(); } @@ -37,9 +36,7 @@ public class UnbakedAutoRetexturedModel extends UnbakedRetexturedModel { ReFramedClient.HELPER.getCamoAppearanceManager(texture_getter), theme_index, bake_settings, - item_state, - state_count, - properties + item_state ) { protected Mesh convertModel(BlockState state) { Renderer r = ReFramedClient.HELPER.getFabricRenderer(); diff --git a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedDoubleRetexturedModel.java b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedDoubleRetexturedModel.java index 70d53d6..81244e0 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedDoubleRetexturedModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedDoubleRetexturedModel.java @@ -1,6 +1,5 @@ package fr.adrien1106.reframed.client.model; -import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.Baker; import net.minecraft.client.render.model.ModelBakeSettings; @@ -41,8 +40,8 @@ public class UnbakedDoubleRetexturedModel implements UnbakedModel { @Override public BakedModel bake(Baker baker, Function texture_getter, ModelBakeSettings model_bake_settings, Identifier identifier) { return new DoubleRetexturingBakedModel( - (ForwardingBakedModel) model_1.bake(baker, texture_getter, model_bake_settings, identifier), - (ForwardingBakedModel) model_2.bake(baker, texture_getter, model_bake_settings, identifier) + (RetexturingBakedModel) model_1.bake(baker, texture_getter, model_bake_settings, identifier), + (RetexturingBakedModel) model_2.bake(baker, texture_getter, model_bake_settings, identifier) ); } } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedJsonRetexturedModel.java b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedJsonRetexturedModel.java index 285f141..5dbe921 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedJsonRetexturedModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedJsonRetexturedModel.java @@ -15,7 +15,6 @@ import net.minecraft.client.render.model.ModelBakeSettings; import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.SpriteIdentifier; import net.minecraft.screen.PlayerScreenHandler; -import net.minecraft.state.property.Property; import net.minecraft.util.Identifier; import net.minecraft.util.math.Direction; import net.minecraft.util.math.random.Random; @@ -25,8 +24,8 @@ import java.util.Objects; import java.util.function.Function; public class UnbakedJsonRetexturedModel extends UnbakedRetexturedModel { - public UnbakedJsonRetexturedModel(Identifier parent, int state_count, Property... properties) { - super(parent, state_count, properties); + public UnbakedJsonRetexturedModel(Identifier parent) { + super(parent); } @Nullable @@ -45,9 +44,7 @@ public class UnbakedJsonRetexturedModel extends UnbakedRetexturedModel { ReFramedClient.HELPER.getCamoAppearanceManager(spriteLookup), theme_index, bake_settings, - item_state, - state_count, - properties + item_state ) { protected Mesh convertModel(BlockState state) { Renderer r = ReFramedClient.HELPER.getFabricRenderer(); diff --git a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedRetexturedModel.java b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedRetexturedModel.java index f60ac40..42d1f3c 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedRetexturedModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedRetexturedModel.java @@ -2,7 +2,6 @@ package fr.adrien1106.reframed.client.model; import net.minecraft.block.BlockState; import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.state.property.Property; import net.minecraft.util.Identifier; import java.util.Collection; @@ -15,13 +14,9 @@ public abstract class UnbakedRetexturedModel implements UnbakedModel { protected int theme_index = 1; protected BlockState item_state; - protected final int state_count; - protected final Property[] properties; - public UnbakedRetexturedModel(Identifier parent, int state_count, Property... properties) { + public UnbakedRetexturedModel(Identifier parent) { this.parent = parent; - this.state_count = state_count; - this.properties = properties; } public UnbakedRetexturedModel setThemeIndex(int theme_index) { diff --git a/src/main/java/fr/adrien1106/reframed/client/util/RenderHelper.java b/src/main/java/fr/adrien1106/reframed/client/util/RenderHelper.java index 12a4481..a881b7d 100644 --- a/src/main/java/fr/adrien1106/reframed/client/util/RenderHelper.java +++ b/src/main/java/fr/adrien1106/reframed/client/util/RenderHelper.java @@ -5,6 +5,7 @@ import com.google.common.cache.CacheBuilder; import fr.adrien1106.reframed.block.ReFramedBlock; import fr.adrien1106.reframed.client.ReFramedClient; import fr.adrien1106.reframed.client.model.QuadPosBounds; +import fr.adrien1106.reframed.client.model.RetexturingBakedModel; import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -32,18 +33,18 @@ import static net.minecraft.util.shape.VoxelShapes.combine; public class RenderHelper { // self culling cache of the models not made thread local so that it is only computed once - private static final Cache INNER_CULL_MAP = CacheBuilder.newBuilder().maximumSize(1024).build(); - private record CullElement(Block block, Object state_key, int model) {} + private static final Cache INNER_CULL_MAP = CacheBuilder.newBuilder().build(); + private record CullElement(Block block, Object state_key, int model) { } /** * compute which quad might cull with another model quad - * @param state - the state of the model + * @param state - the state of the model * @param models - list of models on the same block + * @param hash - the hash of main model */ - public static void computeInnerCull(BlockState state, List models) { + public static void computeInnerCull(BlockState state, List models, int hash) { if (!(state.getBlock() instanceof ReFramedBlock frame_block)) return; - Object key = frame_block.getModelCacheKey(state); - if (INNER_CULL_MAP.asMap().containsKey(new CullElement(frame_block, key, 1))) return; + if (INNER_CULL_MAP.asMap().containsKey(new CullElement(frame_block, hash, 1))) return; Renderer r = ReFramedClient.HELPER.getFabricRenderer(); QuadEmitter quad_emitter = r.meshBuilder().getEmitter(); @@ -60,12 +61,12 @@ public class RenderHelper { }).toList()).toList(); Integer[] cull_array; - for(int self_id = 1; self_id <= model_bounds.size(); self_id++) { + for (int self_id = 1; self_id <= model_bounds.size(); self_id++) { List self_bounds = model_bounds.get(self_id - 1); cull_array = new Integer[self_bounds.size()]; for (int self_quad = 0; self_quad < cull_array.length; self_quad++) { QuadPosBounds self_bound = self_bounds.get(self_quad); - for(int other_id = 1; other_id <= model_bounds.size(); other_id++) { + for (int other_id = 1; other_id <= model_bounds.size(); other_id++) { if (other_id == self_id) continue; if (model_bounds.get(other_id - 1).stream().anyMatch(other_bound -> other_bound.equals(self_bound))) { cull_array[self_quad] = other_id; @@ -73,15 +74,15 @@ public class RenderHelper { } } } - INNER_CULL_MAP.put(new CullElement(frame_block, key, self_id), cull_array); + INNER_CULL_MAP.put(new CullElement(frame_block, hash, self_id), cull_array); } } - public static boolean shouldDrawInnerFace(BlockState state, BlockRenderView view, BlockPos pos, int quad_index, int theme_index) { - if ( !(state.getBlock() instanceof ReFramedBlock frame_block) + public static boolean shouldDrawInnerFace(BlockState state, BlockRenderView view, BlockPos pos, int quad_index, int theme_index, int hash) { + if (!(state.getBlock() instanceof ReFramedBlock frame_block) || !(view.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity) ) return true; - CullElement key = new CullElement(frame_block, frame_block.getModelCacheKey(state), theme_index); + CullElement key = new CullElement(frame_block, hash, theme_index); if (!INNER_CULL_MAP.asMap().containsKey(key)) return true; // needs to be Integer object because array is initialized with null not 0 diff --git a/src/main/java/fr/adrien1106/reframed/compat/RebakedModel.java b/src/main/java/fr/adrien1106/reframed/compat/RebakedModel.java index cb5c54c..7f6524b 100644 --- a/src/main/java/fr/adrien1106/reframed/compat/RebakedModel.java +++ b/src/main/java/fr/adrien1106/reframed/compat/RebakedModel.java @@ -14,9 +14,11 @@ import java.util.Map; public class RebakedModel implements BakedModel { protected final Map> face_quads; + protected boolean ambient_occlusion; - public RebakedModel(Map> face_quads) { + public RebakedModel(Map> face_quads, boolean ambient_occlusion) { this.face_quads = face_quads; + this.ambient_occlusion = ambient_occlusion; } @Override @@ -26,7 +28,7 @@ public class RebakedModel implements BakedModel { @Override public boolean useAmbientOcclusion() { - return true; + return ambient_occlusion; } @Override diff --git a/src/main/java/fr/adrien1106/reframed/generator/GBlockTag.java b/src/main/java/fr/adrien1106/reframed/generator/GBlockTag.java index 81aa5ac..cae2d8e 100644 --- a/src/main/java/fr/adrien1106/reframed/generator/GBlockTag.java +++ b/src/main/java/fr/adrien1106/reframed/generator/GBlockTag.java @@ -16,7 +16,9 @@ import java.util.concurrent.CompletableFuture; public class GBlockTag extends BlockTagProvider { private static final Map, TagGetter> providers = new HashMap<>(); static { - providers.put(ReframedWallBlock.class, new Wall()); + providers.put(ReFramedPillarsWallBlock.class, new PillarsWall()); + providers.put(ReFramedWallBlock.class, new Wall()); + providers.put(ReFramedPaneBlock.class, new Pane()); } public GBlockTag(FabricDataOutput output, CompletableFuture registries) { diff --git a/src/main/java/fr/adrien1106/reframed/generator/GBlockstate.java b/src/main/java/fr/adrien1106/reframed/generator/GBlockstate.java index 7fffe04..d111af5 100644 --- a/src/main/java/fr/adrien1106/reframed/generator/GBlockstate.java +++ b/src/main/java/fr/adrien1106/reframed/generator/GBlockstate.java @@ -32,7 +32,11 @@ public class GBlockstate extends FabricModelProvider { providers.put(ReFramedStairsCubeBlock.class, new StairsCube()); providers.put(ReFramedStepBlock.class, new Step()); providers.put(ReFramedStepsSlabBlock.class, new StepsSlab()); - providers.put(ReframedWallBlock.class, new Wall()); + providers.put(ReFramedPillarsWallBlock.class, new PillarsWall()); + providers.put(ReFramedWallBlock.class, new Wall()); + providers.put(ReFramedPaneBlock.class, new Pane()); + providers.put(ReFramedTrapdoorBlock.class, new Trapdoor()); + providers.put(ReFramedDoorBlock.class, new Door()); } public GBlockstate(FabricDataOutput output) { diff --git a/src/main/java/fr/adrien1106/reframed/generator/GRecipe.java b/src/main/java/fr/adrien1106/reframed/generator/GRecipe.java index c1fbbd6..7ac1beb 100644 --- a/src/main/java/fr/adrien1106/reframed/generator/GRecipe.java +++ b/src/main/java/fr/adrien1106/reframed/generator/GRecipe.java @@ -34,7 +34,11 @@ public class GRecipe extends FabricRecipeProvider { providers.put(ReFramedStairsCubeBlock.class, new StairsCube()); providers.put(ReFramedStepBlock.class, new Step()); providers.put(ReFramedStepsSlabBlock.class, new StepsSlab()); - providers.put(ReframedWallBlock.class, new Wall()); + providers.put(ReFramedPillarsWallBlock.class, new PillarsWall()); + providers.put(ReFramedWallBlock.class, new Wall()); + providers.put(ReFramedPaneBlock.class, new Pane()); + providers.put(ReFramedTrapdoorBlock.class, new Trapdoor()); + providers.put(ReFramedDoorBlock.class, new Door()); providers.put(ReFramedBlueprintItem.class, new Blueprint()); providers.put(ReFramedHammerItem.class, new Hammer()); providers.put(ReFramedScrewdriverItem.class, new Screwdriver()); diff --git a/src/main/java/fr/adrien1106/reframed/generator/block/Door.java b/src/main/java/fr/adrien1106/reframed/generator/block/Door.java new file mode 100644 index 0000000..81dc6e1 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/generator/block/Door.java @@ -0,0 +1,73 @@ +package fr.adrien1106.reframed.generator.block; + +import fr.adrien1106.reframed.ReFramed; +import fr.adrien1106.reframed.generator.BlockStateProvider; +import fr.adrien1106.reframed.generator.GBlockstate; +import fr.adrien1106.reframed.generator.RecipeSetter; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.minecraft.block.Block; +import net.minecraft.data.client.BlockStateSupplier; +import net.minecraft.data.client.MultipartBlockStateSupplier; +import net.minecraft.data.client.When; +import net.minecraft.data.server.recipe.RecipeExporter; +import net.minecraft.data.server.recipe.RecipeProvider; +import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder; +import net.minecraft.item.ItemConvertible; +import net.minecraft.recipe.book.RecipeCategory; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Direction; + +import static net.minecraft.block.enums.DoorHinge.*; +import static net.minecraft.data.client.VariantSettings.Rotation.*; +import static net.minecraft.state.property.Properties.*; + +public class Door implements RecipeSetter, BlockStateProvider { + + @Override + public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) { + RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 1); + ShapedRecipeJsonBuilder + .create(RecipeCategory.BUILDING_BLOCKS, convertible, 3) + .pattern("II") + .pattern("II") + .pattern("II") + .input('I', ReFramed.CUBE) + .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) + .criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible)) + .offerTo(exporter); + } + + @Override + public BlockStateSupplier getMultipart(Block block) { + Identifier door = ReFramed.id("trapdoor_open_special"); + return MultipartBlockStateSupplier.create(block) + // SOUTH + .with(When.anyOf( + GBlockstate.when(OPEN, false, HORIZONTAL_FACING, Direction.SOUTH), + GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.EAST, DOOR_HINGE, LEFT), + GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.WEST, DOOR_HINGE, RIGHT) + ), + GBlockstate.variant(door, true, R0, R0)) + // WEST + .with(When.anyOf( + GBlockstate.when(OPEN, false, HORIZONTAL_FACING, Direction.WEST), + GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.SOUTH, DOOR_HINGE, LEFT), + GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.NORTH, DOOR_HINGE, RIGHT) + ), + GBlockstate.variant(door, true, R0, R90)) + // NORTH + .with(When.anyOf( + GBlockstate.when(OPEN, false, HORIZONTAL_FACING, Direction.NORTH), + GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.WEST, DOOR_HINGE, LEFT), + GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.EAST, DOOR_HINGE, RIGHT) + ), + GBlockstate.variant(door, true, R0, R180)) + // EAST + .with(When.anyOf( + GBlockstate.when(OPEN, false, HORIZONTAL_FACING, Direction.EAST), + GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.NORTH, DOOR_HINGE, LEFT), + GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.SOUTH, DOOR_HINGE, RIGHT) + ), + GBlockstate.variant(door, true, R0, R270)); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/generator/block/Pane.java b/src/main/java/fr/adrien1106/reframed/generator/block/Pane.java new file mode 100644 index 0000000..38081d8 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/generator/block/Pane.java @@ -0,0 +1,76 @@ +package fr.adrien1106.reframed.generator.block; + +import fr.adrien1106.reframed.ReFramed; +import fr.adrien1106.reframed.generator.BlockStateProvider; +import fr.adrien1106.reframed.generator.GBlockstate; +import fr.adrien1106.reframed.generator.RecipeSetter; +import fr.adrien1106.reframed.generator.TagGetter; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.minecraft.block.Block; +import net.minecraft.data.client.BlockStateSupplier; +import net.minecraft.data.client.MultipartBlockStateSupplier; +import net.minecraft.data.server.recipe.RecipeExporter; +import net.minecraft.data.server.recipe.RecipeProvider; +import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder; +import net.minecraft.item.ItemConvertible; +import net.minecraft.recipe.book.RecipeCategory; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.util.Identifier; + +import java.util.List; + +import static net.minecraft.data.client.VariantSettings.Rotation.*; +import static net.minecraft.state.property.Properties.*; + +public class Pane implements RecipeSetter, TagGetter, BlockStateProvider { + + @Override + public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) { + RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 4); + ShapedRecipeJsonBuilder + .create(RecipeCategory.BUILDING_BLOCKS, convertible, 32) + .pattern("III") + .pattern("I I") + .pattern("III") + .input('I', ReFramed.CUBE) + .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) + .criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible)) + .offerTo(exporter); + } + + @Override + public List> getTags() { + return List.of(BlockTags.WALLS); + } + + @Override + public BlockStateSupplier getMultipart(Block block) { + Identifier + pane_side = ReFramed.id("pane_side_special"), + pane_side_alt = ReFramed.id("pane_side_alt_special"), + pane_noside = ReFramed.id("pane_noside_special"), + pane_noside_alt = ReFramed.id("pane_noside_alt_special"); + return MultipartBlockStateSupplier.create(block) + // PILLAR CORE + .with(GBlockstate.variant(ReFramed.id("pane_post_special"), true, R0, R0)) + // SIDE + .with(GBlockstate.when(NORTH, true), + GBlockstate.variant(pane_side, true, R0, R0)) + .with(GBlockstate.when(EAST, true), + GBlockstate.variant(pane_side, true, R0, R90)) + .with(GBlockstate.when(SOUTH, true), + GBlockstate.variant(pane_side_alt, true, R0, R0)) + .with(GBlockstate.when(WEST, true), + GBlockstate.variant(pane_side_alt, true, R0, R90)) + // NOSIDE + .with(GBlockstate.when(NORTH, false), + GBlockstate.variant(pane_noside, true, R0, R0)) + .with(GBlockstate.when(EAST, false), + GBlockstate.variant(pane_noside_alt, true, R0, R0)) + .with(GBlockstate.when(SOUTH, false), + GBlockstate.variant(pane_noside_alt, true, R0, R90)) + .with(GBlockstate.when(WEST, false), + GBlockstate.variant(pane_noside, true, R0, R270)); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/generator/block/PillarsWall.java b/src/main/java/fr/adrien1106/reframed/generator/block/PillarsWall.java new file mode 100644 index 0000000..3d11e61 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/generator/block/PillarsWall.java @@ -0,0 +1,82 @@ +package fr.adrien1106.reframed.generator.block; + +import fr.adrien1106.reframed.ReFramed; +import fr.adrien1106.reframed.generator.BlockStateProvider; +import fr.adrien1106.reframed.generator.GBlockstate; +import fr.adrien1106.reframed.generator.RecipeSetter; +import fr.adrien1106.reframed.generator.TagGetter; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.minecraft.block.Block; +import net.minecraft.data.client.BlockStateSupplier; +import net.minecraft.data.client.MultipartBlockStateSupplier; +import net.minecraft.data.server.recipe.RecipeExporter; +import net.minecraft.data.server.recipe.RecipeProvider; +import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder; +import net.minecraft.item.ItemConvertible; +import net.minecraft.recipe.book.RecipeCategory; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.util.Identifier; + +import java.util.List; + +import static net.minecraft.block.enums.WallShape.*; +import static net.minecraft.data.client.VariantSettings.Rotation.*; +import static net.minecraft.state.property.Properties.*; + +public class PillarsWall implements RecipeSetter, TagGetter, BlockStateProvider { + + @Override + public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) { + RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 1); + ShapelessRecipeJsonBuilder + .create(RecipeCategory.BUILDING_BLOCKS, convertible, 2) + .input(ReFramed.WALL, 2) + .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) + .criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible)) + .offerTo(exporter); + } + + @Override + public List> getTags() { + return List.of(BlockTags.WALLS); + } + + @Override + public BlockStateSupplier getMultipart(Block block) { + Identifier + low = ReFramed.id("pillars_wall_low_special"), + tall = ReFramed.id("pillars_wall_tall_special"), + none = ReFramed.id("wall_pillar_none_special"); + return MultipartBlockStateSupplier.create(block) + // PILLAR CORE + .with(GBlockstate.variant(ReFramed.id("wall_core_special"), true, R0, R0)) + // LOW + .with(GBlockstate.when(NORTH_WALL_SHAPE, LOW), + GBlockstate.variant(low, true, R0, R0)) + .with(GBlockstate.when(EAST_WALL_SHAPE, LOW), + GBlockstate.variant(low, true, R0, R90)) + .with(GBlockstate.when(SOUTH_WALL_SHAPE, LOW), + GBlockstate.variant(low, true, R0, R180)) + .with(GBlockstate.when(WEST_WALL_SHAPE, LOW), + GBlockstate.variant(low, true, R0, R270)) + // TALL + .with(GBlockstate.when(NORTH_WALL_SHAPE, TALL), + GBlockstate.variant(tall, true, R0, R0)) + .with(GBlockstate.when(EAST_WALL_SHAPE, TALL), + GBlockstate.variant(tall, true, R0, R90)) + .with(GBlockstate.when(SOUTH_WALL_SHAPE, TALL), + GBlockstate.variant(tall, true, R0, R180)) + .with(GBlockstate.when(WEST_WALL_SHAPE, TALL), + GBlockstate.variant(tall, true, R0, R270)) + // PILLAR NONE + .with(GBlockstate.when(NORTH_WALL_SHAPE, NONE), + GBlockstate.variant(none, true, R0, R0)) + .with(GBlockstate.when(EAST_WALL_SHAPE, NONE), + GBlockstate.variant(none, true, R0, R90)) + .with(GBlockstate.when(SOUTH_WALL_SHAPE, NONE), + GBlockstate.variant(none, true, R0, R180)) + .with(GBlockstate.when(WEST_WALL_SHAPE, NONE), + GBlockstate.variant(none, true, R0, R270)); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/generator/block/Trapdoor.java b/src/main/java/fr/adrien1106/reframed/generator/block/Trapdoor.java new file mode 100644 index 0000000..50d4689 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/generator/block/Trapdoor.java @@ -0,0 +1,56 @@ +package fr.adrien1106.reframed.generator.block; + +import fr.adrien1106.reframed.ReFramed; +import fr.adrien1106.reframed.generator.BlockStateProvider; +import fr.adrien1106.reframed.generator.GBlockstate; +import fr.adrien1106.reframed.generator.RecipeSetter; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.minecraft.block.Block; +import net.minecraft.block.enums.BlockHalf; +import net.minecraft.data.client.BlockStateSupplier; +import net.minecraft.data.client.MultipartBlockStateSupplier; +import net.minecraft.data.server.recipe.RecipeExporter; +import net.minecraft.data.server.recipe.RecipeProvider; +import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder; +import net.minecraft.item.ItemConvertible; +import net.minecraft.recipe.book.RecipeCategory; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Direction; + +import static net.minecraft.data.client.VariantSettings.Rotation.*; +import static net.minecraft.state.property.Properties.*; + +public class Trapdoor implements RecipeSetter, BlockStateProvider { + + @Override + public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) { + RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2); + ShapedRecipeJsonBuilder + .create(RecipeCategory.BUILDING_BLOCKS, convertible, 2) + .pattern(" I") + .pattern("III") + .pattern("II ") + .input('I', ReFramed.CUBE) + .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) + .criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible)) + .offerTo(exporter); + } + + @Override + public BlockStateSupplier getMultipart(Block block) { + Identifier open = ReFramed.id("trapdoor_open_special"); + return MultipartBlockStateSupplier.create(block) + .with(GBlockstate.when(OPEN, false, BLOCK_HALF, BlockHalf.BOTTOM), + GBlockstate.variant(ReFramed.id("trapdoor_bottom_special"), true, R0, R0)) + .with(GBlockstate.when(OPEN, false, BLOCK_HALF, BlockHalf.TOP), + GBlockstate.variant(ReFramed.id("trapdoor_top_special"), true, R0, R0)) + .with(GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.NORTH), + GBlockstate.variant(open, true, R0, R0)) + .with(GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.EAST), + GBlockstate.variant(open, true, R0, R90)) + .with(GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.SOUTH), + GBlockstate.variant(open, true, R0, R180)) + .with(GBlockstate.when(OPEN, true, HORIZONTAL_FACING, Direction.WEST), + GBlockstate.variant(open, true, R0, R270)); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaBakedModelMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaBakedModelMixin.java index 20bd2f4..d2ab335 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaBakedModelMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaBakedModelMixin.java @@ -32,6 +32,8 @@ public abstract class AthenaBakedModelMixin implements DynamicBakedModel, BakedM @Shadow(remap = false) @Final private Int2ObjectMap textures; + @Shadow public abstract boolean useAmbientOcclusion(); + /** * Reuses the emitQuad method to compute the quads to be used by the frame * @@ -77,6 +79,6 @@ public abstract class AthenaBakedModelMixin implements DynamicBakedModel, BakedM })); }); - return new RebakedModel(face_quads); + return new RebakedModel(face_quads, useAmbientOcclusion()); } } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/ContinuityCTMBakedModelMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/ContinuityCTMBakedModelMixin.java index 4add74d..2c10205 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/compat/ContinuityCTMBakedModelMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/ContinuityCTMBakedModelMixin.java @@ -89,6 +89,6 @@ public abstract class ContinuityCTMBakedModelMixin extends ForwardingBakedModel transform.getProcessingContext().reset(); // reset instead of outputting to emitter transform.invokeReset(); - return new RebakedModel(face_quads); + return new RebakedModel(face_quads, useAmbientOcclusion()); } } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumAbstractBlockRenderContextMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumAbstractBlockRenderContextMixin.java index 4490579..88e8900 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumAbstractBlockRenderContextMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumAbstractBlockRenderContextMixin.java @@ -24,6 +24,6 @@ public abstract class IndiumAbstractBlockRenderContextMixin { private boolean shouldDrawInnerQuad(AbstractBlockRenderContext instance, Direction face, @Local(argsOnly = true) MutableQuadViewImpl quad) { if (face != null || quad.tag() == 0 || !(blockInfo instanceof IBlockRenderInfoMixin info) || info.getThemeIndex() == 0) return isFaceCulled(face); - return !RenderHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex()); + return !RenderHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex(), info.getModelHash()); } } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainBlockRenderInfoMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainBlockRenderInfoMixin.java index 2e95fde..2e925c5 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainBlockRenderInfoMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainBlockRenderInfoMixin.java @@ -19,6 +19,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo implements IBlockRenderInfoMixin { @Unique private int theme_index = 0; + @Unique private int model_hash = 0; @Redirect( method = "shouldDrawFaceInner", @@ -36,8 +37,9 @@ public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo } @Override - public void prepareForBlock(BlockState blockState, BlockPos blockPos, long seed, boolean modelAo, int theme_index) { + public void prepareForBlock(BlockState blockState, BlockPos blockPos, long seed, boolean modelAo, int theme_index, int model_hash) { this.theme_index = theme_index; + this.model_hash = model_hash; prepareForBlock(blockState, blockPos, seed, modelAo); } @@ -45,4 +47,9 @@ public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo public int getThemeIndex() { return theme_index; } + + @Override + public int getModelHash() { + return model_hash; + } } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainRenderContextMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainRenderContextMixin.java index 5855735..b0ea3e0 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainRenderContextMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainRenderContextMixin.java @@ -1,15 +1,19 @@ package fr.adrien1106.reframed.mixin.compat; import fr.adrien1106.reframed.client.model.MultiRetexturableModel; +import fr.adrien1106.reframed.client.model.RetexturingBakedModel; import fr.adrien1106.reframed.client.util.RenderHelper; import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin; import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin; +import link.infra.indium.renderer.aocalc.AoCalculator; import link.infra.indium.renderer.render.AbstractBlockRenderContext; +import link.infra.indium.renderer.render.BlockRenderInfo; import link.infra.indium.renderer.render.TerrainRenderContext; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext; -import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; import net.minecraft.client.render.model.BakedModel; 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.CallbackInfo; @@ -28,18 +32,34 @@ public abstract class IndiumTerrainRenderContextMixin extends AbstractBlockRende ), remap = false, cancellable = true) private void renderMultipleModels(BlockRenderContext ctx, CallbackInfo ci) { - if (!(ctx.model() instanceof IMultipartBakedModelMixin wrapped) - || !(wrapped.getModel(ctx.state()) instanceof MultiRetexturableModel retexturing_model)) return; + if (!(ctx.model() instanceof IMultipartBakedModelMixin wrapped)) return; + List models = wrapped.getModels(ctx.state()); + if (models.stream().noneMatch(bakedModel -> + bakedModel instanceof MultiRetexturableModel + || bakedModel instanceof RetexturingBakedModel + )) return; - List models = retexturing_model.models(); - RenderHelper.computeInnerCull(ctx.state(), models); - int i = 0; - for (BakedModel model : models) { - i++; - aoCalc.clear(); - ((IBlockRenderInfoMixin) blockInfo).prepareForBlock(ctx.state(), ctx.pos(), ctx.seed(), model.useAmbientOcclusion(), i); - model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this); - } + models.forEach(model -> { + if (model instanceof MultiRetexturableModel multi_model) { + RenderHelper.computeInnerCull(ctx.state(), multi_model.models(), model.hashCode()); + multi_model.models().forEach(rexteruable_model -> + renderModel(ctx, rexteruable_model, aoCalc, blockInfo, this, model.hashCode()) + ); + } else if (model instanceof RetexturingBakedModel rexteruable_model) + renderModel(ctx, rexteruable_model, aoCalc, blockInfo, this, model.hashCode()); + else model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this); + }); ci.cancel(); } + + @Unique + private static void renderModel(BlockRenderContext ctx, RetexturingBakedModel model, AoCalculator aoCalc, BlockRenderInfo block_info, RenderContext context, int model_hash) { + aoCalc.clear(); + ((IBlockRenderInfoMixin) block_info).prepareForBlock( + ctx.state(), ctx.pos(), ctx.seed(), + model.useAmbientOcclusion(block_info.blockView, ctx.pos()), + model.getThemeIndex(), model_hash + ); + model.emitBlockQuads(block_info.blockView, block_info.blockState, block_info.blockPos, block_info.randomSupplier, context); + } } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/render/AbstractBlockRenderContextMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/render/AbstractBlockRenderContextMixin.java index 388ea4a..b6c674d 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/render/AbstractBlockRenderContextMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/render/AbstractBlockRenderContextMixin.java @@ -29,8 +29,12 @@ public abstract class AbstractBlockRenderContextMixin { ) ) private boolean shouldDrawInnerQuad(AbstractBlockRenderContext instance, Direction face, @Local(argsOnly = true) MutableQuadViewImpl quad) { - if (face != null || quad.tag() == 0 || !(blockInfo instanceof IBlockRenderInfoMixin info) || info.getThemeIndex() == 0) return isFaceCulled(face); + if (face != null + || quad.tag() == 0 + || !(blockInfo instanceof IBlockRenderInfoMixin info) + || info.getThemeIndex() == 0 + ) return isFaceCulled(face); - return !RenderHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex()); + return !RenderHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex(), info.getModelHash()); } } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/render/BlockRenderInfoMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/render/BlockRenderInfoMixin.java index 122e62a..bd4d414 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/render/BlockRenderInfoMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/render/BlockRenderInfoMixin.java @@ -25,6 +25,7 @@ public abstract class BlockRenderInfoMixin implements IBlockRenderInfoMixin { @Shadow public BlockRenderView blockView; @Unique private int theme_index = 0; + @Unique private int model_hash = 0; @ModifyArg(method = "prepareForBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderLayers;" + @@ -42,8 +43,9 @@ public abstract class BlockRenderInfoMixin implements IBlockRenderInfoMixin { @Override @Unique - public void prepareForBlock(BlockState state, BlockPos pos, boolean ao, int theme_index) { + public void prepareForBlock(BlockState state, BlockPos pos, boolean ao, int theme_index, int model_hash) { this.theme_index = theme_index; + this.model_hash = model_hash; prepareForBlock(state, pos, ao); } @@ -51,4 +53,9 @@ public abstract class BlockRenderInfoMixin implements IBlockRenderInfoMixin { public int getThemeIndex() { return theme_index; } + + @Override + public int getModelHash() { + return model_hash; + } } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/render/MultipartBakedModelMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/render/MultipartBakedModelMixin.java index 2183590..252dedb 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/render/MultipartBakedModelMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/render/MultipartBakedModelMixin.java @@ -19,7 +19,7 @@ public class MultipartBakedModelMixin implements IMultipartBakedModelMixin { @Shadow @Final private List, BakedModel>> components; @Override - public BakedModel getModel(BlockState state) { - return components.stream().map(pair -> pair.getLeft().test(state) ? pair.getRight(): null).filter(Objects::nonNull).findAny().orElse(null); + public List getModels(BlockState state) { + return components.stream().map(pair -> pair.getLeft().test(state) ? pair.getRight(): null).filter(Objects::nonNull).toList(); } } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/render/TerrainRenderContextMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/render/TerrainRenderContextMixin.java index 41e1813..958aa10 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/render/TerrainRenderContextMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/render/TerrainRenderContextMixin.java @@ -1,17 +1,21 @@ package fr.adrien1106.reframed.mixin.render; import fr.adrien1106.reframed.client.model.MultiRetexturableModel; +import fr.adrien1106.reframed.client.model.RetexturingBakedModel; import fr.adrien1106.reframed.client.util.RenderHelper; import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin; import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin; -import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; +import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoCalculator; import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractBlockRenderContext; +import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo; import net.fabricmc.fabric.impl.client.indigo.renderer.render.TerrainRenderContext; import net.minecraft.block.BlockState; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.math.BlockPos; 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.CallbackInfo; @@ -27,18 +31,34 @@ public abstract class TerrainRenderContextMixin extends AbstractBlockRenderConte ), remap = false, cancellable = true) private void renderMultipleModels(BlockState state, BlockPos pos, BakedModel wrapper, MatrixStack matrixStack, CallbackInfo ci) { - if (!(wrapper instanceof IMultipartBakedModelMixin wrapped) - || !(wrapped.getModel(state) instanceof MultiRetexturableModel retexturing_model)) return; + if (!(wrapper instanceof IMultipartBakedModelMixin wrapped)) return; + List models = wrapped.getModels(state); + if (models.stream().noneMatch(bakedModel -> + bakedModel instanceof MultiRetexturableModel + || bakedModel instanceof RetexturingBakedModel + )) return; - List models = retexturing_model.models(); - RenderHelper.computeInnerCull(state, models); - int i = 0; - for (BakedModel model : models) { - i++; - aoCalc.clear(); - ((IBlockRenderInfoMixin) blockInfo).prepareForBlock(state, pos, model.useAmbientOcclusion(), i); - model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this); - } + models.forEach(model -> { + if (model instanceof MultiRetexturableModel multi_model) { + RenderHelper.computeInnerCull(state, multi_model.models(), model.hashCode()); + multi_model.models().forEach(retexturable_model -> + renderModel(state, retexturable_model, pos, aoCalc, blockInfo, this, model.hashCode()) + ); + } else if (model instanceof RetexturingBakedModel retexturable_model) + renderModel(state, retexturable_model, pos, aoCalc, blockInfo, this, model.hashCode()); + else model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this); + }); ci.cancel(); } + + @Unique + private static void renderModel(BlockState state, RetexturingBakedModel model, BlockPos pos, AoCalculator aoCalc, BlockRenderInfo block_info, RenderContext context, int model_hash) { + aoCalc.clear(); + ((IBlockRenderInfoMixin) block_info).prepareForBlock( + state, pos, + model.useAmbientOcclusion(block_info.blockView, pos), + model.getThemeIndex(), model_hash + ); + model.emitBlockQuads(block_info.blockView, block_info.blockState, block_info.blockPos, block_info.randomSupplier, context); + } } diff --git a/src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java b/src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java index e1843de..f6a2f65 100644 --- a/src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java @@ -1,5 +1,7 @@ package fr.adrien1106.reframed.util.blocks; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.StringIdentifiable; import net.minecraft.util.math.Direction; @@ -119,4 +121,20 @@ public enum Corner implements StringIdentifiable { if (edge.getFirstDirection() != third_direction && edge.getSecondDirection() != third_direction) return third_direction; return first_direction; } + + public Corner rotate(BlockRotation rotation) { + return getByDirections( + rotation.rotate(first_direction), + rotation.rotate(second_direction), + rotation.rotate(third_direction) + ); + } + + public Corner mirror(BlockMirror mirror) { + return getByDirections( + mirror.apply(first_direction), + mirror.apply(second_direction), + mirror.apply(third_direction) + ); + } } diff --git a/src/main/java/fr/adrien1106/reframed/util/blocks/Edge.java b/src/main/java/fr/adrien1106/reframed/util/blocks/Edge.java index 9c8e34d..1642f56 100644 --- a/src/main/java/fr/adrien1106/reframed/util/blocks/Edge.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/Edge.java @@ -1,5 +1,7 @@ package fr.adrien1106.reframed.util.blocks; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; import net.minecraft.util.StringIdentifiable; import net.minecraft.util.math.Direction; @@ -48,13 +50,19 @@ public enum Edge implements StringIdentifiable { public Direction getSecondDirection() { return second_direction; } + public Direction getRightDirection() { return Direction.from(axis, Direction.AxisDirection.NEGATIVE); } + public Direction getLeftDirection() { return Direction.from(axis, Direction.AxisDirection.POSITIVE); } + public Direction getFace() { + return first_direction == Direction.UP || first_direction == Direction.DOWN ? second_direction : first_direction; + } + public boolean hasDirection(Direction direction) { return this.first_direction.equals(direction) || this.second_direction.equals(direction); @@ -97,4 +105,18 @@ public enum Edge implements StringIdentifiable { .filter(value -> value.name().equals(name)) .findFirst().orElse(Edge.NORTH_DOWN); } + + public Edge rotate(BlockRotation rotation) { + return getByDirections( + rotation.rotate(first_direction), + rotation.rotate(second_direction) + ); + } + + public Edge mirror(BlockMirror mirror) { + return getByDirections( + mirror.apply(first_direction), + mirror.apply(second_direction) + ); + } } diff --git a/src/main/java/fr/adrien1106/reframed/util/blocks/StairShape.java b/src/main/java/fr/adrien1106/reframed/util/blocks/StairShape.java index 5019e89..63a1b62 100644 --- a/src/main/java/fr/adrien1106/reframed/util/blocks/StairShape.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/StairShape.java @@ -48,4 +48,31 @@ public enum StairShape implements StringIdentifiable { .findFirst().orElse(StairShape.STRAIGHT); } + public StairShape mirror() { + return switch (this) { + case STRAIGHT -> STRAIGHT; + case INNER_RIGHT -> INNER_LEFT; + case INNER_LEFT -> INNER_RIGHT; + case OUTER_RIGHT -> OUTER_LEFT; + case OUTER_LEFT -> OUTER_RIGHT; + case FIRST_OUTER_RIGHT -> FIRST_OUTER_LEFT; + case FIRST_OUTER_LEFT -> FIRST_OUTER_RIGHT; + case SECOND_OUTER_RIGHT -> SECOND_OUTER_LEFT; + case SECOND_OUTER_LEFT -> SECOND_OUTER_RIGHT; + }; + } + + public StairShape flip() { + return switch (this) { + case STRAIGHT -> STRAIGHT; + case INNER_RIGHT -> INNER_RIGHT; + case INNER_LEFT -> INNER_LEFT; + case OUTER_RIGHT -> OUTER_RIGHT; + case OUTER_LEFT -> OUTER_LEFT; + case FIRST_OUTER_RIGHT -> SECOND_OUTER_RIGHT; + case FIRST_OUTER_LEFT -> SECOND_OUTER_LEFT; + case SECOND_OUTER_RIGHT -> FIRST_OUTER_RIGHT; + case SECOND_OUTER_LEFT -> FIRST_OUTER_LEFT; + }; + } } diff --git a/src/main/java/fr/adrien1106/reframed/util/mixin/IBlockRenderInfoMixin.java b/src/main/java/fr/adrien1106/reframed/util/mixin/IBlockRenderInfoMixin.java index 30e0672..edfe9ba 100644 --- a/src/main/java/fr/adrien1106/reframed/util/mixin/IBlockRenderInfoMixin.java +++ b/src/main/java/fr/adrien1106/reframed/util/mixin/IBlockRenderInfoMixin.java @@ -5,9 +5,11 @@ import net.minecraft.util.math.BlockPos; public interface IBlockRenderInfoMixin { - void prepareForBlock(BlockState state, BlockPos pos, boolean ao, int theme_index); + void prepareForBlock(BlockState state, BlockPos pos, boolean ao, int theme_index, int model_hash); - void prepareForBlock(BlockState state, BlockPos pos, long seed, boolean ao, int theme_index); + void prepareForBlock(BlockState state, BlockPos pos, long seed, boolean ao, int theme_index, int model_hash); int getThemeIndex(); + + int getModelHash(); } diff --git a/src/main/java/fr/adrien1106/reframed/util/mixin/IMultipartBakedModelMixin.java b/src/main/java/fr/adrien1106/reframed/util/mixin/IMultipartBakedModelMixin.java index 8b7a01c..09c1042 100644 --- a/src/main/java/fr/adrien1106/reframed/util/mixin/IMultipartBakedModelMixin.java +++ b/src/main/java/fr/adrien1106/reframed/util/mixin/IMultipartBakedModelMixin.java @@ -3,7 +3,9 @@ package fr.adrien1106.reframed.util.mixin; import net.minecraft.block.BlockState; import net.minecraft.client.render.model.BakedModel; +import java.util.List; + public interface IMultipartBakedModelMixin { - BakedModel getModel(BlockState state); + List getModels(BlockState state); } diff --git a/src/main/resources/assets/reframed/models/block/door.json b/src/main/resources/assets/reframed/models/block/door.json new file mode 100644 index 0000000..4c70e48 --- /dev/null +++ b/src/main/resources/assets/reframed/models/block/door.json @@ -0,0 +1,34 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [14, 0, 0], + "to": [16, 16, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 0, 0]}, + "faces": { + "north": {"uv": [0, 0, 2, 16], "texture": "#side", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "east"}, + "south": {"uv": [14, 0, 16, 16], "texture": "#side", "cullface": "south"}, + "west": {"uv": [0, 0, 16, 16], "texture": "#side"}, + "down": {"uv": [14, 0, 16, 16], "texture": "#bottom", "cullface": "down"} + } + }, + { + "from": [14, 16, 0], + "to": [16, 32, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 16, 0]}, + "faces": { + "north": {"uv": [0, 0, 2, 0], "texture": "#side", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "east"}, + "south": {"uv": [14, 0, 16, 0], "texture": "#side", "cullface": "south"}, + "west": {"uv": [0, 0, 16, 16], "texture": "#side"}, + "up": {"uv": [14, 0, 16, 16], "texture": "#top", "cullface": "up"} + } + } + ], + "display": {} +} \ No newline at end of file diff --git a/src/main/resources/assets/reframed/models/block/pane.json b/src/main/resources/assets/reframed/models/block/pane.json new file mode 100644 index 0000000..117fc7b --- /dev/null +++ b/src/main/resources/assets/reframed/models/block/pane.json @@ -0,0 +1,21 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [7, 0, 0], + "to": [9, 16, 16], + "faces": { + "north": {"uv": [7, 0, 9, 16], "texture": "#side", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "texture": "#side"}, + "south": {"uv": [7, 0, 9, 16], "texture": "#side", "cullface": "south"}, + "west": {"uv": [0, 0, 16, 16], "texture": "#side"}, + "up": {"uv": [7, 0, 9, 16], "texture": "#top", "cullface": "up"}, + "down": {"uv": [7, 0, 9, 16], "texture": "#bottom", "cullface": "down"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/reframed/models/block/wall/full/inventory/sides.json b/src/main/resources/assets/reframed/models/block/wall/full/inventory/sides.json new file mode 100644 index 0000000..6f443c0 --- /dev/null +++ b/src/main/resources/assets/reframed/models/block/wall/full/inventory/sides.json @@ -0,0 +1,33 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [5, 0, 0], + "to": [11, 14, 4], + "faces": { + "north": {"uv": [5, 2, 11, 16], "texture": "#side", "cullface": "north"}, + "east": {"uv": [12, 2, 16, 16], "texture": "#side"}, + "south": {"uv": [5, 2, 11, 16], "texture": "#side"}, + "west": {"uv": [0, 2, 4, 16], "texture": "#side"}, + "up": {"uv": [5, 0, 11, 4], "texture": "#top"}, + "down": {"uv": [5, 12, 11, 16], "texture": "#bottom"} + } + }, + { + "from": [5, 0, 12], + "to": [11, 14, 16], + "faces": { + "north": {"uv": [5, 2, 11, 16], "texture": "#side"}, + "east": {"uv": [0, 2, 4, 16], "texture": "#side"}, + "south": {"uv": [5, 2, 11, 16], "texture": "#side", "cullface": "south"}, + "west": {"uv": [12, 2, 16, 16], "texture": "#side"}, + "up": {"uv": [5, 12, 11, 16], "texture": "#top"}, + "down": {"uv": [5, 0, 11, 4], "texture": "#bottom"} + } + } + ] +} \ No newline at end of file