Nullable values are assigned default values in SharedVariable

red_halo

New member
I have a struct defined with nullable fields, and it's used as shared variable like so:
Code:
public struct NavAgentData
{
  public Vector3? targetPoint;
  public Vector3? focusPoint;
  public float?   speed;
  public float?   acceleration;
  public float?   angularSpeed;
  public float?   rotationDelta;
  public float?   rotationTime;
  public bool?    overrideRotation;
}

[System.Serializable]
public class SharedNavAgentData : SharedVariable<NavAgentData>
{
  public static implicit operator SharedNavAgentData(NavAgentData value)
  {
    return new SharedNavAgentData { Value = value };
  }
}

I noticed when a task that has a public SharedNavAgentData field invokes it's OnStart() method, the Value parameter shows all fields of the struct contain a value, which is not what I was expecting.

1699458394755.png


Do shared variables initialize nullables under the hood?
 
The deserializer doesn't specifically check for nullable fields, so I image that it is treating it as a regular bool. I'm not sure why it's initializing the value to true though unless the value has already been serialized. I'll take a closer look at this and let you know.
 
I just tried to reproduce this but wasn't able to. Here's what I did:

1. Created a new task with the SharedNavAgentData variable.
2. Added that task to the behavior tree and inspected the task to view the value.
3. Hit play. Within the task I outputted one of the values and it was null.

Null
UnityEngine.Debug:Log (object)
NewAction:OnStart () (at Assets/NewAction.cs:15)

Code:
public class NewAction : Action
{
    public SharedNavAgentData data;

    public override void OnStart()
    {
        Debug.Log(data.Value.focusPoint);
    }
}

public struct NavAgentData
{
    public Vector3? targetPoint;
    public Vector3? focusPoint;
    public float? speed;
    public float? acceleration;
    public float? angularSpeed;
    public float? rotationDelta;
    public float? rotationTime;
    public bool? overrideRotation;
}

[System.Serializable]
public class SharedNavAgentData : SharedVariable<NavAgentData>
{
    public static implicit operator SharedNavAgentData(NavAgentData value)
    {
        return new SharedNavAgentData { Value = value };
    }
}
 
Hi Justin, thank you for taking a look. In this reply I'll reference the attached images numerically from left to right for clarity.

I tried your test case as well and noticed the same results on a first play-through. However, there is a way to repro the case I mentioned. It doesn't seem like a special case, since it can easily be triggered through an expected use-case. I noticed if I expand the data shared variable in the task inspector (image 1) and press play, the value remains null. Once I expand focusPoint (image 2) and press play I start getting logs with a value set.

Code:
(0.00, 0.00, 0.00)
UnityEngine.Debug:Log (object)
NewAction:OnStart () (at Assets/Scripts/Prototypes/BehviorTrees/Tasks/Debug/NewTask.cs:10)

I suspect it has something to do with serialization, so I tried "clearing" the serialized value while Unity was not playing by clicking circle button (image 3) and then once more to return to it's previous state (image 2). After pressing play I then started seeing null again.

Code:
Null
UnityEngine.Debug:Log (object)
NewAction:OnStart () (at Assets/Scripts/Prototypes/BehviorTrees/Tasks/Debug/NewTask.cs:10)

If I happen to contract the focusPoint (image 1) from that point, the value became set to (0, 0, 0) again upon pressing play.

1699531311645.png 1699531396083.png 1699531399740.png

It seems an interaction with the field through the inspector sets a serialized value that sticks.

By the way, I'm using:
Unity Personal 2021.3.5f1
Behavior Designer 1.7.7
 
Thanks for the repro steps. Based on that it does sound like things are working correctly. When the inspector is expanded it serializes the value of the variable. What else would you expect?
 
I was experimenting using nullables in shared variables expecting them to be null unless explicitly set on a specific tick (like when receiving an event with certain nullable values set). The unexpected part is now confirming that once serialized, the value doesn't get cleared.

I'll just have to work around it, now that I know :)

Appreciate your prompt support.
 
Top