summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/project_settings.cpp11
-rw-r--r--core/config/project_settings.h4
-rw-r--r--core/core_bind.cpp16
-rw-r--r--core/core_bind.h10
-rw-r--r--core/core_string_names.cpp3
-rw-r--r--core/core_string_names.h1
-rw-r--r--core/crypto/crypto.cpp2
-rw-r--r--core/crypto/crypto.h2
-rw-r--r--core/io/image.cpp22
-rw-r--r--core/io/image.h2
-rw-r--r--core/io/image_loader.cpp2
-rw-r--r--core/io/image_loader.h2
-rw-r--r--core/io/logger.cpp4
-rw-r--r--core/io/resource.cpp37
-rw-r--r--core/io/resource.h2
-rw-r--r--core/io/resource_format_binary.cpp69
-rw-r--r--core/io/resource_format_binary.h4
-rw-r--r--core/io/resource_importer.cpp4
-rw-r--r--core/io/resource_importer.h2
-rw-r--r--core/io/resource_loader.cpp22
-rw-r--r--core/io/resource_loader.h16
-rw-r--r--core/io/translation_loader_po.cpp2
-rw-r--r--core/io/translation_loader_po.h2
-rw-r--r--core/math/geometry_3d.h33
-rw-r--r--core/object/object.cpp24
-rw-r--r--core/object/object.h20
-rw-r--r--core/object/script_language.cpp10
-rw-r--r--core/string/ustring.cpp33
-rw-r--r--core/templates/command_queue_mt.h5
-rw-r--r--core/templates/rid_owner.h91
30 files changed, 308 insertions, 149 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 70e8133eaa..b4ca31d77a 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -597,6 +597,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
// If we're loading a project.godot from source code, we can operate some
// ProjectSettings conversions if need be.
_convert_to_last_version(config_version);
+ last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
return OK;
} else if (err != OK) {
ERR_PRINT("Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted.");
@@ -676,7 +677,11 @@ void ProjectSettings::clear(const String &p_name) {
}
Error ProjectSettings::save() {
- return save_custom(get_resource_path().plus_file("project.godot"));
+ Error error = save_custom(get_resource_path().plus_file("project.godot"));
+ if (error == OK) {
+ last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+ }
+ return error;
}
Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
@@ -1239,8 +1244,8 @@ ProjectSettings::ProjectSettings() {
custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor");
custom_prop_info["rendering/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
- custom_prop_info["physics/2d/thread_model"] = PropertyInfo(Variant::INT, "physics/2d/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
- custom_prop_info["rendering/quality/intended_usage/framebuffer_allocation"] = PropertyInfo(Variant::INT, "rendering/quality/intended_usage/framebuffer_allocation", PROPERTY_HINT_ENUM, "2D,2D Without Sampling,3D,3D Without Effects");
+ GLOBAL_DEF("physics/2d/run_on_thread", false);
+ GLOBAL_DEF("physics/3d/run_on_thread", false);
GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1");
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index 59c56c23c2..645506f302 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -78,6 +78,8 @@ protected:
int last_order = NO_BUILTIN_ORDER_BASE;
int last_builtin_order = 0;
+ uint64_t last_save_time = 0;
+
Map<StringName, VariantContainer> props;
String resource_path;
Map<StringName, PropertyInfo> custom_prop_info;
@@ -113,7 +115,6 @@ protected:
Error _setup(const String &p_path, const String &p_main_pack, bool p_upwards = false);
-protected:
static void _bind_methods();
public:
@@ -150,6 +151,7 @@ public:
Error save();
void set_custom_property_info(const String &p_prop, const PropertyInfo &p_info);
const Map<StringName, PropertyInfo> &get_custom_property_info() const;
+ uint64_t get_last_saved_time() { return last_save_time; }
Vector<String> get_optimizer_presets() const;
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 456a97e5e5..dd99c32fa8 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -86,9 +86,9 @@ RES _ResourceLoader::load_threaded_get(const String &p_path) {
return res;
}
-RES _ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache) {
+RES _ResourceLoader::load(const String &p_path, const String &p_type_hint, CacheMode p_cache_mode) {
Error err = OK;
- RES ret = ResourceLoader::load(p_path, p_type_hint, p_no_cache, &err);
+ RES ret = ResourceLoader::load(p_path, p_type_hint, ResourceFormatLoader::CacheMode(p_cache_mode), &err);
ERR_FAIL_COND_V_MSG(err != OK, ret, "Error loading resource: '" + p_path + "'.");
return ret;
@@ -135,7 +135,7 @@ void _ResourceLoader::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_threaded_get_status", "path", "progress"), &_ResourceLoader::load_threaded_get_status, DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("load_threaded_get", "path"), &_ResourceLoader::load_threaded_get);
- ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "no_cache"), &_ResourceLoader::load, DEFVAL(""), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "no_cache"), &_ResourceLoader::load, DEFVAL(""), DEFVAL(CACHE_MODE_REUSE));
ClassDB::bind_method(D_METHOD("get_recognized_extensions_for_type", "type"), &_ResourceLoader::get_recognized_extensions_for_type);
ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &_ResourceLoader::set_abort_on_missing_resources);
ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &_ResourceLoader::get_dependencies);
@@ -146,6 +146,10 @@ void _ResourceLoader::_bind_methods() {
BIND_ENUM_CONSTANT(THREAD_LOAD_IN_PROGRESS);
BIND_ENUM_CONSTANT(THREAD_LOAD_FAILED);
BIND_ENUM_CONSTANT(THREAD_LOAD_LOADED);
+
+ BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE);
+ BIND_ENUM_CONSTANT(CACHE_MODE_REUSE);
+ BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE);
}
////// _ResourceSaver //////
@@ -1250,6 +1254,11 @@ Error _File::open(const String &p_path, ModeFlags p_mode_flags) {
return err;
}
+void _File::flush() {
+ ERR_FAIL_COND_MSG(!f, "File must be opened before flushing.");
+ f->flush();
+}
+
void _File::close() {
if (f) {
memdelete(f);
@@ -1543,6 +1552,7 @@ void _File::_bind_methods() {
ClassDB::bind_method(D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &_File::open_compressed, DEFVAL(0));
ClassDB::bind_method(D_METHOD("open", "path", "flags"), &_File::open);
+ ClassDB::bind_method(D_METHOD("flush"), &_File::flush);
ClassDB::bind_method(D_METHOD("close"), &_File::close);
ClassDB::bind_method(D_METHOD("get_path"), &_File::get_path);
ClassDB::bind_method(D_METHOD("get_path_absolute"), &_File::get_path_absolute);
diff --git a/core/core_bind.h b/core/core_bind.h
index 3305c93089..7f945a9314 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -56,13 +56,19 @@ public:
THREAD_LOAD_LOADED
};
+ enum CacheMode {
+ CACHE_MODE_IGNORE, //resource and subresources do not use path cache, no path is set into resource.
+ CACHE_MODE_REUSE, //resource and subresources use patch cache, reuse existing loaded resources instead of loading from disk when available
+ CACHE_MODE_REPLACE, //resource and and subresource use path cache, but replace existing loaded resources when available with information from disk
+ };
+
static _ResourceLoader *get_singleton() { return singleton; }
Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false);
ThreadLoadStatus load_threaded_get_status(const String &p_path, Array r_progress = Array());
RES load_threaded_get(const String &p_path);
- RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false);
+ RES load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE);
Vector<String> get_recognized_extensions_for_type(const String &p_type);
void set_abort_on_missing_resources(bool p_abort);
PackedStringArray get_dependencies(const String &p_path);
@@ -73,6 +79,7 @@ public:
};
VARIANT_ENUM_CAST(_ResourceLoader::ThreadLoadStatus);
+VARIANT_ENUM_CAST(_ResourceLoader::CacheMode);
class _ResourceSaver : public Object {
GDCLASS(_ResourceSaver, Object);
@@ -379,6 +386,7 @@ public:
Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
Error open(const String &p_path, ModeFlags p_mode_flags); // open a file.
+ void flush(); // Flush a file (write its buffer to disk).
void close(); // Close a file.
bool is_open() const; // True when file is open.
diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp
index 18ac2a2d43..ff8569e45d 100644
--- a/core/core_string_names.cpp
+++ b/core/core_string_names.cpp
@@ -76,5 +76,6 @@ CoreStringNames::CoreStringNames() :
bind(StaticCString::create("bind")),
unbind(StaticCString::create("unbind")),
emit(StaticCString::create("emit")),
- notification(StaticCString::create("notification")) {
+ notification(StaticCString::create("notification")),
+ property_list_changed(StaticCString::create("property_list_changed")) {
}
diff --git a/core/core_string_names.h b/core/core_string_names.h
index b4e386f3bc..abe751372e 100644
--- a/core/core_string_names.h
+++ b/core/core_string_names.h
@@ -96,6 +96,7 @@ public:
StringName unbind;
StringName emit;
StringName notification;
+ StringName property_list_changed;
};
#endif // CORE_STRING_NAMES_H
diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp
index 99f4fb232d..f43f3e3290 100644
--- a/core/crypto/crypto.cpp
+++ b/core/crypto/crypto.cpp
@@ -141,7 +141,7 @@ void Crypto::_bind_methods() {
/// Resource loader/saver
-RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
String el = p_path.get_extension().to_lower();
if (el == "crt") {
X509Certificate *cert = X509Certificate::create();
diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h
index 30d2129e3d..9438fcfea5 100644
--- a/core/crypto/crypto.h
+++ b/core/crypto/crypto.h
@@ -116,7 +116,7 @@ public:
class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 986c29b539..5d46d75efe 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -2985,6 +2985,26 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) {
_set_color_at_ofs(data.ptrw(), ofs, p_color);
}
+void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) {
+ uint8_t *w = data.ptrw();
+ uint32_t pixel_size = get_format_pixel_size(format);
+ uint32_t pixel_count = data.size() / pixel_size;
+
+ for (uint32_t i = 0; i < pixel_count; i++) {
+ Color c = _get_color_at_ofs(w, i);
+ Vector3 rgb(c.r, c.g, c.b);
+
+ rgb *= p_brightness;
+ rgb = Vector3(0.5, 0.5, 0.5).lerp(rgb, p_contrast);
+ float center = (rgb.x + rgb.y + rgb.z) / 3.0;
+ rgb = Vector3(center, center, center).lerp(rgb, p_saturation);
+ c.r = rgb.x;
+ c.g = rgb.y;
+ c.b = rgb.z;
+ _set_color_at_ofs(w, i, c);
+ }
+}
+
Image::UsedChannels Image::detect_used_channels(CompressSource p_source) {
ERR_FAIL_COND_V(data.size() == 0, USED_CHANNELS_RGBA);
ERR_FAIL_COND_V(is_compressed(), USED_CHANNELS_RGBA);
@@ -3132,6 +3152,8 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pixelv", "point", "color"), &Image::set_pixelv);
ClassDB::bind_method(D_METHOD("set_pixel", "x", "y", "color"), &Image::set_pixel);
+ ClassDB::bind_method(D_METHOD("adjust_bcs", "brightness", "contrast", "saturation"), &Image::adjust_bcs);
+
ClassDB::bind_method(D_METHOD("load_png_from_buffer", "buffer"), &Image::load_png_from_buffer);
ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer);
ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer);
diff --git a/core/io/image.h b/core/io/image.h
index b894be7df4..df8f9b35a1 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -390,6 +390,8 @@ public:
void set_pixelv(const Point2i &p_point, const Color &p_color);
void set_pixel(int p_x, int p_y, const Color &p_color);
+ void adjust_bcs(float p_brightness, float p_contrast, float p_saturation);
+
void set_as_black();
void copy_internals_from(const Ref<Image> &p_image) {
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 8ca1cb3beb..7de038e6fe 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -122,7 +122,7 @@ void ImageLoader::cleanup() {
/////////////////
-RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
if (r_error) {
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index bf67e1486f..a5d588e0b5 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -72,7 +72,7 @@ public:
class ResourceFormatLoaderImage : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index da200f5717..bd0285a7a9 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -207,7 +207,7 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) {
Memory::free_static(buf);
}
- if (p_err || GLOBAL_GET("application/run/flush_stdout_on_print")) {
+ if (p_err || !ProjectSettings::get_singleton() || GLOBAL_GET("application/run/flush_stdout_on_print")) {
// Don't always flush when printing stdout to avoid performance
// issues when `print()` is spammed in release builds.
file->flush();
@@ -228,7 +228,7 @@ void StdLogger::logv(const char *p_format, va_list p_list, bool p_err) {
vfprintf(stderr, p_format, p_list);
} else {
vprintf(p_format, p_list);
- if (GLOBAL_GET("application/run/flush_stdout_on_print")) {
+ if (!ProjectSettings::get_singleton() || GLOBAL_GET("application/run/flush_stdout_on_print")) {
// Don't always flush when printing stdout to avoid performance
// issues when `print()` is spammed in release builds.
fflush(stdout);
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index db79998a90..8560e2abc7 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -87,7 +87,6 @@ void Resource::set_path(const String &p_path, bool p_take_over) {
ResourceCache::lock.write_unlock();
}
- _change_notify("resource_path");
_resource_path_changed();
}
@@ -105,7 +104,6 @@ int Resource::get_subindex() const {
void Resource::set_name(const String &p_name) {
name = p_name;
- _change_notify("resource_name");
}
String Resource::get_name() const {
@@ -116,20 +114,18 @@ bool Resource::editor_can_reload_from_file() {
return true; //by default yes
}
-void Resource::reload_from_file() {
- String path = get_path();
- if (!path.is_resource_file()) {
- return;
+void Resource::reset_state() {
+}
+Error Resource::copy_from(const Ref<Resource> &p_resource) {
+ ERR_FAIL_COND_V(p_resource.is_null(), ERR_INVALID_PARAMETER);
+ if (get_class() != p_resource->get_class()) {
+ return ERR_INVALID_PARAMETER;
}
- Ref<Resource> s = ResourceLoader::load(ResourceLoader::path_remap(path), get_class(), true);
-
- if (!s.is_valid()) {
- return;
- }
+ reset_state(); //may want to reset state
List<PropertyInfo> pi;
- s->get_property_list(&pi);
+ p_resource->get_property_list(&pi);
for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) {
if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
@@ -139,8 +135,23 @@ void Resource::reload_from_file() {
continue; //do not change path
}
- set(E->get().name, s->get(E->get().name));
+ set(E->get().name, p_resource->get(E->get().name));
}
+ return OK;
+}
+void Resource::reload_from_file() {
+ String path = get_path();
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ Ref<Resource> s = ResourceLoader::load(ResourceLoader::path_remap(path), get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+
+ if (!s.is_valid()) {
+ return;
+ }
+
+ copy_from(s);
}
Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource>> &remap_cache) {
diff --git a/core/io/resource.h b/core/io/resource.h
index d0cd6ea3ac..ae18ac0c8a 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -90,6 +90,8 @@ public:
static Node *(*_get_local_scene_func)(); //used by editor
virtual bool editor_can_reload_from_file();
+ virtual void reset_state(); //for resources that use variable amount of properties, either via _validate_property or _get_property_list, this function needs to be implemented to correctly clear state
+ virtual Error copy_from(const Ref<Resource> &p_resource);
virtual void reload_from_file();
void register_owner(Object *p_owner);
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index fad58d65fd..fb6ad7d65e 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -313,17 +313,12 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
uint32_t index = f->get_32();
String path = res_path + "::" + itos(index);
- if (use_nocache) {
- if (!internal_index_cache.has(path)) {
- WARN_PRINT(String("Couldn't load resource (no cache): " + path).utf8().get_data());
- }
- r_v = internal_index_cache[path];
+ //always use internal cache for loading internal resources
+ if (!internal_index_cache.has(path)) {
+ WARN_PRINT(String("Couldn't load resource (no cache): " + path).utf8().get_data());
+ r_v = Variant();
} else {
- RES res = ResourceLoader::load(path);
- if (res.is_null()) {
- WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data());
- }
- r_v = res;
+ r_v = internal_index_cache[path];
}
} break;
@@ -645,7 +640,7 @@ Error ResourceLoaderBinary::load() {
}
} else {
- Error err = ResourceLoader::load_threaded_request(path, external_resources[i].type, use_sub_threads, local_path);
+ Error err = ResourceLoader::load_threaded_request(path, external_resources[i].type, use_sub_threads, ResourceFormatLoader::CACHE_MODE_REUSE, local_path);
if (err != OK) {
if (!ResourceLoader::get_abort_on_missing_resources()) {
ResourceLoader::notify_dependency_error(local_path, path, external_resources[i].type);
@@ -675,7 +670,7 @@ Error ResourceLoaderBinary::load() {
path = res_path + "::" + path;
}
- if (!use_nocache) {
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE) {
if (ResourceCache::has(path)) {
//already loaded, don't do anything
stage++;
@@ -684,7 +679,7 @@ Error ResourceLoaderBinary::load() {
}
}
} else {
- if (!use_nocache && !ResourceCache::has(res_path)) {
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && !ResourceCache::has(res_path)) {
path = res_path;
}
}
@@ -695,26 +690,40 @@ Error ResourceLoaderBinary::load() {
String t = get_unicode_string();
- Object *obj = ClassDB::instance(t);
- if (!obj) {
- error = ERR_FILE_CORRUPT;
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
- }
+ RES res;
- Resource *r = Object::cast_to<Resource>(obj);
- if (!r) {
- String obj_class = obj->get_class();
- error = ERR_FILE_CORRUPT;
- memdelete(obj); //bye
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
+ //use the existing one
+ Resource *r = ResourceCache::get(path);
+ if (r->get_class() == t) {
+ r->reset_state();
+ res = Ref<Resource>(r);
+ }
}
- RES res = RES(r);
+ if (res.is_null()) {
+ //did not replace
- if (path != String()) {
- r->set_path(path);
+ Object *obj = ClassDB::instance(t);
+ if (!obj) {
+ 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);
+ if (!r) {
+ String obj_class = obj->get_class();
+ error = ERR_FILE_CORRUPT;
+ memdelete(obj); //bye
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
+ }
+
+ res = RES(r);
+ if (path != String() && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
+ r->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); //if got here because the resource with same path has different type, replace it
+ }
+ r->set_subindex(subindex);
}
- r->set_subindex(subindex);
if (!main) {
internal_index_cache[path] = res;
@@ -961,7 +970,7 @@ ResourceLoaderBinary::~ResourceLoaderBinary() {
}
}
-RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -972,7 +981,7 @@ RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_origi
ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot open file '" + p_path + "'.");
ResourceLoaderBinary loader;
- loader.use_nocache = p_no_cache;
+ loader.cache_mode = p_cache_mode;
loader.use_sub_threads = p_use_sub_threads;
loader.progress = r_progress;
String path = p_original_path != "" ? p_original_path : p_path;
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 428725f1d2..3592bbdbc4 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -78,7 +78,7 @@ class ResourceLoaderBinary {
Map<String, String> remaps;
Error error = OK;
- bool use_nocache = false;
+ ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
friend class ResourceFormatLoaderBinary;
@@ -103,7 +103,7 @@ public:
class ResourceFormatLoaderBinary : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index d86877ee14..3e460726f6 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -116,7 +116,7 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
return OK;
}
-RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
PathAndType pat;
Error err = _get_path_and_type(p_path, pat);
@@ -128,7 +128,7 @@ RES ResourceFormatImporter::load(const String &p_path, const String &p_original_
return RES();
}
- RES res = ResourceLoader::_load(pat.path, p_path, pat.type, p_no_cache, r_error, p_use_sub_threads, r_progress);
+ RES res = ResourceLoader::_load(pat.path, p_path, pat.type, p_cache_mode, r_error, p_use_sub_threads, r_progress);
#ifdef TOOLS_ENABLED
if (res.is_valid()) {
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index d31273e3cb..bda8b74b73 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -57,7 +57,7 @@ class ResourceFormatImporter : public ResourceFormatLoader {
public:
static ResourceFormatImporter *get_singleton() { return singleton; }
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const;
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index d66511a39f..588af0f0ae 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -113,9 +113,9 @@ void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions)
}
}
-RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (get_script_instance() && get_script_instance()->has_method("load")) {
- Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads);
+ Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads, p_cache_mode);
if (res.get_type() == Variant::INT) {
if (r_error) {
@@ -164,7 +164,7 @@ Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map<
void ResourceFormatLoader::_bind_methods() {
{
- MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"));
+ MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"), PropertyInfo(Variant::BOOL, "use_sub_threads"), PropertyInfo(Variant::INT, "cache_mode"));
info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
ClassDB::add_virtual_method(get_class_static(), info);
}
@@ -178,7 +178,7 @@ void ResourceFormatLoader::_bind_methods() {
///////////////////////////////////
-RES ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error, bool p_use_sub_threads, float *r_progress) {
+RES ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress) {
bool found = false;
// Try all loaders and pick the first match for the type hint
@@ -187,7 +187,7 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
continue;
}
found = true;
- RES res = loader[i]->load(p_path, p_original_path != String() ? p_original_path : p_path, r_error, p_use_sub_threads, r_progress, p_no_cache);
+ RES res = loader[i]->load(p_path, p_original_path != String() ? p_original_path : p_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
if (res.is_null()) {
continue;
}
@@ -214,7 +214,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
//this is an actual thread, so wait for Ok fom semaphore
thread_load_semaphore->wait(); //wait until its ok to start loading
}
- load_task.resource = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, false, &load_task.error, load_task.use_sub_threads, &load_task.progress);
+ load_task.resource = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, load_task.cache_mode, &load_task.error, load_task.use_sub_threads, &load_task.progress);
load_task.progress = 1.0; //it was fully loaded at this point, so force progress to 1.0
@@ -267,7 +267,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
thread_load_mutex->unlock();
}
-Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, const String &p_source_resource) {
+Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, ResourceFormatLoader::CacheMode p_cache_mode, const String &p_source_resource) {
String local_path;
if (p_path.is_rel_path()) {
local_path = "res://" + p_path;
@@ -314,6 +314,7 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
load_task.remapped_path = _path_remap(local_path, &load_task.xl_remapped);
load_task.local_path = local_path;
load_task.type_hint = p_type_hint;
+ load_task.cache_mode = p_cache_mode;
load_task.use_sub_threads = p_use_sub_threads;
{ //must check if resource is already loaded before attempting to load it in a thread
@@ -501,7 +502,7 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
return resource;
}
-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, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
@@ -513,7 +514,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
}
- if (!p_no_cache) {
+ if (p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE) {
thread_load_mutex->lock();
//Is it already being loaded? poll until done
@@ -561,6 +562,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
load_task.local_path = local_path;
load_task.remapped_path = _path_remap(local_path, &load_task.xl_remapped);
load_task.type_hint = p_type_hint;
+ load_task.cache_mode = p_cache_mode; //ignore
load_task.loader_id = Thread::get_caller_id();
thread_load_tasks[local_path] = load_task;
@@ -581,7 +583,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
print_verbose("Loading resource: " + path);
float p;
- RES res = _load(path, local_path, p_type_hint, p_no_cache, r_error, false, &p);
+ RES res = _load(path, local_path, p_type_hint, p_cache_mode, r_error, false, &p);
if (res.is_null()) {
print_verbose("Failed loading resource: " + path);
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index dbf6be46c5..38a756c52f 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -38,11 +38,18 @@
class ResourceFormatLoader : public Reference {
GDCLASS(ResourceFormatLoader, Reference);
+public:
+ enum CacheMode {
+ CACHE_MODE_IGNORE, //resource and subresources do not use path cache, no path is set into resource.
+ CACHE_MODE_REUSE, //resource and subresources use patch cache, reuse existing loaded resources instead of loading from disk when available
+ CACHE_MODE_REPLACE, //resource and and subresource use path cache, but replace existing loaded resources when available with information from disk
+ };
+
protected:
static void _bind_methods();
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual bool exists(const String &p_path) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
@@ -99,7 +106,7 @@ private:
friend class ResourceFormatImporter;
friend class ResourceInteractiveLoader;
//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, bool p_use_sub_threads, float *r_progress);
+ static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress);
static ResourceLoadedCallback _loaded_callback;
@@ -114,6 +121,7 @@ private:
String type_hint;
float progress = 0.0;
ThreadLoadStatus status = THREAD_LOAD_IN_PROGRESS;
+ ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
Error error = OK;
RES resource;
bool xl_remapped = false;
@@ -136,11 +144,11 @@ private:
static float _dependency_get_progress(const String &p_path);
public:
- static Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, const String &p_source_resource = String());
+ static Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE, const String &p_source_resource = String());
static ThreadLoadStatus load_threaded_get_status(const String &p_path, float *r_progress = nullptr);
static RES load_threaded_get(const String &p_path, Error *r_error = nullptr);
- static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = nullptr);
+ static RES load(const String &p_path, const String &p_type_hint = "", ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE, Error *r_error = nullptr);
static bool exists(const String &p_path, const String &p_type_hint = "");
static void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions);
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index ce2c3eb1cd..0e11ff514a 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -277,7 +277,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
return translation;
}
-RES TranslationLoaderPO::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES TranslationLoaderPO::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h
index a524972588..36d33fcac3 100644
--- a/core/io/translation_loader_po.h
+++ b/core/io/translation_loader_po.h
@@ -38,7 +38,7 @@
class TranslationLoaderPO : public ResourceFormatLoader {
public:
static RES load_translation(FileAccess *f, Error *r_error = nullptr);
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index 825817af5e..4ef9b4dbe6 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -252,27 +252,34 @@ public:
return true;
}
- static inline bool segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, real_t p_height, real_t p_radius, Vector3 *r_res = nullptr, Vector3 *r_norm = nullptr) {
+ static inline bool segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, real_t p_height, real_t p_radius, Vector3 *r_res = nullptr, Vector3 *r_norm = nullptr, int p_cylinder_axis = 2) {
Vector3 rel = (p_to - p_from);
real_t rel_l = rel.length();
if (rel_l < CMP_EPSILON) {
return false; // Both points are the same.
}
+ ERR_FAIL_COND_V(p_cylinder_axis < 0, false);
+ ERR_FAIL_COND_V(p_cylinder_axis > 2, false);
+ Vector3 cylinder_axis;
+ cylinder_axis[p_cylinder_axis] = 1.0;
+
// First check if they are parallel.
Vector3 normal = (rel / rel_l);
- Vector3 crs = normal.cross(Vector3(0, 0, 1));
+ Vector3 crs = normal.cross(cylinder_axis);
real_t crs_l = crs.length();
- Vector3 z_dir;
+ Vector3 axis_dir;
if (crs_l < CMP_EPSILON) {
- z_dir = Vector3(1, 0, 0); // Any x/y vector OK.
+ Vector3 side_axis;
+ side_axis[(p_cylinder_axis + 1) % 3] = 1.0; // Any side axis OK.
+ axis_dir = side_axis;
} else {
- z_dir = crs / crs_l;
+ axis_dir = crs / crs_l;
}
- real_t dist = z_dir.dot(p_from);
+ real_t dist = axis_dir.dot(p_from);
if (dist >= p_radius) {
return false; // Too far away.
@@ -285,10 +292,10 @@ public:
}
Size2 size(Math::sqrt(w2), p_height * 0.5);
- Vector3 x_dir = z_dir.cross(Vector3(0, 0, 1)).normalized();
+ Vector3 side_dir = axis_dir.cross(cylinder_axis).normalized();
- Vector2 from2D(x_dir.dot(p_from), p_from.z);
- Vector2 to2D(x_dir.dot(p_to), p_to.z);
+ Vector2 from2D(side_dir.dot(p_from), p_from[p_cylinder_axis]);
+ Vector2 to2D(side_dir.dot(p_to), p_to[p_cylinder_axis]);
real_t min = 0, max = 1;
@@ -335,10 +342,12 @@ public:
Vector3 res_normal = result;
if (axis == 0) {
- res_normal.z = 0;
+ res_normal[p_cylinder_axis] = 0;
} else {
- res_normal.x = 0;
- res_normal.y = 0;
+ int axis_side = (p_cylinder_axis + 1) % 3;
+ res_normal[axis_side] = 0;
+ axis_side = (axis_side + 1) % 3;
+ res_normal[axis_side] = 0;
}
res_normal.normalize();
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 171bc4dc2c..8f2eed3200 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -808,21 +808,6 @@ String Object::to_string() {
return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
}
-void Object::_changed_callback(Object *p_changed, const char *p_prop) {
-}
-
-void Object::add_change_receptor(Object *p_receptor) {
- change_receptors.insert(p_receptor);
-}
-
-void Object::remove_change_receptor(Object *p_receptor) {
- change_receptors.erase(p_receptor);
-}
-
-void Object::property_list_changed_notify() {
- _change_notify();
-}
-
void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) {
//this function is not meant to be used in any of these ways
ERR_FAIL_COND(p_script.is_null());
@@ -856,7 +841,7 @@ void Object::set_script(const Variant &p_script) {
}
}
- _change_notify(); //scripts may add variables, so refresh is desired
+ notify_property_list_changed(); //scripts may add variables, so refresh is desired
emit_signal(CoreStringNames::get_singleton()->script_changed);
}
@@ -1496,6 +1481,10 @@ void Object::clear_internal_resource_paths() {
}
}
+void Object::notify_property_list_changed() {
+ emit_signal(CoreStringNames::get_singleton()->property_list_changed);
+}
+
void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_class"), &Object::get_class);
ClassDB::bind_method(D_METHOD("is_class", "class"), &Object::is_class);
@@ -1562,7 +1551,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_block_signals", "enable"), &Object::set_block_signals);
ClassDB::bind_method(D_METHOD("is_blocking_signals"), &Object::is_blocking_signals);
- ClassDB::bind_method(D_METHOD("property_list_changed_notify"), &Object::property_list_changed_notify);
+ ClassDB::bind_method(D_METHOD("notify_property_list_changed"), &Object::notify_property_list_changed);
ClassDB::bind_method(D_METHOD("set_message_translation", "enable"), &Object::set_message_translation);
ClassDB::bind_method(D_METHOD("can_translate_messages"), &Object::can_translate_messages);
@@ -1574,6 +1563,7 @@ void Object::_bind_methods() {
ClassDB::add_virtual_method("Object", MethodInfo("free"), false);
ADD_SIGNAL(MethodInfo("script_changed"));
+ ADD_SIGNAL(MethodInfo("property_list_changed"));
BIND_VMETHOD(MethodInfo("_notification", PropertyInfo(Variant::INT, "what")));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_set", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value")));
diff --git a/core/object/object.h b/core/object/object.h
index 7e460462cf..b695ce9bc3 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -454,7 +454,6 @@ private:
#endif
bool _block_signals = false;
int _predelete_ok = 0;
- Set<Object *> change_receptors;
ObjectID _instance_id;
bool _predelete();
void _postinitialize();
@@ -523,9 +522,6 @@ protected:
static void get_valid_parents_static(List<String> *p_parents);
static void _get_valid_parents_static(List<String> *p_parents);
- void property_list_changed_notify();
- virtual void _changed_callback(Object *p_changed, const char *p_prop);
-
//Variant _call_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant());
//void _call_deferred_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant());
@@ -555,16 +551,8 @@ public: //should be protected, but bug in clang++
_FORCE_INLINE_ static void register_custom_data_to_otdb() {}
public:
-#ifdef TOOLS_ENABLED
- _FORCE_INLINE_ void _change_notify(const char *p_property = "") {
- _edited = true;
- for (Set<Object *>::Element *E = change_receptors.front(); E; E = E->next()) {
- ((Object *)(E->get()))->_changed_callback(this, p_property);
- }
- }
-#else
- _FORCE_INLINE_ void _change_notify(const char *p_what = "") {}
-#endif
+ void notify_property_list_changed();
+
static void *get_class_ptr_static() {
static int ptr;
return &ptr;
@@ -574,10 +562,6 @@ public:
_FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_id; }
- // this is used for editors
- void add_change_receptor(Object *p_receptor);
- void remove_change_receptor(Object *p_receptor);
-
template <class T>
static T *cast_to(Object *p_object) {
#ifndef NO_SAFE_CAST
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index c3f109a147..42fb0a0caf 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -275,6 +275,14 @@ void ScriptServer::save_global_classes() {
gcarr.push_back(d);
}
+ Array old;
+ if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
+ old = ProjectSettings::get_singleton()->get("_global_script_classes");
+ }
+ if ((!old.is_empty() || gcarr.is_empty()) && gcarr.hash() == old.hash()) {
+ return;
+ }
+
if (gcarr.is_empty()) {
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
ProjectSettings::get_singleton()->clear("_global_script_classes");
@@ -515,7 +523,7 @@ void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, c
}
if (owner && owner->get_script_instance() == this) {
- owner->_change_notify();
+ owner->notify_property_list_changed();
}
//change notify
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 0b6311dadf..59fda65d43 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -3072,39 +3072,46 @@ int String::rfindn(const String &p_str, int p_from) const {
bool String::ends_with(const String &p_string) const {
int l = p_string.length();
+ if (l > length()) {
+ return false;
+ }
+
if (l == 0) {
return true;
}
- int pos = rfind(p_string);
- if (pos == -1) {
- return false;
+ const char32_t *p = &p_string[0];
+ const char32_t *s = &operator[](length() - l);
+
+ for (int i = 0; i < l; i++) {
+ if (p[i] != s[i]) {
+ return false;
+ }
}
- return pos + l == length();
+
+ return true;
}
bool String::begins_with(const String &p_string) const {
- if (p_string.length() > length()) {
+ int l = p_string.length();
+ if (l > length()) {
return false;
}
- int l = p_string.length();
if (l == 0) {
return true;
}
- const char32_t *src = &p_string[0];
- const char32_t *str = &operator[](0);
+ const char32_t *p = &p_string[0];
+ const char32_t *s = &operator[](0);
- int i = 0;
- for (; i < l; i++) {
- if (src[i] != str[i]) {
+ for (int i = 0; i < l; i++) {
+ if (p[i] != s[i]) {
return false;
}
}
- // only if i == l the p_string matches the beginning
- return i == l;
+ return true;
}
bool String::begins_with(const char *p_string) const {
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index 7861c76153..0012cea72d 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -498,6 +498,11 @@ public:
flush_one();
}
+ _FORCE_INLINE_ void flush_if_pending() {
+ if (unlikely(read_ptr_and_epoch != write_ptr_and_epoch)) {
+ flush_all();
+ }
+ }
void flush_all() {
//ERR_FAIL_COND(sync);
lock();
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index d26c445eb4..3edc73b1a9 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -79,8 +79,7 @@ class RID_Alloc : public RID_AllocBase {
SpinLock spin_lock;
-public:
- RID make_rid(const T &p_value) {
+ _FORCE_INLINE_ RID _allocate_rid(const T *p_initializer) {
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -115,15 +114,22 @@ public:
uint32_t free_chunk = free_index / elements_in_chunk;
uint32_t free_element = free_index % elements_in_chunk;
- T *ptr = &chunks[free_chunk][free_element];
- memnew_placement(ptr, T(p_value));
+ if (p_initializer) {
+ T *ptr = &chunks[free_chunk][free_element];
+ memnew_placement(ptr, T(*p_initializer));
+ }
- uint32_t validator = (uint32_t)(_gen_id() & 0xFFFFFFFF);
+ uint32_t validator = (uint32_t)(_gen_id() & 0x7FFFFFFF);
uint64_t id = validator;
id <<= 32;
id |= free_index;
validator_chunks[free_chunk][free_element] = validator;
+
+ if (!p_initializer) {
+ validator_chunks[free_chunk][free_element] |= 0x80000000; //mark uninitialized bit
+ }
+
alloc_count++;
if (THREAD_SAFE) {
@@ -133,7 +139,20 @@ public:
return _make_from_id(id);
}
- _FORCE_INLINE_ T *getornull(const RID &p_rid) {
+public:
+ RID make_rid(const T &p_value) {
+ return _allocate_rid(&p_value);
+ }
+
+ //allocate but don't initialize, use initialize_rid afterwards
+ RID allocate_rid() {
+ return _allocate_rid(nullptr);
+ }
+
+ _FORCE_INLINE_ T *getornull(const RID &p_rid, bool p_initialize = false) {
+ if (p_rid == RID()) {
+ return nullptr;
+ }
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -151,10 +170,32 @@ public:
uint32_t idx_element = idx % elements_in_chunk;
uint32_t validator = uint32_t(id >> 32);
- if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
+
+ if (unlikely(p_initialize)) {
+ if (unlikely(!(validator_chunks[idx_chunk][idx_element] & 0x80000000))) {
+ if (THREAD_SAFE) {
+ spin_lock.unlock();
+ }
+ ERR_FAIL_V_MSG(nullptr, "Initializing already initialized RID");
+ }
+
+ if (unlikely((validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) != validator)) {
+ if (THREAD_SAFE) {
+ spin_lock.unlock();
+ }
+ ERR_FAIL_V_MSG(nullptr, "Attempting to initialize the wrong RID");
+ return nullptr;
+ }
+
+ validator_chunks[idx_chunk][idx_element] &= 0x7FFFFFFF; //initialized
+
+ } else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
+ if (validator_chunks[idx_chunk][idx_element] & 0x80000000) {
+ ERR_FAIL_V_MSG(nullptr, "Attempting to use an uninitialized RID");
+ }
return nullptr;
}
@@ -166,6 +207,11 @@ public:
return ptr;
}
+ void initialize_rid(RID p_rid, const T &p_value) {
+ T *mem = getornull(p_rid, true);
+ ERR_FAIL_COND(!mem);
+ memnew_placement(mem, T(p_value));
+ }
_FORCE_INLINE_ bool owns(const RID &p_rid) {
if (THREAD_SAFE) {
@@ -186,7 +232,7 @@ public:
uint32_t validator = uint32_t(id >> 32);
- bool owned = validator_chunks[idx_chunk][idx_element] == validator;
+ bool owned = (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator;
if (THREAD_SAFE) {
spin_lock.unlock();
@@ -213,7 +259,12 @@ public:
uint32_t idx_element = idx % elements_in_chunk;
uint32_t validator = uint32_t(id >> 32);
- if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
+ if (unlikely(validator_chunks[idx_chunk][idx_element] & 0x80000000)) {
+ if (THREAD_SAFE) {
+ spin_lock.unlock();
+ }
+ ERR_FAIL_MSG("Attempted to free an uninitialized or invalid RID");
+ } else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
@@ -330,6 +381,14 @@ public:
return alloc.make_rid(p_ptr);
}
+ _FORCE_INLINE_ RID allocate_rid() {
+ return alloc.allocate_rid();
+ }
+
+ _FORCE_INLINE_ void initialize_rid(RID p_rid, T *p_ptr) {
+ alloc.initialize_rid(p_rid, p_ptr);
+ }
+
_FORCE_INLINE_ T *getornull(const RID &p_rid) {
T **ptr = alloc.getornull(p_rid);
if (unlikely(!ptr)) {
@@ -338,6 +397,12 @@ public:
return *ptr;
}
+ _FORCE_INLINE_ void replace(const RID &p_rid, T *p_new_ptr) {
+ T **ptr = alloc.getornull(p_rid);
+ ERR_FAIL_COND(!ptr);
+ *ptr = p_new_ptr;
+ }
+
_FORCE_INLINE_ bool owns(const RID &p_rid) {
return alloc.owns(p_rid);
}
@@ -379,6 +444,14 @@ public:
return alloc.make_rid(p_ptr);
}
+ _FORCE_INLINE_ RID allocate_rid() {
+ return alloc.allocate_rid();
+ }
+
+ _FORCE_INLINE_ void initialize_rid(RID p_rid, const T &p_ptr) {
+ alloc.initialize_rid(p_rid, p_ptr);
+ }
+
_FORCE_INLINE_ T *getornull(const RID &p_rid) {
return alloc.getornull(p_rid);
}