From 6ce207ad1438bbd4a3f202b0c8ff195a6ca5c725 Mon Sep 17 00:00:00 2001 From: Micle Date: Tue, 9 Jun 2026 20:54:53 +0100 Subject: [PATCH] Implemented SegmentableBlock as is in 1.21.5, including all needed misc classes etc. --- .../block/SegmentableBlock.java | 57 ++++++++++++ .../properties/ModBlockStateProperties.java | 7 ++ .../wildflowers_backport/math/Quadrant.java | 34 +++++++ .../mixin/ArrayVoxelShapeAccessor.java | 15 +++ .../mixin/CubeVoxelShapeAccessor.java | 14 +++ .../mixin/OctahedralGroupAccessor.java | 12 +++ .../mixin/VoxelShapeAccessor.java | 18 ++++ .../util/DirectionAxisUtils.java | 13 +++ .../util/OctahedralGroupUtils.java | 37 ++++++++ .../util/ShapesUtils.java | 93 +++++++++++++++++++ .../util/VoxelShapeUtils.java | 20 ++++ .../wildflowers_backport.mixins.json | 4 + 12 files changed, 324 insertions(+) create mode 100644 src/main/java/dev/micle/wildflowers_backport/block/SegmentableBlock.java create mode 100644 src/main/java/dev/micle/wildflowers_backport/block/state/properties/ModBlockStateProperties.java create mode 100644 src/main/java/dev/micle/wildflowers_backport/math/Quadrant.java create mode 100644 src/main/java/dev/micle/wildflowers_backport/mixin/ArrayVoxelShapeAccessor.java create mode 100644 src/main/java/dev/micle/wildflowers_backport/mixin/CubeVoxelShapeAccessor.java create mode 100644 src/main/java/dev/micle/wildflowers_backport/mixin/OctahedralGroupAccessor.java create mode 100644 src/main/java/dev/micle/wildflowers_backport/mixin/VoxelShapeAccessor.java create mode 100644 src/main/java/dev/micle/wildflowers_backport/util/DirectionAxisUtils.java create mode 100644 src/main/java/dev/micle/wildflowers_backport/util/OctahedralGroupUtils.java create mode 100644 src/main/java/dev/micle/wildflowers_backport/util/ShapesUtils.java create mode 100644 src/main/java/dev/micle/wildflowers_backport/util/VoxelShapeUtils.java diff --git a/src/main/java/dev/micle/wildflowers_backport/block/SegmentableBlock.java b/src/main/java/dev/micle/wildflowers_backport/block/SegmentableBlock.java new file mode 100644 index 0000000..d2804d2 --- /dev/null +++ b/src/main/java/dev/micle/wildflowers_backport/block/SegmentableBlock.java @@ -0,0 +1,57 @@ +package dev.micle.wildflowers_backport.block; + +import dev.micle.wildflowers_backport.block.state.properties.ModBlockStateProperties; +import dev.micle.wildflowers_backport.util.ShapesUtils; +import dev.micle.wildflowers_backport.util.VoxelShapeUtils; +import net.minecraft.core.Direction; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; + +import java.util.Map; +import java.util.function.Function; + +public interface SegmentableBlock { + int MIN_SEGMENT = 1; + int MAX_SEGMENT = 4; + IntegerProperty AMOUNT = ModBlockStateProperties.SEGMENT_AMOUNT; + + default Function getShapeCalculator(EnumProperty dir, IntegerProperty property) { + Map map = ShapesUtils.rotateHorizontal(Block.box(0.0, 0.0, 0.0, 8.0, this.getShapeHeight(), 8.0)); + return x -> { + VoxelShape voxelShape = Shapes.empty(); + Direction direction = x.getValue(dir); + int i = x.getValue(property); + + for (int j = 0; j < i; j++) { + voxelShape = Shapes.or(voxelShape, map.get(direction)); + direction = direction.getCounterClockWise(); + } + + return VoxelShapeUtils.singleEncompassing(voxelShape); + }; + } + + default IntegerProperty getSegmentAmountProperty() { + return AMOUNT; + } + + default double getShapeHeight() { + return 1.0; + } + + default boolean canBeReplaced(BlockState blockState, BlockPlaceContext blockPlaceContext, IntegerProperty property) { + return !blockPlaceContext.isSecondaryUseActive() && blockPlaceContext.getItemInHand().is(blockState.getBlock().asItem()) && blockState.getValue(property) < 4; + } + + default BlockState getStateForPlacement(BlockPlaceContext blockPlaceContext, Block block, IntegerProperty property, EnumProperty dir) { + BlockState blockState = blockPlaceContext.getLevel().getBlockState(blockPlaceContext.getClickedPos()); + return blockState.is(block) + ? blockState.setValue(property, Math.min(4, blockState.getValue(property) + 1)) + : block.defaultBlockState().setValue(dir, blockPlaceContext.getHorizontalDirection().getOpposite()); + } +} diff --git a/src/main/java/dev/micle/wildflowers_backport/block/state/properties/ModBlockStateProperties.java b/src/main/java/dev/micle/wildflowers_backport/block/state/properties/ModBlockStateProperties.java new file mode 100644 index 0000000..af4eb1e --- /dev/null +++ b/src/main/java/dev/micle/wildflowers_backport/block/state/properties/ModBlockStateProperties.java @@ -0,0 +1,7 @@ +package dev.micle.wildflowers_backport.block.state.properties; + +import net.minecraft.world.level.block.state.properties.IntegerProperty; + +public class ModBlockStateProperties { + public static final IntegerProperty SEGMENT_AMOUNT = IntegerProperty.create("segment_amount", 1, 4); +} diff --git a/src/main/java/dev/micle/wildflowers_backport/math/Quadrant.java b/src/main/java/dev/micle/wildflowers_backport/math/Quadrant.java new file mode 100644 index 0000000..9ae503a --- /dev/null +++ b/src/main/java/dev/micle/wildflowers_backport/math/Quadrant.java @@ -0,0 +1,34 @@ +package dev.micle.wildflowers_backport.math; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import net.minecraft.util.Mth; + +public enum Quadrant { + R0(0), + R90(1), + R180(2), + R270(3); + + public static final Codec CODEC = Codec.INT.comapFlatMap(x -> { + return switch (Mth.positiveModulo(x, 360)) { + case 0 -> DataResult.success(R0); + case 90 -> DataResult.success(R90); + case 180 -> DataResult.success(R180); + case 270 -> DataResult.success(R270); + default -> DataResult.error(() -> "Invalid rotation " + x + " found, only 0/90/180/270 allowed"); + }; + }, y -> { + return switch (y) { + case R0 -> 0; + case R90 -> 90; + case R180 -> 180; + case R270 -> 270; + }; + }); + public final int shift; + + Quadrant(final int shift) { + this.shift = shift; + } +} diff --git a/src/main/java/dev/micle/wildflowers_backport/mixin/ArrayVoxelShapeAccessor.java b/src/main/java/dev/micle/wildflowers_backport/mixin/ArrayVoxelShapeAccessor.java new file mode 100644 index 0000000..aef58fc --- /dev/null +++ b/src/main/java/dev/micle/wildflowers_backport/mixin/ArrayVoxelShapeAccessor.java @@ -0,0 +1,15 @@ +package dev.micle.wildflowers_backport.mixin; + +import it.unimi.dsi.fastutil.doubles.DoubleList; +import net.minecraft.world.phys.shapes.ArrayVoxelShape; +import net.minecraft.world.phys.shapes.DiscreteVoxelShape; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ArrayVoxelShape.class) +public interface ArrayVoxelShapeAccessor { + @Invoker("") + static ArrayVoxelShape newArrayVoxelShape(DiscreteVoxelShape pShape, DoubleList pXs, DoubleList pYs, DoubleList pZs) { + throw new AssertionError(); + } +} diff --git a/src/main/java/dev/micle/wildflowers_backport/mixin/CubeVoxelShapeAccessor.java b/src/main/java/dev/micle/wildflowers_backport/mixin/CubeVoxelShapeAccessor.java new file mode 100644 index 0000000..91ff12c --- /dev/null +++ b/src/main/java/dev/micle/wildflowers_backport/mixin/CubeVoxelShapeAccessor.java @@ -0,0 +1,14 @@ +package dev.micle.wildflowers_backport.mixin; + +import net.minecraft.world.phys.shapes.CubeVoxelShape; +import net.minecraft.world.phys.shapes.DiscreteVoxelShape; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(CubeVoxelShape.class) +public interface CubeVoxelShapeAccessor { + @Invoker("") + static CubeVoxelShape newCubeVoxelShape(DiscreteVoxelShape pShape) { + throw new AssertionError(); + } +} diff --git a/src/main/java/dev/micle/wildflowers_backport/mixin/OctahedralGroupAccessor.java b/src/main/java/dev/micle/wildflowers_backport/mixin/OctahedralGroupAccessor.java new file mode 100644 index 0000000..15bde0e --- /dev/null +++ b/src/main/java/dev/micle/wildflowers_backport/mixin/OctahedralGroupAccessor.java @@ -0,0 +1,12 @@ +package dev.micle.wildflowers_backport.mixin; + +import com.mojang.math.OctahedralGroup; +import com.mojang.math.SymmetricGroup3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(OctahedralGroup.class) +public interface OctahedralGroupAccessor { + @Accessor("permutation") + SymmetricGroup3 wildflowers_backport$getPermutation(); +} diff --git a/src/main/java/dev/micle/wildflowers_backport/mixin/VoxelShapeAccessor.java b/src/main/java/dev/micle/wildflowers_backport/mixin/VoxelShapeAccessor.java new file mode 100644 index 0000000..4de5825 --- /dev/null +++ b/src/main/java/dev/micle/wildflowers_backport/mixin/VoxelShapeAccessor.java @@ -0,0 +1,18 @@ +package dev.micle.wildflowers_backport.mixin; + +import it.unimi.dsi.fastutil.doubles.DoubleList; +import net.minecraft.core.Direction; +import net.minecraft.world.phys.shapes.DiscreteVoxelShape; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(VoxelShape.class) +public interface VoxelShapeAccessor { + @Accessor("shape") + DiscreteVoxelShape wildflowers_backport$getShape(); + + @Invoker("getCoords") + DoubleList wildflowers_backport$getCoords(Direction.Axis pAxis); +} diff --git a/src/main/java/dev/micle/wildflowers_backport/util/DirectionAxisUtils.java b/src/main/java/dev/micle/wildflowers_backport/util/DirectionAxisUtils.java new file mode 100644 index 0000000..edbaa89 --- /dev/null +++ b/src/main/java/dev/micle/wildflowers_backport/util/DirectionAxisUtils.java @@ -0,0 +1,13 @@ +package dev.micle.wildflowers_backport.util; + +import net.minecraft.core.Direction; + +public class DirectionAxisUtils { + public static boolean choose(Direction.Axis axis, boolean x, boolean y, boolean z) { + return switch (axis) { + case X -> x; + case Y -> y; + case Z -> z; + }; + } +} diff --git a/src/main/java/dev/micle/wildflowers_backport/util/OctahedralGroupUtils.java b/src/main/java/dev/micle/wildflowers_backport/util/OctahedralGroupUtils.java new file mode 100644 index 0000000..2d68256 --- /dev/null +++ b/src/main/java/dev/micle/wildflowers_backport/util/OctahedralGroupUtils.java @@ -0,0 +1,37 @@ +package dev.micle.wildflowers_backport.util; + +import com.mojang.math.OctahedralGroup; +import dev.micle.wildflowers_backport.math.Quadrant; +import dev.micle.wildflowers_backport.mixin.OctahedralGroupAccessor; +import net.minecraft.Util; +import net.minecraft.core.Direction; + +public class OctahedralGroupUtils { + private static final Direction.Axis[] AXES = Direction.Axis.values(); + private static final OctahedralGroup[][] XY_TABLE = Util.make(new OctahedralGroup[Quadrant.values().length][Quadrant.values().length], x -> { + for (Quadrant quadrant : Quadrant.values()) { + for (Quadrant quadrant1 : Quadrant.values()) { + OctahedralGroup octahedralGroup = OctahedralGroup.IDENTITY; + + for (int i = 0; i < quadrant1.shift; i++) { + octahedralGroup = octahedralGroup.compose(OctahedralGroup.ROT_90_Y_NEG); + } + + for (int j = 0; j < quadrant.shift; j++) { + octahedralGroup = octahedralGroup.compose(OctahedralGroup.ROT_90_X_NEG); + } + + x[quadrant.ordinal()][quadrant1.ordinal()] = octahedralGroup; + } + } + }); + + public static Direction.Axis permute(OctahedralGroup octahedralGroup, Direction.Axis axis) { + return AXES[((OctahedralGroupAccessor) (Object) octahedralGroup).wildflowers_backport$getPermutation().permutation(axis.ordinal())]; + } + + + public static OctahedralGroup fromXYAngles(Quadrant quadrant, Quadrant quadrant1) { + return XY_TABLE[quadrant.ordinal()][quadrant1.ordinal()]; + } +} diff --git a/src/main/java/dev/micle/wildflowers_backport/util/ShapesUtils.java b/src/main/java/dev/micle/wildflowers_backport/util/ShapesUtils.java new file mode 100644 index 0000000..016cae4 --- /dev/null +++ b/src/main/java/dev/micle/wildflowers_backport/util/ShapesUtils.java @@ -0,0 +1,93 @@ +package dev.micle.wildflowers_backport.util; + +import com.google.common.collect.Maps; +import com.mojang.math.OctahedralGroup; +import dev.micle.wildflowers_backport.math.Quadrant; +import dev.micle.wildflowers_backport.mixin.ArrayVoxelShapeAccessor; +import dev.micle.wildflowers_backport.mixin.CubeVoxelShapeAccessor; +import dev.micle.wildflowers_backport.mixin.VoxelShapeAccessor; +import it.unimi.dsi.fastutil.doubles.DoubleArrayList; +import it.unimi.dsi.fastutil.doubles.DoubleList; +import net.minecraft.core.Direction; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CubeVoxelShape; +import net.minecraft.world.phys.shapes.DiscreteVoxelShape; +import net.minecraft.world.phys.shapes.VoxelShape; + +import java.util.Map; + +public class ShapesUtils { + private static final Vec3 BLOCK_CENTER = new Vec3(0.5, 0.5, 0.5); + + public static VoxelShape rotate(VoxelShape voxelShape, OctahedralGroup octahedralGroup) { + return rotate(voxelShape, octahedralGroup, BLOCK_CENTER); + } + + public static VoxelShape rotate(VoxelShape voxelShape, OctahedralGroup octahedralGroup, Vec3 vec3) { + if (octahedralGroup == OctahedralGroup.IDENTITY) { + return voxelShape; + } else { + DiscreteVoxelShape discreteVoxelShape = ((VoxelShapeAccessor) voxelShape).wildflowers_backport$getShape(); + if (voxelShape instanceof CubeVoxelShape && BLOCK_CENTER.equals(vec3)) { + return CubeVoxelShapeAccessor.newCubeVoxelShape(discreteVoxelShape); + } else { + Direction.Axis direction$axis = OctahedralGroupUtils.permute(octahedralGroup, Direction.Axis.X); + Direction.Axis direction$axis1 = OctahedralGroupUtils.permute(octahedralGroup, Direction.Axis.Y); + Direction.Axis direction$axis2 = OctahedralGroupUtils.permute(octahedralGroup, Direction.Axis.Z); + + DoubleList doubleList = ((VoxelShapeAccessor) voxelShape).wildflowers_backport$getCoords(direction$axis); + DoubleList doubleList1 = ((VoxelShapeAccessor) voxelShape).wildflowers_backport$getCoords(direction$axis1); + DoubleList doubleList2 = ((VoxelShapeAccessor) voxelShape).wildflowers_backport$getCoords(direction$axis2); + + boolean flag = octahedralGroup.inverts(direction$axis); + boolean flag1 = octahedralGroup.inverts(direction$axis1); + boolean flag2 = octahedralGroup.inverts(direction$axis2); + boolean flag3 = DirectionAxisUtils.choose(direction$axis, flag, flag1, flag2); + boolean flag4 = DirectionAxisUtils.choose(direction$axis1, flag, flag1, flag2); + boolean flag5 = DirectionAxisUtils.choose(direction$axis2, flag, flag1, flag2); + + return ArrayVoxelShapeAccessor.newArrayVoxelShape( + discreteVoxelShape, + makeAxis(doubleList, flag3, vec3.get(direction$axis), vec3.x), + makeAxis(doubleList1, flag4, vec3.get(direction$axis1), vec3.y), + makeAxis(doubleList2, flag5, vec3.get(direction$axis2), vec3.z) + ); + } + } + } + + public static Map rotateHorizontal(VoxelShape voxelShape) { + return rotateHorizontal(voxelShape, BLOCK_CENTER); + } + + public static Map rotateHorizontal(VoxelShape voxelShape, Vec3 vec3) { + return Maps.newEnumMap( + Map.of( + Direction.NORTH, + voxelShape, + Direction.EAST, + rotate(voxelShape, OctahedralGroupUtils.fromXYAngles(Quadrant.R0, Quadrant.R90), vec3), + Direction.SOUTH, + rotate(voxelShape, OctahedralGroupUtils.fromXYAngles(Quadrant.R0, Quadrant.R180), vec3), + Direction.WEST, + rotate(voxelShape, OctahedralGroupUtils.fromXYAngles(Quadrant.R0, Quadrant.R270), vec3) + ) + ); + } + + public static DoubleList makeAxis(DoubleList doubleList, boolean flag, double d1, double d2) { + if (!flag && d1 == d2) { + return doubleList; + } else { + int i = doubleList.size(); + DoubleList doubleList1 = new DoubleArrayList(i); + int j = flag ? -1 : 1; + + for (int k = flag ? i - 1 : 0; k >= 0 && k < i; k += j) { + doubleList1.add(d2 + j * (doubleList.getDouble(k) - d1)); + } + + return doubleList1; + } + } +} diff --git a/src/main/java/dev/micle/wildflowers_backport/util/VoxelShapeUtils.java b/src/main/java/dev/micle/wildflowers_backport/util/VoxelShapeUtils.java new file mode 100644 index 0000000..68ba5c0 --- /dev/null +++ b/src/main/java/dev/micle/wildflowers_backport/util/VoxelShapeUtils.java @@ -0,0 +1,20 @@ +package dev.micle.wildflowers_backport.util; + +import net.minecraft.core.Direction; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class VoxelShapeUtils { + public static VoxelShape singleEncompassing(VoxelShape voxelShape) { + return voxelShape.isEmpty() + ? Shapes.empty() + : Shapes.box( + voxelShape.min(Direction.Axis.X), + voxelShape.min(Direction.Axis.Y), + voxelShape.min(Direction.Axis.Z), + voxelShape.min(Direction.Axis.X), + voxelShape.min(Direction.Axis.Y), + voxelShape.min(Direction.Axis.Z) + ); + } +} diff --git a/src/main/resources/wildflowers_backport.mixins.json b/src/main/resources/wildflowers_backport.mixins.json index 7facd74..9fb047d 100644 --- a/src/main/resources/wildflowers_backport.mixins.json +++ b/src/main/resources/wildflowers_backport.mixins.json @@ -5,6 +5,10 @@ "compatibilityLevel": "JAVA_8", "refmap": "firefly_bush_backport.refmap.json", "mixins": [ + "OctahedralGroupAccessor", + "VoxelShapeAccessor", + "ArrayVoxelShapeAccessor", + "CubeVoxelShapeAccessor" ], "client": [ ],