Endless GM v2
An AI-driven text RPG and visual novel where a Large Language Model acts as a dynamic Dungeon Master, orchestrating the world, narrative, and mechanical consequences in real-time.
Role
Lead Software Engineer & Systems Architect
Date
August 2025
Interactive Demo / Presentation








Architecture Scheme
Implementation Details
The Challenge
Integrating non-deterministic Large Language Models into a rigid game engine environment presents severe architectural challenges. The primary goals were to maintain absolute game logic integrity (preventing AI hallucinations from corrupting mechanical states like HP or inventory), minimize token consumption while retaining deep character memory, and seamlessly fetch dynamically requested visual and audio assets on the fly.
Architecture & Implementation
- Event-Driven Backbone: The entire game loop operates on a loosely coupled
EventBusarchitecture —IntentRouterknows nothing aboutPromptBuilder, andGameStateManagerknows nothing aboutAIService. Any module can be replaced or unit-tested in isolation, which is critical while the AI pipeline keeps evolving. - Intent Routing & Arbitration: Player inputs are classified by an
IntentRouter. To enforce mechanical integrity (Combat 2.0), the engine'sCombatManagerpre-calculates dice rolls and damage before interacting with the AI. The LLM receives strict system data and acts purely as a narrative formatter, completely eliminating mathematical hallucinations. - Reality Anchor — Honesty Protocol: Every player message enters the prompt as an unverified claim, never as established fact. The only sources of truth are the game state, location data, and knowledge-base facts — deliberately countering the LLM's natural tendency to agree with the player.
- Modular Prompt Pipeline: A centralized
PromptBuilderdynamically constructs system instructions block-by-block depending on the active game state, scene hierarchy (Breadcrumbs system), and player intent. Special modes replace the prompt wholesale:DirectCommandModefor debugging,SessionZerofor AI-hosted character creation, andDyingStatefor death-saving throws. - Light RAG & Context Management: Implemented a robust local inverted index (
TriggerIndexService). Instead of sending the entire game lore to the LLM, the system dynamically fetches and injects relevant data (NPCs, location facts) based on active tags (ContextTags,IndirectTags), heavily optimizing token usage. - Safety Net Validation: The pipeline features a
StreamingJsonParserbacked by a strictResponseValidatorthat acts as a fail-safe firewall. It blocks travel to non-adjacent map nodes, drops damage aimed at non-existent enemy instances, restores missing visual/audio tags from a scene-isolated cache, and reports every interception to the in-editor telemetry window.
Impact & Features
- Provider-Agnostic LLM Engine: Built a flexible AI Service capable of seamless switching between Cloud APIs (Gemini) and Local hosting (Ollama).
- Nested Narrative Architecture: Engineered a system that allows the AI to dynamically spawn virtual "Narrative Scenes" on the fly inside rigid graph-based dungeon locations.
- Cloud Asset Streaming: Developed
AssetDownloadServiceto fetch dynamically requested WebP backgrounds, portraits, and audio files from Cloudflare R2, preventing local app bloat. - Asynchronous Background Agents: Designed a network of background agents (Archivist for memory aggregation, MacroGM for world simulation, and TravelCoordinator for complex scene transitions) that simulate a living world independent of direct player action.
- Session Zero & Genre Modules: A conversational, AI-hosted character-creation interview (
SessionZero) builds the hero, stats, and starting kit, while a swappable genre-module system — economy profiles, combat rule sets, stat renaming — keeps the engine ready for settings beyond fantasy. - Advanced DevTools: Implemented telemetry suites (
GameMasterDebugWindow,DebugTerminal) for real-time prompt profiling, RAG cache auditing, and system visualization directly inside Unity.
Core Philosophy: Narrative Supremacy
The fundamental design principle of Endless GM is Maximum Narrative Integration. The AI Game Master is granted absolute creative authority to adapt the story for optimal player immersion. To support this without breaking game logic, all mathematical heavy-lifting (dice rolls, stats, rule verification) is offloaded to deterministic pre-calculation modules. These modules act as an advisory layer—feeding the GM with structural constraints and mechanical outcomes—while allowing the GM the final say in applying narrative flair, canceling damage, or granting context-appropriate bonuses.
Mechanics Deep Dive
1. Input Pipeline & Intent Routing
Player inputs are intercepted and analyzed by the IntentRouter to classify the intent (Combat, Trade, Travel, Skill Use, Rest, Meta Question) before generating the prompt. An LLM pre-pass for classification was explicitly rejected in favor of Regex (and later on-device ML) to save latency and tokens. A dedicated MetaQuestion mode answers questions about rules and mechanics without touching game parameters.
- Problem Solved: Pre-analysis preserves the main model's focus by strictly excluding irrelevant instructions. If intents overlap (e.g., trying to trade while initiating combat), the modular architecture resolves the conflict based on module hierarchy (combat rules override trade rules). This ensures the AI never loses its focal point on the most critical action.
2. Blind Pre-Roll & Combat 2.0 (Engine-First Arbitration) The game engine calculates mechanical outcomes (dice rolls, weapon damage, active zones, status effects, ammunition) before the LLM request. The AI translates these hard numbers into a narrative, retaining the power to apply AoE, modify health, or allow narrative-driven combo attacks. Dice are thrown before the request too: the "Blind Pre-Roll" injects raw d20 results and modifiers as system text, so numbers come first and narrative second.
- Problem Solved: LLMs cannot hold strict numerical state, and relying on them for math breaks causality (describing success before calculating it). Pre-calculating numbers restores engine integrity. Furthermore, batching all NPC/ally turns into a single prompt was a massive UX and narrative upgrade. Instead of a robotic turn-by-turn loop where the player just hits "next", the AI leverages the batch to narrate simultaneous, coordinated enemy attacks in a cinematic flow, adapting to complex situations like mob tactics seamlessly.
- Spatial Tactics Without a Grid: A lightweight Zone (Melee / Ranged / Out Of Sight) × Formation (Front / Flank / Rear / Isolated) model enforces positioning rules — reach weapons, protected rear lines, flanking vulnerability — at a fraction of the context cost of a full tactical grid.
- SmartAmmo Two-Phase Protocol: The engine checks ammunition read-only while building the prompt and commits the deduction only after the response, verifying the AI has not already consumed it via inventory updates — eliminating double-write conflicts between the AI and the engine.
- Ready Actions as Free Strings: "When the beast leaps — I strike" is stored verbatim. The engine deliberately does not interpret the trigger condition; the AI judges whether it fires, keeping the mechanic infinitely flexible.
- TraumaCap: Severe wounds lower the healing ceiling, so a single potion cannot undo a near-death fight — combat leaves long-term consequences.
3. Reality Anchor — The Anti-Cheat Protocol The core rule of every prompt: the player's text is always an unverified claim. The AI strictly references the provided context (inventory, stats, nearby entities). If a player attempts to "jailbreak" or invent items out of thin air, the AI integrates the failure into the narrative (e.g., trying to draw a non-existent sword).
- Problem Solved: LLMs are naturally agreeable and easily tricked. By anchoring truth exclusively to engine state, cheating becomes narratively impossible. For persistent jailbreakers, the system supports a "Meta-conversation" mode where the AI breaks the fourth wall, pausing the simulation like a real-life GM to explicitly tell the player to stop disrupting the session.
4. Light RAG — Deterministic Knowledge Retrieval
Lore is served in three tiers: core facts are always present; brief summaries of NPCs, locations, and enemies are injected when the player's words trigger their tags; full profiles load only on direct interaction. TriggerIndexService builds a local inverted index with three weighted tag levels (Direct 0.85, Indirect 0.70, Context 0.60), splits multi-word tags into tokens, and updates incrementally — so scenes the AI invents on the fly are indexed immediately.
- Problem Solved: A standard Vector DB / Embeddings RAG approach was rejected because it is too heavy for local execution, especially with future mobile adaptations in mind. More importantly, standard RAG often fetches semantically similar but contextually irrelevant information, blurring the AI's focus. The tag-based inverted index guarantees strict determinism: if an entity isn't explicitly active in the context, its data won't pollute the prompt.
5. Social Fabric — Two-Axis NPC Relationships Every named NPC carries two independent axes: Trust (rational, -100…+100) and Affection (emotional), combined 0.6/0.4 — trust outweighs sympathy, so a merchant will sell to a charming crook but never entrust him with secrets. Faction pressure is an interpolation between personal and factional reputation, weighted by the faction's zealotry and the NPC's loyalty — but the weight is halved once personal reputation exceeds ±50: saving a zealot guard's life lets personal experience outweigh faction dogma.
- Problem Solved: A single "attitude" number flattens social gameplay; two axes plus faction dynamics produce believable behavior without scripting. Anonymous crowd NPCs are deliberately excluded from tracking (per-NPC state is meaningless at city scale), while companions can be relationship-locked until the AI reveals their unlock conditions through play.
- Information as a Resource: NPCs may hold deliberately distorted versions of facts (
IsDeceptive), locations circulate local rumors with credibility scores, and the resolver returns the version the current speaker would actually know: personal secret → local rumor → common knowledge → ground truth. Rumors spread across the map daily, losing credibility with each hop until they die out.
6. MacroGM World Simulation A secondary, lightweight background agent that operates daily in-game time. It distributes rumors, generates global events, and moves NPCs across the world map. Every move from its response is validated against existing NPC and location IDs before being applied — hallucinated entities are dropped with a warning instead of corrupting the world.
- Problem Solved: Creates a living, breathing world independent of the player. By using a cheaper, smaller model (flash-lite) for background tasks, we achieve high immersion and dynamic storytelling without driving up API costs.
7. Travel Pipeline & Scene State Injection
Interiors come in two deliberately different flavors. Dungeons are pre-defined as rigid room graphs — locks, secrets, traps, and connections are established once, before entry. Narrative Scenes (city districts, taverns, hidden basements) are spawned by the AI on the fly as nested hierarchical spaces. Unlike global lore, the local scene state (all objects, NPCs, and interactables in the current room) is hard-fetched and fully injected into the prompt, skipping RAG entirely. A dedicated TravelCoordinator serializes the asynchronous generation chain.
- Problem Solved: Players often write short, single-word inputs that fail to trigger RAG properly. Injecting the entire room guarantees the AI knows exactly what surrounds the player, eliminating structural amnesia. Given the 1M token context window, a single scene never overflows the limit. To prevent context bloat over time, object data is periodically reviewed, merged into historical summaries, or condensed transparently to the user, ensuring optimal token economy without the player ever noticing a loss of detail.
8. Data-Driven Integrity — Closed Vocabularies & Template Stats
ItemData stores no raw numbers: every stat resolves from a central config via the item's iconCategory. The AI only ever emits an icon category and a rarity tag (AuraTag) — and that single tag drives both the mechanical bonuses and the visual aura in the UI: one source of truth. Icon categories form a strictly closed list, an exhausted perk is deactivated with a status note instead of being deleted (preserving history for later recovery), and mid-combat equipping is deferred until endCombat so the AI can narrate the opportunity cost.
- Problem Solved: Every constraint shrinks the AI's degrees of freedom to a safe set. Closed vocabularies stop the model from inventing item categories, template stats rule out save corruption and allow central balance tuning, and deferred equipping keeps combat state deterministic.
9. Responsive Economy Prices are never hardcoded: the engine supplies anchor prices multiplied by the location's base multiplier and active market signals — a siege triples food prices, a quarantine raises consumables, a rich harvest lowers them. The AI then names the final price inside the narrative.
- Problem Solved: Keeping numbers out of static storage lets world events reshape trade without data migrations — and genre modules can rename the currency itself.
10. Single-Pass Execution & Ordered JSON CoT Initially, the architecture relied on two separate LLM calls: one to process game rules and technical outcomes, and a second to generate the narrative based on those outcomes. To eliminate the high latency and API costs of double-calling, the system was refactored into a single-pass JSON generation pipeline.
- Problem Solved: By forcing the LLM to output a strict JSON structure where technical blocks (state changes, internal logic, rule resolutions) are generated first, and the narrative text block is generated last, the model effectively uses the technical fields as a Chain-of-Thought (CoT) scratchpad. This guarantees the narrative is exactly aligned with the technical decisions, retaining the full context and quality of a two-model setup but operating at twice the speed and half the cost.
What's Next
Regex intent heuristics are set to be replaced by on-device ML classification (Unity Sentis), new genre modules (cyberpunk, post-apocalypse, space horror) plug into the ready GenreModuleRegistry, and companion relationships will grow a milestone graph — Acquaintances → Friends → Allies.