diff --git a/no.png b/no.png new file mode 100644 index 0000000..b343f13 Binary files /dev/null and b/no.png differ diff --git a/src/client/java/com/straice/smoothdoors/client/anim/FenceGateAnimation.java b/src/client/java/com/straice/smoothdoors/client/anim/FenceGateAnimation.java index 8cb1b6d..3330326 100644 --- a/src/client/java/com/straice/smoothdoors/client/anim/FenceGateAnimation.java +++ b/src/client/java/com/straice/smoothdoors/client/anim/FenceGateAnimation.java @@ -1,5 +1,6 @@ package com.straice.smoothdoors.client.anim; +import it.unimi.dsi.fastutil.longs.Long2FloatOpenHashMap; import net.minecraft.block.BlockState; import net.minecraft.block.FenceGateBlock; import net.minecraft.client.MinecraftClient; @@ -12,8 +13,10 @@ import net.minecraft.client.render.model.BlockModelPart; import net.minecraft.client.render.model.BlockStateModel; import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.RotationAxis; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.random.Random; import java.util.ArrayList; @@ -24,6 +27,10 @@ final class FenceGateAnimation { private static final float POST_EDGE = 2.0f / 16.0f; private static final float EDGE_EPS = 1.0e-4f; + private static final float ANGLE_EPS = 1.0e-3f; + + private static final Long2FloatOpenHashMap GATE_SIGNS = new Long2FloatOpenHashMap(); + private static final Long2FloatOpenHashMap LAST_ANGLES = new Long2FloatOpenHashMap(); private FenceGateAnimation() {} @@ -55,10 +62,13 @@ final class FenceGateAnimation { float rightPivotX = leftRightIsX ? (15.0f / 16.0f) : 0.5f; float rightPivotZ = leftRightIsX ? 0.5f : (15.0f / 16.0f); + long key = blockKey(mc, matrices); + float signedAngle = angleDeg * resolveSign(mc, key, facing, leftRightIsX, angleDeg); + if (models.left != null) { matrices.push(); matrices.translate(leftPivotX, 0.0f, leftPivotZ); - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-angleDeg)); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-signedAngle)); matrices.translate(-leftPivotX, 0.0f, -leftPivotZ); BlockModelRenderer.render(matrices.peek(), consumer, models.left, r, g, b, light, overlay); matrices.pop(); @@ -67,13 +77,78 @@ final class FenceGateAnimation { if (models.right != null) { matrices.push(); matrices.translate(rightPivotX, 0.0f, rightPivotZ); - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(angleDeg)); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(signedAngle)); matrices.translate(-rightPivotX, 0.0f, -rightPivotZ); BlockModelRenderer.render(matrices.peek(), consumer, models.right, r, g, b, light, overlay); matrices.pop(); } } + private static long blockKey(MinecraftClient mc, MatrixStack matrices) { + Vec3d camPos = mc.gameRenderer.getCamera().getPos(); + var posMat = matrices.peek().getPositionMatrix(); + double worldX = camPos.x + posMat.m30(); + double worldY = camPos.y + posMat.m31(); + double worldZ = camPos.z + posMat.m32(); + int blockX = (int) Math.round(worldX); + int blockY = (int) Math.round(worldY); + int blockZ = (int) Math.round(worldZ); + return BlockPos.asLong(blockX, blockY, blockZ); + } + + private static float resolveSign(MinecraftClient mc, long key, Direction facing, + boolean leftRightIsX, float angleDeg) { + float prevAngle = LAST_ANGLES.containsKey(key) ? LAST_ANGLES.get(key) : angleDeg; + float sign = GATE_SIGNS.containsKey(key) ? GATE_SIGNS.get(key) : 0.0f; + boolean opening = angleDeg > prevAngle + ANGLE_EPS; + boolean closing = angleDeg < prevAngle - ANGLE_EPS; + + if (sign == 0.0f && opening && mc.player != null) { + sign = computeSign(mc, key, facing, leftRightIsX); + GATE_SIGNS.put(key, sign); + } + + if (sign == 0.0f && angleDeg > ANGLE_EPS && mc.player != null) { + sign = computeSign(mc, key, facing, leftRightIsX); + GATE_SIGNS.put(key, sign); + } + + if (closing && angleDeg <= ANGLE_EPS) { + GATE_SIGNS.remove(key); + LAST_ANGLES.remove(key); + return 1.0f; + } + + LAST_ANGLES.put(key, angleDeg); + return (sign == 0.0f) ? 1.0f : sign; + } + + private static float computeSign(MinecraftClient mc, long key, Direction facing, boolean leftRightIsX) { + if (mc.player == null) return 1.0f; + + BlockPos pos = BlockPos.fromLong(key); + double centerX = pos.getX() + 0.5; + double centerZ = pos.getZ() + 0.5; + double dx = mc.player.getX() - centerX; + double dz = mc.player.getZ() - centerZ; + + int facingX = facing.getOffsetX(); + int facingZ = facing.getOffsetZ(); + double dot = dx * facingX + dz * facingZ; + float side; + if (dot > 0.0) { + side = 1.0f; + } else if (dot < 0.0) { + side = -1.0f; + } else { + Direction playerFacing = mc.player.getHorizontalFacing(); + int facingDot = playerFacing.getOffsetX() * facingX + playerFacing.getOffsetZ() * facingZ; + side = (facingDot >= 0) ? 1.0f : -1.0f; + } + + return leftRightIsX ? -side * facingZ : side * facingX; + } + private static FenceGateModels splitFenceGateModels(BlockStateModel model, boolean leftRightIsX) { List parts = model.getParts(Random.create(42L)); List posts = new ArrayList<>(); diff --git a/tex.png b/tex.png new file mode 100644 index 0000000..4d7994d Binary files /dev/null and b/tex.png differ diff --git a/vacio.png b/vacio.png new file mode 100644 index 0000000..9998ce4 Binary files /dev/null and b/vacio.png differ