Remake resource thread safety and API

* Ensures thread safety when resources are destroyed.
* Simplified API by always forcing `ResourceCache::get_ref`, which needs less hacks and is fully thread safe.
* Removed RWLock for resources because its not possible to use for the new logic. Should not be a problem.

Supersedes #57533
This commit is contained in:
reduz 2022-06-22 13:46:46 +02:00
parent c18d0f2035
commit e772b65d92
15 changed files with 117 additions and 126 deletions

View File

@ -52,41 +52,36 @@ void Resource::set_path(const String &p_path, bool p_take_over) {
return; return;
} }
if (p_path.is_empty()) {
p_take_over = false; // Can't take over an empty path
}
ResourceCache::lock.lock();
if (!path_cache.is_empty()) { if (!path_cache.is_empty()) {
ResourceCache::lock.write_lock();
ResourceCache::resources.erase(path_cache); ResourceCache::resources.erase(path_cache);
ResourceCache::lock.write_unlock();
} }
path_cache = ""; path_cache = "";
ResourceCache::lock.read_lock(); Ref<Resource> existing = ResourceCache::get_ref(p_path);
bool has_path = ResourceCache::resources.has(p_path);
ResourceCache::lock.read_unlock();
if (has_path) { if (existing.is_valid()) {
if (p_take_over) { if (p_take_over) {
ResourceCache::lock.write_lock(); existing->path_cache = String();
Resource **res = ResourceCache::resources.getptr(p_path); ResourceCache::resources.erase(p_path);
if (res) {
(*res)->set_name("");
}
ResourceCache::lock.write_unlock();
} else { } else {
ResourceCache::lock.read_lock(); ResourceCache::lock.unlock();
bool exists = ResourceCache::resources.has(p_path); ERR_FAIL_MSG("Another resource is loaded from path '" + p_path + "' (possible cyclic resource inclusion).");
ResourceCache::lock.read_unlock(); }
}
ERR_FAIL_COND_MSG(exists, "Another resource is loaded from path '" + p_path + "' (possible cyclic resource inclusion).");
}
}
path_cache = p_path; path_cache = p_path;
if (!path_cache.is_empty()) { if (!path_cache.is_empty()) {
ResourceCache::lock.write_lock();
ResourceCache::resources[path_cache] = this; ResourceCache::resources[path_cache] = this;
ResourceCache::lock.write_unlock();
} }
ResourceCache::lock.unlock();
_resource_path_changed(); _resource_path_changed();
} }
@ -380,7 +375,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
return; return;
} }
ResourceCache::lock.write_lock(); ResourceCache::lock.lock();
if (p_remapped) { if (p_remapped) {
ResourceLoader::remapped_list.add(&remapped_list); ResourceLoader::remapped_list.add(&remapped_list);
@ -388,7 +383,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
ResourceLoader::remapped_list.remove(&remapped_list); ResourceLoader::remapped_list.remove(&remapped_list);
} }
ResourceCache::lock.write_unlock(); ResourceCache::lock.unlock();
} }
bool Resource::is_translation_remapped() const { bool Resource::is_translation_remapped() const {
@ -455,9 +450,9 @@ Resource::Resource() :
Resource::~Resource() { Resource::~Resource() {
if (!path_cache.is_empty()) { if (!path_cache.is_empty()) {
ResourceCache::lock.write_lock(); ResourceCache::lock.lock();
ResourceCache::resources.erase(path_cache); ResourceCache::resources.erase(path_cache);
ResourceCache::lock.write_unlock(); ResourceCache::lock.unlock();
} }
if (owners.size()) { if (owners.size()) {
WARN_PRINT("Resource is still owned."); WARN_PRINT("Resource is still owned.");
@ -469,7 +464,7 @@ HashMap<String, Resource *> ResourceCache::resources;
HashMap<String, HashMap<String, String>> ResourceCache::resource_path_cache; HashMap<String, HashMap<String, String>> ResourceCache::resource_path_cache;
#endif #endif
RWLock ResourceCache::lock; Mutex ResourceCache::lock;
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
RWLock ResourceCache::path_cache_lock; RWLock ResourceCache::path_cache_lock;
#endif #endif
@ -491,46 +486,67 @@ void ResourceCache::reload_externals() {
} }
bool ResourceCache::has(const String &p_path) { bool ResourceCache::has(const String &p_path) {
lock.read_lock(); lock.lock();
bool b = resources.has(p_path);
lock.read_unlock();
return b;
}
Resource *ResourceCache::get(const String &p_path) {
lock.read_lock();
Resource **res = resources.getptr(p_path); Resource **res = resources.getptr(p_path);
lock.read_unlock(); if (res && (*res)->reference_get_count() == 0) {
// This resource is in the process of being deleted, ignore its existence.
if (!res) { (*res)->path_cache = String();
return nullptr; resources.erase(p_path);
res = nullptr;
} }
return *res; lock.unlock();
if (!res) {
return false;
}
return true;
}
Ref<Resource> ResourceCache::get_ref(const String &p_path) {
Ref<Resource> ref;
lock.lock();
Resource **res = resources.getptr(p_path);
if (res) {
ref = Ref<Resource>(*res);
}
if (res && !ref.is_valid()) {
// This resource is in the process of being deleted, ignore its existence
(*res)->path_cache = String();
resources.erase(p_path);
res = nullptr;
}
lock.unlock();
return ref;
} }
void ResourceCache::get_cached_resources(List<Ref<Resource>> *p_resources) { void ResourceCache::get_cached_resources(List<Ref<Resource>> *p_resources) {
lock.read_lock(); lock.lock();
for (KeyValue<String, Resource *> &E : resources) { for (KeyValue<String, Resource *> &E : resources) {
p_resources->push_back(Ref<Resource>(E.value)); p_resources->push_back(Ref<Resource>(E.value));
} }
lock.read_unlock(); lock.unlock();
} }
int ResourceCache::get_cached_resource_count() { int ResourceCache::get_cached_resource_count() {
lock.read_lock(); lock.lock();
int rc = resources.size(); int rc = resources.size();
lock.read_unlock(); lock.unlock();
return rc; return rc;
} }
void ResourceCache::dump(const char *p_file, bool p_short) { void ResourceCache::dump(const char *p_file, bool p_short) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
lock.read_lock(); lock.lock();
HashMap<String, int> type_count; HashMap<String, int> type_count;
@ -562,7 +578,7 @@ void ResourceCache::dump(const char *p_file, bool p_short) {
} }
} }
lock.read_unlock(); lock.unlock();
#else #else
WARN_PRINT("ResourceCache::dump only with in debug builds."); WARN_PRINT("ResourceCache::dump only with in debug builds.");
#endif #endif

View File

@ -153,7 +153,7 @@ public:
class ResourceCache { class ResourceCache {
friend class Resource; friend class Resource;
friend class ResourceLoader; //need the lock friend class ResourceLoader; //need the lock
static RWLock lock; static Mutex lock;
static HashMap<String, Resource *> resources; static HashMap<String, Resource *> resources;
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
static HashMap<String, HashMap<String, String>> resource_path_cache; // Each tscn has a set of resource paths and IDs. static HashMap<String, HashMap<String, String>> resource_path_cache; // Each tscn has a set of resource paths and IDs.
@ -166,7 +166,7 @@ class ResourceCache {
public: public:
static void reload_externals(); static void reload_externals();
static bool has(const String &p_path); static bool has(const String &p_path);
static Resource *get(const String &p_path); static Ref<Resource> get_ref(const String &p_path);
static void dump(const char *p_file = nullptr, bool p_short = false); static void dump(const char *p_file = nullptr, bool p_short = false);
static void get_cached_resources(List<Ref<Resource>> *p_resources); static void get_cached_resources(List<Ref<Resource>> *p_resources);
static int get_cached_resource_count(); static int get_cached_resource_count();

View File

@ -693,7 +693,7 @@ Error ResourceLoaderBinary::load() {
} }
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE && ResourceCache::has(path)) { if (cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE && ResourceCache::has(path)) {
Ref<Resource> cached = ResourceCache::get(path); Ref<Resource> cached = ResourceCache::get_ref(path);
if (cached.is_valid()) { if (cached.is_valid()) {
//already loaded, don't do anything //already loaded, don't do anything
error = OK; error = OK;
@ -717,10 +717,10 @@ Error ResourceLoaderBinary::load() {
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) { if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
//use the existing one //use the existing one
Resource *r = ResourceCache::get(path); Ref<Resource> cached = ResourceCache::get_ref(path);
if (r->get_class() == t) { if (cached->get_class() == t) {
r->reset_state(); cached->reset_state();
res = Ref<Resource>(r); res = cached;
} }
} }

View File

@ -335,24 +335,16 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
thread_load_mutex->unlock(); thread_load_mutex->unlock();
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Attempted to load a resource already being loaded from this thread, cyclic reference?"); ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Attempted to load a resource already being loaded from this thread, cyclic reference?");
} }
//lock first if possible
ResourceCache::lock.read_lock();
//get ptr Ref<Resource> existing = ResourceCache::get_ref(local_path);
Resource **rptr = ResourceCache::resources.getptr(local_path);
if (rptr) { if (existing.is_valid()) {
Ref<Resource> res(*rptr);
//it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached
if (res.is_valid()) {
//referencing is fine //referencing is fine
load_task.resource = res; load_task.resource = existing;
load_task.status = THREAD_LOAD_LOADED; load_task.status = THREAD_LOAD_LOADED;
load_task.progress = 1.0; load_task.progress = 1.0;
} }
} }
ResourceCache::lock.read_unlock();
}
if (!p_source_resource.is_empty()) { if (!p_source_resource.is_empty()) {
thread_load_tasks[p_source_resource].sub_tasks.insert(local_path); thread_load_tasks[p_source_resource].sub_tasks.insert(local_path);
@ -530,27 +522,18 @@ Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hi
} }
//Is it cached? //Is it cached?
ResourceCache::lock.read_lock();
Resource **rptr = ResourceCache::resources.getptr(local_path); Ref<Resource> existing = ResourceCache::get_ref(local_path);
if (rptr) { if (existing.is_valid()) {
Ref<Resource> res(*rptr);
//it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached
if (res.is_valid()) {
ResourceCache::lock.read_unlock();
thread_load_mutex->unlock(); thread_load_mutex->unlock();
if (r_error) { if (r_error) {
*r_error = OK; *r_error = OK;
} }
return res; //use cached return existing; //use cached
} }
}
ResourceCache::lock.read_unlock();
//load using task (but this thread) //load using task (but this thread)
ThreadLoadTask load_task; ThreadLoadTask load_task;
@ -867,7 +850,7 @@ String ResourceLoader::path_remap(const String &p_path) {
} }
void ResourceLoader::reload_translation_remaps() { void ResourceLoader::reload_translation_remaps() {
ResourceCache::lock.read_lock(); ResourceCache::lock.lock();
List<Resource *> to_reload; List<Resource *> to_reload;
SelfList<Resource> *E = remapped_list.first(); SelfList<Resource> *E = remapped_list.first();
@ -877,7 +860,7 @@ void ResourceLoader::reload_translation_remaps() {
E = E->next(); E = E->next();
} }
ResourceCache::lock.read_unlock(); ResourceCache::lock.unlock();
//now just make sure to not delete any of these resources while changing locale.. //now just make sure to not delete any of these resources while changing locale..
while (to_reload.front()) { while (to_reload.front()) {

View File

@ -487,7 +487,7 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector<
void DependencyRemoveDialog::ok_pressed() { void DependencyRemoveDialog::ok_pressed() {
for (int i = 0; i < files_to_delete.size(); ++i) { for (int i = 0; i < files_to_delete.size(); ++i) {
if (ResourceCache::has(files_to_delete[i])) { if (ResourceCache::has(files_to_delete[i])) {
Resource *res = ResourceCache::get(files_to_delete[i]); Ref<Resource> res = ResourceCache::get_ref(files_to_delete[i]);
res->set_path(""); res->set_path("");
} }

View File

@ -1792,9 +1792,9 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
//if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it //if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it
//to reload properly //to reload properly
if (ResourceCache::has(file)) { Ref<Resource> r = ResourceCache::get_ref(file);
Resource *r = ResourceCache::get(file);
if (r.is_valid()) {
if (!r->get_import_path().is_empty()) { if (!r->get_import_path().is_empty()) {
String dst_path = ResourceFormatImporter::get_singleton()->get_internal_resource_path(file); String dst_path = ResourceFormatImporter::get_singleton()->get_internal_resource_path(file);
r->set_import_path(dst_path); r->set_import_path(dst_path);
@ -2034,9 +2034,8 @@ void EditorFileSystem::_reimport_file(const String &p_file, const HashMap<String
//if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it //if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it
//to reload properly //to reload properly
if (ResourceCache::has(p_file)) { Ref<Resource> r = ResourceCache::get_ref(p_file);
Resource *r = ResourceCache::get(p_file); if (r.is_valid()) {
if (!r->get_import_path().is_empty()) { if (!r->get_import_path().is_empty()) {
String dst_path = ResourceFormatImporter::get_singleton()->get_internal_resource_path(p_file); String dst_path = ResourceFormatImporter::get_singleton()->get_internal_resource_path(p_file);
r->set_import_path(dst_path); r->set_import_path(dst_path);

View File

@ -193,10 +193,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) {
for (int i = 0; i < res_unfolds.size(); i += 2) { for (int i = 0; i < res_unfolds.size(); i += 2) {
String path2 = res_unfolds[i]; String path2 = res_unfolds[i];
Ref<Resource> res; Ref<Resource> res = ResourceCache::get_ref(path2);
if (ResourceCache::has(path2)) {
res = Ref<Resource>(ResourceCache::get(path2));
}
if (res.is_null()) { if (res.is_null()) {
continue; continue;
} }

View File

@ -875,7 +875,7 @@ void EditorNode::_resources_changed(const Vector<String> &p_resources) {
int rc = p_resources.size(); int rc = p_resources.size();
for (int i = 0; i < rc; i++) { for (int i = 0; i < rc; i++) {
Ref<Resource> res(ResourceCache::get(p_resources.get(i))); Ref<Resource> res = ResourceCache::get_ref(p_resources.get(i));
if (res.is_null()) { if (res.is_null()) {
continue; continue;
} }
@ -1005,8 +1005,8 @@ void EditorNode::_resources_reimported(const Vector<String> &p_resources) {
continue; continue;
} }
// Reload normally. // Reload normally.
Resource *resource = ResourceCache::get(p_resources[i]); Ref<Resource> resource = ResourceCache::get_ref(p_resources[i]);
if (resource) { if (resource.is_valid()) {
resource->reload_from_file(); resource->reload_from_file();
} }
} }
@ -1719,7 +1719,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
// We must update it, but also let the previous scene state go, as // We must update it, but also let the previous scene state go, as
// old version still work for referencing changes in instantiated or inherited scenes. // old version still work for referencing changes in instantiated or inherited scenes.
sdata = Ref<PackedScene>(Object::cast_to<PackedScene>(ResourceCache::get(p_file))); sdata = ResourceCache::get_ref(p_file);
if (sdata.is_valid()) { if (sdata.is_valid()) {
sdata->recreate_state(); sdata->recreate_state();
} else { } else {
@ -3711,7 +3711,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
if (ResourceCache::has(lpath)) { if (ResourceCache::has(lpath)) {
// Used from somewhere else? No problem! Update state and replace sdata. // Used from somewhere else? No problem! Update state and replace sdata.
Ref<PackedScene> ps = Ref<PackedScene>(Object::cast_to<PackedScene>(ResourceCache::get(lpath))); Ref<PackedScene> ps = ResourceCache::get_ref(lpath);
if (ps.is_valid()) { if (ps.is_valid()) {
ps->replace_state(sdata->get_state()); ps->replace_state(sdata->get_state());
ps->set_last_modified_time(sdata->get_last_modified_time()); ps->set_last_modified_time(sdata->get_last_modified_time());

View File

@ -1115,7 +1115,7 @@ Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> ani
} }
if (ResourceCache::has(p_save_to_path)) { if (ResourceCache::has(p_save_to_path)) {
Ref<Animation> old_anim = Ref<Resource>(ResourceCache::get(p_save_to_path)); Ref<Animation> old_anim = ResourceCache::get_ref(p_save_to_path);
if (old_anim.is_valid()) { if (old_anim.is_valid()) {
old_anim->copy_from(anim); old_anim->copy_from(anim);
anim = old_anim; anim = old_anim;
@ -1711,7 +1711,7 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m
} }
if (!save_to_file.is_empty()) { if (!save_to_file.is_empty()) {
Ref<Mesh> existing = Ref<Resource>(ResourceCache::get(save_to_file)); Ref<Mesh> existing = ResourceCache::get_ref(save_to_file);
if (existing.is_valid()) { if (existing.is_valid()) {
//if somehow an existing one is useful, create //if somehow an existing one is useful, create
existing->reset_state(); existing->reset_state();

View File

@ -306,10 +306,8 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
//update cache if existing, else create //update cache if existing, else create
Ref<Texture2D> cache; Ref<Texture2D> cache;
if (ResourceCache::has(p_group_file)) { cache = ResourceCache::get_ref(p_group_file);
Resource *resptr = ResourceCache::get(p_group_file); if (!cache.is_valid()) {
cache.reference_ptr(resptr);
} else {
Ref<ImageTexture> res_cache; Ref<ImageTexture> res_cache;
res_cache.instantiate(); res_cache.instantiate();
res_cache->create_from_image(new_atlas); res_cache->create_from_image(new_atlas);

View File

@ -5455,7 +5455,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
} }
child->set_name(name); child->set_name(name);
Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(ResourceCache::get(path))); Ref<Texture2D> texture = ResourceCache::get_ref(path);
if (parent) { if (parent) {
editor_data->get_undo_redo().add_do_method(parent, "add_child", child, true); editor_data->get_undo_redo().add_do_method(parent, "add_child", child, true);

View File

@ -803,7 +803,7 @@ public:
//if the script is not in use by anyone, we can safely assume whatever we got is not casting to it. //if the script is not in use by anyone, we can safely assume whatever we got is not casting to it.
return 1; return 1;
} }
Ref<Script> cast_script = Ref<Resource>(ResourceCache::get(script)); Ref<Script> cast_script = ResourceCache::get_ref(script);
if (!cast_script.is_valid()) { if (!cast_script.is_valid()) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str = "Script path is not a script: " + script; r_error_str = "Script path is not a script: " + script;

View File

@ -377,7 +377,7 @@ void VisualScriptFunctionCall::_update_method_cache() {
} }
if (ResourceCache::has(base_script)) { if (ResourceCache::has(base_script)) {
script = Ref<Resource>(ResourceCache::get(base_script)); script = ResourceCache::get_ref(base_script);
} else { } else {
return; return;
} }
@ -587,7 +587,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const
} }
if (ResourceCache::has(base_script)) { if (ResourceCache::has(base_script)) {
Ref<Script> script = Ref<Resource>(ResourceCache::get(base_script)); Ref<Script> script = ResourceCache::get_ref(base_script);
if (script.is_valid()) { if (script.is_valid()) {
property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT; property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT;
property.hint_string = itos(script->get_instance_id()); property.hint_string = itos(script->get_instance_id());
@ -1178,7 +1178,7 @@ void VisualScriptPropertySet::_update_cache() {
} }
if (ResourceCache::has(base_script)) { if (ResourceCache::has(base_script)) {
script = Ref<Resource>(ResourceCache::get(base_script)); script = ResourceCache::get_ref(base_script);
} else { } else {
return; return;
} }
@ -1338,7 +1338,7 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const {
} }
if (ResourceCache::has(base_script)) { if (ResourceCache::has(base_script)) {
Ref<Script> script = Ref<Resource>(ResourceCache::get(base_script)); Ref<Script> script = ResourceCache::get_ref(base_script);
if (script.is_valid()) { if (script.is_valid()) {
property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT;
property.hint_string = itos(script->get_instance_id()); property.hint_string = itos(script->get_instance_id());
@ -1864,7 +1864,7 @@ void VisualScriptPropertyGet::_update_cache() {
} }
if (ResourceCache::has(base_script)) { if (ResourceCache::has(base_script)) {
script = Ref<Resource>(ResourceCache::get(base_script)); script = ResourceCache::get_ref(base_script);
} else { } else {
return; return;
} }
@ -2044,7 +2044,7 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const {
} }
if (ResourceCache::has(base_script)) { if (ResourceCache::has(base_script)) {
Ref<Script> script = Ref<Resource>(ResourceCache::get(base_script)); Ref<Script> script = ResourceCache::get_ref(base_script);
if (script.is_valid()) { if (script.is_valid()) {
property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT;
property.hint_string = itos(script->get_instance_id()); property.hint_string = itos(script->get_instance_id());

View File

@ -701,7 +701,7 @@ void LiveEditor::_res_set_func(int p_id, const StringName &p_prop, const Variant
return; return;
} }
Ref<Resource> r = ResourceCache::get(resp); Ref<Resource> r = ResourceCache::get_ref(resp);
if (!r.is_valid()) { if (!r.is_valid()) {
return; return;
} }
@ -728,7 +728,7 @@ void LiveEditor::_res_call_func(int p_id, const StringName &p_method, const Vari
return; return;
} }
Ref<Resource> r = ResourceCache::get(resp); Ref<Resource> r = ResourceCache::get_ref(resp);
if (!r.is_valid()) { if (!r.is_valid()) {
return; return;
} }

View File

@ -528,9 +528,9 @@ Error ResourceLoaderText::load() {
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) { if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
//reuse existing //reuse existing
Resource *r = ResourceCache::get(path); Ref<Resource> cache = ResourceCache::get_ref(path);
if (r && r->get_class() == type) { if (cache.is_valid() && cache->get_class() == type) {
res = Ref<Resource>(r); res = cache;
res->reset_state(); res->reset_state();
do_assign = true; do_assign = true;
} }
@ -539,10 +539,10 @@ Error ResourceLoaderText::load() {
MissingResource *missing_resource = nullptr; MissingResource *missing_resource = nullptr;
if (res.is_null()) { //not reuse if (res.is_null()) { //not reuse
if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && ResourceCache::has(path)) { //only if it doesn't exist Ref<Resource> cache = ResourceCache::get_ref(path);
if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && cache.is_valid()) { //only if it doesn't exist
//cached, do not assign //cached, do not assign
Resource *r = ResourceCache::get(path); res = cache;
res = Ref<Resource>(r);
} else { } else {
//create //create
@ -652,12 +652,10 @@ Error ResourceLoaderText::load() {
return error; return error;
} }
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(local_path)) { Ref<Resource> cache = ResourceCache::get_ref(local_path);
Resource *r = ResourceCache::get(local_path); if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && cache.is_valid() && cache->get_class() == res_type) {
if (r->get_class() == res_type) { cache->reset_state();
r->reset_state(); resource = cache;
resource = Ref<Resource>(r);
}
} }
MissingResource *missing_resource = nullptr; MissingResource *missing_resource = nullptr;