Inheritance: HasVersionRange
Exemple #1
0
        private static void AddUndocumentApis(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);
            }

            // 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);
            }
        }
Exemple #2
0
        private UnityApiEventFunction ParseMessage(ApiNode message, Version apiVersion, string hintNamespace)
        {
            var link = message.SelectOne(@"td.lbl/a");
            var desc = message.SelectOne(@"td.desc");

            if (link == null || desc == null)
            {
                return(null);
            }

            var detailsPath = link[@"href"];

            if (string.IsNullOrWhiteSpace(detailsPath))
            {
                return(null);
            }

            var path = Path.Combine(myScriptReferenceRelativePath, detailsPath);

            if (!File.Exists(path))
            {
                return(null);
            }

            var detailsDoc = ApiNode.Load(path);
            var details    = detailsDoc?.SelectOne(@"//div.content/div.section");
            var signature  = details?.SelectOne(@"div.mb20.clear/h1.heading.inherit");
            var staticNode = details?.SelectOne(@"div.subsection/p/code.varname[text()='static']");

            if (signature == null)
            {
                return(null);
            }

            var isCoroutine = CoroutineRegex.IsMatch(details.Text);

            var messageName = link.Text;
            var returnType  = ApiType.Void;

            string[] argumentNames       = null;
            var      isStaticFromExample = false;

            var example = PickExample(details);

            if (example != null)
            {
                var tuple = ParseDetailsFromExample(messageName, example, hintNamespace);
                returnType          = tuple.Item1;
                argumentNames       = tuple.Item2;
                isStaticFromExample = tuple.Item3;
            }

            var docPath       = Path.Combine(myScriptReferenceRelativePath, detailsPath);
            var eventFunction = new UnityApiEventFunction(messageName, staticNode != null || isStaticFromExample, isCoroutine,
                                                          returnType, apiVersion, desc.Text, docPath);

            ParseParameters(eventFunction, signature, details, hintNamespace, argumentNames);

            return(eventFunction);
        }
Exemple #3
0
        public void MergeEventFunction(UnityApiEventFunction newFunction, Version apiVersion)
        {
            UpdateSupportedVersion(apiVersion);

            var newFunctionSig = newFunction.ToString();

            foreach (var eventFunction in myEventFunctions)
            {
                if (eventFunction.ToString() == newFunctionSig)
                {
                    // Prefer an existing documented function that covers this version, than an undocumented one. This
                    // means we will automatically replace our undocumented functions with documented versions without
                    // having to explicitly add an end version
                    if (newFunction.IsUndocumented && !eventFunction.IsUndocumented &&
                        eventFunction.MinimumVersion <= apiVersion && eventFunction.MaximumVersion >= apiVersion)
                    {
                        return;
                    }

                    // If the documented state of both functions is the same, update the function
                    if (newFunction.IsUndocumented == eventFunction.IsUndocumented)
                    {
                        eventFunction.Update(newFunction, apiVersion);
                        return;
                    }
                }
            }

            // Not a match. We either haven't found this function before,
            // or a parameter or return type is different
            myEventFunctions.Add(newFunction);
        }
Exemple #4
0
        public static UnityApiType ImportFrom(XElement element, HasVersionRange apiVersions)
        {
            var ns   = element.Attribute("ns").Value;
            var name = element.Attribute("name").Value;
            var kind = element.Attribute("kind").Value;
            var path = element.Attribute("path").Value;
            var type = new UnityApiType(ns, name, kind, path, new Version(0, 0));

            type.ImportVersionRange(element, apiVersions);
            foreach (var message in element.Descendants("message"))
            {
                type.myEventFunctions.Add(UnityApiEventFunction.ImportFrom(message, type));
            }
            return(type);
        }
Exemple #5
0
        public void Update(UnityApiEventFunction function, Version apiVersion)
        {
            if (UpdateSupportedVersion(apiVersion))
            {
                if (function.myDescription != myDescription && !string.IsNullOrEmpty(function.myDescription))
                {
                    myDescription = function.myDescription;
                }

                for (var i = 0; i < myParameters.Count; i++)
                {
                    myParameters[i].Update(function.myParameters[i]);
                }
            }
        }
Exemple #6
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);
        }
        public void MergeEventFunction(UnityApiEventFunction newFunction, Version apiVersion)
        {
            UpdateSupportedVersion(apiVersion);

            var newFunctionSig = newFunction.ToString();

            foreach (var eventFunction in myEventFunctions)
            {
                // If the signature matches, we've already got it, just
                // make sure it's up to date (newer docs take precedence
                // for e.g. param names, description, etc)
                if (eventFunction.ToString() == newFunctionSig)
                {
                    eventFunction.Update(newFunction, apiVersion);
                    return;
                }
            }

            // Not a match. We either haven't found this function before,
            // or a parameter or return type is different
            myEventFunctions.Add(newFunction);
        }
Exemple #8
0
        public static UnityApiEventFunction ImportFrom(XElement message, HasVersionRange versions)
        {
            var name                  = message.Attribute("name").Value;
            var isStatic              = bool.Parse(message.Attribute("static").Value);
            var coroutineAttribute    = message.Attribute("coroutine");
            var isCoroutine           = coroutineAttribute != null && bool.Parse(coroutineAttribute.Value);
            var description           = message.Attribute("description")?.Value;
            var path                  = message.Attribute("path")?.Value;
            var undocumentedAttribute = message.Attribute("undocumented");
            var isUndocumented        = undocumentedAttribute != null && bool.Parse(undocumentedAttribute.Value);
            var returns               = message.Descendants("returns").First();
            var type                  = returns.Attribute("type").Value;
            var isArray               = bool.Parse(returns.Attribute("array").Value);
            var returnType            = new ApiType(type + (isArray ? "[]" : string.Empty));
            var function              = new UnityApiEventFunction(name, isStatic, isCoroutine, returnType, new Version(int.MaxValue, 0), description,
                                                                  path, isUndocumented);

            function.ImportVersionRange(message, versions);
            foreach (var parameter in message.Descendants("parameter"))
            {
                function.myParameters.Add(UnityApiParameter.ImportFrom(parameter));
            }
            return(function);
        }
Exemple #9
0
        private static void ParseParameters(UnityApiEventFunction eventFunction, ApiNode signature, ApiNode details, string owningMessageNamespace, string[] argumentNames)
        {
            // Capture the arguments string. Note that this might be `string s, int i` or `string, int`
            var match = CaptureArgumentsRegex.Match(signature.Text);

            if (!match.Success)
            {
                return;
            }

            var argumentString  = match.Groups["args"].Value;
            var argumentStrings = argumentString.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                                  .Select(s => s.Trim())
                                  .ToArray();
            var total     = argumentStrings.Length;
            var arguments = argumentStrings.Select((s, i) => new Argument(s, i, total, owningMessageNamespace)).ToArray();

            ResolveArguments(details, arguments, argumentNames);

            foreach (var argument in arguments)
            {
                eventFunction.AddParameter(argument.Name, argument.Type, argument.Description);
            }
        }
Exemple #10
0
        private static void ParseParameters(UnityApiEventFunction eventFunction, ApiNode signature, ApiNode details, string owningMessageNamespace, string[] argumentNames)
        {
            // E.g. OnCollisionExit2D(Collision2D) - doesn't always include the argument name
            // Hopefully, we parsed the argument name from the example
            var argumentString = SigRegex.Replace(signature.Text, "$2$3");

            if (string.IsNullOrWhiteSpace(argumentString))
            {
                return;
            }

            var argumentStrings = argumentString.Split(',')
                                  .Select(s => s.Trim())
                                  .ToArray();
            var total     = argumentStrings.Length;
            var arguments = argumentStrings.Select((s, i) => new Argument(s, i, total, owningMessageNamespace)).ToArray();

            ResolveArguments(details, arguments, argumentNames);

            foreach (var argument in arguments)
            {
                eventFunction.AddParameter(argument.Name, argument.Type, argument.Description);
            }
        }
Exemple #11
0
        private UnityApiEventFunction ParseMessage(string className, ApiNode message, Version apiVersion,
                                                   string hintNamespace, HashSet <string> processed)
        {
            var link = message.SelectOne(@"td.lbl/a");
            var desc = message.SelectOne(@"td.desc");

            if (link == null || desc == null)
            {
                return(null);
            }

            var detailsPath = link[@"href"];

            if (string.IsNullOrWhiteSpace(detailsPath))
            {
                return(null);
            }

            var scriptReferenceRelativePath = Directory.Exists(ScriptReferenceRelativePath1)
                ? ScriptReferenceRelativePath1
                : ScriptReferenceRelativePath2;
            var path = Path.Combine(scriptReferenceRelativePath, detailsPath);

            processed.Add(path);
            if (!File.Exists(path))
            {
                return(null);
            }

            var detailsDoc = ApiNode.Load(path);
            var details    = detailsDoc?.SelectOne(@"//div.content/div.section");
            var signature  = details?.SelectOne(@"div.mb20.clear/h1.heading.inherit");
            var staticNode = details?.SelectOne(@"div.subsection/p/code.varname[text()='static']");

            if (signature == null)
            {
                return(null);
            }

            var isCoroutine = IsCoroutineRegex.IsMatch(details.Text);

            var messageName         = link.Text;
            var returnType          = ApiType.Void;
            var argumentNames       = EmptyArray <string> .Instance;
            var isStaticFromExample = false;

            var examples = PickExample(details);

            if (examples.Length > 0)
            {
                var tuple = ParseDetailsFromExample(messageName, examples, hintNamespace);

                // As of 2017.4, the docs for MonoBehaviour.OnCollisionEnter2D don't include a valid example. It demonstrates
                // OnTriggerEnter2D instead. Similar problems for these other methods
                if (tuple == null)
                {
                    var fullName = $"{className}.{messageName}";
                    switch (fullName)
                    {
                    case "MonoBehaviour.OnCollisionEnter2D":
                    case "MonoBehaviour.OnCollisionExit2D":
                    case "MonoBehaviour.OnCollisionStay2D":
                    case "MonoBehaviour.Start":
                    case "MonoBehaviour.OnDestroy":
                        Console.WriteLine(
                            $"WARNING: Unable to parse example for {fullName}. Example incorrect in docs");
                        break;

//                        case "Network.OnDisconnectedFromServer":
//                            Bug in 2018.2 documentation
//                            Console.WriteLine($"WARNING: Missing example for {fullName}");
//                            break;

                    default:
                        foreach (var example in examples)
                        {
                            Console.WriteLine(example.Text);
                            Console.WriteLine();
                        }

                        throw new InvalidOperationException($"Failed to parse example for {className}.{messageName}");
                    }
                }

                if (tuple != null)
                {
                    returnType          = tuple.Item1;
                    argumentNames       = tuple.Item2;
                    isStaticFromExample = tuple.Item3;
                }
            }

            if (Equals(returnType, ApiType.IEnumerator))
            {
                returnType  = ApiType.Void;
                isCoroutine = true;
            }

            var docPath       = Path.Combine(scriptReferenceRelativePath, detailsPath);
            var eventFunction = new UnityApiEventFunction(messageName, staticNode != null || isStaticFromExample,
                                                          isCoroutine, returnType, apiVersion, desc.Text, docPath);

            ParseParameters(eventFunction, signature, details, hintNamespace, argumentNames);

            return(eventFunction);
        }
Exemple #12
0
        public void Update(UnityApiEventFunction function, Version apiVersion)
        {
            if (UpdateSupportedVersion(apiVersion))
            {
                if (function.myDescription != myDescription && !string.IsNullOrEmpty(function.myDescription))
                {
                    myDescription = function.myDescription;
                }

                for (var i = 0; i < myParameters.Count; i++)
                {
                    myParameters[i].Update(function.myParameters[i]);
                }
            }
        }
        private UnityApiEventFunction ParseMessage(ApiNode message, Version apiVersion, string hintNamespace)
        {
            var link = message.SelectOne(@"td.lbl/a");
            var desc = message.SelectOne(@"td.desc");
            if (link == null || desc == null) return null;

            var detailsPath = link[@"href"];
            if (string.IsNullOrWhiteSpace(detailsPath)) return null;

            var path = Path.Combine(myScriptReferenceRelativePath, detailsPath);
            if (!File.Exists(path)) return null;

            var detailsDoc = ApiNode.Load(path);
            var details = detailsDoc?.SelectOne(@"//div.content/div.section");
            var signature = details?.SelectOne(@"div.mb20.clear/h1.heading.inherit");
            var staticNode = details?.SelectOne(@"div.subsection/p/code.varname[text()='static']");

            if (signature == null) return null;

            var messageName = link.Text;
            var returnType = ApiType.Void;
            string[] argumentNames = null;

            var example = PickExample(details);
            if (example != null)
            {
                var tuple = ParseDetailsFromExample(messageName, example, hintNamespace);
                returnType = tuple.Item1;
                argumentNames = tuple.Item2;
            }

            var docPath = Path.Combine(myScriptReferenceRelativePath, detailsPath);
            var eventFunction = new UnityApiEventFunction(messageName, staticNode != null, returnType, apiVersion, desc.Text, docPath, false);

            ParseParameters(eventFunction, signature, details, hintNamespace, argumentNames);

            return eventFunction;
        }
Exemple #14
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);
            }
        }
Exemple #15
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);
                }
            }
        }
        private static void ParseParameters(UnityApiEventFunction  eventFunction, ApiNode signature, ApiNode details, string owningMessageNamespace, string[] argumentNames)
        {
            // E.g. OnCollisionExit2D(Collision2D) - doesn't always include the argument name
            // Hopefully, we parsed the argument name from the example
            var argumentString = SigRegex.Replace(signature.Text, "$2$3");
            if (string.IsNullOrWhiteSpace(argumentString)) return;

            var argumentStrings = argumentString.Split(',')
                .Select(s => s.Trim())
                .ToArray();
            var total = argumentStrings.Length;
            var arguments = argumentStrings.Select((s, i) => new Argument(s, i, total, owningMessageNamespace)).ToArray();

            ResolveArguments(details, arguments, argumentNames);

            foreach (var argument in arguments)
                eventFunction.AddParameter(argument.Name, argument.Type, argument.Description);
        }
Exemple #17
0
        public void MergeEventFunction(UnityApiEventFunction newFunction, Version apiVersion)
        {
            UpdateSupportedVersion(apiVersion);

            var newFunctionSig = newFunction.ToString();
            foreach (var eventFunction in myEventFunctions)
            {
                // If the signature matches, we've already got it, just
                // make sure it's up to date (newer docs take precedence
                // for e.g. param names, description, etc)
                if (eventFunction.ToString() == newFunctionSig)
                {
                    eventFunction.Update(newFunction, apiVersion);
                    return;
                }
            }

            // Not a match. We either haven't found this function before,
            // or a parameter or return type is different
            myEventFunctions.Add(newFunction);
        }