Blittable bool for Unity ECS

Blittable boolean for Unity ECS

[EDIT]: As of a recent update, it seems that a custom blittable bool is not required anymore, as the bool type can now be used with Unity’s ECS

Did you ever encountered the “ArgumentException: MyComponent is an IComponentData, and thus must be blittable (No managed object is allowed on the struct)” while trying to use a bool as an IComponentData field? If the answer is YES!, then this article is for you.

Indeed, if you have been using the new Unity’s Entity Component System (ECS), you might have noticed that there is a lack of a blittable bool for use in components. Indeed, there previously was a blittable bool1, which was replaced by a recent update of the entity package, with no replacement, while the billatable types bool2, bool3, … still exist.

While I am sure that Unity’s team will quickly fix this and provide a bool type compatible with its new ECS, here is a simple one that you can start using now. The solution is actually quite simple and consists of using a byte encapsulated by a struct as a boolean holder. However, making it compatible with Unity’s inspector ended more complicated than expected. I was new to C# when I started using Unity and I must admit that I didn’t see that one coming…

The blittable boolean struct

So here it is. As simple as that, just a byte value encapsulated inside a struct, and some helper methods to allow easy conversion from and to the standard bool type. It needs to be a struct in order to be blittable since classes are not blittable in C# (see https://docs.microsoft.com/fr-fr/dotnet/framework/interop/blittable-and-non-blittable-types for a list of blittable and non-blittable types).

[System.Serializable]
public struct boolean
{
    public byte boolValue;

    public boolean(bool value)
    {
        boolValue = (byte)(value ? 1 : 0);
    }

    public static implicit operator bool(boolean value)
    {
        return value.boolValue == 1;
    }

    public static implicit operator boolean(bool value)
    {
        return new boolean(value);
    }

    public override string ToString()
    {
        if (boolValue == 1)
            return "true";

        return "false";
    }
}

You might wonder why our internal byte is made public? Ideally we would want to keep it private and hidden. Unfortunately, I had to make it public in order to help with editing our boolean from Unity’s inspector. In C++ I would have probably used something like a friend class, and their might be another solution in C# (probably using reflection dark magic? Hugh…) but this will do for now.

Now it would be nice if we were able to tweak that boolean value directly from unity’s inspector, wouldn’t it ?

In Unity’s ECS, components are structs deriving from IComponentData. Now when using our freshly created blittable bool type, you might write something similar to:

public struct MyComponent : IComponentData
{
    public boolean MyBool;
}

If you are using hybrid ECS, your component is probably wrapped to a MonoBehaviour using the handy ComponentDataWrapper class. Something like this, put inside a MyComponentWrapper.cs script file:

public class MyComponentWrapper : ComponentDataWrapper<MyComponent>{ }

Adding MyComponentWrapper to a game object actually displays our internal byte field instead of a proper checkbox to modify our boolean value:

Blittable bool inspector not working

We don’t want that, do we?

The boolean property drawer

[EDIT] By the time I wrote this article, I found a much much simpler solution for the boolean property drawer. If you don’t care about the details, just jump the following sections until the last one!

For that, we will need a custom property drawer that displays a checkbox for user interraction. THis will be achieved by adding the following code to a booleanDrawer.cs script file, placed into an “Editor” folder:

using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(boolean))]
public class booleanDrawer : PropertyDrawer
{
    public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label)
    {
        EditorGUI.BeginProperty(pos, label, prop);

        boolean myBool = (boolean)prop.GetTargetObject();

        bool before = myBool;
        bool after = EditorGUI.Toggle(pos, label, before);
        if (before != after)
        {
            prop.SetTargetObjectRecursive(new boolean(after));
            EditorUtility.SetDirty(prop.serializedObject.targetObject);
        }

        EditorGUI.EndProperty();
    }
}

At that point, you might wonder why there is this weird call to this unknown method called “SetTargetObjectRecursive” instead of directly settings the property’s value… That’s because structs are passed by value (not reference) !

Structs are passed by value

ComponentDataWrapper provide a “Value” property to get and set your component data. However, when you get your component, you actually get a copy of that component. Any change made to the component returned by “Value” will not be passed to the original component.

Thus, the following code will not have the expected behaviour:

MyComponentWrapper wrapper = gameobject.GetComponent<MyComponentWrapper>(); //get our wrapper from some game object
wrapper.Value.MyBool = true; //the boolean value is actually left unchanged

In this specific case, a workarround would be to first get a copy of the component, then modify the copy, and finally assign the modified copy:

MyComponentWrapper wrapper = gameobject.GetComponent<MyComponentWrapper>(); //get our wrapper from some game object 
MyComponent temp_copy = wrapper.Value; //get a temporary copy
temp_copy.MyBool = true; //modify the copy
wrapper.Value = temp_copy; //assign the modified copy

In order to be able to modify our boolean vale from the inspector, we must thus find a way to achieve the same logic from our custom property drawer.

A recursive solution

And what if our struct is a property of a class which reference we obtained through a struct that is itself the property of another class instance ??? The answer is of course not “Why the hell would you want to do that?!!”.

Nop, the answer is to modify our deep bool and then recursively assign our values from the bottom to the top! And that, folks, is what the SetTargetObjectRecursive function is for!

Since this function is rather complicated and uses a lot of dark magic, here is a full Unity project containing all the C# implementations (including our boolean and property drawer scripts) that you can directly download:

Click here to download a Unity project containing all the scripts of this tutorial as well as a sample scene demonstrating our custom blittable bool editing.

We can finally edit our blittable boolean using a simple checkbox in Unity’s inspector, yeah!

Blittable bool editable through a checkbox in Unity's inspector

IMPORTANT NOTICE:

For some reasons, editing such a boolean property when Unity’s ECS default worlds (especially the one called ‘Editor World’) are active doesn’t work (except for prefabs). To disable automatic world bootstrap, add ‘UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP’ to the scripting define symbols in your project Player options.

A simpler solution?

All the above code might seem a little bit too complicated for just a simple bool type. An alternative and simpler solution might to just use an enum with two values: “TRUE” and “FALSE”. We can even declare this enum as being a byte type:

public enum Boolean : byte
{
   False = 0,
   True = 1
}

Using this enum in our component instead of our previous boolean struct allow Unity’s inspector to provide a direct way of editing its value, while being less elegant in my opinion:

Blittable boolusing an enum

This solution does not provide direct conversion from/to conventional bool type but I am sure C# extensions can help here. This is left as an exercise for the reader 🙂

[Edit] A MUCH simpler solution!

By the time I wrote this article, I found a much much simpler solution to edit our blittable bool through unity’s inspector. For this solution to work, you only require our boolean struct definition and the following property drawer, which replaces our previous booleanDrawer:

[CustomPropertyDrawer(typeof(boolean))]
class booleanDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var field = property.FindPropertyRelative("boolValue");
        field.intValue = EditorGUI.Toggle(position, label, field.intValue != 0) ? 1 : 0;
    }
}

Simple, right? At the time, I think my lack of Unity knowledge resulted in an overly-complicated solution. However, I decided to keep the old solution in case someone might need something similar.

Related Posts

Comments (1)

[…] such as a fire button, would be typically stored as boolean fields. For that, you might require a blittable bool since the built-in bool type is not blittable and thus incompatible with Unity’s […]

Leave a comment