public static bool CanHaveReference([CanBeNull] ITreeNode element)
        {
            var methodNameValue = element as IPlainScalarNode;
            var methodNameEntry = BlockMappingEntryNavigator.GetByValue(methodNameValue);

            return(methodNameValue != null && (methodNameEntry?.Key.MatchesPlainScalarText("m_MethodName") ?? false));
        }
        public ReferenceCollection GetReferences(ITreeNode element, ReferenceCollection oldReferences)
        {
            if (ResolveUtil.CheckThatAllReferencesBelongToElement <MonoScriptReference>(oldReferences, element))
            {
                return(oldReferences);
            }

            if (!(element is IPlainScalarNode guidValue))
            {
                return(ReferenceCollection.Empty);
            }

            // m_Script: {fileID: 11500000, guid: xxx, type: x}
            var guidEntry         = FlowMapEntryNavigator.GetByValue(guidValue);
            var flowIDMap         = FlowMappingNodeNavigator.GetByEntrie(guidEntry);
            var blockMappingEntry = BlockMappingEntryNavigator.GetByValue(flowIDMap);

            if (guidEntry?.Key.MatchesPlainScalarText("guid") == true &&
                blockMappingEntry?.Key.MatchesPlainScalarText("m_Script") == true)
            {
                var fileID = flowIDMap.AsFileID();
                if (fileID != null && !fileID.IsNullReference && fileID.IsMonoScript)
                {
                    var metaGuidCache = element.GetSolution().GetComponent <MetaFileGuidCache>();
                    var reference     = new MonoScriptReference(guidValue, fileID, metaGuidCache);
                    return(new ReferenceCollection(reference));
                }
            }

            return(ReferenceCollection.Empty);
        }
Exemple #3
0
        public ReferenceCollection GetReferences(ITreeNode element, ReferenceCollection oldReferences)
        {
            if (ResolveUtil.CheckThatAllReferencesBelongToElement <UnityEventTargetReference>(oldReferences, element))
            {
                return(oldReferences);
            }

            if (!(element is IPlainScalarNode methodNameValue))
            {
                return(ReferenceCollection.Empty);
            }

            // E.g. element is the m_MethodName scalar value "ButtonClickedHandler" in this structure:
            // m_OnClick:
            //   m_PersistentCalls:
            //     m_Calls:
            //     - m_Target: {fileID: 1870695363}
            //       m_MethodName: ButtonClickedHandler
            //       m_Mode: 3
            //       m_Arguments:
            //         m_ObjectArgument: {fileID: 0}
            //         m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
            //         m_IntArgument: 1
            //         m_FloatArgument: 0
            //         m_StringArgument:
            //         m_BoolArgument: 0
            //       m_CallState: 2
            //   m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
            //     Culture=neutral, PublicKeyToken=null
            var methodNameMapEntry = BlockMappingEntryNavigator.GetByValue(methodNameValue);
            var callMapNode        = BlockMappingNodeNavigator.GetByEntrie(methodNameMapEntry);
            var callsSequenceEntry = SequenceEntryNavigator.GetByValue(callMapNode);
            var callsSequenceNode  = BlockSequenceNodeNavigator.GetByEntrie(callsSequenceEntry);
            var callsMapEntry      = BlockMappingEntryNavigator.GetByValue(callsSequenceNode);

            // callsMapEntry should be "m_Calls" (and contain a value that is a sequence node). If it's not null,
            // everything else is also not null
            if (callsMapEntry == null)
            {
                return(ReferenceCollection.Empty);
            }

            if (methodNameMapEntry.Key.MatchesPlainScalarText("m_MethodName") &&
                callsMapEntry.Key.MatchesPlainScalarText("m_Calls"))
            {
                // If we have a guid, that means this event handler exists inside another asset. That asset might be
                // a .dll, in which case we don't want to add a reference (the primary purpose of these references
                // is to enable Find Usages of methods, not navigation *from* YAML). Or it might be e.g. a prefab.
                // This would be a reference to a prefab that contains a MonoScript asset that has the method
                // TODO: Create an index of other assets that we could target
                var fileID = callMapNode.FindMapEntryBySimpleKey("m_Target")?.Value.AsFileID();
                if (fileID != null && !fileID.IsNullReference && fileID.guid == null)
                {
                    var reference = new UnityEventTargetReference(methodNameValue, fileID);
                    return(new ReferenceCollection(reference));
                }
            }

            return(ReferenceCollection.Empty);
        }
        // Names is likely to contain the name of the class. All we have in the file is the guid
        public bool HasReference(ITreeNode element, IReferenceNameContainer names)
        {
            var guidValue         = element as IPlainScalarNode;
            var guidEntry         = FlowMapEntryNavigator.GetByValue(guidValue);
            var flowIDMap         = FlowMappingNodeNavigator.GetByEntrie(guidEntry);
            var blockMappingEntry = BlockMappingEntryNavigator.GetByValue(flowIDMap);

            return(guidEntry?.Key.MatchesPlainScalarText("guid") == true &&
                   blockMappingEntry?.Key.MatchesPlainScalarText("m_Script") == true);
        }
        public ReferenceCollection GetReferences(ITreeNode element, ReferenceCollection oldReferences)
        {
            if (ResolveUtil.CheckThatAllReferencesBelongToElement <UnityEventTargetReference>(oldReferences, element))
            {
                return(oldReferences);
            }

            if (!(element is IPlainScalarNode methodNameValue))
            {
                return(ReferenceCollection.Empty);
            }

            // E.g. element is the m_MethodName scalar value "ButtonClickedHandler" in this structure:
            // m_OnClick:
            //   m_PersistentCalls:
            //     m_Calls:
            //     - m_Target: {fileID: 1870695363}
            //       m_MethodName: ButtonClickedHandler
            //       m_Mode: 3
            //       m_Arguments:
            //         m_ObjectArgument: {fileID: 0}
            //         m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
            //         m_IntArgument: 1
            //         m_FloatArgument: 0
            //         m_StringArgument:
            //         m_BoolArgument: 0
            //       m_CallState: 2
            //   m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
            //     Culture=neutral, PublicKeyToken=null
            var methodNameMapEntry = BlockMappingEntryNavigator.GetByContent(ContentNodeNavigator.GetByValue(methodNameValue));
            var callMapNode        = BlockMappingNodeNavigator.GetByEntrie(methodNameMapEntry);
            var callsSequenceEntry = SequenceEntryNavigator.GetByValue(callMapNode);
            var callsSequenceNode  = BlockSequenceNodeNavigator.GetByEntrie(callsSequenceEntry);
            var callsMapEntry      = BlockMappingEntryNavigator.GetByContent(ContentNodeNavigator.GetByValue(callsSequenceNode));

            // callsMapEntry should be "m_Calls" (and contain a value that is a sequence node). If it's not null,
            // everything else is also not null
            if (callsMapEntry == null)
            {
                return(ReferenceCollection.Empty);
            }

            if (methodNameMapEntry.Key.MatchesPlainScalarText("m_MethodName") &&
                callsMapEntry.Key.MatchesPlainScalarText("m_Calls"))
            {
                var fileID = callMapNode.FindMapEntryBySimpleKey("m_Target")?.Content.Value.AsFileID();
                if (fileID != null && !fileID.IsNullReference)
                {
                    var text = callMapNode.Entries.FirstOrDefault(t => t.Key.MatchesPlainScalarText("m_Mode"))?.Content.Value
                               .GetPlainScalarText();

                    var argMode = EventHandlerArgumentMode.Unknown;
                    if (int.TryParse(text, out var mode))
                    {
                        if (1 <= mode && mode <= 6)
                        {
                            argMode = (EventHandlerArgumentMode)mode;
                        }
                    }

                    var arguments      = callMapNode.Entries.FirstOrDefault(t => t.Key.MatchesPlainScalarText("m_Arguments"))?.Content.Value as IBlockMappingNode;
                    var typeNameRecord = arguments?.Entries.FirstOrDefault(t => t.Key.MatchesPlainScalarText("m_ObjectArgumentAssemblyTypeName"))?.Content.Value;
                    var type           = typeNameRecord?.GetPlainScalarText()?.Split(',').FirstOrDefault();
                    if (type.IsNullOrEmpty() && mode == 1)
                    {
                        type = null;
                    }

                    var reference = new UnityEventTargetReference(methodNameValue, argMode, type, fileID);
                    return(new ReferenceCollection(reference));
                }
            }

            return(ReferenceCollection.Empty);
        }
Exemple #6
0
        public ReferenceCollection GetReferences(ITreeNode element, ReferenceCollection oldReferences)
        {
            if (ResolveUtil.CheckThatAllReferencesBelongToElement <UnityEventTargetReference>(oldReferences, element))
            {
                return(oldReferences);
            }

            if (!(element is IPlainScalarNode methodNameValue))
            {
                return(ReferenceCollection.Empty);
            }

            // E.g. element is the m_MethodName scalar value "ButtonClickedHandler" in this structure:
            // m_OnClick:
            //   m_PersistentCalls:
            //     m_Calls:
            //     - m_Target: {fileID: 1870695363}
            //       m_MethodName: ButtonClickedHandler
            //       m_Mode: 3
            //       m_Arguments:
            //         m_ObjectArgument: {fileID: 0}
            //         m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
            //         m_IntArgument: 1
            //         m_FloatArgument: 0
            //         m_StringArgument:
            //         m_BoolArgument: 0
            //       m_CallState: 2
            //   m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
            //     Culture=neutral, PublicKeyToken=null
            // Note that m_TypeName was removed in Unity 2018.4
            var methodNameMapEntry = BlockMappingEntryNavigator.GetByContent(ContentNodeNavigator.GetByValue(methodNameValue));
            var callMapNode        = BlockMappingNodeNavigator.GetByEntrie(methodNameMapEntry);
            var callsMapEntry      = BlockMappingEntryNavigator.GetByContent(
                ContentNodeNavigator.GetByValue(
                    BlockSequenceNodeNavigator.GetByEntrie(SequenceEntryNavigator.GetByValue(callMapNode))));

            // callsMapEntry should be "m_Calls" (and contain a value that is a sequence node). If it's not null,
            // everything else is also not null
            if (callsMapEntry == null)
            {
                return(ReferenceCollection.Empty);
            }

            // Get the event type name, if it's serialised. This field was removed in Unity 2018.4, but remember that
            // the serialised value will remain in the scene until it is re-saved.
            // The only way to get the type name in Unity 2018.4+ is to get the type of the event (e.g. m_OnClick). This
            // requires getting the type referenced in the m_Script serialised field, which might be in a referenced
            // assembly, and could be arbitrarily deep in a custom class.
            // The Event System has this problem, as the EventTrigger MonoBehaviour serialises a list of
            // EventTrigger.Event instances, and it's EventTrigger.Event.callback that gives us the UnityEvent derived
            // event type
            // The only way to do this would be to resolve all types and fields between m_PersistentCalls and the "root"
            // of the object, taking [FormerlySerialisedAs] into account
            var persistentCallsMapNode = BlockMappingNodeNavigator.GetByEntrie(
                BlockMappingEntryNavigator.GetByContent(
                    ContentNodeNavigator.GetByValue(BlockMappingNodeNavigator.GetByEntrie(callsMapEntry))));
            var eventTypeName = persistentCallsMapNode?.FindMapEntryBySimpleKey("m_TypeName")?.Content?.Value
                                ?.GetPlainScalarText();

            if (methodNameMapEntry.Key.MatchesPlainScalarText("m_MethodName") &&
                callsMapEntry.Key.MatchesPlainScalarText("m_Calls"))
            {
                var fileID = callMapNode.FindMapEntryBySimpleKey("m_Target")?.Content.Value.AsFileID();
                if (fileID != null && !fileID.IsNullReference)
                {
                    var modeText = callMapNode.FindMapEntryBySimpleKey("m_Mode")?.Content.Value.GetPlainScalarText();

                    var argMode = EventHandlerArgumentMode.EventDefined;
                    if (int.TryParse(modeText, out var mode))
                    {
                        if (1 <= mode && mode <= 6)
                        {
                            argMode = (EventHandlerArgumentMode)mode;
                        }
                    }

                    var arguments        = callMapNode.FindMapEntryBySimpleKey("m_Arguments")?.Content.Value as IBlockMappingNode;
                    var argumentTypeName = arguments.FindMapEntryBySimpleKey("m_ObjectArgumentAssemblyTypeName")?.Content
                                           .Value.GetPlainScalarText();
                    var type = argumentTypeName?.Split(',').FirstOrDefault();
                    if (argMode == EventHandlerArgumentMode.EventDefined)
                    {
                        type = eventTypeName?.Split(',').FirstOrDefault();
                    }
                    else if (argMode == EventHandlerArgumentMode.Void)
                    {
                        type = null;
                    }

                    var reference = new UnityEventTargetReference(methodNameValue, argMode, type, fileID);
                    return(new ReferenceCollection(reference));
                }
            }

            return(ReferenceCollection.Empty);
        }