Implemented SegmentableBlock as is in 1.21.5, including all needed misc classes etc.
This commit is contained in:
@ -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<BlockState, VoxelShape> getShapeCalculator(EnumProperty<Direction> dir, IntegerProperty property) {
|
||||
Map<Direction, VoxelShape> 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<Direction> 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());
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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<Quadrant> 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;
|
||||
}
|
||||
}
|
||||
@ -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("<init>")
|
||||
static ArrayVoxelShape newArrayVoxelShape(DiscreteVoxelShape pShape, DoubleList pXs, DoubleList pYs, DoubleList pZs) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
@ -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("<init>")
|
||||
static CubeVoxelShape newCubeVoxelShape(DiscreteVoxelShape pShape) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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()];
|
||||
}
|
||||
}
|
||||
@ -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<Direction, VoxelShape> rotateHorizontal(VoxelShape voxelShape) {
|
||||
return rotateHorizontal(voxelShape, BLOCK_CENTER);
|
||||
}
|
||||
|
||||
public static Map<Direction, VoxelShape> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,10 @@
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"refmap": "firefly_bush_backport.refmap.json",
|
||||
"mixins": [
|
||||
"OctahedralGroupAccessor",
|
||||
"VoxelShapeAccessor",
|
||||
"ArrayVoxelShapeAccessor",
|
||||
"CubeVoxelShapeAccessor"
|
||||
],
|
||||
"client": [
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user