diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/api/Bendable.java b/common/src/main/java/com/zigythebird/bendable_cuboids/api/Bendable.java new file mode 100644 index 0000000..2c6bb36 --- /dev/null +++ b/common/src/main/java/com/zigythebird/bendable_cuboids/api/Bendable.java @@ -0,0 +1,5 @@ +package com.zigythebird.bendable_cuboids.api; + +public interface Bendable { + float getBend(); +} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/api/BendableCube.java b/common/src/main/java/com/zigythebird/bendable_cuboids/api/BendableCube.java new file mode 100644 index 0000000..1f5c57b --- /dev/null +++ b/common/src/main/java/com/zigythebird/bendable_cuboids/api/BendableCube.java @@ -0,0 +1,54 @@ +package com.zigythebird.bendable_cuboids.api; + +import com.zigythebird.bendable_cuboids.impl.Plane; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import org.joml.Matrix4f; + +/** + * Should be pretty self-explanatory... + * Bend XYZ are the coordinates of the bend's center + * If you don't know the math behind it, don't try to edit. + *

+ * Use {@link BendableCube#applyBend} to bend the cube + */ +public interface BendableCube extends Bendable { + /** + * Apply bend on this cuboid + * Values are in radians + * @param bendValue bend value (Same as rotX) + * @return Transformation matrix for transforming children + */ + Matrix4f applyBend(float bendValue); + + default Matrix4f applyBendDegrees(float bendValue) { + return applyBend(bendValue * Mth.DEG_TO_RAD); + } + + Direction getBendDirection(); + + float getBendX(); + float getBendY(); + float getBendZ(); + + Plane getBasePlane(); + Plane getOtherPlane(); + + /** + * Distance between the two opposite surface of the cuboid. + * Calculate two plane distance is inefficient. + * Try to override it (If you have size) + * @return the size of the cube + */ + float bendHeight(); + + default boolean isBendInverted() { + return getBendDirection() == Direction.UP || getBendDirection() == Direction.SOUTH || getBendDirection() == Direction.EAST; + } + + default void rebuild(Direction direction) { + rebuild(direction, -1); + } + + void rebuild(Direction direction, int pivot); +} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/api/BendableModelPart.java b/common/src/main/java/com/zigythebird/bendable_cuboids/api/BendableModelPart.java new file mode 100644 index 0000000..6bf020a --- /dev/null +++ b/common/src/main/java/com/zigythebird/bendable_cuboids/api/BendableModelPart.java @@ -0,0 +1,11 @@ +package com.zigythebird.bendable_cuboids.api; + +import org.jetbrains.annotations.Nullable; + +public interface BendableModelPart { + /** + * Get a cuboid, and cast it to {@link BendableCube} + */ + @Nullable + BendableCube bc$getCuboid(int index); +} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/api/ModelPartAccessor.java b/common/src/main/java/com/zigythebird/bendable_cuboids/api/ModelPartAccessor.java deleted file mode 100644 index 5480743..0000000 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/api/ModelPartAccessor.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.zigythebird.bendable_cuboids.api; - -import com.zigythebird.bendable_cuboids.impl.accessors.IModelPartAccessor; -import net.minecraft.client.model.geom.ModelPart; - -import java.util.List; -import java.util.Map; -import java.util.Optional; - -/** - * Access to children and cuboids in {@link ModelPart} - * Don't have to reinterpret the object... - */ -public final class ModelPartAccessor { - - public static Map getChildren(ModelPart modelPart){ - return ((IModelPartAccessor)modelPart).bendableCuboids$getChildren(); - } - - /** - * Get a cuboid, and cast it to {@link MutableCuboid} - */ - public static Optional optionalGetCuboid(ModelPart modelPart, int index){ - if(modelPart == null || getCuboids(modelPart) == null || getCuboids(modelPart).size() <= index) return Optional.empty(); - return Optional.of((MutableCuboid)getCuboids(modelPart).get(index)); - } - - public static List getCuboids(ModelPart modelPart){ - return ((IModelPartAccessor)modelPart).bendableCuboids$getCuboids(); - } -} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/api/MutableCuboid.java b/common/src/main/java/com/zigythebird/bendable_cuboids/api/MutableCuboid.java deleted file mode 100644 index 8b6bed2..0000000 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/api/MutableCuboid.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.zigythebird.bendable_cuboids.api; - -import com.zigythebird.bendable_cuboids.impl.BendableCuboid; -import com.zigythebird.bendable_cuboids.impl.BendableCuboidData; -import net.minecraft.util.Tuple; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Function; - -public interface MutableCuboid { - - /** - * Register a mutator to a cuboid - * @param name registration name - * @param builder BendableCuboid builder - * @return is the registration success - */ - boolean bendableCuboids$registerMutator(String name, Function builder); - - /** - * Unregister a mutator - * @param name registration name - * @return could unregister something - */ - boolean bendableCuboids$unregisterMutator(String name); - - /** - * Get the active mutator and its identifier - * @return null, if no active - */ - @Nullable - Tuple bendableCuboids$getActiveMutator(); - - /** - * Check if mutator with key exists - * @param key key - * @return is the mutator registered (even if not active) - */ - boolean bendableCuboids$hasMutator(String key); - - @Nullable - Function bendableCuboids$getCuboidBuilder(String key); - - /** - * Get a mutator - * @param name mutator identifier - * @return null, if no mutator exists or created - */ - @Nullable - @Deprecated - //it can be removed in any future version - BendableCuboid bendableCuboids$getMutator(String name); - - /** - * Get a mutator and make it the active - * @param name mutator identifier - * @return null, if no registered - */ - @Nullable - BendableCuboid bendableCuboids$getAndActivateMutator(@Nullable String name); - - void bendableCuboids$copyStateFrom(MutableCuboid other); - -} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendUtil.java b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendUtil.java index 941ab46..c68dc0b 100644 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendUtil.java +++ b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendUtil.java @@ -2,6 +2,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; +import com.zigythebird.bendable_cuboids.api.BendableCube; import com.zigythebird.bendable_cuboids.impl.compatibility.PlayerBendHelper; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.PlayerModel; @@ -13,9 +14,9 @@ public class BendUtil { private static final Vector3f Z_AXIS = new Vector3f(0, 0, 1); - public static BendApplier getBend(BendableCuboid cuboid, float bendValue) { + public static BendApplier getBend(BendableCube cuboid, float bendValue) { return getBend(cuboid.getBendX(), cuboid.getBendY(), cuboid.getBendZ(), - cuboid.basePlane, cuboid.otherPlane, false, cuboid.bendHeight(), bendValue); + cuboid.getBasePlane(), cuboid.getOtherPlane(), false, cuboid.bendHeight(), bendValue); } /** @@ -33,13 +34,13 @@ public static BendApplier getBend(float bendX, float bendY, float bendZ, Plane b return new BendApplier(transformMatrix, pos -> { float distFromBase = Math.abs(basePlane.distanceTo(pos)); float distFromOther = Math.abs(otherPlane.distanceTo(pos)); - float s = (float) Math.clamp(Math.tan(finalBend/2)*pos.z, -2f, 2f); + float s = (float) Math.tan(finalBend/2)*pos.z; if (mirrorBend) { float temp = distFromBase; distFromBase = distFromOther; distFromOther = temp; } - float v = halfSize - (s < 0 ? Math.abs(s)/2 : Math.abs(s)); + float v = halfSize - (s < 0 ? Math.min(Math.abs(s)/2, 1) : Math.abs(s)); if (distFromBase < distFromOther) { if (distFromBase + distFromOther <= bendHeight && distFromBase > v) pos.y = bendY + s; @@ -54,9 +55,9 @@ else if (distFromBase + distFromOther <= bendHeight && distFromOther > v) { }); } - public static BendApplier getBendLegacy(BendableCuboid cuboid, float bendValue) { + public static BendApplier getBendLegacy(BendableCube cuboid, float bendValue) { return getBendLegacy(cuboid.getBendDirection(), cuboid.getBendX(), cuboid.getBendY(), cuboid.getBendZ(), - cuboid.basePlane, cuboid.otherPlane, cuboid.isBendInverted(), false, cuboid.bendHeight(), bendValue); + cuboid.getBasePlane(), cuboid.getOtherPlane(), cuboid.isBendInverted(), false, cuboid.bendHeight(), bendValue); } /** diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendableCuboid.java b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendableCuboid.java deleted file mode 100644 index 2a37c86..0000000 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendableCuboid.java +++ /dev/null @@ -1,186 +0,0 @@ -package com.zigythebird.bendable_cuboids.impl; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.zigythebird.bendable_cuboids.impl.compatibility.PlayerBendHelper; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import org.joml.Matrix4f; -import org.joml.Vector3f; -import org.joml.Vector4f; - -import java.util.function.Function; - -/** - * Should be pretty self-explanatory... - * Bend XYZ are the coordinates of the bend's center - * If you don't know the math behind it, don't try to edit. - *

- * Use {@link BendableCuboid#applyBend} to bend the cube - */ -public class BendableCuboid { - protected final Quad[] sides; - protected final RememberingPos[] positions; - - //to shift the matrix to the center axis - protected final float fixX; - protected final float fixY; - protected final float fixZ; - protected final Direction direction; - protected final Plane basePlane; - protected final Plane otherPlane; - protected final float fullSize; - - protected float bend; - - /** - * To see how you can make existing model parts bendable look at {@link PlayerBendHelper} - * Or you can use {@link BendableCuboidBuilder#build}. - */ - public BendableCuboid(Quad[] sides, RememberingPos[] positions, float fixX, float fixY, float fixZ, Direction direction, Plane basePlane, Plane otherPlane, float fullSize) { - this.sides = sides; - this.positions = positions; - this.fixX = fixX; - this.fixY = fixY; - this.fixZ = fixZ; - this.direction = direction; - this.basePlane = basePlane; - this.otherPlane = otherPlane; - this.fullSize = fullSize; - - this.applyBend(0);//Init values to render - } - - /** - * Apply bend on this cuboid - * Values are in radians - * @param bendValue bend value (Same as rotX) - * @return Transformation matrix for transforming children - */ - public Matrix4f applyBend(float bendValue) { - this.bend = bendValue; - BendApplier bendApplier = BendUtil.getBend(this, bendValue); - this.iteratePositions(bendApplier.consumer()); - return bendApplier.matrix4f(); - } - - public Matrix4f applyBendDegrees(float bendValue) { - return applyBend(bendValue * Mth.DEG_TO_RAD); - } - - public Direction getBendDirection() { - return this.direction; - } - - public float getBendX() { - return fixX; - } - - public float getBendY() { - return fixY; - } - - public float getBendZ() { - return fixZ; - } - - public Plane getBasePlane() { - return basePlane; - } - - public Plane getOtherSidePlane() { - return otherPlane; - } - - /** - * Distance between the two opposite surface of the cuboid. - * Calculate two plane distance is inefficient. - * Try to override it (If you have size) - * @return the size of the cube - */ - public float bendHeight() { - return fullSize; - } - - public boolean isBendInverted() { - return getBendDirection() == Direction.UP || getBendDirection() == Direction.SOUTH || getBendDirection() == Direction.EAST; - } - - public void iteratePositions(Function function) { - for(RememberingPos pos: positions){ - pos.setPos(function.apply(pos.getOriginalPos())); - } - } - - public float getBend() { - return bend; - } - - public void render(PoseStack.Pose matrices, VertexConsumer vertexConsumer, int light, int overlay, int color) { - for(Quad quad:sides) { - quad.render(matrices, vertexConsumer, light, overlay, color); - } - } - - public void copyState(BendableCuboid other) { - if(other instanceof BendableCuboid b){ - this.applyBend(b.bend); //This works only in J16 or higher - } - } - - /* - * A replica of {@link ModelPart.Quad} - * with IVertex and render() - */ - public static class Quad { - public final RepositionableVertex[] vertices; - - public Quad(RememberingPos[] vertices, float u1, float v1, float u2, float v2, boolean flip) { - this.vertices = new RepositionableVertex[4]; - this.vertices[0] = new RepositionableVertex(u2, v1, vertices[0]); - this.vertices[1] = new RepositionableVertex(u1, v1, vertices[1]); - this.vertices[2] = new RepositionableVertex(u1, v2, vertices[2]); - this.vertices[3] = new RepositionableVertex(u2, v2, vertices[3]); - if (flip){ - int i = vertices.length; - - for(int j = 0; j < i / 2; ++j) { - RepositionableVertex vertex = this.vertices[j]; - this.vertices[j] = this.vertices[i - 1 - j]; - this.vertices[i - 1 - j] = vertex; - } - } - } - - public void render(PoseStack.Pose matrices, VertexConsumer vertexConsumer, int light, int overlay, int color) { - Vector3f normal = this.getDirection(); - normal.mul(matrices.normal()); - - for (int i = 0; i != 4; ++i){ - IVertex vertex = this.vertices[i]; - Vector3f vertexPos = vertex.getPos(); - Vector4f pos = new Vector4f(vertexPos.x/16f, vertexPos.y/16f, vertexPos.z/16f, 1); - pos.mul(matrices.pose()); - vertexConsumer.addVertex(pos.x, pos.y, pos.z, color, vertex.getU(), vertex.getV(), overlay, light, normal.x, normal.y, normal.z); - } - } - - /** - * calculate the normal vector from the vertices' coordinates with cross-product - * @return the normal vector (direction) - */ - private Vector3f getDirection() { - Vector3f buf = new Vector3f(vertices[3].getPos()); - buf.mul(-1); - Vector3f vecB = new Vector3f(vertices[1].getPos()); - vecB.add(buf); - buf = new Vector3f(vertices[2].getPos()); - buf.mul(-1); - Vector3f vecA = new Vector3f(vertices[0].getPos()); - vecA.add(buf); - vecA.cross(vecB); - // Return the cross-product, if it's zero then return anything non-zero to not cause crash... - return vecA.normalize().isFinite() ? vecA : Direction.NORTH.step(); - } - } -} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendableCuboidBuilder.java b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendableCuboidBuilder.java deleted file mode 100644 index 34226db..0000000 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendableCuboidBuilder.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.zigythebird.bendable_cuboids.impl; - -import net.minecraft.core.Direction; -import org.joml.Vector3f; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; - -public class BendableCuboidBuilder { - public Direction direction; - - public BendableCuboidBuilder setDirection(Direction d) { - this.direction = d; - return this; - } - - public BendableCuboid build(BendableCuboidData data) { - ArrayList planes = new ArrayList<>(); - HashMap positions = new HashMap<>(); - float minX = data.x, minY = data.y, minZ = data.z, maxX = data.x + data.sizeX, maxY = data.y + data.sizeY, maxZ = data.z + data.sizeZ; - float pminX = data.x - data.extraX, pminY = data.y - data.extraY, pminZ = data.z - data.extraZ, pmaxX = maxX + data.extraX, pmaxY = maxY + data.extraY, pmaxZ = maxZ + data.extraZ; - if(data.mirror){ - float tmp = pminX; - pminX = pmaxX; - pmaxX = tmp; - } - - //this is copy from MC's cuboid constructor - Vector3f vertex1 = new Vector3f(pminX, pminY, pminZ); //west south down - Vector3f vertex2 = new Vector3f(pmaxX, pminY, pminZ); //east south down - Vector3f vertex3 = new Vector3f(pmaxX, pmaxY, pminZ); //east south up - Vector3f vertex4 = new Vector3f(pminX, pmaxY, pminZ); //west south up - Vector3f vertex5 = new Vector3f(pminX, pminY, pmaxZ); //west north down - Vector3f vertex6 = new Vector3f(pmaxX, pminY, pmaxZ); //east north down - Vector3f vertex7 = new Vector3f(pmaxX, pmaxY, pmaxZ); //east north up - Vector3f vertex8 = new Vector3f(pminX, pmaxY, pmaxZ); //west north up - - int j = data.u; - int k = (int) (data.u + data.sizeZ); - int l = (int) (data.u + data.sizeZ + data.sizeX); - int m = (int) (data.u + data.sizeZ + data.sizeX + data.sizeX); - int n = (int) (data.u + data.sizeZ + data.sizeX + data.sizeZ); - int o = (int) (data.u + data.sizeZ + data.sizeX + data.sizeZ + data.sizeX); - int p = data.v; - int q = (int) (data.v + data.sizeZ); - int r = (int) (data.v + data.sizeZ + data.sizeY); - float textureWidth = data.textureWidth; - float textureHeight = data.textureHeight; - boolean mirror = data.mirror; - if (data.visibleFaces.contains(Direction.DOWN)) createAndAddQuads(planes, positions, new Vector3f[]{vertex6, vertex5, vertex2}, k, p, l, q, textureWidth, textureHeight, mirror); //down - if (data.visibleFaces.contains(Direction.UP)) createAndAddQuads(planes, positions, new Vector3f[]{vertex3, vertex4, vertex7}, l, q, m, p, textureWidth, textureHeight, mirror); //up - if (data.visibleFaces.contains(Direction.WEST)) createAndAddQuads(planes, positions, new Vector3f[]{vertex1, vertex5, vertex4}, j, q, k, r, textureWidth, textureHeight, mirror); //west - if (data.visibleFaces.contains(Direction.NORTH)) createAndAddQuads(planes, positions, new Vector3f[]{vertex2, vertex1, vertex3}, k, q, l, r, textureWidth, textureHeight, mirror); //north - if (data.visibleFaces.contains(Direction.EAST)) createAndAddQuads(planes, positions, new Vector3f[]{vertex6, vertex2, vertex7}, l, q, n, r, textureWidth, textureHeight, mirror); //east - if (data.visibleFaces.contains(Direction.SOUTH)) createAndAddQuads(planes, positions, new Vector3f[]{vertex5, vertex6, vertex8}, n, q, o, r, textureWidth, textureHeight, mirror); //south - - Vector3f pivot = new Vector3f(0, 0, 0); - if (data.pivot >= 0) { - float size = direction.step().mul(maxX - minX, maxY - minY, maxZ - minZ).length(); - if (data.pivot <= size) { - pivot = direction.step().mul(size - (data.pivot * 2)); - vertex7 = vertex7.sub(pivot); - } - } - boolean bl = direction == Direction.UP || direction == Direction.SOUTH || direction == Direction.EAST; - Plane aPlane = new Plane(direction.step(), vertex7); - Plane bPlane = new Plane(direction.step(), vertex1); - float fullSize = - direction.step().dot(vertex1) + direction.step().dot(vertex7); - float bendX = (data.sizeX + data.x + data.x - pivot.x())/2; - float bendY = (data.sizeY + data.y + data.y - pivot.y())/2; - float bendZ = (data.sizeZ + data.z + data.z - pivot.z())/2; - return new BendableCuboid(planes.toArray(new BendableCuboid.Quad[0]), positions.values().toArray(new RememberingPos[0]), bendX, bendY, bendZ, direction, bl ? aPlane : bPlane, bl ? bPlane : aPlane, fullSize); - } - - //edge[2] can be calculated from edge 0, 1, 3... - protected void createAndAddQuads(Collection quads, HashMap positions, Vector3f[] edges, int u1, int v1, int u2, int v2, float textureWidth, float textureHeight, boolean mirror) { - int du = u2 < u1 ? 1 : -1; - int dv = v1 < v2 ? 1 : -1; - - Vector3f origin = edges[0]; - Vector3f vecU = new Vector3f(edges[1]).sub(origin); - Vector3f vecV = new Vector3f(edges[2]).sub(origin); - - float uFracScale = 1.0f / (u1 - u2); - Vector3f uStep = vecU.mul(du * uFracScale); - - float vFracScale = 1.0f / (v2 - v1); - Vector3f vStep = vecV.mul(dv * vFracScale); - - Vector3f uPos = new Vector3f(origin); - - for (int localU = u2; localU != u1; localU += du) { - Vector3f nextUPos = new Vector3f(uPos).add(uStep); - - Vector3f vPos = new Vector3f(uPos); - Vector3f nextVPos = new Vector3f(nextUPos); - - for (int localV = v1; localV != v2; localV += dv) { - int localU2 = localU + du; - int localV2 = localV + dv; - - RememberingPos rp3 = getOrCreate(positions, vPos); - RememberingPos rp0 = getOrCreate(positions, nextVPos); - vPos.add(vStep); - nextVPos.add(vStep); - RememberingPos rp2 = getOrCreate(positions, vPos); - RememberingPos rp1 = getOrCreate(positions, nextVPos); - - quads.add(new BendableCuboid.Quad(new RememberingPos[]{rp3, rp0, rp1, rp2}, localU2 / textureWidth, localV / textureHeight, localU / textureWidth, localV2 / textureHeight, mirror)); - } - uPos = nextUPos; - } - } - - protected RememberingPos getOrCreate(HashMap positions, Vector3f pos) { - return positions.computeIfAbsent(pos, p -> new RememberingPos(new Vector3f(p))); - } -} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendableCuboidData.java b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendableCuboidData.java index 7acda0b..b098b9a 100644 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendableCuboidData.java +++ b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/BendableCuboidData.java @@ -4,41 +4,12 @@ import java.util.Set; -public class BendableCuboidData { - /** - * Size parameters - */ - public float x, y, z, sizeX, sizeY, sizeZ; - public float extraX, extraY, extraZ; - public int u, v; - public boolean mirror = false; - public float textureWidth, textureHeight; //That will be int - public int pivot; - //public float bendX, bendY, bendZ; - public Set visibleFaces; - - public BendableCuboidData() {} - - public BendableCuboidData(int u, int v, float x, float y, float z, float sizeX, float sizeY, float sizeZ, float extraX, float extraY, float extraZ, boolean mirror, float textureWidth, float textureHeight, Set visibleFaces, int pivot) { - this.u = u; - this.v = v; - this.x = x; - this.y = y; - this.z = z; - this.sizeX = sizeX; - this.sizeY = sizeY; - this.sizeZ = sizeZ; - this.extraX = extraX; - this.extraY = extraY; - this.extraZ = extraZ; - this.mirror = mirror; - this.pivot = pivot; - this.textureWidth = textureWidth; - this.textureHeight = textureHeight; - this.visibleFaces = visibleFaces; - } - - public BendableCuboidData(int u, int v, float x, float y, float z, float sizeX, float sizeY, float sizeZ, float extraX, float extraY, float extraZ, boolean mirror, float textureWidth, float textureHeight, Set visibleFaces) { - this(u, v, x, y, z, sizeX, sizeY, sizeZ, extraX, extraY, extraZ, mirror, textureWidth, textureHeight, visibleFaces, -1); - } +public record BendableCuboidData( + int u, int v, + float sizeX, float sizeY, float sizeZ, + float extraX, float extraY, float extraZ, + boolean mirror, + float textureWidth, float textureHeight, + Set visibleFaces +) { } diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/MutableModelPart.java b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/MutableModelPart.java deleted file mode 100644 index 25998bb..0000000 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/MutableModelPart.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.zigythebird.bendable_cuboids.impl; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.zigythebird.bendable_cuboids.api.ModelPartAccessor; -import com.zigythebird.bendable_cuboids.api.MutableCuboid; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectList; -import net.minecraft.client.model.geom.ModelPart; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Map; - -/** - * ModelPart to support BendableCuboids - *

- * If you want to mutate existing Cuboids, see {@link ModelPartAccessor} and {@link MutableCuboid} - * - * This can be used with {@link BendableCuboid}. - */ -public abstract class MutableModelPart extends ModelPart { - - @Nullable - @Deprecated - private MutableModelPart last = null; - - protected final ObjectList BendableCuboids = new ObjectArrayList<>(); - - public MutableModelPart(List cuboids, Map children) { - super(cuboids, children); - } - - @Override - public void render(PoseStack matrices, VertexConsumer vertices, int light, int overlay, int color) { - super.render(matrices, vertices, light, overlay); - if(!BendableCuboids.isEmpty()){ - matrices.pushPose(); - this.translateAndRotate(matrices); - this.renderBendableCuboids(matrices.last(), vertices, light, overlay, color); - matrices.popPose(); - } - } - - protected void renderBendableCuboids(PoseStack.Pose matrices, VertexConsumer vertexConsumer, int light, int overlay, int color) { - this.BendableCuboids.forEach((cuboid)-> cuboid.render(matrices, vertexConsumer, light, overlay, color)); - } - - public void addBendableCuboid(BendableCuboid cuboid){ - this.BendableCuboids.add(cuboid); - } - -} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/Quad.java b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/Quad.java new file mode 100644 index 0000000..0ad6dc0 --- /dev/null +++ b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/Quad.java @@ -0,0 +1,181 @@ +package com.zigythebird.bendable_cuboids.impl; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import org.joml.Vector3f; +import org.joml.Vector4f; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/* + * A replica of {@link ModelPart.Quad} + * with IVertex and render() + */ +public class Quad { + public final RepositionableVertex[] vertices; + + public Quad(RememberingPos[] vertices, float u1, float v1, float u2, float v2, boolean flip) { + this.vertices = new RepositionableVertex[4]; + this.vertices[0] = new RepositionableVertex(u2, v1, vertices[0]); + this.vertices[1] = new RepositionableVertex(u1, v1, vertices[1]); + this.vertices[2] = new RepositionableVertex(u1, v2, vertices[2]); + this.vertices[3] = new RepositionableVertex(u2, v2, vertices[3]); + if (flip){ + int i = vertices.length; + + for(int j = 0; j < i / 2; ++j) { + RepositionableVertex vertex = this.vertices[j]; + this.vertices[j] = this.vertices[i - 1 - j]; + this.vertices[i - 1 - j] = vertex; + } + } + } + + public void render(PoseStack.Pose matrices, VertexConsumer vertexConsumer, int light, int overlay, int color) { + Vector3f normal = this.getDirection(); + normal.mul(matrices.normal()); + + for (int i = 0; i != 4; ++i){ + IVertex vertex = this.vertices[i]; + Vector3f vertexPos = vertex.getPos(); + Vector4f pos = new Vector4f(vertexPos.x/16f, vertexPos.y/16f, vertexPos.z/16f, 1); + pos.mul(matrices.pose()); + vertexConsumer.addVertex(pos.x, pos.y, pos.z, color, vertex.getU(), vertex.getV(), overlay, light, normal.x, normal.y, normal.z); + } + } + + /** + * calculate the normal vector from the vertices' coordinates with cross-product + * @return the normal vector (direction) + */ + private Vector3f getDirection() { + Vector3f buf = new Vector3f(vertices[3].getPos()); + buf.mul(-1); + Vector3f vecB = new Vector3f(vertices[1].getPos()); + vecB.add(buf); + buf = new Vector3f(vertices[2].getPos()); + buf.mul(-1); + Vector3f vecA = new Vector3f(vertices[0].getPos()); + vecA.add(buf); + vecA.cross(vecB); + // Return the cross-product, if it's zero then return anything non-zero to not cause crash... + return vecA.normalize().isFinite() ? vecA : Direction.NORTH.step(); + } + + // edge[2] can be calculated from edge 0, 1, 3... + public static void createAndAddQuads(List quads, Map positions, Vector3f[] edges, float u1, float v1, float u2, float v2, float textureWidth, float textureHeight, boolean mirror) { + boolean positiveDirection = v2 > v1; + float totalTexHeight = Mth.abs(v2 - v1); + + Vector3f origin = edges[0]; + Vector3f vecV = new Vector3f(edges[2]).sub(origin); + float vFracScale = (v1 == v2) ? 0 : 1.0f / (v2 - v1); + Vector3f vecU = new Vector3f(edges[1]).sub(origin); + float uFracScale = (u1 == u2) ? 0 : 1.0f / (u2 - u1); + + Vector3f vPos = new Vector3f(origin); + Vector3f nextVPos = new Vector3f(edges[1]); + Vector3f vStep = new Vector3f(); + + float[] quadHeights = null; + int segmentHeight = 0; + if (totalTexHeight > 0 && totalTexHeight % 3.0f == 0) { + segmentHeight = (int) (totalTexHeight / 3.0f); + if (segmentHeight > 0) { + quadHeights = new float[2 + segmentHeight]; + quadHeights[0] = segmentHeight; + Arrays.fill(quadHeights, 1, 1 + segmentHeight, 1.0f); + quadHeights[1 + segmentHeight] = segmentHeight; + } + } + + int layerIndex = 0; + + for (float localV = v1; positiveDirection ? localV < v2 : localV > v2; ) { + float dv; + boolean isMiddleSegment = false; + if (quadHeights != null) { + if (layerIndex >= quadHeights.length) { + break; + } + dv = positiveDirection ? quadHeights[layerIndex] : -quadHeights[layerIndex]; + if (layerIndex > 0 && layerIndex <= segmentHeight) { + isMiddleSegment = true; + } + layerIndex++; + } else { + dv = positiveDirection ? 1 : -1; + } + + float localV2 = localV + dv; + if (quadHeights == null) { + if (positiveDirection) { + if (localV2 > v2) { + localV2 = v2; + } + } else { + if (localV2 < v2) { + localV2 = v2; + } + } + } + + float actual_dv = localV2 - localV; + if (actual_dv == 0) break; + vStep.set(vecV).mul(actual_dv * vFracScale); + + if (isMiddleSegment && Mth.abs(u2 - u1) > 1.0f) { + boolean uPositive = u2 > u1; + float du = uPositive ? 1.0f : -1.0f; + + Vector3f uScanPosBottom = new Vector3f(vPos); + Vector3f uScanPosTop = new Vector3f(vPos).add(vStep); + + for (float localU = u2; localU != u1; localU -= du) { + float localU2 = localU - du; + if (uPositive) { + if (localU2 > u2) localU2 = u2; + } else { + if (localU2 < u2) localU2 = u2; + } + if (localU == localU2) break; + + float actual_du = localU2 - localU; + Vector3f uStep = new Vector3f(vecU).mul(actual_du * uFracScale); + + RememberingPos bottomLeft = getOrCreate(positions, uScanPosBottom); + RememberingPos topLeft = getOrCreate(positions, uScanPosTop); + + uScanPosBottom.sub(uStep); + uScanPosTop.sub(uStep); + + RememberingPos bottomRight = getOrCreate(positions, uScanPosBottom); + RememberingPos topRight = getOrCreate(positions, uScanPosTop); + + quads.add(new Quad(new RememberingPos[]{bottomLeft, bottomRight, topRight, topLeft}, localU2 / textureWidth, localV / textureHeight, localU / textureWidth, localV2 / textureHeight, mirror)); + } + + vPos.add(vStep); + nextVPos.add(vStep); + } else { + RememberingPos rp3 = getOrCreate(positions, vPos); + RememberingPos rp0 = getOrCreate(positions, nextVPos); + vPos.add(vStep); + nextVPos.add(vStep); + RememberingPos rp2 = getOrCreate(positions, vPos); + RememberingPos rp1 = getOrCreate(positions, nextVPos); + quads.add(new Quad(new RememberingPos[]{rp3, rp0, rp1, rp2}, u1 / textureWidth, localV / textureHeight, u2 / textureWidth, localV2 / textureHeight, mirror)); + } + + localV = localV2; + } + } + + public static RememberingPos getOrCreate(Map positions, Vector3f pos) { + return positions.computeIfAbsent(pos, p -> new RememberingPos(new Vector3f(p))); + } +} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/accessors/IModelPartAccessor.java b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/accessors/IModelPartAccessor.java deleted file mode 100644 index 1238bd8..0000000 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/accessors/IModelPartAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.zigythebird.bendable_cuboids.impl.accessors; - -import net.minecraft.client.model.geom.ModelPart; - -import java.util.List; -import java.util.Map; - -/** - * Basic operation to access cuboid in ModelPart - */ -public interface IModelPartAccessor { - List bendableCuboids$getCuboids(); - - Map bendableCuboids$getChildren(); //easy to search in it :D -} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/accessors/IPlayerModel.java b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/accessors/IPlayerModel.java deleted file mode 100644 index d7f7e84..0000000 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/accessors/IPlayerModel.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.zigythebird.bendable_cuboids.impl.accessors; - -public interface IPlayerModel { - void bendableCuboids$prepForFirstPersonRender(); - boolean bendableCuboids$isFirstPersonRender(); -} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/compatibility/PlayerBendHelper.java b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/compatibility/PlayerBendHelper.java index b884dcf..fbe7dab 100644 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/impl/compatibility/PlayerBendHelper.java +++ b/common/src/main/java/com/zigythebird/bendable_cuboids/impl/compatibility/PlayerBendHelper.java @@ -1,39 +1,34 @@ package com.zigythebird.bendable_cuboids.impl.compatibility; import com.mojang.blaze3d.vertex.PoseStack; +import com.zigythebird.bendable_cuboids.api.BendableCube; +import com.zigythebird.bendable_cuboids.api.BendableModelPart; import com.zigythebird.bendable_cuboids.impl.BendUtil; -import com.zigythebird.bendable_cuboids.api.ModelPartAccessor; -import com.zigythebird.bendable_cuboids.api.MutableCuboid; -import com.zigythebird.bendable_cuboids.impl.BendableCuboidBuilder; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.core.Direction; -import java.util.Optional; - public class PlayerBendHelper { public static void bend(ModelPart modelPart, float rotation) { - Optional optionalMutableCuboid = ModelPartAccessor.optionalGetCuboid(modelPart, 0); - if (optionalMutableCuboid.isPresent()) { - MutableCuboid cuboid = optionalMutableCuboid.get(); - // Don't enable bend until rotation is bigger than epsilon. - // This should avoid unnecessary heavy calculations. - if (Math.abs(rotation) >= 0.0001f && cuboid.bendableCuboids$hasMutator("bend")) { - cuboid.bendableCuboids$getAndActivateMutator("bend").applyBend(rotation); - } - else cuboid.bendableCuboids$getAndActivateMutator(null); + BendableCube cube = ((BendableModelPart) modelPart).bc$getCuboid(0); + if (cube == null) return; + + // Don't enable bend until rotation is bigger than epsilon. + // This should avoid unnecessary heavy calculations. + if (Math.abs(rotation) >= 0.0001f) { + cube.applyBend(rotation); + } else { + cube.applyBend(0); } } public static void initBend(ModelPart modelPart, Direction direction) { - ModelPartAccessor.optionalGetCuboid(modelPart, 0).ifPresent(mutableModelPart -> mutableModelPart.bendableCuboids$registerMutator("bend", data -> new BendableCuboidBuilder().setDirection(direction).build(data))); + BendableCube cube = ((BendableModelPart) modelPart).bc$getCuboid(0); + if (cube != null) cube.rebuild(direction); } public static void initCapeBend(ModelPart modelPart) { - ModelPartAccessor.optionalGetCuboid(modelPart, 0).ifPresent(mutableModelPart -> mutableModelPart.bendableCuboids$registerMutator("bend", data -> { - data.pivot = 6; - - return new BendableCuboidBuilder().setDirection(Direction.UP).build(data); - })); + BendableCube cube = ((BendableModelPart) modelPart).bc$getCuboid(0); + if (cube != null) cube.rebuild(Direction.UP, 6); } public static void applyTorsoBendToMatrix(PoseStack poseStack, float bend) { diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/CubeMixin.java b/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/CubeMixin.java new file mode 100644 index 0000000..8a6cf16 --- /dev/null +++ b/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/CubeMixin.java @@ -0,0 +1,220 @@ +package com.zigythebird.bendable_cuboids.mixin; + +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.zigythebird.bendable_cuboids.api.BendableCube; +import com.zigythebird.bendable_cuboids.impl.*; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.core.Direction; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.*; +import java.util.function.Function; + +import static com.zigythebird.bendable_cuboids.impl.Quad.createAndAddQuads; + +@Mixin(ModelPart.Cube.class) +public class CubeMixin implements BendableCube { + @Shadow + @Final + public float minX; + @Shadow + @Final + public float minY; + @Shadow + @Final + public float minZ; + @Shadow + @Final + public float maxX; + @Shadow + @Final + public float maxY; + @Shadow + @Final + public float maxZ; + + @Unique + private BendableCuboidData bc$data; + + @Unique + private final Vector3f[] bc$vertices = new Vector3f[8]; + @Unique + private Quad[] sides; + @Unique + private RememberingPos[] positions; + + @Unique + protected float bc$fixX; + @Unique + protected float bc$fixY; + @Unique + protected float bc$fixZ; + @Unique + protected Direction bc$direction; + @Unique + protected Plane bc$basePlane; + @Unique + protected Plane bc$otherPlane; + @Unique + protected float bc$fullSize; + + @Unique + protected float bc$bend; + + @Inject(method = "", at = @At(value = "RETURN")) + private void constructor(int u, int v, float x, float y, float z, float sizeX, float sizeY, float sizeZ, float extraX, float extraY, float extraZ, boolean mirror, float textureWidth, float textureHeight, Set visibleFaces, CallbackInfo ci){ + this.bc$data = new BendableCuboidData(u, v, sizeX, sizeY, sizeZ, extraX, extraY, extraZ, mirror, textureWidth, textureHeight, visibleFaces); + } + + @Override + public void rebuild(Direction direction, int point) { + if (this.sides == null || this.positions == null) bc$build(); + + this.bc$direction = direction; + + Vector3f pivot = new Vector3f(0, 0, 0); + if (point >= 0) { + float size = direction.step().mul(bc$data.sizeX(), bc$data.sizeY(), bc$data.sizeZ()).length(); + if (point <= size) { + pivot = direction.step().mul(size - (point * 2)); + bc$vertices[6] = bc$vertices[6].sub(pivot); + } + } + boolean bl = direction == Direction.UP || direction == Direction.SOUTH || direction == Direction.EAST; + Plane aPlane = new Plane(direction.step(), bc$vertices[6]); + Plane bPlane = new Plane(direction.step(), bc$vertices[0]); + this.bc$basePlane = bl ? aPlane : bPlane; + this.bc$otherPlane = bl ? bPlane : aPlane; + + this.bc$fullSize = -direction.step().dot(bc$vertices[0]) + direction.step().dot(bc$vertices[6]); + this.bc$fixX = (bc$data.sizeX() + minX + minX - pivot.x())/2; + this.bc$fixY = (bc$data.sizeY() + minY + minY - pivot.y())/2; + this.bc$fixZ = (bc$data.sizeZ() + minZ + minZ - pivot.z())/2; + } + + @Unique + private void bc$build() { + List planes = new ArrayList<>(); + Map positions = new HashMap<>(); + float pminX = minX - bc$data.extraX(), pminY = minY - bc$data.extraY(), pminZ = minZ - bc$data.extraZ(), pmaxX = maxX + bc$data.extraX(), pmaxY = maxY + bc$data.extraY(), pmaxZ = maxZ + bc$data.extraZ(); + if (bc$data.mirror()) { + float tmp = pminX; + pminX = pmaxX; + pmaxX = tmp; + } + + //this is copy from MC's cuboid constructor + this.bc$vertices[0] = new Vector3f(pminX, pminY, pminZ); //west south down + this.bc$vertices[1] = new Vector3f(pmaxX, pminY, pminZ); //east south down + this.bc$vertices[2] = new Vector3f(pmaxX, pmaxY, pminZ); //east south up + this.bc$vertices[3] = new Vector3f(pminX, pmaxY, pminZ); //west south up + this.bc$vertices[4] = new Vector3f(pminX, pminY, pmaxZ); //west north down + this.bc$vertices[5] = new Vector3f(pmaxX, pminY, pmaxZ); //east north down + this.bc$vertices[6] = new Vector3f(pmaxX, pmaxY, pmaxZ); //east north up + this.bc$vertices[7] = new Vector3f(pminX, pmaxY, pmaxZ); //west north up + + float j = bc$data.u(); + float k = bc$data.u() + bc$data.sizeZ(); + float l = bc$data.u() + bc$data.sizeZ() + bc$data.sizeX(); + float m = bc$data.u() + bc$data.sizeZ() + bc$data.sizeX() + bc$data.sizeX(); + float n = bc$data.u() + bc$data.sizeZ() + bc$data.sizeX() + bc$data.sizeZ(); + float o = bc$data.u() + bc$data.sizeZ() + bc$data.sizeX() + bc$data.sizeZ() + bc$data.sizeX(); + float p = bc$data.v(); + float q = bc$data.v() + bc$data.sizeZ(); + float r = bc$data.v() + bc$data.sizeZ() + bc$data.sizeY(); + float textureWidth = bc$data.textureWidth(); + float textureHeight = bc$data.textureHeight(); + boolean mirror = bc$data.mirror(); + if (bc$data.visibleFaces().contains(Direction.DOWN)) createAndAddQuads(planes, positions, new Vector3f[]{bc$vertices[5], bc$vertices[4], bc$vertices[1]}, k, p, l, q, textureWidth, textureHeight, mirror); //down + if (bc$data.visibleFaces().contains(Direction.UP)) createAndAddQuads(planes, positions, new Vector3f[]{bc$vertices[2], bc$vertices[3], bc$vertices[6]}, l, q, m, p, textureWidth, textureHeight, mirror); //up + if (bc$data.visibleFaces().contains(Direction.WEST)) createAndAddQuads(planes, positions, new Vector3f[]{bc$vertices[0], bc$vertices[4], bc$vertices[3]}, j, q, k, r, textureWidth, textureHeight, mirror); //west + if (bc$data.visibleFaces().contains(Direction.NORTH)) createAndAddQuads(planes, positions, new Vector3f[]{bc$vertices[1], bc$vertices[0], bc$vertices[2]}, k, q, l, r, textureWidth, textureHeight, mirror); //north + if (bc$data.visibleFaces().contains(Direction.EAST)) createAndAddQuads(planes, positions, new Vector3f[]{bc$vertices[5], bc$vertices[1], bc$vertices[6]}, l, q, n, r, textureWidth, textureHeight, mirror); //east + if (bc$data.visibleFaces().contains(Direction.SOUTH)) createAndAddQuads(planes, positions, new Vector3f[]{bc$vertices[4], bc$vertices[5], bc$vertices[7]}, n, q, o, r, textureWidth, textureHeight, mirror); //south + + this.sides = planes.toArray(new Quad[0]); + this.positions = positions.values().toArray(new RememberingPos[0]); + } + + @WrapMethod(method = "compile") + private void bc$render(PoseStack.Pose pose, VertexConsumer buffer, int packedLight, int packedOverlay, int color, Operation original) { + if (bc$bend == 0) { + original.call(pose, buffer, packedLight, packedOverlay, color); + return; + } + + for (Quad quad : sides) { + quad.render(pose, buffer, packedLight, packedOverlay, color); + } + } + + /** + * Apply bend on this cuboid + * Values are in radians + * @param bendValue bend value (Same as rotX) + * @return Transformation matrix for transforming children + */ + @Override + public Matrix4f applyBend(float bendValue) { + this.bc$bend = bendValue; + BendApplier bendApplier = BendUtil.getBend(this, bendValue); + bc$iteratePositions(bendApplier.consumer()); + return bendApplier.matrix4f(); + } + + + @Override + public Direction getBendDirection() { + return this.bc$direction; + } + + @Override + public float getBendX() { + return this.bc$fixX; + } + + @Override + public float getBendY() { + return this.bc$fixY; + } + + @Override + public float getBendZ() { + return this.bc$fixZ; + } + + @Override + public Plane getBasePlane() { + return this.bc$basePlane; + } + + @Override + public Plane getOtherPlane() { + return this.bc$otherPlane; + } + + @Override + public float bendHeight() { + return this.bc$fullSize; + } + + @Unique + public void bc$iteratePositions(Function function) { + for (RememberingPos pos: this.positions) { + pos.setPos(function.apply(pos.getOriginalPos())); + } + } + + @Override + public float getBend() { + return this.bc$bend; + } +} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/CuboidMutator.java b/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/CuboidMutator.java deleted file mode 100644 index 167718f..0000000 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/CuboidMutator.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.zigythebird.bendable_cuboids.mixin; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.zigythebird.bendable_cuboids.api.MutableCuboid; -import com.zigythebird.bendable_cuboids.impl.BendableCuboid; -import com.zigythebird.bendable_cuboids.impl.BendableCuboidData; -import net.minecraft.client.model.geom.ModelPart; -import net.minecraft.core.Direction; -import net.minecraft.util.Tuple; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.*; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.HashMap; -import java.util.Set; -import java.util.function.Function; - -@Mixin(ModelPart.Cube.class) -public class CuboidMutator implements MutableCuboid { - @Shadow - @Final - public float minX; - @Shadow - @Final - public float minY; - @Shadow - @Final - public float minZ; - //Store the mutators and the mutator builders. - - @Unique - private final HashMap mutators = new HashMap<>(); - - @Unique - private final HashMap> mutatorBuilders = new HashMap<>(); - - @Unique - private BendableCuboidData partData; - - @Nullable - @Unique - private BendableCuboid activeMutator; - - @Nullable - @Unique - private String activeMutatorID; - - @Inject(method = "", at = @At(value = "RETURN")) - private void constructor(int u, int v, float x, float y, float z, float sizeX, float sizeY, float sizeZ, float extraX, float extraY, float extraZ, boolean mirror, float textureWidth, float textureHeight, Set visibleFaces, CallbackInfo ci){ - partData = new BendableCuboidData(u, v, minX, minY, minZ, sizeX, sizeY, sizeZ, extraX, extraY, extraZ, mirror, textureWidth, textureHeight, visibleFaces); - } - - @Override - public boolean bendableCuboids$registerMutator(String name, Function builder) { - if(mutatorBuilders.containsKey(name)) return false; - if(builder == null) throw new NullPointerException("builder can not be null"); - mutatorBuilders.put(name, builder); - return true; - } - - @Override - public boolean bendableCuboids$unregisterMutator(String name) { - if(mutatorBuilders.remove(name) != null){ - if(name.equals(activeMutatorID)){ - activeMutator = null; - activeMutatorID = null; - } - mutators.remove(name); - - return true; - } - return false; - } - - @Nullable - @Override - public Tuple bendableCuboids$getActiveMutator() { - return activeMutator == null ? null : new Tuple<>(activeMutatorID, activeMutator); - } - - @Override - public boolean bendableCuboids$hasMutator(String key) { - return mutators.containsKey(key) || mutatorBuilders.containsKey(key); - } - - @Nullable - @Override - public Function bendableCuboids$getCuboidBuilder(String key) { - return mutatorBuilders.get(key); - } - - @Nullable - @Override - public BendableCuboid bendableCuboids$getMutator(String name) { - return mutators.get(name); - } - - @Nullable - @Override - public BendableCuboid bendableCuboids$getAndActivateMutator(@Nullable String name) { - if(name == null){ - activeMutatorID = null; - activeMutator = null; - return null; - } - if(mutatorBuilders.containsKey(name)){ - if(!mutators.containsKey(name)){ - mutators.put(name, mutatorBuilders.get(name).apply(partData)); - } - activeMutatorID = name; - return activeMutator = mutators.get(name); - } - return null; - } - - @SuppressWarnings("ConstantConditions") - @Override - public void bendableCuboids$copyStateFrom(MutableCuboid other) { - if(other.bendableCuboids$getActiveMutator() == null){ - activeMutator = null; - activeMutatorID = null; - } - else { - if(this.bendableCuboids$getAndActivateMutator(other.bendableCuboids$getActiveMutator().getA()) != null){ - activeMutator.copyState(other.bendableCuboids$getActiveMutator().getB()); - } - } - } - - @Inject(method = "compile", at = @At(value = "HEAD"), cancellable = true) - private void renderRedirect(PoseStack.Pose entry, VertexConsumer vertexConsumer, int light, int overlay, int color, CallbackInfo ci){ - if(bendableCuboids$getActiveMutator() != null){ - bendableCuboids$getActiveMutator().getB().render(entry, vertexConsumer, light, overlay, color); - ci.cancel(); - } - } -} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/IModelPartMixin.java b/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/IModelPartMixin.java deleted file mode 100644 index 7cb6519..0000000 --- a/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/IModelPartMixin.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.zigythebird.bendable_cuboids.mixin; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.zigythebird.bendable_cuboids.api.MutableCuboid; -import com.zigythebird.bendable_cuboids.impl.accessors.IModelPartAccessor; -import net.minecraft.client.model.geom.ModelPart; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -@Mixin(ModelPart.class) -public abstract class IModelPartMixin implements IModelPartAccessor { - @Shadow @Final private Map children; - - @Shadow @Final private List cubes; - - @Unique - private boolean bendableCuboids$hasMutatedCuboid = false; - - @Override - public List bendableCuboids$getCuboids() { - bendableCuboids$hasMutatedCuboid = true; - return cubes; - } - - @Override - public Map bendableCuboids$getChildren() { - return children; - } - - @Inject(method = "copyFrom", at = @At("RETURN")) - private void copyTransformExtended(ModelPart part, CallbackInfo ci){ - if (((IModelPartAccessor)part).bendableCuboids$getCuboids() == null || cubes == null) return; // Not copying state - Iterator iterator0 = ((IModelPartAccessor)part).bendableCuboids$getCuboids().iterator(); - Iterator iterator1 = cubes.iterator(); - - while (iterator0.hasNext() && iterator1.hasNext()){ - MutableCuboid cuboid1 = (MutableCuboid) iterator1.next(); - MutableCuboid cuboid0 = (MutableCuboid) iterator0.next(); - cuboid1.bendableCuboids$copyStateFrom(cuboid0); - } - } - - @WrapOperation(method = "render(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;III)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/geom/ModelPart;compile(Lcom/mojang/blaze3d/vertex/PoseStack$Pose;Lcom/mojang/blaze3d/vertex/VertexConsumer;III)V"), require = 0) //It might not find anything if OF already broke the game - private void redirectRenderCuboids(ModelPart modelPart, PoseStack.Pose entry, VertexConsumer vertexConsumer, int light, int overlay, int color, Operation original){ - bendableCuboids$redirectedFunction(modelPart, entry, vertexConsumer, light, overlay, color, original); - } - - @Unique - private void bendableCuboids$redirectedFunction(ModelPart modelPart, PoseStack.Pose entry, VertexConsumer vertexConsumer, int light, int overlay, int color, Operation original) { - if(!bendableCuboids$hasMutatedCuboid || cubes.size() == 1 && ((MutableCuboid)cubes.get(0)).bendableCuboids$getActiveMutator() == null){ - original.call(modelPart, entry, vertexConsumer, light, overlay, color); - } - else { - for(ModelPart.Cube cuboid:cubes){ - cuboid.compile(entry, vertexConsumer, light, overlay, color); - } - } - } -} diff --git a/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/ModelPartMixin.java b/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/ModelPartMixin.java new file mode 100644 index 0000000..0399f7c --- /dev/null +++ b/common/src/main/java/com/zigythebird/bendable_cuboids/mixin/ModelPartMixin.java @@ -0,0 +1,24 @@ +package com.zigythebird.bendable_cuboids.mixin; + +import com.zigythebird.bendable_cuboids.api.BendableCube; +import com.zigythebird.bendable_cuboids.api.BendableModelPart; +import net.minecraft.client.model.geom.ModelPart; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.List; + +@Mixin(ModelPart.class) +public class ModelPartMixin implements BendableModelPart { + @Shadow + @Final + private List cubes; + + @Override + public @Nullable BendableCube bc$getCuboid(int index) { + if (index > this.cubes.size() || index < 0) return null; + return this.cubes.get(index); + } +} diff --git a/common/src/main/resources/architectury.common.json b/common/src/main/resources/architectury.common.json index f7316ae..2c678b6 100644 --- a/common/src/main/resources/architectury.common.json +++ b/common/src/main/resources/architectury.common.json @@ -1,3 +1,11 @@ { + "injected_interfaces": { + "net/minecraft/class_630$class_628": [ + "com/zigythebird/bendable_cuboids/api/BendableCube" + ], + "net/minecraft/class_630": [ + "com/zigythebird/bendable_cuboids/api/BendableModelPart" + ] + }, "accessWidener": "bendable_cuboids.accesswidener" } \ No newline at end of file diff --git a/common/src/main/resources/bendable_cuboids.mixins.json b/common/src/main/resources/bendable_cuboids.mixins.json index b603b53..d85cbca 100644 --- a/common/src/main/resources/bendable_cuboids.mixins.json +++ b/common/src/main/resources/bendable_cuboids.mixins.json @@ -5,8 +5,8 @@ "plugin": "com.zigythebird.bendable_cuboids.ModMixinPlugin", "compatibilityLevel": "JAVA_21", "client": [ - "CuboidMutator", - "IModelPartMixin", + "CubeMixin", + "ModelPartMixin", "playeranim.CapeLayerAccessor_playerAnim", "playeranim.CapeLayerMixin_playerAnim", "playeranim.ElytraLayerMixin_playerAnim", diff --git a/forge/build.gradle b/forge/build.gradle index b92dffd..ba595d4 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -26,6 +26,7 @@ dependencies { shadowCommon(project(path: ":common", configuration: "transformProductionNeoForge")) { transitive = false } modImplementation "com.zigythebird.playeranim:PlayerAnimationLibNeo:${rootProject.player_anim_version}" + forgeRuntimeLibrary "org.javassist:javassist:3.30.2-GA" } processResources {