Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.21.4] Reimplement EntityRenderersEvent.CreateSkullModels #1936

Open
wants to merge 4 commits into
base: 1.21.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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);
+ }
}
}
11 changes: 11 additions & 0 deletions src/main/java/net/neoforged/neoforge/client/ClientHooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -695,6 +698,13 @@ public static void loadLayerDefinitions(ImmutableMap.Builder<ModelLayerLocation,
layerDefinitions.forEach((k, v) -> builder.put(k, v.get()));
}

private static final Map<SkullBlock.Type, Function<EntityModelSet, SkullModelBase>> skullModelsByType = new HashMap<>();

@Nullable
public static SkullModelBase getModdedSkullModel(EntityModelSet modelSet, SkullBlock.Type type) {
return skullModelsByType.getOrDefault(type, set -> null).apply(modelSet);
}

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) {
Expand Down Expand Up @@ -982,6 +992,7 @@ public static void initClientHooks(Minecraft mc, ReloadableResourceManager resou
MenuScreens.init();
ModLoader.postEvent(new RegisterClientReloadListenersEvent(resourceManager));
ModLoader.postEvent(new EntityRenderersEvent.RegisterLayerDefinitions());
ModLoader.postEvent(new EntityRenderersEvent.CreateSkullModels(skullModelsByType));
ModLoader.postEvent(new EntityRenderersEvent.RegisterRenderers());
ModLoader.postEvent(new RegisterRenderStateModifiersEvent());
ClientTooltipComponentManager.init();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@

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;
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;
Expand All @@ -27,7 +28,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;
Expand Down Expand Up @@ -195,43 +195,61 @@ 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}.
*
* <p>This event is not {@linkplain ICancellableEvent cancellable}, and does not {@linkplain HasResult have a result}.</p>
* <p>This event is not {@linkplain ICancellableEvent cancellable}, and does not have a result.</p>
*
* <p>This event is fired on the mod-specific event bus,
* only on the {@linkplain LogicalSide#CLIENT logical client}.</p>
*/
public static class CreateSkullModels extends EntityRenderersEvent {
private final ImmutableMap.Builder<Type, SkullModelBase> builder;
private final EntityModelSet entityModelSet;
private final Map<SkullBlock.Type, Function<EntityModelSet, SkullModelBase>> skullModels;

@ApiStatus.Internal
public CreateSkullModels(ImmutableMap.Builder<Type, SkullModelBase> builder, EntityModelSet entityModelSet) {
this.builder = builder;
this.entityModelSet = entityModelSet;
public CreateSkullModels(Map<SkullBlock.Type, Function<EntityModelSet, SkullModelBase>> skullModels) {
this.skullModels = skullModels;
}

/**
* {@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<ModelPart, SkullModelBase> 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)
ChampionAsh5357 marked this conversation as resolved.
Show resolved Hide resolved
* register models for the same type
ChampionAsh5357 marked this conversation as resolved.
Show resolved Hide resolved
* @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<EntityModelSet, SkullModelBase> factory) {
if (type instanceof SkullBlock.Types) {
throw new IllegalArgumentException("Cannot register skull model for vanilla skull type: " + type.getSerializedName());
}
if (skullModels.putIfAbsent(type, factory) != null) {
throw new IllegalArgumentException("Factory already registered for provided skull type: " + type.getSerializedName());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -53,7 +56,7 @@ public class CustomHeadTest {
private static final DeferredRegister<BlockEntityType<?>> BLOCK_ENTITIES = DeferredRegister.create(BuiltInRegistries.BLOCK_ENTITY_TYPE, MODID);
private static final DeferredBlock<Block> BLAZE_HEAD = BLOCKS.registerBlock("blaze_head", props -> new CustomSkullBlock(SkullType.BLAZE, props), BlockBehaviour.Properties.of().strength(1.0F));
private static final DeferredBlock<Block> 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<Item> 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<Item> 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<?>, BlockEntityType<CustomSkullBlockEntity>> CUSTOM_SKULL = BLOCK_ENTITIES.register("custom_skull", () -> new BlockEntityType<>(CustomSkullBlockEntity::new, BLAZE_HEAD.get(), BLAZE_HEAD_WALL.get()));

public CustomHeadTest(IEventBus modBus) {
Expand Down Expand Up @@ -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));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"model": {
"type": "minecraft:special",
"base": "custom_head_test:item/blaze_head",
"model": {
"type": "minecraft:head",
"kind": "blaze"
}
}
}