解析与导入
概述
engine 是格式无关的 — engine.init({ data }) 接收一个已反序列化的 BlueprintExport 对象,而不是文件或原始字符串。engine 不读取文件,也不依赖任何序列化库。
LSDE 编辑器以多种格式导出蓝图:
| 格式 | 完整图? | 用途 |
|---|---|---|
| JSON | 是 | 默认 — 所有平台支持最广泛 |
| XML | 是 | XML 管线、本地化工具 (XLIFF)、旧系统 |
| YAML | 是 | 人类可读编辑、git diff 友好、配置驱动工作流 |
| CSV | 否(扁平) | 本地化/翻译 — 导出到 Excel 或 Google Sheets |
CSV 导出按区域设置的对话文本扁平表。它不包含连接、条件或动作 — 不能用于 engine 运行时。
推荐解析器
| 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
csharp
// 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 });csharp
// 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 });csharp
// 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
cpp
#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.cpp
#include "XmlParser.h"
FXmlFile XmlFile(TEXT("blueprint.xml"));
auto* Root = XmlFile.GetRootNode();
// Walk XML nodes → map to BlueprintExport.Godot
gdscript
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.gdscript
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)
ts
// Bundlers (Vite, Webpack, esbuild) auto-parse .json imports.
import blueprintJson from './blueprint.json';
engine.init({ data: blueprintJson });ts
const json = fs.readFileSync('./blueprint.json', 'utf-8');
engine.init({ data: JSON.parse(json) });
// No polymorphism issues — JS objects are dynamically typed.ts
// 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 });ts
// npm install yaml
import { parse } from 'yaml';
const yml = fs.readFileSync('./blueprint.yaml', 'utf-8');
engine.init({ data: parse(yml) });CSharp (C#)
csharp
// 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 });csharp
// 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 });csharp
// 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.csharp
// 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++)
cpp
// 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});cpp
// 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.cpp
#include <tinyxml2.h>
tinyxml2::XMLDocument doc;
doc.LoadFile("blueprint.xml");
// Walk XML elements → map to BlueprintExport.cpp
// 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.多态分发
BlueprintScene.blocks 是 BlueprintBlock 的数组 — 一个通过 type 字段标识的可辨识联合类型,包含 5 个子类型:
type | 子类型 | 特有字段 |
|---|---|---|
DIALOG | DialogBlock | dialogueText, content, structureKey |
CHOICE | ChoiceBlock | choices |
CONDITION | ConditionBlock | conditions |
ACTION | ActionBlock | actions |
NOTE | NoteBlock | (无) |
动态类型语言(TypeScript、GDScript)自动处理 — 解析后的对象已包含所有字段。
静态类型语言(C#、C++)需要自定义转换器来读取 type 字段并构造正确的子类型。否则,dialogueText 或 choices 等子类型特有字段将被静默丢失。
配套包
如果您使用 LsdeDialogEngine.Newtonsoft 或 LsdeDialogEngine.SystemTextJson,这些转换器已经包含在内 — 只需调用 LsdeJson.Parse(json) 即可。以下代码仅用于手动集成。
CSharp — Newtonsoft.Json (Unity)
csharp
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+)
csharp
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
cpp
#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);
}