117 lines
3.6 KiB
C#
117 lines
3.6 KiB
C#
using System.Collections.Generic;
|
||
using Sirenix.OdinInspector;
|
||
using UnityEngine;
|
||
|
||
namespace SLSUtilities.General
|
||
{
|
||
/// <summary>
|
||
/// 一个复合布尔值类,支持多来源修改和优先级系统。
|
||
/// 可以将多个来源对布尔值的修改综合起来,由高优先级的修改决定最终结果。
|
||
/// </summary>
|
||
[InlineProperty]
|
||
[HideReferenceObjectPicker]
|
||
public class CompoundBool
|
||
{
|
||
/// <summary>
|
||
/// 返回当前生效优先级层级的计数。
|
||
/// </summary>
|
||
[ShowInInspector]
|
||
[LabelText("True Count"), LabelWidth(70)]
|
||
[HorizontalGroup("Stats", Width = 100)]
|
||
public int TrueCount => GetEffectiveCount();
|
||
|
||
private SortedList<int, int> counts = new SortedList<int, int>();
|
||
private bool isDirty = true;
|
||
private bool cachedValue;
|
||
|
||
/// <summary>
|
||
/// 获取最终计算出的布尔值。
|
||
/// </summary>
|
||
[ShowInInspector]
|
||
[LabelText("Value"), LabelWidth(50)]
|
||
[HorizontalGroup("Stats", Width = 100)]
|
||
public bool Value
|
||
{
|
||
get
|
||
{
|
||
if (isDirty) RecalculateValue();
|
||
return cachedValue;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化 CompoundBool。
|
||
/// </summary>
|
||
/// <param name="initialValue">初始值。如果为 true,将在优先级 0 初始化计数为 1。</param>
|
||
public CompoundBool(bool initialValue = false)
|
||
{
|
||
if (initialValue) Modify(true, 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在指定的优先级层级修改布尔值。
|
||
/// 高优先级的值会覆盖低优先级的值。
|
||
/// 如果某个非零优先级的计数变为零,将自动移除该优先级层级。
|
||
/// </summary>
|
||
/// <param name="marker">修改意图(true 增加计数,false 减少计数)。</param>
|
||
/// <param name="priority">优先级,默认为 0。数字越大优先级越高。</param>
|
||
public void Modify(bool marker, int priority = 0)
|
||
{
|
||
if (counts.TryGetValue(priority, out int currentCount))
|
||
{
|
||
counts[priority] = marker ? currentCount + 1 : currentCount - 1;
|
||
}
|
||
else
|
||
{
|
||
counts.Add(priority, marker ? 1 : -1);
|
||
}
|
||
|
||
if(priority != 0 && counts[priority] == 0)
|
||
{
|
||
counts.Remove(priority);
|
||
}
|
||
|
||
isDirty = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置所有修改,恢复到默认状态(false)。
|
||
/// </summary>
|
||
public void Reset()
|
||
{
|
||
counts.Clear();
|
||
isDirty = true;
|
||
}
|
||
|
||
private void RecalculateValue()
|
||
{
|
||
// 从最高优先级(列表末尾)向最低优先级迭代
|
||
for (int i = counts.Count - 1; i >= 0; i--)
|
||
{
|
||
int count = counts.Values[i];
|
||
if (count != 0)
|
||
{
|
||
cachedValue = count > 0;
|
||
isDirty = false;
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 如果所有计数都为零或列表为空,则默认为 false
|
||
cachedValue = false;
|
||
isDirty = false;
|
||
}
|
||
|
||
private int GetEffectiveCount()
|
||
{
|
||
// 从最高优先级向最低优先级迭代
|
||
for (int i = counts.Count - 1; i >= 0; i--)
|
||
{
|
||
int count = counts.Values[i];
|
||
if (count != 0) return count;
|
||
}
|
||
return 0;
|
||
}
|
||
}
|
||
}
|