From 5f095d7543eb314cd9ce96f4efef4a4f69e6bdd6 Mon Sep 17 00:00:00 2001 From: ChampionAsh5357 Date: Mon, 3 Feb 2025 14:07:40 -0500 Subject: [PATCH 1/5] fix(neoforge): Reimplement EntityRenderersEvent.CreateSkullModels --- .../blockentity/SkullBlockRenderer.java.patch | 16 +++++- .../neoforge/client/ClientHooks.java | 19 ++++++- .../client/event/EntityRenderersEvent.java | 57 ++++++++++++------- .../oldtest/block/CustomHeadTest.java | 12 +++- .../custom_head_test/items/blaze_head.json | 10 ++++ 5 files changed, 88 insertions(+), 26 deletions(-) create mode 100644 tests/src/main/resources/assets/custom_head_test/items/blaze_head.json diff --git a/patches/net/minecraft/client/renderer/blockentity/SkullBlockRenderer.java.patch b/patches/net/minecraft/client/renderer/blockentity/SkullBlockRenderer.java.patch index 2d8d0090603..6e9c950aae6 100644 --- a/patches/net/minecraft/client/renderer/blockentity/SkullBlockRenderer.java.patch +++ b/patches/net/minecraft/client/renderer/blockentity/SkullBlockRenderer.java.patch @@ -1,9 +1,19 @@ --- a/net/minecraft/client/renderer/blockentity/SkullBlockRenderer.java +++ b/net/minecraft/client/renderer/blockentity/SkullBlockRenderer.java -@@ -115,4 +_,14 @@ +@@ -57,7 +_,7 @@ + case PIGLIN -> new PiglinHeadModel(p_387840_.bakeLayer(ModelLayers.PIGLIN_HEAD)); + }); + } else { +- return null; ++ return net.neoforged.neoforge.client.ClientHooks.getModdedSkullModel(p_387840_, p_388801_); // Neo: Lookup model for modded skull types + } + } + +@@ -114,5 +_,15 @@ + p_389624_ != null ? p_389624_ : Minecraft.getInstance().getSkinManager().getInsecureSkin(p_389483_.gameProfile()).texture() ) : RenderType.entityCutoutNoCullZOffset(p_389624_ != null ? p_389624_ : SKIN_BY_TYPE.get(p_389566_)); - } ++ } + + @Override + public net.minecraft.world.phys.AABB getRenderBoundingBox(SkullBlockEntity blockEntity) { @@ -13,5 +23,5 @@ + return new net.minecraft.world.phys.AABB(pos.getX() - .75, pos.getY() - .35, pos.getZ() - .75, pos.getX() + 1.75, pos.getY() + 1.0, pos.getZ() + 1.75); + } + return BlockEntityRenderer.super.getRenderBoundingBox(blockEntity); -+ } + } } diff --git a/src/main/java/net/neoforged/neoforge/client/ClientHooks.java b/src/main/java/net/neoforged/neoforge/client/ClientHooks.java index 40d8b2c25e4..46e76692e4b 100644 --- a/src/main/java/net/neoforged/neoforge/client/ClientHooks.java +++ b/src/main/java/net/neoforged/neoforge/client/ClientHooks.java @@ -53,6 +53,8 @@ import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipPositioner; import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.SkullModelBase; +import net.minecraft.client.model.geom.EntityModelSet; import net.minecraft.client.model.geom.ModelLayerLocation; import net.minecraft.client.model.geom.builders.LayerDefinition; import net.minecraft.client.multiplayer.ClientLevel; @@ -124,6 +126,7 @@ import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SkullBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.FluidState; @@ -685,7 +688,7 @@ public static boolean shouldRenderEffect(MobEffectInstance effectInstance) { return IClientMobEffectExtensions.of(effectInstance).isVisibleInInventory(effectInstance); } - private static final Map> layerDefinitions = new HashMap<>(); + private static Map> layerDefinitions = new HashMap<>(); public static void registerLayerDefinition(ModelLayerLocation layerLocation, Supplier supplier) { layerDefinitions.put(layerLocation, supplier); @@ -695,6 +698,19 @@ public static void loadLayerDefinitions(ImmutableMap.Builder builder.put(k, v.get())); } + private static Map> skullModelsByType = null; + + @Nullable + public static SkullModelBase getModdedSkullModel(EntityModelSet modelSet, SkullBlock.Type type) { + return skullModelsByType.getOrDefault(type, set -> null).apply(modelSet); + } + + public static void registerModdedSkullModels() { + ImmutableMap.Builder> builder = ImmutableMap.builder(); + ModLoader.postEvent(new EntityRenderersEvent.CreateSkullModels(builder)); + skullModelsByType = builder.build(); + } + private static final ResourceLocation ICON_SHEET = ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "textures/gui/icons.png"); public static void firePlayerLogin(MultiPlayerGameMode pc, LocalPlayer player, Connection networkManager) { @@ -982,6 +998,7 @@ public static void initClientHooks(Minecraft mc, ReloadableResourceManager resou MenuScreens.init(); ModLoader.postEvent(new RegisterClientReloadListenersEvent(resourceManager)); ModLoader.postEvent(new EntityRenderersEvent.RegisterLayerDefinitions()); + registerModdedSkullModels(); ModLoader.postEvent(new EntityRenderersEvent.RegisterRenderers()); ModLoader.postEvent(new RegisterRenderStateModifiersEvent()); ClientTooltipComponentManager.init(); diff --git a/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java b/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java index fc2d26c7ac9..8ce064982f3 100644 --- a/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java +++ b/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java @@ -8,12 +8,14 @@ import com.google.common.collect.ImmutableMap; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.function.Supplier; import net.minecraft.client.model.SkullModel; import net.minecraft.client.model.SkullModelBase; import net.minecraft.client.model.geom.EntityModelSet; import net.minecraft.client.model.geom.ModelLayerLocation; import net.minecraft.client.model.geom.ModelLayers; +import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.model.geom.builders.LayerDefinition; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; @@ -27,7 +29,6 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.SkullBlock; -import net.minecraft.world.level.block.SkullBlock.Type; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.neoforged.bus.api.Event; @@ -195,43 +196,59 @@ public EntityRendererProvider.Context getContext() { } /** - * Fired for registering additional {@linkplain net.minecraft.client.model.SkullModelBase skull models} at the appropriate time. + * Fired for registering additional {@linkplain net.minecraft.client.model.SkullModelBase skull models}. * - *

This event is not {@linkplain ICancellableEvent cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain ICancellableEvent cancellable}, and does not have a result.

* *

This event is fired on the mod-specific event bus, * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public static class CreateSkullModels extends EntityRenderersEvent { - private final ImmutableMap.Builder builder; - private final EntityModelSet entityModelSet; + private final ImmutableMap.Builder> builder; @ApiStatus.Internal - public CreateSkullModels(ImmutableMap.Builder builder, EntityModelSet entityModelSet) { + public CreateSkullModels(ImmutableMap.Builder> builder) { this.builder = builder; - this.entityModelSet = entityModelSet; } /** - * {@return the set of entity models} + * Registers a {@link SkullModel} for a skull block with the given {@link SkullBlock.Type}. + * + * @param type a unique skull type; an exception will be thrown later if multiple mods (including vanilla) + * register models for the same type + * @param layerLocation the key that identifies the {@link LayerDefinition} used by the model + */ + public void registerSkullModel(SkullBlock.Type type, ModelLayerLocation layerLocation) { + this.registerSkullModel(type, layerLocation, SkullModel::new); + } + + /** + * Registers the entity model for a skull block with the given {@link SkullBlock.Type}. + * + * @param type a unique skull type; an exception will be thrown later if multiple mods (including vanilla) + * register models for the same type + * @param layerLocation the key that identifies the {@link LayerDefinition} used by the model + * @param factory the factory to create the skull model instance, taking in the root {@link ModelPart} and + * returning the model. */ - public EntityModelSet getEntityModelSet() { - return entityModelSet; + public void registerSkullModel(SkullBlock.Type type, ModelLayerLocation layerLocation, Function factory) { + this.registerSkullModel(type, modelSet -> factory.apply(modelSet.bakeLayer(layerLocation))); } /** - * Registers the constructor for a skull block with the given {@link SkullBlock.Type}. - * These will be inserted into the maps used by the item, entity, and block model renderers at the appropriate - * time. + * Registers the entity model for a skull block with the given {@link SkullBlock.Type}. * - * @param type a unique skull type; an exception will be thrown later if multiple mods (including vanilla) - * register models for the same type - * @param model the skull model instance. A typical implementation will simply bake a model using - * {@link EntityModelSet#bakeLayer(ModelLayerLocation)} and pass it to the constructor for - * {@link SkullModel}. + * @param type a unique skull type; an exception will be thrown later if multiple mods (including vanilla) + * register models for the same type + * @param factory the factory to create the skull model instance. A typical implementation will simply bake + * a model using {@link EntityModelSet#bakeLayer(ModelLayerLocation)} and pass it to the + * constructor for {@link SkullModel} */ - public void registerSkullModel(SkullBlock.Type type, SkullModelBase model) { - builder.put(type, model); + public void registerSkullModel(SkullBlock.Type type, Function factory) { + if (type instanceof SkullBlock.Types) { + throw new IllegalArgumentException("Cannot register skull model for vanilla skull type: " + type.getSerializedName()); + } + builder.put(type, factory); } } } diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/block/CustomHeadTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/block/CustomHeadTest.java index 7c4f41299c4..c6ae6c79df7 100644 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/block/CustomHeadTest.java +++ b/tests/src/main/java/net/neoforged/neoforge/oldtest/block/CustomHeadTest.java @@ -8,10 +8,12 @@ import net.minecraft.client.model.SkullModel; import net.minecraft.client.model.geom.ModelLayerLocation; import net.minecraft.client.renderer.blockentity.SkullBlockRenderer; +import net.minecraft.client.renderer.special.SkullSpecialRenderer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.Item; import net.minecraft.world.item.Rarity; @@ -32,6 +34,7 @@ import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import net.neoforged.neoforge.client.event.EntityRenderersEvent; +import net.neoforged.neoforge.client.event.RegisterSpecialBlockModelRendererEvent; import net.neoforged.neoforge.common.util.Lazy; import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; import net.neoforged.neoforge.registries.DeferredBlock; @@ -53,7 +56,7 @@ public class CustomHeadTest { private static final DeferredRegister> BLOCK_ENTITIES = DeferredRegister.create(BuiltInRegistries.BLOCK_ENTITY_TYPE, MODID); private static final DeferredBlock BLAZE_HEAD = BLOCKS.registerBlock("blaze_head", props -> new CustomSkullBlock(SkullType.BLAZE, props), BlockBehaviour.Properties.of().strength(1.0F)); private static final DeferredBlock BLAZE_HEAD_WALL = BLOCKS.registerBlock("blaze_wall_head", props -> new CustomWallSkullBlock(SkullType.BLAZE, props.strength(1.0F).overrideLootTable(BLAZE_HEAD.get().getLootTable())), BlockBehaviour.Properties.of()); - private static final DeferredItem BLAZE_HEAD_ITEM = ITEMS.registerItem("blaze_head", props -> new StandingAndWallBlockItem(BLAZE_HEAD.get(), BLAZE_HEAD_WALL.get(), Direction.DOWN, props.rarity(Rarity.UNCOMMON))); + private static final DeferredItem BLAZE_HEAD_ITEM = ITEMS.registerItem("blaze_head", props -> new StandingAndWallBlockItem(BLAZE_HEAD.get(), BLAZE_HEAD_WALL.get(), Direction.DOWN, props.rarity(Rarity.UNCOMMON).equippableUnswappable(EquipmentSlot.HEAD))); private static final DeferredHolder, BlockEntityType> CUSTOM_SKULL = BLOCK_ENTITIES.register("custom_skull", () -> new BlockEntityType<>(CustomSkullBlockEntity::new, BLAZE_HEAD.get(), BLAZE_HEAD_WALL.get())); public CustomHeadTest(IEventBus modBus) { @@ -135,7 +138,12 @@ static void clientSetupEvent(FMLClientSetupEvent event) { @SubscribeEvent static void registerSkullModel(EntityRenderersEvent.CreateSkullModels event) { - event.registerSkullModel(SkullType.BLAZE, new SkullModel(event.getEntityModelSet().bakeLayer(ClientEvents.BLAZE_HEAD_LAYER))); + event.registerSkullModel(SkullType.BLAZE, ClientEvents.BLAZE_HEAD_LAYER); + } + + @SubscribeEvent + static void registerSpecialBlockRenderer(RegisterSpecialBlockModelRendererEvent event) { + event.register(BLAZE_HEAD.get(), new SkullSpecialRenderer.Unbaked(SkullType.BLAZE)); } } } diff --git a/tests/src/main/resources/assets/custom_head_test/items/blaze_head.json b/tests/src/main/resources/assets/custom_head_test/items/blaze_head.json new file mode 100644 index 00000000000..2c01f4dbc75 --- /dev/null +++ b/tests/src/main/resources/assets/custom_head_test/items/blaze_head.json @@ -0,0 +1,10 @@ +{ + "model": { + "type": "minecraft:special", + "base": "custom_head_test:item/blaze_head", + "model": { + "type": "minecraft:head", + "kind": "blaze" + } + } +} \ No newline at end of file From 82d158cfbd809fd1696776732b110d855621523f Mon Sep 17 00:00:00 2001 From: ChampionAsh5357 Date: Mon, 3 Feb 2025 14:10:59 -0500 Subject: [PATCH 2/5] chore(neoforge): Make register method private --- src/main/java/net/neoforged/neoforge/client/ClientHooks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/neoforged/neoforge/client/ClientHooks.java b/src/main/java/net/neoforged/neoforge/client/ClientHooks.java index 46e76692e4b..f7d59da318d 100644 --- a/src/main/java/net/neoforged/neoforge/client/ClientHooks.java +++ b/src/main/java/net/neoforged/neoforge/client/ClientHooks.java @@ -705,7 +705,7 @@ public static SkullModelBase getModdedSkullModel(EntityModelSet modelSet, SkullB return skullModelsByType.getOrDefault(type, set -> null).apply(modelSet); } - public static void registerModdedSkullModels() { + private static void registerModdedSkullModels() { ImmutableMap.Builder> builder = ImmutableMap.builder(); ModLoader.postEvent(new EntityRenderersEvent.CreateSkullModels(builder)); skullModelsByType = builder.build(); From 866c46b61a7f6932d218fe6f87a643d8591febe8 Mon Sep 17 00:00:00 2001 From: ChampionAsh5357 Date: Tue, 4 Feb 2025 14:23:44 -0500 Subject: [PATCH 3/5] fix(neoforge): Use map instead of builder and revert layer def changes --- .../net/neoforged/neoforge/client/ClientHooks.java | 12 +++--------- .../neoforge/client/event/EntityRenderersEvent.java | 11 ++++++----- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/client/ClientHooks.java b/src/main/java/net/neoforged/neoforge/client/ClientHooks.java index f7d59da318d..b19889061fe 100644 --- a/src/main/java/net/neoforged/neoforge/client/ClientHooks.java +++ b/src/main/java/net/neoforged/neoforge/client/ClientHooks.java @@ -688,7 +688,7 @@ public static boolean shouldRenderEffect(MobEffectInstance effectInstance) { return IClientMobEffectExtensions.of(effectInstance).isVisibleInInventory(effectInstance); } - private static Map> layerDefinitions = new HashMap<>(); + private static final Map> layerDefinitions = new HashMap<>(); public static void registerLayerDefinition(ModelLayerLocation layerLocation, Supplier supplier) { layerDefinitions.put(layerLocation, supplier); @@ -698,19 +698,13 @@ public static void loadLayerDefinitions(ImmutableMap.Builder builder.put(k, v.get())); } - private static Map> skullModelsByType = null; + private static final Map> skullModelsByType = new HashMap<>(); @Nullable public static SkullModelBase getModdedSkullModel(EntityModelSet modelSet, SkullBlock.Type type) { return skullModelsByType.getOrDefault(type, set -> null).apply(modelSet); } - private static void registerModdedSkullModels() { - ImmutableMap.Builder> builder = ImmutableMap.builder(); - ModLoader.postEvent(new EntityRenderersEvent.CreateSkullModels(builder)); - skullModelsByType = builder.build(); - } - private static final ResourceLocation ICON_SHEET = ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "textures/gui/icons.png"); public static void firePlayerLogin(MultiPlayerGameMode pc, LocalPlayer player, Connection networkManager) { @@ -998,7 +992,7 @@ public static void initClientHooks(Minecraft mc, ReloadableResourceManager resou MenuScreens.init(); ModLoader.postEvent(new RegisterClientReloadListenersEvent(resourceManager)); ModLoader.postEvent(new EntityRenderersEvent.RegisterLayerDefinitions()); - registerModdedSkullModels(); + ModLoader.postEvent(new EntityRenderersEvent.CreateSkullModels(skullModelsByType)); ModLoader.postEvent(new EntityRenderersEvent.RegisterRenderers()); ModLoader.postEvent(new RegisterRenderStateModifiersEvent()); ClientTooltipComponentManager.init(); diff --git a/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java b/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java index 8ce064982f3..096ffd0f308 100644 --- a/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java +++ b/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java @@ -5,7 +5,6 @@ package net.neoforged.neoforge.client.event; -import com.google.common.collect.ImmutableMap; import java.util.Map; import java.util.Set; import java.util.function.Function; @@ -204,11 +203,11 @@ public EntityRendererProvider.Context getContext() { * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public static class CreateSkullModels extends EntityRenderersEvent { - private final ImmutableMap.Builder> builder; + private final Map> skullModels; @ApiStatus.Internal - public CreateSkullModels(ImmutableMap.Builder> builder) { - this.builder = builder; + public CreateSkullModels(Map> skullModels) { + this.skullModels = skullModels; } /** @@ -248,7 +247,9 @@ public void registerSkullModel(SkullBlock.Type type, Function Date: Tue, 4 Feb 2025 17:09:08 -0500 Subject: [PATCH 4/5] fix(neoforge): Add xfact's suggestion Co-authored-by: Dennis C --- .../neoforged/neoforge/client/event/EntityRenderersEvent.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java b/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java index 096ffd0f308..c64181dda3e 100644 --- a/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java +++ b/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java @@ -237,8 +237,8 @@ public void registerSkullModel(SkullBlock.Type type, ModelLayerLocation layerLoc /** * Registers the entity model for a skull block with the given {@link SkullBlock.Type}. * - * @param type a unique skull type; an exception will be thrown later if multiple mods (including vanilla) - * register models for the same type + * @param type a unique skull type; an exception will be thrown if multiple mods register models for + * the same type or a mod tries to register a model for a vanilla type * @param factory the factory to create the skull model instance. A typical implementation will simply bake * a model using {@link EntityModelSet#bakeLayer(ModelLayerLocation)} and pass it to the * constructor for {@link SkullModel} From 3fc6e30239f00c216dc2efb74d141699185c90a9 Mon Sep 17 00:00:00 2001 From: ChampionAsh5357 Date: Wed, 5 Feb 2025 16:26:26 -0500 Subject: [PATCH 5/5] fix(neoforge): Update the other two messages Co-authored-by: Dennis C --- .../neoforge/client/event/EntityRenderersEvent.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java b/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java index c64181dda3e..d71fa9cf0d5 100644 --- a/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java +++ b/src/main/java/net/neoforged/neoforge/client/event/EntityRenderersEvent.java @@ -213,8 +213,8 @@ public CreateSkullModels(Map