Fabric Registration Guide
Fabric Registration Guide
Section titled “Fabric Registration Guide”This guide covers all the essential registration patterns you’ll need when creating rendering mods with Fabric. Unlike Forge, Fabric uses a more direct approach to registration that’s simpler and more explicit.
Mod Initialization
Section titled “Mod Initialization”Every Fabric mod starts with initialization classes that implement the appropriate interfaces:
Main Mod Class
Section titled “Main Mod Class”// Example: Main mod class with client and server entry pointspublic class MyRenderingMod implements ModInitializer { public static final String MOD_ID = "myrenderingmod";
@Override public void onInitialize() { // Server-side initialization MyEntities.register(); MyBlockEntities.register(); MyItems.register(); // Register other mod components... }}Client-Side Initialization
Section titled “Client-Side Initialization”Rendering components must be registered on the client side:
// Example: Client entry point for renderer registrationpublic class MyRenderingModClient implements ClientModInitializer { @Override public void onInitializeClient() { // Client-side initialization MyRenderers.registerEntityRenderers(); MyRenderers.registerBlockEntityRenderers(); MyRenderers.registerModelLayers(); // Register other client components... }}Entity Registration
Section titled “Entity Registration”Step 1: Create Entity Class
Section titled “Step 1: Create Entity Class”// Example: Custom entity classpublic class CrystalEntity extends Entity { public CrystalEntity(EntityType<? extends CrystalEntity> entityType, Level level) { super(entityType, level); }
@Override public void tick() { super.tick(); // Entity logic here }
// Other entity methods...}Step 2: Register Entity Type
Section titled “Step 2: Register Entity Type”// Example: Entity registration classpublic class MyEntities { public static final EntityType<CrystalEntity> CRYSTAL = Registry.register(Registries.ENTITY_TYPE, new ResourceLocation(MyRenderingMod.MOD_ID, "crystal"), EntityType.Builder.of(CrystalEntity::new, MobCategory.MISC) .sized(0.8f, 1.6f) .clientTrackingRange(32) .build("crystal"));
public static void register() { // Registration happens in static initialization MyRenderingMod.LOGGER.info("Registering entities for " + MyRenderingMod.MOD_ID); }}Entity Renderer Registration
Section titled “Entity Renderer Registration”Step 1: Create Entity Renderer
Section titled “Step 1: Create Entity Renderer”// Example: Entity renderer implementationpublic class CrystalEntityRenderer extends EntityRenderer<CrystalEntity> { private final CrystalModel model;
public CrystalEntityRenderer(EntityRendererProvider.Context context) { super(context); this.model = new CrystalModel(context.bakeLayer(CrystalModel.LAYER_LOCATION)); }
@Override public void render(CrystalEntity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) {
poseStack.pushPose(); poseStack.translate(0.0, entity.getBbHeight() * 0.5, 0.0);
this.model.renderToBuffer(poseStack, bufferSource.getBuffer(RenderType.entityCutout(getTextureLocation(entity))), packedLight, OverlayTexture.NO_OVERLAY, 1.0f, 1.0f, 1.0f, 1.0f);
poseStack.popPose(); }
@Override public ResourceLocation getTextureLocation(CrystalEntity entity) { return new ResourceLocation(MyRenderingMod.MOD_ID, "textures/entity/crystal.png"); }}Step 2: Register Entity Renderer
Section titled “Step 2: Register Entity Renderer”// Example: Entity renderer registrationpublic class MyRenderers { public static void registerEntityRenderers() { EntityRendererRegistry.register(MyEntities.CRYSTAL, CrystalEntityRenderer::new);
// Register other entity renderers... EntityRendererRegistry.register(MyEntities.OTHER_ENTITY, OtherEntityRenderer::new); }}Block Entity Registration
Section titled “Block Entity Registration”Step 1: Create Block Entity Class
Section titled “Step 1: Create Block Entity Class”// Example: Block entity implementationpublic class EnergyCoreBlockEntity extends BlockEntity { private int energy = 0;
public EnergyCoreBlockEntity(BlockPos pos, BlockState state) { super(MyBlockEntities.ENERGY_CORE, pos, state); }
public int getEnergy() { return energy; }
public void setEnergy(int energy) { this.energy = energy; setChanged(); }
@Override public void save(CompoundTag tag) { super.save(tag); tag.putInt("Energy", energy); }
@Override public void load(CompoundTag tag) { super.load(tag); energy = tag.getInt("Energy"); }}Step 2: Register Block Entity Type
Section titled “Step 2: Register Block Entity Type”// Example: Block entity registrationpublic class MyBlockEntities { public static final BlockEntityType<EnergyCoreBlockEntity> ENERGY_CORE = Registry.register(Registries.BLOCK_ENTITY_TYPE, new ResourceLocation(MyRenderingMod.MOD_ID, "energy_core"), BlockEntityType.Builder.of(EnergyCoreBlockEntity::new, MyBlocks.ENERGY_CORE_BLOCK).build(null));
public static void register() { // Registration happens in static initialization }}Block Entity Renderer Registration
Section titled “Block Entity Renderer Registration”Step 1: Create Block Entity Renderer
Section titled “Step 1: Create Block Entity Renderer”// Example: Block entity rendererpublic class EnergyCoreRenderer implements BlockEntityRenderer<EnergyCoreBlockEntity> { private final EnergyCoreModel model;
public EnergyCoreRenderer(BlockEntityRendererProvider.Context context) { this.model = new EnergyCoreModel(context.bakeLayer(EnergyCoreModel.LAYER_LOCATION)); }
@Override public void render(EnergyCoreBlockEntity blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int light, int overlay) {
poseStack.pushPose(); poseStack.translate(0.5, 0.5, 0.5);
float energyRatio = (float) blockEntity.getEnergy() / 1000.0f; this.model.renderToBuffer(poseStack, bufferSource.getBuffer(RenderType.entityCutout(getTextureLocation(blockEntity))), light, overlay, energyRatio, energyRatio, 1.0f, 1.0f);
poseStack.popPose(); }}Step 2: Register Block Entity Renderer
Section titled “Step 2: Register Block Entity Renderer”// Example: Block entity renderer registrationpublic class MyRenderers { public static void registerBlockEntityRenderers() { BlockEntityRendererRegistry.register(MyBlockEntities.ENERGY_CORE, EnergyCoreRenderer::new);
// Register other block entity renderers... BlockEntityRendererRegistry.register(MyBlockEntities.CUSTOM_DISPLAY, CustomDisplayRenderer::new); }}Model Layer Registration
Section titled “Model Layer Registration”Step 1: Create Model Classes
Section titled “Step 1: Create Model Classes”// Example: Entity model with layer definitionpublic class CrystalModel extends EntityModel<CrystalEntity> { public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(new ResourceLocation(MyRenderingMod.MOD_ID, "crystal"), "main");
private final ModelPart crystal;
public CrystalModel(ModelPart root) { this.crystal = root.getChild("crystal"); }
public static LayerDefinition createBodyLayer() { MeshDefinition meshDefinition = new MeshDefinition(); PartDefinition partDefinition = meshDefinition.getRoot();
partDefinition.addOrReplaceChild("crystal", CubeListBuilder.create() .texOffs(0, 0) .addBox(-4.0f, -8.0f, -4.0f, 8.0f, 16.0f, 8.0f), PartPose.ZERO);
return LayerDefinition.create(meshDefinition, 32, 32); }
@Override public void renderToBuffer(PoseStack poseStack, VertexConsumer consumer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
crystal.render(poseStack, consumer, packedLight, packedOverlay, red, green, blue, alpha); }}Step 2: Register Model Layers
Section titled “Step 2: Register Model Layers”// Example: Model layer registrationpublic class MyRenderers { public static void registerModelLayers() { EntityModelLayerRegistry.registerModelLayer(CrystalModel.LAYER_LOCATION, CrystalModel::createBodyLayer); EntityModelLayerRegistry.registerModelLayer(EnergyCoreModel.LAYER_LOCATION, EnergyCoreModel::createBodyLayer); }}Event Registration
Section titled “Event Registration”Fabric uses a different event system than Forge. Here are common rendering-related events:
Client Tick Events
Section titled “Client Tick Events”// Example: Client tick event registrationpublic class ClientEventHandler { public static void registerEvents() { ClientTickEvents.END_CLIENT_TICK.register(ClientEventHandler::onClientTick); RenderTickEvent.END.register(ClientEventHandler::onRenderTickEnd); }
private static void onClientTick(MinecraftClient client) { // Client-side tick logic if (client.world != null && client.player != null) { // Update animations, effects, etc. } }
private static void onRenderTickEnd(TickEvent.RenderTickEvent event) { // End of render tick logic updateRenderEffects(event.tickDelta); }}World Render Events
Section titled “World Render Events”// Example: World render event registrationpublic class WorldRenderEventHandler { public static void registerEvents() { WorldRenderEvents.AFTER_ENTITIES.register(WorldRenderEventHandler::renderAfterEntities); }
private static void renderAfterEntities(WorldRenderContext context) { MatrixStack matrices = context.matrixStack(); Camera camera = context.camera();
matrices.push(); // Custom world rendering logic renderCustomEffects(matrices, camera); matrices.pop(); }}Resource Registration
Section titled “Resource Registration”Texture and Asset Registration
Section titled “Texture and Asset Registration”Fabric uses the standard resource loading system:
// Example: Resource loadingpublic class MyResourceManager { public static void registerResources() { // Most resources are automatically loaded from assets folder // Custom resource packs can be registered here }}Complete Registration Example
Section titled “Complete Registration Example”Here’s a complete example showing all registrations together:
{ "schemaVersion": 1, "id": "myrenderingmod", "version": "1.0.0", "name": "My Rendering Mod", "description": "Example rendering mod for Minecraft 26.1", "authors": ["YourName"], "contact": { "homepage": "https://github.com/yourname/myrenderingmod", "sources": "https://github.com/yourname/myrenderingmod" }, "license": "MIT", "icon": "assets/myrenderingmod/icon.png", "environment": "*", "entrypoints": { "main": [ "com.example.myrenderingmod.MyRenderingMod" ], "client": [ "com.example.myrenderingmod.MyRenderingModClient" ] }, "mixins": [ "myrenderingmod.mixins.json" ], "depends": { "fabricloader": ">=0.14.0", "fabric-api": "*", "minecraft": "~1.26.1", "java": ">=17" }, "suggests": { "another-mod": "*" }}// Complete main mod classpublic class MyRenderingMod implements ModInitializer { public static final String MOD_ID = "myrenderingmod"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
@Override public void onInitialize() { LOGGER.info("Initializing " + MOD_ID);
// Register all mod components MyEntities.register(); MyBlockEntities.register(); MyBlocks.register(); MyItems.register();
LOGGER.info("Finished initializing " + MOD_ID); }}// Complete client mod classpublic class MyRenderingModClient implements ClientModInitializer { @Override public void onInitializeClient() { MyRenderingMod.LOGGER.info("Initializing client side");
// Register all client-side components MyRenderers.registerEntityRenderers(); MyRenderers.registerBlockEntityRenderers(); MyRenderers.registerModelLayers();
// Register events ClientEventHandler.registerEvents(); WorldRenderEventHandler.registerEvents();
MyRenderingMod.LOGGER.info("Finished initializing client side"); }}Common Registration Pitfalls
Section titled “Common Registration Pitfalls”1. Thread Safety Issues
Section titled “1. Thread Safety Issues”// ❌ WRONG - Creating render resources in main mod initializerpublic class MyMod implements ModInitializer { @Override public void onInitialize() { // This is server-side, not safe for rendering GpuBuffer buffer = RenderSystem.getDevice().createBuffer(...); // Will crash! }}
// ✅ CORRECT - Creating render resources in client initializerpublic class MyModClient implements ClientModInitializer { @Override public void onInitializeClient() { // This is client-side, safe for rendering MyRenderers.initializeResources(); // Safe! }}2. Registration Order
Section titled “2. Registration Order”// ❌ WRONG - Trying to use entity before it's registeredpublic class MyRenderers { public static void registerEntityRenderers() { EntityRendererRegistry.register(MyEntities.ENTITY_THAT_DOESNT_EXIST_YET, MyRenderer::new); }}
// ✅ CORRECT - Ensure entities are registered firstpublic class MyModClient implements ClientModInitializer { @Override public void onInitializeClient() { MyEntities.register(); // Register entities first MyRenderers.registerEntityRenderers(); // Then register renderers }}3. Resource Location Consistency
Section titled “3. Resource Location Consistency”// ❌ WRONG - Inconsistent resource location namespublic class MyEntities { public static final EntityType<MyEntity> ENTITY = Registry.register(Registries.ENTITY_TYPE, new ResourceLocation("differentmodid", "entity_name"), // Different MOD_ID! EntityType.Builder.of(MyEntity::new, MobCategory.MISC).build());}
// ✅ CORRECT - Consistent resource location namespublic class MyEntities { public static final EntityType<MyEntity> ENTITY = Registry.register(Registries.ENTITY_TYPE, new ResourceLocation(MyRenderingMod.MOD_ID, "entity_name"), // Same MOD_ID EntityType.Builder.of(MyEntity::new, MobCategory.MISC).build());}Next Steps
Section titled “Next Steps”- First Renderer - Build your first simple entity renderer
- RenderSystem Deep Dive - Advanced RenderSystem usage
- Resource Management - Working with GPU resources
- Complete Examples - Full working examples