diff --git a/src/main/java/io/github/cottonmc/templates/TemplatesClient.java b/src/main/java/io/github/cottonmc/templates/TemplatesClient.java index 9ddf320..bb467ab 100644 --- a/src/main/java/io/github/cottonmc/templates/TemplatesClient.java +++ b/src/main/java/io/github/cottonmc/templates/TemplatesClient.java @@ -89,7 +89,8 @@ public class TemplatesClient implements ClientModInitializer { provider.addTemplateModel(Templates.id("lever_on_special"), new UnbakedJsonRetexturedModel(Templates.id("block/lever_on"))); //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 provider.addTemplateModel(Templates.id("button_inventory_special"), new UnbakedAutoRetexturedModel(new Identifier("block/button_inventory"))); diff --git a/src/main/java/io/github/cottonmc/templates/block/TemplateSlopeBlock.java b/src/main/java/io/github/cottonmc/templates/block/TemplateSlopeBlock.java index fc0494c..27aea82 100644 --- a/src/main/java/io/github/cottonmc/templates/block/TemplateSlopeBlock.java +++ b/src/main/java/io/github/cottonmc/templates/block/TemplateSlopeBlock.java @@ -1,19 +1,15 @@ package io.github.cottonmc.templates.block; import com.google.common.base.MoreObjects; -import io.github.cottonmc.templates.Templates; -import io.github.cottonmc.templates.api.TemplateInteractionUtil; +import io.github.cottonmc.templates.util.EdgeDirection; import io.github.cottonmc.templates.util.StairShapeMaker; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.ShapeContext; -import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.enums.BlockHalf; import net.minecraft.item.ItemPlacementContext; import net.minecraft.state.StateManager; -import net.minecraft.state.property.DirectionProperty; import net.minecraft.state.property.EnumProperty; -import net.minecraft.state.property.Properties; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; @@ -22,14 +18,14 @@ import net.minecraft.world.BlockView; import javax.annotation.Nullable; public class TemplateSlopeBlock extends WaterloggableTemplateBlock { - public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; - public static final EnumProperty HALF = Properties.BLOCK_HALF; + public static final EnumProperty FACING = EnumProperty.of("facing", EdgeDirection.class); private static final VoxelShape[] shapes = new VoxelShape[8]; private static int shapeIndex(Direction dir, BlockHalf half) { return dir.getHorizontal() + (half == BlockHalf.TOP ? 4 : 0); } static { + //TODO for(BlockHalf half : BlockHalf.values()) { for(Direction d : Direction.values()) { if(d.getHorizontal() == -1) continue; @@ -40,36 +36,37 @@ public class TemplateSlopeBlock extends WaterloggableTemplateBlock { public TemplateSlopeBlock(Settings settings) { super(settings); - setDefaultState(getDefaultState().with(FACING, Direction.NORTH).with(HALF, BlockHalf.BOTTOM)); + setDefaultState(getDefaultState().with(FACING, EdgeDirection.DOWN_NORTH)); } @Override protected void appendProperties(StateManager.Builder builder) { - super.appendProperties(builder.add(FACING, HALF)); + super.appendProperties(builder.add(FACING)); } @Nullable @Override public BlockState getPlacementState(ItemPlacementContext ctx) { + EdgeDirection.guessFromHitResult(ctx.getHitPos(), ctx.getBlockPos()); + BlockState sup = super.getPlacementState(ctx); - if(sup != null) sup = sup - .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; - }); + if(sup != null) sup = sup.with(FACING, EdgeDirection.guessFromHitResult(ctx.getHitPos(), ctx.getBlockPos())); return sup; } @Override 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 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 } } diff --git a/src/main/java/io/github/cottonmc/templates/model/MeshTransformUtil.java b/src/main/java/io/github/cottonmc/templates/model/MeshTransformUtil.java index dd146cd..52c3caf 100644 --- a/src/main/java/io/github/cottonmc/templates/model/MeshTransformUtil.java +++ b/src/main/java/io/github/cottonmc/templates/model/MeshTransformUtil.java @@ -75,8 +75,14 @@ public class MeshTransformUtil { 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())); + //permute cullface Direction cull = quad.cullFace(); if(cull != null) quad.cullFace(facePermutation.get(cull)); diff --git a/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java b/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java index 9ec2fc2..8e00e26 100644 --- a/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java +++ b/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java @@ -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.MeshBuilder; 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 java.util.function.Function; +import net.minecraft.util.math.RotationAxis; +import org.joml.Matrix4f; 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_BOTTOM = Direction.DOWN.ordinal() + 1; - public static Mesh make() { + public static Mesh makeUpright() { Renderer renderer = TemplatesClient.getFabricRenderer(); MeshBuilder builder = renderer.meshBuilder(); @@ -56,4 +54,11 @@ public class SlopeBaseMesh { .emit(); 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)); + } } diff --git a/src/main/java/io/github/cottonmc/templates/util/EdgeDirection.java b/src/main/java/io/github/cottonmc/templates/util/EdgeDirection.java new file mode 100644 index 0000000..9810ea2 --- /dev/null +++ b/src/main/java/io/github/cottonmc/templates/util/EdgeDirection.java @@ -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 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; + } +} diff --git a/src/main/resources/assets/templates/blockstates/slope.json b/src/main/resources/assets/templates/blockstates/slope.json index 992a2d7..55cd966 100644 --- a/src/main/resources/assets/templates/blockstates/slope.json +++ b/src/main/resources/assets/templates/blockstates/slope.json @@ -1,45 +1,64 @@ { "variants": { - "facing=east,half=bottom": { + "facing=down_east": { "model": "templates:slope_special", "uvlock": true, "y": 270 }, - "facing=north,half=bottom": { + "facing=down_north": { "model": "templates:slope_special", "uvlock": true, "y": 180 }, - "facing=south,half=bottom": { + "facing=down_south": { "model": "templates:slope_special" }, - "facing=west,half=bottom": { + "facing=down_west": { "model": "templates:slope_special", "uvlock": true, "y": 90 }, - "facing=east,half=top": { + "facing=up_east": { "model": "templates:slope_special", "uvlock": true, "x": 180, "y": 90 }, - "facing=north,half=top": { + "facing=up_north": { "model": "templates:slope_special", "uvlock": true, "x": 180 }, - "facing=south,half=top": { + "facing=up_south": { "model": "templates:slope_special", "uvlock": true, "x": 180, "y": 180 }, - "facing=west,half=top": { + "facing=up_west": { "model": "templates:slope_special", "uvlock": true, "x": 180, "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 } } } \ No newline at end of file