Unsigned long integer field does not show correctly in the inspector

I just discovered this not too long ago. I use unsigned long integers (ulong) for globally-unique identifiers, or GUIDs, for tracking objects in between sessions and over a network. They show up as signed longs instead. What’s more, there is no method in EditorGUILayout to create a ulong field - just long. If I create a label field and use UInt64.ToString(), I can see what the correct ID is, but if I want to set a specific GUID it gets sticky if it’s over half of the ulong range (which is 50% likely because we randomly generate them), because then it shows as a negative number and won’t let me paste in the correct number unless I convert it to a signed value.

I don’t want to use the built-in .Net System.Guid type because I would have to refactor close to 50k lines of code across both the client and server, restructure the database, convert all of the existing records to Guids, and reestablish the references to those Guids in other records - and I already have over a thousand records. Not to mention there is no Guid field in EditorGUILayout either. I guess I could just use longs, but there’s still the matter of refactoring 50k lines of code.

I haven’t worried about having it in the inspector until now, because we always just generated them randomly and didn’t have a need to modify it. And yeah, I know there are probably 289.333 (repeating, of course) workarounds for this, but it’s kind of a surprise that it’s missing, given that there’s a ulongValue field on the SerializedProperty class, but no EditorGUILayout.UlongField.

Anything to do with unsigned variables is always gonna be the unloved redheaded stepchild, missing all kinds of support, requiring ugly casts all over the place, etc.

If you want proof that using unsigned vars is problematic, ask yourself why Array.Length and List<T>().Count return int and not uint . You can’t have a negative count or length, so why didn’t they use uint ? Well, because C# is just typesafe enough that it makes unsigned stuff a complete pain in the butt, forcing you to liberally sprinkle filthy dirty casts everywhere. :slight_smile:

I know it’s a little bit late in your codebase, but wherever possible you should stick with either int or long. Or if it has to be user-facing, throw it in a string and be done with it, and then it’s easy to debug and search for with grep or strings commands. When I need GUIDs in Unity, I just .ToString() them and use that.

All that said, you might get away with using your existing ulong setup by making a custom drawer for some other kind of container that you can use to present these things, or just with a few custom editors where you need it most.

Honestly, at this point I’m just going to deal with it.

You’re not wrong. I guess the main reason I went with ulong instead of long comes from when I was doing coding for embedded systems, some older of which are optimized for unsigned numbers, and the prevailing wisdom is to use an unsigned if you don’t need a negative. Or if you’re dealing with positional data where a negative number could cause a linear stepper carrier to crash into its own chassis or something. I’m not gonna lie - I never did look into the why of it as much as perhaps I should have.

1 Like

The Odin Inspector devs ran into this issue too, and are in the process of just making a ulong field from the ground up.

Their workaround was to just use a text field and .ulong.TryParse that into the underlying value. Should be possible with a property drawer.

That said, do you need to edit these identifiers? A property drawer that just draws it as a label would be an even simpler work around.

1 Like

I was changing them for troubleshooting, mainly. I guess what they’re doing would be a good way to do it if necessary. Right now what I do is use a calculator to convert it to bytes and then from there convert it to a signed long, and then I can paste it in. To make sure it’s correct, I do have a label field where the correct ulong value is displayed.

It’s good to know I’m not the only one affected by it, though.