BITKit/Src/Unity/BitMask/ScriptableBitMask.cs

192 lines
7.1 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using AYellowpaper.SerializedCollections;
using BITKit;
using UnityEngine;
using UnityEngine.Pool;
using UnityEngine.UIElements;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Net.BITKit.BitMask
{
public class ScriptableBitMask : ScriptableObject,ISerializationCallbackReceiver
{
[SerializeField] public ScriptableImplements implements;
internal readonly Dictionary<string, List<string>> Dictionary=new();
[SerializeField] public string yaml;
public Type Type => implements.Type;
public Type[] Types => implements ? implements.Types : Array.Empty<Type>();
private void OnEnable()
{
OnBeforeSerialize();
}
public void OnBeforeSerialize()
{
if(string.IsNullOrEmpty(yaml))return;
var deserializer = new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance) // 驼峰命名
.Build();
Dictionary.Clear();
var newDictionary = deserializer.Deserialize<Dictionary<string, List<string>>>(yaml);
foreach (var pair in newDictionary)
{
Dictionary[pair.Key] = pair.Value;
}
}
public void OnAfterDeserialize()
{
if(Dictionary.Count is 0)return;
var serializer = new SerializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.Build();
yaml = serializer.Serialize(Dictionary);
}
public IDictionary<Type,HashSet<Type>> FlagMask
{
get
{
var typeDictionary = implements.Types.ToDictionary(x => x.Name, x => x);
var nextDictionary = new Dictionary<Type, HashSet<Type>>();
foreach (var (key, d) in Dictionary)
{
if (typeDictionary.TryGetValue(key, out var type) is false) continue;
var hashSet = new HashSet<Type>();
foreach (var x in d)
{
if(typeDictionary.TryGetValue(x,out var t1) is false)continue;
hashSet.Add(t1);
}
nextDictionary[type]=hashSet;
}
foreach (var type in Types)
{
if (nextDictionary.TryAdd(type, new HashSet<Type>())) ;
}
return nextDictionary;
}
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(ScriptableBitMask),true)]
public sealed class ScriptableBitMaskEditor:Editor
{
private const int CellSize = 24;
public override VisualElement CreateInspectorGUI()
{
if (serializedObject.targetObject is not ScriptableBitMask scriptableBitMask)
return base.CreateInspectorGUI();
var inspector = new VisualElement
{
style =
{
flexDirection = FlexDirection.Column
}
};
var defaultPropertyFields = inspector.Create<VisualElement>();
BITInspectorExtensions.FillDefaultInspector(defaultPropertyFields.Create<VisualElement>(),serializedObject,false);
var root = inspector.Create<VisualElement>();
root.style.flexDirection = new StyleEnum<FlexDirection>(FlexDirection.Row);
var allFlags = scriptableBitMask.Types;
var labelRow = root.Create<VisualElement>();
var toggleRot = root.Create<VisualElement>();
labelRow.style.alignSelf = new StyleEnum<Align>(Align.FlexEnd);
for (var x = -1; x < allFlags.Length; x++)
{
if (x is -1)
{
var container = toggleRot.Create<VisualElement>();
container.style.flexDirection = FlexDirection.Row;
foreach (var type in scriptableBitMask.Types.Reverse())
{
var text = container.Create<Label>();
text.style.width = CellSize;
text.text = string.Join("\n", type.Name.ToArray());
}
continue;
}
{
var xEnum = allFlags[x];
var label = labelRow.Create<Label>();
label.text = xEnum.Name;
label.style.height = CellSize;
label.style.unityTextAlign = TextAnchor.MiddleRight;
var toggles = toggleRot.Create<VisualElement>();
toggles.style.flexDirection = new StyleEnum<FlexDirection>(FlexDirection.Row);
for (var y = allFlags.Length-1; y >= 0+x; y--)
{
var yEnum = allFlags[y];
var toggle = toggles.Create<Toggle>();
toggle.tooltip = $"{xEnum.Name}/{yEnum.Name}";
toggle.style.width = toggle.style.height = CellSize;
toggle.style.marginBottom
= toggleRot.style.marginLeft
= toggleRot.style.marginRight
= toggleRot.style.marginTop
= toggleRot.style.paddingBottom
=toggleRot.style.paddingLeft
=toggleRot.style.paddingRight
=toggleRot.style.paddingTop
=-1;
toggle.SetValueWithoutNotify(scriptableBitMask.Dictionary.GetOrCreate(xEnum.Name).Contains(yEnum.Name));
toggle.RegisterValueChangedCallback(changeEvent =>
{
if (changeEvent.newValue)
{
scriptableBitMask.Dictionary.GetOrCreate(xEnum.Name).TryAdd(yEnum.Name);
scriptableBitMask.Dictionary.GetOrCreate(yEnum.Name).TryAdd(xEnum.Name);
}
else
{
scriptableBitMask.Dictionary.GetOrCreate(xEnum.Name).TryRemove(yEnum.Name);
scriptableBitMask.Dictionary.GetOrCreate(yEnum.Name).TryRemove(xEnum.Name);
}
scriptableBitMask.OnAfterDeserialize();
EditorUtility.SetDirty(serializedObject.targetObject);
});
}
}
}
return root;
}
}
#endif
}