From 81af046eba642f7d3301aba7fdb0b26321bac9e9 Mon Sep 17 00:00:00 2001
From: Mark <modmuss50@gmail.com>
Date: Fri, 20 Jan 2023 17:56:36 +0000
Subject: [PATCH] [1.19.3] Implement custom SignTypes (#2832)

* 1.19.3 custom sign types

Co-authored-by: AlphaMode <26313415+alphamode@users.noreply.github.com>

* fix mixin name

Co-authored-by: AlphaMode <26313415+alphamode@users.noreply.github.com>
(cherry picked from commit eb2a3ba986c43bd110f5d3d4d540aec227f81926)
---
 .../client/EntityModelLayersMixin.java        |  46 ++++++++
 .../client/HangingSignEditScreenMixin.java    |  43 +++++++
 .../client/TexturedRenderLayersMixin.java     |  52 +++++++++
 ...abric-object-builder-v1.client.mixins.json |   5 +-
 .../builder/v1/sign/SignTypeRegistry.java     |  42 +++++++
 ...fabric-object-builder-api-v1.accesswidener |   3 +
 .../test/object/builder/TealSignTest.java     | 107 ++++++++++++++++++
 .../builder/client/TealSignClientTest.java    |  32 ++++++
 .../BlockEntityRendererFactoriesAccessor.java |  33 ++++++
 .../blockstates/teal_hanging_sign.json        |   7 ++
 .../blockstates/teal_sign.json                |   7 ++
 .../blockstates/teal_wall_hanging_sign.json   |   7 ++
 .../blockstates/teal_wall_sign.json           |   7 ++
 .../lang/en_us.json                           |   2 +
 .../models/block/teal_sign.json               |   5 +
 .../models/item/teal_hanging_sign.json        |   6 +
 .../models/item/teal_sign.json                |   6 +
 .../textures/entity/signs/hanging/teal.png    | Bin 0 -> 6183 bytes
 .../textures/entity/signs/teal.png            | Bin 0 -> 195 bytes
 .../textures/gui/hanging_signs/teal.png       | Bin 0 -> 5046 bytes
 .../textures/item/teal_hanging_sign.png       | Bin 0 -> 5135 bytes
 .../textures/item/teal_sign.png               | Bin 0 -> 221 bytes
 ...-object-builder-api-v1-testmod.mixins.json |  11 ++
 .../src/testmod/resources/fabric.mod.json     |   9 +-
 fabric-rendering-v1/build.gradle              |   4 +
 25 files changed, 432 insertions(+), 2 deletions(-)
 create mode 100644 fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/EntityModelLayersMixin.java
 create mode 100644 fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/HangingSignEditScreenMixin.java
 create mode 100644 fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/TexturedRenderLayersMixin.java
 create mode 100644 fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/sign/SignTypeRegistry.java
 create mode 100644 fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/TealSignTest.java
 create mode 100644 fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/client/TealSignClientTest.java
 create mode 100644 fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/mixin/BlockEntityRendererFactoriesAccessor.java
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_hanging_sign.json
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_sign.json
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_wall_hanging_sign.json
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_wall_sign.json
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/block/teal_sign.json
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/item/teal_hanging_sign.json
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/item/teal_sign.json
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/entity/signs/hanging/teal.png
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/entity/signs/teal.png
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/gui/hanging_signs/teal.png
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/item/teal_hanging_sign.png
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/item/teal_sign.png
 create mode 100644 fabric-object-builder-api-v1/src/testmod/resources/fabric-object-builder-api-v1-testmod.mixins.json

diff --git a/fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/EntityModelLayersMixin.java b/fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/EntityModelLayersMixin.java
new file mode 100644
index 000000000..4df0417e3
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/EntityModelLayersMixin.java
@@ -0,0 +1,46 @@
+/*
+ * 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 net.fabricmc.fabric.mixin.object.builder.client;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+import net.minecraft.client.render.entity.model.EntityModelLayer;
+import net.minecraft.client.render.entity.model.EntityModelLayers;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.SignType;
+
+@Mixin(EntityModelLayers.class)
+public class EntityModelLayersMixin {
+	@Inject(method = "createSign", at = @At("HEAD"), cancellable = true)
+	private static void createSign(SignType type, CallbackInfoReturnable<EntityModelLayer> cir) {
+		if (type.getName().indexOf(Identifier.NAMESPACE_SEPARATOR) != -1) {
+			Identifier identifier = new Identifier(type.getName());
+			cir.setReturnValue(new EntityModelLayer(new Identifier(identifier.getNamespace(), "sign/" + identifier.getPath()), "main"));
+		}
+	}
+
+	@Inject(method = "createHangingSign", at = @At("HEAD"), cancellable = true)
+	private static void createHangingSign(SignType type, CallbackInfoReturnable<EntityModelLayer> cir) {
+		if (type.getName().indexOf(Identifier.NAMESPACE_SEPARATOR) != -1) {
+			Identifier identifier = new Identifier(type.getName());
+			cir.setReturnValue(new EntityModelLayer(new Identifier(identifier.getNamespace(), "hanging_sign/" + identifier.getPath()), "main"));
+		}
+	}
+}
diff --git a/fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/HangingSignEditScreenMixin.java b/fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/HangingSignEditScreenMixin.java
new file mode 100644
index 000000000..f100af24b
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/HangingSignEditScreenMixin.java
@@ -0,0 +1,43 @@
+/*
+ * 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 net.fabricmc.fabric.mixin.object.builder.client;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.ModifyArg;
+
+import net.minecraft.block.entity.SignBlockEntity;
+import net.minecraft.client.gui.screen.ingame.AbstractSignEditScreen;
+import net.minecraft.client.gui.screen.ingame.HangingSignEditScreen;
+import net.minecraft.util.Identifier;
+
+@Mixin(HangingSignEditScreen.class)
+public abstract class HangingSignEditScreenMixin extends AbstractSignEditScreen {
+	private HangingSignEditScreenMixin(SignBlockEntity blockEntity, boolean filtered) {
+		super(blockEntity, filtered);
+	}
+
+	@ModifyArg(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Identifier;<init>(Ljava/lang/String;)V"))
+	private String init(String id) {
+		if (signType.getName().indexOf(Identifier.NAMESPACE_SEPARATOR) != -1) {
+			Identifier identifier = new Identifier(signType.getName());
+			return identifier.getNamespace() + ":textures/gui/hanging_signs/" + identifier.getPath() + ".png";
+		}
+
+		return id;
+	}
+}
diff --git a/fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/TexturedRenderLayersMixin.java b/fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/TexturedRenderLayersMixin.java
new file mode 100644
index 000000000..f594e77f0
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/mixin/object/builder/client/TexturedRenderLayersMixin.java
@@ -0,0 +1,52 @@
+/*
+ * 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 net.fabricmc.fabric.mixin.object.builder.client;
+
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+import net.minecraft.client.render.TexturedRenderLayers;
+import net.minecraft.client.util.SpriteIdentifier;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.SignType;
+
+@Mixin(TexturedRenderLayers.class)
+public class TexturedRenderLayersMixin {
+	@Shadow
+	@Final
+	public static Identifier SIGNS_ATLAS_TEXTURE;
+
+	@Inject(method = "createSignTextureId", at = @At("HEAD"), cancellable = true)
+	private static void modifyTextureId(SignType type, CallbackInfoReturnable<SpriteIdentifier> cir) {
+		if (type.getName().indexOf(Identifier.NAMESPACE_SEPARATOR) != -1) {
+			Identifier identifier = new Identifier(type.getName());
+			cir.setReturnValue(new SpriteIdentifier(SIGNS_ATLAS_TEXTURE, new Identifier(identifier.getNamespace(), "entity/signs/" + identifier.getPath())));
+		}
+	}
+
+	@Inject(method = "createHangingSignTextureId", at = @At("HEAD"), cancellable = true)
+	private static void modifyHangingTextureId(SignType type, CallbackInfoReturnable<SpriteIdentifier> cir) {
+		if (type.getName().indexOf(Identifier.NAMESPACE_SEPARATOR) != -1) {
+			Identifier identifier = new Identifier(type.getName());
+			cir.setReturnValue(new SpriteIdentifier(SIGNS_ATLAS_TEXTURE, new Identifier(identifier.getNamespace(), "entity/signs/hanging/" + identifier.getPath())));
+		}
+	}
+}
diff --git a/fabric-object-builder-api-v1/src/client/resources/fabric-object-builder-v1.client.mixins.json b/fabric-object-builder-api-v1/src/client/resources/fabric-object-builder-v1.client.mixins.json
index a2e2d9426..58f51649a 100644
--- a/fabric-object-builder-api-v1/src/client/resources/fabric-object-builder-v1.client.mixins.json
+++ b/fabric-object-builder-api-v1/src/client/resources/fabric-object-builder-v1.client.mixins.json
@@ -3,8 +3,11 @@
   "package": "net.fabricmc.fabric.mixin.object.builder.client",
   "compatibilityLevel": "JAVA_16",
   "client": [
+    "EntityModelLayersMixin",
+    "HangingSignEditScreenMixin",
     "ModelPredicateProviderRegistryAccessor",
-    "ModelPredicateProviderRegistrySpecificAccessor"
+    "ModelPredicateProviderRegistrySpecificAccessor",
+    "TexturedRenderLayersMixin"
   ],
   "injectors": {
     "defaultRequire": 1
diff --git a/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/sign/SignTypeRegistry.java b/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/sign/SignTypeRegistry.java
new file mode 100644
index 000000000..333ca1409
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/sign/SignTypeRegistry.java
@@ -0,0 +1,42 @@
+/*
+ * 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 net.fabricmc.fabric.api.object.builder.v1.sign;
+
+import net.minecraft.util.Identifier;
+import net.minecraft.util.SignType;
+
+/**
+ * This class allows registering {@link SignType}s.
+ *
+ * <p>A {@link SignType} is used to tell the game what texture a sign should use.
+ *
+ * <p>These textures are stored under {@code namespace/textures/entity/signs/}.
+ */
+public final class SignTypeRegistry {
+	private SignTypeRegistry() {
+	}
+
+	/**
+	 * Creates and registers a {@link SignType}.
+	 *
+	 * @param id the id of this {@link SignType}
+	 * @return a new {@link SignType}.
+	 */
+	public static SignType registerSignType(Identifier id) {
+		return SignType.register(new SignType(id.toString()));
+	}
+}
diff --git a/fabric-object-builder-api-v1/src/main/resources/fabric-object-builder-api-v1.accesswidener b/fabric-object-builder-api-v1/src/main/resources/fabric-object-builder-api-v1.accesswidener
index c0f622f39..946642229 100644
--- a/fabric-object-builder-api-v1/src/main/resources/fabric-object-builder-api-v1.accesswidener
+++ b/fabric-object-builder-api-v1/src/main/resources/fabric-object-builder-api-v1.accesswidener
@@ -11,3 +11,6 @@ accessible method net/minecraft/entity/SpawnRestriction register (Lnet/minecraft
 
 accessible field net/minecraft/village/VillagerType BIOME_TO_TYPE Ljava/util/Map;
 accessible method net/minecraft/village/VillagerType <init> (Ljava/lang/String;)V
+
+accessible method net/minecraft/util/SignType <init> (Ljava/lang/String;)V
+accessible method net/minecraft/util/SignType register (Lnet/minecraft/util/SignType;)Lnet/minecraft/util/SignType;
diff --git a/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/TealSignTest.java b/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/TealSignTest.java
new file mode 100644
index 000000000..b384ccc89
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/TealSignTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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 net.fabricmc.fabric.test.object.builder;
+
+import net.minecraft.block.BlockState;
+import net.minecraft.block.Blocks;
+import net.minecraft.block.HangingSignBlock;
+import net.minecraft.block.SignBlock;
+import net.minecraft.block.WallHangingSignBlock;
+import net.minecraft.block.WallSignBlock;
+import net.minecraft.block.entity.BlockEntityType;
+import net.minecraft.block.entity.HangingSignBlockEntity;
+import net.minecraft.block.entity.SignBlockEntity;
+import net.minecraft.item.HangingSignItem;
+import net.minecraft.item.Item;
+import net.minecraft.item.SignItem;
+import net.minecraft.registry.Registries;
+import net.minecraft.registry.Registry;
+import net.minecraft.util.SignType;
+import net.minecraft.util.math.BlockPos;
+
+import net.fabricmc.api.ModInitializer;
+import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
+import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
+import net.fabricmc.fabric.api.object.builder.v1.sign.SignTypeRegistry;
+
+public class TealSignTest implements ModInitializer {
+	public static final SignType TEAL_TYPE = SignTypeRegistry.registerSignType(ObjectBuilderTestConstants.id("teal"));
+	public static final SignBlock TEAL_SIGN = new SignBlock(FabricBlockSettings.copy(Blocks.OAK_SIGN), TEAL_TYPE) {
+		@Override
+		public TealSign createBlockEntity(BlockPos pos, BlockState state) {
+			return new TealSign(pos, state);
+		}
+	};
+	public static final WallSignBlock TEAL_WALL_SIGN = new WallSignBlock(FabricBlockSettings.copy(Blocks.OAK_SIGN), TEAL_TYPE) {
+		@Override
+		public TealSign createBlockEntity(BlockPos pos, BlockState state) {
+			return new TealSign(pos, state);
+		}
+	};
+	public static final HangingSignBlock TEAL_HANGING_SIGN = new HangingSignBlock(FabricBlockSettings.copy(Blocks.OAK_HANGING_SIGN), TEAL_TYPE) {
+		@Override
+		public TealHangingSign createBlockEntity(BlockPos pos, BlockState state) {
+			return new TealHangingSign(pos, state);
+		}
+	};
+	public static final WallHangingSignBlock TEAL_WALL_HANGING_SIGN = new WallHangingSignBlock(FabricBlockSettings.copy(Blocks.OAK_HANGING_SIGN), TEAL_TYPE) {
+		@Override
+		public TealHangingSign createBlockEntity(BlockPos pos, BlockState state) {
+			return new TealHangingSign(pos, state);
+		}
+	};
+	public static final SignItem TEAL_SIGN_ITEM = new SignItem(new Item.Settings(), TEAL_SIGN, TEAL_WALL_SIGN);
+	public static final HangingSignItem TEAL_HANGING_SIGN_ITEM = new HangingSignItem(TEAL_HANGING_SIGN, TEAL_WALL_HANGING_SIGN, new Item.Settings());
+	public static final BlockEntityType<TealSign> TEST_SIGN_BLOCK_ENTITY = FabricBlockEntityTypeBuilder.create(TealSign::new, TEAL_SIGN, TEAL_WALL_SIGN).build();
+	public static final BlockEntityType<TealHangingSign> TEST_HANGING_SIGN_BLOCK_ENTITY = FabricBlockEntityTypeBuilder.create(TealHangingSign::new, TEAL_HANGING_SIGN, TEAL_WALL_HANGING_SIGN).build();
+
+	@Override
+	public void onInitialize() {
+		Registry.register(Registries.BLOCK, ObjectBuilderTestConstants.id("teal_sign"), TEAL_SIGN);
+		Registry.register(Registries.BLOCK, ObjectBuilderTestConstants.id("teal_wall_sign"), TEAL_WALL_SIGN);
+		Registry.register(Registries.BLOCK, ObjectBuilderTestConstants.id("teal_hanging_sign"), TEAL_HANGING_SIGN);
+		Registry.register(Registries.BLOCK, ObjectBuilderTestConstants.id("teal_wall_hanging_sign"), TEAL_WALL_HANGING_SIGN);
+
+		Registry.register(Registries.ITEM, ObjectBuilderTestConstants.id("teal_sign"), TEAL_SIGN_ITEM);
+		Registry.register(Registries.ITEM, ObjectBuilderTestConstants.id("teal_hanging_sign"), TEAL_HANGING_SIGN_ITEM);
+
+		Registry.register(Registries.BLOCK_ENTITY_TYPE, ObjectBuilderTestConstants.id("teal_sign"), TEST_SIGN_BLOCK_ENTITY);
+		Registry.register(Registries.BLOCK_ENTITY_TYPE, ObjectBuilderTestConstants.id("teal_hanging_sign"), TEST_HANGING_SIGN_BLOCK_ENTITY);
+	}
+
+	public static class TealSign extends SignBlockEntity {
+		public TealSign(BlockPos pos, BlockState state) {
+			super(pos, state);
+		}
+
+		@Override
+		public BlockEntityType<?> getType() {
+			return TEST_SIGN_BLOCK_ENTITY;
+		}
+	}
+
+	public static class TealHangingSign extends HangingSignBlockEntity {
+		public TealHangingSign(BlockPos pos, BlockState state) {
+			super(pos, state);
+		}
+
+		@Override
+		public BlockEntityType<?> getType() {
+			return TEST_HANGING_SIGN_BLOCK_ENTITY;
+		}
+	}
+}
diff --git a/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/client/TealSignClientTest.java b/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/client/TealSignClientTest.java
new file mode 100644
index 000000000..4dc63b785
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/client/TealSignClientTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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 net.fabricmc.fabric.test.object.builder.client;
+
+import net.minecraft.client.render.block.entity.HangingSignBlockEntityRenderer;
+import net.minecraft.client.render.block.entity.SignBlockEntityRenderer;
+
+import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.fabric.test.object.builder.TealSignTest;
+import net.fabricmc.fabric.test.object.builder.mixin.BlockEntityRendererFactoriesAccessor;
+
+public class TealSignClientTest implements ClientModInitializer {
+	@Override
+	public void onInitializeClient() {
+		BlockEntityRendererFactoriesAccessor.callRegister(TealSignTest.TEST_SIGN_BLOCK_ENTITY, SignBlockEntityRenderer::new);
+		BlockEntityRendererFactoriesAccessor.callRegister(TealSignTest.TEST_HANGING_SIGN_BLOCK_ENTITY, HangingSignBlockEntityRenderer::new);
+	}
+}
diff --git a/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/mixin/BlockEntityRendererFactoriesAccessor.java b/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/mixin/BlockEntityRendererFactoriesAccessor.java
new file mode 100644
index 000000000..ec4ae6910
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/mixin/BlockEntityRendererFactoriesAccessor.java
@@ -0,0 +1,33 @@
+/*
+ * 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 net.fabricmc.fabric.test.object.builder.mixin;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+import net.minecraft.block.entity.BlockEntity;
+import net.minecraft.block.entity.BlockEntityType;
+import net.minecraft.client.render.block.entity.BlockEntityRendererFactories;
+import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
+
+@Mixin(BlockEntityRendererFactories.class)
+public interface BlockEntityRendererFactoriesAccessor {
+	@Invoker
+	static <T extends BlockEntity> void callRegister(BlockEntityType<? extends T> type, BlockEntityRendererFactory<T> factory) {
+		throw new UnsupportedOperationException();
+	}
+}
diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_hanging_sign.json b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_hanging_sign.json
new file mode 100644
index 000000000..c591d1edc
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_hanging_sign.json
@@ -0,0 +1,7 @@
+{
+  "variants": {
+    "": {
+      "model": "fabric-rendering-v1-testmod:block/teal_hanging_sign"
+    }
+  }
+}
diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_sign.json b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_sign.json
new file mode 100644
index 000000000..1a05e4cfe
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_sign.json
@@ -0,0 +1,7 @@
+{
+  "variants": {
+    "": {
+      "model": "fabric-rendering-v1-testmod:block/teal_sign"
+    }
+  }
+}
diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_wall_hanging_sign.json b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_wall_hanging_sign.json
new file mode 100644
index 000000000..c591d1edc
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_wall_hanging_sign.json
@@ -0,0 +1,7 @@
+{
+  "variants": {
+    "": {
+      "model": "fabric-rendering-v1-testmod:block/teal_hanging_sign"
+    }
+  }
+}
diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_wall_sign.json b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_wall_sign.json
new file mode 100644
index 000000000..1a05e4cfe
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/blockstates/teal_wall_sign.json
@@ -0,0 +1,7 @@
+{
+  "variants": {
+    "": {
+      "model": "fabric-rendering-v1-testmod:block/teal_sign"
+    }
+  }
+}
diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/lang/en_us.json b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/lang/en_us.json
index e2cf21775..174bf682d 100644
--- a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/lang/en_us.json
+++ b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/lang/en_us.json
@@ -3,5 +3,7 @@
   "block.fabric-object-builder-api-v1-testmod.first_multi_betrayal_block": "First Multi Betrayal Block",
   "block.fabric-object-builder-api-v1-testmod.initial_betrayal_block": "Initial Betrayal Block",
   "block.fabric-object-builder-api-v1-testmod.second_multi_betrayal_block": "Second Multi Betrayal Block",
+  "block.fabric-object-builder-api-v1-testmod.teal_sign": "Teal Sign",
+  "block.fabric-object-builder-api-v1-testmod.teal_hanging_sign": "Teal Hanging Sign",
   "text.fabric-object-builder-api-v1-testmod.block_entity_type_success": "Betrayal block at %s has correct block entity type: %s"
 }
diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/block/teal_sign.json b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/block/teal_sign.json
new file mode 100644
index 000000000..ca1fbd87f
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/block/teal_sign.json
@@ -0,0 +1,5 @@
+{
+  "textures": {
+    "particle": "fabric-object-builder-api-v1-testmod:entity/signs/teal"
+  }
+}
diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/item/teal_hanging_sign.json b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/item/teal_hanging_sign.json
new file mode 100644
index 000000000..fe1dac76e
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/item/teal_hanging_sign.json
@@ -0,0 +1,6 @@
+{
+  "parent": "minecraft:item/generated",
+  "textures": {
+    "layer0": "fabric-object-builder-api-v1-testmod:item/teal_hanging_sign"
+  }
+}
diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/item/teal_sign.json b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/item/teal_sign.json
new file mode 100644
index 000000000..cf02bcf95
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/models/item/teal_sign.json
@@ -0,0 +1,6 @@
+{
+  "parent": "minecraft:item/generated",
+  "textures": {
+    "layer0": "fabric-object-builder-api-v1-testmod:item/teal_sign"
+  }
+}
diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/entity/signs/hanging/teal.png b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/entity/signs/hanging/teal.png
new file mode 100644
index 0000000000000000000000000000000000000000..62a871ffb3b867f846b0ae36ddb55dec11ca59ec
GIT binary patch
literal 6183
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
Qs6K>jv&s6RrEko?0E8*T@Bjb+

literal 0
HcmV?d00001

diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/entity/signs/teal.png b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/entity/signs/teal.png
new file mode 100644
index 0000000000000000000000000000000000000000..030b2ffc76035d7ef9a14350b8d4a98839ceddd2
GIT binary patch
literal 195
zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQjEnx?oJHr&dIz4a%w$Y978f1
z-%fYrI-nqM<c{5e|NAfV-w4*MnCPXrM(w*(NAU}{%8b3!&s^!4dVbx0+f9Nm<LjP0
z7V3*{V9a2YV!ps+!nS}lgU5mUf<%MZg3AB1kIzo{xa(9K_l&sa+4>KEu!4jQ8FU?z
m8KN4FF>GPzh3Zq%F`xI1$MRvA*d?Gt7(8A5T-G@yGywo907fAI

literal 0
HcmV?d00001

diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/gui/hanging_signs/teal.png b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/gui/hanging_signs/teal.png
new file mode 100644
index 0000000000000000000000000000000000000000..f67a1f3b3334acb75a78158648ea7a9ee5e807f7
GIT binary patch
literal 5046
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
Bd(;2`

literal 0
HcmV?d00001

diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/item/teal_hanging_sign.png b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/item/teal_hanging_sign.png
new file mode 100644
index 0000000000000000000000000000000000000000..96a029a306917228bcb43f6a1b164cd068c0bc64
GIT binary patch
literal 5135
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

literal 0
HcmV?d00001

diff --git a/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/item/teal_sign.png b/fabric-object-builder-api-v1/src/testmod/resources/assets/fabric-object-builder-api-v1-testmod/textures/item/teal_sign.png
new file mode 100644
index 0000000000000000000000000000000000000000..d75f302f84117ed6b68c6b3f36acb1ea9c1c5390
GIT binary patch
literal 221
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|rhB?LhFJ6_
zCrD%*;7G6i^?$xd@1ycOqdg{<5>lMRLNZn!Ty^8q4aOZZyQD;zRp!P>==94TxWF<w
zIAdkvgp#6#3&khQU2!3(`4Ll0T!Q1X2s!Hm2Oc~*^nu}33L6N_*gWxwe86Sy0`ZEP
zzaCw6ZJz_A@(#RL@AounXq-8f!*%|@|LH%z{NMj$r?kc1c0ukXO^FE%3>S7<E6>}w
RXcEwg44$rjF6*2UngE1hS1kYl

literal 0
HcmV?d00001

diff --git a/fabric-object-builder-api-v1/src/testmod/resources/fabric-object-builder-api-v1-testmod.mixins.json b/fabric-object-builder-api-v1/src/testmod/resources/fabric-object-builder-api-v1-testmod.mixins.json
new file mode 100644
index 000000000..26fe75093
--- /dev/null
+++ b/fabric-object-builder-api-v1/src/testmod/resources/fabric-object-builder-api-v1-testmod.mixins.json
@@ -0,0 +1,11 @@
+{
+  "required": true,
+  "package": "net.fabricmc.fabric.test.object.builder.mixin",
+  "compatibilityLevel": "JAVA_17",
+  "client": [
+    "BlockEntityRendererFactoriesAccessor"
+  ],
+  "injectors": {
+    "defaultRequire": 1
+  }
+}
diff --git a/fabric-object-builder-api-v1/src/testmod/resources/fabric.mod.json b/fabric-object-builder-api-v1/src/testmod/resources/fabric.mod.json
index a2093ce7b..15a089569 100644
--- a/fabric-object-builder-api-v1/src/testmod/resources/fabric.mod.json
+++ b/fabric-object-builder-api-v1/src/testmod/resources/fabric.mod.json
@@ -20,12 +20,19 @@
     "fabric-object-builder-api-v1": "*"
   },
   "description": "Test mod for fabric object builder API v1.",
+  "mixins": [
+    "fabric-object-builder-api-v1-testmod.mixins.json"
+  ],
   "entrypoints": {
     "main": [
       "net.fabricmc.fabric.test.object.builder.BlockEntityTypeBuilderTest",
       "net.fabricmc.fabric.test.object.builder.CriterionRegistryTest::init",
       "net.fabricmc.fabric.test.object.builder.VillagerTypeTest1",
-      "net.fabricmc.fabric.test.object.builder.VillagerTypeTest2"
+      "net.fabricmc.fabric.test.object.builder.VillagerTypeTest2",
+      "net.fabricmc.fabric.test.object.builder.TealSignTest"
+    ],
+    "client": [
+      "net.fabricmc.fabric.test.object.builder.client.TealSignClientTest"
     ],
     "fabric-gametest": [
       "net.fabricmc.fabric.test.object.builder.ObjectBuilderGameTest"
diff --git a/fabric-rendering-v1/build.gradle b/fabric-rendering-v1/build.gradle
index 3cbec3aae..781aef96d 100644
--- a/fabric-rendering-v1/build.gradle
+++ b/fabric-rendering-v1/build.gradle
@@ -4,3 +4,7 @@ version = getSubprojectVersion(project)
 moduleDependencies(project, [
 		'fabric-api-base'
 ])
+
+testDependencies(project, [
+		':fabric-object-builder-api-v1'
+])