Skip to content
On this page
Common

EntityRenderer

top.katton.api.registrycommon/src/main/kotlin/top/katton/api/registry/EntityRenderer.kt
Registers a custom entity renderer for a script-registered entity type.

registerEntityRenderer

registerEntityRendererCommonFunction
kotlin
@ApiStatus.Experimental
@ApiStatus.Experimental fun <T : Entity> registerEntityRenderer(entityType: EntityType<T>, rendererFactory: EntityRendererProvider<T>)

Registers a custom entity renderer for a script-registered entity type.

This is the client-side counterpart to [registerNativeEntity]. After registering an entity type with [registerNativeEntity], call this on the client to give your entity a visual appearance.

The [rendererFactory] receives an [EntityRendererProvider.Context], which provides access to the entity render dispatcher, item renderer, resource manager, and entity model set — everything you need to construct a standard [EntityRenderer].

Parameters

ParameterDescription
entityTypethe entity type (obtained from [registerNativeEntity]'s return value)
rendererFactoryfactory that creates the [EntityRenderer] instance

registerEntityRenderer

registerEntityRendererCommonFunction
kotlin
@ApiStatus.Experimental
@ApiStatus.Experimental fun <T : Entity> registerEntityRenderer(entityTypeId: String, rendererFactory: EntityRendererProvider<T>)

Registers a custom entity renderer by entity type ID.

Convenience overload that resolves the [EntityType] from the built-in registry using the given [entityTypeId].

Parameters

ParameterDescription
entityTypeIdthe entity type identifier (e.g., "mymod:ghost")
rendererFactoryfactory that creates the [EntityRenderer] instance

Throws

ExceptionDescription
IllegalStateExceptionif the entity type is not registered

registerEntityModelLayer

registerEntityModelLayerCommonFunction
kotlin
@ApiStatus.Experimental
@ApiStatus.Experimental fun registerEntityModelLayer(layer: ModelLayerLocation, definition: () -> LayerDefinition)

Registers a [ModelLayerLocation] and its [LayerDefinition] for entity model rendering.

In Minecraft 1.21.11+, [net.minecraft.client.model.geom.EntityModelSet] uses an ImmutableMap internally, so model layers registered this way cannot be resolved via context.bakeLayer(). Instead, use [getBakedModelPart] to retrieve the pre-baked [ModelPart] and pass it directly to your model constructor.

Parameters

ParameterDescription
layerthe model layer location (e.g., ModelLayerLocation(id("mymod:ghost"), "main"))
definitionfactory that creates the layer definition

getBakedModelPart

getBakedModelPartCommonFunction
kotlin
@ApiStatus.Experimental
@ApiStatus.Experimental fun getBakedModelPart(layer: ModelLayerLocation): ModelPart

Returns the pre-baked [ModelPart] for a model layer registered with [registerEntityModelLayer].

Since Minecraft 1.21.11+ uses an ImmutableMap for model layers, context.bakeLayer() cannot resolve dynamically registered layers. Use this function instead to obtain the baked root directly.

KeyframeEvent

KeyframeEventCommonData Class
kotlin
data class KeyframeEvent( val animName: String, val timeSeconds: Float, val action: (entity: Mob, model: EntityModel<*>, state: LivingEntityRenderState, bakedAnims: Map<String, KeyframeAnimation>) -> Unit )

A time-stamped callback that fires at a specific point during an entity animation.

Created per-entity-type in [registerAnimatedEntityRenderer]'s [keyframeEvents] list. The callback receives the animated model, entity, render state, and pre-baked animations — use [top.katton.api.createBoneExecution] to get an ExecutionContext at a bone position.

Properties

PropertyDescription
animNamethe animation name matching a key in [registerAnimatedEntityRenderer.animations]
timeSecondstime in seconds from animation start when the callback should fire
actionthe callback (entity, model, state, baked animations)

registerAnimatedEntityRenderer

registerAnimatedEntityRendererCommonFunction
kotlin
@ApiStatus.Experimental
@ApiStatus.Experimental fun <S : LivingEntityRenderState, M : EntityModel<S>> registerAnimatedEntityRenderer(entityTypeId: String, modelLayer: ModelLayerLocation, bodyLayer: () -> LayerDefinition, modelFactory: (ModelPart) -> M, texture: Identifier, renderStateFactory: () -> S = { @Suppress("UNCHECKED_CAST") (LivingEntityRenderState() as S) }, shadowRadius: Float = 0.5f, animations: Map<String, AnimationDefinition> = emptyMap(), animate: ((M, Mob, S, Map<String, KeyframeAnimation>) -> Unit)? = null, keyframeEvents: List<KeyframeEvent> = emptyList())

Simplified entity renderer registration with animation support.

One call handles model layer, renderer construction, and animation wiring. Uses [Mob] as entity type internally to avoid ClassCastException across script reloads. Animation state is shared through [KattonBridge].

Entity side — publish animation states in tick():

kotlin
KattonBridge["anim:$id:idle"] = idleAnimationState
KattonBridge["anim:$id:walk"] = walkAnimationState

Client side — one call:

kotlin
registerAnimatedEntityRenderer<Zombie1RenderState, Zombie1Model<Zombie1RenderState>>(
entityTypeId = "test:zombie1",
modelLayer = Zombie1Model.LAYER_LOCATION,
bodyLayer = { Zombie1Model.createBodyLayer() },
modelFactory = { root -> Zombie1Model(root) },
texture = id("test", "textures/entity/zombie1.png"),
renderStateFactory = { Zombie1RenderState() },
animations = mapOf(
"idle" to Zombie1Animation.idle,
"walk" to Zombie1Animation.walkforward
)
)

Custom animation logic — pass an animate callback. It receives the model, entity, render state, and a map of pre-baked animations:

kotlin
animate = { model, entity, state, baked ->
model.resetPose()
// your custom logic...
baked["walk"]?.apply(walkAnimState, state.ageInTicks)
}

Parameters

ParameterDescription
animationsmap of name → AnimationDefinition. Default logic plays
"walk" when moving and "idle" otherwise. Animation states are read from
KattonBridge["anim:<entityId>:<name>"].