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)
);
}
}
}