using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Runtime.Serialization; using UnityEditor; using UnityEngine; namespace VF.Model { public abstract class VRCFuryComponent : MonoBehaviour, ISerializationCallbackReceiver { private static readonly int VRCFURY_SER_VERSION = 7; private static readonly HashSet attemptedReload = new HashSet(); public int vrcfSerVersion; [NonSerialized] public bool failedToLoad = false; public bool IsBroken() { return vrcfSerVersion > VRCFURY_SER_VERSION || ContainsNullsInList(this); } public virtual void OnAfterDeserialize() { if (IsBroken()) { failedToLoad = true; #if UNITY_EDITOR EditorApplication.delayCall += () => { var path = AssetDatabase.GetAssetPath(this); if (!string.IsNullOrWhiteSpace(path) && !attemptedReload.Contains(path)) { //Debug.LogError("VRCFury is triggering manual reload of asset " + path + " (previous import corrupted)"); Debug.LogWarning( $"VRCFury detected VRCFury component in asset at path ${path} is corrupted. " + "Hopefully it will be fixed during the prefab import auto-fix."); attemptedReload.Add(path); //AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceSynchronousImport); } }; #endif } else { vrcfSerVersion = VRCFURY_SER_VERSION; failedToLoad = false; } } public virtual void OnBeforeSerialize() { } private static bool ContainsNullsInList(object obj) { if (obj == null) return false; var objType = obj.GetType(); if (!objType.FullName.StartsWith("VF")) return false; var fields = objType.GetFields(); foreach (var field in fields) { var value = field.GetValue(obj); if (value is IList) { var list = value as IList; var isRef = field.GetCustomAttribute() != null; foreach (var t in list) { if (t == null && isRef) return true; if (ContainsNullsInList(t)) return true; } } else { var type = field.FieldType; if (type.IsClass) { if (ContainsNullsInList(value)) return true; } } } return false; } } }