Making "Compare Field Value" Conditional Compatible with ScriptableObject

kremi

New member
Hello,

I am currently working on a custom conditional for Behavior Designer, basically same as "CompareFieldValue" but with a scriptable objects instead of a game object.

Writing the custom task is easy (see below) but the problem is that it has raw string fields for "fieldName" and "compareValue" in the editor.

Could you provide guidance or consider implementing a "CompareScriptableObjectFieldValue" task in Behavior Designer that would support this functionality?

Thank you for your time and the amazing work on Behavior Designer!

CompareScriptableObjectFieldValue.cs
Code:
using UnityEngine;
using System;
using System.Reflection;
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
using Boids.Behavior;

namespace MyNamespace
{
    [TaskDescription("Compares the field value to the value specified. Returns success if the values are the same.")]
    [TaskCategory("Reflection")]
    [TaskIcon("{SkinColor}ReflectionIcon.png")]
    public class CompareScriptableObjectFieldValue : Conditional
    {
        [UnityEngine.Tooltip("The GameObject to compare the field on")]
        public SharedScriptableObject TargetScriptableObject;

        [UnityEngine.Tooltip("The name of the field")]
        public SharedFieldNameString FieldName;

        [UnityEngine.Tooltip("The value to compare to")]
        public SharedVariable compareValue;

        public override TaskStatus OnUpdate()
        {
            if (compareValue == null)
            {
                Debug.LogWarning("Unable to compare field - compare value is null");
                return TaskStatus.Failure;
            }

            var component = TargetScriptableObject.Value;
            if (component == null)
            {
                Debug.LogWarning("Unable to compare the field with scriptable object");
                return TaskStatus.Failure;
            }

            // If you are receiving a compiler error on the Windows Store platform see this topic:
            // https://www.opsive.com/support/documentation/behavior-designer/installation/
            var field = component.GetType().GetField(FieldName.Value);
            var fieldValue = field.GetValue(component);

            if (fieldValue == null && compareValue.GetValue() == null)
            {
                return TaskStatus.Success;
            }

            return fieldValue.Equals(compareValue.GetValue()) ? TaskStatus.Success : TaskStatus.Failure;
        }

        public override void OnReset()
        {
            TargetScriptableObject = null;
            FieldName = null;
            compareValue = null;
        }
    }
}

}

SharedScriptableObject.cs
Code:
using BehaviorDesigner.Runtime;
using UnityEngine;

namespace MyNamespace
{
    [System.Serializable]
    public class SharedScriptableObject : SharedVariable<ScriptableObject>
    {
        public static implicit operator SharedScriptableObject(ScriptableObject value)
        {
            return new SharedScriptableObject { mValue = value };
        }
    }
}
 
Thanks. I made a working dropdown for the field (code below). However it seems much more complicated for `SharedVariable`. Could you give me pointers?

FieldString.cs
Code:
namespace MyNamespace
{
    [System.Serializable]
    public class FieldString
    {
        public string Field;
    }
}

FieldStringDrawer.cs
Code:
using System.Linq;
using BehaviorDesigner.Editor;
using UnityEditor;
using UnityEngine;

namespace MyNamespace
{
    [CustomObjectDrawer(typeof(FieldString))]
    public class FieldStringDrawer : ObjectDrawer
    {
        public override void OnGUI(GUIContent label)
        {
            Debug.Log("Shared string field drawer");
            var sharedString = value as FieldString;

            // Access the specific task instance
            var compareScriptableObjectFieldValue = task as CompareScriptableObjectFieldValue;

            // Ensure that we have a valid CompareScriptableObjectFieldValue instance and a selected TargetScriptableObject
            if (compareScriptableObjectFieldValue != null &&
                compareScriptableObjectFieldValue.TargetScriptableObject.Value != null)
            {
                var type = compareScriptableObjectFieldValue.TargetScriptableObject.Value.GetType();
                var fields = type.GetFields();
                var fieldNames = fields.Select(field => field.Name).ToArray();

                int currentIndex = fieldNames.ToList().IndexOf(sharedString.Field);
                currentIndex = Mathf.Max(currentIndex, 0); // Fallback to the first item if not found

                // Display a popup with field names
                int selectedIndex = EditorGUILayout.Popup(label, currentIndex, fieldNames);

                // Update the fieldName if a new field is selected
                if (currentIndex != selectedIndex)
                {
                    sharedString.Field = fieldNames[selectedIndex];
                    GUI.changed = true; // Ensure that the change is registered
                }
            }
        }
    }
}
 
Glad you are making progress. SharedVariables have a separate editor that you can call: FieldInspector.DrawSharedVariable.
 
Back
Top