Inheritance: HasVersionRange
Example #1
0
        private static void AddUndocumentApis(UnityApi unityApi, Version apiVersion)
        {
            // From AssetPostprocessingInternal
            var type = unityApi.FindType("AssetPostprocessor");

            var eventFunction = new UnityApiEventFunction("OnPreprocessAssembly", false, ApiType.Void, apiVersion, undocumented: true);
            eventFunction.AddParameter("pathName", ApiType.String);
            type.MergeEventFunction(eventFunction, apiVersion);

            eventFunction = new UnityApiEventFunction("OnGeneratedCSProjectFiles", true, ApiType.Void, apiVersion, undocumented: true);
            type.MergeEventFunction(eventFunction, apiVersion);

            // Technically, return type is optional
            eventFunction = new UnityApiEventFunction("OnPreGeneratingCSProjectFiles", true, ApiType.Bool, apiVersion,  undocumented: true);
            type.MergeEventFunction(eventFunction, apiVersion);

            // From AssetModificationProcessorInternal
            type = unityApi.FindType("AssetModificationProcessor");
            eventFunction = new UnityApiEventFunction("OnStatusUpdated", true, ApiType.Void, apiVersion, undocumented: true);
            type.MergeEventFunction(eventFunction, apiVersion);

            // ScriptableObject
            // From Shawn White @ Unity (https://github.com/JetBrains/resharper-unity/issues/79#issuecomment-266727851):
            // OnValidate's behavior on ScriptableObject is the same as on MonoBehaviour. OnValidate is a non-static
            // method which is invoked from native and isn't picky about visibility (it'll get invoked regardless of
            // visibility). OnValidate is different from the other magic methods in that it only gets invoked from
            // the Editor. A good practice is to wrap OnValidate with #if UNITY_EDITOR so that the function can be
            // stripped out for deployment.
            //
            // To expand on ScriptableObject a bit. Native Unity code doesn't distinguish between MonoBehaviour and
            // ScriptableObject. They are the same native type (it's confusing, I know, and everyone gets tripped up
            // by it that looks at the native code base). The only difference is in how the object is used,
            // MonoBehaviours live on GameObjects, while ScriptableObjects can live alone.So in general, all magic
            // methods that would make sense without a GameObject context should work and be implemented for
            // ScriptableObjects. Off the top of my head this includes, Awake, OnEnable, OnDisable, OnDestroy,
            // OnValidate, and Reset, but there could be more.
            type = unityApi.FindType("ScriptableObject");

            eventFunction = new UnityApiEventFunction("OnValidate", false, ApiType.Void, apiVersion,
                description: "This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only).",
                undocumented: true);
            type.MergeEventFunction(eventFunction, apiVersion);

            eventFunction = new UnityApiEventFunction("Reset", false, ApiType.Void, apiVersion,
                description: "Reset to default values.", undocumented: true);
            type.MergeEventFunction(eventFunction, apiVersion);
        }
Example #2
0
        private static void AddUndocumentedCoroutines(UnityApi unityApi)
        {
            Console.WriteLine("Adding undocumented coroutines");

            var type = unityApi.FindType("MonoBehaviour");

            if (type != null)
            {
                // Not documented directly, but shown in examples
                // https://docs.unity3d.com/ScriptReference/MonoBehaviour.StartCoroutine.html
                // https://docs.unity3d.com/ScriptReference/WaitForEndOfFrame.html
                SetIsCoroutine(type, "Start");

                // Not documented as co-routines, but the non-2D versions are
                SetIsCoroutine(type, "OnCollisionEnter2D");
                SetIsCoroutine(type, "OnCollisionExit2D");
                SetIsCoroutine(type, "OnCollisionStay2D");
                SetIsCoroutine(type, "OnTriggerEnter2D");
                SetIsCoroutine(type, "OnTriggerExit2D");
                SetIsCoroutine(type, "OnTriggerStay2D");
            }
        }
Example #3
0
        public static void Main(string[] args)
        {
            var progPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
            var dataPath = Path.Combine(progPath, @"Unity\Editor\Data");
            var monoPath = Path.Combine(dataPath, @"Mono\lib\mono\unity");
            var basePath = Path.Combine(dataPath, @"Managed");

            TypeResolver.AddAssembly(typeof(string).Assembly);
            TypeResolver.AddAssembly(Assembly.LoadFrom(Path.Combine(basePath, @"UnityEngine.dll")));
            TypeResolver.AddAssembly(Assembly.LoadFrom(Path.Combine(monoPath, @"UnityScript.dll")));
            TypeResolver.AddAssembly(Assembly.LoadFrom(Path.Combine(basePath, @"UnityEditor.dll")));
            Console.WriteLine();

            var unityApi = new UnityApi();
            var parser = new ApiParser(unityApi, ScriptReferenceRelativePath);

            parser.Progress += (s, e) =>
            {
                var cursorTop = Console.CursorTop;
                Console.WriteLine("{0,5} / {1,5} ({2,3}%)", e.Current, e.Total, e.Percent);
                Console.SetCursorPosition(0, cursorTop);
            };

            foreach (var doc in Docs)
            {
                Console.WriteLine(doc.Item1);
                parser.ParseFolder(doc.Item1, doc.Item2);
                AddUndocumentApis(unityApi, doc.Item2);
            }

            using (var writer = new XmlTextWriter(@"api.xml", Encoding.UTF8) {Formatting = Formatting.Indented})
            {
                parser.ExportTo(writer);
            }

            // Console.WriteLine( "Press <Enter> key to continue..." );
            // Console.ReadLine();
        }
Example #4
0
 public ApiParser(UnityApi api, string scriptReferenceRelativePath)
 {
     myApi = api;
     myScriptReferenceRelativePath = scriptReferenceRelativePath;
 }
Example #5
0
 public ApiParser(UnityApi api, TypeResolver typeResolver)
 {
     myApi          = api;
     myTypeResolver = typeResolver;
 }
Example #6
0
 public ApiParser(UnityApi api)
 {
     myApi = api;
 }
Example #7
0
 public ApiParser(UnityApi api, string scriptReferenceRelativePath)
 {
     this.api = api;
     myScriptReferenceRelativePath = scriptReferenceRelativePath;
 }
Example #8
0
        public static void Main(string[] args)
        {
            if (args.Length != 1)
            {
                Console.WriteLine("Usage: ApiParser.exe docsFolder");
                Console.WriteLine();
                Console.WriteLine("  docsFolder - folder that contains all versions of Unity docs");
                return;
            }

            var stopwatch = Stopwatch.StartNew();

            Directory.SetCurrentDirectory(args[0]);

            var progPath    = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
            var managedPath = Path.Combine(progPath, "Unity", "Editor", "Data", "Managed");

            if (!Directory.Exists(managedPath))
            {
                // TODO: Find the latest version rather than hardcode it
                // TODO: Handle this in Windows, too
                //managedPath = Path.Combine(progPath, "Unity", "Hub", "Editor", "2018.1.0b9", "Unity.app", "Contents", "Managed");
                managedPath = Path.Combine(progPath, "Unity", "Hub", "Editor", "2017.3.1f1", "Unity.app", "Contents", "Managed");
            }

            // Add assemblies to the type resolver so we can get the fully qualified names of types
            // The Unity docs only give us the short names
            TypeResolver.AddAssembly(Assembly.LoadFrom(Path.Combine(managedPath, @"UnityEngine.dll")));
            TypeResolver.AddAssembly(Assembly.LoadFrom(Path.Combine(managedPath, @"UnityEditor.dll")));
            Console.WriteLine();

            var unityApi = new UnityApi();
            var parser   = new ApiParser(unityApi, ScriptReferenceRelativePath);

            parser.Progress += (s, e) =>
            {
                var cursorTop = Console.CursorTop;
                Console.WriteLine("{0,5} / {1,5} ({2,3}%)", e.Current, e.Total, e.Percent);
                Console.SetCursorPosition(0, cursorTop);
            };

            foreach (var doc in Docs)
            {
                Console.WriteLine(doc.Item1);
                parser.ParseFolder(doc.Item1, doc.Item2);

                // These are valid for all versions
                AddUndocumentedApis(unityApi, doc.Item2);
            }

            // THese modify existing functions
            AddUndocumentedOptionalParameters(unityApi);
            AddUndocumentedCoroutines(unityApi);
            FixDataFromIncorrectDocs(unityApi);

            using (var writer = new XmlTextWriter(@"api.xml", Encoding.UTF8)
            {
                Formatting = Formatting.Indented
            })
            {
                parser.ExportTo(writer);
            }

            Console.WriteLine("Done. Elapsed time: {0}", stopwatch.Elapsed);

            // Console.WriteLine( "Press <Enter> key to continue..." );
            // Console.ReadLine();
        }
Example #9
0
        private static void AddUndocumentedApis(UnityApi unityApi, Version apiVersion)
        {
            // From AssetPostprocessingInternal
            var type = unityApi.FindType("AssetPostprocessor");

            if (type != null)
            {
                var eventFunction = new UnityApiEventFunction("OnPreprocessAssembly",
                                                              false, false, ApiType.Void, apiVersion, undocumented: true);
                eventFunction.AddParameter("pathName", ApiType.String);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnGeneratedCSProjectFiles",
                                                          true, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                // Technically, return type is optional
                eventFunction = new UnityApiEventFunction("OnPreGeneratingCSProjectFiles",
                                                          true, false, ApiType.Bool, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);
            }

            // From AssetModificationProcessorInternal
            type = unityApi.FindType("AssetModificationProcessor");
            if (type != null)
            {
                var eventFunction = new UnityApiEventFunction("OnStatusUpdated", true,
                                                              false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);
            }

            type = unityApi.FindType("MonoBehaviour");
            if (type != null)
            {
                const string description =
                    "This callback is called if an associated RectTransform has its dimensions changed.";
                var eventFunction = new UnityApiEventFunction("OnRectTransformDimensionsChange",
                                                              false, false, ApiType.Void, apiVersion, description, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnBeforeTransformParentChanged",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnDidApplyAnimationProperties",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnCanvasGroupChanged",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnCanvasHierarchyChanged",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);
            }

            // ScriptableObject
            // From Shawn White @ Unity (https://github.com/JetBrains/resharper-unity/issues/79#issuecomment-266727851):
            // OnValidate's behavior on ScriptableObject is the same as on MonoBehaviour. OnValidate is a non-static
            // method which is invoked from native and isn't picky about visibility (it'll get invoked regardless of
            // visibility). OnValidate is different from the other magic methods in that it only gets invoked from
            // the Editor. A good practice is to wrap OnValidate with #if UNITY_EDITOR so that the function can be
            // stripped out for deployment.
            //
            // To expand on ScriptableObject a bit. Native Unity code doesn't distinguish between MonoBehaviour and
            // ScriptableObject. They are the same native type (it's confusing, I know, and everyone gets tripped up
            // by it that looks at the native code base). The only difference is in how the object is used,
            // MonoBehaviours live on GameObjects, while ScriptableObjects can live alone.So in general, all magic
            // methods that would make sense without a GameObject context should work and be implemented for
            // ScriptableObjects. Off the top of my head this includes, Awake, OnEnable, OnDisable, OnDestroy,
            // OnValidate, and Reset, but there could be more.
            type = unityApi.FindType("ScriptableObject");
            if (type != null)
            {
                var eventFunction = new UnityApiEventFunction("OnValidate", false, false, ApiType.Void, apiVersion,
                                                              description:
                                                              "This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only).",
                                                              undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("Reset", false, false, ApiType.Void, apiVersion,
                                                          description: "Reset to default values.", undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);
            }
        }
Example #10
0
        private static void AddUndocumentedApis(UnityApi unityApi, Version apiVersion)
        {
            // From AssetPostprocessingInternal
            var type = unityApi.FindType("AssetPostprocessor");

            if (type != null)
            {
                var eventFunction = new UnityApiEventFunction("OnPreprocessAssembly",
                                                              false, false, ApiType.Void, apiVersion, undocumented: true);
                eventFunction.AddParameter("pathName", ApiType.String);
                type.MergeEventFunction(eventFunction, apiVersion);

                // From GitHub. Love the optimism in this one :)
                // https://github.com/Unity-Technologies/UnityCsReference/blob/96187e5fc1a23847206bf66b6f2d0e4a1ad43301/Editor/Mono/AssetPostprocessor.cs#L96
                var description =
                    "This is undocumented, and a 'safeguard' for when Visual Studio gets a new release that "
                    + "is incompatible with Unity, so that users can postprocess our csproj files to fix the issue (or "
                    + "just completely replace them). Hopefully we'll never need this.";
                eventFunction = new UnityApiEventFunction("OnGeneratedCSProjectFiles",
                                                          true, false, ApiType.Void, apiVersion, description, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                // Technically, return type is optional
                // https://github.com/Unity-Technologies/UnityCsReference/blob/96187e5fc1a23847206bf66b6f2d0e4a1ad43301/Editor/Mono/AssetPostprocessor.cs#L138
                description   = "This callback is used by UnityVS to take over project generation from Unity";
                eventFunction = new UnityApiEventFunction("OnPreGeneratingCSProjectFiles",
                                                          true, false, ApiType.Bool, apiVersion, description, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                // These two were added in 2018.1, as verified on GitHub
                // https://github.com/Unity-Technologies/UnityCsReference/blob/2017.4/Editor/Mono/AssetPostprocessor.cs
                // https://github.com/Unity-Technologies/UnityCsReference/blob/2018.1/Editor/Mono/AssetPostprocessor.cs#L76
                if (apiVersion >= new Version(2018, 1))
                {
                    // Technically, return type is optional
                    // https://github.com/Unity-Technologies/UnityCsReference/blob/96187e5fc1a23847206bf66b6f2d0e4a1ad43301/Editor/Mono/AssetPostprocessor.cs#L123
                    description   = "This callback is used by C# code editors to modify the .csproj files.";
                    eventFunction = new UnityApiEventFunction("OnGeneratedCSProject",
                                                              true, false, ApiType.String, apiVersion, description, undocumented: true);
                    eventFunction.AddParameter("path", ApiType.String);
                    eventFunction.AddParameter("content", ApiType.String);
                    type.MergeEventFunction(eventFunction, apiVersion);

                    // Technically, return type is optional
                    // https://github.com/Unity-Technologies/UnityCsReference/blob/96187e5fc1a23847206bf66b6f2d0e4a1ad43301/Editor/Mono/AssetPostprocessor.cs#L108
                    description   = "This callback is used by C# code editors to modify the .sln file";
                    eventFunction = new UnityApiEventFunction("OnGeneratedSlnSolution",
                                                              true, false, ApiType.String, apiVersion, description, undocumented: true);
                    eventFunction.AddParameter("path", ApiType.String);
                    eventFunction.AddParameter("content", ApiType.String);
                    type.MergeEventFunction(eventFunction, apiVersion);
                }
            }

            // From AssetModificationProcessorInternal
            type = unityApi.FindType("AssetModificationProcessor");
            if (type != null)
            {
                var eventFunction = new UnityApiEventFunction("OnStatusUpdated", true,
                                                              false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);
            }

            type = unityApi.FindType("MonoBehaviour");
            if (type != null)
            {
                const string description =
                    "This callback is called if an associated RectTransform has its dimensions changed.";
                var eventFunction = new UnityApiEventFunction("OnRectTransformDimensionsChange",
                                                              false, false, ApiType.Void, apiVersion, description, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnBeforeTransformParentChanged",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnDidApplyAnimationProperties",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnCanvasGroupChanged",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnCanvasHierarchyChanged",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);
            }

            // ScriptableObject
            // From Shawn White @ Unity (https://github.com/JetBrains/resharper-unity/issues/79#issuecomment-266727851):
            // OnValidate's behavior on ScriptableObject is the same as on MonoBehaviour. OnValidate is a non-static
            // method which is invoked from native and isn't picky about visibility (it'll get invoked regardless of
            // visibility). OnValidate is different from the other magic methods in that it only gets invoked from
            // the Editor. A good practice is to wrap OnValidate with #if UNITY_EDITOR so that the function can be
            // stripped out for deployment.
            //
            // To expand on ScriptableObject a bit. Native Unity code doesn't distinguish between MonoBehaviour and
            // ScriptableObject. They are the same native type (it's confusing, I know, and everyone gets tripped up
            // by it that looks at the native code base). The only difference is in how the object is used,
            // MonoBehaviours live on GameObjects, while ScriptableObjects can live alone.So in general, all magic
            // methods that would make sense without a GameObject context should work and be implemented for
            // ScriptableObjects. Off the top of my head this includes, Awake, OnEnable, OnDisable, OnDestroy,
            // OnValidate, and Reset, but there could be more.
            type = unityApi.FindType("ScriptableObject");
            if (type != null)
            {
                var eventFunction = new UnityApiEventFunction("OnValidate", false, false, ApiType.Void, apiVersion,
                                                              description:
                                                              "This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only).",
                                                              undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("Reset", false, false, ApiType.Void, apiVersion,
                                                          description: "Reset to default values.", undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);
            }
        }
Example #11
0
        public static void Main(string[] args)
        {
            if (args.Length != 1 && args.Length != 2)
            {
                Console.WriteLine("Usage: ApiParser.exe docsFolder");
                Console.WriteLine("       ApiParser.exe apiXmlPath version");
                Console.WriteLine();
                Console.WriteLine("ApiParser.exe docsFolder");
                Console.WriteLine("  Parse all documentation installed by Unity Hub, as well as everything in the docsFolder and create a new api.xml");
                Console.WriteLine();
                Console.WriteLine("  docsFolder - folder that contains multiple versions of Unity docs");
                Console.WriteLine("               Contents should be in the format Documentation-X.Y.ZfA/Documentation/en/ScriptReference");
                Console.WriteLine();
                Console.WriteLine("ApiParser.exe apiXmlPath version");
                Console.WriteLine("  Parse the installed documentation corresponding to version and merge into an existing api.xml file");
                Console.WriteLine();
                Console.WriteLine("  apiXmlPath - location of api.xml to read and merge into");
                Console.WriteLine("  version - version of Unity to read docs from. Must be installed in standard Unity Hub location");
                Console.WriteLine();
                Console.WriteLine("Note that the output file is written to the current directory");
                return;
            }

            var stopwatch = Stopwatch.StartNew();
            var apiXml    = FileSystemPath.Parse("api.xml");

            var docVersions = new List <(string, Version)>();

            if (args.Length == 1)
            {
                Directory.SetCurrentDirectory(args[0]);
                foreach (var directory in Directory.EnumerateDirectories(Directory.GetCurrentDirectory()))
                {
                    var docFolder = Path.Combine(Directory.GetCurrentDirectory(), directory);
                    var version   = Regex.Match(directory, @"Documentation-(\d+.\d+)").Groups[1].Value;
                    docVersions.Add((docFolder, Version.Parse(version)));
                }

                foreach (var directory in Directory.EnumerateDirectories(Path.Combine(
                                                                             Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Unity", "Hub", "Editor")))
                {
                    var docFolder = GetDocumentationRoot(directory).FullPath;
                    var version   = Regex.Match(directory, @"(\d+.\d+)").Groups[1].Value;
                    docVersions.Add((docFolder, Version.Parse(version)));
                }

                docVersions = docVersions.OrderBy(v => v.Item2).ToList();
            }
            else
            {
                apiXml = FileSystemPath.ParseRelativelyTo(args[0], FileSystemPath.Parse(Directory.GetCurrentDirectory()));
                if (!apiXml.ExistsFile)
                {
                    throw new InvalidOperationException("api.xml path does not exist");
                }

                var requiredVersion = args[1];
                var docRoot         = GetDocumentationRoot(requiredVersion);
                if (!docRoot.ExistsDirectory)
                {
                    throw new InvalidOperationException($"Cannot find locally installed docs: {docRoot}");
                }
                var parseableVersion = Regex.Match(requiredVersion, @"^(\d+\.\d+)").Groups[1].Value;
                docVersions.Add((docRoot.FullPath, Version.Parse(parseableVersion)));
            }

            var unityApi = new UnityApi();

            if (apiXml.ExistsFile)
            {
                unityApi = UnityApi.ImportFrom(apiXml);
            }
            var typeResolver = new TypeResolver();
            var parser       = new ApiParser(unityApi, typeResolver);

            foreach (var(name, version) in docVersions)
            {
                Console.WriteLine($"{name} ({version})");
                parser.ParseFolder(name, version);

                AddUndocumentedApis(unityApi, version);
            }

            // These modify existing functions
            AddUndocumentedOptionalParameters(unityApi);
            AddUndocumentedCoroutines(unityApi);
            FixDataFromIncorrectDocs(unityApi, typeResolver);

            using (var writer = new XmlTextWriter(apiXml.FullPath, Encoding.UTF8)
            {
                Formatting = Formatting.Indented
            })
            {
                parser.ExportTo(writer);
            }

            Console.WriteLine("Done. Elapsed time: {0}", stopwatch.Elapsed);

            // Console.WriteLine( "Press <Enter> key to continue..." );
            // Console.ReadLine();
        }
Example #12
0
        // Note that if we add new undocumented APIs, this won't set the correct min/max version range, and will only
        // apply the given api versions. That gives us two options:
        // 1) Recreate the api.xml file from scratch by parsing the documentation of every Unity version since 5.0
        // 2) Cheat a little. When incrementally updating an existing api.xml for a single version and also adding new
        //    undocumented APIs, add extra calls to AddUndocumentedApis with the min/max version for those new APIs.
        //    Don't check these extra calls in!
        private static void AddUndocumentedApis(UnityApi unityApi, Version apiVersion)
        {
            // From AssetPostprocessingInternal
            var type = unityApi.FindType("AssetPostprocessor");

            if (type != null)
            {
                var eventFunction = new UnityApiEventFunction("OnPreprocessAssembly",
                                                              false, false, ApiType.Void, apiVersion, undocumented: true);
                eventFunction.AddParameter("pathName", ApiType.String);
                type.MergeEventFunction(eventFunction, apiVersion);

                // From GitHub. Love the optimism in this one :)
                // https://github.com/Unity-Technologies/UnityCsReference/blob/96187e5fc1a23847206bf66b6f2d0e4a1ad43301/Editor/Mono/AssetPostprocessor.cs#L96
                var description =
                    "This is undocumented, and a 'safeguard' for when Visual Studio gets a new release that "
                    + "is incompatible with Unity, so that users can postprocess our csproj files to fix the issue (or "
                    + "just completely replace them). Hopefully we'll never need this.";
                eventFunction = new UnityApiEventFunction("OnGeneratedCSProjectFiles",
                                                          true, false, ApiType.Void, apiVersion, description, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                // Technically, return type is optional
                // https://github.com/Unity-Technologies/UnityCsReference/blob/96187e5fc1a23847206bf66b6f2d0e4a1ad43301/Editor/Mono/AssetPostprocessor.cs#L138
                description   = "This callback is used by UnityVS to take over project generation from Unity";
                eventFunction = new UnityApiEventFunction("OnPreGeneratingCSProjectFiles",
                                                          true, false, ApiType.Bool, apiVersion, description, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                // These two were added in 2018.1, as verified on GitHub
                // https://github.com/Unity-Technologies/UnityCsReference/blob/2017.4/Editor/Mono/AssetPostprocessor.cs
                // https://github.com/Unity-Technologies/UnityCsReference/blob/2018.1/Editor/Mono/AssetPostprocessor.cs#L76
                if (apiVersion >= new Version(2018, 1))
                {
                    // Technically, return type is optional
                    // https://github.com/Unity-Technologies/UnityCsReference/blob/96187e5fc1a23847206bf66b6f2d0e4a1ad43301/Editor/Mono/AssetPostprocessor.cs#L123
                    description   = "This callback is used by C# code editors to modify the .csproj files.";
                    eventFunction = new UnityApiEventFunction("OnGeneratedCSProject",
                                                              true, false, ApiType.String, apiVersion, description, undocumented: true);
                    eventFunction.AddParameter("path", ApiType.String);
                    eventFunction.AddParameter("content", ApiType.String);
                    type.MergeEventFunction(eventFunction, apiVersion);

                    // Technically, return type is optional
                    // https://github.com/Unity-Technologies/UnityCsReference/blob/96187e5fc1a23847206bf66b6f2d0e4a1ad43301/Editor/Mono/AssetPostprocessor.cs#L108
                    description   = "This callback is used by C# code editors to modify the .sln file";
                    eventFunction = new UnityApiEventFunction("OnGeneratedSlnSolution",
                                                              true, false, ApiType.String, apiVersion, description, undocumented: true);
                    eventFunction.AddParameter("path", ApiType.String);
                    eventFunction.AddParameter("content", ApiType.String);
                    type.MergeEventFunction(eventFunction, apiVersion);
                }
            }

            // From AssetModificationProcessorInternal
            type = unityApi.FindType("AssetModificationProcessor");
            if (type != null)
            {
                var eventFunction = new UnityApiEventFunction("OnStatusUpdated", true,
                                                              false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);
            }

            type = unityApi.FindType("MonoBehaviour");
            if (type != null)
            {
                const string description =
                    "This callback is called if an associated RectTransform has its dimensions changed.";
                var eventFunction = new UnityApiEventFunction("OnRectTransformDimensionsChange",
                                                              false, false, ApiType.Void, apiVersion, description, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnBeforeTransformParentChanged",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnDidApplyAnimationProperties",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnCanvasGroupChanged",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                eventFunction = new UnityApiEventFunction("OnCanvasHierarchyChanged",
                                                          false, false, ApiType.Void, apiVersion, undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);
            }

            // ScriptableObject
            // From Shawn White @ Unity (https://github.com/JetBrains/resharper-unity/issues/79#issuecomment-266727851):
            // OnValidate's behavior on ScriptableObject is the same as on MonoBehaviour. OnValidate is a non-static
            // method which is invoked from native and isn't picky about visibility (it'll get invoked regardless of
            // visibility). OnValidate is different from the other magic methods in that it only gets invoked from
            // the Editor. A good practice is to wrap OnValidate with #if UNITY_EDITOR so that the function can be
            // stripped out for deployment.
            //
            // To expand on ScriptableObject a bit. Native Unity code doesn't distinguish between MonoBehaviour and
            // ScriptableObject. They are the same native type (it's confusing, I know, and everyone gets tripped up
            // by it that looks at the native code base). The only difference is in how the object is used,
            // MonoBehaviours live on GameObjects, while ScriptableObjects can live alone.So in general, all magic
            // methods that would make sense without a GameObject context should work and be implemented for
            // ScriptableObjects. Off the top of my head this includes, Awake, OnEnable, OnDisable, OnDestroy,
            // OnValidate, and Reset, but there could be more.
            type = unityApi.FindType("ScriptableObject");
            if (type != null && apiVersion < new Version(2020, 1))
            {
                // Documented in 2020.1
                var eventFunction = new UnityApiEventFunction("OnValidate", false, false, ApiType.Void, apiVersion,
                                                              description:
                                                              "This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only).",
                                                              undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                // Documented in 2020.1
                eventFunction = new UnityApiEventFunction("Reset", false, false, ApiType.Void, apiVersion,
                                                          description: "Reset to default values.", undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);
            }

            // TODO: Check if these event functions are available in 5.0 - 5.6
            type = unityApi.FindType("Editor");
            if (type != null && apiVersion >= new Version(2017, 1))
            {
                // Editor.OnPreSceneGUI has been around since at least 2017.1. Still undocumented as of 2020.2
                // https://github.com/Unity-Technologies/UnityCsReference/blob/2017.1/Editor/Mono/SceneView/SceneView.cs#L2436
                var eventFunction = new UnityApiEventFunction("OnPreSceneGUI", false, false, ApiType.Void, apiVersion,
                                                              description: "Called before the Scene view is drawn.",
                                                              undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                // Editor.OnSceneDrag has been around since at least 2017.1. Still undocumented as of 2020.2
                // https://github.com/Unity-Technologies/UnityCsReference/blob/2017.1/Editor/Mono/GUI/EditorCache.cs#L63
                eventFunction = new UnityApiEventFunction("OnSceneDrag", false, false, ApiType.Void, apiVersion,
                                                          description: "Called for each object dragged onto the scene view",
                                                          undocumented: true);
                eventFunction.AddParameter("sceneView", new ApiType("UnityEditor.SceneView"), "The current scene view");
                eventFunction.AddParameter("index", ApiType.Int, "The index into the DragAndDrop.objectReferences array");
                type.MergeEventFunction(eventFunction, apiVersion);

                if (apiVersion < new Version(2020, 2))
                {
                    // Editor.HasFrameBounds has been around since at least 2017.1. First documented in 2020.2
                    // https://github.com/Unity-Technologies/UnityCsReference/blob/2017.1/Editor/Mono/SceneView/SceneView.cs#L2296
                    // https://docs.unity3d.com/2020.2/Documentation/ScriptReference/Editor.HasFrameBounds.html
                    eventFunction = new UnityApiEventFunction("HasFrameBounds", false, false, ApiType.Bool,
                                                              apiVersion,
                                                              description: "Validates whether custom bounds can be calculated for this editor.",
                                                              undocumented: true);
                    type.MergeEventFunction(eventFunction, apiVersion);

                    // Editor.OnGetFrameBounds has been around since at least 2017.1. First documented in 2020.2
                    // https://github.com/Unity-Technologies/UnityCsReference/blob/2017.1/Editor/Mono/SceneView/SceneView.cs#L2303
                    // https://docs.unity3d.com/2020.2/Documentation/ScriptReference/Editor.OnGetFrameBounds.html
                    eventFunction = new UnityApiEventFunction("OnGetFrameBounds", false, false,
                                                              new ApiType("UnityEngine.Bounds"), apiVersion,
                                                              description: "Gets custom bounds for the target of this editor.",
                                                              undocumented: true);
                    type.MergeEventFunction(eventFunction, apiVersion);
                }
            }

            // TODO: Check if these event functions are available in 5.0 - 5.6
            type = unityApi.FindType("EditorWindow");
            if (type != null && apiVersion >= new Version(2017, 1))
            {
                // EditorWindow.ModifierKeysChanged has been around since at least 2017.1. Still undocumented as of 2020.2
                // https://github.com/Unity-Technologies/UnityCsReference/blob/2017.1/Editor/Mono/HostView.cs#L290
                // http://www.improck.com/2014/11/editorwindow-modifier-keys/
                var eventFunction = new UnityApiEventFunction("ModifierKeysChanged", false, false, ApiType.Void, apiVersion,
                                                              description: "Called when the modifier keys are changed. Automatically registers and de-registers the EditorApplication.modifierKeysChanged event",
                                                              undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                // EditorWindow.ShowButton has been around since at least 2017.1. Still undocumented as of 2020.2
                // https://github.com/Unity-Technologies/UnityCsReference/blob/2017.1/Editor/Mono/HostView.cs#L356
                // http://www.improck.com/2014/11/editorwindow-inspector-lock-icon/
                eventFunction = new UnityApiEventFunction("ShowButton", false, false, ApiType.Void, apiVersion,
                                                          description: "Allow Editor panes to show a small button next to the generic menu (e.g. inspector lock icon)",
                                                          undocumented: true);
                eventFunction.AddParameter("rect", new ApiType("UnityEngine.Rect"), "Position to draw the button");
                type.MergeEventFunction(eventFunction, apiVersion);

                // EditorWindow.OnBecameVisible has been around since at least 2017.1. Still undocumented as of 2020.2
                // https://github.com/Unity-Technologies/UnityCsReference/blob/2017.1/Editor/Mono/HostView.cs#L302
                eventFunction = new UnityApiEventFunction("OnBecameVisible", false, false, ApiType.Void, apiVersion,
                                                          description: "Called when an editor window has been opened",
                                                          undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                // EditorWindow.OnBecameInvisible has been around since at least 2017.1. Still undocumented as of 2020.2
                // https://github.com/Unity-Technologies/UnityCsReference/blob/2017.1/Editor/Mono/HostView.cs#L337
                eventFunction = new UnityApiEventFunction("OnBecameInvisible", false, false, ApiType.Void, apiVersion,
                                                          description: "Called when an editor window has been closed",
                                                          undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                // EditorWindow.OnDidOpenScene has been around since at least 2017.1. Still undocumented as of 2020.2
                // https://github.com/Unity-Technologies/UnityCsReference/blob/2017.1/Editor/Mono/HostView.cs#L163
                eventFunction = new UnityApiEventFunction("OnDidOpenScene", false, false, ApiType.Void, apiVersion,
                                                          description: "Called when a scene has been opened",
                                                          undocumented: true);
                type.MergeEventFunction(eventFunction, apiVersion);

                if (apiVersion >= new Version(2019, 1))
                {
                    // EditorWindow.OnAddedAsTab was introduced in 2019.1. Still undocumented as of 2020.2
                    // https://github.com/Unity-Technologies/UnityCsReference/blob/2019.1/Editor/Mono/GUI/DockArea.cs#L188
                    eventFunction = new UnityApiEventFunction("OnAddedAsTab", false, false, ApiType.Void, apiVersion,
                                                              description: "Called when the editor window is added as a tab",
                                                              undocumented: true);
                    type.MergeEventFunction(eventFunction, apiVersion);

                    // EditorWindow.OnBeforeRemovedAsTab was introduced in 2019.1
                    // https://github.com/Unity-Technologies/UnityCsReference/blob/2019.1/Editor/Mono/GUI/DockArea.cs#L195
                    eventFunction = new UnityApiEventFunction("OnBeforeRemovedAsTab", false, false, ApiType.Void, apiVersion,
                                                              description: "Called before an editor window is removed as a tab",
                                                              undocumented: true);
                }

                if (apiVersion >= new Version(2019, 3))
                {
                    // EditorWindow.OnTabDetached was introduced in 2019.3
                    // https://github.com/Unity-Technologies/UnityCsReference/blob/2019.3/Editor/Mono/GUI/DockArea.cs#L940
                    eventFunction = new UnityApiEventFunction("OnTabDetached", false, false, ApiType.Void, apiVersion,
                                                              description: "Called during drag and drop, when an editor window tab is detached",
                                                              undocumented: true);
                    type.MergeEventFunction(eventFunction, apiVersion);
                }

                if (apiVersion >= new Version(2020, 1))
                {
                    // EditorWindow.OnMainWindowMove was introduced in 2020.1
                    // https://github.com/Unity-Technologies/UnityCsReference/blob/2020.1/Editor/Mono/HostView.cs#L343
                    // See comment here
                    // https://github.com/Unity-Technologies/UnityCsReference/blob/2020.1/Editor/Mono/ExternalPlayModeView/ExternalPlayModeView.cs#L112
                    eventFunction = new UnityApiEventFunction("OnMainWindowMove", false, false, ApiType.Void, apiVersion,
                                                              description: "Called when the main window is moved",
                                                              undocumented: true);
                    type.MergeEventFunction(eventFunction, apiVersion);
                }
            }
        }