feat: updated engine

This commit is contained in:
Sara Gerretsen 2026-07-10 17:04:34 +02:00
parent cbe99774ff
commit f4cf6b3999
6607 changed files with 910135 additions and 430025 deletions

View file

@ -32,10 +32,14 @@
#include "core/debugger/debugger_marshalls.h"
#include "core/io/marshalls.h"
#include "core/io/resource_loader.h"
#include "core/object/callable_mp.h"
#include "core/object/class_db.h"
#include "core/variant/typed_dictionary.h"
#include "editor/docks/inspector_dock.h"
#include "editor/editor_node.h"
#include "editor/editor_undo_redo_manager.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/debugger/scene_debugger_object.h"
bool EditorDebuggerRemoteObjects::_set(const StringName &p_name, const Variant &p_value) {
return _set_impl(p_name, p_value, "");
@ -47,7 +51,7 @@ bool EditorDebuggerRemoteObjects::_set_impl(const StringName &p_name, const Vari
return false;
}
// Change it back to the real name when fetching.
// Change it back to the real name when sending it.
if (name == "Script") {
name = "script";
} else if (name.begins_with("Metadata/")) {
@ -72,18 +76,10 @@ bool EditorDebuggerRemoteObjects::_set_impl(const StringName &p_name, const Vari
}
bool EditorDebuggerRemoteObjects::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name;
if (!prop_values.has(name)) {
if (!prop_values.has(p_name)) {
return false;
}
// Change it back to the real name when fetching.
if (name == "Script") {
name = "script";
} else if (name.begins_with("Metadata/")) {
name = name.replace_first("Metadata/", "metadata/");
}
r_ret = prop_values[p_name][remote_object_ids[0]];
return true;
}
@ -108,7 +104,13 @@ void EditorDebuggerRemoteObjects::set_property_field(const StringName &p_propert
String EditorDebuggerRemoteObjects::get_title() {
if (!remote_object_ids.is_empty() && ObjectID(remote_object_ids[0].operator uint64_t()).is_valid()) {
const int size = remote_object_ids.size();
return size == 1 ? vformat(TTR("Remote %s: %d"), type_name, remote_object_ids[0]) : vformat(TTR("Remote %s (%d Selected)"), type_name, size);
if (size == 1) {
if (node_name.is_empty() || node_name == type_name) {
return vformat(TTR("Remote %s: %d"), type_name, remote_object_ids[0]);
}
return vformat(TTR("Remote %s (%s): %d"), type_name, node_name, remote_object_ids[0]);
}
return vformat(TTR("Remote %s (%d Selected)"), type_name, size);
}
return "<null>";
@ -120,12 +122,17 @@ Variant EditorDebuggerRemoteObjects::get_variant(const StringName &p_name) {
return var;
}
void EditorDebuggerRemoteObjects::clear() {
prop_list.clear();
prop_values.clear();
}
void EditorDebuggerRemoteObjects::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_title"), &EditorDebuggerRemoteObjects::get_title);
ClassDB::bind_method("_hide_script_from_inspector", &EditorDebuggerRemoteObjects::_hide_script_from_inspector);
ClassDB::bind_method("_hide_metadata_from_inspector", &EditorDebuggerRemoteObjects::_hide_metadata_from_inspector);
ADD_SIGNAL(MethodInfo("values_edited", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::DICTIONARY, "values", PROPERTY_HINT_DICTIONARY_TYPE, "uint64_t:Variant"), PropertyInfo(Variant::STRING, "field")));
ADD_SIGNAL(MethodInfo("values_edited", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::DICTIONARY, "values", PROPERTY_HINT_DICTIONARY_TYPE, "uint64_t;Variant"), PropertyInfo(Variant::STRING, "field")));
}
/// EditorDebuggerInspector
@ -200,34 +207,6 @@ EditorDebuggerRemoteObjects *EditorDebuggerInspector::set_objects(const Array &p
remote_objects_list.push_back(remote_objects);
}
StringName class_name = objects[0].class_name;
if (class_name != SNAME("Object")) {
// Search for the common class between all selected objects.
bool check_type_again = true;
while (check_type_again) {
check_type_again = false;
if (class_name == SNAME("Object") || class_name == StringName()) {
// All objects inherit from Object, so no need to continue checking.
class_name = SNAME("Object");
break;
}
// Check that all objects inherit from type_name.
for (const SceneDebuggerObject &obj : objects) {
if (obj.class_name == class_name || ClassDB::is_parent_class(obj.class_name, class_name)) {
continue; // class_name is the same or a parent of the object's class.
}
// class_name is not a parent of the node's class, so check again with the parent class.
class_name = ClassDB::get_parent_class(class_name);
check_type_again = true;
break;
}
}
}
remote_objects->type_name = class_name;
// Search for properties that are present in all selected objects.
struct UsageData {
int qty = 0;
@ -254,8 +233,27 @@ EditorDebuggerRemoteObjects *EditorDebuggerInspector::set_objects(const Array &p
usage[pinfo.name] = usage_dt;
}
// Make sure only properties with the same exact PropertyInfo data will appear.
if (usage[pinfo.name].prop.first == pinfo) {
// Make sure only properties with matching PropertyInfo data will appear.
if (usage[pinfo.name].prop.first.name == pinfo.name &&
usage[pinfo.name].prop.first.type == pinfo.type &&
usage[pinfo.name].prop.first.class_name == pinfo.class_name &&
usage[pinfo.name].prop.first.hint == pinfo.hint &&
usage[pinfo.name].prop.first.hint_string == pinfo.hint_string) {
if (usage[pinfo.name].prop.first.usage != pinfo.usage) {
// Checkable properties (mostly theme items) need special treatment.
if (usage[pinfo.name].prop.first.usage & PROPERTY_USAGE_CHECKABLE && pinfo.usage & PROPERTY_USAGE_CHECKABLE) {
if (usage[pinfo.name].prop.first.usage & PROPERTY_USAGE_CHECKED) {
pinfo.usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
} else {
pinfo.usage &= ~(PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED);
}
if (usage[pinfo.name].prop.first.usage != pinfo.usage) {
continue;
}
}
}
usage[pinfo.name].qty++;
usage[pinfo.name].values[obj.id] = prop.second;
}
@ -311,6 +309,79 @@ EditorDebuggerRemoteObjects *EditorDebuggerInspector::set_objects(const Array &p
remote_objects->prop_values[pinfo.name] = KV.value.values;
}
StringName class_name = objects[0].class_name;
bool has_custom_class = true;
if (usage.has("Script")) {
// Check if all objects have the same script.
Ref<Script> common_scr;
LocalVector<Variant> keys = usage["Script"].values.get_key_list();
for (const Variant &key : keys) {
Ref<Script> scr = usage["Script"].values[key];
if (scr.is_null()) {
has_custom_class = false;
break;
}
if (common_scr.is_null()) {
common_scr = scr;
} else if (scr != common_scr) {
has_custom_class = false;
break;
}
}
if (has_custom_class) {
// Now check if the script has a custom class.
if (common_scr.is_null()) {
has_custom_class = false;
} else {
const StringName scr_class = common_scr->get_global_name();
if (scr_class.is_empty()) {
has_custom_class = false;
} else {
class_name = scr_class;
}
}
}
}
if (!has_custom_class && class_name != SNAME("Object")) {
// Search for the common class between all selected objects.
bool check_type_again = true;
while (check_type_again) {
check_type_again = false;
if (class_name.is_empty() || class_name == SNAME("Object")) {
// All objects inherit from Object, so no need to continue checking.
class_name = SNAME("Object");
break;
}
// Check that all objects inherit from type_name.
for (const SceneDebuggerObject &obj : objects) {
if (obj.class_name == class_name || ClassDB::is_parent_class(obj.class_name, class_name)) {
continue; // class_name is the same or a parent of the object's class.
}
// class_name is not a parent of the node's class, so check again with the parent class.
class_name = ClassDB::get_parent_class(class_name);
check_type_again = true;
break;
}
}
}
remote_objects->type_name = class_name;
remote_objects->node_name = "";
if (objects.size() == 1) {
for (const SceneDebuggerObject::SceneDebuggerProperty &prop : objects[0].properties) {
if (prop.first.name == "name") {
remote_objects->node_name = prop.second;
break;
}
}
}
if (old_prop_size == remote_objects->prop_list.size() && new_props_added == 0) {
// Only some may have changed, if so, then update those, if they exist.
for (const String &E : changed) {
@ -374,8 +445,14 @@ void EditorDebuggerInspector::add_stack_variable(const Array &p_array, int p_off
if (var.var_type == Variant::OBJECT && v) {
v = Object::cast_to<EncodedObjectAsID>(v)->get_object_id();
h = PROPERTY_HINT_OBJECT_ID;
hs = "Object";
hs = var.type_hint;
// Makes the call stack select the node in the remote tree. See https://github.com/godotengine/godot/issues/79477
if (n == "self") {
_object_selected(v);
}
}
String type;
switch (var.type) {
case 0:
@ -427,7 +504,7 @@ void EditorDebuggerInspector::clear_stack_variables() {
String EditorDebuggerInspector::get_stack_variable(const String &p_var) {
for (KeyValue<StringName, TypedDictionary<uint64_t, Variant>> &E : variables->prop_values) {
String v = E.key.operator String();
String v = E.key.string();
if (v.get_slicec('/', 1) == p_var) {
return variables->get_variant(v);
}