INDEX_RETURN

EntityAI Kotlin DSL

A fluent Kotlin DSL and AI library for Minecraft entities. Features Behavior Trees, State Machines, and a type-safe builder syntax that abstracts NMS complexity.

EntityAI is a proof-of-concept library designed to solve a specific problem: writing Artificial Intelligence logic in Minecraft’s native Java API is verbose, fragile, and difficult to maintain.

This project is the result of “over-engineering” a university assignment.

The task was simple: implement basic character behaviors using a provided (and quite limited) AI library for Unity. Instead of following the easy path, my team and I decided to build a Minecraft Mod.

Since we couldn’t use the provided Unity tools (and Minecraft’s internal AI system is notoriously verbose and fragile), I had to architect my own solution. I engineered a high-level Kotlin DSL (Domain Specific Language) that replaces the spaghetti code of native Minecraft development with a clean, declarative syntax for Behavior Trees and State Machines.

The Kotlin DSL

The core innovation is the use of Kotlin Type-Safe Builders and Higher-Order Functions to create a readable syntax for AI logic. Instead of chaining objects manually, the API allows defining behavior hierarchies naturally.

ai.activities += TreeActivity("default", ai, rootLoopUnconditional {
    runAndWait {
        or {
            and {
                findNearestLivingEntities()
                or {
                    // Find enemy in a distance of 32 blocks.
                    findAttackTargetIfNotFound(32.0f) { it is EnderVillager }
                    findAttackTargetIfNotFound(32.0f) {
                        it is PlayerEntity && !it.isCreative && !it.isSpectator
                    }
                }
                // walkToEntity is a macro: generates more nodes under the hood.
                walkToEntity(MemoryTypes.ATTACK_TARGET, 1.5f, 1.0f, 32.0f)
                succeeder { attack() }
            }
            and {
                findRandomWalkTarget(1.0f)
                timed(40, 60) { walkToTarget() } // 40-60 ticks. 1 tick = 0.05s
            }
        }
    }
})

Architecture: The “Activity” System

The library introduces an architecture based on Activities. Unlike standard Minecraft entities that run a single flat list of goals, EntityAI entities run a Hierarchical State Machine.

:: Behavior Tree Implementation

A robust implementation of standard AI nodes: Composites (Sequence, Selector), Decorators (Inverter, Timed, Loop), and Leafs (Action, Condition).

:: Memory & Blackboard

Implemented a strongly-typed Blackboard System (MemoryTypes). Nodes can share data like ATTACK_TARGET or HOME_POS without coupling, resolving references at runtime.

:: Hybrid State Machines

Entities can switch between entire Behavior Trees based on high-level states (e.g., “Working”, “Sleeping”, “Fleeing”). This Activity Manager prevents giant, unmanageable trees.

:: NMS Abstraction Layer

Wraps Minecraft’s obfuscated internal methods (NMS) into stable Kotlin interfaces. This decoupling allowed the mod to survive game updates with minimal refactoring.

Behavior Tree Diagram for Ender Guardian
â–˛ Visual representation of the Ender Guardian's main activity.

Use Case: Magic End

The library was validated by building Magic End, a mod that introduces a new ecosystem to the End dimension.

  • Complex Societies: Implemented as Endervilles, villages where entities have professions (Farmer, Guardian, Shaman) and interact socially (sharing food, calling for help).
  • Evolution Mechanics: The Void Worm entity uses the State Machine to track its “kill count” and physically evolves into a Void Snake boss after consuming enough enemies.

Technical Challenges

Navigating the Spaghetti

The Challenge

Minecraft’s internal pathfinding engine is notoriously unpredictable and undocumented. Complex entities often got stuck or spun in circles when calculating paths in the floating islands of the End.

The Solution

I reverse-engineered the pathfinding code and re-implemented a Path Debugger left unfinished by Mojang devs. By visualizing the navigation mesh and node weights in real-time, I was able to tune the A* heuristic to handle verticality and void gaps correctly.

Kotlin Interoperability

The Challenge

The goal was to make the API feel “Native Kotlin” while running inside Minecraft.

The Solution

I used Inline Functions and Reified Type Parameters to eliminate Java boilerplate. For example, looking up a component becomes entity.get<MyComponent>() instead of entity.getComponent(MyComponent.class), reducing verbosity and improving runtime safety.

Pathfinding Debug Visualization
â–˛ Real-time visualization of the A* pathfinding nodes used to debug navigation.