Skip to content

feat(ecs): AI system — priority goal list and goal scheduler #119

Description

@iverly

Context

The server runtime architecture spec (section 7) defines an AI system based on priority goal lists, matching the vanilla Minecraft MobGoal pattern. The ECS foundation is in place (basalt-ecs with system scheduler, phase ordering, component access declarations), and the physics plugin demonstrates the pattern. The AI system is the next simulation layer needed to enable mob behavior.

Spec reference: docs/superpowers/specs/2026-04-15-server-runtime-architecture-design.md sections 7.1 and 7.2.

Problem

  1. There is no AI system — entities (mobs, NPCs) have no autonomous behavior.
  2. No Goal trait exists for defining reusable behavior primitives (wander, look at player, flee, attack).
  3. No GoalScheduler exists to evaluate and switch between goals by priority each AI tick.
  4. No core components (AiGoals, Health, EntityType) are registered for AI-driven entities.

Proposed approach

7.1 — Goal trait

Define a Goal trait in basalt-ecs (or a new basalt-ai crate if preferred):

trait Goal: Send + Sync {
    fn can_start(&self, entity: EntityId, ecs: &Ecs) -> bool;
    fn start(&mut self, entity: EntityId, ecs: &mut Ecs);
    fn tick(&mut self, entity: EntityId, ecs: &mut Ecs);
    fn can_continue(&self, entity: EntityId, ecs: &Ecs) -> bool;
    fn stop(&mut self, entity: EntityId, ecs: &mut Ecs);
}

7.2 — GoalScheduler

An ECS system running in the Simulate phase at every(5) (4 effective TPS at 20 TPS global):

  1. For each entity with AiGoals, iterate goals from highest to lowest priority.
  2. If a higher-priority goal can start, interrupt the current goal (stop()) and start the new one.
  3. If the current goal can no longer continue, stop it and evaluate the next candidate.
  4. Call tick() on the active goal.

Core goals (provided by basalt)

  • RandomWalkGoal — picks a random nearby position and walks toward it.
  • LookAtPlayerGoal — rotates to face the nearest player within range.
  • PanicGoal — runs in a random direction when damaged.
  • FloatGoal — prevents drowning by swimming to the surface.

Core components to add

  • AiGoalsgoals: Vec<PrioritizedGoal> (priority + boxed goal)
  • Healthcurrent: f32, max: f32
  • EntityTypetype_id: u32 (Minecraft entity type ID)

Plugin extensibility

Plugins add custom goals and reorder goal lists per mob type via registrar.system(). Survival plugins add combat, farming, breeding, etc.

Scope

  • crates/basalt-ecs/ — new components (AiGoals, Health, EntityType), Goal trait, GoalScheduler system
  • crates/basalt-server/src/game/tick.rs — register AI system in game loop
  • Possibly a new basalt-ai plugin under plugins/ for the core goals

Benefits

  • Enables autonomous mob behavior (zombies, animals, villagers)
  • Provides the foundation for all PvE gameplay
  • Plugin-extensible: server operators can customize mob AI per server type
  • Matches vanilla Minecraft patterns — familiar to plugin developers

Non-goals

  • Mob spawning rules and spawn rate configuration (separate feature)
  • Entity rendering/model system (client-side concern)
  • Combat mechanics (PvP, damage, knockback) — separate issue
  • Pathfinding algorithm itself — covered by a dedicated issue

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ecsRelative to basalt-ecs crateenhancementNew feature or requestserverRelative to basalt-server crate

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions