12 way slope blocks (hitboxes broken now)

This commit is contained in:
quat1024 2023-07-09 20:41:37 -04:00
parent aea5fa4e5d
commit d70997faa0
6 changed files with 154 additions and 32 deletions

View File

@ -89,7 +89,8 @@ public class TemplatesClient implements ClientModInitializer {
provider.addTemplateModel(Templates.id("lever_on_special"), new UnbakedJsonRetexturedModel(Templates.id("block/lever_on"))); provider.addTemplateModel(Templates.id("lever_on_special"), new UnbakedJsonRetexturedModel(Templates.id("block/lever_on")));
//mesh models //mesh models
provider.addTemplateModel(Templates.id("slope_special"), new UnbakedMeshRetexturedModel(Templates.id("block/slope_base"), SlopeBaseMesh::make)); provider.addTemplateModel(Templates.id("slope_special"), new UnbakedMeshRetexturedModel(Templates.id("block/slope_base"), SlopeBaseMesh::makeUpright));
provider.addTemplateModel(Templates.id("slope_side_special"), new UnbakedMeshRetexturedModel(Templates.id("block/slope_base"), SlopeBaseMesh::makeSide));
//item only models //item only models
provider.addTemplateModel(Templates.id("button_inventory_special"), new UnbakedAutoRetexturedModel(new Identifier("block/button_inventory"))); provider.addTemplateModel(Templates.id("button_inventory_special"), new UnbakedAutoRetexturedModel(new Identifier("block/button_inventory")));

View File

@ -1,19 +1,15 @@
package io.github.cottonmc.templates.block; package io.github.cottonmc.templates.block;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import io.github.cottonmc.templates.Templates; import io.github.cottonmc.templates.util.EdgeDirection;
import io.github.cottonmc.templates.api.TemplateInteractionUtil;
import io.github.cottonmc.templates.util.StairShapeMaker; import io.github.cottonmc.templates.util.StairShapeMaker;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext; import net.minecraft.block.ShapeContext;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.enums.BlockHalf; import net.minecraft.block.enums.BlockHalf;
import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemPlacementContext;
import net.minecraft.state.StateManager; import net.minecraft.state.StateManager;
import net.minecraft.state.property.DirectionProperty;
import net.minecraft.state.property.EnumProperty; import net.minecraft.state.property.EnumProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShape;
@ -22,14 +18,14 @@ import net.minecraft.world.BlockView;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class TemplateSlopeBlock extends WaterloggableTemplateBlock { public class TemplateSlopeBlock extends WaterloggableTemplateBlock {
public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; public static final EnumProperty<EdgeDirection> FACING = EnumProperty.of("facing", EdgeDirection.class);
public static final EnumProperty<BlockHalf> HALF = Properties.BLOCK_HALF;
private static final VoxelShape[] shapes = new VoxelShape[8]; private static final VoxelShape[] shapes = new VoxelShape[8];
private static int shapeIndex(Direction dir, BlockHalf half) { private static int shapeIndex(Direction dir, BlockHalf half) {
return dir.getHorizontal() + (half == BlockHalf.TOP ? 4 : 0); return dir.getHorizontal() + (half == BlockHalf.TOP ? 4 : 0);
} }
static { static {
//TODO
for(BlockHalf half : BlockHalf.values()) { for(BlockHalf half : BlockHalf.values()) {
for(Direction d : Direction.values()) { for(Direction d : Direction.values()) {
if(d.getHorizontal() == -1) continue; if(d.getHorizontal() == -1) continue;
@ -40,36 +36,37 @@ public class TemplateSlopeBlock extends WaterloggableTemplateBlock {
public TemplateSlopeBlock(Settings settings) { public TemplateSlopeBlock(Settings settings) {
super(settings); super(settings);
setDefaultState(getDefaultState().with(FACING, Direction.NORTH).with(HALF, BlockHalf.BOTTOM)); setDefaultState(getDefaultState().with(FACING, EdgeDirection.DOWN_NORTH));
} }
@Override @Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) { protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
super.appendProperties(builder.add(FACING, HALF)); super.appendProperties(builder.add(FACING));
} }
@Nullable @Nullable
@Override @Override
public BlockState getPlacementState(ItemPlacementContext ctx) { public BlockState getPlacementState(ItemPlacementContext ctx) {
EdgeDirection.guessFromHitResult(ctx.getHitPos(), ctx.getBlockPos());
BlockState sup = super.getPlacementState(ctx); BlockState sup = super.getPlacementState(ctx);
if(sup != null) sup = sup if(sup != null) sup = sup.with(FACING, EdgeDirection.guessFromHitResult(ctx.getHitPos(), ctx.getBlockPos()));
.with(FACING, ctx.getHorizontalPlayerFacing())
.with(HALF, switch(ctx.getSide()) {
case UP -> BlockHalf.BOTTOM;
case DOWN -> BlockHalf.TOP;
default -> (ctx.getHitPos().getY() - (double) ctx.getBlockPos().getY() < 0.5) ? BlockHalf.BOTTOM : BlockHalf.TOP;
});
return sup; return sup;
} }
@Override @Override
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) { public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
return MoreObjects.firstNonNull(super.getCollisionShape(state, view, pos, ctx), shapes[shapeIndex(state.get(FACING), state.get(HALF))]); return MoreObjects.firstNonNull(
super.getCollisionShape(state, view, pos, ctx),
//shapes[shapeIndex(state.get(FACING_OLD), state.get(HALF_OLD))]
shapes[0] //TODO
);
} }
@Override @Override
public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) { public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
return shapes[shapeIndex(state.get(FACING), state.get(HALF))]; //return shapes[shapeIndex(state.get(FACING_OLD), state.get(HALF_OLD))];
return shapes[0]; //TODO
} }
} }

View File

@ -75,8 +75,14 @@ public class MeshTransformUtil {
quad.pos(i, pos4.x + 0.5f, pos4.y + 0.5f, pos4.z + 0.5f); quad.pos(i, pos4.x + 0.5f, pos4.y + 0.5f, pos4.z + 0.5f);
} }
//permute tags
int tag = quad.tag();
if(tag != 0) quad.tag(facePermutation.get(RetexturingBakedModel.DIRECTIONS[tag - 1]).ordinal() + 1);
//permute lighting face (?)
quad.nominalFace(facePermutation.get(quad.lightFace())); quad.nominalFace(facePermutation.get(quad.lightFace()));
//permute cullface
Direction cull = quad.cullFace(); Direction cull = quad.cullFace();
if(cull != null) quad.cullFace(facePermutation.get(cull)); if(cull != null) quad.cullFace(facePermutation.get(cull));

View File

@ -5,11 +5,9 @@ import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder; import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.util.math.RotationAxis;
import java.util.function.Function; import org.joml.Matrix4f;
public class SlopeBaseMesh { public class SlopeBaseMesh {
/** /**
@ -21,7 +19,7 @@ public class SlopeBaseMesh {
public static final int TAG_BACK = Direction.SOUTH.ordinal() + 1; public static final int TAG_BACK = Direction.SOUTH.ordinal() + 1;
public static final int TAG_BOTTOM = Direction.DOWN.ordinal() + 1; public static final int TAG_BOTTOM = Direction.DOWN.ordinal() + 1;
public static Mesh make() { public static Mesh makeUpright() {
Renderer renderer = TemplatesClient.getFabricRenderer(); Renderer renderer = TemplatesClient.getFabricRenderer();
MeshBuilder builder = renderer.meshBuilder(); MeshBuilder builder = renderer.meshBuilder();
@ -56,4 +54,11 @@ public class SlopeBaseMesh {
.emit(); .emit();
return builder.build(); return builder.build();
} }
public static Mesh makeSide() {
Matrix4f mat = new Matrix4f();
RotationAxis.POSITIVE_Z.rotationDegrees(90).get(mat);
return MeshTransformUtil.pretransformMesh(makeUpright(), MeshTransformUtil.applyMatrix(mat));
}
} }

View File

@ -0,0 +1,94 @@
package io.github.cottonmc.templates.util;
import it.unimi.dsi.fastutil.bytes.Byte2ObjectMap;
import it.unimi.dsi.fastutil.bytes.Byte2ObjectOpenHashMap;
import net.minecraft.util.StringIdentifiable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import java.util.Locale;
public enum EdgeDirection implements StringIdentifiable {
DOWN_NORTH(AxisRelation.PARALLEL, AxisRelation.LOW_SIDE, AxisRelation.LOW_SIDE),
DOWN_SOUTH(AxisRelation.PARALLEL, AxisRelation.LOW_SIDE, AxisRelation.HIGH_SIDE),
UP_SOUTH(AxisRelation.PARALLEL, AxisRelation.HIGH_SIDE, AxisRelation.HIGH_SIDE),
UP_NORTH(AxisRelation.PARALLEL, AxisRelation.HIGH_SIDE, AxisRelation.LOW_SIDE),
NORTH_WEST(AxisRelation.LOW_SIDE, AxisRelation.PARALLEL, AxisRelation.LOW_SIDE),
SOUTH_WEST(AxisRelation.LOW_SIDE, AxisRelation.PARALLEL, AxisRelation.HIGH_SIDE),
SOUTH_EAST(AxisRelation.HIGH_SIDE, AxisRelation.PARALLEL, AxisRelation.HIGH_SIDE),
NORTH_EAST(AxisRelation.HIGH_SIDE, AxisRelation.PARALLEL, AxisRelation.LOW_SIDE),
DOWN_WEST(AxisRelation.LOW_SIDE, AxisRelation.LOW_SIDE, AxisRelation.PARALLEL),
UP_WEST(AxisRelation.LOW_SIDE, AxisRelation.HIGH_SIDE, AxisRelation.PARALLEL),
UP_EAST(AxisRelation.HIGH_SIDE, AxisRelation.HIGH_SIDE, AxisRelation.PARALLEL),
DOWN_EAST(AxisRelation.HIGH_SIDE, AxisRelation.LOW_SIDE, AxisRelation.PARALLEL),
;
EdgeDirection(AxisRelation x, AxisRelation y, AxisRelation z) {
this.key = key(x, y, z);
}
private final byte key;
private static final Byte2ObjectMap<EdgeDirection> LOOKUP = new Byte2ObjectOpenHashMap<>();
static { for(EdgeDirection e : values()) LOOKUP.put(e.key, e); }
private static byte key(AxisRelation x, AxisRelation y, AxisRelation z) {
return (byte) (x.ordinal() + 1 << 4 | y.ordinal() + 1 << 2 | z.ordinal() + 1);
}
public static EdgeDirection guessFromHitResult(Vec3d precise, BlockPos coarse) {
double dx = precise.x - coarse.getX();
double dy = precise.y - coarse.getY();
double dz = precise.z - coarse.getZ();
//distances your click was from the 6 faces of the block (each 0..1)
float distToLowX = (float) (dx);
float distToHighX = (float) (1 - dx);
float distToLowY = (float) (dy);
float distToHighY = (float) (1 - dy);
float distToLowZ = (float) (dz);
float distToHighZ = (float) (1 - dz);
//distances your click was from either pair of edges (each 0..0.5)
float distToAnyX = Math.min(distToLowX, distToHighX);
float distToAnyY = Math.min(distToLowY, distToHighY);
float distToAnyZ = Math.min(distToLowZ, distToHighZ);
//figure out which two differences are the smallest
AxisRelation clickX, clickY, clickZ;
if((distToAnyX < distToAnyZ) && (distToAnyY < distToAnyZ)) {
clickX = lowOrHigh(distToLowX);
clickY = lowOrHigh(distToLowY);
clickZ = AxisRelation.PARALLEL;
} else if((distToAnyX < distToAnyY) && (distToAnyZ < distToAnyY)) {
clickX = lowOrHigh(distToLowX);
clickY = AxisRelation.PARALLEL;
clickZ = lowOrHigh(distToLowZ);
} else {
clickX = AxisRelation.PARALLEL;
clickY = lowOrHigh(distToLowY);
clickZ = lowOrHigh(distToLowZ);
}
return LOOKUP.getOrDefault(key(clickX, clickY, clickZ), DOWN_SOUTH);
}
@Override
public String asString() {
return name().toLowerCase(Locale.ROOT);
}
//if you imagine moving along this edge, your coordinates:
public enum AxisRelation {
//change along this axis
PARALLEL,
//stay fixed along this axis, with the coordinate being the more negative possibility
LOW_SIDE,
//stay fixed along this axis, with the coordinate being the more positive possibility
HIGH_SIDE
}
private static AxisRelation lowOrHigh(float distToLow) {
return (distToLow < 0.5f) ? AxisRelation.LOW_SIDE : AxisRelation.HIGH_SIDE;
}
}

View File

@ -1,45 +1,64 @@
{ {
"variants": { "variants": {
"facing=east,half=bottom": { "facing=down_east": {
"model": "templates:slope_special", "model": "templates:slope_special",
"uvlock": true, "uvlock": true,
"y": 270 "y": 270
}, },
"facing=north,half=bottom": { "facing=down_north": {
"model": "templates:slope_special", "model": "templates:slope_special",
"uvlock": true, "uvlock": true,
"y": 180 "y": 180
}, },
"facing=south,half=bottom": { "facing=down_south": {
"model": "templates:slope_special" "model": "templates:slope_special"
}, },
"facing=west,half=bottom": { "facing=down_west": {
"model": "templates:slope_special", "model": "templates:slope_special",
"uvlock": true, "uvlock": true,
"y": 90 "y": 90
}, },
"facing=east,half=top": { "facing=up_east": {
"model": "templates:slope_special", "model": "templates:slope_special",
"uvlock": true, "uvlock": true,
"x": 180, "x": 180,
"y": 90 "y": 90
}, },
"facing=north,half=top": { "facing=up_north": {
"model": "templates:slope_special", "model": "templates:slope_special",
"uvlock": true, "uvlock": true,
"x": 180 "x": 180
}, },
"facing=south,half=top": { "facing=up_south": {
"model": "templates:slope_special", "model": "templates:slope_special",
"uvlock": true, "uvlock": true,
"x": 180, "x": 180,
"y": 180 "y": 180
}, },
"facing=west,half=top": { "facing=up_west": {
"model": "templates:slope_special", "model": "templates:slope_special",
"uvlock": true, "uvlock": true,
"x": 180, "x": 180,
"y": 270 "y": 270
},
"facing=north_east": {
"model": "templates:slope_side_special",
"uvlock": true,
"y": 270
},
"facing=north_west": {
"model": "templates:slope_side_special",
"uvlock": true,
"y": 180
},
"facing=south_east": {
"model": "templates:slope_side_special",
"uvlock": true
},
"facing=south_west": {
"model": "templates:slope_side_special",
"uvlock": true,
"y": 90
} }
} }
} }