Parsing & Import
Overview
The engine is format-agnostic — engine.init({ data }) receives a deserialized BlueprintExport object, not a file or raw string. The engine never reads files and has no dependency on any serialization library.
The LSDE editor exports blueprints in multiple formats:
| Format | Full graph? | Use case |
|---|---|---|
| JSON | Yes | Default — widest parser support across all platforms |
| XML | Yes | XML-based pipelines, localization tools (XLIFF), legacy systems |
| YAML | Yes | Human-readable editing, git-friendly diffs, config-driven workflows |
| CSV | No (flat) | Localization / translation — export to Excel or Google Sheets |
CSV exports a flat table of dialogue text by locale. It does not contain connections, conditions, or actions — it cannot be used with the engine runtime.
Recommended Parsers
| Platform | JSON | XML | YAML |
|---|---|---|---|
| Unity | Newtonsoft.Json (com.unity.nuget.newtonsoft-json) | System.Xml (native) | not recommended |
| Unreal Engine | FJsonSerializer (native module Json) | XmlParser (native) | UnrealYAML (marketplace) |
| Godot | JSON.parse_string() (native) | XMLParser (native) | godot-yaml (GDExtension) |
| TypeScript | JSON.parse() (native) | fast-xml-parser | yaml |
| CSharp | System.Text.Json (.NET 5+) / Newtonsoft.Json | System.Xml (native) | YamlDotNet |
| CPP | nlohmann/json (header-only) | tinyxml2 / pugixml | yaml-cpp |
Unity
// Install: dotnet add package LsdeDialogEngine.Newtonsoft
// Unity Package Manager: com.unity.nuget.newtonsoft-json (auto-pulled)
using LsdeDialogEngine;
using LsdeDialogEngine.Newtonsoft;
var json = File.ReadAllText("blueprint.json");
var blueprint = LsdeJson.Parse(json);
engine.Init(new InitOptions { Data = blueprint });// Without companion package — manual converter setup
using Newtonsoft.Json;
using LsdeDialogEngine;
var json = File.ReadAllText("blueprint.json");
var settings = new JsonSerializerSettings();
settings.Converters.Add(new BlueprintBlockNewtonsoftConverter()); // see Polymorphic Dispatch
var blueprint = JsonConvert.DeserializeObject<BlueprintExport>(json, settings);
engine.Init(new InitOptions { Data = blueprint });// System.Xml is native — nothing to install
using System.Xml.Linq;
using LsdeDialogEngine;
var doc = XDocument.Load("blueprint.xml");
// Manual mapping from XElement → BlueprintExport required.
// See polymorphic dispatch section below for BlueprintBlock handling.Unreal Engine
#include "Json.h"
#include <lsde/engine.h>
FString JsonStr;
FFileHelper::LoadFileToString(JsonStr, TEXT("blueprint.json"));
TSharedPtr<FJsonObject> JsonObject;
auto Reader = TJsonReaderFactory<>::Create(JsonStr);
FJsonSerializer::Deserialize(Reader, JsonObject);
// Map FJsonObject → BlueprintExport manually.
// Dispatch on block "type" field for polymorphism.#include "XmlParser.h"
FXmlFile XmlFile(TEXT("blueprint.xml"));
auto* Root = XmlFile.GetRootNode();
// Walk XML nodes → map to BlueprintExport.Godot
var file = FileAccess.open("res://blueprint.json", FileAccess.READ)
var data = JSON.parse_string(file.get_as_text())
file.close()
engine.init({"data": data})
# No polymorphism issues — GDScript uses dynamic Dictionaries.var parser = XMLParser.new()
parser.open("res://blueprint.xml")
# Walk parser events → build Dictionary matching BlueprintExport structure.
# See Godot docs: XMLParser class reference.TypeScript (TS/JS)
// Bundlers (Vite, Webpack, esbuild) auto-parse .json imports.
import blueprintJson from './blueprint.json';
engine.init({ data: blueprintJson });const json = fs.readFileSync('./blueprint.json', 'utf-8');
engine.init({ data: JSON.parse(json) });
// No polymorphism issues — JS objects are dynamically typed.// npm install fast-xml-parser
import { XMLParser } from 'fast-xml-parser';
const xml = fs.readFileSync('./blueprint.xml', 'utf-8');
const parser = new XMLParser({ ignoreAttributes: false });
const data = parser.parse(xml);
engine.init({ data });// npm install yaml
import { parse } from 'yaml';
const yml = fs.readFileSync('./blueprint.yaml', 'utf-8');
engine.init({ data: parse(yml) });CSharp (C#)
// Install: dotnet add package LsdeDialogEngine.SystemTextJson
using LsdeDialogEngine;
using LsdeDialogEngine.Json;
var json = File.ReadAllText("blueprint.json");
var blueprint = LsdeJson.Parse(json);
engine.Init(new InitOptions { Data = blueprint });// Without companion package — manual converter setup
using System.Text.Json;
using System.Text.Json.Serialization;
using LsdeDialogEngine;
var json = File.ReadAllText("blueprint.json");
var options = new JsonSerializerOptions {
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters = {
new JsonStringEnumConverter(),
new BlueprintBlockConverter(), // see Polymorphic Dispatch
new BlockPropertyValueConverter(),
},
};
var blueprint = JsonSerializer.Deserialize<BlueprintExport>(json, options);
engine.Init(new InitOptions { Data = blueprint });// System.Xml is included in .NET — nothing to install.
using System.Xml.Linq;
using LsdeDialogEngine;
var doc = XDocument.Load("blueprint.xml");
// Manual mapping from XElement → BlueprintExport required.// dotnet add package YamlDotNet
using YamlDotNet.Serialization;
using LsdeDialogEngine;
var yaml = File.ReadAllText("blueprint.yaml");
var deserializer = new DeserializerBuilder().Build();
// YamlDotNet requires custom type converters for polymorphic blocks.CPP (C++)
// Include the optional JSON loader (requires nlohmann/json)
#include <lsde/json_loader.h>
auto blueprint = lsde::LsdeJson::parseFile("blueprint.json");
// or from string:
// auto blueprint = lsde::LsdeJson::parse(jsonString);
engine.init({blueprint});// Without json_loader.h — manual polymorphic dispatch
#include <nlohmann/json.hpp>
#include <lsde/engine.h>
std::ifstream f("blueprint.json");
auto j = nlohmann::json::parse(f);
auto blueprint = j.get<lsde::BlueprintExport>();
// Requires custom from_json — see polymorphic dispatch below.#include <tinyxml2.h>
tinyxml2::XMLDocument doc;
doc.LoadFile("blueprint.xml");
// Walk XML elements → map to BlueprintExport.// Install: apt install libyaml-cpp-dev (or include source)
#include <yaml-cpp/yaml.h>
auto node = YAML::LoadFile("blueprint.yaml");
// Requires custom YAML::convert specializations.Polymorphic Dispatch
BlueprintScene.blocks is an array of BlueprintBlock — a discriminated union with 5 subtypes identified by the type field:
type | Subtype | Specific fields |
|---|---|---|
DIALOG | DialogBlock | dialogueText, content, structureKey |
CHOICE | ChoiceBlock | choices |
CONDITION | ConditionBlock | conditions |
ACTION | ActionBlock | actions |
NOTE | NoteBlock | (none) |
Dynamically-typed languages (TypeScript, GDScript) handle this automatically — parsed objects already contain all fields.
Statically-typed languages (C#, C++) need a custom converter that reads the type field and constructs the correct subtype. Without it, subtype-specific fields like dialogueText or choices are silently lost.
Companion packages
If you use LsdeDialogEngine.Newtonsoft or LsdeDialogEngine.SystemTextJson, these converters are already included — just call LsdeJson.Parse(json). The code below is for manual integration only.
CSharp — Newtonsoft.Json (Unity)
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using LsdeDialogEngine;
class BlueprintBlockNewtonsoftConverter : JsonConverter<BlueprintBlock>
{
public override BlueprintBlock ReadJson(JsonReader reader, Type objectType,
BlueprintBlock existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var obj = JObject.Load(reader);
var type = obj["type"]?.ToString();
BlueprintBlock block = type switch
{
"DIALOG" => new DialogBlock(),
"CHOICE" => new ChoiceBlock(),
"CONDITION" => new ConditionBlock(),
"ACTION" => new ActionBlock(),
"NOTE" => new NoteBlock(),
_ => throw new JsonException($"Unknown block type: {type}")
};
serializer.Populate(obj.CreateReader(), block);
return block;
}
public override void WriteJson(JsonWriter writer, BlueprintBlock value, JsonSerializer serializer)
=> serializer.Serialize(writer, value, value.GetType());
}CSharp — System.Text.Json (.NET 5+)
using System.Text.Json;
using System.Text.Json.Serialization;
using LsdeDialogEngine;
class BlueprintBlockConverter : JsonConverter<BlueprintBlock>
{
public override BlueprintBlock Read(ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options)
{
using var doc = JsonDocument.ParseValue(ref reader);
var root = doc.RootElement;
var type = root.GetProperty("type").GetString();
var json = root.GetRawText();
return type switch
{
"DIALOG" => JsonSerializer.Deserialize<DialogBlock>(json, options)!,
"CHOICE" => JsonSerializer.Deserialize<ChoiceBlock>(json, options)!,
"CONDITION" => JsonSerializer.Deserialize<ConditionBlock>(json, options)!,
"ACTION" => JsonSerializer.Deserialize<ActionBlock>(json, options)!,
"NOTE" => JsonSerializer.Deserialize<NoteBlock>(json, options)!,
_ => throw new JsonException($"Unknown block type: {type}")
};
}
public override void Write(Utf8JsonWriter writer, BlueprintBlock value,
JsonSerializerOptions options)
=> JsonSerializer.Serialize(writer, value, value.GetType(), options);
}
class BlockPropertyValueConverter : JsonConverter<object>
{
public override object Read(ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options)
{
return reader.TokenType switch
{
JsonTokenType.String => reader.GetString(),
JsonTokenType.Number => reader.TryGetInt64(out var l) ? (object)(double)l : reader.GetDouble(),
JsonTokenType.True => true,
JsonTokenType.False => false,
JsonTokenType.Null => null,
_ => throw new JsonException($"Unexpected token {reader.TokenType}")
};
}
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
=> JsonSerializer.Serialize(writer, value, options);
}CPP — nlohmann/json
#include <nlohmann/json.hpp>
#include <lsde/types.h>
void from_json(const nlohmann::json& j, std::unique_ptr<lsde::BlueprintBlock>& block) {
auto type = j.at("type").get<std::string>();
if (type == "DIALOG") block = std::make_unique<lsde::DialogBlock>();
else if (type == "CHOICE") block = std::make_unique<lsde::ChoiceBlock>();
else if (type == "CONDITION") block = std::make_unique<lsde::ConditionBlock>();
else if (type == "ACTION") block = std::make_unique<lsde::ActionBlock>();
else if (type == "NOTE") block = std::make_unique<lsde::NoteBlock>();
else throw std::runtime_error("Unknown block type: " + type);
j.get_to(*block);
}