This page documents the Resource base class: its internal data fields, path management, the ResourceCache it interacts with, scene-unique IDs, the change notification mechanism, and duplication behaviour.
For how resources are loaded from disk, see ResourceLoader. For how the engine avoids redundant loading via its cache, see Resource Cache. For how resources are persisted to disk, see ResourceSaver.
Resource is the base class for all data containers that can be saved to and loaded from disk. It inherits from RefCounted, so instances are managed by reference counting and are freed automatically when no more references exist.
The class is declared in core/io/resource.h and implemented in core/io/resource.cpp
Key responsibilities of the Resource class:
| Responsibility | Mechanism |
|---|---|
| Identify location on disk | path_cache field + ResourceCache |
| Identify self within a scene file | scene_unique_id field |
| Notify observers of changes | emit_changed() / changed signal |
| Copy itself | duplicate() / duplicate_deep() |
| Provide per-scene-instance copies | local_to_scene + local_scene |
| Report a server-side handle | get_rid() virtual |
Inheritance diagram:
Sources: core/io/resource.h53-194 core/io/resource.h198-216
The private data of Resource is defined in core/io/resource.h69-97:
| Field | Type | Purpose |
|---|---|---|
name | String | Optional display name shown in the Inspector |
path_cache | String | The registered path; may be a filesystem path or a sub-resource path |
scene_unique_id | String | Short alphanumeric ID used within packed scenes |
local_to_scene | bool | If true, a fresh copy is made for every scene instance |
local_scene | Node* | Set at instantiation time to the scene root that owns this copy |
emit_changed_state | EmitChangedState | Tracks whether changed emission is blocked |
Editor-only fields (inside #ifdef TOOLS_ENABLED): last_modified_time, import_last_modified_time, and import_path.
There are two methods for assigning a path:
| Method | Cache involved? | Use case |
|---|---|---|
set_path(path, take_over) | Yes — registers into ResourceCache | Normal load/save lifecycle |
set_path_cache(path) | No — sets path_cache raw | Cache-ignore modes, internal use by loaders |
set_path() is defined in core/io/resource.cpp71-108 It acquires ResourceCache::lock, removes the old cache entry if present, and inserts the new one. If another resource already occupies the target path:
p_take_over is true, the existing resource's path_cache is cleared and the slot is taken.set_path_cache() is defined in core/io/resource.cpp114-117 and simply writes path_cache directly, optionally calling the _set_path_cache GDVirtual override.
is_built_in() is declared in core/io/resource.h148 as:
path_cache.is_empty() || path_cache.contains("::") || path_cache.begins_with("local://")
A resource is "built-in" when it has no path (unsaved), when its path is scene_path::id (embedded inside another file), or when it uses a local:// prefix. External resources are those with a plain res:// path.
Diagram: Path registration in ResourceCache
Sources: core/io/resource.cpp71-108
ResourceCache is a companion class defined in core/io/resource.h198-216 It is not a singleton instance but a collection of static members accessed by Resource and ResourceLoader.
| Member | Type | Purpose |
|---|---|---|
resources | HashMap<String, Resource*> | Maps path strings to raw (non-owning) Resource pointers |
lock | Mutex | Guards all access to resources |
resource_path_cache (editor only) | HashMap<String, HashMap<String, String>> | Maps scene paths → resource paths → IDs |
Key methods:
| Method | Description |
|---|---|
has(path) | Returns true if a live resource is registered at that path |
get_ref(path) | Returns a Ref<Resource> from the map; the ref is empty if the resource is being destroyed |
get_cached_resources(list) | Enumerates all live cached resources |
Because resources stores raw pointers, get_ref() must attempt to increment the reference count atomically to avoid races with destruction. See core/io/resource.cpp for this logic.
Sub-resources embedded in .tscn or .scn files are identified by a short alphanumeric ID stored in scene_unique_id. These IDs appear in paths such as res://scene.tscn::abc12.
generate_scene_unique_id() (core/io/resource.cpp125-161) produces a 5-character string from a seeded RandomPCG generator. The seed is derived from the current date/time and OS::get_ticks_usec() to make collisions unlikely. If the saver detects a collision, it generates a new ID.
set_scene_unique_id() (core/io/resource.cpp163-175) validates that the ID contains only ASCII identifier characters (letters, digits, underscores), generating a fresh ID if not.
Resources expose a changed signal. The mechanism is three-layered to handle both normal and threaded load contexts.
Diagram: emit_changed routing
Sources: core/io/resource.cpp41-52
The blocking mechanism (_block_emit_changed / _unblock_emit_changed at core/io/resource.cpp54-66) is used internally during copy_from() to suppress intermediate change signals while properties are being bulk-applied.
connect_changed() and disconnect_changed() (core/io/resource.cpp200-219) similarly route through ResourceLoader::resource_changed_connect/disconnect() when called from a non-main thread during a load, to defer the actual signal connection until the load completes on the main thread.
Resource provides two public duplication entry points:
| Method | Shallow/Deep | Subresource handling |
|---|---|---|
duplicate(false) | Shallow | Sub-resources are shared, arrays/dicts are not copied |
duplicate(true) | Deep | Built-in sub-resources are duplicated; arrays/dicts copied recursively |
duplicate_deep(mode) | Always deep | Mode controls which sub-resources are recursively duplicated |
Defined in doc/classes/Resource.xml187-197:
| Constant | Value | Meaning |
|---|---|---|
DEEP_DUPLICATE_NONE | 0 | Arrays and dicts are copied, but sub-resources are shared |
DEEP_DUPLICATE_INTERNAL | 1 | Sub-resources without a path (built-in) are duplicated |
DEEP_DUPLICATE_ALL | 2 | All sub-resources are duplicated, even external ones |
The internal _duplicate() method (core/io/resource.cpp368-423) instantiates a new object of the same class via ClassDB::instantiate, sets the script, then iterates PROPERTY_USAGE_STORAGE properties and calls _duplicate_recursive() on each value.
_duplicate_recursive() (core/io/resource.cpp270-366) handles:
Variant::OBJECT — decides whether to duplicate based on flags (PROPERTY_USAGE_ALWAYS_DUPLICATE, PROPERTY_USAGE_NEVER_DUPLICATE, local-to-scene, and DuplicateParams.subres_mode).Variant::ARRAY / Variant::DICTIONARY — recursively duplicates entries.Variant::duplicate() for value-type copy.A thread-local thread_duplicate_remap_cache (core/io/resource.h96-97) is used to ensure that any single resource reachable via multiple paths within the graph is duplicated exactly once per session.
Diagram: Duplication call chain
Sources: core/io/resource.cpp509-551 core/io/resource.cpp368-423 core/io/resource.cpp270-366
When resource_local_to_scene is true, a resource is duplicated for each PackedScene instantiation rather than being shared across all instances.
duplicate_for_local_scene() (core/io/resource.cpp425-454) is called during scene instantiation with a remap cache to ensure shared sub-resources are deduplicated within that one instantiation.
configure_for_local_scene() (core/io/resource.cpp482-507) walks properties and recursively applies configure_for_local_scene() to nested local-to-scene resources.
After duplication, setup_local_to_scene() is called (via the _setup_local_to_scene GDVirtual), giving the subclass an opportunity to do per-instance initialization.
get_local_scene() returns the local_scene pointer only if local_to_scene is true and the resource was instantiated from a scene.
Some resources are thin wrappers over server-side objects (e.g., Texture2D wrapping a rendering server texture). The get_rid() virtual method (core/io/resource.h185) allows the engine to retrieve the underlying RID. Subclasses override the GDVirtual _get_rid to return the appropriate handle.
copy_from() (core/io/resource.cpp226-253) copies all PROPERTY_USAGE_STORAGE properties from one resource instance to another of the same type. It blocks emit_changed during the copy and unblocks at the end, emitting once if needed. It is used by ResourceLoader in CACHE_MODE_REPLACE to refresh an in-cache instance in-place.
reload_from_file() (core/io/resource.cpp255-268) loads a fresh copy from the resource's own path (ignoring cache) and calls copy_from() to apply the data in-place. This is how the editor hot-reloads resources without invalidating existing references.
Under #ifdef TOOLS_ENABLED in core/io/resource.h168-181:
| Member / Method | Purpose |
|---|---|
last_modified_time | Filesystem modification time, set by ResourceLoader after loading |
import_last_modified_time | Modification time of the source file at import time |
import_path | Path inside .godot/imported/ |
hash_edited_version_for_preview() | Override to trigger thumbnail updates when the resource changes |
set_edited(bool) / get_edited() | Tracks unsaved editor state |
The static resource_path_cache in ResourceCache (core/io/resource.h204) maps scene paths to their embedded resource ID assignments, allowing scene savers to maintain stable IDs across save/load cycles. The methods set_resource_id_for_path() and get_id_for_path() (core/io/resource.h188-190) manage this cache.
| Virtual Method | Signature | Purpose |
|---|---|---|
_get_rid | virtual RID _get_rid() const | Return server-side RID |
_reset_state | virtual void _reset_state() | Clear non-exported state before reload |
_set_path_cache | virtual void _set_path_cache(String) const | Notification hook after raw path assignment |
_setup_local_to_scene | virtual void _setup_local_to_scene() | Per-instance initialization after scene duplication |
_resource_path_changed | virtual void _resource_path_changed() | Called after set_path() completes |
Sources: core/io/resource.h108-127 doc/classes/Resource.xml17-145
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.