Things I love about UID's

When UID’s were first introduced I must admit that I refrained from using them. I thought “why would I want to use some anonymous reference instead of the actual path to the thing I wanted?”.

const WALKER = preload("res://components/actors/enemies/walker/walker.tscn")

# Better than:
const WALKER = preload("uid://dtce7txae2e0j")

However, I did start using them. Two things convinced me. The first was that the UID has this brilliant rollover:

And then of course the real reason for UID’s really struck home. I can now shovel around my folder structures in my game without breaking anything! During my game dev cycle I am always moving my folders around, keeping everything as ‘sorted’ as possible. Now I can just move entire folders at will, and the UID’s work perfectly.

I have been totally converted and now I love UID’s. Just wanted to share that.

16 Likes

Couldn’t editor already update paths, the ones referenced properly? And even track existing references, like when you attempt to delete a file?

Not to strings in code.

1 Like

True, and still that is more than what uids offer. There is a reason why using strings in code is considered a bad practice, but uids seem to encourage using them.

Don’t get me wrong, having an option is great. I would just prefered seeing this effort put towards fixing some old bugs and quirks first, there is no shortage of those in the bugtracker. Just afraid of Godot evolving into a disorganized pile of undercooked features.

Using magic strings is bad practice. Using strings in constants is not bad coding practice. UIDs do not encourage bad practice. They allow good practices.

For example, while you can @export a variable and drop a scene or asset in to maintain a reference to it - your scene is going to automatically load it. That’s fine if it is integral to your running scene. But if you want to reference a larger array or objects you don’t want in memory until you need them (e.g. a list of all the levels in your game), it is nice to have a reference to them that does not autoload.

It’s an open source project with a staff of less than a dozen, and hundreds of individual contributors. Emi has talked in the live stream about how people often complain about new features being added instead of bugs being fixed. They do not have control over what the individual contributors want to fix. Sometimes features are added by 3rd parties (like the embedded Game toolbar), sometimes donated money is earmarked for certain areas, and sometimes the expertise needed to fix bugs just doesn’t exist. (Which is why the audio functionality just got a bunch of features in the last two revs.)

Also, a lot of bugs in the bug tracker doesn’t mean anything. In any professional project, you are going to get lots of bugs that never get fixed. They aren’t severe enough, they don’t affect enough people, or they no longer exist because the feature they are logged against has a whole new implementation. Triaging bugs is a full time job for multiple people, and requires the time to go back over bugs and review them. As someone who goes into companies as a consultant to teach professionals how to do this, I can tell you it is very complex.

This is an open source project. If there are bugs that you think should be addressed, you can fix them, you can post in issues updating that they still exist, and/or create new projects that reproduce the bug.

3 Likes

You reference them with paths. The paths are not automatically updated - but neither are uids. When putting them in code you are just relying on whatever they pointing to to still be there, which sometimes will be so, and other times won’t. The illusion of advantage.

You see, this is not a flaw with the paths specifically. No system can manage the strings in code reliably, whether they are paths or opaque ids. Forget for a moment the trivial case of having uid pasted directly - what if this string is loaded, unpacked, decoded, or otherwise processed at runtime, and simply does not exist in the source in reconizeable form?
You just can’t make a system that verifies the strings in code reliably - that is what makes using them inherently a bad practice, not a formal declaration somewhere. People are bound to end up with dead references to wrongly deleted resources either way. Only now they look like “uid://dtce7txae2e0j” so you can’t even tell what it was pointing to.

I would say that expanding the long existing @export feature options to not load the resource automatically is the way to address this particular issue - as it was proposed.

That was an interesting link - thank you.

When UID’s were first introduced I recall reading a lot about the pros and cons from different viewpoints both liking and disliking various aspects of the UID solution. I sided initially on the “I don’t like them” side and that is why I didn’t use them.

Since using them, I have been converted and am now on the “I like them” side. No, they do not solve everything, yes they do involve some negative aspects, but it is an ingenious approach IMHO that I had not seen anywhere before (although nothing is completely original of course).

For me, any negatives (like populating the folders with lots of additional files) are currently overwhelmed by the positives, and I think they have proven, for me at least, to be extremely helpful and significantly improved my daily Godot UX.

I also did a quick test, I set up a scene with references to another test scene.

extends Node2D

@onready var test_preload: PackedScene = preload("uid://vgmmawohw0uu")
@onready var test_preload_2: PackedScene = preload("res://testing/uid_test/to_be_deleted.tscn")

All was fine, so I closed Godot and manually change the file name of the test scene to to_be_deleted_DELETED.tscn

When I opened the project, the UID now pointed to the renamed scene automatically. (I have no idea how it managed to know that but it did! I can only guess it is referencing something other than the files actual name, but what I don’t know.) However, the direct file reference preload threw an error.

So I commented out the file path preload, leaving just the UID, and closed the project again. I then manually deleted the test scene only from the folder and re-opened the project, and I got the error as expected that the UID was not recognised.

  ERROR: Unrecognized UID: "uid://vgmmawohw0uu".
  ERROR: res://testing/uid_test/uid_test.gd:3 - Parse Error: Preload file "uid://vgmmawohw0uu" does not exist.
  ERROR: modules/gdscript/gdscript.cpp:3041 - Failed to load script "res://testing/uid_test/uid_test.gd" with error "Parse error".

But you were correct that no trace of what it was pointing to remained.

So, as I said, it does not solve everything, but I really like using them. What it does solve for me I encounter on a regular basis, and this example, at least for me, is very much an edge case.

So yes, I still really like them and think they are a clever solution to an otherwise difficult to solve issue.

Actually, looks like @export_file will manage the paths just fine (and will in fact use uid where it makes sense). So the pieces to reference resources in a trouble-free way are all in place, we just need to make proper use of them. It does not seem to count the reference though.

1 Like