summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/project_settings.cpp2
-rw-r--r--core/core_constants.cpp1
-rw-r--r--core/debugger/remote_debugger.cpp36
-rw-r--r--core/extension/gdextension_library_loader.cpp4
-rw-r--r--core/extension/gdextension_library_loader.h1
-rw-r--r--core/extension/gdextension_loader.h1
-rw-r--r--core/extension/gdextension_manager.cpp3
-rw-r--r--core/input/input_map.compat.inc41
-rw-r--r--core/input/input_map.cpp5
-rw-r--r--core/input/input_map.h7
-rw-r--r--core/object/object.h1
-rw-r--r--core/object/ref_counted.h102
-rw-r--r--core/string/ustring.cpp25
-rw-r--r--core/string/ustring.h2
-rw-r--r--core/variant/callable.cpp19
-rw-r--r--core/variant/variant.cpp132
-rw-r--r--core/variant/variant.h18
-rw-r--r--core/variant/variant_construct.cpp30
-rw-r--r--core/variant/variant_construct.h9
-rw-r--r--core/variant/variant_internal.h29
20 files changed, 271 insertions, 197 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 7951ee9edd..562bde978e 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1398,7 +1398,7 @@ void ProjectSettings::_add_builtin_input_map() {
}
Dictionary action;
- action["deadzone"] = Variant(0.5f);
+ action["deadzone"] = Variant(0.2f);
action["events"] = events;
String action_name = "input/" + E.key;
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 68af5abf66..25da49fa5c 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -677,6 +677,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TOOL_BUTTON);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE);
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index e2ed7245a2..fc1b7b74f9 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -37,6 +37,7 @@
#include "core/debugger/script_debugger.h"
#include "core/input/input.h"
#include "core/io/resource_loader.h"
+#include "core/math/expression.h"
#include "core/object/script_language.h"
#include "core/os/os.h"
#include "servers/display_server.h"
@@ -529,6 +530,41 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
} else if (command == "set_skip_breakpoints") {
ERR_FAIL_COND(data.is_empty());
script_debugger->set_skip_breakpoints(data[0]);
+ } else if (command == "evaluate") {
+ String expression_str = data[0];
+ int frame = data[1];
+
+ ScriptInstance *breaked_instance = script_debugger->get_break_language()->debug_get_stack_level_instance(frame);
+ if (!breaked_instance) {
+ break;
+ }
+
+ List<String> locals;
+ List<Variant> local_vals;
+
+ script_debugger->get_break_language()->debug_get_stack_level_locals(frame, &locals, &local_vals);
+ ERR_FAIL_COND(locals.size() != local_vals.size());
+
+ PackedStringArray locals_vector;
+ for (const String &S : locals) {
+ locals_vector.append(S);
+ }
+
+ Array local_vals_array;
+ for (const Variant &V : local_vals) {
+ local_vals_array.append(V);
+ }
+
+ Expression expression;
+ expression.parse(expression_str, locals_vector);
+ const Variant return_val = expression.execute(local_vals_array, breaked_instance->get_owner());
+
+ DebuggerMarshalls::ScriptStackVariable stvar;
+ stvar.name = expression_str;
+ stvar.value = return_val;
+ stvar.type = 3;
+
+ send_message("evaluation_return", stvar.serialize());
} else {
bool captured = false;
ERR_CONTINUE(_try_capture(command, data, captured) != OK);
diff --git a/core/extension/gdextension_library_loader.cpp b/core/extension/gdextension_library_loader.cpp
index 5ba4933c35..d5f2eb668f 100644
--- a/core/extension/gdextension_library_loader.cpp
+++ b/core/extension/gdextension_library_loader.cpp
@@ -259,6 +259,10 @@ bool GDExtensionLibraryLoader::has_library_changed() const {
return false;
}
+bool GDExtensionLibraryLoader::library_exists() const {
+ return FileAccess::exists(resource_path);
+}
+
Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) {
resource_path = p_path;
diff --git a/core/extension/gdextension_library_loader.h b/core/extension/gdextension_library_loader.h
index f4372a75d4..f781611b30 100644
--- a/core/extension/gdextension_library_loader.h
+++ b/core/extension/gdextension_library_loader.h
@@ -77,6 +77,7 @@ public:
virtual void close_library() override;
virtual bool is_library_open() const override;
virtual bool has_library_changed() const override;
+ virtual bool library_exists() const override;
Error parse_gdextension_file(const String &p_path);
};
diff --git a/core/extension/gdextension_loader.h b/core/extension/gdextension_loader.h
index 7d779858b7..2289550329 100644
--- a/core/extension/gdextension_loader.h
+++ b/core/extension/gdextension_loader.h
@@ -42,6 +42,7 @@ public:
virtual void close_library() = 0;
virtual bool is_library_open() const = 0;
virtual bool has_library_changed() const = 0;
+ virtual bool library_exists() const = 0;
};
#endif // GDEXTENSION_LOADER_H
diff --git a/core/extension/gdextension_manager.cpp b/core/extension/gdextension_manager.cpp
index 01efe0d96e..fff938858f 100644
--- a/core/extension/gdextension_manager.cpp
+++ b/core/extension/gdextension_manager.cpp
@@ -302,7 +302,8 @@ bool GDExtensionManager::ensure_extensions_loaded(const HashSet<String> &p_exten
for (const String &loaded_extension : loaded_extensions) {
if (!p_extensions.has(loaded_extension)) {
// The extension may not have a .gdextension file.
- if (!FileAccess::exists(loaded_extension)) {
+ const Ref<GDExtension> extension = GDExtensionManager::get_singleton()->get_extension(loaded_extension);
+ if (!extension->get_loader()->library_exists()) {
extensions_removed.push_back(loaded_extension);
}
}
diff --git a/core/input/input_map.compat.inc b/core/input/input_map.compat.inc
new file mode 100644
index 0000000000..da4bd962b6
--- /dev/null
+++ b/core/input/input_map.compat.inc
@@ -0,0 +1,41 @@
+/**************************************************************************/
+/* input_map.compat.inc */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 DISABLE_DEPRECATED
+
+void InputMap::_add_action_bind_compat_97281(const StringName &p_action, float p_deadzone) {
+ add_action(p_action, p_deadzone);
+}
+
+void InputMap::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::_add_action_bind_compat_97281, DEFVAL(0.5f));
+}
+
+#endif // DISABLE_DEPRECATED
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 9a772c87c9..27a50c79f6 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "input_map.h"
+#include "input_map.compat.inc"
#include "core/config/project_settings.h"
#include "core/input/input.h"
@@ -43,7 +44,7 @@ int InputMap::ALL_DEVICES = -1;
void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action);
ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions);
- ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(0.5f));
+ ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(0.2f));
ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action);
ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone);
@@ -306,7 +307,7 @@ void InputMap::load_from_project_settings() {
String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
Dictionary action = GLOBAL_GET(pi.name);
- float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.5f;
+ float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.2f;
Array events = action["events"];
add_action(name, deadzone);
diff --git a/core/input/input_map.h b/core/input/input_map.h
index 3774a131e6..b29687d144 100644
--- a/core/input/input_map.h
+++ b/core/input/input_map.h
@@ -69,12 +69,17 @@ private:
protected:
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ void _add_action_bind_compat_97281(const StringName &p_action, float p_deadzone = 0.5);
+ static void _bind_compatibility_methods();
+#endif // DISABLE_DEPRECATED
+
public:
static _FORCE_INLINE_ InputMap *get_singleton() { return singleton; }
bool has_action(const StringName &p_action) const;
List<StringName> get_actions() const;
- void add_action(const StringName &p_action, float p_deadzone = 0.5);
+ void add_action(const StringName &p_action, float p_deadzone = 0.2);
void erase_action(const StringName &p_action);
float action_get_deadzone(const StringName &p_action);
diff --git a/core/object/object.h b/core/object/object.h
index efe22ecc1a..110d2790c5 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -87,6 +87,7 @@ enum PropertyHint {
PROPERTY_HINT_PASSWORD,
PROPERTY_HINT_LAYERS_AVOIDANCE,
PROPERTY_HINT_DICTIONARY_TYPE,
+ PROPERTY_HINT_TOOL_BUTTON,
PROPERTY_HINT_MAX,
};
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index f0706b4d08..22eb5a7a3f 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -57,24 +57,30 @@ template <typename T>
class Ref {
T *reference = nullptr;
- void ref(const Ref &p_from) {
- if (p_from.reference == reference) {
+ _FORCE_INLINE_ void ref(const Ref &p_from) {
+ ref_pointer<false>(p_from.reference);
+ }
+
+ template <bool Init>
+ _FORCE_INLINE_ void ref_pointer(T *p_refcounted) {
+ if (p_refcounted == reference) {
return;
}
- unref();
-
- reference = p_from.reference;
+ // This will go out of scope and get unref'd.
+ Ref cleanup_ref;
+ cleanup_ref.reference = reference;
+ reference = p_refcounted;
if (reference) {
- reference->reference();
- }
- }
-
- void ref_pointer(T *p_ref) {
- ERR_FAIL_NULL(p_ref);
-
- if (p_ref->init_ref()) {
- reference = p_ref;
+ if constexpr (Init) {
+ if (!reference->init_ref()) {
+ reference = nullptr;
+ }
+ } else {
+ if (!reference->reference()) {
+ reference = nullptr;
+ }
+ }
}
}
@@ -124,15 +130,11 @@ public:
template <typename T_Other>
void operator=(const Ref<T_Other> &p_from) {
- RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
- if (!refb) {
- unref();
- return;
- }
- Ref r;
- r.reference = Object::cast_to<T>(refb);
- ref(r);
- r.reference = nullptr;
+ ref_pointer<false>(Object::cast_to<T>(p_from.ptr()));
+ }
+
+ void operator=(T *p_from) {
+ ref_pointer<true>(p_from);
}
void operator=(const Variant &p_variant) {
@@ -142,16 +144,7 @@ public:
return;
}
- unref();
-
- if (!object) {
- return;
- }
-
- T *r = Object::cast_to<T>(object);
- if (r && r->reference()) {
- reference = r;
- }
+ ref_pointer<false>(Object::cast_to<T>(object));
}
template <typename T_Other>
@@ -159,48 +152,25 @@ public:
if (reference == p_ptr) {
return;
}
- unref();
- T *r = Object::cast_to<T>(p_ptr);
- if (r) {
- ref_pointer(r);
- }
+ ref_pointer<true>(Object::cast_to<T>(p_ptr));
}
Ref(const Ref &p_from) {
- ref(p_from);
+ this->operator=(p_from);
}
template <typename T_Other>
Ref(const Ref<T_Other> &p_from) {
- RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
- if (!refb) {
- unref();
- return;
- }
- Ref r;
- r.reference = Object::cast_to<T>(refb);
- ref(r);
- r.reference = nullptr;
+ this->operator=(p_from);
}
- Ref(T *p_reference) {
- if (p_reference) {
- ref_pointer(p_reference);
- }
+ Ref(T *p_from) {
+ this->operator=(p_from);
}
- Ref(const Variant &p_variant) {
- Object *object = p_variant.get_validated_object();
-
- if (!object) {
- return;
- }
-
- T *r = Object::cast_to<T>(object);
- if (r && r->reference()) {
- reference = r;
- }
+ Ref(const Variant &p_from) {
+ this->operator=(p_from);
}
inline bool is_valid() const { return reference != nullptr; }
@@ -222,7 +192,7 @@ public:
ref(memnew(T(p_params...)));
}
- Ref() {}
+ Ref() = default;
~Ref() {
unref();
@@ -299,13 +269,13 @@ struct GetTypeInfo<const Ref<T> &> {
template <typename T>
struct VariantInternalAccessor<Ref<T>> {
static _FORCE_INLINE_ Ref<T> get(const Variant *v) { return Ref<T>(*VariantInternal::get_object(v)); }
- static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::refcounted_object_assign(v, p_ref.ptr()); }
+ static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::object_assign(v, p_ref); }
};
template <typename T>
struct VariantInternalAccessor<const Ref<T> &> {
static _FORCE_INLINE_ Ref<T> get(const Variant *v) { return Ref<T>(*VariantInternal::get_object(v)); }
- static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::refcounted_object_assign(v, p_ref.ptr()); }
+ static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::object_assign(v, p_ref); }
};
#endif // REF_COUNTED_H
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 391a203d5b..e6f7492a18 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -221,18 +221,35 @@ void CharString::copy_from(const char *p_cstr) {
/* String */
/*************************************************************************/
-Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path) const {
- // Splits the URL into scheme, host, port, path. Strip credentials when present.
+Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path, String &r_fragment) const {
+ // Splits the URL into scheme, host, port, path, fragment. Strip credentials when present.
String base = *this;
r_scheme = "";
r_host = "";
r_port = 0;
r_path = "";
+ r_fragment = "";
+
int pos = base.find("://");
// Scheme
if (pos != -1) {
- r_scheme = base.substr(0, pos + 3).to_lower();
- base = base.substr(pos + 3, base.length() - pos - 3);
+ bool is_scheme_valid = true;
+ for (int i = 0; i < pos; i++) {
+ if (!is_ascii_alphanumeric_char(base[i]) && base[i] != '+' && base[i] != '-' && base[i] != '.') {
+ is_scheme_valid = false;
+ break;
+ }
+ }
+ if (is_scheme_valid) {
+ r_scheme = base.substr(0, pos + 3).to_lower();
+ base = base.substr(pos + 3, base.length() - pos - 3);
+ }
+ }
+ pos = base.find("#");
+ // Fragment
+ if (pos != -1) {
+ r_fragment = base.substr(pos + 1);
+ base = base.substr(0, pos);
}
pos = base.find("/");
// Path
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 5d4b209c25..aa62c9cb18 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -452,7 +452,7 @@ public:
String c_escape_multiline() const;
String c_unescape() const;
String json_escape() const;
- Error parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path) const;
+ Error parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path, String &r_fragment) const;
String property_name_encode() const;
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index bb2d0313f6..5ce90cd8ff 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -315,31 +315,32 @@ bool Callable::operator<(const Callable &p_callable) const {
}
void Callable::operator=(const Callable &p_callable) {
+ CallableCustom *cleanup_ref = nullptr;
if (is_custom()) {
if (p_callable.is_custom()) {
if (custom == p_callable.custom) {
return;
}
}
-
- if (custom->ref_count.unref()) {
- memdelete(custom);
- custom = nullptr;
- }
+ cleanup_ref = custom;
+ custom = nullptr;
}
if (p_callable.is_custom()) {
method = StringName();
- if (!p_callable.custom->ref_count.ref()) {
- object = 0;
- } else {
- object = 0;
+ object = 0;
+ if (p_callable.custom->ref_count.ref()) {
custom = p_callable.custom;
}
} else {
method = p_callable.method;
object = p_callable.object;
}
+
+ if (cleanup_ref != nullptr && cleanup_ref->ref_count.unref()) {
+ memdelete(cleanup_ref);
+ }
+ cleanup_ref = nullptr;
}
Callable::operator String() const {
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 186643b024..e2865a06be 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -1072,17 +1072,69 @@ bool Variant::is_null() const {
}
}
+void Variant::ObjData::ref(const ObjData &p_from) {
+ // Mirrors Ref::ref in refcounted.h
+ if (p_from.id == id) {
+ return;
+ }
+
+ ObjData cleanup_ref = *this;
+
+ *this = p_from;
+ if (id.is_ref_counted()) {
+ RefCounted *reference = static_cast<RefCounted *>(obj);
+ // Assuming reference is not null because id.is_ref_counted() was true.
+ if (!reference->reference()) {
+ *this = ObjData();
+ }
+ }
+
+ cleanup_ref.unref();
+}
+
+void Variant::ObjData::ref_pointer(Object *p_object) {
+ // Mirrors Ref::ref_pointer in refcounted.h
+ if (p_object == obj) {
+ return;
+ }
+
+ ObjData cleanup_ref = *this;
+
+ if (p_object) {
+ *this = ObjData{ p_object->get_instance_id(), p_object };
+ if (p_object->is_ref_counted()) {
+ RefCounted *reference = static_cast<RefCounted *>(p_object);
+ if (!reference->init_ref()) {
+ *this = ObjData();
+ }
+ }
+ } else {
+ *this = ObjData();
+ }
+
+ cleanup_ref.unref();
+}
+
+void Variant::ObjData::unref() {
+ // Mirrors Ref::unref in refcounted.h
+ if (id.is_ref_counted()) {
+ RefCounted *reference = static_cast<RefCounted *>(obj);
+ // Assuming reference is not null because id.is_ref_counted() was true.
+ if (reference->unreference()) {
+ memdelete(reference);
+ }
+ }
+ *this = ObjData();
+}
+
void Variant::reference(const Variant &p_variant) {
- switch (type) {
- case NIL:
- case BOOL:
- case INT:
- case FLOAT:
- break;
- default:
- clear();
+ if (type == OBJECT && p_variant.type == OBJECT) {
+ _get_obj().ref(p_variant._get_obj());
+ return;
}
+ clear();
+
type = p_variant.type;
switch (p_variant.type) {
@@ -1165,18 +1217,7 @@ void Variant::reference(const Variant &p_variant) {
} break;
case OBJECT: {
memnew_placement(_data._mem, ObjData);
-
- if (p_variant._get_obj().obj && p_variant._get_obj().id.is_ref_counted()) {
- RefCounted *ref_counted = static_cast<RefCounted *>(p_variant._get_obj().obj);
- if (!ref_counted->reference()) {
- _get_obj().obj = nullptr;
- _get_obj().id = ObjectID();
- break;
- }
- }
-
- _get_obj().obj = const_cast<Object *>(p_variant._get_obj().obj);
- _get_obj().id = p_variant._get_obj().id;
+ _get_obj().ref(p_variant._get_obj());
} break;
case CALLABLE: {
memnew_placement(_data._mem, Callable(*reinterpret_cast<const Callable *>(p_variant._data._mem)));
@@ -1375,15 +1416,7 @@ void Variant::_clear_internal() {
reinterpret_cast<NodePath *>(_data._mem)->~NodePath();
} break;
case OBJECT: {
- if (_get_obj().id.is_ref_counted()) {
- // We are safe that there is a reference here.
- RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj);
- if (ref_counted->unreference()) {
- memdelete(ref_counted);
- }
- }
- _get_obj().obj = nullptr;
- _get_obj().id = ObjectID();
+ _get_obj().unref();
} break;
case RID: {
// Not much need probably.
@@ -2589,24 +2622,8 @@ Variant::Variant(const ::RID &p_rid) :
Variant::Variant(const Object *p_object) :
type(OBJECT) {
- memnew_placement(_data._mem, ObjData);
-
- if (p_object) {
- if (p_object->is_ref_counted()) {
- RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_object));
- if (!ref_counted->init_ref()) {
- _get_obj().obj = nullptr;
- _get_obj().id = ObjectID();
- return;
- }
- }
-
- _get_obj().obj = const_cast<Object *>(p_object);
- _get_obj().id = p_object->get_instance_id();
- } else {
- _get_obj().obj = nullptr;
- _get_obj().id = ObjectID();
- }
+ _get_obj() = ObjData();
+ _get_obj().ref_pointer(const_cast<Object *>(p_object));
}
Variant::Variant(const Callable &p_callable) :
@@ -2828,26 +2845,7 @@ void Variant::operator=(const Variant &p_variant) {
*reinterpret_cast<::RID *>(_data._mem) = *reinterpret_cast<const ::RID *>(p_variant._data._mem);
} break;
case OBJECT: {
- if (_get_obj().id.is_ref_counted()) {
- //we are safe that there is a reference here
- RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj);
- if (ref_counted->unreference()) {
- memdelete(ref_counted);
- }
- }
-
- if (p_variant._get_obj().obj && p_variant._get_obj().id.is_ref_counted()) {
- RefCounted *ref_counted = static_cast<RefCounted *>(p_variant._get_obj().obj);
- if (!ref_counted->reference()) {
- _get_obj().obj = nullptr;
- _get_obj().id = ObjectID();
- break;
- }
- }
-
- _get_obj().obj = const_cast<Object *>(p_variant._get_obj().obj);
- _get_obj().id = p_variant._get_obj().id;
-
+ _get_obj().ref(p_variant._get_obj());
} break;
case CALLABLE: {
*reinterpret_cast<Callable *>(_data._mem) = *reinterpret_cast<const Callable *>(p_variant._data._mem);
diff --git a/core/variant/variant.h b/core/variant/variant.h
index d4e4b330cd..c76b849abd 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -62,6 +62,10 @@
#include "core/variant/dictionary.h"
class Object;
+class RefCounted;
+
+template <typename T>
+class Ref;
struct PropertyInfo;
struct MethodInfo;
@@ -175,6 +179,20 @@ private:
struct ObjData {
ObjectID id;
Object *obj = nullptr;
+
+ void ref(const ObjData &p_from);
+ void ref_pointer(Object *p_object);
+ void ref_pointer(RefCounted *p_object);
+ void unref();
+
+ template <typename T>
+ _ALWAYS_INLINE_ void ref(const Ref<T> &p_from) {
+ if (p_from.is_valid()) {
+ ref(ObjData{ p_from->get_instance_id(), p_from.ptr() });
+ } else {
+ unref();
+ }
+ }
};
/* array helpers */
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index fb75a874e7..6c37d5e4b7 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -323,36 +323,6 @@ String Variant::get_constructor_argument_name(Variant::Type p_type, int p_constr
return construct_data[p_type][p_constructor].arg_names[p_argument];
}
-void VariantInternal::refcounted_object_assign(Variant *v, const RefCounted *rc) {
- if (!rc || !const_cast<RefCounted *>(rc)->init_ref()) {
- v->_get_obj().obj = nullptr;
- v->_get_obj().id = ObjectID();
- return;
- }
-
- v->_get_obj().obj = const_cast<RefCounted *>(rc);
- v->_get_obj().id = rc->get_instance_id();
-}
-
-void VariantInternal::object_assign(Variant *v, const Object *o) {
- if (o) {
- if (o->is_ref_counted()) {
- RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(o));
- if (!ref_counted->init_ref()) {
- v->_get_obj().obj = nullptr;
- v->_get_obj().id = ObjectID();
- return;
- }
- }
-
- v->_get_obj().obj = const_cast<Object *>(o);
- v->_get_obj().id = o->get_instance_id();
- } else {
- v->_get_obj().obj = nullptr;
- v->_get_obj().id = ObjectID();
- }
-}
-
void Variant::get_constructor_list(Type p_type, List<MethodInfo> *r_list) {
ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h
index 68210a9451..f625419da7 100644
--- a/core/variant/variant_construct.h
+++ b/core/variant/variant_construct.h
@@ -156,14 +156,14 @@ public:
if (p_args[0]->get_type() == Variant::NIL) {
VariantInternal::clear(&r_ret);
VariantTypeChanger<Object *>::change(&r_ret);
- VariantInternal::object_assign_null(&r_ret);
+ VariantInternal::object_reset_data(&r_ret);
r_error.error = Callable::CallError::CALL_OK;
} else if (p_args[0]->get_type() == Variant::OBJECT) {
- VariantInternal::clear(&r_ret);
VariantTypeChanger<Object *>::change(&r_ret);
VariantInternal::object_assign(&r_ret, p_args[0]);
r_error.error = Callable::CallError::CALL_OK;
} else {
+ VariantInternal::clear(&r_ret);
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::OBJECT;
@@ -171,7 +171,6 @@ public:
}
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
- VariantInternal::clear(r_ret);
VariantTypeChanger<Object *>::change(r_ret);
VariantInternal::object_assign(r_ret, p_args[0]);
}
@@ -203,13 +202,13 @@ public:
VariantInternal::clear(&r_ret);
VariantTypeChanger<Object *>::change(&r_ret);
- VariantInternal::object_assign_null(&r_ret);
+ VariantInternal::object_reset_data(&r_ret);
}
static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
VariantInternal::clear(r_ret);
VariantTypeChanger<Object *>::change(r_ret);
- VariantInternal::object_assign_null(r_ret);
+ VariantInternal::object_reset_data(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
PtrConstruct<Object *>::construct(nullptr, base);
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 58a45c0a1f..58652d26e0 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -220,7 +220,7 @@ public:
// Should be in the same order as Variant::Type for consistency.
// Those primitive and vector types don't need an `init_` method:
// Nil, bool, float, Vector2/i, Rect2/i, Vector3/i, Plane, Quat, RID.
- // Object is a special case, handled via `object_assign_null`.
+ // Object is a special case, handled via `object_reset_data`.
_FORCE_INLINE_ static void init_string(Variant *v) {
memnew_placement(v->_data._mem, String);
v->type = Variant::STRING;
@@ -319,7 +319,7 @@ public:
v->type = Variant::PACKED_VECTOR4_ARRAY;
}
_FORCE_INLINE_ static void init_object(Variant *v) {
- object_assign_null(v);
+ object_reset_data(v);
v->type = Variant::OBJECT;
}
@@ -327,19 +327,28 @@ public:
v->clear();
}
- static void object_assign(Variant *v, const Object *o); // Needs RefCounted, so it's implemented elsewhere.
- static void refcounted_object_assign(Variant *v, const RefCounted *rc);
+ _FORCE_INLINE_ static void object_assign(Variant *v, const Variant *vo) {
+ v->_get_obj().ref(vo->_get_obj());
+ }
+
+ _FORCE_INLINE_ static void object_assign(Variant *v, Object *o) {
+ v->_get_obj().ref_pointer(o);
+ }
- _FORCE_INLINE_ static void object_assign(Variant *v, const Variant *o) {
- object_assign(v, o->_get_obj().obj);
+ _FORCE_INLINE_ static void object_assign(Variant *v, const Object *o) {
+ v->_get_obj().ref_pointer(const_cast<Object *>(o));
+ }
+
+ template <typename T>
+ _FORCE_INLINE_ static void object_assign(Variant *v, const Ref<T> &r) {
+ v->_get_obj().ref(r);
}
- _FORCE_INLINE_ static void object_assign_null(Variant *v) {
- v->_get_obj().obj = nullptr;
- v->_get_obj().id = ObjectID();
+ _FORCE_INLINE_ static void object_reset_data(Variant *v) {
+ v->_get_obj() = Variant::ObjData();
}
- static void update_object_id(Variant *v) {
+ _FORCE_INLINE_ static void update_object_id(Variant *v) {
const Object *o = v->_get_obj().obj;
if (o) {
v->_get_obj().id = o->get_instance_id();