LsdeDialogEngine 0.3.0
dotnet add package LsdeDialogEngine --version 0.3.0
NuGet\Install-Package LsdeDialogEngine -Version 0.3.0
<PackageReference Include="LsdeDialogEngine" Version="0.3.0" />
<PackageVersion Include="LsdeDialogEngine" Version="0.3.0" />
<PackageReference Include="LsdeDialogEngine" />
paket add LsdeDialogEngine --version 0.3.0
#r "nuget: LsdeDialogEngine, 0.3.0"
#:package LsdeDialogEngine@0.3.0
#addin nuget:?package=LsdeDialogEngine&version=0.3.0
#tool nuget:?package=LsdeDialogEngine&version=0.3.0

LSDE Dialog Engine — C#
C# runtime for Unity (2021+) and .NET Standard 2.1. Zero external dependencies.
Port of the TypeScript reference implementation. Validated against the same 42 cross-language JSON test specifications. The engine is a pure .NET Standard 2.1 library with no NuGet dependencies — drop it into Unity or any .NET project.
Installation
# Core engine
dotnet add package LsdeDialogEngine
# JSON loader — choose ONE based on your platform:
dotnet add package LsdeDialogEngine.Newtonsoft # Unity
dotnet add package LsdeDialogEngine.SystemTextJson # .NET 5+ / Godot .NET
Unity (alternative)
Copy the src/LsdeDialogEngine/ folder into your Unity project's Assets/Plugins/ directory. Install com.unity.nuget.newtonsoft-json via Unity Package Manager for JSON parsing.
Quick Start
using LsdeDialogEngine;
using LsdeDialogEngine.Json; // or LsdeDialogEngine.Newtonsoft for Unity
var blueprint = LsdeJson.Parse(File.ReadAllText("blueprint.json"));
var engine = new DialogueEngine();
var report = engine.Init(new InitOptions { Data = blueprint });
engine.SetLocale("en");
// Character resolver (optional — default: first character in list)
engine.OnResolveCharacter(chars => chars.Count > 0 ? chars[0] : null);
// Unified condition resolver — handles choice visibility + condition block pre-evaluation.
// choice: conditions are handled internally by the engine via choice history.
engine.OnResolveCondition(cond => GameState.Evaluate(cond));
// ─── 4 Required Handlers ────────────────────────────────────────
engine.OnDialog(args => {
var text = LsdeUtils.GetLocalizedText(args.Block.DialogueText);
var ch = args.Context.Character;
Debug.Log($"{ch?.Name ?? "???"}: {text ?? "—"}");
args.Next();
return null; // or return a cleanup Action
});
engine.OnChoice(args => {
var visible = args.Context.Choices
.Where(c => c.Visible != false)
.ToList();
args.Context.SelectChoice(visible[0].Uuid);
args.Next();
return null;
});
// onCondition is OPTIONAL when OnResolveCondition is installed.
// The engine pre-evaluates condition groups and auto-routes.
// Add it only for logging, UI, or custom override logic.
engine.OnCondition(args => {
var groups = args.Context.ConditionGroups!;
var matched = groups.Where(g => g.Result == true).Select(g => g.PortIndex).ToList();
var isDispatcher = args.Block.NativeProperties?.EnableDispatcher == true;
object result = isDispatcher ? (object)matched : (object)(matched.Count > 0 ? matched[0] : -1);
args.Context.Resolve(result);
args.Next();
return null;
});
engine.OnAction(args => {
foreach (var a in args.Block.Actions)
Debug.Log($"Action: {a.ActionId}");
args.Context.Resolve();
args.Next();
return null;
});
// ─── Run ─────────────────────────────────────────────────────────
var handle = engine.Scene("scene-uuid");
handle.Start();
Unity Integration
In Unity, store the next callback and trigger it from your UI events:
engine.OnDialog(args => {
dialogueUI.SetText(args.Context.Character?.Name,
LsdeUtils.GetLocalizedText(args.Block.DialogueText));
dialogueUI.Show();
// Store next — triggered by UI button click
_pendingNext = args.Next;
return () => dialogueUI.Hide(); // cleanup
});
// Called from your UI button
public void OnContinueClicked() {
_pendingNext?.Invoke();
_pendingNext = null;
}
Scripts
| Command | Description |
|---|---|
npm run build |
Build the solution |
npm run test |
Run 42 cross-language tests (xUnit) |
npm run playground |
Run playground against a real blueprint |
npm run clean |
Clean build artifacts |
Project Structure
src/LsdeDialogEngine/ # Engine library (netstandard2.1, zero dependencies)
├── Types.cs # All types, interfaces, delegates
├── DialogueEngine.cs # Public facade
├── SceneHandle.cs # Traversal loop + AsyncTrack
├── HandlerRegistry.cs # Two-tier handler resolution
├── PortResolver.cs # Output port routing
├── BlockContext.cs # Context factories
├── ConditionEvaluator.cs # AND/OR chain evaluation
├── Graph.cs # Scene + Blueprint indexing
├── Validator.cs # Blueprint validation
└── Utils.cs # Type checks, helpers
tests/LsdeDialogEngine.Tests/ # xUnit test runner
samples/MiniRuntime/ # Console playground
API Overview
Engine Lifecycle
| Method | Description |
|---|---|
engine.Init(options) |
Validate + build graph. Returns DiagnosticReport. |
engine.SetLocale(locale) |
Set active locale. |
engine.Scene(sceneId) |
Create scene handle. Call handle.Start() to begin. |
engine.Stop() |
Cancel all active scenes. |
engine.IsRunning() |
True if at least one scene is active. |
engine.GetActiveScenes() |
Get all running scene handles. |
engine.GetCurrentBlocks() |
Get current block of every active scene. |
engine.GetSceneConnections(sceneId) |
Get all connections for a scene. |
Handler Registration (Tier 1 — Global)
All 4 type handlers are required — the engine will throw if a scene starts without them.
| Method | Description |
|---|---|
engine.OnDialog(handler) |
Handle DIALOG blocks. |
engine.OnChoice(handler) |
Handle CHOICE blocks (choices tagged with Visible when OnResolveCondition is set). |
engine.OnCondition(handler) |
Handle CONDITION blocks. Optional when OnResolveCondition is installed. |
engine.OnAction(handler) |
Handle ACTION blocks. Developer must call context.Resolve() or context.Reject(). |
Optional Handlers
| Method | Description |
|---|---|
engine.OnResolveCharacter(fn) |
Character resolver. Default: first character in the list. |
engine.OnResolveCondition(fn) |
Unified condition resolver (choice visibility + condition pre-evaluation). |
engine.SetChoiceFilter(fn) |
Deprecated — use OnResolveCondition instead. |
engine.OnBeforeBlock(handler) |
Pre-execution gate. Must call Resolve() to continue. |
engine.OnValidateNextBlock(handler) |
Validate before entering a block. |
engine.OnInvalidateBlock(handler) |
Called when a block fails validation. |
engine.OnSceneEnter(handler) |
Called when any scene starts. |
engine.OnSceneExit(handler) |
Called when any scene ends. |
Scene Handle (Tier 2 — Per-Scene)
| Method | Description |
|---|---|
handle.Start() |
Begin traversal from the entry block. |
handle.Cancel() |
Stop the scene and all async tracks. |
handle.OnDialog(handler) |
Override global DIALOG handler for this scene. |
handle.OnChoice(handler) |
Override global CHOICE handler for this scene. |
handle.OnCondition(handler) |
Override global CONDITION handler for this scene. |
handle.OnAction(handler) |
Override global ACTION handler for this scene. |
handle.OnBlock(uuid, handler) |
Override handler for a specific block by UUID. |
handle.OnDialogId(uuid, handler) |
Override a specific DIALOG block by UUID (type-safe). |
handle.OnChoiceId(uuid, handler) |
Override a specific CHOICE block by UUID (type-safe). |
handle.OnConditionId(uuid, handler) |
Override a specific CONDITION block by UUID (type-safe). |
handle.OnActionId(uuid, handler) |
Override a specific ACTION block by UUID (type-safe). |
handle.OnEnter(handler) |
Override global OnSceneEnter for this scene. |
handle.OnExit(handler) |
Override global OnSceneExit for this scene. |
handle.OnResolveCharacter(fn) |
Override character resolver for this scene. |
handle.GetCurrentBlock() |
Get the block currently being executed, or null. |
handle.GetVisitedBlocks() |
Set of visited block UUIDs. |
handle.GetChoiceHistory() |
Map of block UUID → selected choice UUIDs. |
handle.GetChoice(blockUuid) |
Get choice(s) selected at a specific block. |
handle.EvaluateCondition(cond) |
Evaluate a choice: condition against history. |
handle.IsRunning() |
Whether the scene is still active. |
handle.GetActiveTracks() |
Number of active async tracks. |
handle.GetTrackInfos() |
Snapshot of all track states. |
Handler Pattern
Every handler receives a typed args object and may return a cleanup Action:
engine.OnDialog(args => {
// Display dialogue...
args.Next(); // Advance to next block
return () => {
// Called when leaving this block (cleanup)
};
});
Utilities (LsdeUtils)
| Method | Description |
|---|---|
LsdeUtils.Locale |
Current locale, synced by engine.SetLocale(). |
LsdeUtils.IsDialogBlock(block) |
Type guard: true if block is a DialogBlock. |
LsdeUtils.IsChoiceBlock(block) |
Type guard: true if block is a ChoiceBlock. |
LsdeUtils.IsConditionBlock(block) |
Type guard: true if block is a ConditionBlock. |
LsdeUtils.IsActionBlock(block) |
Type guard: true if block is an ActionBlock. |
LsdeUtils.IsNoteBlock(block) |
Type guard: true if block is a NoteBlock. |
LsdeUtils.GetBlockLabel(block) |
Block label, or first 8 chars of UUID as fallback. |
LsdeUtils.GetLocalizedText(dialogueText, locale?) |
Lookup localized text. Uses engine locale by default. |
LsdeUtils.IsChoiceCondition(condition) |
True if condition references a previous choice (choice:<uuid>). |
LsdeUtils.GetChoiceConditionBlockUuid(condition) |
Extract block UUID from a choice condition. |
LsdeUtils.EvaluateConditionChain(conditions, evaluator) |
Evaluate AND/OR condition chain. Empty = true. |
LsdeUtils.EvaluateConditionGroups(groups, evaluator, dispatcher?) |
Evaluate 2D condition groups. Returns int (switch) or List<int> (dispatcher). |
LsdeUtils.FilterVisibleChoices(choices, evaluator, scene?) |
Filter choices by visibility conditions. |
Cross-Language Conformance
42 shared JSON tests across all runtimes: 42/42 passing.
License
Proprietary — distributed under the LSDE license.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on LsdeDialogEngine:
| Package | Downloads |
|---|---|
|
LsdeDialogEngine.Newtonsoft
Newtonsoft.Json loader for LsdeDialogEngine — polymorphic BlueprintBlock deserialization for Unity |
|
|
LsdeDialogEngine.SystemTextJson
System.Text.Json loader for LsdeDialogEngine — polymorphic BlueprintBlock deserialization out-of-the-box |
GitHub repositories
This package is not used by any popular GitHub repositories.