diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/io/missing_resource.cpp | 90 | ||||
-rw-r--r-- | core/io/missing_resource.h | 63 | ||||
-rw-r--r-- | core/io/resource_format_binary.cpp | 72 | ||||
-rw-r--r-- | core/io/resource_loader.cpp | 5 | ||||
-rw-r--r-- | core/io/resource_loader.h | 4 | ||||
-rw-r--r-- | core/object/object.cpp | 35 | ||||
-rw-r--r-- | core/register_core_types.cpp | 2 |
7 files changed, 247 insertions, 24 deletions
diff --git a/core/io/missing_resource.cpp b/core/io/missing_resource.cpp new file mode 100644 index 0000000000..7aae6c6f0a --- /dev/null +++ b/core/io/missing_resource.cpp @@ -0,0 +1,90 @@ +/*************************************************************************/ +/* missing_resource.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "missing_resource.h" + +bool MissingResource::_set(const StringName &p_name, const Variant &p_value) { + if (is_recording_properties()) { + properties.insert(p_name, p_value); + return true; //always valid to set (add) + } else { + if (!properties.has(p_name)) { + return false; + } + + properties[p_name] = p_value; + return true; + } +} + +bool MissingResource::_get(const StringName &p_name, Variant &r_ret) const { + if (!properties.has(p_name)) { + return false; + } + r_ret = properties[p_name]; + return true; +} + +void MissingResource::_get_property_list(List<PropertyInfo> *p_list) const { + for (OrderedHashMap<StringName, Variant>::ConstElement E = properties.front(); E; E = E.next()) { + p_list->push_back(PropertyInfo(E.value().get_type(), E.key())); + } +} + +void MissingResource::set_original_class(const String &p_class) { + original_class = p_class; +} + +String MissingResource::get_original_class() const { + return original_class; +} + +void MissingResource::set_recording_properties(bool p_enable) { + recording_properties = p_enable; +} + +bool MissingResource::is_recording_properties() const { + return recording_properties; +} + +void MissingResource::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_original_class", "name"), &MissingResource::set_original_class); + ClassDB::bind_method(D_METHOD("get_original_class"), &MissingResource::get_original_class); + + ClassDB::bind_method(D_METHOD("set_recording_properties", "enable"), &MissingResource::set_recording_properties); + ClassDB::bind_method(D_METHOD("is_recording_properties"), &MissingResource::is_recording_properties); + + // Expose, but not save. + ADD_PROPERTY(PropertyInfo(Variant::STRING, "original_class", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_original_class", "get_original_class"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "recording_properties", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_recording_properties", "is_recording_properties"); +} + +MissingResource::MissingResource() { +} diff --git a/core/io/missing_resource.h b/core/io/missing_resource.h new file mode 100644 index 0000000000..e87efe1a98 --- /dev/null +++ b/core/io/missing_resource.h @@ -0,0 +1,63 @@ +/*************************************************************************/ +/* missing_resource.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef MISSING_RESOURCE_H +#define MISSING_RESOURCE_H + +#include "core/io/resource.h" + +#define META_PROPERTY_MISSING_RESOURCES "metadata/_missing_resources" +#define META_MISSING_RESOURCES "_missing_resources" + +class MissingResource : public Resource { + GDCLASS(MissingResource, Resource) + OrderedHashMap<StringName, Variant> properties; + + String original_class; + bool recording_properties = false; + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + static void _bind_methods(); + +public: + void set_original_class(const String &p_class); + String get_original_class() const; + + void set_recording_properties(bool p_enable); + bool is_recording_properties() const; + + MissingResource(); +}; + +#endif // MISSING_RESOURCE_H diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index c9eb0e5234..fbb4293961 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -35,6 +35,7 @@ #include "core/io/file_access_compressed.h" #include "core/io/image.h" #include "core/io/marshalls.h" +#include "core/io/missing_resource.h" #include "core/version.h" //#define print_bl(m_what) print_line(m_what) @@ -728,13 +729,23 @@ Error ResourceLoaderBinary::load() { } } + MissingResource *missing_resource = nullptr; + if (res.is_null()) { //did not replace Object *obj = ClassDB::instantiate(t); if (!obj) { - error = ERR_FILE_CORRUPT; - ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + "."); + if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) { + //create a missing resource + missing_resource = memnew(MissingResource); + missing_resource->set_original_class(t); + missing_resource->set_recording_properties(true); + obj = missing_resource; + } else { + error = ERR_FILE_CORRUPT; + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + "."); + } } Resource *r = Object::cast_to<Resource>(obj); @@ -760,6 +771,8 @@ Error ResourceLoaderBinary::load() { //set properties + Dictionary missing_resource_properties; + for (int j = 0; j < pc; j++) { StringName name = _get_string(); @@ -775,8 +788,32 @@ Error ResourceLoaderBinary::load() { return error; } - res->set(name, value); + bool set_valid = true; + if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) { + // If the property being set is a missing resource (and the parent is not), + // then setting it will most likely not work. + // Instead, save it as metadata. + + Ref<MissingResource> mr = value; + if (mr.is_valid()) { + missing_resource_properties[name] = mr; + set_valid = false; + } + } + + if (set_valid) { + res->set(name, value); + } + } + + if (missing_resource) { + missing_resource->set_recording_properties(false); + } + + if (!missing_resource_properties.is_empty()) { + res->set_meta(META_MISSING_RESOURCES, missing_resource_properties); } + #ifdef TOOLS_ENABLED res->set_edited(false); #endif @@ -1833,6 +1870,15 @@ int ResourceFormatSaverBinaryInstance::get_string_index(const String &p_string) return strings.size() - 1; } +static String _resource_get_class(Ref<Resource> p_resource) { + Ref<MissingResource> missing_resource = p_resource; + if (missing_resource.is_valid()) { + return missing_resource->get_original_class(); + } else { + return p_resource->get_class(); + } +} + Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) { Error err; Ref<FileAccess> f; @@ -1885,7 +1931,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re return ERR_CANT_CREATE; } - save_unicode_string(f, p_resource->get_class()); + save_unicode_string(f, _resource_get_class(p_resource)); f->store_64(0); //offset to import metadata { uint32_t format_flags = FORMAT_FLAG_NAMED_SCENE_IDS | FORMAT_FLAG_UIDS; @@ -1902,10 +1948,12 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re List<ResourceData> resources; + Dictionary missing_resource_properties = p_resource->get_meta(META_MISSING_RESOURCES, Dictionary()); + { for (const Ref<Resource> &E : saved_resources) { ResourceData &rd = resources.push_back(ResourceData())->get(); - rd.type = E->get_class(); + rd.type = _resource_get_class(E); List<PropertyInfo> property_list; E->get_property_list(&property_list); @@ -1914,6 +1962,10 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re if (skip_editor && F.name.begins_with("__editor")) { continue; } + if (F.name == META_PROPERTY_MISSING_RESOURCES) { + continue; + } + if ((F.usage & PROPERTY_USAGE_STORAGE)) { Property p; p.name_idx = get_string_index(F.name); @@ -1929,6 +1981,14 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re p.value = E->get(F.name); } + if (p.pi.type == Variant::OBJECT && missing_resource_properties.has(F.name)) { + // Was this missing resource overriden? If so do not save the old value. + Ref<Resource> res = p.value; + if (res.is_null()) { + p.value = missing_resource_properties[F.name]; + } + } + Variant default_value = ClassDB::class_get_default_property_value(E->get_class(), F.name); if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, p.value, default_value))) { @@ -1990,7 +2050,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re String new_id; while (true) { - new_id = r->get_class() + "_" + Resource::generate_scene_unique_id(); + new_id = _resource_get_class(r) + "_" + Resource::generate_scene_unique_id(); if (!used_unique_ids.has(new_id)) { break; } diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index c8cebd672a..d125dd4e91 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -979,6 +979,10 @@ void ResourceLoader::remove_custom_resource_format_loader(String script_path) { } } +void ResourceLoader::set_create_missing_resources_if_class_unavailable(bool p_enable) { + create_missing_resources_if_class_unavailable = p_enable; +} + void ResourceLoader::add_custom_loaders() { // Custom loaders registration exploits global class names @@ -1030,6 +1034,7 @@ void *ResourceLoader::err_notify_ud = nullptr; DependencyErrorNotify ResourceLoader::dep_err_notify = nullptr; void *ResourceLoader::dep_err_notify_ud = nullptr; +bool ResourceLoader::create_missing_resources_if_class_unavailable = false; bool ResourceLoader::abort_on_missing_resource = true; bool ResourceLoader::timestamp_on_load = false; diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 15ecfacf4a..ea18ac23fd 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -110,6 +110,7 @@ private: static void *dep_err_notify_ud; static DependencyErrorNotify dep_err_notify; static bool abort_on_missing_resource; + static bool create_missing_resources_if_class_unavailable; static HashMap<String, Vector<String>> translation_remaps; static HashMap<String, String> path_remaps; @@ -222,6 +223,9 @@ public: static void add_custom_loaders(); static void remove_custom_loaders(); + static void set_create_missing_resources_if_class_unavailable(bool p_enable); + _FORCE_INLINE_ static bool is_creating_missing_resources_if_class_unavailable_enabled() { return create_missing_resources_if_class_unavailable; } + static void initialize(); static void finalize(); }; diff --git a/core/object/object.cpp b/core/object/object.cpp index 1defd85a14..2b62041533 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -434,15 +434,6 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid } } - // Something inside the object... :| - bool success = _setv(p_name, p_value); - if (success) { - if (r_valid) { - *r_valid = true; - } - return; - } - #ifdef TOOLS_ENABLED if (script_instance) { bool valid; @@ -456,6 +447,15 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid } #endif + // Something inside the object... :| + bool success = _setv(p_name, p_value); + if (success) { + if (r_valid) { + *r_valid = true; + } + return; + } + if (r_valid) { *r_valid = false; } @@ -518,15 +518,6 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { return ret; } else { - // Something inside the object... :| - bool success = _getv(p_name, ret); - if (success) { - if (r_valid) { - *r_valid = true; - } - return ret; - } - #ifdef TOOLS_ENABLED if (script_instance) { bool valid; @@ -539,6 +530,14 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { } } #endif + // Something inside the object... :| + bool success = _getv(p_name, ret); + if (success) { + if (r_valid) { + *r_valid = true; + } + return ret; + } if (r_valid) { *r_valid = false; diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 415b56cd83..e60d325f74 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -49,6 +49,7 @@ #include "core/io/image_loader.h" #include "core/io/json.h" #include "core/io/marshalls.h" +#include "core/io/missing_resource.h" #include "core/io/packed_data_container.h" #include "core/io/packet_peer.h" #include "core/io/packet_peer_dtls.h" @@ -151,6 +152,7 @@ void register_core_types() { GDREGISTER_CLASS(RefCounted); GDREGISTER_CLASS(WeakRef); GDREGISTER_CLASS(Resource); + GDREGISTER_VIRTUAL_CLASS(MissingResource); GDREGISTER_CLASS(Image); GDREGISTER_CLASS(Shortcut); |