Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

AbolethSM

A Blueprint-integrated hierarchical state machine system for Unreal Engine 5.8

AbolethSM is a custom Unreal Engine plugin for visually authoring, compiling, running, and debugging gameplay state machines. It combines a dedicated graph editor with normal Blueprint logic, reusable node classes, hierarchical state machines, multiple transition models, and live Play In Editor visualization.

Source status: Private production code. This case study documents the system and its engineering without distributing the implementation.

Project context

AbolethSM was built for Lower Management, a multiplayer cooperative looting game inspired by Lethal Company. The plugin provides a structured way to build actor and gameplay behavior without allowing large Blueprint event graphs to become the only source of truth.

The goal was to give behavior a readable high-level shape while preserving Blueprint as the place where designers implement the details.

AbolethSM coordinating Utility AI and Smart Object behavior

A gameplay state machine coordinating Utility AI selection, Smart Object movement and use, fallback positioning, and shared data. The high-level behavior remains readable while reusable state classes implement the individual actions.

Project snapshot

Role Systems design, C++ implementation, Unreal Editor tooling, Blueprint integration
Game Lower Management
Genre Multiplayer cooperative looting game
Engine Unreal Engine 5.8
Technology C++, Slate, Blueprint/Kismet compiler integration, Gameplay Tags, Actor Components
Architecture Separate runtime and editor modules
Current scale Approximately 8,400 lines across the private runtime and editor modules
Status Active production development

The designer workflow

The central feature is the complete workflow from visual design to live runtime inspection:

flowchart LR
    A["Create a state machine asset<br/>or Aboleth Actor Blueprint"] --> B["Lay out behavior<br/>states + transitions + conduits"]
    B --> C["Double-click a node<br/>to author Blueprint logic"]
    C --> D["Configure transitions<br/>event + condition + timed + automatic"]
    D --> E["Compile the asset<br/>into runtime data"]
    E --> F["Run through an actor<br/>with an AbolethSM component"]
    F --> G["Debug during PIE<br/>active state + transition history"]
    G --> B
Loading

1. Describe the behavior visually

The designer creates states and connects them into an immediately readable behavior graph. An Entry node identifies the starting state, directional connections show control flow, and transition nodes describe why the machine can move.

Complex behavior can be divided into nested state machines instead of expanding one flat graph indefinitely. Any State nodes and conduits support global reactions and conditional routing.

2. Put implementation inside the relevant node

Double-clicking a state opens its bound Blueprint graph. Each state exposes three explicit lifecycle points:

  • On State Begin for setup when the state becomes active.
  • On State Update for behavior that must run while active.
  • On State End for cleanup when leaving the state.

Transition nodes can open a Boolean condition graph and separate transition-entered and transition-exited hooks. This keeps the behavior graph readable while allowing ordinary Blueprint nodes to implement game-specific logic.

Smart Object search state lifecycle graph

The implementation behind the Find Smart Object state. On State Begin queries the Aboleth Utility Subsystem, compares the new selection with the current Smart Object, and exposes the result through the state's output data.

3. Choose how transitions fire

AbolethSM supports four transition models:

Transition Purpose
Event React to a named gameplay event sent to the state machine
Condition Evaluate authored Blueprint logic while the source state is active
Timed Fire after the source state has remained active for a configured duration
Auto Continue immediately when a state is entered and its transition is valid

Transitions also support explicit priority and optional Gameplay Tag guards. These controls keep routing decisions visible in the graph rather than hiding every branch inside general-purpose Blueprint flow control.

Compiled Boolean transition condition graph

A minimal transition condition graph. More complex transitions can use ordinary Blueprint logic and return a Boolean result through the generated condition function.

4. Reuse behavior through node classes and data pins

A state, transition, or conduit can use a Blueprintable node-instance class. Instance classes expose node-specific input and output properties as pins, allowing reusable behavior to be configured directly from the state machine graph.

Variable Get and Set nodes, default values, and compiled property links move data between the state machine context and node instances. This separates reusable behavior from the particular actor or asset that configures it.

5. Compile to a runtime representation

The custom compiler converts editor-only graph nodes into compact generated-class data. It recursively records states, nested machines, conduits, transitions, property links, function bindings, and the root entry point.

The runtime module does not execute the visual editor graph directly. An AbolethSM component builds an owned runtime object tree from the compiled data, starts the root machine, updates active states, evaluates transitions, and broadcasts state changes.

State machine embedded inside an actor Blueprint

The embedded Actor Blueprint running during simulation. The actor owns its state-machine component, State 2 is outlined as the active state, and its live 5.66-second duration is displayed above the node. The same view also exposes nested machines, actor variables, transition data pins, and Variable Get nodes.

6. Watch the machine while the game runs

During Play In Editor or simulation, the designer selects the actor being debugged and keeps the state machine graph open. Active states receive a live highlight, recently exited states fade over time, active transitions change color, and the current time in state is displayed.

This closes the authoring loop: the same graph used to design the behavior becomes the primary runtime diagnostic view.

Production example: coordinating Utility AI

The captured Lower Management example shows how AbolethSM composes with a separate Utility AI system rather than trying to replace it.

flowchart LR
    A["State machine<br/>owns behavior sequence"] --> B["Find Smart Object state"]
    B --> C["Utility AI subsystem<br/>scores available choices"]
    C --> D["Selected Smart Object<br/>returned through state output"]
    D --> E["Compiled graph data link<br/>shares the selection"]
    E --> F["Move to object"]
    F --> G["Use object"]
    G --> B
    B --> H["Random location<br/>fallback behavior"]
Loading

The state machine answers what phase of behavior is active. The Utility AI subsystem answers which available Smart Object is the best choice. A reusable state instance bridges the two by requesting a selection during On State Begin and publishing that selection as graph data.

This division keeps scoring logic independent from behavior sequencing. The state graph can change how an actor reacts to a result without rewriting the selection system, and the Utility AI implementation can evolve without turning the state graph into a scoring algorithm.

The problem

Blueprint is flexible, but complex actor behavior can become difficult to understand when lifecycle, routing, state, and implementation are mixed inside a large event graph.

The system needed to:

  • Make the current behavior model understandable at a glance.
  • Keep state entry, update, and exit logic clearly separated.
  • Support multiple transition styles without duplicating runtime plumbing.
  • Allow complex behavior to be grouped hierarchically.
  • Preserve normal Blueprint authoring for game-specific logic.
  • Support reusable state, transition, and conduit implementations.
  • Compile editor-authored graphs into a runtime-safe representation.
  • Expose runtime state changes to both Blueprint and the custom editor.
  • Avoid re-entrant transition failures when gameplay events are sent during a state change.
  • Provide useful compiler diagnostics before gameplay begins.

System architecture

The plugin separates visual authoring, compilation, and execution:

flowchart LR
    A["Custom state machine graph<br/>editor-only nodes"] --> B["AbolethSM compiler<br/>validation + graph traversal"]
    B --> C["Generated class data<br/>states + transitions + bindings"]
    C --> D["AbolethSM component<br/>runtime tree construction"]
    D --> E["Runtime state machine<br/>active states + event routing"]
    E --> F["Blueprint callbacks<br/>behavior implementation"]
    E --> G["PIE debug state<br/>editor visualization"]
Loading

The runtime module contains no dependency on the editor module. Packaged builds use the generated data and runtime objects; Slate widgets, graph schemas, factories, and compiler tooling remain editor-only.

Core engineering decisions

1. Make the state graph an Unreal Blueprint asset

AbolethSM assets participate in the Blueprint compilation pipeline rather than acting as disconnected configuration files. State and transition subgraphs use familiar K2 Blueprint nodes, generated functions, variables, and compile results.

This gives designers a specialized high-level editor without requiring a second scripting language.

2. Compile intent instead of interpreting editor nodes

The compiler walks the custom graph recursively and emits runtime records for each state machine, state, conduit, and transition. It also maps authored Blueprint graphs to generated function names and converts data-pin connections into property links.

This establishes a deliberate boundary:

  • Editor nodes describe the authored model.
  • Generated data stores the compiled model.
  • Runtime objects execute the model.

That separation keeps packaged-game execution independent of Slate and editor graph objects.

3. Treat states as lifecycle-owned runtime objects

Every state has explicit initialization, start, update, end, and reset behavior. Nested state machines derive from the runtime state type, so a parent can treat a complete child machine as one state while the child owns its active branch.

The component creates the runtime tree with clear ownership and supplies the actor or generated state-machine instance as the execution context.

4. Centralize transition evaluation

The runtime evaluates only the active states' outgoing transitions plus applicable Any State transitions. Lower numeric priority wins, allowing routing order to remain deterministic.

Transition behavior is centralized by type:

  • Named events are dispatched explicitly.
  • Conditions are evaluated while the source state is active.
  • Timed transitions use the source state's elapsed time.
  • Automatic transitions are processed on state entry.

Automatic transition chains have a depth guard, and events received during a transition are deferred until the transition completes. These protections prevent common re-entrancy and accidental infinite-loop failures.

5. Keep reusable logic data-driven

Blueprintable node-instance classes allow behavior to be reused without copying subgraphs. The editor reflects supported properties into graph pins, and the compiler records links and defaults for runtime application.

This makes the high-level state graph both control flow and a visible configuration surface for reusable behavior.

6. Make runtime state observable

The runtime publishes state-changed, state-tick, and transition-fired delegates. It also exposes current state, previous state, active states, time in state, history, and Gameplay Tag guard operations through Blueprint-facing APIs.

The editor uses the selected Blueprint debug object to resolve the live AbolethSM component and visualize active behavior without requiring a separate debugging window.

7. Validate structural errors during compilation

The custom compiler reports invalid structures before runtime, including:

  • State machines with no states.
  • Missing entry states.
  • States with no outgoing transitions.
  • Transitions with missing targets.
  • Any State transitions with missing targets.

The diagnostics appear through Unreal's normal Blueprint compiler results, keeping failures inside the workflow designers already use.

Runtime model

flowchart TD
    A(["Start"]) --> B["Initialize runtime tree"]
    B --> C["Enter configured entry state"]
    C --> D["Active state"]
    D -->|"Update"| D
    D -->|"Valid transition"| E["Exit source state"]
    E --> F["Apply data links"]
    F --> G["Enter target state"]
    G --> D
    D -->|"Stop"| H(["End"])
Loading

The component can auto-start on BeginPlay or be controlled explicitly. Gameplay can send named events, query active state, add or remove guard tags, and subscribe to lifecycle delegates.

When a transition fires, the runtime:

  1. Confirms its type, priority, guard, and authored condition.
  2. Executes transition-entered behavior.
  3. Ends the source state when appropriate.
  4. Applies compiled variable writes and property links.
  5. Starts the target state.
  6. Records history and broadcasts the state change.
  7. Processes valid automatic follow-up transitions.
  8. Executes transition-exited behavior.

Editor tooling

The custom editor includes:

  • Entry, State, nested State Machine, Transition, Conduit, and Any State nodes.
  • Variable Get and Set nodes for state-machine context data.
  • Custom Slate widgets for state and transition presentation.
  • Directed, color-coded transition connections.
  • Bound Blueprint graphs opened by double-clicking nodes.
  • Asset factories for standalone state machines and actor Blueprints with an embedded machine.
  • Project settings for node, transition, and PIE debug colors.
  • Live active-state and recent-transition visualization.
  • Custom Kismet compilation and structural validation.

Current evidence

Engineering objective Current evidence
Visual behavior authoring Dedicated state-machine graph schema and custom Slate nodes
Blueprint integration Bound state lifecycle, transition condition, and transition event graphs
Runtime/editor separation Independent runtime and editor modules
Hierarchical composition Nested machines compile recursively and execute as runtime states
Reusable behavior Blueprintable node instances with compiled data-pin property links
System composition Utility AI selection is consumed by reusable state classes and passed through the state graph
Deterministic routing Explicit transition priority and scoped active-state evaluation
Runtime safety Deferred transition-time events and automatic-transition depth guard
Debuggability PIE active-state highlighting, time-in-state display, delegates, and state history
Authoring feedback Custom compile validation through Unreal's normal compiler results
Game integration Blueprint-spawnable Actor Component and optional embedded Actor Blueprint workflow

Current limitations and next steps

  • Complete and expose a dedicated nested-machine exit-node workflow.
  • Add Unreal Automation coverage for runtime lifecycle, transition ordering, event deferral, and compiler validation.
  • Profile condition-heavy machines and cache resolved property links where useful.
  • Allow event-only machines to opt out of unnecessary ticking.
  • Continue production testing of the newer parallel active-state workflow.

Built by JMathisPluto.

© 2026 JMathisPluto. All rights reserved. This case study does not grant permission to copy, redistribute, reverse engineer, or use the underlying proprietary implementation.

About

Portfolio case study for a Blueprint-integrated hierarchical state machine system built for Unreal Engine 5.8

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors