using System.Collections.Generic; using System.Globalization; using UnityEngine; namespace Ichni.Story { /// /// 全局剧情变量的统一数据枢纽。 /// 所有外部系统(包括 Yarn、UI、小游戏)读写剧情变量的唯一官方入口。 /// 自动桥接至 GameSaveManager 的 StorySaveModule 中持久化。 /// public static class StoryVariables { // 应对游戏尚未初始化(或者单独测试场景)的内存兜底 private static readonly StoryVariablesSave _fallback = new StoryVariablesSave(); private static StoryVariablesSave Variables { get { if (GameSaveManager.instance != null && GameSaveManager.instance.StorySaveModule != null) return GameSaveManager.instance.StorySaveModule.variables; return _fallback; } } // ── 读取 ──────────────────────────────────────────────────────────────── public static float GetFloat(string key, float defaultValue = 0f) { StoryVariablesSave vars = Variables; if (vars.floatVariables.TryGetValue(key, out float f)) return f; if (vars.boolVariables.TryGetValue(key, out bool b)) return b ? 1f : 0f; if (vars.stringVariables.TryGetValue(key, out string s) && float.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out float p)) return p; return defaultValue; } public static int GetInt(string key, int defaultValue = 0) { StoryVariablesSave vars = Variables; if (vars.floatVariables.TryGetValue(key, out float f)) return Mathf.RoundToInt(f); if (vars.boolVariables.TryGetValue(key, out bool b)) return b ? 1 : 0; if (vars.stringVariables.TryGetValue(key, out string s) && float.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out float p)) return Mathf.RoundToInt(p); return defaultValue; } public static bool GetBool(string key, bool defaultValue = false) { StoryVariablesSave vars = Variables; if (vars.boolVariables.TryGetValue(key, out bool b)) return b; if (vars.floatVariables.TryGetValue(key, out float f)) return f != 0f; if (vars.stringVariables.TryGetValue(key, out string s) && bool.TryParse(s, out bool p)) return p; return defaultValue; } public static string GetString(string key, string defaultValue = "") { StoryVariablesSave vars = Variables; if (vars.stringVariables.TryGetValue(key, out string s)) return s; if (vars.floatVariables.TryGetValue(key, out float f)) return f.ToString(CultureInfo.InvariantCulture); if (vars.boolVariables.TryGetValue(key, out bool b)) return b.ToString(); return defaultValue; } public static bool HasVariable(string key) { StoryVariablesSave vars = Variables; return vars.floatVariables.ContainsKey(key) || vars.boolVariables.ContainsKey(key) || vars.stringVariables.ContainsKey(key); } // ── 写入 ──────────────────────────────────────────────────────────────── public static void SetFloat(string key, float value) { RemoveStaleEntries(key, keepFloat: true, keepString: false, keepBool: false); Variables.floatVariables[key] = value; } public static void SetInt(string key, int value) { // 在 Yarn/存档底层中数字统一存为 float,避免双字典冗余 SetFloat(key, value); } public static void SetBool(string key, bool value) { RemoveStaleEntries(key, keepFloat: false, keepString: false, keepBool: true); Variables.boolVariables[key] = value; } public static void SetString(string key, string value) { RemoveStaleEntries(key, keepFloat: false, keepString: true, keepBool: false); Variables.stringVariables[key] = value; } public static void ClearAll() { StoryVariablesSave vars = Variables; vars.floatVariables.Clear(); vars.stringVariables.Clear(); vars.boolVariables.Clear(); } private static void RemoveStaleEntries(string name, bool keepFloat, bool keepString, bool keepBool) { StoryVariablesSave vars = Variables; if (!keepFloat) vars.floatVariables.Remove(name); if (!keepString) vars.stringVariables.Remove(name); if (!keepBool) vars.boolVariables.Remove(name); } // ── 字典批量操作(内部供 Yarn Adapter 使用) ───────────────────────────── internal static void SetAllVariables(Dictionary floats, Dictionary strings, Dictionary bools, bool clear = true) { StoryVariablesSave vars = Variables; if (clear) { vars.floatVariables.Clear(); vars.stringVariables.Clear(); vars.boolVariables.Clear(); } if (floats != null) foreach (var kv in floats) vars.floatVariables[kv.Key] = kv.Value; if (strings != null) foreach (var kv in strings) vars.stringVariables[kv.Key] = kv.Value; if (bools != null) foreach (var kv in bools) vars.boolVariables[kv.Key] = kv.Value; } internal static (Dictionary floats, Dictionary strings, Dictionary bools) GetAllVariables() { StoryVariablesSave vars = Variables; return ( new Dictionary(vars.floatVariables), new Dictionary(vars.stringVariables), new Dictionary(vars.boolVariables) ); } } }