mirror of https://github.com/godotengine/godot
Avoid cyclic resource loading of any type, fixes #22673
This commit is contained in:
parent
0d438c7b18
commit
11642b92d1
|
|
@ -53,6 +53,12 @@ Error ResourceInteractiveLoader::wait() {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResourceInteractiveLoader::~ResourceInteractiveLoader() {
|
||||||
|
if (path_loading != String()) {
|
||||||
|
ResourceLoader::_remove_from_loading_map(path_loading);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_for_type) const {
|
bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_for_type) const {
|
||||||
|
|
||||||
String extension = p_path.get_extension();
|
String extension = p_path.get_extension();
|
||||||
|
|
@ -280,6 +286,39 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
|
||||||
return RES();
|
return RES();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ResourceLoader::_add_to_loading_map(const String &p_path) {
|
||||||
|
|
||||||
|
bool success;
|
||||||
|
if (loading_map_mutex) {
|
||||||
|
loading_map_mutex->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading_map.has(p_path)) {
|
||||||
|
success = false;
|
||||||
|
} else {
|
||||||
|
loading_map[p_path] = true;
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading_map_mutex) {
|
||||||
|
loading_map_mutex->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceLoader::_remove_from_loading_map(const String &p_path) {
|
||||||
|
if (loading_map_mutex) {
|
||||||
|
loading_map_mutex->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
loading_map.erase(p_path);
|
||||||
|
|
||||||
|
if (loading_map_mutex) {
|
||||||
|
loading_map_mutex->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) {
|
RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) {
|
||||||
|
|
||||||
if (r_error)
|
if (r_error)
|
||||||
|
|
@ -292,6 +331,15 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
|
||||||
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||||
|
|
||||||
if (!p_no_cache) {
|
if (!p_no_cache) {
|
||||||
|
|
||||||
|
{
|
||||||
|
bool success = _add_to_loading_map(local_path);
|
||||||
|
if (!success) {
|
||||||
|
ERR_EXPLAIN("Resource: '" + local_path + "' is already being loaded. Cyclic reference?");
|
||||||
|
ERR_FAIL_V(RES());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//lock first if possible
|
//lock first if possible
|
||||||
if (ResourceCache::lock) {
|
if (ResourceCache::lock) {
|
||||||
ResourceCache::lock->read_lock();
|
ResourceCache::lock->read_lock();
|
||||||
|
|
@ -310,7 +358,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
|
||||||
if (ResourceCache::lock) {
|
if (ResourceCache::lock) {
|
||||||
ResourceCache::lock->read_unlock();
|
ResourceCache::lock->read_unlock();
|
||||||
}
|
}
|
||||||
print_verbose("Loading resource: " + local_path + " (cached)");
|
_remove_from_loading_map(local_path);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -322,12 +370,21 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
|
||||||
bool xl_remapped = false;
|
bool xl_remapped = false;
|
||||||
String path = _path_remap(local_path, &xl_remapped);
|
String path = _path_remap(local_path, &xl_remapped);
|
||||||
|
|
||||||
ERR_FAIL_COND_V(path == "", RES());
|
if (path == "") {
|
||||||
|
if (!p_no_cache) {
|
||||||
|
_remove_from_loading_map(local_path);
|
||||||
|
}
|
||||||
|
ERR_EXPLAIN("Remapping '" + local_path + "'failed.");
|
||||||
|
ERR_FAIL_V(RES());
|
||||||
|
}
|
||||||
|
|
||||||
print_verbose("Loading resource: " + path);
|
print_verbose("Loading resource: " + path);
|
||||||
RES res = _load(path, local_path, p_type_hint, p_no_cache, r_error);
|
RES res = _load(path, local_path, p_type_hint, p_no_cache, r_error);
|
||||||
|
|
||||||
if (res.is_null()) {
|
if (res.is_null()) {
|
||||||
|
if (!p_no_cache) {
|
||||||
|
_remove_from_loading_map(local_path);
|
||||||
|
}
|
||||||
return RES();
|
return RES();
|
||||||
}
|
}
|
||||||
if (!p_no_cache)
|
if (!p_no_cache)
|
||||||
|
|
@ -346,6 +403,10 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!p_no_cache) {
|
||||||
|
_remove_from_loading_map(local_path);
|
||||||
|
}
|
||||||
|
|
||||||
if (_loaded_callback) {
|
if (_loaded_callback) {
|
||||||
_loaded_callback(res, p_path);
|
_loaded_callback(res, p_path);
|
||||||
}
|
}
|
||||||
|
|
@ -394,19 +455,36 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
|
||||||
else
|
else
|
||||||
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||||
|
|
||||||
if (!p_no_cache && ResourceCache::has(local_path)) {
|
if (!p_no_cache) {
|
||||||
|
|
||||||
print_verbose("Loading resource: " + local_path + " (cached)");
|
bool success = _add_to_loading_map(local_path);
|
||||||
Ref<Resource> res_cached = ResourceCache::get(local_path);
|
if (!success) {
|
||||||
Ref<ResourceInteractiveLoaderDefault> ril = Ref<ResourceInteractiveLoaderDefault>(memnew(ResourceInteractiveLoaderDefault));
|
ERR_EXPLAIN("Resource: '" + local_path + "' is already being loaded. Cyclic reference?");
|
||||||
|
ERR_FAIL_V(RES());
|
||||||
|
}
|
||||||
|
|
||||||
ril->resource = res_cached;
|
if (ResourceCache::has(local_path)) {
|
||||||
return ril;
|
|
||||||
|
print_verbose("Loading resource: " + local_path + " (cached)");
|
||||||
|
Ref<Resource> res_cached = ResourceCache::get(local_path);
|
||||||
|
Ref<ResourceInteractiveLoaderDefault> ril = Ref<ResourceInteractiveLoaderDefault>(memnew(ResourceInteractiveLoaderDefault));
|
||||||
|
|
||||||
|
ril->resource = res_cached;
|
||||||
|
ril->path_loading = local_path;
|
||||||
|
return ril;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool xl_remapped = false;
|
bool xl_remapped = false;
|
||||||
String path = _path_remap(local_path, &xl_remapped);
|
String path = _path_remap(local_path, &xl_remapped);
|
||||||
ERR_FAIL_COND_V(path == "", Ref<ResourceInteractiveLoader>());
|
if (path == "") {
|
||||||
|
if (!p_no_cache) {
|
||||||
|
_remove_from_loading_map(local_path);
|
||||||
|
}
|
||||||
|
ERR_EXPLAIN("Remapping '" + local_path + "'failed.");
|
||||||
|
ERR_FAIL_V(RES());
|
||||||
|
}
|
||||||
|
|
||||||
print_verbose("Loading resource: " + path);
|
print_verbose("Loading resource: " + path);
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
@ -418,14 +496,21 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
|
||||||
Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(path, local_path, r_error);
|
Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(path, local_path, r_error);
|
||||||
if (ril.is_null())
|
if (ril.is_null())
|
||||||
continue;
|
continue;
|
||||||
if (!p_no_cache)
|
if (!p_no_cache) {
|
||||||
ril->set_local_path(local_path);
|
ril->set_local_path(local_path);
|
||||||
|
ril->path_loading = local_path;
|
||||||
|
}
|
||||||
|
|
||||||
if (xl_remapped)
|
if (xl_remapped)
|
||||||
ril->set_translation_remapped(true);
|
ril->set_translation_remapped(true);
|
||||||
|
|
||||||
return ril;
|
return ril;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!p_no_cache) {
|
||||||
|
_remove_from_loading_map(local_path);
|
||||||
|
}
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
ERR_EXPLAIN("Failed loading resource: " + path);
|
ERR_EXPLAIN("Failed loading resource: " + path);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -833,6 +918,27 @@ void ResourceLoader::remove_custom_loaders() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Mutex *ResourceLoader::loading_map_mutex = NULL;
|
||||||
|
HashMap<String, int> ResourceLoader::loading_map;
|
||||||
|
|
||||||
|
void ResourceLoader::initialize() {
|
||||||
|
#ifndef NO_THREADS
|
||||||
|
loading_map_mutex = Mutex::create();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceLoader::finalize() {
|
||||||
|
#ifndef NO_THREADS
|
||||||
|
const String *K = NULL;
|
||||||
|
while ((K = loading_map.next(K))) {
|
||||||
|
ERR_PRINTS("Exited while resource is being loaded: " + *K);
|
||||||
|
}
|
||||||
|
loading_map.clear();
|
||||||
|
memdelete(loading_map_mutex);
|
||||||
|
loading_map_mutex = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
ResourceLoadErrorNotify ResourceLoader::err_notify = NULL;
|
ResourceLoadErrorNotify ResourceLoader::err_notify = NULL;
|
||||||
void *ResourceLoader::err_notify_ud = NULL;
|
void *ResourceLoader::err_notify_ud = NULL;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@
|
||||||
class ResourceInteractiveLoader : public Reference {
|
class ResourceInteractiveLoader : public Reference {
|
||||||
|
|
||||||
GDCLASS(ResourceInteractiveLoader, Reference);
|
GDCLASS(ResourceInteractiveLoader, Reference);
|
||||||
|
friend class ResourceLoader;
|
||||||
|
String path_loading;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
@ -54,6 +56,7 @@ public:
|
||||||
virtual Error wait();
|
virtual Error wait();
|
||||||
|
|
||||||
ResourceInteractiveLoader() {}
|
ResourceInteractiveLoader() {}
|
||||||
|
~ResourceInteractiveLoader();
|
||||||
};
|
};
|
||||||
|
|
||||||
class ResourceFormatLoader : public Reference {
|
class ResourceFormatLoader : public Reference {
|
||||||
|
|
@ -110,12 +113,18 @@ class ResourceLoader {
|
||||||
static SelfList<Resource>::List remapped_list;
|
static SelfList<Resource>::List remapped_list;
|
||||||
|
|
||||||
friend class ResourceFormatImporter;
|
friend class ResourceFormatImporter;
|
||||||
|
friend class ResourceInteractiveLoader;
|
||||||
//internal load function
|
//internal load function
|
||||||
static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error);
|
static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error);
|
||||||
|
|
||||||
static ResourceLoadedCallback _loaded_callback;
|
static ResourceLoadedCallback _loaded_callback;
|
||||||
|
|
||||||
static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(String path);
|
static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(String path);
|
||||||
|
static Mutex *loading_map_mutex;
|
||||||
|
static HashMap<String, int> loading_map;
|
||||||
|
|
||||||
|
static bool _add_to_loading_map(const String &p_path);
|
||||||
|
static void _remove_from_loading_map(const String &p_path);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL);
|
static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL);
|
||||||
|
|
@ -170,6 +179,9 @@ public:
|
||||||
static void remove_custom_resource_format_loader(String script_path);
|
static void remove_custom_resource_format_loader(String script_path);
|
||||||
static void add_custom_loaders();
|
static void add_custom_loaders();
|
||||||
static void remove_custom_loaders();
|
static void remove_custom_loaders();
|
||||||
|
|
||||||
|
static void initialize();
|
||||||
|
static void finalize();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ void register_core_types() {
|
||||||
_global_mutex = Mutex::create();
|
_global_mutex = Mutex::create();
|
||||||
|
|
||||||
StringName::setup();
|
StringName::setup();
|
||||||
|
ResourceLoader::initialize();
|
||||||
|
|
||||||
register_global_constants();
|
register_global_constants();
|
||||||
register_variant_methods();
|
register_variant_methods();
|
||||||
|
|
@ -269,6 +270,8 @@ void unregister_core_types() {
|
||||||
if (ip)
|
if (ip)
|
||||||
memdelete(ip);
|
memdelete(ip);
|
||||||
|
|
||||||
|
ResourceLoader::finalize();
|
||||||
|
|
||||||
ObjectDB::cleanup();
|
ObjectDB::cleanup();
|
||||||
|
|
||||||
unregister_variant_methods();
|
unregister_variant_methods();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue