Search Unity

Resolved Change ValueOutput's label without changing its key

Discussion in 'Visual Scripting' started by marcuslelus, Nov 8, 2021.

  1. marcuslelus

    marcuslelus

    Joined:
    Jun 18, 2018
    Posts:
    67
    Is there a way to change how the ValueOutput's labels are displayed without changing their keys? This implies that I'm making my own CustomUnit of course.

    I'm generating ValueOutputs from an inspectable list (like SwitchUnit), but I want to change how they are displayed. So let's say I have a ValueOutput with a key named "value", I want to show the key as "this.value" without actually changing the underlying key. This is purely visual.

    Thanks in advance!
     
    Last edited: Nov 8, 2021
    zammorrak, Trypants and Ilovepatatos like this.
  2. Starpaq2

    Starpaq2

    Joined:
    Mar 14, 2013
    Posts:
    77
    Code (CSharp):
    1. [PortLabel("monster")]
    2.         [DoNotSerialize]
    3.         public ValueInput spriteRect;
    Arrgh, there be monsters at ye ports!
    upload_2021-11-10_1-14-10.png
     
  3. marcuslelus

    marcuslelus

    Joined:
    Jun 18, 2018
    Posts:
    67
    Not quite what I was looking for. Attributes are defined at compile time, but I'm generating ValueOutput at runtime/Definition time (I don't even have a variable to hold the ValueOutput)

    Here's a sample code
    Code (CSharp):
    1.     public class TempUnit : Unit
    2.     {
    3.         [Inspectable, Serialize]
    4.         public List<GameObject> options { get; set; } = new List<GameObject>();
    5.  
    6.         public override bool canDefine => options != null;
    7.  
    8.         protected override void Definition()
    9.         {
    10.             foreach (var option in options)
    11.             {
    12.                 var key = "%" + option.GetInstanceID();
    13.  
    14.                 if (!controlOutputs.Contains(key))
    15.                 {
    16.                     ValueOutput(key,flow => option);
    17.                 }
    18.             }
    19.         }
    20.     }
    This is heavily inspired from the SwitchUnit<T>. I want the ValueOutput's key to be unique (ID), tho the visual should display the GameObject's name.

    The code above works tho it's not really useful since InstanceIDs are resetted when we reopen Unity, and we can't really get a GameObject by ID without Reflection, but let's pretend we can and it's easy. In my real code, I use GUIDReference and the keys are GUIDs.

    In this context, we can't use Attributes
     
  4. Starpaq2

    Starpaq2

    Joined:
    Mar 14, 2013
    Posts:
    77
    That may be quite complex to develop a solution to. The provided classes that create the value output does not have an additional property for identification. Perhaps it may be extended on top of that.

    As far as the references and generation of value inputs during runtime... you may want to consider a Scriptable Object approach. A scriptable object [its like hard coded serialized file that remains persistent] cannot reference in scene objects, but the scene runtime can reference the Scriptable Object Values. Also the scriptable object does not save new data via runtime so values or generated id's would have to be pre planned somehow.

    Of course if you are aware of juggling scriptable object data between scenes then you may have already attempted this.

    There are probably other ways, but perhaps another developer may happen across your inquiry.
     
  5. Trindenberg

    Trindenberg

    Joined:
    Dec 3, 2017
    Posts:
    398
    Somehow you need to get to the ValueInputDefinition.label.

    This is held in the Flowgraph.(UnitPortDefinitionCollection)valueInputDefinitions

    (ValueInput)myValueInput.unit.graph.valueInputDefinitions[(int) indexOfMyValueInput].label ....... somehow you need to find the index.
     
    Starpaq2 likes this.
  6. marcuslelus

    marcuslelus

    Joined:
    Jun 18, 2018
    Posts:
    67
    Thanks everyone for your time. I did managed to do it, Trindenberg's solution was correct, tho for some reason, Bolt gets mad when I change the label during definition (also After and Before and Prewarm). The solution was to use a UnitWidget<>. It's almost "perfect" because it kinda struggle with the dimensions (they are set to fit the keys, tho it ignores the label's size sometime, so I'm close to the perfect solution, but not quite there). But other than that, it's flawless. My use case is a bit complex so I'll use the first one I gave, which was to prepend "this." to the label.

    Quick note: You need to create another class that inherits from UnitWidget<YourUnitTypeHere> and add the attribute [Widget(typeof(YourUnitTypeHere))]

    All of the code below should work, if you want to copy-paste it and play with it.



    Code (CSharp):
    1.  
    2. using Unity.VisualScripting;
    3.  
    4. [Widget(typeof(CustomStringUnit))]
    5. public class CustomStringUnitWidget : UnitWidget<CustomStringUnit>
    6. {
    7.     public CustomStringUnitWidget(FlowCanvas canvas, CustomStringUnit unit) : base(canvas, unit)
    8.     {
    9.         unit.onPortsChanged += ChangeNames;
    10.     }
    11.  
    12.     private void ChangeNames()
    13.     {
    14.         foreach (var port in outputs)
    15.         {
    16.             port.port.Description<UnitPortDescription>().label = $"this.{port.port.key}";
    17.         }
    18.     }
    19. }
    20.  
    And here's the CustomStringUnit, copy-paste all of it to test it, with extra stuff like TypeIcon

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.VisualScripting;
    3.  
    4. [UnitCategory(@"Custom\strings")]
    5. [UnitTitle("Custom String")]
    6. [TypeIcon(typeof(string))]
    7. public class CustomStringUnit : Unit
    8. {
    9.     [Inspectable, Serialize]
    10.     public List<string> options { get; set; } = new List<string>();
    11.  
    12.     public override bool canDefine => options != null;
    13.    
    14.    
    15.     protected override void Definition()
    16.     {
    17.         foreach (var option in options)
    18.         {
    19.             if (string.IsNullOrEmpty(option)) continue;
    20.  
    21.             if (!valueOutputs.Contains(option))
    22.             {
    23.                 ValueOutput(option, flow => option);
    24.             }
    25.         }
    26.     }
    27. }
    28.  
    Still need to figure out how to resize the Unit to fit the labels, not the keys. It's a bit misleading tho because it does resize with the labels, but it seems to take the max size between the keys and labels, and in my case, the keys are quite large, but the label are often small so it looks weird.
     
    Trindenberg and Starpaq2 like this.
  7. Trindenberg

    Trindenberg

    Joined:
    Dec 3, 2017
    Posts:
    398
    @marcuslelus Glad you managed to figure it out! There is very little documentation and examples out there; it's a case of discovering things. Will bear in mind your example here. You should join Unity's Visual Scripting Discord channel. I'm currently trying to figure out custom property drawers so I can make a selectable input, but kind of stuck on that. Enum's have a property drawer but no idea how to do say a string[] draw :)
     
    marcuslelus likes this.
  8. marcuslelus

    marcuslelus

    Joined:
    Jun 18, 2018
    Posts:
    67
    I would, tho I can't find any valid link to the Unity's Visual Scripting Discord :/ If you have a link somewhere, feel free to drop it here and I'll join it!
     
  9. ericb_unity

    ericb_unity

    Unity Technologies

    Joined:
    Nov 24, 2017
    Posts:
    167
    This link will bring you to the Visual Scripting Discord.
    https://discord.gg/u8vwkDrazP
     
    Trindenberg likes this.