Skip to content

Conversation

@TruelyMostWanted
Copy link

@TruelyMostWanted TruelyMostWanted commented Oct 30, 2025

Hey, this is my first PR / contribution to the engine 👋

Description:

This PR extends the ResourceLoader class with a set of new utility methods that allow querying the engine's internal ResourceCache for paths matching specific criteria. No existing logic has been changed, only additions have been made
This feature is fully available in both C++, GDScript and C#

Knowledge

Any Resource is considered "cached", when one of the following conditions is true:

  • The resource is assigned to a export variable in the Inspector (RefCount > 0)
  • The resource was loaded via code ResourceLoader.load(...)

Use Cases:

Retrieve all cached resource paths where ...

  • the "TypeHint"
    • matches a given "p_TypeHint" (e.g "Image", "AudioStreamWAV", "AudioStreamMP3", "JSON", "Shader", "VisualShader")
  • the "ResourceName"
    • matches a given "p_ResourceName" (e.g. "Spritesheet_Char01_Idle")
    • begins with a given "p_ResourceNamePrefix" (e.g. "Spritesheet_")
    • contains a given "p_ResourceNameSubstring" (e.g. "Char01")
  • the "Path"
    • begins with a given "p_PathPrefix" (e.g. "user://", "res://", "C:/" )
    • contains a given "p_PathSubstring" (e.g. "/data", "/settings", "/images")
  • the "FileName"
    • matches a given "p_fileName" (e.g. "Spritesheet_Char01_Attack.png")
    • begins with a given "p_fileNamePrefix" (e.g. "Spritesheet_", "IMG_", "Sprite_")
    • contains a given "p_fileNameSubstring" (e.g. "Char01")
  • the "FileExtension"
    • matches a given "p_fileExtension" (e.g "mp3", "wav", "ogg", "jpeg", "png", "json")
    • begins with a given "p_fileExtensionPrefix" (e.g. "t") --> could match: ( "txt", "tres", "translation" )
    • contains a given "p_fileExtensionSubstring" (e.g. "res") --> could match: ( "tres", "res" )
      And once you have them, just load them directly from the cache via ResourceLoader.load(...)

Usages On UI:

  • Dropdowns listing all assets of a certain type/path/name/extension to select from
  • Text input fields where you type a name, path, extension and the matches show up in a list

Results

Note: Retrievals on the "ResourceName" target the "Name" in the inspector
image

(1) Dictionary Retrieval (formatted via JSON.stringify() )
image

(2) Array Retrieval (using p_with_godot_type=true and separator=" -> " )
image

(3) Full Documentation with 2 examples per function
image

How To Test / Use:

C# Test Code:

using Godot;
using Godot.Collections;

[GlobalClass]
public partial class GdScriptTestNode : Node
{
    [Export] public Array<Resource> Resources;

    public override void _Ready()
    {
        GD.Print("=================== BEGIN OF TEST (C#/.NET) ===========================");

        // Dictionary tests
        var allTestDict = ResourceLoader.GetCachedPathsDict();
        var typeHintTestDict = ResourceLoader.GetCachedPathsByTypeHintDict("Image");

        var resNameTestDict1 = ResourceLoader.GetCachedPathsByResourceNameDict("MyResource");
        var resNameTestDict2 = ResourceLoader.GetCachedPathsByResourceNamePrefixDict("My");
        var resNameTestDict3 = ResourceLoader.GetCachedPathsByResourceNameSubstringDict(" ");

        var pathTestDict1 = ResourceLoader.GetCachedPathsByPathSubstringDict("_");
        var pathTestDict2 = ResourceLoader.GetCachedPathsByPathPrefixDict("res://");

        var nameTestDict1 = ResourceLoader.GetCachedPathsByFileNameDict("MyResource");
        var nameTestDict2 = ResourceLoader.GetCachedPathsByFileNamePrefixDict("new");
        var nameTestDict3 = ResourceLoader.GetCachedPathsByFileNameSubstringDict("_");

        var extTestDict1 = ResourceLoader.GetCachedPathsByFileExtensionDict("tres");
        var extTestDict2 = ResourceLoader.GetCachedPathsByFileExtensionPrefixDict("t");
        var extTestDict3 = ResourceLoader.GetCachedPathsByFileExtensionSubstringDict("res");

        GD.Print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");

        // Array tests
        var allTestArray = ResourceLoader.GetCachedPaths(true, " -> ")

        var typeHintTestArray = ResourceLoader.GetCachedPathsByTypeHint("Image", true, " -> ");

        var resNameTestArray1 = ResourceLoader.GetCachedPathsByResourceName("MyResource", true, " -> ");
        var resNameTestArray2 = ResourceLoader.GetCachedPathsByResourceNamePrefix("My", true, " -> ");
        var resNameTestArray3 = ResourceLoader.GetCachedPathsByResourceNameSubstring(" ", true, " -> ");

        var pathTestArray1 = ResourceLoader.GetCachedPathsByPathSubstring("_", true, " -> ");
        var pathTestArray2 = ResourceLoader.GetCachedPathsByPathPrefix("res://", true, " -> ");

        var nameTestArray1 = ResourceLoader.GetCachedPathsByFileName("MyResource", true, " -> ");
        var nameTestArray2 = ResourceLoader.GetCachedPathsByFileNamePrefix("new", true, " -> ");
        var nameTestArray3 = ResourceLoader.GetCachedPathsByFileNameSubstring("_", true, " -> ");

        var extTestArray1 = ResourceLoader.GetCachedPathsByFileExtension("tres", true, " -> ");
        var extTestArray2 = ResourceLoader.GetCachedPathsByFileExtensionPrefix("t", true, " -> ");
        var extTestArray3 = ResourceLoader.GetCachedPathsByFileExtensionSubstring("res", true, " -> ");
    }
}

GDScript Test Code

extends Node
class_name GdScriptTestNode

@export var resources : Array[Resource]

func _ready() -> void:	
	print("=================== BEGIN OF TEST (GDScript) ===========================");
	#Dictionary tests
	var allTestDict = ResourceLoader.get_cached_paths_dict()
	
	var typeHintTestDict = ResourceLoader.get_cached_paths_by_type_hint_dict("Image")
	
	var resNameTestDict1 = ResourceLoader.get_cached_paths_by_resource_name_dict("MyResource")
	var resNameTestDict2 = ResourceLoader.get_cached_paths_by_resource_name_prefix_dict("My")
	var resNameTestDict3 = ResourceLoader.get_cached_paths_by_resource_name_substring_dict(" ")
	
	var pathTestDict1 = ResourceLoader.get_cached_paths_by_path_substring_dict("_")
	var pathTestDict2 = ResourceLoader.get_cached_paths_by_path_prefix_dict("res://")
	
	var nameTestDict1 = ResourceLoader.get_cached_paths_by_file_name_dict("MyResource")
	var nameTestDict2 = ResourceLoader.get_cached_paths_by_file_name_prefix_dict("new")
	var nameTestDict3 = ResourceLoader.get_cached_paths_by_file_name_substring_dict("_")
	
	var extTestDict1 = ResourceLoader.get_cached_paths_by_file_extension_dict("tres")
	var extTestDict2 = ResourceLoader.get_cached_paths_by_file_extension_prefix_dict("t")
	var extTestDict3 = ResourceLoader.get_cached_paths_by_file_extension_substring_dict("res")
	
	print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	
	#Array tests
	var allTestArray = ResourceLoader.get_cached_paths(true, " -> ")
	
	var typeHintTestArray = ResourceLoader.get_cached_paths_by_type_hint("Image", true, " -> ")
	
	var resNameTestArray1 = ResourceLoader.get_cached_paths_by_resource_name("MyResource", true, " -> ")
	var resNameTestArray2 = ResourceLoader.get_cached_paths_by_resource_name_prefix("My", true, " -> ")
	var resNameTestArray3 = ResourceLoader.get_cached_paths_by_resource_name_substring(" ", true, " -> ")
	
	var pathTestArray1 = ResourceLoader.get_cached_paths_by_path_substring("_", true, " -> ")
	var pathTestArray2 = ResourceLoader.get_cached_paths_by_path_prefix("res://", true, " -> ")
	
	var nameTestArray1 = ResourceLoader.get_cached_paths_by_file_name("MyResource", true, " -> ")
	var nameTestArray2 = ResourceLoader.get_cached_paths_by_file_name_prefix("new", true, " -> ")
	var nameTestArray3 = ResourceLoader.get_cached_paths_by_file_name_substring("_", true, " -> ")
	
	var extTestArray1 = ResourceLoader.get_cached_paths_by_file_extension("tres", true, " -> ")
	var extTestArray2 = ResourceLoader.get_cached_paths_by_file_extension_prefix("t", true, " -> ")
	var extTestArray3 = ResourceLoader.get_cached_paths_by_file_extension_substring("res", true, " -> ")

I hope this helps a lot of your projects out! ✨
Feel free to give me any feedback on the idea, the PR, the description/text of the PR and such

Now you can retrieve all cached paths or only those with certain typeHint, pathPrefix, fileNamePrefix or fileExtension (C++/C#/GDScript)
@TruelyMostWanted TruelyMostWanted requested a review from a team as a code owner October 30, 2025 19:45
@TruelyMostWanted TruelyMostWanted requested a review from a team as a code owner October 31, 2025 05:37
@TruelyMostWanted
Copy link
Author

Oh i forget the docs, of course!
doctools called, Documentation updated, Description inserted, clang-format applied
(The failures were a good learning for the first PR 👍)

@AThousandShips
Copy link
Member

Thanks for opening a pull request!

Feature pull requests should be associated to a feature proposal to justify the need for implementing the feature in Godot core. Please open a proposal on the Godot proposals repository (and link to the proposal in this pull request's body).

@TruelyMostWanted
Copy link
Author

Thanks for opening a pull request!

Feature pull requests should be associated to a feature proposal to justify the need for implementing the feature in Godot core. Please open a proposal on the Godot proposals repository (and link to the proposal in this pull request's body).

Created it at: godotengine/godot-proposals#13523

@TruelyMostWanted
Copy link
Author

TruelyMostWanted commented Nov 3, 2025

Feature is now finalized
Proposal + Pull-Request texts as well as Code + Documentation are now finalized from my side

Feel free to provide any form of feedback 😊

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.

Add retrieval methods to ResourceLoader for querying cached resource paths (C++, C#, GDScript)

2 participants