hytale-custom-entities
Creating Custom Hytale Entities
Complete guide for defining custom entities with AI, components, spawning, and animations.
When to use this skill
Use this skill when:
- Creating new entity types (mobs, NPCs, creatures)
- Designing AI behaviors with sensors and actions
- Setting up entity spawning rules
- Adding custom entity components
- Configuring entity animations and models
- Creating interactive NPCs
Entity Architecture Overview
Hytale uses an ECS (Entity Component System) architecture:
- Entity: Container with unique ID
- Components: Data attached to entities
- Systems: Logic that processes components
Entity Hierarchy
Entity
├── LivingEntity (has health, inventory, stats)
│ ├── Player
│ └── NPCEntity (has AI role, pathfinding)
├── BlockEntity (block-attached entities)
├── ProjectileEntity
└── ItemEntity (dropped items)
Entity Asset Structure
my-plugin/
└── assets/
└── Server/
└── Content/
├── Entities/
│ └── my_creature.entity
├── Roles/
│ └── my_creature_role.role
└── Spawns/
└── my_creature_spawn.spawn
Basic Entity Definition
File: my_creature.entity
{
"DisplayName": {
"en-US": "Custom Creature"
},
"Model": "MyPlugin/Models/custom_creature",
"Health": 20,
"MovementSpeed": 1.0,
"Role": "MyPlugin:CustomCreatureRole",
"Tags": {
"Type": ["Monster", "Hostile"]
}
}
Entity Properties Reference
Core Properties
| Property | Type | Description |
|---|---|---|
DisplayName |
LocalizedString | Entity name |
Model |
String | Model asset reference |
Health |
Float | Maximum health |
Role |
String | AI role reference |
Team |
String | Team/faction ID |
Tags |
Object | Classification tags |
Physical Properties
| Property | Type | Default | Description |
|---|---|---|---|
MovementSpeed |
Float | 1.0 | Base move speed |
BoundingBox |
Object | auto | Collision box |
Mass |
Float | 1.0 | Physics mass |
Gravity |
Float | 1.0 | Gravity multiplier |
CanSwim |
Boolean | false | Can swim in water |
CanFly |
Boolean | false | Can fly |
StepHeight |
Float | 0.5 | Max step-up height |
Combat Properties
| Property | Type | Description |
|---|---|---|
AttackDamage |
Float | Base attack damage |
AttackSpeed |
Float | Attacks per second |
AttackRange |
Float | Melee attack range |
Armor |
Float | Damage reduction |
KnockbackResistance |
Float | Knockback reduction |
Visual Properties
| Property | Type | Description |
|---|---|---|
Scale |
Float | Model scale |
RenderDistance |
Float | Max render distance |
ShadowSize |
Float | Shadow radius |
GlowColor |
Color | Outline glow color |
Particles |
String | Ambient particles |
AI Role System
NPCs are controlled by Roles containing Instructions with:
- Sensors: Conditions for activation
- BodyMotion: Movement behavior
- HeadMotion: Look behavior
- Actions: Effects to execute
Basic Role Definition
File: my_creature_role.role
{
"MotionController": "Walk",
"DefaultInstruction": {
"Sensor": {
"Type": "Always"
},
"BodyMotion": {
"Type": "Wander",
"Speed": 0.5,
"Radius": 10
},
"HeadMotion": {
"Type": "Nothing"
}
},
"Instructions": [
{
"Priority": 10,
"Sensor": {
"Type": "SensorPlayer",
"Range": 15,
"Condition": "Visible"
},
"BodyMotion": {
"Type": "Pursue",
"Target": "Player",
"Speed": 1.0
},
"HeadMotion": {
"Type": "Watch",
"Target": "Player"
},
"Actions": [
{
"Type": "Attack",
"Range": 2.0,
"Damage": 5,
"Cooldown": 1.0
}
]
}
]
}
Motion Controllers
| Controller | Description |
|---|---|
Walk |
Ground-based movement |
Fly |
Aerial movement |
Dive |
Swimming movement |
Hover |
Stationary flight |
Sensor Types
| Sensor | Description | Parameters |
|---|---|---|
Always |
Always true | - |
Never |
Always false | - |
Random |
Random chance | Chance |
SensorPlayer |
Detect players | Range, Condition |
SensorEntity |
Detect entities | Range, EntityType, Tags |
SensorDamage |
When damaged | Threshold |
SensorHealth |
Health check | Below, Above |
SensorTime |
Time of day | DayTime, NightTime |
SensorNav |
Navigation state | HasPath, AtDestination |
SensorDistance |
Distance check | Target, Min, Max |
Body Motion Types
| Motion | Description | Parameters |
|---|---|---|
Wander |
Random wandering | Speed, Radius, IdleTime |
Pursue |
Chase target | Target, Speed, StopDistance |
Flee |
Run from target | Target, Speed, SafeDistance |
MoveTo |
Go to position | Position, Speed |
MoveAway |
Move away | Target, Distance |
Patrol |
Follow path | Waypoints, Speed |
Circle |
Circle target | Target, Radius, Speed |
Stay |
Don't move | - |
TakeOff |
Start flying | - |
Land |
Stop flying | - |
Teleport |
Instant move | Position |
Head Motion Types
| Motion | Description | Parameters |
|---|---|---|
Watch |
Look at target | Target |
Aim |
Aim at target | Target, Offset |
Look |
Look direction | Direction |
Nothing |
Don't control head | - |
Action Types
| Action | Description | Parameters |
|---|---|---|
Attack |
Melee attack | Damage, Range, Cooldown |
RangedAttack |
Projectile attack | Projectile, Speed, Cooldown |
ApplyEntityEffect |
Apply effect | Effect, Duration, Target |
PlaySound |
Play sound | Sound, Volume |
SpawnEntity |
Spawn entity | Entity, Count |
SetStat |
Modify stat | Stat, Value |
SetFlag |
Set flag | Flag, Value |
Notify |
Trigger event | Event, Data |
Wait |
Delay | Duration |
Complex AI Example
Aggressive mob with multiple behaviors:
{
"MotionController": "Walk",
"CombatRange": 2.0,
"AggroRange": 20,
"LeashRange": 40,
"DefaultInstruction": {
"Sensor": { "Type": "Always" },
"BodyMotion": {
"Type": "Wander",
"Speed": 0.4,
"Radius": 15,
"IdleTime": { "Min": 2, "Max": 5 }
},
"HeadMotion": { "Type": "Nothing" }
},
"Instructions": [
{
"Name": "ReturnToLeash",
"Priority": 100,
"Sensor": {
"Type": "SensorDistance",
"Target": "LeashPosition",
"Min": 40
},
"BodyMotion": {
"Type": "MoveTo",
"Target": "LeashPosition",
"Speed": 1.5
}
},
{
"Name": "AttackPlayer",
"Priority": 50,
"Sensor": {
"Type": "And",
"Sensors": [
{
"Type": "SensorPlayer",
"Range": 2.5,
"Condition": "Visible"
},
{
"Type": "SensorCooldown",
"Cooldown": "AttackCooldown",
"Ready": true
}
]
},
"BodyMotion": { "Type": "Stay" },
"HeadMotion": {
"Type": "Aim",
"Target": "Player"
},
"Actions": [
{
"Type": "Attack",
"Damage": 8,
"Animation": "attack_swing"
},
{
"Type": "SetCooldown",
"Cooldown": "AttackCooldown",
"Duration": 1.5
}
]
},
{
"Name": "ChasePlayer",
"Priority": 40,
"Sensor": {
"Type": "SensorPlayer",
"Range": 20,
"Condition": "Visible"
},
"BodyMotion": {
"Type": "Pursue",
"Target": "Player",
"Speed": 1.0,
"StopDistance": 1.5
},
"HeadMotion": {
"Type": "Watch",
"Target": "Player"
}
},
{
"Name": "FleeWhenLow",
"Priority": 60,
"Sensor": {
"Type": "And",
"Sensors": [
{ "Type": "SensorHealth", "Below": 0.25 },
{ "Type": "SensorPlayer", "Range": 15 }
]
},
"BodyMotion": {
"Type": "Flee",
"Target": "Player",
"Speed": 1.3,
"SafeDistance": 25
}
}
]
}
Entity Spawning
Define where and when entities spawn:
Spawn Point Configuration
File: my_creature_spawn.spawn
{
"Entity": "MyPlugin:CustomCreature",
"SpawnWeight": 10,
"GroupSize": { "Min": 1, "Max": 3 },
"SpawnConditions": {
"Biomes": ["Plains", "Forest"],
"TimeOfDay": {
"Start": 0.75,
"End": 0.25
},
"LightLevel": { "Max": 7 },
"MoonPhase": ["Full", "Waning"],
"Weather": ["Clear", "Cloudy"],
"Surface": true
},
"SpawnCooldown": 300,
"MaxNearby": 4,
"NearbyCheckRadius": 32
}
Spawn Beacon (Block-based spawning)
{
"Type": "Beacon",
"Entity": "MyPlugin:CustomCreature",
"SpawnRadius": 10,
"SpawnInterval": 100,
"MaxSpawns": 5,
"DespawnDistance": 64,
"RequiredBlock": "MyPlugin:SpawnerBlock"
}
Custom Entity Components
Create custom data components:
Component Definition
public class MyEntityData implements Component<EntityStore> {
public static final BuilderCodec<MyEntityData> CODEC = BuilderCodec.builder(
Codec.INT.required().fieldOf("Level"),
Codec.STRING.optionalFieldOf("CustomName", ""),
Codec.BOOL.optionalFieldOf("IsEnraged", false)
).constructor(MyEntityData::new);
private int level;
private String customName;
private boolean isEnraged;
public MyEntityData() {
this(1, "", false);
}
public MyEntityData(int level, String customName, boolean isEnraged) {
this.level = level;
this.customName = customName;
this.isEnraged = isEnraged;
}
// Getters and setters
public int getLevel() { return level; }
public void setLevel(int level) { this.level = level; }
public String getCustomName() { return customName; }
public void setCustomName(String name) { this.customName = name; }
public boolean isEnraged() { return isEnraged; }
public void setEnraged(boolean enraged) { this.isEnraged = enraged; }
}
Component Registration
@Override
protected void setup() {
ComponentType<EntityStore, MyEntityData> myDataType =
getEntityStoreRegistry().registerComponent(
MyEntityData.class,
"myPluginEntityData",
MyEntityData.CODEC
);
}
Custom Entity Systems
Process entities with matching components:
Tick System
public class EnrageSystem extends TickSystem<EntityStore> {
private ComponentAccess<EntityStore, MyEntityData> myData;
private ComponentAccess<EntityStore, HealthComponent> health;
@Override
protected void register(Store<EntityStore> store) {
myData = registerComponent(MyEntityData.class);
health = registerComponent(HealthComponent.class);
}
@Override
public void tick(
int index,
ArchetypeChunk<EntityStore> chunk,
Store<EntityStore> store,
CommandBuffer<EntityStore> buffer
) {
MyEntityData data = myData.get(chunk, index);
HealthComponent hp = health.getOptional(chunk, index);
if (hp != null && hp.getPercent() < 0.25f && !data.isEnraged()) {
data.setEnraged(true);
// Apply enrage buff
}
}
}
Event System
public class MyDamageHandler extends EntityEventSystem<EntityStore, Damage> {
private ComponentAccess<EntityStore, MyEntityData> myData;
public MyDamageHandler() {
super(Damage.class);
}
@Override
protected void register(Store<EntityStore> store) {
myData = registerComponent(MyEntityData.class);
}
@Override
public void handle(
int index,
ArchetypeChunk<EntityStore> chunk,
Store<EntityStore> store,
CommandBuffer<EntityStore> buffer,
Damage damage
) {
MyEntityData data = myData.getOptional(chunk, index);
if (data != null && data.isEnraged()) {
// Reduce damage when enraged
damage.setAmount(damage.getAmount() * 0.5f);
}
}
}
Entity Registration in Plugin
@Override
protected void setup() {
// Register components
ComponentType<EntityStore, MyEntityData> dataType =
getEntityStoreRegistry().registerComponent(
MyEntityData.class,
"myEntityData",
MyEntityData.CODEC
);
// Register systems
getEntityStoreRegistry().registerSystem(new EnrageSystem());
getEntityStoreRegistry().registerSystem(new MyDamageHandler());
// Register custom sensors
getCodecRegistry(Sensor.CODEC).register(
"MySensor", MySensor.class, MySensor.CODEC
);
// Register custom actions
getCodecRegistry(Action.CODEC).register(
"MyAction", MyAction.class, MyAction.CODEC
);
}
NPC Interactions
Create interactive NPCs:
{
"DisplayName": { "en-US": "Village Merchant" },
"Model": "MyPlugin/Models/merchant",
"Role": "MyPlugin:MerchantRole",
"IsInteractable": true,
"Interactions": {
"Use": "MyPlugin:OpenShop"
},
"DialogueTree": "MyPlugin:MerchantDialogue",
"Schedule": {
"06:00-18:00": "WorkAtShop",
"18:00-22:00": "Wander",
"22:00-06:00": "Sleep"
}
}
Complete Example: Boss Entity
{
"DisplayName": {
"en-US": "Shadow Guardian"
},
"Description": {
"en-US": "Ancient protector of the dark temple"
},
"Model": "MyPlugin/Models/shadow_guardian",
"Scale": 2.0,
"Health": 500,
"Armor": 10,
"AttackDamage": 20,
"MovementSpeed": 0.8,
"KnockbackResistance": 0.8,
"Role": "MyPlugin:ShadowGuardianRole",
"BossBar": {
"Enabled": true,
"Color": "Purple",
"Style": "Notched"
},
"Loot": "MyPlugin:ShadowGuardianLoot",
"DeathSound": "MyPlugin/Sounds/boss_death",
"AmbientSound": {
"Sound": "MyPlugin/Sounds/dark_ambient",
"Interval": 5
},
"Particles": "MyPlugin/Particles/shadow_aura",
"GlowColor": { "R": 0.5, "G": 0.0, "B": 0.8 },
"Tags": {
"Type": ["Boss", "Undead", "Hostile"]
}
}
Troubleshooting
Entity Not Spawning
- Check spawn conditions match environment
- Verify spawn weight is > 0
- Check MaxNearby limit
- Ensure biome/time conditions are met
AI Not Working
- Verify Role reference is correct
- Check sensor conditions are achievable
- Ensure instruction priorities are ordered
- Debug with
/npc debugcommand
Components Not Saving
- Ensure CODEC is defined correctly
- Register with unique string ID
- Check serialization in logs
See references/entity-components.md for built-in components.
See references/ai-sensors.md for all sensor types.
See references/ai-actions.md for all action types.
More from mnkyarts/hytale-skills
hytale-plugin-basics
Create and structure Hytale server plugins with proper lifecycle, manifest, dependencies, and registries. Use when asked to "create a Hytale plugin", "make a Hytale mod", "start a new Hytale plugin", "setup plugin structure", or "write plugin boilerplate".
21hytale-networking
Handle Hytale network packets, create custom packets, and implement client-server communication. Use when asked to "create custom packets", "handle network messages", "send data to client", "receive client data", or "implement networking".
20hytale-ui-windows
Create custom UI windows, containers, and interactive interfaces for Hytale plugins. Use when asked to "create inventory UI", "make custom window", "add container interface", "build crafting UI", "custom GUI", "create .ui file", or "design UI layout".
19hytale-crafting-recipes
Create custom crafting recipes for Hytale plugins including shaped, shapeless, processing, and blueprint recipes. Use when asked to "add crafting recipe", "create recipe", "make craftable item", "add smelting recipe", or "custom crafting".
18hytale-commands
Create custom commands for Hytale server plugins with arguments, permissions, and execution handling. Use when asked to "create a command", "add slash command", "make admin command", "register commands", or "command with arguments".
15hytale-custom-assets
Create and manage custom assets for Hytale including models, textures, sounds, particles, and asset packs. Use when asked to "add custom assets", "create textures", "make models", "add sounds", "configure particles", or "build an asset pack".
15