Skip to content

NPC System Overview

The NPC (Non-Player Character) System manages AI-controlled entities in Hytale. It uses a sophisticated role-based behavior system with support for flocking, spawning, and complex decision making.

  • NPC entities: com.hypixel.hytale.server.npc
  • Flock system: com.hypixel.hytale.server.flock
  • Role system: com.hypixel.hytale.server.npc.role
  • Blackboard: com.hypixel.hytale.server.npc.blackboard
┌─────────────────────────────────────────────────────────────┐
│ NPC System │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ NPCEntity ││
│ │ ┌─────────┐ ┌─────────┐ ┌─────────────┐ ┌───────────┐ ││
│ │ │ Role │ │Blackboard│ │ PathManager │ │DamageData │ ││
│ │ └─────────┘ └─────────┘ └─────────────┘ └───────────┘ ││
│ └─────────────────────────────────────────────────────────┘│
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Flock System ││
│ │ ┌─────────┐ ┌─────────────┐ ┌─────────────────────┐ ││
│ │ │ Flock │ │FlockMembership│ │FlockPlugin │ ││
│ │ └─────────┘ └─────────────┘ └─────────────────────┘ ││
│ └─────────────────────────────────────────────────────────┘│
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Spawning System ││
│ │ ┌────────────┐ ┌────────────┐ ┌────────────────────┐ ││
│ │ │SpawnBeacon │ │SpawnMarker │ │SpawnController │ ││
│ │ └────────────┘ └────────────┘ └────────────────────┘ ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘

NPCEntity extends LivingEntity and is the base class for AI-controlled characters.

public class NPCEntity extends LivingEntity implements INonPlayerCharacter {
// Role management
public Role getRole();
// Position tracking
public Vector3d getLeashPoint(); // Spawn anchor point
public float getLeashHeading();
public float getLeashPitch();
// Spawning
public Instant getSpawnInstant();
public String getSpawnConfigurationName();
// Pathing
public PathManager getPathManager();
// Events
public AlarmStore getAlarmStore();
public DamageData getDamageData();
}
ComponentType<EntityStore, NPCEntity> npcType = NPCEntity.getComponentType();
// Query for NPCs
Query<EntityStore> query = npcType;

Roles define NPC behavior, stats, and AI decision making.

public class Role implements IAnnotatedComponentCollection {
// Support objects
CombatSupport combatSupport; // Combat behavior
StateSupport stateSupport; // State machine
MarkedEntitySupport markedEntitySupport; // Target tracking
WorldSupport worldSupport; // World interaction
EntitySupport entitySupport; // Entity queries
PositionCache positionCache; // Position caching
DebugSupport debugSupport; // Debug features
// Stats
int initialMaxHealth;
double knockbackScale;
double inertia;
boolean invulnerable;
// Movement
Map<String, MotionController> motionControllers;
MotionController activeMotionController;
Steering bodySteering;
Steering headSteering;
// Behavior
Instruction rootInstruction;
Instruction interactionInstruction;
Instruction deathInstruction;
// Spawning
String[] flockSpawnTypes;
String[] flockAllowedRoles;
boolean canLeadFlock;
// Lifecycle
void loaded();
void unloaded();
void removed();
}
PropertyTypeDescription
maxHealthintMaximum health points
knockbackScaledoubleKnockback force multiplier
inertiadoubleMovement inertia
invulnerableboolCannot take damage
deathAnimationTimedoubleDeath animation duration
despawnAnimationTimefloatDespawn animation duration
dropListIdstringLoot drop list
balanceAssetstringBalance configuration
hotbarItemsstring[]Starting hotbar items
offHandItemsstring[]Starting offhand items
armorstring[]Starting armor

Motion controllers handle NPC movement patterns:

// Built-in motion controllers
BodyMotionWander // Random wandering
BodyMotionMaintainDistance // Keep distance from target
BodyMotionFindWithTarget // Pathfind to target
BodyMotionMatchLook // Match look direction
BodyMotionFlock // Flock movement
BodyMotionTeleport // Teleportation

The Blackboard is shared memory for NPC decision making.

ViewDescription
BlockTypeViewTrack block type changes
BlockEventViewTrack block events
EntityEventViewTrack entity events
public enum BlockEventType {
PLACED,
REMOVED,
INTERACTED
}
public enum EntityEventType {
SPAWNED,
DESPAWNED,
DAMAGED,
KILLED
}

Flocks group NPCs for coordinated behavior.

public class Flock implements Component<EntityStore> {
// Flock data
PersistentFlockData getFlockData();
// Damage tracking
DamageData getDamageData();
DamageData getLeaderDamageData();
// Status
FlockRemovedStatus getRemovedStatus();
}
public class FlockMembership implements Component<EntityStore> {
UUID getFlockId();
void setFlockId(UUID flockId);
Ref<EntityStore> getFlockRef();
void setFlockRef(Ref<EntityStore> flockRef);
Type getMembershipType();
void setMembershipType(Type membershipType);
}
ValueActs as LeaderDescription
JOININGNoJoining a flock
MEMBERNoRegular flock member
LEADERYesFlock leader
INTERIM_LEADERYesTemporary leader
public enum FlockRemovedStatus {
NOT_REMOVED,
DISSOLVED,
UNLOADED
}
{
"Id": "MyPlugin_WolfPack",
"MinSize": 2,
"MaxSize": 6,
"AllowedRoles": ["Wolf", "AlphaWolf"],
"WeightAlignment": 1.0,
"WeightSeparation": 1.5,
"WeightCohesion": 1.0,
"InfluenceRange": 20.0
}
BehaviorDescription
AlignmentMatch velocity with nearby flock members
SeparationMaintain distance from other members
CohesionStay close to flock center

The spawning system controls when and where NPCs appear.

Spawn beacons define spawn locations:

public class SpawnBeacon implements Component<EntityStore> {
// Configured in assets
}

Spawn markers define specific spawn points:

public class SpawnMarkerEntity extends Entity {
// Spawn marker data
}
{
"Id": "MyPlugin_ZombieSpawn",
"Role": "Zombie",
"MinCount": 1,
"MaxCount": 3,
"SpawnChance": 0.5,
"Conditions": {
"TimeOfDay": "Night",
"LightLevel": { "Max": 7 }
}
}

World spawn configuration for natural spawning:

// Spawn parameters
LightType lightType; // BLOCK, SKY, COMBINED
int minLightLevel;
int maxLightLevel;

Control spawn rates in areas:

public class SpawnSuppressionComponent implements Component<EntityStore> {
// Suppress spawns in area
}

The NPC plugin registers many systems for NPC behavior:

SystemDescription
NPCPreTickSystemPre-tick setup
StateEvaluatorSystemEvaluate state transitions
SteeringSystemCalculate steering forces
ComputeVelocitySystemCompute final velocity
AvoidanceSystemCollision avoidance
MovementStatesSystemMovement state updates
RoleChangeSystemHandle role changes
NPCDamageSystemsDamage handling
NPCDeathSystemsDeath handling
NPCInteractionSystemsPlayer interactions

NPCs use instructions for behavior trees:

TypeDescription
BodyMotionMovement instructions
ActionDiscrete actions
SensorEnvironmental sensing
ActionRecomputePath // Recalculate path
ActionOverrideAltitude // Set altitude
ActionFlockJoin // Join a flock
ActionFlockLeave // Leave flock
ActionFlockBeacon // Respond to beacon
ActionFlockSetTarget // Set flock target
ActionTriggerSpawnBeacon // Trigger spawn
SensorOnGround // Ground detection
SensorFlockLeader // Leader detection
SensorFlockCombatDamage // Combat damage sensing
SensorInflictedDamage // Damage dealt sensing

NPCs use state machines for behavior:

public class StateTransitionController {
// Manage state transitions
}
// State transition edges
public class BuilderStateTransitionEdges {
// Define transition conditions
}

NPCs support expression evaluation for conditions:

// Expression syntax
"health < 50"
"distance(target) > 10"
"hasTag(\"hostile\")"
// NPC added to world
getEventRegistry().register(AddPlayerToWorldEvent.class, event -> {
// Not for NPCs - use RefSystem for NPC lifecycle
});
// Use RefSystem for NPC tracking
public class MyNPCSystem extends RefSystem<EntityStore> {
@Override
public void onEntityAdded(Ref<EntityStore> ref, AddReason reason,
Store<EntityStore> store, CommandBuffer<EntityStore> buffer) {
NPCEntity npc = store.getComponent(ref, NPCEntity.getComponentType());
// Handle NPC spawn
}
@Override
public Query<EntityStore> getQuery() {
return NPCEntity.getComponentType();
}
}
// NPC kill event
getEventRegistry().register(KillFeedEvent.class, event -> {
// Handle kill
});
// Create NPC holder
Holder<EntityStore> holder = EntityStore.REGISTRY.newHolder();
// Add NPCEntity component
NPCEntity npc = new NPCEntity();
holder.addComponent(NPCEntity.getComponentType(), npc);
// Add transform
TransformComponent transform = new TransformComponent(x, y, z, 0, 0, 0);
holder.addComponent(TransformComponent.getComponentType(), transform);
// Add UUID
holder.addComponent(UUIDComponent.getComponentType(),
new UUIDComponent(UUID.randomUUID()));
// Spawn
Store<EntityStore> store = world.getEntityStore().getStore();
Ref<EntityStore> ref = store.spawn(holder);

NPCs are configured through role assets:

{
"Id": "MyPlugin_CustomNPC",
"MaxHealth": 20,
"Appearance": "Models/NPCs/custom_npc",
"DropList": "MyPlugin_CustomDrops",
"Behavior": {
"Root": {
"Type": "Selector",
"Children": [
{
"Type": "Sequence",
"Conditions": ["health < 50"],
"Actions": ["Flee"]
},
{
"Type": "Wander"
}
]
}
}
}
  1. Use roles: Define behavior through role configurations
  2. Leverage flocks: Group related NPCs for coordinated behavior
  3. Optimize queries: Use efficient ECS queries for NPC systems
  4. Handle lifecycle: Properly handle NPC add/remove events
  5. Use blackboards: Share state through blackboard system
  6. Configure spawning: Use spawn beacons and markers for controlled spawning