Custom Render Type
A render type controls how a bone behavior is rendered to clients. Every BoneBehaviorType carries an IRenderType,
which is asked to produce a BehaviorRenderer for each ActiveModel that uses the behavior. The built-in
DefaultRenderType values (ANY, NONE, MODEL) are markers that only gate which bones may use a behavior; a custom
render type lets you attach your own renderer.
Creating a render type
IRenderType is a functional interface with a single method that returns a BehaviorRenderer, or null if the behavior
should not render anything for the given model.
public class CustomRenderType implements IRenderType {
@Override
@Nullable
public BehaviorRenderer createBehaviorRenderer(ActiveModel activeModel) {
// Return null if this model should not render the behavior,
// otherwise return your renderer instance.
return new CustomRenderer(activeModel);
}
}
Because IRenderType is functional, a renderer whose constructor takes an ActiveModel can be supplied directly as a
constructor reference (this is how the built-in behaviors do it, e.g. CustomRenderer::new).
Implementing the renderer
The actual rendering work lives in a BehaviorRenderer. It extends DataIO, so load / save are already given
default no-op implementations you only override if your renderer needs persistence.
public class CustomRenderer implements BehaviorRenderer {
private final ActiveModel activeModel;
private ModelRenderer modelRenderer;
public CustomRenderer(ActiveModel activeModel) {
this.activeModel = activeModel;
}
@Override
public ModelRenderer getModelRenderer() {
return modelRenderer;
}
@Override
public void setModelRenderer(ModelRenderer renderer) {
this.modelRenderer = renderer;
}
@Override
public ActiveModel getActiveModel() {
return activeModel;
}
@Override
public void initialize() {
// Set up state once when the renderer is created
}
@Override
public void readBoneData() {
// Pull the latest transforms / values from the bone each tick
}
@Override
public void sendToClient(RenderParsers parsers) {
// Build and send packets through the supplied parsers
}
@Override
public void destroy(RenderParsers parsers) {
// Tear down / remove any spawned entities
}
}
The RenderParsers passed into sendToClient and destroy is the version-specific NMS bridge used to actually emit
packets.
Using the render type
A render type is attached to a behavior through the BoneBehaviorType.Builder. Pass your IRenderType (or a renderer
constructor reference) to renderType(...) when building the type.
BoneBehaviorType<CustomBehavior> type = BoneBehaviorType.Builder
.of(CustomBehavior::new, null, "custom")
.renderType(new CustomRenderType())
// or, equivalently, .renderType(CustomRenderer::new)
.build();
When the behavior is active on a model, Model Engine lazily calls createBehaviorRenderer(activeModel) and caches the
result; you can retrieve it via ActiveModel#getBehaviorRenderer(BoneBehaviorType). Returning null from the render
type means no renderer is created for that model.