diff --git a/Assets/Scripts/Dialog System/BaseYarnCommand.cs b/Assets/Scripts/Dialog System/BaseYarnCommand.cs
index efd9e26d8..faf3ab03b 100644
--- a/Assets/Scripts/Dialog System/BaseYarnCommand.cs
+++ b/Assets/Scripts/Dialog System/BaseYarnCommand.cs
@@ -15,7 +15,7 @@ namespace AibisDream
public static void NextYarn(string exitName = null)
{
EnumEventSystem.Global.Send(EventEnum.NextYarn);
- StorageSystem.Instance.ClearLocal();
+ YarnVariableStorage.Instance.ClearLocal();
DialogController.Instance.StartCoroutine(GameManager.Instance.NextSceneSo(exitName));
}
diff --git a/Assets/Scripts/Dialog System/DialogController.cs b/Assets/Scripts/Dialog System/DialogController.cs
index cd2dd40ce..816eae864 100644
--- a/Assets/Scripts/Dialog System/DialogController.cs
+++ b/Assets/Scripts/Dialog System/DialogController.cs
@@ -83,7 +83,7 @@ namespace AibisDream
public void StopDialog()
{
_ = _dialogueRunner.Stop();
- StorageSystem.Instance.Clear();
+ YarnVariableStorage.Instance.Clear();
DialogUIManager.Instance.HideDialog();
}
diff --git a/Assets/Scripts/FixSystemNew/BodyModule/CableSystem.cs b/Assets/Scripts/FixSystemNew/BodyModule/CableSystem.cs
index 46cfb6c71..a9e3aa142 100644
--- a/Assets/Scripts/FixSystemNew/BodyModule/CableSystem.cs
+++ b/Assets/Scripts/FixSystemNew/BodyModule/CableSystem.cs
@@ -67,7 +67,7 @@ namespace AibisDream.FixSystem
private void LoadCableState()
{
- if (StorageSystem.Instance.TryGetValue(CableRetractedKey, out bool savedRetractedState))
+ if (YarnVariableStorage.Instance.TryGetValue(CableRetractedKey, out bool savedRetractedState))
{
if (isCableRetracted)
{
@@ -89,7 +89,7 @@ namespace AibisDream.FixSystem
private void SaveCableState()
{
Debug.Log("Save cableRetractedstate" + isCableRetracted);
- StorageSystem.Instance.SetValue(CableRetractedKey, isCableRetracted);
+ YarnVariableStorage.Instance.SetValue(CableRetractedKey, isCableRetracted);
}
private void Update()
diff --git a/Assets/Scripts/FixSystemNew/Screen System/FixPanel/CablePanel.cs b/Assets/Scripts/FixSystemNew/Screen System/FixPanel/CablePanel.cs
index dce151fbe..9e3c1b7d8 100644
--- a/Assets/Scripts/FixSystemNew/Screen System/FixPanel/CablePanel.cs
+++ b/Assets/Scripts/FixSystemNew/Screen System/FixPanel/CablePanel.cs
@@ -95,7 +95,7 @@ namespace AibisDream.FixSystem
}
// 从存储系统读取
- if (!StorageSystem.Instance.TryGetValue(CableRetractedKey, out bool savedRetractedState))
+ if (!YarnVariableStorage.Instance.TryGetValue(CableRetractedKey, out bool savedRetractedState))
return;
if (savedRetractedState)
@@ -112,7 +112,7 @@ namespace AibisDream.FixSystem
private void SaveCableState()
{
Debug.Log("Save cableRetractedstate" + isCableRetracted);
- StorageSystem.Instance.SetValue(CableRetractedKey, isCableRetracted);
+ YarnVariableStorage.Instance.SetValue(CableRetractedKey, isCableRetracted);
}
private void Update()
diff --git a/Assets/Scripts/FixSystemNew/WhackMole/WhackMoleSystem.cs b/Assets/Scripts/FixSystemNew/WhackMole/WhackMoleSystem.cs
index b57ac866c..59dc3e6b0 100644
--- a/Assets/Scripts/FixSystemNew/WhackMole/WhackMoleSystem.cs
+++ b/Assets/Scripts/FixSystemNew/WhackMole/WhackMoleSystem.cs
@@ -58,17 +58,17 @@ namespace AibisDream.FixSystem
_whackMoleHandler.EndWhackGame();
var whackRes = _whackMoleHandler.res;
Debug.Log($"结果:共计{whackRes.totalMoleNum}个,成功击中{whackRes.hitMoleNum}个");
- StorageSystem.Instance.SetValue("$whackRes.totalMoleNum", whackRes.totalMoleNum);
- StorageSystem.Instance.SetValue("$whackRes.hitMoleNum", whackRes.hitMoleNum);
+ YarnVariableStorage.Instance.SetValue("$whackRes.totalMoleNum", whackRes.totalMoleNum);
+ YarnVariableStorage.Instance.SetValue("$whackRes.hitMoleNum", whackRes.hitMoleNum);
// 流水线结果
if (_data.HasPipeline())
{
var pipelineRes = pipelineSystem.res;
Debug.Log(
$"流水线结果:共计{pipelineRes.totalProductNum}个,成功{pipelineRes.successNum}个,失败{pipelineRes.failNum}个");
- StorageSystem.Instance.SetValue("$whackRes.totalProductNum", pipelineRes.totalProductNum);
- StorageSystem.Instance.SetValue("$whackRes.successNum", pipelineRes.successNum);
- StorageSystem.Instance.SetValue("$whackRes.failNum", pipelineRes.failNum);
+ YarnVariableStorage.Instance.SetValue("$whackRes.totalProductNum", pipelineRes.totalProductNum);
+ YarnVariableStorage.Instance.SetValue("$whackRes.successNum", pipelineRes.successNum);
+ YarnVariableStorage.Instance.SetValue("$whackRes.failNum", pipelineRes.failNum);
}
// 结束
DialogController.Instance?.StartDialogNode("打地鼠结束");
diff --git a/Assets/Scripts/Game Loop/YarnVariableStorage.cs b/Assets/Scripts/Game Loop/YarnVariableStorage.cs
new file mode 100644
index 000000000..35b2dfe04
--- /dev/null
+++ b/Assets/Scripts/Game Loop/YarnVariableStorage.cs
@@ -0,0 +1,232 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using AibisDream.Framework;
+using AibisDream.SaveSystem;
+using UnityEngine;
+using Yarn.Unity;
+
+namespace AibisDream
+{
+ ///
+ /// Yarn 运行时变量存储(VariableStorageBehaviour)。
+ /// 存档快照、落盘、深度维修容器见 SaveSystem 下各类。
+ ///
+ public class YarnVariableStorage : VariableStorageBehaviour
+ {
+ private const string VariablePrefix = "$";
+ private const string GlobalPrefix = "$global_";
+
+ private readonly Dictionary _variableDict = new();
+
+ #region 变量设置
+
+ public override void SetValue(string variableName, bool boolValue)
+ {
+ SetValue(variableName, boolValue);
+ }
+
+ public override void SetValue(string variableName, string stringValue)
+ {
+ SetValue(variableName, stringValue);
+ }
+
+ public override void SetValue(string variableName, float floatValue)
+ {
+ SetValue(variableName, floatValue);
+ }
+
+ private void SetValue(string variableName, T value)
+ {
+ var variableType = ValidateVariableName(variableName);
+
+ if (variableType == VariableType.Illegal)
+ {
+ Debug.LogError($"{variableName}: 缺少$前缀");
+ return;
+ }
+
+ _variableDict[variableName] = value;
+
+ var variableItem = new VariableItem
+ {
+ variableName = variableName,
+ value = value
+ };
+ EnumEventSystem.Global.Send(StorageEvent.VariableSet, variableItem);
+ }
+
+ public override void Clear()
+ {
+ _variableDict.Clear();
+ }
+
+ public void ClearLocal()
+ {
+ var locals = _variableDict.Keys.Where(item => ValidateVariableName(item) == VariableType.Local).ToArray();
+ foreach (var localKey in locals)
+ {
+ _variableDict.Remove(localKey);
+ }
+ }
+
+ #endregion
+
+ #region 变量获取
+
+ public override bool Contains(string variableName)
+ {
+ var variableType = ValidateVariableName(variableName);
+ if (variableType == VariableType.Illegal)
+ {
+ return false;
+ }
+
+ return _variableDict.ContainsKey(variableName);
+ }
+
+ public override bool TryGetValue(string variableName, out T result)
+ {
+ var variableType = ValidateVariableName(variableName);
+ if (variableType == VariableType.Illegal)
+ {
+ result = default;
+ return false;
+ }
+
+ if (_variableDict.TryGetValue(variableName, out var value))
+ {
+ if (value is T target)
+ {
+ result = target;
+ return true;
+ }
+ }
+
+ result = default;
+ return false;
+ }
+
+ #endregion
+
+ #region 序列化(供 SnapshotCapture / SnapshotRestore 使用)
+
+ public override void SetAllVariables(Dictionary floats, Dictionary strings,
+ Dictionary bools, bool clear = true)
+ {
+ if (clear)
+ {
+ Clear();
+ }
+
+ if (floats != null)
+ {
+ foreach (var value in floats)
+ {
+ SetValue(value.Key, value.Value);
+ }
+ }
+
+ if (strings != null)
+ {
+ foreach (var value in strings)
+ {
+ SetValue(value.Key, value.Value);
+ }
+ }
+
+ if (bools != null)
+ {
+ foreach (var value in bools)
+ {
+ SetValue(value.Key, value.Value);
+ }
+ }
+ }
+
+ public override (Dictionary FloatVariables, Dictionary StringVariables,
+ Dictionary BoolVariables) GetAllVariables()
+ {
+ var floatDict = new Dictionary();
+ var stringDict = new Dictionary();
+ var boolDict = new Dictionary();
+
+ foreach (var variablePair in _variableDict)
+ {
+ switch (variablePair.Value)
+ {
+ case float:
+ {
+ var value = Convert.ToSingle(variablePair.Value);
+ floatDict.Add(variablePair.Key, value);
+ break;
+ }
+ case string:
+ {
+ var value = Convert.ToString(variablePair.Value);
+ stringDict.Add(variablePair.Key, value);
+ break;
+ }
+ case bool:
+ {
+ var value = Convert.ToBoolean(variablePair.Value);
+ boolDict.Add(variablePair.Key, value);
+ break;
+ }
+ default:
+ Debug.Log($"{variablePair.Key} is not a valid type");
+ break;
+ }
+ }
+
+ return (floatDict, stringDict, boolDict);
+ }
+
+ #endregion
+
+ private static VariableType ValidateVariableName(string variableName)
+ {
+ if (string.IsNullOrWhiteSpace(variableName) || !variableName.StartsWith(VariablePrefix))
+ {
+ return VariableType.Illegal;
+ }
+
+ if (variableName.StartsWith(GlobalPrefix))
+ {
+ return VariableType.Global;
+ }
+
+ return VariableType.Local;
+ }
+
+ #region 单例
+
+ public static YarnVariableStorage Instance { get; private set; }
+
+ private void Awake()
+ {
+ if (Instance != null)
+ {
+ Destroy(gameObject);
+ }
+
+ Instance = this;
+ SnapshotBootstrap.EnsureInitialized();
+ }
+
+ #endregion
+ }
+
+ public enum VariableType
+ {
+ Local,
+ Global,
+ Illegal
+ }
+
+ public struct VariableItem
+ {
+ public string variableName;
+ public object value;
+ }
+}
diff --git a/Assets/Scripts/Game Loop/YarnVariableStorage.cs.meta b/Assets/Scripts/Game Loop/YarnVariableStorage.cs.meta
new file mode 100644
index 000000000..6af3a5a80
--- /dev/null
+++ b/Assets/Scripts/Game Loop/YarnVariableStorage.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bd2f44edfbd942b49bb7a37f80d7a5eb
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleSystem.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleSystem.cs
index 42e62b7e1..95e77202a 100644
--- a/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleSystem.cs
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleSystem.cs
@@ -123,7 +123,7 @@ namespace AibisDream
var validateResult = validator.Validate(grid.GetShapes());
var shapesInGrid = grid.GetShapes().Select(s => s.BlockShapeData.blockShapeInfo.shapeName).ToArray();
- StorageSystem.Instance.SetValue("$shapesInGrid", string.Join(",", shapesInGrid));
+ YarnVariableStorage.Instance.SetValue("$shapesInGrid", string.Join(",", shapesInGrid));
// 如果验证通过, 则设置变量并弹出对话
if (validateResult.isPass)
@@ -236,7 +236,7 @@ namespace AibisDream
// 点击形状
blockPuzzlePanel.ShowShapeInScreen(blockShape.BlockShapeData.blockShapeInfo);
// 播放事件节点
- StorageSystem.Instance.SetValue("$selectedShape", blockShape.BlockShapeData.blockShapeInfo.shapeName);
+ YarnVariableStorage.Instance.SetValue("$selectedShape", blockShape.BlockShapeData.blockShapeInfo.shapeName);
SingleCastEventSystem.Global.Trigger(DialogEventEnum.StartNode, "ShapeSelected");
}
diff --git a/Assets/Scripts/MiniGame/HuoShan/SalesSystem/KnobController.cs b/Assets/Scripts/MiniGame/HuoShan/SalesSystem/KnobController.cs
index c719e1211..f39bbfc05 100644
--- a/Assets/Scripts/MiniGame/HuoShan/SalesSystem/KnobController.cs
+++ b/Assets/Scripts/MiniGame/HuoShan/SalesSystem/KnobController.cs
@@ -707,7 +707,7 @@ namespace AibisDream.MiniGame.HuoShan
private void TriggerFailure()
{
_failCount++;
- StorageSystem.Instance?.SetValue("$knobFailCount", (float)_failCount);
+ YarnVariableStorage.Instance?.SetValue("$knobFailCount", (float)_failCount);
_hasFailed = true;
Debug.Log($"[KnobController] Failure #{_failCount} at {_currentPower:F1}%, waiting for snapback...");
diff --git a/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SalesManager.cs b/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SalesManager.cs
index 02c735180..423f85f11 100644
--- a/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SalesManager.cs
+++ b/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SalesManager.cs
@@ -307,7 +307,7 @@ namespace AibisDream.MiniGame.Language
if (_currentTurnIndex > totalTurns) return;
// 滑片开始转动前,先触发 ChipModule 解释当前步骤(Stage3 等配合)
- StorageSystem.Instance?.SetValue("$salesTurnIndex", (float)_currentTurnIndex);
+ YarnVariableStorage.Instance?.SetValue("$salesTurnIndex", (float)_currentTurnIndex);
if (!string.IsNullOrEmpty(crankSlideStartNode))
DialogController.Instance?.StartDialogNode(crankSlideStartNode);
@@ -327,7 +327,7 @@ namespace AibisDream.MiniGame.Language
{
if (string.IsNullOrEmpty(crankCompleteNode)) return;
- StorageSystem.Instance?.SetValue("$salesTurnIndex", (float)_currentTurnIndex);
+ YarnVariableStorage.Instance?.SetValue("$salesTurnIndex", (float)_currentTurnIndex);
DialogController.Instance?.StartDialogNode(crankCompleteNode);
}
diff --git a/Assets/Scripts/MiniGame/Tarot/TarotManager.cs b/Assets/Scripts/MiniGame/Tarot/TarotManager.cs
index 5d6560e22..f15cdd0df 100644
--- a/Assets/Scripts/MiniGame/Tarot/TarotManager.cs
+++ b/Assets/Scripts/MiniGame/Tarot/TarotManager.cs
@@ -164,7 +164,7 @@ namespace AibisDream.MiniGame.Tarot
{
_isCardSelected = true;
_selectedIndex = card.Index;
- StorageSystem.Instance?.SetValue("$tarotSelectedIndex", (float)card.Index);
+ YarnVariableStorage.Instance?.SetValue("$tarotSelectedIndex", (float)card.Index);
}
private void OnDestroy()
diff --git a/Assets/Scripts/UI/DialogUI/VariableBar.cs b/Assets/Scripts/UI/DialogUI/VariableBar.cs
index a35c4700e..d2aa9c728 100644
--- a/Assets/Scripts/UI/DialogUI/VariableBar.cs
+++ b/Assets/Scripts/UI/DialogUI/VariableBar.cs
@@ -19,7 +19,7 @@ namespace AibisDream.UI
{
// 读取存储中所有变量并打印
- var variables = StorageSystem.Instance.GetAllVariables();
+ var variables = YarnVariableStorage.Instance.GetAllVariables();
PrintAllVariables(variables);
EnumEventSystem.Global.Register(StorageEvent.VariableSet, OnVariableUpdate);
}
diff --git a/Assets/Scripts/Utility/GlobalVariableKit.cs b/Assets/Scripts/Utility/GlobalVariableKit.cs
index 0c83ca7a0..24fbe65b3 100644
--- a/Assets/Scripts/Utility/GlobalVariableKit.cs
+++ b/Assets/Scripts/Utility/GlobalVariableKit.cs
@@ -4,14 +4,14 @@
{
public static bool IsPlugHighLight
{
- get => !(StorageSystem.Instance.TryGetValue("$global.IsPlugHighLight", out bool res) && res);
- set => StorageSystem.Instance.SetValue("$global.IsPlugHighLight", !value);
+ get => !(YarnVariableStorage.Instance.TryGetValue("$global.IsPlugHighLight", out bool res) && res);
+ set => YarnVariableStorage.Instance.SetValue("$global.IsPlugHighLight", !value);
}
public static bool IsCordHighLight
{
- get => !(StorageSystem.Instance.TryGetValue("$global.IsCurdHighLight", out bool res) && res);
- set => StorageSystem.Instance.SetValue("$global.IsCurdHighLight", !value);
+ get => !(YarnVariableStorage.Instance.TryGetValue("$global.IsCurdHighLight", out bool res) && res);
+ set => YarnVariableStorage.Instance.SetValue("$global.IsCurdHighLight", !value);
}
}
}
\ No newline at end of file