新增磁导航内部交管和信号交互界面
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using MiGu.Server.Launcher;
|
||||
|
||||
namespace MiGu.Server.Signal;
|
||||
|
||||
public sealed record SignalColumn(string Key, string Label, string Type, IReadOnlyList<string>? Options = null, string? Group = null);
|
||||
|
||||
public sealed record SignalTableDef(
|
||||
string Id,
|
||||
string Title,
|
||||
string Category,
|
||||
string FileName,
|
||||
IReadOnlyList<SignalColumn> Columns);
|
||||
|
||||
/// <summary>
|
||||
/// 读写 SimpleLite 工作目录 <c>Config/Signal/*.json</c>,供迷毂「数据中心」表格编辑。
|
||||
/// 表结构优先从 StandardScene.Signal.dll 反射;无插件时才读 signal-tables.json。
|
||||
/// </summary>
|
||||
public sealed class SignalDataStore
|
||||
{
|
||||
private static readonly JsonSerializerOptions FileJson = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
};
|
||||
|
||||
private static readonly object FileLock = new();
|
||||
|
||||
private readonly SimpleLiteLauncher _launcher;
|
||||
private IReadOnlyList<SignalTableDef>? _cachedTables;
|
||||
private long _cachedSignature;
|
||||
|
||||
public SignalDataStore(SimpleLiteLauncher launcher) => _launcher = launcher;
|
||||
|
||||
public IReadOnlyList<SignalTableDef> GetTables()
|
||||
{
|
||||
var sig = SignalTableManifestLoader.ComputeManifestSignature(_launcher);
|
||||
if (_cachedTables == null || sig != _cachedSignature)
|
||||
{
|
||||
_cachedTables = SignalTableManifestLoader.Load(_launcher);
|
||||
_cachedSignature = sig;
|
||||
}
|
||||
|
||||
return _cachedTables;
|
||||
}
|
||||
|
||||
public SignalTableDef? Find(string id) =>
|
||||
GetTables().FirstOrDefault(t => string.Equals(t.Id, id, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
public string? ResolveWorkingDirectory() => _launcher.ResolveWorkingDirectory();
|
||||
|
||||
public (string? Path, string? Error) ResolveFile(SignalTableDef table, bool createDir)
|
||||
{
|
||||
var wd = _launcher.ResolveWorkingDirectory();
|
||||
if (string.IsNullOrWhiteSpace(wd))
|
||||
return (null, "未找到 SimpleLite 工作目录,无法定位 Config/Signal");
|
||||
|
||||
var dest = Path.GetFullPath(Path.Combine(wd, "Config", "Signal", table.FileName));
|
||||
if (File.Exists(dest))
|
||||
return (dest, null);
|
||||
|
||||
if (createDir)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dir = Path.GetDirectoryName(dest);
|
||||
if (!string.IsNullOrEmpty(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (null, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return (dest, null);
|
||||
}
|
||||
|
||||
public JsonArray LoadRows(SignalTableDef table)
|
||||
{
|
||||
var (path, _) = ResolveFile(table, createDir: false);
|
||||
if (path == null || !File.Exists(path))
|
||||
return new JsonArray();
|
||||
|
||||
lock (FileLock)
|
||||
{
|
||||
var json = File.ReadAllText(path);
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
return new JsonArray();
|
||||
var node = JsonNode.Parse(json);
|
||||
if (node is JsonArray arr)
|
||||
return arr;
|
||||
return new JsonArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveRows(SignalTableDef table, JsonArray rows)
|
||||
{
|
||||
var (path, error) = ResolveFile(table, createDir: true);
|
||||
if (path == null)
|
||||
throw new InvalidOperationException(error ?? "无法解析信号配置文件路径");
|
||||
|
||||
var dir = Path.GetDirectoryName(path);
|
||||
if (!string.IsNullOrEmpty(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
lock (FileLock)
|
||||
File.WriteAllText(path, rows.ToJsonString(FileJson));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user