DragonECS-Unity/src/RefRepairer/MissingRefContainer.cs

270 lines
11 KiB
C#
Raw Normal View History

2024-09-30 19:40:50 +08:00
#if UNITY_EDITOR
2024-10-01 07:13:13 +08:00
using DCFApixels.DragonECS.Unity.RefRepairer.Internal;
using System;
2024-09-29 23:31:12 +08:00
using System.Collections.Generic;
2024-09-29 15:59:14 +08:00
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityObject = UnityEngine.Object;
2024-09-29 23:31:12 +08:00
namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors
2024-09-29 15:59:14 +08:00
{
2024-10-01 07:13:13 +08:00
internal class MissingRefContainer
2024-09-29 15:59:14 +08:00
{
2024-10-01 07:13:13 +08:00
public CollectedAssetMissingRecord[] collectedMissingTypesBuffer = null;
public int collectedMissingTypesBufferCount = 0;
public readonly Dictionary<TypeData, MissingsResolvingData> MissingsResolvingDatas = new Dictionary<TypeData, MissingsResolvingData>();
2024-10-01 07:42:54 +08:00
public MissingsResolvingData[] MissingsResolvingDataValues;
public bool IsEmplty
{
get { return collectedMissingTypesBufferCount == 0; }
}
2024-09-29 15:59:14 +08:00
2024-10-01 07:13:13 +08:00
#region Clear/RemoveResolved
public void Clear()
2024-09-30 19:40:50 +08:00
{
2024-10-01 07:13:13 +08:00
for (int i = 0; i < collectedMissingTypesBufferCount; i++)
{
collectedMissingTypesBuffer[i] = default;
}
collectedMissingTypesBufferCount = 0;
MissingsResolvingDatas.Clear();
2024-09-30 19:40:50 +08:00
}
2024-10-01 07:13:13 +08:00
public void RemoveResolved()
{
int offset = 0;
int i = 0;
int newLength = collectedMissingTypesBufferCount;
for (; i < newLength; i++)
{
ref var collectedMissingType = ref collectedMissingTypesBuffer[i];
if (collectedMissingType.IsResolvedOrNull)
{
if (collectedMissingType.ResolvingData != null)
{
MissingsResolvingDatas.Remove(collectedMissingType.ResolvingData.OldTypeData);
}
offset = 1;
newLength--;
break;
}
}
if (i >= newLength) { return; }
2024-09-30 19:40:50 +08:00
2024-10-01 07:13:13 +08:00
int nextI = i + offset;
for (; nextI < newLength; nextI++)
{
ref var collectedMissingType = ref collectedMissingTypesBuffer[i];
if (collectedMissingType.IsResolvedOrNull)
{
if (collectedMissingType.ResolvingData != null)
{
MissingsResolvingDatas.Remove(collectedMissingType.ResolvingData.OldTypeData);
}
offset++;
newLength--;
}
else
{
collectedMissingTypesBuffer[i] = collectedMissingTypesBuffer[nextI];
i++;
}
}
2024-09-29 15:59:14 +08:00
2024-10-01 07:13:13 +08:00
for (i = newLength; i < collectedMissingTypesBufferCount; i++)
{
collectedMissingTypesBuffer[i] = default;
}
collectedMissingTypesBufferCount = newLength;
}
#endregion
2024-09-29 15:59:14 +08:00
#region Collect
2024-10-01 07:13:13 +08:00
public void Collect()
2024-09-29 15:59:14 +08:00
{
2024-10-01 07:13:13 +08:00
int oldCollectedMissingTypesBufferCount = collectedMissingTypesBufferCount;
if (collectedMissingTypesBuffer == null)
{
collectedMissingTypesBuffer = new CollectedAssetMissingRecord[256];
}
collectedMissingTypesBufferCount = 0;
MissingsResolvingDatas.Clear();
2024-09-29 15:59:14 +08:00
2024-10-01 07:13:13 +08:00
CollectByPrefabs();
CollectByScriptableObjects();
CollectByScenes();
2024-09-29 15:59:14 +08:00
2024-10-01 07:42:54 +08:00
MissingsResolvingDataValues = MissingsResolvingDatas.Values.ToArray();
2024-10-01 07:13:13 +08:00
for (int i = collectedMissingTypesBufferCount; i < oldCollectedMissingTypesBufferCount; i++)
{
collectedMissingTypesBuffer[i] = default;
}
2024-09-30 19:40:50 +08:00
2024-09-29 15:59:14 +08:00
}
2024-10-01 07:13:13 +08:00
private void Add(UnityObjectDataBase unityObjectData, ref ManagedReferenceMissingType missing)
2024-09-30 19:40:50 +08:00
{
2024-10-01 07:13:13 +08:00
var typeData = new TypeData(missing);
if (MissingsResolvingDatas.TryGetValue(typeData, out var resolvingData) == false)
{
resolvingData = new MissingsResolvingData(typeData);
MissingsResolvingDatas.Add(typeData, resolvingData);
}
if (collectedMissingTypesBufferCount >= collectedMissingTypesBuffer.Length)
2024-09-30 19:40:50 +08:00
{
2024-10-01 07:13:13 +08:00
Array.Resize(ref collectedMissingTypesBuffer, collectedMissingTypesBuffer.Length << 1);
2024-09-30 19:40:50 +08:00
}
2024-10-01 07:13:13 +08:00
collectedMissingTypesBuffer[collectedMissingTypesBufferCount++] = new CollectedAssetMissingRecord(unityObjectData, missing, resolvingData);
2024-09-30 19:40:50 +08:00
}
2024-10-01 07:13:13 +08:00
private void CollectByPrefabs()
2024-09-29 15:59:14 +08:00
{
Scene previewScene = EditorSceneManager.NewPreviewScene();
foreach (var pathToPrefab in AssetDatabase.GetAllAssetPaths().Where(path => path.StartsWith("Assets/") && path.EndsWith(".prefab")))
{
2024-09-30 19:40:50 +08:00
var prefabAsset = AssetDatabase.LoadAssetAtPath<GameObject>(pathToPrefab);
var unityObjectData = new UnityObjectData(prefabAsset, pathToPrefab);
2024-09-29 15:59:14 +08:00
2024-09-30 19:40:50 +08:00
PrefabUtility.LoadPrefabContentsIntoPreviewScene(pathToPrefab, previewScene);
var prefabLoaded = previewScene.GetRootGameObjects()[0];
2024-09-29 15:59:14 +08:00
2024-09-30 19:40:50 +08:00
foreach (var component in prefabLoaded.GetComponentsInChildren<MonoBehaviour>())
2024-09-29 15:59:14 +08:00
{
2024-09-30 19:40:50 +08:00
if (SerializationUtility.HasManagedReferencesWithMissingTypes(component) == false) { continue; }
2024-09-29 15:59:14 +08:00
2024-09-30 19:40:50 +08:00
var missings = SerializationUtility.GetManagedReferencesWithMissingTypes(component);
2024-10-01 07:13:13 +08:00
for (int i = 0; i < missings.Length; i++)
{
Add(unityObjectData, ref missings[i]);
}
2024-09-29 15:59:14 +08:00
}
2024-09-30 19:40:50 +08:00
UnityObject.DestroyImmediate(prefabLoaded);
2024-09-29 15:59:14 +08:00
}
EditorSceneManager.ClosePreviewScene(previewScene);
}
2024-10-01 07:13:13 +08:00
private void CollectByScriptableObjects()
2024-09-29 15:59:14 +08:00
{
foreach (var pathToPrefab in AssetDatabase.GetAllAssetPaths().Where(path => path.StartsWith("Assets/") && path.EndsWith(".asset")))
{
var scriptableObject = AssetDatabase.LoadAssetAtPath<ScriptableObject>(pathToPrefab);
2024-09-30 19:40:50 +08:00
var unityObjectData = new UnityObjectData(scriptableObject, pathToPrefab);
2024-09-29 15:59:14 +08:00
2024-09-30 19:40:50 +08:00
if (SerializationUtility.HasManagedReferencesWithMissingTypes(scriptableObject) == false) { continue; }
2024-09-29 15:59:14 +08:00
2024-09-30 19:40:50 +08:00
var missings = SerializationUtility.GetManagedReferencesWithMissingTypes(scriptableObject);
2024-10-01 07:13:13 +08:00
for (int i = 0; i < missings.Length; i++)
{
Add(unityObjectData, ref missings[i]);
}
2024-09-29 15:59:14 +08:00
}
}
2024-10-01 07:13:13 +08:00
private void CollectByScenes()
2024-09-29 15:59:14 +08:00
{
try
{
foreach (var scene in GetAllScenesInAssets())
{
2024-09-30 19:40:50 +08:00
var unityObjectData = new SceneObjectData(scene);
2024-09-29 15:59:14 +08:00
var gameObjects = scene.GetRootGameObjects();
foreach (var objectOnScene in gameObjects)
{
foreach (var monoBehaviour in objectOnScene.GetComponentsInChildren<MonoBehaviour>())
{
2024-09-30 19:40:50 +08:00
if (SerializationUtility.HasManagedReferencesWithMissingTypes(monoBehaviour) == false) { continue; }
var missings = SerializationUtility.GetManagedReferencesWithMissingTypes(monoBehaviour);
2024-10-01 07:13:13 +08:00
for (int i = 0; i < missings.Length; i++)
{
Add(unityObjectData, ref missings[i]);
}
2024-09-29 15:59:14 +08:00
}
}
}
}
2024-10-01 07:13:13 +08:00
catch (Exception e)
2024-09-29 15:59:14 +08:00
{
Debug.LogException(e);
}
}
#endregion
#region Utils
private static IEnumerable<Scene> GetAllScenesInAssets()
{
var oldScenesSetup = EditorSceneManager.GetSceneManagerSetup();
(bool isHasSelected, string scenePath, int identifierInFile) oldSelectedObject = default;
GameObject activeGameObject = Selection.activeGameObject;
if (activeGameObject != null)
{
oldSelectedObject.isHasSelected = true;
oldSelectedObject.scenePath = activeGameObject.scene.path;
oldSelectedObject.identifierInFile = activeGameObject.GetLocalIdentifierInFile();
}
foreach (var pathToScene in AssetDatabase.GetAllAssetPaths().Where(path => path.StartsWith("Assets/") && path.EndsWith(".unity")))
{
Scene scene = EditorSceneManager.OpenScene(pathToScene, OpenSceneMode.Single);
yield return scene;
}
EditorSceneManager.RestoreSceneManagerSetup(oldScenesSetup);
if (oldSelectedObject.isHasSelected)
{
Selection.activeGameObject = SceneManager.GetSceneByPath(oldSelectedObject.scenePath)
.GetRootGameObjects()
.FirstOrDefault(gameObject => gameObject.GetLocalIdentifierInFile() == oldSelectedObject.identifierInFile);
}
else
{
Selection.activeGameObject = null;
}
}
2024-09-30 19:40:50 +08:00
//private void AddMissingType(ManagedReferenceMissingType missingType, UnityObjectDataBase unityObject)
//{
// var typeData = new TypeData(missingType);
// var missingTypeData = new MissingTypeData(missingType, unityObject);
// if (_manualRepairedMissingRefs.TryGetValue(typeData, out var containerMissingTypes) == false)
// {
// containerMissingTypes = new ContainerMissingRefs(typeData);
// _manualRepairedMissingRefs.Add(typeData, containerMissingTypes);
// }
//
// containerMissingTypes.ManagedReferencesMissingTypeDatas.Add(missingTypeData);
//}
2024-09-29 15:59:14 +08:00
#endregion
}
2024-10-01 07:13:13 +08:00
internal static class UnityObjectExtensions
{
public static int GetLocalIdentifierInFile(this UnityObject unityObject)
{
PropertyInfo inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance);
SerializedObject serializedObject = new SerializedObject(unityObject);
inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null);
SerializedProperty localIdProp = serializedObject.FindProperty("m_LocalIdentfierInFile");
return localIdProp.intValue;
}
}
//internal class ContainerMissingTypes
//{
// public readonly GUID AssetGUID;
// public readonly List<ContainerMissingRefs> Recirds = new List<ContainerMissingRefs>();
// public ContainerMissingTypes(GUID assetGUID)
// {
// AssetGUID = assetGUID;
// }
//}
2024-09-30 19:40:50 +08:00
}
#endif