From 4acd70e2dc2ea06967f93d1b907671971db1966b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:10:06 +0300 Subject: [PATCH 01/66] sometihng about CTM quads --- .../gtceu/client/util/GTQuadTransformers.java | 29 ++ .../gtceu/client/util/ModelUtils.java | 21 +- .../gtceu/client/util/QuadInfo.java | 282 ++++++++++++++++++ .../gtceu/client/util/QuadUtils.java | 141 +++++++++ 4 files changed, 470 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/GTQuadTransformers.java b/src/main/java/com/gregtechceu/gtceu/client/util/GTQuadTransformers.java index fdfea07a48d..7b6d077d821 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/GTQuadTransformers.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/GTQuadTransformers.java @@ -8,6 +8,8 @@ import net.minecraftforge.client.model.IQuadTransformer; import net.minecraftforge.client.model.QuadTransformers; +import java.lang.reflect.Array; + public final class GTQuadTransformers { public static IQuadTransformer offset(float by) { @@ -74,6 +76,33 @@ public static BakedQuad setColor(BakedQuad quad, int argbColor, boolean clearTin return copy.gtceu$setTextureKey(quad.gtceu$getTextureKey()); } + public static IQuadTransformer derotate() { + return quad -> { + int[] vertices = quad.getVertices(); + + int start = 0; + float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE; + int[][] uvs = (int[][]) Array.newInstance(int.class, 4, 2); + + for (int i = 0; i < 4; i++) { + int offset = i * IQuadTransformer.STRIDE + IQuadTransformer.UV0; + System.arraycopy(vertices, offset, uvs[i], 0, 2); + + float u = Float.intBitsToFloat(uvs[i][0]); + float v = Float.intBitsToFloat(uvs[i][1]); + if (u <= minU && v <= minV) { + minU = Math.min(minU, u); + minV = Math.min(minV, v); + start = i; + } + } + for (int i = 0; i < 4; i++) { + int offset = i * IQuadTransformer.STRIDE + IQuadTransformer.UV0; + System.arraycopy(uvs[(i + start) % 4], 0, vertices, offset, 2); + } + }; + } + public static BakedQuad copy(BakedQuad quad) { return new BakedQuad(quad.getVertices().clone(), quad.getTintIndex(), quad.getDirection(), quad.getSprite(), quad.isShade(), quad.hasAmbientOcclusion()) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java index 8568412da98..be53024ad2d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java @@ -6,12 +6,14 @@ import com.gregtechceu.gtceu.integration.modernfix.GTModernFixIntegration; import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; +import com.lowdragmc.lowdraglib.client.model.custommodel.LDLMetadataSection; import net.minecraft.ChatFormatting; import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.*; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -33,9 +35,8 @@ import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; @Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public class ModelUtils { @@ -43,6 +44,7 @@ public class ModelUtils { private ModelUtils() {} private static final List EVENT_LISTENERS = new ArrayList<>(); + public static final Map CTM_SPRITE_CACHE = new ConcurrentHashMap<>(); public static List getBakedModelQuads(BakedModel model, BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side, RandomSource rand) { @@ -105,6 +107,19 @@ public void onResourceManagerReload(@NotNull ResourceManager resourceManager) { @SuppressWarnings({ "unchecked", "deprecation" }) @SubscribeEvent(priority = EventPriority.LOWEST) public static void onAtlasStitched(TextureStitchEvent.Post event) { + if (event.getAtlas().location().equals(TextureAtlas.LOCATION_BLOCKS)) { + CTM_SPRITE_CACHE.clear(); + for (ResourceLocation location : event.getAtlas().getTextureLocations()) { + ResourceLocation absLoc = LDLMetadataSection.spriteToAbsolute(location); + LDLMetadataSection section = LDLMetadataSection.getMetadata(absLoc); + if (section.connection != null) { + TextureAtlasSprite baseSprite = event.getAtlas().getSprite(location); + TextureAtlasSprite ctmSprite = event.getAtlas().getSprite(section.connection); + CTM_SPRITE_CACHE.put(baseSprite, ctmSprite); + } + } + } + TextureAtlas atlas = event.getAtlas(); if (atlas.location() == TextureAtlas.LOCATION_BLOCKS) { MachineModel.initSprites(atlas); diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java b/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java new file mode 100644 index 00000000000..7116e3fcc5a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java @@ -0,0 +1,282 @@ +package com.gregtechceu.gtceu.client.util; + +import com.lowdragmc.lowdraglib.client.bakedpipeline.ISubmap; +import com.lowdragmc.lowdraglib.client.bakedpipeline.Submap; +import com.lowdragmc.lowdraglib.client.model.custommodel.Connection; +import com.lowdragmc.lowdraglib.client.model.custommodel.Connections; + +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraftforge.client.model.IQuadTransformer; + +import it.unimi.dsi.fastutil.Pair; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector2f; +import org.joml.Vector3f; + +public record QuadInfo(TextureAtlasSprite sprite, int tintIndex, Direction direction, + boolean shade, boolean ao, int blockLight, int skyLight, + Vector3f[] vertices, Vector2f[] uvs, Vector2f minUV, Vector2f maxUV) { + + // Mapping the different corner indices to their respective dirs + private static final Connection[][] SUBMAP_MAP = new Connection[][] { + { Connection.DOWN, Connection.LEFT, Connection.DOWN_LEFT }, + { Connection.DOWN, Connection.RIGHT, Connection.DOWN_RIGHT }, + { Connection.UP, Connection.RIGHT, Connection.UP_RIGHT }, + { Connection.UP, Connection.LEFT, Connection.UP_LEFT } + }; + + public QuadInfo(TextureAtlasSprite sprite, int tintIndex, Direction direction, boolean shade, boolean ao, + Vector3f[] vertices, Vector2f[] uvs, Vector2f minUV, Vector2f maxUV) { + this(sprite, tintIndex, direction, shade, ao, 0, 0, vertices, uvs, minUV, maxUV); + } + + // region UV operations + + public Vector2f[] normalizeUVs() { + Vector2f[] ret = new Vector2f[uvs.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = QuadUtils.normalizeUV(sprite, uvs[i]); + } + return ret; + } + + public Vector2f[] relativizeUVs() { + Vector2f[] ret = new Vector2f[uvs.length]; + for (int i = 0; i < uvs.length; i++) { + ret[i] = QuadUtils.relativizeUV(sprite, uvs[i]); + } + return ret; + } + + public int getNormalizedUVQuadrant() { + return getUVQuadrant(QuadUtils.normalizeUV(sprite, maxUV)); + } + + public static int getUVQuadrant(Vector2f uv) { + if (uv.x() <= 0.5f) { + if (uv.y() <= 0.5f) { + return 3; + } else { + return 0; + } + } else { + if (uv.y() <= 0.5f) { + return 2; + } else { + return 1; + } + } + } + + public Vector2f[] normalizeUVQuadrant() { + Vector2f[] normalized = normalizeUVs(); + + int quadrant = getNormalizedUVQuadrant(); + float minUInterp = quadrant == 1 || quadrant == 2 ? 0.5f : 0; + float minVInterp = quadrant < 2 ? 0.5f : 0; + float maxUInterp = quadrant == 0 || quadrant == 3 ? 0.5f : 1; + float maxVInterp = quadrant > 1 ? 0.5f : 1; + + normalized = QuadUtils.normalizeUVs( + new Vector2f(minUInterp, minVInterp), + new Vector2f(maxUInterp, maxVInterp), + normalized); + return QuadUtils.relativizeUVs(sprite, normalized); + } + + public Vector2f[] transformUVData(TextureAtlasSprite other, ISubmap submap) { + Vector2f[] normalized = normalizeUVs(); + var maxUVs = QuadUtils.findMinMaxUVs(normalized); + submap = submap.normalize(); + + float width = maxUVs.second().x() - maxUVs.first().x(); + float height = maxUVs.second().y() - maxUVs.first().y(); + + float minU = submap.getXOffset(); + float minV = submap.getYOffset(); + minU += maxUVs.first().x() * submap.getWidth(); + minV += maxUVs.first().y() * submap.getHeight(); + + float maxU = minU + (width * submap.getWidth()); + float maxV = minV + (height * submap.getHeight()); + + Vector2f[] newUvs = new Vector2f[4]; + for (int i = 0; i < 4; i++) { + Vector2f uv = new Vector2f(this.uvs[i]); + // same as sprite.getX(oldSprite.getXOffset(x)), but we don't multiply and divide in between + uv.x = Mth.map(uv.x, this.sprite.getU0(), this.sprite.getU1(), other.getU0(), other.getU1()); + uv.y = Mth.map(uv.y, this.sprite.getV0(), this.sprite.getV1(), other.getV0(), other.getV1()); + newUvs[i] = uv; + } + + // FIXME this... isn't all that great. + Vector2f[] newUVs = { + new Vector2f(newUvs[0].x() == this.minUV.x() ? minU : maxU, newUvs[0].y() == this.minUV.y() ? minV : maxV), + new Vector2f(newUvs[1].x() == this.minUV.x() ? minU : maxU, newUvs[1].y() == this.minUV.y() ? minV : maxV), + new Vector2f(newUvs[2].x() == this.minUV.x() ? minU : maxU, newUvs[2].y() == this.minUV.y() ? minV : maxV), + new Vector2f(newUvs[3].x() == this.minUV.x() ? minU : maxU, newUvs[3].y() == this.minUV.y() ? minV : maxV) + }; + return QuadUtils.relativizeUVs(other, newUVs); + } + + public @Nullable Submap findSubmap(Connections connections) { + Vector2f uv = QuadUtils.normalizeUV(sprite, maxUV); + int xPos = uv.x() <= 0.5f ? 0 : 1; + int yPos = uv.y() <= 0.5f ? 0 : 1; + + Connection[] toConnect = SUBMAP_MAP[xPos + yPos]; + if (connections.connectedOr(toConnect[0], toConnect[1])) { + // If all dirs are connected, we use the fully connected face, the base offset value. + if (!connections.connectedAnd(toConnect)) { + // if a location isn't connected on all sides, the edge submap is at base+2 in the submap table + xPos += connections.contains(toConnect[0]) ? 2 : 0; + yPos += connections.contains(toConnect[1]) ? 2 : 0; + } + return Submap.X4[xPos][yPos]; + } + return null; + } + + public Vector2f[] copyUVs() { + Vector2f[] result = new Vector2f[uvs.length]; + for (int i = 0; i < uvs.length; ++i) { + result[i] = new Vector2f(uvs[i]); + } + return result; + } + + // endregion + + // region vertex operations + + public Vector3f[] copyVertices() { + Vector3f[] result = new Vector3f[vertices.length]; + for (int i = 0; i < vertices.length; ++i) { + result[i] = new Vector3f(vertices[i]); + } + return result; + } + + public QuadInfo grow() { + return new QuadInfo(sprite, tintIndex, direction, shade, ao, blockLight, skyLight, + copyVertices(), normalizeUVQuadrant(), new Vector2f(minUV), new Vector2f(maxUV)); + } + + public QuadInfo copy() { + return new QuadInfo(sprite, tintIndex, direction, shade, ao, blockLight, skyLight, + copyVertices(), copyUVs(), new Vector2f(minUV), new Vector2f(maxUV)); + } + + public QuadInfo transformUVs(TextureAtlasSprite sprite, ISubmap submap) { + return new QuadInfo(sprite, tintIndex, direction, shade, ao, blockLight, skyLight, + copyVertices(), transformUVData(sprite, submap), new Vector2f(minUV), new Vector2f(maxUV)); + } + + public QuadInfo[] subdivide() { + QuadInfo[] rects = new QuadInfo[4]; + + var firstDivide = this.divide(false); + var secondDivide = firstDivide.left().divide(true); + rects[0] = secondDivide.left(); + if (firstDivide.right() != null) { + Pair thirdDivide = firstDivide.right().divide(true); + rects[1] = thirdDivide.left(); + rects[2] = thirdDivide.right(); + } + rects[3] = secondDivide.right(); + + return rects; + } + + private Pair divide(boolean vertical) { + Vector2f[] normalizedUvs = this.normalizeUVs(); + float minUV, maxUV; + float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE, maxU = Float.MIN_VALUE, maxV = Float.MIN_VALUE; + + int start = 0; + for (int i = 0; i < 4; i++) { + if (minU >= normalizedUvs[i].x() && minV >= normalizedUvs[i].y()) { + start = i; + } + minU = Math.min(minU, normalizedUvs[i].x()); + minV = Math.min(minV, normalizedUvs[i].y()); + maxU = Math.max(maxU, normalizedUvs[i].x()); + maxV = Math.max(maxV, normalizedUvs[i].y()); + } + if (vertical) { + minUV = minV; + maxUV = maxV; + } else { + minUV = minU; + maxUV = maxU; + } + + if (minUV < 0.5f && maxUV > 0.5f) { + float delta = Mth.inverseLerp(minUV, maxUV, 0.5f); + + Vector2f[] firstUVs = QuadUtils.relativizeUVs(sprite, + new Vector2f(vertical ? minU : 0.5f, vertical ? 0.5f : minV), + new Vector2f(vertical ? minU : 0.5f, maxV), + new Vector2f(maxU, maxV), + new Vector2f(maxU, vertical ? 0.5f : minV)); + Vector2f[] secondUVs = QuadUtils.relativizeUVs(sprite, + new Vector2f(minU, minV), + new Vector2f(minU, vertical ? 0.5f : maxV), + new Vector2f(vertical ? maxU : 0.5f, vertical ? 0.5f : maxV), + new Vector2f(vertical ? maxU : 0.5f, minV)); + + Vector3f[] firstVerts = new Vector3f[4]; + Vector3f[] secondVerts = new Vector3f[4]; + for (int i = 0; i < 4; i++) { + int idx = (start + i) % 4; + firstVerts[i] = new Vector3f(vertices[idx]); + secondVerts[i] = new Vector3f(vertices[idx]); + } + + int i0 = 0; + int i1 = vertical ? 1 : 3; + int i2 = 2; + int i3 = vertical ? 3 : 1; + + firstVerts[i0].lerp(firstVerts[i1], delta); + firstVerts[i3].lerp(firstVerts[i2], delta); + secondVerts[i0].lerp(secondVerts[i1], delta, secondVerts[i1]); + secondVerts[i3].lerp(secondVerts[i2], delta, secondVerts[i2]); + + return Pair.of( + new QuadInfo(sprite, tintIndex, direction, shade, ao, blockLight, skyLight, + firstVerts, firstUVs, firstUVs[0], firstUVs[2]), + new QuadInfo(sprite, tintIndex, direction, shade, ao, blockLight, skyLight, + secondVerts, secondUVs, secondUVs[0], secondUVs[2])); + } else { + return Pair.of(this, null); + } + } + + // endregion + + public BakedQuad rebake() { + int[] vertexData = new int[32]; + for (int i = 0; i < 4; ++i) { + Vector3f pos = vertices[i]; + Vector2f uv = uvs[i]; + Vector2f nextUv = uvs[(i + 2) % 4]; + + int v = i * IQuadTransformer.STRIDE; + vertexData[v + IQuadTransformer.POSITION] = Float.floatToRawIntBits(pos.x()); + vertexData[v + IQuadTransformer.POSITION + 1] = Float.floatToRawIntBits(pos.y()); + vertexData[v + IQuadTransformer.POSITION + 2] = Float.floatToRawIntBits(pos.z()); + vertexData[v + IQuadTransformer.COLOR] = 0xffffffff; + vertexData[v + IQuadTransformer.UV0] = Float.floatToRawIntBits( + sprite.getU(uv.x() * 0.999f + nextUv.x() * 0.001f)); + vertexData[v + IQuadTransformer.UV0 + 1] = Float.floatToRawIntBits( + sprite.getV(uv.y() * 0.999f + nextUv.y() * 0.001f)); + vertexData[i * IQuadTransformer.STRIDE + IQuadTransformer.UV2] = LightTexture.pack(blockLight, skyLight); + } + return new BakedQuad(vertexData, tintIndex, direction, sprite, shade, ao); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java new file mode 100644 index 00000000000..31130f730c3 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java @@ -0,0 +1,141 @@ +package com.gregtechceu.gtceu.client.util; + +import com.lowdragmc.lowdraglib.client.bakedpipeline.Submap; +import com.lowdragmc.lowdraglib.client.model.custommodel.Connections; + +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.IQuadTransformer; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector2f; +import org.joml.Vector3f; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import static com.gregtechceu.gtceu.client.util.ModelUtils.*; + +public class QuadUtils { + + public static Vector2f[] getQuadUVs(int[] vertices) { + Vector2f[] uvs = new Vector2f[4]; + + for (int i = 0; i < 4; i++) { + int offset = i * IQuadTransformer.STRIDE + IQuadTransformer.UV0; + float u = Float.intBitsToFloat(vertices[offset]); + float v = Float.intBitsToFloat(vertices[offset + 1]); + uvs[i] = new Vector2f(u, v); + } + return uvs; + } + + public static Vector3f[] getQuadVertices(int[] vertices) { + Vector3f[] vertPos = new Vector3f[4]; + + for (int i = 0; i < 4; i++) { + int offset = i * IQuadTransformer.STRIDE + IQuadTransformer.POSITION; + float x = Float.intBitsToFloat(vertices[offset]); + float y = Float.intBitsToFloat(vertices[offset + 1]); + float z = Float.intBitsToFloat(vertices[offset + 2]); + vertPos[i] = new Vector3f(x, y, z); + } + return vertPos; + } + + public static QuadInfo[] subdivide(BakedQuad baked) { + Vector3f[] vertPos = getQuadVertices(baked.getVertices()); + Vector2f[] uvs = getQuadUVs(baked.getVertices()); + var maxUVs = findMinMaxUVs(uvs); + QuadInfo quad = new QuadInfo(baked.getSprite(), baked.getTintIndex(), baked.getDirection(), + baked.isShade(), baked.hasAmbientOcclusion(), + vertPos, uvs, maxUVs.first(), maxUVs.second()); + + return quad.subdivide(); + } + + private static void putVertexData(int[] vertices, int index, Vector3f pos, Vector2f uv) { + int posOffset = index * IQuadTransformer.STRIDE + IQuadTransformer.POSITION; + vertices[posOffset] = Float.floatToRawIntBits(pos.x()); + vertices[posOffset + 1] = Float.floatToRawIntBits(pos.y()); + vertices[posOffset + 2] = Float.floatToRawIntBits(pos.z()); + + int uvOffset = index * IQuadTransformer.STRIDE + IQuadTransformer.UV0; + vertices[uvOffset] = Float.floatToRawIntBits(uv.x()); + vertices[uvOffset + 1] = Float.floatToRawIntBits(uv.y()); + } + + public static Vector2f[] normalizeUVs(Vector2f min, Vector2f max, Vector2f... uvs) { + Vector2f[] ret = new Vector2f[uvs.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = normalizeUV(min, max, uvs[i]); + } + return ret; + } + + public static Vector2f normalizeUV(TextureAtlasSprite sprite, Vector2f vec) { + return normalizeUV( + new Vector2f(sprite.getU0(), sprite.getU1()), + new Vector2f(sprite.getV0(), sprite.getV1()), + vec); + } + + public static Vector2f normalizeUV(Vector2f min, Vector2f max, Vector2f vec) { + return new Vector2f( + Mth.inverseLerp(vec.x(), min.x(), max.x()), + Mth.inverseLerp(vec.y(), min.y(), max.y())); + } + + public static Vector2f[] relativizeUVs(TextureAtlasSprite sprite, Vector2f... uvs) { + for (int i = 0; i < uvs.length; i++) { + uvs[i] = relativizeUV(sprite, uvs[i]); + } + return uvs; + } + + public static Vector2f relativizeUV(TextureAtlasSprite sprite, Vector2f vec) { + return new Vector2f( + Mth.lerp(vec.x(), sprite.getU0(), sprite.getU1()), + Mth.lerp(vec.y(), sprite.getV0(), sprite.getV1())); + } + + public static List buildCTMQuads(List quads, BlockAndTintGetter level, BlockPos pos, + @NotNull BlockState state, @Nullable Direction elementSide) { + return buildCTMQuads(Connections.checkConnections(level, pos, state, elementSide), quads); + } + + public static List buildCTMQuads(Connections connections, List base) { + List result = new ArrayList<>(); + for (BakedQuad originalQuad : base) { + TextureAtlasSprite connection = CTM_SPRITE_CACHE.get(originalQuad.getSprite()); + if (connection == null) { + result.add(originalQuad); + continue; + } + GTQuadTransformers.derotate().processInPlace(originalQuad); + + QuadInfo[] subdivided = QuadUtils.subdivide(originalQuad); + int[] ctm = connections.getSubmapIndices(); + + for (int j = 0; j < subdivided.length; j++) { + QuadInfo quad = subdivided[j]; + if (quad != null) { + int quadrant = quad.getNormalizedUVQuadrant(); + Submap submap = quad.findSubmap(connections); + TextureAtlasSprite ctmSprite = ctm[quadrant] > 15 ? originalQuad.getSprite() : connection; + subdivided[j] = quad.grow().transformUVs(ctmSprite, submap); + } + } + result.addAll(Arrays.stream(subdivided).filter(Objects::nonNull).map(QuadInfo::rebake).toList()); + } + return result; + } +} From 8fa98994863ed5499524363e54d1cc41411714c5 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Fri, 17 Apr 2026 18:37:36 +0300 Subject: [PATCH 02/66] "remake" the baked model replacement stuff (but not really) --- .../gregtechceu/gtceu/client/ClientProxy.java | 19 ++++++ .../gtceu/client/util/AssetEventListener.java | 14 +++-- .../gtceu/client/util/ModelUtils.java | 52 +++++++++-------- .../gtceu/common/item/LampBlockItem.java | 58 ++++++++++++++----- .../modernfix/GTModernFixIntegration.java | 16 +++-- 5 files changed, 113 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java index 9a0574d59a7..9895b34514d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java @@ -9,6 +9,7 @@ import com.gregtechceu.gtceu.api.item.IComponentItem; import com.gregtechceu.gtceu.api.item.IGTTool; import com.gregtechceu.gtceu.client.model.item.FacadeUnbakedModel; +import com.gregtechceu.gtceu.client.model.machine.MachineModel; import com.gregtechceu.gtceu.client.model.machine.MachineModelLoader; import com.gregtechceu.gtceu.client.model.pipe.PipeModel; import com.gregtechceu.gtceu.client.model.pipe.PipeModelLoader; @@ -29,6 +30,7 @@ import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderManager; import com.gregtechceu.gtceu.client.renderer.machine.impl.*; import com.gregtechceu.gtceu.client.renderer.machine.impl.BoilerMultiPartRender; +import com.gregtechceu.gtceu.client.util.ModelUtils; import com.gregtechceu.gtceu.common.CommonEventListener; import com.gregtechceu.gtceu.common.CommonProxy; import com.gregtechceu.gtceu.common.data.GTBlockEntities; @@ -54,6 +56,7 @@ import com.gregtechceu.gtceu.utils.data.RuntimeBlockstateProvider; import com.gregtechceu.gtceu.utils.input.SyncedKeyMapping; +import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; import net.minecraft.client.model.BoatModel; import net.minecraft.client.model.ChestBoatModel; import net.minecraft.client.renderer.blockentity.HangingSignRenderer; @@ -175,6 +178,22 @@ public void onRegisterModelLoaders(ModelEvent.RegisterGeometryLoaders event) { event.register(MachineModelLoader.ID.getPath(), MachineModelLoader.INSTANCE); event.register(PipeModelLoader.ID.getPath(), PipeModelLoader.INSTANCE); event.register("facade", FacadeUnbakedModel.Loader.INSTANCE); + + // register CTM model (un)wrapper + ModelUtils.registerBakeEventListener(false, (modelLocation, model, modelBakery) -> { + // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins + if (model instanceof CustomBakedModel ctmModel) { + if (ctmModel.getParent() instanceof MachineModel machineModel) { + return machineModel; + } + } + // do not register automatic CTM for machine models, they handle it themselves + if (model instanceof MachineModel) { + return model; + } + + return model; + }); } @SubscribeEvent(priority = EventPriority.HIGHEST) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java b/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java index eb035bf4ed0..d45a95e5663 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java @@ -1,5 +1,8 @@ package com.gregtechceu.gtceu.client.util; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.resources.ResourceLocation; import net.minecraftforge.client.event.ModelEvent; import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.eventbus.api.Event; @@ -15,6 +18,7 @@ public interface AssetEventListener { return null; } + @FunctionalInterface interface AtlasStitched extends AssetEventListener { @Override @@ -24,15 +28,13 @@ default Class eventClass() { } } - interface ModifyBakingResult extends AssetEventListener { + @FunctionalInterface + interface BakedModelReplacement { - @Override - @Nullable - default Class eventClass() { - return ModelEvent.ModifyBakingResult.class; - } + BakedModel modifyBakedModel(ResourceLocation modelLocation, BakedModel model, ModelBakery modelBakery); } + @FunctionalInterface interface RegisterAdditional extends AssetEventListener { @Override diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java index be53024ad2d..717cf048a8d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java @@ -34,6 +34,7 @@ import net.minecraftforge.fml.common.Mod; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.ApiStatus; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -43,7 +44,8 @@ public class ModelUtils { private ModelUtils() {} - private static final List EVENT_LISTENERS = new ArrayList<>(); + @ApiStatus.Internal + public static final List> EVENT_LISTENERS = new ArrayList<>(); public static final Map CTM_SPRITE_CACHE = new ConcurrentHashMap<>(); public static List getBakedModelQuads(BakedModel model, BlockAndTintGetter level, BlockPos pos, @@ -71,7 +73,7 @@ public static String getPropertyValueString(Map.Entry, Comparable public static void registerAtlasStitchedEventListener(boolean removeOnReload, AssetEventListener.AtlasStitched listener) { - EVENT_LISTENERS.add(new EventListenerHolder(listener, removeOnReload)); + EVENT_LISTENERS.add(new EventListenerHolder<>(listener, removeOnReload)); } public static void registerAtlasStitchedEventListener(boolean removeOnReload, final ResourceLocation atlasLocation, @@ -84,13 +86,13 @@ public static void registerAtlasStitchedEventListener(boolean removeOnReload, fi } public static void registerBakeEventListener(boolean removeOnReload, - AssetEventListener.ModifyBakingResult listener) { - EVENT_LISTENERS.add(new EventListenerHolder(listener, removeOnReload)); + AssetEventListener.BakedModelReplacement listener) { + EVENT_LISTENERS.add(new EventListenerHolder<>(listener, removeOnReload)); } public static void registerAddModelsEventListener(boolean removeOnReload, AssetEventListener.RegisterAdditional listener) { - EVENT_LISTENERS.add(new EventListenerHolder(listener, removeOnReload)); + EVENT_LISTENERS.add(new EventListenerHolder<>(listener, removeOnReload)); } @SubscribeEvent(priority = EventPriority.HIGH) @@ -127,35 +129,36 @@ public static void onAtlasStitched(TextureStitchEvent.Post event) { } for (var listener : EVENT_LISTENERS) { - Class eventClass = listener.listener.eventClass(); + if (!(listener.listener instanceof AssetEventListener assetEventListener)) continue; + + Class eventClass = assetEventListener.eventClass(); if (eventClass != null && eventClass.isInstance(event)) { ((AssetEventListener) listener.listener).accept(event); } } } - @SuppressWarnings("unchecked") @SubscribeEvent(priority = EventPriority.LOWEST) public static void onModifyBakingResult(ModelEvent.ModifyBakingResult event) { - for (var listener : EVENT_LISTENERS) { - Class eventClass = listener.listener.eventClass(); - if (eventClass != null && eventClass.isInstance(event)) { - ((AssetEventListener) listener.listener).accept(event); - } - } - - // don't process the CTM model unwrapping here if modernfix dynamic resources is enabled + // don't process baked model replacement here if modernfix dynamic resources is enabled if (GTCEu.Mods.isModernFixLoaded() && GTModernFixIntegration.isDynamicResourcesEnabled()) return; - // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins - // Also, the caching they have stops our models from updating properly for (var entry : event.getModels().entrySet()) { BakedModel model = entry.getValue(); - if (!(model instanceof CustomBakedModel ctmModel)) { - continue; + + // run through all model replacers first + for (var listener : EVENT_LISTENERS) { + if (!(listener.listener instanceof AssetEventListener.BakedModelReplacement modelReplacement)) continue; + model = modelReplacement.modifyBakedModel(entry.getKey(), model, event.getModelBakery()); } - if (ctmModel.getParent() instanceof MachineModel machine) { - entry.setValue(machine); + entry.setValue(model); + + // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins + // Also, the caching they have stops our models from updating properly + if (model instanceof CustomBakedModel ctmModel) { + if (ctmModel.getParent() instanceof MachineModel machineModel) { + entry.setValue(machineModel); + } } } } @@ -164,12 +167,15 @@ public static void onModifyBakingResult(ModelEvent.ModifyBakingResult event) { @SubscribeEvent(priority = EventPriority.LOWEST) public static void onRegisterAdditional(ModelEvent.RegisterAdditional event) { for (var listener : EVENT_LISTENERS) { - Class eventClass = listener.listener.eventClass(); + if (!(listener.listener instanceof AssetEventListener assetEventListener)) continue; + + Class eventClass = assetEventListener.eventClass(); if (eventClass != null && eventClass.isInstance(event)) { ((AssetEventListener) listener.listener).accept(event); } } } - private record EventListenerHolder(AssetEventListener listener, boolean removeOnReload) {} + @ApiStatus.Internal + public record EventListenerHolder(T listener, boolean removeOnReload) {} } diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java index c1e59d991b2..33028c2a399 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java @@ -5,14 +5,16 @@ import com.gregtechceu.gtceu.client.util.ModelUtils; import com.gregtechceu.gtceu.common.block.LampBlock; +import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; -import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.core.NonNullList; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.block.state.BlockState; @@ -22,6 +24,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.function.Consumer; import javax.annotation.ParametersAreNonnullByDefault; @@ -84,21 +89,48 @@ public BlockEntityWithoutLevelRenderer getCustomRenderer() { private static class ClientCallWrapper { - private static void registerEventListener(LampBlockItem item) { - ModelUtils.registerBakeEventListener(false, event -> { - ResourceLocation model = BuiltInRegistries.ITEM.getKey(item).withPrefix("item/"); - BakedModel original = event.getModels().get(model); - if (original == null) { - model = new ModelResourceLocation(model, "inventory"); - original = event.getModels().get(model); + private static boolean registeredListener = false; + private static final Map trackedItems = new Reference2ObjectArrayMap<>(); + + private static void registerEventListener(LampBlockItem toWrap) { + trackedItems.put(toWrap, null); + + if (registeredListener) return; + registeredListener = true; + ModelUtils.registerBakeEventListener(false, (modelLocation, model, modelBakery) -> { + + // handle both cases 1.20 can have passed here. 1.21 *only* has the ModelResourceLocation case. + ResourceLocation possibleItemId; + if (modelLocation instanceof ModelResourceLocation modelResLoc && Objects.equals(modelResLoc.getVariant(), "inventory")) { + // unwrap ModelResourceLocations + // 1.21 needs different code here as ModelResourceLocation is a wrapper record instead of a subclass + possibleItemId = modelResLoc.withPrefix(""); + } else if (!modelLocation.getPath().startsWith("item/")) { + // remove the "item/" prefix from the model path + possibleItemId = modelLocation.withPath(path -> path.substring("item/".length())); + } else { + return model; } - event.getModels().put(model, new BakedModelWrapper<>(original) { - @Override - public boolean isCustomRenderer() { - return true; + for (var entry : trackedItems.entrySet()) { + ResourceLocation itemId = entry.getValue(); + if (itemId == null) { + entry.setValue(itemId = BuiltInRegistries.ITEM.getKey(entry.getKey())); } - }); + // if the current model is a lamp item, replace it with one that has isCustomRenderer()==true + // so the custom renderer in `LampBlockItem#initializeClient` works + if (itemId.equals(possibleItemId)) { + return new BakedModelWrapper<>(model) { + + @Override + public boolean isCustomRenderer() { + return true; + } + }; + } + } + + return model; }); } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java b/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java index a36f05bde92..4cf15c7b130 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java @@ -2,6 +2,8 @@ import com.gregtechceu.gtceu.client.model.machine.MachineModel; +import com.gregtechceu.gtceu.client.util.AssetEventListener; +import com.gregtechceu.gtceu.client.util.ModelUtils; import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -41,15 +43,21 @@ public void onDynamicResourcesStatusChange(boolean enabled) { } @Override - public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, - BakedModel originalModel, ModelState state, ModelBakery bakery, + public BakedModel onBakedModelLoad(ResourceLocation modelLocation, UnbakedModel baseModel, + BakedModel model, ModelState state, ModelBakery bakery, Function textureGetter) { - if (originalModel instanceof CustomBakedModel ctmModel) { + // run through all model replacers first + for (var listener : ModelUtils.EVENT_LISTENERS) { + if (!(listener.listener() instanceof AssetEventListener.BakedModelReplacement modelReplacement)) continue; + model = modelReplacement.modifyBakedModel(modelLocation, model, bakery); + } + + if (model instanceof CustomBakedModel ctmModel) { // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins if (ctmModel.getParent() instanceof MachineModel machineModel) { return machineModel; } } - return originalModel; + return model; } } From 9979fe3d4a5c928144f7d731b9f27e48e251264b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Mon, 23 Jun 2025 21:30:41 +0300 Subject: [PATCH 03/66] reimplement LDLib's CTM wrapper model --- .../gtceu/client/model/CTMBakedModel.java | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 src/main/java/com/gregtechceu/gtceu/client/model/CTMBakedModel.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/CTMBakedModel.java new file mode 100644 index 00000000000..cf01fd27cdf --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/CTMBakedModel.java @@ -0,0 +1,137 @@ +package com.gregtechceu.gtceu.client.model; + +import com.gregtechceu.gtceu.client.util.ModelUtils; +import com.gregtechceu.gtceu.client.util.QuadInfo; + +import com.lowdragmc.lowdraglib.client.bakedpipeline.Submap; +import com.lowdragmc.lowdraglib.client.model.custommodel.Connections; +import com.lowdragmc.lowdraglib.client.model.custommodel.LDLMetadataSection; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.BakedModelWrapper; +import net.minecraftforge.client.model.QuadTransformers; +import net.minecraftforge.client.model.data.ModelData; +import net.minecraftforge.client.model.data.ModelProperty; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class CTMBakedModel extends BakedModelWrapper { + + private final Map>> sideCache; + private final List noSideCache; + + public static final ModelProperty LEVEL = new ModelProperty<>(); + public static final ModelProperty POS = new ModelProperty<>(); + public static final ModelProperty MODEL_DATA = new ModelProperty<>(); + + public CTMBakedModel(T parent) { + super(parent); + this.sideCache = new EnumMap<>(Direction.class); + this.noSideCache = new ArrayList<>(); + } + + public BakedModel getParent() { + return this.originalModel; + } + + @Override + public @NotNull List getQuads(@Nullable BlockState state, @Nullable Direction side, + @NotNull RandomSource rand, @NotNull ModelData data, + @Nullable RenderType renderType) { + BlockAndTintGetter level = data.get(LEVEL); + BlockPos pos = data.get(POS); + if (level != null && pos != null && state != null) { + return getCustomQuads(level, pos, state, side, rand, data, renderType); + } else { + return super.getQuads(state, side, rand, data, renderType); + } + } + + @Override + public @NotNull ModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, + @NotNull BlockState state, @NotNull ModelData modelData) { + modelData = super.getModelData(level, pos, state, modelData); + return ModelData.builder() + .with(LEVEL, level) + .with(POS, pos) + .with(MODEL_DATA, modelData) + .build(); + } + + @SuppressWarnings("DataFlowIssue") + @NotNull + public List getCustomQuads(BlockAndTintGetter level, BlockPos pos, @NotNull BlockState state, + @Nullable Direction side, RandomSource rand, + @NotNull ModelData data, @Nullable RenderType renderType) { + final ModelData parentData = data.has(MODEL_DATA) ? data.get(MODEL_DATA) : ModelData.EMPTY; + + var connections = Connections.checkConnections(level, pos, state, side); + if (side == null) { + if (noSideCache.isEmpty()) { + noSideCache.addAll(buildCustomQuads(connections, + super.getQuads(state, null, rand, parentData, renderType), 0.0f)); + } + return noSideCache; + } + return sideCache.computeIfAbsent(side, this::makeMap) + .computeIfAbsent(connections, c -> buildCustomQuads(c, + super.getQuads(state, side, rand, parentData, renderType), 0.0f)); + } + + public static List reBakeCustomQuads(List quads, BlockAndTintGetter level, BlockPos pos, + @NotNull BlockState state, @Nullable Direction side, float offset) { + return buildCustomQuads(Connections.checkConnections(level, pos, state, side), quads, offset); + } + + public static List buildCustomQuads(Connections connections, List base, float offset) { + List result = new ArrayList<>(); + for (BakedQuad bakedQuad : base) { + var section = LDLMetadataSection.getMetadata(bakedQuad.getSprite()); + TextureAtlasSprite connection = section.connection == null ? null : + ModelUtils.getBlockSprite(section.connection); + if (connection == null) { + result.add(makeQuad(bakedQuad, section, offset)); + continue; + } + + BakedQuad baked = ModelUtils.derotateQuad(makeQuad(bakedQuad, section, offset)); + QuadInfo[] subdivided = ModelUtils.subdivide(baked); + + int[] ctm = connections.getSubmapIndices(); + + for (int j = 0; j < subdivided.length; j++) { + QuadInfo quad = subdivided[j]; + if (quad != null) { + int quadrant = quad.getNormalizedUVQuadrant(); + TextureAtlasSprite ctmSprite = ctm[quadrant] > 15 ? bakedQuad.getSprite() : connection; + subdivided[j] = quad.grow().transformUVs(ctmSprite, Submap.uvs[ctm[quadrant]]); + } + } + result.addAll(Arrays.stream(subdivided).filter(Objects::nonNull).map(QuadInfo::rebake).toList()); + } + return result; + } + + protected static BakedQuad makeQuad(BakedQuad quad, LDLMetadataSection section, float offset) { + int light = section.emissive ? 15 : 0; + quad = ModelUtils.offsetQuad(quad, offset); + QuadTransformers.settingEmissivity(light).process(quad); + return quad; + } + + private Map> makeMap(Direction ignored) { + return new ConcurrentHashMap<>(); + } +} From 9253abcad0c9a6b7aeeab9b4b1f2610100af0b48 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:20:31 +0300 Subject: [PATCH 04/66] Rip out almost* all LDLib CustomBakedModel usages & replace them with fresh (commented!) copies from CTM proper. \*: LDLMetadataSection is still missing, but that's easy enough to solve. --- .../gregtechceu/gtceu/client/ClientProxy.java | 66 ++++- .../gtceu/client/model/CTMBakedModel.java | 109 ++------ .../gtceu/client/model/GTModelProperties.java | 2 + .../client/model/connected/CTMCache.java | 255 ++++++++++++++++++ .../model/connected/ConnectionCheck.java | 97 +++++++ .../gtceu/client/model/connected/ISubmap.java | 103 +++++++ .../model/connected/OctagonalOrientation.java | 156 +++++++++++ .../gtceu/client/model/connected/Submap.java | 74 +++++ .../client/model/connected/package-info.java | 4 + .../client/model/machine/MachineModel.java | 5 +- .../gtceu/client/util/AssetEventListener.java | 3 +- .../gtceu/client/util/ModelUtils.java | 47 ++-- .../gtceu/client/util/QuadInfo.java | 56 ++-- .../gtceu/client/util/QuadUtils.java | 38 ++- .../client/util/SpriteFunctionWrapper.java | 28 ++ .../gtceu/common/item/LampBlockItem.java | 2 +- .../mixins/client/ModelBakerImplMixin.java | 29 ++ .../modernfix/GTModernFixIntegration.java | 14 +- src/main/resources/gtceu.mixins.json | 1 + 19 files changed, 921 insertions(+), 168 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/client/model/connected/CTMCache.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/model/connected/ConnectionCheck.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/model/connected/ISubmap.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/model/connected/OctagonalOrientation.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/model/connected/Submap.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/model/connected/package-info.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java create mode 100644 src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java index 9895b34514d..c521efcc894 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java @@ -8,6 +8,7 @@ import com.gregtechceu.gtceu.api.data.worldgen.bedrockore.BedrockOreDefinition; import com.gregtechceu.gtceu.api.item.IComponentItem; import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.client.model.CTMBakedModel; import com.gregtechceu.gtceu.client.model.item.FacadeUnbakedModel; import com.gregtechceu.gtceu.client.model.machine.MachineModel; import com.gregtechceu.gtceu.client.model.machine.MachineModelLoader; @@ -57,11 +58,16 @@ import com.gregtechceu.gtceu.utils.input.SyncedKeyMapping; import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; +import com.lowdragmc.lowdraglib.client.model.custommodel.LDLMetadataSection; + import net.minecraft.client.model.BoatModel; import net.minecraft.client.model.ChestBoatModel; import net.minecraft.client.renderer.blockentity.HangingSignRenderer; import net.minecraft.client.renderer.blockentity.SignRenderer; import net.minecraft.client.renderer.entity.ThrownItemRenderer; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraftforge.client.ForgeHooksClient; @@ -74,6 +80,11 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashSet; +import java.util.Set; + public class ClientProxy extends CommonProxy { public static final BiMap CLIENT_ORE_VEINS = HashBiMap.create(); @@ -180,7 +191,9 @@ public void onRegisterModelLoaders(ModelEvent.RegisterGeometryLoaders event) { event.register("facade", FacadeUnbakedModel.Loader.INSTANCE); // register CTM model (un)wrapper - ModelUtils.registerBakeEventListener(false, (modelLocation, model, modelBakery) -> { + ModelUtils.registerBakeEventListener(false, (modelLocation, model, rootModel, modelBakery) -> { + if (model == null) return null; + // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins if (model instanceof CustomBakedModel ctmModel) { if (ctmModel.getParent() instanceof MachineModel machineModel) { @@ -192,6 +205,57 @@ public void onRegisterModelLoaders(ModelEvent.RegisterGeometryLoaders event) { return model; } + + if (modelLocation instanceof ModelResourceLocation && rootModel != null) { + if (model.isCustomRenderer()) { // Nothing we can add to builtin models + return model; + } + Deque dependencies = new ArrayDeque<>(); + Set seenModels = new HashSet<>(); + dependencies.push(modelLocation); + seenModels.add(modelLocation); + boolean shouldWrap = ModelUtils.WRAPPED_MODELS.getOrDefault(modelLocation, false); + // Breadth-first loop through dependencies + // exiting as soon as a CTM texture is found, and skipping duplicates/cycles + while (!shouldWrap && !dependencies.isEmpty()) { + ResourceLocation dep = dependencies.pop(); + UnbakedModel unbaked; + try { + unbaked = dep == modelLocation ? rootModel : modelBakery.getModel(dep); + } catch (Exception e) { + continue; + } + try { + // have to copy because the set is updated during this loop + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + Set textures = new HashSet<>(ModelUtils.SCRAPED_TEXTURES.get(dep)); + for (Material tex : textures) { + // Cache all dependent texture metadata + // TODO lazy + if (!LDLMetadataSection.getMetadata(LDLMetadataSection.spriteToAbsolute(tex.texture())).isMissing()) { + // At least one texture has CTM metadata, so we should wrap this model + shouldWrap = true; + break; + } + } + if (!shouldWrap) { + for (ResourceLocation newDep : unbaked.getDependencies()) { + if (seenModels.add(newDep)) { + dependencies.push(newDep); + } + } + } + } catch (Exception e) { + GTCEu.LOGGER.error("Error loading baked dependency {} for baked {}. Skipping...", + dep, modelLocation, e); + } + } + ModelUtils.WRAPPED_MODELS.put(modelLocation, shouldWrap); + if (shouldWrap) { + return new CTMBakedModel<>(model); + } + } + return model; }); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/CTMBakedModel.java index cf01fd27cdf..5806e3dfec0 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/CTMBakedModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/CTMBakedModel.java @@ -1,15 +1,10 @@ package com.gregtechceu.gtceu.client.model; -import com.gregtechceu.gtceu.client.util.ModelUtils; -import com.gregtechceu.gtceu.client.util.QuadInfo; - -import com.lowdragmc.lowdraglib.client.bakedpipeline.Submap; -import com.lowdragmc.lowdraglib.client.model.custommodel.Connections; -import com.lowdragmc.lowdraglib.client.model.custommodel.LDLMetadataSection; +import com.gregtechceu.gtceu.client.model.connected.CTMCache; +import com.gregtechceu.gtceu.client.util.QuadUtils; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -17,121 +12,63 @@ import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.client.model.BakedModelWrapper; -import net.minecraftforge.client.model.QuadTransformers; import net.minecraftforge.client.model.data.ModelData; -import net.minecraftforge.client.model.data.ModelProperty; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -public class CTMBakedModel extends BakedModelWrapper { +import static com.gregtechceu.gtceu.client.model.GTModelProperties.*; - private final Map>> sideCache; - private final List noSideCache; +public class CTMBakedModel extends BakedModelWrapper { - public static final ModelProperty LEVEL = new ModelProperty<>(); - public static final ModelProperty POS = new ModelProperty<>(); - public static final ModelProperty MODEL_DATA = new ModelProperty<>(); + private final Map>> sideCache = new EnumMap<>(Direction.class); public CTMBakedModel(T parent) { super(parent); - this.sideCache = new EnumMap<>(Direction.class); - this.noSideCache = new ArrayList<>(); } public BakedModel getParent() { return this.originalModel; } + @SuppressWarnings("DataFlowIssue") @Override - public @NotNull List getQuads(@Nullable BlockState state, @Nullable Direction side, - @NotNull RandomSource rand, @NotNull ModelData data, - @Nullable RenderType renderType) { + public List getQuads(@Nullable BlockState state, @Nullable Direction side, + RandomSource rand, ModelData data, @Nullable RenderType renderType) { BlockAndTintGetter level = data.get(LEVEL); BlockPos pos = data.get(POS); + ModelData parentData = data.has(PARENT_MODEL_DATA) ? data.get(PARENT_MODEL_DATA) : data; + if (level != null && pos != null && state != null) { - return getCustomQuads(level, pos, state, side, rand, data, renderType); + return getCustomQuads(level, pos, state, side, rand, parentData, renderType); } else { - return super.getQuads(state, side, rand, data, renderType); + return super.getQuads(state, side, rand, parentData, renderType); } } @Override - public @NotNull ModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, - @NotNull BlockState state, @NotNull ModelData modelData) { - modelData = super.getModelData(level, pos, state, modelData); + public ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState state, ModelData modelData) { + ModelData parentModelData = super.getModelData(level, pos, state, modelData); return ModelData.builder() .with(LEVEL, level) .with(POS, pos) - .with(MODEL_DATA, modelData) + .with(PARENT_MODEL_DATA, parentModelData) .build(); } - @SuppressWarnings("DataFlowIssue") - @NotNull - public List getCustomQuads(BlockAndTintGetter level, BlockPos pos, @NotNull BlockState state, + public List getCustomQuads(BlockAndTintGetter level, BlockPos pos, BlockState state, @Nullable Direction side, RandomSource rand, - @NotNull ModelData data, @Nullable RenderType renderType) { - final ModelData parentData = data.has(MODEL_DATA) ? data.get(MODEL_DATA) : ModelData.EMPTY; - - var connections = Connections.checkConnections(level, pos, state, side); + ModelData modelData, @Nullable RenderType renderType) { if (side == null) { - if (noSideCache.isEmpty()) { - noSideCache.addAll(buildCustomQuads(connections, - super.getQuads(state, null, rand, parentData, renderType), 0.0f)); - } - return noSideCache; - } - return sideCache.computeIfAbsent(side, this::makeMap) - .computeIfAbsent(connections, c -> buildCustomQuads(c, - super.getQuads(state, side, rand, parentData, renderType), 0.0f)); - } - - public static List reBakeCustomQuads(List quads, BlockAndTintGetter level, BlockPos pos, - @NotNull BlockState state, @Nullable Direction side, float offset) { - return buildCustomQuads(Connections.checkConnections(level, pos, state, side), quads, offset); - } - - public static List buildCustomQuads(Connections connections, List base, float offset) { - List result = new ArrayList<>(); - for (BakedQuad bakedQuad : base) { - var section = LDLMetadataSection.getMetadata(bakedQuad.getSprite()); - TextureAtlasSprite connection = section.connection == null ? null : - ModelUtils.getBlockSprite(section.connection); - if (connection == null) { - result.add(makeQuad(bakedQuad, section, offset)); - continue; - } - - BakedQuad baked = ModelUtils.derotateQuad(makeQuad(bakedQuad, section, offset)); - QuadInfo[] subdivided = ModelUtils.subdivide(baked); - - int[] ctm = connections.getSubmapIndices(); - - for (int j = 0; j < subdivided.length; j++) { - QuadInfo quad = subdivided[j]; - if (quad != null) { - int quadrant = quad.getNormalizedUVQuadrant(); - TextureAtlasSprite ctmSprite = ctm[quadrant] > 15 ? bakedQuad.getSprite() : connection; - subdivided[j] = quad.grow().transformUVs(ctmSprite, Submap.uvs[ctm[quadrant]]); - } - } - result.addAll(Arrays.stream(subdivided).filter(Objects::nonNull).map(QuadInfo::rebake).toList()); + return super.getQuads(state, null, rand, modelData, renderType); } - return result; - } - - protected static BakedQuad makeQuad(BakedQuad quad, LDLMetadataSection section, float offset) { - int light = section.emissive ? 15 : 0; - quad = ModelUtils.offsetQuad(quad, offset); - QuadTransformers.settingEmissivity(light).process(quad); - return quad; - } - private Map> makeMap(Direction ignored) { - return new ConcurrentHashMap<>(); + CTMCache ctmCache = CTMCache.getInstance(); + ctmCache.getSubmapIds(level, pos, state, side); + return this.sideCache.computeIfAbsent(side, $ -> new ConcurrentHashMap<>()) + .computeIfAbsent(ctmCache, cache -> QuadUtils.buildCTMQuads(cache, + super.getQuads(state, side, rand, modelData, renderType))); } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/GTModelProperties.java b/src/main/java/com/gregtechceu/gtceu/client/model/GTModelProperties.java index 547af6d647e..316cc6c722c 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/GTModelProperties.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/GTModelProperties.java @@ -2,12 +2,14 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraftforge.client.model.data.ModelData; import net.minecraftforge.client.model.data.ModelProperty; public class GTModelProperties { public static final ModelProperty LEVEL = new ModelProperty<>(); public static final ModelProperty POS = new ModelProperty<>(); + public static final ModelProperty PARENT_MODEL_DATA = new ModelProperty<>(); public static final ModelProperty PIPE_CONNECTION_MASK = new ModelProperty<>(); public static final ModelProperty PIPE_BLOCKED_MASK = new ModelProperty<>(); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/connected/CTMCache.java new file mode 100644 index 00000000000..be75c64be9a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/connected/CTMCache.java @@ -0,0 +1,255 @@ +package com.gregtechceu.gtceu.client.model.connected; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +import lombok.experimental.Accessors; +import org.jetbrains.annotations.Nullable; + +import static com.gregtechceu.gtceu.client.model.connected.OctagonalOrientation.*; + +// @formatter:off +/** + * The CTM renderer will draw the block's FACE by assembling 4 quadrants from the 5 available block textures. + * The normal {@code texture.png} is the block's "unconnected" texture, and is used when CTM is disabled or the block has nothing to connect to. + * This texture has all the outside corner quadrants, and {@code texture_ctm.png} contains the rest of the quadrants. + *
+ * ┌─────────────────┐ ┌────────────────────────────────┐
+ * │ texture.png     │ │ texture_ctm.png                │
+ * │ ╔══════╤══════╗ │ │  ──────┼────── ║ ─────┼───── ║ │
+ * │ ║      │      ║ │ │ │      │      │║      │      ║ │
+ * │ ║ 16   │ 17   ║ │ │ │ 0    │ 1    │║ 2    │ 3    ║ │
+ * │ ╟──────┼──────╢ │ │ ┼──────┼──────┼╟──────┼──────╢ │
+ * │ ║      │      ║ │ │ │      │      │║      │      ║ │
+ * │ ║ 18   │ 19   ║ │ │ │ 4    │ 5    │║ 6    │ 7    ║ │
+ * │ ╚══════╧══════╝ │ │  ──────┼────── ║ ─────┼───── ║ │
+ * └─────────────────┘ │ ═══════╤═══════╝ ─────┼───── ╚ │
+ *                     │ │      │      ││      │      │ │
+ *                     │ │ 8    │ 9    ││ 10   │ 11   │ │
+ *                     │ ┼──────┼──────┼┼──────┼──────┼ │
+ *                     │ │      │      ││      │      │ │
+ *                     │ │ 12   │ 13   ││ 14   │ 15   │ │
+ *                     │ ═══════╧═══════╗ ─────┼───── ╔ │
+ *                     └────────────────────────────────┘
+ * 
+ * combining { 18, 13, 9, 16 }, we can generate a texture connected to the right! + *
+ * ╔══════╤═══════
+ * ║      │      │
+ * ║ 16   │ 9    │
+ * ╟──────┼──────┼
+ * ║      │      │
+ * ║ 18   │ 13   │
+ * ╚══════╧═══════
+ * 
+ * + * combining { 18, 13, 11, 2 }, we can generate a texture, in the shape of an L (connected to the right, and up + *
+ * ║ ─────┼───── ╚
+ * ║      │      │
+ * ║ 2    │ 11   │
+ * ╟──────┼──────┼
+ * ║      │      │
+ * ║ 18   │ 13   │
+ * ╚══════╧═══════
+ * 
+ * + * HAVE FUN! + * -CptRageToaster- + *

+ * Sourced from ConnectedTexturesMod. + */ +@Accessors(fluent = true, chain = true) +public class CTMCache { + + @FunctionalInterface + public interface StateComparisonCallback { + + StateComparisonCallback DEFAULT = (connectionCheck, from, to, dir) -> connectionCheck.ignoreStates() ? from.getBlock() == to.getBlock() : from == to; + + boolean connects(ConnectionCheck instance, BlockState from, BlockState to, Direction dir); + } + + /** + * The UVs for the specific "magic number" value + */ + public static final ISubmap[] uvs = { + // CTM texture + Submap.fromPixelScale(4, 4, 0, 0), // 0 + Submap.fromPixelScale(4, 4, 4, 0), // 1 + Submap.fromPixelScale(4, 4, 8, 0), // 2 + Submap.fromPixelScale(4, 4, 12, 0), // 3 + Submap.fromPixelScale(4, 4, 0, 4), // 4 + Submap.fromPixelScale(4, 4, 4, 4), // 5 + Submap.fromPixelScale(4, 4, 8, 4), // 6 + Submap.fromPixelScale(4, 4, 12, 4), // 7 + Submap.fromPixelScale(4, 4, 0, 8), // 8 + Submap.fromPixelScale(4, 4, 4, 8), // 9 + Submap.fromPixelScale(4, 4, 8, 8), // 10 + Submap.fromPixelScale(4, 4, 12, 8), // 11 + Submap.fromPixelScale(4, 4, 0, 12), // 12 + Submap.fromPixelScale(4, 4, 4, 12), // 13 + Submap.fromPixelScale(4, 4, 8, 12), // 14 + Submap.fromPixelScale(4, 4, 12, 12), // 15 + // Default texture + Submap.fromPixelScale(8, 8, 0, 0), // 16 + Submap.fromPixelScale(8, 8, 8, 0), // 17 + Submap.fromPixelScale(8, 8, 0, 8), // 18 + Submap.fromPixelScale(8, 8, 8, 8) // 19 + }; + + public static final ISubmap FULL_TEXTURE = Submap.X1; + + // @formatter:on + + /** Some hardcoded offset values for the different corner indeces */ + protected static int[] submapOffsets = { 4, 5, 1, 0 }; + protected static int[] defaultSubmapCache = { 18, 19, 17, 16 }; + + // TODO encapsulate + public ConnectionCheck connectionCheck = new ConnectionCheck(); + + // Mapping the different corner indeces to their respective dirs + protected static final OctagonalOrientation[][] submapMap = { + { BOTTOM, LEFT, BOTTOM_LEFT }, + { BOTTOM, RIGHT, BOTTOM_RIGHT }, + { TOP, RIGHT, TOP_RIGHT }, + { TOP, LEFT, TOP_LEFT } + }; + + protected byte connectionMap; + protected int[] submapCache = defaultSubmapCache.clone(); + + + public static CTMCache getInstance() { + return new CTMCache(); + } + + /** + * Indeces are in counter-clockwise order starting at bottom left. + * + * @return The indeces of the typical 4x4 submap to use for the given face at the given location. + */ + public int[] getSubmapIds(@Nullable BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side) { + if (level == null) { + return this.submapCache; + } + + buildConnectionMap(level, pos, state, side); + // Map connections to submap indices + for (int i = 0; i < 4; i++) { + fillSubmaps(i); + } + + return this.submapCache; + } + + public int[] getSubmapIndices() { + return this.submapCache; + } + + public static boolean isDefaultTexture(int id) { + return (id == 16 || id == 17 || id == 18 || id == 19); + } + + protected void setConnectedState(OctagonalOrientation dir, boolean connected) { + this.connectionMap = setConnectedState(this.connectionMap, dir, connected); + } + + private static byte setConnectedState(byte map, OctagonalOrientation dir, boolean connected) { + if (connected) { + return (byte) (map | (1 << dir.ordinal())); + } else { + return (byte) (map & ~(1 << dir.ordinal())); + } + } + + /** + * Builds the connection map and stores it in this CTMLogic instance. + * The {@link #connected(OctagonalOrientation)}, {@link #connectedAnd(OctagonalOrientation...)}, + * and {@link #connectedOr(OctagonalOrientation...)} methods can be used to access it. + */ + public void buildConnectionMap(BlockAndTintGetter world, BlockPos pos, BlockState state, Direction side) { + // TODO this naive check doesn't work for models that have unculled faces. + // Perhaps a smarter optimization could be done eventually? + for (OctagonalOrientation dir : OctagonalOrientation.VALUES) { + //Note: We can't cache the state that we are checking about connection for as we want to ensure that + // we can take into account the side of the block we want to know the "state" of as if the block is + // a facade of some sort it might return different results based on where it is being queried from + setConnectedState(dir, dir.isConnected(this.connectionCheck, world, pos, state, side)); + } + } + + @SuppressWarnings("null") + protected void fillSubmaps(int idx) { + OctagonalOrientation[] dirs = submapMap[idx]; + if (connectedOr(dirs[0], dirs[1])) { + if (connectedAnd(dirs)) { + // If all dirs are connected, we use the fully connected face, the base offset value. + this.submapCache[idx] = submapOffsets[idx]; + } else { + // This is a bit magic-y, but basically the array is ordered so + // the first dir requires an offset of 2, and the second dir requires an offset of 8 + // plus the initial offset for the corner. + this.submapCache[idx] = submapOffsets[idx] + (connected(dirs[0]) ? 2 : 0) + (connected(dirs[1]) ? 8 : 0); + } + } + } + + /** + * @param dir + * The direction to check connection in. + * @return True if the cached connectionMap holds a connection in this {@link OctagonalOrientation direction}. + */ + public boolean connected(OctagonalOrientation dir) { + return ((this.connectionMap >> dir.ordinal()) & 1) == 1; + } + + /** + * @param dirs + * The directions to check connection in. + * @return True if the cached connectionMap holds a connection in all the given {@link OctagonalOrientation directions}. + */ + @SuppressWarnings("null") + public boolean connectedAnd(OctagonalOrientation... dirs) { + for (OctagonalOrientation dir : dirs) { + if (!connected(dir)) { + return false; + } + } + return true; + } + + /** + * @param dirs + * The directions to check connection in. + * @return True if the cached connectionMap holds a connection in one of the given {@link OctagonalOrientation directions}. + */ + @SuppressWarnings("null") + public boolean connectedOr(OctagonalOrientation... dirs) { + for (OctagonalOrientation dir : dirs) { + if (connected(dir)) { + return true; + } + } + return false; + } + + public boolean connectedNone(OctagonalOrientation... dirs) { + for (OctagonalOrientation dir : dirs) { + if (connected(dir)) { + return false; + } + } + return true; + } + + public boolean connectedOnly(OctagonalOrientation... dirs) { + byte map = 0; + for (OctagonalOrientation dir : dirs) { + map = setConnectedState(map, dir, true); + } + return map == this.connectionMap; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/ConnectionCheck.java b/src/main/java/com/gregtechceu/gtceu/client/model/connected/ConnectionCheck.java new file mode 100644 index 00000000000..afa0242ec85 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/connected/ConnectionCheck.java @@ -0,0 +1,97 @@ +package com.gregtechceu.gtceu.client.model.connected; + +import com.gregtechceu.gtceu.client.model.connected.CTMCache.StateComparisonCallback; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.jetbrains.annotations.Nullable; + +/** + * Sourced from ConnectedTexturesMod. + */ +@NoArgsConstructor +@AllArgsConstructor +@Accessors(fluent = true, chain = true) +public class ConnectionCheck { + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + Codec.BOOL.optionalFieldOf("ignore_states", false).forGetter(ConnectionCheck::ignoreStates) + ).apply(instance, ignoredStates -> new ConnectionCheck().ignoreStates(ignoredStates))); + + @Getter + @Setter + protected boolean ignoreStates; + + @Getter + @Setter + protected StateComparisonCallback stateComparator = StateComparisonCallback.DEFAULT; + + /** + * A simple check for if the given block can connect to the given direction on the given side. + * + * @param level The level the positions are in. + * @param current The position of your block. + * @param currentState The current state of your block. + * @param connection The position of the block to check against. + * @param dir The {@link Direction side} of the block to check for connection status. + * This is not the direction to check in. + * @return True if the given block can connect to the given location on the given side. + */ + public final boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, + BlockPos connection, Direction dir) { + BlockState state = getConnectionState(level, current, currentState, + dir, connection, level.getBlockState(connection)); + return isConnected(level, current, currentState, connection, dir, state); + } + + /** + * A simple check for if the given block can connect to the given direction on the given side. + * + * @param level The level the positions are in. + * @param current The position of your block. + * @param connection The position of the block to check against. + * @param dir The {@link Direction side} of the block to check for connection status. + * This is not the direction to check in. + * @param state The state to check against for connection. + * @return True if the given block can connect to the given location on the given side. + */ + @SuppressWarnings({ "unused", "null" }) + public boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, BlockPos connection, Direction dir, BlockState state) { + BlockState connectionState = getConnectionState(level, connection, level.getBlockState(connection), dir, current, currentState); + BlockPos obscuringPos = connection.relative(dir); + BlockState obscuring = getConnectionState(level, obscuringPos, level.getBlockState(obscuringPos), + dir, current, currentState); + + // check that we aren't already connected to / from this side + return stateComparator(state, connectionState, dir) && !stateComparator(state, obscuring, dir); + } + + public boolean stateComparator(BlockState from, BlockState to, Direction dir) { + return stateComparator.connects(this, from, to, dir); + } + + public BlockState getConnectionState(BlockAndTintGetter level, BlockPos pos, @Nullable Direction side, + BlockPos connection, BlockState connectionState) { + return getConnectionState(level, pos, level.getBlockState(pos), side, connection, connectionState); + } + + public BlockState getConnectionState(BlockAndTintGetter level, BlockPos pos, BlockState state, + @Nullable Direction side, BlockPos connection, BlockState connectionState) { + if (side != null) { + return state.getAppearance(level, pos, side, connectionState, connection); + } + return state; + } + +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/ISubmap.java b/src/main/java/com/gregtechceu/gtceu/client/model/connected/ISubmap.java new file mode 100644 index 00000000000..ccd66874017 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/connected/ISubmap.java @@ -0,0 +1,103 @@ +package com.gregtechceu.gtceu.client.model.connected; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; + +import lombok.RequiredArgsConstructor; + +/** + * Sourced from ConnectedTexturesMod. + */ +public interface ISubmap { + + float getYOffset(); + + float getXOffset(); + + float getWidth(); + + float getHeight(); + + default float getInterpolatedU(TextureAtlasSprite sprite, float u) { + return sprite.getU((getXOffset() + u / getWidth()) / 16F); + } + + default float getInterpolatedV(TextureAtlasSprite sprite, float v) { + return sprite.getV((getYOffset() + v / getHeight()) / 16F); + } + + default float[] toArray() { + return new float[] { getXOffset(), getYOffset(), getXOffset() + getWidth(), getYOffset() + getHeight() }; + } + + default ISubmap unitScale() { + return new SubmapRescaled(this, UNITS_PER_PIXEL, false); + } + + default ISubmap pixelScale() { + return this; + } + + float PIXELS_PER_UNIT = 16f; + float UNITS_PER_PIXEL = 1f / PIXELS_PER_UNIT; + + @RequiredArgsConstructor + class SubmapRescaled implements ISubmap { + + private final ISubmap parent; + private final float ratio; + private final boolean isPixelScale; + + @Override + public float getXOffset() { + return parent.getXOffset() * ratio; + } + + @Override + public float getYOffset() { + return parent.getYOffset() * ratio; + } + + @Override + public float getWidth() { + return parent.getWidth() * ratio; + } + + @Override + public float getHeight() { + return parent.getHeight() * ratio; + } + + @Override + public ISubmap pixelScale() { + return isPixelScale ? this : parent; + } + + @Override + public ISubmap unitScale() { + return isPixelScale ? parent : this; + } + + @Override + public float getInterpolatedU(TextureAtlasSprite sprite, float u) { + return parent.getInterpolatedU(sprite, u); + } + + @Override + public float getInterpolatedV(TextureAtlasSprite sprite, float v) { + return parent.getInterpolatedV(sprite, v); + } + + @Override + public float[] toArray() { + return parent.toArray(); + } + } + + default ISubmap flipX() { + return Submap.fromPixelScale(getWidth(), getHeight(), PIXELS_PER_UNIT - getXOffset() - getWidth(), getYOffset()); + } + + default ISubmap flipY() { + return Submap.fromPixelScale(getWidth(), getHeight(), getXOffset(), PIXELS_PER_UNIT - getYOffset() - getHeight()); + } +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/OctagonalOrientation.java b/src/main/java/com/gregtechceu/gtceu/client/model/connected/OctagonalOrientation.java new file mode 100644 index 00000000000..300d90dc3bf --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/connected/OctagonalOrientation.java @@ -0,0 +1,156 @@ +package com.gregtechceu.gtceu.client.model.connected; + +import net.createmod.catnip.math.DirectionHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.Locale; + +import static net.minecraft.core.Direction.*; + +/** + * Think of this class as an octagonal {@link net.minecraft.core.Direction}. + *

+ * It represents the eight different directions a face of a block can connect with CTM, + * and contains the logic for determining if a block is indeed connected in that direction. + *

+ * Note that, for example, {@link #TOP_RIGHT} does not mean connected to the {@link #TOP} and {@link #RIGHT}, + * but connected in the diagonal direction represented by {@link #TOP_RIGHT}. + * This is used for inner corner rendering. + *

+ * Sourced from ConnectedTexturesMod. + */ +public enum OctagonalOrientation implements StringRepresentable { + // spotless:off + TOP(UP), + TOP_RIGHT(UP, EAST), + RIGHT(EAST), + BOTTOM_RIGHT(DOWN, EAST), + BOTTOM(DOWN), + BOTTOM_LEFT(DOWN, WEST), + LEFT(WEST), + TOP_LEFT(UP, WEST); + // spotless:on + + public static final OctagonalOrientation[] VALUES = values(); + private static final Direction NORMAL = SOUTH; + + static { + // Run after static init + for (OctagonalOrientation dir : OctagonalOrientation.VALUES) { + dir.buildCaches(); + } + } + + private final Direction[] dirs; + + private final BlockPos[] offsets = new BlockPos[6]; + + OctagonalOrientation(Direction... dirs) { + this.dirs = dirs; + } + + private void buildCaches() { + // Fill normalized dirs + for (Direction normal : Direction.values()) { + Direction[] normalized; + if (normal == NORMAL) { + normalized = dirs; + } else if (normal == NORMAL.getOpposite()) { + // If this is the opposite direction of the default normal, we need to mirror the dirs + // A mirror version does not affect y+ and y- so we ignore those + Direction[] ret = new Direction[dirs.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = dirs[i].getStepY() != 0 ? dirs[i] : dirs[i].getOpposite(); + } + normalized = ret; + } else { + Direction axis; + // Next, we need different a different rotation axis depending on if this is up/down or not + if (normal.getAxis() != Axis.Y) { + // If it is not up/down, pick either the left or right-hand rotation + axis = normal == NORMAL.getClockWise() ? UP : DOWN; + } else { + // If it is up/down, pick either the up or down rotation. + axis = normal == UP ? NORMAL.getCounterClockWise() : NORMAL.getClockWise(); + } + Direction[] ret = new Direction[dirs.length]; + // Finally apply all the rotations + for (int i = 0; i < ret.length; i++) { + ret[i] = rotate(dirs[i], axis); + } + normalized = ret; + } + BlockPos ret = BlockPos.ZERO; + for (Direction dir : normalized) { + ret = ret.relative(dir); + } + offsets[normal.ordinal()] = ret; + } + } + + /** + * Finds if this block is connected for the given side in this OctagonalOrientation. + * + * @param ctm The ConnectionCheck instance to use for logic. + * @param level The level the block is in. + * @param pos The position of your block. + * @param state The state of your block. + * @param side The side of the current face. + * @return True if the block is connected in the given OctagonalOrientation, false otherwise. + */ + public boolean isConnected(ConnectionCheck ctm, BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side) { + return ctm.isConnected(level, pos, state, applyConnection(pos, side), side); + } + + /** + * Finds if this block is connected for the given side in this OctagonalOrientation. + * + * @param ctm The ConnectionCheck instance to use for logic. + * @param level The level the block is in. + * @param pos The position of your block. + * @param state The state of your block. + * @param side The side of the current face. + * @param connectionState The state to check for connection with. + * @return True if the block is connected in the given OctagonalOrientation, false otherwise. + */ + public boolean isConnected(ConnectionCheck ctm, BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side, BlockState connectionState) { + return ctm.isConnected(level, pos, state, applyConnection(pos, side), side, connectionState); + } + + /** + * Apply this OctagonalOrientation to the given BlockPos for the given normal direction. + * + * @return The offset BlockPos + */ + public BlockPos applyConnection(BlockPos pos, Direction side) { + return pos.offset(getOffset(side)); + } + + public BlockPos getOffset(Direction normal) { + return offsets[normal.ordinal()]; + } + + private Direction rotate(Direction facing, Direction axisFacing) { + Direction.Axis axis = axisFacing.getAxis(); + AxisDirection axisDir = axisFacing.getAxisDirection(); + + if (axisDir == AxisDirection.POSITIVE) { + return DirectionHelper.rotateAround(facing, axis); + } + + if (facing.getAxis() != axis) { + return facing.getCounterClockWise(axis); + } + + return facing; + } + + @Override + public String getSerializedName() { + return name().toLowerCase(Locale.ROOT); + } +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/Submap.java b/src/main/java/com/gregtechceu/gtceu/client/model/connected/Submap.java new file mode 100644 index 00000000000..4d7db40e1b2 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/connected/Submap.java @@ -0,0 +1,74 @@ +package com.gregtechceu.gtceu.client.model.connected; + +import lombok.Getter; + +/** + * Sourced from ConnectedTexturesMod. + */ +public class Submap implements ISubmap { + + public static final ISubmap X1 = fromPixelScale(16, 16, 0, 0); + + public static final ISubmap[][] X2 = { + { fromPixelScale(8, 8, 0, 0), fromPixelScale(8, 8, 8, 0) }, + { fromPixelScale(8, 8, 0, 8), fromPixelScale(8, 8, 8, 8) } + }; + + private static final float DIV3 = 16 / 3f; + public static final ISubmap[][] X3 = { + { fromPixelScale(DIV3, DIV3, 0, 0), fromPixelScale(DIV3, DIV3, DIV3, 0), fromPixelScale(DIV3, DIV3, DIV3 * 2, 0) }, + { fromPixelScale(DIV3, DIV3, 0, DIV3), fromPixelScale(DIV3, DIV3, DIV3, DIV3), fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3) }, + { fromPixelScale(DIV3, DIV3, 0, DIV3 * 2), fromPixelScale(DIV3, DIV3, DIV3, DIV3 * 2), fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3 * 2) }, + }; + + public static final ISubmap[][] X4 = { + { fromPixelScale(4, 4, 0, 0), fromPixelScale(4, 4, 4, 0), fromPixelScale(4, 4, 8, 0), fromPixelScale(4, 4, 12, 0) }, + { fromPixelScale(4, 4, 0, 4), fromPixelScale(4, 4, 4, 4), fromPixelScale(4, 4, 8, 4), fromPixelScale(4, 4, 12, 4) }, + { fromPixelScale(4, 4, 0, 8), fromPixelScale(4, 4, 4, 8), fromPixelScale(4, 4, 8, 8), fromPixelScale(4, 4, 12, 8) }, + { fromPixelScale(4, 4, 0, 12), fromPixelScale(4, 4, 4, 12), fromPixelScale(4, 4, 8, 12), fromPixelScale(4, 4, 12, 12) }, + }; + + public static ISubmap[][] grid(int w, int h) { + float xDiv = 16f / w; + float yDiv = 16f / h; + ISubmap[][] ret = new ISubmap[h][w]; + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + ret[y][x] = fromPixelScale(xDiv, yDiv, xDiv * x, yDiv * y); + } + } + return ret; + } + + public static ISubmap raw(float width, float height, float xOffset, float yOffset) { + return new Submap(width, height, xOffset, yOffset, 1); + } + + public static ISubmap fromUnitScale(float width, float height, float xOffset, float yOffset) { + return fromPixelScale(width * PIXELS_PER_UNIT, height * PIXELS_PER_UNIT, xOffset * PIXELS_PER_UNIT, yOffset * PIXELS_PER_UNIT); + } + + public static ISubmap fromPixelScale(float width, float height, float xOffset, float yOffset) { + return new Submap(width, height, xOffset, yOffset, UNITS_PER_PIXEL); + } + + @Getter + private final float width, height; + @Getter + private final float xOffset, yOffset; + + final SubmapRescaled rescaled; + + private Submap(float width, float height, float xOffset, float yOffset, float rescale) { + this.width = width; + this.height = height; + this.xOffset = xOffset; + this.yOffset = yOffset; + this.rescaled = new SubmapRescaled(this, rescale, false); + } + + @Override + public SubmapRescaled pixelScale() { + return this.rescaled; + } +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/model/connected/package-info.java new file mode 100644 index 00000000000..a7df99e25f9 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/connected/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.client.model.connected; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java index 81c150e8358..803f4094a5a 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java @@ -12,12 +12,11 @@ import com.gregtechceu.gtceu.client.model.machine.multipart.MultiPartBakedModel; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; +import com.gregtechceu.gtceu.client.util.QuadUtils; import com.gregtechceu.gtceu.client.util.StaticFaceBakery; import com.gregtechceu.gtceu.common.data.models.GTModels; import com.gregtechceu.gtceu.common.machine.trait.AutoOutputTrait; -import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; - import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; @@ -275,7 +274,7 @@ public List renderMachine(@Nullable MetaMachine machine, @Nullable Bl // we have to recalculate CTM ourselves. // this is the slowest part by a long shot because the LDLib quad logic isn't very optimized. if (level != null && pos != null && blockState != null) { - return CustomBakedModel.reBakeCustomQuads(quads, level, pos, blockState, side, 0.0f); + return QuadUtils.buildCTMQuads(quads, level, pos, blockState, side); } return quads; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java b/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java index d45a95e5663..24907a997a0 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java @@ -2,6 +2,7 @@ import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.client.event.ModelEvent; import net.minecraftforge.client.event.TextureStitchEvent; @@ -31,7 +32,7 @@ default Class eventClass() { @FunctionalInterface interface BakedModelReplacement { - BakedModel modifyBakedModel(ResourceLocation modelLocation, BakedModel model, ModelBakery modelBakery); + BakedModel modifyBakedModel(ResourceLocation modelLocation, BakedModel model, UnbakedModel rootModel, ModelBakery modelBakery); } @FunctionalInterface diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java index 717cf048a8d..f9749f0fced 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java @@ -3,9 +3,7 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.client.model.machine.MachineModel; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; -import com.gregtechceu.gtceu.integration.modernfix.GTModernFixIntegration; -import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; import com.lowdragmc.lowdraglib.client.model.custommodel.LDLMetadataSection; import net.minecraft.ChatFormatting; @@ -33,6 +31,10 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import it.unimi.dsi.fastutil.objects.Object2BooleanLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2BooleanMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.ApiStatus; @@ -46,7 +48,18 @@ private ModelUtils() {} @ApiStatus.Internal public static final List> EVENT_LISTENERS = new ArrayList<>(); - public static final Map CTM_SPRITE_CACHE = new ConcurrentHashMap<>(); + @ApiStatus.Internal + public static final Map CTM_SPRITE_CACHE = new ConcurrentHashMap<>(); + + @ApiStatus.Internal + public static final Multimap SCRAPED_TEXTURES = HashMultimap.create(); + @ApiStatus.Internal + public static final Object2BooleanMap WRAPPED_MODELS = new Object2BooleanLinkedOpenHashMap<>(); + + @ApiStatus.Internal + public static void textureScraped(ResourceLocation modelLocation, Material material) { + SCRAPED_TEXTURES.put(modelLocation, material); + } public static List getBakedModelQuads(BakedModel model, BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side, RandomSource rand) { @@ -57,6 +70,11 @@ public static BakedModel getModelForState(BlockState state) { return Minecraft.getInstance().getBlockRenderer().getBlockModel(state); } + @SuppressWarnings("deprecation") + public static TextureAtlasSprite getBlockSprite(ResourceLocation textureLocation) { + return Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(textureLocation); + } + public static String getPropertyValueString(Map.Entry, Comparable> entry) { Property property = entry.getKey(); Comparable value = entry.getValue(); @@ -110,14 +128,15 @@ public void onResourceManagerReload(@NotNull ResourceManager resourceManager) { @SubscribeEvent(priority = EventPriority.LOWEST) public static void onAtlasStitched(TextureStitchEvent.Post event) { if (event.getAtlas().location().equals(TextureAtlas.LOCATION_BLOCKS)) { + // Cache all textures' CTM metadata + // TODO lazy CTM_SPRITE_CACHE.clear(); for (ResourceLocation location : event.getAtlas().getTextureLocations()) { ResourceLocation absLoc = LDLMetadataSection.spriteToAbsolute(location); LDLMetadataSection section = LDLMetadataSection.getMetadata(absLoc); if (section.connection != null) { - TextureAtlasSprite baseSprite = event.getAtlas().getSprite(location); TextureAtlasSprite ctmSprite = event.getAtlas().getSprite(section.connection); - CTM_SPRITE_CACHE.put(baseSprite, ctmSprite); + CTM_SPRITE_CACHE.put(location, ctmSprite); } } } @@ -140,26 +159,20 @@ public static void onAtlasStitched(TextureStitchEvent.Post event) { @SubscribeEvent(priority = EventPriority.LOWEST) public static void onModifyBakingResult(ModelEvent.ModifyBakingResult event) { - // don't process baked model replacement here if modernfix dynamic resources is enabled - if (GTCEu.Mods.isModernFixLoaded() && GTModernFixIntegration.isDynamicResourcesEnabled()) return; + // don't process baked model replacement here if modernfix is loaded, as + // GTModernFixIntegration#onBakedModelLoad does the same thing & it's always called + if (GTCEu.Mods.isModernFixLoaded()) return; for (var entry : event.getModels().entrySet()) { BakedModel model = entry.getValue(); - // run through all model replacers first + // process all model replacers for (var listener : EVENT_LISTENERS) { if (!(listener.listener instanceof AssetEventListener.BakedModelReplacement modelReplacement)) continue; - model = modelReplacement.modifyBakedModel(entry.getKey(), model, event.getModelBakery()); + model = modelReplacement.modifyBakedModel(entry.getKey(), model, + event.getModelBakery().getModel(entry.getKey()), event.getModelBakery()); } entry.setValue(model); - - // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins - // Also, the caching they have stops our models from updating properly - if (model instanceof CustomBakedModel ctmModel) { - if (ctmModel.getParent() instanceof MachineModel machineModel) { - entry.setValue(machineModel); - } - } } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java b/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java index 7116e3fcc5a..9718d5c6451 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java @@ -1,9 +1,7 @@ package com.gregtechceu.gtceu.client.util; -import com.lowdragmc.lowdraglib.client.bakedpipeline.ISubmap; -import com.lowdragmc.lowdraglib.client.bakedpipeline.Submap; -import com.lowdragmc.lowdraglib.client.model.custommodel.Connection; -import com.lowdragmc.lowdraglib.client.model.custommodel.Connections; +import com.gregtechceu.gtceu.client.model.connected.ISubmap; +import com.gregtechceu.gtceu.client.model.connected.OctagonalOrientation; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.block.model.BakedQuad; @@ -13,20 +11,21 @@ import net.minecraftforge.client.model.IQuadTransformer; import it.unimi.dsi.fastutil.Pair; -import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; import org.joml.Vector3f; +import static com.gregtechceu.gtceu.client.model.connected.OctagonalOrientation.*; + public record QuadInfo(TextureAtlasSprite sprite, int tintIndex, Direction direction, boolean shade, boolean ao, int blockLight, int skyLight, Vector3f[] vertices, Vector2f[] uvs, Vector2f minUV, Vector2f maxUV) { // Mapping the different corner indices to their respective dirs - private static final Connection[][] SUBMAP_MAP = new Connection[][] { - { Connection.DOWN, Connection.LEFT, Connection.DOWN_LEFT }, - { Connection.DOWN, Connection.RIGHT, Connection.DOWN_RIGHT }, - { Connection.UP, Connection.RIGHT, Connection.UP_RIGHT }, - { Connection.UP, Connection.LEFT, Connection.UP_LEFT } + private static final OctagonalOrientation[][] SUBMAP_MAP = new OctagonalOrientation[][] { + { BOTTOM, LEFT, BOTTOM_LEFT }, + { BOTTOM, RIGHT, BOTTOM_RIGHT }, + { TOP, RIGHT, TOP_RIGHT }, + { TOP, LEFT, TOP_LEFT } }; public QuadInfo(TextureAtlasSprite sprite, int tintIndex, Direction direction, boolean shade, boolean ao, @@ -91,7 +90,7 @@ public Vector2f[] normalizeUVQuadrant() { public Vector2f[] transformUVData(TextureAtlasSprite other, ISubmap submap) { Vector2f[] normalized = normalizeUVs(); var maxUVs = QuadUtils.findMinMaxUVs(normalized); - submap = submap.normalize(); + submap = submap.unitScale(); float width = maxUVs.second().x() - maxUVs.first().x(); float height = maxUVs.second().y() - maxUVs.first().y(); @@ -104,43 +103,26 @@ public Vector2f[] transformUVData(TextureAtlasSprite other, ISubmap submap) { float maxU = minU + (width * submap.getWidth()); float maxV = minV + (height * submap.getHeight()); - Vector2f[] newUvs = new Vector2f[4]; + Vector2f[] newUVs = new Vector2f[4]; for (int i = 0; i < 4; i++) { Vector2f uv = new Vector2f(this.uvs[i]); - // same as sprite.getX(oldSprite.getXOffset(x)), but we don't multiply and divide in between + // same as sprite.getU(oldSprite.getUOffset(uv.x)), but we don't multiply and divide in between + // NOTE: can be simplified to ^ on 1.21 uv.x = Mth.map(uv.x, this.sprite.getU0(), this.sprite.getU1(), other.getU0(), other.getU1()); uv.y = Mth.map(uv.y, this.sprite.getV0(), this.sprite.getV1(), other.getV0(), other.getV1()); - newUvs[i] = uv; + newUVs[i] = uv; } // FIXME this... isn't all that great. - Vector2f[] newUVs = { - new Vector2f(newUvs[0].x() == this.minUV.x() ? minU : maxU, newUvs[0].y() == this.minUV.y() ? minV : maxV), - new Vector2f(newUvs[1].x() == this.minUV.x() ? minU : maxU, newUvs[1].y() == this.minUV.y() ? minV : maxV), - new Vector2f(newUvs[2].x() == this.minUV.x() ? minU : maxU, newUvs[2].y() == this.minUV.y() ? minV : maxV), - new Vector2f(newUvs[3].x() == this.minUV.x() ? minU : maxU, newUvs[3].y() == this.minUV.y() ? minV : maxV) + newUVs = new Vector2f[] { + new Vector2f(newUVs[0].x() == this.minUV.x() ? minU : maxU, newUVs[0].y() == this.minUV.y() ? minV : maxV), + new Vector2f(newUVs[1].x() == this.minUV.x() ? minU : maxU, newUVs[1].y() == this.minUV.y() ? minV : maxV), + new Vector2f(newUVs[2].x() == this.minUV.x() ? minU : maxU, newUVs[2].y() == this.minUV.y() ? minV : maxV), + new Vector2f(newUVs[3].x() == this.minUV.x() ? minU : maxU, newUVs[3].y() == this.minUV.y() ? minV : maxV) }; return QuadUtils.relativizeUVs(other, newUVs); } - public @Nullable Submap findSubmap(Connections connections) { - Vector2f uv = QuadUtils.normalizeUV(sprite, maxUV); - int xPos = uv.x() <= 0.5f ? 0 : 1; - int yPos = uv.y() <= 0.5f ? 0 : 1; - - Connection[] toConnect = SUBMAP_MAP[xPos + yPos]; - if (connections.connectedOr(toConnect[0], toConnect[1])) { - // If all dirs are connected, we use the fully connected face, the base offset value. - if (!connections.connectedAnd(toConnect)) { - // if a location isn't connected on all sides, the edge submap is at base+2 in the submap table - xPos += connections.contains(toConnect[0]) ? 2 : 0; - yPos += connections.contains(toConnect[1]) ? 2 : 0; - } - return Submap.X4[xPos][yPos]; - } - return null; - } - public Vector2f[] copyUVs() { Vector2f[] result = new Vector2f[uvs.length]; for (int i = 0; i < uvs.length; ++i) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java index 31130f730c3..90960bd6880 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java @@ -1,7 +1,6 @@ package com.gregtechceu.gtceu.client.util; -import com.lowdragmc.lowdraglib.client.bakedpipeline.Submap; -import com.lowdragmc.lowdraglib.client.model.custommodel.Connections; +import com.gregtechceu.gtceu.client.model.connected.CTMCache; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -12,6 +11,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.client.model.IQuadTransformer; +import it.unimi.dsi.fastutil.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; @@ -62,6 +62,19 @@ public static QuadInfo[] subdivide(BakedQuad baked) { return quad.subdivide(); } + public static Pair findMinMaxUVs(Vector2f[] uvs) { + float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE, maxU = Float.MIN_VALUE, maxV = Float.MIN_VALUE; + + for (int i = 0; i < 4; i++) { + Vector2f uv = uvs[i]; + minU = Math.min(minU, uv.x()); + minV = Math.min(minV, uv.y()); + maxU = Math.max(maxU, uv.x()); + maxV = Math.max(maxV, uv.y()); + } + return Pair.of(new Vector2f(minU, minV), new Vector2f(maxU, maxV)); + } + private static void putVertexData(int[] vertices, int index, Vector3f pos, Vector2f uv) { int posOffset = index * IQuadTransformer.STRIDE + IQuadTransformer.POSITION; vertices[posOffset] = Float.floatToRawIntBits(pos.x()); @@ -108,11 +121,16 @@ public static Vector2f relativizeUV(TextureAtlasSprite sprite, Vector2f vec) { } public static List buildCTMQuads(List quads, BlockAndTintGetter level, BlockPos pos, - @NotNull BlockState state, @Nullable Direction elementSide) { - return buildCTMQuads(Connections.checkConnections(level, pos, state, elementSide), quads); + @NotNull BlockState state, @Nullable Direction side) { + CTMCache ctmCache = CTMCache.getInstance(); + if (side != null) { + ctmCache.getSubmapIds(level, pos, state, side); + } + + return buildCTMQuads(ctmCache, quads); } - public static List buildCTMQuads(Connections connections, List base) { + public static List buildCTMQuads(CTMCache cachedConnections, List base) { List result = new ArrayList<>(); for (BakedQuad originalQuad : base) { TextureAtlasSprite connection = CTM_SPRITE_CACHE.get(originalQuad.getSprite()); @@ -120,18 +138,18 @@ public static List buildCTMQuads(Connections connections, List 15 ? originalQuad.getSprite() : connection; - subdivided[j] = quad.grow().transformUVs(ctmSprite, submap); + subdivided[j] = quad.grow().transformUVs(ctmSprite, CTMCache.uvs[ctm[quadrant]].unitScale()); } } result.addAll(Arrays.stream(subdivided).filter(Objects::nonNull).map(QuadInfo::rebake).toList()); diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java b/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java new file mode 100644 index 00000000000..81b8ba41c5a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java @@ -0,0 +1,28 @@ +package com.gregtechceu.gtceu.client.util; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.Material; +import net.minecraft.resources.ResourceLocation; + +import java.util.function.Function; + +public class SpriteFunctionWrapper implements Function { + + private final Function internal; + private final ResourceLocation modelLocation; + + public SpriteFunctionWrapper(Function internal, ResourceLocation modelLocation) { + if (internal instanceof SpriteFunctionWrapper wrapper) { + this.internal = wrapper.internal; + } else { + this.internal = internal; + } + this.modelLocation = modelLocation; + } + + @Override + public TextureAtlasSprite apply(Material material) { + ModelUtils.textureScraped(modelLocation, material); + return internal.apply(material); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java index 33028c2a399..baee251db2e 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java @@ -97,7 +97,7 @@ private static void registerEventListener(LampBlockItem toWrap) { if (registeredListener) return; registeredListener = true; - ModelUtils.registerBakeEventListener(false, (modelLocation, model, modelBakery) -> { + ModelUtils.registerBakeEventListener(false, (modelLocation, model, unbakedModel, modelBakery) -> { // handle both cases 1.20 can have passed here. 1.21 *only* has the ModelResourceLocation case. ResourceLocation possibleItemId; diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java new file mode 100644 index 00000000000..c2587e92896 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java @@ -0,0 +1,29 @@ +package com.gregtechceu.gtceu.core.mixins.client; + +import com.gregtechceu.gtceu.client.util.SpriteFunctionWrapper; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.resources.ResourceLocation; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import java.util.function.Function; + +@Mixin(targets = {"net.minecraft.client.resources.model.ModelBakery$ModelBakerImpl"}) +public abstract class ModelBakerImplMixin { + + // Note: We don't remap this method as it's added by forge + @ModifyVariable(at = @At("HEAD"), + method = "bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;", + argsOnly = true, + remap = false) + private Function ldlib$scrapeTextures(Function sprites, + ResourceLocation modelLocation, + ModelState modelState) { + return new SpriteFunctionWrapper(sprites, modelLocation); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java b/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java index 4cf15c7b130..370482a12b6 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java @@ -1,10 +1,7 @@ package com.gregtechceu.gtceu.integration.modernfix; -import com.gregtechceu.gtceu.client.model.machine.MachineModel; - import com.gregtechceu.gtceu.client.util.AssetEventListener; import com.gregtechceu.gtceu.client.util.ModelUtils; -import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.*; @@ -46,17 +43,10 @@ public void onDynamicResourcesStatusChange(boolean enabled) { public BakedModel onBakedModelLoad(ResourceLocation modelLocation, UnbakedModel baseModel, BakedModel model, ModelState state, ModelBakery bakery, Function textureGetter) { - // run through all model replacers first + // process all model replacers for (var listener : ModelUtils.EVENT_LISTENERS) { if (!(listener.listener() instanceof AssetEventListener.BakedModelReplacement modelReplacement)) continue; - model = modelReplacement.modifyBakedModel(modelLocation, model, bakery); - } - - if (model instanceof CustomBakedModel ctmModel) { - // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins - if (ctmModel.getParent() instanceof MachineModel machineModel) { - return machineModel; - } + model = modelReplacement.modifyBakedModel(modelLocation, model, baseModel, bakery); } return model; } diff --git a/src/main/resources/gtceu.mixins.json b/src/main/resources/gtceu.mixins.json index 5661b433819..200c8d9795b 100644 --- a/src/main/resources/gtceu.mixins.json +++ b/src/main/resources/gtceu.mixins.json @@ -17,6 +17,7 @@ "client.GuiHeartTypeMixin", "client.HumanoidArmorLayerMixin", "client.LevelRendererMixin", + "client.ModelBakerImplMixin", "client.ModelManagerMixin", "client.MultiPlayerGameModeMixin", "client.PlayerInfoAccessor", From 96721b397e2f3ae42b43c5feb39d6669f63d07cc Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 11:37:27 +0300 Subject: [PATCH 05/66] Move CTM things to `client.model.ctm` --- src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java | 2 +- .../gtceu/client/model/{ => ctm}/CTMBakedModel.java | 3 +-- .../gtceu/client/model/{connected => ctm}/CTMCache.java | 4 ++-- .../client/model/{connected => ctm}/ConnectionCheck.java | 4 ++-- .../gtceu/client/model/{connected => ctm}/ISubmap.java | 2 +- .../model/{connected => ctm}/OctagonalOrientation.java | 2 +- .../gtceu/client/model/{connected => ctm}/Submap.java | 2 +- .../gtceu/client/model/{connected => ctm}/package-info.java | 2 +- .../java/com/gregtechceu/gtceu/client/util/QuadInfo.java | 6 +++--- .../java/com/gregtechceu/gtceu/client/util/QuadUtils.java | 2 +- 10 files changed, 14 insertions(+), 15 deletions(-) rename src/main/java/com/gregtechceu/gtceu/client/model/{ => ctm}/CTMBakedModel.java (96%) rename src/main/java/com/gregtechceu/gtceu/client/model/{connected => ctm}/CTMCache.java (98%) rename src/main/java/com/gregtechceu/gtceu/client/model/{connected => ctm}/ConnectionCheck.java (97%) rename src/main/java/com/gregtechceu/gtceu/client/model/{connected => ctm}/ISubmap.java (98%) rename src/main/java/com/gregtechceu/gtceu/client/model/{connected => ctm}/OctagonalOrientation.java (99%) rename src/main/java/com/gregtechceu/gtceu/client/model/{connected => ctm}/Submap.java (98%) rename src/main/java/com/gregtechceu/gtceu/client/model/{connected => ctm}/package-info.java (56%) diff --git a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java index c521efcc894..642db33f11d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java @@ -8,7 +8,7 @@ import com.gregtechceu.gtceu.api.data.worldgen.bedrockore.BedrockOreDefinition; import com.gregtechceu.gtceu.api.item.IComponentItem; import com.gregtechceu.gtceu.api.item.IGTTool; -import com.gregtechceu.gtceu.client.model.CTMBakedModel; +import com.gregtechceu.gtceu.client.model.ctm.CTMBakedModel; import com.gregtechceu.gtceu.client.model.item.FacadeUnbakedModel; import com.gregtechceu.gtceu.client.model.machine.MachineModel; import com.gregtechceu.gtceu.client.model.machine.MachineModelLoader; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java similarity index 96% rename from src/main/java/com/gregtechceu/gtceu/client/model/CTMBakedModel.java rename to src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java index 5806e3dfec0..23a76d05806 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/CTMBakedModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java @@ -1,6 +1,5 @@ -package com.gregtechceu.gtceu.client.model; +package com.gregtechceu.gtceu.client.model.ctm; -import com.gregtechceu.gtceu.client.model.connected.CTMCache; import com.gregtechceu.gtceu.client.util.QuadUtils; import net.minecraft.client.renderer.RenderType; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java similarity index 98% rename from src/main/java/com/gregtechceu/gtceu/client/model/connected/CTMCache.java rename to src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index be75c64be9a..294a4cc8e1d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/connected/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.model.connected; +package com.gregtechceu.gtceu.client.model.ctm; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.BlockAndTintGetter; @@ -7,7 +7,7 @@ import lombok.experimental.Accessors; import org.jetbrains.annotations.Nullable; -import static com.gregtechceu.gtceu.client.model.connected.OctagonalOrientation.*; +import static com.gregtechceu.gtceu.client.model.ctm.OctagonalOrientation.*; // @formatter:off /** diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/ConnectionCheck.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java similarity index 97% rename from src/main/java/com/gregtechceu/gtceu/client/model/connected/ConnectionCheck.java rename to src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java index afa0242ec85..489ebf6c1c0 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/connected/ConnectionCheck.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java @@ -1,6 +1,6 @@ -package com.gregtechceu.gtceu.client.model.connected; +package com.gregtechceu.gtceu.client.model.ctm; -import com.gregtechceu.gtceu.client.model.connected.CTMCache.StateComparisonCallback; +import com.gregtechceu.gtceu.client.model.ctm.CTMCache.StateComparisonCallback; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/ISubmap.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java similarity index 98% rename from src/main/java/com/gregtechceu/gtceu/client/model/connected/ISubmap.java rename to src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java index ccd66874017..4e9716492a9 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/connected/ISubmap.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.model.connected; +package com.gregtechceu.gtceu.client.model.ctm; import net.minecraft.client.renderer.texture.TextureAtlasSprite; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/OctagonalOrientation.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java similarity index 99% rename from src/main/java/com/gregtechceu/gtceu/client/model/connected/OctagonalOrientation.java rename to src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java index 300d90dc3bf..2aa94bf3f17 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/connected/OctagonalOrientation.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.model.connected; +package com.gregtechceu.gtceu.client.model.ctm; import net.createmod.catnip.math.DirectionHelper; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/Submap.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java similarity index 98% rename from src/main/java/com/gregtechceu/gtceu/client/model/connected/Submap.java rename to src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java index 4d7db40e1b2..bea4f7531d6 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/connected/Submap.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.model.connected; +package com.gregtechceu.gtceu.client.model.ctm; import lombok.Getter; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/connected/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/package-info.java similarity index 56% rename from src/main/java/com/gregtechceu/gtceu/client/model/connected/package-info.java rename to src/main/java/com/gregtechceu/gtceu/client/model/ctm/package-info.java index a7df99e25f9..ca86d8adbbc 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/connected/package-info.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/package-info.java @@ -1,4 +1,4 @@ @NotNullByDefault -package com.gregtechceu.gtceu.client.model.connected; +package com.gregtechceu.gtceu.client.model.ctm; import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java b/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java index 9718d5c6451..fe84750b075 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.client.util; -import com.gregtechceu.gtceu.client.model.connected.ISubmap; -import com.gregtechceu.gtceu.client.model.connected.OctagonalOrientation; +import com.gregtechceu.gtceu.client.model.ctm.ISubmap; +import com.gregtechceu.gtceu.client.model.ctm.OctagonalOrientation; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.block.model.BakedQuad; @@ -14,7 +14,7 @@ import org.joml.Vector2f; import org.joml.Vector3f; -import static com.gregtechceu.gtceu.client.model.connected.OctagonalOrientation.*; +import static com.gregtechceu.gtceu.client.model.ctm.OctagonalOrientation.*; public record QuadInfo(TextureAtlasSprite sprite, int tintIndex, Direction direction, boolean shade, boolean ao, int blockLight, int skyLight, diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java index 90960bd6880..72b5d52cc59 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java @@ -1,6 +1,6 @@ package com.gregtechceu.gtceu.client.util; -import com.gregtechceu.gtceu.client.model.connected.CTMCache; +import com.gregtechceu.gtceu.client.model.ctm.CTMCache; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; From e86f96520264b917882f310218c56e8394452667 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 11:58:31 +0300 Subject: [PATCH 06/66] Clean up CTMBakedModel#getQuads --- .../gtceu/client/model/ctm/CTMBakedModel.java | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java index 23a76d05806..ec1f14c5de8 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java @@ -36,15 +36,21 @@ public BakedModel getParent() { @Override public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand, ModelData data, @Nullable RenderType renderType) { + ModelData parentModelData = data.has(PARENT_MODEL_DATA) ? data.get(PARENT_MODEL_DATA) : data; + if (state == null || side == null) { + return super.getQuads(state, side, rand, parentModelData, renderType); + } BlockAndTintGetter level = data.get(LEVEL); BlockPos pos = data.get(POS); - ModelData parentData = data.has(PARENT_MODEL_DATA) ? data.get(PARENT_MODEL_DATA) : data; - - if (level != null && pos != null && state != null) { - return getCustomQuads(level, pos, state, side, rand, parentData, renderType); - } else { - return super.getQuads(state, side, rand, parentData, renderType); + if (level == null || pos == null) { + return super.getQuads(state, side, rand, parentModelData, renderType); } + + CTMCache ctmCache = CTMCache.getInstance(); + ctmCache.getSubmapIds(level, pos, state, side); + return this.sideCache.computeIfAbsent(side, $ -> new ConcurrentHashMap<>()) + .computeIfAbsent(ctmCache, cache -> QuadUtils.buildCTMQuads(cache, + super.getQuads(state, side, rand, parentModelData, renderType))); } @Override @@ -56,18 +62,4 @@ public ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState .with(PARENT_MODEL_DATA, parentModelData) .build(); } - - public List getCustomQuads(BlockAndTintGetter level, BlockPos pos, BlockState state, - @Nullable Direction side, RandomSource rand, - ModelData modelData, @Nullable RenderType renderType) { - if (side == null) { - return super.getQuads(state, null, rand, modelData, renderType); - } - - CTMCache ctmCache = CTMCache.getInstance(); - ctmCache.getSubmapIds(level, pos, state, side); - return this.sideCache.computeIfAbsent(side, $ -> new ConcurrentHashMap<>()) - .computeIfAbsent(ctmCache, cache -> QuadUtils.buildCTMQuads(cache, - super.getQuads(state, side, rand, modelData, renderType))); - } } From 3d21cdf755ddb3cd4450b843ee7f1dd46ec40b90 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 12:39:56 +0300 Subject: [PATCH 07/66] Move quad utils to `client.util.quad` --- .../gregtechceu/gtceu/client/model/TextureOverrideModel.java | 2 +- .../com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java | 2 +- .../gregtechceu/gtceu/client/model/machine/MachineModel.java | 4 ++-- .../gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java | 2 +- .../gtceu/client/renderer/cover/FacadeCoverRenderer.java | 4 ++-- .../gtceu/client/renderer/cover/IOCoverRenderer.java | 2 +- .../gtceu/client/renderer/cover/SimpleCoverRenderer.java | 2 +- .../gtceu/client/util/{ => quad}/GTQuadTransformers.java | 2 +- .../gregtechceu/gtceu/client/util/{ => quad}/QuadInfo.java | 2 +- .../gregtechceu/gtceu/client/util/{ => quad}/QuadUtils.java | 2 +- .../gtceu/client/util/{ => quad}/StaticFaceBakery.java | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) rename src/main/java/com/gregtechceu/gtceu/client/util/{ => quad}/GTQuadTransformers.java (99%) rename src/main/java/com/gregtechceu/gtceu/client/util/{ => quad}/QuadInfo.java (99%) rename src/main/java/com/gregtechceu/gtceu/client/util/{ => quad}/QuadUtils.java (99%) rename src/main/java/com/gregtechceu/gtceu/client/util/{ => quad}/StaticFaceBakery.java (99%) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java index 652d19bbba8..0b34bcf432b 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java @@ -1,6 +1,6 @@ package com.gregtechceu.gtceu.client.model; -import com.gregtechceu.gtceu.client.util.GTQuadTransformers; +import com.gregtechceu.gtceu.client.util.quad.GTQuadTransformers; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java index ec1f14c5de8..a172baec992 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java @@ -1,6 +1,6 @@ package com.gregtechceu.gtceu.client.model.ctm; -import com.gregtechceu.gtceu.client.util.QuadUtils; +import com.gregtechceu.gtceu.client.util.quad.QuadUtils; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java index 803f4094a5a..5b15c2087f6 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java @@ -12,8 +12,8 @@ import com.gregtechceu.gtceu.client.model.machine.multipart.MultiPartBakedModel; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; -import com.gregtechceu.gtceu.client.util.QuadUtils; -import com.gregtechceu.gtceu.client.util.StaticFaceBakery; +import com.gregtechceu.gtceu.client.util.quad.QuadUtils; +import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; import com.gregtechceu.gtceu.common.data.models.GTModels; import com.gregtechceu.gtceu.common.machine.trait.AutoOutputTrait; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java index 3553bd37510..a4bd08d99b5 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java @@ -8,7 +8,7 @@ import com.gregtechceu.gtceu.client.model.GTModelProperties; import com.gregtechceu.gtceu.client.model.IBlockEntityRendererBakedModel; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; -import com.gregtechceu.gtceu.client.util.GTQuadTransformers; +import com.gregtechceu.gtceu.client.util.quad.GTQuadTransformers; import com.gregtechceu.gtceu.common.data.GTMaterialBlocks; import com.gregtechceu.gtceu.utils.GTUtil; diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java index ce935bc334a..a5f833941d9 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java @@ -6,8 +6,8 @@ import com.gregtechceu.gtceu.client.model.ItemBakedModel; import com.gregtechceu.gtceu.client.model.TextureOverrideModel; import com.gregtechceu.gtceu.client.util.FacadeBlockAndTintGetter; -import com.gregtechceu.gtceu.client.util.GTQuadTransformers; -import com.gregtechceu.gtceu.client.util.StaticFaceBakery; +import com.gregtechceu.gtceu.client.util.quad.GTQuadTransformers; +import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; import com.gregtechceu.gtceu.common.cover.FacadeCover; import com.gregtechceu.gtceu.common.item.behavior.FacadeItemBehaviour; import com.gregtechceu.gtceu.utils.GTUtil; diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java index 28f0c8d5cc9..da7c4336a31 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java @@ -5,7 +5,7 @@ import com.gregtechceu.gtceu.api.cover.CoverBehavior; import com.gregtechceu.gtceu.api.cover.IIOCover; import com.gregtechceu.gtceu.client.util.ModelUtils; -import com.gregtechceu.gtceu.client.util.StaticFaceBakery; +import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java index 472597cafcd..ab2913318c6 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java @@ -2,7 +2,7 @@ import com.gregtechceu.gtceu.api.cover.CoverBehavior; import com.gregtechceu.gtceu.client.util.ModelUtils; -import com.gregtechceu.gtceu.client.util.StaticFaceBakery; +import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/GTQuadTransformers.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/GTQuadTransformers.java similarity index 99% rename from src/main/java/com/gregtechceu/gtceu/client/util/GTQuadTransformers.java rename to src/main/java/com/gregtechceu/gtceu/client/util/quad/GTQuadTransformers.java index 7b6d077d821..ccb3dd07099 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/GTQuadTransformers.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/GTQuadTransformers.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.util; +package com.gregtechceu.gtceu.client.util.quad; import net.minecraft.client.renderer.FaceInfo; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadInfo.java similarity index 99% rename from src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java rename to src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadInfo.java index fe84750b075..3b65c349ba0 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/QuadInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadInfo.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.util; +package com.gregtechceu.gtceu.client.util.quad; import com.gregtechceu.gtceu.client.model.ctm.ISubmap; import com.gregtechceu.gtceu.client.model.ctm.OctagonalOrientation; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java similarity index 99% rename from src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java rename to src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java index 72b5d52cc59..2aa41be3880 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.util; +package com.gregtechceu.gtceu.client.util.quad; import com.gregtechceu.gtceu.client.model.ctm.CTMCache; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/StaticFaceBakery.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/StaticFaceBakery.java similarity index 99% rename from src/main/java/com/gregtechceu/gtceu/client/util/StaticFaceBakery.java rename to src/main/java/com/gregtechceu/gtceu/client/util/quad/StaticFaceBakery.java index dd7b1c9a7c0..200eee8b51a 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/StaticFaceBakery.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/StaticFaceBakery.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.util; +package com.gregtechceu.gtceu.client.util.quad; import com.lowdragmc.lowdraglib.client.bakedpipeline.FaceQuad; From 75c5a96779d9270d3ec8f5058a768507ef892479 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 15:23:51 +0300 Subject: [PATCH 08/66] Rename `ModelUtils` to `ModelEventHelper` and move unrelated utility methods out of it --- .../gtceu/api/machine/MetaMachine.java | 10 ++- .../gregtechceu/gtceu/client/ClientProxy.java | 65 ++++++++++++++++++- .../client/model/machine/MachineModel.java | 3 +- .../client/model/pipe/BakedPipeModel.java | 3 +- .../renderer/block/LampItemRenderer.java | 6 +- .../renderer/cover/FacadeCoverRenderer.java | 16 ++++- .../renderer/cover/IOCoverRenderer.java | 4 +- .../renderer/cover/SimpleCoverRenderer.java | 4 +- .../machine/impl/BoilerMultiPartRender.java | 8 +-- ...{ModelUtils.java => ModelEventHelper.java} | 30 +-------- .../gtceu/client/util/RenderUtil.java | 4 ++ .../client/util/SpriteFunctionWrapper.java | 2 +- .../gtceu/client/util/quad/QuadUtils.java | 2 +- .../gtceu/common/item/LampBlockItem.java | 7 +- .../modernfix/GTModernFixIntegration.java | 4 +- .../gtceu/utils/GTStringUtils.java | 17 +++++ 16 files changed, 124 insertions(+), 61 deletions(-) rename src/main/java/com/gregtechceu/gtceu/client/util/{ModelUtils.java => ModelEventHelper.java} (88%) diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java index b6564371097..455502a441f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java @@ -38,7 +38,7 @@ import com.gregtechceu.gtceu.api.transfer.fluid.IFluidHandlerModifiable; import com.gregtechceu.gtceu.client.model.IBlockEntityRendererBakedModel; import com.gregtechceu.gtceu.client.model.machine.MachineRenderState; -import com.gregtechceu.gtceu.client.util.ModelUtils; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.common.cover.FluidFilterCover; import com.gregtechceu.gtceu.common.cover.ItemFilterCover; import com.gregtechceu.gtceu.common.cover.data.ManualIOMode; @@ -46,6 +46,7 @@ import com.gregtechceu.gtceu.common.machine.owner.PlayerOwner; import com.gregtechceu.gtceu.common.machine.trait.AutoOutputTrait; import com.gregtechceu.gtceu.utils.ExtendedUseOnContext; +import com.gregtechceu.gtceu.utils.GTStringUtils; import com.gregtechceu.gtceu.utils.data.TagCompatibilityFixer; import com.lowdragmc.lowdraglib.gui.texture.IGuiTexture; @@ -53,8 +54,6 @@ import com.lowdragmc.lowdraglib.utils.DummyWorld; import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -615,7 +614,7 @@ public void addDebugOverlayText(Consumer lines) { // add render state info MachineRenderState renderState = this.getRenderState(); for (var property : renderState.getValues().entrySet()) { - lines.accept(ModelUtils.getPropertyValueString(property)); + lines.accept(GTStringUtils.getPropertyValueString(property)); } } @@ -847,8 +846,7 @@ public int getDefaultPaintingColor() { @OnlyIn(Dist.CLIENT) @Override public AABB getRenderBoundingBox() { - BlockRenderDispatcher blockRenderDispatcher = Minecraft.getInstance().getBlockRenderer(); - BakedModel model = blockRenderDispatcher.getBlockModel(this.getBlockState()); + BakedModel model = RenderUtil.getModelForState(this.getBlockState()); if (model instanceof IBlockEntityRendererBakedModel modelWithBER) { if (modelWithBER.getBlockEntityType() == this.getType()) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java index 642db33f11d..b09008d5c95 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java @@ -31,7 +31,7 @@ import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderManager; import com.gregtechceu.gtceu.client.renderer.machine.impl.*; import com.gregtechceu.gtceu.client.renderer.machine.impl.BoilerMultiPartRender; -import com.gregtechceu.gtceu.client.util.ModelUtils; +import com.gregtechceu.gtceu.client.util.ModelEventHelper; import com.gregtechceu.gtceu.common.CommonEventListener; import com.gregtechceu.gtceu.common.CommonProxy; import com.gregtechceu.gtceu.common.data.GTBlockEntities; @@ -191,8 +191,67 @@ public void onRegisterModelLoaders(ModelEvent.RegisterGeometryLoaders event) { event.register("facade", FacadeUnbakedModel.Loader.INSTANCE); // register CTM model (un)wrapper - ModelUtils.registerBakeEventListener(false, (modelLocation, model, rootModel, modelBakery) -> { - if (model == null) return null; + ModelEventUtils.registerBakeEventListener(false, (modelLocation, baked, rootModel, modelBakery) -> { + if (!(modelLocation instanceof ModelResourceLocation) || baked instanceof CTMBakedModel || baked.isCustomRenderer()) { + return baked; + } + Deque dependencies = new ArrayDeque<>(); + Set seenModels = new HashSet<>(); + dependencies.push(modelLocation); + seenModels.add(modelLocation); + + // each model is (should be) processed once, so caching what models have been wrapped is a waste of RAM, + // especially when the cache is only updated after wrapping a model + boolean shouldWrap = false; + Set> errors = new HashSet<>(); + // Breadth-first loop through dependencies, exiting as soon as a CTM texture is found, + // and skipping duplicates/cycles + PARENT_LOOP: + while (!shouldWrap && !dependencies.isEmpty()) { + ResourceLocation dep = dependencies.pop(); + UnbakedModel model; + try { + model = dep == modelLocation ? rootModel : modelBakery.getModel(dep); + } catch (Exception e) { + continue; + } + + // have to copy because the set is updated during this loop + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + Set textures = new HashSet<>(ModelEventUtils.getModelUsedCTMTextures(dep)); + for (Material tex : textures) { + IMetadataSectionCTM meta = null; + // Cache all dependent texture metadata + // TODO make lazy + try { + meta = ResourceUtil.getMetadata(ResourceUtil.spriteToAbsolute(tex.texture())).orElse(null); + } catch (IOException ignored) {} // Fallthrough + if (meta != null) { + // At least one texture has CTM metadata, so we should wrap this model + shouldWrap = true; + break PARENT_LOOP; + } + } + // shouldWrap is always false here because of the `break` above + Collection newDependencies = model.getDependencies(); + for (ResourceLocation newDep : newDependencies) { + if (seenModels.add(newDep)) { + dependencies.push(newDep); + } + } + } + if (shouldWrap) { + try { + baked = new CTMBakedModel<>(baked); + handleInit(modelLocation, baked, bakery); + dependencies.clear(); + } catch (IOException e) { + GTCEu.LOGGER.error("Could not wrap model {}. Aborting...", modelLocation, e); + } + } + return baked; + + if (baked == null) return null; // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins if (model instanceof CustomBakedModel ctmModel) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java index 5b15c2087f6..2d556585382 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java @@ -12,6 +12,7 @@ import com.gregtechceu.gtceu.client.model.machine.multipart.MultiPartBakedModel; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.client.util.quad.QuadUtils; import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; import com.gregtechceu.gtceu.common.data.models.GTModels; @@ -297,7 +298,7 @@ public List replacePartBaseModel(List originalQuads, IMult var controllers = part.getControllers(); for (MultiblockControllerMachine controller : controllers) { var state = controller.getBlockState(); - BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state); + BakedModel model = RenderUtil.getModelForState(state); List newQuads = null; // spotless:off diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java index a4bd08d99b5..cb8e67085b1 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java @@ -8,6 +8,7 @@ import com.gregtechceu.gtceu.client.model.GTModelProperties; import com.gregtechceu.gtceu.client.model.IBlockEntityRendererBakedModel; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.client.util.quad.GTQuadTransformers; import com.gregtechceu.gtceu.common.data.GTMaterialBlocks; import com.gregtechceu.gtceu.utils.GTUtil; @@ -103,7 +104,7 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction return quads; } BlockState frameState = frameBlockEntry.getDefaultState(); - BakedModel frameModel = Minecraft.getInstance().getBlockRenderer().getBlockModel(frameState); + BakedModel frameModel = RenderUtil.getModelForState(frameState); modelData = frameModel.getModelData(level, pos, frameState, modelData); diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/LampItemRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/LampItemRenderer.java index 268af12e43c..ee64e9830b2 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/LampItemRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/LampItemRenderer.java @@ -1,11 +1,11 @@ package com.gregtechceu.gtceu.client.renderer.block; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.common.item.LampBlockItem; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.world.item.ItemDisplayContext; @@ -32,13 +32,11 @@ public static LampItemRenderer getInstance() { } protected final ItemRenderer itemRenderer; - protected final BlockRenderDispatcher blockRenderer; protected LampItemRenderer() { super(Minecraft.getInstance().getBlockEntityRenderDispatcher(), Minecraft.getInstance().getEntityModels()); this.itemRenderer = Minecraft.getInstance().getItemRenderer(); - this.blockRenderer = Minecraft.getInstance().getBlockRenderer(); } @Override @@ -49,7 +47,7 @@ public void renderByItem(@NotNull ItemStack stack, @NotNull ItemDisplayContext d return; } BlockState state = item.getStateFromStack(stack, null); - BakedModel p_model = blockRenderer.getBlockModel(state); + BakedModel p_model = RenderUtil.getModelForState(state); for (var model : p_model.getRenderPasses(stack, true)) { for (var rendertype : model.getRenderTypes(stack, true)) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java index a5f833941d9..c5d1094b28f 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java @@ -6,6 +6,7 @@ import com.gregtechceu.gtceu.client.model.ItemBakedModel; import com.gregtechceu.gtceu.client.model.TextureOverrideModel; import com.gregtechceu.gtceu.client.util.FacadeBlockAndTintGetter; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.client.util.quad.GTQuadTransformers; import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; import com.gregtechceu.gtceu.common.cover.FacadeCover; @@ -187,14 +188,23 @@ public void renderCover(List quads, Direction side, RandomSource rand Direction attachedSide = coverBehavior.attachedSide; - BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state); - ModelData extraData = model.getModelData(level, pos, state, modelData); + BakedModel model = RenderUtil.getModelForState(state); + ModelData facadeModelData = model.getModelData(level, pos, state, modelData); - List facadeQuads = model.getQuads(state, attachedSide, rand, extraData, renderType); + + if (renderType != null && !facadeModel.getRenderTypes(facadeState, rand, facadeModelData).contains(renderType)) { + return; + } + + List facadeQuads = model.getQuads(state, attachedSide, rand, facadeModelData, renderType); facadeQuads = new LinkedList<>(facadeQuads); List coverQuads = new ArrayList<>(); if (side == attachedSide) { + for (BakedQuad quad : facadeQuads) { + // clamp the facade quads' vertices into the model + coverQuads.add(FACADE_PLANE_TRANSFORMER.process(quad)); + } coverQuads.addAll(facadeQuads); } else if (side == null && coverBehavior.coverHolder.shouldRenderBackSide()) { AABB cube = COVER_BACK_CUBES.get(attachedSide); diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java index da7c4336a31..317e5e10285 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java @@ -4,7 +4,7 @@ import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.cover.CoverBehavior; import com.gregtechceu.gtceu.api.cover.IIOCover; -import com.gregtechceu.gtceu.client.util.ModelUtils; +import com.gregtechceu.gtceu.client.util.ModelEventHelper; import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; import net.minecraft.client.renderer.RenderType; @@ -46,7 +46,7 @@ public IOCoverRenderer(@Nullable ResourceLocation overlay, @Nullable ResourceLocation invertedOverlay, @Nullable ResourceLocation emissiveOverlay, @Nullable ResourceLocation invertedEmissiveOverlay) { - ModelUtils.registerAtlasStitchedEventListener(false, InventoryMenu.BLOCK_ATLAS, event -> { + ModelEventHelper.registerAtlasStitchedEventListener(false, InventoryMenu.BLOCK_ATLAS, event -> { var atlas = event.getAtlas(); if (overlay != null) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java index ab2913318c6..a7ae78de074 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.client.renderer.cover; import com.gregtechceu.gtceu.api.cover.CoverBehavior; -import com.gregtechceu.gtceu.client.util.ModelUtils; +import com.gregtechceu.gtceu.client.util.ModelEventHelper; import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; import net.minecraft.client.renderer.RenderType; @@ -34,7 +34,7 @@ public SimpleCoverRenderer(ResourceLocation texture) { } public SimpleCoverRenderer(ResourceLocation texture, ResourceLocation emissiveTexture) { - ModelUtils.registerAtlasStitchedEventListener(false, InventoryMenu.BLOCK_ATLAS, event -> { + ModelEventHelper.registerAtlasStitchedEventListener(false, InventoryMenu.BLOCK_ATLAS, event -> { var atlas = event.getAtlas(); sprite = atlas.getSprite(texture); diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/BoilerMultiPartRender.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/BoilerMultiPartRender.java index dc4dcd9b5c4..f450e986b41 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/BoilerMultiPartRender.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/BoilerMultiPartRender.java @@ -8,7 +8,7 @@ import com.gregtechceu.gtceu.client.model.machine.IControllerModelRenderer; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderType; -import com.gregtechceu.gtceu.client.util.ModelUtils; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.common.block.BoilerFireboxType; import com.gregtechceu.gtceu.common.data.GTBlocks; @@ -96,13 +96,13 @@ public void renderPartModel(List quads, MultiblockControllerMachine c Direction frontFacing, @Nullable Direction side, RandomSource rand, @NotNull ModelData modelData, @Nullable RenderType renderType) { if (this.fireboxIdleModel == null) { - this.fireboxIdleModel = ModelUtils.getModelForState(fireboxIdle); + this.fireboxIdleModel = RenderUtil.getModelForState(fireboxIdle); } if (this.fireboxActiveModel == null) { - this.fireboxActiveModel = ModelUtils.getModelForState(fireboxActive); + this.fireboxActiveModel = RenderUtil.getModelForState(fireboxActive); } if (this.casingModel == null) { - this.casingModel = ModelUtils.getModelForState(casing); + this.casingModel = RenderUtil.getModelForState(casing); } BlockPos partPos = part.self().getBlockPos(); diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java similarity index 88% rename from src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java rename to src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java index f9749f0fced..ed79654826d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java @@ -35,16 +35,15 @@ import com.google.common.collect.Multimap; import it.unimi.dsi.fastutil.objects.Object2BooleanLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2BooleanMap; -import org.jetbrains.annotations.NotNull; +import lombok.experimental.UtilityClass; import org.jetbrains.annotations.ApiStatus; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +@UtilityClass @Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) -public class ModelUtils { - - private ModelUtils() {} +public class ModelEventHelper { @ApiStatus.Internal public static final List> EVENT_LISTENERS = new ArrayList<>(); @@ -66,29 +65,6 @@ public static List getBakedModelQuads(BakedModel model, BlockAndTintG return model.getQuads(state, side, rand, model.getModelData(level, pos, state, ModelData.EMPTY), null); } - public static BakedModel getModelForState(BlockState state) { - return Minecraft.getInstance().getBlockRenderer().getBlockModel(state); - } - - @SuppressWarnings("deprecation") - public static TextureAtlasSprite getBlockSprite(ResourceLocation textureLocation) { - return Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(textureLocation); - } - - public static String getPropertyValueString(Map.Entry, Comparable> entry) { - Property property = entry.getKey(); - Comparable value = entry.getValue(); - - String valueString = Util.getPropertyName(property, value); - if (Boolean.TRUE.equals(value)) { - valueString = ChatFormatting.GREEN + valueString; - } else if (Boolean.FALSE.equals(value)) { - valueString = ChatFormatting.RED + valueString; - } - - return property.getName() + ": " + valueString; - } - public static void registerAtlasStitchedEventListener(boolean removeOnReload, AssetEventListener.AtlasStitched listener) { EVENT_LISTENERS.add(new EventListenerHolder<>(listener, removeOnReload)); diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/RenderUtil.java b/src/main/java/com/gregtechceu/gtceu/client/util/RenderUtil.java index f1dec39d941..663c823b530 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/RenderUtil.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/RenderUtil.java @@ -61,6 +61,10 @@ @OnlyIn(Dist.CLIENT) public class RenderUtil { + public static BakedModel getModelForState(BlockState state) { + return Minecraft.getInstance().getBlockRenderer().getBlockModel(state); + } + public enum FluidTextureType { STILL((fluidTypeExtensions, fluidStack) -> { diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java b/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java index 81b8ba41c5a..67341b88e87 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java @@ -22,7 +22,7 @@ public SpriteFunctionWrapper(Function internal, Re @Override public TextureAtlasSprite apply(Material material) { - ModelUtils.textureScraped(modelLocation, material); + ModelEventHelper.textureScraped(modelLocation, material); return internal.apply(material); } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java index 2aa41be3880..d51c30ea856 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java @@ -22,7 +22,7 @@ import java.util.List; import java.util.Objects; -import static com.gregtechceu.gtceu.client.util.ModelUtils.*; +import static com.gregtechceu.gtceu.client.util.ModelEventHelper.*; public class QuadUtils { diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java index baee251db2e..05e8f0f5df4 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java @@ -2,11 +2,11 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.client.renderer.block.LampItemRenderer; -import com.gregtechceu.gtceu.client.util.ModelUtils; +import com.gregtechceu.gtceu.client.util.ModelEventHelper; import com.gregtechceu.gtceu.common.block.LampBlock; import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; -import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; + import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.core.NonNullList; @@ -26,7 +26,6 @@ import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.function.Consumer; import javax.annotation.ParametersAreNonnullByDefault; @@ -97,7 +96,7 @@ private static void registerEventListener(LampBlockItem toWrap) { if (registeredListener) return; registeredListener = true; - ModelUtils.registerBakeEventListener(false, (modelLocation, model, unbakedModel, modelBakery) -> { + ModelEventHelper.registerBakeEventListener(false, (modelLocation, model, unbakedModel, modelBakery) -> { // handle both cases 1.20 can have passed here. 1.21 *only* has the ModelResourceLocation case. ResourceLocation possibleItemId; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java b/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java index 370482a12b6..6946e0c45b5 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.modernfix; import com.gregtechceu.gtceu.client.util.AssetEventListener; -import com.gregtechceu.gtceu.client.util.ModelUtils; +import com.gregtechceu.gtceu.client.util.ModelEventHelper; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.*; @@ -44,7 +44,7 @@ public BakedModel onBakedModelLoad(ResourceLocation modelLocation, UnbakedModel BakedModel model, ModelState state, ModelBakery bakery, Function textureGetter) { // process all model replacers - for (var listener : ModelUtils.EVENT_LISTENERS) { + for (var listener : ModelEventHelper.EVENT_LISTENERS) { if (!(listener.listener() instanceof AssetEventListener.BakedModelReplacement modelReplacement)) continue; model = modelReplacement.modifyBakedModel(modelLocation, model, baseModel, bakery); } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/GTStringUtils.java b/src/main/java/com/gregtechceu/gtceu/utils/GTStringUtils.java index 70912110719..32d503a7f57 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/GTStringUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/GTStringUtils.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.utils; import net.minecraft.ChatFormatting; +import net.minecraft.Util; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.ListTag; import net.minecraft.network.chat.Component; @@ -8,6 +9,7 @@ import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.NotNull; @@ -15,6 +17,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; public class GTStringUtils { @@ -222,4 +225,18 @@ public static Component toComponent(ListTag arr) { component.append("]"); return component; } + + public static String getPropertyValueString(Map.Entry, Comparable> entry) { + Property property = entry.getKey(); + Comparable value = entry.getValue(); + + String valueString = Util.getPropertyName(property, value); + if (Boolean.TRUE.equals(value)) { + valueString = ChatFormatting.GREEN + valueString; + } else if (Boolean.FALSE.equals(value)) { + valueString = ChatFormatting.RED + valueString; + } + + return property.getName() + ": " + valueString; + } } From ee18024f594a340b75478f4c337f76eced4f3c01 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 15:43:10 +0300 Subject: [PATCH 09/66] Fix up the CTM reload listener in ClientProxy --- .../gregtechceu/gtceu/client/ClientProxy.java | 173 ++++++------------ .../gtceu/client/util/AssetEventListener.java | 3 +- .../gtceu/client/util/ModelEventHelper.java | 34 +--- .../client/util/SpriteFunctionWrapper.java | 2 +- .../mixins/client/ModelBakerImplMixin.java | 10 +- .../gregtechceu/gtceu/utils/ResourceUtil.java | 81 ++++++++ 6 files changed, 160 insertions(+), 143 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/utils/ResourceUtil.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java index b09008d5c95..29f6b91575f 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java @@ -54,11 +54,11 @@ import com.gregtechceu.gtceu.integration.map.layer.Layers; import com.gregtechceu.gtceu.integration.map.layer.builtin.FluidRenderLayer; import com.gregtechceu.gtceu.integration.map.layer.builtin.OreRenderLayer; +import com.gregtechceu.gtceu.utils.ResourceUtil; import com.gregtechceu.gtceu.utils.data.RuntimeBlockstateProvider; import com.gregtechceu.gtceu.utils.input.SyncedKeyMapping; import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; -import com.lowdragmc.lowdraglib.client.model.custommodel.LDLMetadataSection; import net.minecraft.client.model.BoatModel; import net.minecraft.client.model.ChestBoatModel; @@ -80,10 +80,8 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.HashSet; -import java.util.Set; +import java.io.IOException; +import java.util.*; public class ClientProxy extends CommonProxy { @@ -191,131 +189,80 @@ public void onRegisterModelLoaders(ModelEvent.RegisterGeometryLoaders event) { event.register("facade", FacadeUnbakedModel.Loader.INSTANCE); // register CTM model (un)wrapper - ModelEventUtils.registerBakeEventListener(false, (modelLocation, baked, rootModel, modelBakery) -> { - if (!(modelLocation instanceof ModelResourceLocation) || baked instanceof CTMBakedModel || baked.isCustomRenderer()) { + ModelEventHelper.registerBakeEventListener(false, (originalModelName, baked, rootUnbaked, modelBakery) -> { + // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins + if (baked instanceof CustomBakedModel ctmModel) { + if (ctmModel.getParent() instanceof MachineModel machineModel) { + return machineModel; + } else { + // Skip LDLib CTM models + return baked; + } + } + if (baked.isCustomRenderer()) { + // Nothing we can add to builtin models + return baked; + } + // do not register automatic CTM for machine models, they handle it themselves + if (baked instanceof MachineModel) { + return baked; + } + + if (!(originalModelName instanceof ModelResourceLocation) || rootUnbaked == null || baked instanceof CTMBakedModel) { return baked; } Deque dependencies = new ArrayDeque<>(); Set seenModels = new HashSet<>(); - dependencies.push(modelLocation); - seenModels.add(modelLocation); - - // each model is (should be) processed once, so caching what models have been wrapped is a waste of RAM, - // especially when the cache is only updated after wrapping a model - boolean shouldWrap = false; - Set> errors = new HashSet<>(); - // Breadth-first loop through dependencies, exiting as soon as a CTM texture is found, - // and skipping duplicates/cycles + dependencies.push(originalModelName); + seenModels.add(originalModelName); + + boolean shouldWrap = ModelEventHelper.WRAPPED_MODELS.getOrDefault(originalModelName, false); + // Breadth-first loop through dependencies + // exiting as soon as a CTM texture is found, and skipping duplicates/cycles PARENT_LOOP: while (!shouldWrap && !dependencies.isEmpty()) { - ResourceLocation dep = dependencies.pop(); - UnbakedModel model; + ResourceLocation dependencyModelName = dependencies.pop(); + UnbakedModel unbaked; try { - model = dep == modelLocation ? rootModel : modelBakery.getModel(dep); + unbaked = dependencyModelName == originalModelName ? rootUnbaked + : modelBakery.getModel(dependencyModelName); } catch (Exception e) { continue; } - - // have to copy because the set is updated during this loop - @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") - Set textures = new HashSet<>(ModelEventUtils.getModelUsedCTMTextures(dep)); - for (Material tex : textures) { - IMetadataSectionCTM meta = null; - // Cache all dependent texture metadata - // TODO make lazy - try { - meta = ResourceUtil.getMetadata(ResourceUtil.spriteToAbsolute(tex.texture())).orElse(null); - } catch (IOException ignored) {} // Fallthrough - if (meta != null) { - // At least one texture has CTM metadata, so we should wrap this model - shouldWrap = true; - break PARENT_LOOP; - } - } - // shouldWrap is always false here because of the `break` above - Collection newDependencies = model.getDependencies(); - for (ResourceLocation newDep : newDependencies) { - if (seenModels.add(newDep)) { - dependencies.push(newDep); - } - } - } - if (shouldWrap) { try { - baked = new CTMBakedModel<>(baked); - handleInit(modelLocation, baked, bakery); - dependencies.clear(); - } catch (IOException e) { - GTCEu.LOGGER.error("Could not wrap model {}. Aborting...", modelLocation, e); - } - } - return baked; - - if (baked == null) return null; - - // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins - if (model instanceof CustomBakedModel ctmModel) { - if (ctmModel.getParent() instanceof MachineModel machineModel) { - return machineModel; - } - } - // do not register automatic CTM for machine models, they handle it themselves - if (model instanceof MachineModel) { - return model; - } - - - if (modelLocation instanceof ModelResourceLocation && rootModel != null) { - if (model.isCustomRenderer()) { // Nothing we can add to builtin models - return model; - } - Deque dependencies = new ArrayDeque<>(); - Set seenModels = new HashSet<>(); - dependencies.push(modelLocation); - seenModels.add(modelLocation); - boolean shouldWrap = ModelUtils.WRAPPED_MODELS.getOrDefault(modelLocation, false); - // Breadth-first loop through dependencies - // exiting as soon as a CTM texture is found, and skipping duplicates/cycles - while (!shouldWrap && !dependencies.isEmpty()) { - ResourceLocation dep = dependencies.pop(); - UnbakedModel unbaked; - try { - unbaked = dep == modelLocation ? rootModel : modelBakery.getModel(dep); - } catch (Exception e) { - continue; - } - try { - // have to copy because the set is updated during this loop - @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") - Set textures = new HashSet<>(ModelUtils.SCRAPED_TEXTURES.get(dep)); - for (Material tex : textures) { - // Cache all dependent texture metadata - // TODO lazy - if (!LDLMetadataSection.getMetadata(LDLMetadataSection.spriteToAbsolute(tex.texture())).isMissing()) { - // At least one texture has CTM metadata, so we should wrap this model - shouldWrap = true; - break; - } + // have to copy because the set is updated during this loop + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + Set textures = new HashSet<>(ModelEventHelper.getModelUsedCTMTextures(dependencyModelName)); + for (Material tex : textures) { + Optional meta = Optional.empty(); + // Cache all dependent texture metadata + // TODO lazy + try { + meta = ResourceUtil.getMetadata(ResourceUtil.spriteToAbsolute(tex.texture())); + } catch (IOException ignored) {} // Fallthrough + if (meta.isPresent()) { + // At least one texture has CTM metadata, so we should wrap this model + shouldWrap = true; + break PARENT_LOOP; } - if (!shouldWrap) { - for (ResourceLocation newDep : unbaked.getDependencies()) { - if (seenModels.add(newDep)) { - dependencies.push(newDep); - } - } + } + // shouldWrap is always false here because of the `break` above + for (ResourceLocation newDep : unbaked.getDependencies()) { + if (seenModels.add(newDep)) { + dependencies.push(newDep); } - } catch (Exception e) { - GTCEu.LOGGER.error("Error loading baked dependency {} for baked {}. Skipping...", - dep, modelLocation, e); } - } - ModelUtils.WRAPPED_MODELS.put(modelLocation, shouldWrap); - if (shouldWrap) { - return new CTMBakedModel<>(model); + } catch (Exception e) { + GTCEu.LOGGER.error("Error loading dependency {} for model {}. Skipping...", + dependencyModelName, originalModelName, e); } } + ModelEventHelper.WRAPPED_MODELS.put(originalModelName, shouldWrap); + if (shouldWrap) { + return new CTMBakedModel<>(baked); + } - return model; + return baked; }); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java b/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java index 24907a997a0..ffdc9caed12 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java @@ -32,7 +32,8 @@ default Class eventClass() { @FunctionalInterface interface BakedModelReplacement { - BakedModel modifyBakedModel(ResourceLocation modelLocation, BakedModel model, UnbakedModel rootModel, ModelBakery modelBakery); + BakedModel modifyBakedModel(ResourceLocation modelLocation, BakedModel model, + @Nullable UnbakedModel rootModel, ModelBakery modelBakery); } @FunctionalInterface diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java index ed79654826d..c7a1cfb23ab 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java @@ -6,35 +6,24 @@ import com.lowdragmc.lowdraglib.client.model.custommodel.LDLMetadataSection; -import net.minecraft.ChatFormatting; -import net.minecraft.Util; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.*; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManagerReloadListener; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ModelEvent; import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; import net.minecraftforge.client.event.TextureStitchEvent; -import net.minecraftforge.client.model.data.ModelData; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; -import it.unimi.dsi.fastutil.objects.Object2BooleanLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2BooleanMap; +import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; import lombok.experimental.UtilityClass; import org.jetbrains.annotations.ApiStatus; @@ -50,19 +39,18 @@ public class ModelEventHelper { @ApiStatus.Internal public static final Map CTM_SPRITE_CACHE = new ConcurrentHashMap<>(); + private static final Multimap SCRAPED_TEXTURES = HashMultimap.create(); @ApiStatus.Internal - public static final Multimap SCRAPED_TEXTURES = HashMultimap.create(); - @ApiStatus.Internal - public static final Object2BooleanMap WRAPPED_MODELS = new Object2BooleanLinkedOpenHashMap<>(); + public static final Object2BooleanMap WRAPPED_MODELS = new Object2BooleanOpenHashMap<>(); @ApiStatus.Internal - public static void textureScraped(ResourceLocation modelLocation, Material material) { + public static void markTextureUsedForModel(ResourceLocation modelLocation, Material material) { SCRAPED_TEXTURES.put(modelLocation, material); } - public static List getBakedModelQuads(BakedModel model, BlockAndTintGetter level, BlockPos pos, - BlockState state, Direction side, RandomSource rand) { - return model.getQuads(state, side, rand, model.getModelData(level, pos, state, ModelData.EMPTY), null); + @ApiStatus.Internal + public static Collection getModelUsedCTMTextures(ResourceLocation modelLocation) { + return SCRAPED_TEXTURES.get(modelLocation); } public static void registerAtlasStitchedEventListener(boolean removeOnReload, @@ -94,7 +82,7 @@ public static void registerReloadListener(RegisterClientReloadListenersEvent eve event.registerReloadListener(new ResourceManagerReloadListener() { @Override - public void onResourceManagerReload(@NotNull ResourceManager resourceManager) { + public void onResourceManagerReload(ResourceManager resourceManager) { EVENT_LISTENERS.removeIf(EventListenerHolder::removeOnReload); } }); @@ -103,7 +91,8 @@ public void onResourceManagerReload(@NotNull ResourceManager resourceManager) { @SuppressWarnings({ "unchecked", "deprecation" }) @SubscribeEvent(priority = EventPriority.LOWEST) public static void onAtlasStitched(TextureStitchEvent.Post event) { - if (event.getAtlas().location().equals(TextureAtlas.LOCATION_BLOCKS)) { + TextureAtlas atlas = event.getAtlas(); + if (atlas.location().equals(TextureAtlas.LOCATION_BLOCKS)) { // Cache all textures' CTM metadata // TODO lazy CTM_SPRITE_CACHE.clear(); @@ -115,10 +104,7 @@ public static void onAtlasStitched(TextureStitchEvent.Post event) { CTM_SPRITE_CACHE.put(location, ctmSprite); } } - } - TextureAtlas atlas = event.getAtlas(); - if (atlas.location() == TextureAtlas.LOCATION_BLOCKS) { MachineModel.initSprites(atlas); ICoverableRenderer.initSprites(atlas); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java b/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java index 67341b88e87..452b46b9540 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java @@ -22,7 +22,7 @@ public SpriteFunctionWrapper(Function internal, Re @Override public TextureAtlasSprite apply(Material material) { - ModelEventHelper.textureScraped(modelLocation, material); + ModelEventHelper.markTextureUsedForModel(this.modelLocation, material); return internal.apply(material); } } diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java index c2587e92896..6cf2c33db95 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java @@ -16,14 +16,16 @@ @Mixin(targets = {"net.minecraft.client.resources.model.ModelBakery$ModelBakerImpl"}) public abstract class ModelBakerImplMixin { + // the parameters aren't remapped because Parchment can't remap Forge's patches + @SuppressWarnings("NameDoesntMatchTargetClass") // Note: We don't remap this method as it's added by forge @ModifyVariable(at = @At("HEAD"), method = "bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;", argsOnly = true, remap = false) - private Function ldlib$scrapeTextures(Function sprites, - ResourceLocation modelLocation, - ModelState modelState) { - return new SpriteFunctionWrapper(sprites, modelLocation); + private Function gtceu$injectTextureScraper(Function spriteGetter, + ResourceLocation modelLocation, + ModelState transform) { + return new SpriteFunctionWrapper(spriteGetter, modelLocation); } } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/ResourceUtil.java b/src/main/java/com/gregtechceu/gtceu/utils/ResourceUtil.java new file mode 100644 index 00000000000..f8bb663cdae --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/ResourceUtil.java @@ -0,0 +1,81 @@ +package com.gregtechceu.gtceu.utils; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; + +import com.google.gson.JsonParseException; +import lombok.experimental.UtilityClass; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.HashMap; +import java.util.Optional; + +@UtilityClass +public class ResourceUtil { + + public static Resource getResource(TextureAtlasSprite sprite) throws IOException { + return getResource(spriteToAbsolute(sprite.contents().name())); + } + + public static ResourceLocation spriteToAbsolute(ResourceLocation sprite) { + if (!sprite.getPath().startsWith("textures/")) { + sprite = sprite.withPrefix("textures/"); + } + if (!sprite.getPath().endsWith(".png")) { + sprite = sprite.withSuffix(".png"); + } + return sprite; + } + + public static Resource getResource(ResourceLocation res) throws FileNotFoundException { + return Minecraft.getInstance().getResourceManager().getResourceOrThrow(res); + } + + public static Resource getResourceUnsafe(ResourceLocation res) { + try { + return getResource(res); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static final Map metadataCache = new HashMap<>(); + private static final IMetadataSectionCTM.Serializer SERIALIZER = new IMetadataSectionCTM.Serializer(); + + public static Optional getMetadata(ResourceLocation res) throws IOException { + // Note, semantically different from computeIfAbsent, as we DO care about keys mapped to null values + if (metadataCache.containsKey(res)) { + return Optional.ofNullable(metadataCache.get(res)); + } + Optional ret; + try { + Resource resource = getResource(res); + ret = resource.metadata().getSection(SERIALIZER); + } catch (FileNotFoundException e) { + ret = Optional.empty(); + } catch (JsonParseException e) { + throw new IOException("Error loading metadata for location " + res, e); + } + ret.ifPresentOrElse(r -> metadataCache.put(res, r), () -> metadataCache.put(res, null)); + return ret; + } + + public static Optional getMetadata(TextureAtlasSprite sprite) throws IOException { + return getMetadata(spriteToAbsolute(sprite.contents().name())); + } + + public static Optional getMetadataUnsafe(TextureAtlasSprite sprite) { + try { + return getMetadata(sprite); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static void invalidateCaches() { + metadataCache.clear(); + } +} \ No newline at end of file From 2bb52f8dbfda0398a31596f28504521fdf7c6383 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 16:56:47 +0300 Subject: [PATCH 10/66] Add copyright headers to all the classes I copied from CTM --- .../gtceu/client/model/ctm/CTMCache.java | 18 ++++++++++++++++++ .../client/model/ctm/ConnectionCheck.java | 18 ++++++++++++++++++ .../gtceu/client/model/ctm/ISubmap.java | 18 ++++++++++++++++++ .../client/model/ctm/OctagonalOrientation.java | 18 ++++++++++++++++++ .../gtceu/client/model/ctm/Submap.java | 18 ++++++++++++++++++ .../gtceu/client/model/package-info.java | 7 ++----- .../gtceu/client/util/package-info.java | 4 ++++ 7 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/package-info.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index 294a4cc8e1d..fd0733ae276 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -1,3 +1,21 @@ +/* + * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). + * Copyright (c) 2023 Chisel Team. + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * ConnectedTexturesMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with ConnectedTexturesMod; if not, If not, see . + */ + package com.gregtechceu.gtceu.client.model.ctm; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java index 489ebf6c1c0..a316143f23f 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java @@ -1,3 +1,21 @@ +/* + * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). + * Copyright (c) 2023 Chisel Team. + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * ConnectedTexturesMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with ConnectedTexturesMod; if not, If not, see . + */ + package com.gregtechceu.gtceu.client.model.ctm; import com.gregtechceu.gtceu.client.model.ctm.CTMCache.StateComparisonCallback; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java index 4e9716492a9..2bd1818daa9 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java @@ -1,3 +1,21 @@ +/* + * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). + * Copyright (c) 2023 Chisel Team. + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * ConnectedTexturesMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with ConnectedTexturesMod; if not, If not, see . + */ + package com.gregtechceu.gtceu.client.model.ctm; import net.minecraft.client.renderer.texture.TextureAtlasSprite; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java index 2aa94bf3f17..4b0a682568e 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java @@ -1,3 +1,21 @@ +/* + * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). + * Copyright (c) 2023 Chisel Team. + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * ConnectedTexturesMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with ConnectedTexturesMod; if not, If not, see . + */ + package com.gregtechceu.gtceu.client.model.ctm; import net.createmod.catnip.math.DirectionHelper; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java index bea4f7531d6..3253750ebf1 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java @@ -1,3 +1,21 @@ +/* + * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). + * Copyright (c) 2023 Chisel Team. + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * ConnectedTexturesMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with ConnectedTexturesMod; if not, If not, see . + */ + package com.gregtechceu.gtceu.client.model.ctm; import lombok.Getter; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/model/package-info.java index 756fd4d977e..9c694981ff8 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/package-info.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/package-info.java @@ -1,7 +1,4 @@ -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault +@NotNullByDefault package com.gregtechceu.gtceu.client.model; -import net.minecraft.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/util/package-info.java new file mode 100644 index 00000000000..1bc08b04b82 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.client.util; + +import org.jetbrains.annotations.NotNullByDefault; From 6fc6f1417e2b6ca66576668fb39089a6fc95e937 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:08:40 +0300 Subject: [PATCH 11/66] Add a simplified version of Fabric's dynamic model API --- .../gtceu/client/util/TextureHelper.java | 117 +++++ .../client/util/quad/EncodingFormat.java | 86 ++++ .../client/util/quad/GeometryHelper.java | 198 ++++++++ .../gtceu/client/util/quad/Mesh.java | 49 ++ .../gtceu/client/util/quad/MeshBuilder.java | 83 ++++ .../client/util/quad/MutableQuadView.java | 467 ++++++++++++++++++ .../gtceu/client/util/quad/QuadTransform.java | 20 + .../gtceu/client/util/quad/QuadView.java | 355 +++++++++++++ .../gtceu/client/util/quad/SpriteFinder.java | 177 +++++++ .../gtceu/client/util/quad/package-info.java | 4 + .../quad/transformers/QuadCornerKicker.java | 209 ++++++++ .../core/mixins/client/TextureAtlasMixin.java | 56 +++ src/main/resources/gtceu.mixins.json | 1 + 13 files changed, 1822 insertions(+) create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/EncodingFormat.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/Mesh.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/MeshBuilder.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/MutableQuadView.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadTransform.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadView.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/SpriteFinder.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/package-info.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java create mode 100644 src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java new file mode 100644 index 00000000000..1c893d6799f --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gregtechceu.gtceu.client.util; + +import com.gregtechceu.gtceu.client.util.quad.MutableQuadView; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; + +import lombok.experimental.UtilityClass; + +/** + * Handles most texture-baking use cases for model loaders and model libraries via + * {@link #bakeSprite(MutableQuadView, TextureAtlasSprite, int)}. + */ +@UtilityClass +public class TextureHelper { + + public static final float NORMALIZER = 1f / 16f; + + private static final int BAKE_ROTATE_ANY = 3; + + /** + * Bakes textures in the provided vertex data, handling UV locking, rotation, interpolation, etc. + * Textures must not be already baked. + */ + public static void bakeSprite(MutableQuadView quad, TextureAtlasSprite sprite, int bakeFlags) { + if (quad.nominalFace() != null && (MutableQuadView.BAKE_LOCK_UV & bakeFlags) != 0) { + // Assigns normalized UV coordinates based on vertex positions + applyModifier(quad, UV_LOCKERS[quad.nominalFace().get3DDataValue()]); + } else if ((MutableQuadView.BAKE_NORMALIZED & bakeFlags) == 0) { + // flag is NOT set, UVs are assumed to not be normalized yet as is the default, + // normalize through dividing by 16 + + // Scales from 0-16 to 0-1 + applyModifier(quad, (q, i) -> q.uv(i, q.u(i) * NORMALIZER, q.v(i) * NORMALIZER)); + } + + final int rotation = bakeFlags & BAKE_ROTATE_ANY; + + if (rotation != 0) { + // Rotates texture around the center of sprite. + // Assumes normalized coordinates. + applyModifier(quad, ROTATIONS[rotation]); + } + + if ((MutableQuadView.BAKE_FLIP_U & bakeFlags) != 0) { + // Inverts U coordinates. Assumes normalized (0-1) values. + applyModifier(quad, (q, i) -> q.uv(i, 1 - q.u(i), q.v(i))); + } + + if ((MutableQuadView.BAKE_FLIP_V & bakeFlags) != 0) { + // Inverts V coordinates. Assumes normalized (0-1) values. + applyModifier(quad, (q, i) -> q.uv(i, q.u(i), 1 - q.v(i))); + } + + interpolate(quad, sprite); + } + + /** + * Faster than sprite method. Sprite computes span and normalizes inputs each call, so we'd have to denormalize + * before we called, only to have the sprite renormalize immediately. + */ + private static void interpolate(MutableQuadView q, TextureAtlasSprite sprite) { + final float uMin = sprite.getU0(); + final float uSpan = sprite.getU1() - uMin; + final float vMin = sprite.getV0(); + final float vSpan = sprite.getV1() - vMin; + + for (int i = 0; i < 4; i++) { + q.uv(i, uMin + q.u(i) * uSpan, vMin + q.v(i) * vSpan); + } + } + + @FunctionalInterface + private interface VertexModifier { + void apply(MutableQuadView quad, int vertexIndex); + } + + private static void applyModifier(MutableQuadView quad, VertexModifier modifier) { + for (int i = 0; i < 4; i++) { + modifier.apply(quad, i); + } + } + + private static final VertexModifier[] ROTATIONS = new VertexModifier[] { + (q, i) -> {}, // 0 + (q, i) -> q.uv(i, q.v(i), 1 - q.u(i)), // 90 + (q, i) -> q.uv(i, 1 - q.u(i), 1 - q.v(i)), // 180 + (q, i) -> q.uv(i, 1 - q.v(i), q.u(i)) // 270 + }; + + private static final VertexModifier[] UV_LOCKERS = new VertexModifier[6]; + + static { + UV_LOCKERS[Direction.EAST.get3DDataValue()] = (q, i) -> q.uv(i, 1 - q.z(i), 1 - q.y(i)); + UV_LOCKERS[Direction.WEST.get3DDataValue()] = (q, i) -> q.uv(i, q.z(i), 1 - q.y(i)); + UV_LOCKERS[Direction.NORTH.get3DDataValue()] = (q, i) -> q.uv(i, 1 - q.x(i), 1 - q.y(i)); + UV_LOCKERS[Direction.SOUTH.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), 1 - q.y(i)); + UV_LOCKERS[Direction.DOWN.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), 1 - q.z(i)); + UV_LOCKERS[Direction.UP.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), q.z(i)); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/EncodingFormat.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/EncodingFormat.java new file mode 100644 index 00000000000..18eaa10ef2c --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/EncodingFormat.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gregtechceu.gtceu.client.util.quad; + +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Nullable; + +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraftforge.client.model.IQuadTransformer; + +import java.util.Objects; + +/** + * Holds all the array offsets and bit-wise encoders/decoders for packing/unpacking quad data in an array of integers. + * All of this is implementation-specific - that's why it isn't a "helper" class. + */ +@SuppressWarnings("PointlessArithmeticExpression") +@UtilityClass +public class EncodingFormat { + + static final int VERTEX_X = IQuadTransformer.POSITION + 0; + static final int VERTEX_Y = IQuadTransformer.POSITION + 1; + static final int VERTEX_Z = IQuadTransformer.POSITION + 2; + static final int VERTEX_COLOR = IQuadTransformer.COLOR; + static final int VERTEX_U = IQuadTransformer.UV0 + 0; + static final int VERTEX_V = IQuadTransformer.UV0 + 1; + static final int VERTEX_LIGHTMAP = IQuadTransformer.UV2; + static final int VERTEX_NORMAL = IQuadTransformer.NORMAL; + public static final int VERTEX_STRIDE = IQuadTransformer.STRIDE; + + public static final int QUAD_STRIDE = VERTEX_STRIDE * 4; + + /** used for quick clearing of quad buffers. */ + static final int[] EMPTY = new int[QUAD_STRIDE]; + + private static final int DIRECTION_MASK = Mth.smallestEncompassingPowerOfTwo(GeometryHelper.NULL_FACE_ID) - 1; + private static final int DIRECTION_BIT_COUNT = Integer.bitCount(DIRECTION_MASK); + private static final int CULL_SHIFT = 0; + private static final int CULL_INVERSE_MASK = ~(DIRECTION_MASK << CULL_SHIFT); + private static final int LIGHT_SHIFT = CULL_SHIFT + DIRECTION_BIT_COUNT; + private static final int LIGHT_INVERSE_MASK = ~(DIRECTION_MASK << LIGHT_SHIFT); + private static final int NORMALS_SHIFT = LIGHT_SHIFT + DIRECTION_BIT_COUNT; + private static final int NORMALS_COUNT = 4; + private static final int NORMALS_MASK = (1 << NORMALS_COUNT) - 1; + private static final int NORMALS_INVERSE_MASK = ~(NORMALS_MASK << NORMALS_SHIFT); + + static @Nullable Direction cullFace(long bits) { + return GeometryHelper.faceFromIndex((int) ((bits >> CULL_SHIFT) & DIRECTION_MASK)); + } + + static long cullFace(long bits, @Nullable Direction face) { + return (bits & CULL_INVERSE_MASK) | (GeometryHelper.toFaceIndex(face) << CULL_SHIFT); + } + + static Direction lightFace(long bits) { + return Objects.requireNonNull(GeometryHelper.faceFromIndex((int) ((bits >> LIGHT_SHIFT) & DIRECTION_MASK))); + } + + static long lightFace(long bits, Direction face) { + return (bits & LIGHT_INVERSE_MASK) | ((long) GeometryHelper.toFaceIndex(face) << LIGHT_SHIFT); + } + + /** indicate if vertex normal has been set - bits correspond to vertex ordinals. */ + static int normalFlags(long bits) { + return (int) ((bits >> NORMALS_SHIFT) & NORMALS_MASK); + } + + static long normalFlags(long bits, int normalFlags) { + return (bits & NORMALS_INVERSE_MASK) | ((long) (normalFlags & NORMALS_MASK) << NORMALS_SHIFT); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java new file mode 100644 index 00000000000..58cf95bfa34 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gregtechceu.gtceu.client.util.quad; + +import com.gregtechceu.gtceu.utils.GTUtil; + +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; + +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Vec3i; +import net.minecraft.util.Mth; + +/** + * Static routines of general utility for renderer implementations. + * Renderers are not required to use these helpers, but they were designed to be usable without the default renderer. + */ +@UtilityClass +public class GeometryHelper { + + /** Result from {@link #toFaceIndex(Direction)} for null values. */ + public static final int NULL_FACE_ID = 6; + + /** + * Convenient way to encode faces that may be null. Null is returned as {@link #NULL_FACE_ID}. + * Use {@link #faceFromIndex(int)} to retrieve encoded face. + */ + public static int toFaceIndex(@Nullable Direction face) { + return face == null ? NULL_FACE_ID : face.get3DDataValue(); + } + + /** + * Use to decode a result from {@link #toFaceIndex(Direction)}. Return value will be null if encoded value was null. + */ + @Contract("null -> null") + public static @Nullable Direction faceFromIndex(int faceIndex) { + return GTUtil.DIRECTIONS_WITH_NULL[faceIndex]; + } + + /** + * Identifies the face to which the quad is most closely aligned. This mimics the value that + * {@link BakedQuad#getDirection()} returns, and is used in the vanilla renderer for all diffuse lighting. + * + *

+ * Derived from the quad face normal and expects convex quads with all points co-planar. + */ + public static Direction lightFace(QuadView quad) { + final Vector3f normal = quad.faceNormal(); + return switch (GeometryHelper.longestAxis(normal)) { + case X -> normal.x() > 0 ? Direction.EAST : Direction.WEST; + case Y -> normal.y() > 0 ? Direction.UP : Direction.DOWN; + case Z -> normal.z() > 0 ? Direction.SOUTH : Direction.NORTH; + }; + } + + /** + * @see #longestAxis(float, float, float) + */ + public static Axis longestAxis(Vector3f vec) { + return longestAxis(vec.x(), vec.y(), vec.z()); + } + + /** + * Identifies the largest (max absolute magnitude) component (X, Y, Z) in the given vector. + */ + public static Axis longestAxis(float normalX, float normalY, float normalZ) { + Axis result = Axis.Y; + float longest = Math.abs(normalY); + float a = Math.abs(normalX); + + if (a > longest) { + result = Axis.X; + longest = a; + } + + return Math.abs(normalZ) > longest ? Axis.Z : result; + } + + /** + * Stores a normal plus an extra value as a quartet of signed bytes. This is the same normal format that vanilla + * item rendering expects. The extra value is for use by shaders. + */ + public static int packNormal(float x, float y, float z, float w) { + x = Mth.clamp(x, -1, 1); + y = Mth.clamp(y, -1, 1); + z = Mth.clamp(z, -1, 1); + w = Mth.clamp(w, -1, 1); + + return ((int) (x * 127) & 255) + | (((int) (y * 127) & 255) << 8) + | (((int) (z * 127) & 255) << 16) + | (((int) (w * 127) & 255) << 24); + } + + /** + * Version of {@link #packNormal(float, float, float, float)} that accepts a vector type. + */ + public static int packNormal(Vector3f normal, float w) { + return packNormal(normal.x(), normal.y(), normal.z(), w); + } + + /** + * Retrieves values packed by {@link #packNormal(float, float, float, float)}. + * + *

+ * Components are x, y, z, w - zero based. + */ + public static float getPackedNormalComponent(int packedNormal, int component) { + return ((byte) (packedNormal >> (8 * component))) / 127f; + } + + /** + * Computes the face normal of the given quad and saves it in the provided non-null vector. + * If {@link QuadView#nominalFace()} is set will optimize by confirming quad is parallel to that face and, + * if so, use the standard normal for that face direction. + * + *

+ * Will work with triangles also. Assumes counter-clockwise winding order, which is the norm. Expects convex quads + * with all points co-planar. + */ + public static void computeFaceNormal(Vector3f saveTo, QuadView q) { + final Direction nominalFace = q.nominalFace(); + + if (isQuadParallelToFace(nominalFace, q)) { + Vec3i vec = nominalFace.getNormal(); + saveTo.set(vec.getX(), vec.getY(), vec.getZ()); + return; + } + + final float x0 = q.x(0); + final float y0 = q.y(0); + final float z0 = q.z(0); + final float x1 = q.x(1); + final float y1 = q.y(1); + final float z1 = q.z(1); + final float x2 = q.x(2); + final float y2 = q.y(2); + final float z2 = q.z(2); + final float x3 = q.x(3); + final float y3 = q.y(3); + final float z3 = q.z(3); + + final float dx0 = x2 - x0; + final float dy0 = y2 - y0; + final float dz0 = z2 - z0; + final float dx1 = x3 - x1; + final float dy1 = y3 - y1; + final float dz1 = z3 - z1; + + float normX = dy0 * dz1 - dz0 * dy1; + float normY = dz0 * dx1 - dx0 * dz1; + float normZ = dx0 * dy1 - dy0 * dx1; + + float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ); + + if (l != 0) { + normX /= l; + normY /= l; + normZ /= l; + } + + saveTo.set(normX, normY, normZ); + } + + /** + * Returns true if quad is parallel to the given face. Does not validate quad winding order. Expects convex quads + * with all points co-planar. + */ + public static boolean isQuadParallelToFace(@Nullable Direction face, QuadView quad) { + if (face == null) { + return false; + } + + int i = face.getAxis().ordinal(); + final float val = quad.posByIndex(0, i); + return Mth.equal(val, quad.posByIndex(1, i)) + && Mth.equal(val, quad.posByIndex(2, i)) + && Mth.equal(val, quad.posByIndex(3, i)); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/Mesh.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/Mesh.java new file mode 100644 index 00000000000..a9a6f5ca2de --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/Mesh.java @@ -0,0 +1,49 @@ +package com.gregtechceu.gtceu.client.util.quad; + +import java.util.function.Consumer; + +/** + * A bundle of one or more {@link QuadView} instances encoded by the renderer. + * + *

+ * Similar in purpose to the {@code List} instances returned by BakedModel, but affords the renderer the + * ability to optimize the format for performance and memory allocation. + * + *

+ * Only the renderer should implement or extend this interface. + * + * @implNote The way we encode meshes makes it very simple. + */ +public class Mesh { + /** Used to satisfy external calls to {@link #forEach(Consumer)}. */ + ThreadLocal POOL = ThreadLocal.withInitial(QuadView::new); + + final int[] data; + + Mesh(int[] data) { + this.data = data; + } + + public int[] data() { + return data; + } + + public void forEach(Consumer consumer) { + forEach(consumer, POOL.get()); + } + + /** + * The renderer will call this with its own cursor to avoid the performance hit of a thread-local lookup. Also + * means renderer can hold final references to quad buffers. + */ + void forEach(Consumer consumer, QuadView cursor) { + final int limit = data.length; + int index = 0; + + while (index < limit) { + cursor.load(data, index); + consumer.accept(cursor); + index += EncodingFormat.QUAD_STRIDE; + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/MeshBuilder.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/MeshBuilder.java new file mode 100644 index 00000000000..4d7384acb01 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/MeshBuilder.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gregtechceu.gtceu.client.util.quad; + + +/** + * Similar in purpose to {@link com.mojang.blaze3d.vertex.BufferBuilder} but simpler and not tied to NIO + * or any other specific implementation, plus designed to handle both static and dynamic building. + * + *

+ * Decouples models from the vertex format(s) used by ModelRenderer to allow compatibility across diverse + * implementations. + * + * @implNote Not much to it - mainly it just needs to grow the int[] array as quads are appended and + * maintain/provide a properly-configured {@link MutableQuadView} instance. + * All the encoding and other work is handled in the quad base classes. + * The one interesting bit is in {@link Maker#emit()}. + */ +public class MeshBuilder { + + private int[] data = new int[256]; + private final Maker maker = new Maker(); + private int index = 0; + private int limit = data.length; + + public static MeshBuilder getInstance() { + return new MeshBuilder(); + } + + protected void ensureCapacity() { + if (EncodingFormat.QUAD_STRIDE > limit - index) { + limit *= 2; + final int[] bigger = new int[limit]; + System.arraycopy(data, 0, bigger, 0, index); + data = bigger; + maker.data = bigger; + } + } + + public Mesh build() { + final int[] packed = new int[index]; + System.arraycopy(data, 0, packed, 0, index); + index = 0; + maker.begin(data, index); + return new Mesh(packed); + } + + public MutableQuadView getEmitter() { + ensureCapacity(); + maker.begin(data, index); + return maker; + } + + /** + * Our base classes are used differently so we define final encoding steps in subtypes. This will be a static mesh + * used at render time so we want to capture all geometry now and apply non-location-dependent lighting. + */ + private class Maker extends MutableQuadView { + @Override + public Maker emit() { + computeGeometry(); + index += EncodingFormat.QUAD_STRIDE; + ensureCapacity(); + baseIndex = index; + clear(); + return this; + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/MutableQuadView.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/MutableQuadView.java new file mode 100644 index 00000000000..1b6fd9c2b4a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/MutableQuadView.java @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gregtechceu.gtceu.client.util.quad; + +import com.gregtechceu.gtceu.client.util.TextureHelper; + +import org.jetbrains.annotations.Nullable; +import org.joml.Vector2f; +import org.joml.Vector3f; + +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraftforge.client.model.QuadTransformers; + +import static com.gregtechceu.gtceu.client.util.quad.EncodingFormat.*; +/** + * A mutable {@link QuadView} instance. + * + *

+ * Instances of {@link MutableQuadView} will practically always be thread local and/or reused - do not retain references. + * + *

+ * Only the renderer should implement or extend this interface. + * + * @implNote Almost-concrete implementation of a mutable quad. + */ +public abstract class MutableQuadView extends QuadView { + + /** + * Causes texture to appear with no rotation. + * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_ROTATE_NONE = 0b000000; + + /** + * Causes texture to appear rotated 90 deg. clockwise relative to nominal face. Pass in bakeFlags parameter to + * {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_ROTATE_90 = 0b000001; + + /** + * Causes texture to appear rotated 180 deg. relative to nominal face. Pass in bakeFlags parameter to + * {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_ROTATE_180 = 0b000010; + + /** + * Causes texture to appear rotated 270 deg. clockwise relative to nominal face. Pass in bakeFlags parameter to + * {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_ROTATE_270 = 0b000011; + + /** + * When enabled, texture coordinate are assigned based on vertex position. Any existing UV coordinates will be + * replaced. Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + * + *

+ * UV lock always derives texture coordinates based on nominal face, even when the quad is not co-planar with that + * face, and the result is the same as if the quad were projected onto the nominal face, which is usually the + * desired result. + */ + public static final int BAKE_LOCK_UV = 0b000100; + + /** + * When set, U texture coordinates for the given sprite are flipped as part of baking. Can be useful for some + * randomization and texture mapping scenarios. Results are different from what can be obtained via rotation and + * both can be applied. Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_FLIP_U = 0b001000; + + /** + * Same as {@link #BAKE_FLIP_U} but for V coordinate. + */ + public static final int BAKE_FLIP_V = 0b010000; + + /** + * UV coordinates by default are assumed to be 0-16 scale for consistency with conventional Minecraft model format. + * This is scaled to 0-1 during baking before interpolation. Model loaders that already have 0-1 coordinates can + * avoid wasteful multiplication/division by passing 0-1 coordinates directly. Pass in bakeFlags parameter to + * {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_NORMALIZED = 0b100000; + + public static MutableQuadView getInstance() { + return MutableQuadView.THREAD_LOCAL.get(); + } + + + public static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(() -> new MutableQuadView() { + { + begin(new int[QUAD_STRIDE], 0); + } + + @Override + public MutableQuadView emit() { + throw new UnsupportedOperationException(); + } + }); + + public final void begin(int[] data, int baseIndex) { + this.data = data; + this.baseIndex = baseIndex; + clear(); + } + + @Override + protected void computeGeometry() { + this.populateMissingNormals(); + super.computeGeometry(); + } + + public void clear() { + System.arraycopy(EMPTY, 0, data, baseIndex, QUAD_STRIDE); + isGeometryInvalid = true; + nominalFace = null; + tintIndex(-1); + cullFace(null); + } + + /** + * Sets the geometric vertex position for the given vertex, relative to block origin, (0,0,0). Minecraft rendering + * is designed for models that fit within a single block space and is recommended that coordinates remain in the 0-1 + * range, with multi-block meshes split into multiple per-block models. + */ + public MutableQuadView pos(int vertexIndex, float x, float y, float z) { + final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X; + data[index] = Float.floatToRawIntBits(x); + data[index + 1] = Float.floatToRawIntBits(y); + data[index + 2] = Float.floatToRawIntBits(z); + isGeometryInvalid = true; + return this; + } + + /** + * Same as {@link #pos(int, float, float, float)} but accepts a vector type. + */ + public MutableQuadView pos(int vertexIndex, Vector3f pos) { + return pos(vertexIndex, pos.x(), pos.y(), pos.z()); + } + + /** + * Set vertex color. + */ + public MutableQuadView color(int vertexIndex, int color) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR] = color; + return this; + } + + /** + * Convenience: set vertex color for all vertices at once. + */ + public MutableQuadView color(int c0, int c1, int c2, int c3) { + color(0, c0); + color(1, c1); + color(2, c2); + color(3, c3); + return this; + } + + /** + * Set texture coordinates. + */ + public MutableQuadView uv(int vertexIndex, float u, float v) { + final int i = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U; + data[i] = Float.floatToRawIntBits(u); + data[i + 1] = Float.floatToRawIntBits(v); + return this; + } + + /** + * Set texture coordinates. + * + *

+ * Only use this function if you already have a {@link Vector2f}. + * Otherwise, see {@link MutableQuadView#uv(int, float, float)}. + * + * @see MutableQuadView#uv(int, float, float) + */ + public MutableQuadView uv(int vertexIndex, Vector2f uv) { + return uv(vertexIndex, uv.x, uv.y); + } + + /** + * Assigns sprite atlas u,v coordinates to this quad for the given sprite. + * Can handle UV locking, rotation, interpolation, etc. + * Control this behavior by passing additive combinations of the BAKE_ flags defined in this interface. + */ + public MutableQuadView spriteBake(TextureAtlasSprite sprite, int bakeFlags) { + TextureHelper.bakeSprite(this, sprite, bakeFlags); + return this; + } + + /** + * Accept vanilla lightmap values. + * Input values will override lightmap values computed from world state if input values are higher. + */ + public MutableQuadView lightmap(int vertexIndex, int lightmap) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP] = lightmap; + return this; + } + + /** + * Convenience: set lightmap for all vertices at once. + * + * @see #lightmap(int, int) + */ + public MutableQuadView lightmap(int b0, int b1, int b2, int b3) { + lightmap(0, b0); + lightmap(1, b1); + lightmap(2, b2); + lightmap(3, b3); + return this; + } + + protected void normalFlags(int flags) { + this.flags = EncodingFormat.normalFlags(this.flags, flags); + } + + /** + * Adds a vertex normal. + * Models that have per-vertex normals should include them to get correct lighting when it matters. + * Computed face normal is used when no vertex normal is provided. + */ + public MutableQuadView normal(int vertexIndex, float x, float y, float z) { + normalFlags(normalFlags() | (1 << vertexIndex)); + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL] = GeometryHelper.packNormal(x, y, z, 0); + return this; + } + + /** + * Same as {@link #normal(int, float, float, float)} but accepts a vector type. + */ + public MutableQuadView normal(int vertexIndex, Vector3f normal) { + return normal(vertexIndex, normal.x(), normal.y(), normal.z()); + } + + /** + * Internal helper method. Copies face normals to vertex normals lacking one. + */ + public final void populateMissingNormals() { + final int normalFlags = this.normalFlags(); + if (normalFlags == 0b1111) + return; + + final int packedFaceNormal = GeometryHelper.packNormal(faceNormal(), 0); + + for (int v = 0; v < 4; v++) { + if ((normalFlags & (1 << v)) == 0) { + data[baseIndex + v * VERTEX_STRIDE + VERTEX_NORMAL] = packedFaceNormal; + } + } + + normalFlags(0b1111); + } + + /** + * If non-null, quad is coplanar with a block face which, if known, simplifies or shortcuts geometric analysis + * that might otherwise be needed. Set to null if quad is not coplanar or if this is not known. + * Also controls face culling during block rendering. + * + *

+ * Null by default. + * + *

+ * When called with a non-null value, also sets {@link #nominalFace(Direction)} to the same value. + * + *

+ * This is different from the value reported by {@link BakedQuad#getDirection()}. That value is computed based on + * face geometry and must be non-null in vanilla quads. That computed value is returned by {@link #lightFace()}. + */ + public final MutableQuadView cullFace(@Nullable Direction face) { + flags = EncodingFormat.cullFace(flags, face); + nominalFace(face); + return this; + } + + /** + * Provides a hint to renderer about the facing of this quad. + * Not required, but if provided can shortcut some geometric analysis if the quad is parallel to a block face. + * Should be the expected value of {@link #lightFace()}. + * Value will be confirmed and if invalid the correct light face will be calculated. + * + *

+ * Null by default, and set automatically by {@link #cullFace()}. + * + *

+ * Models may also find this useful as the face for texture UV locking and rotation semantics. + * + *

+ * Note: This value is not persisted independently when the quad is encoded. + * When reading encoded quads, this value will always be the same as {@link #lightFace()}. + */ + public final MutableQuadView nominalFace(@Nullable Direction face) { + this.nominalFace = face; + return this; + } + + /** + * Value functions identically to {@link BakedQuad#getTintIndex()} + * and is used by renderer / model builder in same way.
+ * Default value is -1. + */ + public final MutableQuadView tintIndex(int tintIndex) { + this.tintIndex = tintIndex; + return this; + } + + /** + * Value functions identically to {@link BakedQuad#isShade()} + * and is used by renderer / model builder in the same way.
+ * Default value is true. + */ + public final MutableQuadView shade(boolean shade) { + this.shade = shade; + return this; + } + + /** + * Value functions identically to {@link BakedQuad#hasAmbientOcclusion()} + * and is used by renderer / model builder in the same way.
+ * Default value is true. + */ + public final MutableQuadView ambientOcclusion(boolean ao) { + this.ambientOcclusion = ao; + return this; + } + + /** + * Enables bulk vertex data transfer using the standard Minecraft vertex formats. Only the + * {@link BakedQuad#getVertices() quad vertex data} is copied. This method should be performant whenever caller's + * vertex representation makes it feasible. + * + *

+ * Use {@link #fromVanilla(BakedQuad, Direction) the other overload} which has better encapsulation + * unless you have a specific reason to use this one. + * + *

+ * Calling this method does not emit the quad. + */ + public final MutableQuadView fromVanilla(int[] quadData, int startIndex) { + clear(); + System.arraycopy(quadData, startIndex, this.data, this.baseIndex, QUAD_STRIDE); + this.isGeometryInvalid = true; + + int colorIndex = baseIndex + VERTEX_COLOR; + + for (int i = 0; i < 4; i++) { + // ARGB -> ABGR is a transitive process, e.g. it can be reversed and works fine. + this.data[colorIndex] = QuadTransformers.toABGR(this.data[colorIndex]); + colorIndex += VERTEX_STRIDE; + } + + return this; + } + + /** + * Enables bulk vertex data transfer using the standard Minecraft quad format. + * + *

+ * Calling this method does not emit the quad. + */ + public final MutableQuadView fromVanilla(BakedQuad quad, @Nullable Direction cullFace) { + fromVanilla(quad.getVertices(), 0); + flags = EncodingFormat.cullFace(0, cullFace); + + nominalFace(quad.getDirection()); + tintIndex(quad.getTintIndex()); + shade(quad.isShade()); + ambientOcclusion(quad.hasAmbientOcclusion()); + + return this; + } + + /** + * In static mesh building, causes quad to be appended to the mesh being built. In a dynamic render context, create + * a new quad to be output to rendering. In both cases, current instance is reset to default values. + */ + public abstract MutableQuadView emit(); + + + /** + * Tolerance for determining if the depth parameter to {@link #square(Direction, float, float, float, float, float)} + * is effectively zero - meaning the face is a cull face. + */ + private static final float CULL_FACE_EPSILON = Mth.EPSILON; + + /** + * Helper method to assign vertex coordinates for a square aligned with the given face. Ensures that vertex order is + * consistent with vanilla convention. (Incorrect order can lead to bad AO lighting unless enhanced lighting logic + * is available/enabled.) + * + *

+ * Square will be parallel to the given face and coplanar with the face (and culled if the face is occluded) if the + * depth parameter is approximately zero. See {@link #CULL_FACE_EPSILON}. + * + *

+ * All coordinates should be normalized (0-1). + */ + public MutableQuadView square(Direction nominalFace, float left, float bottom, float right, float top, float depth) { + if (Math.abs(depth) < CULL_FACE_EPSILON) { + cullFace(nominalFace); + depth = 0; // avoid any inconsistency for face quads + } else { + cullFace(null); + } + + nominalFace(nominalFace); + switch (nominalFace) { + case UP: + depth = 1 - depth; + top = 1 - top; + bottom = 1 - bottom; + // Fallthrough + + case DOWN: + pos(0, left, depth, top); + pos(1, left, depth, bottom); + pos(2, right, depth, bottom); + pos(3, right, depth, top); + break; + + case EAST: + depth = 1 - depth; + left = 1 - left; + right = 1 - right; + // Fallthrough + + case WEST: + pos(0, depth, top, left); + pos(1, depth, bottom, left); + pos(2, depth, bottom, right); + pos(3, depth, top, right); + break; + + case SOUTH: + depth = 1 - depth; + left = 1 - left; + right = 1 - right; + // Fallthrough + + case NORTH: + pos(0, 1 - left, top, depth); + pos(1, 1 - left, bottom, depth); + pos(2, 1 - right, bottom, depth); + pos(3, 1 - right, top, depth); + break; + } + + return this; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadTransform.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadTransform.java new file mode 100644 index 00000000000..de76ed61ea6 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadTransform.java @@ -0,0 +1,20 @@ +package com.gregtechceu.gtceu.client.util.quad; + +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraftforge.client.model.IQuadTransformer; + +@FunctionalInterface +public interface QuadTransform extends IQuadTransformer { + /** + * Return false to filter out quads from rendering. When more than one transform is in effect, returning false + * means unapplied transforms will not receive the quad. + */ + boolean transform(MutableQuadView quad); + + @Override + default void processInPlace(BakedQuad quad) { + MutableQuadView quadView = MutableQuadView.getInstance().fromVanilla(quad.getVertices(), 0); + this.transform(quadView); + quadView.toVanilla(quad.getVertices(), 0); + } +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadView.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadView.java new file mode 100644 index 00000000000..9bbe29be364 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadView.java @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gregtechceu.gtceu.client.util.quad; + +import lombok.Getter; +import lombok.experimental.Accessors; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; +import org.joml.Vector2f; +import org.joml.Vector3f; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; +import net.minecraftforge.client.model.QuadTransformers; + +import static com.gregtechceu.gtceu.client.util.quad.EncodingFormat.*; + +/** + * Interface for reading quad data encoded by {@link MeshBuilder}. + * Enables models to do analysis, re-texturing or translation + * without knowing the renderer's vertex formats and without retaining redundant information. + * + * @implNote Base class for all quads / quad makers. Handles the ugly bits of maintaining and encoding the quad state. + */ +@Accessors(fluent = true, chain = true) +public class QuadView { + /** + * See {@link MutableQuadView#nominalFace(Direction)}. + */ + @Getter + protected @Nullable Direction nominalFace; + /** True when geometry flags or light face may not match geometry. */ + protected boolean isGeometryInvalid = true; + protected final Vector3f faceNormal = new Vector3f(); + /** + * Equivalent to {@link BakedQuad#isShade()}. If false, quad should not have shadows cast on it. + * + * @see MutableQuadView#shade(boolean) + */ + @Getter + protected boolean shade = true; + /** + * Equivalent to {@link BakedQuad#hasAmbientOcclusion()}. If false, quad should not have AO. + * + * @see MutableQuadView#ambientOcclusion(boolean) + */ + @Getter + protected boolean ambientOcclusion = true; + /** + * The quad color index serialized with the quad. + */ + @Getter + protected int tintIndex; + + protected long flags = 0; + /** Size and where it comes from will vary in subtypes. But in all cases quad is fully encoded to array. */ + protected int @UnknownNullability [] data; + + /** Beginning of the quad. Also the header index. */ + protected int baseIndex = 0; + + /** + * Use when subtype is "attached" to a pre-existing array. Sets data reference and index and decodes state from + * array. + */ + final void load(int[] data, int baseIndex) { + this.data = data; + this.baseIndex = baseIndex; + load(); + } + + /** + * Like {@link #load(int[], int)} but assumes array and index already set. Only does the decoding part. + */ + public final void load() { + isGeometryInvalid = false; + nominalFace = lightFace(); + + // face normal isn't encoded + GeometryHelper.computeFaceNormal(faceNormal, this); + } + + /** Reference to underlying array. Use with caution. Meant for fast renderer access */ + public int[] data() { + return data; + } + + public int normalFlags() { + return EncodingFormat.normalFlags(flags); + } + + /** True if any vertex normal has been set. */ + public boolean hasVertexNormals() { + return normalFlags() != 0; + } + + protected void computeGeometry() { + if (isGeometryInvalid) { + isGeometryInvalid = false; + + GeometryHelper.computeFaceNormal(faceNormal, this); + + // depends on face normal + flags = EncodingFormat.lightFace(flags, GeometryHelper.lightFace(this)); + } + } + + /** + * Equivalent to {@link BakedQuad#getDirection()}. This is the face used for vanilla lighting calculations and will + * be the block face to which the quad is most closely aligned. + * Always the same as cull face for quads that are on a block face, but never null. + */ + public final Direction lightFace() { + computeGeometry(); + return EncodingFormat.lightFace(flags); + } + + /** + * If non-null, quad should not be rendered in-world if the opposite face of a neighbor block occludes it. + * + * @see MutableQuadView#cullFace(Direction) + */ + public final @Nullable Direction cullFace() { + computeGeometry(); + return EncodingFormat.cullFace(flags); + } + + /** + * Normal of the quad as implied by geometry. Will be invalid if quad vertices are not co-planar. Typically computed + * lazily on demand and not encoded. + * + *

+ * Not typically needed by models. Exposed to enable standard lighting utility functions for use by renderers. + */ + public final Vector3f faceNormal() { + computeGeometry(); + return faceNormal; + } + + /** + * Extracts all quad properties except material to the given {@link MutableQuadView} instance. Must be used before + * calling {link QuadEmitter#emit()} on the target instance. Meant for re-texturing, analysis and static + * transformation use cases. + */ + public void copyTo(MutableQuadView quad) { + computeGeometry(); + + // copy everything except the material + System.arraycopy(data, baseIndex, quad.data, quad.baseIndex, QUAD_STRIDE); + quad.faceNormal.set(faceNormal.x(), faceNormal.y(), faceNormal.z()); + quad.nominalFace = this.nominalFace; + quad.isGeometryInvalid = false; + quad.shade(this.shade); + quad.flags = this.flags; + } + + /** + * Pass a non-null target to avoid allocation - will be returned with values. Otherwise returns a new instance. + */ + public Vector3f copyPos(int vertexIndex, @Nullable Vector3f target) { + if (target == null) { + target = new Vector3f(); + } + + final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X; + target.set(Float.intBitsToFloat(data[index]), Float.intBitsToFloat(data[index + 1]), + Float.intBitsToFloat(data[index + 2])); + return target; + } + + /** + * Pass a non-null target to avoid allocation - will be returned with values. Otherwise, returns a new instance. + * Returns null if normal not present. + */ + public @Nullable Vector3f copyNormal(int vertexIndex, @Nullable Vector3f target) { + if (hasNormal(vertexIndex)) { + if (target == null) { + target = new Vector3f(); + } + + final int normal = data[normalIndex(vertexIndex)]; + target.set(GeometryHelper.getPackedNormalComponent(normal, 0), + GeometryHelper.getPackedNormalComponent(normal, 1), + GeometryHelper.getPackedNormalComponent(normal, 2)); + return target; + } else { + return null; + } + } + + /** + * Pass a non-null target to avoid allocation - will be returned with values. Otherwise returns a new instance. + */ + public Vector2f copyUv(int vertexIndex, @Nullable Vector2f target) { + if (target == null) { + target = new Vector2f(); + } + + target.set(u(vertexIndex), v(vertexIndex)); + return target; + } + + /** + * Retrieve geometric position, x coordinate. + */ + public float x(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X]); + } + + + /** + * Retrieve geometric position, y coordinate. + */ + public float y(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Y]); + } + + /** + * Retrieve geometric position, z coordinate. + */ + public float z(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Z]); + } + + /** + * Retrieve vertex color. + */ + public int color(int vertexIndex) { + return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR]; + } + + /** + * Convenience: access x, y, z by index 0-2. + */ + public float posByIndex(int vertexIndex, int coordinateIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X + coordinateIndex]); + } + + /** + * If false, no vertex normal was provided. Lighting should use face normal in that case. + */ + public boolean hasNormal(int vertexIndex) { + return (normalFlags() & (1 << vertexIndex)) != 0; + } + + protected final int normalIndex(int vertexIndex) { + return baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL; + } + + /** + * Will return {@link Float#NaN} if normal not present. + */ + public float normalX(int vertexIndex) { + return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 0) + : Float.NaN; + } + + /** + * Will return {@link Float#NaN} if normal not present. + */ + public float normalY(int vertexIndex) { + return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 1) + : Float.NaN; + } + + /** + * Will return {@link Float#NaN} if normal not present. + */ + public float normalZ(int vertexIndex) { + return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 2) + : Float.NaN; + } + + /** + * Minimum block brightness. Zero if not set. + */ + public int lightmap(int vertexIndex) { + return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP]; + } + + /** + * Retrieve horizontal texture coordinates. + */ + public float u(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U]); + } + + /** + * Retrieve vertical texture coordinates. + */ + public float v(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_V]); + } + + /** + * Reads baked vertex data and outputs standard {@link BakedQuad#getVertices() baked quad vertex data} in the given + * array and location. + * + * @param target Target array for the baked quad data. + * + * @param targetIndex Starting position in target array - array must have at least 28 elements available at this + * index. + */ + public final void toVanilla(int[] target, int targetIndex) { + System.arraycopy(data, baseIndex, target, targetIndex, QUAD_STRIDE); + + // The color is the fourth integer in each vertex. + // EncodingFormat.VERTEX_COLOR is not used because it also + // contains the header size; vanilla quads do not have a header. + int colorIndex = targetIndex + 3; + + for (int i = 0; i < 4; i++) { + target[colorIndex] = QuadTransformers.toABGR(target[colorIndex]); + colorIndex += VERTEX_STRIDE; + } + } + + /** + * Generates a new BakedQuad instance with texture coordinates and colors from the given sprite. + * + * @param sprite {@link MutableQuadView} does not serialize sprites so the sprite must be provided by the caller. + * + * @return A new baked quad instance with the closest-available appearance supported by vanilla features. Will + * retain emissive light maps, for example, but the standard Minecraft renderer will not use them. + */ + public BakedQuad toBakedQuad(TextureAtlasSprite sprite) { + int[] vertexData = new int[QUAD_STRIDE]; + toVanilla(vertexData, 0); + return new BakedQuad(vertexData, tintIndex(), lightFace(), sprite, shade()); + } + + @SuppressWarnings("deprecation") + public BakedQuad toBlockBakedQuad() { + var finder = SpriteFinder.get(Minecraft.getInstance().getModelManager() + .getAtlas(TextureAtlas.LOCATION_BLOCKS)); + return toBakedQuad(finder.find(this)); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/SpriteFinder.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/SpriteFinder.java new file mode 100644 index 00000000000..6ed318dee77 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/SpriteFinder.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gregtechceu.gtceu.client.util.quad; + +import java.util.Map; +import java.util.function.Consumer; + +import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; + +import org.jetbrains.annotations.Nullable; + +/** + * Indexes a texture atlas to allow fast lookup of Sprites from baked vertex coordinates. + * Main use is for {@link Mesh}-based models to generate vanilla quads on demand + * without tracking and retaining the sprites that were baked into the mesh. + * In other words, this class supplies the sprite parameter for + * {@link QuadView#toBakedQuad(TextureAtlasSprite)}. + * + * @implNote Implementation is a straightforward quad tree. + * Other options that were considered were linear search (slow) and direct indexing of fixed-size cells. + * Direct indexing would be fastest but would be memory-intensive for large atlases + * and unsuitable for any atlas that isn't consistently aligned to a fixed cell size. + */ +public class SpriteFinder { + + /** + * Retrieves or creates the finder for the given atlas. Instances should not be retained as fields or they must be + * refreshed whenever there is a resource reload or other event that causes atlas textures to be re-stitched. + */ + public static SpriteFinder get(TextureAtlas atlas) { + return ((SpriteFinderAccess) atlas).gtceu$spriteFinder(); + } + + private final Node root; + private final TextureAtlas spriteAtlasTexture; + + public SpriteFinder(Map sprites, TextureAtlas spriteAtlasTexture) { + root = new Node(0.5f, 0.5f, 0.25f); + this.spriteAtlasTexture = spriteAtlasTexture; + sprites.values().forEach(root::add); + } + + /** + * Finds the atlas sprite containing the vertex centroid of the quad. Vertex centroid is essentially the mean u,v + * coordinate - the intent being to find a point that is unambiguously inside the sprite (vs on an edge.) + * + *

+ * Should be reliable for any convex quad or triangle. May fail for non-convex quads. Note that all the above refers + * to u,v coordinates. Geometric vertex does not matter, except to the extent it was used to determine u,v. + */ + public TextureAtlasSprite find(QuadView quad) { + float u = 0; + float v = 0; + + for (int i = 0; i < 4; i++) { + u += quad.u(i); + v += quad.v(i); + } + + return find(u * 0.25f, v * 0.25f); + } + + /** + * Alternative to {@link #find(QuadView)} when vertex centroid is already known or unsuitable. + * Expects normalized (0-1) coordinates on the atlas texture, which should already be the case for u,v values + * in vanilla baked quads and in {@link QuadView} after calling + * {@link MutableQuadView#spriteBake(TextureAtlasSprite, int)}. + * + *

+ * Coordinates must be in the sprite interior for reliable results. + * Generally it'll be easier to use {@link #find(QuadView)} unless you know + * the vertex centroid will somehow not be in the quad interior. + * This method will be slightly faster if you already have the centroid or another appropriate value. + */ + public TextureAtlasSprite find(float u, float v) { + return root.find(u, v); + } + + private class Node { + final float midU; + final float midV; + final float cellRadius; + @Nullable Object lowLow = null; + @Nullable Object lowHigh = null; + @Nullable Object highLow = null; + @Nullable Object highHigh = null; + + Node(float midU, float midV, float radius) { + this.midU = midU; + this.midV = midV; + cellRadius = radius; + } + + static final float EPS = Mth.EPSILON; + + void add(TextureAtlasSprite sprite) { + final boolean lowU = sprite.getU0() < midU - EPS; + final boolean highU = sprite.getU1() > midU + EPS; + final boolean lowV = sprite.getV0() < midV - EPS; + final boolean highV = sprite.getV1() > midV + EPS; + + if (lowU && lowV) { + addInner(sprite, lowLow, -1, -1, q -> lowLow = q); + } + + if (lowU && highV) { + addInner(sprite, lowHigh, -1, 1, q -> lowHigh = q); + } + + if (highU && lowV) { + addInner(sprite, highLow, 1, -1, q -> highLow = q); + } + + if (highU && highV) { + addInner(sprite, highHigh, 1, 1, q -> highHigh = q); + } + } + + private void addInner(TextureAtlasSprite sprite, @Nullable Object quadrant, int uStep, int vStep, + Consumer setter) { + if (quadrant == null) { + setter.accept(sprite); + } else if (quadrant instanceof Node node) { + node.add(sprite); + } else { + Node n = new Node(midU + cellRadius * uStep, midV + cellRadius * vStep, cellRadius * 0.5f); + + if (quadrant instanceof TextureAtlasSprite) { + n.add((TextureAtlasSprite) quadrant); + } + + n.add(sprite); + setter.accept(n); + } + } + + private TextureAtlasSprite find(float u, float v) { + if (u < midU) { + return v < midV ? findInner(lowLow, u, v) : findInner(lowHigh, u, v); + } else { + return v < midV ? findInner(highLow, u, v) : findInner(highHigh, u, v); + } + } + + private TextureAtlasSprite findInner(@Nullable Object quadrant, float u, float v) { + if (quadrant instanceof TextureAtlasSprite sprite) { + return sprite; + } else if (quadrant instanceof Node node) { + return node.find(u, v); + } else { + return spriteAtlasTexture.getSprite(MissingTextureAtlasSprite.getLocation()); + } + } + } + + public interface SpriteFinderAccess { + SpriteFinder gtceu$spriteFinder(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/package-info.java new file mode 100644 index 00000000000..f6a6ca48793 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.client.util.quad; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java new file mode 100644 index 00000000000..8d47b277774 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java @@ -0,0 +1,209 @@ +/* + * This file is part of CodeChickenLib. + * Copyright (c) 2018, covers1624, All rights reserved. + * + * CodeChickenLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * CodeChickenLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CodeChickenLib. If not, see . + */ +package com.gregtechceu.gtceu.client.util.quad.transformers; + +import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; +import com.gregtechceu.gtceu.client.util.quad.MutableQuadView; +import com.gregtechceu.gtceu.client.util.quad.QuadTransform; + +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.core.Vec3i; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.AABB; + +import org.jetbrains.annotations.Nullable; + +import static net.minecraft.core.Direction.AxisDirection.*; +import static net.minecraft.core.Direction.*; + +/** + * This transformer is a little complicated. + * Basically, a Facade / Cover can use this to 'kick' the edges of quads in to fix Z-fighting in the corners. + *

+ * Use it by specifying + *

    + *
  • the side of the block you are on,
  • + *
  • the bitmask for where the other Facades / Covers are,
  • + *
  • the bounding box of the facade (NOT the hole piece),
  • + *
  • and the thickness of your Facade / Cover (which is used as the kick amount).
  • + *
+ * + * @author covers1624 + */ +public class QuadCornerKicker implements QuadTransform { + + public static final QuadCornerKicker INSTANCE = new QuadCornerKicker(); + + // Simple horizonal lookups. + public static Direction[][] horizonals = new Direction[][] { + // Around Y axis, NSWE. + { NORTH, SOUTH, WEST, EAST }, + { NORTH, SOUTH, WEST, EAST }, + + // Around Z axis, DUWE. + { DOWN, UP, WEST, EAST }, + { DOWN, UP, WEST, EAST }, + + // Around X axis, DUNS. + { DOWN, UP, NORTH, SOUTH }, + { DOWN, UP, NORTH, SOUTH } }; + + private Direction mySide; + private int facadeMask; + private AABB bounds; + private double thickness; + + public QuadCornerKicker() { + super(); + } + + /** + * Set's the side this Facade / Cover is attached to. + * + * @param side The side. + */ + public void setSide(Direction side) { + this.mySide = side; + } + + /** + * Sets the bitmask of Facades / Covers in the block space. + * This is as simple as {@code mask = (1 << side)}. + * + * @param mask The mask. + */ + public void setFacadeMask(int mask) { + this.facadeMask = mask; + } + + /** + * Sets the bounding box of the Facade / Cover, this should be the full box, not just a piece of the hole's 'ring'. + * + * @param bounds The bounding box. + */ + public void setBounds(AABB bounds) { + this.bounds = bounds; + } + + /** + * Sets the amount to kick the vertex in by, this is your facades thickness. + * + * @param thickness The thickness. + */ + public void setThickness(double thickness) { + this.thickness = thickness; + } + + @Override + public boolean transform(MutableQuadView quad) { + Direction side = quad.nominalFace(); + if (side == this.mySide || side == this.mySide.getOpposite()) { + return true; + } + for (Direction hoz : horizonals[this.mySide.get3DDataValue()]) { + if (side == hoz || side == hoz.getOpposite() || (this.facadeMask & (1 << hoz.ordinal())) == 0) { + continue; + } + Corner corner = Corner.fromSides(this.mySide.getOpposite(), side, hoz); + for (int i = 0; i < 4; i++) { + float x = quad.posByIndex(i, 0); + float y = quad.posByIndex(i, 1); + float z = quad.posByIndex(i, 2); + if (Mth.equal(x, corner.pX(this.bounds)) + && Mth.equal(y, corner.pY(this.bounds)) + && Mth.equal(z, corner.pZ(this.bounds))) { + Vec3i normal = hoz.getNormal(); + x -= normal.getX() * this.thickness; + y -= normal.getY() * this.thickness; + z -= normal.getZ() * this.thickness; + quad.pos(i, x, y, z); + } + } + } + + return true; + } + + @Override + public void processInPlace(BakedQuad quad) { + + } + + public enum Corner { + + MIN_X_MIN_Y_MIN_Z(NEGATIVE, NEGATIVE, NEGATIVE), + MIN_X_MIN_Y_MAX_Z(NEGATIVE, NEGATIVE, POSITIVE), + MIN_X_MAX_Y_MIN_Z(NEGATIVE, POSITIVE, NEGATIVE), + MIN_X_MAX_Y_MAX_Z(NEGATIVE, POSITIVE, POSITIVE), + + MAX_X_MIN_Y_MIN_Z(POSITIVE, NEGATIVE, NEGATIVE), + MAX_X_MIN_Y_MAX_Z(POSITIVE, NEGATIVE, POSITIVE), + MAX_X_MAX_Y_MIN_Z(POSITIVE, POSITIVE, NEGATIVE), + MAX_X_MAX_Y_MAX_Z(POSITIVE, POSITIVE, POSITIVE); + + private final AxisDirection xAxis; + private final AxisDirection yAxis; + private final AxisDirection zAxis; + + public static final Corner[] VALUES = values(); + private static final int[] sideMask = { 0, 2, 0, 1, 0, 4 }; + + Corner(AxisDirection xAxis, AxisDirection yAxis, AxisDirection zAxis) { + this.xAxis = xAxis; + this.yAxis = yAxis; + this.zAxis = zAxis; + } + + /** + * Used to find what corner is at the 3 sides. + * This method assumes you pass in the X axis side, Y axis side, and Z axis side, + * it will NOT complain about an invalid side, you will just get garbage data. + * This method also does not care what order the 3 axes are in. + * + * @param sideA Side one. + * @param sideB Side two. + * @param sideC Side three. + * @return The corner at the 3 sides. + */ + public static Corner fromSides(@Nullable Direction sideA, + @Nullable Direction sideB, + @Nullable Direction sideC) { + int aIndex = GeometryHelper.toFaceIndex(sideA); + int bIndex = GeometryHelper.toFaceIndex(sideB); + int cIndex = GeometryHelper.toFaceIndex(sideC); + + // <3 Chicken-Bones. + return Corner.VALUES[sideMask[aIndex] | sideMask[bIndex] | sideMask[cIndex]]; + } + + public float pX(AABB box) { + return (float) (this.xAxis == NEGATIVE ? box.minX : box.maxX); + } + + public float pY(AABB box) { + return (float) (this.yAxis == NEGATIVE ? box.minY : box.maxY); + } + + public float pZ(AABB box) { + return (float) (this.zAxis == NEGATIVE ? box.minZ : box.maxZ); + } + } + +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java new file mode 100644 index 00000000000..dc1620e49c1 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gregtechceu.gtceu.core.mixins.client; + +import com.gregtechceu.gtceu.client.util.quad.SpriteFinder; + +import java.util.Map; + +import org.jetbrains.annotations.NotNull; +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 net.minecraft.client.renderer.texture.SpriteLoader; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.resources.ResourceLocation; + +@Mixin(TextureAtlas.class) +public class TextureAtlasMixin implements SpriteFinder.SpriteFinderAccess { + @Shadow + private Map texturesByName; + + @Unique + private SpriteFinder gtceu$spriteFinder = null; + + @Inject(at = @At("TAIL"), method = "upload") + private void uploadHook(SpriteLoader.Preparations preparations, CallbackInfo info) { + gtceu$spriteFinder = null; + } + + @Override + public @NotNull SpriteFinder gtceu$spriteFinder() { + if (this.gtceu$spriteFinder == null) { + this.gtceu$spriteFinder = new SpriteFinder(texturesByName, (TextureAtlas) (Object) this); + } + return this.gtceu$spriteFinder; + } +} diff --git a/src/main/resources/gtceu.mixins.json b/src/main/resources/gtceu.mixins.json index 200c8d9795b..cd2192122ee 100644 --- a/src/main/resources/gtceu.mixins.json +++ b/src/main/resources/gtceu.mixins.json @@ -21,6 +21,7 @@ "client.ModelManagerMixin", "client.MultiPlayerGameModeMixin", "client.PlayerInfoAccessor", + "client.TextureAtlasMixin", "client.VariantDeserializerMixin", "dev.client.KeyboardHandlerMixin", "ftbchunks.FTBChunksClientMixin", From 271e51df310c1dfc4159350e5c41eb89b8417c69 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:09:32 +0300 Subject: [PATCH 12/66] Move all internal asset reload listeners (including the CTM model replacer) to ModelEventHelper#initInternalAssetReloadListeners --- .../gregtechceu/gtceu/client/ClientProxy.java | 89 +----------- .../gtceu/client/util/ModelEventHelper.java | 130 +++++++++++++----- .../client/util/TextureMetadataHelper.java | 67 +++++++++ .../gregtechceu/gtceu/utils/ResourceUtil.java | 81 ----------- 4 files changed, 163 insertions(+), 204 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/TextureMetadataHelper.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/utils/ResourceUtil.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java index 29f6b91575f..30b452f69c6 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java @@ -8,9 +8,7 @@ import com.gregtechceu.gtceu.api.data.worldgen.bedrockore.BedrockOreDefinition; import com.gregtechceu.gtceu.api.item.IComponentItem; import com.gregtechceu.gtceu.api.item.IGTTool; -import com.gregtechceu.gtceu.client.model.ctm.CTMBakedModel; import com.gregtechceu.gtceu.client.model.item.FacadeUnbakedModel; -import com.gregtechceu.gtceu.client.model.machine.MachineModel; import com.gregtechceu.gtceu.client.model.machine.MachineModelLoader; import com.gregtechceu.gtceu.client.model.pipe.PipeModel; import com.gregtechceu.gtceu.client.model.pipe.PipeModelLoader; @@ -54,20 +52,14 @@ import com.gregtechceu.gtceu.integration.map.layer.Layers; import com.gregtechceu.gtceu.integration.map.layer.builtin.FluidRenderLayer; import com.gregtechceu.gtceu.integration.map.layer.builtin.OreRenderLayer; -import com.gregtechceu.gtceu.utils.ResourceUtil; import com.gregtechceu.gtceu.utils.data.RuntimeBlockstateProvider; import com.gregtechceu.gtceu.utils.input.SyncedKeyMapping; -import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; - import net.minecraft.client.model.BoatModel; import net.minecraft.client.model.ChestBoatModel; import net.minecraft.client.renderer.blockentity.HangingSignRenderer; import net.minecraft.client.renderer.blockentity.SignRenderer; import net.minecraft.client.renderer.entity.ThrownItemRenderer; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelResourceLocation; -import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraftforge.client.ForgeHooksClient; @@ -80,7 +72,6 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; -import java.io.IOException; import java.util.*; public class ClientProxy extends CommonProxy { @@ -102,6 +93,7 @@ public static void init() { CommonEventListener.registerCapes(new RegisterGTCapesEvent()); } initializeDynamicRenders(); + ModelEventHelper.initInternalAssetReloadListeners(); } @SubscribeEvent @@ -169,7 +161,7 @@ public void onClientSetup(FMLClientSetupEvent event) { } } - public static void initializeDynamicRenders() { + private static void initializeDynamicRenders() { DynamicRenderManager.register(GTCEu.id("quantum_tank_fluid"), QuantumTankFluidRender.TYPE); DynamicRenderManager.register(GTCEu.id("quantum_chest_item"), QuantumChestItemRender.TYPE); @@ -187,83 +179,6 @@ public void onRegisterModelLoaders(ModelEvent.RegisterGeometryLoaders event) { event.register(MachineModelLoader.ID.getPath(), MachineModelLoader.INSTANCE); event.register(PipeModelLoader.ID.getPath(), PipeModelLoader.INSTANCE); event.register("facade", FacadeUnbakedModel.Loader.INSTANCE); - - // register CTM model (un)wrapper - ModelEventHelper.registerBakeEventListener(false, (originalModelName, baked, rootUnbaked, modelBakery) -> { - // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins - if (baked instanceof CustomBakedModel ctmModel) { - if (ctmModel.getParent() instanceof MachineModel machineModel) { - return machineModel; - } else { - // Skip LDLib CTM models - return baked; - } - } - if (baked.isCustomRenderer()) { - // Nothing we can add to builtin models - return baked; - } - // do not register automatic CTM for machine models, they handle it themselves - if (baked instanceof MachineModel) { - return baked; - } - - if (!(originalModelName instanceof ModelResourceLocation) || rootUnbaked == null || baked instanceof CTMBakedModel) { - return baked; - } - Deque dependencies = new ArrayDeque<>(); - Set seenModels = new HashSet<>(); - dependencies.push(originalModelName); - seenModels.add(originalModelName); - - boolean shouldWrap = ModelEventHelper.WRAPPED_MODELS.getOrDefault(originalModelName, false); - // Breadth-first loop through dependencies - // exiting as soon as a CTM texture is found, and skipping duplicates/cycles - PARENT_LOOP: - while (!shouldWrap && !dependencies.isEmpty()) { - ResourceLocation dependencyModelName = dependencies.pop(); - UnbakedModel unbaked; - try { - unbaked = dependencyModelName == originalModelName ? rootUnbaked - : modelBakery.getModel(dependencyModelName); - } catch (Exception e) { - continue; - } - try { - // have to copy because the set is updated during this loop - @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") - Set textures = new HashSet<>(ModelEventHelper.getModelUsedCTMTextures(dependencyModelName)); - for (Material tex : textures) { - Optional meta = Optional.empty(); - // Cache all dependent texture metadata - // TODO lazy - try { - meta = ResourceUtil.getMetadata(ResourceUtil.spriteToAbsolute(tex.texture())); - } catch (IOException ignored) {} // Fallthrough - if (meta.isPresent()) { - // At least one texture has CTM metadata, so we should wrap this model - shouldWrap = true; - break PARENT_LOOP; - } - } - // shouldWrap is always false here because of the `break` above - for (ResourceLocation newDep : unbaked.getDependencies()) { - if (seenModels.add(newDep)) { - dependencies.push(newDep); - } - } - } catch (Exception e) { - GTCEu.LOGGER.error("Error loading dependency {} for model {}. Skipping...", - dependencyModelName, originalModelName, e); - } - } - ModelEventHelper.WRAPPED_MODELS.put(originalModelName, shouldWrap); - if (shouldWrap) { - return new CTMBakedModel<>(baked); - } - - return baked; - }); } @SubscribeEvent(priority = EventPriority.HIGHEST) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java index c7a1cfb23ab..bd94a742896 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java @@ -1,16 +1,14 @@ package com.gregtechceu.gtceu.client.util; import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.client.model.ctm.CTMBakedModel; import com.gregtechceu.gtceu.client.model.machine.MachineModel; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; -import com.lowdragmc.lowdraglib.client.model.custommodel.LDLMetadataSection; - import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.*; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManagerReloadListener; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ModelEvent; @@ -30,29 +28,27 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; +@SuppressWarnings("deprecation") @UtilityClass @Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public class ModelEventHelper { + @ApiStatus.Internal + public record EventListenerHolder(T listener, boolean removeOnReload) {} + @ApiStatus.Internal public static final List> EVENT_LISTENERS = new ArrayList<>(); @ApiStatus.Internal public static final Map CTM_SPRITE_CACHE = new ConcurrentHashMap<>(); private static final Multimap SCRAPED_TEXTURES = HashMultimap.create(); - @ApiStatus.Internal - public static final Object2BooleanMap WRAPPED_MODELS = new Object2BooleanOpenHashMap<>(); + private static final Object2BooleanMap WRAPPED_MODELS = new Object2BooleanOpenHashMap<>(); @ApiStatus.Internal public static void markTextureUsedForModel(ResourceLocation modelLocation, Material material) { SCRAPED_TEXTURES.put(modelLocation, material); } - @ApiStatus.Internal - public static Collection getModelUsedCTMTextures(ResourceLocation modelLocation) { - return SCRAPED_TEXTURES.get(modelLocation); - } - public static void registerAtlasStitchedEventListener(boolean removeOnReload, AssetEventListener.AtlasStitched listener) { EVENT_LISTENERS.add(new EventListenerHolder<>(listener, removeOnReload)); @@ -79,36 +75,17 @@ public static void registerAddModelsEventListener(boolean removeOnReload, @SubscribeEvent(priority = EventPriority.HIGH) public static void registerReloadListener(RegisterClientReloadListenersEvent event) { - event.registerReloadListener(new ResourceManagerReloadListener() { + event.registerReloadListener((ResourceManagerReloadListener) resourceManager -> { + EVENT_LISTENERS.removeIf(EventListenerHolder::removeOnReload); - @Override - public void onResourceManagerReload(ResourceManager resourceManager) { - EVENT_LISTENERS.removeIf(EventListenerHolder::removeOnReload); - } + CTM_SPRITE_CACHE.clear(); + TextureMetadataHelper.invalidateCaches(); }); } - @SuppressWarnings({ "unchecked", "deprecation" }) + @SuppressWarnings("unchecked") @SubscribeEvent(priority = EventPriority.LOWEST) public static void onAtlasStitched(TextureStitchEvent.Post event) { - TextureAtlas atlas = event.getAtlas(); - if (atlas.location().equals(TextureAtlas.LOCATION_BLOCKS)) { - // Cache all textures' CTM metadata - // TODO lazy - CTM_SPRITE_CACHE.clear(); - for (ResourceLocation location : event.getAtlas().getTextureLocations()) { - ResourceLocation absLoc = LDLMetadataSection.spriteToAbsolute(location); - LDLMetadataSection section = LDLMetadataSection.getMetadata(absLoc); - if (section.connection != null) { - TextureAtlasSprite ctmSprite = event.getAtlas().getSprite(section.connection); - CTM_SPRITE_CACHE.put(location, ctmSprite); - } - } - - MachineModel.initSprites(atlas); - ICoverableRenderer.initSprites(atlas); - } - for (var listener : EVENT_LISTENERS) { if (!(listener.listener instanceof AssetEventListener assetEventListener)) continue; @@ -121,7 +98,7 @@ public static void onAtlasStitched(TextureStitchEvent.Post event) { @SubscribeEvent(priority = EventPriority.LOWEST) public static void onModifyBakingResult(ModelEvent.ModifyBakingResult event) { - // don't process baked model replacement here if modernfix is loaded, as + // don't process baked model replacement here if ModernFix is loaded, as // GTModernFixIntegration#onBakedModelLoad does the same thing & it's always called if (GTCEu.Mods.isModernFixLoaded()) return; @@ -151,6 +128,87 @@ public static void onRegisterAdditional(ModelEvent.RegisterAdditional event) { } } + // INTERNAL ASSET RELOAD LISTENER REGISTRATION + @ApiStatus.Internal - public record EventListenerHolder(T listener, boolean removeOnReload) {} + public static void initInternalAssetReloadListeners() { + registerAtlasStitchedEventListener(false, TextureAtlas.LOCATION_BLOCKS, event -> { + TextureAtlas atlas = event.getAtlas(); + // Cache all textures' CTM metadata + // TODO lazy + for (ResourceLocation location : atlas.getTextureLocations()) { + var sec = TextureMetadataHelper.getMetadataFromRelativeLocation(location); + sec.ifPresent(section -> { + if (section.connectionTexture() != null) { + TextureAtlasSprite ctmSprite = atlas.getSprite(section.connectionTexture()); + CTM_SPRITE_CACHE.put(location, ctmSprite); + } + }); + } + + MachineModel.initSprites(atlas); + ICoverableRenderer.initSprites(atlas); + }); + + // register CTM model wrapper + ModelEventHelper.registerBakeEventListener(false, (rl, baked, rootModel, modelBakery) -> { + if (baked.isCustomRenderer()) { + // Nothing we can add to builtin models + return baked; + } + // do not register automatic CTM for machine models, they handle it themselves + if (baked instanceof MachineModel) { + return baked; + } + + if (!(rl instanceof ModelResourceLocation) || rootModel == null || baked instanceof CTMBakedModel) { + return baked; + } + Deque dependencies = new ArrayDeque<>(); + Set seenModels = new HashSet<>(); + dependencies.push(rl); + seenModels.add(rl); + + boolean shouldWrap = ModelEventHelper.WRAPPED_MODELS.getOrDefault(rl, false); + // Breadth-first loop through dependencies + // exiting as soon as a CTM texture is found, and skipping duplicates/cycles + PARENT_LOOP: + while (!shouldWrap && !dependencies.isEmpty()) { + ResourceLocation dependencyName = dependencies.pop(); + UnbakedModel unbaked; + try { + unbaked = dependencyName == rl ? rootModel : modelBakery.getModel(dependencyName); + } catch (Exception e) { + continue; + } + try { + // have to copy because the set is updated during this loop + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + Set textures = new HashSet<>(SCRAPED_TEXTURES.get(dependencyName)); + for (Material tex : textures) { + if (TextureMetadataHelper.getMetadata(tex).isPresent()) { + // At least one texture has CTM metadata, so we should wrap this model + shouldWrap = true; + break PARENT_LOOP; + } + } + // shouldWrap is always false here because of the `break` above + for (ResourceLocation newDep : unbaked.getDependencies()) { + if (seenModels.add(newDep)) { + dependencies.push(newDep); + } + } + } catch (Exception e) { + GTCEu.LOGGER.error("Error loading dependency {} for model {}. Skipping...", + dependencyName, rl, e); + } + } + ModelEventHelper.WRAPPED_MODELS.put(rl, shouldWrap); + if (shouldWrap) { + return new CTMBakedModel<>(baked); + } + + return baked; + }); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/TextureMetadataHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/TextureMetadataHelper.java new file mode 100644 index 00000000000..515e895ec2f --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/TextureMetadataHelper.java @@ -0,0 +1,67 @@ +package com.gregtechceu.gtceu.client.util; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.client.model.ctm.GTTextureMetadata; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.Material; +import net.minecraft.resources.ResourceLocation; + +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@UtilityClass +public class TextureMetadataHelper { + + private static final Map metadataCache = new HashMap<>(); + + public static Optional getMetadata(ResourceLocation res) { + // Note, semantically different from computeIfAbsent, as we DO care about keys mapped to null values + if (metadataCache.containsKey(res)) { + return Optional.ofNullable(metadataCache.get(res)); + } + Optional ret; + try { + ret = Minecraft.getInstance().getResourceManager().getResource(res) + .flatMap(GTTextureMetadata::getForResourceUnsafe); + } catch (Exception e) { + // the real exception that's caught should always be an IOException, + // but @SneakyThrows hides that from us so we catch all exceptions instead. + ret = Optional.empty(); + GTCEu.LOGGER.error("Error loading metadata for location {}", res, e); + } + ret.ifPresentOrElse(r -> metadataCache.put(res, r), () -> metadataCache.put(res, null)); + return ret; + } + + public static Optional getMetadata(TextureAtlasSprite sprite) { + return getMetadata(spriteToAbsolute(sprite.contents().name())); + } + + public static Optional getMetadata(Material material) { + return getMetadata(spriteToAbsolute(material.texture())); + } + + public static Optional getMetadataFromRelativeLocation(ResourceLocation relativeLocation) { + return getMetadata(spriteToAbsolute(relativeLocation)); + } + + public static ResourceLocation spriteToAbsolute(ResourceLocation sprite) { + if (!sprite.getPath().startsWith("textures/")) { + sprite = sprite.withPrefix("textures/"); + } + if (!sprite.getPath().endsWith(".png")) { + sprite = sprite.withSuffix(".png"); + } + return sprite; + } + + static void invalidateCaches() { + metadataCache.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/utils/ResourceUtil.java b/src/main/java/com/gregtechceu/gtceu/utils/ResourceUtil.java deleted file mode 100644 index f8bb663cdae..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/utils/ResourceUtil.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.gregtechceu.gtceu.utils; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.Resource; - -import com.google.gson.JsonParseException; -import lombok.experimental.UtilityClass; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.HashMap; -import java.util.Optional; - -@UtilityClass -public class ResourceUtil { - - public static Resource getResource(TextureAtlasSprite sprite) throws IOException { - return getResource(spriteToAbsolute(sprite.contents().name())); - } - - public static ResourceLocation spriteToAbsolute(ResourceLocation sprite) { - if (!sprite.getPath().startsWith("textures/")) { - sprite = sprite.withPrefix("textures/"); - } - if (!sprite.getPath().endsWith(".png")) { - sprite = sprite.withSuffix(".png"); - } - return sprite; - } - - public static Resource getResource(ResourceLocation res) throws FileNotFoundException { - return Minecraft.getInstance().getResourceManager().getResourceOrThrow(res); - } - - public static Resource getResourceUnsafe(ResourceLocation res) { - try { - return getResource(res); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private static final Map metadataCache = new HashMap<>(); - private static final IMetadataSectionCTM.Serializer SERIALIZER = new IMetadataSectionCTM.Serializer(); - - public static Optional getMetadata(ResourceLocation res) throws IOException { - // Note, semantically different from computeIfAbsent, as we DO care about keys mapped to null values - if (metadataCache.containsKey(res)) { - return Optional.ofNullable(metadataCache.get(res)); - } - Optional ret; - try { - Resource resource = getResource(res); - ret = resource.metadata().getSection(SERIALIZER); - } catch (FileNotFoundException e) { - ret = Optional.empty(); - } catch (JsonParseException e) { - throw new IOException("Error loading metadata for location " + res, e); - } - ret.ifPresentOrElse(r -> metadataCache.put(res, r), () -> metadataCache.put(res, null)); - return ret; - } - - public static Optional getMetadata(TextureAtlasSprite sprite) throws IOException { - return getMetadata(spriteToAbsolute(sprite.contents().name())); - } - - public static Optional getMetadataUnsafe(TextureAtlasSprite sprite) { - try { - return getMetadata(sprite); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public static void invalidateCaches() { - metadataCache.clear(); - } -} \ No newline at end of file From 5eff24fbdd555a0a53a0616ebc17d4d615e847f2 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:10:53 +0300 Subject: [PATCH 13/66] Move GTQuadTransformers to `client.util.quad.transformers` --- .../gtceu/client/model/TextureOverrideModel.java | 2 +- .../gtceu/client/model/pipe/BakedPipeModel.java | 2 +- .../gtceu/client/renderer/cover/FacadeCoverRenderer.java | 2 +- .../com/gregtechceu/gtceu/client/util/quad/QuadUtils.java | 1 + .../util/quad/{ => transformers}/GTQuadTransformers.java | 8 ++++---- 5 files changed, 8 insertions(+), 7 deletions(-) rename src/main/java/com/gregtechceu/gtceu/client/util/quad/{ => transformers}/GTQuadTransformers.java (95%) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java index 0b34bcf432b..b8a0492a13a 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java @@ -1,6 +1,6 @@ package com.gregtechceu.gtceu.client.model; -import com.gregtechceu.gtceu.client.util.quad.GTQuadTransformers; +import com.gregtechceu.gtceu.client.util.quad.transformers.GTQuadTransformers; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java index cb8e67085b1..c6df01e5622 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java @@ -9,7 +9,7 @@ import com.gregtechceu.gtceu.client.model.IBlockEntityRendererBakedModel; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; import com.gregtechceu.gtceu.client.util.RenderUtil; -import com.gregtechceu.gtceu.client.util.quad.GTQuadTransformers; +import com.gregtechceu.gtceu.client.util.quad.transformers.GTQuadTransformers; import com.gregtechceu.gtceu.common.data.GTMaterialBlocks; import com.gregtechceu.gtceu.utils.GTUtil; diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java index c5d1094b28f..731a05a881c 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java @@ -7,7 +7,7 @@ import com.gregtechceu.gtceu.client.model.TextureOverrideModel; import com.gregtechceu.gtceu.client.util.FacadeBlockAndTintGetter; import com.gregtechceu.gtceu.client.util.RenderUtil; -import com.gregtechceu.gtceu.client.util.quad.GTQuadTransformers; +import com.gregtechceu.gtceu.client.util.quad.transformers.GTQuadTransformers; import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; import com.gregtechceu.gtceu.common.cover.FacadeCover; import com.gregtechceu.gtceu.common.item.behavior.FacadeItemBehaviour; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java index d51c30ea856..391a0024726 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.client.util.quad; import com.gregtechceu.gtceu.client.model.ctm.CTMCache; +import com.gregtechceu.gtceu.client.util.quad.transformers.GTQuadTransformers; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/GTQuadTransformers.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/GTQuadTransformers.java similarity index 95% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/GTQuadTransformers.java rename to src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/GTQuadTransformers.java index ccb3dd07099..3b56dd4c519 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/GTQuadTransformers.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/GTQuadTransformers.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.util.quad; +package com.gregtechceu.gtceu.client.util.quad.transformers; import net.minecraft.client.renderer.FaceInfo; import net.minecraft.client.renderer.block.model.BakedQuad; @@ -62,9 +62,9 @@ public static BakedQuad setSprite(BakedQuad quad, TextureAtlasSprite sprite) { vertices[offset] = Float.floatToRawIntBits(u); vertices[offset + 1] = Float.floatToRawIntBits(v); } - BakedQuad newQuad = new BakedQuad(vertices, quad.getTintIndex(), quad.getDirection(), - sprite, quad.isShade(), quad.hasAmbientOcclusion()); - return newQuad.gtceu$setTextureKey(quad.gtceu$getTextureKey()); + return new BakedQuad(vertices, quad.getTintIndex(), quad.getDirection(), + sprite, quad.isShade(), quad.hasAmbientOcclusion()) + .gtceu$setTextureKey(quad.gtceu$getTextureKey()); } public static BakedQuad setColor(BakedQuad quad, int argbColor, boolean clearTintIndex) { From 5226e481f6778fa365194ff38ecfe7291efa21db Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:11:12 +0300 Subject: [PATCH 14/66] Add GTTextureMetadata (forgot to commit this) --- .../client/model/ctm/GTTextureMetadata.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java new file mode 100644 index 00000000000..f0e28744fd6 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java @@ -0,0 +1,65 @@ +package com.gregtechceu.gtceu.client.model.ctm; + +import com.gregtechceu.gtceu.GTCEu; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.metadata.MetadataSectionSerializer; +import net.minecraft.server.packs.resources.Resource; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.SneakyThrows; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.Optional; +import java.util.function.Function; + +public record GTTextureMetadata(@Nullable ResourceLocation connectionTexture) { + + public static final String SECTION_NAME = GTCEu.MOD_ID; + public static final MetadataSectionSerializer SERIALIZER = new Serializer(); + + /** + * @apiNote This method throws {@link IOException} even though it isn't specified in the method definition. + */ + @SneakyThrows(IOException.class) + public static Optional getForResourceUnsafe(Resource resource) { + return resource.metadata().getSection(SERIALIZER); + } + + public GTTextureMetadata { + // Optional codec fields can't have null as the default value, so we do this instead. + // It's impossible to define an entirely empty ResourceLocation in a resource file, + // as even ":" is converted to "minecraft:". Thus, this should be entirely safe. + if (connectionTexture == Serializer.EMPTY_CONNECTION) connectionTexture = null; + } + + public static class Serializer implements MetadataSectionSerializer { + + protected static final ResourceLocation EMPTY_CONNECTION = new ResourceLocation("", ""); + + // spotless:off + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + ResourceLocation.CODEC.optionalFieldOf("connection", EMPTY_CONNECTION).forGetter(GTTextureMetadata::connectionTexture) + ).apply(instance, GTTextureMetadata::new)); + // spotless:on + + @Override + public GTTextureMetadata fromJson(@Nullable JsonObject json) throws JsonParseException { + return CODEC.parse(JsonOps.INSTANCE, json).get() + .map(Function.identity(), r -> { + throw new JsonParseException(r.message()); + }); + } + + @Override + public String getMetadataSectionName() { + return SECTION_NAME; + } + } + +} \ No newline at end of file From b327fe685e3dec9e5a9302a9c643962d7c20734a Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:48:13 +0300 Subject: [PATCH 15/66] Move classes again --- .../client/{util => model}/quad/EncodingFormat.java | 4 +++- .../gtceu/client/{util => model}/quad/Mesh.java | 2 +- .../gtceu/client/{util => model}/quad/MeshBuilder.java | 2 +- .../client/{util => model}/quad/MutableQuadView.java | 10 +++++----- .../gtceu/client/{util => model}/quad/QuadView.java | 6 ++++-- .../client/{util => model}/quad/SpriteFinder.java | 2 +- .../client/{util => model}/quad/StaticFaceBakery.java | 2 +- .../client/{util => model}/quad/package-info.java | 2 +- .../quad => model/quad/transform}/QuadTransform.java | 4 +++- .../client/renderer/cover/FacadeCoverRenderer.java | 2 +- .../gtceu/client/renderer/cover/IOCoverRenderer.java | 2 +- .../client/renderer/cover/SimpleCoverRenderer.java | 2 +- .../gregtechceu/gtceu/client/util/TextureHelper.java | 2 +- .../gtceu/client/util/quad/GeometryHelper.java | 1 + .../util/quad/transformers/QuadCornerKicker.java | 5 +++-- 15 files changed, 28 insertions(+), 20 deletions(-) rename src/main/java/com/gregtechceu/gtceu/client/{util => model}/quad/EncodingFormat.java (97%) rename src/main/java/com/gregtechceu/gtceu/client/{util => model}/quad/Mesh.java (96%) rename src/main/java/com/gregtechceu/gtceu/client/{util => model}/quad/MeshBuilder.java (98%) rename src/main/java/com/gregtechceu/gtceu/client/{util => model}/quad/MutableQuadView.java (97%) rename src/main/java/com/gregtechceu/gtceu/client/{util => model}/quad/QuadView.java (98%) rename src/main/java/com/gregtechceu/gtceu/client/{util => model}/quad/SpriteFinder.java (99%) rename src/main/java/com/gregtechceu/gtceu/client/{util => model}/quad/StaticFaceBakery.java (99%) rename src/main/java/com/gregtechceu/gtceu/client/{util => model}/quad/package-info.java (58%) rename src/main/java/com/gregtechceu/gtceu/client/{util/quad => model/quad/transform}/QuadTransform.java (84%) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/EncodingFormat.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/EncodingFormat.java similarity index 97% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/EncodingFormat.java rename to src/main/java/com/gregtechceu/gtceu/client/model/quad/EncodingFormat.java index 18eaa10ef2c..0005d09728c 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/EncodingFormat.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/EncodingFormat.java @@ -14,7 +14,9 @@ * limitations under the License. */ -package com.gregtechceu.gtceu.client.util.quad; +package com.gregtechceu.gtceu.client.model.quad; + +import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; import lombok.experimental.UtilityClass; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/Mesh.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java similarity index 96% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/Mesh.java rename to src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java index a9a6f5ca2de..3b1061a62e6 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/Mesh.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.util.quad; +package com.gregtechceu.gtceu.client.model.quad; import java.util.function.Consumer; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/MeshBuilder.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java similarity index 98% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/MeshBuilder.java rename to src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java index 4d7384acb01..7201327ac92 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/MeshBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.gregtechceu.gtceu.client.util.quad; +package com.gregtechceu.gtceu.client.model.quad; /** diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/MutableQuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java similarity index 97% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/MutableQuadView.java rename to src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java index 1b6fd9c2b4a..7b106d32324 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/MutableQuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.gregtechceu.gtceu.client.util.quad; +package com.gregtechceu.gtceu.client.model.quad; import com.gregtechceu.gtceu.client.util.TextureHelper; @@ -28,7 +28,7 @@ import net.minecraft.util.Mth; import net.minecraftforge.client.model.QuadTransformers; -import static com.gregtechceu.gtceu.client.util.quad.EncodingFormat.*; +import static com.gregtechceu.gtceu.client.model.quad.EncodingFormat.*; /** * A mutable {@link QuadView} instance. * @@ -134,9 +134,9 @@ public void clear() { } /** - * Sets the geometric vertex position for the given vertex, relative to block origin, (0,0,0). Minecraft rendering - * is designed for models that fit within a single block space and is recommended that coordinates remain in the 0-1 - * range, with multi-block meshes split into multiple per-block models. + * Sets the geometric vertex position for the given vertex, relative to block origin, (0,0,0). + * Minecraft rendering is designed for models that fit within a single block space and is recommended + * that coordinates remain in the 0-1 range, with multi-block meshes split into multiple per-block models. */ public MutableQuadView pos(int vertexIndex, float x, float y, float z) { final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java similarity index 98% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadView.java rename to src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java index 9bbe29be364..8a9e6e05e7f 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java @@ -14,7 +14,9 @@ * limitations under the License. */ -package com.gregtechceu.gtceu.client.util.quad; +package com.gregtechceu.gtceu.client.model.quad; + +import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; import lombok.Getter; import lombok.experimental.Accessors; @@ -30,7 +32,7 @@ import net.minecraft.core.Direction; import net.minecraftforge.client.model.QuadTransformers; -import static com.gregtechceu.gtceu.client.util.quad.EncodingFormat.*; +import static com.gregtechceu.gtceu.client.model.quad.EncodingFormat.*; /** * Interface for reading quad data encoded by {@link MeshBuilder}. diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/SpriteFinder.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java similarity index 99% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/SpriteFinder.java rename to src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java index 6ed318dee77..cc912bfc868 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/SpriteFinder.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.gregtechceu.gtceu.client.util.quad; +package com.gregtechceu.gtceu.client.model.quad; import java.util.Map; import java.util.function.Consumer; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/StaticFaceBakery.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/StaticFaceBakery.java similarity index 99% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/StaticFaceBakery.java rename to src/main/java/com/gregtechceu/gtceu/client/model/quad/StaticFaceBakery.java index 200eee8b51a..f5ab5e077d6 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/StaticFaceBakery.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/StaticFaceBakery.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.util.quad; +package com.gregtechceu.gtceu.client.model.quad; import com.lowdragmc.lowdraglib.client.bakedpipeline.FaceQuad; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/package-info.java similarity index 58% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/package-info.java rename to src/main/java/com/gregtechceu/gtceu/client/model/quad/package-info.java index f6a6ca48793..04eef27d2b2 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/package-info.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/package-info.java @@ -1,4 +1,4 @@ @NotNullByDefault -package com.gregtechceu.gtceu.client.util.quad; +package com.gregtechceu.gtceu.client.model.quad; import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadTransform.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/transform/QuadTransform.java similarity index 84% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadTransform.java rename to src/main/java/com/gregtechceu/gtceu/client/model/quad/transform/QuadTransform.java index de76ed61ea6..0f7186c3da3 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadTransform.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/transform/QuadTransform.java @@ -1,4 +1,6 @@ -package com.gregtechceu.gtceu.client.util.quad; +package com.gregtechceu.gtceu.client.model.quad.transform; + +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraftforge.client.model.IQuadTransformer; diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java index 731a05a881c..8c1d79c06e7 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java @@ -8,7 +8,7 @@ import com.gregtechceu.gtceu.client.util.FacadeBlockAndTintGetter; import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.client.util.quad.transformers.GTQuadTransformers; -import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; +import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; import com.gregtechceu.gtceu.common.cover.FacadeCover; import com.gregtechceu.gtceu.common.item.behavior.FacadeItemBehaviour; import com.gregtechceu.gtceu.utils.GTUtil; diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java index 317e5e10285..ea1e98634bf 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java @@ -5,7 +5,7 @@ import com.gregtechceu.gtceu.api.cover.CoverBehavior; import com.gregtechceu.gtceu.api.cover.IIOCover; import com.gregtechceu.gtceu.client.util.ModelEventHelper; -import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; +import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java index a7ae78de074..767a3cad5af 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java @@ -2,7 +2,7 @@ import com.gregtechceu.gtceu.api.cover.CoverBehavior; import com.gregtechceu.gtceu.client.util.ModelEventHelper; -import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; +import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java index 1c893d6799f..b77ed10115d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java @@ -16,7 +16,7 @@ package com.gregtechceu.gtceu.client.util; -import com.gregtechceu.gtceu.client.util.quad.MutableQuadView; +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java index 58cf95bfa34..dd91c8b60b0 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java @@ -16,6 +16,7 @@ package com.gregtechceu.gtceu.client.util.quad; +import com.gregtechceu.gtceu.client.model.quad.QuadView; import com.gregtechceu.gtceu.utils.GTUtil; import lombok.experimental.UtilityClass; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java index 8d47b277774..1d62b2f4f55 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java @@ -15,11 +15,12 @@ * You should have received a copy of the GNU Lesser General Public License * along with CodeChickenLib. If not, see . */ + package com.gregtechceu.gtceu.client.util.quad.transformers; +import com.gregtechceu.gtceu.client.model.quad.transform.QuadTransform; import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; -import com.gregtechceu.gtceu.client.util.quad.MutableQuadView; -import com.gregtechceu.gtceu.client.util.quad.QuadTransform; +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.core.Direction; From 624ee1d1c6f5828e8a60ee098833ae438b5dc8f2 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:48:40 +0300 Subject: [PATCH 16/66] Import CCL quad transformers from AE2 --- .../transformers/InterpolationHelper.java | 121 +++++++++++ .../util/quad/transformers/QuadClamper.java | 107 ++++++++++ .../quad/transformers/QuadReInterpolator.java | 191 ++++++++++++++++++ .../util/quad/transformers/QuadTinter.java | 61 ++++++ 4 files changed, 480 insertions(+) create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/InterpolationHelper.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadClamper.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadReInterpolator.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadTinter.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/InterpolationHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/InterpolationHelper.java new file mode 100644 index 00000000000..275d5fa6a6b --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/InterpolationHelper.java @@ -0,0 +1,121 @@ +/* + * This file is part of CodeChickenLib. + * Copyright (c) 2018, covers1624, All rights reserved. + * + * CodeChickenLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * CodeChickenLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CodeChickenLib. If not, see . + */ + +package com.gregtechceu.gtceu.client.util.quad.transformers; + +import net.minecraft.util.Mth; + +/** + * @author covers1624 + */ +public class InterpolationHelper { + + private final float[][] posCache = new float[4][2]; + private final float[] valCache = new float[4]; + + private float x0; + private float x1; + private float y0; + private float y1; + + private float rX; + private float rY; + + private int p00; + private int p10; + private int p11; + private int p01; + + /** + * Resets the interpolation helper with the given quad. Does not care what order the vertices are in. + */ + public void reset(float dx0, float dy0, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) { + float[] vec0 = this.posCache[0]; + float[] vec1 = this.posCache[1]; + float[] vec2 = this.posCache[2]; + float[] vec3 = this.posCache[3]; + + vec0[0] = dx0; + vec1[0] = dx1; + vec2[0] = dx2; + vec3[0] = dx3; + + vec0[1] = dy0; + vec1[1] = dy1; + vec2[1] = dy2; + vec3[1] = dy3; + } + + /** + * Call when you are ready to use the interpolation helper. + */ + public void setup() { + this.p00 = 0; // Bottom Left is always first. + this.x0 = this.posCache[this.p00][0]; + this.y0 = this.posCache[this.p00][1]; + + for (int i = 1; i < 4; i++) { + float x = this.posCache[i][0]; + float y = this.posCache[i][1]; + + if (this.y0 == y) { + // Bottom right. + this.p10 = i; + this.x1 = x; + } else if (this.x0 == x) { + // Top left. + this.p01 = i; + this.y1 = y; + } else { + // Top right. + this.p11 = i; + } + } + } + + /** + * Computes the coefficients for the interpolation. + * + * @param x X interpolation location. + * @param y Y interpolation location. + */ + public void locate(float x, float y) { + this.rX = Mth.inverseLerp(x, this.x0, this.x1); + this.rY = Mth.inverseLerp(y, this.y0, this.y1); + } + + /** + * Interpolates using the already computed coefficients. + * + * @param q0 Value at dx0 dy0 + * @param q1 Value at dx1 dy1 + * @param q2 Value at dx2 dy2 + * @param q3 Value at dx3 dy3 + * @return The result. + */ + public float interpolate(float q0, float q1, float q2, float q3) { + this.valCache[0] = q0; + this.valCache[1] = q1; + this.valCache[2] = q2; + this.valCache[3] = q3; + float f0 = Mth.lerp(this.rX, this.valCache[this.p00], this.valCache[this.p10]); + float f1 = Mth.lerp(this.rX, this.valCache[this.p01], this.valCache[this.p11]); + + return Mth.lerp(this.rY, f0, f1); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadClamper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadClamper.java new file mode 100644 index 00000000000..9e7aa728dae --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadClamper.java @@ -0,0 +1,107 @@ +/* + * This file is part of CodeChickenLib. + * Copyright (c) 2018, covers1624, All rights reserved. + * + * CodeChickenLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * CodeChickenLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CodeChickenLib. If not, see . + */ + +package com.gregtechceu.gtceu.client.util.quad.transformers; + +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; +import com.gregtechceu.gtceu.client.model.quad.transform.QuadTransform; + +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.AABB; + +import org.joml.Vector3f; + +/** + * This transformer simply clamps the vertices inside the provided box.
+ * You probably want to Re-Interpolate the UV's, Color, and Lightmap. For that, see {@link QuadReInterpolator}. + * + * @see QuadReInterpolator + * @author covers1624 + */ +public class QuadClamper implements QuadTransform { + + private final AABB clampBounds; + + private final Vector3f pos = new Vector3f(); + + public QuadClamper(AABB clampBounds) { + this.clampBounds = clampBounds; + } + + @Override + public boolean transform(MutableQuadView quad) { + Direction.Axis axis = quad.nominalFace().getAxis(); + + clamp(quad, this.clampBounds); + + // Check if the quad would be invisible and cull it. + float x1 = quad.posByIndex(0, xCoord(axis)); + float x2 = quad.posByIndex(1, xCoord(axis)); + float x3 = quad.posByIndex(2, xCoord(axis)); + float x4 = quad.posByIndex(3, xCoord(axis)); + + float y1 = quad.posByIndex(0, yCoord(axis)); + float y2 = quad.posByIndex(1, yCoord(axis)); + float y3 = quad.posByIndex(2, yCoord(axis)); + float y4 = quad.posByIndex(3, yCoord(axis)); + + // These comparisons are safe as we are comparing clamped values. + boolean flag1 = x1 == x2 && x2 == x3 && x3 == x4; + boolean flag2 = y1 == y2 && y2 == y3 && y3 == y4; + return !flag1 && !flag2; + } + + private void clamp(MutableQuadView quad, AABB bb) { + for (int i = 0; i < 4; i++) { + quad.copyPos(i, pos); + pos.set((float) Mth.clamp(pos.x(), bb.minX, bb.maxX), + (float) Mth.clamp(pos.y(), bb.minY, bb.maxY), + (float) Mth.clamp(pos.z(), bb.minZ, bb.maxZ)); + quad.pos(i, pos); + } + } + + /** + * Gets the 2d X coordinate for the given axis. + * + * @param axis The axis. side >> 1 + * @return The x coordinate. + */ + private static int xCoord(Direction.Axis axis) { + if (axis == Direction.Axis.Y) { + return 0; + } else { + return 2; + } + } + + /** + * Gets the 2d Y coordinate for the given axis. + * + * @param axis The axis. + * @return The y coordinate. + */ + private static int yCoord(Direction.Axis axis) { + if (axis != Direction.Axis.Y) { + return 1; + } else { + return 2; + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadReInterpolator.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadReInterpolator.java new file mode 100644 index 00000000000..4c0849b0c9a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadReInterpolator.java @@ -0,0 +1,191 @@ +/* + * This file is part of CodeChickenLib. + * Copyright (c) 2018, covers1624, All rights reserved. + * + * CodeChickenLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * CodeChickenLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CodeChickenLib. If not, see . + */ + +package com.gregtechceu.gtceu.client.util.quad.transformers; + +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; +import com.gregtechceu.gtceu.client.model.quad.QuadView; +import com.gregtechceu.gtceu.client.model.quad.transform.QuadTransform; + +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.core.Direction; + +/** + * This transformer Re-Interpolates the Color, UV's and LightMaps. Use this after all transformations that translate + * vertices in the pipeline. + *

+ * This Transformation can only be used in the BakedPipeline. + * + * @author covers1624 + */ +public class QuadReInterpolator implements QuadTransform { + + private final InterpolationHelper interpolationHelper = new InterpolationHelper(); + + private final int[] originalSpriteColor = new int[4]; + private final float[] originalSpriteU = new float[4]; + private final float[] originalSpriteV = new float[4]; + private final int[] originalSpriteLightmap = new int[4]; + + public QuadReInterpolator() { + super(); + } + + public void setInputQuad(QuadView quad) { + Direction.Axis axis = quad.nominalFace().getAxis(); + int xIndex = xCoord(axis); + int yIndex = yCoord(axis); + + interpolationHelper.reset( + quad.posByIndex(0, xIndex), quad.posByIndex(0, yIndex), + quad.posByIndex(1, xIndex), quad.posByIndex(1, yIndex), + quad.posByIndex(2, xIndex), quad.posByIndex(2, yIndex), + quad.posByIndex(3, xIndex), quad.posByIndex(3, yIndex)); + + // Save the original properties of the quad's vertices + for (int v = 0; v < 4; v++) { + originalSpriteColor[v] = quad.color(v); + originalSpriteU[v] = quad.u(v); + originalSpriteV[v] = quad.v(v); + originalSpriteLightmap[v] = quad.lightmap(v); + } + } + + @Override + public boolean transform(MutableQuadView quad) { + Direction.Axis axis = quad.nominalFace().getAxis(); + int xIndex = xCoord(axis); + int yIndex = yCoord(axis); + + this.interpolationHelper.setup(); + for (int i = 0; i < 4; i++) { + float x = quad.posByIndex(i, xIndex); + float y = quad.posByIndex(i, yIndex); + this.interpolationHelper.locate(x, y); + interpolateColorFrom(quad, i); + interpolateUVFrom(quad, i); + interpolateLightmapFrom(quad, i); + } + return true; + } + + /** + * Interpolates the new color values for this Vertex using the others as a reference. + */ + public void interpolateColorFrom(MutableQuadView quad, int vertexIndex) { + int p1 = this.originalSpriteColor[0]; + int p2 = this.originalSpriteColor[1]; + int p3 = this.originalSpriteColor[2]; + int p4 = this.originalSpriteColor[3]; + if (p1 == p2 && p2 == p3 && p3 == p4) { + return; // Don't bother for uniformly colored quads + } + + // Interpolate each color component separately + int color = 0; + int mask = 0xFF; + for (int i = 0; i < 4; i++) { + int p1c = p1 & mask; + int p2c = p2 & mask; + int p3c = p3 & mask; + int p4c = p4 & mask; + int interpolated = (int) interpolationHelper.interpolate(p1c, p2c, p3c, p4c); + color |= interpolated & mask; + mask <<= 8; + } + + quad.color(vertexIndex, color); + } + + /** + * Interpolates the new UV values for this Vertex using the others as a reference. + */ + public void interpolateUVFrom(MutableQuadView quad, int vertexIndex) { + float p1 = originalSpriteU[0]; + float p2 = originalSpriteU[1]; + float p3 = originalSpriteU[2]; + float p4 = originalSpriteU[3]; + float u = interpolationHelper.interpolate(p1, p2, p3, p4); + + p1 = originalSpriteV[0]; + p2 = originalSpriteV[1]; + p3 = originalSpriteV[2]; + p4 = originalSpriteV[3]; + float v = interpolationHelper.interpolate(p1, p2, p3, p4); + quad.uv(vertexIndex, u, v); + } + + /** + * Interpolates the new LightMap values for this Vertex using the others as a reference. + * + * @return The same Vertex. + */ + public void interpolateLightmapFrom(MutableQuadView quad, int vertexIndex) { + int p1 = originalSpriteLightmap[0]; + int p2 = originalSpriteLightmap[1]; + int p3 = originalSpriteLightmap[2]; + int p4 = originalSpriteLightmap[3]; + if (p1 == p2 && p2 == p3 && p3 == p4) { + return; // Don't bother for uniformly lit quads + } + + // Interpolate both lightmap components separately + int p1l = LightTexture.block(p1); + int p2l = LightTexture.block(p2); + int p3l = LightTexture.block(p3); + int p4l = LightTexture.block(p4); + int block = (int) interpolationHelper.interpolate(p1l, p2l, p3l, p4l); + + p1l = LightTexture.sky(p1); + p2l = LightTexture.sky(p2); + p3l = LightTexture.sky(p3); + p4l = LightTexture.sky(p4); + int sky = (int) interpolationHelper.interpolate(p1l, p2l, p3l, p4l); + + quad.lightmap(vertexIndex, block, sky); + } + + /** + * Gets the 2d X coordinate for the given axis. + * + * @param axis The axis. side >> 1 + * @return The x coordinate. + */ + private static int xCoord(Direction.Axis axis) { + if (axis == Direction.Axis.Y) { + return 0; + } else { + return 2; + } + } + + /** + * Gets the 2d Y coordinate for the given axis. + * + * @param axis The axis. + * @return The y coordinate. + */ + private static int yCoord(Direction.Axis axis) { + if (axis != Direction.Axis.Y) { + return 1; + } else { + return 2; + } + } + +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadTinter.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadTinter.java new file mode 100644 index 00000000000..0af06ab6c11 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadTinter.java @@ -0,0 +1,61 @@ +/* + * This file is part of CodeChickenLib. + * Copyright (c) 2018, covers1624, All rights reserved. + * + * CodeChickenLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * CodeChickenLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CodeChickenLib. If not, see . + */ + +package com.gregtechceu.gtceu.client.util.quad.transformers; + +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; +import com.gregtechceu.gtceu.client.model.quad.transform.QuadTransform; + +/** + * This transformer tints quads. + */ +public class QuadTinter implements QuadTransform { + + private final int argb; + + public QuadTinter(int rgb) { + this.argb = 0xFF000000 | rgb; + } + + @Override + public boolean transform(MutableQuadView quad) { + // Nuke tintIndex. + quad.tintIndex(-1); + for (int i = 0; i < 4; i++) { + int color = quad.color(i); + color = multiplyColor(color, argb); + quad.color(i, color); + } + return true; + } + + private static int multiplyColor(int color1, int color2) { + if (color1 == -1) { + return color2; + } else if (color2 == -1) { + return color1; + } + + final int alpha = ((color1 >> 24) & 0xFF) * ((color2 >> 24) & 0xFF) / 0xFF; + final int red = ((color1 >> 16) & 0xFF) * ((color2 >> 16) & 0xFF) / 0xFF; + final int green = ((color1 >> 8) & 0xFF) * ((color2 >> 8) & 0xFF) / 0xFF; + final int blue = (color1 & 0xFF) * (color2 & 0xFF) / 0xFF; + + return (alpha << 24) | (red << 16) | (green << 8) | blue; + } +} From a6628ea1aab0c95938030a3d992fbaf1d82204cd Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:50:35 +0300 Subject: [PATCH 17/66] Use the Fabric quad modification pipeline for connected textures --- .../client/model/TextureOverrideModel.java | 9 +- .../gtceu/client/model/ctm/CTMBakedModel.java | 2 +- .../client/model/machine/MachineModel.java | 4 +- .../gtceu/client/model/quad/Mesh.java | 18 +- .../client/model/quad/MutableQuadView.java | 52 +++- .../gtceu/client/model/quad/QuadView.java | 12 +- .../gtceu/client/util/TextureHelper.java | 35 ++- .../gtceu/client/util/quad/QuadInfo.java | 264 ------------------ .../gtceu/client/util/quad/QuadUtils.java | 217 +++++++++----- .../core/mixins/client/TextureAtlasMixin.java | 2 +- 10 files changed, 260 insertions(+), 355 deletions(-) delete mode 100644 src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadInfo.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java index b8a0492a13a..d554b30c13f 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java @@ -14,7 +14,6 @@ import net.minecraftforge.client.model.data.ModelData; import lombok.Getter; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -23,7 +22,6 @@ public class TextureOverrideModel extends BakedModelWrappe public static final IQuadTransformer OVERLAY_OFFSET = GTQuadTransformers.offset(0.002f); - @NotNull @Getter protected final Map textureOverrides; @@ -37,10 +35,9 @@ public BakedModel getChild() { } @Override - public @NotNull List getQuads(@Nullable BlockState state, @Nullable Direction side, - @NotNull RandomSource rand, @NotNull ModelData extraData, - @Nullable RenderType renderType) { - return retextureQuads(super.getQuads(state, side, rand, extraData, renderType), textureOverrides); + public List getQuads(@Nullable BlockState state, @Nullable Direction side, + RandomSource rand, ModelData modelData, @Nullable RenderType renderType) { + return retextureQuads(super.getQuads(state, side, rand, modelData, renderType), textureOverrides); } public static List retextureQuads(List quads, Map overrides) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java index a172baec992..0bb2ad76b67 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java @@ -50,7 +50,7 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction ctmCache.getSubmapIds(level, pos, state, side); return this.sideCache.computeIfAbsent(side, $ -> new ConcurrentHashMap<>()) .computeIfAbsent(ctmCache, cache -> QuadUtils.buildCTMQuads(cache, - super.getQuads(state, side, rand, parentModelData, renderType))); + super.getQuads(state, side, rand, parentModelData, renderType), side)); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java index 2d556585382..8d3982fca6f 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java @@ -14,7 +14,7 @@ import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.client.util.quad.QuadUtils; -import com.gregtechceu.gtceu.client.util.quad.StaticFaceBakery; +import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; import com.gregtechceu.gtceu.common.data.models.GTModels; import com.gregtechceu.gtceu.common.machine.trait.AutoOutputTrait; @@ -275,7 +275,7 @@ public List renderMachine(@Nullable MetaMachine machine, @Nullable Bl // we have to recalculate CTM ourselves. // this is the slowest part by a long shot because the LDLib quad logic isn't very optimized. if (level != null && pos != null && blockState != null) { - return QuadUtils.buildCTMQuads(quads, level, pos, blockState, side); + return QuadUtils.buildCTMQuads(level, pos, blockState, quads, side); } return quads; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java index 3b1061a62e6..bb27314165b 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java @@ -1,5 +1,11 @@ package com.gregtechceu.gtceu.client.model.quad; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlas; + +import java.util.ArrayList; +import java.util.List; import java.util.function.Consumer; /** @@ -16,7 +22,7 @@ */ public class Mesh { /** Used to satisfy external calls to {@link #forEach(Consumer)}. */ - ThreadLocal POOL = ThreadLocal.withInitial(QuadView::new); + private static final ThreadLocal POOL = ThreadLocal.withInitial(QuadView::new); final int[] data; @@ -46,4 +52,14 @@ void forEach(Consumer consumer, QuadView cursor) { index += EncodingFormat.QUAD_STRIDE; } } + + @SuppressWarnings("deprecation") + public List toBakedBlockQuads() { + SpriteFinder finder = SpriteFinder.get(Minecraft.getInstance().getModelManager() + .getAtlas(TextureAtlas.LOCATION_BLOCKS)); + + List result = new ArrayList<>(); + forEach(qv -> result.add(qv.toBakedQuad(finder.find(qv)))); + return result; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java index 7b106d32324..b65d8a45b6e 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java @@ -17,11 +17,13 @@ package com.gregtechceu.gtceu.client.model.quad; import com.gregtechceu.gtceu.client.util.TextureHelper; +import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; import org.joml.Vector3f; +import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; @@ -154,6 +156,39 @@ public MutableQuadView pos(int vertexIndex, Vector3f pos) { return pos(vertexIndex, pos.x(), pos.y(), pos.z()); } + /** + * Sets the vertex X position for the given vertex, relative to block origin, (0,0,0). + * Minecraft rendering is designed for models that fit within a single block space and is recommended + * that coordinates remain in the 0-1 range, with multi-block meshes split into multiple per-block models. + */ + public MutableQuadView x(int vertexIndex, float x) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X] = Float.floatToRawIntBits(x); + isGeometryInvalid = true; + return this; + } + + /** + * Sets the vertex Y position for the given vertex, relative to block origin, (0,0,0). + * Minecraft rendering is designed for models that fit within a single block space and is recommended + * that coordinates remain in the 0-1 range, with multi-block meshes split into multiple per-block models. + */ + public MutableQuadView y(int vertexIndex, float y) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Y] = Float.floatToRawIntBits(y); + isGeometryInvalid = true; + return this; + } + + /** + * Sets the vertex Z position for the given vertex, relative to block origin, (0,0,0). + * Minecraft rendering is designed for models that fit within a single block space and is recommended + * that coordinates remain in the 0-1 range, with multi-block meshes split into multiple per-block models. + */ + public MutableQuadView z(int vertexIndex, float z) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Z] = Float.floatToRawIntBits(z); + isGeometryInvalid = true; + return this; + } + /** * Set vertex color. */ @@ -201,7 +236,7 @@ public MutableQuadView uv(int vertexIndex, Vector2f uv) { * Can handle UV locking, rotation, interpolation, etc. * Control this behavior by passing additive combinations of the BAKE_ flags defined in this interface. */ - public MutableQuadView spriteBake(TextureAtlasSprite sprite, int bakeFlags) { + public MutableQuadView spriteBake(@Nullable TextureAtlasSprite sprite, int bakeFlags) { TextureHelper.bakeSprite(this, sprite, bakeFlags); return this; } @@ -215,6 +250,15 @@ public MutableQuadView lightmap(int vertexIndex, int lightmap) { return this; } + /** + * Accept vanilla lightmap values. + * Input values will override lightmap values computed from world state if input values are higher. + */ + public MutableQuadView lightmap(int vertexIndex, int block, int sky) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP] = LightTexture.pack(block, sky); + return this; + } + /** * Convenience: set lightmap for all vertices at once. * @@ -229,7 +273,7 @@ public MutableQuadView lightmap(int b0, int b1, int b2, int b3) { } protected void normalFlags(int flags) { - this.flags = EncodingFormat.normalFlags(this.flags, flags); + headerFlags = EncodingFormat.normalFlags(headerFlags, flags); } /** @@ -285,7 +329,7 @@ public final void populateMissingNormals() { * face geometry and must be non-null in vanilla quads. That computed value is returned by {@link #lightFace()}. */ public final MutableQuadView cullFace(@Nullable Direction face) { - flags = EncodingFormat.cullFace(flags, face); + headerFlags = EncodingFormat.cullFace(headerFlags, face); nominalFace(face); return this; } @@ -377,7 +421,7 @@ public final MutableQuadView fromVanilla(int[] quadData, int startIndex) { */ public final MutableQuadView fromVanilla(BakedQuad quad, @Nullable Direction cullFace) { fromVanilla(quad.getVertices(), 0); - flags = EncodingFormat.cullFace(0, cullFace); + headerFlags = EncodingFormat.cullFace(0, cullFace); nominalFace(quad.getDirection()); tintIndex(quad.getTintIndex()); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java index 8a9e6e05e7f..416b88c33a1 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java @@ -71,7 +71,7 @@ public class QuadView { @Getter protected int tintIndex; - protected long flags = 0; + protected long headerFlags = 0; /** Size and where it comes from will vary in subtypes. But in all cases quad is fully encoded to array. */ protected int @UnknownNullability [] data; @@ -105,7 +105,7 @@ public int[] data() { } public int normalFlags() { - return EncodingFormat.normalFlags(flags); + return EncodingFormat.normalFlags(headerFlags); } /** True if any vertex normal has been set. */ @@ -120,7 +120,7 @@ protected void computeGeometry() { GeometryHelper.computeFaceNormal(faceNormal, this); // depends on face normal - flags = EncodingFormat.lightFace(flags, GeometryHelper.lightFace(this)); + headerFlags = EncodingFormat.lightFace(headerFlags, GeometryHelper.lightFace(this)); } } @@ -131,7 +131,7 @@ protected void computeGeometry() { */ public final Direction lightFace() { computeGeometry(); - return EncodingFormat.lightFace(flags); + return EncodingFormat.lightFace(headerFlags); } /** @@ -141,7 +141,7 @@ public final Direction lightFace() { */ public final @Nullable Direction cullFace() { computeGeometry(); - return EncodingFormat.cullFace(flags); + return EncodingFormat.cullFace(headerFlags); } /** @@ -170,7 +170,7 @@ public void copyTo(MutableQuadView quad) { quad.nominalFace = this.nominalFace; quad.isGeometryInvalid = false; quad.shade(this.shade); - quad.flags = this.flags; + quad.headerFlags = this.headerFlags; } /** diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java index b77ed10115d..cd21ca50246 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java @@ -22,6 +22,7 @@ import net.minecraft.core.Direction; import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Nullable; /** * Handles most texture-baking use cases for model loaders and model libraries via @@ -37,8 +38,12 @@ public class TextureHelper { /** * Bakes textures in the provided vertex data, handling UV locking, rotation, interpolation, etc. * Textures must not be already baked. + * + *

+ * If {@code sprite == null}, only the UV modifiers will be applied, but they won't be translated to the sprite's + * atlas coordinates. */ - public static void bakeSprite(MutableQuadView quad, TextureAtlasSprite sprite, int bakeFlags) { + public static void bakeSprite(MutableQuadView quad, @Nullable TextureAtlasSprite sprite, int bakeFlags) { if (quad.nominalFace() != null && (MutableQuadView.BAKE_LOCK_UV & bakeFlags) != 0) { // Assigns normalized UV coordinates based on vertex positions applyModifier(quad, UV_LOCKERS[quad.nominalFace().get3DDataValue()]); @@ -68,14 +73,16 @@ public static void bakeSprite(MutableQuadView quad, TextureAtlasSprite sprite, i applyModifier(quad, (q, i) -> q.uv(i, q.u(i), 1 - q.v(i))); } - interpolate(quad, sprite); + if (sprite != null) { + interpolate(quad, sprite); + } } /** * Faster than sprite method. Sprite computes span and normalizes inputs each call, so we'd have to denormalize * before we called, only to have the sprite renormalize immediately. */ - private static void interpolate(MutableQuadView q, TextureAtlasSprite sprite) { + public static void interpolate(MutableQuadView q, TextureAtlasSprite sprite) { final float uMin = sprite.getU0(); final float uSpan = sprite.getU1() - uMin; final float vMin = sprite.getV0(); @@ -86,8 +93,28 @@ private static void interpolate(MutableQuadView q, TextureAtlasSprite sprite) { } } + /** + * Faster than sprite method. Sprite computes span and normalizes inputs each call, so we'd have to denormalize + * before we called, only to have the sprite renormalize immediately. + */ + public static void normalizeBy(MutableQuadView q, TextureAtlasSprite sprite) { + final float uMin = sprite.getU0(), uMax = sprite.getU1(); + final float uSpan = uMax - uMin; + final float vMin = sprite.getV0(), vMax = sprite.getV1(); + final float vSpan = vMax - vMin; + + for (int i = 0; i < 4; i++) { + final float u = q.u(i), v = q.v(i); + // Skip invalid UV coordinates. + // If the UV is outside the texture's boundaries, this was probably called by mistake. + if (u < uMin || u > uMax || v < vMin || v > vMax) continue; + + q.uv(i, (u - uMin) / uSpan, (v - vMin) / vSpan); + } + } + @FunctionalInterface - private interface VertexModifier { + public interface VertexModifier { void apply(MutableQuadView quad, int vertexIndex); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadInfo.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadInfo.java deleted file mode 100644 index 3b65c349ba0..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadInfo.java +++ /dev/null @@ -1,264 +0,0 @@ -package com.gregtechceu.gtceu.client.util.quad; - -import com.gregtechceu.gtceu.client.model.ctm.ISubmap; -import com.gregtechceu.gtceu.client.model.ctm.OctagonalOrientation; - -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraftforge.client.model.IQuadTransformer; - -import it.unimi.dsi.fastutil.Pair; -import org.joml.Vector2f; -import org.joml.Vector3f; - -import static com.gregtechceu.gtceu.client.model.ctm.OctagonalOrientation.*; - -public record QuadInfo(TextureAtlasSprite sprite, int tintIndex, Direction direction, - boolean shade, boolean ao, int blockLight, int skyLight, - Vector3f[] vertices, Vector2f[] uvs, Vector2f minUV, Vector2f maxUV) { - - // Mapping the different corner indices to their respective dirs - private static final OctagonalOrientation[][] SUBMAP_MAP = new OctagonalOrientation[][] { - { BOTTOM, LEFT, BOTTOM_LEFT }, - { BOTTOM, RIGHT, BOTTOM_RIGHT }, - { TOP, RIGHT, TOP_RIGHT }, - { TOP, LEFT, TOP_LEFT } - }; - - public QuadInfo(TextureAtlasSprite sprite, int tintIndex, Direction direction, boolean shade, boolean ao, - Vector3f[] vertices, Vector2f[] uvs, Vector2f minUV, Vector2f maxUV) { - this(sprite, tintIndex, direction, shade, ao, 0, 0, vertices, uvs, minUV, maxUV); - } - - // region UV operations - - public Vector2f[] normalizeUVs() { - Vector2f[] ret = new Vector2f[uvs.length]; - for (int i = 0; i < ret.length; i++) { - ret[i] = QuadUtils.normalizeUV(sprite, uvs[i]); - } - return ret; - } - - public Vector2f[] relativizeUVs() { - Vector2f[] ret = new Vector2f[uvs.length]; - for (int i = 0; i < uvs.length; i++) { - ret[i] = QuadUtils.relativizeUV(sprite, uvs[i]); - } - return ret; - } - - public int getNormalizedUVQuadrant() { - return getUVQuadrant(QuadUtils.normalizeUV(sprite, maxUV)); - } - - public static int getUVQuadrant(Vector2f uv) { - if (uv.x() <= 0.5f) { - if (uv.y() <= 0.5f) { - return 3; - } else { - return 0; - } - } else { - if (uv.y() <= 0.5f) { - return 2; - } else { - return 1; - } - } - } - - public Vector2f[] normalizeUVQuadrant() { - Vector2f[] normalized = normalizeUVs(); - - int quadrant = getNormalizedUVQuadrant(); - float minUInterp = quadrant == 1 || quadrant == 2 ? 0.5f : 0; - float minVInterp = quadrant < 2 ? 0.5f : 0; - float maxUInterp = quadrant == 0 || quadrant == 3 ? 0.5f : 1; - float maxVInterp = quadrant > 1 ? 0.5f : 1; - - normalized = QuadUtils.normalizeUVs( - new Vector2f(minUInterp, minVInterp), - new Vector2f(maxUInterp, maxVInterp), - normalized); - return QuadUtils.relativizeUVs(sprite, normalized); - } - - public Vector2f[] transformUVData(TextureAtlasSprite other, ISubmap submap) { - Vector2f[] normalized = normalizeUVs(); - var maxUVs = QuadUtils.findMinMaxUVs(normalized); - submap = submap.unitScale(); - - float width = maxUVs.second().x() - maxUVs.first().x(); - float height = maxUVs.second().y() - maxUVs.first().y(); - - float minU = submap.getXOffset(); - float minV = submap.getYOffset(); - minU += maxUVs.first().x() * submap.getWidth(); - minV += maxUVs.first().y() * submap.getHeight(); - - float maxU = minU + (width * submap.getWidth()); - float maxV = minV + (height * submap.getHeight()); - - Vector2f[] newUVs = new Vector2f[4]; - for (int i = 0; i < 4; i++) { - Vector2f uv = new Vector2f(this.uvs[i]); - // same as sprite.getU(oldSprite.getUOffset(uv.x)), but we don't multiply and divide in between - // NOTE: can be simplified to ^ on 1.21 - uv.x = Mth.map(uv.x, this.sprite.getU0(), this.sprite.getU1(), other.getU0(), other.getU1()); - uv.y = Mth.map(uv.y, this.sprite.getV0(), this.sprite.getV1(), other.getV0(), other.getV1()); - newUVs[i] = uv; - } - - // FIXME this... isn't all that great. - newUVs = new Vector2f[] { - new Vector2f(newUVs[0].x() == this.minUV.x() ? minU : maxU, newUVs[0].y() == this.minUV.y() ? minV : maxV), - new Vector2f(newUVs[1].x() == this.minUV.x() ? minU : maxU, newUVs[1].y() == this.minUV.y() ? minV : maxV), - new Vector2f(newUVs[2].x() == this.minUV.x() ? minU : maxU, newUVs[2].y() == this.minUV.y() ? minV : maxV), - new Vector2f(newUVs[3].x() == this.minUV.x() ? minU : maxU, newUVs[3].y() == this.minUV.y() ? minV : maxV) - }; - return QuadUtils.relativizeUVs(other, newUVs); - } - - public Vector2f[] copyUVs() { - Vector2f[] result = new Vector2f[uvs.length]; - for (int i = 0; i < uvs.length; ++i) { - result[i] = new Vector2f(uvs[i]); - } - return result; - } - - // endregion - - // region vertex operations - - public Vector3f[] copyVertices() { - Vector3f[] result = new Vector3f[vertices.length]; - for (int i = 0; i < vertices.length; ++i) { - result[i] = new Vector3f(vertices[i]); - } - return result; - } - - public QuadInfo grow() { - return new QuadInfo(sprite, tintIndex, direction, shade, ao, blockLight, skyLight, - copyVertices(), normalizeUVQuadrant(), new Vector2f(minUV), new Vector2f(maxUV)); - } - - public QuadInfo copy() { - return new QuadInfo(sprite, tintIndex, direction, shade, ao, blockLight, skyLight, - copyVertices(), copyUVs(), new Vector2f(minUV), new Vector2f(maxUV)); - } - - public QuadInfo transformUVs(TextureAtlasSprite sprite, ISubmap submap) { - return new QuadInfo(sprite, tintIndex, direction, shade, ao, blockLight, skyLight, - copyVertices(), transformUVData(sprite, submap), new Vector2f(minUV), new Vector2f(maxUV)); - } - - public QuadInfo[] subdivide() { - QuadInfo[] rects = new QuadInfo[4]; - - var firstDivide = this.divide(false); - var secondDivide = firstDivide.left().divide(true); - rects[0] = secondDivide.left(); - if (firstDivide.right() != null) { - Pair thirdDivide = firstDivide.right().divide(true); - rects[1] = thirdDivide.left(); - rects[2] = thirdDivide.right(); - } - rects[3] = secondDivide.right(); - - return rects; - } - - private Pair divide(boolean vertical) { - Vector2f[] normalizedUvs = this.normalizeUVs(); - float minUV, maxUV; - float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE, maxU = Float.MIN_VALUE, maxV = Float.MIN_VALUE; - - int start = 0; - for (int i = 0; i < 4; i++) { - if (minU >= normalizedUvs[i].x() && minV >= normalizedUvs[i].y()) { - start = i; - } - minU = Math.min(minU, normalizedUvs[i].x()); - minV = Math.min(minV, normalizedUvs[i].y()); - maxU = Math.max(maxU, normalizedUvs[i].x()); - maxV = Math.max(maxV, normalizedUvs[i].y()); - } - if (vertical) { - minUV = minV; - maxUV = maxV; - } else { - minUV = minU; - maxUV = maxU; - } - - if (minUV < 0.5f && maxUV > 0.5f) { - float delta = Mth.inverseLerp(minUV, maxUV, 0.5f); - - Vector2f[] firstUVs = QuadUtils.relativizeUVs(sprite, - new Vector2f(vertical ? minU : 0.5f, vertical ? 0.5f : minV), - new Vector2f(vertical ? minU : 0.5f, maxV), - new Vector2f(maxU, maxV), - new Vector2f(maxU, vertical ? 0.5f : minV)); - Vector2f[] secondUVs = QuadUtils.relativizeUVs(sprite, - new Vector2f(minU, minV), - new Vector2f(minU, vertical ? 0.5f : maxV), - new Vector2f(vertical ? maxU : 0.5f, vertical ? 0.5f : maxV), - new Vector2f(vertical ? maxU : 0.5f, minV)); - - Vector3f[] firstVerts = new Vector3f[4]; - Vector3f[] secondVerts = new Vector3f[4]; - for (int i = 0; i < 4; i++) { - int idx = (start + i) % 4; - firstVerts[i] = new Vector3f(vertices[idx]); - secondVerts[i] = new Vector3f(vertices[idx]); - } - - int i0 = 0; - int i1 = vertical ? 1 : 3; - int i2 = 2; - int i3 = vertical ? 3 : 1; - - firstVerts[i0].lerp(firstVerts[i1], delta); - firstVerts[i3].lerp(firstVerts[i2], delta); - secondVerts[i0].lerp(secondVerts[i1], delta, secondVerts[i1]); - secondVerts[i3].lerp(secondVerts[i2], delta, secondVerts[i2]); - - return Pair.of( - new QuadInfo(sprite, tintIndex, direction, shade, ao, blockLight, skyLight, - firstVerts, firstUVs, firstUVs[0], firstUVs[2]), - new QuadInfo(sprite, tintIndex, direction, shade, ao, blockLight, skyLight, - secondVerts, secondUVs, secondUVs[0], secondUVs[2])); - } else { - return Pair.of(this, null); - } - } - - // endregion - - public BakedQuad rebake() { - int[] vertexData = new int[32]; - for (int i = 0; i < 4; ++i) { - Vector3f pos = vertices[i]; - Vector2f uv = uvs[i]; - Vector2f nextUv = uvs[(i + 2) % 4]; - - int v = i * IQuadTransformer.STRIDE; - vertexData[v + IQuadTransformer.POSITION] = Float.floatToRawIntBits(pos.x()); - vertexData[v + IQuadTransformer.POSITION + 1] = Float.floatToRawIntBits(pos.y()); - vertexData[v + IQuadTransformer.POSITION + 2] = Float.floatToRawIntBits(pos.z()); - vertexData[v + IQuadTransformer.COLOR] = 0xffffffff; - vertexData[v + IQuadTransformer.UV0] = Float.floatToRawIntBits( - sprite.getU(uv.x() * 0.999f + nextUv.x() * 0.001f)); - vertexData[v + IQuadTransformer.UV0 + 1] = Float.floatToRawIntBits( - sprite.getV(uv.y() * 0.999f + nextUv.y() * 0.001f)); - vertexData[i * IQuadTransformer.STRIDE + IQuadTransformer.UV2] = LightTexture.pack(blockLight, skyLight); - } - return new BakedQuad(vertexData, tintIndex, direction, sprite, shade, ao); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java index 391a0024726..83ac4aebefc 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java @@ -1,7 +1,11 @@ package com.gregtechceu.gtceu.client.util.quad; import com.gregtechceu.gtceu.client.model.ctm.CTMCache; -import com.gregtechceu.gtceu.client.util.quad.transformers.GTQuadTransformers; +import com.gregtechceu.gtceu.client.model.ctm.ISubmap; +import com.gregtechceu.gtceu.client.model.quad.MeshBuilder; +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; +import com.gregtechceu.gtceu.client.util.TextureHelper; +import com.gregtechceu.gtceu.client.util.quad.transformers.QuadReInterpolator; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -13,56 +17,17 @@ import net.minecraftforge.client.model.IQuadTransformer; import it.unimi.dsi.fastutil.Pair; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; import org.joml.Vector3f; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.util.Objects; +import static com.gregtechceu.gtceu.client.model.quad.MutableQuadView.*; import static com.gregtechceu.gtceu.client.util.ModelEventHelper.*; public class QuadUtils { - public static Vector2f[] getQuadUVs(int[] vertices) { - Vector2f[] uvs = new Vector2f[4]; - - for (int i = 0; i < 4; i++) { - int offset = i * IQuadTransformer.STRIDE + IQuadTransformer.UV0; - float u = Float.intBitsToFloat(vertices[offset]); - float v = Float.intBitsToFloat(vertices[offset + 1]); - uvs[i] = new Vector2f(u, v); - } - return uvs; - } - - public static Vector3f[] getQuadVertices(int[] vertices) { - Vector3f[] vertPos = new Vector3f[4]; - - for (int i = 0; i < 4; i++) { - int offset = i * IQuadTransformer.STRIDE + IQuadTransformer.POSITION; - float x = Float.intBitsToFloat(vertices[offset]); - float y = Float.intBitsToFloat(vertices[offset + 1]); - float z = Float.intBitsToFloat(vertices[offset + 2]); - vertPos[i] = new Vector3f(x, y, z); - } - return vertPos; - } - - public static QuadInfo[] subdivide(BakedQuad baked) { - Vector3f[] vertPos = getQuadVertices(baked.getVertices()); - Vector2f[] uvs = getQuadUVs(baked.getVertices()); - var maxUVs = findMinMaxUVs(uvs); - QuadInfo quad = new QuadInfo(baked.getSprite(), baked.getTintIndex(), baked.getDirection(), - baked.isShade(), baked.hasAmbientOcclusion(), - vertPos, uvs, maxUVs.first(), maxUVs.second()); - - return quad.subdivide(); - } - public static Pair findMinMaxUVs(Vector2f[] uvs) { float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE, maxU = Float.MIN_VALUE, maxV = Float.MIN_VALUE; @@ -76,6 +41,21 @@ public static Pair findMinMaxUVs(Vector2f[] uvs) { return Pair.of(new Vector2f(minU, minV), new Vector2f(maxU, maxV)); } + public static int findMinUVIndex(Vector2f[] uvs) { + int minIndex = 0; + float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE; + + for (int v = 0; v < 4; v++) { + Vector2f uv = uvs[v]; + if (uv.x() <= minU && uv.y() <= minV) { + minIndex = v; + minU = uv.x(); + minV = uv.y(); + } + } + return minIndex; + } + private static void putVertexData(int[] vertices, int index, Vector3f pos, Vector2f uv) { int posOffset = index * IQuadTransformer.STRIDE + IQuadTransformer.POSITION; vertices[posOffset] = Float.floatToRawIntBits(pos.x()); @@ -96,10 +76,9 @@ public static Vector2f[] normalizeUVs(Vector2f min, Vector2f max, Vector2f... uv } public static Vector2f normalizeUV(TextureAtlasSprite sprite, Vector2f vec) { - return normalizeUV( - new Vector2f(sprite.getU0(), sprite.getU1()), - new Vector2f(sprite.getV0(), sprite.getV1()), - vec); + return new Vector2f( + Mth.inverseLerp(vec.x(), sprite.getU0(), sprite.getU1()), + Mth.inverseLerp(vec.y(), sprite.getV0(), sprite.getV1())); } public static Vector2f normalizeUV(Vector2f min, Vector2f max, Vector2f vec) { @@ -121,40 +100,146 @@ public static Vector2f relativizeUV(TextureAtlasSprite sprite, Vector2f vec) { Mth.lerp(vec.y(), sprite.getV0(), sprite.getV1())); } - public static List buildCTMQuads(List quads, BlockAndTintGetter level, BlockPos pos, - @NotNull BlockState state, @Nullable Direction side) { + public static List buildCTMQuads(BlockAndTintGetter level, BlockPos pos, BlockState state, + List quads, @Nullable Direction cullFace) { CTMCache ctmCache = CTMCache.getInstance(); - if (side != null) { - ctmCache.getSubmapIds(level, pos, state, side); + if (cullFace != null) { + ctmCache.getSubmapIds(level, pos, state, cullFace); } - return buildCTMQuads(ctmCache, quads); + return buildCTMQuads(ctmCache, quads, cullFace); } - public static List buildCTMQuads(CTMCache cachedConnections, List base) { - List result = new ArrayList<>(); + public static List buildCTMQuads(CTMCache cachedConnections, List base, + @Nullable Direction cullFace) { + MeshBuilder meshBuilder = MeshBuilder.getInstance(); + var emitter = meshBuilder.getEmitter(); + + QuadReInterpolator interpolator = new QuadReInterpolator(); + for (BakedQuad originalQuad : base) { - TextureAtlasSprite connection = CTM_SPRITE_CACHE.get(originalQuad.getSprite()); + TextureAtlasSprite sprite = originalQuad.getSprite(); + + TextureAtlasSprite connection = CTM_SPRITE_CACHE.get(sprite.contents().name()); if (connection == null) { - result.add(originalQuad); + emitter.fromVanilla(originalQuad, cullFace); + emitter.emit(); continue; } - // make sure to copy the quad here so the original model isn't mutated - BakedQuad newBQ = GTQuadTransformers.derotate().process(originalQuad); - QuadInfo[] subdivided = QuadUtils.subdivide(newBQ); int[] ctm = cachedConnections.getSubmapIndices(); - for (int j = 0; j < subdivided.length; j++) { - QuadInfo quad = subdivided[j]; - if (quad != null) { - int quadrant = quad.getNormalizedUVQuadrant(); - TextureAtlasSprite ctmSprite = ctm[quadrant] > 15 ? originalQuad.getSprite() : connection; - subdivided[j] = quad.grow().transformUVs(ctmSprite, CTMCache.uvs[ctm[quadrant]].unitScale()); - } + for (int quadrant = 0; quadrant < 4; quadrant++) { + TextureAtlasSprite ctmSprite = ctm[quadrant] > 15 ? originalQuad.getSprite() : connection; + + emitter.fromVanilla(originalQuad, cullFace); + TextureHelper.normalizeBy(emitter, sprite); + interpolator.setInputQuad(emitter); + + // slice quad into the current quadrant + subsect(emitter, CTMCache.uvs[ctm[quadrant]].unitScale()); + + interpolator.transform(emitter); + + // derotate quad here + emitter.spriteBake(ctmSprite, BAKE_LOCK_UV | BAKE_NORMALIZED); + + emitter.emit(); } - result.addAll(Arrays.stream(subdivided).filter(Objects::nonNull).map(QuadInfo::rebake).toList()); } - return result; + return meshBuilder.build().toBakedBlockQuads(); + } + + // TODO simplify, this is quite long + public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { + Vector2f[] uvs = new Vector2f[4]; + for (int i = 0; i < 4; i++) { + uvs[i] = quad.copyUv(i, uvs[i]); + } + int firstIndex = findMinUVIndex(uvs); + + Vector3f[] positions = new Vector3f[4]; + for (int i = 0; i < 4; i++) { + int idx = (firstIndex + i) % 4; + positions[i] = quad.copyPos(i, positions[idx]); + } + + Direction normal = quad.nominalFace(); + + Vector2f[] xy = new Vector2f[4]; + Vector2f[] newXy = new Vector2f[4]; + for (int i = 0; i < 4; i++) { + switch (normal.getAxis()) { + case Y -> xy[i] = new Vector2f(positions[i].x, positions[i].z); + case Z -> xy[i] = new Vector2f(positions[i].x, positions[i].y); + case X -> xy[i] = new Vector2f(positions[i].z, positions[i].y); + } + newXy[i] = new Vector2f(); + } + + if (normal.getAxis() != Direction.Axis.Y) { + submap = submap.flipY(); + } + if (normal == Direction.EAST || normal == Direction.NORTH) { + submap = submap.flipX(); + } + + submap = submap.unitScale(); + + if (normal.getAxis() == Direction.Axis.Y || normal.getAxisDirection() == Direction.AxisDirection.POSITIVE) { + // Relative X is the same sign for DOWN, UP, SOUTH, and WEST + newXy[0].x = Math.max(xy[0].x, submap.getXOffset()); // DUSW + newXy[1].x = Math.max(xy[1].x, submap.getXOffset()); // DUSW + newXy[2].x = Math.min(xy[2].x, submap.getXOffset() + submap.getWidth()); // DUSW + newXy[3].x = Math.min(xy[3].x, submap.getXOffset() + submap.getWidth()); // DUSW + } else { + // Flip relative X for NORTH and EAST + newXy[0].x = Math.min(xy[0].x, submap.getXOffset() + submap.getWidth()); // NE + newXy[1].x = Math.min(xy[1].x, submap.getXOffset() + submap.getWidth()); // NE + newXy[2].x = Math.max(xy[2].x, submap.getXOffset()); // NE + newXy[3].x = Math.max(xy[3].x, submap.getXOffset()); // NE + } + if (normal != Direction.UP) { + // Relative Y is the same sign for all but UP + newXy[0].y = Math.min(xy[0].y, submap.getYOffset() + submap.getHeight()); // DNSWE + newXy[1].y = Math.max(xy[1].y, submap.getYOffset()); // DNSWE + newXy[2].y = Math.max(xy[2].y, submap.getYOffset()); // DNSWE + newXy[3].y = Math.min(xy[3].y, submap.getYOffset() + submap.getHeight()); // DNSWE + } else { + // Flip relative Y for UP + newXy[0].y = Math.max(xy[0].y, submap.getYOffset()); // U + newXy[1].y = Math.min(xy[1].y, submap.getYOffset() + submap.getHeight()); // U + newXy[2].y = Math.min(xy[2].y, submap.getYOffset() + submap.getHeight()); // U + newXy[3].y = Math.max(xy[3].y, submap.getYOffset()); // U + } + + float u0 = normalize(xy[0].x, xy[3].x, newXy[0].x); + float v0 = normalize(xy[0].y, xy[1].y, newXy[0].y); + float u1 = normalize(xy[1].x, xy[2].x, newXy[1].x); + float v1 = normalize(xy[1].y, xy[0].y, newXy[1].y); + float u2 = normalize(xy[2].x, xy[1].x, newXy[2].x); + float v2 = normalize(xy[2].y, xy[3].y, newXy[2].y); + float u3 = normalize(xy[3].x, xy[0].x, newXy[3].x); + float v3 = normalize(xy[3].y, xy[2].y, newXy[3].y); + + quad.uv(0, Mth.lerp(uvs[0].x, uvs[3].x, u0), Mth.lerp(uvs[0].y, uvs[1].y, v0)); + quad.uv(1, Mth.lerp(uvs[1].x, uvs[2].x, u1), Mth.lerp(uvs[1].y, uvs[0].y, v1)); + quad.uv(2, Mth.lerp(uvs[2].x, uvs[1].x, u2), Mth.lerp(uvs[2].y, uvs[3].y, v2)); + quad.uv(3, Mth.lerp(uvs[3].x, uvs[0].x, u3), Mth.lerp(uvs[3].y, uvs[2].y, v3)); + + for (int i = 0; i < 4; i++) { + switch (normal.getAxis()) { + case Y -> quad.pos(i, newXy[i].x, quad.y(i), newXy[i].y); + case Z -> quad.pos(i, newXy[i].x, newXy[i].y, quad.z(i)); + case X -> quad.pos(i, quad.x(i), newXy[i].y, newXy[i].x); + } + } + + return quad; + } + + public static float normalize(float min, float max, float x) { + if (min == max) return 0.5f; + return Mth.inverseLerp(x, min, max); } } diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java index dc1620e49c1..1427a97168b 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java @@ -16,7 +16,7 @@ package com.gregtechceu.gtceu.core.mixins.client; -import com.gregtechceu.gtceu.client.util.quad.SpriteFinder; +import com.gregtechceu.gtceu.client.model.quad.SpriteFinder; import java.util.Map; From 7c941bc69fe0562496eec74d92cdd6a49e17503c Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:50:53 +0300 Subject: [PATCH 18/66] Reformat doc comments --- .../client/model/quad/MutableQuadView.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java index b65d8a45b6e..f83c03413ec 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java @@ -69,12 +69,13 @@ public abstract class MutableQuadView extends QuadView { public static final int BAKE_ROTATE_270 = 0b000011; /** - * When enabled, texture coordinate are assigned based on vertex position. Any existing UV coordinates will be - * replaced. Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + * When enabled, texture coordinates are assigned based on vertex position. + * Any existing UV coordinates will be replaced. + * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. * *

- * UV lock always derives texture coordinates based on nominal face, even when the quad is not co-planar with that - * face, and the result is the same as if the quad were projected onto the nominal face, which is usually the + * UV lock always derives texture coordinates based on nominal face, even when the quad is not co-planar + * with that face. The result is the same as if the quad were projected onto the nominal face, which is usually the * desired result. */ public static final int BAKE_LOCK_UV = 0b000100; @@ -445,13 +446,13 @@ public final MutableQuadView fromVanilla(BakedQuad quad, @Nullable Direction cul private static final float CULL_FACE_EPSILON = Mth.EPSILON; /** - * Helper method to assign vertex coordinates for a square aligned with the given face. Ensures that vertex order is - * consistent with vanilla convention. (Incorrect order can lead to bad AO lighting unless enhanced lighting logic - * is available/enabled.) + * Helper method to assign vertex coordinates for a square aligned with the given face. + * Ensures that vertex order is consistent with vanilla convention. + * (Incorrect order can lead to bad AO lighting unless enhanced lighting logic is available/enabled.) * *

- * Square will be parallel to the given face and coplanar with the face (and culled if the face is occluded) if the - * depth parameter is approximately zero. See {@link #CULL_FACE_EPSILON}. + * Square will be parallel to the given face and coplanar with the face (and culled if the face is occluded) + * if the depth parameter is approximately zero. See {@link #CULL_FACE_EPSILON}. * *

* All coordinates should be normalized (0-1). From 469b346fc12a35fa2288e5656b145c1f420ce98b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:59:22 +0300 Subject: [PATCH 19/66] Rename the "connection" metadata field to "connection_texture" --- .../gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java index f0e28744fd6..945b3df778b 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java @@ -44,7 +44,7 @@ public static class Serializer implements MetadataSectionSerializer CODEC = RecordCodecBuilder.create(instance -> instance.group( - ResourceLocation.CODEC.optionalFieldOf("connection", EMPTY_CONNECTION).forGetter(GTTextureMetadata::connectionTexture) + ResourceLocation.CODEC.optionalFieldOf("connection_texture", EMPTY_CONNECTION).forGetter(GTTextureMetadata::connectionTexture) ).apply(instance, GTTextureMetadata::new)); // spotless:on From 78a0ad7d5946c721b71018f88bf674b486956851 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:59:31 +0300 Subject: [PATCH 20/66] Fix all the resource files --- .../block/casings/cleanroom/filter_casing.png.mcmeta | 4 ++-- .../textures/block/casings/cleanroom/plascrete.png.mcmeta | 6 +++--- .../cleanroom/sterilizing_filter_casing.png.mcmeta | 4 ++-- .../casings/coils/machine_coil_cupronickel.png.mcmeta | 6 +++--- .../coils/machine_coil_cupronickel_bloom.png.mcmeta | 7 ++----- .../coils/machine_coil_cupronickel_bloom_ctm.png.mcmeta | 2 +- .../block/casings/coils/machine_coil_hssg.png.mcmeta | 4 ++-- .../casings/coils/machine_coil_hssg_bloom.png.mcmeta | 7 ++----- .../casings/coils/machine_coil_hssg_bloom_ctm.png.mcmeta | 2 +- .../block/casings/coils/machine_coil_kanthal.png.mcmeta | 4 ++-- .../casings/coils/machine_coil_kanthal_bloom.png.mcmeta | 7 ++----- .../coils/machine_coil_kanthal_bloom_ctm.png.mcmeta | 2 +- .../coils/machine_coil_molybdenum_disilicide.png.mcmeta | 4 ++-- .../machine_coil_molybdenum_disilicide_bloom.png.mcmeta | 7 ++----- ...achine_coil_molybdenum_disilicide_bloom_ctm.png.mcmeta | 2 +- .../block/casings/coils/machine_coil_naquadah.png.mcmeta | 4 ++-- .../casings/coils/machine_coil_naquadah_bloom.png.mcmeta | 7 ++----- .../coils/machine_coil_naquadah_bloom_ctm.png.mcmeta | 2 +- .../block/casings/coils/machine_coil_nichrome.png.mcmeta | 4 ++-- .../casings/coils/machine_coil_nichrome_bloom.png.mcmeta | 7 ++----- .../coils/machine_coil_nichrome_bloom_ctm.png.mcmeta | 2 +- .../block/casings/coils/machine_coil_rtm_alloy.png.mcmeta | 4 ++-- .../casings/coils/machine_coil_rtm_alloy_bloom.png.mcmeta | 7 ++----- .../coils/machine_coil_rtm_alloy_bloom_ctm.png.mcmeta | 2 +- .../casings/coils/machine_coil_superconductor.png.mcmeta | 4 ++-- .../coils/machine_coil_superconductor_bloom.png.mcmeta | 7 ++----- .../machine_coil_superconductor_bloom_ctm.png.mcmeta | 2 +- .../block/casings/coils/machine_coil_trinium.png.mcmeta | 4 ++-- .../casings/coils/machine_coil_trinium_bloom.png.mcmeta | 7 ++----- .../coils/machine_coil_trinium_bloom_ctm.png.mcmeta | 2 +- .../block/casings/coils/machine_coil_tritanium.png.mcmeta | 4 ++-- .../casings/coils/machine_coil_tritanium_bloom.png.mcmeta | 7 ++----- .../coils/machine_coil_tritanium_bloom_ctm.png.mcmeta | 2 +- .../casings/coils/machine_coil_tungstensteel.png.mcmeta | 4 ++-- .../coils/machine_coil_tungstensteel_bloom.png.mcmeta | 7 ++----- .../coils/machine_coil_tungstensteel_bloom_ctm.png.mcmeta | 2 +- .../firebox/machine_casing_firebox_bronze.png.mcmeta | 4 ++-- .../firebox/machine_casing_firebox_steel.png.mcmeta | 4 ++-- .../firebox/machine_casing_firebox_titanium.png.mcmeta | 4 ++-- .../machine_casing_firebox_tungstensteel.png.mcmeta | 4 ++-- .../block/casings/fusion/fusion_casing.png.mcmeta | 4 ++-- .../block/casings/fusion/fusion_casing_bloom.png.mcmeta | 7 ++----- .../block/casings/fusion/fusion_casing_mk2.png.mcmeta | 4 ++-- .../block/casings/fusion/fusion_casing_mk3.png.mcmeta | 4 ++-- .../block/casings/fusion/superconducting_coil.png.mcmeta | 4 ++-- .../casings/fusion/superconducting_coil_bloom.png.mcmeta | 7 ++----- .../fusion/superconducting_coil_bloom_ctm.png.mcmeta | 2 +- .../textures/block/casings/gcym/atomic_casing.png.mcmeta | 4 ++-- .../block/casings/gcym/corrosion_proof_casing.png.mcmeta | 4 ++-- .../gcym/high_temperature_smelting_casing.png.mcmeta | 4 ++-- .../block/casings/gcym/industrial_steam_casing.png.mcmeta | 4 ++-- .../casings/gcym/large_scale_assembling_casing.png.mcmeta | 4 ++-- .../casings/gcym/laser_safe_engraving_casing.png.mcmeta | 4 ++-- .../block/casings/gcym/nonconducting_casing.png.mcmeta | 4 ++-- .../casings/gcym/reaction_safe_mixing_casing.png.mcmeta | 4 ++-- .../casings/gcym/secure_maceration_casing.png.mcmeta | 4 ++-- .../casings/gcym/shock_proof_cutting_casing.png.mcmeta | 4 ++-- .../textures/block/casings/gcym/sifter_casing.png.mcmeta | 4 ++-- .../block/casings/gcym/stress_proof_casing.png.mcmeta | 4 ++-- .../block/casings/gcym/vibration_safe_casing.png.mcmeta | 4 ++-- .../block/casings/gcym/watertight_casing.png.mcmeta | 4 ++-- .../casings/hpca/advanced_computer_casing/back.png.mcmeta | 4 ++-- .../hpca/advanced_computer_casing/bottom.png.mcmeta | 4 ++-- .../hpca/advanced_computer_casing/front.png.mcmeta | 4 ++-- .../casings/hpca/advanced_computer_casing/side.png.mcmeta | 4 ++-- .../casings/hpca/advanced_computer_casing/top.png.mcmeta | 4 ++-- .../block/casings/hpca/computer_casing/back.png.mcmeta | 4 ++-- .../block/casings/hpca/computer_casing/bottom.png.mcmeta | 4 ++-- .../block/casings/hpca/computer_casing/front.png.mcmeta | 4 ++-- .../block/casings/hpca/computer_casing/side.png.mcmeta | 4 ++-- .../block/casings/hpca/computer_casing/top.png.mcmeta | 4 ++-- .../block/casings/hpca/computer_heat_vent_side.png.mcmeta | 4 ++-- .../casings/hpca/computer_heat_vent_top_bot.png.mcmeta | 4 ++-- .../block/casings/hpca/high_power_casing.png.mcmeta | 4 ++-- .../machine_casing_assembly_line_bloom.png.mcmeta | 5 +---- .../machine_casing_turbine_stainless_steel.png.mcmeta | 4 ++-- .../mechanic/machine_casing_turbine_steel.png.mcmeta | 4 ++-- .../mechanic/machine_casing_turbine_titanium.png.mcmeta | 4 ++-- .../machine_casing_turbine_tungstensteel.png.mcmeta | 4 ++-- .../casings/signs/machine_casing_stripes_a.png.mcmeta | 4 ++-- .../casings/signs/machine_casing_stripes_b.png.mcmeta | 4 ++-- .../casings/signs/machine_casing_stripes_c.png.mcmeta | 4 ++-- .../casings/signs/machine_casing_stripes_d.png.mcmeta | 4 ++-- .../block/casings/slicing_blades/bottom.png.mcmeta | 4 ++-- .../textures/block/casings/slicing_blades/side.png.mcmeta | 4 ++-- .../textures/block/casings/slicing_blades/top.png.mcmeta | 4 ++-- .../solid/machine_casing_bronze_plated_bricks.png.mcmeta | 4 ++-- .../solid/machine_casing_clean_stainless_steel.png.mcmeta | 4 ++-- .../casings/solid/machine_casing_frost_proof.png.mcmeta | 4 ++-- .../casings/solid/machine_casing_heatproof.png.mcmeta | 4 ++-- .../casings/solid/machine_casing_inert_ptfe.png.mcmeta | 4 ++-- .../solid/machine_casing_palladium_substation.png.mcmeta | 4 ++-- .../solid/machine_casing_robust_tungstensteel.png.mcmeta | 4 ++-- .../casings/solid/machine_casing_solid_steel.png.mcmeta | 4 ++-- .../solid/machine_casing_stable_titanium.png.mcmeta | 4 ++-- .../solid/machine_casing_stainless_evaporation.png.mcmeta | 4 ++-- .../casings/solid/machine_casing_sturdy_hsse.png.mcmeta | 4 ++-- .../solid/machine_casing_sturdy_hsse_green.png.mcmeta | 4 ++-- .../block/casings/transparent/cleanroom_glass.png.mcmeta | 4 ++-- .../block/casings/transparent/fusion_glass.png.mcmeta | 4 ++-- .../block/casings/transparent/laminated_glass.png.mcmeta | 4 ++-- .../block/casings/transparent/tempered_glass.png.mcmeta | 4 ++-- .../block/casings/unique/crushing_wheels.png.mcmeta | 4 ++-- .../casings/unique/crushing_wheels_active.png.mcmeta | 4 ++-- .../block/casings/unique/heat_vent_bloom.png.mcmeta | 2 +- .../block/casings/unique/slicing_blades.png.mcmeta | 4 ++-- .../block/casings/unique/slicing_blades_active.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/black.png.mcmeta | 4 ++-- .../block/lamps/black_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/black_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/black_emissive.png.mcmeta | 8 +++----- .../gtceu/textures/block/lamps/black_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/blue.png.mcmeta | 4 ++-- .../block/lamps/blue_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/blue_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/blue_emissive.png.mcmeta | 6 ++---- .../assets/gtceu/textures/block/lamps/blue_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/brown.png.mcmeta | 4 ++-- .../block/lamps/brown_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/brown_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/brown_emissive.png.mcmeta | 6 ++---- .../gtceu/textures/block/lamps/brown_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/cyan.png.mcmeta | 4 ++-- .../block/lamps/cyan_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/cyan_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/cyan_emissive.png.mcmeta | 6 ++---- .../assets/gtceu/textures/block/lamps/cyan_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/gray.png.mcmeta | 4 ++-- .../block/lamps/gray_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/gray_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/gray_emissive.png.mcmeta | 6 ++---- .../assets/gtceu/textures/block/lamps/gray_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/green.png.mcmeta | 4 ++-- .../block/lamps/green_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/green_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/green_emissive.png.mcmeta | 6 ++---- .../gtceu/textures/block/lamps/green_off.png.mcmeta | 4 ++-- .../gtceu/textures/block/lamps/light_blue.png.mcmeta | 4 ++-- .../block/lamps/light_blue_borderless_emissive.png.mcmeta | 2 +- .../block/lamps/light_blue_ctm_emissive.png.mcmeta | 2 +- .../textures/block/lamps/light_blue_emissive.png.mcmeta | 6 ++---- .../gtceu/textures/block/lamps/light_blue_off.png.mcmeta | 4 ++-- .../gtceu/textures/block/lamps/light_gray.png.mcmeta | 4 ++-- .../block/lamps/light_gray_borderless_emissive.png.mcmeta | 2 +- .../block/lamps/light_gray_ctm_emissive.png.mcmeta | 2 +- .../textures/block/lamps/light_gray_emissive.png.mcmeta | 6 ++---- .../gtceu/textures/block/lamps/light_gray_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/lime.png.mcmeta | 4 ++-- .../block/lamps/lime_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/lime_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/lime_emissive.png.mcmeta | 6 ++---- .../assets/gtceu/textures/block/lamps/lime_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/magenta.png.mcmeta | 4 ++-- .../block/lamps/magenta_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/magenta_ctm_emissive.png.mcmeta | 2 +- .../textures/block/lamps/magenta_emissive.png.mcmeta | 6 ++---- .../gtceu/textures/block/lamps/magenta_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/orange.png.mcmeta | 4 ++-- .../block/lamps/orange_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/orange_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/orange_emissive.png.mcmeta | 6 ++---- .../gtceu/textures/block/lamps/orange_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/pink.png.mcmeta | 4 ++-- .../block/lamps/pink_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/pink_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/pink_emissive.png.mcmeta | 6 ++---- .../assets/gtceu/textures/block/lamps/pink_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/purple.png.mcmeta | 4 ++-- .../block/lamps/purple_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/purple_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/purple_emissive.png.mcmeta | 6 ++---- .../gtceu/textures/block/lamps/purple_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/red.png.mcmeta | 4 ++-- .../block/lamps/red_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/red_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/red_emissive.png.mcmeta | 6 ++---- .../assets/gtceu/textures/block/lamps/red_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/white.png.mcmeta | 4 ++-- .../block/lamps/white_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/white_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/white_emissive.png.mcmeta | 6 ++---- .../gtceu/textures/block/lamps/white_off.png.mcmeta | 4 ++-- .../assets/gtceu/textures/block/lamps/yellow.png.mcmeta | 4 ++-- .../block/lamps/yellow_borderless_emissive.png.mcmeta | 2 +- .../textures/block/lamps/yellow_ctm_emissive.png.mcmeta | 2 +- .../gtceu/textures/block/lamps/yellow_emissive.png.mcmeta | 6 ++---- .../gtceu/textures/block/lamps/yellow_off.png.mcmeta | 4 ++-- .../block/overlay/machine/overlay_monitor.png.mcmeta | 4 ++-- .../block/pipe/ld_fluid_pipe/overlay_emissive.png.mcmeta | 5 +---- .../block/pipe/ld_item_pipe/overlay_emissive.png.mcmeta | 5 +---- 190 files changed, 335 insertions(+), 415 deletions(-) diff --git a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/filter_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/filter_casing.png.mcmeta index 679654e7450..197e174c743 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/filter_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/filter_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/cleanroom/filter_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/cleanroom/filter_casing_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/plascrete.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/plascrete.png.mcmeta index 0b6135d2c98..bcfe132b2ef 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/plascrete.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/plascrete.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/cleanroom/plascrete_ctm" - } + "gtceu": { + "connection_texture": "gtceu:block/casings/cleanroom/plascrete_ctm" + } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/sterilizing_filter_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/sterilizing_filter_casing.png.mcmeta index 0e1b3e83e63..bb26602ecf7 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/sterilizing_filter_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/sterilizing_filter_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/cleanroom/sterilizing_filter_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/cleanroom/sterilizing_filter_casing_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel.png.mcmeta index d611cacb4ef..78607c6ca08 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_cupronickel_ctm" - } + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_cupronickel_ctm" + } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom.png.mcmeta index b1e5096ccb5..419344f2357 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_cupronickel_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_cupronickel_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg.png.mcmeta index d0eb5a1b4e0..2f8b0f3c606 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_hssg_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_hssg_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom.png.mcmeta index a3d39d70b26..7007fd7d399 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_hssg_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_hssg_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal.png.mcmeta index a543d938427..7323ad0e179 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_kanthal_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_kanthal_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom.png.mcmeta index 5f77e5af023..369076e1f9d 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_kanthal_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_kanthal_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide.png.mcmeta index cdf115622d5..ee713eaaf40 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_molybdenum_disilicide_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_molybdenum_disilicide_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom.png.mcmeta index e5d9efbf204..15eded51a94 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah.png.mcmeta index 2e4b0f7663e..8d778222e5f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_naquadah_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_naquadah_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom.png.mcmeta index 89be208adcf..4e7c10b2cff 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_naquadah_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_naquadah_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome.png.mcmeta index 4ea55aec150..b769004afbd 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_nichrome_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_nichrome_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom.png.mcmeta index d454af3ff67..8afaa449311 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_nichrome_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_nichrome_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy.png.mcmeta index 746da5c90c5..6b2870c83a6 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_rtm_alloy_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_rtm_alloy_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom.png.mcmeta index 527eb9bb051..6d09c673e6f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_rtm_alloy_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_rtm_alloy_bloom_ctm", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor.png.mcmeta index 5e76601ac3e..a604c36f15e 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_superconductor_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_superconductor_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom.png.mcmeta index 2f5edd2ed74..824306dde04 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_superconductor_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_superconductor_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium.png.mcmeta index 6ae83eb0551..17e24d0d0f3 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_trinium_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_trinium_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom.png.mcmeta index 0d93c95e458..75e5e226e1f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_trinium_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_trinium_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium.png.mcmeta index 49409f48da5..76d31028072 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_tritanium_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_tritanium_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom.png.mcmeta index 1aa566dca58..5153271f7ba 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_tritanium_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_tritanium_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel.png.mcmeta index 274e5147e1d..66a136186c5 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_tungstensteel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_tungstensteel_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom.png.mcmeta index 11a9a3bcd34..df8fd23d60c 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_tungstensteel_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_tungstensteel_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_bronze.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_bronze.png.mcmeta index 618e068e4dd..653afb29006 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_bronze.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_bronze.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/firebox/machine_casing_firebox_bronze_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/firebox/machine_casing_firebox_bronze_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_steel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_steel.png.mcmeta index f07082f52f5..f120eaf9032 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_steel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_steel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/firebox/machine_casing_firebox_steel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/firebox/machine_casing_firebox_steel_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_titanium.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_titanium.png.mcmeta index 06e9796abed..afe2869054b 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_titanium.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_titanium.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/firebox/machine_casing_firebox_titanium_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/firebox/machine_casing_firebox_titanium_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_tungstensteel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_tungstensteel.png.mcmeta index fdd57cb4a7a..6ee0e5eb3d5 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_tungstensteel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_tungstensteel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/firebox/machine_casing_firebox_tungstensteel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/firebox/machine_casing_firebox_tungstensteel_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing.png.mcmeta index 60ef8c970be..42c81b1632c 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/fusion/fusion_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/fusion/fusion_casing_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_bloom.png.mcmeta index d63d26a280c..72d1a0104b4 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/fusion/fusion_casing_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/fusion/fusion_casing_bloom_ctm", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk2.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk2.png.mcmeta index 266021414e4..f8063da866f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk2.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk2.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/fusion/fusion_casing_mk2_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/fusion/fusion_casing_mk2_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk3.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk3.png.mcmeta index 8b45a91c06a..4fd16130b5c 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk3.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk3.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/fusion/fusion_casing_mk3_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/fusion/fusion_casing_mk3_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil.png.mcmeta index 0efbe8cd43c..e8fd0abfc97 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/fusion/superconducting_coil_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/fusion/superconducting_coil_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom.png.mcmeta index 2f5edd2ed74..824306dde04 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_superconductor_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_superconductor_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom_ctm.png.mcmeta index e333118814e..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/atomic_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/atomic_casing.png.mcmeta index ec7ee024889..4e544655bb0 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/atomic_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/atomic_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/atomic_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/atomic_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/corrosion_proof_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/corrosion_proof_casing.png.mcmeta index c5ad2294e42..34dd301c21d 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/corrosion_proof_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/corrosion_proof_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/corrosion_proof_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/corrosion_proof_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/high_temperature_smelting_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/high_temperature_smelting_casing.png.mcmeta index 2457291b40f..c5fa362c0f9 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/high_temperature_smelting_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/high_temperature_smelting_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/high_temperature_smelting_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/high_temperature_smelting_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/industrial_steam_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/industrial_steam_casing.png.mcmeta index 0f942a68354..cebb04f9e44 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/industrial_steam_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/industrial_steam_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/industrial_steam_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/industrial_steam_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/large_scale_assembling_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/large_scale_assembling_casing.png.mcmeta index 306854983f3..67a616a6316 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/large_scale_assembling_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/large_scale_assembling_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/large_scale_assembling_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/large_scale_assembling_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/laser_safe_engraving_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/laser_safe_engraving_casing.png.mcmeta index df8cb84ff6f..24476332093 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/laser_safe_engraving_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/laser_safe_engraving_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/laser_safe_engraving_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/laser_safe_engraving_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/nonconducting_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/nonconducting_casing.png.mcmeta index eafb895c281..1e3827124a1 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/nonconducting_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/nonconducting_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/nonconducting_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/nonconducting_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/reaction_safe_mixing_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/reaction_safe_mixing_casing.png.mcmeta index ae09e8eb280..5b62e5ce35d 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/reaction_safe_mixing_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/reaction_safe_mixing_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/reaction_safe_mixing_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/reaction_safe_mixing_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/secure_maceration_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/secure_maceration_casing.png.mcmeta index 3768093e52a..f6ec7e514b4 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/secure_maceration_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/secure_maceration_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/secure_maceration_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/secure_maceration_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/shock_proof_cutting_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/shock_proof_cutting_casing.png.mcmeta index cf058736156..b13d57a26f7 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/shock_proof_cutting_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/shock_proof_cutting_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/shock_proof_cutting_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/shock_proof_cutting_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/sifter_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/sifter_casing.png.mcmeta index 58804a3f988..f3cd3b2d23c 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/sifter_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/sifter_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/sifter_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/sifter_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/stress_proof_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/stress_proof_casing.png.mcmeta index 19fb6ad2f8f..bf95820d5b5 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/stress_proof_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/stress_proof_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/stress_proof_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/stress_proof_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/vibration_safe_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/vibration_safe_casing.png.mcmeta index 20efcbc319f..1e13a18a0da 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/vibration_safe_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/vibration_safe_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/vibration_safe_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/vibration_safe_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/watertight_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/watertight_casing.png.mcmeta index 4a3033b0362..01c2c216764 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/watertight_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/watertight_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/watertight_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/watertight_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/back.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/back.png.mcmeta index 42e07d2dea7..184b499a8ba 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/back.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/back.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/advanced_computer_casing/back_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/advanced_computer_casing/back_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/bottom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/bottom.png.mcmeta index 8c187a0684a..8cd3c5a5935 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/bottom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/bottom.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/advanced_computer_casing/bottom_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/advanced_computer_casing/bottom_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/front.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/front.png.mcmeta index c57c972dc1c..5f54ab8dbe8 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/front.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/front.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/advanced_computer_casing/front_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/advanced_computer_casing/front_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/side.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/side.png.mcmeta index 961092b3f9e..7435e5af674 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/side.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/side.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/advanced_computer_casing/side_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/advanced_computer_casing/side_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/top.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/top.png.mcmeta index 7e23f5cded5..693c691f8d1 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/top.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/top.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/advanced_computer_casing/top_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/advanced_computer_casing/top_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/back.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/back.png.mcmeta index 5878953ae0d..6e6e8c6bb63 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/back.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/back.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_casing/back_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_casing/back_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/bottom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/bottom.png.mcmeta index 9fb2a643fdb..eddb4850067 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/bottom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/bottom.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_casing/bottom_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_casing/bottom_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/front.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/front.png.mcmeta index 303678ceb2d..ab496cd7ff0 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/front.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/front.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_casing/front_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_casing/front_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/side.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/side.png.mcmeta index cc1c5d48c57..7ad5ef7f1ea 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/side.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/side.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_casing/side_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_casing/side_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/top.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/top.png.mcmeta index d4805c14851..e5d8d808ff4 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/top.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/top.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_casing/top_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_casing/top_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_side.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_side.png.mcmeta index c50ce958d8a..714dd86272f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_side.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_side.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_heat_vent_side_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_heat_vent_side_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_top_bot.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_top_bot.png.mcmeta index f41eea02b1d..a5dbe2bc9c0 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_top_bot.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_top_bot.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_heat_vent_top_bot_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_heat_vent_top_bot_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/high_power_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/high_power_casing.png.mcmeta index 787770c3abd..07dec6c8212 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/high_power_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/high_power_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/high_power_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/high_power_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_assembly_line_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_assembly_line_bloom.png.mcmeta index f2e939b3527..a3edcb551d9 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_assembly_line_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_assembly_line_bloom.png.mcmeta @@ -2,10 +2,7 @@ "animation":{ "frametime":2 }, - "ldlib": { - "emissive": true - }, - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_stainless_steel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_stainless_steel.png.mcmeta index aa9b988334d..5e2dd444e27 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_stainless_steel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_stainless_steel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/mechanic/machine_casing_turbine_stainless_steel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/mechanic/machine_casing_turbine_stainless_steel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_steel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_steel.png.mcmeta index a7fd421b3b3..72c1a53ba16 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_steel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_steel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/mechanic/machine_casing_turbine_steel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/mechanic/machine_casing_turbine_steel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_titanium.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_titanium.png.mcmeta index 728b371f290..a79cc793f76 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_titanium.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_titanium.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/mechanic/machine_casing_turbine_titanium_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/mechanic/machine_casing_turbine_titanium_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_tungstensteel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_tungstensteel.png.mcmeta index 4a128ac164e..d23695359ad 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_tungstensteel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_tungstensteel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/mechanic/machine_casing_turbine_tungstensteel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/mechanic/machine_casing_turbine_tungstensteel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_a.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_a.png.mcmeta index 7e7c3fcc388..edb2af3afa7 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_a.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_a.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/signs/machine_casing_stripes_a_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/signs/machine_casing_stripes_a_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_b.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_b.png.mcmeta index 41f9c4fca66..1e4a835fdfd 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_b.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_b.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/signs/machine_casing_stripes_b_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/signs/machine_casing_stripes_b_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_c.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_c.png.mcmeta index 24ae068cdf3..58c74e507cf 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_c.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_c.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/signs/machine_casing_stripes_c_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/signs/machine_casing_stripes_c_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_d.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_d.png.mcmeta index be0c3b09523..31d57035871 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_d.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_d.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/signs/machine_casing_stripes_d_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/signs/machine_casing_stripes_d_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/bottom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/bottom.png.mcmeta index 752d89be69b..27d8682d91a 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/bottom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/bottom.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/slicing_blades/bottom_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/slicing_blades/bottom_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/side.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/side.png.mcmeta index 2e013feb3a1..92fe24d573a 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/side.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/side.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/slicing_blades/side_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/slicing_blades/side_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/top.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/top.png.mcmeta index fe5e643f07c..7716663f87c 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/top.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/top.png.mcmeta @@ -1,6 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/slicing_blades/top_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/slicing_blades/top_ctm" }, "animation": { "interpolate": false, diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_bronze_plated_bricks.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_bronze_plated_bricks.png.mcmeta index 84d6ac55955..f7bc18370f4 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_bronze_plated_bricks.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_bronze_plated_bricks.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_bronze_plated_bricks_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_bronze_plated_bricks_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_clean_stainless_steel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_clean_stainless_steel.png.mcmeta index 87b382c8442..37fdc7ef59f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_clean_stainless_steel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_clean_stainless_steel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_clean_stainless_steel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_clean_stainless_steel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_frost_proof.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_frost_proof.png.mcmeta index 06e68458b87..063daa7f6df 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_frost_proof.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_frost_proof.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_frost_proof_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_frost_proof_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_heatproof.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_heatproof.png.mcmeta index 46a7987cfed..6a69dafbaed 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_heatproof.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_heatproof.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_heatproof_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_heatproof_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_inert_ptfe.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_inert_ptfe.png.mcmeta index df90ab84c03..af024fa07e3 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_inert_ptfe.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_inert_ptfe.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_inert_ptfe_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_inert_ptfe_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_palladium_substation.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_palladium_substation.png.mcmeta index 7cdf09342f4..6960d04e965 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_palladium_substation.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_palladium_substation.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_palladium_substation_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_palladium_substation_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_robust_tungstensteel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_robust_tungstensteel.png.mcmeta index 854f8df3dbe..1a2b15bb41b 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_robust_tungstensteel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_robust_tungstensteel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_robust_tungstensteel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_robust_tungstensteel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_solid_steel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_solid_steel.png.mcmeta index 12cc1053c71..ad374a7d98d 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_solid_steel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_solid_steel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_solid_steel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_solid_steel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stable_titanium.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stable_titanium.png.mcmeta index 97014a06a14..bb8fdf80156 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stable_titanium.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stable_titanium.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_stable_titanium_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_stable_titanium_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stainless_evaporation.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stainless_evaporation.png.mcmeta index 53b118fbefe..e5b5ae4c3e4 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stainless_evaporation.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stainless_evaporation.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_stainless_evaporation_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_stainless_evaporation_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse.png.mcmeta index 225285146b7..6299e80252e 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_sturdy_hsse_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_sturdy_hsse_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse_green.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse_green.png.mcmeta index 225285146b7..6299e80252e 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse_green.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse_green.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_sturdy_hsse_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_sturdy_hsse_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/transparent/cleanroom_glass.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/transparent/cleanroom_glass.png.mcmeta index 4e88ec7cc0c..26a4910f29a 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/transparent/cleanroom_glass.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/transparent/cleanroom_glass.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/transparent/cleanroom_glass_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/transparent/cleanroom_glass_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/transparent/fusion_glass.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/transparent/fusion_glass.png.mcmeta index d193e57fef1..6264f382525 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/transparent/fusion_glass.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/transparent/fusion_glass.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/transparent/fusion_glass_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/transparent/fusion_glass_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/transparent/laminated_glass.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/transparent/laminated_glass.png.mcmeta index 0a0ee21c685..b4319b49730 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/transparent/laminated_glass.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/transparent/laminated_glass.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/transparent/laminated_glass_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/transparent/laminated_glass_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/transparent/tempered_glass.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/transparent/tempered_glass.png.mcmeta index 502bb849399..ff94fb81b10 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/transparent/tempered_glass.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/transparent/tempered_glass.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/transparent/tempered_glass_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/transparent/tempered_glass_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels.png.mcmeta index 17b629c309c..71c9206ffbd 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/unique/crushing_wheels_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/unique/crushing_wheels_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels_active.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels_active.png.mcmeta index cbe1abf13b7..b4a2ed95093 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels_active.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels_active.png.mcmeta @@ -1,6 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/unique/crushing_wheels_active_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/unique/crushing_wheels_active_ctm" }, "animation": { "interpolate": false, diff --git a/src/main/resources/assets/gtceu/textures/block/casings/unique/heat_vent_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/unique/heat_vent_bloom.png.mcmeta index 89d89e9d079..8d624c1275a 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/unique/heat_vent_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/unique/heat_vent_bloom.png.mcmeta @@ -2,7 +2,7 @@ "animation": { "frametime": 1 }, - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades.png.mcmeta index 39765a1c5d6..60a0eb8b058 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/unique/slicing_blades_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/unique/slicing_blades_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades_active.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades_active.png.mcmeta index 1440c3a3821..721f4cb651e 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades_active.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades_active.png.mcmeta @@ -1,6 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/unique/slicing_blades_active_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/unique/slicing_blades_active_ctm" }, "animation": { "interpolate": false, diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black.png.mcmeta index 8f14d9b9cb1..61780d9adbf 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black.png.mcmeta @@ -1,6 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/black_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/black_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_emissive.png.mcmeta index 986fc3c4b9b..a11349bfaee 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_emissive.png.mcmeta @@ -1,9 +1,7 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/black_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/black_ctm_emissive", "bloom": true - } + }, } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_off.png.mcmeta index 077f1b444bc..b3ef78b25d4 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/black_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/black_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue.png.mcmeta index b2d32fbdde0..add4878dcad 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/blue_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/blue_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue_emissive.png.mcmeta index 6c7c62e8adb..8fe261e2931 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/blue_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/blue_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue_off.png.mcmeta index 6692caee337..d006e50c70d 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/blue_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/blue_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown.png.mcmeta index 10bc639e0fc..79c45dc0aa2 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/brown_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/brown_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown_emissive.png.mcmeta index 5716c714030..19d59029d1a 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/brown_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/brown_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown_off.png.mcmeta index f222ed9e8ac..bee93308f69 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/brown_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/brown_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan.png.mcmeta index c0f13e9c0bf..6adda24f923 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/cyan_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/cyan_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_emissive.png.mcmeta index b1725e83fa5..dd41b557d46 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/cyan_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/cyan_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_off.png.mcmeta index 0e6b73d84f3..8ae56b50cc3 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/cyan_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/cyan_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray.png.mcmeta index 4cc28d73d35..a9e458cb136 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/gray_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/gray_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray_emissive.png.mcmeta index c55ae8fc192..5c7197a78e7 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/gray_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/gray_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray_off.png.mcmeta index 1bf1376070e..e299f580208 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/gray_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/gray_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green.png.mcmeta index 8c0cb78a3db..84fb000f84d 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/green_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/green_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green_emissive.png.mcmeta index 61c740ca6c9..c04d90f7125 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/green_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/green_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green_off.png.mcmeta index 183ef8c6ac6..ede85c6111e 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/green_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/green_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue.png.mcmeta index 7be5820dc99..f1db0ef3cdf 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_blue_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_blue_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_emissive.png.mcmeta index 3c37363340e..056eeb31a66 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_blue_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_blue_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_off.png.mcmeta index 36da8684b59..55f47d21dc1 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_blue_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_blue_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray.png.mcmeta index d9f02a1f1eb..08256dfb955 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_gray_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_gray_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_emissive.png.mcmeta index f198565e7c6..70ecdc41c1f 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_gray_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_gray_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_off.png.mcmeta index 74f9b7d0d2e..3729e392d0e 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_gray_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_gray_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime.png.mcmeta index c1576b94772..83f4bcca823 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/lime_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/lime_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime_emissive.png.mcmeta index 2eddeede772..d4860e9edd5 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/lime_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/lime_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime_off.png.mcmeta index 3ece38171e2..531de7d0542 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/lime_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/lime_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta.png.mcmeta index 8296eb3a51b..6e1b63fa26a 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/magenta_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/magenta_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_emissive.png.mcmeta index bbcbde7bc8b..654ce71902d 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/magenta_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/magenta_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_off.png.mcmeta index c5d19b0dac8..8dcee76d766 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/magenta_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/magenta_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange.png.mcmeta index 53fdb4a15cd..31d40f12d08 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/orange_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/orange_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange_emissive.png.mcmeta index 6bd561037cd..6c91be41e02 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/orange_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/orange_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange_off.png.mcmeta index 2d87bf7df39..13159c135bd 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/orange_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/orange_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink.png.mcmeta index 37808e80592..bc114052df6 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/pink_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/pink_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink_emissive.png.mcmeta index 8ca9c17de14..6570ddd3cd5 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/pink_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/pink_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink_off.png.mcmeta index 7894d02278d..edca1be5376 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/pink_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/pink_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple.png.mcmeta index 121eed221ea..d878709d313 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/purple_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/purple_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple_emissive.png.mcmeta index 8c82cc421b1..ab8cea0ade7 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/purple_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/purple_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple_off.png.mcmeta index e912715ff62..d0c0c0d235a 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/purple_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/purple_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red.png.mcmeta index b0bef295adf..c77b242bec0 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/red_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/red_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red_emissive.png.mcmeta index 71f134efd0c..e1a9f28bbd0 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/red_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/red_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red_off.png.mcmeta index d9f98de71da..561e150e04e 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/red_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/red_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white.png.mcmeta index d21e74fd68e..88d612ca4a7 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/white_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/white_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white_emissive.png.mcmeta index 5b460863ca0..c2c53c6c68d 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/white_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/white_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white_off.png.mcmeta index 8defbca3800..793551b1f47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/white_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/white_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow.png.mcmeta index 92cd97707cd..dae5b12c102 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/yellow_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/yellow_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_ctm_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_ctm_emissive.png.mcmeta index 4da3f5f1299..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_ctm_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_ctm_emissive.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_emissive.png.mcmeta index 4e0110c9e7c..01f8f09342c 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_emissive.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/yellow_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/yellow_ctm_emissive", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_off.png.mcmeta index 160ab566143..dc463f4a85e 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/yellow_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/yellow_off_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/overlay/machine/overlay_monitor.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/overlay/machine/overlay_monitor.png.mcmeta index 38c2c75c408..deb8a6cb565 100644 --- a/src/main/resources/assets/gtceu/textures/block/overlay/machine/overlay_monitor.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/overlay/machine/overlay_monitor.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/overlay/machine/overlay_monitor_ctm" + "gtceu": { + "connection_texture": "gtceu:block/overlay/machine/overlay_monitor_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/pipe/ld_fluid_pipe/overlay_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/pipe/ld_fluid_pipe/overlay_emissive.png.mcmeta index 53a9815890b..352db4d3be4 100644 --- a/src/main/resources/assets/gtceu/textures/block/pipe/ld_fluid_pipe/overlay_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/pipe/ld_fluid_pipe/overlay_emissive.png.mcmeta @@ -1,8 +1,5 @@ { - "ldlib": { - "emissive": true - }, - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/pipe/ld_item_pipe/overlay_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/pipe/ld_item_pipe/overlay_emissive.png.mcmeta index 53a9815890b..352db4d3be4 100644 --- a/src/main/resources/assets/gtceu/textures/block/pipe/ld_item_pipe/overlay_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/pipe/ld_item_pipe/overlay_emissive.png.mcmeta @@ -1,8 +1,5 @@ { - "ldlib": { - "emissive": true - }, - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file From df0c06bfdae23d783c2d15f40ea485728208146b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 21:58:05 +0300 Subject: [PATCH 21/66] spotless --- .../gtceu/client/model/ctm/CTMCache.java | 28 ++++--- .../client/model/ctm/ConnectionCheck.java | 53 ++++++------ .../client/model/ctm/GTTextureMetadata.java | 3 +- .../gtceu/client/model/ctm/ISubmap.java | 28 ++++--- .../model/ctm/OctagonalOrientation.java | 83 ++++++++++--------- .../gtceu/client/model/ctm/Submap.java | 56 +++++++------ .../client/model/machine/MachineModel.java | 2 +- .../client/model/quad/EncodingFormat.java | 9 +- .../gtceu/client/model/quad/Mesh.java | 1 + .../gtceu/client/model/quad/MeshBuilder.java | 5 +- .../client/model/quad/MutableQuadView.java | 22 ++--- .../gtceu/client/model/quad/QuadView.java | 31 ++++--- .../gtceu/client/model/quad/SpriteFinder.java | 23 +++-- .../model/quad/transform/QuadTransform.java | 3 +- .../renderer/cover/FacadeCoverRenderer.java | 6 +- .../renderer/cover/IOCoverRenderer.java | 2 +- .../renderer/cover/SimpleCoverRenderer.java | 2 +- .../gtceu/client/util/TextureHelper.java | 6 +- .../client/util/TextureMetadataHelper.java | 6 +- .../client/util/quad/GeometryHelper.java | 24 +++--- .../transformers/InterpolationHelper.java | 3 +- .../util/quad/transformers/QuadClamper.java | 3 +- .../quad/transformers/QuadCornerKicker.java | 25 +++--- .../quad/transformers/QuadReInterpolator.java | 4 +- .../util/quad/transformers/QuadTinter.java | 3 +- .../common/data/models/GTMachineModels.java | 3 +- .../gtceu/common/item/LampBlockItem.java | 6 +- .../mixins/client/ModelBakerImplMixin.java | 2 +- .../core/mixins/client/TextureAtlasMixin.java | 14 ++-- 29 files changed, 232 insertions(+), 224 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index fd0733ae276..36ab302626e 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -1,22 +1,22 @@ /* * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). - * Copyright (c) 2023 Chisel Team. - + * Copyright (c) 2023 Chisel Team. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - + * * ConnectedTexturesMod is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * * You should have received a copy of the GNU General Public License along * with ConnectedTexturesMod; if not, If not, see . */ - package com.gregtechceu.gtceu.client.model.ctm; + import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.BlockAndTintGetter; @@ -139,7 +139,6 @@ public interface StateComparisonCallback { protected byte connectionMap; protected int[] submapCache = defaultSubmapCache.clone(); - public static CTMCache getInstance() { return new CTMCache(); } @@ -192,7 +191,7 @@ public void buildConnectionMap(BlockAndTintGetter world, BlockPos pos, BlockStat // TODO this naive check doesn't work for models that have unculled faces. // Perhaps a smarter optimization could be done eventually? for (OctagonalOrientation dir : OctagonalOrientation.VALUES) { - //Note: We can't cache the state that we are checking about connection for as we want to ensure that + // Note: We can't cache the state that we are checking about connection for as we want to ensure that // we can take into account the side of the block we want to know the "state" of as if the block is // a facade of some sort it might return different results based on where it is being queried from setConnectedState(dir, dir.isConnected(this.connectionCheck, world, pos, state, side)); @@ -210,7 +209,8 @@ protected void fillSubmaps(int idx) { // This is a bit magic-y, but basically the array is ordered so // the first dir requires an offset of 2, and the second dir requires an offset of 8 // plus the initial offset for the corner. - this.submapCache[idx] = submapOffsets[idx] + (connected(dirs[0]) ? 2 : 0) + (connected(dirs[1]) ? 8 : 0); + this.submapCache[idx] = submapOffsets[idx] + (connected(dirs[0]) ? 2 : 0) + + (connected(dirs[1]) ? 8 : 0); } } } @@ -226,8 +226,9 @@ public boolean connected(OctagonalOrientation dir) { /** * @param dirs - * The directions to check connection in. - * @return True if the cached connectionMap holds a connection in all the given {@link OctagonalOrientation directions}. + * The directions to check connection in. + * @return True if the cached connectionMap holds a connection in all the given + * {@link OctagonalOrientation directions}. */ @SuppressWarnings("null") public boolean connectedAnd(OctagonalOrientation... dirs) { @@ -241,8 +242,9 @@ public boolean connectedAnd(OctagonalOrientation... dirs) { /** * @param dirs - * The directions to check connection in. - * @return True if the cached connectionMap holds a connection in one of the given {@link OctagonalOrientation directions}. + * The directions to check connection in. + * @return True if the cached connectionMap holds a connection in one of the given + * {@link OctagonalOrientation directions}. */ @SuppressWarnings("null") public boolean connectedOr(OctagonalOrientation... dirs) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java index a316143f23f..e2ea42d0882 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java @@ -1,21 +1,20 @@ /* * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). - * Copyright (c) 2023 Chisel Team. - + * Copyright (c) 2023 Chisel Team. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - + * * ConnectedTexturesMod is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * * You should have received a copy of the GNU General Public License along * with ConnectedTexturesMod; if not, If not, see . */ - package com.gregtechceu.gtceu.client.model.ctm; import com.gregtechceu.gtceu.client.model.ctm.CTMCache.StateComparisonCallback; @@ -36,7 +35,8 @@ import org.jetbrains.annotations.Nullable; /** - * Sourced from ConnectedTexturesMod. + * Sourced from ConnectedTexturesMod. */ @NoArgsConstructor @AllArgsConstructor @@ -44,13 +44,13 @@ public class ConnectionCheck { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( - Codec.BOOL.optionalFieldOf("ignore_states", false).forGetter(ConnectionCheck::ignoreStates) - ).apply(instance, ignoredStates -> new ConnectionCheck().ignoreStates(ignoredStates))); - + Codec.BOOL.optionalFieldOf("ignore_states", false).forGetter(ConnectionCheck::ignoreStates)) + .apply(instance, ignoredStates -> new ConnectionCheck().ignoreStates(ignoredStates))); + @Getter @Setter protected boolean ignoreStates; - + @Getter @Setter protected StateComparisonCallback stateComparator = StateComparisonCallback.DEFAULT; @@ -58,12 +58,12 @@ public class ConnectionCheck { /** * A simple check for if the given block can connect to the given direction on the given side. * - * @param level The level the positions are in. - * @param current The position of your block. + * @param level The level the positions are in. + * @param current The position of your block. * @param currentState The current state of your block. - * @param connection The position of the block to check against. - * @param dir The {@link Direction side} of the block to check for connection status. - * This is not the direction to check in. + * @param connection The position of the block to check against. + * @param dir The {@link Direction side} of the block to check for connection status. + * This is not the direction to check in. * @return True if the given block can connect to the given location on the given side. */ public final boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, @@ -76,17 +76,19 @@ public final boolean isConnected(BlockAndTintGetter level, BlockPos current, Blo /** * A simple check for if the given block can connect to the given direction on the given side. * - * @param level The level the positions are in. - * @param current The position of your block. + * @param level The level the positions are in. + * @param current The position of your block. * @param connection The position of the block to check against. - * @param dir The {@link Direction side} of the block to check for connection status. - * This is not the direction to check in. - * @param state The state to check against for connection. + * @param dir The {@link Direction side} of the block to check for connection status. + * This is not the direction to check in. + * @param state The state to check against for connection. * @return True if the given block can connect to the given location on the given side. */ @SuppressWarnings({ "unused", "null" }) - public boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, BlockPos connection, Direction dir, BlockState state) { - BlockState connectionState = getConnectionState(level, connection, level.getBlockState(connection), dir, current, currentState); + public boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, BlockPos connection, + Direction dir, BlockState state) { + BlockState connectionState = getConnectionState(level, connection, level.getBlockState(connection), dir, + current, currentState); BlockPos obscuringPos = connection.relative(dir); BlockState obscuring = getConnectionState(level, obscuringPos, level.getBlockState(obscuringPos), dir, current, currentState); @@ -94,7 +96,7 @@ public boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockStat // check that we aren't already connected to / from this side return stateComparator(state, connectionState, dir) && !stateComparator(state, obscuring, dir); } - + public boolean stateComparator(BlockState from, BlockState to, Direction dir) { return stateComparator.connects(this, from, to, dir); } @@ -111,5 +113,4 @@ public BlockState getConnectionState(BlockAndTintGetter level, BlockPos pos, Blo } return state; } - -} \ No newline at end of file +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java index 945b3df778b..03922701d1c 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java @@ -61,5 +61,4 @@ public String getMetadataSectionName() { return SECTION_NAME; } } - -} \ No newline at end of file +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java index 2bd1818daa9..bfea41eb64a 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java @@ -1,21 +1,20 @@ /* * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). - * Copyright (c) 2023 Chisel Team. - + * Copyright (c) 2023 Chisel Team. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - + * * ConnectedTexturesMod is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * * You should have received a copy of the GNU General Public License along * with ConnectedTexturesMod; if not, If not, see . */ - package com.gregtechceu.gtceu.client.model.ctm; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -23,7 +22,8 @@ import lombok.RequiredArgsConstructor; /** - * Sourced from ConnectedTexturesMod. + * Sourced from ConnectedTexturesMod. */ public interface ISubmap { @@ -54,13 +54,13 @@ default ISubmap unitScale() { default ISubmap pixelScale() { return this; } - + float PIXELS_PER_UNIT = 16f; float UNITS_PER_PIXEL = 1f / PIXELS_PER_UNIT; @RequiredArgsConstructor class SubmapRescaled implements ISubmap { - + private final ISubmap parent; private final float ratio; private final boolean isPixelScale; @@ -110,12 +110,14 @@ public float[] toArray() { return parent.toArray(); } } - + default ISubmap flipX() { - return Submap.fromPixelScale(getWidth(), getHeight(), PIXELS_PER_UNIT - getXOffset() - getWidth(), getYOffset()); + return Submap.fromPixelScale(getWidth(), getHeight(), PIXELS_PER_UNIT - getXOffset() - getWidth(), + getYOffset()); } default ISubmap flipY() { - return Submap.fromPixelScale(getWidth(), getHeight(), getXOffset(), PIXELS_PER_UNIT - getYOffset() - getHeight()); + return Submap.fromPixelScale(getWidth(), getHeight(), getXOffset(), + PIXELS_PER_UNIT - getYOffset() - getHeight()); } -} \ No newline at end of file +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java index 4b0a682568e..3bd98726df5 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java @@ -1,21 +1,20 @@ /* * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). - * Copyright (c) 2023 Chisel Team. - + * Copyright (c) 2023 Chisel Team. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - + * * ConnectedTexturesMod is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * * You should have received a copy of the GNU General Public License along * with ConnectedTexturesMod; if not, If not, see . */ - package com.gregtechceu.gtceu.client.model.ctm; import net.createmod.catnip.math.DirectionHelper; @@ -39,10 +38,12 @@ * but connected in the diagonal direction represented by {@link #TOP_RIGHT}. * This is used for inner corner rendering. *

- * Sourced from ConnectedTexturesMod. + * Sourced from ConnectedTexturesMod. */ public enum OctagonalOrientation implements StringRepresentable { - // spotless:off + + // spotless:off TOP(UP), TOP_RIGHT(UP, EAST), RIGHT(EAST), @@ -53,24 +54,24 @@ public enum OctagonalOrientation implements StringRepresentable { TOP_LEFT(UP, WEST); // spotless:on - public static final OctagonalOrientation[] VALUES = values(); - private static final Direction NORMAL = SOUTH; - - static { - // Run after static init - for (OctagonalOrientation dir : OctagonalOrientation.VALUES) { - dir.buildCaches(); - } - } - - private final Direction[] dirs; - - private final BlockPos[] offsets = new BlockPos[6]; - - OctagonalOrientation(Direction... dirs) { - this.dirs = dirs; + public static final OctagonalOrientation[] VALUES = values(); + private static final Direction NORMAL = SOUTH; + + static { + // Run after static init + for (OctagonalOrientation dir : OctagonalOrientation.VALUES) { + dir.buildCaches(); + } } - + + private final Direction[] dirs; + + private final BlockPos[] offsets = new BlockPos[6]; + + OctagonalOrientation(Direction... dirs) { + this.dirs = dirs; + } + private void buildCaches() { // Fill normalized dirs for (Direction normal : Direction.values()) { @@ -108,34 +109,36 @@ private void buildCaches() { } offsets[normal.ordinal()] = ret; } - } + } /** * Finds if this block is connected for the given side in this OctagonalOrientation. * - * @param ctm The ConnectionCheck instance to use for logic. + * @param ctm The ConnectionCheck instance to use for logic. * @param level The level the block is in. - * @param pos The position of your block. + * @param pos The position of your block. * @param state The state of your block. - * @param side The side of the current face. + * @param side The side of the current face. * @return True if the block is connected in the given OctagonalOrientation, false otherwise. */ - public boolean isConnected(ConnectionCheck ctm, BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side) { + public boolean isConnected(ConnectionCheck ctm, BlockAndTintGetter level, BlockPos pos, BlockState state, + Direction side) { return ctm.isConnected(level, pos, state, applyConnection(pos, side), side); } /** * Finds if this block is connected for the given side in this OctagonalOrientation. * - * @param ctm The ConnectionCheck instance to use for logic. - * @param level The level the block is in. - * @param pos The position of your block. - * @param state The state of your block. - * @param side The side of the current face. + * @param ctm The ConnectionCheck instance to use for logic. + * @param level The level the block is in. + * @param pos The position of your block. + * @param state The state of your block. + * @param side The side of the current face. * @param connectionState The state to check for connection with. * @return True if the block is connected in the given OctagonalOrientation, false otherwise. */ - public boolean isConnected(ConnectionCheck ctm, BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side, BlockState connectionState) { + public boolean isConnected(ConnectionCheck ctm, BlockAndTintGetter level, BlockPos pos, BlockState state, + Direction side, BlockState connectionState) { return ctm.isConnected(level, pos, state, applyConnection(pos, side), side, connectionState); } @@ -147,12 +150,12 @@ public boolean isConnected(ConnectionCheck ctm, BlockAndTintGetter level, BlockP public BlockPos applyConnection(BlockPos pos, Direction side) { return pos.offset(getOffset(side)); } - + public BlockPos getOffset(Direction normal) { return offsets[normal.ordinal()]; } - private Direction rotate(Direction facing, Direction axisFacing) { + private Direction rotate(Direction facing, Direction axisFacing) { Direction.Axis axis = axisFacing.getAxis(); AxisDirection axisDir = axisFacing.getAxisDirection(); @@ -165,10 +168,10 @@ private Direction rotate(Direction facing, Direction axisFacing) { } return facing; - } + } @Override public String getSerializedName() { return name().toLowerCase(Locale.ROOT); } -} \ No newline at end of file +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java index 3253750ebf1..56f7c2e3be1 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java @@ -1,51 +1,58 @@ /* * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). - * Copyright (c) 2023 Chisel Team. - + * Copyright (c) 2023 Chisel Team. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - + * * ConnectedTexturesMod is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * * You should have received a copy of the GNU General Public License along * with ConnectedTexturesMod; if not, If not, see . */ - package com.gregtechceu.gtceu.client.model.ctm; import lombok.Getter; /** - * Sourced from ConnectedTexturesMod. + * Sourced from ConnectedTexturesMod. */ public class Submap implements ISubmap { - + public static final ISubmap X1 = fromPixelScale(16, 16, 0, 0); - + public static final ISubmap[][] X2 = { - { fromPixelScale(8, 8, 0, 0), fromPixelScale(8, 8, 8, 0) }, - { fromPixelScale(8, 8, 0, 8), fromPixelScale(8, 8, 8, 8) } + { fromPixelScale(8, 8, 0, 0), fromPixelScale(8, 8, 8, 0) }, + { fromPixelScale(8, 8, 0, 8), fromPixelScale(8, 8, 8, 8) } }; - + private static final float DIV3 = 16 / 3f; public static final ISubmap[][] X3 = { - { fromPixelScale(DIV3, DIV3, 0, 0), fromPixelScale(DIV3, DIV3, DIV3, 0), fromPixelScale(DIV3, DIV3, DIV3 * 2, 0) }, - { fromPixelScale(DIV3, DIV3, 0, DIV3), fromPixelScale(DIV3, DIV3, DIV3, DIV3), fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3) }, - { fromPixelScale(DIV3, DIV3, 0, DIV3 * 2), fromPixelScale(DIV3, DIV3, DIV3, DIV3 * 2), fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3 * 2) }, + { fromPixelScale(DIV3, DIV3, 0, 0), fromPixelScale(DIV3, DIV3, DIV3, 0), + fromPixelScale(DIV3, DIV3, DIV3 * 2, 0) }, + { fromPixelScale(DIV3, DIV3, 0, DIV3), fromPixelScale(DIV3, DIV3, DIV3, DIV3), + fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3) }, + { fromPixelScale(DIV3, DIV3, 0, DIV3 * 2), fromPixelScale(DIV3, DIV3, DIV3, DIV3 * 2), + fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3 * 2) }, }; - + public static final ISubmap[][] X4 = { - { fromPixelScale(4, 4, 0, 0), fromPixelScale(4, 4, 4, 0), fromPixelScale(4, 4, 8, 0), fromPixelScale(4, 4, 12, 0) }, - { fromPixelScale(4, 4, 0, 4), fromPixelScale(4, 4, 4, 4), fromPixelScale(4, 4, 8, 4), fromPixelScale(4, 4, 12, 4) }, - { fromPixelScale(4, 4, 0, 8), fromPixelScale(4, 4, 4, 8), fromPixelScale(4, 4, 8, 8), fromPixelScale(4, 4, 12, 8) }, - { fromPixelScale(4, 4, 0, 12), fromPixelScale(4, 4, 4, 12), fromPixelScale(4, 4, 8, 12), fromPixelScale(4, 4, 12, 12) }, + { fromPixelScale(4, 4, 0, 0), fromPixelScale(4, 4, 4, 0), fromPixelScale(4, 4, 8, 0), + fromPixelScale(4, 4, 12, 0) }, + { fromPixelScale(4, 4, 0, 4), fromPixelScale(4, 4, 4, 4), fromPixelScale(4, 4, 8, 4), + fromPixelScale(4, 4, 12, 4) }, + { fromPixelScale(4, 4, 0, 8), fromPixelScale(4, 4, 4, 8), fromPixelScale(4, 4, 8, 8), + fromPixelScale(4, 4, 12, 8) }, + { fromPixelScale(4, 4, 0, 12), fromPixelScale(4, 4, 4, 12), fromPixelScale(4, 4, 8, 12), + fromPixelScale(4, 4, 12, 12) }, }; - + public static ISubmap[][] grid(int w, int h) { float xDiv = 16f / w; float yDiv = 16f / h; @@ -63,7 +70,8 @@ public static ISubmap raw(float width, float height, float xOffset, float yOffse } public static ISubmap fromUnitScale(float width, float height, float xOffset, float yOffset) { - return fromPixelScale(width * PIXELS_PER_UNIT, height * PIXELS_PER_UNIT, xOffset * PIXELS_PER_UNIT, yOffset * PIXELS_PER_UNIT); + return fromPixelScale(width * PIXELS_PER_UNIT, height * PIXELS_PER_UNIT, xOffset * PIXELS_PER_UNIT, + yOffset * PIXELS_PER_UNIT); } public static ISubmap fromPixelScale(float width, float height, float xOffset, float yOffset) { @@ -76,7 +84,7 @@ public static ISubmap fromPixelScale(float width, float height, float xOffset, f private final float xOffset, yOffset; final SubmapRescaled rescaled; - + private Submap(float width, float height, float xOffset, float yOffset, float rescale) { this.width = width; this.height = height; @@ -89,4 +97,4 @@ private Submap(float width, float height, float xOffset, float yOffset, float re public SubmapRescaled pixelScale() { return this.rescaled; } -} \ No newline at end of file +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java index 8d3982fca6f..068ddfcb348 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java @@ -10,11 +10,11 @@ import com.gregtechceu.gtceu.client.model.IBlockEntityRendererBakedModel; import com.gregtechceu.gtceu.client.model.TextureOverrideModel; import com.gregtechceu.gtceu.client.model.machine.multipart.MultiPartBakedModel; +import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.client.util.quad.QuadUtils; -import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; import com.gregtechceu.gtceu.common.data.models.GTModels; import com.gregtechceu.gtceu.common.machine.trait.AutoOutputTrait; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/EncodingFormat.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/EncodingFormat.java index 0005d09728c..85795309e0f 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/EncodingFormat.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/EncodingFormat.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,18 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.gregtechceu.gtceu.client.model.quad; import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; -import lombok.experimental.UtilityClass; -import org.jetbrains.annotations.Nullable; - import net.minecraft.core.Direction; import net.minecraft.util.Mth; import net.minecraftforge.client.model.IQuadTransformer; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Nullable; + import java.util.Objects; /** diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java index bb27314165b..43f0d6610b4 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java @@ -21,6 +21,7 @@ * @implNote The way we encode meshes makes it very simple. */ public class Mesh { + /** Used to satisfy external calls to {@link #forEach(Consumer)}. */ private static final ThreadLocal POOL = ThreadLocal.withInitial(QuadView::new); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java index 7201327ac92..6da93a5ca21 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,10 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.gregtechceu.gtceu.client.model.quad; - /** * Similar in purpose to {@link com.mojang.blaze3d.vertex.BufferBuilder} but simpler and not tied to NIO * or any other specific implementation, plus designed to handle both static and dynamic building. @@ -70,6 +68,7 @@ public MutableQuadView getEmitter() { * used at render time so we want to capture all geometry now and apply non-location-dependent lighting. */ private class Maker extends MutableQuadView { + @Override public Maker emit() { computeGeometry(); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java index f83c03413ec..997af972b23 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,16 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.gregtechceu.gtceu.client.model.quad; import com.gregtechceu.gtceu.client.util.TextureHelper; import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; -import org.jetbrains.annotations.Nullable; -import org.joml.Vector2f; -import org.joml.Vector3f; - import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -30,12 +25,18 @@ import net.minecraft.util.Mth; import net.minecraftforge.client.model.QuadTransformers; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector2f; +import org.joml.Vector3f; + import static com.gregtechceu.gtceu.client.model.quad.EncodingFormat.*; + /** * A mutable {@link QuadView} instance. * *

- * Instances of {@link MutableQuadView} will practically always be thread local and/or reused - do not retain references. + * Instances of {@link MutableQuadView} will practically always be thread local and/or reused - do not retain + * references. * *

* Only the renderer should implement or extend this interface. @@ -104,8 +105,9 @@ public static MutableQuadView getInstance() { return MutableQuadView.THREAD_LOCAL.get(); } + public static final ThreadLocal THREAD_LOCAL = ThreadLocal + .withInitial(() -> new MutableQuadView() { - public static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(() -> new MutableQuadView() { { begin(new int[QUAD_STRIDE], 0); } @@ -438,7 +440,6 @@ public final MutableQuadView fromVanilla(BakedQuad quad, @Nullable Direction cul */ public abstract MutableQuadView emit(); - /** * Tolerance for determining if the depth parameter to {@link #square(Direction, float, float, float, float, float)} * is effectively zero - meaning the face is a cull face. @@ -457,7 +458,8 @@ public final MutableQuadView fromVanilla(BakedQuad quad, @Nullable Direction cul *

* All coordinates should be normalized (0-1). */ - public MutableQuadView square(Direction nominalFace, float left, float bottom, float right, float top, float depth) { + public MutableQuadView square(Direction nominalFace, float left, float bottom, float right, float top, + float depth) { if (Math.abs(depth) < CULL_FACE_EPSILON) { cullFace(nominalFace); depth = 0; // avoid any inconsistency for face quads diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java index 416b88c33a1..5dd5101c791 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,18 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.gregtechceu.gtceu.client.model.quad; import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; -import lombok.Getter; -import lombok.experimental.Accessors; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.UnknownNullability; -import org.joml.Vector2f; -import org.joml.Vector3f; - import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlas; @@ -32,6 +24,13 @@ import net.minecraft.core.Direction; import net.minecraftforge.client.model.QuadTransformers; +import lombok.Getter; +import lombok.experimental.Accessors; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; +import org.joml.Vector2f; +import org.joml.Vector3f; + import static com.gregtechceu.gtceu.client.model.quad.EncodingFormat.*; /** @@ -43,6 +42,7 @@ */ @Accessors(fluent = true, chain = true) public class QuadView { + /** * See {@link MutableQuadView#nominalFace(Direction)}. */ @@ -226,7 +226,6 @@ public float x(int vertexIndex) { return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X]); } - /** * Retrieve geometric position, y coordinate. */ @@ -270,24 +269,24 @@ protected final int normalIndex(int vertexIndex) { * Will return {@link Float#NaN} if normal not present. */ public float normalX(int vertexIndex) { - return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 0) - : Float.NaN; + return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 0) : + Float.NaN; } /** * Will return {@link Float#NaN} if normal not present. */ public float normalY(int vertexIndex) { - return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 1) - : Float.NaN; + return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 1) : + Float.NaN; } /** * Will return {@link Float#NaN} if normal not present. */ public float normalZ(int vertexIndex) { - return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 2) - : Float.NaN; + return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 2) : + Float.NaN; } /** diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java index cc912bfc868..a7c67f1cb40 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,12 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.gregtechceu.gtceu.client.model.quad; -import java.util.Map; -import java.util.function.Consumer; - import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -27,6 +23,9 @@ import org.jetbrains.annotations.Nullable; +import java.util.Map; +import java.util.function.Consumer; + /** * Indexes a texture atlas to allow fast lookup of Sprites from baked vertex coordinates. * Main use is for {@link Mesh}-based models to generate vanilla quads on demand @@ -95,13 +94,18 @@ public TextureAtlasSprite find(float u, float v) { } private class Node { + final float midU; final float midV; final float cellRadius; - @Nullable Object lowLow = null; - @Nullable Object lowHigh = null; - @Nullable Object highLow = null; - @Nullable Object highHigh = null; + @Nullable + Object lowLow = null; + @Nullable + Object lowHigh = null; + @Nullable + Object highLow = null; + @Nullable + Object highHigh = null; Node(float midU, float midV, float radius) { this.midU = midU; @@ -172,6 +176,7 @@ private TextureAtlasSprite findInner(@Nullable Object quadrant, float u, float v } public interface SpriteFinderAccess { + SpriteFinder gtceu$spriteFinder(); } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/transform/QuadTransform.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/transform/QuadTransform.java index 0f7186c3da3..b604160adf5 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/transform/QuadTransform.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/transform/QuadTransform.java @@ -7,6 +7,7 @@ @FunctionalInterface public interface QuadTransform extends IQuadTransformer { + /** * Return false to filter out quads from rendering. When more than one transform is in effect, returning false * means unapplied transforms will not receive the quad. @@ -19,4 +20,4 @@ default void processInPlace(BakedQuad quad) { this.transform(quadView); quadView.toVanilla(quad.getVertices(), 0); } -} \ No newline at end of file +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java index 8c1d79c06e7..be3f81685a5 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java @@ -5,10 +5,10 @@ import com.gregtechceu.gtceu.client.model.BaseBakedModel; import com.gregtechceu.gtceu.client.model.ItemBakedModel; import com.gregtechceu.gtceu.client.model.TextureOverrideModel; +import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; import com.gregtechceu.gtceu.client.util.FacadeBlockAndTintGetter; import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.client.util.quad.transformers.GTQuadTransformers; -import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; import com.gregtechceu.gtceu.common.cover.FacadeCover; import com.gregtechceu.gtceu.common.item.behavior.FacadeItemBehaviour; import com.gregtechceu.gtceu.utils.GTUtil; @@ -191,8 +191,8 @@ public void renderCover(List quads, Direction side, RandomSource rand BakedModel model = RenderUtil.getModelForState(state); ModelData facadeModelData = model.getModelData(level, pos, state, modelData); - - if (renderType != null && !facadeModel.getRenderTypes(facadeState, rand, facadeModelData).contains(renderType)) { + if (renderType != null && + !facadeModel.getRenderTypes(facadeState, rand, facadeModelData).contains(renderType)) { return; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java index ea1e98634bf..5c8fd4da25d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java @@ -4,8 +4,8 @@ import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.cover.CoverBehavior; import com.gregtechceu.gtceu.api.cover.IIOCover; -import com.gregtechceu.gtceu.client.util.ModelEventHelper; import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; +import com.gregtechceu.gtceu.client.util.ModelEventHelper; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java index 767a3cad5af..c9acfcd6477 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java @@ -1,8 +1,8 @@ package com.gregtechceu.gtceu.client.renderer.cover; import com.gregtechceu.gtceu.api.cover.CoverBehavior; -import com.gregtechceu.gtceu.client.util.ModelEventHelper; import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; +import com.gregtechceu.gtceu.client.util.ModelEventHelper; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java index cd21ca50246..f31a66b4de9 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.gregtechceu.gtceu.client.util; import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; @@ -109,12 +108,13 @@ public static void normalizeBy(MutableQuadView q, TextureAtlasSprite sprite) { // If the UV is outside the texture's boundaries, this was probably called by mistake. if (u < uMin || u > uMax || v < vMin || v > vMax) continue; - q.uv(i, (u - uMin) / uSpan, (v - vMin) / vSpan); + q.uv(i, (u - uMin) / uSpan, (v - vMin) / vSpan); } } @FunctionalInterface public interface VertexModifier { + void apply(MutableQuadView quad, int vertexIndex); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/TextureMetadataHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/TextureMetadataHelper.java index 515e895ec2f..9ed03e35404 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/TextureMetadataHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/TextureMetadataHelper.java @@ -17,7 +17,7 @@ @UtilityClass public class TextureMetadataHelper { - + private static final Map metadataCache = new HashMap<>(); public static Optional getMetadata(ResourceLocation res) { @@ -60,8 +60,8 @@ public static ResourceLocation spriteToAbsolute(ResourceLocation sprite) { } return sprite; } - + static void invalidateCaches() { metadataCache.clear(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java index dd91c8b60b0..01fc65ccd43 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,23 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.gregtechceu.gtceu.client.util.quad; import com.gregtechceu.gtceu.client.model.quad.QuadView; import com.gregtechceu.gtceu.utils.GTUtil; -import lombok.experimental.UtilityClass; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.Nullable; -import org.joml.Vector3f; - import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; import net.minecraft.core.Vec3i; import net.minecraft.util.Mth; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; + /** * Static routines of general utility for renderer implementations. * Renderers are not required to use these helpers, but they were designed to be usable without the default renderer. @@ -105,10 +104,8 @@ public static int packNormal(float x, float y, float z, float w) { z = Mth.clamp(z, -1, 1); w = Mth.clamp(w, -1, 1); - return ((int) (x * 127) & 255) - | (((int) (y * 127) & 255) << 8) - | (((int) (z * 127) & 255) << 16) - | (((int) (w * 127) & 255) << 24); + return ((int) (x * 127) & 255) | (((int) (y * 127) & 255) << 8) | (((int) (z * 127) & 255) << 16) | + (((int) (w * 127) & 255) << 24); } /** @@ -192,8 +189,7 @@ public static boolean isQuadParallelToFace(@Nullable Direction face, QuadView qu int i = face.getAxis().ordinal(); final float val = quad.posByIndex(0, i); - return Mth.equal(val, quad.posByIndex(1, i)) - && Mth.equal(val, quad.posByIndex(2, i)) - && Mth.equal(val, quad.posByIndex(3, i)); + return Mth.equal(val, quad.posByIndex(1, i)) && Mth.equal(val, quad.posByIndex(2, i)) && + Mth.equal(val, quad.posByIndex(3, i)); } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/InterpolationHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/InterpolationHelper.java index 275d5fa6a6b..f1b1d5404fa 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/InterpolationHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/InterpolationHelper.java @@ -9,13 +9,12 @@ * * CodeChickenLib is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with CodeChickenLib. If not, see . */ - package com.gregtechceu.gtceu.client.util.quad.transformers; import net.minecraft.util.Mth; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadClamper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadClamper.java index 9e7aa728dae..9ca6980a74d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadClamper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadClamper.java @@ -9,13 +9,12 @@ * * CodeChickenLib is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with CodeChickenLib. If not, see . */ - package com.gregtechceu.gtceu.client.util.quad.transformers; import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java index 1d62b2f4f55..fe849c4d525 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java @@ -9,18 +9,17 @@ * * CodeChickenLib is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with CodeChickenLib. If not, see . */ - package com.gregtechceu.gtceu.client.util.quad.transformers; +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; import com.gregtechceu.gtceu.client.model.quad.transform.QuadTransform; import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; -import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.core.Direction; @@ -31,8 +30,8 @@ import org.jetbrains.annotations.Nullable; -import static net.minecraft.core.Direction.AxisDirection.*; import static net.minecraft.core.Direction.*; +import static net.minecraft.core.Direction.AxisDirection.*; /** * This transformer is a little complicated. @@ -40,10 +39,10 @@ *

* Use it by specifying *

    - *
  • the side of the block you are on,
  • - *
  • the bitmask for where the other Facades / Covers are,
  • - *
  • the bounding box of the facade (NOT the hole piece),
  • - *
  • and the thickness of your Facade / Cover (which is used as the kick amount).
  • + *
  • the side of the block you are on,
  • + *
  • the bitmask for where the other Facades / Covers are,
  • + *
  • the bounding box of the facade (NOT the hole piece),
  • + *
  • and the thickness of your Facade / Cover (which is used as the kick amount).
  • *
* * @author covers1624 @@ -127,9 +126,8 @@ public boolean transform(MutableQuadView quad) { float x = quad.posByIndex(i, 0); float y = quad.posByIndex(i, 1); float z = quad.posByIndex(i, 2); - if (Mth.equal(x, corner.pX(this.bounds)) - && Mth.equal(y, corner.pY(this.bounds)) - && Mth.equal(z, corner.pZ(this.bounds))) { + if (Mth.equal(x, corner.pX(this.bounds)) && Mth.equal(y, corner.pY(this.bounds)) && + Mth.equal(z, corner.pZ(this.bounds))) { Vec3i normal = hoz.getNormal(); x -= normal.getX() * this.thickness; y -= normal.getY() * this.thickness; @@ -143,9 +141,7 @@ public boolean transform(MutableQuadView quad) { } @Override - public void processInPlace(BakedQuad quad) { - - } + public void processInPlace(BakedQuad quad) {} public enum Corner { @@ -206,5 +202,4 @@ public float pZ(AABB box) { return (float) (this.zAxis == NEGATIVE ? box.minZ : box.maxZ); } } - } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadReInterpolator.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadReInterpolator.java index 4c0849b0c9a..bc3cf275201 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadReInterpolator.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadReInterpolator.java @@ -9,13 +9,12 @@ * * CodeChickenLib is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with CodeChickenLib. If not, see . */ - package com.gregtechceu.gtceu.client.util.quad.transformers; import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; @@ -187,5 +186,4 @@ private static int yCoord(Direction.Axis axis) { return 2; } } - } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadTinter.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadTinter.java index 0af06ab6c11..06a50545782 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadTinter.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadTinter.java @@ -9,13 +9,12 @@ * * CodeChickenLib is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with CodeChickenLib. If not, see . */ - package com.gregtechceu.gtceu.client.util.quad.transformers; import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java b/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java index d4cdf600f2c..6ba47cd12d2 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java @@ -598,7 +598,8 @@ public static MachineBuilder.ModelInitializer createHPCAPartModel(boolean advanc } public static final ResourceLocation OVERLAY_SCREEN_TEXTURE = GTCEu.id("block/overlay/machine/overlay_screen"); - public static final ResourceLocation OVERLAY_QTANK_EMISSIVE_TEXTURE = GTCEu.id("block/overlay/machine/overlay_qtank_emissive"); + public static final ResourceLocation OVERLAY_QTANK_EMISSIVE_TEXTURE = GTCEu + .id("block/overlay/machine/overlay_qtank_emissive"); public static MachineBuilder.ModelInitializer createFisherModel() { return (ctx, prov, builder) -> { diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java index 05e8f0f5df4..4f961ad3af0 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java @@ -5,8 +5,6 @@ import com.gregtechceu.gtceu.client.util.ModelEventHelper; import com.gregtechceu.gtceu.common.block.LampBlock; -import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; - import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.core.NonNullList; @@ -21,6 +19,7 @@ import net.minecraftforge.client.extensions.common.IClientItemExtensions; import net.minecraftforge.client.model.BakedModelWrapper; +import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -100,7 +99,8 @@ private static void registerEventListener(LampBlockItem toWrap) { // handle both cases 1.20 can have passed here. 1.21 *only* has the ModelResourceLocation case. ResourceLocation possibleItemId; - if (modelLocation instanceof ModelResourceLocation modelResLoc && Objects.equals(modelResLoc.getVariant(), "inventory")) { + if (modelLocation instanceof ModelResourceLocation modelResLoc && + Objects.equals(modelResLoc.getVariant(), "inventory")) { // unwrap ModelResourceLocations // 1.21 needs different code here as ModelResourceLocation is a wrapper record instead of a subclass possibleItemId = modelResLoc.withPrefix(""); diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java index 6cf2c33db95..bd8aef34c66 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java @@ -13,7 +13,7 @@ import java.util.function.Function; -@Mixin(targets = {"net.minecraft.client.resources.model.ModelBakery$ModelBakerImpl"}) +@Mixin(targets = { "net.minecraft.client.resources.model.ModelBakery$ModelBakerImpl" }) public abstract class ModelBakerImplMixin { // the parameters aren't remapped because Parchment can't remap Forge's patches diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java index 1427a97168b..e06a756efb9 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.gregtechceu.gtceu.core.mixins.client; import com.gregtechceu.gtceu.client.model.quad.SpriteFinder; -import java.util.Map; +import net.minecraft.client.renderer.texture.SpriteLoader; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Mixin; @@ -28,13 +30,11 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import net.minecraft.client.renderer.texture.SpriteLoader; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.resources.ResourceLocation; +import java.util.Map; @Mixin(TextureAtlas.class) public class TextureAtlasMixin implements SpriteFinder.SpriteFinderAccess { + @Shadow private Map texturesByName; From 0648242c4df553f39ae5f414edb0f99af225de85 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 22:00:49 +0300 Subject: [PATCH 22/66] Fix errors caused by dropping commits a bit too hastily --- .../renderer/cover/FacadeCoverRenderer.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java index be3f81685a5..2ca9c016403 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java @@ -181,30 +181,26 @@ public void renderCover(List quads, Direction side, RandomSource rand if (!(coverBehavior instanceof FacadeCover facadeCover)) { return; } - BlockState state = facadeCover.getFacadeState(); - if (state.getRenderShape() != RenderShape.MODEL) { + BlockState facadeSate = facadeCover.getFacadeState(); + if (facadeSate.getRenderShape() != RenderShape.MODEL) { return; } Direction attachedSide = coverBehavior.attachedSide; - BakedModel model = RenderUtil.getModelForState(state); - ModelData facadeModelData = model.getModelData(level, pos, state, modelData); + BakedModel facadeModel = RenderUtil.getModelForState(facadeSate); + ModelData facadeModelData = facadeModel.getModelData(level, pos, facadeSate, modelData); if (renderType != null && - !facadeModel.getRenderTypes(facadeState, rand, facadeModelData).contains(renderType)) { + !facadeModel.getRenderTypes(facadeSate, rand, facadeModelData).contains(renderType)) { return; } - List facadeQuads = model.getQuads(state, attachedSide, rand, facadeModelData, renderType); + List facadeQuads = facadeModel.getQuads(facadeSate, attachedSide, rand, facadeModelData, renderType); facadeQuads = new LinkedList<>(facadeQuads); List coverQuads = new ArrayList<>(); if (side == attachedSide) { - for (BakedQuad quad : facadeQuads) { - // clamp the facade quads' vertices into the model - coverQuads.add(FACADE_PLANE_TRANSFORMER.process(quad)); - } coverQuads.addAll(facadeQuads); } else if (side == null && coverBehavior.coverHolder.shouldRenderBackSide()) { AABB cube = COVER_BACK_CUBES.get(attachedSide); @@ -221,7 +217,7 @@ public void renderCover(List quads, Direction side, RandomSource rand for (BakedQuad quad : coverQuads) { if (quad.isTinted()) { // if the quad has a tint index set, bake the tint into the vertex - int color = blockColors.getColor(state, level, pos, quad.getTintIndex()); + int color = blockColors.getColor(facadeSate, level, pos, quad.getTintIndex()); quad = GTQuadTransformers.setColor(quad, color, true); } else { // otherwise just copy the quad so we don't mutate the original model with the overlay offset From 40efad08cdb1df8466cf4396dde5b01dd35edca0 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 22:59:25 +0300 Subject: [PATCH 23/66] Fix corrupt JSON --- .../assets/gtceu/textures/block/lamps/black_emissive.png.mcmeta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_emissive.png.mcmeta index a11349bfaee..ccea6d28ebc 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_emissive.png.mcmeta @@ -2,6 +2,6 @@ "gtceu": { "connection_texture": "gtceu:block/lamps/black_ctm_emissive", "bloom": true - }, + } } From 4000a51d04de3da98c41f226b21e7d6a40abbdc3 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sat, 18 Apr 2026 23:24:41 +0300 Subject: [PATCH 24/66] Make world load --- .../model/ctm/OctagonalOrientation.java | 9 +---- .../gtceu/client/model/quad/MeshBuilder.java | 1 + .../client/model/quad/MutableQuadView.java | 6 --- .../gtceu/common/item/LampBlockItem.java | 40 +++++++++---------- 4 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java index 3bd98726df5..18d1e22378c 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java @@ -17,7 +17,6 @@ */ package com.gregtechceu.gtceu.client.model.ctm; -import net.createmod.catnip.math.DirectionHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.StringRepresentable; @@ -160,14 +159,10 @@ private Direction rotate(Direction facing, Direction axisFacing) { AxisDirection axisDir = axisFacing.getAxisDirection(); if (axisDir == AxisDirection.POSITIVE) { - return DirectionHelper.rotateAround(facing, axis); - } - - if (facing.getAxis() != axis) { + return facing.getClockWise(axis); + } else { return facing.getCounterClockWise(axis); } - - return facing; } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java index 6da93a5ca21..bfebec00b2b 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java @@ -72,6 +72,7 @@ private class Maker extends MutableQuadView { @Override public Maker emit() { computeGeometry(); + populateMissingNormals(); index += EncodingFormat.QUAD_STRIDE; ensureCapacity(); baseIndex = index; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java index 997af972b23..f9c85947d44 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java @@ -124,12 +124,6 @@ public final void begin(int[] data, int baseIndex) { clear(); } - @Override - protected void computeGeometry() { - this.populateMissingNormals(); - super.computeGeometry(); - } - public void clear() { System.arraycopy(EMPTY, 0, data, baseIndex, QUAD_STRIDE); isGeometryInvalid = true; diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java index 4f961ad3af0..45ce8c53b40 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java @@ -19,12 +19,12 @@ import net.minecraftforge.client.extensions.common.IClientItemExtensions; import net.minecraftforge.client.model.BakedModelWrapper; -import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.function.Consumer; import javax.annotation.ParametersAreNonnullByDefault; @@ -88,14 +88,20 @@ public BlockEntityWithoutLevelRenderer getCustomRenderer() { private static class ClientCallWrapper { private static boolean registeredListener = false; - private static final Map trackedItems = new Reference2ObjectArrayMap<>(); + private static final Set trackedItems = new ReferenceLinkedOpenHashSet<>(); + private static final Set trackedItemIds = new ObjectLinkedOpenHashSet<>(); private static void registerEventListener(LampBlockItem toWrap) { - trackedItems.put(toWrap, null); + trackedItems.add(toWrap); if (registeredListener) return; registeredListener = true; ModelEventHelper.registerBakeEventListener(false, (modelLocation, model, unbakedModel, modelBakery) -> { + if (trackedItemIds.isEmpty()) { + for (Item item : trackedItems) { + trackedItemIds.add(BuiltInRegistries.ITEM.getKey(item)); + } + } // handle both cases 1.20 can have passed here. 1.21 *only* has the ModelResourceLocation case. ResourceLocation possibleItemId; @@ -111,25 +117,19 @@ private static void registerEventListener(LampBlockItem toWrap) { return model; } - for (var entry : trackedItems.entrySet()) { - ResourceLocation itemId = entry.getValue(); - if (itemId == null) { - entry.setValue(itemId = BuiltInRegistries.ITEM.getKey(entry.getKey())); - } + if (trackedItemIds.contains(possibleItemId)) { // if the current model is a lamp item, replace it with one that has isCustomRenderer()==true // so the custom renderer in `LampBlockItem#initializeClient` works - if (itemId.equals(possibleItemId)) { - return new BakedModelWrapper<>(model) { - - @Override - public boolean isCustomRenderer() { - return true; - } - }; - } - } + return new BakedModelWrapper<>(model) { - return model; + @Override + public boolean isCustomRenderer() { + return true; + } + }; + } else { + return model; + } }); } } From 18a7165e381d1044df68b299d7b8aa84596e2e9a Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 00:04:56 +0300 Subject: [PATCH 25/66] Force our reload listener to the front of the queue --- .../gtceu/client/util/ModelEventHelper.java | 17 +++++++++++------ .../ReloadableResourceManagerAccessor.java | 16 ++++++++++++++++ src/main/resources/gtceu.mixins.json | 1 + 3 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/core/mixins/ReloadableResourceManagerAccessor.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java index bd94a742896..1a25613bc34 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java @@ -4,7 +4,9 @@ import com.gregtechceu.gtceu.client.model.ctm.CTMBakedModel; import com.gregtechceu.gtceu.client.model.machine.MachineModel; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; +import com.gregtechceu.gtceu.core.mixins.ReloadableResourceManagerAccessor; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.*; @@ -75,12 +77,15 @@ public static void registerAddModelsEventListener(boolean removeOnReload, @SubscribeEvent(priority = EventPriority.HIGH) public static void registerReloadListener(RegisterClientReloadListenersEvent event) { - event.registerReloadListener((ResourceManagerReloadListener) resourceManager -> { - EVENT_LISTENERS.removeIf(EventListenerHolder::removeOnReload); - - CTM_SPRITE_CACHE.clear(); - TextureMetadataHelper.invalidateCaches(); - }); + ((ReloadableResourceManagerAccessor) Minecraft.getInstance().getResourceManager()).getListeners() + .add(0, (ResourceManagerReloadListener) resourceManager -> { + EVENT_LISTENERS.removeIf(EventListenerHolder::removeOnReload); + + CTM_SPRITE_CACHE.clear(); + WRAPPED_MODELS.clear(); + SCRAPED_TEXTURES.clear(); + TextureMetadataHelper.invalidateCaches(); + }); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/ReloadableResourceManagerAccessor.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/ReloadableResourceManagerAccessor.java new file mode 100644 index 00000000000..1aae111b199 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/ReloadableResourceManagerAccessor.java @@ -0,0 +1,16 @@ +package com.gregtechceu.gtceu.core.mixins; + +import net.minecraft.server.packs.resources.PreparableReloadListener; +import net.minecraft.server.packs.resources.ReloadableResourceManager; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(ReloadableResourceManager.class) +public interface ReloadableResourceManagerAccessor { + + @Accessor + List getListeners(); +} diff --git a/src/main/resources/gtceu.mixins.json b/src/main/resources/gtceu.mixins.json index cd2192122ee..2e54e0bb7f2 100644 --- a/src/main/resources/gtceu.mixins.json +++ b/src/main/resources/gtceu.mixins.json @@ -55,6 +55,7 @@ "PotionBrewingAccessor", "PrimedTntAccessor", "RecipeManagerMixin", + "ReloadableResourceManagerAccessor", "RepairItemRecipeMixin", "ServerChunkProviderMixin", "ServerGamePacketListenerImplAccessor", From aa375a343a20d8969d4142a43757aa2ade6883fe Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 01:09:33 +0300 Subject: [PATCH 26/66] quh. --- .../client/model/quad/MutableQuadView.java | 6 +- .../gtceu/client/model/quad/QuadView.java | 8 +- .../gtceu/client/util/ModelEventHelper.java | 15 +++- .../gtceu/client/util/TextureHelper.java | 2 +- .../gtceu/client/util/quad/QuadUtils.java | 78 +++++++++++++++---- 5 files changed, 83 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java index f9c85947d44..271e187f2c9 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java @@ -96,8 +96,8 @@ public abstract class MutableQuadView extends QuadView { /** * UV coordinates by default are assumed to be 0-16 scale for consistency with conventional Minecraft model format. * This is scaled to 0-1 during baking before interpolation. Model loaders that already have 0-1 coordinates can - * avoid wasteful multiplication/division by passing 0-1 coordinates directly. Pass in bakeFlags parameter to - * {@link #spriteBake(TextureAtlasSprite, int)}. + * avoid wasteful multiplication/division by passing 0-1 coordinates directly. + * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. */ public static final int BAKE_NORMALIZED = 0b100000; @@ -403,7 +403,7 @@ public final MutableQuadView fromVanilla(int[] quadData, int startIndex) { for (int i = 0; i < 4; i++) { // ARGB -> ABGR is a transitive process, e.g. it can be reversed and works fine. - this.data[colorIndex] = QuadTransformers.toABGR(this.data[colorIndex]); + //this.data[colorIndex] = QuadTransformers.toABGR(this.data[colorIndex]); colorIndex += VERTEX_STRIDE; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java index 5dd5101c791..34b292774a7 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java @@ -322,13 +322,9 @@ public float v(int vertexIndex) { public final void toVanilla(int[] target, int targetIndex) { System.arraycopy(data, baseIndex, target, targetIndex, QUAD_STRIDE); - // The color is the fourth integer in each vertex. - // EncodingFormat.VERTEX_COLOR is not used because it also - // contains the header size; vanilla quads do not have a header. - int colorIndex = targetIndex + 3; - + int colorIndex = EncodingFormat.VERTEX_COLOR; for (int i = 0; i < 4; i++) { - target[colorIndex] = QuadTransformers.toABGR(target[colorIndex]); + //target[colorIndex] = QuadTransformers.toABGR(target[colorIndex]); colorIndex += VERTEX_STRIDE; } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java index 1a25613bc34..89600e160bc 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java @@ -29,6 +29,8 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; @SuppressWarnings("deprecation") @UtilityClass @@ -75,11 +77,15 @@ public static void registerAddModelsEventListener(boolean removeOnReload, EVENT_LISTENERS.add(new EventListenerHolder<>(listener, removeOnReload)); } + private static final AtomicInteger reloadCounter = new AtomicInteger(0); + @SubscribeEvent(priority = EventPriority.HIGH) public static void registerReloadListener(RegisterClientReloadListenersEvent event) { ((ReloadableResourceManagerAccessor) Minecraft.getInstance().getResourceManager()).getListeners() .add(0, (ResourceManagerReloadListener) resourceManager -> { - EVENT_LISTENERS.removeIf(EventListenerHolder::removeOnReload); + if (reloadCounter.addAndGet(1) > 1) { + EVENT_LISTENERS.removeIf(EventListenerHolder::removeOnReload); + } CTM_SPRITE_CACHE.clear(); WRAPPED_MODELS.clear(); @@ -174,7 +180,12 @@ public static void initInternalAssetReloadListeners() { dependencies.push(rl); seenModels.add(rl); - boolean shouldWrap = ModelEventHelper.WRAPPED_MODELS.getOrDefault(rl, false); + boolean shouldWrap = WRAPPED_MODELS.getOrDefault(rl, false); + if (WRAPPED_MODELS.containsKey(rl)) { + // shortcut if the model's already been checked + if (shouldWrap) return new CTMBakedModel<>(baked); + else return baked; + } // Breadth-first loop through dependencies // exiting as soon as a CTM texture is found, and skipping duplicates/cycles PARENT_LOOP: diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java index f31a66b4de9..e77d911a02a 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java @@ -47,7 +47,7 @@ public static void bakeSprite(MutableQuadView quad, @Nullable TextureAtlasSprite // Assigns normalized UV coordinates based on vertex positions applyModifier(quad, UV_LOCKERS[quad.nominalFace().get3DDataValue()]); } else if ((MutableQuadView.BAKE_NORMALIZED & bakeFlags) == 0) { - // flag is NOT set, UVs are assumed to not be normalized yet as is the default, + // flag is NOT set, UVs are assumed to not be normalized yet as is the default. // normalize through dividing by 16 // Scales from 0-16 to 0-1 diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java index 83ac4aebefc..6d1ff7bc06d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java @@ -2,6 +2,7 @@ import com.gregtechceu.gtceu.client.model.ctm.CTMCache; import com.gregtechceu.gtceu.client.model.ctm.ISubmap; +import com.gregtechceu.gtceu.client.model.ctm.Submap; import com.gregtechceu.gtceu.client.model.quad.MeshBuilder; import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; import com.gregtechceu.gtceu.client.util.TextureHelper; @@ -14,9 +15,9 @@ import net.minecraft.util.Mth; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec2; import net.minecraftforge.client.model.IQuadTransformer; -import it.unimi.dsi.fastutil.Pair; import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; import org.joml.Vector3f; @@ -28,7 +29,7 @@ public class QuadUtils { - public static Pair findMinMaxUVs(Vector2f[] uvs) { + public static Vector2f[] findMinMaxUVs(Vector2f[] uvs) { float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE, maxU = Float.MIN_VALUE, maxV = Float.MIN_VALUE; for (int i = 0; i < 4; i++) { @@ -38,7 +39,7 @@ public static Pair findMinMaxUVs(Vector2f[] uvs) { maxU = Math.max(maxU, uv.x()); maxV = Math.max(maxV, uv.y()); } - return Pair.of(new Vector2f(minU, minV), new Vector2f(maxU, maxV)); + return new Vector2f[]{ new Vector2f(minU, minV), new Vector2f(maxU, maxV) }; } public static int findMinUVIndex(Vector2f[] uvs) { @@ -118,10 +119,10 @@ public static List buildCTMQuads(CTMCache cachedConnections, List buildCTMQuads(CTMCache cachedConnections, List 15 ? originalQuad.getSprite() : connection; + TextureAtlasSprite ctmSprite = ctm[quadrant] > 15 ? originalSprite : connectionSprite; emitter.fromVanilla(originalQuad, cullFace); - TextureHelper.normalizeBy(emitter, sprite); + TextureHelper.normalizeBy(emitter, originalSprite); interpolator.setInputQuad(emitter); // slice quad into the current quadrant - subsect(emitter, CTMCache.uvs[ctm[quadrant]].unitScale()); - - interpolator.transform(emitter); + subsect(emitter, Submap.X2[quadrant % 2][quadrant / 2]); + transformUVs(emitter, CTMCache.uvs[ctm[quadrant]]); // derotate quad here - emitter.spriteBake(ctmSprite, BAKE_LOCK_UV | BAKE_NORMALIZED); + emitter.spriteBake(ctmSprite, BAKE_NORMALIZED); + + //interpolator.transform(emitter); emitter.emit(); } @@ -150,6 +152,46 @@ public static List buildCTMQuads(CTMCache cachedConnections, List 0.5f ? 0.5f : 0.0f, maxUV.y > 0.5f ? 0.5f : 0.0f); + Vector2f interpolatedMaxUV = new Vector2f(maxUV.x <= 0.5f ? 0.5f : 1.0f, maxUV.y <= 0.5f ? 0.5f : 1.0f); + + uvs[0] = normalize(interpolatedMinUV, interpolatedMaxUV, uvs[0]); + uvs[1] = normalize(interpolatedMinUV, interpolatedMaxUV, uvs[1]); + uvs[2] = normalize(interpolatedMinUV, interpolatedMaxUV, uvs[2]); + uvs[3] = normalize(interpolatedMinUV, interpolatedMaxUV, uvs[3]); + } + + private static void transformUVs(MutableQuadView quad, ISubmap submap) { + submap = submap.unitScale(); + + Vector2f[] uvs = new Vector2f[4]; + for (int i = 0; i < 4; i++) { + uvs[i] = quad.copyUv(i, uvs[i]); + } + Vector2f[] minMaxUVs = findMinMaxUVs(uvs); + Vector2f minUV = minMaxUVs[0], maxUV = minMaxUVs[1]; + + growQuadrantUVs(uvs, maxUV); + + + float width = maxUV.x - minUV.x; + float height = maxUV.y - minUV.y; + + float minU = submap.getXOffset(); + float minV = submap.getYOffset(); + minU += minUV.x * submap.getWidth(); + minV += minUV.y * submap.getHeight(); + + float maxU = minU + (width * submap.getWidth()); + float maxV = minV + (height * submap.getHeight()); + + quad.uv(0, equal(uvs[0].x, minUV.x) ? minU : maxU, equal(uvs[0].y, minUV.y) ? minV : maxV); + quad.uv(1, equal(uvs[1].x, minUV.x) ? minU : maxU, equal(uvs[1].y, minUV.y) ? minV : maxV); + quad.uv(2, equal(uvs[2].x, minUV.x) ? minU : maxU, equal(uvs[2].y, minUV.y) ? minV : maxV); + quad.uv(3, equal(uvs[3].x, minUV.x) ? minU : maxU, equal(uvs[3].y, minUV.y) ? minV : maxV); + } + // TODO simplify, this is quite long public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { Vector2f[] uvs = new Vector2f[4]; @@ -238,8 +280,16 @@ public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { return quad; } - public static float normalize(float min, float max, float x) { + private static Vector2f normalize(Vector2f min, Vector2f max, Vector2f delta) { + return new Vector2f(normalize(min.x, max.x, delta.x), normalize(min.y, max.y, delta.y)); + } + + public static float normalize(float min, float max, float delta) { if (min == max) return 0.5f; - return Mth.inverseLerp(x, min, max); + return Mth.inverseLerp(delta, min, max); + } + + public static boolean equal(float x, float y) { + return Math.abs(y - x) < 1.0E-2F; } } From d7326c166430f1e9f692ecd475aac97abcbe0396 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:33:48 +0300 Subject: [PATCH 27/66] Make CTMCache have a stable hash --- .../gregtechceu/gtceu/client/model/ctm/CTMCache.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index 36ab302626e..802bc32fdef 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -272,4 +272,15 @@ public boolean connectedOnly(OctagonalOrientation... dirs) { } return map == this.connectionMap; } + + @Override + public int hashCode() { + return this.connectionMap; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof CTMCache other)) return false; + return this.connectionMap == other.connectionMap; + } } From 734ac556cb79b934fc23a988ded0af6ceeca1e9b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:52:28 +0300 Subject: [PATCH 28/66] Fix the quads' UV layout --- .../gtceu/client/util/quad/QuadUtils.java | 100 ++++++++++-------- 1 file changed, 56 insertions(+), 44 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java index 6d1ff7bc06d..e43d87791c8 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java @@ -152,14 +152,20 @@ public static List buildCTMQuads(CTMCache cachedConnections, List 0.5f ? 0.5f : 0.0f, maxUV.y > 0.5f ? 0.5f : 0.0f); - Vector2f interpolatedMaxUV = new Vector2f(maxUV.x <= 0.5f ? 0.5f : 1.0f, maxUV.y <= 0.5f ? 0.5f : 1.0f); - - uvs[0] = normalize(interpolatedMinUV, interpolatedMaxUV, uvs[0]); - uvs[1] = normalize(interpolatedMinUV, interpolatedMaxUV, uvs[1]); - uvs[2] = normalize(interpolatedMinUV, interpolatedMaxUV, uvs[2]); - uvs[3] = normalize(interpolatedMinUV, interpolatedMaxUV, uvs[3]); + float minUInterp = maxUV.x > 0.5f ? 0.5f : 0.0f, + minVInterp = maxUV.y > 0.5f ? 0.5f : 0.0f; + float maxUInterp = maxUV.x > 0.5f ? 1.0f : 0.5f, + maxVInterp = maxUV.y > 0.5f ? 1.0f : 0.5f; + + normalize(minUInterp, minVInterp, maxUInterp, maxVInterp, uvs[0]); + normalize(minUInterp, minVInterp, maxUInterp, maxVInterp, uvs[1]); + normalize(minUInterp, minVInterp, maxUInterp, maxVInterp, uvs[2]); + normalize(minUInterp, minVInterp, maxUInterp, maxVInterp, uvs[3]); } private static void transformUVs(MutableQuadView quad, ISubmap submap) { @@ -170,10 +176,11 @@ private static void transformUVs(MutableQuadView quad, ISubmap submap) { uvs[i] = quad.copyUv(i, uvs[i]); } Vector2f[] minMaxUVs = findMinMaxUVs(uvs); - Vector2f minUV = minMaxUVs[0], maxUV = minMaxUVs[1]; - - growQuadrantUVs(uvs, maxUV); + growQuadrantUVs(uvs, minMaxUVs[1]); + // recompute min & max UVs + minMaxUVs = findMinMaxUVs(uvs); + Vector2f minUV = minMaxUVs[0], maxUV = minMaxUVs[1]; float width = maxUV.x - minUV.x; float height = maxUV.y - minUV.y; @@ -186,12 +193,24 @@ private static void transformUVs(MutableQuadView quad, ISubmap submap) { float maxU = minU + (width * submap.getWidth()); float maxV = minV + (height * submap.getHeight()); - quad.uv(0, equal(uvs[0].x, minUV.x) ? minU : maxU, equal(uvs[0].y, minUV.y) ? minV : maxV); - quad.uv(1, equal(uvs[1].x, minUV.x) ? minU : maxU, equal(uvs[1].y, minUV.y) ? minV : maxV); - quad.uv(2, equal(uvs[2].x, minUV.x) ? minU : maxU, equal(uvs[2].y, minUV.y) ? minV : maxV); - quad.uv(3, equal(uvs[3].x, minUV.x) ? minU : maxU, equal(uvs[3].y, minUV.y) ? minV : maxV); + quad.uv(0, uvs[0].x == minUV.x ? minU : maxU, uvs[0].y == minUV.y ? minV : maxV); + quad.uv(1, uvs[1].x == minUV.x ? minU : maxU, uvs[1].y == minUV.y ? minV : maxV); + quad.uv(2, uvs[2].x == minUV.x ? minU : maxU, uvs[2].y == minUV.y ? minV : maxV); + quad.uv(3, uvs[3].x == minUV.x ? minU : maxU, uvs[3].y == minUV.y ? minV : maxV); } + /** + * Quadrant table is as follows: + *
+     * ╔══════╤══════╗
+     * ║      │      ║
+     * ║  2   │  3   ║
+     * ╟──────┼──────╢
+     * ║      │      ║
+     * ║  0   │  1   ║
+     * ╚══════╧══════╝
+     * 
+ */ // TODO simplify, this is quite long public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { Vector2f[] uvs = new Vector2f[4]; @@ -206,17 +225,11 @@ public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { positions[i] = quad.copyPos(i, positions[idx]); } - Direction normal = quad.nominalFace(); - - Vector2f[] xy = new Vector2f[4]; - Vector2f[] newXy = new Vector2f[4]; - for (int i = 0; i < 4; i++) { switch (normal.getAxis()) { - case Y -> xy[i] = new Vector2f(positions[i].x, positions[i].z); - case Z -> xy[i] = new Vector2f(positions[i].x, positions[i].y); - case X -> xy[i] = new Vector2f(positions[i].z, positions[i].y); + case X -> xy[i].set(position.z, position.y); + case Y -> xy[i].set(position.x, position.z); + case Z -> xy[i].set(position.x, position.y); } - newXy[i] = new Vector2f(); } if (normal.getAxis() != Direction.Axis.Y) { @@ -228,7 +241,7 @@ public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { submap = submap.unitScale(); - if (normal.getAxis() == Direction.Axis.Y || normal.getAxisDirection() == Direction.AxisDirection.POSITIVE) { + if (normal.getAxis() == Direction.Axis.Y || normal == Direction.SOUTH || normal == Direction.WEST) { // Relative X is the same sign for DOWN, UP, SOUTH, and WEST newXy[0].x = Math.max(xy[0].x, submap.getXOffset()); // DUSW newXy[1].x = Math.max(xy[1].x, submap.getXOffset()); // DUSW @@ -255,41 +268,40 @@ public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { newXy[3].y = Math.max(xy[3].y, submap.getYOffset()); // U } - float u0 = normalize(xy[0].x, xy[3].x, newXy[0].x); - float v0 = normalize(xy[0].y, xy[1].y, newXy[0].y); - float u1 = normalize(xy[1].x, xy[2].x, newXy[1].x); - float v1 = normalize(xy[1].y, xy[0].y, newXy[1].y); - float u2 = normalize(xy[2].x, xy[1].x, newXy[2].x); - float v2 = normalize(xy[2].y, xy[3].y, newXy[2].y); - float u3 = normalize(xy[3].x, xy[0].x, newXy[3].x); - float v3 = normalize(xy[3].y, xy[2].y, newXy[3].y); + float u0 = normalize(newXy[0].x, xy[0].x, xy[3].x), + v0 = normalize(newXy[0].y, xy[0].y, xy[1].y); + float u1 = normalize(newXy[1].x, xy[1].x, xy[2].x), + v1 = normalize(newXy[1].y, xy[1].y, xy[0].y); + float u2 = normalize(newXy[2].x, xy[2].x, xy[1].x), + v2 = normalize(newXy[2].y, xy[2].y, xy[3].y); + float u3 = normalize(newXy[3].x, xy[3].x, xy[0].x), + v3 = normalize(newXy[3].y, xy[3].y, xy[2].y); - quad.uv(0, Mth.lerp(uvs[0].x, uvs[3].x, u0), Mth.lerp(uvs[0].y, uvs[1].y, v0)); - quad.uv(1, Mth.lerp(uvs[1].x, uvs[2].x, u1), Mth.lerp(uvs[1].y, uvs[0].y, v1)); - quad.uv(2, Mth.lerp(uvs[2].x, uvs[1].x, u2), Mth.lerp(uvs[2].y, uvs[3].y, v2)); - quad.uv(3, Mth.lerp(uvs[3].x, uvs[0].x, u3), Mth.lerp(uvs[3].y, uvs[2].y, v3)); + quad.uv(0, Mth.lerp(u0, uvs[0].x, uvs[3].x), Mth.lerp(v0, uvs[0].y, uvs[1].y)); + quad.uv(1, Mth.lerp(u1, uvs[1].x, uvs[2].x), Mth.lerp(v1, uvs[1].y, uvs[0].y)); + quad.uv(2, Mth.lerp(u2, uvs[2].x, uvs[1].x), Mth.lerp(v2, uvs[2].y, uvs[3].y)); + quad.uv(3, Mth.lerp(u3, uvs[3].x, uvs[0].x), Mth.lerp(v3, uvs[3].y, uvs[2].y)); for (int i = 0; i < 4; i++) { switch (normal.getAxis()) { + case X -> quad.pos(i, quad.x(i), newXy[i].y, newXy[i].x); case Y -> quad.pos(i, newXy[i].x, quad.y(i), newXy[i].y); case Z -> quad.pos(i, newXy[i].x, newXy[i].y, quad.z(i)); - case X -> quad.pos(i, quad.x(i), newXy[i].y, newXy[i].x); } } return quad; } - private static Vector2f normalize(Vector2f min, Vector2f max, Vector2f delta) { - return new Vector2f(normalize(min.x, max.x, delta.x), normalize(min.y, max.y, delta.y)); + /// scale {@code value} to a 0-1 range component-wise based on {@code min} and {@code max} + private static Vector2f normalize(float minU, float minV, float maxU, float maxV, Vector2f value) { + value.set(normalize(value.x, minU, maxU), normalize(value.y, minV, maxV)); + return value; } - public static float normalize(float min, float max, float delta) { + /// scale {@code delta} to a 0-1 range based on {@code min} and {@code max} + public static float normalize(float delta, float min, float max) { if (min == max) return 0.5f; return Mth.inverseLerp(delta, min, max); } - - public static boolean equal(float x, float y) { - return Math.abs(y - x) < 1.0E-2F; - } } From 8cbb15ce9e7946d6b0ab52f9d698da6d7815676c Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:53:17 +0300 Subject: [PATCH 29/66] Use thread-local variables for vectors to reduce garbage collection pressure --- .../gtceu/client/util/quad/QuadUtils.java | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java index e43d87791c8..3ceb2f5c8dd 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java @@ -168,10 +168,24 @@ private static void growQuadrantUVs(Vector2f[] uvs, Vector2f maxUV) { normalize(minUInterp, minVInterp, maxUInterp, maxVInterp, uvs[3]); } + // these are only used within the below methods, but are stored here as consts to reduce allocations + // because they can be reused infinitely. DO NOT USE OUTSIDE subsect()/transformUVs()!! + + // filled in first copyUv() calls + private static final ThreadLocal uvs = ThreadLocal.withInitial(() -> new Vector2f[4]); + // set in copyPos() calls + private static final ThreadLocal position = ThreadLocal.withInitial(Vector3f::new); + private static final ThreadLocal xy = ThreadLocal.withInitial(() -> { + return new Vector2f[] { new Vector2f(), new Vector2f(), new Vector2f(), new Vector2f() }; + }); + private static final ThreadLocal newXy = ThreadLocal.withInitial(() -> { + return new Vector2f[] { new Vector2f(), new Vector2f(), new Vector2f(), new Vector2f() }; + }); + private static void transformUVs(MutableQuadView quad, ISubmap submap) { submap = submap.unitScale(); - Vector2f[] uvs = new Vector2f[4]; + Vector2f[] uvs = QuadUtils.uvs.get(); for (int i = 0; i < 4; i++) { uvs[i] = quad.copyUv(i, uvs[i]); } @@ -213,17 +227,21 @@ private static void transformUVs(MutableQuadView quad, ISubmap submap) { */ // TODO simplify, this is quite long public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { - Vector2f[] uvs = new Vector2f[4]; + Direction normal = quad.nominalFace(); + + Vector2f[] uvs = QuadUtils.uvs.get(); for (int i = 0; i < 4; i++) { uvs[i] = quad.copyUv(i, uvs[i]); } int firstIndex = findMinUVIndex(uvs); - Vector3f[] positions = new Vector3f[4]; + Vector2f[] xy = QuadUtils.xy.get(); + Vector2f[] newXy = QuadUtils.newXy.get(); + Vector3f position = QuadUtils.position.get(); for (int i = 0; i < 4; i++) { int idx = (firstIndex + i) % 4; - positions[i] = quad.copyPos(i, positions[idx]); - } + // updates position + quad.copyPos(idx, position); switch (normal.getAxis()) { case X -> xy[i].set(position.z, position.y); From 7987e77dc1a5f1250d1b48c5a55e9c6072171bdb Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:54:37 +0300 Subject: [PATCH 30/66] Remove unused bits & bobs --- .../gtceu/client/util/quad/QuadUtils.java | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java index 3ceb2f5c8dd..2dfa6d178f8 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java @@ -6,7 +6,6 @@ import com.gregtechceu.gtceu.client.model.quad.MeshBuilder; import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; import com.gregtechceu.gtceu.client.util.TextureHelper; -import com.gregtechceu.gtceu.client.util.quad.transformers.QuadReInterpolator; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -15,8 +14,6 @@ import net.minecraft.util.Mth; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec2; -import net.minecraftforge.client.model.IQuadTransformer; import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; @@ -57,50 +54,6 @@ public static int findMinUVIndex(Vector2f[] uvs) { return minIndex; } - private static void putVertexData(int[] vertices, int index, Vector3f pos, Vector2f uv) { - int posOffset = index * IQuadTransformer.STRIDE + IQuadTransformer.POSITION; - vertices[posOffset] = Float.floatToRawIntBits(pos.x()); - vertices[posOffset + 1] = Float.floatToRawIntBits(pos.y()); - vertices[posOffset + 2] = Float.floatToRawIntBits(pos.z()); - - int uvOffset = index * IQuadTransformer.STRIDE + IQuadTransformer.UV0; - vertices[uvOffset] = Float.floatToRawIntBits(uv.x()); - vertices[uvOffset + 1] = Float.floatToRawIntBits(uv.y()); - } - - public static Vector2f[] normalizeUVs(Vector2f min, Vector2f max, Vector2f... uvs) { - Vector2f[] ret = new Vector2f[uvs.length]; - for (int i = 0; i < ret.length; i++) { - ret[i] = normalizeUV(min, max, uvs[i]); - } - return ret; - } - - public static Vector2f normalizeUV(TextureAtlasSprite sprite, Vector2f vec) { - return new Vector2f( - Mth.inverseLerp(vec.x(), sprite.getU0(), sprite.getU1()), - Mth.inverseLerp(vec.y(), sprite.getV0(), sprite.getV1())); - } - - public static Vector2f normalizeUV(Vector2f min, Vector2f max, Vector2f vec) { - return new Vector2f( - Mth.inverseLerp(vec.x(), min.x(), max.x()), - Mth.inverseLerp(vec.y(), min.y(), max.y())); - } - - public static Vector2f[] relativizeUVs(TextureAtlasSprite sprite, Vector2f... uvs) { - for (int i = 0; i < uvs.length; i++) { - uvs[i] = relativizeUV(sprite, uvs[i]); - } - return uvs; - } - - public static Vector2f relativizeUV(TextureAtlasSprite sprite, Vector2f vec) { - return new Vector2f( - Mth.lerp(vec.x(), sprite.getU0(), sprite.getU1()), - Mth.lerp(vec.y(), sprite.getV0(), sprite.getV1())); - } - public static List buildCTMQuads(BlockAndTintGetter level, BlockPos pos, BlockState state, List quads, @Nullable Direction cullFace) { CTMCache ctmCache = CTMCache.getInstance(); @@ -116,8 +69,6 @@ public static List buildCTMQuads(CTMCache cachedConnections, List buildCTMQuads(CTMCache cachedConnections, List buildCTMQuads(CTMCache cachedConnections, List Date: Sun, 19 Apr 2026 20:55:38 +0300 Subject: [PATCH 31/66] Fix my UV normalization being bad --- .../gtceu/client/util/TextureHelper.java | 85 +++++++++++++++---- .../gtceu/client/util/quad/QuadUtils.java | 2 +- 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java index e77d911a02a..faf745ffae9 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java @@ -23,6 +23,8 @@ import lombok.experimental.UtilityClass; import org.jetbrains.annotations.Nullable; +import static com.gregtechceu.gtceu.client.model.quad.MutableQuadView.*; + /** * Handles most texture-baking use cases for model loaders and model libraries via * {@link #bakeSprite(MutableQuadView, TextureAtlasSprite, int)}. @@ -31,22 +33,26 @@ public class TextureHelper { public static final float NORMALIZER = 1f / 16f; + public static final float DENORMALIZER = 16f; - private static final int BAKE_ROTATE_ANY = 3; + private static final int BAKE_ROTATE_ANY = BAKE_ROTATE_270 | BAKE_ROTATE_180 | BAKE_ROTATE_90; /** * Bakes textures in the provided vertex data, handling UV locking, rotation, interpolation, etc. * Textures must not be already baked. * *

- * If {@code sprite == null}, only the UV modifiers will be applied, but they won't be translated to the sprite's - * atlas coordinates. + * If {@code sprite == null}, only the UV modifiers will be applied, + * but they won't be translated to the sprite's atlas coordinates. + * + * @see #unbakeSprite(MutableQuadView, TextureAtlasSprite, int) + * @see MutableQuadView#BAKE_ROTATE_NONE bake flags */ public static void bakeSprite(MutableQuadView quad, @Nullable TextureAtlasSprite sprite, int bakeFlags) { - if (quad.nominalFace() != null && (MutableQuadView.BAKE_LOCK_UV & bakeFlags) != 0) { + if (quad.nominalFace() != null && (BAKE_LOCK_UV & bakeFlags) != 0) { // Assigns normalized UV coordinates based on vertex positions applyModifier(quad, UV_LOCKERS[quad.nominalFace().get3DDataValue()]); - } else if ((MutableQuadView.BAKE_NORMALIZED & bakeFlags) == 0) { + } else if ((BAKE_NORMALIZED & bakeFlags) == 0) { // flag is NOT set, UVs are assumed to not be normalized yet as is the default. // normalize through dividing by 16 @@ -62,12 +68,12 @@ public static void bakeSprite(MutableQuadView quad, @Nullable TextureAtlasSprite applyModifier(quad, ROTATIONS[rotation]); } - if ((MutableQuadView.BAKE_FLIP_U & bakeFlags) != 0) { + if ((BAKE_FLIP_U & bakeFlags) != 0) { // Inverts U coordinates. Assumes normalized (0-1) values. applyModifier(quad, (q, i) -> q.uv(i, 1 - q.u(i), q.v(i))); } - if ((MutableQuadView.BAKE_FLIP_V & bakeFlags) != 0) { + if ((BAKE_FLIP_V & bakeFlags) != 0) { // Inverts V coordinates. Assumes normalized (0-1) values. applyModifier(quad, (q, i) -> q.uv(i, q.u(i), 1 - q.v(i))); } @@ -92,23 +98,66 @@ public static void interpolate(MutableQuadView q, TextureAtlasSprite sprite) { } } + /** + * The reverse operation of {@link #bakeSprite}. Undoes the same operations except UV locking. + * Textures must be already baked. + * + *

+ * Note this the function's order of operations is reversed in relation to {@link #bakeSprite}.
+ * The {@link MutableQuadView#BAKE_NORMALIZED BAKE_NORMALIZED} flag also works inversely + * to the one in {@link #bakeSprite}. + * + *

+ * If {@code sprite == null}, only the UV modifiers will be applied, + * but they won't be translated from the sprite's atlas coordinates to a 0-16 range. + * + * @see #bakeSprite(MutableQuadView, TextureAtlasSprite, int) + * @see MutableQuadView#BAKE_ROTATE_NONE bake flags + */ + public static void unbakeSprite(MutableQuadView quad, @Nullable TextureAtlasSprite sprite, int bakeFlags) { + if (sprite != null) { + deInterpolate(quad, sprite); + } + + if ((BAKE_FLIP_V & bakeFlags) != 0) { + // Inverts V coordinates. Assumes normalized (0-1) values. + applyModifier(quad, (q, i) -> q.uv(i, q.u(i), 1 - q.v(i))); + } + + if ((BAKE_FLIP_U & bakeFlags) != 0) { + // Inverts U coordinates. Assumes normalized (0-1) values. + applyModifier(quad, (q, i) -> q.uv(i, 1 - q.u(i), q.v(i))); + } + + final int rotation = bakeFlags & BAKE_ROTATE_ANY; + + if (rotation != 0) { + // Rotates texture around the center of sprite. + // Assumes normalized coordinates. + applyModifier(quad, ROTATIONS[rotation]); + } + + if ((BAKE_NORMALIZED & bakeFlags) == 0) { + // flag is NOT set, UVs are assumed to be normalized as is the default. + // denormalize through multiplying by 16 + + // Scales from 0-1 to 0-16 + applyModifier(quad, (q, i) -> q.uv(i, q.u(i) * DENORMALIZER, q.v(i) * DENORMALIZER)); + } + } + /** * Faster than sprite method. Sprite computes span and normalizes inputs each call, so we'd have to denormalize * before we called, only to have the sprite renormalize immediately. */ - public static void normalizeBy(MutableQuadView q, TextureAtlasSprite sprite) { - final float uMin = sprite.getU0(), uMax = sprite.getU1(); - final float uSpan = uMax - uMin; - final float vMin = sprite.getV0(), vMax = sprite.getV1(); - final float vSpan = vMax - vMin; + public static void deInterpolate(MutableQuadView q, TextureAtlasSprite sprite) { + final float uMin = sprite.getU0(); + final float uSpan = sprite.getU1() - uMin; + final float vMin = sprite.getV0(); + final float vSpan = sprite.getV1() - vMin; for (int i = 0; i < 4; i++) { - final float u = q.u(i), v = q.v(i); - // Skip invalid UV coordinates. - // If the UV is outside the texture's boundaries, this was probably called by mistake. - if (u < uMin || u > uMax || v < vMin || v > vMax) continue; - - q.uv(i, (u - uMin) / uSpan, (v - vMin) / vSpan); + q.uv(i, (q.u(i) - uMin) / uSpan, (q.v(i) - vMin) / vSpan); } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java index 2dfa6d178f8..701923392e4 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java @@ -85,7 +85,7 @@ public static List buildCTMQuads(CTMCache cachedConnections, List 15 ? originalSprite : connectionSprite; emitter.fromVanilla(originalQuad, cullFace); - TextureHelper.normalizeBy(emitter, originalSprite); + TextureHelper.unbakeSprite(emitter, originalSprite, BAKE_NORMALIZED); // slice quad into the current quadrant subsect(emitter, Submap.X2[quadrant % 2][quadrant / 2]); From 70dce9e5071728e73c5ff1041b4825e8031e37ab Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:56:34 +0300 Subject: [PATCH 32/66] Make Submap lookup use a 2D array as the LUT --- .../gtceu/client/model/ctm/CTMBakedModel.java | 2 +- .../gtceu/client/model/ctm/CTMCache.java | 123 +++++++++--------- .../gtceu/client/model/ctm/Submap.java | 23 ++-- .../gtceu/client/util/quad/QuadUtils.java | 37 +++--- 4 files changed, 90 insertions(+), 95 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java index 0bb2ad76b67..ca25fea962d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java @@ -47,7 +47,7 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction } CTMCache ctmCache = CTMCache.getInstance(); - ctmCache.getSubmapIds(level, pos, state, side); + ctmCache.fillSubmapCache(level, pos, state, side); return this.sideCache.computeIfAbsent(side, $ -> new ConcurrentHashMap<>()) .computeIfAbsent(ctmCache, cache -> QuadUtils.buildCTMQuads(cache, super.getQuads(state, side, rand, parentModelData, renderType), side)); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index 802bc32fdef..5a0a699667d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -24,52 +24,55 @@ import lombok.experimental.Accessors; import org.jetbrains.annotations.Nullable; +import org.joml.Vector2i; +import org.joml.Vector2ic; import static com.gregtechceu.gtceu.client.model.ctm.OctagonalOrientation.*; -// @formatter:off /** * The CTM renderer will draw the block's FACE by assembling 4 quadrants from the 5 available block textures. - * The normal {@code texture.png} is the block's "unconnected" texture, and is used when CTM is disabled or the block has nothing to connect to. + * The normal {@code texture.png} is the block's "unconnected" texture, and is used when CTM is disabled or the block + * has nothing to connect to. * This texture has all the outside corner quadrants, and {@code texture_ctm.png} contains the rest of the quadrants. *

  * ┌─────────────────┐ ┌────────────────────────────────┐
  * │ texture.png     │ │ texture_ctm.png                │
  * │ ╔══════╤══════╗ │ │  ──────┼────── ║ ─────┼───── ║ │
  * │ ║      │      ║ │ │ │      │      │║      │      ║ │
- * │ ║ 16   │ 17   ║ │ │ │ 0    │ 1    │║ 2    │ 3    ║ │
+ * │ ║ 4/4  │ 4/5  ║ │ │ │ 0/0  │ 1/0  │║ 2/0  │ 3/0  ║ │
  * │ ╟──────┼──────╢ │ │ ┼──────┼──────┼╟──────┼──────╢ │
  * │ ║      │      ║ │ │ │      │      │║      │      ║ │
- * │ ║ 18   │ 19   ║ │ │ │ 4    │ 5    │║ 6    │ 7    ║ │
+ * │ ║ 5/4  │ 5/5  ║ │ │ │ 0/1  │ 1/1  │║ 2/1  │ 3/1  ║ │
  * │ ╚══════╧══════╝ │ │  ──────┼────── ║ ─────┼───── ║ │
  * └─────────────────┘ │ ═══════╤═══════╝ ─────┼───── ╚ │
  *                     │ │      │      ││      │      │ │
- *                     │ │ 8    │ 9    ││ 10   │ 11   │ │
+ *                     │ │ 0/2  │ 1/2  ││ 2/2  │ 3/2  │ │
  *                     │ ┼──────┼──────┼┼──────┼──────┼ │
  *                     │ │      │      ││      │      │ │
- *                     │ │ 12   │ 13   ││ 14   │ 15   │ │
+ *                     │ │ 0/3  │ 1/3  ││ 2/3  │ 3/3  │ │
  *                     │ ═══════╧═══════╗ ─────┼───── ╔ │
  *                     └────────────────────────────────┘
  * 
- * combining { 18, 13, 9, 16 }, we can generate a texture connected to the right! + * combining { { 5/4, 1/3 }, { 1/2, 4/4 } }, we can generate a texture connected to the right! *
  * ╔══════╤═══════
  * ║      │      │
- * ║ 16   │ 9    │
+ * ║ 4/4  │ 1/2  │
  * ╟──────┼──────┼
  * ║      │      │
- * ║ 18   │ 13   │
+ * ║ 5/4  │ 1/3  │
  * ╚══════╧═══════
  * 
* - * combining { 18, 13, 11, 2 }, we can generate a texture, in the shape of an L (connected to the right, and up + * combining { { 5/4, 1/3 }, { 3/2, 2/0 } }, we can generate a texture in the shape of an L + * (connected to the right and up) *
  * ║ ─────┼───── ╚
  * ║      │      │
- * ║ 2    │ 11   │
+ * ║ 2/0  │ 3/2  │
  * ╟──────┼──────┼
  * ║      │      │
- * ║ 18   │ 13   │
+ * ║ 5/4  │ 1/3  │
  * ╚══════╧═══════
  * 
* @@ -84,51 +87,27 @@ public class CTMCache { @FunctionalInterface public interface StateComparisonCallback { - StateComparisonCallback DEFAULT = (connectionCheck, from, to, dir) -> connectionCheck.ignoreStates() ? from.getBlock() == to.getBlock() : from == to; + StateComparisonCallback DEFAULT = (connectionCheck, from, to, dir) -> { + return connectionCheck.ignoreStates() ? from.getBlock() == to.getBlock() : from == to; + }; boolean connects(ConnectionCheck instance, BlockState from, BlockState to, Direction dir); } - - /** - * The UVs for the specific "magic number" value - */ - public static final ISubmap[] uvs = { - // CTM texture - Submap.fromPixelScale(4, 4, 0, 0), // 0 - Submap.fromPixelScale(4, 4, 4, 0), // 1 - Submap.fromPixelScale(4, 4, 8, 0), // 2 - Submap.fromPixelScale(4, 4, 12, 0), // 3 - Submap.fromPixelScale(4, 4, 0, 4), // 4 - Submap.fromPixelScale(4, 4, 4, 4), // 5 - Submap.fromPixelScale(4, 4, 8, 4), // 6 - Submap.fromPixelScale(4, 4, 12, 4), // 7 - Submap.fromPixelScale(4, 4, 0, 8), // 8 - Submap.fromPixelScale(4, 4, 4, 8), // 9 - Submap.fromPixelScale(4, 4, 8, 8), // 10 - Submap.fromPixelScale(4, 4, 12, 8), // 11 - Submap.fromPixelScale(4, 4, 0, 12), // 12 - Submap.fromPixelScale(4, 4, 4, 12), // 13 - Submap.fromPixelScale(4, 4, 8, 12), // 14 - Submap.fromPixelScale(4, 4, 12, 12), // 15 - // Default texture - Submap.fromPixelScale(8, 8, 0, 0), // 16 - Submap.fromPixelScale(8, 8, 8, 0), // 17 - Submap.fromPixelScale(8, 8, 0, 8), // 18 - Submap.fromPixelScale(8, 8, 8, 8) // 19 - }; - - public static final ISubmap FULL_TEXTURE = Submap.X1; - - // @formatter:on /** Some hardcoded offset values for the different corner indeces */ - protected static int[] submapOffsets = { 4, 5, 1, 0 }; - protected static int[] defaultSubmapCache = { 18, 19, 17, 16 }; + protected static Vector2ic[][] submapOffsets = { + { new Vector2i(0, 3), new Vector2i(1, 3) }, + { new Vector2i(0, 2), new Vector2i(1, 2) }, + }; + protected static Vector2ic[][] defaultSubmapCache = { + { new Vector2i(4, 5), new Vector2i(5, 5) }, + { new Vector2i(4, 4), new Vector2i(5, 4) }, + }; // TODO encapsulate public ConnectionCheck connectionCheck = new ConnectionCheck(); - // Mapping the different corner indeces to their respective dirs + // Mapping the different corner indices to their respective dirs protected static final OctagonalOrientation[][] submapMap = { { BOTTOM, LEFT, BOTTOM_LEFT }, { BOTTOM, RIGHT, BOTTOM_RIGHT }, @@ -137,7 +116,7 @@ public interface StateComparisonCallback { }; protected byte connectionMap; - protected int[] submapCache = defaultSubmapCache.clone(); + protected Vector2ic[][] submapCache = defaultSubmapCache.clone(); public static CTMCache getInstance() { return new CTMCache(); @@ -148,21 +127,24 @@ public static CTMCache getInstance() { * * @return The indeces of the typical 4x4 submap to use for the given face at the given location. */ - public int[] getSubmapIds(@Nullable BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side) { + public Vector2ic[][] fillSubmapCache(@Nullable BlockAndTintGetter level, BlockPos pos, + BlockState state, Direction side) { if (level == null) { return this.submapCache; } buildConnectionMap(level, pos, state, side); // Map connections to submap indices - for (int i = 0; i < 4; i++) { - fillSubmaps(i); + for (int x = 0; x < 2; x++) { + for (int y = 0; y < 2; y++) { + fillSubmaps(x, y); + } } return this.submapCache; } - public int[] getSubmapIndices() { + public Vector2ic[][] getCachedSubmapIndices() { return this.submapCache; } @@ -170,6 +152,18 @@ public static boolean isDefaultTexture(int id) { return (id == 16 || id == 17 || id == 18 || id == 19); } + public static boolean isDefaultTexture(Vector2ic id) { + return id.x() >= 4 && id.y() >= 4; + } + + public static ISubmap getSubmapFor(Vector2ic coordinates) { + if (isDefaultTexture(coordinates)) { + return Submap.X2[coordinates.x() % 4][coordinates.y() % 4]; + } else { + return Submap.X4[(coordinates.x() + 2) % 4][(coordinates.y() + 2) % 4]; + } + } + protected void setConnectedState(OctagonalOrientation dir, boolean connected) { this.connectionMap = setConnectedState(this.connectionMap, dir, connected); } @@ -199,25 +193,25 @@ public void buildConnectionMap(BlockAndTintGetter world, BlockPos pos, BlockStat } @SuppressWarnings("null") - protected void fillSubmaps(int idx) { - OctagonalOrientation[] dirs = submapMap[idx]; + protected void fillSubmaps(int x, int y) { + OctagonalOrientation[] dirs = submapMap[x + y * 2]; if (connectedOr(dirs[0], dirs[1])) { if (connectedAnd(dirs)) { // If all dirs are connected, we use the fully connected face, the base offset value. - this.submapCache[idx] = submapOffsets[idx]; + this.submapCache[x][y] = submapOffsets[x][y]; } else { - // This is a bit magic-y, but basically the array is ordered so - // the first dir requires an offset of 2, and the second dir requires an offset of 8 - // plus the initial offset for the corner. - this.submapCache[idx] = submapOffsets[idx] + (connected(dirs[0]) ? 2 : 0) + - (connected(dirs[1]) ? 8 : 0); + // dirs[0] is vertical, dirs[1] is horizontal + Vector2i offsets = new Vector2i(submapOffsets[x][y]); + if (connected(dirs[0])) offsets.x += 2; + if (connected(dirs[1])) offsets.y += 2; + + this.submapCache[x][y] = offsets; } } } /** - * @param dir - * The direction to check connection in. + * @param dir The direction to check connection in. * @return True if the cached connectionMap holds a connection in this {@link OctagonalOrientation direction}. */ public boolean connected(OctagonalOrientation dir) { @@ -225,8 +219,7 @@ public boolean connected(OctagonalOrientation dir) { } /** - * @param dirs - * The directions to check connection in. + * @param dirs The directions to check connection in. * @return True if the cached connectionMap holds a connection in all the given * {@link OctagonalOrientation directions}. */ diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java index 56f7c2e3be1..3fbfba47392 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java @@ -25,6 +25,7 @@ */ public class Submap implements ISubmap { + // spotless:off public static final ISubmap X1 = fromPixelScale(16, 16, 0, 0); public static final ISubmap[][] X2 = { @@ -34,24 +35,18 @@ public class Submap implements ISubmap { private static final float DIV3 = 16 / 3f; public static final ISubmap[][] X3 = { - { fromPixelScale(DIV3, DIV3, 0, 0), fromPixelScale(DIV3, DIV3, DIV3, 0), - fromPixelScale(DIV3, DIV3, DIV3 * 2, 0) }, - { fromPixelScale(DIV3, DIV3, 0, DIV3), fromPixelScale(DIV3, DIV3, DIV3, DIV3), - fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3) }, - { fromPixelScale(DIV3, DIV3, 0, DIV3 * 2), fromPixelScale(DIV3, DIV3, DIV3, DIV3 * 2), - fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3 * 2) }, + { fromPixelScale(DIV3, DIV3, 0, 0), fromPixelScale(DIV3, DIV3, DIV3, 0), fromPixelScale(DIV3, DIV3, DIV3 * 2, 0) }, + { fromPixelScale(DIV3, DIV3, 0, DIV3), fromPixelScale(DIV3, DIV3, DIV3, DIV3), fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3) }, + { fromPixelScale(DIV3, DIV3, 0, DIV3 * 2), fromPixelScale(DIV3, DIV3, DIV3, DIV3 * 2), fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3 * 2) }, }; public static final ISubmap[][] X4 = { - { fromPixelScale(4, 4, 0, 0), fromPixelScale(4, 4, 4, 0), fromPixelScale(4, 4, 8, 0), - fromPixelScale(4, 4, 12, 0) }, - { fromPixelScale(4, 4, 0, 4), fromPixelScale(4, 4, 4, 4), fromPixelScale(4, 4, 8, 4), - fromPixelScale(4, 4, 12, 4) }, - { fromPixelScale(4, 4, 0, 8), fromPixelScale(4, 4, 4, 8), fromPixelScale(4, 4, 8, 8), - fromPixelScale(4, 4, 12, 8) }, - { fromPixelScale(4, 4, 0, 12), fromPixelScale(4, 4, 4, 12), fromPixelScale(4, 4, 8, 12), - fromPixelScale(4, 4, 12, 12) }, + { fromPixelScale(4, 4, 0, 0), fromPixelScale(4, 4, 4, 0), fromPixelScale(4, 4, 8, 0), fromPixelScale(4, 4, 12, 0) }, + { fromPixelScale(4, 4, 0, 4), fromPixelScale(4, 4, 4, 4), fromPixelScale(4, 4, 8, 4), fromPixelScale(4, 4, 12, 4) }, + { fromPixelScale(4, 4, 0, 8), fromPixelScale(4, 4, 4, 8), fromPixelScale(4, 4, 8, 8), fromPixelScale(4, 4, 12, 8) }, + { fromPixelScale(4, 4, 0, 12), fromPixelScale(4, 4, 4, 12), fromPixelScale(4, 4, 8, 12), fromPixelScale(4, 4, 12, 12) }, }; + // spotless:on public static ISubmap[][] grid(int w, int h) { float xDiv = 16f / w; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java index 701923392e4..98c85e376e9 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java @@ -17,8 +17,10 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; +import org.joml.Vector2ic; import org.joml.Vector3f; +import java.util.LinkedList; import java.util.List; import static com.gregtechceu.gtceu.client.model.quad.MutableQuadView.*; @@ -58,7 +60,7 @@ public static List buildCTMQuads(BlockAndTintGetter level, BlockPos p List quads, @Nullable Direction cullFace) { CTMCache ctmCache = CTMCache.getInstance(); if (cullFace != null) { - ctmCache.getSubmapIds(level, pos, state, cullFace); + ctmCache.fillSubmapCache(level, pos, state, cullFace); } return buildCTMQuads(ctmCache, quads, cullFace); @@ -66,6 +68,7 @@ public static List buildCTMQuads(BlockAndTintGetter level, BlockPos p public static List buildCTMQuads(CTMCache cachedConnections, List base, @Nullable Direction cullFace) { + List result = new LinkedList<>(); MeshBuilder meshBuilder = MeshBuilder.getInstance(); var emitter = meshBuilder.getEmitter(); @@ -74,31 +77,35 @@ public static List buildCTMQuads(CTMCache cachedConnections, List 15 ? originalSprite : connectionSprite; + for (int xQ = 0; xQ < 2; xQ++) { + for (int yQ = 0; yQ < 2; yQ++) { + boolean defaultTexture = CTMCache.isDefaultTexture(ctm[xQ][yQ]); + TextureAtlasSprite ctmSprite = defaultTexture ? originalSprite : connectionSprite; - emitter.fromVanilla(originalQuad, cullFace); - TextureHelper.unbakeSprite(emitter, originalSprite, BAKE_NORMALIZED); + emitter.fromVanilla(originalQuad, cullFace); + TextureHelper.unbakeSprite(emitter, originalSprite, BAKE_NORMALIZED); - // slice quad into the current quadrant - subsect(emitter, Submap.X2[quadrant % 2][quadrant / 2]); - transformUVs(emitter, CTMCache.uvs[ctm[quadrant]]); + // slice quad into the current quadrant + subsect(emitter, Submap.X2[yQ][xQ]); + transformUVs(emitter, CTMCache.getSubmapFor(ctm[xQ][yQ])); - // derotate quad here - emitter.spriteBake(ctmSprite, BAKE_NORMALIZED); + emitter.spriteBake(ctmSprite, BAKE_NORMALIZED); + emitter.computeGeometry(); + emitter.populateMissingNormals(); - emitter.emit(); + result.add(emitter.toBakedQuad(ctmSprite)); + emitter.emit(); + } } } - return meshBuilder.build().toBakedBlockQuads(); + return result; } /** From 8498f991f8eacc20733f8ff35e9a515e344ee999 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:57:22 +0300 Subject: [PATCH 33/66] Clean up related util files & improve new ones' documentation(s) --- .../gtceu/client/model/quad/Mesh.java | 2 +- .../gtceu/client/model/quad/QuadView.java | 65 ++++++++++++++++--- .../gtceu/client/model/quad/SpriteFinder.java | 31 ++++----- .../gtceu/client/util/RenderUtil.java | 8 +-- .../gtceu/utils/GTMatrixUtils.java | 11 ++-- 5 files changed, 78 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java index 43f0d6610b4..29403d1af8a 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java @@ -55,7 +55,7 @@ void forEach(Consumer consumer, QuadView cursor) { } @SuppressWarnings("deprecation") - public List toBakedBlockQuads() { + public List toBlockBakedQuads() { SpriteFinder finder = SpriteFinder.get(Minecraft.getInstance().getModelManager() .getAtlas(TextureAtlas.LOCATION_BLOCKS)); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java index 34b292774a7..d5d6726ea86 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java @@ -22,10 +22,11 @@ import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; -import net.minecraftforge.client.model.QuadTransformers; import lombok.Getter; import lombok.experimental.Accessors; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.UnknownNullability; import org.joml.Vector2f; @@ -72,7 +73,13 @@ public class QuadView { protected int tintIndex; protected long headerFlags = 0; - /** Size and where it comes from will vary in subtypes. But in all cases quad is fully encoded to array. */ + /** + * Size and where it comes from will vary in subtypes. But in all cases quad is fully encoded to array. + * + * -- GETTER -- + * Reference to underlying array. Use with caution. Meant for fast renderer access + */ + @Getter protected int @UnknownNullability [] data; /** Beginning of the quad. Also the header index. */ @@ -99,11 +106,6 @@ public final void load() { GeometryHelper.computeFaceNormal(faceNormal, this); } - /** Reference to underlying array. Use with caution. Meant for fast renderer access */ - public int[] data() { - return data; - } - public int normalFlags() { return EncodingFormat.normalFlags(headerFlags); } @@ -113,7 +115,8 @@ public boolean hasVertexNormals() { return normalFlags() != 0; } - protected void computeGeometry() { + @ApiStatus.Internal + public void computeGeometry() { if (isGeometryInvalid) { isGeometryInvalid = false; @@ -161,6 +164,7 @@ public final Vector3f faceNormal() { * calling {link QuadEmitter#emit()} on the target instance. Meant for re-texturing, analysis and static * transformation use cases. */ + @Contract(mutates = "param") public void copyTo(MutableQuadView quad) { computeGeometry(); @@ -174,8 +178,12 @@ public void copyTo(MutableQuadView quad) { } /** - * Pass a non-null target to avoid allocation - will be returned with values. Otherwise returns a new instance. + * Returns the specified vertex's geometric position. + * + *

+ * Pass a non-null target to avoid allocation - will be returned with values. Otherwise, returns a new instance. */ + @Contract(value = "_, !null -> param2; _, null -> new", mutates = "param2") public Vector3f copyPos(int vertexIndex, @Nullable Vector3f target) { if (target == null) { target = new Vector3f(); @@ -188,9 +196,23 @@ public Vector3f copyPos(int vertexIndex, @Nullable Vector3f target) { } /** + * Returns the specified vertex's geometric position. + */ + @Contract(value = "_ -> new", pure = true) + public Vector3f copyPos(int vertexIndex) { + return copyPos(vertexIndex, null); + } + + /** + * Returns the specified vertex's normal vector. + * + *

* Pass a non-null target to avoid allocation - will be returned with values. Otherwise, returns a new instance. + * + *

* Returns null if normal not present. */ + @Contract(value = "_, !null -> param2; _, null -> new", mutates = "param2") public @Nullable Vector3f copyNormal(int vertexIndex, @Nullable Vector3f target) { if (hasNormal(vertexIndex)) { if (target == null) { @@ -208,8 +230,23 @@ public Vector3f copyPos(int vertexIndex, @Nullable Vector3f target) { } /** - * Pass a non-null target to avoid allocation - will be returned with values. Otherwise returns a new instance. + * Returns the specified vertex's normal vector. + * + *

+ * Returns null if normal not present. */ + @Contract(value = "_ -> new", pure = true) + public @Nullable Vector3f copyNormal(int vertexIndex) { + return copyNormal(vertexIndex, null); + } + + /** + * Returns the specified vertex's UV coordinates. + * + *

+ * Pass a non-null target to avoid allocation - will be returned with values. Otherwise, returns a new instance. + */ + @Contract(value = "_, !null -> param2; _, null -> new", mutates = "param2") public Vector2f copyUv(int vertexIndex, @Nullable Vector2f target) { if (target == null) { target = new Vector2f(); @@ -219,6 +256,14 @@ public Vector2f copyUv(int vertexIndex, @Nullable Vector2f target) { return target; } + /** + * Returns the specified vertex's UV coordinates. + */ + @Contract(value = "_ -> new", pure = true) + public Vector2f copyUv(int vertexIndex) { + return copyUv(vertexIndex, null); + } + /** * Retrieve geometric position, x coordinate. */ diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java index a7c67f1cb40..b77c1b59d64 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java @@ -49,11 +49,11 @@ public static SpriteFinder get(TextureAtlas atlas) { } private final Node root; - private final TextureAtlas spriteAtlasTexture; + private final TextureAtlas textureAtlas; - public SpriteFinder(Map sprites, TextureAtlas spriteAtlasTexture) { + public SpriteFinder(Map sprites, TextureAtlas textureAtlas) { root = new Node(0.5f, 0.5f, 0.25f); - this.spriteAtlasTexture = spriteAtlasTexture; + this.textureAtlas = textureAtlas; sprites.values().forEach(root::add); } @@ -95,17 +95,14 @@ public TextureAtlasSprite find(float u, float v) { private class Node { - final float midU; - final float midV; - final float cellRadius; - @Nullable - Object lowLow = null; - @Nullable - Object lowHigh = null; - @Nullable - Object highLow = null; - @Nullable - Object highHigh = null; + private final float midU; + private final float midV; + private final float cellRadius; + + private @Nullable Object lowLow = null; + private @Nullable Object lowHigh = null; + private @Nullable Object highLow = null; + private @Nullable Object highHigh = null; Node(float midU, float midV, float radius) { this.midU = midU; @@ -147,8 +144,8 @@ private void addInner(TextureAtlasSprite sprite, @Nullable Object quadrant, int } else { Node n = new Node(midU + cellRadius * uStep, midV + cellRadius * vStep, cellRadius * 0.5f); - if (quadrant instanceof TextureAtlasSprite) { - n.add((TextureAtlasSprite) quadrant); + if (quadrant instanceof TextureAtlasSprite quadrantSprite) { + n.add(quadrantSprite); } n.add(sprite); @@ -170,7 +167,7 @@ private TextureAtlasSprite findInner(@Nullable Object quadrant, float u, float v } else if (quadrant instanceof Node node) { return node.find(u, v); } else { - return spriteAtlasTexture.getSprite(MissingTextureAtlasSprite.getLocation()); + return textureAtlas.getSprite(MissingTextureAtlasSprite.getLocation()); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/RenderUtil.java b/src/main/java/com/gregtechceu/gtceu/client/util/RenderUtil.java index 663c823b530..2fe929c0818 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/RenderUtil.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/RenderUtil.java @@ -61,10 +61,6 @@ @OnlyIn(Dist.CLIENT) public class RenderUtil { - public static BakedModel getModelForState(BlockState state) { - return Minecraft.getInstance().getBlockRenderer().getBlockModel(state); - } - public enum FluidTextureType { STILL((fluidTypeExtensions, fluidStack) -> { @@ -220,6 +216,10 @@ public static void moveToFace(PoseStack poseStack, float x, float y, float z, Di Math.fma(face.getStepZ(), 0.5f, z)); } + public static BakedModel getModelForState(BlockState state) { + return Minecraft.getInstance().getBlockRenderer().getBlockModel(state); + } + public static void drawBlock(BlockAndTintGetter level, BlockPos pos, BlockState state, MultiBufferSource bufferSource, PoseStack poseStack) { int packedLight = LevelRenderer.getLightColor(level, state, pos); diff --git a/src/main/java/com/gregtechceu/gtceu/utils/GTMatrixUtils.java b/src/main/java/com/gregtechceu/gtceu/utils/GTMatrixUtils.java index 44f6ad29e34..b5b9d31a626 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/GTMatrixUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/GTMatrixUtils.java @@ -6,7 +6,6 @@ import net.minecraft.util.Mth; import com.google.common.collect.HashBasedTable; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.Table; import com.google.common.collect.Tables; import org.jetbrains.annotations.Contract; @@ -14,7 +13,8 @@ import java.lang.Math; import java.security.InvalidParameterException; -import java.util.Objects; +import java.util.EnumMap; +import java.util.Map; import javax.annotation.ParametersAreNonnullByDefault; @@ -22,13 +22,10 @@ @MethodsReturnNonnullByDefault public class GTMatrixUtils { - @SuppressWarnings("UnstableApiUsage") - private static final ImmutableMap directionAxises = Util.make(() -> { - ImmutableMap.Builder map = ImmutableMap.builderWithExpectedSize(6); + private static final Map directionAxes = Util.make(new EnumMap<>(Direction.class), map -> { for (Direction dir : GTUtil.DIRECTIONS) { map.put(dir, dir.step()); } - return map.build(); }); private static final Table rotations = Tables .synchronizedTable(HashBasedTable.create()); @@ -160,6 +157,6 @@ public static Matrix4fc createRotationState(Direction frontFace, Direction upwar } public static Vector3fc getDirectionAxis(Direction dir) { - return Objects.requireNonNull(directionAxises.get(dir)); + return directionAxes.get(dir); } } From 2f61fe3cc429c8d988caba2f3e28261060c9badd Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 21:06:00 +0300 Subject: [PATCH 34/66] Fix lamp model wrapping corrupting block models --- .../java/com/gregtechceu/gtceu/common/item/LampBlockItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java index 45ce8c53b40..2c4f9de17f7 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/LampBlockItem.java @@ -110,7 +110,7 @@ private static void registerEventListener(LampBlockItem toWrap) { // unwrap ModelResourceLocations // 1.21 needs different code here as ModelResourceLocation is a wrapper record instead of a subclass possibleItemId = modelResLoc.withPrefix(""); - } else if (!modelLocation.getPath().startsWith("item/")) { + } else if (modelLocation.getPath().startsWith("item/")) { // remove the "item/" prefix from the model path possibleItemId = modelLocation.withPath(path -> path.substring("item/".length())); } else { From 874c0b0d4ecea4978c95c887a55728a34d4f5685 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 22:09:36 +0300 Subject: [PATCH 35/66] Bad direction offset doc --- .../gtceu/client/model/ctm/CTMCache.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index 5a0a699667d..22b63914809 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -39,40 +39,40 @@ * │ texture.png │ │ texture_ctm.png │ * │ ╔══════╤══════╗ │ │ ──────┼────── ║ ─────┼───── ║ │ * │ ║ │ ║ │ │ │ │ │║ │ ║ │ - * │ ║ 4/4 │ 4/5 ║ │ │ │ 0/0 │ 1/0 │║ 2/0 │ 3/0 ║ │ + * │ ║ 5/4 │ 5/5 ║ │ │ │ 3/0 │ 3/1 │║ 3/2 │ 3/3 ║ │ * │ ╟──────┼──────╢ │ │ ┼──────┼──────┼╟──────┼──────╢ │ * │ ║ │ ║ │ │ │ │ │║ │ ║ │ - * │ ║ 5/4 │ 5/5 ║ │ │ │ 0/1 │ 1/1 │║ 2/1 │ 3/1 ║ │ + * │ ║ 4/4 │ 4/5 ║ │ │ │ 2/0 │ 2/1 │║ 2/2 │ 2/3 ║ │ * │ ╚══════╧══════╝ │ │ ──────┼────── ║ ─────┼───── ║ │ * └─────────────────┘ │ ═══════╤═══════╝ ─────┼───── ╚ │ * │ │ │ ││ │ │ │ - * │ │ 0/2 │ 1/2 ││ 2/2 │ 3/2 │ │ + * │ │ 1/0 │ 1/1 ││ 1/2 │ 1/3 │ │ * │ ┼──────┼──────┼┼──────┼──────┼ │ * │ │ │ ││ │ │ │ - * │ │ 0/3 │ 1/3 ││ 2/3 │ 3/3 │ │ + * │ │ 0/0 │ 0/1 ││ 0/2 │ 0/3 │ │ * │ ═══════╧═══════╗ ─────┼───── ╔ │ * └────────────────────────────────┘ * - * combining { { 5/4, 1/3 }, { 1/2, 4/4 } }, we can generate a texture connected to the right! + * combining { { 4/4, 1/1 }, { 0/1, 4/5 } }, we can generate a texture connected to the right! *

  * ╔══════╤═══════
  * ║      │      │
- * ║ 4/4  │ 1/2  │
+ * ║ 4/5  │ 1/1  │
  * ╟──────┼──────┼
  * ║      │      │
- * ║ 5/4  │ 1/3  │
+ * ║ 4/4  │ 0/1  │
  * ╚══════╧═══════
  * 
* - * combining { { 5/4, 1/3 }, { 3/2, 2/0 } }, we can generate a texture in the shape of an L + * combining { { 4/4, 1/0 }, { 3/2, 1/3 } }, we can generate a texture in the shape of an L * (connected to the right and up) *
  * ║ ─────┼───── ╚
  * ║      │      │
- * ║ 2/0  │ 3/2  │
+ * ║ 3/2  │ 1/3  │
  * ╟──────┼──────┼
  * ║      │      │
- * ║ 5/4  │ 1/3  │
+ * ║ 5/4  │ 1/0  │
  * ╚══════╧═══════
  * 
* From 98d02c6d99fc24645a19d9129325b9a4b5a24db2 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 22:09:49 +0300 Subject: [PATCH 36/66] Revert "Bad direction offset doc" This reverts commit a2a8102b3cd57f06c9e16009869cda747c6c2f1b. --- .../gtceu/client/model/ctm/CTMCache.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index 22b63914809..5a0a699667d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -39,40 +39,40 @@ * │ texture.png │ │ texture_ctm.png │ * │ ╔══════╤══════╗ │ │ ──────┼────── ║ ─────┼───── ║ │ * │ ║ │ ║ │ │ │ │ │║ │ ║ │ - * │ ║ 5/4 │ 5/5 ║ │ │ │ 3/0 │ 3/1 │║ 3/2 │ 3/3 ║ │ + * │ ║ 4/4 │ 4/5 ║ │ │ │ 0/0 │ 1/0 │║ 2/0 │ 3/0 ║ │ * │ ╟──────┼──────╢ │ │ ┼──────┼──────┼╟──────┼──────╢ │ * │ ║ │ ║ │ │ │ │ │║ │ ║ │ - * │ ║ 4/4 │ 4/5 ║ │ │ │ 2/0 │ 2/1 │║ 2/2 │ 2/3 ║ │ + * │ ║ 5/4 │ 5/5 ║ │ │ │ 0/1 │ 1/1 │║ 2/1 │ 3/1 ║ │ * │ ╚══════╧══════╝ │ │ ──────┼────── ║ ─────┼───── ║ │ * └─────────────────┘ │ ═══════╤═══════╝ ─────┼───── ╚ │ * │ │ │ ││ │ │ │ - * │ │ 1/0 │ 1/1 ││ 1/2 │ 1/3 │ │ + * │ │ 0/2 │ 1/2 ││ 2/2 │ 3/2 │ │ * │ ┼──────┼──────┼┼──────┼──────┼ │ * │ │ │ ││ │ │ │ - * │ │ 0/0 │ 0/1 ││ 0/2 │ 0/3 │ │ + * │ │ 0/3 │ 1/3 ││ 2/3 │ 3/3 │ │ * │ ═══════╧═══════╗ ─────┼───── ╔ │ * └────────────────────────────────┘ * - * combining { { 4/4, 1/1 }, { 0/1, 4/5 } }, we can generate a texture connected to the right! + * combining { { 5/4, 1/3 }, { 1/2, 4/4 } }, we can generate a texture connected to the right! *
  * ╔══════╤═══════
  * ║      │      │
- * ║ 4/5  │ 1/1  │
+ * ║ 4/4  │ 1/2  │
  * ╟──────┼──────┼
  * ║      │      │
- * ║ 4/4  │ 0/1  │
+ * ║ 5/4  │ 1/3  │
  * ╚══════╧═══════
  * 
* - * combining { { 4/4, 1/0 }, { 3/2, 1/3 } }, we can generate a texture in the shape of an L + * combining { { 5/4, 1/3 }, { 3/2, 2/0 } }, we can generate a texture in the shape of an L * (connected to the right and up) *
  * ║ ─────┼───── ╚
  * ║      │      │
- * ║ 3/2  │ 1/3  │
+ * ║ 2/0  │ 3/2  │
  * ╟──────┼──────┼
  * ║      │      │
- * ║ 5/4  │ 1/0  │
+ * ║ 5/4  │ 1/3  │
  * ╚══════╧═══════
  * 
* From bbf445f9a096263ff4d02bfa649f1e11834d3680 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Sun, 19 Apr 2026 23:08:37 +0300 Subject: [PATCH 37/66] it _almost_ works. It's taunting me. --- .../gtceu/client/model/ctm/CTMCache.java | 21 ++++++++++--------- .../client/model/ctm/ConnectionCheck.java | 8 +++++-- .../gtceu/client/util/quad/QuadUtils.java | 14 +++++++------ 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index 5a0a699667d..189715e4c5a 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -94,14 +94,15 @@ public interface StateComparisonCallback { boolean connects(ConnectionCheck instance, BlockState from, BlockState to, Direction dir); } - /** Some hardcoded offset values for the different corner indeces */ + // these are inverted (on y) compared to the graphic; top row is bottom row and vice versa. + /** Some hardcoded offset values for the different corner indices */ protected static Vector2ic[][] submapOffsets = { - { new Vector2i(0, 3), new Vector2i(1, 3) }, - { new Vector2i(0, 2), new Vector2i(1, 2) }, + { new Vector2i(0, 0), new Vector2i(1, 0) }, + { new Vector2i(0, 1), new Vector2i(1, 1) }, }; protected static Vector2ic[][] defaultSubmapCache = { - { new Vector2i(4, 5), new Vector2i(5, 5) }, { new Vector2i(4, 4), new Vector2i(5, 4) }, + { new Vector2i(4, 5), new Vector2i(5, 5) }, }; // TODO encapsulate @@ -160,7 +161,7 @@ public static ISubmap getSubmapFor(Vector2ic coordinates) { if (isDefaultTexture(coordinates)) { return Submap.X2[coordinates.x() % 4][coordinates.y() % 4]; } else { - return Submap.X4[(coordinates.x() + 2) % 4][(coordinates.y() + 2) % 4]; + return Submap.X4[3 - (coordinates.x() + 2) % 4][3 - (coordinates.y() + 0) % 4]; } } @@ -177,7 +178,7 @@ private static byte setConnectedState(byte map, OctagonalOrientation dir, boolea } /** - * Builds the connection map and stores it in this CTMLogic instance. + * Builds the connection map and stores it in this CTMLogic instance.
* The {@link #connected(OctagonalOrientation)}, {@link #connectedAnd(OctagonalOrientation...)}, * and {@link #connectedOr(OctagonalOrientation...)} methods can be used to access it. */ @@ -201,11 +202,11 @@ protected void fillSubmaps(int x, int y) { this.submapCache[x][y] = submapOffsets[x][y]; } else { // dirs[0] is vertical, dirs[1] is horizontal - Vector2i offsets = new Vector2i(submapOffsets[x][y]); - if (connected(dirs[0])) offsets.x += 2; - if (connected(dirs[1])) offsets.y += 2; + Vector2i offset = new Vector2i(submapOffsets[x][y]); + if (connected(dirs[1])) offset.x += 2; + if (connected(dirs[0])) offset.y += 2; - this.submapCache[x][y] = offsets; + this.submapCache[x][y] = offset; } } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java index e2ea42d0882..a2f7bd9c3b2 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java @@ -93,8 +93,12 @@ public boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockStat BlockState obscuring = getConnectionState(level, obscuringPos, level.getBlockState(obscuringPos), dir, current, currentState); - // check that we aren't already connected to / from this side - return stateComparator(state, connectionState, dir) && !stateComparator(state, obscuring, dir); + boolean ret = stateComparator(state, connectionState, dir); + + // check that we aren't already connected outwards from this side + ret &= !stateComparator(state, obscuring, dir); + + return ret; } public boolean stateComparator(BlockState from, BlockState to, Direction dir) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java index 98c85e376e9..69f2fe05829 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java @@ -85,15 +85,15 @@ public static List buildCTMQuads(CTMCache cachedConnections, List quad.pos(i, quad.x(i), newXy[i].y, newXy[i].x); - case Y -> quad.pos(i, newXy[i].x, quad.y(i), newXy[i].y); - case Z -> quad.pos(i, newXy[i].x, newXy[i].y, quad.z(i)); + case X -> quad.pos(i, quad.x(i), 1 - newXy[i].y, 1 - newXy[i].x); + case Y -> quad.pos(i, 1 - newXy[i].x, quad.y(i), 1 - newXy[i].y); + case Z -> quad.pos(i, 1 - newXy[i].x, 1 - newXy[i].y, quad.z(i) ); } } + // spotless:on return quad; } From b26a46b821479c7a5a482d569c6ce0db7b38490b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Mon, 20 Apr 2026 11:59:59 +0300 Subject: [PATCH 38/66] Rename QuadUtils to CTMHelper --- .../gtceu/client/model/ctm/CTMBakedModel.java | 4 ++-- .../gtceu/client/model/machine/MachineModel.java | 4 ++-- .../util/quad/{QuadUtils.java => CTMHelper.java} | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) rename src/main/java/com/gregtechceu/gtceu/client/util/quad/{QuadUtils.java => CTMHelper.java} (97%) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java index ca25fea962d..7c2af228f87 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java @@ -1,6 +1,6 @@ package com.gregtechceu.gtceu.client.model.ctm; -import com.gregtechceu.gtceu.client.util.quad.QuadUtils; +import com.gregtechceu.gtceu.client.util.quad.CTMHelper; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; @@ -49,7 +49,7 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction CTMCache ctmCache = CTMCache.getInstance(); ctmCache.fillSubmapCache(level, pos, state, side); return this.sideCache.computeIfAbsent(side, $ -> new ConcurrentHashMap<>()) - .computeIfAbsent(ctmCache, cache -> QuadUtils.buildCTMQuads(cache, + .computeIfAbsent(ctmCache, cache -> CTMHelper.buildCTMQuads(cache, super.getQuads(state, side, rand, parentModelData, renderType), side)); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java index 068ddfcb348..64629914f05 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java @@ -14,7 +14,7 @@ import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; import com.gregtechceu.gtceu.client.util.RenderUtil; -import com.gregtechceu.gtceu.client.util.quad.QuadUtils; +import com.gregtechceu.gtceu.client.util.quad.CTMHelper; import com.gregtechceu.gtceu.common.data.models.GTModels; import com.gregtechceu.gtceu.common.machine.trait.AutoOutputTrait; @@ -275,7 +275,7 @@ public List renderMachine(@Nullable MetaMachine machine, @Nullable Bl // we have to recalculate CTM ourselves. // this is the slowest part by a long shot because the LDLib quad logic isn't very optimized. if (level != null && pos != null && blockState != null) { - return QuadUtils.buildCTMQuads(level, pos, blockState, quads, side); + return CTMHelper.buildCTMQuads(level, pos, blockState, quads, side); } return quads; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java similarity index 97% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java rename to src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java index 69f2fe05829..f2a7f642299 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/QuadUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java @@ -26,7 +26,7 @@ import static com.gregtechceu.gtceu.client.model.quad.MutableQuadView.*; import static com.gregtechceu.gtceu.client.util.ModelEventHelper.*; -public class QuadUtils { +public class CTMHelper { public static Vector2f[] findMinMaxUVs(Vector2f[] uvs) { float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE, maxU = Float.MIN_VALUE, maxV = Float.MIN_VALUE; @@ -141,7 +141,7 @@ private static void growQuadrantUVs(Vector2f[] uvs, Vector2f maxUV) { private static void transformUVs(MutableQuadView quad, ISubmap submap) { submap = submap.unitScale(); - Vector2f[] uvs = QuadUtils.uvs.get(); + Vector2f[] uvs = CTMHelper.uvs.get(); for (int i = 0; i < 4; i++) { uvs[i] = quad.copyUv(i, uvs[i]); } @@ -185,15 +185,15 @@ private static void transformUVs(MutableQuadView quad, ISubmap submap) { public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { Direction normal = quad.nominalFace(); - Vector2f[] uvs = QuadUtils.uvs.get(); + Vector2f[] uvs = CTMHelper.uvs.get(); for (int i = 0; i < 4; i++) { uvs[i] = quad.copyUv(i, uvs[i]); } int firstIndex = findMinUVIndex(uvs); - Vector2f[] xy = QuadUtils.xy.get(); - Vector2f[] newXy = QuadUtils.newXy.get(); - Vector3f position = QuadUtils.position.get(); + Vector2f[] xy = CTMHelper.xy.get(); + Vector2f[] newXy = CTMHelper.newXy.get(); + Vector3f position = CTMHelper.position.get(); for (int i = 0; i < 4; i++) { int idx = (firstIndex + i) % 4; // updates position From 613de0132b658f879983b590f0016b9ca95d1a8e Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Mon, 20 Apr 2026 12:38:24 +0300 Subject: [PATCH 39/66] The 'is dynamic resources enabled' check is needed, actually --- .../com/gregtechceu/gtceu/client/util/ModelEventHelper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java index 89600e160bc..3a1c21b8db5 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java @@ -6,6 +6,7 @@ import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; import com.gregtechceu.gtceu.core.mixins.ReloadableResourceManagerAccessor; +import com.gregtechceu.gtceu.integration.modernfix.GTModernFixIntegration; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -109,9 +110,8 @@ public static void onAtlasStitched(TextureStitchEvent.Post event) { @SubscribeEvent(priority = EventPriority.LOWEST) public static void onModifyBakingResult(ModelEvent.ModifyBakingResult event) { - // don't process baked model replacement here if ModernFix is loaded, as - // GTModernFixIntegration#onBakedModelLoad does the same thing & it's always called - if (GTCEu.Mods.isModernFixLoaded()) return; + // don't process baked model replacement here if ModernFix is loaded & dynamic resources is enabled + if (GTCEu.Mods.isModernFixLoaded() && GTModernFixIntegration.isDynamicResourcesEnabled()) return; for (var entry : event.getModels().entrySet()) { BakedModel model = entry.getValue(); From 4a4b975c8bfdb2ce34f1cfba6b370952b2141a1a Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Mon, 20 Apr 2026 16:14:09 +0300 Subject: [PATCH 40/66] Add a CTM UV test block --- .../gtceu/common/data/GTBlocks.java | 6 ++++++ .../gtceu/common/data/blocks/GTDevBlocks.java | 17 +++++++++++++++++ .../assets/gtceu/textures/block/ctm_test.png | Bin 0 -> 258 bytes .../gtceu/textures/block/ctm_test.png.mcmeta | 5 +++++ .../gtceu/textures/block/ctm_test_ctm.png | Bin 0 -> 688 bytes 5 files changed, 28 insertions(+) create mode 100644 src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java create mode 100644 src/main/resources/assets/gtceu/textures/block/ctm_test.png create mode 100644 src/main/resources/assets/gtceu/textures/block/ctm_test.png.mcmeta create mode 100644 src/main/resources/assets/gtceu/textures/block/ctm_test_ctm.png diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java index b2a8f0e4f87..daea299f782 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java @@ -18,6 +18,7 @@ import com.gregtechceu.gtceu.common.block.*; import com.gregtechceu.gtceu.common.block.explosive.IndustrialTNTBlock; import com.gregtechceu.gtceu.common.block.explosive.PowderbarrelBlock; +import com.gregtechceu.gtceu.common.data.blocks.GTDevBlocks; import com.gregtechceu.gtceu.common.data.models.GTModels; import com.gregtechceu.gtceu.common.item.LampBlockItem; import com.gregtechceu.gtceu.common.item.LaserPipeBlockItem; @@ -1420,6 +1421,11 @@ public static void init() { // GCYM GCYMBlocks.init(); + + // Dev-only test blocks + if (GTCEu.isDev()) { + GTDevBlocks.init(); + } } private static void initializeCobbleReplacements() { diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java b/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java new file mode 100644 index 00000000000..f11fecf4211 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java @@ -0,0 +1,17 @@ +package com.gregtechceu.gtceu.common.data.blocks; + +import com.tterrag.registrate.util.entry.BlockEntry; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; + +import static com.gregtechceu.gtceu.common.registry.GTRegistration.REGISTRATE; + +public class GTDevBlocks { + + public static final BlockEntry CTM_TEST = REGISTRATE.block("ctm_test", Block::new) + .properties(p -> p.noLootTable().sound(SoundType.SCULK)) + .simpleItem() + .register(); + + public static void init() {} +} diff --git a/src/main/resources/assets/gtceu/textures/block/ctm_test.png b/src/main/resources/assets/gtceu/textures/block/ctm_test.png new file mode 100644 index 0000000000000000000000000000000000000000..5a9f059f5127d3920e644f188ab533155fc17647 GIT binary patch literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9F3${@^GvDCf{D9B#o z>Fdh=ibaIeP|d5*w+ARBS>hT|;+&tGo0?a`;9QiNSdyBeP@Y+mq2TW68xY>eCk|9p z`)X-P)@w;eMsR(qTQcZ(}nZJ z&y~eroy=D&X`OQU(#j{x*Yvqv(_VM`v2Suj{-e^|83GaJ8H_VKjbBztEuS*jp7n!9;rJdG^AI%6_*|Gd>e>Y$5);!4mnHiy>v2YqSkJrdlnqW7{w1sqie7 z>q2m}$m>QFfOpy@wvTt}1Ch72vr~Z{MH!G2kj}cy-sKdyGtD_>4% Date: Mon, 20 Apr 2026 16:14:42 +0300 Subject: [PATCH 41/66] Remove bad offsets --- .../com/gregtechceu/gtceu/client/model/ctm/CTMCache.java | 2 +- .../com/gregtechceu/gtceu/client/util/quad/CTMHelper.java | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index 189715e4c5a..3a6c408d803 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -161,7 +161,7 @@ public static ISubmap getSubmapFor(Vector2ic coordinates) { if (isDefaultTexture(coordinates)) { return Submap.X2[coordinates.x() % 4][coordinates.y() % 4]; } else { - return Submap.X4[3 - (coordinates.x() + 2) % 4][3 - (coordinates.y() + 0) % 4]; + return Submap.X4[3 - (coordinates.x() + 0) % 4][3 - (coordinates.y() + 0) % 4]; } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java index f2a7f642299..f94ed7eff9e 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java @@ -141,10 +141,12 @@ private static void growQuadrantUVs(Vector2f[] uvs, Vector2f maxUV) { private static void transformUVs(MutableQuadView quad, ISubmap submap) { submap = submap.unitScale(); + // cache UVs Vector2f[] uvs = CTMHelper.uvs.get(); for (int i = 0; i < 4; i++) { uvs[i] = quad.copyUv(i, uvs[i]); } + // scale the quadrants' UVs to the full block range Vector2f[] minMaxUVs = findMinMaxUVs(uvs); growQuadrantUVs(uvs, minMaxUVs[1]); @@ -259,9 +261,9 @@ public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { // spotless:off for (int i = 0; i < 4; i++) { switch (normal.getAxis()) { - case X -> quad.pos(i, quad.x(i), 1 - newXy[i].y, 1 - newXy[i].x); - case Y -> quad.pos(i, 1 - newXy[i].x, quad.y(i), 1 - newXy[i].y); - case Z -> quad.pos(i, 1 - newXy[i].x, 1 - newXy[i].y, quad.z(i) ); + case X -> quad.pos(i, quad.x(i), newXy[i].y, newXy[i].x); + case Y -> quad.pos(i, newXy[i].x, quad.y(i), newXy[i].y); + case Z -> quad.pos(i, newXy[i].x, newXy[i].y, quad.z(i)); } } // spotless:on From f529c743e1aa204ee0dbe8aca32d30e755ed5bbb Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Mon, 20 Apr 2026 17:37:51 +0300 Subject: [PATCH 42/66] Run datagen for CTM test block --- .../resources/assets/gtceu/blockstates/ctm_test.json | 7 +++++++ src/generated/resources/assets/gtceu/lang/en_ud.json | 1 + src/generated/resources/assets/gtceu/lang/en_us.json | 1 + .../resources/assets/gtceu/models/block/ctm_test.json | 6 ++++++ .../resources/assets/gtceu/models/item/ctm_test.json | 3 +++ .../gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java | 1 + 6 files changed, 19 insertions(+) create mode 100644 src/generated/resources/assets/gtceu/blockstates/ctm_test.json create mode 100644 src/generated/resources/assets/gtceu/models/block/ctm_test.json create mode 100644 src/generated/resources/assets/gtceu/models/item/ctm_test.json diff --git a/src/generated/resources/assets/gtceu/blockstates/ctm_test.json b/src/generated/resources/assets/gtceu/blockstates/ctm_test.json new file mode 100644 index 00000000000..9332a79dea2 --- /dev/null +++ b/src/generated/resources/assets/gtceu/blockstates/ctm_test.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "gtceu:block/ctm_test" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/gtceu/lang/en_ud.json b/src/generated/resources/assets/gtceu/lang/en_ud.json index 23ce21657c2..ba8c5771331 100644 --- a/src/generated/resources/assets/gtceu/lang/en_ud.json +++ b/src/generated/resources/assets/gtceu/lang/en_ud.json @@ -188,6 +188,7 @@ "block.gtceu.creative_tank": "ʞuɐ⟘ ǝʌıʇɐǝɹƆ", "block.gtceu.creosote": "ǝʇosoǝɹƆ", "block.gtceu.crushing_wheels": "sןǝǝɥM buıɥsnɹƆ", + "block.gtceu.ctm_test": "ʞɔoןᗺ ʇsǝ⟘ ǝɹnʇxǝ⟘ pǝʇɔǝuuoƆ", "block.gtceu.cupronickel_coil_block": "ʞɔoןᗺ ןıoƆ ןǝʞɔıuoɹdnƆ", "block.gtceu.cyan_borderless_lamp": "dɯɐꞀ ssǝןɹǝpɹoᗺ uɐʎƆ", "block.gtceu.cyan_lamp": "dɯɐꞀ uɐʎƆ", diff --git a/src/generated/resources/assets/gtceu/lang/en_us.json b/src/generated/resources/assets/gtceu/lang/en_us.json index 6eca15057a9..3aafbf00c3c 100644 --- a/src/generated/resources/assets/gtceu/lang/en_us.json +++ b/src/generated/resources/assets/gtceu/lang/en_us.json @@ -188,6 +188,7 @@ "block.gtceu.creative_tank": "Creative Tank", "block.gtceu.creosote": "Creosote", "block.gtceu.crushing_wheels": "Crushing Wheels", + "block.gtceu.ctm_test": "Connected Texture Test Block", "block.gtceu.cupronickel_coil_block": "Cupronickel Coil Block", "block.gtceu.cyan_borderless_lamp": "Cyan Borderless Lamp", "block.gtceu.cyan_lamp": "Cyan Lamp", diff --git a/src/generated/resources/assets/gtceu/models/block/ctm_test.json b/src/generated/resources/assets/gtceu/models/block/ctm_test.json new file mode 100644 index 00000000000..47bfa0945dd --- /dev/null +++ b/src/generated/resources/assets/gtceu/models/block/ctm_test.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "gtceu:block/ctm_test" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/gtceu/models/item/ctm_test.json b/src/generated/resources/assets/gtceu/models/item/ctm_test.json new file mode 100644 index 00000000000..1dec31234c8 --- /dev/null +++ b/src/generated/resources/assets/gtceu/models/item/ctm_test.json @@ -0,0 +1,3 @@ +{ + "parent": "gtceu:block/ctm_test" +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java b/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java index f11fecf4211..bea187acb4b 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java @@ -9,6 +9,7 @@ public class GTDevBlocks { public static final BlockEntry CTM_TEST = REGISTRATE.block("ctm_test", Block::new) + .lang("Connected Texture Test Block") .properties(p -> p.noLootTable().sound(SoundType.SCULK)) .simpleItem() .register(); From 2f833bcb85f48fc607a5414afee5332084b50eef Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Mon, 20 Apr 2026 22:00:15 +0300 Subject: [PATCH 43/66] Fix CTM UV layouts --- .../gtceu/client/model/ctm/CTMCache.java | 49 +++++++++--------- .../assets/gtceu/textures/block/ctm_test.png | Bin 258 -> 318 bytes .../gtceu/textures/block/ctm_test_ctm.png | Bin 688 -> 812 bytes 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index 3a6c408d803..3410558f469 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -39,40 +39,40 @@ * │ texture.png │ │ texture_ctm.png │ * │ ╔══════╤══════╗ │ │ ──────┼────── ║ ─────┼───── ║ │ * │ ║ │ ║ │ │ │ │ │║ │ ║ │ - * │ ║ 4/4 │ 4/5 ║ │ │ │ 0/0 │ 1/0 │║ 2/0 │ 3/0 ║ │ + * │ ║ 4/4 │ 4/5 ║ │ │ │ 0/0 │ 0/1 │║ 0/2 │ 0/3 ║ │ * │ ╟──────┼──────╢ │ │ ┼──────┼──────┼╟──────┼──────╢ │ * │ ║ │ ║ │ │ │ │ │║ │ ║ │ - * │ ║ 5/4 │ 5/5 ║ │ │ │ 0/1 │ 1/1 │║ 2/1 │ 3/1 ║ │ + * │ ║ 5/4 │ 5/5 ║ │ │ │ 1/0 │ 1/1 │║ 1/2 │ 1/3 ║ │ * │ ╚══════╧══════╝ │ │ ──────┼────── ║ ─────┼───── ║ │ * └─────────────────┘ │ ═══════╤═══════╝ ─────┼───── ╚ │ * │ │ │ ││ │ │ │ - * │ │ 0/2 │ 1/2 ││ 2/2 │ 3/2 │ │ + * │ │ 2/0 │ 2/1 ││ 2/2 │ 2/3 │ │ * │ ┼──────┼──────┼┼──────┼──────┼ │ * │ │ │ ││ │ │ │ - * │ │ 0/3 │ 1/3 ││ 2/3 │ 3/3 │ │ + * │ │ 3/0 │ 3/1 ││ 3/2 │ 3/3 │ │ * │ ═══════╧═══════╗ ─────┼───── ╔ │ * └────────────────────────────────┘ * - * combining { { 5/4, 1/3 }, { 1/2, 4/4 } }, we can generate a texture connected to the right! + * combining { { 5/4, 3/1 }, { 2/1, 4/4 } }, we can generate a texture connected to the right! *
  * ╔══════╤═══════
  * ║      │      │
- * ║ 4/4  │ 1/2  │
+ * ║ 4/4  │ 2/1  │
  * ╟──────┼──────┼
  * ║      │      │
- * ║ 5/4  │ 1/3  │
+ * ║ 5/4  │ 3/1  │
  * ╚══════╧═══════
  * 
* - * combining { { 5/4, 1/3 }, { 3/2, 2/0 } }, we can generate a texture in the shape of an L + * combining { { 5/4, 3/1 }, { 0/2, 2/3 } }, we can generate a texture in the shape of an L * (connected to the right and up) *
  * ║ ─────┼───── ╚
  * ║      │      │
- * ║ 2/0  │ 3/2  │
+ * ║ 0/2  │ 2/3  │
  * ╟──────┼──────┼
  * ║      │      │
- * ║ 5/4  │ 1/3  │
+ * ║ 5/4  │ 3/1  │
  * ╚══════╧═══════
  * 
* @@ -94,27 +94,27 @@ public interface StateComparisonCallback { boolean connects(ConnectionCheck instance, BlockState from, BlockState to, Direction dir); } - // these are inverted (on y) compared to the graphic; top row is bottom row and vice versa. - /** Some hardcoded offset values for the different corner indices */ - protected static Vector2ic[][] submapOffsets = { - { new Vector2i(0, 0), new Vector2i(1, 0) }, - { new Vector2i(0, 1), new Vector2i(1, 1) }, + /** Hardcoded offset values for the different submap indices */ + // store the full table(s) to reduce non-required allocations + protected static final Vector2ic[][] submapOffsets = { + { new Vector2i(0, 0), new Vector2i(0, 1), }, + { new Vector2i(1, 0), new Vector2i(1, 1), }, }; - protected static Vector2ic[][] defaultSubmapCache = { - { new Vector2i(4, 4), new Vector2i(5, 4) }, - { new Vector2i(4, 5), new Vector2i(5, 5) }, + protected static final Vector2ic[][] defaultSubmapCache = { + { new Vector2i(4, 4), new Vector2i(4, 5), }, + { new Vector2i(5, 4), new Vector2i(5, 5), }, }; // TODO encapsulate public ConnectionCheck connectionCheck = new ConnectionCheck(); + // spotless:off // Mapping the different corner indices to their respective dirs - protected static final OctagonalOrientation[][] submapMap = { - { BOTTOM, LEFT, BOTTOM_LEFT }, - { BOTTOM, RIGHT, BOTTOM_RIGHT }, - { TOP, RIGHT, TOP_RIGHT }, - { TOP, LEFT, TOP_LEFT } + protected static final OctagonalOrientation[][][] submapMap = { + { { LEFT, TOP, TOP_LEFT }, { RIGHT, TOP, TOP_RIGHT }, }, + { { LEFT, BOTTOM, BOTTOM_LEFT }, { RIGHT, BOTTOM, BOTTOM_RIGHT }, }, }; + // spotless:on protected byte connectionMap; protected Vector2ic[][] submapCache = defaultSubmapCache.clone(); @@ -195,7 +195,8 @@ public void buildConnectionMap(BlockAndTintGetter world, BlockPos pos, BlockStat @SuppressWarnings("null") protected void fillSubmaps(int x, int y) { - OctagonalOrientation[] dirs = submapMap[x + y * 2]; + // [0] is horizontal, [1] is vertical, [2] is diagonal + OctagonalOrientation[] dirs = submapMap[x][y]; if (connectedOr(dirs[0], dirs[1])) { if (connectedAnd(dirs)) { // If all dirs are connected, we use the fully connected face, the base offset value. diff --git a/src/main/resources/assets/gtceu/textures/block/ctm_test.png b/src/main/resources/assets/gtceu/textures/block/ctm_test.png index 5a9f059f5127d3920e644f188ab533155fc17647..88ea914d2f39a3ff1aad101a64a5796c9db70053 100644 GIT binary patch delta 281 zcmV+!0p|XK0=@!}8BqoR001BJ|6u?C00DDSM?wMF$t-^W000DMK}|sb0I`n?{9y$E z001CkNK#Dz0D2|>0Dy!50Qvv`0D$NK0Cg|`0P0`>06Lfe02gqax=}olAsBzBNkl|n3&v+&Nur>I%Yz?eoqb{{`fHCSUYKWZ=nm4Z*QGm%GX?G(`0a$iuIF6ZnU4#6qn zjRM8-9S&(fdJ^8(tbAmBC*VC!Gw&|Qh=*$&8W@NYkP3)WoGXR0=G1+(3{-k9)^>f0 fXRhU~{d>+2hT%^r0h1gK00000NkvXXu0mjfK>li+ delta 241 zcmdnT)WkGFvYv^7fnmbL3^O3bS>O>_%)p?h48n{ROYO^mg6t)pzOL-ASVTAt)w~LQ zdw@ccC9V-A&iT2ysd*&~&PAz-C8;S2<(VZJ3hti10pX2&;y^_;o-U3d8t3OuJji$0 zfX7Kb_}~BOHxJHzVzFh_GiQ;+4n?s9<;2V0S%(yEB-;InHC;Gg{9IZ5)yaIdlGZ7g zFRgsCd`+L*HSKk`ANwXp)zv(Hc`V{i=DYFmAPeC$`nx9hLDzgt@{ZK>RM1n3Y3Pgg&ebxsLQ080U1ApigX diff --git a/src/main/resources/assets/gtceu/textures/block/ctm_test_ctm.png b/src/main/resources/assets/gtceu/textures/block/ctm_test_ctm.png index 0307672b01bda63550263c503978ec324b9fb62b..7e4b5d08300128942724a7c9aed9edc4d5c3364b 100644 GIT binary patch delta 769 zcmV+c1OEK51*`^;Bt`*qQb$4o*~u(_00004XF*Lt006O%3;baP0000WV@Og>004R> z004l5008;`004mK004C`008P>0026e000+ooVrmwks%j<0+mTbK~z}7wU@DO6G0G$ z=eMq)i(eulJOFNJe0_|Bkf4kuiV)=?Zv6z%L{W-JZYcmMggO;M3J*XaFX41hO^UnS zo86n)wZR$5lI`{0%zX3j%o@bRl(oV#K&#b-xxDlKxxLj9RYXLL-U%40lRlndK)ZX( z@c#B@KHM&U_Auh-SJE+qiC`qp+y?>-0=d1J)9&7q#^XL?Nrr(okVfotpwYij&)I5q zku3==(7sXv+cHVOG(ln1BPxq6XHo|m1*wApfk=3uSOmuB! z{+WQX^-r=VBC1|Zp5}l5_IGyu2@$;;&&+k_TxPd_>oxH5JFE8>I3<6$@FL+B6D=}iq*S| zcM9eR6{EWkG|VI^)JdK0jyR$)9F$DxM40#pjspcCnygidernzAPEpVRvQwLlYhBe( z$-EXl0V@!MV+d7{o&b9S-RCM5-jpcP!6w;%r-V}tXvbyH2h#d$<^{OnRYAR3;h@k5 zmZb(buvX;>?cEed%dvI;&>NMao2&_@mq3s)|247C9eq34VS)Q7K~y)Hc{^TGcx zq)M|tNOVxn9*OWI0nTO*!uH0o^%#3fw?W_CX>@2HM@dakSAh-}0006iNklH_VKjbBztEuS*jp7n!9;rJ zdG^AI%6_*|Gd>e>Y$5);!4mD%CCZ{|h1&1fq@?U*Q@SFo$P&QP+E-UiGu4wl&Z+ zdI^ZGZv?ZZ)*W-Fiepm)n5pps=D~RDI&%!pCC3%qXj|9W1Uv;91P>sWaY+zq4LG|G zl+-^Zz@$@|{l$IY9}OvkV1;XQfv@F|XeSdy0;n)(~O>~|7yxTo0I6PA& zs55oSHAageWtwZW4LhbW=Xtcbj45QsxJ@A4c|0r_*0?AK;x?4Q#>|J5xdP z!vfhe6hsEvWyB=Xq9_Ln3NaB1zWzcYm3Ae|9?=s@)R`g*sB{AUY~VBISw{p~YfMVk yamJEDkp{}LzwDzz5~(h|kfyd{>4$~f5x-^J@)2)WEEjnI0000 Date: Mon, 20 Apr 2026 22:02:41 +0300 Subject: [PATCH 44/66] Do, a copy, do it deep --- .../gtceu/client/model/ctm/CTMCache.java | 21 +++++---- .../gregtechceu/gtceu/utils/ArrayHelpers.java | 45 +++++++++++++++++++ 2 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index 3410558f469..cea35f2ab03 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -17,6 +17,8 @@ */ package com.gregtechceu.gtceu.client.model.ctm; +import com.gregtechceu.gtceu.utils.ArrayHelpers; + import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.BlockAndTintGetter; @@ -97,15 +99,16 @@ public interface StateComparisonCallback { /** Hardcoded offset values for the different submap indices */ // store the full table(s) to reduce non-required allocations protected static final Vector2ic[][] submapOffsets = { - { new Vector2i(0, 0), new Vector2i(0, 1), }, - { new Vector2i(1, 0), new Vector2i(1, 1), }, + { new Vector2i(0, 0), new Vector2i(0, 1), new Vector2i(0, 2), new Vector2i(0, 3), }, + { new Vector2i(1, 0), new Vector2i(1, 1), new Vector2i(1, 2), new Vector2i(1, 3), }, + { new Vector2i(2, 0), new Vector2i(2, 1), new Vector2i(2, 2), new Vector2i(2, 3), }, + { new Vector2i(3, 0), new Vector2i(3, 1), new Vector2i(3, 2), new Vector2i(3, 3), }, }; protected static final Vector2ic[][] defaultSubmapCache = { { new Vector2i(4, 4), new Vector2i(4, 5), }, { new Vector2i(5, 4), new Vector2i(5, 5), }, }; - // TODO encapsulate public ConnectionCheck connectionCheck = new ConnectionCheck(); // spotless:off @@ -117,7 +120,7 @@ public interface StateComparisonCallback { // spotless:on protected byte connectionMap; - protected Vector2ic[][] submapCache = defaultSubmapCache.clone(); + protected Vector2ic[][] submapCache = ArrayHelpers.deepCopy(defaultSubmapCache); public static CTMCache getInstance() { return new CTMCache(); @@ -161,7 +164,7 @@ public static ISubmap getSubmapFor(Vector2ic coordinates) { if (isDefaultTexture(coordinates)) { return Submap.X2[coordinates.x() % 4][coordinates.y() % 4]; } else { - return Submap.X4[3 - (coordinates.x() + 0) % 4][3 - (coordinates.y() + 0) % 4]; + return Submap.X4[coordinates.x()][coordinates.y()]; } } @@ -202,12 +205,8 @@ protected void fillSubmaps(int x, int y) { // If all dirs are connected, we use the fully connected face, the base offset value. this.submapCache[x][y] = submapOffsets[x][y]; } else { - // dirs[0] is vertical, dirs[1] is horizontal - Vector2i offset = new Vector2i(submapOffsets[x][y]); - if (connected(dirs[1])) offset.x += 2; - if (connected(dirs[0])) offset.y += 2; - - this.submapCache[x][y] = offset; + this.submapCache[x][y] = submapOffsets[x + (connected(dirs[0]) ? 2 : 0)] + [y + (connected(dirs[1]) ? 2 : 0)]; } } } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java b/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java new file mode 100644 index 00000000000..e8e54ea8c99 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java @@ -0,0 +1,45 @@ +package com.gregtechceu.gtceu.utils; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Array; + +public class ArrayHelpers { + + /** + * Returns a copy of the specified array object, deeply copying multidimensional arrays. + * If the specified object is null, the return value is null. + * + *

+ * Note: if the array object has an element type which is a reference type that is not an array type, + * the elements themselves are not deeply copied. This method only copies array objects. + * + * @param array the array object to deep copy + * @param the type of the array to deep copy + * @return a copy of the specified array object, deeply copying multidimensional arrays, or null if the object is + * null + */ + @Contract(value = "!null -> !null; null -> null", pure = true) + public static @Nullable T @Nullable [] deepCopy(@Nullable T @Nullable [] array) { + if (array == null) { + return null; + } + + Class componentType = array.getClass().getComponentType(); + + @SuppressWarnings("unchecked") + T[] copy = (T[]) Array.newInstance(componentType, array.length); + + if (componentType.isArray()) { + for (int i = 0; i < array.length; ++i) { + //noinspection unchecked + Array.set(copy, i, deepCopy((T[]) array[i])); + } + } else { + System.arraycopy(array, 0, copy, 0, array.length); + } + + return copy; + } +} From 66339bbecea569a4b2b12d28570e5780817a3ecb Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Mon, 20 Apr 2026 22:03:59 +0300 Subject: [PATCH 45/66] nonnull normal face, less copying --- .../client/model/ctm/OctagonalOrientation.java | 4 +++- .../gtceu/client/model/machine/MachineModel.java | 2 +- .../gtceu/client/util/quad/CTMHelper.java | 15 +++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java index 18d1e22378c..eae8c487e6f 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java @@ -17,6 +17,8 @@ */ package com.gregtechceu.gtceu.client.model.ctm; +import com.gregtechceu.gtceu.utils.GTUtil; + import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.StringRepresentable; @@ -73,7 +75,7 @@ public enum OctagonalOrientation implements StringRepresentable { private void buildCaches() { // Fill normalized dirs - for (Direction normal : Direction.values()) { + for (Direction normal : GTUtil.DIRECTIONS) { Direction[] normalized; if (normal == NORMAL) { normalized = dirs; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java index 64629914f05..9ac6a409d8b 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java @@ -274,7 +274,7 @@ public List renderMachine(@Nullable MetaMachine machine, @Nullable Bl // we have to recalculate CTM ourselves. // this is the slowest part by a long shot because the LDLib quad logic isn't very optimized. - if (level != null && pos != null && blockState != null) { + if (level != null && pos != null && blockState != null && side != null) { return CTMHelper.buildCTMQuads(level, pos, blockState, quads, side); } return quads; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java index f94ed7eff9e..1580b8ed4f6 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java @@ -57,7 +57,7 @@ public static int findMinUVIndex(Vector2f[] uvs) { } public static List buildCTMQuads(BlockAndTintGetter level, BlockPos pos, BlockState state, - List quads, @Nullable Direction cullFace) { + List quads, Direction cullFace) { CTMCache ctmCache = CTMCache.getInstance(); if (cullFace != null) { ctmCache.fillSubmapCache(level, pos, state, cullFace); @@ -66,8 +66,7 @@ public static List buildCTMQuads(BlockAndTintGetter level, BlockPos p return buildCTMQuads(ctmCache, quads, cullFace); } - public static List buildCTMQuads(CTMCache cachedConnections, List base, - @Nullable Direction cullFace) { + public static List buildCTMQuads(CTMCache cachedConnections, List base, Direction cullFace) { List result = new LinkedList<>(); MeshBuilder meshBuilder = MeshBuilder.getInstance(); var emitter = meshBuilder.getEmitter(); @@ -83,17 +82,17 @@ public static List buildCTMQuads(CTMCache cachedConnections, List Date: Mon, 20 Apr 2026 22:04:36 +0300 Subject: [PATCH 46/66] Fix the bottom face being off --- .../java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java index 1580b8ed4f6..b6663348330 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java @@ -207,7 +207,7 @@ public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { } } - if (normal.getAxis() != Direction.Axis.Y) { + if (normal != Direction.UP) { submap = submap.flipY(); } if (normal == Direction.EAST || normal == Direction.NORTH) { From 42eb7d0d7800e929503ef4de65058aeb23cb7ce7 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Mon, 20 Apr 2026 22:04:57 +0300 Subject: [PATCH 47/66] remove no longer correct doc comments --- .../gtceu/client/util/quad/CTMHelper.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java index b6663348330..f0f73deee1d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java @@ -107,10 +107,6 @@ public static List buildCTMQuads(CTMCache cachedConnections, List 0.5f ? 0.5f : 0.0f, minVInterp = maxUV.y > 0.5f ? 0.5f : 0.0f; @@ -170,18 +166,6 @@ private static void transformUVs(MutableQuadView quad, ISubmap submap) { quad.uv(3, uvs[3].x == minUV.x ? minU : maxU, uvs[3].y == minUV.y ? minV : maxV); } - /** - * Quadrant table is as follows: - *

-     * ╔══════╤══════╗
-     * ║      │      ║
-     * ║  2   │  3   ║
-     * ╟──────┼──────╢
-     * ║      │      ║
-     * ║  0   │  1   ║
-     * ╚══════╧══════╝
-     * 
- */ // TODO simplify, this is quite long public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { Direction normal = quad.nominalFace(); From 54d8b9ab8432f52c483eb51c77517213fc54f82e Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 21 Apr 2026 10:26:51 +0300 Subject: [PATCH 48/66] Re-enable ARGB->ABGR color translation --- .../gregtechceu/gtceu/client/model/quad/MutableQuadView.java | 3 +-- .../java/com/gregtechceu/gtceu/client/model/quad/QuadView.java | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java index 271e187f2c9..33ffcfb44cc 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java @@ -402,8 +402,7 @@ public final MutableQuadView fromVanilla(int[] quadData, int startIndex) { int colorIndex = baseIndex + VERTEX_COLOR; for (int i = 0; i < 4; i++) { - // ARGB -> ABGR is a transitive process, e.g. it can be reversed and works fine. - //this.data[colorIndex] = QuadTransformers.toABGR(this.data[colorIndex]); + this.data[colorIndex] = QuadTransformers.toABGR(this.data[colorIndex]); colorIndex += VERTEX_STRIDE; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java index d5d6726ea86..224930a8409 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java @@ -22,6 +22,7 @@ import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; +import net.minecraftforge.client.model.QuadTransformers; import lombok.Getter; import lombok.experimental.Accessors; @@ -369,7 +370,7 @@ public final void toVanilla(int[] target, int targetIndex) { int colorIndex = EncodingFormat.VERTEX_COLOR; for (int i = 0; i < 4; i++) { - //target[colorIndex] = QuadTransformers.toABGR(target[colorIndex]); + target[colorIndex] = QuadTransformers.toABGR(target[colorIndex]); colorIndex += VERTEX_STRIDE; } } From d3c6afa7aa1d26024dd75938259f3b977fe8d042 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 21 Apr 2026 10:57:00 +0300 Subject: [PATCH 49/66] Spotless --- .../gregtechceu/gtceu/client/model/ctm/CTMCache.java | 10 ++++++---- .../gtceu/client/util/ModelEventHelper.java | 3 +-- .../gregtechceu/gtceu/client/util/quad/CTMHelper.java | 3 +-- .../gtceu/common/data/blocks/GTDevBlocks.java | 3 ++- .../java/com/gregtechceu/gtceu/utils/ArrayHelpers.java | 6 +++--- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index cea35f2ab03..72b71e536b7 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -31,6 +31,7 @@ import static com.gregtechceu.gtceu.client.model.ctm.OctagonalOrientation.*; +// spotless:off /** * The CTM renderer will draw the block's FACE by assembling 4 quadrants from the 5 available block textures. * The normal {@code texture.png} is the block's "unconnected" texture, and is used when CTM is disabled or the block @@ -83,16 +84,17 @@ *

* Sourced from ConnectedTexturesMod. */ +// spotless:on @Accessors(fluent = true, chain = true) public class CTMCache { @FunctionalInterface public interface StateComparisonCallback { - + StateComparisonCallback DEFAULT = (connectionCheck, from, to, dir) -> { return connectionCheck.ignoreStates() ? from.getBlock() == to.getBlock() : from == to; }; - + boolean connects(ConnectionCheck instance, BlockState from, BlockState to, Direction dir); } @@ -205,8 +207,8 @@ protected void fillSubmaps(int x, int y) { // If all dirs are connected, we use the fully connected face, the base offset value. this.submapCache[x][y] = submapOffsets[x][y]; } else { - this.submapCache[x][y] = submapOffsets[x + (connected(dirs[0]) ? 2 : 0)] - [y + (connected(dirs[1]) ? 2 : 0)]; + this.submapCache[x][y] = submapOffsets[x + (connected(dirs[0]) ? 2 : 0)][y + + (connected(dirs[1]) ? 2 : 0)]; } } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java index 3a1c21b8db5..bb616bf300c 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java @@ -5,8 +5,8 @@ import com.gregtechceu.gtceu.client.model.machine.MachineModel; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; import com.gregtechceu.gtceu.core.mixins.ReloadableResourceManagerAccessor; - import com.gregtechceu.gtceu.integration.modernfix.GTModernFixIntegration; + import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -30,7 +30,6 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @SuppressWarnings("deprecation") diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java index f0f73deee1d..d9fd7eadba1 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java @@ -15,7 +15,6 @@ import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; -import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; import org.joml.Vector2ic; import org.joml.Vector3f; @@ -38,7 +37,7 @@ public static Vector2f[] findMinMaxUVs(Vector2f[] uvs) { maxU = Math.max(maxU, uv.x()); maxV = Math.max(maxV, uv.y()); } - return new Vector2f[]{ new Vector2f(minU, minV), new Vector2f(maxU, maxV) }; + return new Vector2f[] { new Vector2f(minU, minV), new Vector2f(maxU, maxV) }; } public static int findMinUVIndex(Vector2f[] uvs) { diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java b/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java index bea187acb4b..e0cca005d91 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java @@ -1,9 +1,10 @@ package com.gregtechceu.gtceu.common.data.blocks; -import com.tterrag.registrate.util.entry.BlockEntry; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; +import com.tterrag.registrate.util.entry.BlockEntry; + import static com.gregtechceu.gtceu.common.registry.GTRegistration.REGISTRATE; public class GTDevBlocks { diff --git a/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java b/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java index e8e54ea8c99..d0cf73b0cd1 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java @@ -15,8 +15,8 @@ public class ArrayHelpers { * Note: if the array object has an element type which is a reference type that is not an array type, * the elements themselves are not deeply copied. This method only copies array objects. * - * @param array the array object to deep copy - * @param the type of the array to deep copy + * @param array the array object to deep copy + * @param the type of the array to deep copy * @return a copy of the specified array object, deeply copying multidimensional arrays, or null if the object is * null */ @@ -33,7 +33,7 @@ public class ArrayHelpers { if (componentType.isArray()) { for (int i = 0; i < array.length; ++i) { - //noinspection unchecked + // noinspection unchecked Array.set(copy, i, deepCopy((T[]) array[i])); } } else { From 768d994d709a430ec49d94aaaa212fc8c2271fb8 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Fri, 24 Apr 2026 10:31:23 +0300 Subject: [PATCH 50/66] Add update doc --- docs/content/Modpacks/Changes/v8.0.0.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/content/Modpacks/Changes/v8.0.0.md b/docs/content/Modpacks/Changes/v8.0.0.md index fc7c33f8651..eca9b7b85d1 100644 --- a/docs/content/Modpacks/Changes/v8.0.0.md +++ b/docs/content/Modpacks/Changes/v8.0.0.md @@ -125,9 +125,22 @@ A large number of machine feature interfaces have been removed, and have had the - `IFluidRendererMulti` - Use `MultiblockFluidRendererTrait` +## Connected texture reimplementation +The mod's connected texture logic has been reimplemented in GTM proper. +Texture packs, addons, and modpacks will have to change their texture metadata files for connected texures slightly. +A few regexes for fixing all the MCMeta files is follows, run them in order: + +1. Match: `"ldlib":([\s\{]*)"connection"(:\s".*?")(?:,\s.*)?` + Replace with: `"gtceu":$1"connection_texture"$2` +2. Match: `\s*\},\s*"shimmer":\s*\{(\s*"bloom":.*)` + Replace with: `,$1` +3. Match: `(\{\s*)"shimmer":(\s*\{\s*"bloom":.*)` + Replace with: `$1"gtceu":$2` + + ## Other Changes - `BlastingRecipeBuilder`, `CampfireRecipeBuilder`, `SmeltingRecipeBuilder` and `SmokingRecipeBuilder` have been merged into `SimpleCookingRecipeBuilder` - Example usage: `SimpleCookingRecipeBuilder.campfireCooking("cooking_chicken").input(new ItemStack(Items.CHICKEN)).output(new ItemStacks(Items.COOKED_CHICKEN)).cookingTime(100).experience(100).save(provider);` - `GTFluidImpl` has been merged into `GTFluid`, use `GTFluid.Flowing` and `GTFluid.Source` instead of `GTFluidImpl.Flowing` and `GTFluidImpl.Source`. -- Item behaviors have been moved to `common/item/behavior`, and some items have been moved from `api/item` to `common/item`. \ No newline at end of file +- Item behaviors have been moved to `common/item/behavior`, and some items have been moved from `api/item` to `common/item`. From ce6bff4b3b4913b3df08528c2160850cf1c6ce0b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Fri, 24 Apr 2026 14:19:50 +0300 Subject: [PATCH 51/66] CTM layout documentation --- .../Other-Topics/Connected-Textures.md | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 docs/content/Modpacks/Other-Topics/Connected-Textures.md diff --git a/docs/content/Modpacks/Other-Topics/Connected-Textures.md b/docs/content/Modpacks/Other-Topics/Connected-Textures.md new file mode 100644 index 00000000000..1b929e6aefe --- /dev/null +++ b/docs/content/Modpacks/Other-Topics/Connected-Textures.md @@ -0,0 +1,63 @@ +--- +title: Creating Connected Textures +--- + +**Connected textures** are, as the name would imply, textures that connect with neighboring blocks. + +The CTM renderer will draw the block faces by assembling 4 quadrants from the 5 available block textures. +The normal `texture.png` is the block's "unconnected" texture, and is used when CTM is disabled or the block +has nothing to connect to. +`texture.png` has the outside corner quadrants and `texture_ctm.png` contains the connections. +``` +┌─────────────────┐ ┌────────────────────────────────┐ +│ texture.png │ │ texture_ctm.png │ +│ ╔══════╤══════╗ │ │ ──────┼────── ║ ─────┼───── ║ │ +│ ║ │ ║ │ │ │ │ │║ │ ║ │ +│ ║ 4/4 │ 4/5 ║ │ │ │ 0/0 │ 0/1 │║ 0/2 │ 0/3 ║ │ +│ ╟──────┼──────╢ │ │ ┼──────┼──────┼╟──────┼──────╢ │ +│ ║ │ ║ │ │ │ │ │║ │ ║ │ +│ ║ 5/4 │ 5/5 ║ │ │ │ 1/0 │ 1/1 │║ 1/2 │ 1/3 ║ │ +│ ╚══════╧══════╝ │ │ ──────┼────── ║ ─────┼───── ║ │ +└─────────────────┘ │ ═══════╤═══════╝ ─────┼───── ╚ │ + │ │ │ ││ │ │ │ + │ │ 2/0 │ 2/1 ││ 2/2 │ 2/3 │ │ + │ ┼──────┼──────┼┼──────┼──────┼ │ + │ │ │ ││ │ │ │ + │ │ 3/0 │ 3/1 ││ 3/2 │ 3/3 │ │ + │ ═══════╧═══════╗ ─────┼───── ╔ │ + └────────────────────────────────┘ +``` + +For example, combining sections 4/4, 2/1, 5/4, and 3/1, we can generate a texture connected to the right! +``` +╔══════╤═══════ +║ │ │ +║ 4/4 │ 2/1 │ +╟──────┼──────┼ +║ │ │ +║ 5/4 │ 3/1 │ +╚══════╧═══════ +``` +Combining sections 0/2, 2/3, 5/4, and 3/1, we can generate a texture in the shape of an L (connected to the right and up): +``` +║ ─────┼───── ╚ +║ │ │ +║ 0/2 │ 2/3 │ +╟──────┼──────┼ +║ │ │ +║ 5/4 │ 3/1 │ +╚══════╧═══════ +``` + + +??? example "Example MCMeta file" + (For a texture `mypack/assets/textures/blocks/texture.png` with a ctm texture `mypack/assets/textures/blocks/texture_ctm.png`) + ```json title="mypack:blocks/texture.png.mcmeta" + { + "gtceu": { + "connection_texture": "mypack:blocks/texture_ctm" + } + } + ``` + The CTM texture layout is [here](https://github.com/GregTechCEu/GregTech-Modern/blob/1.20.1/src/main/resources/assets/gtceu/textures/block/ctm_test.png) for the unconnected texture and [here](https://github.com/GregTechCEu/GregTech-Modern/blob/1.20.1/src/main/resources/assets/gtceu/textures/block/ctm_test_ctm.png) for its connections. + Its MCMeta metadata file is [this one](https://github.com/GregTechCEu/GregTech-Modern/blob/1.20.1/src/main/resources/assets/gtceu/textures/block/ctm_test.png.mcmeta). From 0758c321a5f15d9bde19ebfdeb8690cc082ffbb0 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Fri, 1 May 2026 19:29:08 +0300 Subject: [PATCH 52/66] Apply patch --- .../registry/registrate/MachineBuilder.java | 5 +- .../provider/GTBlockstateProvider.java | 24 ++- .../gtceu/common/data/GTMachines.java | 14 +- .../common/data/machines/GTMultiMachines.java | 1 + .../common/data/models/GTMachineModels.java | 145 ++++++++---------- .../model/builder/MachineModelBuilder.java | 14 +- 6 files changed, 103 insertions(+), 100 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java index c1b59704aa3..455863eca4b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java @@ -717,9 +717,8 @@ public DEFINITION register() { @FunctionalInterface public interface ModelInitializer { - void configureModel(@NotNull DataGenContext context, - @NotNull GTBlockstateProvider provider, - @NotNull MachineModelBuilder builder); + void configureModel(DataGenContext context, GTBlockstateProvider provider, + MachineModelBuilder builder); default ModelInitializer andThen(ModelInitializer after) { Objects.requireNonNull(after); diff --git a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java index 6b7789b5159..5a669b9c9a2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java +++ b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java @@ -101,20 +101,18 @@ public T addVanillaGenerator(Block block, T gene if (rotationState == RotationState.NONE) return null; PropertyDispatch dispatch; - if (!allowExtendedFacing) { - var disp = PropertyDispatch.property(rotationState.property); - - dispatch = disp.generate((front) -> { - var orientation = ExtendedBlockModelRotation.get(front, Direction.NORTH); - return applyOrientation(Variant.variant(), orientation); - }); + if (allowExtendedFacing) { + dispatch = PropertyDispatch.properties(rotationState.property, GTBlockStateProperties.UPWARDS_FACING) + .generate((front, up) -> { + var orientation = ExtendedBlockModelRotation.get(front, up); + return applyOrientation(Variant.variant(), orientation); + }); } else { - var disp = PropertyDispatch.properties(rotationState.property, GTBlockStateProperties.UPWARDS_FACING); - - dispatch = disp.generate((front, up) -> { - var orientation = ExtendedBlockModelRotation.get(front, up); - return applyOrientation(Variant.variant(), orientation); - }); + dispatch = PropertyDispatch.property(rotationState.property) + .generate((front) -> { + var orientation = ExtendedBlockModelRotation.get(front, Direction.NORTH); + return applyOrientation(Variant.variant(), orientation); + }); } return dispatch; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java index dfdf9ae80ef..1dcb16fd70c 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java @@ -40,6 +40,7 @@ import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; +import net.minecraftforge.client.model.generators.ConfiguredModel; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidType; import net.minecraftforge.fml.ModLoader; @@ -878,7 +879,18 @@ public class GTMachines { .rotationState(RotationState.ALL) .abilities(PartAbility.PUMP_FLUID_HATCH) .modelProperty(IS_FORMED, false) - .model(createBasicReplaceableTextureMachineModel(GTCEu.id("block/machine/part/pump_hatch"))) + .model(createBasicReplaceableTextureMachineModel(GTCEu.id("block/machine/part/pump_hatch")) + .andThen(builder -> { + // UV lock the model so the plank texture doesn't rotate weirdly + builder.replaceForAllStates((state, models) -> { + for (int i = 0; i < models.length; i++) { + models[i] = ConfiguredModel.builder() + .modelFile(models[i].model).uvLock(true) + .buildLast(); + } + return models; + }); + })) .register(); public static final MachineDefinition MAINTENANCE_HATCH = REGISTRATE diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java index dfbcf64b53d..a4f22f1f7ab 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java @@ -585,6 +585,7 @@ public class GTMultiMachines { .model(createSidedWorkableCasingMachineModel(GTCEu.id("block/casings/pump_deck"), GTCEu.id("block/multiblock/primitive_pump")) .andThen(builder -> { + // UV lock the model so the plank texture doesn't rotate weirdly builder.replaceForAllStates((state, models) -> { for (int i = 0; i < models.length; i++) { models[i] = ConfiguredModel.builder() diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java b/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java index 6ba47cd12d2..17453ba2366 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java @@ -30,6 +30,7 @@ import com.tterrag.registrate.util.nullness.NonNullBiConsumer; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Locale; @@ -70,14 +71,14 @@ public class GTMachineModels { public static MachineBuilder.ModelInitializer createBasicMachineModel(ResourceLocation baseModel) { return (ctx, prov, builder) -> { var model = prov.models().getExistingFile(baseModel); - builder.forAllStatesModels(state -> model); + builder.partialState().setModel(model); }; } public static MachineBuilder.ModelInitializer createBasicReplaceableTextureMachineModel(ResourceLocation baseModel) { return (ctx, prov, builder) -> { var model = prov.models().getExistingFile(baseModel); - builder.forAllStatesModels(state -> model); + builder.partialState().setModel(model); builder.addReplaceableTextures("bottom", "top", "side"); }; } @@ -88,7 +89,7 @@ public static MachineBuilder.ModelInitializer createTieredHullMachineModel(Resou .parent(prov.models().getExistingFile(parentModel)); tieredHullTextures(model, builder.getOwner().getTier()); - builder.forAllStatesModels(state -> model); + builder.partialState().setModel(model); }; } @@ -97,7 +98,7 @@ public static MachineBuilder.ModelInitializer createOverlayTieredHullMachineMode BlockModelBuilder model = prov.models().nested() .parent(prov.models().getExistingFile(overlayModel)); tieredHullTextures(model, builder.getOwner().getTier()); - builder.forAllStatesModels(state -> model); + builder.partialState().setModel(model); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -110,7 +111,7 @@ public static MachineBuilder.ModelInitializer createOverlayCasingMachineModel(Re .parent(prov.models().getExistingFile(overlayModel)); model.texture("all", baseCasingTexture); - builder.forAllStatesModels(state -> model); + builder.partialState().setModel(model); builder.addReplaceableTextures("all"); }; } @@ -119,11 +120,11 @@ public static MachineBuilder.ModelInitializer createColorOverlayTieredHullMachin @Nullable ResourceLocation pipeOverlay, @Nullable ResourceLocation emissiveOverlay) { return (ctx, prov, builder) -> { - builder.forAllStatesModels(state -> { - BlockModelBuilder model = colorOverlayHullModel(overlay, pipeOverlay, emissiveOverlay, state, - prov.models()); + builder.forAllStatesModelsExcept(state -> { + BlockModelBuilder model = colorOverlayHullModel(overlay, pipeOverlay, emissiveOverlay, + state, prov.models()); return tieredHullTextures(model, builder.getOwner().getTier()); - }); + }, IS_FORMED); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -137,7 +138,7 @@ public static MachineBuilder.ModelInitializer createSingleOverlayTieredHullMachi .texture("overlay", overlayTexture) .texture("overlay_emissive", emissiveOverlayTexture); tieredHullTextures(model, builder.getOwner().getTier()); - builder.forAllStatesModels(state -> model); + builder.partialState().setModel(model); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -147,25 +148,25 @@ public static MachineBuilder.ModelInitializer createWorkableTieredHullMachineMod return (ctx, prov, builder) -> { WorkableOverlays overlays = WorkableOverlays.get(overlayDir, prov.getExistingFileHelper()); - builder.forAllStates(state -> { + builder.forAllStatesModelsExcept(state -> { RecipeLogic.Status status = state.getValue(RECIPE_LOGIC_STATUS); BlockModelBuilder model = prov.models().nested().parent(tieredHullModel(prov.models(), builder)); return addWorkableOverlays(overlays, status, model); - }); + }, IS_FORMED); }; } public static MachineBuilder.ModelInitializer createOverlaySteamHullMachineModel(ResourceLocation overlayModel) { return (ctx, prov, builder) -> { - builder.forAllStatesModels(state -> { + builder.forAllStatesModelsExcept(state -> { boolean steel = state.getOptionalValue(IS_STEEL_MACHINE).orElse(false); BlockModelBuilder model = prov.models().nested() .parent(prov.models().getExistingFile(overlayModel)); steamCasingTextures(model, steel); return model; - }); + }, IS_FORMED); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -175,12 +176,12 @@ public static MachineBuilder.ModelInitializer createColorOverlaySteamHullMachine @Nullable ResourceLocation pipeOverlay, @Nullable ResourceLocation emissiveOverlay) { return (ctx, prov, builder) -> { - builder.forAllStatesModels(state -> { - BlockModelBuilder model = colorOverlayHullModel(overlay, pipeOverlay, emissiveOverlay, state, - prov.models()); + builder.forAllStatesModelsExcept(state -> { + BlockModelBuilder model = colorOverlayHullModel(overlay, pipeOverlay, emissiveOverlay, + state, prov.models()); steamCasingTextures(model, state.getOptionalValue(IS_STEEL_MACHINE).orElse(false)); return model; - }); + }, IS_FORMED); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -228,14 +229,14 @@ public static MachineBuilder.ModelInitializer createWorkableCasingMachineModel(R return (ctx, prov, builder) -> { WorkableOverlays overlays = WorkableOverlays.get(overlayDir, prov.getExistingFileHelper()); - builder.forAllStates(state -> { + builder.forAllStatesModelsExcept(state -> { RecipeLogic.Status status = state.getValue(RECIPE_LOGIC_STATUS); BlockModelBuilder model = prov.models().nested() .parent(prov.models().getExistingFile(CUBE_ALL_SIDED_OVERLAY_MODEL)) .texture("all", baseCasingTexture); return addWorkableOverlays(overlays, status, model); - }); + }, IS_FORMED); builder.addTextureOverride("all", baseCasingTexture); }; } @@ -247,7 +248,7 @@ public static MachineBuilder.ModelInitializer createSidedOverlayCasingMachineMod BlockModelBuilder model = prov.models().nested() .parent(prov.models().getExistingFile(overlayModel)); casingTextures(model, baseCasingTexture); - builder.forAllStatesModels(state -> model); + builder.partialState().setModel(model); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -258,14 +259,14 @@ public static MachineBuilder.ModelInitializer createSidedWorkableCasingMachineMo return (ctx, prov, builder) -> { WorkableOverlays overlays = WorkableOverlays.get(overlayDir, prov.getExistingFileHelper()); - builder.forAllStates(state -> { + builder.forAllStatesModelsExcept(state -> { RecipeLogic.Status status = state.getValue(RECIPE_LOGIC_STATUS); BlockModelBuilder model = prov.models().nested() .parent(prov.models().getExistingFile(SIDED_SIDED_OVERLAY_MODEL)); casingTextures(model, baseCasingTexture); return addWorkableOverlays(overlays, status, model); - }); + }, IS_FORMED); var texturePath = baseCasingTexture; if (!texturePath.getPath().endsWith("/")) { @@ -325,7 +326,7 @@ public static MachineBuilder.ModelInitializer createBatteryBufferModel(int inven .texture("overlay_out_io", BLANK_TEXTURE); tieredHullTextures(model, builder.getOwner().getTier()); - builder.forAllStatesModels(state -> model); + builder.partialState().setModel(model); }; } @@ -362,17 +363,14 @@ public static MachineBuilder.ModelInitializer createChargerModel() { }); }; } - // spotless:on public static final ResourceLocation TRANSFORMER_LIKE = GTCEu.id("block/machine/template/transformer_like_machine"); public static final ResourceLocation CONVERTER_FE_IN = GTCEu.id("block/overlay/converter/converter_native_in"); public static final ResourceLocation CONVERTER_FE_OUT = GTCEu.id("block/overlay/converter/converter_native_out"); - public static final ResourceLocation CONVERTER_FE_IN_EMISSIVE = GTCEu - .id("block/overlay/converter/converter_native_in_emissive"); - public static final ResourceLocation CONVERTER_FE_OUT_EMISSIVE = GTCEu - .id("block/overlay/converter/converter_native_out_emissive"); + public static final ResourceLocation CONVERTER_FE_IN_EMISSIVE = GTCEu.id("block/overlay/converter/converter_native_in_emissive"); + public static final ResourceLocation CONVERTER_FE_OUT_EMISSIVE = GTCEu.id("block/overlay/converter/converter_native_out_emissive"); public static MachineBuilder.ModelInitializer createConverterModel(int amperage) { return (ctx, prov, builder) -> { @@ -398,14 +396,14 @@ public static MachineBuilder.ModelInitializer createConverterModel(int amperage) tieredHullTextures(feToEuModel, builder.getOwner().getTier()); builder.partialState() - .with(IS_FE_TO_EU, false) - .setModel(euToFeModel) + .with(IS_FE_TO_EU, false) + .setModel(euToFeModel) .partialState() - .with(IS_FE_TO_EU, true) - .setModel(feToEuModel) - .end(); + .with(IS_FE_TO_EU, true) + .setModel(feToEuModel); }; } + // spotless:on public static MachineBuilder.ModelInitializer createCrateModel(boolean wooden) { return (ctx, prov, builder) -> { @@ -425,7 +423,7 @@ public static MachineBuilder.ModelInitializer createCrateModel(boolean wooden) { public static MachineBuilder.ModelInitializer createDiodeModel() { return (ctx, prov, builder) -> { - builder.forAllStatesModels(renderState -> { + builder.forAllStatesModelsExcept(renderState -> { DiodePartMachine.AmpMode mode = renderState.getValue(DIODE_AMP_MODE); final EnergyIOOverlay energyIn = IN_OVERLAYS_FOR_AMP.get(mode.getAmpValue()); final EnergyIOOverlay energyOut = OUT_OVERLAYS_FOR_AMP.get(mode.getAmpValue()); @@ -440,7 +438,7 @@ public static MachineBuilder.ModelInitializer createDiodeModel() { .texture("overlay_out_tinted", energyOut.getTintedPart()); tieredHullTextures(model, builder.getOwner().getTier()); return model; - }); + }, IS_FORMED); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -448,7 +446,7 @@ public static MachineBuilder.ModelInitializer createDiodeModel() { public static MachineBuilder.ModelInitializer createTransformerModel(int baseAmp) { return (ctx, prov, builder) -> { - builder.forAllStatesModels(renderState -> { + builder.forAllStatesModelsExcept(renderState -> { boolean transformUp = renderState.getValue(IS_TRANSFORM_UP); EnergyIOOverlay frontFace = (transformUp ? OUT_OVERLAYS_FOR_AMP : IN_OVERLAYS_FOR_AMP) .get(baseAmp); @@ -464,7 +462,7 @@ public static MachineBuilder.ModelInitializer createTransformerModel(int baseAmp .texture("overlay_out_tinted", otherFace.getTintedPart()); tieredHullTextures(model, builder.getOwner().getTier()); return model; - }); + }, IS_FORMED); }; } @@ -526,23 +524,9 @@ public static MachineBuilder.ModelInitializer createWorldAcceleratorModel(Resour WorkableOverlays rtOverlays = WorkableOverlays.get(rtModeModelPath, prov.getExistingFileHelper()); WorkableOverlays beOverlays = WorkableOverlays.get(beModeModelPath, prov.getExistingFileHelper()); - builder.forAllStates(state -> { - boolean rtMode = state.getValue(IS_RANDOM_TICK_MODE); - WorkableOverlays overlays = rtMode ? rtOverlays : beOverlays; - - boolean active = state.getValue(IS_ACTIVE); - boolean workingEnabled = state.getValue(IS_WORKING_ENABLED); - RecipeLogic.Status status = active ? - workingEnabled ? - RecipeLogic.Status.WORKING : - RecipeLogic.Status.SUSPEND : - RecipeLogic.Status.IDLE; - - BlockModelBuilder model = prov.models().nested() - .parent(prov.models().getExistingFile(SIDED_SIDED_OVERLAY_MODEL)); - tieredHullTextures(model, builder.getOwner().getTier()); - - return addWorkableOverlays(overlays, status, model); + builder.forAllStatesModels(state -> { + WorkableOverlays overlays = state.getValue(IS_RANDOM_TICK_MODE) ? rtOverlays : beOverlays; + return createModelFromActiveWorkingState(prov, builder, overlays, state); }); }; } @@ -552,7 +536,7 @@ public static MachineBuilder.ModelInitializer createWorldAcceleratorModel(Resour public static MachineBuilder.ModelInitializer createMaintenanceModel(ResourceLocation overlayModel) { return (ctx, prov, builder) -> { - builder.forAllStatesModels(state -> { + builder.forAllStatesModelsExcept(state -> { var baseModel = prov.models().nested() .parent(prov.models().getExistingFile(overlayModel)); tieredHullTextures(baseModel, builder.getOwner().getTier()); @@ -561,7 +545,7 @@ public static MachineBuilder.ModelInitializer createMaintenanceModel(ResourceLoc baseModel.texture("overlay_2", MAINTENANCE_TAPED_OVERLAY); } return baseModel; - }); + }, IS_FORMED); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -571,6 +555,7 @@ public static MachineBuilder.ModelInitializer createMaintenanceModel(ResourceLoc public static final ResourceLocation HPCA_PART_MODEL = GTCEu.id("block/machine/template/part/hpca_part_machine"); public static final ResourceLocation COMPUTER_CASING_TEXTURE = GTCEu.id("block/casings/hpca/computer_casing/"); public static final ResourceLocation ADVANCED_COMPUTER_CASING_TEXTURE = GTCEu.id("block/casings/hpca/advanced_computer_casing/"); + // spotless:on public static MachineBuilder.ModelInitializer createHPCAPartModel(boolean advanced, ResourceLocation normalTexture, @@ -586,14 +571,14 @@ public static MachineBuilder.ModelInitializer createHPCAPartModel(boolean advanc casingTexture(baseModel, "back", textures); casingTexture(baseModel, "side", textures); - builder.forAllStatesModels(state -> { + builder.forAllStatesModelsExcept(state -> { boolean damaged = state.getValue(IS_HPCA_PART_DAMAGED); boolean active = state.getValue(IS_ACTIVE); return prov.models().nested().parent(baseModel) .texture("overlay", overlay.getTexture(active, damaged)) .texture("overlay_emissive", overlay.getEmissiveTexture(active, damaged)); - }); + }, IS_FORMED); }; } @@ -609,7 +594,7 @@ public static MachineBuilder.ModelInitializer createFisherModel() { .texture("overlay_emissive", OVERLAY_QTANK_EMISSIVE_TEXTURE); tieredHullTextures(model, builder.getOwner().getTier()); - builder.forAllStatesModels(state -> model); + builder.partialState().setModel(model); }; } @@ -617,28 +602,31 @@ public static MachineBuilder.ModelInitializer createItemCollectorModel(ResourceL return (ctx, prov, builder) -> { WorkableOverlays overlays = WorkableOverlays.get(overlayDir, prov.getExistingFileHelper()); - builder.forAllStates(state -> { - boolean active = state.getValue(IS_ACTIVE); - boolean workingEnabled = state.getValue(IS_WORKING_ENABLED); - RecipeLogic.Status status = active ? - workingEnabled ? - RecipeLogic.Status.WORKING : - RecipeLogic.Status.SUSPEND : - RecipeLogic.Status.IDLE; + builder.forAllStatesModels(state -> createModelFromActiveWorkingState(prov, builder, overlays, state)); + }; + } - BlockModelBuilder model = prov.models().nested() - .parent(prov.models().getExistingFile(SIDED_SIDED_OVERLAY_MODEL)); - tieredHullTextures(model, builder.getOwner().getTier()); + public static ModelFile createModelFromActiveWorkingState(@NotNull GTBlockstateProvider prov, + @NotNull MachineModelBuilder builder, + WorkableOverlays overlays, MachineRenderState state) { + RecipeLogic.Status status = state.getValue(IS_ACTIVE) ? + state.getValue(IS_WORKING_ENABLED) ? + RecipeLogic.Status.WORKING : + RecipeLogic.Status.SUSPEND : + RecipeLogic.Status.IDLE; - return addWorkableOverlays(overlays, status, model); - }); - }; + BlockModelBuilder model = prov.models().nested() + .parent(prov.models().getExistingFile(SIDED_SIDED_OVERLAY_MODEL)); + tieredHullTextures(model, builder.getOwner().getTier()); + + return addWorkableOverlays(overlays, status, model); } // endregion // region helper functions + // spotless:off public static NonNullBiConsumer, GTBlockstateProvider> createMachineModel(MachineBuilder.ModelInitializer modelInitializer) { return (ctx, prov) -> { Block block = ctx.getEntry(); @@ -652,8 +640,9 @@ public static MachineBuilder.ModelInitializer createItemCollectorModel(ResourceL MachineModelBuilder builder = prov.models().getBuilder(modelLocation) .customLoader(MachineModelBuilder.begin(definition)); modelInitializer.configureModel(ctx, prov, builder); + final BlockModelBuilder model = builder.end(); - model.parent(prov.models().getExistingFile(prov.mcLoc("block/block"))); + model.parent(new ModelFile.UncheckedModelFile("block/block")); var generator = prov.multiVariantGenerator(block, Variant.variant().with(VariantProperties.MODEL, model.getLocation())); @@ -665,8 +654,8 @@ public static MachineBuilder.ModelInitializer createItemCollectorModel(ResourceL } // spotless:on - public static ConfiguredModel[] addWorkableOverlays(WorkableOverlays overlays, RecipeLogic.Status status, - BlockModelBuilder model) { + public static ModelFile addWorkableOverlays(WorkableOverlays overlays, RecipeLogic.Status status, + BlockModelBuilder model) { for (var entry : overlays.getTextures().entrySet()) { var face = entry.getKey(); var textures = entry.getValue(); @@ -681,7 +670,7 @@ public static ConfiguredModel[] addWorkableOverlays(WorkableOverlays overlays, R model.texture(OVERLAY_PREFIX + face.getName() + EMISSIVE_SUFFIX, overlayEmissive); } } - return ConfiguredModel.builder().modelFile(model).build(); + return model; } public static BlockModelBuilder colorOverlayHullModel(ResourceLocation overlay, diff --git a/src/main/java/com/gregtechceu/gtceu/data/model/builder/MachineModelBuilder.java b/src/main/java/com/gregtechceu/gtceu/data/model/builder/MachineModelBuilder.java index 27284c95f96..f532e194db5 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/model/builder/MachineModelBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/data/model/builder/MachineModelBuilder.java @@ -302,7 +302,12 @@ public PartBuilder part(ResourceLocation model) { } public MachineModelBuilder forAllStatesModels(Function mapper) { - return forAllStates(mapper.andThen(m -> ConfiguredModel.builder().modelFile(m).build())); + return forAllStatesModelsExcept(mapper); + } + + public MachineModelBuilder forAllStatesModelsExcept(Function mapper, + Property... ignored) { + return forAllStatesExcept(mapper.andThen(m -> ConfiguredModel.builder().modelFile(m).build()), ignored); } public MachineModelBuilder forAllStates(Function mapper) { @@ -357,15 +362,14 @@ public static class PartialState> implements Predicate private final MachineDefinition owner; @Getter private final SortedMap, Comparable> setStates; - @Nullable private final MachineModelBuilder outerBuilder; - private PartialState(MachineDefinition owner, @Nullable MachineModelBuilder outerBuilder) { + private PartialState(MachineDefinition owner, MachineModelBuilder outerBuilder) { this(owner, ImmutableMap.of(), outerBuilder); } private PartialState(MachineDefinition owner, Map, Comparable> setStates, - @Nullable MachineModelBuilder outerBuilder) { + MachineModelBuilder outerBuilder) { this.owner = owner; this.outerBuilder = outerBuilder; for (Map.Entry, Comparable> entry : setStates.entrySet()) { @@ -688,7 +692,7 @@ public class ConditionGroup { .arrayListValues() .build(); public final List nestedConditionGroups = new ArrayList<>(); - private ConditionGroup parent = null; + private @Nullable ConditionGroup parent = null; public boolean useOr; /** From 0455aa244d5051ba1c73c002d9707f324a35bb8a Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Fri, 1 May 2026 20:52:39 +0300 Subject: [PATCH 53/66] Fix quad derotation not working as intended --- .../client/model/quad/MutableQuadView.java | 7 ++- .../gtceu/client/util/quad/CTMHelper.java | 59 ++++++++++--------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java index 33ffcfb44cc..c807573e0c1 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java @@ -27,6 +27,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; +import org.joml.Vector2fc; import org.joml.Vector3f; import static com.gregtechceu.gtceu.client.model.quad.EncodingFormat.*; @@ -219,13 +220,13 @@ public MutableQuadView uv(int vertexIndex, float u, float v) { * Set texture coordinates. * *

- * Only use this function if you already have a {@link Vector2f}. + * Only use this function if you already have a {@link Vector2fc}. * Otherwise, see {@link MutableQuadView#uv(int, float, float)}. * * @see MutableQuadView#uv(int, float, float) */ - public MutableQuadView uv(int vertexIndex, Vector2f uv) { - return uv(vertexIndex, uv.x, uv.y); + public MutableQuadView uv(int vertexIndex, Vector2fc uv) { + return uv(vertexIndex, uv.x(), uv.y()); } /** diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java index d9fd7eadba1..e6d4c3aa0be 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java @@ -40,21 +40,6 @@ public static Vector2f[] findMinMaxUVs(Vector2f[] uvs) { return new Vector2f[] { new Vector2f(minU, minV), new Vector2f(maxU, maxV) }; } - public static int findMinUVIndex(Vector2f[] uvs) { - int minIndex = 0; - float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE; - - for (int v = 0; v < 4; v++) { - Vector2f uv = uvs[v]; - if (uv.x() <= minU && uv.y() <= minV) { - minIndex = v; - minU = uv.x(); - minV = uv.y(); - } - } - return minIndex; - } - public static List buildCTMQuads(BlockAndTintGetter level, BlockPos pos, BlockState state, List quads, Direction cullFace) { CTMCache ctmCache = CTMCache.getInstance(); @@ -90,6 +75,7 @@ public static List buildCTMQuads(CTMCache cachedConnections, List xy[i].set(position.z, position.y); @@ -235,10 +236,10 @@ public static MutableQuadView subsect(MutableQuadView quad, ISubmap submap) { float u3 = normalize(newXy[3].x, xy[3].x, xy[0].x), v3 = normalize(newXy[3].y, xy[3].y, xy[2].y); - quad.uv(0, Mth.lerp(u0, uvs[0].x, uvs[3].x), Mth.lerp(v0, uvs[0].y, uvs[1].y)); - quad.uv(1, Mth.lerp(u1, uvs[1].x, uvs[2].x), Mth.lerp(v1, uvs[1].y, uvs[0].y)); - quad.uv(2, Mth.lerp(u2, uvs[2].x, uvs[1].x), Mth.lerp(v2, uvs[2].y, uvs[3].y)); - quad.uv(3, Mth.lerp(u3, uvs[3].x, uvs[0].x), Mth.lerp(v3, uvs[3].y, uvs[2].y)); + quad.uv(0, Mth.lerp(u0, quad.u(0), quad.u(3)), Mth.lerp(v0, quad.v(0), quad.v(1))); + quad.uv(1, Mth.lerp(u1, quad.u(1), quad.u(2)), Mth.lerp(v1, quad.v(1), quad.v(0))); + quad.uv(2, Mth.lerp(u2, quad.u(2), quad.u(1)), Mth.lerp(v2, quad.v(2), quad.v(3))); + quad.uv(3, Mth.lerp(u3, quad.u(3), quad.u(0)), Mth.lerp(v3, quad.v(3), quad.v(2))); // spotless:off for (int i = 0; i < 4; i++) { @@ -262,6 +263,6 @@ private static Vector2f normalize(float minU, float minV, float maxU, float maxV /// scale {@code delta} to a 0-1 range based on {@code min} and {@code max} public static float normalize(float delta, float min, float max) { if (min == max) return 0.5f; - return Mth.inverseLerp(delta, min, max); + return Mth.clamp(Mth.inverseLerp(delta, min, max), 0.0f, 1.0f); } } From fd05e9b044bae126e5e6181c498e290a2efd812a Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Fri, 1 May 2026 23:27:49 +0300 Subject: [PATCH 54/66] Oops, that belonged to a different branch Revert "Apply patch" This reverts commit 0758c321a5f15d9bde19ebfdeb8690cc082ffbb0. --- .../registry/registrate/MachineBuilder.java | 5 +- .../provider/GTBlockstateProvider.java | 24 +-- .../gtceu/common/data/GTMachines.java | 14 +- .../common/data/machines/GTMultiMachines.java | 1 - .../common/data/models/GTMachineModels.java | 145 ++++++++++-------- .../model/builder/MachineModelBuilder.java | 14 +- 6 files changed, 100 insertions(+), 103 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java index 455863eca4b..c1b59704aa3 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java @@ -717,8 +717,9 @@ public DEFINITION register() { @FunctionalInterface public interface ModelInitializer { - void configureModel(DataGenContext context, GTBlockstateProvider provider, - MachineModelBuilder builder); + void configureModel(@NotNull DataGenContext context, + @NotNull GTBlockstateProvider provider, + @NotNull MachineModelBuilder builder); default ModelInitializer andThen(ModelInitializer after) { Objects.requireNonNull(after); diff --git a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java index 5a669b9c9a2..6b7789b5159 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java +++ b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java @@ -101,18 +101,20 @@ public T addVanillaGenerator(Block block, T gene if (rotationState == RotationState.NONE) return null; PropertyDispatch dispatch; - if (allowExtendedFacing) { - dispatch = PropertyDispatch.properties(rotationState.property, GTBlockStateProperties.UPWARDS_FACING) - .generate((front, up) -> { - var orientation = ExtendedBlockModelRotation.get(front, up); - return applyOrientation(Variant.variant(), orientation); - }); + if (!allowExtendedFacing) { + var disp = PropertyDispatch.property(rotationState.property); + + dispatch = disp.generate((front) -> { + var orientation = ExtendedBlockModelRotation.get(front, Direction.NORTH); + return applyOrientation(Variant.variant(), orientation); + }); } else { - dispatch = PropertyDispatch.property(rotationState.property) - .generate((front) -> { - var orientation = ExtendedBlockModelRotation.get(front, Direction.NORTH); - return applyOrientation(Variant.variant(), orientation); - }); + var disp = PropertyDispatch.properties(rotationState.property, GTBlockStateProperties.UPWARDS_FACING); + + dispatch = disp.generate((front, up) -> { + var orientation = ExtendedBlockModelRotation.get(front, up); + return applyOrientation(Variant.variant(), orientation); + }); } return dispatch; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java index 1dcb16fd70c..dfdf9ae80ef 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java @@ -40,7 +40,6 @@ import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.client.model.generators.ConfiguredModel; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidType; import net.minecraftforge.fml.ModLoader; @@ -879,18 +878,7 @@ public class GTMachines { .rotationState(RotationState.ALL) .abilities(PartAbility.PUMP_FLUID_HATCH) .modelProperty(IS_FORMED, false) - .model(createBasicReplaceableTextureMachineModel(GTCEu.id("block/machine/part/pump_hatch")) - .andThen(builder -> { - // UV lock the model so the plank texture doesn't rotate weirdly - builder.replaceForAllStates((state, models) -> { - for (int i = 0; i < models.length; i++) { - models[i] = ConfiguredModel.builder() - .modelFile(models[i].model).uvLock(true) - .buildLast(); - } - return models; - }); - })) + .model(createBasicReplaceableTextureMachineModel(GTCEu.id("block/machine/part/pump_hatch"))) .register(); public static final MachineDefinition MAINTENANCE_HATCH = REGISTRATE diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java index a4f22f1f7ab..dfbcf64b53d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java @@ -585,7 +585,6 @@ public class GTMultiMachines { .model(createSidedWorkableCasingMachineModel(GTCEu.id("block/casings/pump_deck"), GTCEu.id("block/multiblock/primitive_pump")) .andThen(builder -> { - // UV lock the model so the plank texture doesn't rotate weirdly builder.replaceForAllStates((state, models) -> { for (int i = 0; i < models.length; i++) { models[i] = ConfiguredModel.builder() diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java b/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java index 17453ba2366..6ba47cd12d2 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java @@ -30,7 +30,6 @@ import com.tterrag.registrate.util.nullness.NonNullBiConsumer; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Locale; @@ -71,14 +70,14 @@ public class GTMachineModels { public static MachineBuilder.ModelInitializer createBasicMachineModel(ResourceLocation baseModel) { return (ctx, prov, builder) -> { var model = prov.models().getExistingFile(baseModel); - builder.partialState().setModel(model); + builder.forAllStatesModels(state -> model); }; } public static MachineBuilder.ModelInitializer createBasicReplaceableTextureMachineModel(ResourceLocation baseModel) { return (ctx, prov, builder) -> { var model = prov.models().getExistingFile(baseModel); - builder.partialState().setModel(model); + builder.forAllStatesModels(state -> model); builder.addReplaceableTextures("bottom", "top", "side"); }; } @@ -89,7 +88,7 @@ public static MachineBuilder.ModelInitializer createTieredHullMachineModel(Resou .parent(prov.models().getExistingFile(parentModel)); tieredHullTextures(model, builder.getOwner().getTier()); - builder.partialState().setModel(model); + builder.forAllStatesModels(state -> model); }; } @@ -98,7 +97,7 @@ public static MachineBuilder.ModelInitializer createOverlayTieredHullMachineMode BlockModelBuilder model = prov.models().nested() .parent(prov.models().getExistingFile(overlayModel)); tieredHullTextures(model, builder.getOwner().getTier()); - builder.partialState().setModel(model); + builder.forAllStatesModels(state -> model); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -111,7 +110,7 @@ public static MachineBuilder.ModelInitializer createOverlayCasingMachineModel(Re .parent(prov.models().getExistingFile(overlayModel)); model.texture("all", baseCasingTexture); - builder.partialState().setModel(model); + builder.forAllStatesModels(state -> model); builder.addReplaceableTextures("all"); }; } @@ -120,11 +119,11 @@ public static MachineBuilder.ModelInitializer createColorOverlayTieredHullMachin @Nullable ResourceLocation pipeOverlay, @Nullable ResourceLocation emissiveOverlay) { return (ctx, prov, builder) -> { - builder.forAllStatesModelsExcept(state -> { - BlockModelBuilder model = colorOverlayHullModel(overlay, pipeOverlay, emissiveOverlay, - state, prov.models()); + builder.forAllStatesModels(state -> { + BlockModelBuilder model = colorOverlayHullModel(overlay, pipeOverlay, emissiveOverlay, state, + prov.models()); return tieredHullTextures(model, builder.getOwner().getTier()); - }, IS_FORMED); + }); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -138,7 +137,7 @@ public static MachineBuilder.ModelInitializer createSingleOverlayTieredHullMachi .texture("overlay", overlayTexture) .texture("overlay_emissive", emissiveOverlayTexture); tieredHullTextures(model, builder.getOwner().getTier()); - builder.partialState().setModel(model); + builder.forAllStatesModels(state -> model); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -148,25 +147,25 @@ public static MachineBuilder.ModelInitializer createWorkableTieredHullMachineMod return (ctx, prov, builder) -> { WorkableOverlays overlays = WorkableOverlays.get(overlayDir, prov.getExistingFileHelper()); - builder.forAllStatesModelsExcept(state -> { + builder.forAllStates(state -> { RecipeLogic.Status status = state.getValue(RECIPE_LOGIC_STATUS); BlockModelBuilder model = prov.models().nested().parent(tieredHullModel(prov.models(), builder)); return addWorkableOverlays(overlays, status, model); - }, IS_FORMED); + }); }; } public static MachineBuilder.ModelInitializer createOverlaySteamHullMachineModel(ResourceLocation overlayModel) { return (ctx, prov, builder) -> { - builder.forAllStatesModelsExcept(state -> { + builder.forAllStatesModels(state -> { boolean steel = state.getOptionalValue(IS_STEEL_MACHINE).orElse(false); BlockModelBuilder model = prov.models().nested() .parent(prov.models().getExistingFile(overlayModel)); steamCasingTextures(model, steel); return model; - }, IS_FORMED); + }); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -176,12 +175,12 @@ public static MachineBuilder.ModelInitializer createColorOverlaySteamHullMachine @Nullable ResourceLocation pipeOverlay, @Nullable ResourceLocation emissiveOverlay) { return (ctx, prov, builder) -> { - builder.forAllStatesModelsExcept(state -> { - BlockModelBuilder model = colorOverlayHullModel(overlay, pipeOverlay, emissiveOverlay, - state, prov.models()); + builder.forAllStatesModels(state -> { + BlockModelBuilder model = colorOverlayHullModel(overlay, pipeOverlay, emissiveOverlay, state, + prov.models()); steamCasingTextures(model, state.getOptionalValue(IS_STEEL_MACHINE).orElse(false)); return model; - }, IS_FORMED); + }); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -229,14 +228,14 @@ public static MachineBuilder.ModelInitializer createWorkableCasingMachineModel(R return (ctx, prov, builder) -> { WorkableOverlays overlays = WorkableOverlays.get(overlayDir, prov.getExistingFileHelper()); - builder.forAllStatesModelsExcept(state -> { + builder.forAllStates(state -> { RecipeLogic.Status status = state.getValue(RECIPE_LOGIC_STATUS); BlockModelBuilder model = prov.models().nested() .parent(prov.models().getExistingFile(CUBE_ALL_SIDED_OVERLAY_MODEL)) .texture("all", baseCasingTexture); return addWorkableOverlays(overlays, status, model); - }, IS_FORMED); + }); builder.addTextureOverride("all", baseCasingTexture); }; } @@ -248,7 +247,7 @@ public static MachineBuilder.ModelInitializer createSidedOverlayCasingMachineMod BlockModelBuilder model = prov.models().nested() .parent(prov.models().getExistingFile(overlayModel)); casingTextures(model, baseCasingTexture); - builder.partialState().setModel(model); + builder.forAllStatesModels(state -> model); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -259,14 +258,14 @@ public static MachineBuilder.ModelInitializer createSidedWorkableCasingMachineMo return (ctx, prov, builder) -> { WorkableOverlays overlays = WorkableOverlays.get(overlayDir, prov.getExistingFileHelper()); - builder.forAllStatesModelsExcept(state -> { + builder.forAllStates(state -> { RecipeLogic.Status status = state.getValue(RECIPE_LOGIC_STATUS); BlockModelBuilder model = prov.models().nested() .parent(prov.models().getExistingFile(SIDED_SIDED_OVERLAY_MODEL)); casingTextures(model, baseCasingTexture); return addWorkableOverlays(overlays, status, model); - }, IS_FORMED); + }); var texturePath = baseCasingTexture; if (!texturePath.getPath().endsWith("/")) { @@ -326,7 +325,7 @@ public static MachineBuilder.ModelInitializer createBatteryBufferModel(int inven .texture("overlay_out_io", BLANK_TEXTURE); tieredHullTextures(model, builder.getOwner().getTier()); - builder.partialState().setModel(model); + builder.forAllStatesModels(state -> model); }; } @@ -363,14 +362,17 @@ public static MachineBuilder.ModelInitializer createChargerModel() { }); }; } + // spotless:on public static final ResourceLocation TRANSFORMER_LIKE = GTCEu.id("block/machine/template/transformer_like_machine"); public static final ResourceLocation CONVERTER_FE_IN = GTCEu.id("block/overlay/converter/converter_native_in"); public static final ResourceLocation CONVERTER_FE_OUT = GTCEu.id("block/overlay/converter/converter_native_out"); - public static final ResourceLocation CONVERTER_FE_IN_EMISSIVE = GTCEu.id("block/overlay/converter/converter_native_in_emissive"); - public static final ResourceLocation CONVERTER_FE_OUT_EMISSIVE = GTCEu.id("block/overlay/converter/converter_native_out_emissive"); + public static final ResourceLocation CONVERTER_FE_IN_EMISSIVE = GTCEu + .id("block/overlay/converter/converter_native_in_emissive"); + public static final ResourceLocation CONVERTER_FE_OUT_EMISSIVE = GTCEu + .id("block/overlay/converter/converter_native_out_emissive"); public static MachineBuilder.ModelInitializer createConverterModel(int amperage) { return (ctx, prov, builder) -> { @@ -396,14 +398,14 @@ public static MachineBuilder.ModelInitializer createConverterModel(int amperage) tieredHullTextures(feToEuModel, builder.getOwner().getTier()); builder.partialState() - .with(IS_FE_TO_EU, false) - .setModel(euToFeModel) + .with(IS_FE_TO_EU, false) + .setModel(euToFeModel) .partialState() - .with(IS_FE_TO_EU, true) - .setModel(feToEuModel); + .with(IS_FE_TO_EU, true) + .setModel(feToEuModel) + .end(); }; } - // spotless:on public static MachineBuilder.ModelInitializer createCrateModel(boolean wooden) { return (ctx, prov, builder) -> { @@ -423,7 +425,7 @@ public static MachineBuilder.ModelInitializer createCrateModel(boolean wooden) { public static MachineBuilder.ModelInitializer createDiodeModel() { return (ctx, prov, builder) -> { - builder.forAllStatesModelsExcept(renderState -> { + builder.forAllStatesModels(renderState -> { DiodePartMachine.AmpMode mode = renderState.getValue(DIODE_AMP_MODE); final EnergyIOOverlay energyIn = IN_OVERLAYS_FOR_AMP.get(mode.getAmpValue()); final EnergyIOOverlay energyOut = OUT_OVERLAYS_FOR_AMP.get(mode.getAmpValue()); @@ -438,7 +440,7 @@ public static MachineBuilder.ModelInitializer createDiodeModel() { .texture("overlay_out_tinted", energyOut.getTintedPart()); tieredHullTextures(model, builder.getOwner().getTier()); return model; - }, IS_FORMED); + }); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -446,7 +448,7 @@ public static MachineBuilder.ModelInitializer createDiodeModel() { public static MachineBuilder.ModelInitializer createTransformerModel(int baseAmp) { return (ctx, prov, builder) -> { - builder.forAllStatesModelsExcept(renderState -> { + builder.forAllStatesModels(renderState -> { boolean transformUp = renderState.getValue(IS_TRANSFORM_UP); EnergyIOOverlay frontFace = (transformUp ? OUT_OVERLAYS_FOR_AMP : IN_OVERLAYS_FOR_AMP) .get(baseAmp); @@ -462,7 +464,7 @@ public static MachineBuilder.ModelInitializer createTransformerModel(int baseAmp .texture("overlay_out_tinted", otherFace.getTintedPart()); tieredHullTextures(model, builder.getOwner().getTier()); return model; - }, IS_FORMED); + }); }; } @@ -524,9 +526,23 @@ public static MachineBuilder.ModelInitializer createWorldAcceleratorModel(Resour WorkableOverlays rtOverlays = WorkableOverlays.get(rtModeModelPath, prov.getExistingFileHelper()); WorkableOverlays beOverlays = WorkableOverlays.get(beModeModelPath, prov.getExistingFileHelper()); - builder.forAllStatesModels(state -> { - WorkableOverlays overlays = state.getValue(IS_RANDOM_TICK_MODE) ? rtOverlays : beOverlays; - return createModelFromActiveWorkingState(prov, builder, overlays, state); + builder.forAllStates(state -> { + boolean rtMode = state.getValue(IS_RANDOM_TICK_MODE); + WorkableOverlays overlays = rtMode ? rtOverlays : beOverlays; + + boolean active = state.getValue(IS_ACTIVE); + boolean workingEnabled = state.getValue(IS_WORKING_ENABLED); + RecipeLogic.Status status = active ? + workingEnabled ? + RecipeLogic.Status.WORKING : + RecipeLogic.Status.SUSPEND : + RecipeLogic.Status.IDLE; + + BlockModelBuilder model = prov.models().nested() + .parent(prov.models().getExistingFile(SIDED_SIDED_OVERLAY_MODEL)); + tieredHullTextures(model, builder.getOwner().getTier()); + + return addWorkableOverlays(overlays, status, model); }); }; } @@ -536,7 +552,7 @@ public static MachineBuilder.ModelInitializer createWorldAcceleratorModel(Resour public static MachineBuilder.ModelInitializer createMaintenanceModel(ResourceLocation overlayModel) { return (ctx, prov, builder) -> { - builder.forAllStatesModelsExcept(state -> { + builder.forAllStatesModels(state -> { var baseModel = prov.models().nested() .parent(prov.models().getExistingFile(overlayModel)); tieredHullTextures(baseModel, builder.getOwner().getTier()); @@ -545,7 +561,7 @@ public static MachineBuilder.ModelInitializer createMaintenanceModel(ResourceLoc baseModel.texture("overlay_2", MAINTENANCE_TAPED_OVERLAY); } return baseModel; - }, IS_FORMED); + }); builder.addReplaceableTextures("bottom", "top", "side"); }; @@ -555,7 +571,6 @@ public static MachineBuilder.ModelInitializer createMaintenanceModel(ResourceLoc public static final ResourceLocation HPCA_PART_MODEL = GTCEu.id("block/machine/template/part/hpca_part_machine"); public static final ResourceLocation COMPUTER_CASING_TEXTURE = GTCEu.id("block/casings/hpca/computer_casing/"); public static final ResourceLocation ADVANCED_COMPUTER_CASING_TEXTURE = GTCEu.id("block/casings/hpca/advanced_computer_casing/"); - // spotless:on public static MachineBuilder.ModelInitializer createHPCAPartModel(boolean advanced, ResourceLocation normalTexture, @@ -571,14 +586,14 @@ public static MachineBuilder.ModelInitializer createHPCAPartModel(boolean advanc casingTexture(baseModel, "back", textures); casingTexture(baseModel, "side", textures); - builder.forAllStatesModelsExcept(state -> { + builder.forAllStatesModels(state -> { boolean damaged = state.getValue(IS_HPCA_PART_DAMAGED); boolean active = state.getValue(IS_ACTIVE); return prov.models().nested().parent(baseModel) .texture("overlay", overlay.getTexture(active, damaged)) .texture("overlay_emissive", overlay.getEmissiveTexture(active, damaged)); - }, IS_FORMED); + }); }; } @@ -594,7 +609,7 @@ public static MachineBuilder.ModelInitializer createFisherModel() { .texture("overlay_emissive", OVERLAY_QTANK_EMISSIVE_TEXTURE); tieredHullTextures(model, builder.getOwner().getTier()); - builder.partialState().setModel(model); + builder.forAllStatesModels(state -> model); }; } @@ -602,31 +617,28 @@ public static MachineBuilder.ModelInitializer createItemCollectorModel(ResourceL return (ctx, prov, builder) -> { WorkableOverlays overlays = WorkableOverlays.get(overlayDir, prov.getExistingFileHelper()); - builder.forAllStatesModels(state -> createModelFromActiveWorkingState(prov, builder, overlays, state)); - }; - } - - public static ModelFile createModelFromActiveWorkingState(@NotNull GTBlockstateProvider prov, - @NotNull MachineModelBuilder builder, - WorkableOverlays overlays, MachineRenderState state) { - RecipeLogic.Status status = state.getValue(IS_ACTIVE) ? - state.getValue(IS_WORKING_ENABLED) ? - RecipeLogic.Status.WORKING : - RecipeLogic.Status.SUSPEND : - RecipeLogic.Status.IDLE; + builder.forAllStates(state -> { + boolean active = state.getValue(IS_ACTIVE); + boolean workingEnabled = state.getValue(IS_WORKING_ENABLED); + RecipeLogic.Status status = active ? + workingEnabled ? + RecipeLogic.Status.WORKING : + RecipeLogic.Status.SUSPEND : + RecipeLogic.Status.IDLE; - BlockModelBuilder model = prov.models().nested() - .parent(prov.models().getExistingFile(SIDED_SIDED_OVERLAY_MODEL)); - tieredHullTextures(model, builder.getOwner().getTier()); + BlockModelBuilder model = prov.models().nested() + .parent(prov.models().getExistingFile(SIDED_SIDED_OVERLAY_MODEL)); + tieredHullTextures(model, builder.getOwner().getTier()); - return addWorkableOverlays(overlays, status, model); + return addWorkableOverlays(overlays, status, model); + }); + }; } // endregion // region helper functions - // spotless:off public static NonNullBiConsumer, GTBlockstateProvider> createMachineModel(MachineBuilder.ModelInitializer modelInitializer) { return (ctx, prov) -> { Block block = ctx.getEntry(); @@ -640,9 +652,8 @@ public static ModelFile createModelFromActiveWorkingState(@NotNull GTBlockstateP MachineModelBuilder builder = prov.models().getBuilder(modelLocation) .customLoader(MachineModelBuilder.begin(definition)); modelInitializer.configureModel(ctx, prov, builder); - final BlockModelBuilder model = builder.end(); - model.parent(new ModelFile.UncheckedModelFile("block/block")); + model.parent(prov.models().getExistingFile(prov.mcLoc("block/block"))); var generator = prov.multiVariantGenerator(block, Variant.variant().with(VariantProperties.MODEL, model.getLocation())); @@ -654,8 +665,8 @@ public static ModelFile createModelFromActiveWorkingState(@NotNull GTBlockstateP } // spotless:on - public static ModelFile addWorkableOverlays(WorkableOverlays overlays, RecipeLogic.Status status, - BlockModelBuilder model) { + public static ConfiguredModel[] addWorkableOverlays(WorkableOverlays overlays, RecipeLogic.Status status, + BlockModelBuilder model) { for (var entry : overlays.getTextures().entrySet()) { var face = entry.getKey(); var textures = entry.getValue(); @@ -670,7 +681,7 @@ public static ModelFile addWorkableOverlays(WorkableOverlays overlays, RecipeLog model.texture(OVERLAY_PREFIX + face.getName() + EMISSIVE_SUFFIX, overlayEmissive); } } - return model; + return ConfiguredModel.builder().modelFile(model).build(); } public static BlockModelBuilder colorOverlayHullModel(ResourceLocation overlay, diff --git a/src/main/java/com/gregtechceu/gtceu/data/model/builder/MachineModelBuilder.java b/src/main/java/com/gregtechceu/gtceu/data/model/builder/MachineModelBuilder.java index f532e194db5..27284c95f96 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/model/builder/MachineModelBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/data/model/builder/MachineModelBuilder.java @@ -302,12 +302,7 @@ public PartBuilder part(ResourceLocation model) { } public MachineModelBuilder forAllStatesModels(Function mapper) { - return forAllStatesModelsExcept(mapper); - } - - public MachineModelBuilder forAllStatesModelsExcept(Function mapper, - Property... ignored) { - return forAllStatesExcept(mapper.andThen(m -> ConfiguredModel.builder().modelFile(m).build()), ignored); + return forAllStates(mapper.andThen(m -> ConfiguredModel.builder().modelFile(m).build())); } public MachineModelBuilder forAllStates(Function mapper) { @@ -362,14 +357,15 @@ public static class PartialState> implements Predicate private final MachineDefinition owner; @Getter private final SortedMap, Comparable> setStates; + @Nullable private final MachineModelBuilder outerBuilder; - private PartialState(MachineDefinition owner, MachineModelBuilder outerBuilder) { + private PartialState(MachineDefinition owner, @Nullable MachineModelBuilder outerBuilder) { this(owner, ImmutableMap.of(), outerBuilder); } private PartialState(MachineDefinition owner, Map, Comparable> setStates, - MachineModelBuilder outerBuilder) { + @Nullable MachineModelBuilder outerBuilder) { this.owner = owner; this.outerBuilder = outerBuilder; for (Map.Entry, Comparable> entry : setStates.entrySet()) { @@ -692,7 +688,7 @@ public class ConditionGroup { .arrayListValues() .build(); public final List nestedConditionGroups = new ArrayList<>(); - private @Nullable ConditionGroup parent = null; + private ConditionGroup parent = null; public boolean useOr; /** From 98e3f09f6860b92880e56e055165a19c4b67197d Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Thu, 7 May 2026 13:57:56 +0300 Subject: [PATCH 55/66] Fix CTM not working when embeddium isn't installed because of a rounding error. --- .../gtceu/client/util/quad/CTMHelper.java | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java index e6d4c3aa0be..60d8c9c61ba 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java @@ -27,19 +27,6 @@ public class CTMHelper { - public static Vector2f[] findMinMaxUVs(Vector2f[] uvs) { - float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE, maxU = Float.MIN_VALUE, maxV = Float.MIN_VALUE; - - for (int i = 0; i < 4; i++) { - Vector2f uv = uvs[i]; - minU = Math.min(minU, uv.x()); - minV = Math.min(minV, uv.y()); - maxU = Math.max(maxU, uv.x()); - maxV = Math.max(maxV, uv.y()); - } - return new Vector2f[] { new Vector2f(minU, minV), new Vector2f(maxU, maxV) }; - } - public static List buildCTMQuads(BlockAndTintGetter level, BlockPos pos, BlockState state, List quads, Direction cullFace) { CTMCache ctmCache = CTMCache.getInstance(); @@ -92,23 +79,14 @@ public static List buildCTMQuads(CTMCache cachedConnections, List 0.5f ? 0.5f : 0.0f, - minVInterp = maxUV.y > 0.5f ? 0.5f : 0.0f; - float maxUInterp = maxUV.x > 0.5f ? 1.0f : 0.5f, - maxVInterp = maxUV.y > 0.5f ? 1.0f : 0.5f; - - normalize(minUInterp, minVInterp, maxUInterp, maxVInterp, uvs[0]); - normalize(minUInterp, minVInterp, maxUInterp, maxVInterp, uvs[1]); - normalize(minUInterp, minVInterp, maxUInterp, maxVInterp, uvs[2]); - normalize(minUInterp, minVInterp, maxUInterp, maxVInterp, uvs[3]); - } - // these are only used within the below methods, but are stored here as consts to reduce allocations // because they can be reused infinitely. DO NOT USE OUTSIDE subsect()/transformUVs()!! // filled in first copyUv() calls private static final ThreadLocal uvs = ThreadLocal.withInitial(() -> new Vector2f[4]); + private static final ThreadLocal uvExtremes = ThreadLocal.withInitial(() -> { + return new Vector2f[] { new Vector2f(), new Vector2f() }; + }); // set in copyPos() calls private static final ThreadLocal position = ThreadLocal.withInitial(Vector3f::new); private static final ThreadLocal xy = ThreadLocal.withInitial(() -> { @@ -145,16 +123,20 @@ private static void transformUVs(MutableQuadView quad, ISubmap submap) { // cache UVs Vector2f[] uvs = CTMHelper.uvs.get(); + + Vector2f maxUV = CTMHelper.uvExtremes.get()[0]; + maxUV.set(Float.MIN_VALUE, Float.MIN_VALUE); for (int i = 0; i < 4; i++) { uvs[i] = quad.copyUv(i, uvs[i]); + maxUV.max(uvs[i]); } // scale the quadrants' UVs to the full block range - Vector2f[] minMaxUVs = findMinMaxUVs(uvs); - growQuadrantUVs(uvs, minMaxUVs[1]); + normalizeQuadrantUVs(uvs, maxUV); // recompute min & max UVs - minMaxUVs = findMinMaxUVs(uvs); - Vector2f minUV = minMaxUVs[0], maxUV = minMaxUVs[1]; + Vector2f[] uvExtremes = getUVExtremes(uvs); + Vector2f minUV = uvExtremes[0]; + maxUV = uvExtremes[1]; float width = maxUV.x - minUV.x; float height = maxUV.y - minUV.y; @@ -167,10 +149,10 @@ private static void transformUVs(MutableQuadView quad, ISubmap submap) { float maxU = minU + (width * submap.getWidth()); float maxV = minV + (height * submap.getHeight()); - quad.uv(0, uvs[0].x == minUV.x ? minU : maxU, uvs[0].y == minUV.y ? minV : maxV); - quad.uv(1, uvs[1].x == minUV.x ? minU : maxU, uvs[1].y == minUV.y ? minV : maxV); - quad.uv(2, uvs[2].x == minUV.x ? minU : maxU, uvs[2].y == minUV.y ? minV : maxV); - quad.uv(3, uvs[3].x == minUV.x ? minU : maxU, uvs[3].y == minUV.y ? minV : maxV); + quad.uv(0, uvs[0].x <= minUV.x ? minU : maxU, uvs[0].y <= minUV.y ? minV : maxV); + quad.uv(1, uvs[1].x <= minUV.x ? minU : maxU, uvs[1].y <= minUV.y ? minV : maxV); + quad.uv(2, uvs[2].x <= minUV.x ? minU : maxU, uvs[2].y <= minUV.y ? minV : maxV); + quad.uv(3, uvs[3].x <= minUV.x ? minU : maxU, uvs[3].y <= minUV.y ? minV : maxV); } // TODO simplify, this is quite long @@ -254,10 +236,29 @@ public static MutableQuadView subsect(final MutableQuadView quad, ISubmap submap return quad; } - /// scale {@code value} to a 0-1 range component-wise based on {@code min} and {@code max} - private static Vector2f normalize(float minU, float minV, float maxU, float maxV, Vector2f value) { - value.set(normalize(value.x, minU, maxU), normalize(value.y, minV, maxV)); - return value; + public static Vector2f[] getUVExtremes(Vector2f[] uvs) { + Vector2f[] uvExtremes = CTMHelper.uvExtremes.get(); + uvExtremes[0].set(Float.MAX_VALUE, Float.MAX_VALUE); + uvExtremes[1].set(Float.MIN_VALUE, Float.MIN_VALUE); + + for (int i = 0; i < 4; i++) { + Vector2f vertexUV = uvs[i]; + uvExtremes[0].min(vertexUV); + uvExtremes[1].max(vertexUV); + } + return uvExtremes; + } + + private static void normalizeQuadrantUVs(Vector2f[] uvs, Vector2f maxUV) { + float minU = maxUV.x() - 0.5f > Mth.EPSILON ? 0.5f : 0.0f, + minV = maxUV.y() - 0.5f > Mth.EPSILON ? 0.5f : 0.0f; + float maxU = maxUV.x() - 0.5f > Mth.EPSILON ? 1.0f : 0.5f, + maxV = maxUV.y() - 0.5f > Mth.EPSILON ? 1.0f : 0.5f; + + for (int i = 0; i < 4; i++) { + // scale u,v to a 0-1 range + uvs[i].set(normalize(uvs[i].x, minU, maxU), normalize(uvs[i].y, minV, maxV)); + } } /// scale {@code delta} to a 0-1 range based on {@code min} and {@code max} From 5141557bae8500238442d3b0e61e11e1fd1ad29e Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Thu, 7 May 2026 13:59:05 +0300 Subject: [PATCH 56/66] Remove quad caching; it didn't really do much and has the possibility of breaking things --- .../gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java index 7c2af228f87..e0250f6e71c 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java @@ -16,14 +16,11 @@ import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; import static com.gregtechceu.gtceu.client.model.GTModelProperties.*; public class CTMBakedModel extends BakedModelWrapper { - private final Map>> sideCache = new EnumMap<>(Direction.class); - public CTMBakedModel(T parent) { super(parent); } @@ -48,9 +45,7 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction CTMCache ctmCache = CTMCache.getInstance(); ctmCache.fillSubmapCache(level, pos, state, side); - return this.sideCache.computeIfAbsent(side, $ -> new ConcurrentHashMap<>()) - .computeIfAbsent(ctmCache, cache -> CTMHelper.buildCTMQuads(cache, - super.getQuads(state, side, rand, parentModelData, renderType), side)); + return CTMHelper.buildCTMQuads(ctmCache, super.getQuads(state, side, rand, parentModelData, renderType), side); } @Override From bf63e04e15cfa1f3fffdfad98aa8afb4c0cc1d38 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Thu, 7 May 2026 14:01:09 +0300 Subject: [PATCH 57/66] Add debake method to MutableQuadView --- .../client/model/quad/MutableQuadView.java | 16 ++++++++++++ .../gtceu/client/util/TextureHelper.java | 18 +++++++++++++ .../gtceu/client/util/quad/CTMHelper.java | 26 +------------------ 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java index ff414ce72a4..828720357f5 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java @@ -81,6 +81,12 @@ public abstract class MutableQuadView extends QuadView { */ public static final int BAKE_LOCK_UV = 0b000100; + /** + * When enabled, texture coordinates are cycled so that vertex 0's UVs are the smallest. + * Pass in bakeFlags parameter to {@link TextureHelper#unbakeSprite(MutableQuadView, TextureAtlasSprite, int)}. + */ + public static final int BAKE_DEROTATE_UV = 0b000100; + /** * When set, U texture coordinates for the given sprite are flipped as part of baking. Can be useful for some * randomization and texture mapping scenarios. Results are different from what can be obtained via rotation and @@ -238,6 +244,16 @@ public MutableQuadView spriteBake(@Nullable TextureAtlasSprite sprite, int bakeF return this; } + /** + * Normalizes this quad's u,v coordinates based on the given sprite. + * Can handle UV rotation, interpolation, etc. + * Control this behavior by passing additive combinations of the BAKE_ flags defined in this interface. + */ + public MutableQuadView spriteUnbake(@Nullable TextureAtlasSprite sprite, int bakeFlags) { + TextureHelper.unbakeSprite(this, sprite, bakeFlags); + return this; + } + /** * Accept vanilla lightmap values. * Input values will override lightmap values computed from world state if input values are higher. diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java index faf745ffae9..facecba1cfb 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java @@ -144,6 +144,10 @@ public static void unbakeSprite(MutableQuadView quad, @Nullable TextureAtlasSpri // Scales from 0-1 to 0-16 applyModifier(quad, (q, i) -> q.uv(i, q.u(i) * DENORMALIZER, q.v(i) * DENORMALIZER)); } + if ((BAKE_DEROTATE_UV & bakeFlags) != 0) { + // Cycles texture coordinates so that vertex 0's UVs are the smallest + derotateUV(quad); + } } /** @@ -161,6 +165,20 @@ public static void deInterpolate(MutableQuadView q, TextureAtlasSprite sprite) { } } + private static void derotateUV(MutableQuadView quad) { + int minIndex = 0; + float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE; + + for (int i = 0; i < 4; i++) { + if (quad.u(i) <= minU && quad.v(i) <= minV) { + minIndex = i; + minU = quad.u(i); + minV = quad.v(i); + } + } + applyModifier(quad, ROTATIONS[minIndex]); + } + @FunctionalInterface public interface VertexModifier { diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java index 60d8c9c61ba..76d2cb483b0 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java @@ -5,7 +5,6 @@ import com.gregtechceu.gtceu.client.model.ctm.Submap; import com.gregtechceu.gtceu.client.model.quad.MeshBuilder; import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; -import com.gregtechceu.gtceu.client.util.TextureHelper; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -59,10 +58,9 @@ public static List buildCTMQuads(CTMCache cachedConnections, List buildCTMQuads(CTMCache cachedConnections, List Date: Thu, 7 May 2026 14:02:20 +0300 Subject: [PATCH 58/66] more checks; clearer names --- .../gtceu/client/model/ctm/CTMCache.java | 4 ---- .../gtceu/client/util/quad/CTMHelper.java | 16 +++++++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java index 72b71e536b7..7da2d4a602f 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMCache.java @@ -154,10 +154,6 @@ public Vector2ic[][] getCachedSubmapIndices() { return this.submapCache; } - public static boolean isDefaultTexture(int id) { - return (id == 16 || id == 17 || id == 18 || id == 19); - } - public static boolean isDefaultTexture(Vector2ic id) { return id.x() >= 4 && id.y() >= 4; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java index 76d2cb483b0..884bd4c164d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java @@ -50,19 +50,19 @@ public static List buildCTMQuads(CTMCache cachedConnections, List buildCTMQuads(CTMCache cachedConnections, List Date: Thu, 7 May 2026 14:02:58 +0300 Subject: [PATCH 59/66] client.util.quad.CTMHelper -> client.model.ctm.CTMMeshBuilder --- .../gtceu/client/model/ctm/CTMBakedModel.java | 4 +--- .../ctm/CTMMeshBuilder.java} | 19 ++++++++----------- .../client/model/machine/MachineModel.java | 4 ++-- 3 files changed, 11 insertions(+), 16 deletions(-) rename src/main/java/com/gregtechceu/gtceu/client/{util/quad/CTMHelper.java => model/ctm/CTMMeshBuilder.java} (95%) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java index e0250f6e71c..5646ecffabb 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java @@ -1,7 +1,5 @@ package com.gregtechceu.gtceu.client.model.ctm; -import com.gregtechceu.gtceu.client.util.quad.CTMHelper; - import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.resources.model.BakedModel; @@ -45,7 +43,7 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction CTMCache ctmCache = CTMCache.getInstance(); ctmCache.fillSubmapCache(level, pos, state, side); - return CTMHelper.buildCTMQuads(ctmCache, super.getQuads(state, side, rand, parentModelData, renderType), side); + return CTMMeshBuilder.buildCTMQuads(ctmCache, super.getQuads(state, side, rand, parentModelData, renderType), side); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java similarity index 95% rename from src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java rename to src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java index 884bd4c164d..00422b495d5 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/quad/CTMHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java @@ -1,8 +1,5 @@ -package com.gregtechceu.gtceu.client.util.quad; +package com.gregtechceu.gtceu.client.model.ctm; -import com.gregtechceu.gtceu.client.model.ctm.CTMCache; -import com.gregtechceu.gtceu.client.model.ctm.ISubmap; -import com.gregtechceu.gtceu.client.model.ctm.Submap; import com.gregtechceu.gtceu.client.model.quad.MeshBuilder; import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; @@ -24,7 +21,7 @@ import static com.gregtechceu.gtceu.client.model.quad.MutableQuadView.*; import static com.gregtechceu.gtceu.client.util.ModelEventHelper.*; -public class CTMHelper { +public class CTMMeshBuilder { public static List buildCTMQuads(BlockAndTintGetter level, BlockPos pos, BlockState state, List quads, Direction cullFace) { @@ -98,9 +95,9 @@ private static void normalizeQuadrantUVs(MutableQuadView quad, ISubmap submap) { submap = submap.unitScale(); // cache UVs - Vector2f[] uvs = CTMHelper.uvs.get(); + Vector2f[] uvs = CTMMeshBuilder.uvs.get(); - Vector2f maxUV = CTMHelper.uvExtremes.get()[0]; + Vector2f maxUV = CTMMeshBuilder.uvExtremes.get()[0]; maxUV.set(Float.MIN_VALUE, Float.MIN_VALUE); for (int i = 0; i < 4; i++) { uvs[i] = quad.copyUv(i, uvs[i]); @@ -137,9 +134,9 @@ public static MutableQuadView subsect(final MutableQuadView quad, ISubmap submap // nominalFace should never be null here; MutableQuadView.fromVanilla updates it assert normal != null; - Vector2f[] xy = CTMHelper.xy.get(); - Vector2f[] newXy = CTMHelper.newXy.get(); - Vector3f position = CTMHelper.position.get(); + Vector2f[] xy = CTMMeshBuilder.xy.get(); + Vector2f[] newXy = CTMMeshBuilder.newXy.get(); + Vector3f position = CTMMeshBuilder.position.get(); for (int i = 0; i < 4; i++) { // updates position quad.copyPos(i, position); @@ -215,7 +212,7 @@ public static MutableQuadView subsect(final MutableQuadView quad, ISubmap submap } public static Vector2f[] getUVExtremes(Vector2f[] uvs) { - Vector2f[] uvExtremes = CTMHelper.uvExtremes.get(); + Vector2f[] uvExtremes = CTMMeshBuilder.uvExtremes.get(); uvExtremes[0].set(Float.MAX_VALUE, Float.MAX_VALUE); uvExtremes[1].set(Float.MIN_VALUE, Float.MIN_VALUE); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java index c69f80e0e4d..278a4b77a1c 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java @@ -15,7 +15,7 @@ import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; import com.gregtechceu.gtceu.client.util.RenderUtil; -import com.gregtechceu.gtceu.client.util.quad.CTMHelper; +import com.gregtechceu.gtceu.client.model.ctm.CTMMeshBuilder; import com.gregtechceu.gtceu.common.data.models.GTModels; import com.gregtechceu.gtceu.common.machine.trait.AutoOutputTrait; import com.gregtechceu.gtceu.utils.GTUtil; @@ -320,7 +320,7 @@ public List renderMachine(@Nullable MetaMachine machine, @Nullable Bl // we have to recalculate CTM ourselves. // this is the slowest part by a long shot because the LDLib quad logic isn't very optimized. if (level != null && pos != null && blockState != null && side != null) { - return CTMHelper.buildCTMQuads(level, pos, blockState, quads, side); + return CTMMeshBuilder.buildCTMQuads(level, pos, blockState, quads, side); } return quads; } From 65943aebf2b8c87d61abc66e0729957b6086ff2c Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Thu, 7 May 2026 17:31:33 +0300 Subject: [PATCH 60/66] Rename CTMCache -> TextureConnections --- .../gtceu/client/model/ctm/CTMBakedModel.java | 6 +++--- .../gtceu/client/model/ctm/CTMMeshBuilder.java | 16 +++++++--------- .../gtceu/client/model/ctm/ConnectionCheck.java | 2 +- .../{CTMCache.java => TextureConnections.java} | 13 +++++++------ 4 files changed, 18 insertions(+), 19 deletions(-) rename src/main/java/com/gregtechceu/gtceu/client/model/ctm/{CTMCache.java => TextureConnections.java} (96%) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java index 5646ecffabb..57cb8fb77b4 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java @@ -41,9 +41,9 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction return super.getQuads(state, side, rand, parentModelData, renderType); } - CTMCache ctmCache = CTMCache.getInstance(); - ctmCache.fillSubmapCache(level, pos, state, side); - return CTMMeshBuilder.buildCTMQuads(ctmCache, super.getQuads(state, side, rand, parentModelData, renderType), side); + TextureConnections connections = TextureConnections.getInstance(); + connections.fillSubmapCache(level, pos, state, side); + return CTMMeshBuilder.buildCTMQuads(connections, super.getQuads(state, side, rand, parentModelData, renderType), side); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java index 00422b495d5..2172ce558f3 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java @@ -25,15 +25,13 @@ public class CTMMeshBuilder { public static List buildCTMQuads(BlockAndTintGetter level, BlockPos pos, BlockState state, List quads, Direction cullFace) { - CTMCache ctmCache = CTMCache.getInstance(); - if (cullFace != null) { - ctmCache.fillSubmapCache(level, pos, state, cullFace); - } + TextureConnections connections = TextureConnections.getInstance(); + connections.fillSubmapCache(level, pos, state, cullFace); - return buildCTMQuads(ctmCache, quads, cullFace); + return buildCTMQuads(connections, quads, cullFace); } - public static List buildCTMQuads(CTMCache cachedConnections, List base, Direction cullFace) { + public static List buildCTMQuads(TextureConnections connections, List base, Direction cullFace) { List result = new LinkedList<>(); MeshBuilder meshBuilder = MeshBuilder.getInstance(); var emitter = meshBuilder.getEmitter(); @@ -47,11 +45,11 @@ public static List buildCTMQuads(CTMCache cachedConnections, List buildCTMQuads(CTMCache cachedConnections, List Date: Thu, 7 May 2026 17:32:52 +0300 Subject: [PATCH 61/66] More util methods --- .../gtceu/client/model/ctm/CTMMeshBuilder.java | 6 ++---- .../gtceu/client/model/ctm/TextureConnections.java | 12 ++++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java index 2172ce558f3..22fca72f6a7 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java @@ -45,11 +45,9 @@ public static List buildCTMQuads(TextureConnections connections, List continue; } - Vector2ic[][] submapIndices = connections.getCachedSubmapIndices(); - for (int xQuadrant = 0; xQuadrant < 2; xQuadrant++) { for (int yQuadrant = 0; yQuadrant < 2; yQuadrant++) { - boolean defaultTexture = TextureConnections.isDefaultTexture(submapIndices[xQuadrant][yQuadrant]); + boolean defaultTexture = connections.isDefaultTexture(xQuadrant, yQuadrant); TextureAtlasSprite ctmSprite = defaultTexture ? originalSprite : connectionSprite; emitter.fromVanilla(originalQuad, cullFace); @@ -57,7 +55,7 @@ public static List buildCTMQuads(TextureConnections connections, List // slice quad into the current quadrant subsect(emitter, Submap.X2[xQuadrant][yQuadrant]); - normalizeQuadrantUVs(emitter, TextureConnections.getSubmapFor(submapIndices[xQuadrant][yQuadrant])); + normalizeQuadrantUVs(emitter, connections.getSubmapFor(xQuadrant, yQuadrant)); emitter.spriteBake(ctmSprite, BAKE_NORMALIZED); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/TextureConnections.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/TextureConnections.java index 6252ca06870..64c2e2a0912 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/TextureConnections.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/TextureConnections.java @@ -155,10 +155,22 @@ public Vector2ic[][] getCachedSubmapIndices() { return this.submapCache; } + public Vector2ic getSubmapCoordinatesFor(int quadrantX, int quadrantY) { + return this.submapCache[quadrantX][quadrantY]; + } + + public boolean isDefaultTexture(int quadrantX, int quadrantY) { + return isDefaultTexture(getSubmapCoordinatesFor(quadrantX, quadrantY)); + } + public static boolean isDefaultTexture(Vector2ic id) { return id.x() >= 4 && id.y() >= 4; } + public ISubmap getSubmapFor(int quadrantX, int quadrantY) { + return getSubmapFor(getSubmapCoordinatesFor(quadrantX, quadrantY)); + } + public static ISubmap getSubmapFor(Vector2ic coordinates) { if (isDefaultTexture(coordinates)) { return Submap.X2[coordinates.x() % 4][coordinates.y() % 4]; From a11439a35765cc173c401f58a51c03d858a2cf3b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Thu, 7 May 2026 17:37:45 +0300 Subject: [PATCH 62/66] make ConnectionCheck a static utility class; we don't allow using custom state comparators so having instances of it around did nothing except waste RAM. --- .../client/model/ctm/ConnectionCheck.java | 54 ++++--------------- .../model/ctm/OctagonalOrientation.java | 11 ++-- .../client/model/ctm/TextureConnections.java | 14 +---- 3 files changed, 14 insertions(+), 65 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java index 276814c9001..7a13f8e8f22 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java @@ -17,44 +17,22 @@ */ package com.gregtechceu.gtceu.client.model.ctm; -import com.gregtechceu.gtceu.client.model.ctm.TextureConnections.StateComparisonCallback; - import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; -import com.mojang.serialization.Codec; -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.Accessors; +import lombok.experimental.UtilityClass; import org.jetbrains.annotations.Nullable; /** * Sourced from ConnectedTexturesMod. + * "https://github.com/Chisel-Team/ConnectedTexturesMod/blob/19a58b080ff2d4fec4fd44ffdb426fc078ce853d/src/main/java/team/chisel/ctm/client/newctm/ConnectionCheck.java">ConnectedTexturesMod + * with considerable simplification. */ -@NoArgsConstructor -@AllArgsConstructor -@Accessors(fluent = true, chain = true) +@UtilityClass public class ConnectionCheck { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( - Codec.BOOL.optionalFieldOf("ignore_states", false).forGetter(ConnectionCheck::ignoreStates)) - .apply(instance, ignoredStates -> new ConnectionCheck().ignoreStates(ignoredStates))); - - @Getter - @Setter - protected boolean ignoreStates; - - @Getter - @Setter - protected StateComparisonCallback stateComparator = StateComparisonCallback.DEFAULT; - /** * A simple check for if the given block can connect to the given direction on the given side. * @@ -66,7 +44,7 @@ public class ConnectionCheck { * This is not the direction to check in. * @return True if the given block can connect to the given location on the given side. */ - public final boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, + public static boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, BlockPos connection, Direction dir) { BlockState state = getConnectionState(level, current, currentState, dir, connection, level.getBlockState(connection)); @@ -84,8 +62,7 @@ public final boolean isConnected(BlockAndTintGetter level, BlockPos current, Blo * @param state The state to check against for connection. * @return True if the given block can connect to the given location on the given side. */ - @SuppressWarnings({ "unused", "null" }) - public boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, BlockPos connection, + public static boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, BlockPos connection, Direction dir, BlockState state) { BlockState connectionState = getConnectionState(level, connection, level.getBlockState(connection), dir, current, currentState); @@ -93,24 +70,11 @@ public boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockStat BlockState obscuring = getConnectionState(level, obscuringPos, level.getBlockState(obscuringPos), dir, current, currentState); - boolean ret = stateComparator(state, connectionState, dir); - - // check that we aren't already connected outwards from this side - ret &= !stateComparator(state, obscuring, dir); - - return ret; - } - - public boolean stateComparator(BlockState from, BlockState to, Direction dir) { - return stateComparator.connects(this, from, to, dir); - } - - public BlockState getConnectionState(BlockAndTintGetter level, BlockPos pos, @Nullable Direction side, - BlockPos connection, BlockState connectionState) { - return getConnectionState(level, pos, level.getBlockState(pos), side, connection, connectionState); + // check that we are connected AND aren't already connected outwards from this side + return state == connectionState && state != obscuring; } - public BlockState getConnectionState(BlockAndTintGetter level, BlockPos pos, BlockState state, + public static BlockState getConnectionState(BlockAndTintGetter level, BlockPos pos, BlockState state, @Nullable Direction side, BlockPos connection, BlockState connectionState) { if (side != null) { return state.getAppearance(level, pos, side, connectionState, connection); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java index eae8c487e6f..ca8c0b4d925 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java @@ -115,22 +115,19 @@ private void buildCaches() { /** * Finds if this block is connected for the given side in this OctagonalOrientation. * - * @param ctm The ConnectionCheck instance to use for logic. * @param level The level the block is in. * @param pos The position of your block. * @param state The state of your block. * @param side The side of the current face. * @return True if the block is connected in the given OctagonalOrientation, false otherwise. */ - public boolean isConnected(ConnectionCheck ctm, BlockAndTintGetter level, BlockPos pos, BlockState state, - Direction side) { - return ctm.isConnected(level, pos, state, applyConnection(pos, side), side); + public boolean isConnected(BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side) { + return ConnectionCheck.isConnected(level, pos, state, applyConnection(pos, side), side); } /** * Finds if this block is connected for the given side in this OctagonalOrientation. * - * @param ctm The ConnectionCheck instance to use for logic. * @param level The level the block is in. * @param pos The position of your block. * @param state The state of your block. @@ -138,9 +135,9 @@ public boolean isConnected(ConnectionCheck ctm, BlockAndTintGetter level, BlockP * @param connectionState The state to check for connection with. * @return True if the block is connected in the given OctagonalOrientation, false otherwise. */ - public boolean isConnected(ConnectionCheck ctm, BlockAndTintGetter level, BlockPos pos, BlockState state, + public boolean isConnected(BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side, BlockState connectionState) { - return ctm.isConnected(level, pos, state, applyConnection(pos, side), side, connectionState); + return ConnectionCheck.isConnected(level, pos, state, applyConnection(pos, side), side, connectionState); } /** diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/TextureConnections.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/TextureConnections.java index 64c2e2a0912..1e717a3bb3c 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/TextureConnections.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/TextureConnections.java @@ -88,16 +88,6 @@ @Accessors(fluent = true, chain = true) public class TextureConnections { - @FunctionalInterface - public interface StateComparisonCallback { - - StateComparisonCallback DEFAULT = (connectionCheck, from, to, dir) -> { - return connectionCheck.ignoreStates() ? from.getBlock() == to.getBlock() : from == to; - }; - - boolean connects(ConnectionCheck instance, BlockState from, BlockState to, Direction dir); - } - /** Hardcoded offset values for the different submap indices */ // store the full table(s) to reduce non-required allocations protected static final Vector2ic[][] submapOffsets = { @@ -111,8 +101,6 @@ public interface StateComparisonCallback { { new Vector2i(5, 4), new Vector2i(5, 5), }, }; - public ConnectionCheck connectionCheck = new ConnectionCheck(); - // spotless:off // Mapping the different corner indices to their respective dirs protected static final OctagonalOrientation[][][] submapMap = { @@ -203,7 +191,7 @@ public void buildConnectionMap(BlockAndTintGetter world, BlockPos pos, BlockStat // Note: We can't cache the state that we are checking about connection for as we want to ensure that // we can take into account the side of the block we want to know the "state" of as if the block is // a facade of some sort it might return different results based on where it is being queried from - setConnectedState(dir, dir.isConnected(this.connectionCheck, world, pos, state, side)); + setConnectedState(dir, dir.isConnected(world, pos, state, side)); } } From 79bf7e228845c367b6534427fd8dcea0a0bfc3ba Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Thu, 7 May 2026 17:38:03 +0300 Subject: [PATCH 63/66] Remove extra `@Nullable` IntelliJ didn't like --- src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java b/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java index d0cf73b0cd1..b1722d9620b 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java @@ -20,8 +20,8 @@ public class ArrayHelpers { * @return a copy of the specified array object, deeply copying multidimensional arrays, or null if the object is * null */ - @Contract(value = "!null -> !null; null -> null", pure = true) - public static @Nullable T @Nullable [] deepCopy(@Nullable T @Nullable [] array) { + @Contract(value = "!null -> !null; _ -> null", pure = true) + public static T @Nullable [] deepCopy(T @Nullable [] array) { if (array == null) { return null; } From 4d16858dd865f54c7eb0396aec9dad7fe89d6d60 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Thu, 7 May 2026 18:10:10 +0300 Subject: [PATCH 64/66] rename functions --- .../gtceu/client/model/ctm/CTMMeshBuilder.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java index 22fca72f6a7..53e3d11b8c7 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java @@ -12,7 +12,6 @@ import net.minecraft.world.level.block.state.BlockState; import org.joml.Vector2f; -import org.joml.Vector2ic; import org.joml.Vector3f; import java.util.LinkedList; @@ -55,7 +54,7 @@ public static List buildCTMQuads(TextureConnections connections, List // slice quad into the current quadrant subsect(emitter, Submap.X2[xQuadrant][yQuadrant]); - normalizeQuadrantUVs(emitter, connections.getSubmapFor(xQuadrant, yQuadrant)); + remapUVs(emitter, connections.getSubmapFor(xQuadrant, yQuadrant)); emitter.spriteBake(ctmSprite, BAKE_NORMALIZED); @@ -87,20 +86,20 @@ public static List buildCTMQuads(TextureConnections connections, List return new Vector2f[] { new Vector2f(), new Vector2f(), new Vector2f(), new Vector2f() }; }); - private static void normalizeQuadrantUVs(MutableQuadView quad, ISubmap submap) { + private static void remapUVs(MutableQuadView quad, ISubmap submap) { submap = submap.unitScale(); - // cache UVs - Vector2f[] uvs = CTMMeshBuilder.uvs.get(); - Vector2f maxUV = CTMMeshBuilder.uvExtremes.get()[0]; maxUV.set(Float.MIN_VALUE, Float.MIN_VALUE); + + // cache UVs + Vector2f[] uvs = CTMMeshBuilder.uvs.get(); for (int i = 0; i < 4; i++) { uvs[i] = quad.copyUv(i, uvs[i]); maxUV.max(uvs[i]); } - // scale the quadrants' UVs to the full block range - normalizeQuadrantUVs(uvs, maxUV); + // scale the quadrants' UVs to the quadrant's area + scaleUVCoordinatesToQuadrant(uvs, maxUV); // recompute min & max UVs Vector2f[] uvExtremes = getUVExtremes(uvs); @@ -220,7 +219,7 @@ public static Vector2f[] getUVExtremes(Vector2f[] uvs) { return uvExtremes; } - private static void normalizeQuadrantUVs(Vector2f[] uvs, Vector2f maxUV) { + private static void scaleUVCoordinatesToQuadrant(Vector2f[] uvs, Vector2f maxUV) { float minU = maxUV.x() - 0.5f > Mth.EPSILON ? 0.5f : 0.0f, minV = maxUV.y() - 0.5f > Mth.EPSILON ? 0.5f : 0.0f; float maxU = maxUV.x() - 0.5f > Mth.EPSILON ? 1.0f : 0.5f, From dbbfa56bae7e0bd7b8483dd45c9b0880625cdd75 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Thu, 7 May 2026 18:10:59 +0300 Subject: [PATCH 65/66] Spotless --- .../gtceu/client/model/ctm/CTMBakedModel.java | 3 ++- .../gtceu/client/model/ctm/CTMMeshBuilder.java | 3 ++- .../gtceu/client/model/ctm/ConnectionCheck.java | 10 ++++++---- .../gtceu/client/model/machine/MachineModel.java | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java index 57cb8fb77b4..9cf0d70302a 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java @@ -43,7 +43,8 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction TextureConnections connections = TextureConnections.getInstance(); connections.fillSubmapCache(level, pos, state, side); - return CTMMeshBuilder.buildCTMQuads(connections, super.getQuads(state, side, rand, parentModelData, renderType), side); + return CTMMeshBuilder.buildCTMQuads(connections, super.getQuads(state, side, rand, parentModelData, renderType), + side); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java index 53e3d11b8c7..cf0f19c3656 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java @@ -30,7 +30,8 @@ public static List buildCTMQuads(BlockAndTintGetter level, BlockPos p return buildCTMQuads(connections, quads, cullFace); } - public static List buildCTMQuads(TextureConnections connections, List base, Direction cullFace) { + public static List buildCTMQuads(TextureConnections connections, List base, + Direction cullFace) { List result = new LinkedList<>(); MeshBuilder meshBuilder = MeshBuilder.getInstance(); var emitter = meshBuilder.getEmitter(); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java index 7a13f8e8f22..33724843038 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java @@ -45,7 +45,7 @@ public class ConnectionCheck { * @return True if the given block can connect to the given location on the given side. */ public static boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, - BlockPos connection, Direction dir) { + BlockPos connection, Direction dir) { BlockState state = getConnectionState(level, current, currentState, dir, connection, level.getBlockState(connection)); return isConnected(level, current, currentState, connection, dir, state); @@ -62,8 +62,9 @@ public static boolean isConnected(BlockAndTintGetter level, BlockPos current, Bl * @param state The state to check against for connection. * @return True if the given block can connect to the given location on the given side. */ - public static boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, BlockPos connection, - Direction dir, BlockState state) { + public static boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, + BlockPos connection, + Direction dir, BlockState state) { BlockState connectionState = getConnectionState(level, connection, level.getBlockState(connection), dir, current, currentState); BlockPos obscuringPos = connection.relative(dir); @@ -75,7 +76,8 @@ public static boolean isConnected(BlockAndTintGetter level, BlockPos current, Bl } public static BlockState getConnectionState(BlockAndTintGetter level, BlockPos pos, BlockState state, - @Nullable Direction side, BlockPos connection, BlockState connectionState) { + @Nullable Direction side, BlockPos connection, + BlockState connectionState) { if (side != null) { return state.getAppearance(level, pos, side, connectionState, connection); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java index 278a4b77a1c..e580ab23c2d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java @@ -10,12 +10,12 @@ import com.gregtechceu.gtceu.client.model.GTModelProperties; import com.gregtechceu.gtceu.client.model.IBlockEntityRendererBakedModel; import com.gregtechceu.gtceu.client.model.TextureOverrideModel; +import com.gregtechceu.gtceu.client.model.ctm.CTMMeshBuilder; import com.gregtechceu.gtceu.client.model.machine.multipart.MultiPartBakedModel; import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; import com.gregtechceu.gtceu.client.util.RenderUtil; -import com.gregtechceu.gtceu.client.model.ctm.CTMMeshBuilder; import com.gregtechceu.gtceu.common.data.models.GTModels; import com.gregtechceu.gtceu.common.machine.trait.AutoOutputTrait; import com.gregtechceu.gtceu.utils.GTUtil; From e71eafdca593c0f74365799027c65676be18f89b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Thu, 7 May 2026 18:21:14 +0300 Subject: [PATCH 66/66] Fix light gray lamps' connections --- .../gtceu/textures/block/lamps/light_gray_bloom.png.mcmeta | 2 +- .../assets/gtceu/textures/block/lamps/light_gray_on.png.mcmeta | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom.png.mcmeta index 756b9920894..52d15b67196 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom.png.mcmeta @@ -1,6 +1,6 @@ { "gtceu": { - "connection_texture": "gtceu:block/lamps/light_gray_ctm_emissive", + "connection_texture": "gtceu:block/lamps/light_gray_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on.png.mcmeta index 6bb38120805..f8cdf3acb09 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on.png.mcmeta @@ -1,6 +1,6 @@ { "gtceu": { - "connection_texture": "gtceu:block/lamps/light_gray_ctm", + "connection_texture": "gtceu:block/lamps/light_gray_on_ctm", "bloom": false } } \ No newline at end of file