Search Unity

Question Side Panel Observer

Discussion in 'Editor Workflows' started by broots, Apr 20, 2021.

  1. broots

    broots

    Joined:
    Dec 20, 2019
    Posts:
    54
    Heya, I've been working with graph foundation over the last week and I'm really excited about it, it's an awesome API! However, I've encountered a dilema which I've found no good ways of resolving:

    o6i3t5Uji2.gif

    If you pay close attention, the value at the top does not change to match the new selected node. It only changes after I drop my selection completely! My guess is that because these nodes are actually the same type graph foundation is assuming they should be drawn the same! You can see though, this result is not actually correct.

    I have attached two files to demonstrate how this result was achieved, one which is GraphifyNodeModel.cs where I have a RuntimeNode base class like

    Code (CSharp):
    1.     [Serializable]
    2.     [GraphifyNode("Schlongos/wowBongo!")]
    3.     public class BongoNode : RuntimeNode
    4.     {
    5.         [SerializeField]
    6.         public int mySchlongo;
    7.     }
    or

    Code (CSharp):
    1.     [Serializable]
    2.     [GraphifyNode("wow!")]
    3.     public class MongoNode : RuntimeNode
    4.     {
    5.         [In]
    6.         public ValuePort<int> mongoPort = new();
    7.     }
    Based on these different node types, the node is actually drawing different things. However, graph foundation seems to be making assumptions that if two types are equivalent they should be drawn equivalently.

    The second file is the search database, which is using an activator to set the node type, here's the important snippet:

    Code (CSharp):
    1.                     var node = new GraphNodeModelSearcherItem(
    2.                         new NodeSearcherItemData(typeof(GraphifyNodeModel)),
    3.                         data =>
    4.                         {
    5.                             return data.CreateNode(typeof(GraphifyNodeModel), name, obj =>
    6.                             {
    7.                                 if (obj is not GraphifyNodeModel gfm) return;
    8.                                 if (Activator.CreateInstance(type) is not RuntimeNode rtNode) return;
    9.                                 gfm.runtimeNode = rtNode;
    10.                             });
    11.                         },
    12.                         name
    13.                     );

    This issue is extremely hard to solve right now; Why?

    Problem 1:
    class SidePanelObserver : StateObserver


    The side panel observer is inaccessible as a class, this is actually not that big of a deal. We can work around this.

    Problem 2:
    SidePanelObserver m_SidePanelObserver;


    The side panel observer variable in GraphViewEditorWindow is inaccessible, this is also not a problem on it's own. However, it is a problem that it's being initialized in OnEnable and there's no way to change that behaviour right now. It's hard coded. I am also somewhat puzzled in general by this arrangement, because I've used reflection to get this variable, unregister the observer registered in on-enable, and register my own custom one. However, this actually changed literally nothing, which is a bit perplexing. (Even unregistering the observer completely had no apparant effect)

    Problem 3:

    public void ShowNodeInSidePanel(IGraphElementModel model, bool show)

    This is a function in GraphViewEditorWindow and it is unfortunately not able to be overriden. This is quite an edge case I've constructed here, but having access to this function means I could hack together a solution.

    So, I arrive at the bottom line:
    Can I force-update the observer and get it's state to correctly change when I select a new node. Can I tell the system these types are actuall distinct (Because of the limitations of serialize reference, I cant actually seperate these types using generic inflation) Or is their some other workaround/hack I can perform to simply update the window display so it's correct?

    Cheers very much,
    Z.
     

    Attached Files:

    Ruchir likes this.
  2. broots

    broots

    Joined:
    Dec 20, 2019
    Posts:
    54
    Update:

    I managed to hack together an interim solution, I tried a ton of things but this is the only one I could stumbled upon that actually worked. Here's the important bits:


    Code (CSharp):
    1. public class RecipeGraphWindow : GraphViewEditorWindow
    2.  
    3. private Unity.Properties.UI.PropertyElement sidePanelTarget;
    4.         protected override void OnEnable()
    5.         {
    6.             base.OnEnable();
    7.             EditorToolName = "Recipe Editor";
    8.          
    9.             sidePanelTarget =
    10.                 m_SidePanel.Q("sidePanelInspector") as Unity.Properties.UI.PropertyElement;
    11.         }
    12.  
    13.         private INodeModel prevTarget = null;
    14.         protected override void Update()
    15.         {
    16.             base.Update();
    17.             //TODO(Z):: NOTICE! Hack, this is likely to break in new versions!
    18.             //We are checking the side panel property target every update and if it's a different target then last frame,
    19.             //we just clear and reset the target! Without this, the graph does not correctly update the side panel inspector
    20.             if (sidePanelTarget.TryGetTarget<INodeModel>(out var mew) && mew != prevTarget)
    21.             {
    22.                 prevTarget = mew;
    23.                 sidePanelTarget.ClearTarget();
    24.                 sidePanelTarget.SetTarget(mew);
    25.             }
    26.         }
    You can see, simply poking the target state seems good enough and it resolves my issue!

    This is a hack, and certainly doesn't appear to be an intended solution to the problem. Would love to hear how this should be properely resolved if there's such a notion right now.

    Cheers,
    Z.