using System; using System.Collections.Generic; using System.Linq; using Yarn.Unity; namespace AibisDream.UI { internal readonly struct DeveloperVariableRecord { public readonly string Name; public readonly string Type; public readonly string Value; public readonly string Kind; public readonly bool IsGlobal; public readonly bool HasRuntimeOverride; public DeveloperVariableRecord( string name, string type, object value, string kind, bool isGlobal, bool hasRuntimeOverride) { Name = name; Type = type; Value = FormatValue(value); Kind = kind; IsGlobal = isGlobal; HasRuntimeOverride = hasRuntimeOverride; } private static string FormatValue(object value) { if (value == null) return "null"; if (value is bool boolean) return boolean ? "true" : "false"; if (value is float number) return number.ToString("0.###"); if (value is double doubleNumber) return doubleNumber.ToString("0.###"); return value.ToString(); } } internal static class DeveloperVariableSnapshot { public static DeveloperVariableRecord[] Capture(YarnVariableStorage storage, YarnProject project) { if (storage == null) { return Array.Empty(); } var values = new Dictionary(StringComparer.Ordinal); var runtimeNames = new HashSet(StringComparer.Ordinal); try { if (project?.InitialValues != null) { foreach (var pair in project.InitialValues) { values[pair.Key] = pair.Value; } } } catch { // YarnProject 正在切换或尚未编译完成时仍显示运行时覆盖值。 } var runtime = storage.GetAllVariables(); AddRuntime(runtime.FloatVariables, values, runtimeNames); AddRuntime(runtime.StringVariables, values, runtimeNames); AddRuntime(runtime.BoolVariables, values, runtimeNames); var result = new List(values.Count); foreach (var pair in values.OrderBy(item => item.Key, StringComparer.Ordinal)) { var effectiveValue = ResolveEffectiveValue(storage, pair.Key, pair.Value); var type = effectiveValue switch { bool => "Bool", string => "String", float or double or int or long => "Number", _ => effectiveValue?.GetType().Name ?? "Unknown" }; string kind; try { kind = storage.GetVariableKind(pair.Key).ToString(); } catch { kind = "Unknown"; } result.Add(new DeveloperVariableRecord( pair.Key, type, effectiveValue, kind, pair.Key.StartsWith("$global_", StringComparison.Ordinal), runtimeNames.Contains(pair.Key))); } return result.ToArray(); } private static void AddRuntime( Dictionary source, IDictionary values, ISet runtimeNames) { if (source == null) return; foreach (var pair in source) { values[pair.Key] = pair.Value; runtimeNames.Add(pair.Key); } } private static object ResolveEffectiveValue(YarnVariableStorage storage, string name, object fallback) { try { switch (fallback) { case bool when storage.TryGetValue(name, out bool boolean): return boolean; case string when storage.TryGetValue(name, out string text): return text; case float or double or int or long when storage.TryGetValue(name, out float number): return number; default: return fallback; } } catch { return fallback; } } } }