1
0
Fork 0

Move `RuntimeNodeSelect` to its own files

This commit is contained in:
Michael Alexsander 2026-01-28 21:54:02 -03:00
parent 5ad8b27d8d
commit 6862edcede
No known key found for this signature in database
GPG Key ID: A9C91EE110F4EABA
15 changed files with 2308 additions and 2153 deletions

View File

@ -35,7 +35,7 @@
#include "core/io/stream_peer_tcp.h"
#include "core/io/tcp_server.h"
#include "editor/debugger/debug_adapter/debug_adapter_types.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/debugger/scene_debugger_object.h"
#define DAP_MAX_BUFFER_SIZE 4194304 // 4MB
#define DAP_MAX_CLIENTS 8

View File

@ -35,7 +35,7 @@
#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, "");

View File

@ -37,7 +37,7 @@
#include "editor/gui/editor_file_dialog.h"
#include "editor/gui/editor_toaster.h"
#include "editor/settings/editor_settings.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/debugger/scene_debugger_object.h"
#include "scene/gui/texture_rect.h"
#include "scene/resources/packed_scene.h"
#include "servers/display/display_server.h"

View File

@ -54,7 +54,7 @@
#include "editor/themes/editor_scale.h"
#include "main/performance.h"
#include "scene/3d/camera_3d.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/debugger/scene_debugger_object.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/grid_container.h"

View File

@ -32,7 +32,6 @@
#include "core/config/project_settings.h"
#include "core/debugger/debugger_marshalls.h"
#include "core/debugger/engine_debugger.h"
#include "core/string/translation_server.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/debugger/script_editor_debugger.h"

View File

@ -34,7 +34,7 @@
#include "editor/debugger/editor_debugger_plugin.h"
#include "editor/editor_main_screen.h"
#include "editor/plugins/editor_plugin.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/debugger/runtime_node_select.h"
#include "scene/gui/box_container.h"
class EmbeddedProcessBase;

View File

@ -30,6 +30,7 @@
#include "editor_network_profiler.h"
#include "core/io/resource_loader.h"
#include "editor/editor_string_names.h"
#include "editor/run/editor_run_bar.h"
#include "editor/settings/editor_settings.h"

View File

@ -33,7 +33,7 @@
#include "core/core_bind.h"
#include "core/io/compression.h"
#include "core/object/script_language.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/debugger/scene_debugger_object.h"
#if defined(MODULE_GDSCRIPT_ENABLED) && defined(DEBUG_ENABLED)
#include "modules/gdscript/gdscript.h"

View File

@ -30,7 +30,7 @@
#pragma once
#include "scene/debugger/scene_debugger.h"
#include "scene/debugger/scene_debugger_object.h"
struct SnapshotDataTransportObject : public SceneDebuggerObject {
SnapshotDataTransportObject() :

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,248 @@
/**************************************************************************/
/* runtime_node_select.h */
/**************************************************************************/
/* 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. */
/**************************************************************************/
#pragma once
#ifdef DEBUG_ENABLED
#include "scene/gui/view_panner.h"
#ifndef _3D_DISABLED
#include "scene/resources/mesh.h"
#endif // _3D_DISABLED
class PopupMenu;
class RuntimeNodeSelect : public Object {
GDCLASS(RuntimeNodeSelect, Object);
public:
enum NodeType {
NODE_TYPE_NONE,
NODE_TYPE_2D,
NODE_TYPE_3D,
NODE_TYPE_MAX,
};
enum SelectMode {
SELECT_MODE_SINGLE,
SELECT_MODE_LIST,
SELECT_MODE_MAX,
};
private:
friend class SceneDebugger;
NodeType node_select_type = NODE_TYPE_2D;
SelectMode node_select_mode = SELECT_MODE_SINGLE;
struct SelectResult {
Node *item = nullptr;
real_t order = 0;
_FORCE_INLINE_ bool operator<(const SelectResult &p_rr) const { return p_rr.order < order; }
};
const int SELECTION_MIN_AREA = 8 * 8;
enum SelectionDragState {
SELECTION_DRAG_NONE,
SELECTION_DRAG_MOVE,
SELECTION_DRAG_END,
};
SelectionDragState selection_drag_state = SELECTION_DRAG_NONE;
bool has_selection = false;
int max_selection = 1;
Point2 selection_position = Point2(Math::INF, Math::INF);
Rect2 selection_drag_area;
PopupMenu *selection_list = nullptr;
Color selection_area_fill;
Color selection_area_outline;
bool selection_visible = true;
bool selection_update_queued = false;
bool avoid_locked_nodes = false;
bool prefer_group_selection = false;
bool multi_shortcut_pressed = false;
bool list_shortcut_pressed = false;
RID draw_canvas;
RID sel_drag_ci;
bool camera_override = false;
bool camera_first_override = true;
// Values taken from EditorZoomWidget.
const float VIEW_2D_MIN_ZOOM = 1.0 / 128;
const float VIEW_2D_MAX_ZOOM = 128;
Ref<ViewPanner> panner;
Vector2 view_2d_offset;
real_t view_2d_zoom = 1.0;
bool warped_panning = false;
LocalVector<ObjectID> selected_ci_nodes;
real_t sel_2d_grab_dist = 0;
int sel_2d_scale = 1;
RID sbox_2d_ci;
#ifndef _3D_DISABLED
struct Cursor {
Vector3 pos;
real_t x_rot, y_rot, distance, fov_scale;
Vector3 eye_pos; // Used in freelook mode.
Cursor() {
// These rotations place the camera in +X +Y +Z, aka south east, facing north west.
x_rot = 0.5;
y_rot = -0.5;
distance = 4;
fov_scale = 1.0;
}
};
Cursor cursor;
// Values taken from Node3DEditor.
const float VIEW_3D_MIN_ZOOM = 0.01;
#ifdef REAL_T_IS_DOUBLE
const double VIEW_3D_MAX_ZOOM = 1'000'000'000'000;
#else
const float VIEW_3D_MAX_ZOOM = 10'000;
#endif // REAL_T_IS_DOUBLE
const float CAMERA_MIN_FOV_SCALE = 0.1;
const float CAMERA_MAX_FOV_SCALE = 2.5;
bool camera_freelook = false;
real_t camera_fov = 0;
real_t camera_znear = 0;
real_t camera_zfar = 0;
bool invert_x_axis = false;
bool invert_y_axis = false;
bool warped_mouse_panning_3d = false;
real_t freelook_base_speed = 0;
real_t freelook_sensitivity = 0;
real_t orbit_sensitivity = 0;
real_t translation_sensitivity = 0;
Vector2 previous_mouse_position;
struct SelectionBox3D : public RefCounted {
RID instance;
RID instance_ofs;
RID instance_xray;
RID instance_xray_ofs;
Transform3D transform;
AABB bounds;
~SelectionBox3D() {
if (instance.is_valid()) {
RS::get_singleton()->free_rid(instance);
RS::get_singleton()->free_rid(instance_ofs);
RS::get_singleton()->free_rid(instance_xray);
RS::get_singleton()->free_rid(instance_xray_ofs);
}
}
};
HashMap<ObjectID, Ref<SelectionBox3D>> selected_3d_nodes;
Color sbox_3d_color;
Ref<ArrayMesh> sbox_3d_mesh;
Ref<ArrayMesh> sbox_3d_mesh_xray;
RID sbox_3d;
RID sbox_3d_ofs;
RID sbox_3d_xray;
RID sbox_3d_xray_ofs;
#endif // _3D_DISABLED
void _setup(const Dictionary &p_settings);
void _node_set_type(NodeType p_type);
void _select_set_mode(SelectMode p_mode);
void _set_camera_override_enabled(bool p_enabled);
void _root_window_input(const Ref<InputEvent> &p_event);
void _items_popup_index_pressed(int p_index, PopupMenu *p_popup);
void _update_input_state();
void _process_frame();
void _physics_frame();
void _send_ids(const Vector<Node *> &p_picked_nodes, bool p_invert_new_selections = true);
void _set_selected_nodes(const Vector<Node *> &p_nodes);
void _queue_selection_update();
void _update_selection();
void _clear_selection();
void _update_selection_drag(const Point2 &p_end_pos = Point2());
void _set_selection_visible(bool p_visible);
void _set_avoid_locked(bool p_enabled);
void _set_prefer_group(bool p_enabled);
void _open_selection_list(const Vector<SelectResult> &p_items, const Point2 &p_pos);
void _close_selection_list();
void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
void _find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_node, Vector<SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);
void _reset_camera_2d();
void _update_view_2d();
#ifndef _3D_DISABLED
void _find_3d_items_at_pos(const Point2 &p_pos, Vector<SelectResult> &r_items);
void _find_3d_items_at_rect(const Rect2 &p_rect, Vector<SelectResult> &r_items);
Vector3 _get_screen_to_space(const Vector3 &p_vector3);
bool _handle_3d_input(const Ref<InputEvent> &p_event);
void _set_camera_freelook_enabled(bool p_enabled);
void _cursor_scale_distance(real_t p_scale);
void _scale_freelook_speed(real_t p_scale);
void _cursor_look(Ref<InputEventWithModifiers> p_event);
void _cursor_pan(Ref<InputEventWithModifiers> p_event);
void _cursor_orbit(Ref<InputEventWithModifiers> p_event);
Point2 _get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_event, Rect2 p_border) const;
Transform3D _get_cursor_transform();
void _reset_camera_3d();
#endif // _3D_DISABLED
RuntimeNodeSelect() { singleton = this; }
inline static RuntimeNodeSelect *singleton = nullptr;
public:
static RuntimeNodeSelect *get_singleton();
~RuntimeNodeSelect();
};
#endif // DEBUG_ENABLED

File diff suppressed because it is too large Load Diff

View File

@ -33,12 +33,7 @@
#include "core/input/shortcut.h"
#include "core/object/ref_counted.h"
#include "core/string/ustring.h"
#include "core/templates/pair.h"
#include "core/variant/array.h"
#include "scene/gui/view_panner.h"
#ifndef _3D_DISABLED
#include "scene/resources/mesh.h"
#endif // _3D_DISABLED
class CanvasItem;
class LiveEditor;
@ -46,9 +41,6 @@ class PopupMenu;
class RuntimeNodeSelect;
class Script;
class SceneTree;
#ifndef _3D_DISABLED
class Node3D;
#endif // _3D_DISABLED
class SceneDebugger {
private:
@ -135,62 +127,6 @@ public:
};
#ifdef DEBUG_ENABLED
class SceneDebuggerObject {
private:
void _parse_script_properties(Script *p_script, ScriptInstance *p_instance);
public:
typedef Pair<PropertyInfo, Variant> SceneDebuggerProperty;
ObjectID id;
String class_name;
List<SceneDebuggerProperty> properties;
SceneDebuggerObject(ObjectID p_id);
SceneDebuggerObject(Object *p_obj);
SceneDebuggerObject() {}
void serialize(Array &r_arr, int p_max_size = 1 << 20);
void deserialize(const Array &p_arr);
void deserialize(uint64_t p_id, const String &p_class_name, const Array &p_props);
};
class SceneDebuggerTree {
public:
struct RemoteNode {
int child_count = 0;
String name;
String type_name;
ObjectID id;
String scene_file_path;
uint8_t view_flags = 0;
enum ViewFlags {
VIEW_HAS_VISIBLE_METHOD = 1 << 1,
VIEW_VISIBLE = 1 << 2,
VIEW_VISIBLE_IN_TREE = 1 << 3,
};
RemoteNode(int p_child, const String &p_name, const String &p_type, ObjectID p_id, const String p_scene_file_path, int p_view_flags) {
child_count = p_child;
name = p_name;
type_name = p_type;
id = p_id;
scene_file_path = p_scene_file_path;
view_flags = p_view_flags;
}
RemoteNode() {}
};
List<RemoteNode> nodes;
void serialize(Array &r_arr);
void deserialize(const Array &p_arr);
SceneDebuggerTree(Node *p_root);
SceneDebuggerTree() {}
};
class LiveEditor {
private:
friend class SceneDebugger;
@ -234,211 +170,4 @@ private:
public:
static LiveEditor *get_singleton();
};
class RuntimeNodeSelect : public Object {
GDCLASS(RuntimeNodeSelect, Object);
public:
enum NodeType {
NODE_TYPE_NONE,
NODE_TYPE_2D,
NODE_TYPE_3D,
NODE_TYPE_MAX,
};
enum SelectMode {
SELECT_MODE_SINGLE,
SELECT_MODE_LIST,
SELECT_MODE_MAX,
};
private:
friend class SceneDebugger;
NodeType node_select_type = NODE_TYPE_2D;
SelectMode node_select_mode = SELECT_MODE_SINGLE;
struct SelectResult {
Node *item = nullptr;
real_t order = 0;
_FORCE_INLINE_ bool operator<(const SelectResult &p_rr) const { return p_rr.order < order; }
};
const int SELECTION_MIN_AREA = 8 * 8;
enum SelectionDragState {
SELECTION_DRAG_NONE,
SELECTION_DRAG_MOVE,
SELECTION_DRAG_END,
};
SelectionDragState selection_drag_state = SELECTION_DRAG_NONE;
bool has_selection = false;
int max_selection = 1;
Point2 selection_position = Point2(Math::INF, Math::INF);
Rect2 selection_drag_area;
PopupMenu *selection_list = nullptr;
Color selection_area_fill;
Color selection_area_outline;
bool selection_visible = true;
bool selection_update_queued = false;
bool avoid_locked_nodes = false;
bool prefer_group_selection = false;
bool multi_shortcut_pressed = false;
bool list_shortcut_pressed = false;
RID draw_canvas;
RID sel_drag_ci;
bool camera_override = false;
bool camera_first_override = true;
// Values taken from EditorZoomWidget.
const float VIEW_2D_MIN_ZOOM = 1.0 / 128;
const float VIEW_2D_MAX_ZOOM = 128;
Ref<ViewPanner> panner;
Vector2 view_2d_offset;
real_t view_2d_zoom = 1.0;
bool warped_panning = false;
LocalVector<ObjectID> selected_ci_nodes;
real_t sel_2d_grab_dist = 0;
int sel_2d_scale = 1;
RID sbox_2d_ci;
#ifndef _3D_DISABLED
struct Cursor {
Vector3 pos;
real_t x_rot, y_rot, distance, fov_scale;
Vector3 eye_pos; // Used in freelook mode.
Cursor() {
// These rotations place the camera in +X +Y +Z, aka south east, facing north west.
x_rot = 0.5;
y_rot = -0.5;
distance = 4;
fov_scale = 1.0;
}
};
Cursor cursor;
// Values taken from Node3DEditor.
const float VIEW_3D_MIN_ZOOM = 0.01;
#ifdef REAL_T_IS_DOUBLE
const double VIEW_3D_MAX_ZOOM = 1'000'000'000'000;
#else
const float VIEW_3D_MAX_ZOOM = 10'000;
#endif // REAL_T_IS_DOUBLE
const float CAMERA_MIN_FOV_SCALE = 0.1;
const float CAMERA_MAX_FOV_SCALE = 2.5;
bool camera_freelook = false;
real_t camera_fov = 0;
real_t camera_znear = 0;
real_t camera_zfar = 0;
bool invert_x_axis = false;
bool invert_y_axis = false;
bool warped_mouse_panning_3d = false;
real_t freelook_base_speed = 0;
real_t freelook_sensitivity = 0;
real_t orbit_sensitivity = 0;
real_t translation_sensitivity = 0;
Vector2 previous_mouse_position;
struct SelectionBox3D : public RefCounted {
RID instance;
RID instance_ofs;
RID instance_xray;
RID instance_xray_ofs;
Transform3D transform;
AABB bounds;
~SelectionBox3D() {
if (instance.is_valid()) {
RS::get_singleton()->free_rid(instance);
RS::get_singleton()->free_rid(instance_ofs);
RS::get_singleton()->free_rid(instance_xray);
RS::get_singleton()->free_rid(instance_xray_ofs);
}
}
};
HashMap<ObjectID, Ref<SelectionBox3D>> selected_3d_nodes;
Color sbox_3d_color;
Ref<ArrayMesh> sbox_3d_mesh;
Ref<ArrayMesh> sbox_3d_mesh_xray;
RID sbox_3d;
RID sbox_3d_ofs;
RID sbox_3d_xray;
RID sbox_3d_xray_ofs;
#endif // _3D_DISABLED
void _setup(const Dictionary &p_settings);
void _node_set_type(NodeType p_type);
void _select_set_mode(SelectMode p_mode);
void _set_camera_override_enabled(bool p_enabled);
void _root_window_input(const Ref<InputEvent> &p_event);
void _items_popup_index_pressed(int p_index, PopupMenu *p_popup);
void _update_input_state();
void _process_frame();
void _physics_frame();
void _send_ids(const Vector<Node *> &p_picked_nodes, bool p_invert_new_selections = true);
void _set_selected_nodes(const Vector<Node *> &p_nodes);
void _queue_selection_update();
void _update_selection();
void _clear_selection();
void _update_selection_drag(const Point2 &p_end_pos = Point2());
void _set_selection_visible(bool p_visible);
void _set_avoid_locked(bool p_enabled);
void _set_prefer_group(bool p_enabled);
void _open_selection_list(const Vector<SelectResult> &p_items, const Point2 &p_pos);
void _close_selection_list();
void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
void _find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_node, Vector<SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);
void _reset_camera_2d();
void _update_view_2d();
#ifndef _3D_DISABLED
void _find_3d_items_at_pos(const Point2 &p_pos, Vector<SelectResult> &r_items);
void _find_3d_items_at_rect(const Rect2 &p_rect, Vector<SelectResult> &r_items);
Vector3 _get_screen_to_space(const Vector3 &p_vector3);
bool _handle_3d_input(const Ref<InputEvent> &p_event);
void _set_camera_freelook_enabled(bool p_enabled);
void _cursor_scale_distance(real_t p_scale);
void _scale_freelook_speed(real_t p_scale);
void _cursor_look(Ref<InputEventWithModifiers> p_event);
void _cursor_pan(Ref<InputEventWithModifiers> p_event);
void _cursor_orbit(Ref<InputEventWithModifiers> p_event);
Point2 _get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_event, Rect2 p_border) const;
Transform3D _get_cursor_transform();
void _reset_camera_3d();
#endif // _3D_DISABLED
RuntimeNodeSelect() { singleton = this; }
inline static RuntimeNodeSelect *singleton = nullptr;
public:
static RuntimeNodeSelect *get_singleton();
~RuntimeNodeSelect();
};
#endif // DEBUG_ENABLED

View File

@ -0,0 +1,319 @@
/**************************************************************************/
/* scene_debugger_object.cpp */
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifdef DEBUG_ENABLED
#include "scene_debugger_object.h"
#include "core/io/marshalls.h"
#include "core/object/script_language.h"
SceneDebuggerObject::SceneDebuggerObject(Object *p_obj) {
if (!p_obj) {
return;
}
id = p_obj->get_instance_id();
class_name = p_obj->get_class();
if (ScriptInstance *si = p_obj->get_script_instance()) {
// Read script instance constants and variables.
if (!si->get_script().is_null()) {
Script *s = si->get_script().ptr();
_parse_script_properties(s, si);
}
}
if (Node *node = Object::cast_to<Node>(p_obj)) {
// For debugging multiplayer.
{
PropertyInfo pi(Variant::INT, String("Node/multiplayer_authority"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY);
properties.push_back(SceneDebuggerProperty(pi, node->get_multiplayer_authority()));
}
// Add specialized NodePath info (if inside tree).
if (node->is_inside_tree()) {
PropertyInfo pi(Variant::NODE_PATH, String("Node/path"));
properties.push_back(SceneDebuggerProperty(pi, node->get_path()));
} else { // Can't ask for path if a node is not in tree.
PropertyInfo pi(Variant::STRING, String("Node/path"));
properties.push_back(SceneDebuggerProperty(pi, "[Orphan]"));
}
} else if (Script *s = Object::cast_to<Script>(p_obj)) {
// Add script constants (no instance).
_parse_script_properties(s, nullptr);
}
// Add base object properties.
List<PropertyInfo> pinfo;
p_obj->get_property_list(&pinfo, true);
for (const PropertyInfo &E : pinfo) {
if (E.usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) {
properties.push_back(SceneDebuggerProperty(E, p_obj->get(E.name)));
}
}
}
void SceneDebuggerObject::_parse_script_properties(Script *p_script, ScriptInstance *p_instance) {
typedef HashMap<const Script *, HashSet<StringName>> ScriptMemberMap;
typedef HashMap<const Script *, HashMap<StringName, Variant>> ScriptConstantsMap;
ScriptMemberMap members;
if (p_instance) {
members[p_script] = HashSet<StringName>();
p_script->get_members(&(members[p_script]));
}
ScriptConstantsMap constants;
constants[p_script] = HashMap<StringName, Variant>();
p_script->get_constants(&(constants[p_script]));
Ref<Script> base = p_script->get_base_script();
while (base.is_valid()) {
if (p_instance) {
members[base.ptr()] = HashSet<StringName>();
base->get_members(&(members[base.ptr()]));
}
constants[base.ptr()] = HashMap<StringName, Variant>();
base->get_constants(&(constants[base.ptr()]));
base = base->get_base_script();
}
HashSet<String> exported_members;
if (p_instance) {
List<PropertyInfo> pinfo;
p_instance->get_property_list(&pinfo);
for (const PropertyInfo &E : pinfo) {
if (E.usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) {
exported_members.insert(E.name);
}
}
}
// Members
for (KeyValue<const Script *, HashSet<StringName>> sm : members) {
for (const StringName &E : sm.value) {
if (exported_members.has(E)) {
continue; // Exported variables already show up in the inspector.
}
if (String(E).begins_with("@")) {
continue; // Skip groups.
}
Variant m;
if (p_instance->get(E, m)) {
String script_path = sm.key == p_script ? "" : sm.key->get_path().get_file() + "/";
PropertyInfo pi(m.get_type(), "Members/" + script_path + E);
properties.push_back(SceneDebuggerProperty(pi, m));
}
}
}
// Constants
for (KeyValue<const Script *, HashMap<StringName, Variant>> &sc : constants) {
for (const KeyValue<StringName, Variant> &E : sc.value) {
String script_path = sc.key == p_script ? "" : sc.key->get_path().get_file() + "/";
if (E.value.get_type() == Variant::OBJECT) {
Variant inst_id = ((Object *)E.value)->get_instance_id();
PropertyInfo pi(inst_id.get_type(), "Constants/" + E.key, PROPERTY_HINT_OBJECT_ID, "Object");
properties.push_back(SceneDebuggerProperty(pi, inst_id));
} else {
PropertyInfo pi(E.value.get_type(), "Constants/" + script_path + E.key);
properties.push_back(SceneDebuggerProperty(pi, E.value));
}
}
}
}
void SceneDebuggerObject::serialize(Array &r_arr, int p_max_size) {
Array send_props;
for (SceneDebuggerProperty &property : properties) {
const PropertyInfo &pi = property.first;
Variant &var = property.second;
Ref<Resource> res = var;
Array prop = { pi.name, pi.type };
PropertyHint hint = pi.hint;
String hint_string = pi.hint_string;
if (res.is_valid() && !res->get_path().is_empty()) {
var = res->get_path();
} else { //only send information that can be sent..
int len = 0; //test how big is this to encode
encode_variant(var, nullptr, len);
if (len > p_max_size) { //limit to max size
hint = PROPERTY_HINT_OBJECT_TOO_BIG;
hint_string = "";
var = Variant();
}
}
prop.push_back(hint);
prop.push_back(hint_string);
prop.push_back(pi.usage);
prop.push_back(var);
send_props.push_back(prop);
}
r_arr.push_back(uint64_t(id));
r_arr.push_back(class_name);
r_arr.push_back(send_props);
}
#define CHECK_TYPE(p_what, p_type) ERR_FAIL_COND(p_what.get_type() != Variant::p_type)
void SceneDebuggerObject::deserialize(const Array &p_arr) {
ERR_FAIL_COND(p_arr.size() < 3);
CHECK_TYPE(p_arr[0], INT);
CHECK_TYPE(p_arr[1], STRING);
CHECK_TYPE(p_arr[2], ARRAY);
deserialize(uint64_t(p_arr[0]), p_arr[1], p_arr[2]);
}
void SceneDebuggerObject::deserialize(uint64_t p_id, const String &p_class_name, const Array &p_props) {
id = p_id;
class_name = p_class_name;
for (int i = 0; i < p_props.size(); i++) {
CHECK_TYPE(p_props[i], ARRAY);
Array prop = p_props[i];
ERR_FAIL_COND(prop.size() != 6);
CHECK_TYPE(prop[0], STRING);
CHECK_TYPE(prop[1], INT);
CHECK_TYPE(prop[2], INT);
CHECK_TYPE(prop[3], STRING);
CHECK_TYPE(prop[4], INT);
PropertyInfo pinfo;
pinfo.name = prop[0];
pinfo.type = Variant::Type(int(prop[1]));
pinfo.hint = PropertyHint(int(prop[2]));
pinfo.hint_string = prop[3];
pinfo.usage = PropertyUsageFlags(int(prop[4]));
Variant var = prop[5];
if (pinfo.type == Variant::OBJECT) {
if (var.is_zero()) {
var = Ref<Resource>();
} else if (var.get_type() == Variant::OBJECT) {
if (((Object *)var)->is_class("EncodedObjectAsID")) {
var = Object::cast_to<EncodedObjectAsID>(var)->get_object_id();
pinfo.type = var.get_type();
pinfo.hint = PROPERTY_HINT_OBJECT_ID;
pinfo.hint_string = "Object";
}
}
}
properties.push_back(SceneDebuggerProperty(pinfo, var));
}
}
SceneDebuggerTree::SceneDebuggerTree(Node *p_root) {
// Flatten tree into list, depth first, use stack to avoid recursion.
List<Node *> stack;
stack.push_back(p_root);
bool is_root = true;
const StringName &is_visible_sn = SNAME("is_visible");
const StringName &is_visible_in_tree_sn = SNAME("is_visible_in_tree");
while (stack.size()) {
Node *n = stack.front()->get();
stack.pop_front();
int count = n->get_child_count();
for (int i = 0; i < count; i++) {
stack.push_front(n->get_child(count - i - 1));
}
int view_flags = 0;
if (is_root) {
// Prevent root window visibility from being changed.
is_root = false;
} else if (n->has_method(is_visible_sn)) {
const Variant visible = n->call(is_visible_sn);
if (visible.get_type() == Variant::BOOL) {
view_flags = RemoteNode::VIEW_HAS_VISIBLE_METHOD;
view_flags |= uint8_t(visible) * RemoteNode::VIEW_VISIBLE;
}
if (n->has_method(is_visible_in_tree_sn)) {
const Variant visible_in_tree = n->call(is_visible_in_tree_sn);
if (visible_in_tree.get_type() == Variant::BOOL) {
view_flags |= uint8_t(visible_in_tree) * RemoteNode::VIEW_VISIBLE_IN_TREE;
}
}
}
String class_name;
ScriptInstance *script_instance = n->get_script_instance();
if (script_instance) {
Ref<Script> script = script_instance->get_script();
if (script.is_valid()) {
class_name = script->get_global_name();
if (class_name.is_empty()) {
// If there is no class_name in this script we just take the script path.
class_name = script->get_path();
}
}
}
nodes.push_back(RemoteNode(count, n->get_name(), class_name.is_empty() ? n->get_class() : class_name, n->get_instance_id(), n->get_scene_file_path(), view_flags));
}
}
void SceneDebuggerTree::serialize(Array &p_arr) {
for (const RemoteNode &n : nodes) {
p_arr.push_back(n.child_count);
p_arr.push_back(n.name);
p_arr.push_back(n.type_name);
p_arr.push_back(n.id);
p_arr.push_back(n.scene_file_path);
p_arr.push_back(n.view_flags);
}
}
void SceneDebuggerTree::deserialize(const Array &p_arr) {
int idx = 0;
while (p_arr.size() > idx) {
ERR_FAIL_COND(p_arr.size() < 6);
CHECK_TYPE(p_arr[idx], INT); // child_count.
CHECK_TYPE(p_arr[idx + 1], STRING); // name.
CHECK_TYPE(p_arr[idx + 2], STRING); // type_name.
CHECK_TYPE(p_arr[idx + 3], INT); // id.
CHECK_TYPE(p_arr[idx + 4], STRING); // scene_file_path.
CHECK_TYPE(p_arr[idx + 5], INT); // view_flags.
nodes.push_back(RemoteNode(p_arr[idx], p_arr[idx + 1], p_arr[idx + 2], p_arr[idx + 3], p_arr[idx + 4], p_arr[idx + 5]));
idx += 6;
}
}
#undef CHECK_TYPE
#endif // DEBUG_ENABLED

View File

@ -0,0 +1,92 @@
/**************************************************************************/
/* scene_debugger_object.h */
/**************************************************************************/
/* 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. */
/**************************************************************************/
#pragma once
#ifdef DEBUG_ENABLED
#include "scene/main/node.h"
class SceneDebuggerObject {
private:
void _parse_script_properties(Script *p_script, ScriptInstance *p_instance);
public:
typedef Pair<PropertyInfo, Variant> SceneDebuggerProperty;
ObjectID id;
String class_name;
List<SceneDebuggerProperty> properties;
SceneDebuggerObject(ObjectID p_id);
SceneDebuggerObject(Object *p_obj);
SceneDebuggerObject() {}
void serialize(Array &r_arr, int p_max_size = 1 << 20);
void deserialize(const Array &p_arr);
void deserialize(uint64_t p_id, const String &p_class_name, const Array &p_props);
};
class SceneDebuggerTree {
public:
struct RemoteNode {
int child_count = 0;
String name;
String type_name;
ObjectID id;
String scene_file_path;
uint8_t view_flags = 0;
enum ViewFlags {
VIEW_HAS_VISIBLE_METHOD = 1 << 1,
VIEW_VISIBLE = 1 << 2,
VIEW_VISIBLE_IN_TREE = 1 << 3,
};
RemoteNode(int p_child, const String &p_name, const String &p_type, ObjectID p_id, const String p_scene_file_path, int p_view_flags) {
child_count = p_child;
name = p_name;
type_name = p_type;
id = p_id;
scene_file_path = p_scene_file_path;
view_flags = p_view_flags;
}
RemoteNode() {}
};
List<RemoteNode> nodes;
void serialize(Array &r_arr);
void deserialize(const Array &p_arr);
SceneDebuggerTree(Node *p_root);
SceneDebuggerTree() {}
};
#endif // DEBUG_ENABLED