259 lines
7.5 KiB
C#
259 lines
7.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using AibisDream.Framework;
|
|
using AibisDream.SaveSystem;
|
|
using UnityEngine;
|
|
using Yarn;
|
|
using Yarn.Unity;
|
|
|
|
namespace AibisDream
|
|
{
|
|
/// <summary>
|
|
/// Yarn 运行时变量存储(VariableStorageBehaviour)。
|
|
/// 存档快照、落盘、深度维修容器见 SaveSystem 下各类。
|
|
/// </summary>
|
|
public class YarnVariableStorage : VariableStorageBehaviour
|
|
{
|
|
private const string VariablePrefix = "$";
|
|
private const string GlobalPrefix = "$global_";
|
|
|
|
private readonly Dictionary<string, object> _variableDict = new();
|
|
|
|
#region 变量设置
|
|
|
|
public override void SetValue(string variableName, bool boolValue)
|
|
{
|
|
SetStoredValue(variableName, boolValue);
|
|
}
|
|
|
|
public override void SetValue(string variableName, string stringValue)
|
|
{
|
|
SetStoredValue(variableName, stringValue);
|
|
}
|
|
|
|
public override void SetValue(string variableName, float floatValue)
|
|
{
|
|
SetStoredValue(variableName, floatValue);
|
|
}
|
|
|
|
private void SetStoredValue<T>(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();
|
|
EnumEventSystem.Global.Send(StorageEvent.VariablesCleared);
|
|
}
|
|
|
|
public void ClearLocal()
|
|
{
|
|
var locals = _variableDict.Keys.Where(item => ValidateVariableName(item) == VariableType.Local).ToArray();
|
|
foreach (var localKey in locals)
|
|
{
|
|
_variableDict.Remove(localKey);
|
|
}
|
|
|
|
if (locals.Length > 0)
|
|
{
|
|
EnumEventSystem.Global.Send(StorageEvent.VariablesCleared);
|
|
}
|
|
}
|
|
|
|
#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<T>(string variableName, out T result)
|
|
{
|
|
var variableType = ValidateVariableName(variableName);
|
|
if (variableType == VariableType.Illegal)
|
|
{
|
|
result = default;
|
|
return false;
|
|
}
|
|
|
|
switch (GetVariableKind(variableName))
|
|
{
|
|
case VariableKind.Stored:
|
|
if (_variableDict.TryGetValue(variableName, out var value) && value is T target)
|
|
{
|
|
result = target;
|
|
return true;
|
|
}
|
|
|
|
if (Program == null)
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"Can't get initial value for variable {variableName}, because {nameof(Program)} is not set");
|
|
}
|
|
|
|
return Program.TryGetInitialValue(variableName, out result);
|
|
|
|
case VariableKind.Smart:
|
|
if (SmartVariableEvaluator == null)
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"Can't get value for smart variable {variableName}, because {nameof(SmartVariableEvaluator)} is not set");
|
|
}
|
|
|
|
return SmartVariableEvaluator.TryGetSmartVariable(variableName, out result);
|
|
|
|
default:
|
|
result = default;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 序列化(供 SnapshotCapture / SnapshotRestore 使用)
|
|
|
|
public override void SetAllVariables(Dictionary<string, float> floats, Dictionary<string, string> strings,
|
|
Dictionary<string, bool> 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<string, float> FloatVariables, Dictionary<string, string> StringVariables,
|
|
Dictionary<string, bool> BoolVariables) GetAllVariables()
|
|
{
|
|
var floatDict = new Dictionary<string, float>();
|
|
var stringDict = new Dictionary<string, string>();
|
|
var boolDict = new Dictionary<string, bool>();
|
|
|
|
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;
|
|
SnapshotRegistry.EnsureInitialized();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
public enum VariableType
|
|
{
|
|
Local,
|
|
Global,
|
|
Illegal
|
|
}
|
|
|
|
public struct VariableItem
|
|
{
|
|
public string variableName;
|
|
public object value;
|
|
}
|
|
}
|