Fabric entities
Complete reference for custom mob and entity creation in Fabric Minecraft 1.20.1 — entity classes, attributes, goal/AI systems, server registration, client renderer registration, spawn eggs, entity NBT, and spawn rules. Use this skill whenever the user asks about creating a custom mob, custom entity, entity AI, EntityType registration, DefaultAttributeContainer, EntityGoal, MobEntity, PathAwareEntity, renderer, EntityModelLayer, spawn egg, or entity spawn rules. Triggers on: "custom mob", "custom entity", "EntityType", "MobEntity", "PathAwareEntity", "entity AI", "entity goal", "GoalSelector", "EntityAttributes", "spawn egg", "entity renderer", "entity model", "EntityModelLayer", or "biome spawn rules". Part of the fabric-mc-modding skill family.From its SKILL.md
npx -y skills add PSB1234/Fabric-Minecraft-Skill-1.20.1 --skill fabric-entitiesAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
10.8 KB, ~2.5k tokens by cl100k_base, as published. Nobody here has run it
Fabric Entities — 1.20.1 Reference
Entity Class Hierarchy — Pick the Right Base
| Base Class | Use When |
|---|---|
Entity | Purely data/logic, not a living creature (e.g. projectile, marker) |
LivingEntity | Has health, can be damaged, but not a mob |
MobEntity | AI-controlled creature (base for all mobs) |
PathAwareEntity | Mob that navigates terrain (most mobs) |
AnimalEntity | Passive animal with breeding |
PassiveEntity | Passive, no attack |
HostileEntity | Aggressive mob |
TameableEntity | Tameable (wolf/cat pattern) |
1. Entity Class
public class MyMobEntity extends PathAwareEntity {
public MyMobEntity(EntityType<? extends MyMobEntity> type, World world) {
super(type, world);
}
// Register default attributes (health, speed, etc.)
public static DefaultAttributeContainer.Builder createAttributes() {
return MobEntity.createMobAttributes()
.add(EntityAttributes.GENERIC_MAX_HEALTH, 20.0)
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25)
.add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 3.0)
.add(EntityAttributes.GENERIC_FOLLOW_RANGE, 16.0)
.add(EntityAttributes.GENERIC_ARMOR, 2.0);
}
// Configure AI goals
@Override
protected void initGoals() {
// Targeting goals (higher priority = runs first)
this.targetSelector.add(1, new ActiveTargetGoal<>(this, PlayerEntity.class, true));
this.targetSelector.add(2, new RevengeGoal(this));
// Behavior goals
this.goalSelector.add(1, new SwimGoal(this));
this.goalSelector.add(2, new MeleeAttackGoal(this, 1.2, false));
this.goalSelector.add(3, new WanderAroundFarGoal(this, 0.8));
this.goalSelector.add(4, new LookAtEntityGoal(this, PlayerEntity.class, 8.0f));
this.goalSelector.add(5, new LookAroundGoal(this));
}
// NBT persistence
@Override
public void writeCustomDataToNbt(NbtCompound nbt) {
super.writeCustomDataToNbt(nbt);
nbt.putBoolean("my_flag", myFlag);
}
@Override
public void readCustomDataFromNbt(NbtCompound nbt) {
super.readCustomDataFromNbt(nbt);
myFlag = nbt.getBoolean("my_flag");
}
// Entity sounds
@Override protected SoundEvent getAmbientSound() { return SoundEvents.ENTITY_ZOMBIE_AMBIENT; }
@Override protected SoundEvent getHurtSound(DamageSource src) { return SoundEvents.ENTITY_ZOMBIE_HURT; }
@Override protected SoundEvent getDeathSound() { return SoundEvents.ENTITY_ZOMBIE_DEATH; }
@Override protected void playStepSound(BlockPos pos, BlockState state) {
playSound(SoundEvents.ENTITY_ZOMBIE_STEP, 0.15f, 1.0f);
}
private boolean myFlag;
}
2. Register Entity Type
public class ModEntities {
public static EntityType<MyMobEntity> MY_MOB;
public static void register() {
MY_MOB = FabricEntityTypeBuilder.createMob()
.entityFactory(MyMobEntity::new)
.defaultAttributes(MyMobEntity::createAttributes)
.spawnGroup(SpawnGroup.MONSTER) // MONSTER / CREATURE / AMBIENT / WATER_CREATURE / MISC
.dimensions(EntityDimensions.fixed(0.6f, 1.95f)) // width, height in blocks
.build();
Registry.register(Registries.ENTITY_TYPE,
new Identifier("mymod", "my_mob"), MY_MOB);
}
}
Register in onInitialize():
ModEntities.register();
// Also register default attributes:
FabricDefaultAttributeRegistry.register(ModEntities.MY_MOB, MyMobEntity.createAttributes());
3. Entity Model (client-only)
@Environment(EnvType.CLIENT)
public class MyMobModel<T extends MyMobEntity> extends EntityModel<T> {
public static final ModelLayer MODEL_LAYER =
new ModelLayer(new Identifier("mymod", "my_mob"), "main");
private final ModelPart root;
private final ModelPart head;
private final ModelPart body;
public MyMobModel(ModelPart root) {
this.root = root;
this.head = root.getChild("head");
this.body = root.getChild("body");
}
// Define the model hierarchy
public static TexturedModelData getTexturedModelData() {
ModelData data = new ModelData();
ModelPartData parts = data.getRoot();
parts.addChild("head",
ModelPartBuilder.create()
.uv(0, 0).cuboid(-4f, -8f, -4f, 8, 8, 8),
ModelTransform.pivot(0f, 0f, 0f));
parts.addChild("body",
ModelPartBuilder.create()
.uv(16, 16).cuboid(-4f, 0f, -2f, 8, 12, 4),
ModelTransform.pivot(0f, 0f, 0f));
return TexturedModelData.of(data, 64, 32);
}
@Override
public void setAngles(T entity, float limbAngle, float limbDistance,
float animationProgress, float headYaw, float headPitch) {
head.yaw = headYaw * (float)(Math.PI / 180);
head.pitch = headPitch * (float)(Math.PI / 180);
// animate limbs for walking:
body.roll = (float)Math.sin(limbAngle * 0.6662f) * limbDistance * 0.5f;
}
@Override
public void render(MatrixStack matrices, VertexConsumer vertexConsumer,
int light, int overlay, float red, float green, float blue, float alpha) {
root.render(matrices, vertexConsumer, light, overlay, red, green, blue, alpha);
}
}
4. Entity Renderer (client-only)
@Environment(EnvType.CLIENT)
public class MyMobRenderer extends MobEntityRenderer<MyMobEntity, MyMobModel<MyMobEntity>> {
private static final Identifier TEXTURE =
new Identifier("mymod", "textures/entity/my_mob.png");
public MyMobRenderer(EntityRendererFactory.Context ctx) {
super(ctx, new MyMobModel<>(ctx.getPart(MyMobModel.MODEL_LAYER)), 0.5f); // shadow radius
// Add feature renderers (e.g. armor, overlay):
// addFeature(new MyFeatureRenderer(this));
}
@Override
public Identifier getTexture(MyMobEntity entity) {
return TEXTURE;
}
}
Register in onInitializeClient():
// Register model layer
EntityModelLayerRegistry.registerModelLayer(
MyMobModel.MODEL_LAYER, MyMobModel::getTexturedModelData);
// Register entity renderer
EntityRendererRegistry.register(ModEntities.MY_MOB, MyMobRenderer::new);
5. Spawn Egg Item
// In ModItems.register():
Registry.register(Registries.ITEM,
new Identifier("mymod", "my_mob_spawn_egg"),
new SpawnEggItem(ModEntities.MY_MOB,
0x3B3B3B, // primary shell color (hex int)
0xFF5733, // secondary spot color
new FabricItemSettings())
);
Add to loot tables / creative tab as needed.
6. Natural Spawning Rules
// In onInitialize() — add spawn rules to existing biomes
BiomeModifications.addSpawn(
BiomeSelectors.foundInOverworld(),
SpawnGroup.MONSTER,
ModEntities.MY_MOB,
5, // weight (relative to other mobs)
1, // minGroupSize
3 // maxGroupSize
);
// Set spawn conditions (e.g. only on stone at night)
SpawnRestriction.register(
ModEntities.MY_MOB,
SpawnLocationTypes.ON_GROUND,
Heightmap.Type.MOTION_BLOCKING_NO_LEAVES,
MobEntity::canMobSpawn // or custom predicate
);
Custom Goal / AI
public class MyCustomGoal extends Goal {
private final MyMobEntity mob;
private int cooldown;
public MyCustomGoal(MyMobEntity mob) {
this.mob = mob;
setControls(EnumSet.of(Control.MOVE, Control.LOOK));
}
@Override
public boolean canStart() {
return mob.getTarget() != null && cooldown <= 0;
}
@Override
public void start() {
cooldown = 40;
}
@Override
public void tick() {
cooldown--;
LivingEntity target = mob.getTarget();
if (target != null) {
mob.getLookControl().lookAt(target, 30f, 30f);
// custom attack logic...
}
}
@Override
public boolean shouldContinue() {
return cooldown > 0 && mob.getTarget() != null;
}
}
Tracked Data (Synced Fields)
For data that must be visible on the client (e.g. animation state, variant):
public class MyMobEntity extends PathAwareEntity {
private static final TrackedData<Boolean> ENRAGED =
DataTracker.registerData(MyMobEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
@Override
protected void initDataTracker() {
super.initDataTracker();
dataTracker.startTracking(ENRAGED, false);
}
public boolean isEnraged() {
return dataTracker.get(ENRAGED);
}
public void setEnraged(boolean enraged) {
dataTracker.set(ENRAGED, enraged);
}
}
Common Mistakes
FabricDefaultAttributeRegistry.register()missing — causes crash on entity spawn.- Model layer not registered —
EntityModelLayerRegistry.registerModelLayer()must be called client-side before rendering. - Entity not spawning naturally — check
BiomeModifications.addSpawnis called andSpawnRestrictionallows the block/light conditions. - Spawn egg NPE — ensure the entity type is fully registered before creating the
SpawnEggItem. - Tracked data crash —
initDataTracker()must callsuperfirst and register all tracked data.
Scripts
| Script | What it does |
|---|---|
scripts/add_entity.py | Scaffold entity class, model, renderer + print registration snippets |
python scripts/add_entity.py \
--mod-id mymod --group com.example \
--entity-id crystal_golem --name "Crystal Golem" \
--base PathAwareEntity
References
| File | When to load |
|---|---|
references/ai-goals.md | Full goal class listing (movement, attack, target, look, flee, special goals), goal priority guidelines, and EntityAttributes table |
Related Skills
fabric-mc-modding— project structure, general registrationfabric-rendering— custom renderers and particle effectsfabric-mixins— hooking into existing entity logicfabric-datagen— generating lang entries, loot tables for entities
What ships with it: 2 files
15.8 KB alongside SKILL.md, 1 of them executable
references/
- ai-goals.md7.2 KB
scripts/
- add_entity.pyruns8.6 KB