Ejemplo n.º 1
0
        /// <summary>
        /// Gets the UClass for the given type
        /// </summary>
        /// <param name="type">The type</param>
        /// <returns>The UClass for the given type</returns>
        public static UClass GetClass(Type type)
        {
            UClass result = null;

            if (classes.TryGetValue(type, out result))
            {
                return(result);
            }

            if (type.IsEnum || type.IsValueType || typeof(IDelegateBase).IsAssignableFrom(type))
            {
                // Find the top-most UClass (UUserDefinedEnum, UEnum, UUserDefinedStruct, UUserStruct, etc)
                // NOTE: This wont contain any useful information about the actual type itself

                IntPtr address = IntPtr.Zero;
                if (type.IsEnum)
                {
                    address = UEnum.GetEnumAddress(type);
                }
                else if (type.IsValueType)
                {
                    address = UScriptStruct.GetStructAddress(type);
                }
                else
                {
                    address = UFunction.GetDelegateSignatureAddress(type);
                }
                if (address != IntPtr.Zero)
                {
                    return(GetClass(address));
                }
                return(null);
            }

            if (!type.IsSameOrSubclassOf(typeof(UObject)) &&
                (!type.IsInterface || !typeof(IInterface).IsAssignableFrom(type)) || type == typeof(IInterface))
            {
                return(null);
            }

            if (seenClasses.Contains(type))
            {
                // Note: GetModuleCount uses a lock
                // TODO: Find some multicast delegate which is called when a module is loaded or a new class type is created.
                // - FModuleManager::Get().OnProcessLoadedObjectsCallback
                if (FModuleManager.Get().GetModuleCount() != lastModuleCount)
                {
                    seenClasses.Clear();
                }
                else
                {
                    return(null);
                }
            }

            if (!seenClasses.Contains(type))
            {
                seenClasses.Add(type);

                UMetaPathAttribute pathAttribute;
                if (UnrealTypes.Native.TryGetValue(type, out pathAttribute))
                {
                    IntPtr classAddress = GetClassAddress(pathAttribute.Path);
                    if (classAddress == IntPtr.Zero)
                    {
                        // Fallback if this class isn't loaded yet. TODO: Check if this is the correct method to call.
                        classAddress = NativeReflection.LoadObject(Classes.UClass, IntPtr.Zero, pathAttribute.Path);
                    }
                    if (classAddress != IntPtr.Zero)
                    {
                        UClass unrealClass = GCHelper.Find <UClass>(classAddress);
                        if (unrealClass != null)
                        {
                            classesByAddress[classAddress] = type;
                            classes[type] = unrealClass;
                            return(unrealClass);
                        }
                    }
                }
            }

            return(null);
        }