User Tools

Site Tools


tutorial:entity

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
tutorial:entity [2025/03/31 13:02] – new Identifier -> Identifier.of slainlighttutorial:entity [2026/03/02 22:49] (current) – Mojmap and 1.21.11 cassiancc
Line 10: Line 10:
 Living Entities are Entities that have health and can deal damage.  Living Entities are Entities that have health and can deal damage. 
 There are various classes that branch off `LivingEntity` for different purposes, including: There are various classes that branch off `LivingEntity` for different purposes, including:
-  * ''HostileEntity'' for Zombies, Creepers and Skeletons +  * ''Monster'' for Zombies, Creepers and Skeletons 
-  * ''AnimalEntity'' for Sheep, Cows and Pigs +  * ''Animal'' for Sheep, Cows and Pigs 
-  * ''WaterCreatureEntity'' for things that swim +  * ''WaterAnimal'' for things that swim 
-  * ''FishEntity'' for fishies (use instead of ''WaterCreatureEntity'' for schooling behavior)+  * ''AbstractFish'' for fish (use instead of ''WaterAnimal'' for schooling behavior)
    
 What you extend depends on what your needs and goals are.  What you extend depends on what your needs and goals are. 
 As you get further down the chain, the entity logic becomes more specific and curated to certain tasks. As you get further down the chain, the entity logic becomes more specific and curated to certain tasks.
 The two generic entity classes that come after ''LivingEntity'' are: The two generic entity classes that come after ''LivingEntity'' are:
-  * ''MobEntity'' +  * ''Mob'' 
-  * ''PathAwareEntity''+  * ''PathfinderMob''
    
-''MobEntity'' has AI logic and movement controls. ''PathAwareEntity'' provides extra capabilities+''Mob'' has AI logic and movement controls. ''PathfinderMob'' provides extra capabilities
 for pathfinding favor, and various AI tasks require this to operate. for pathfinding favor, and various AI tasks require this to operate.
  
-In this tutorial, we will look at creating a cube entity that extends ''PathAwareEntity''.+In this tutorial, we will look at creating a cube entity that extends ''PathfinderMob''.
 This entity will have a model & texture. Movement and mechanics will be covered in a future tutorial. This entity will have a model & texture. Movement and mechanics will be covered in a future tutorial.
  
 ===== Creating & Registering an Entity ===== ===== Creating & Registering an Entity =====
  
-Create a class that extends ''PathAwareEntity''. This class serves as the brains and main hub for our custom entity.+Create a class that extends ''PathfinderMob''. This class serves as the brains and main hub for our custom entity.
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
 /* /*
- * Our Cube Entity extends PathAwareEntity, which extends MobEntity, which extends LivingEntity.+ * Our Cube Entity extends ''PathfinderMob'', which extends ''Mob'', which extends ''LivingEntity''.
  *  *
- * LivingEntity has health and can deal damage. + ''LivingEntity'' has health and can deal damage. 
- MobEntity has movement controls and AI capabilities. + ''Mob'' has movement controls and AI capabilities. 
- PathAwareEntity has pathfinding favor and slightly tweaked leash behavior.+ ''PathfinderMob'' has pathfinding favor and slightly tweaked leash behavior.
  */  */
-public class CubeEntity extends PathAwareEntity {+public class CubeEntity extends PathfinderMob {
  
-    public CubeEntity(EntityType<? extends PathAwareEntity> entityType, World world) { +    public CubeEntity(EntityType<? extends PathfinderMob> entityType, Level level) { 
-        super(entityType, world);+        super(entityType, level);
     }     }
 } }
Line 57: Line 57:
      * Registers our Cube Entity under the ID "entitytesting:cube".      * Registers our Cube Entity under the ID "entitytesting:cube".
      *      *
-     * The entity is registered under the SpawnGroup#CREATURE category, which is what most animals and passive/neutral mobs use.+     * The entity is registered under the MobCategory#CREATURE category, which is what most animals and passive/neutral mobs use.
      * It has a hitbox size of .75x.75, or 12 "pixels" wide (3/4ths of a block).      * It has a hitbox size of .75x.75, or 12 "pixels" wide (3/4ths of a block).
      */      */
     public static final EntityType<CubeEntity> CUBE = Registry.register(     public static final EntityType<CubeEntity> CUBE = Registry.register(
-            Registries.ENTITY_TYPE, +            BuiltInRegistries.ENTITY_TYPE, 
-            Identifier.of("entitytesting", "cube"), +            Identifier.fromNamespaceAndPath("entitytesting", "cube"), 
-            EntityType.Builder.create(CubeEntity::new, SpawnGroup.CREATURE).dimensions(0.75f, 0.75f).build("cube")+            EntityType.Builder.create(CubeEntity::new, MobCategory.CREATURE).dimensions(0.75f, 0.75f).build("cube")
     );     );
  
Line 76: Line 76:
  
 ===== Registering Entity Attributes ===== ===== Registering Entity Attributes =====
 +
 +~~REDIRECT>https://docs.fabricmc.net/develop/entities/attributes#reading-modifying-attributes~~
  
 **Attributes** define the properties of the mob: how much health does it have? How much damage does it do? Does it have any default armor points? **Attributes** define the properties of the mob: how much health does it have? How much damage does it do? Does it have any default armor points?
  
-Most vanilla entities have a static method that returns their attributes (such as ''ZombieEntity#createZombieAttributes''). +Most vanilla entities have a static method that returns their attributes (such as ''Zombie#createAttributes''). 
-Our custom entity doesn't have any unique properties, for now, so we can use ''MobEntity#createMobAttributes''.+Our custom entity doesn't have any unique properties, for now, so we can use ''Mob#createMobAttributes''.
  
 Vanilla has a ''DefaultAttributeRegistry'' class for registering these properties.  Vanilla has a ''DefaultAttributeRegistry'' class for registering these properties. 
Line 99: Line 101:
          *          *
          * In 1.15, this was done by a method override inside the entity class.          * In 1.15, this was done by a method override inside the entity class.
-         * Most vanilla entities have a static method (eg. ZombieEntity#createZombieAttributes) for initializing their attributes.+         * Most vanilla entities have a static method (eg. Zombie#createAttributes) for initializing their attributes.
          */          */
         FabricDefaultAttributeRegistry.register(CUBE, CubeEntity.createMobAttributes());         FabricDefaultAttributeRegistry.register(CUBE, CubeEntity.createMobAttributes());
Line 109: Line 111:
  
 The last requirement of an entity is a **Renderer**. Renderers define *what* the entity looks like, generally by providing a model. The last requirement of an entity is a **Renderer**. Renderers define *what* the entity looks like, generally by providing a model.
-''MobEntityRenderer'' is the best choice for MobEntities. The class has one required method override for providing a texture,+''MobRenderer'' is the best choice for MobEntities. The class has one required method override for providing a texture,
 and wants 3 parameters for the super constructor: and wants 3 parameters for the super constructor:
   * ''EntityRenderDispatcher'' instance   * ''EntityRenderDispatcher'' instance
Line 123: Line 125:
  * A renderer is used to provide an entity model, shadow size, and texture.  * A renderer is used to provide an entity model, shadow size, and texture.
  */  */
-public class CubeEntityRenderer extends MobEntityRenderer<CubeEntity, CubeEntityModel> {+public class CubeEntityRenderer extends MobRenderer<CubeEntity, CubeEntityRenderState, CubeEntityModel> {
  
-    public CubeEntityRenderer(EntityRendererFactory.Context context) { +    public CubeEntityRenderer(EntityRendererProvider.Context context) { 
-        super(context, new CubeEntityModel(context.getPart(EntityTestingClient.MODEL_CUBE_LAYER)), 0.5f);+        super(context, new CubeEntityModel(context.bakeLayer(EntityTestingClient.MODEL_CUBE_LAYER)), 0.5f);
     }     }
  
     @Override     @Override
-    public Identifier getTexture(CubeEntity entity) { + public CubeEntityRenderState createRenderState() { 
-        return Identifier.of("entitytesting", "textures/entity/cube/cube.png"); + return new CubeEntityRenderState(); 
-    }+
 + 
 + @Override 
 + public Identifier getTextureLocation(CubeEntityRenderState livingEntityRenderState) { 
 + return Identifier.fromNamespaceAndPath("entitytesting", "textures/entity/cube/cube.png"); 
 + }
 } }
 </code> </code>
  
-To register this renderer, use ''EntityRendererRegistry'' in a **client initializer**:+To register this renderer, use ''EntityRenderers'' in a **client initializer**:
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-@Environment(EnvType.CLIENT) 
 public class EntityTestingClient implements ClientModInitializer { public class EntityTestingClient implements ClientModInitializer {
-    public static final EntityModelLayer MODEL_CUBE_LAYER = new EntityModelLayer(Identifier.of("entitytesting", "cube"), "main");+    public static final ModelLayerLocation MODEL_CUBE_LAYER = new ModelLayerLocation(Identifier.fromNamespaceAndPath("entitytesting", "cube"), "main");
     @Override     @Override
     public void onInitializeClient() {     public void onInitializeClient() {
Line 148: Line 154:
          * Entity Renderers can also manipulate the model before it renders based on entity context (EndermanEntityRenderer#render).          * Entity Renderers can also manipulate the model before it renders based on entity context (EndermanEntityRenderer#render).
          */          */
-        EntityRendererRegistry.INSTANCE.register(EntityTesting.CUBE, (context) -> { +        EntityRenderers.register(EntityTesting.CUBE, (context) -> {
-            return new CubeEntityRenderer(context); +
-        }); +
-        // In 1.17, use EntityRendererRegistry.register (seen below) instead of EntityRendererRegistry.INSTANCE.register (seen above) +
-        EntityRendererRegistry.register(EntityTesting.CUBE, (context) -> {+
             return new CubeEntityRenderer(context);             return new CubeEntityRenderer(context);
         });         });
Line 158: Line 160:
         EntityModelLayerRegistry.registerModelLayer(MODEL_CUBE_LAYER, CubeEntityModel::getTexturedModelData);         EntityModelLayerRegistry.registerModelLayer(MODEL_CUBE_LAYER, CubeEntityModel::getTexturedModelData);
     }     }
 +}
 +</code>
 +
 +===== Creating a Render State =====
 +
 +The render state is a class that can be used to store data for the renderer. It is passed into the renderer and model, and can be used to store data about the entity, like the entity's variant or other properties that affect rendering.
 +<code java [enable_line_numbers="true"]>
 +
 +public class CubeEntityRenderState extends EntityRenderState {
 +    // You can add fields here to store data for the renderer and model.
 } }
 </code> </code>
Line 171: Line 183:
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-public class CubeEntityModel extends EntityModel<CubeEntity> {+public class CubeEntityModel extends EntityModel<CubeEntityRenderState> {
  
     private final ModelPart base;     private final ModelPart base;
  
     public CubeEntityModel(ModelPart modelPart) {     public CubeEntityModel(ModelPart modelPart) {
-        this.base = modelPart.getChild(EntityModelPartNames.CUBE);+        this.base = modelPart.getChild(PartNames.CUBE);
     }     }
          
Line 189: Line 201:
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-public class CubeEntityModel extends EntityModel<CubeEntity> {+public class CubeEntityModel extends EntityModel<CubeEntityRenderState> {
  
     private final ModelPart base;     private final ModelPart base;
Line 198: Line 210:
          
     // You can use BlockBench, make your model and export it to get this method for your entity model.     // You can use BlockBench, make your model and export it to get this method for your entity model.
-    public static TexturedModelData getTexturedModelData() { + public static LayerDefinition getTexturedModelData() { 
-        ModelData modelData = new ModelData(); + MeshDefinition modelData = new MeshDefinition(); 
-     ModelPartData modelPartData = modelData.getRoot(); + PartDefinition modelPartData = modelData.getRoot(); 
-        modelPartData.addChild(EntityModelPartNames.CUBE, ModelPartBuilder.create().uv(0, 0).cuboid(-6F, 12F, -6F, 12F, 12F, 12F), ModelTransform.pivot(0F, 0F, 0F)); + modelPartData.addOrReplaceChild(PartNames.CUBE, CubeListBuilder.create().texOffs(0, 0).addBox(-6F, 12F, -6F, 12F, 12F, 12F), PartPose.rotation(0F, 0F, 0F)); 
-        return TexturedModelData.of(modelData, 64, 64); + return LayerDefinition.create(modelData, 64, 64); 
-    }+ }
 </code> </code>
  
 Our entity model now has a single cube that is 12x12x12 wide (75% of a block) centered around 0, 0, 0. Our entity model now has a single cube that is 12x12x12 wide (75% of a block) centered around 0, 0, 0.
-''setAngles'' is used for animating the model, but we will keep it empty for now.  +''setupAnim'' is used for animating the model, but we will keep it empty for now.
-''render'' is where we tell our cube to show up. Note that standard vanilla models appear //higher// +
-than the entity hitbox, so we translate the model down to account for this+
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-public class CubeEntityModel extends EntityModel<CubeEntity> {+public class CubeEntityModel extends EntityModel<CubeEntityRenderState> {
          
     private final ModelPart base;     private final ModelPart base;
Line 218: Line 228:
     public CubeEntityModel() [...]     public CubeEntityModel() [...]
          
-    public static TexturedModelData getTexturedModelData() [...]+    public static LayerDefinition getTexturedModelData() [...]
  
     @Override     @Override
-    public void setAngles(CubeEntity entity, float limbAngle, float limbDistance, float animationProgress, float headYaw, float headPitch) { +    public void setupAnim(CubeEntityRenderState entity) {
-    } +
- +
-    @Override +
-    public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha) { +
-        ImmutableList.of(this.base).forEach((modelRenderer) -> { +
-            modelRenderer.render(matrices, vertices, light, overlay, red, green, blue, alpha); +
-        });+
     }     }
 } }
 </code> </code>
  
-To complete our model, we need to add a texture file. The default texture size is 64 wide and 32 tall; +To complete our model, we need to add a texture file. The default texture size is 64 pixels wide and 32 pixels tall; 
-you can change this by adding a return of your texturedModelData+you can change this by adding a return of your LayerDefinition with a custom width and height.
 We will set it to 64x64 for our texture: We will set it to 64x64 for our texture:
  
Line 240: Line 243:
    
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-public class CubeEntityModel extends EntityModel<CubeEntity> {+public class CubeEntityModel extends EntityModel<CubeEntityRenderState> {
  
     private final ModelPart base;     private final ModelPart base;
Line 246: Line 249:
     [...]     [...]
          
-    public static TexturedModelData getTexturedModelData() {+    public static LayerDefinition getTexturedModelData() {
         [...]         [...]
-        return TexturedModelData.of(modelData, 64, 64);+        return LayerDefinition.create(modelData, 64, 64);
     }     }
  
Line 273: Line 276:
 {{https://i.imgur.com/MmQvluB.png}} {{https://i.imgur.com/MmQvluB.png}}
  
-**NOTE:** If your entity does not extend ''LivingEntity'' you have to create your own spawn packet handler. Either do this through the networking API, or mixin to ''ClientPlayNetworkHandler#onEntitySpawn''+**NOTE:** If your entity does not extend ''LivingEntity'' you have to create your own spawn packet handler. Either do this through the networking API, or mixin to ''ClientPacketListener#handleAddEntity''
 ===== Adding tasks & activities ===== ===== Adding tasks & activities =====
  
 To add activities see [[tutorial:villager_activities|here]]. To add activities see [[tutorial:villager_activities|here]].
  
tutorial/entity.txt · Last modified: 2026/03/02 22:49 by cassiancc