예제 #1
0
        // Thanks for not using the Resources folder IronGate
        // There is probably some oddities in there
        private static void FixReferences(this object objectToFix, int depth)
        {
            // This is totally arbitrary.
            // I had to add a depth because of call stack exploding otherwise
            if (depth == 3)
            {
                return;
            }

            depth++;

            var type = objectToFix.GetType();

            const BindingFlags flags = ReflectionHelper.AllBindingFlags & ~BindingFlags.Static;

            var fields   = type.GetFields(flags);
            var baseType = type.BaseType;

            while (baseType != null)
            {
                var parentFields = baseType.GetFields(flags);
                fields   = fields.Union(parentFields).ToArray();
                baseType = baseType.BaseType;
            }
            foreach (var field in fields)
            {
                var fieldType = field.FieldType;

                // Special treatment for DropTable, its a List of struct DropData
                // Maybe there comes a time when I am willing to do some generic stuff
                // But mono did not implement FieldInfo.GetValueDirect()
                if (fieldType == typeof(DropTable))
                {
                    var drops = ((DropTable)field.GetValue(objectToFix)).m_drops;

                    for (int i = 0; i < drops.Count; i++)
                    {
                        var drop       = drops[i];
                        var realPrefab = MockManager.GetRealPrefabFromMock(drop.m_item, typeof(GameObject));
                        if (realPrefab)
                        {
                            drop.m_item = (GameObject)realPrefab;
                        }
                        drops[i] = drop;
                    }

                    continue;
                }

                var isUnityObject = fieldType.IsSameOrSubclass(typeof(Object));
                if (isUnityObject)
                {
                    var mock       = (Object)field.GetValue(objectToFix);
                    var realPrefab = MockManager.GetRealPrefabFromMock(mock, fieldType);
                    if (realPrefab)
                    {
                        field.SetValue(objectToFix, realPrefab);
                    }
                }
                else
                {
                    var enumeratedType             = fieldType.GetEnumeratedType();
                    var isEnumerableOfUnityObjects = enumeratedType?.IsSameOrSubclass(typeof(Object)) == true;
                    if (isEnumerableOfUnityObjects)
                    {
                        var isArray   = fieldType.IsArray;
                        var isList    = fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(List <>);
                        var isHashSet = fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(HashSet <>);

                        if (!(isArray || isList || isHashSet))
                        {
                            Logger.LogWarning($"Not fixing potential mock references for field {field.Name} : {fieldType} is not supported.");
                            continue;
                        }

                        var currentValues = (IEnumerable <Object>)field.GetValue(objectToFix);
                        if (currentValues != null)
                        {
                            var list = new List <Object>();
                            foreach (var unityObject in currentValues)
                            {
                                var realPrefab = MockManager.GetRealPrefabFromMock(unityObject, enumeratedType);
                                list.Add(realPrefab ? realPrefab : unityObject);
                            }

                            if (list.Count > 0)
                            {
                                if (isArray)
                                {
                                    var toArray  = ReflectionHelper.Cache.EnumerableToArray;
                                    var toArrayT = toArray.MakeGenericMethod(enumeratedType);

                                    // mono...
                                    var cast            = ReflectionHelper.Cache.EnumerableCast;
                                    var castT           = cast.MakeGenericMethod(enumeratedType);
                                    var correctTypeList = castT.Invoke(null, new object[] { list });

                                    var array = toArrayT.Invoke(null, new object[] { correctTypeList });
                                    field.SetValue(objectToFix, array);
                                }
                                else if (isList)
                                {
                                    var toList  = ReflectionHelper.Cache.EnumerableToList;
                                    var toListT = toList.MakeGenericMethod(enumeratedType);

                                    // mono...
                                    var cast            = ReflectionHelper.Cache.EnumerableCast;
                                    var castT           = cast.MakeGenericMethod(enumeratedType);
                                    var correctTypeList = castT.Invoke(null, new object[] { list });

                                    var newList = toListT.Invoke(null, new object[] { correctTypeList });
                                    field.SetValue(objectToFix, newList);
                                }
                                else if (isHashSet)
                                {
                                    var hash = typeof(HashSet <>).MakeGenericType(enumeratedType);

                                    // mono...
                                    var cast            = ReflectionHelper.Cache.EnumerableCast;
                                    var castT           = cast.MakeGenericMethod(enumeratedType);
                                    var correctTypeList = castT.Invoke(null, new object[] { list });

                                    var newHash = Activator.CreateInstance(hash, correctTypeList);
                                    field.SetValue(objectToFix, newHash);
                                }
                            }
                        }
                    }
                    else if (enumeratedType?.IsClass == true)
                    {
                        var isDict = fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Dictionary <,>);
                        if (isDict)
                        {
                            Logger.LogWarning($"Not fixing potential mock references for field {field.Name} : Dictionary is not supported.");
                            continue;
                        }

                        var currentValues = (IEnumerable <object>)field.GetValue(objectToFix);
                        if (currentValues == null)
                        {
                            continue;
                        }
                        foreach (var value in currentValues)
                        {
                            value?.FixReferences(depth);
                        }
                    }
                    else if (fieldType.IsClass)
                    {
                        field.GetValue(objectToFix)?.FixReferences(depth);
                    }
                }
            }

            var properties = type.GetProperties(flags).ToList();

            baseType = type.BaseType;
            if (baseType != null)
            {
                var parentProperties = baseType.GetProperties(flags).ToList();
                foreach (var a in parentProperties)
                {
                    properties.Add(a);
                }
            }
            foreach (var property in properties)
            {
                var propertyType = property.PropertyType;

                var isUnityObject = propertyType.IsSameOrSubclass(typeof(Object));
                if (isUnityObject)
                {
                    var mock       = (Object)property.GetValue(objectToFix, null);
                    var realPrefab = MockManager.GetRealPrefabFromMock(mock, propertyType);
                    if (realPrefab)
                    {
                        property.SetValue(objectToFix, realPrefab, null);
                    }
                }
                else
                {
                    var enumeratedType             = propertyType.GetEnumeratedType();
                    var isEnumerableOfUnityObjects = enumeratedType?.IsSameOrSubclass(typeof(Object)) == true;
                    if (isEnumerableOfUnityObjects)
                    {
                        var isArray   = propertyType.IsArray;
                        var isList    = propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List <>);
                        var isHashSet = propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(HashSet <>);

                        if (!(isArray || isList || isHashSet))
                        {
                            Logger.LogWarning($"Not fixing potential mock references for property {property.Name} : {propertyType} is not supported.");
                            continue;
                        }

                        var currentValues = (IEnumerable <Object>)property.GetValue(objectToFix, null);
                        if (currentValues != null)
                        {
                            var list = new List <Object>();
                            foreach (var unityObject in currentValues)
                            {
                                var realPrefab = MockManager.GetRealPrefabFromMock(unityObject, enumeratedType);
                                list.Add(realPrefab ? realPrefab : unityObject);
                            }

                            if (list.Count > 0)
                            {
                                if (isArray)
                                {
                                    var toArray  = ReflectionHelper.Cache.EnumerableToArray;
                                    var toArrayT = toArray.MakeGenericMethod(enumeratedType);

                                    // mono...
                                    var cast            = ReflectionHelper.Cache.EnumerableCast;
                                    var castT           = cast.MakeGenericMethod(enumeratedType);
                                    var correctTypeList = castT.Invoke(null, new object[] { list });

                                    var array = toArrayT.Invoke(null, new object[] { correctTypeList });
                                    property.SetValue(objectToFix, array, null);
                                }
                                else if (isList)
                                {
                                    var toList  = ReflectionHelper.Cache.EnumerableToList;
                                    var toListT = toList.MakeGenericMethod(enumeratedType);

                                    // mono...
                                    var cast            = ReflectionHelper.Cache.EnumerableCast;
                                    var castT           = cast.MakeGenericMethod(enumeratedType);
                                    var correctTypeList = castT.Invoke(null, new object[] { list });

                                    var newList = toListT.Invoke(null, new object[] { correctTypeList });
                                    property.SetValue(objectToFix, newList, null);
                                }
                                else if (isHashSet)
                                {
                                    var hash = typeof(HashSet <>).MakeGenericType(enumeratedType);

                                    // mono...
                                    var cast            = ReflectionHelper.Cache.EnumerableCast;
                                    var castT           = cast.MakeGenericMethod(enumeratedType);
                                    var correctTypeList = castT.Invoke(null, new object[] { list });

                                    var newHash = Activator.CreateInstance(hash, correctTypeList);
                                    property.SetValue(objectToFix, newHash, null);
                                }
                            }
                        }
                    }
                    else if (enumeratedType?.IsClass == true)
                    {
                        var isDict = propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Dictionary <,>);
                        if (isDict)
                        {
                            Logger.LogWarning($"Not fixing potential mock references for field {property.Name} : Dictionary is not supported.");
                            continue;
                        }

                        var currentValues = (IEnumerable <object>)property.GetValue(objectToFix, null);
                        if (currentValues == null)
                        {
                            continue;
                        }
                        foreach (var value in currentValues)
                        {
                            value?.FixReferences(depth);
                        }
                    }
                    else if (propertyType.IsClass)
                    {
                        if (property.GetIndexParameters().Length == 0)
                        {
                            property.GetValue(objectToFix, null)?.FixReferences(depth);
                        }
                    }
                }
            }
        }