Ejemplo n.º 1
0
 public IEnumerable <string> GetDynamicVariableNames(VariableKind kind, GraphReference reference)
 {
     return(units.OfType <IUnifiedVariableUnit>()
            .Where(v => v.kind == kind && Flow.CanPredict(v.name, reference))
            .Select(v => Flow.Predict <string>(v.name, reference))
            .Where(name => !StringUtility.IsNullOrWhiteSpace(name))
            .Distinct()
            .OrderBy(name => name));
 }
Ejemplo n.º 2
0
        private IEnumerable <Warning> ValueInputWarnings(ValueInput valueInput)
        {
            // We can disable null reference check if no self is available
            // and the port requires an owner, for example in macros.
            var trustFutureOwner = valueInput.nullMeansSelf && reference.self == null;

            var checkForNullReference = BoltFlow.Configuration.predictPotentialNullReferences && !valueInput.allowsNull && !trustFutureOwner;

            var checkForMissingComponent = BoltFlow.Configuration.predictPotentialMissingComponents && typeof(Component).IsAssignableFrom(valueInput.type);

            // Note that we cannot directly check the input's predicted value, because it
            // will return false for safeguard specifically because it might be missing requirements.
            // Therefore, we first check the connected value, then the default value.

            // If the port is connected to a predictable output, use the connected value to perform checks.
            if (valueInput.hasValidConnection)
            {
                var valueOutput = valueInput.validConnectedPorts.Single();

                if (Flow.CanPredict(valueOutput, reference))
                {
                    if (checkForNullReference)
                    {
                        if (Flow.Predict(valueOutput, reference) == null)
                        {
                            yield return(Warning.Severe($"{PortLabel(valueInput)} cannot be null."));
                        }
                    }

                    if (checkForMissingComponent)
                    {
                        var connectedPredictedValue = Flow.Predict(valueOutput, reference);

                        // This check is necessary, because the predicted value could be
                        // incompatible as connections with non-guaranteed conversions are allowed.
                        if (ConversionUtility.CanConvert(connectedPredictedValue, typeof(GameObject), true))
                        {
                            var gameObject = ConversionUtility.Convert <GameObject>(connectedPredictedValue);

                            if (gameObject != null)
                            {
                                var component = (Component)ConversionUtility.Convert(gameObject, valueInput.type);

                                if (component == null)
                                {
                                    yield return(Warning.Caution($"{PortLabel(valueInput)} is missing a {valueInput.type.DisplayName()} component."));
                                }
                            }
                        }
                    }
                }
            }
            // If the port isn't connected but has a default value, use the default value to perform checks.
            else if (valueInput.hasDefaultValue)
            {
                if (checkForNullReference)
                {
                    if (Flow.Predict(valueInput, reference) == null)
                    {
                        yield return(Warning.Severe($"{PortLabel(valueInput)} cannot be null."));
                    }
                }

                if (checkForMissingComponent)
                {
                    var unconnectedPredictedValue = Flow.Predict(valueInput, reference);

                    if (ConversionUtility.CanConvert(unconnectedPredictedValue, typeof(GameObject), true))
                    {
                        var gameObject = ConversionUtility.Convert <GameObject>(unconnectedPredictedValue);

                        if (gameObject != null)
                        {
                            var component = (Component)ConversionUtility.Convert(gameObject, valueInput.type);

                            if (component == null)
                            {
                                yield return(Warning.Caution($"{PortLabel(valueInput)} is missing a {valueInput.type.DisplayName()} component."));
                            }
                        }
                    }
                }
            }
            // The value isn't connected and has no default value,
            // therefore it is certain to be missing at runtime.
            else
            {
                yield return(Warning.Severe($"{PortLabel(valueInput)} is missing."));
            }
        }
Ejemplo n.º 3
0
        public override void DrawForeground()
        {
            base.DrawForeground();

            if (BoltFlow.Configuration.showConnectionValues)
            {
                var showLastValue      = EditorApplication.isPlaying && ConnectionDebugData.assignedLastValue;
                var showPredictedvalue = BoltFlow.Configuration.predictConnectionValues && !EditorApplication.isPlaying && Flow.CanPredict(connection.source, reference);

                if (showLastValue || showPredictedvalue)
                {
                    var previousIconSize = EditorGUIUtility.GetIconSize();
                    EditorGUIUtility.SetIconSize(new Vector2(IconSize.Small, IconSize.Small));

                    object value;

                    if (showLastValue)
                    {
                        value = ConnectionDebugData.lastValue;
                    }
                    else // if (showPredictedvalue)
                    {
                        value = Flow.Predict(connection.source, reference);
                    }

                    var label         = new GUIContent(value.ToShortString(), Icons.Type(value?.GetType())?[IconSize.Small]);
                    var labelSize     = Styles.prediction.CalcSize(label);
                    var labelPosition = new Rect(position.position - labelSize / 2, labelSize);

                    BeginDim();

                    GUI.Label(labelPosition, label, Styles.prediction);

                    EndDim();

                    EditorGUIUtility.SetIconSize(previousIconSize);
                }
            }
        }