Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing Port Order With OverrideFieldOrder Loses Port Edge Type #199

Open
dannymate opened this issue Jan 30, 2022 · 0 comments
Open

Changing Port Order With OverrideFieldOrder Loses Port Edge Type #199

dannymate opened this issue Jan 30, 2022 · 0 comments

Comments

@dannymate
Copy link

dannymate commented Jan 30, 2022

So I have a couple layers of inheritance first. It looks like this: BaseNode > DynamicNode > SequenceNode

In Dynamic node I'm creating ports on the fly with CustomPortBehavior and CustomPortInput. Everything works how you would expect except I'd prefer if the ports were reordered so I did by implementing the OverrideFieldOrder method. Essentially all I'm doing is reversing the original order. i.e. return base.OverrideFieldOrder(fields).Reverse();.

image
Also for some reason the property drawer for a float in DynamicNode is in the wrong place by default.

The order is reversed correctly but when creating a connection node in the menu it doesn't pickup up the correct type.
Before (Dragging&Dropping an edge):
image
After (Dragging&Dropping an edge):
image

The float itself does work before and after so I think it could be some kind of generic inheritance thing.

Code For DynamicNode:

DynamicNode Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GraphProcessor;
using System.Linq;
using System.Reflection;
using System;

[System.Serializable]
public abstract class DynamicNode<T> : BaseNode
{
    [Input("Action Data")]
    public Dictionary<string, object> actionData = new Dictionary<string, object>();
    [Input("Float Val"), SerializeField] public float floatVal;

    [SerializeField, ExpandableSO, ValueChangedCallback(nameof(OnDataChanged))] public T data;

    protected override void Process()
    {
        UpdateActionWithCustomPortData();
    }

    protected virtual void UpdateActionWithCustomPortData()
    {
        // We clone due to reference issues
        Dictionary<string, object> actionDataClone = new Dictionary<string, object>(actionData);

        foreach (var field in GetInputFieldsOfType())
        {
            if (!actionDataClone.ContainsKey(field.fieldInfo.Name))
            {
                field.fieldInfo.SetValue(data, default);
            }
            else
            {
                field.fieldInfo.SetValue(data, actionDataClone[field.fieldInfo.Name]);
            }
        }

        actionData.Clear();
    }

    protected virtual void OnDataChanged(UnityEditor.SerializedProperty serializedProperty)
    {
        UpdatePortsForFieldLocal(nameof(actionData));
    }

    #region Reflection Generation Of Ports

    private List<FieldPortInfo> GetInputFieldsOfType()
    {
        List<FieldPortInfo> foundInputFields = new List<FieldPortInfo>();

        Type dataType = actionData != null ? data.GetType() : typeof(T);
        foreach (var field in dataType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
        {
            foreach (var attribute in field.GetCustomAttributes(typeof(InputAttribute), true))
            {
                if (attribute.GetType() != typeof(InputAttribute)) continue;

                foundInputFields.Add(new FieldPortInfo(field, attribute as InputAttribute));
                break;
            }
        }

        return foundInputFields;
    }

    [CustomPortInput(nameof(actionData), typeof(object))]
    protected void PullInputs(List<SerializableEdge> connectedEdges)
    {
        if (actionData == null) actionData = new Dictionary<string, object>();
        foreach (SerializableEdge t in connectedEdges)
        {
            actionData.Add(t.inputPortIdentifier, t.passThroughBuffer);
        }
    }

    [CustomPortBehavior(nameof(actionData))]
    protected IEnumerable<PortData> ActionDataBehaviour(List<SerializableEdge> edges)
    {
        foreach (var field in GetInputFieldsOfType())
        {
            yield return new PortData
            {
                displayName = field.inputAttribute.name,
                displayType = field.fieldInfo.FieldType,
                identifier = field.fieldInfo.Name,
                acceptMultipleEdges = false,
            };
        }
    }

    public override IEnumerable<FieldInfo> OverrideFieldOrder(IEnumerable<FieldInfo> fields)
    {
        return base.OverrideFieldOrder(fields).Reverse();

        // static long GetFieldInheritanceLevel(FieldInfo f)
        // {
        //     int level = 0;
        //     var t = f.DeclaringType;
        //     while (t != null)
        //     {
        //         t = t.BaseType;
        //         level++;
        //     }

        //     return level;
        // }

        // // Order by MetadataToken and inheritance level to sync the order with the port order (make sure FieldDrawers are next to the correct port)
        // return fields.OrderByDescending(f => (GetFieldInheritanceLevel(f) << 32) | (long)f.MetadataToken);

    }

    #endregion
}

public struct FieldPortInfo
{
    public FieldInfo fieldInfo;
    public InputAttribute inputAttribute;

    public FieldPortInfo(FieldInfo fieldInfo, InputAttribute inputAttribute)
    {
        this.fieldInfo = fieldInfo;
        this.inputAttribute = inputAttribute;
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant