Revisions for ⁨Baked model issue⁩

View the changes made to this paste.

unlisted ⁨3⁩ ⁨files⁩ 2022-07-29 09:27:56 UTC

ClientTools

@@ -0,0 +1,68 @@

+package net.nicgamer.automatek.varia;
+
+import com.mojang.blaze3d.vertex.VertexFormatElement;
+import com.mojang.math.Transformation;
+import com.mojang.math.Vector3f;
+import com.mojang.math.Vector4f;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.core.Direction;
+import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
+
+public class ClientTools {
+
+    private static void putVertex(BakedQuadBuilder builder, Vector3f normal, Vector4f vector, float u, float v, TextureAtlasSprite sprite) {
+
+        var elements = builder.getVertexFormat().getElements().asList();
+        for (int j = 0; j < elements.size(); j++) {
+            var e = elements.get(j);
+            switch (e.getUsage()) {
+                case POSITION -> builder.put(j, vector.x(), vector.y(), vector.z(), 1.0f);
+                case COLOR -> builder.put(j, 1.0f, 1.0f, 1.0f, 1.0f);
+                case UV -> putVertexUV(builder, u, v, sprite, j, e);
+                case NORMAL -> builder.put(j, normal.x(), normal.y(), normal.z());
+                default -> builder.put(j);
+            }
+        }
+    }
+
+    private static void putVertexUV(BakedQuadBuilder builder, float u, float v, TextureAtlasSprite sprite, int j, VertexFormatElement e) {
+        switch (e.getIndex()) {
+            case 0 -> builder.put(j, sprite.getU(u), sprite.getV(v));
+            case 2 -> builder.put(j, (short) 0, (short) 0);
+                default -> builder.put(j);
+        }
+    }
+
+    public static Vector3f v(float x, float y, float z) {
+        return new Vector3f(x, y, z);
+    }
+
+    public static BakedQuad createQuad(Vector3f v1, Vector3f v2, Vector3f v3, Vector3f v4, Transformation rotation, TextureAtlasSprite sprite) {
+        Vector3f normal = v3.copy();
+        normal.sub(v2);
+        Vector3f temp = v1.copy();
+        temp.sub(v2);
+        normal.cross(temp);
+        normal.normalize();
+
+        int tw = sprite.getWidth();
+        int th = sprite.getHeight();
+
+        rotation = rotation.blockCenterToCorner();
+        rotation.transformNormal(normal);
+
+        Vector4f vv1 = new Vector4f(v1); rotation.transformPosition(vv1);
+        Vector4f vv2 = new Vector4f(v2); rotation.transformPosition(vv2);
+        Vector4f vv3 = new Vector4f(v3); rotation.transformPosition(vv3);
+        Vector4f vv4 = new Vector4f(v4); rotation.transformPosition(vv4);
+
+        var builder = new BakedQuadBuilder(sprite);
+        builder.setQuadOrientation(Direction.getNearest(normal.x(), normal.y(), normal.z()));
+        putVertex(builder, normal, vv1, 0, 0, sprite);
+        putVertex(builder, normal, vv2, 0, th, sprite);
+        putVertex(builder, normal, vv3, tw, th, sprite);
+        putVertex(builder, normal, vv4, tw, 0, sprite);
+        return builder.build();
+    }
+}

ConnectingBlockBakedModel

@@ -0,0 +1,279 @@

+package net.nicgamer.automatek.utilities;
+
+import com.mojang.math.Transformation;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.renderer.block.model.ItemOverrides;
+import net.minecraft.client.renderer.block.model.ItemTransforms;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.client.resources.model.Material;
+import net.minecraft.client.resources.model.ModelState;
+import net.minecraft.core.Direction;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraftforge.client.MinecraftForgeClient;
+import net.minecraftforge.client.model.data.IDynamicBakedModel;
+import net.minecraftforge.client.model.data.IModelData;
+import net.nicgamer.automatek.blocks.ConnectingBlockModelLoader;
+import net.nicgamer.automatek.blocks.ModelKey;
+import net.nicgamer.automatek.varia.ClientTools;
+import org.jetbrains.annotations.NotNull;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.*;
+import java.util.function.Function;
+
+import static java.lang.Boolean.TRUE;
+import static net.nicgamer.automatek.varia.ClientTools.v;
+
+public class ConnectingBlockBakedModel implements IDynamicBakedModel {
+
+    private final ModelState modelState;
+    private final Function<Material, TextureAtlasSprite> spriteGetter;
+    private final Map<ModelKey, List<BakedQuad>> quadCache = new HashMap<>();
+    private final ItemOverrides overrides;
+    private final ItemTransforms itemTransforms;
+
+    /**
+     * @param modelState     represents the transformation (orientation) of our model. This is generated from the FACING property that our blockstate uses
+     * @param spriteGetter   gives a way to convert materials to actual sprites on the main atlas
+     * @param overrides      this is used for using this baked model when it is rendered in an inventory (as an item)
+     * @param itemTransforms these represent the transforms to use for the item model
+     */
+    public ConnectingBlockBakedModel(ModelState modelState, Function<Material, TextureAtlasSprite> spriteGetter,
+                                     ItemOverrides overrides, ItemTransforms itemTransforms) {
+        this.modelState = modelState;
+        this.spriteGetter = spriteGetter;
+        this.overrides = overrides;
+        this.itemTransforms = itemTransforms;
+        generateQuadCache();
+    }
+
+    @Override
+    public boolean usesBlockLight() {
+        return false;
+    }
+
+    /**
+     * Whenever a chunk where our block is in needs to be rerendered this method is called to return the quads (polygons)
+     * for our model. Typically this will be called seven times: one time for every direction and one time in general.
+     * If you have a block that is solid at one of the six sides it can be a good idea to render that face only for that
+     * direction. That way Minecraft knows that it can get rid of that face when another solid block is adjacent to that.
+     * All faces or quads that are generated for side == null are not going to be culled away like that
+     *
+     * @param state     the blockstate for our block
+     * @param side      the six directions or null for quads that are not at a specific direction
+     * @param rand      random generator that you can use to add variations to your model (usually for textures)
+     * @param extraData this represents the data that is given to use from our block entity
+     * @return a list of quads
+     */
+    @Nonnull
+    @Override
+    public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand, @Nonnull IModelData extraData) {
+
+        // Are we on the solid render type and are we rendering for side == null
+        RenderType layer = MinecraftForgeClient.getRenderType();
+        if (side != null || (layer != null && !layer.equals(RenderType.solid()))) {
+            return Collections.emptyList();
+        }
+
+        // Get the data from our block entity
+        boolean northConnected = TRUE == extraData.getData(ConnectingBlockBE.NORTH_CONNECTED);
+        boolean eastConnected = TRUE == extraData.getData(ConnectingBlockBE.EAST_CONNECTED);
+        boolean southConnected = TRUE == extraData.getData(ConnectingBlockBE.SOUTH_CONNECTED);
+        boolean westConnected = TRUE == extraData.getData(ConnectingBlockBE.WEST_CONNECTED);
+        boolean upConnected = TRUE == extraData.getData(ConnectingBlockBE.UP_CONNECTED);
+        boolean downConnected = TRUE == extraData.getData(ConnectingBlockBE.DOWN_CONNECTED);
+
+        // ModelKey represents a unique configuration. We can use this to get our cached quads
+        ModelKey key = new ModelKey(northConnected, eastConnected, southConnected, westConnected, upConnected, downConnected, modelState);
+
+        var quads = new ArrayList<>(quadCache.get(key));
+        return quads;
+    }
+
+    private void generateQuadCache() {
+        boolean northConnected;
+        boolean eastConnected;
+        boolean southConnected;
+        boolean westConnected;
+        boolean upConnected;
+        boolean downConnected;
+        for (int i = 0; i < 2; i++) {
+            northConnected = i != 0;
+            for (int j = 0; j < 2; j++) {
+                eastConnected = j != 0;
+                for (int k = 0; k < 2; k++) {
+                    southConnected = k != 0;
+                    for (int l = 0; l < 2; l++) {
+                        westConnected = l != 0;
+                        for (int m = 0; m < 2; m++) {
+                            upConnected = m != 0;
+                            for (int n = 0; n < 2; n++) {
+                                downConnected = n != 0;
+                                quadCache.put(new ModelKey(northConnected, eastConnected, southConnected, westConnected, upConnected, downConnected, modelState), generateQuads(northConnected, eastConnected, southConnected, westConnected, upConnected, downConnected));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Generate the quads for a given configuration. This is done in the constructor in order to populate
+     * our quad cache.
+     */
+    @NotNull
+    private List<BakedQuad> generateQuads(boolean northConnected, boolean eastConnected, boolean southConnected, boolean westConnected, boolean upConnected, boolean downConnected) {
+        var quads = new ArrayList<BakedQuad>();
+        float l = 0;
+        float r = 1;
+
+        Transformation rotation = modelState.getRotation();
+
+        TextureAtlasSprite O = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_ZERO_CONNECTIONS);
+        TextureAtlasSprite U = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_UP);
+        TextureAtlasSprite R = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_RIGHT);
+        TextureAtlasSprite D = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_DOWN);
+        TextureAtlasSprite L = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_LEFT);
+        TextureAtlasSprite LR = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_TWO_STRAIGHT_CONNECTION_LR);
+        TextureAtlasSprite DU = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_TWO_STRAIGHT_CONNECTION_UD);
+        TextureAtlasSprite RU = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_UR);
+        TextureAtlasSprite DR = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_RD);
+        TextureAtlasSprite DL = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_DL);
+        TextureAtlasSprite LU = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_LU);
+        TextureAtlasSprite DRU = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_URD);
+        TextureAtlasSprite DLR = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_RDL);
+        TextureAtlasSprite DLU = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_DLU);
+        TextureAtlasSprite LRU = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_LUR);
+        TextureAtlasSprite DLRU = spriteGetter.apply(ConnectingBlockModelLoader.MATERIAL_CONNECTING_BLOCK_FOUR_CONNECTION);
+
+        blockMaterials.put("O", O);
+        blockMaterials.put("D", D);
+        blockMaterials.put("L", L);
+        blockMaterials.put("R", R);
+        blockMaterials.put("U", U);
+        blockMaterials.put("DL", DL);
+        blockMaterials.put("DR", DR);
+        blockMaterials.put("DU", DU);
+        blockMaterials.put("LR", LR);
+        blockMaterials.put("LU", LU);
+        blockMaterials.put("RU", RU);
+        blockMaterials.put("DLR", DLR);
+        blockMaterials.put("DLU", DLU);
+        blockMaterials.put("DRU", DRU);
+        blockMaterials.put("LRU", LRU);
+        blockMaterials.put("DLRU", DLRU);
+
+        var sideTextures = texturesForFaces(northConnected, eastConnected, southConnected, westConnected, upConnected, downConnected);
+
+        // The base
+        quads.add(ClientTools.createQuad(v(r, r, r), v(r, r, l), v(l, r, l), v(l, r, r), rotation, sideTextures[4]));      // Top
+        quads.add(ClientTools.createQuad(v(l, l, l), v(r, l, l), v(r, l, r), v(l, l, r), rotation, sideTextures[5]));      // Bottom
+        quads.add(ClientTools.createQuad(v(l, r, r), v(l, l, r), v(l, l, l), v(l, r, l), rotation, sideTextures[3]));      // West
+        quads.add(ClientTools.createQuad(v(r, r, l), v(r, l, l), v(r, l, r), v(r, r, r), rotation, sideTextures[1]));      // East
+        quads.add(ClientTools.createQuad(v(r, r, r), v(r, l, r), v(l, l, l), v(l, r, l), rotation, sideTextures[0]));      // North
+        quads.add(ClientTools.createQuad(v(l, r, l), v(l, l, l), v(r, l, r), v(r, r, r), rotation, sideTextures[2]));      // South
+
+        return quads;
+    }
+
+    @Override
+    public boolean useAmbientOcclusion() {
+        return true;
+    }
+
+    @Override
+    public boolean isGui3d() {
+        return false;
+    }
+
+    @Override
+    public boolean isCustomRenderer() {
+        return false;
+    }
+
+    @Override
+    public TextureAtlasSprite getParticleIcon() {
+        return blockMaterials.get("O");
+    }
+
+    @Override
+    public ItemOverrides getOverrides() {
+        return overrides;
+    }
+
+    @Override
+    public ItemTransforms getTransforms() {
+        return itemTransforms;
+    }
+
+    private final Map<String, TextureAtlasSprite> blockMaterials = new HashMap<>();
+
+    private TextureAtlasSprite[] texturesForFaces(boolean northConnected, boolean eastConnected, boolean southConnected, boolean westConnected, boolean upConnected, boolean downConnected) {
+        boolean[] connectedSidesBooleans = new boolean[]{northConnected, eastConnected, southConnected, westConnected, upConnected, downConnected};
+        TextureAtlasSprite[] sprites = new TextureAtlasSprite[6];
+        Character[][] connectedSides = new Character[6][4];   //[North, East, South, West, Up, Down] [U, R, D, L]
+        int[] amountOccurrenceSide = new int[]{0, 0, 0, 0, 0, 0};
+        char[][] mapper = new char[][]{{0, 'L', 0, 'R', 'U', 'D'}, {'R', 0, 'L', 0, 'U', 'D'}, {0, 'R', 0, 'L', 'U', 'D'}, {'L', 0, 'R', 0, 'U', 'D'}, {'U', 'R', 'D', 'L', 0, 0}, {'U', 'L', 'D', 'R', 0, 0}};
+        int[] activeSide = new int[4];
+        for (int i = 0; i < 6; i++) {
+            switch (i) {
+                case 4, 5 -> {
+                    activeSide[0] = 0;
+                    activeSide[1] = 1;
+                    activeSide[2] = 2;
+                    activeSide[3] = 3;
+                }
+                default -> {
+                    activeSide[2] = 4;
+                    activeSide[3] = 5;
+                    switch (i) {
+                        case 0, 2 -> {
+                            activeSide[0] = 1;
+                            activeSide[1] = 3;
+                        }
+                        case 1, 3 -> {
+                            activeSide[0] = 0;
+                            activeSide[1] = 2;
+                        }
+                    }
+                }
+            }
+            if (connectedSidesBooleans[i]) {
+                connectedSides[activeSide[0]][amountOccurrenceSide[activeSide[0]]] = mapper[activeSide[0]][i];
+                connectedSides[activeSide[1]][amountOccurrenceSide[activeSide[1]]] = mapper[activeSide[1]][i];
+                connectedSides[activeSide[2]][amountOccurrenceSide[activeSide[2]]] = mapper[activeSide[2]][i];
+                connectedSides[activeSide[3]][amountOccurrenceSide[activeSide[3]]] = mapper[activeSide[3]][i];
+            } else {
+                connectedSides[activeSide[0]][amountOccurrenceSide[activeSide[0]]] = 0;
+                connectedSides[activeSide[1]][amountOccurrenceSide[activeSide[1]]] = 0;
+                connectedSides[activeSide[2]][amountOccurrenceSide[activeSide[2]]] = 0;
+                connectedSides[activeSide[3]][amountOccurrenceSide[activeSide[3]]] = 0;
+            }
+            amountOccurrenceSide[activeSide[0]]++;
+            amountOccurrenceSide[activeSide[1]]++;
+            amountOccurrenceSide[activeSide[2]]++;
+            amountOccurrenceSide[activeSide[3]]++;
+        }
+        String[] keys = new String[6];
+        for (int j = 0; j < 6; j++) {
+            String key = "";
+            var character = Arrays.stream(connectedSides[j]).sorted().map(value -> value == 0 ? "" : value).toArray();
+            for (int k = 0; k < 4; k++) {
+                key = key.concat(character[k].toString());
+            }
+            keys[j] = key;
+        }
+        for (int l = 0; l < sprites.length; l++) {
+            if (!keys[l].equals("")) {
+                sprites[l] = blockMaterials.get(keys[l]);
+            } else {
+                sprites[l] = blockMaterials.get("O");
+            }
+        }
+        return sprites;
+    }
+}
+

ConnectingBlockModelLoader

@@ -0,0 +1,86 @@

+package net.nicgamer.automatek.blocks;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonObject;
+import com.mojang.datafixers.util.Pair;
+import net.minecraft.client.renderer.block.model.ItemOverrides;
+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.minecraftforge.client.ForgeHooksClient;
+import net.minecraftforge.client.model.IModelConfiguration;
+import net.minecraftforge.client.model.IModelLoader;
+import net.minecraftforge.client.model.geometry.IModelGeometry;
+import net.nicgamer.automatek.AutomatekMod;
+import net.nicgamer.automatek.utilities.ConnectingBlockBakedModel;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+
+public class ConnectingBlockModelLoader implements IModelLoader<ConnectingBlockModelLoader.ConnectingBlockModelGeometry> {
+
+    public static final ResourceLocation CONNECTING_BLOCK_LOADER = new ResourceLocation(AutomatekMod.MOD_ID, "connecting_block_loader");
+
+    public static final ResourceLocation CONNECTING_BLOCK_ZERO_CONNECTIONS = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/zero_sides_connected");
+    public static final ResourceLocation CONNECTING_BLOCK_ONE_CONNECTION_UP = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/one_side_connected_u");
+    public static final ResourceLocation CONNECTING_BLOCK_ONE_CONNECTION_RIGHT = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/one_side_connected_r");
+    public static final ResourceLocation CONNECTING_BLOCK_ONE_CONNECTION_LEFT = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/one_side_connected_l");
+    public static final ResourceLocation CONNECTING_BLOCK_ONE_CONNECTION_DOWN = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/one_side_connected_d");
+    public static final ResourceLocation CONNECTING_BLOCK_TWO_CURVE_CONNECTION_UR = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/two_sides_connected_curve_ur");
+    public static final ResourceLocation CONNECTING_BLOCK_TWO_CURVE_CONNECTION_RD = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/two_sides_connected_curve_rd");
+    public static final ResourceLocation CONNECTING_BLOCK_TWO_CURVE_CONNECTION_DL = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/two_sides_connected_curve_dl");
+    public static final ResourceLocation CONNECTING_BLOCK_TWO_CURVE_CONNECTION_LU = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/two_sides_connected_curve_lu");
+    public static final ResourceLocation CONNECTING_BLOCK_TWO_STRAIGHT_CONNECTION_UD = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/two_sides_connected_straight_ud");
+    public static final ResourceLocation CONNECTING_BLOCK_TWO_STRAIGHT_CONNECTION_LR = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/two_sides_connected_straight_lr");
+    public static final ResourceLocation CONNECTING_BLOCK_THREE_CONNECTION_URD = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/three_sides_connected_urd");
+    public static final ResourceLocation CONNECTING_BLOCK_THREE_CONNECTION_RDL = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/three_sides_connected_rdl");
+    public static final ResourceLocation CONNECTING_BLOCK_THREE_CONNECTION_DLU = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/three_sides_connected_dlu");
+    public static final ResourceLocation CONNECTING_BLOCK_THREE_CONNECTION_LUR = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/three_sides_connected_lur");
+    public static final ResourceLocation CONNECTING_BLOCK_FOUR_CONNECTION = new ResourceLocation(AutomatekMod.MOD_ID, "block/frames/transparent");
+
+    public static final Material MATERIAL_CONNECTING_BLOCK_ZERO_CONNECTIONS = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_ZERO_CONNECTIONS);
+    public static final Material MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_UP = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_ONE_CONNECTION_UP);
+    public static final Material MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_RIGHT = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_ONE_CONNECTION_RIGHT);
+    public static final Material MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_LEFT = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_ONE_CONNECTION_LEFT);
+    public static final Material MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_DOWN = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_ONE_CONNECTION_DOWN);
+    public static final Material MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_UR = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_TWO_CURVE_CONNECTION_UR);
+    public static final Material MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_RD = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_TWO_CURVE_CONNECTION_RD);
+    public static final Material MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_DL = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_TWO_CURVE_CONNECTION_DL);
+    public static final Material MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_LU = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_TWO_CURVE_CONNECTION_LU);
+    public static final Material MATERIAL_CONNECTING_BLOCK_TWO_STRAIGHT_CONNECTION_UD = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_TWO_STRAIGHT_CONNECTION_UD);
+    public static final Material MATERIAL_CONNECTING_BLOCK_TWO_STRAIGHT_CONNECTION_LR = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_TWO_STRAIGHT_CONNECTION_LR);
+    public static final Material MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_URD = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_THREE_CONNECTION_URD);
+    public static final Material MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_RDL = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_THREE_CONNECTION_RDL);
+    public static final Material MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_DLU = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_THREE_CONNECTION_DLU);
+    public static final Material MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_LUR = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_THREE_CONNECTION_LUR);
+    public static final Material MATERIAL_CONNECTING_BLOCK_FOUR_CONNECTION = ForgeHooksClient.getBlockMaterial(CONNECTING_BLOCK_FOUR_CONNECTION);
+
+    @Override
+    public void onResourceManagerReload(ResourceManager resourceManager) {
+    }
+
+    @Override
+    public ConnectingBlockModelGeometry read(JsonDeserializationContext deserializationContext, JsonObject modelContents) {
+        return new ConnectingBlockModelGeometry();
+    }
+
+
+    public static class ConnectingBlockModelGeometry implements IModelGeometry<ConnectingBlockModelGeometry> {
+
+        @Override
+        public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelTransform, ItemOverrides overrides, ResourceLocation modelLocation) {
+            return new ConnectingBlockBakedModel(modelTransform, spriteGetter, overrides, owner.getCameraTransforms());
+        }
+
+        @Override
+        public Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, UnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
+            return List.of(MATERIAL_CONNECTING_BLOCK_ZERO_CONNECTIONS, MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_UP, MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_RIGHT, MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_LEFT, MATERIAL_CONNECTING_BLOCK_ONE_CONNECTION_DOWN,
+                    MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_UR, MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_RD, MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_DL, MATERIAL_CONNECTING_BLOCK_TWO_CURVE_CONNECTION_LU,
+                    MATERIAL_CONNECTING_BLOCK_TWO_STRAIGHT_CONNECTION_UD, MATERIAL_CONNECTING_BLOCK_TWO_STRAIGHT_CONNECTION_LR, MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_URD, MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_RDL,
+                    MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_DLU, MATERIAL_CONNECTING_BLOCK_THREE_CONNECTION_LUR, MATERIAL_CONNECTING_BLOCK_FOUR_CONNECTION);
+        }
+    }
+}