TH1/Unity/Assets/Scripts/Loader/MonoBehaviour/ReferenceCollector.cs
2025-07-17 18:26:28 +08:00

154 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using UnityEngine;
//Object并非C#基础中的Object而是 UnityEngine.Object
using Object = UnityEngine.Object;
//使其能在Inspector面板显示并且可以被赋予相应值
[Serializable]
public class ReferenceCollectorData
{
public string key;
//Object并非C#基础中的Object而是 UnityEngine.Object
public Object gameObject;
}
//继承IComparer对比器Ordinal会使用序号排序规则比较字符串因为是byte级别的比较所以准确性和性能都不错
public class ReferenceCollectorDataComparer: IComparer<ReferenceCollectorData>
{
public int Compare(ReferenceCollectorData x, ReferenceCollectorData y)
{
return string.Compare(x.key, y.key, StringComparison.Ordinal);
}
}
//继承ISerializationCallbackReceiver后会增加OnAfterDeserialize和OnBeforeSerialize两个回调函数如果有需要可以在对需要序列化的东西进行操作
//ET在这里主要是在OnAfterDeserialize回调函数中将data中存储的ReferenceCollectorData转换为dict中的Object方便之后的使用
//注意UNITY_EDITOR宏定义在编译以后部分编辑器相关函数并不存在
public class ReferenceCollector: MonoBehaviour, ISerializationCallbackReceiver
{
//用于序列化的List
public List<ReferenceCollectorData> data = new List<ReferenceCollectorData>();
//Object并非C#基础中的Object而是 UnityEngine.Object
private readonly Dictionary<string, Object> dict = new Dictionary<string, Object>();
#if UNITY_EDITOR
//添加新的元素
public void Add(string key, Object obj)
{
UnityEditor.SerializedObject serializedObject = new UnityEditor.SerializedObject(this);
//根据PropertyPath读取数据
//如果不知道具体的格式可以右键用文本编辑器打开一个prefab文件如Bundles/UI目录中的几个
//因为这几个prefab挂载了ReferenceCollector所以搜索data就能找到存储的数据
UnityEditor.SerializedProperty dataProperty = serializedObject.FindProperty("data");
int i;
//遍历data看添加的数据是否存在相同key
for (i = 0; i < data.Count; i++)
{
if (data[i].key == key)
{
break;
}
}
//不等于data.Count意为已经存在于data List中直接赋值即可
if (i != data.Count)
{
//根据i的值获取dataProperty也就是data中的对应ReferenceCollectorData不过在这里是对Property进行的读取有点类似json或者xml的节点
UnityEditor.SerializedProperty element = dataProperty.GetArrayElementAtIndex(i);
//对对应节点进行赋值值为gameobject相对应的fileID
//fileID独一无二单对单关系其他挂载在这个gameobject上的script或组件会保存相对应的fileID
element.FindPropertyRelative("gameObject").objectReferenceValue = obj;
}
else
{
//等于则说明key在data中无对应元素所以得向其插入新的元素
dataProperty.InsertArrayElementAtIndex(i);
UnityEditor.SerializedProperty element = dataProperty.GetArrayElementAtIndex(i);
element.FindPropertyRelative("key").stringValue = key;
element.FindPropertyRelative("gameObject").objectReferenceValue = obj;
}
//应用与更新
UnityEditor.EditorUtility.SetDirty(this);
serializedObject.ApplyModifiedProperties();
serializedObject.UpdateIfRequiredOrScript();
}
//删除元素,知识点与上面的添加相似
public void Remove(string key)
{
UnityEditor.SerializedObject serializedObject = new UnityEditor.SerializedObject(this);
UnityEditor.SerializedProperty dataProperty = serializedObject.FindProperty("data");
int i;
for (i = 0; i < data.Count; i++)
{
if (data[i].key == key)
{
break;
}
}
if (i != data.Count)
{
dataProperty.DeleteArrayElementAtIndex(i);
}
UnityEditor.EditorUtility.SetDirty(this);
serializedObject.ApplyModifiedProperties();
serializedObject.UpdateIfRequiredOrScript();
}
public void Clear()
{
UnityEditor.SerializedObject serializedObject = new UnityEditor.SerializedObject(this);
//根据PropertyPath读取prefab文件中的数据
//如果不知道具体的格式可以直接右键用文本编辑器打开搜索data就能找到
var dataProperty = serializedObject.FindProperty("data");
dataProperty.ClearArray();
UnityEditor.EditorUtility.SetDirty(this);
serializedObject.ApplyModifiedProperties();
serializedObject.UpdateIfRequiredOrScript();
}
public void Sort()
{
UnityEditor.SerializedObject serializedObject = new UnityEditor.SerializedObject(this);
data.Sort(new ReferenceCollectorDataComparer());
UnityEditor.EditorUtility.SetDirty(this);
serializedObject.ApplyModifiedProperties();
serializedObject.UpdateIfRequiredOrScript();
}
#endif
//使用泛型返回对应key的gameobject
public T Get<T>(string key) where T : class
{
Object dictGo;
if (!dict.TryGetValue(key, out dictGo))
{
return null;
}
return dictGo as T;
}
public Object GetObject(string key)
{
Object dictGo;
if (!dict.TryGetValue(key, out dictGo))
{
return null;
}
return dictGo;
}
public void OnBeforeSerialize()
{
}
//在反序列化后运行
public void OnAfterDeserialize()
{
dict.Clear();
foreach (ReferenceCollectorData referenceCollectorData in data)
{
if (!dict.ContainsKey(referenceCollectorData.key))
{
dict.Add(referenceCollectorData.key, referenceCollectorData.gameObject);
}
}
}
}