Skip to content

Conversation

@SatLess
Copy link
Contributor

@SatLess SatLess commented Aug 9, 2025

Attempts to somewhat implement
godotengine/godot-proposals#904 , godotengine/godot-proposals#9603 , godotengine/godot-proposals#10319 (comment)

Feature

Adds an indicator to tells whether a resource is shared. The button's tooltip shows the number of times a Resource was shared, along with whether there are subresources to be made unique:

showtime

Left Click on the Icon makes Resources Unique. Right Click - Recursive

Implementation

For this feature, after a lot of trial and error, I settled for reduz's approach of using a
HashMap to track how many times a Resource is referenced by a Node within a Scene.

  • If a Resource is referenced more than once, you can make it unique (recursively or not).
  • If there's only one instance of a Resource, it's already unique, so make_unique and make_unique_recursive is disabled.

Note

Duplicating built-in SubResources is also disabled if the 'Parent' Resource wasn't previously made unique. This is because Making a SubResource unique does not matter if the parent isn't also duplicated. See #109458 (comment) (gradient example)

  • External Resources are not added to the HashMap — since we can't for certain indicate how many of them there are.
    Outside from that, I would separate this feature into two parts:

SceneTree Operations


In the Scene tree, you can add, delete, duplicate and paste nodes. Each time you do these operations, update_resource_count collects built-in non-empty Resources and add them to the HashMap, along with their respective Node. So basically you update the Resource counter each time you do these operations.


Inspector Operations

Each time you made a revelvant change to a property that holds a Resource (e.g Made a Resource unique, added a resource to an Array, etc), you update the Resource counter like above, inserting the Resource and its Node in the HashMap.

Note

When setting Subresources in the inspector (if not external), they should have the same number of References as the parent. So if Reference A is referenced by 3 Nodes, if you add a SubResource B, it should also be linked to 3 Nodes.

It uses a much "simpler" version of update_resource_count (although they could be merged but it would make using this API much more cumbersome for the Inspector and SceneTree). update_node_reference collects the Resources found withing a single property and either removes or adds to the HashMap. That way you're only dealing with a specific property is being set and not touching what's already added.

In short, The inspector part was the most tricky, as I did have to fix all the edge cases found when making unique, setting or removing Resources . As of 09/28, it's pretty clean all things considered. Using strictly update_node_reference and tweaking some pre existing code made it much cleaner than it previously was.

To-Do List

The following is a to-do list of everything that should be dealt with. There are some things left undetermined on how they should work, so I added Waiting for Input right after the task.

  • Display a warning indicator for sub resources as to why they can't be duplicated (Waiting on review for input)
  • Move Make Unique and Make Unique recursive funcionality to Icons (Waiting on review for input) Edit: NVM, moving functionality to icons hasnt been well supported by users in previous attempts by other PRs
  • Hashmaps clears and updates itself when Nodes are Added/Removed from a scene
  • Disable make_unique if there's only copy of the Resource or It's a subresource
  • Update Hashmap through other means, such as using Resource Picker
  • Counter not updating once you've done an operation.
  • Track Subresources
  • Bulk-Setting Node's Resources does not add them to hashmap.
  • Duplicated Arrays full of Resources do not increase counter for some reason.
  • External SubResources made unique should be included in the Hashmap, pointing to the parent's Nodes.
  • Find better way of knowing whether a resource is external or not
  • History mismatch when undo-redoing packed scenes if they're open on the editor. (Waiting on review for input) Seems to have fixed itself
  • Empty Resources/Sub resources using the wrong icon (fixes itself after saving)
  • Arrays (probly Dictionaries too) don't update counter when making unique
  • Inconsistent Redo error might happen??
  • Fix edge case when saving to disk/deleting resource from disk
  • Dictionaries with Resources as Keys don't show an icon
  • Edge Case with SubResources not showing the correct amount after adding them to a Resource already referenced by multiple nodes

Test Project

Added a test project so people interested in this feature can test it. It's a pretty dynamic feature though, so please toy around it and report any weird behavior!
indicator-test.zip

@fire fire changed the title Add Indicator to Resources That Are Linked Add indicator to linked resources Aug 9, 2025
@AThousandShips AThousandShips added this to the 4.x milestone Aug 11, 2025
@SatLess

This comment was marked as outdated.

@AThousandShips
Copy link
Member

Please make sure your code is formatted properly locally before pushing again if you want checks to run, see here

@SatLess SatLess force-pushed the DumbRes branch 2 times, most recently from ea7d0bb to f1ce477 Compare August 13, 2025 00:36
@SatLess

This comment has been minimized.

@dawdle-deer
Copy link
Contributor

So the counter idea would be scrapped, being replaced by an icon instead.

I do much prefer the counter - perhaps there's a middle ground that still offers one without the effort of tracking scene-external link counts. Maybe it could display the scene-local link count if it's internal, and then if it's external, make it instead read N or Ext or something?

@SatLess
Copy link
Contributor Author

SatLess commented Aug 15, 2025

Local duplicated Resources now have a counter
image

External Resources use an icon, and can be turned into local if clicked:
AAAAAAAAAA

Sadly, despite 5 days trying to get it to work, Subresources will not use the counter (unless a way is found ofc). It works pretty unreliably:
Why

Kinda upsetting, since that is mostly why I decided to make this PR. Will make the finishing touches needed , will try to indicate that making subresources unique is sorta pointless, and will leave it as is for review.

EDIT: Maybe I could in fact track the amount of sub resources locally, but it wouldn't do much more than that, unless you made their parent Resource unique

@arkology
Copy link
Contributor

Adds an icon on the side of a resource if it is not unique.

Move Make Unique and Make Unique recursive to Icons

Makes sense to take into account concerns raised in #102196:

User feedback has shown that this change isn't always a clear improvement, because:

The icon eats up horizontal space that's already limited here, cutting the text or previews significantly.
It breaks user expectations to no longer have load options next to Clear/Save/etc.

@SatLess
Copy link
Contributor Author

SatLess commented Aug 15, 2025

The icon for sub resources is more of a suggestion, one I'm particularly not that fond of. Maybe changing the theme of The Sub resource to indicate that? Or maybe adding a notification when trying to make that resource unique?

@arkology
Copy link
Contributor

I think the main (and most difficult) thing that should be done first it to detect amount of references to a resource.
On UI side:

(Please note that this is my personal opinion, and it may not coincide with the opinion of the Godot team members.)

@SatLess SatLess force-pushed the DumbRes branch 3 times, most recently from 763256c to d9c3e5b Compare August 16, 2025 01:50
@SatLess
Copy link
Contributor Author

SatLess commented Aug 16, 2025

Edge Cases aside, I'm done with this PR and it's ready for review! (I'm tired help)

@SatLess SatLess marked this pull request as ready for review August 16, 2025 01:59
@SatLess SatLess requested review from a team as code owners August 16, 2025 01:59
@SatLess SatLess force-pushed the DumbRes branch 3 times, most recently from a61f0e0 to 44af052 Compare August 22, 2025 23:36
@SatLess
Copy link
Contributor Author

SatLess commented Aug 22, 2025

Hey everyone, small update: Reinforced Support for Subresources, so they're taken into account when making external ones unique, and also when they're deleted with the parent. Arrays/Dictionaries are also using the counter now.
The PR is in a functional state, besides some quirks, so It's 'okay' for use (at least for my projects). This PR def needs some refactoring, perhaps some optimization ,reducing recursion calls, but I'll force myself to take a break from it until Godot 4.6 starts development, around the time someone from the Godot team might actually take a look at this.

Note (mostly to self): Subresources in this PR are treated as inseparable from their parents, as it's impossible for a Resource and its nested child not have the same Nodes referencing them. So I took advantage of this when needed to keep better track of Subresources' counter. Also, dont use Vscode for git, it suckssss

@SatLess SatLess force-pushed the DumbRes branch 3 times, most recently from 55cd5f1 to a0e9cb4 Compare August 23, 2025 00:15
@KoBeWi
Copy link
Member

KoBeWi commented Oct 16, 2025

I did a code review. I didn't delve very deep into the implementation, at glance it looks ok. It's limited only to editor code, which is good.

The only concern is scanning all properties whenever object/array/dictionary is changed. I did test some cases that I think could be heavily affected and didn't notice any big slowdowns, so it's not as bad as it looks.

Also the code duplication. OBJECT/ARRAY/DICTIONARY is a famous trio in inspector-related code. I've seen the same methods many times already, but since they always do something a bit different, it's difficult to really unify it :/

@SatLess
Copy link
Contributor Author

SatLess commented Oct 16, 2025

Thanks for you guys Input!

I gave it a bit testing and it seems to work fine overall. One issue I found is the note about sub-resources

This is most likely due to how External Resources are checked for recursive uniqueness, I'll take a look on that. But the main idea is that make_unique_recursive is only enabled if there's at least one subresource A that's either external or has multiple copies.

As for the MultiNodeEdit:

So for multinode, it still makes sense if the Resource is used in other nodes. This is tricky. Maybe check if usage count is equal to number of nodes? But I guess that's unreliable.

In that case, it's pretty difficult to determine how to proceed. My initial idea would be to have godotengine/godot-proposals#13163 implemented so Make Unique actually duplicates for each Node instead of making only of copy that is shared between selected Nodes.
Then, I guess we could enable/disable MultiNodeEdit using these:

  • To enable duplicating property A, we must find at least a Node from selection which shares Resource A with another Node in the Tree. Then, we duplicate this Resource the amount necessary, while leaving the others Nodes whose A is already unique alone.
  • If A is already unique for all Nodes in a selection, disable it.

It takes space. It's similar to the quick load button, which users weren't very happy about. Though it only shows in specific cases, so probably it's fine?

That was one of my worries, but currently there's no way to indicate that if not by an icon. Reduz's puts a counter on here, which is a really weird design IMO and not rly descriptive.

image

The only concern is scanning all properties whenever object/array/dictionary is changed. I did test some cases that I think could be heavily affected and didn't notice any big slowdowns, so it's not as bad as it looks.

Yeah it's wasteful currently, removing Resources only to re-add them again, with the exception of the one that changed, but covering all possible cases an Array/Dictionary can change would be pretty painful 😅


Noticing that there are places where TTR is applied to variables like TTR(tooltip), that won't work AFAIK as the string won't be extractable, TTR should be around raw strings so the content can be extracted for translation data

@AThousandShips is there a way to circumvent this? My previous approach was changing the tooltip text directly after a set of conditions were met, and there was a lot of overlap (e.g A external Resource with Subresources vs an Internal Resources with Subresouces share more of less the same message).

@KoBeWi
Copy link
Member

KoBeWi commented Oct 16, 2025

For TTR, see my suggestions: #109458 (comment)

@arkology
Copy link
Contributor

Screenshot_2025-10-17-08-51-50-422_org godotengine editor v4 debug

Tested on Android, and this is how it looks😄 Sprite texture preview is extremely tiny

@SatLess
Copy link
Contributor Author

SatLess commented Oct 17, 2025

Added the required changes. For MultiNodeEdit i decided to check the Node selection against the Resource counter. If they're equal or if the edited resource is not external, you're not allowed to make them unique.

I'd like to implement this proposal after this gets merged (so this PR is not dependent on another). Therefore a more fine-tuned solution for this can flourish. Since I guess, as it stands now, making many Resources unique in bulk like that is pretty niche, specially since it might break user expectations of what this means, the current solution is fine?

Tested on Android, and this is how it looks😄 Sprite texture preview is extremely tiny

Damn, seems like there's no easy solution to indicate a resource is unique/linked, I've tried seeing how blender handles ui and well...
blenda

I'm not sure how to circumvent this without having an icon of sorts. Long term we could refactor the UI so it accepts more buttons or shinks appropriately. Any suggestions are appreciated, but idk if there's something to be done

@SatLess
Copy link
Contributor Author

SatLess commented Oct 25, 2025

Will wait to push the Rebased commit, but what I did in this one is to remove the Resource icon if there is a preview and the button's size meets a certain threshold:

showff

This is the least intrusive approach I could find. The previous ones involved either increasing the minimum inspector size to accommodate all buttons or removing the preview altogether.
Although, it's worth pointing out that the preview is usually not helpful for bigger sprites. I didn't remove the preview however bc 3D meshes seem to be more helpful even when the inspector's size is pretty small:

collage

I also solved an edge case where saved to disk resources would be included in the hash map if it was previously built in.

EDIT: Rebased

@SatLess SatLess force-pushed the DumbRes branch 2 times, most recently from 9950939 to 97d83d9 Compare October 25, 2025 15:38
@farfalk
Copy link

farfalk commented Oct 30, 2025

I'm so, so glad this PR exists! I've been trying to build a GDscript based prototype around the start of this year (even consulted with the dev chat and passivestar about it) but failed to find the time to bring it forward. The inability to understand which resources were non-unique has been a great pain point for my team, it brought upon us so many hard to understand interactions. Thank you so much!

P.s. I don't think it will be very useful at this point, but here is my attempt for reference https://github.com/farfalk/resource-users-addon. There is an attempt to deal with external resources shared among scenes in the whole project, with a hint to implement a resource database in the .godot folder

@SatLess
Copy link
Contributor Author

SatLess commented Oct 30, 2025

@farfalk I'm really happy this PR is being of great use!
As for external Resources, I had looked into your code as well as trying other approaches to the problem, but I couldn't really bring them to work. One of my ideas at the time was to imitate how Godot's save global groups, but I couldn't get much out of it.

Nerverheless, since counting external Resources is most useful only when you want to look up which Nodes are using it, it seems this PR can currently do without it.
I think currently the only advantage to implement this as it stands now would be to unify some code between external internal Resources inside Resource picker, but it's rather trivial

@SatLess
Copy link
Contributor Author

SatLess commented Oct 31, 2025

Rebased and added a better check for Android (the one I had presented wasn't working for it). This is how it looks currently:
Screenshot_20251031_193712.jpg

EDIT: This is how it looks with the old editor theme (it looks bigger so the new theme seemed to shrink the theme a bit)

Screenshot_20251101_105203.jpg

Copy link
Member

@KoBeWi KoBeWi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor code problems, but otherwise looks fine now.

Comment on lines 693 to 695
if (!make_unique_button->is_disabled()) {
_edit_menu_cbk((_is_uniqueness_enabled(true) ? OBJ_MENU_MAKE_UNIQUE_RECURSIVE : OBJ_MENU_MAKE_UNIQUE));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This minor, but there is inconsistency between instant right-clicks and left-clicks that take effect on button release.

I think the most feasible way to fix it is to enable Mouse Right in button mask and check if right mouse is pressed in the pressed callback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used Input singleton to discern a left click from a right click, so I also changed the button's action mode to ACTION_MODE_BUTTON_PRESS

@KoBeWi KoBeWi modified the milestones: 4.x, 4.6 Nov 3, 2025
@KoBeWi KoBeWi removed the request for review from a team November 3, 2025 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants