diff --git a/src/Internal/ArrayUtility.cs b/src/Internal/ArrayUtility.cs index 43cbe92..f55393e 100644 --- a/src/Internal/ArrayUtility.cs +++ b/src/Internal/ArrayUtility.cs @@ -5,6 +5,16 @@ using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS.Unity.Internal { + public readonly struct ArrayBuffer + { + public readonly T[] Array; + public readonly int Length; + public ArrayBuffer(T[] array, int length) + { + Array = array; + Length = length; + } + } internal interface ILinkedNext { int Next { get; } diff --git a/src/RefRepairer/Editor/RefRepairerWindow.cs b/src/RefRepairer/Editor/RefRepairerWindow.cs index 3c50c4b..cdeeec5 100644 --- a/src/RefRepairer/Editor/RefRepairerWindow.cs +++ b/src/RefRepairer/Editor/RefRepairerWindow.cs @@ -20,7 +20,7 @@ namespace DCFApixels.DragonECS.Unity.Editors wnd.Show(); } - private List _missingTypes; + //private List _missingTypes; //private readonly CollectorMissingTypes _collectorMissingTypes = new CollectorMissingTypes(); private bool TryInit() diff --git a/src/RefRepairer/MissingRefCollectUtility.cs b/src/RefRepairer/MissingRefContainer.cs similarity index 54% rename from src/RefRepairer/MissingRefCollectUtility.cs rename to src/RefRepairer/MissingRefContainer.cs index e614fdb..b7be9c6 100644 --- a/src/RefRepairer/MissingRefCollectUtility.cs +++ b/src/RefRepairer/MissingRefContainer.cs @@ -1,4 +1,6 @@ п»ї#if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.RefRepairer.Internal; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -10,62 +12,109 @@ using UnityObject = UnityEngine.Object; namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors { - internal static class UnityObjectExtensions + internal class MissingRefContainer { - public static int GetLocalIdentifierInFile(this UnityObject unityObject) + public CollectedAssetMissingRecord[] collectedMissingTypesBuffer = null; + public int collectedMissingTypesBufferCount = 0; + public readonly Dictionary MissingsResolvingDatas = new Dictionary(); + + #region Clear/RemoveResolved + public void Clear() { - 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; + for (int i = 0; i < collectedMissingTypesBufferCount; i++) + { + collectedMissingTypesBuffer[i] = default; + } + collectedMissingTypesBufferCount = 0; + MissingsResolvingDatas.Clear(); } - } - - internal class ContainerMissingTypes - { - public readonly GUID AssetGUID; - public readonly List Recirds = new List(); - public ContainerMissingTypes(GUID assetGUID) + public void RemoveResolved() { - AssetGUID = assetGUID; + 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; } + + 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++; + } + } + + for (i = newLength; i < collectedMissingTypesBufferCount; i++) + { + collectedMissingTypesBuffer[i] = default; + } + + collectedMissingTypesBufferCount = newLength; } - } - - internal class MissingRefCollectUtility - { - //private readonly Dictionary _manualRepairedMissingRefs = new Dictionary(); - //private readonly List _autoRepariedMissingTypes = new List(); - - private readonly List _collectedMissingTypes = new List(); + #endregion #region Collect - public List Collect() + public void Collect() { - //_manualRepairedMissingRefs.Clear(); - - _collectedMissingTypes.Clear(); - - CollectByPrefabs(_collectedMissingTypes); - CollectByScriptableObjects(_collectedMissingTypes); - CollectByScenes(_collectedMissingTypes); - - //ContainerMissingRefs[] result = _manualRepairedMissingRefs.Values.ToArray(); - //_manualRepairedMissingRefs.Clear(); - - return _collectedMissingTypes; - } - public readonly struct Record - { - public readonly UnityObjectDataBase UnityObject; - public readonly ManagedReferenceMissingType[] missingTypes; - public Record(UnityObjectDataBase unityObject, ManagedReferenceMissingType[] missingTypes) + int oldCollectedMissingTypesBufferCount = collectedMissingTypesBufferCount; + if (collectedMissingTypesBuffer == null) { - UnityObject = unityObject; - this.missingTypes = missingTypes; + collectedMissingTypesBuffer = new CollectedAssetMissingRecord[256]; } + collectedMissingTypesBufferCount = 0; + MissingsResolvingDatas.Clear(); + + CollectByPrefabs(); + CollectByScriptableObjects(); + CollectByScenes(); + + for (int i = collectedMissingTypesBufferCount; i < oldCollectedMissingTypesBufferCount; i++) + { + collectedMissingTypesBuffer[i] = default; + } + } - private void CollectByPrefabs(List list) + private void Add(UnityObjectDataBase unityObjectData, ref ManagedReferenceMissingType missing) + { + 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) + { + Array.Resize(ref collectedMissingTypesBuffer, collectedMissingTypesBuffer.Length << 1); + } + collectedMissingTypesBuffer[collectedMissingTypesBufferCount++] = new CollectedAssetMissingRecord(unityObjectData, missing, resolvingData); + } + private void CollectByPrefabs() { Scene previewScene = EditorSceneManager.NewPreviewScene(); foreach (var pathToPrefab in AssetDatabase.GetAllAssetPaths().Where(path => path.StartsWith("Assets/") && path.EndsWith(".prefab"))) @@ -81,14 +130,17 @@ namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors if (SerializationUtility.HasManagedReferencesWithMissingTypes(component) == false) { continue; } var missings = SerializationUtility.GetManagedReferencesWithMissingTypes(component); - list.Add(new Record(unityObjectData, missings)); + for (int i = 0; i < missings.Length; i++) + { + Add(unityObjectData, ref missings[i]); + } } UnityObject.DestroyImmediate(prefabLoaded); } EditorSceneManager.ClosePreviewScene(previewScene); } - private void CollectByScriptableObjects(List list) + private void CollectByScriptableObjects() { foreach (var pathToPrefab in AssetDatabase.GetAllAssetPaths().Where(path => path.StartsWith("Assets/") && path.EndsWith(".asset"))) { @@ -98,10 +150,13 @@ namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors if (SerializationUtility.HasManagedReferencesWithMissingTypes(scriptableObject) == false) { continue; } var missings = SerializationUtility.GetManagedReferencesWithMissingTypes(scriptableObject); - list.Add(new Record(unityObjectData, missings)); + for (int i = 0; i < missings.Length; i++) + { + Add(unityObjectData, ref missings[i]); + } } } - private void CollectByScenes(List list) + private void CollectByScenes() { try { @@ -118,12 +173,15 @@ namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors if (SerializationUtility.HasManagedReferencesWithMissingTypes(monoBehaviour) == false) { continue; } var missings = SerializationUtility.GetManagedReferencesWithMissingTypes(monoBehaviour); - list.Add(new Record(unityObjectData, missings)); + for (int i = 0; i < missings.Length; i++) + { + Add(unityObjectData, ref missings[i]); + } } } } } - catch (System.Exception e) + catch (Exception e) { Debug.LogException(e); } @@ -179,5 +237,28 @@ namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors #endregion } + + 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 Recirds = new List(); + // public ContainerMissingTypes(GUID assetGUID) + // { + // AssetGUID = assetGUID; + // } + //} } #endif \ No newline at end of file diff --git a/src/RefRepairer/MissingRefCollectUtility.cs.meta b/src/RefRepairer/MissingRefContainer.cs.meta similarity index 100% rename from src/RefRepairer/MissingRefCollectUtility.cs.meta rename to src/RefRepairer/MissingRefContainer.cs.meta diff --git a/src/RefRepairer/RepairerFile.cs b/src/RefRepairer/RepairerFile.cs index 85e4279..e0f8b7c 100644 --- a/src/RefRepairer/RepairerFile.cs +++ b/src/RefRepairer/RepairerFile.cs @@ -1,6 +1,8 @@ +#if UNITY_EDITOR using DCFApixels.DragonECS.Unity.RefRepairer.Internal; using System; using System.IO; +using System.Linq; using UnityEditor; using UnityEngine; @@ -34,11 +36,60 @@ namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors { return $"type: {{class: {typeData.ClassName}, ns: {typeData.NamespaceName}, asm: {typeData.AssemblyName}}}"; } - public static string GenerateReplacedLine(ManagedReferenceMissingType typeData) + public static void RepaieAsset(MissingRefContainer container) { - return $"type: {{class: {typeData.className}, ns: {typeData.namespaceName}, asm: {typeData.assemblyName}}}"; - } + if (container.collectedMissingTypesBufferCount <= 0) { return; } + MissingsResolvingData[] missingsResolvingDatas = container.MissingsResolvingDatas.Values.Where(o => o.IsResolved).ToArray(); + for (int i = 0; i < container.collectedMissingTypesBufferCount; i++) + { + ref var missing = ref container.collectedMissingTypesBuffer[i]; + if (missing.IsNull) { continue; } + + var unityObjectData = missing.UnityObject; + using (var file = new FileScope(AssetDatabase.GUIDToAssetPath(unityObjectData.AssetGuid))) + { + int startRepaierLineIndex = 0;//Это нужно чтобы скипать уже "отремонтированную" часть файл. + + // тут итерируюсь по блоку missingsResolvingDatas с одинаковым юнити объектом, так как такие идеут подрят + do + { + bool isAnySkiped = false; + int lineIndex = NextRefLine(file.lines, startRepaierLineIndex); + while (lineIndex > 0) + { + var line = file.lines[lineIndex]; + + // Как сказанно в документации к методу Replace + // A string that is equivalent to this instance except that all instances of oldChar are replaced with newChar. + // If oldChar is not found in the current instance, the method returns the current instance unchanged. + // А конкретно строчки "returns the current instance unchanged", можно сделать упрощенную проверку через ReferenceEquals + string oldLine = line; + line = line.Replace(missing.ResolvingData.OldSerializedInfoLine, missing.ResolvingData.NewSerializedInfoLine); + bool isChanged = !ReferenceEquals(oldLine, line); + + + if (isChanged == false) + { + isAnySkiped = true; + } + else + { + if (isAnySkiped == false) + { + startRepaierLineIndex = lineIndex; + } + } + lineIndex = NextRefLine(file.lines, lineIndex); + } + + missing = ref container.collectedMissingTypesBuffer[i++]; + } while (unityObjectData == missing.UnityObject); + i--;//чтобы итерация не поломалась + } + } + container.RemoveResolved(); + } public struct FileScope : IDisposable { public readonly string FilePath; @@ -61,63 +112,64 @@ namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors } - internal class RepairerFile - { - private readonly Type _type; - private readonly string[] _fileLines; - - private string _currentLine; - private string _nextLine; - - private int _currentIndex; - - private readonly string _path; - private readonly string _localAssetPath; - - public RepairerFile(Type type, string localAssetPath) - { - _type = type; - _localAssetPath = localAssetPath; - - _path = $"{Application.dataPath.Replace("/Assets", "")}/{localAssetPath}"; - _fileLines = File.ReadAllLines(_path); - } - - public delegate bool GetterMissingTypeData(out MissingTypeData missingType); - - public void Repair(Func callbackForNextLine) - { - for (int i = 0; i < _fileLines.Length - 1; ++i) - { - _currentIndex = i; - - _currentLine = _fileLines[i]; - _nextLine = _fileLines[i + 1]; - - if (callbackForNextLine.Invoke()) - break; - } - - File.WriteAllLines(_path, _fileLines); - - AssetDatabase.ImportAsset(_localAssetPath, ImportAssetOptions.ForceUpdate); - AssetDatabase.Refresh(); - } - - public bool CheckNeedLineAndReplacedIt(ManagedReferenceMissingType missingType) - { - string rid = $"rid: {missingType.referenceId}"; - string oldTypeData = $"type: {{class: {missingType.className}, ns: {missingType.namespaceName}, asm: {missingType.assemblyName}}}"; - - if (_currentLine.Contains(rid) && _nextLine.Contains(oldTypeData)) - { - string newTypeData = $"type: {{class: {_type.Name}, ns: {_type.Namespace}, asm: {_type.Assembly.GetName().Name}}}"; - _fileLines[_currentIndex + 1] = _nextLine.Replace(oldTypeData, newTypeData); - - return true; - } - - return false; - } - } + //internal class RepairerFile + //{ + // private readonly Type _type; + // private readonly string[] _fileLines; + // + // private string _currentLine; + // private string _nextLine; + // + // private int _currentIndex; + // + // private readonly string _path; + // private readonly string _localAssetPath; + // + // public RepairerFile(Type type, string localAssetPath) + // { + // _type = type; + // _localAssetPath = localAssetPath; + // + // _path = $"{Application.dataPath.Replace("/Assets", "")}/{localAssetPath}"; + // _fileLines = File.ReadAllLines(_path); + // } + // + // public delegate bool GetterMissingTypeData(out MissingTypeData missingType); + // + // public void Repair(Func callbackForNextLine) + // { + // for (int i = 0; i < _fileLines.Length - 1; ++i) + // { + // _currentIndex = i; + // + // _currentLine = _fileLines[i]; + // _nextLine = _fileLines[i + 1]; + // + // if (callbackForNextLine.Invoke()) + // break; + // } + // + // File.WriteAllLines(_path, _fileLines); + // + // AssetDatabase.ImportAsset(_localAssetPath, ImportAssetOptions.ForceUpdate); + // AssetDatabase.Refresh(); + // } + // + // public bool CheckNeedLineAndReplacedIt(ManagedReferenceMissingType missingType) + // { + // string rid = $"rid: {missingType.referenceId}"; + // string oldTypeData = $"type: {{class: {missingType.className}, ns: {missingType.namespaceName}, asm: {missingType.assemblyName}}}"; + // + // if (_currentLine.Contains(rid) && _nextLine.Contains(oldTypeData)) + // { + // string newTypeData = $"type: {{class: {_type.Name}, ns: {_type.Namespace}, asm: {_type.Assembly.GetName().Name}}}"; + // _fileLines[_currentIndex + 1] = _nextLine.Replace(oldTypeData, newTypeData); + // + // return true; + // } + // + // return false; + // } + //} } +#endif \ No newline at end of file diff --git a/src/RefRepairer/Utils/CollectedAssetMissingRecord.cs b/src/RefRepairer/Utils/CollectedAssetMissingRecord.cs new file mode 100644 index 0000000..8e40ef1 --- /dev/null +++ b/src/RefRepairer/Utils/CollectedAssetMissingRecord.cs @@ -0,0 +1,27 @@ +п»ї#if UNITY_EDITOR +using UnityEditor; + +namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors +{ + internal readonly struct CollectedAssetMissingRecord + { + public readonly UnityObjectDataBase UnityObject; + public readonly ManagedReferenceMissingType Missing; + public readonly MissingsResolvingData ResolvingData; + public bool IsResolvedOrNull + { + get { return UnityObject == null || ResolvingData.IsResolved; } + } + public bool IsNull + { + get { return UnityObject == null; } + } + public CollectedAssetMissingRecord(UnityObjectDataBase unityObject, ManagedReferenceMissingType missing, MissingsResolvingData resolvingData) + { + UnityObject = unityObject; + Missing = missing; + ResolvingData = resolvingData; + } + } +} +#endif \ No newline at end of file diff --git a/src/RefRepairer/Utils/ContainerMissingRefs.cs b/src/RefRepairer/Utils/ContainerMissingRefs.cs index d8d52f1..1a4fff3 100644 --- a/src/RefRepairer/Utils/ContainerMissingRefs.cs +++ b/src/RefRepairer/Utils/ContainerMissingRefs.cs @@ -4,18 +4,18 @@ using System.Collections.Generic; namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors { - internal class ContainerMissingRefs - { - public readonly TypeData TypeData; - public readonly string ReplacedLine; - public readonly List ManagedReferencesMissingTypeDatas = new List(4); - public readonly bool IsHasMetaIDRegistry; - public ContainerMissingRefs(TypeData typeData) - { - TypeData = typeData; - ReplacedLine = RepaireFileUtility.GenerateReplacedLine(typeData); - IsHasMetaIDRegistry = MetaIDRegistry.instance.TryGetMetaID(TypeData, out _); - } - } + //internal class ContainerMissingRefs + //{ + // public readonly TypeData TypeData; + // public readonly string ReplacedLine; + // public readonly List ManagedReferencesMissingTypeDatas = new List(4); + // public readonly bool IsHasMetaIDRegistry; + // public ContainerMissingRefs(TypeData typeData) + // { + // TypeData = typeData; + // ReplacedLine = RepaireFileUtility.GenerateReplacedLine(typeData); + // IsHasMetaIDRegistry = MetaIDRegistry.instance.TryGetMetaID(TypeData, out _); + // } + //} } #endif \ No newline at end of file diff --git a/src/RefRepairer/Utils/MissingTypeData.cs b/src/RefRepairer/Utils/MissingTypeData.cs index 245873a..4fd8b22 100644 --- a/src/RefRepairer/Utils/MissingTypeData.cs +++ b/src/RefRepairer/Utils/MissingTypeData.cs @@ -3,16 +3,16 @@ using UnityEditor; namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors { - internal readonly struct MissingTypeData - { - public readonly ManagedReferenceMissingType Data; - public readonly UnityObjectDataBase UnityObject; - - public MissingTypeData(ManagedReferenceMissingType missingType, UnityObjectDataBase unityObject) - { - Data = missingType; - UnityObject = unityObject; - } - } + //internal readonly struct MissingTypeData + //{ + // public readonly ManagedReferenceMissingType Data; + // public readonly UnityObjectDataBase UnityObject; + // + // public MissingTypeData(ManagedReferenceMissingType missingType, UnityObjectDataBase unityObject) + // { + // Data = missingType; + // UnityObject = unityObject; + // } + //} } #endif \ No newline at end of file diff --git a/src/RefRepairer/Utils/MissingsResolvingData.cs b/src/RefRepairer/Utils/MissingsResolvingData.cs new file mode 100644 index 0000000..4ddedbb --- /dev/null +++ b/src/RefRepairer/Utils/MissingsResolvingData.cs @@ -0,0 +1,43 @@ +п»ї#if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.RefRepairer.Internal; + +namespace DCFApixels.DragonECS.Unity.RefRepairer.Editors +{ + internal class MissingsResolvingData + { + public readonly TypeData OldTypeData; + public readonly string OldSerializedInfoLine; + private TypeData _newTypeData; + private string _newSerializedInfoLine; + public MissingsResolvingData(TypeData oldTypeData) + { + OldTypeData = oldTypeData; + OldSerializedInfoLine = RepaireFileUtility.GenerateReplacedLine(oldTypeData); + } + public bool IsResolved + { + get { return string.IsNullOrEmpty(_newTypeData.ClassName) == false; } + } + public TypeData NewTypeData + { + get { return _newTypeData; } + set + { + _newTypeData = value; + _newSerializedInfoLine = null; + } + } + public string NewSerializedInfoLine + { + get + { + if (_newSerializedInfoLine == null) + { + _newSerializedInfoLine = RepaireFileUtility.GenerateReplacedLine(_newTypeData); + } + return _newSerializedInfoLine; + } + } + } +} +#endif \ No newline at end of file