feat: modules moved and engine moved to submodule
This commit is contained in:
parent
dfb5e645cd
commit
c33d2130cc
5136 changed files with 225275 additions and 64485 deletions
|
|
@ -144,9 +144,7 @@ Dictionary DebugAdapterParser::req_initialize(const Dictionary &p_params) const
|
|||
// Send all current breakpoints
|
||||
List<String> breakpoints;
|
||||
ScriptEditor::get_singleton()->get_breakpoints(&breakpoints);
|
||||
for (List<String>::Element *E = breakpoints.front(); E; E = E->next()) {
|
||||
String breakpoint = E->get();
|
||||
|
||||
for (const String &breakpoint : breakpoints) {
|
||||
String path = breakpoint.left(breakpoint.find_char(':', 6)); // Skip initial part of path, aka "res://"
|
||||
int line = breakpoint.substr(path.size()).to_int();
|
||||
|
||||
|
|
@ -301,12 +299,11 @@ Dictionary DebugAdapterParser::req_threads(const Dictionary &p_params) const {
|
|||
Dictionary response = prepare_success_response(p_params), body;
|
||||
response["body"] = body;
|
||||
|
||||
Array arr;
|
||||
DAP::Thread thread;
|
||||
|
||||
thread.id = 1; // Hardcoded because Godot only supports debugging one thread at the moment
|
||||
thread.name = "Main";
|
||||
arr.push_back(thread.to_json());
|
||||
Array arr = { thread.to_json() };
|
||||
body["threads"] = arr;
|
||||
|
||||
return response;
|
||||
|
|
@ -325,8 +322,7 @@ Dictionary DebugAdapterParser::req_stackTrace(const Dictionary &p_params) const
|
|||
|
||||
Array arr;
|
||||
DebugAdapterProtocol *dap = DebugAdapterProtocol::get_singleton();
|
||||
for (const KeyValue<DAP::StackFrame, List<int>> &E : dap->stackframe_list) {
|
||||
DAP::StackFrame sf = E.key;
|
||||
for (DAP::StackFrame sf : dap->stackframe_list) {
|
||||
if (!lines_at_one) {
|
||||
sf.line--;
|
||||
}
|
||||
|
|
@ -360,7 +356,7 @@ Dictionary DebugAdapterParser::req_setBreakpoints(const Dictionary &p_params) co
|
|||
|
||||
// If path contains \, it's a Windows path, so we need to convert it to /, and make the drive letter uppercase
|
||||
if (source.path.contains_char('\\')) {
|
||||
source.path = source.path.replace("\\", "/");
|
||||
source.path = source.path.replace_char('\\', '/');
|
||||
source.path = source.path.substr(0, 1).to_upper() + source.path.substr(1);
|
||||
}
|
||||
|
||||
|
|
@ -372,6 +368,8 @@ Dictionary DebugAdapterParser::req_setBreakpoints(const Dictionary &p_params) co
|
|||
lines.push_back(breakpoint.line + !lines_at_one);
|
||||
}
|
||||
|
||||
// Always update the source checksum for the requested path, as it might have been modified externally.
|
||||
DebugAdapterProtocol::get_singleton()->update_source(source.path);
|
||||
Array updated_breakpoints = DebugAdapterProtocol::get_singleton()->update_breakpoints(source.path, lines);
|
||||
body["breakpoints"] = updated_breakpoints;
|
||||
|
||||
|
|
@ -383,13 +381,12 @@ Dictionary DebugAdapterParser::req_breakpointLocations(const Dictionary &p_param
|
|||
response["body"] = body;
|
||||
Dictionary args = p_params["arguments"];
|
||||
|
||||
Array locations;
|
||||
DAP::BreakpointLocation location;
|
||||
location.line = args["line"];
|
||||
if (args.has("endLine")) {
|
||||
location.endLine = args["endLine"];
|
||||
}
|
||||
locations.push_back(location.to_json());
|
||||
Array locations = { location.to_json() };
|
||||
|
||||
body["breakpoints"] = locations;
|
||||
return response;
|
||||
|
|
@ -403,15 +400,13 @@ Dictionary DebugAdapterParser::req_scopes(const Dictionary &p_params) const {
|
|||
int frame_id = args["frameId"];
|
||||
Array scope_list;
|
||||
|
||||
DAP::StackFrame frame;
|
||||
frame.id = frame_id;
|
||||
HashMap<DAP::StackFrame, List<int>, DAP::StackFrame>::Iterator E = DebugAdapterProtocol::get_singleton()->stackframe_list.find(frame);
|
||||
HashMap<DebugAdapterProtocol::DAPStackFrameID, Vector<int>>::Iterator E = DebugAdapterProtocol::get_singleton()->scope_list.find(frame_id);
|
||||
if (E) {
|
||||
ERR_FAIL_COND_V(E->value.size() != 3, prepare_error_response(p_params, DAP::ErrorType::UNKNOWN));
|
||||
List<int>::ConstIterator itr = E->value.begin();
|
||||
for (int i = 0; i < 3; ++itr, ++i) {
|
||||
const Vector<int> &scope_ids = E->value;
|
||||
ERR_FAIL_COND_V(scope_ids.size() != 3, prepare_error_response(p_params, DAP::ErrorType::UNKNOWN));
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
DAP::Scope scope;
|
||||
scope.variablesReference = *itr;
|
||||
scope.variablesReference = scope_ids[i];
|
||||
switch (i) {
|
||||
case 0:
|
||||
scope.name = "Locals";
|
||||
|
|
@ -595,8 +590,7 @@ Dictionary DebugAdapterParser::ev_stopped_breakpoint(const int &p_id) const {
|
|||
body["reason"] = "breakpoint";
|
||||
body["description"] = "Breakpoint";
|
||||
|
||||
Array breakpoints;
|
||||
breakpoints.push_back(p_id);
|
||||
Array breakpoints = { p_id };
|
||||
body["hitBreakpointIds"] = breakpoints;
|
||||
|
||||
return event;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEBUG_ADAPTER_PARSER_H
|
||||
#define DEBUG_ADAPTER_PARSER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/debugger/remote_debugger.h"
|
||||
|
|
@ -49,7 +48,7 @@ private:
|
|||
// If path contains \, it's a Windows path, so we need to convert it to /, and check as case-insensitive.
|
||||
if (p_path.contains_char('\\')) {
|
||||
String project_path = ProjectSettings::get_singleton()->get_resource_path();
|
||||
String path = p_path.replace("\\", "/");
|
||||
String path = p_path.replace_char('\\', '/');
|
||||
return path.containsn(project_path);
|
||||
}
|
||||
return p_path.begins_with(ProjectSettings::get_singleton()->get_resource_path());
|
||||
|
|
@ -103,5 +102,3 @@ public:
|
|||
Dictionary ev_custom_data(const String &p_msg, const Array &p_data) const;
|
||||
Dictionary ev_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled) const;
|
||||
};
|
||||
|
||||
#endif // DEBUG_ADAPTER_PARSER_H
|
||||
|
|
|
|||
|
|
@ -66,8 +66,7 @@ Error DAPeer::handle_data() {
|
|||
// End of headers
|
||||
if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
|
||||
r[l - 3] = '\0'; // Null terminate to read string
|
||||
String header;
|
||||
header.parse_utf8(r);
|
||||
String header = String::utf8(r);
|
||||
content_length = header.substr(16).to_int();
|
||||
has_header = true;
|
||||
req_pos = 0;
|
||||
|
|
@ -93,8 +92,7 @@ Error DAPeer::handle_data() {
|
|||
}
|
||||
|
||||
// Parse data
|
||||
String msg;
|
||||
msg.parse_utf8((const char *)req_buf, req_pos);
|
||||
String msg = String::utf8((const char *)req_buf, req_pos);
|
||||
|
||||
// Apply a timestamp if it there's none yet
|
||||
if (!timestamp) {
|
||||
|
|
@ -118,12 +116,12 @@ Error DAPeer::send_data() {
|
|||
if (!data.has("seq")) {
|
||||
data["seq"] = ++seq;
|
||||
}
|
||||
String formatted_data = format_output(data);
|
||||
const Vector<uint8_t> &formatted_data = format_output(data);
|
||||
|
||||
int data_sent = 0;
|
||||
while (data_sent < formatted_data.length()) {
|
||||
while (data_sent < formatted_data.size()) {
|
||||
int curr_sent = 0;
|
||||
Error err = connection->put_partial_data((const uint8_t *)formatted_data.utf8().get_data(), formatted_data.size() - data_sent - 1, curr_sent);
|
||||
Error err = connection->put_partial_data(formatted_data.ptr() + data_sent, formatted_data.size() - data_sent, curr_sent);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
|
@ -134,15 +132,12 @@ Error DAPeer::send_data() {
|
|||
return OK;
|
||||
}
|
||||
|
||||
String DAPeer::format_output(const Dictionary &p_params) const {
|
||||
String response = Variant(p_params).to_json_string();
|
||||
String header = "Content-Length: ";
|
||||
CharString charstr = response.utf8();
|
||||
size_t len = charstr.length();
|
||||
header += itos(len);
|
||||
header += "\r\n\r\n";
|
||||
Vector<uint8_t> DAPeer::format_output(const Dictionary &p_params) const {
|
||||
const Vector<uint8_t> &content = Variant(p_params).to_json_string().to_utf8_buffer();
|
||||
Vector<uint8_t> response = vformat("Content-Length: %d\r\n\r\n", content.size()).to_utf8_buffer();
|
||||
|
||||
return header + response;
|
||||
response.append_array(content);
|
||||
return response;
|
||||
}
|
||||
|
||||
Error DebugAdapterProtocol::on_client_connected() {
|
||||
|
|
@ -176,6 +171,7 @@ void DebugAdapterProtocol::reset_current_info() {
|
|||
void DebugAdapterProtocol::reset_ids() {
|
||||
breakpoint_id = 0;
|
||||
breakpoint_list.clear();
|
||||
breakpoint_source_list.clear();
|
||||
|
||||
reset_stack_info();
|
||||
}
|
||||
|
|
@ -185,6 +181,7 @@ void DebugAdapterProtocol::reset_stack_info() {
|
|||
variable_id = 1;
|
||||
|
||||
stackframe_list.clear();
|
||||
scope_list.clear();
|
||||
variable_list.clear();
|
||||
object_list.clear();
|
||||
object_pending_set.clear();
|
||||
|
|
@ -205,9 +202,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
x.value = rtos(vec.x);
|
||||
y.value = rtos(vec.y);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
Array arr = { x.to_json(), y.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -230,11 +225,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
w.value = rtos(rect.size.x);
|
||||
h.value = rtos(rect.size.y);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
arr.push_back(w.to_json());
|
||||
arr.push_back(h.to_json());
|
||||
Array arr = { x.to_json(), y.to_json(), w.to_json(), h.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -254,10 +245,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
y.value = rtos(vec.y);
|
||||
z.value = rtos(vec.z);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
arr.push_back(z.to_json());
|
||||
Array arr = { x.to_json(), y.to_json(), z.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -279,10 +267,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
y.variablesReference = parse_variant(transform.columns[1]);
|
||||
origin.variablesReference = parse_variant(transform.columns[2]);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
arr.push_back(origin.to_json());
|
||||
Array arr = { x.to_json(), y.to_json(), origin.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -298,9 +283,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
normal.value = plane.normal;
|
||||
normal.variablesReference = parse_variant(plane.normal);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(d.to_json());
|
||||
arr.push_back(normal.to_json());
|
||||
Array arr = { d.to_json(), normal.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -322,11 +305,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
z.value = rtos(quat.z);
|
||||
w.value = rtos(quat.w);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
arr.push_back(z.to_json());
|
||||
arr.push_back(w.to_json());
|
||||
Array arr = { x.to_json(), y.to_json(), z.to_json(), w.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -344,9 +323,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
position.variablesReference = parse_variant(aabb.position);
|
||||
size.variablesReference = parse_variant(aabb.size);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(position.to_json());
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { position.to_json(), size.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -368,10 +345,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
y.variablesReference = parse_variant(basis.rows[1]);
|
||||
z.variablesReference = parse_variant(basis.rows[2]);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
arr.push_back(z.to_json());
|
||||
Array arr = { x.to_json(), y.to_json(), z.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -388,9 +362,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
basis.variablesReference = parse_variant(transform.basis);
|
||||
origin.variablesReference = parse_variant(transform.origin);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(basis.to_json());
|
||||
arr.push_back(origin.to_json());
|
||||
Array arr = { basis.to_json(), origin.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -412,11 +384,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
b.value = rtos(color.b);
|
||||
a.value = rtos(color.a);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(r.to_json());
|
||||
arr.push_back(g.to_json());
|
||||
arr.push_back(b.to_json());
|
||||
arr.push_back(a.to_json());
|
||||
Array arr = { r.to_json(), g.to_json(), b.to_json(), a.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -428,8 +396,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -447,10 +414,10 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
Dictionary dictionary = p_var;
|
||||
Array arr;
|
||||
|
||||
for (int i = 0; i < dictionary.size(); i++) {
|
||||
for (const KeyValue<Variant, Variant> &kv : dictionary) {
|
||||
DAP::Variable var;
|
||||
var.name = dictionary.get_key_at_index(i);
|
||||
Variant value = dictionary.get_value_at_index(i);
|
||||
var.name = kv.key;
|
||||
Variant value = kv.value;
|
||||
var.type = Variant::get_type_name(value.get_type());
|
||||
var.value = value;
|
||||
var.variablesReference = parse_variant(value);
|
||||
|
|
@ -467,8 +434,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -488,8 +454,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -509,8 +474,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -530,8 +494,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -551,8 +514,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -572,8 +534,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -593,8 +554,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -615,8 +575,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -637,8 +596,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -843,7 +801,9 @@ bool DebugAdapterProtocol::request_remote_object(const ObjectID &p_object_id) {
|
|||
return false;
|
||||
}
|
||||
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_object(p_object_id);
|
||||
TypedArray<uint64_t> arr;
|
||||
arr.append(p_object_id);
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_objects(arr);
|
||||
object_pending_set.insert(p_object_id);
|
||||
|
||||
return true;
|
||||
|
|
@ -861,6 +821,30 @@ bool DebugAdapterProtocol::request_remote_evaluate(const String &p_eval, int p_s
|
|||
return true;
|
||||
}
|
||||
|
||||
const DAP::Source &DebugAdapterProtocol::fetch_source(const String &p_path) {
|
||||
const String &global_path = ProjectSettings::get_singleton()->globalize_path(p_path);
|
||||
|
||||
HashMap<String, DAP::Source>::Iterator E = breakpoint_source_list.find(global_path);
|
||||
if (E != breakpoint_source_list.end()) {
|
||||
return E->value;
|
||||
}
|
||||
DAP::Source &added_source = breakpoint_source_list.insert(global_path, DAP::Source())->value;
|
||||
added_source.name = global_path.get_file();
|
||||
added_source.path = global_path;
|
||||
added_source.compute_checksums();
|
||||
|
||||
return added_source;
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::update_source(const String &p_path) {
|
||||
const String &global_path = ProjectSettings::get_singleton()->globalize_path(p_path);
|
||||
|
||||
HashMap<String, DAP::Source>::Iterator E = breakpoint_source_list.find(global_path);
|
||||
if (E != breakpoint_source_list.end()) {
|
||||
E->value.compute_checksums();
|
||||
}
|
||||
}
|
||||
|
||||
bool DebugAdapterProtocol::process_message(const String &p_text) {
|
||||
JSON json;
|
||||
ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Malformed message!");
|
||||
|
|
@ -878,8 +862,7 @@ bool DebugAdapterProtocol::process_message(const String &p_text) {
|
|||
if (parser->has_method(command)) {
|
||||
_current_request = params["command"];
|
||||
|
||||
Array args;
|
||||
args.push_back(params);
|
||||
Array args = { params };
|
||||
Dictionary response = parser->callv(command, args);
|
||||
if (!response.is_empty()) {
|
||||
_current_peer->res_queue.push_front(response);
|
||||
|
|
@ -904,66 +887,66 @@ void DebugAdapterProtocol::notify_process() {
|
|||
String launch_mode = _current_peer->attached ? "attach" : "launch";
|
||||
|
||||
Dictionary event = parser->ev_process(launch_mode);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_terminated() {
|
||||
Dictionary event = parser->ev_terminated();
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
if ((_current_request == "launch" || _current_request == "restart") && _current_peer == E->get()) {
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
if ((_current_request == "launch" || _current_request == "restart") && _current_peer == peer) {
|
||||
continue;
|
||||
}
|
||||
E->get()->res_queue.push_back(event);
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_exited(const int &p_exitcode) {
|
||||
Dictionary event = parser->ev_exited(p_exitcode);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
if ((_current_request == "launch" || _current_request == "restart") && _current_peer == E->get()) {
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
if ((_current_request == "launch" || _current_request == "restart") && _current_peer == peer) {
|
||||
continue;
|
||||
}
|
||||
E->get()->res_queue.push_back(event);
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_stopped_paused() {
|
||||
Dictionary event = parser->ev_stopped_paused();
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_stopped_exception(const String &p_error) {
|
||||
Dictionary event = parser->ev_stopped_exception(p_error);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_stopped_breakpoint(const int &p_id) {
|
||||
Dictionary event = parser->ev_stopped_breakpoint(p_id);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_stopped_step() {
|
||||
Dictionary event = parser->ev_stopped_step();
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_continued() {
|
||||
Dictionary event = parser->ev_continued();
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
if (_current_request == "continue" && E->get() == _current_peer) {
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
if (_current_request == "continue" && peer == _current_peer) {
|
||||
continue;
|
||||
}
|
||||
E->get()->res_queue.push_back(event);
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
|
||||
reset_stack_info();
|
||||
|
|
@ -971,15 +954,14 @@ void DebugAdapterProtocol::notify_continued() {
|
|||
|
||||
void DebugAdapterProtocol::notify_output(const String &p_message, RemoteDebugger::MessageType p_type) {
|
||||
Dictionary event = parser->ev_output(p_message, p_type);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_custom_data(const String &p_msg, const Array &p_data) {
|
||||
Dictionary event = parser->ev_custom_data(p_msg, p_data);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
Ref<DAPeer> peer = E->get();
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
if (peer->supportsCustomData) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
|
|
@ -988,11 +970,11 @@ void DebugAdapterProtocol::notify_custom_data(const String &p_msg, const Array &
|
|||
|
||||
void DebugAdapterProtocol::notify_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled) {
|
||||
Dictionary event = parser->ev_breakpoint(p_breakpoint, p_enabled);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
if (_current_request == "setBreakpoints" && E->get() == _current_peer) {
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
if (_current_request == "setBreakpoints" && peer == _current_peer) {
|
||||
continue;
|
||||
}
|
||||
E->get()->res_queue.push_back(event);
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1001,23 +983,40 @@ Array DebugAdapterProtocol::update_breakpoints(const String &p_path, const Array
|
|||
|
||||
// Add breakpoints
|
||||
for (int i = 0; i < p_lines.size(); i++) {
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, p_lines[i], true);
|
||||
DAP::Breakpoint breakpoint;
|
||||
DAP::Breakpoint breakpoint(fetch_source(p_path));
|
||||
breakpoint.line = p_lines[i];
|
||||
breakpoint.source.path = p_path;
|
||||
|
||||
ERR_FAIL_COND_V(!breakpoint_list.find(breakpoint), Array());
|
||||
updated_breakpoints.push_back(breakpoint_list.find(breakpoint)->get().to_json());
|
||||
// Avoid duplicated entries.
|
||||
List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);
|
||||
if (E) {
|
||||
updated_breakpoints.push_back(E->get().to_json());
|
||||
continue;
|
||||
}
|
||||
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, p_lines[i], true);
|
||||
|
||||
// Breakpoints are inserted at the end of the breakpoint list.
|
||||
List<DAP::Breakpoint>::Element *added_breakpoint = breakpoint_list.back();
|
||||
ERR_FAIL_NULL_V(added_breakpoint, Array());
|
||||
ERR_FAIL_COND_V(!(added_breakpoint->get() == breakpoint), Array());
|
||||
updated_breakpoints.push_back(added_breakpoint->get().to_json());
|
||||
}
|
||||
|
||||
// Remove breakpoints
|
||||
for (List<DAP::Breakpoint>::Element *E = breakpoint_list.front(); E; E = E->next()) {
|
||||
DAP::Breakpoint b = E->get();
|
||||
if (b.source.path == p_path && !p_lines.has(b.line)) {
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, b.line, false);
|
||||
// Must be deferred because we are iterating the breakpoint list.
|
||||
Vector<int> to_remove;
|
||||
|
||||
for (const DAP::Breakpoint &b : breakpoint_list) {
|
||||
if (b.source->path == p_path && !p_lines.has(b.line)) {
|
||||
to_remove.push_back(b.line);
|
||||
}
|
||||
}
|
||||
|
||||
// Safe to remove queued data now.
|
||||
for (const int &line : to_remove) {
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, line, false);
|
||||
}
|
||||
|
||||
return updated_breakpoints;
|
||||
}
|
||||
|
||||
|
|
@ -1032,6 +1031,7 @@ void DebugAdapterProtocol::on_debug_paused() {
|
|||
void DebugAdapterProtocol::on_debug_stopped() {
|
||||
notify_exited();
|
||||
notify_terminated();
|
||||
reset_ids();
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::on_debug_output(const String &p_message, int p_type) {
|
||||
|
|
@ -1059,10 +1059,8 @@ void DebugAdapterProtocol::on_debug_breaked(const bool &p_reallydid, const bool
|
|||
}
|
||||
|
||||
void DebugAdapterProtocol::on_debug_breakpoint_toggled(const String &p_path, const int &p_line, const bool &p_enabled) {
|
||||
DAP::Breakpoint breakpoint;
|
||||
DAP::Breakpoint breakpoint(fetch_source(p_path));
|
||||
breakpoint.verified = true;
|
||||
breakpoint.source.path = ProjectSettings::get_singleton()->globalize_path(p_path);
|
||||
breakpoint.source.compute_checksums();
|
||||
breakpoint.line = p_line;
|
||||
|
||||
if (p_enabled) {
|
||||
|
|
@ -1085,8 +1083,7 @@ void DebugAdapterProtocol::on_debug_stack_dump(const Array &p_stack_dump) {
|
|||
if (_processing_breakpoint && !p_stack_dump.is_empty()) {
|
||||
// Find existing breakpoint
|
||||
Dictionary d = p_stack_dump[0];
|
||||
DAP::Breakpoint breakpoint;
|
||||
breakpoint.source.path = ProjectSettings::get_singleton()->globalize_path(d["file"]);
|
||||
DAP::Breakpoint breakpoint(fetch_source(d["file"]));
|
||||
breakpoint.line = d["line"];
|
||||
|
||||
List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);
|
||||
|
|
@ -1099,25 +1096,26 @@ void DebugAdapterProtocol::on_debug_stack_dump(const Array &p_stack_dump) {
|
|||
|
||||
stackframe_id = 0;
|
||||
stackframe_list.clear();
|
||||
scope_list.clear();
|
||||
|
||||
// Fill in stacktrace information
|
||||
for (int i = 0; i < p_stack_dump.size(); i++) {
|
||||
Dictionary stack_info = p_stack_dump[i];
|
||||
DAP::StackFrame stackframe;
|
||||
|
||||
DAP::StackFrame stackframe(fetch_source(stack_info["file"]));
|
||||
stackframe.id = stackframe_id++;
|
||||
stackframe.name = stack_info["function"];
|
||||
stackframe.line = stack_info["line"];
|
||||
stackframe.column = 0;
|
||||
stackframe.source.path = ProjectSettings::get_singleton()->globalize_path(stack_info["file"]);
|
||||
stackframe.source.compute_checksums();
|
||||
|
||||
// Information for "Locals", "Members" and "Globals" variables respectively
|
||||
List<int> scope_ids;
|
||||
Vector<int> scope_ids;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
scope_ids.push_back(variable_id++);
|
||||
}
|
||||
|
||||
stackframe_list.insert(stackframe, scope_ids);
|
||||
stackframe_list.push_back(stackframe);
|
||||
scope_list.insert(stackframe.id, scope_ids);
|
||||
}
|
||||
|
||||
_current_frame = 0;
|
||||
|
|
@ -1126,12 +1124,9 @@ void DebugAdapterProtocol::on_debug_stack_dump(const Array &p_stack_dump) {
|
|||
|
||||
void DebugAdapterProtocol::on_debug_stack_frame_vars(const int &p_size) {
|
||||
_remaining_vars = p_size;
|
||||
DAP::StackFrame frame;
|
||||
frame.id = _current_frame;
|
||||
ERR_FAIL_COND(!stackframe_list.has(frame));
|
||||
List<int> scope_ids = stackframe_list.find(frame)->value;
|
||||
for (List<int>::Element *E = scope_ids.front(); E; E = E->next()) {
|
||||
int var_id = E->get();
|
||||
ERR_FAIL_COND(!scope_list.has(_current_frame));
|
||||
Vector<int> scope_ids = scope_list.find(_current_frame)->value;
|
||||
for (const int &var_id : scope_ids) {
|
||||
if (variable_list.has(var_id)) {
|
||||
variable_list.find(var_id)->value.clear();
|
||||
} else {
|
||||
|
|
@ -1144,11 +1139,9 @@ void DebugAdapterProtocol::on_debug_stack_frame_var(const Array &p_data) {
|
|||
DebuggerMarshalls::ScriptStackVariable stack_var;
|
||||
stack_var.deserialize(p_data);
|
||||
|
||||
ERR_FAIL_COND(stackframe_list.is_empty());
|
||||
DAP::StackFrame frame;
|
||||
frame.id = _current_frame;
|
||||
ERR_FAIL_COND(!scope_list.has(_current_frame));
|
||||
Vector<int> scope_ids = scope_list.find(_current_frame)->value;
|
||||
|
||||
List<int> scope_ids = stackframe_list.find(frame)->value;
|
||||
ERR_FAIL_COND(scope_ids.size() != 3);
|
||||
ERR_FAIL_INDEX(stack_var.type, 4);
|
||||
int var_id = scope_ids.get(stack_var.type);
|
||||
|
|
@ -1192,8 +1185,7 @@ void DebugAdapterProtocol::poll() {
|
|||
on_client_connected();
|
||||
}
|
||||
List<Ref<DAPeer>> to_delete;
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
Ref<DAPeer> peer = E->get();
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->connection->poll();
|
||||
StreamPeerTCP::Status status = peer->connection->get_status();
|
||||
if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {
|
||||
|
|
@ -1211,8 +1203,8 @@ void DebugAdapterProtocol::poll() {
|
|||
}
|
||||
}
|
||||
|
||||
for (List<Ref<DAPeer>>::Element *E = to_delete.front(); E; E = E->next()) {
|
||||
on_client_disconnected(E->get());
|
||||
for (const Ref<DAPeer> &peer : to_delete) {
|
||||
on_client_disconnected(peer);
|
||||
}
|
||||
to_delete.clear();
|
||||
}
|
||||
|
|
@ -1225,8 +1217,8 @@ Error DebugAdapterProtocol::start(int p_port, const IPAddress &p_bind_ip) {
|
|||
}
|
||||
|
||||
void DebugAdapterProtocol::stop() {
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->connection->disconnect_from_host();
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->connection->disconnect_from_host();
|
||||
}
|
||||
|
||||
clients.clear();
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEBUG_ADAPTER_PROTOCOL_H
|
||||
#define DEBUG_ADAPTER_PROTOCOL_H
|
||||
#pragma once
|
||||
|
||||
#include "core/debugger/debugger_marshalls.h"
|
||||
#include "core/io/stream_peer_tcp.h"
|
||||
|
|
@ -68,7 +67,7 @@ struct DAPeer : RefCounted {
|
|||
|
||||
Error handle_data();
|
||||
Error send_data();
|
||||
String format_output(const Dictionary &p_params) const;
|
||||
Vector<uint8_t> format_output(const Dictionary &p_params) const;
|
||||
};
|
||||
|
||||
class DebugAdapterProtocol : public Object {
|
||||
|
|
@ -77,6 +76,7 @@ class DebugAdapterProtocol : public Object {
|
|||
friend class DebugAdapterParser;
|
||||
|
||||
using DAPVarID = int;
|
||||
using DAPStackFrameID = int;
|
||||
|
||||
private:
|
||||
static DebugAdapterProtocol *singleton;
|
||||
|
|
@ -110,6 +110,9 @@ private:
|
|||
bool request_remote_object(const ObjectID &p_object_id);
|
||||
bool request_remote_evaluate(const String &p_eval, int p_stack_frame);
|
||||
|
||||
const DAP::Source &fetch_source(const String &p_path);
|
||||
void update_source(const String &p_path);
|
||||
|
||||
bool _initialized = false;
|
||||
bool _processing_breakpoint = false;
|
||||
bool _stepping = false;
|
||||
|
|
@ -126,7 +129,9 @@ private:
|
|||
int stackframe_id = 0;
|
||||
DAPVarID variable_id = 0;
|
||||
List<DAP::Breakpoint> breakpoint_list;
|
||||
HashMap<DAP::StackFrame, List<int>, DAP::StackFrame> stackframe_list;
|
||||
HashMap<String, DAP::Source> breakpoint_source_list;
|
||||
List<DAP::StackFrame> stackframe_list;
|
||||
HashMap<DAPStackFrameID, Vector<int>> scope_list;
|
||||
HashMap<DAPVarID, Array> variable_list;
|
||||
|
||||
HashMap<ObjectID, DAPVarID> object_list;
|
||||
|
|
@ -168,5 +173,3 @@ public:
|
|||
DebugAdapterProtocol();
|
||||
~DebugAdapterProtocol();
|
||||
};
|
||||
|
||||
#endif // DEBUG_ADAPTER_PROTOCOL_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEBUG_ADAPTER_SERVER_H
|
||||
#define DEBUG_ADAPTER_SERVER_H
|
||||
#pragma once
|
||||
|
||||
#include "debug_adapter_protocol.h"
|
||||
#include "editor/plugins/editor_plugin.h"
|
||||
|
|
@ -54,5 +53,3 @@ public:
|
|||
void start();
|
||||
void stop();
|
||||
};
|
||||
|
||||
#endif // DEBUG_ADAPTER_SERVER_H
|
||||
|
|
|
|||
|
|
@ -28,11 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEBUG_ADAPTER_TYPES_H
|
||||
#define DEBUG_ADAPTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/json.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
#include "core/io/file_access.h"
|
||||
|
||||
namespace DAP {
|
||||
|
||||
|
|
@ -69,6 +67,8 @@ public:
|
|||
void compute_checksums() {
|
||||
ERR_FAIL_COND(path.is_empty());
|
||||
|
||||
_checksums.clear();
|
||||
|
||||
// MD5
|
||||
Checksum md5;
|
||||
md5.algorithm = "MD5";
|
||||
|
|
@ -102,18 +102,24 @@ public:
|
|||
struct Breakpoint {
|
||||
int id = 0;
|
||||
bool verified = false;
|
||||
Source source;
|
||||
const Source *source = nullptr;
|
||||
int line = 0;
|
||||
|
||||
Breakpoint() = default; // Empty constructor is invalid, but is necessary because Godot's collections don't support rvalues.
|
||||
Breakpoint(const Source &p_source) :
|
||||
source(&p_source) {}
|
||||
|
||||
bool operator==(const Breakpoint &p_other) const {
|
||||
return source.path == p_other.source.path && line == p_other.line;
|
||||
return source == p_other.source && line == p_other.line;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Dictionary to_json() const {
|
||||
Dictionary dict;
|
||||
dict["id"] = id;
|
||||
dict["verified"] = verified;
|
||||
dict["source"] = source.to_json();
|
||||
if (source) {
|
||||
dict["source"] = source->to_json();
|
||||
}
|
||||
dict["line"] = line;
|
||||
|
||||
return dict;
|
||||
|
|
@ -159,9 +165,7 @@ struct Capabilities {
|
|||
dict["supportsTerminateRequest"] = supportsTerminateRequest;
|
||||
dict["supportsBreakpointLocationsRequest"] = supportsBreakpointLocationsRequest;
|
||||
|
||||
Array arr;
|
||||
arr.push_back(supportedChecksumAlgorithms[0]);
|
||||
arr.push_back(supportedChecksumAlgorithms[1]);
|
||||
Array arr = { supportedChecksumAlgorithms[0], supportedChecksumAlgorithms[1] };
|
||||
dict["supportedChecksumAlgorithms"] = arr;
|
||||
|
||||
return dict;
|
||||
|
|
@ -215,30 +219,25 @@ struct SourceBreakpoint {
|
|||
struct StackFrame {
|
||||
int id = 0;
|
||||
String name;
|
||||
Source source;
|
||||
const Source *source = nullptr;
|
||||
int line = 0;
|
||||
int column = 0;
|
||||
|
||||
StackFrame() = default; // Empty constructor is invalid, but is necessary because Godot's collections don't support rvalues.
|
||||
StackFrame(const Source &p_source) :
|
||||
source(&p_source) {}
|
||||
|
||||
static uint32_t hash(const StackFrame &p_frame) {
|
||||
return hash_murmur3_one_32(p_frame.id);
|
||||
}
|
||||
bool operator==(const StackFrame &p_other) const {
|
||||
return id == p_other.id;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void from_json(const Dictionary &p_params) {
|
||||
id = p_params["id"];
|
||||
name = p_params["name"];
|
||||
source.from_json(p_params["source"]);
|
||||
line = p_params["line"];
|
||||
column = p_params["column"];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Dictionary to_json() const {
|
||||
Dictionary dict;
|
||||
dict["id"] = id;
|
||||
dict["name"] = name;
|
||||
dict["source"] = source.to_json();
|
||||
if (source) {
|
||||
dict["source"] = source->to_json();
|
||||
}
|
||||
dict["line"] = line;
|
||||
dict["column"] = column;
|
||||
|
||||
|
|
@ -277,5 +276,3 @@ struct Variable {
|
|||
};
|
||||
|
||||
} // namespace DAP
|
||||
|
||||
#endif // DEBUG_ADAPTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -33,29 +33,57 @@
|
|||
#include "core/debugger/debugger_marshalls.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "editor/inspector_dock.h"
|
||||
#include "scene/debugger/scene_debugger.h"
|
||||
|
||||
bool EditorDebuggerRemoteObject::_set(const StringName &p_name, const Variant &p_value) {
|
||||
if (!prop_values.has(p_name) || String(p_name).begins_with("Constants/")) {
|
||||
bool EditorDebuggerRemoteObjects::_set(const StringName &p_name, const Variant &p_value) {
|
||||
return _set_impl(p_name, p_value, "");
|
||||
}
|
||||
|
||||
bool EditorDebuggerRemoteObjects::_set_impl(const StringName &p_name, const Variant &p_value, const String &p_field) {
|
||||
String name = p_name;
|
||||
|
||||
if (name.begins_with("Metadata/")) {
|
||||
name = name.replace_first("Metadata/", "metadata/");
|
||||
}
|
||||
if (!prop_values.has(name) || String(name).begins_with("Constants/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
prop_values[p_name] = p_value;
|
||||
emit_signal(SNAME("value_edited"), remote_object_id, p_name, p_value);
|
||||
Dictionary &values = prop_values[p_name];
|
||||
Dictionary old_values = values.duplicate();
|
||||
for (const uint64_t key : values.keys()) {
|
||||
values.set(key, p_value);
|
||||
}
|
||||
|
||||
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
|
||||
const int size = remote_object_ids.size();
|
||||
ur->create_action(size == 1 ? vformat(TTR("Set %s"), name) : vformat(TTR("Set %s on %d objects"), name, size), UndoRedo::MERGE_ENDS);
|
||||
|
||||
ur->add_do_method(this, SNAME("emit_signal"), SNAME("values_edited"), name, values, p_field);
|
||||
ur->add_undo_method(this, SNAME("emit_signal"), SNAME("values_edited"), name, old_values, p_field);
|
||||
ur->commit_action();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditorDebuggerRemoteObject::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
if (!prop_values.has(p_name)) {
|
||||
bool EditorDebuggerRemoteObjects::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
String name = p_name;
|
||||
|
||||
if (name.begins_with("Metadata/")) {
|
||||
name = name.replace_first("Metadata/", "metadata/");
|
||||
}
|
||||
if (!prop_values.has(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r_ret = prop_values[p_name];
|
||||
r_ret = prop_values[p_name][remote_object_ids[0]];
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditorDebuggerRemoteObject::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
p_list->clear(); // Sorry, no want category.
|
||||
void EditorDebuggerRemoteObjects::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
p_list->clear(); // Sorry, don't want any categories.
|
||||
for (const PropertyInfo &prop : prop_list) {
|
||||
if (prop.name == "script") {
|
||||
// Skip the script property, it's always added by the non-virtual method.
|
||||
|
|
@ -66,31 +94,35 @@ void EditorDebuggerRemoteObject::_get_property_list(List<PropertyInfo> *p_list)
|
|||
}
|
||||
}
|
||||
|
||||
String EditorDebuggerRemoteObject::get_title() {
|
||||
if (remote_object_id.is_valid()) {
|
||||
return vformat(TTR("Remote %s:"), String(type_name)) + " " + itos(remote_object_id);
|
||||
} else {
|
||||
return "<null>";
|
||||
}
|
||||
void EditorDebuggerRemoteObjects::set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field) {
|
||||
_set_impl(p_property, p_value, p_field);
|
||||
}
|
||||
|
||||
Variant EditorDebuggerRemoteObject::get_variant(const StringName &p_name) {
|
||||
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);
|
||||
}
|
||||
|
||||
return "<null>";
|
||||
}
|
||||
|
||||
Variant EditorDebuggerRemoteObjects::get_variant(const StringName &p_name) {
|
||||
Variant var;
|
||||
_get(p_name, var);
|
||||
return var;
|
||||
}
|
||||
|
||||
void EditorDebuggerRemoteObject::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_title"), &EditorDebuggerRemoteObject::get_title);
|
||||
ClassDB::bind_method(D_METHOD("get_variant"), &EditorDebuggerRemoteObject::get_variant);
|
||||
ClassDB::bind_method(D_METHOD("clear"), &EditorDebuggerRemoteObject::clear);
|
||||
ClassDB::bind_method(D_METHOD("get_remote_object_id"), &EditorDebuggerRemoteObject::get_remote_object_id);
|
||||
void EditorDebuggerRemoteObjects::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_title"), &EditorDebuggerRemoteObjects::get_title);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("value_edited", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value")));
|
||||
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
|
||||
|
||||
EditorDebuggerInspector::EditorDebuggerInspector() {
|
||||
variables = memnew(EditorDebuggerRemoteObject);
|
||||
variables = memnew(EditorDebuggerRemoteObjects);
|
||||
}
|
||||
|
||||
EditorDebuggerInspector::~EditorDebuggerInspector() {
|
||||
|
|
@ -100,7 +132,7 @@ EditorDebuggerInspector::~EditorDebuggerInspector() {
|
|||
|
||||
void EditorDebuggerInspector::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("object_selected", PropertyInfo(Variant::INT, "id")));
|
||||
ADD_SIGNAL(MethodInfo("object_edited", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value")));
|
||||
ADD_SIGNAL(MethodInfo("objects_edited", PropertyInfo(Variant::ARRAY, "ids"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value"), PropertyInfo(Variant::STRING, "field")));
|
||||
ADD_SIGNAL(MethodInfo("object_property_updated", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property")));
|
||||
}
|
||||
|
||||
|
|
@ -111,50 +143,143 @@ void EditorDebuggerInspector::_notification(int p_what) {
|
|||
} break;
|
||||
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
variables->remote_object_ids.append(0);
|
||||
edit(variables);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerInspector::_object_edited(ObjectID p_id, const String &p_prop, const Variant &p_value) {
|
||||
emit_signal(SNAME("object_edited"), p_id, p_prop, p_value);
|
||||
void EditorDebuggerInspector::_objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field) {
|
||||
emit_signal(SNAME("objects_edited"), p_prop, p_values, p_field);
|
||||
}
|
||||
|
||||
void EditorDebuggerInspector::_object_selected(ObjectID p_object) {
|
||||
emit_signal(SNAME("object_selected"), p_object);
|
||||
}
|
||||
|
||||
ObjectID EditorDebuggerInspector::add_object(const Array &p_arr) {
|
||||
EditorDebuggerRemoteObject *debug_obj = nullptr;
|
||||
EditorDebuggerRemoteObjects *EditorDebuggerInspector::set_objects(const Array &p_arr) {
|
||||
ERR_FAIL_COND_V(p_arr.is_empty(), nullptr);
|
||||
|
||||
SceneDebuggerObject obj;
|
||||
obj.deserialize(p_arr);
|
||||
ERR_FAIL_COND_V(obj.id.is_null(), ObjectID());
|
||||
TypedArray<uint64_t> ids;
|
||||
LocalVector<SceneDebuggerObject> objects;
|
||||
for (const Array arr : p_arr) {
|
||||
SceneDebuggerObject obj;
|
||||
obj.deserialize(arr);
|
||||
if (obj.id.is_valid()) {
|
||||
ids.push_back((uint64_t)obj.id);
|
||||
objects.push_back(obj);
|
||||
}
|
||||
}
|
||||
ERR_FAIL_COND_V(ids.is_empty(), nullptr);
|
||||
|
||||
if (remote_objects.has(obj.id)) {
|
||||
debug_obj = remote_objects[obj.id];
|
||||
} else {
|
||||
debug_obj = memnew(EditorDebuggerRemoteObject);
|
||||
debug_obj->remote_object_id = obj.id;
|
||||
debug_obj->type_name = obj.class_name;
|
||||
remote_objects[obj.id] = debug_obj;
|
||||
debug_obj->connect("value_edited", callable_mp(this, &EditorDebuggerInspector::_object_edited));
|
||||
// Sorting is necessary, as selected nodes in the remote tree are ordered by index.
|
||||
ids.sort();
|
||||
|
||||
EditorDebuggerRemoteObjects *remote_objects = nullptr;
|
||||
for (EditorDebuggerRemoteObjects *robjs : remote_objects_list) {
|
||||
if (robjs->remote_object_ids == ids) {
|
||||
remote_objects = robjs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int old_prop_size = debug_obj->prop_list.size();
|
||||
if (!remote_objects) {
|
||||
remote_objects = memnew(EditorDebuggerRemoteObjects);
|
||||
remote_objects->remote_object_ids = ids;
|
||||
remote_objects->remote_object_ids.make_read_only();
|
||||
remote_objects->connect("values_edited", callable_mp(this, &EditorDebuggerInspector::_objects_edited));
|
||||
remote_objects_list.push_back(remote_objects);
|
||||
}
|
||||
|
||||
debug_obj->prop_list.clear();
|
||||
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;
|
||||
SceneDebuggerObject::SceneDebuggerProperty prop;
|
||||
TypedDictionary<uint64_t, Variant> values;
|
||||
};
|
||||
HashMap<String, UsageData> usage;
|
||||
int nc = 0;
|
||||
for (const SceneDebuggerObject &obj : objects) {
|
||||
for (const SceneDebuggerObject::SceneDebuggerProperty &prop : obj.properties) {
|
||||
PropertyInfo pinfo = prop.first;
|
||||
if (pinfo.name == "script") {
|
||||
continue; // Added later manually, since this is intercepted before being set (check Variant Object::get()).
|
||||
} else if (pinfo.name.begins_with("metadata/")) {
|
||||
pinfo.name = pinfo.name.replace_first("metadata/", "Metadata/"); // Trick to not get actual metadata edited from EditorDebuggerRemoteObjects.
|
||||
}
|
||||
|
||||
if (!usage.has(pinfo.name)) {
|
||||
UsageData usage_dt;
|
||||
usage_dt.prop = prop;
|
||||
usage_dt.prop.first.name = pinfo.name;
|
||||
usage_dt.values[obj.id] = prop.second;
|
||||
usage[pinfo.name] = usage_dt;
|
||||
}
|
||||
|
||||
// Make sure only properties with the same exact PropertyInfo data will appear.
|
||||
if (usage[pinfo.name].prop.first == pinfo) {
|
||||
usage[pinfo.name].qty++;
|
||||
usage[pinfo.name].values[obj.id] = prop.second;
|
||||
}
|
||||
}
|
||||
|
||||
nc++;
|
||||
}
|
||||
for (HashMap<String, UsageData>::Iterator E = usage.begin(); E;) {
|
||||
HashMap<String, UsageData>::Iterator next = E;
|
||||
++next;
|
||||
|
||||
UsageData usage_dt = E->value;
|
||||
if (nc != usage_dt.qty) {
|
||||
// Doesn't appear on all of them, remove it.
|
||||
usage.erase(E->key);
|
||||
}
|
||||
|
||||
E = next;
|
||||
}
|
||||
|
||||
int old_prop_size = remote_objects->prop_list.size();
|
||||
|
||||
remote_objects->prop_list.clear();
|
||||
int new_props_added = 0;
|
||||
HashSet<String> changed;
|
||||
for (SceneDebuggerObject::SceneDebuggerProperty &property : obj.properties) {
|
||||
PropertyInfo &pinfo = property.first;
|
||||
Variant &var = property.second;
|
||||
for (KeyValue<String, UsageData> &KV : usage) {
|
||||
const PropertyInfo &pinfo = KV.value.prop.first;
|
||||
Variant var = KV.value.values[remote_objects->remote_object_ids[0]];
|
||||
|
||||
if (pinfo.type == Variant::OBJECT) {
|
||||
if (var.is_string()) {
|
||||
String path = var;
|
||||
if (path.contains("::")) {
|
||||
// built-in resource
|
||||
// Built-in resource.
|
||||
String base_path = path.get_slice("::", 0);
|
||||
Ref<Resource> dependency = ResourceLoader::load(base_path);
|
||||
if (dependency.is_valid()) {
|
||||
|
|
@ -162,15 +287,16 @@ ObjectID EditorDebuggerInspector::add_object(const Array &p_arr) {
|
|||
}
|
||||
}
|
||||
var = ResourceLoader::load(path);
|
||||
KV.value.values[remote_objects->remote_object_ids[0]] = var;
|
||||
|
||||
if (pinfo.hint_string == "Script") {
|
||||
if (debug_obj->get_script() != var) {
|
||||
debug_obj->set_script(Ref<RefCounted>());
|
||||
if (remote_objects->get_script() != var) {
|
||||
remote_objects->set_script(Ref<RefCounted>());
|
||||
Ref<Script> scr(var);
|
||||
if (scr.is_valid()) {
|
||||
ScriptInstance *scr_instance = scr->placeholder_instance_create(debug_obj);
|
||||
ScriptInstance *scr_instance = scr->placeholder_instance_create(remote_objects);
|
||||
if (scr_instance) {
|
||||
debug_obj->set_script_and_instance(var, scr_instance);
|
||||
remote_objects->set_script_and_instance(var, scr_instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -178,49 +304,67 @@ ObjectID EditorDebuggerInspector::add_object(const Array &p_arr) {
|
|||
}
|
||||
}
|
||||
|
||||
//always add the property, since props may have been added or removed
|
||||
debug_obj->prop_list.push_back(pinfo);
|
||||
// Always add the property, since props may have been added or removed.
|
||||
remote_objects->prop_list.push_back(pinfo);
|
||||
|
||||
if (!debug_obj->prop_values.has(pinfo.name)) {
|
||||
if (!remote_objects->prop_values.has(pinfo.name)) {
|
||||
new_props_added++;
|
||||
debug_obj->prop_values[pinfo.name] = var;
|
||||
} else {
|
||||
if (bool(Variant::evaluate(Variant::OP_NOT_EQUAL, debug_obj->prop_values[pinfo.name], var))) {
|
||||
debug_obj->prop_values[pinfo.name] = var;
|
||||
changed.insert(pinfo.name);
|
||||
}
|
||||
} else if (bool(Variant::evaluate(Variant::OP_NOT_EQUAL, remote_objects->prop_values[pinfo.name], var))) {
|
||||
changed.insert(pinfo.name);
|
||||
}
|
||||
|
||||
remote_objects->prop_values[pinfo.name] = KV.value.values;
|
||||
}
|
||||
|
||||
if (old_prop_size == debug_obj->prop_list.size() && new_props_added == 0) {
|
||||
//only some may have changed, if so, then update those, if exist
|
||||
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) {
|
||||
emit_signal(SNAME("object_property_updated"), debug_obj->remote_object_id, E);
|
||||
emit_signal(SNAME("object_property_updated"), remote_objects->get_instance_id(), E);
|
||||
}
|
||||
} else {
|
||||
//full update, because props were added or removed
|
||||
debug_obj->update();
|
||||
// Full update, because props were added or removed.
|
||||
remote_objects->update();
|
||||
}
|
||||
|
||||
return remote_objects;
|
||||
}
|
||||
|
||||
void EditorDebuggerInspector::clear_remote_inspector() {
|
||||
if (remote_objects_list.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Object *obj = InspectorDock::get_inspector_singleton()->get_edited_object();
|
||||
// Check if the inspector holds remote items, and take it out if so.
|
||||
if (Object::cast_to<EditorDebuggerRemoteObjects>(obj)) {
|
||||
EditorNode::get_singleton()->push_item(nullptr);
|
||||
}
|
||||
return obj.id;
|
||||
}
|
||||
|
||||
void EditorDebuggerInspector::clear_cache() {
|
||||
for (const KeyValue<ObjectID, EditorDebuggerRemoteObject *> &E : remote_objects) {
|
||||
EditorNode *editor = EditorNode::get_singleton();
|
||||
if (editor->get_editor_selection_history()->get_current() == E.value->get_instance_id()) {
|
||||
editor->push_item(nullptr);
|
||||
}
|
||||
memdelete(E.value);
|
||||
clear_remote_inspector();
|
||||
|
||||
for (EditorDebuggerRemoteObjects *robjs : remote_objects_list) {
|
||||
memdelete(robjs);
|
||||
}
|
||||
remote_objects.clear();
|
||||
remote_objects_list.clear();
|
||||
|
||||
remote_dependencies.clear();
|
||||
}
|
||||
|
||||
Object *EditorDebuggerInspector::get_object(ObjectID p_id) {
|
||||
if (remote_objects.has(p_id)) {
|
||||
return remote_objects[p_id];
|
||||
void EditorDebuggerInspector::invalidate_selection_from_cache(const TypedArray<uint64_t> &p_ids) {
|
||||
for (EditorDebuggerRemoteObjects *robjs : remote_objects_list) {
|
||||
if (robjs->remote_object_ids == p_ids) {
|
||||
const Object *obj = InspectorDock::get_inspector_singleton()->get_edited_object();
|
||||
if (obj == robjs) {
|
||||
EditorNode::get_singleton()->push_item(nullptr);
|
||||
}
|
||||
|
||||
remote_objects_list.erase(robjs);
|
||||
memdelete(robjs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void EditorDebuggerInspector::add_stack_variable(const Array &p_array, int p_offset) {
|
||||
|
|
@ -270,7 +414,7 @@ void EditorDebuggerInspector::add_stack_variable(const Array &p_array, int p_off
|
|||
}
|
||||
variables->prop_list.insert_before(current, pinfo);
|
||||
}
|
||||
variables->prop_values[type + n] = v;
|
||||
variables->prop_values[type + n][0] = v;
|
||||
variables->update();
|
||||
edit(variables);
|
||||
|
||||
|
|
@ -288,9 +432,9 @@ void EditorDebuggerInspector::clear_stack_variables() {
|
|||
}
|
||||
|
||||
String EditorDebuggerInspector::get_stack_variable(const String &p_var) {
|
||||
for (KeyValue<StringName, Variant> &E : variables->prop_values) {
|
||||
for (KeyValue<StringName, TypedDictionary<uint64_t, Variant>> &E : variables->prop_values) {
|
||||
String v = E.key.operator String();
|
||||
if (v.get_slice("/", 1) == p_var) {
|
||||
if (v.get_slicec('/', 1) == p_var) {
|
||||
return variables->get_variant(v);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,13 +28,18 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_DEBUGGER_INSPECTOR_H
|
||||
#define EDITOR_DEBUGGER_INSPECTOR_H
|
||||
#pragma once
|
||||
|
||||
#include "core/variant/typed_dictionary.h"
|
||||
#include "editor/editor_inspector.h"
|
||||
|
||||
class EditorDebuggerRemoteObject : public Object {
|
||||
GDCLASS(EditorDebuggerRemoteObject, Object);
|
||||
class SceneDebuggerObject;
|
||||
|
||||
class EditorDebuggerRemoteObjects : public Object {
|
||||
GDCLASS(EditorDebuggerRemoteObjects, Object);
|
||||
|
||||
private:
|
||||
bool _set_impl(const StringName &p_name, const Variant &p_value, const String &p_field);
|
||||
|
||||
protected:
|
||||
bool _set(const StringName &p_name, const Variant &p_value);
|
||||
|
|
@ -43,14 +48,13 @@ protected:
|
|||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
ObjectID remote_object_id;
|
||||
TypedArray<uint64_t> remote_object_ids;
|
||||
String type_name;
|
||||
List<PropertyInfo> prop_list;
|
||||
HashMap<StringName, Variant> prop_values;
|
||||
HashMap<StringName, TypedDictionary<uint64_t, Variant>> prop_values;
|
||||
|
||||
ObjectID get_remote_object_id() { return remote_object_id; }
|
||||
void set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field);
|
||||
String get_title();
|
||||
|
||||
Variant get_variant(const StringName &p_name);
|
||||
|
||||
void clear() {
|
||||
|
|
@ -59,21 +63,18 @@ public:
|
|||
}
|
||||
|
||||
void update() { notify_property_list_changed(); }
|
||||
|
||||
EditorDebuggerRemoteObject() {}
|
||||
};
|
||||
|
||||
class EditorDebuggerInspector : public EditorInspector {
|
||||
GDCLASS(EditorDebuggerInspector, EditorInspector);
|
||||
|
||||
private:
|
||||
ObjectID inspected_object_id;
|
||||
HashMap<ObjectID, EditorDebuggerRemoteObject *> remote_objects;
|
||||
LocalVector<EditorDebuggerRemoteObjects *> remote_objects_list;
|
||||
HashSet<Ref<Resource>> remote_dependencies;
|
||||
EditorDebuggerRemoteObject *variables = nullptr;
|
||||
EditorDebuggerRemoteObjects *variables = nullptr;
|
||||
|
||||
void _object_selected(ObjectID p_object);
|
||||
void _object_edited(ObjectID p_id, const String &p_prop, const Variant &p_value);
|
||||
void _objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field);
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
|
@ -84,14 +85,13 @@ public:
|
|||
~EditorDebuggerInspector();
|
||||
|
||||
// Remote Object cache
|
||||
ObjectID add_object(const Array &p_arr);
|
||||
Object *get_object(ObjectID p_id);
|
||||
EditorDebuggerRemoteObjects *set_objects(const Array &p_array);
|
||||
void clear_remote_inspector();
|
||||
void clear_cache();
|
||||
void invalidate_selection_from_cache(const TypedArray<uint64_t> &p_ids);
|
||||
|
||||
// Stack Dump variables
|
||||
String get_stack_variable(const String &p_var);
|
||||
void add_stack_variable(const Array &p_arr, int p_offset = -1);
|
||||
void clear_stack_variables();
|
||||
};
|
||||
|
||||
#endif // EDITOR_DEBUGGER_INSPECTOR_H
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ EditorDebuggerNode::EditorDebuggerNode() {
|
|||
|
||||
// Remote scene tree
|
||||
remote_scene_tree = memnew(EditorDebuggerTree);
|
||||
remote_scene_tree->connect("object_selected", callable_mp(this, &EditorDebuggerNode::_remote_object_requested));
|
||||
remote_scene_tree->connect("objects_selected", callable_mp(this, &EditorDebuggerNode::_remote_objects_requested));
|
||||
remote_scene_tree->connect("selection_cleared", callable_mp(this, &EditorDebuggerNode::_remote_selection_cleared));
|
||||
remote_scene_tree->connect("save_node", callable_mp(this, &EditorDebuggerNode::_save_node_requested));
|
||||
remote_scene_tree->connect("button_clicked", callable_mp(this, &EditorDebuggerNode::_remote_tree_button_pressed));
|
||||
SceneTreeDock::get_singleton()->add_remote_tree_editor(remote_scene_tree);
|
||||
|
|
@ -109,11 +110,13 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
|
|||
node->connect("breakpoint_selected", callable_mp(this, &EditorDebuggerNode::_error_selected).bind(id));
|
||||
node->connect("clear_execution", callable_mp(this, &EditorDebuggerNode::_clear_execution));
|
||||
node->connect("breaked", callable_mp(this, &EditorDebuggerNode::_breaked).bind(id));
|
||||
node->connect("debug_data", callable_mp(this, &EditorDebuggerNode::_debug_data).bind(id));
|
||||
node->connect("remote_tree_select_requested", callable_mp(this, &EditorDebuggerNode::_remote_tree_select_requested).bind(id));
|
||||
node->connect("remote_tree_clear_selection_requested", callable_mp(this, &EditorDebuggerNode::_remote_tree_clear_selection_requested).bind(id));
|
||||
node->connect("remote_tree_updated", callable_mp(this, &EditorDebuggerNode::_remote_tree_updated).bind(id));
|
||||
node->connect("remote_object_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_updated).bind(id));
|
||||
node->connect("remote_objects_updated", callable_mp(this, &EditorDebuggerNode::_remote_objects_updated).bind(id));
|
||||
node->connect("remote_object_property_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_property_updated).bind(id));
|
||||
node->connect("remote_object_requested", callable_mp(this, &EditorDebuggerNode::_remote_object_requested).bind(id));
|
||||
node->connect("remote_objects_requested", callable_mp(this, &EditorDebuggerNode::_remote_objects_requested).bind(id));
|
||||
node->connect("set_breakpoint", callable_mp(this, &EditorDebuggerNode::_breakpoint_set_in_tree).bind(id));
|
||||
node->connect("clear_breakpoints", callable_mp(this, &EditorDebuggerNode::_breakpoints_cleared_in_tree).bind(id));
|
||||
node->connect("errors_cleared", callable_mp(this, &EditorDebuggerNode::_update_errors));
|
||||
|
|
@ -222,10 +225,6 @@ void EditorDebuggerNode::register_undo_redo(UndoRedo *p_undo_redo) {
|
|||
p_undo_redo->set_property_notify_callback(_properties_changed, this);
|
||||
}
|
||||
|
||||
EditorDebuggerRemoteObject *EditorDebuggerNode::get_inspected_remote_object() {
|
||||
return Object::cast_to<EditorDebuggerRemoteObject>(ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_current()));
|
||||
}
|
||||
|
||||
ScriptEditorDebugger *EditorDebuggerNode::get_debugger(int p_id) const {
|
||||
return Object::cast_to<ScriptEditorDebugger>(tabs->get_tab_control(p_id));
|
||||
}
|
||||
|
|
@ -292,6 +291,10 @@ void EditorDebuggerNode::stop(bool p_force) {
|
|||
if (keep_open && !p_force) {
|
||||
return;
|
||||
}
|
||||
|
||||
remote_scene_tree_wait = false;
|
||||
inspect_edited_object_wait = false;
|
||||
|
||||
current_uri.clear();
|
||||
if (server.is_valid()) {
|
||||
server->stop();
|
||||
|
|
@ -304,6 +307,7 @@ void EditorDebuggerNode::stop(bool p_force) {
|
|||
|
||||
server.unref();
|
||||
}
|
||||
|
||||
// Also close all debugging sessions.
|
||||
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
|
||||
if (dbg->is_session_active()) {
|
||||
|
|
@ -351,21 +355,29 @@ void EditorDebuggerNode::_notification(int p_what) {
|
|||
|
||||
_update_errors();
|
||||
|
||||
// Remote scene tree update
|
||||
remote_scene_tree_timeout -= get_process_delta_time();
|
||||
if (remote_scene_tree_timeout < 0) {
|
||||
remote_scene_tree_timeout = EDITOR_GET("debugger/remote_scene_tree_refresh_interval");
|
||||
if (remote_scene_tree->is_visible_in_tree()) {
|
||||
get_current_debugger()->request_remote_tree();
|
||||
// Remote scene tree update.
|
||||
if (!remote_scene_tree_wait) {
|
||||
remote_scene_tree_timeout -= get_process_delta_time();
|
||||
if (remote_scene_tree_timeout < 0) {
|
||||
remote_scene_tree_timeout = EDITOR_GET("debugger/remote_scene_tree_refresh_interval");
|
||||
|
||||
if (remote_scene_tree->is_visible_in_tree()) {
|
||||
remote_scene_tree_wait = true;
|
||||
get_current_debugger()->request_remote_tree();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remote inspector update
|
||||
inspect_edited_object_timeout -= get_process_delta_time();
|
||||
if (inspect_edited_object_timeout < 0) {
|
||||
inspect_edited_object_timeout = EDITOR_GET("debugger/remote_inspect_refresh_interval");
|
||||
if (EditorDebuggerRemoteObject *obj = get_inspected_remote_object()) {
|
||||
get_current_debugger()->request_remote_object(obj->remote_object_id);
|
||||
// Remote inspector update.
|
||||
if (!inspect_edited_object_wait) {
|
||||
inspect_edited_object_timeout -= get_process_delta_time();
|
||||
if (inspect_edited_object_timeout < 0) {
|
||||
inspect_edited_object_timeout = EDITOR_GET("debugger/remote_inspect_refresh_interval");
|
||||
|
||||
if (EditorDebuggerRemoteObjects *robjs = Object::cast_to<EditorDebuggerRemoteObjects>(InspectorDock::get_inspector_singleton()->get_edited_object())) {
|
||||
inspect_edited_object_wait = true;
|
||||
get_current_debugger()->request_remote_objects(robjs->remote_object_ids, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -467,21 +479,26 @@ void EditorDebuggerNode::_debugger_stopped(int p_id) {
|
|||
|
||||
void EditorDebuggerNode::_debugger_wants_stop(int p_id) {
|
||||
// Ask editor to kill PID.
|
||||
int pid = get_debugger(p_id)->get_remote_pid();
|
||||
if (pid) {
|
||||
if (int pid = get_debugger(p_id)->get_remote_pid()) {
|
||||
callable_mp(EditorNode::get_singleton(), &EditorNode::stop_child_process).call_deferred(pid);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_debugger_changed(int p_tab) {
|
||||
if (get_inspected_remote_object()) {
|
||||
// Clear inspected object, you can only inspect objects in selected debugger.
|
||||
// Hopefully, in the future, we will have one inspector per debugger.
|
||||
EditorNode::get_singleton()->push_item(nullptr);
|
||||
remote_scene_tree_wait = false;
|
||||
inspect_edited_object_wait = false;
|
||||
|
||||
if (Object *robjs = InspectorDock::get_inspector_singleton()->get_edited_object()) {
|
||||
if (Object::cast_to<EditorDebuggerRemoteObjects>(robjs)) {
|
||||
// Clear inspected object, you can only inspect objects in selected debugger.
|
||||
// Hopefully, in the future, we will have one inspector per debugger.
|
||||
EditorNode::get_singleton()->push_item(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (get_previous_debugger()) {
|
||||
_text_editor_stack_clear(get_previous_debugger());
|
||||
if (ScriptEditorDebugger *prev_debug = get_previous_debugger()) {
|
||||
prev_debug->clear_inspector();
|
||||
_text_editor_stack_clear(prev_debug);
|
||||
}
|
||||
if (remote_scene_tree->is_visible_in_tree()) {
|
||||
get_current_debugger()->request_remote_tree();
|
||||
|
|
@ -493,6 +510,18 @@ void EditorDebuggerNode::_debugger_changed(int p_tab) {
|
|||
_break_state_changed();
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_debug_data(const String &p_msg, const Array &p_data, int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_msg == "scene:scene_tree") {
|
||||
remote_scene_tree_wait = false;
|
||||
} else if (p_msg == "scene:inspect_objects") {
|
||||
inspect_edited_object_wait = false;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::set_script_debug_button(MenuButton *p_button) {
|
||||
script_menu = p_button;
|
||||
script_menu->set_text(TTR("Debug"));
|
||||
|
|
@ -587,6 +616,10 @@ bool EditorDebuggerNode::is_skip_breakpoints() const {
|
|||
return get_current_debugger()->is_skip_breakpoints();
|
||||
}
|
||||
|
||||
bool EditorDebuggerNode::is_ignore_error_breaks() const {
|
||||
return get_default_debugger()->is_ignore_error_breaks();
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::set_breakpoint(const String &p_path, int p_line, bool p_enabled) {
|
||||
breakpoints[Breakpoint(p_path, p_line)] = p_enabled;
|
||||
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
|
||||
|
|
@ -646,11 +679,39 @@ void EditorDebuggerNode::request_remote_tree() {
|
|||
get_current_debugger()->request_remote_tree();
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_tree_select_requested(ObjectID p_id, int p_debugger) {
|
||||
void EditorDebuggerNode::set_remote_selection(const TypedArray<int64_t> &p_ids) {
|
||||
stop_waiting_inspection();
|
||||
get_current_debugger()->request_remote_objects(p_ids);
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::clear_remote_tree_selection() {
|
||||
remote_scene_tree->clear_selection();
|
||||
get_current_debugger()->clear_inspector(remote_scene_tree_clear_msg);
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::stop_waiting_inspection() {
|
||||
inspect_edited_object_timeout = EDITOR_GET("debugger/remote_inspect_refresh_interval");
|
||||
inspect_edited_object_wait = false;
|
||||
}
|
||||
|
||||
bool EditorDebuggerNode::match_remote_selection(const TypedArray<uint64_t> &p_ids) const {
|
||||
return p_ids == remote_scene_tree->get_selection();
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_tree_select_requested(const TypedArray<int64_t> &p_ids, int p_debugger) {
|
||||
if (p_debugger == tabs->get_current_tab()) {
|
||||
remote_scene_tree->select_nodes(p_ids);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_tree_clear_selection_requested(int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
}
|
||||
remote_scene_tree->select_node(p_id);
|
||||
remote_scene_tree->clear_selection();
|
||||
remote_scene_tree_clear_msg = false;
|
||||
get_current_debugger()->clear_inspector(false);
|
||||
remote_scene_tree_clear_msg = true;
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_tree_updated(int p_debugger) {
|
||||
|
|
@ -679,37 +740,37 @@ void EditorDebuggerNode::_remote_tree_button_pressed(Object *p_item, int p_colum
|
|||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_object_updated(ObjectID p_id, int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
void EditorDebuggerNode::_remote_objects_updated(EditorDebuggerRemoteObjects *p_objs, int p_debugger) {
|
||||
if (p_debugger == tabs->get_current_tab() && p_objs != InspectorDock::get_inspector_singleton()->get_edited_object()) {
|
||||
EditorNode::get_singleton()->push_item(p_objs);
|
||||
}
|
||||
if (EditorDebuggerRemoteObject *obj = get_inspected_remote_object()) {
|
||||
if (obj->remote_object_id == p_id) {
|
||||
return; // Already being edited
|
||||
}
|
||||
}
|
||||
|
||||
EditorNode::get_singleton()->push_item(get_current_debugger()->get_remote_object(p_id));
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_object_property_updated(ObjectID p_id, const String &p_property, int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
}
|
||||
if (EditorDebuggerRemoteObject *obj = get_inspected_remote_object()) {
|
||||
if (obj->remote_object_id != p_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object *obj = InspectorDock::get_inspector_singleton()->get_edited_object();
|
||||
if (obj && obj->get_instance_id() == p_id) {
|
||||
InspectorDock::get_inspector_singleton()->update_property(p_property);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_object_requested(ObjectID p_id, int p_debugger) {
|
||||
void EditorDebuggerNode::_remote_objects_requested(const TypedArray<uint64_t> &p_ids, int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
}
|
||||
inspect_edited_object_timeout = 0.7; // Temporarily disable timeout to avoid multiple requests.
|
||||
get_current_debugger()->request_remote_object(p_id);
|
||||
stop_waiting_inspection();
|
||||
get_current_debugger()->request_remote_objects(p_ids);
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_selection_cleared(int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
}
|
||||
stop_waiting_inspection();
|
||||
get_current_debugger()->clear_inspector();
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_save_node_requested(ObjectID p_id, const String &p_file, int p_debugger) {
|
||||
|
|
@ -809,6 +870,17 @@ void EditorDebuggerNode::live_debug_reparent_node(const NodePath &p_at, const No
|
|||
});
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::set_debug_mute_audio(bool p_mute) {
|
||||
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
|
||||
dbg->set_debug_mute_audio(p_mute);
|
||||
});
|
||||
debug_mute_audio = p_mute;
|
||||
}
|
||||
|
||||
bool EditorDebuggerNode::get_debug_mute_audio() const {
|
||||
return debug_mute_audio;
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::set_camera_override(CameraOverride p_override) {
|
||||
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
|
||||
dbg->set_camera_override(p_override);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_DEBUGGER_NODE_H
|
||||
#define EDITOR_DEBUGGER_NODE_H
|
||||
#pragma once
|
||||
|
||||
#include "core/object/script_language.h"
|
||||
#include "editor/debugger/editor_debugger_server.h"
|
||||
|
|
@ -39,7 +38,7 @@ class Button;
|
|||
class DebugAdapterParser;
|
||||
class EditorDebuggerPlugin;
|
||||
class EditorDebuggerTree;
|
||||
class EditorDebuggerRemoteObject;
|
||||
class EditorDebuggerRemoteObjects;
|
||||
class MenuButton;
|
||||
class ScriptEditorDebugger;
|
||||
class TabContainer;
|
||||
|
|
@ -103,21 +102,25 @@ private:
|
|||
int last_error_count = 0;
|
||||
int last_warning_count = 0;
|
||||
|
||||
bool inspect_edited_object_wait = false;
|
||||
float inspect_edited_object_timeout = 0;
|
||||
EditorDebuggerTree *remote_scene_tree = nullptr;
|
||||
bool remote_scene_tree_wait = false;
|
||||
float remote_scene_tree_timeout = 0.0;
|
||||
bool remote_scene_tree_clear_msg = true;
|
||||
bool auto_switch_remote_scene_tree = false;
|
||||
bool debug_with_external_editor = false;
|
||||
bool keep_open = false;
|
||||
String current_uri;
|
||||
|
||||
bool debug_mute_audio = false;
|
||||
|
||||
CameraOverride camera_override = OVERRIDE_NONE;
|
||||
HashMap<Breakpoint, bool, Breakpoint> breakpoints;
|
||||
|
||||
HashSet<Ref<EditorDebuggerPlugin>> debugger_plugins;
|
||||
|
||||
ScriptEditorDebugger *_add_debugger();
|
||||
EditorDebuggerRemoteObject *get_inspected_remote_object();
|
||||
void _update_errors();
|
||||
|
||||
friend class DebuggerEditorPlugin;
|
||||
|
|
@ -129,12 +132,15 @@ protected:
|
|||
void _debugger_stopped(int p_id);
|
||||
void _debugger_wants_stop(int p_id);
|
||||
void _debugger_changed(int p_tab);
|
||||
void _remote_tree_select_requested(ObjectID p_id, int p_debugger);
|
||||
void _debug_data(const String &p_msg, const Array &p_data, int p_debugger);
|
||||
void _remote_tree_select_requested(const TypedArray<int64_t> &p_ids, int p_debugger);
|
||||
void _remote_tree_clear_selection_requested(int p_debugger);
|
||||
void _remote_tree_updated(int p_debugger);
|
||||
void _remote_tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
|
||||
void _remote_object_updated(ObjectID p_id, int p_debugger);
|
||||
void _remote_objects_updated(EditorDebuggerRemoteObjects *p_objs, int p_debugger);
|
||||
void _remote_object_property_updated(ObjectID p_id, const String &p_property, int p_debugger);
|
||||
void _remote_object_requested(ObjectID p_id, int p_debugger);
|
||||
void _remote_objects_requested(const TypedArray<uint64_t> &p_ids, int p_debugger);
|
||||
void _remote_selection_cleared(int p_debugger);
|
||||
void _save_node_requested(ObjectID p_id, const String &p_file, int p_debugger);
|
||||
|
||||
void _breakpoint_set_in_tree(Ref<RefCounted> p_script, int p_line, bool p_enabled, int p_debugger);
|
||||
|
|
@ -184,6 +190,7 @@ public:
|
|||
bool get_debug_with_external_editor() { return debug_with_external_editor; }
|
||||
|
||||
bool is_skip_breakpoints() const;
|
||||
bool is_ignore_error_breaks() const;
|
||||
void set_breakpoint(const String &p_path, int p_line, bool p_enabled);
|
||||
void set_breakpoints(const String &p_path, const Array &p_lines);
|
||||
void reload_all_scripts();
|
||||
|
|
@ -191,6 +198,10 @@ public:
|
|||
|
||||
// Remote inspector/edit.
|
||||
void request_remote_tree();
|
||||
void set_remote_selection(const TypedArray<int64_t> &p_ids);
|
||||
void clear_remote_tree_selection();
|
||||
void stop_waiting_inspection();
|
||||
bool match_remote_selection(const TypedArray<uint64_t> &p_ids) const;
|
||||
static void _methods_changed(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount);
|
||||
static void _properties_changed(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value);
|
||||
|
||||
|
|
@ -205,6 +216,9 @@ public:
|
|||
void live_debug_duplicate_node(const NodePath &p_at, const String &p_new_name);
|
||||
void live_debug_reparent_node(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos);
|
||||
|
||||
void set_debug_mute_audio(bool p_mute);
|
||||
bool get_debug_mute_audio() const;
|
||||
|
||||
void set_camera_override(CameraOverride p_override);
|
||||
CameraOverride get_camera_override();
|
||||
|
||||
|
|
@ -218,5 +232,3 @@ public:
|
|||
void add_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin);
|
||||
void remove_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin);
|
||||
};
|
||||
|
||||
#endif // EDITOR_DEBUGGER_NODE_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_DEBUGGER_SERVER_H
|
||||
#define EDITOR_DEBUGGER_SERVER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/debugger/remote_debugger_peer.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
|
|
@ -56,5 +55,3 @@ public:
|
|||
virtual bool is_connection_available() const = 0;
|
||||
virtual Ref<RemoteDebuggerPeer> take_connection() = 0;
|
||||
};
|
||||
|
||||
#endif // EDITOR_DEBUGGER_SERVER_H
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "editor/editor_settings.h"
|
||||
#include "editor/editor_string_names.h"
|
||||
#include "editor/gui/editor_file_dialog.h"
|
||||
#include "editor/gui/editor_toaster.h"
|
||||
#include "editor/scene_tree_dock.h"
|
||||
#include "scene/debugger/scene_debugger.h"
|
||||
#include "scene/gui/texture_rect.h"
|
||||
|
|
@ -44,6 +45,7 @@
|
|||
EditorDebuggerTree::EditorDebuggerTree() {
|
||||
set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
set_allow_rmb_select(true);
|
||||
set_select_mode(SELECT_MULTI);
|
||||
|
||||
// Popup
|
||||
item_menu = memnew(PopupMenu);
|
||||
|
|
@ -54,6 +56,9 @@ EditorDebuggerTree::EditorDebuggerTree() {
|
|||
file_dialog = memnew(EditorFileDialog);
|
||||
file_dialog->connect("file_selected", callable_mp(this, &EditorDebuggerTree::_file_selected));
|
||||
add_child(file_dialog);
|
||||
|
||||
accept = memnew(AcceptDialog);
|
||||
add_child(accept);
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::_notification(int p_what) {
|
||||
|
|
@ -61,7 +66,8 @@ void EditorDebuggerTree::_notification(int p_what) {
|
|||
case NOTIFICATION_POSTINITIALIZE: {
|
||||
set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
|
||||
connect("cell_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_selected));
|
||||
connect("multi_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_selection_changed));
|
||||
connect("nothing_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_nothing_selected));
|
||||
connect("item_collapsed", callable_mp(this, &EditorDebuggerTree::_scene_tree_folded));
|
||||
connect("item_mouse_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_rmb_selected));
|
||||
} break;
|
||||
|
|
@ -73,24 +79,57 @@ void EditorDebuggerTree::_notification(int p_what) {
|
|||
}
|
||||
|
||||
void EditorDebuggerTree::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("object_selected", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::INT, "debugger")));
|
||||
ADD_SIGNAL(MethodInfo("objects_selected", PropertyInfo(Variant::ARRAY, "object_ids"), PropertyInfo(Variant::INT, "debugger")));
|
||||
ADD_SIGNAL(MethodInfo("selection_cleared", PropertyInfo(Variant::INT, "debugger")));
|
||||
ADD_SIGNAL(MethodInfo("save_node", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "filename"), PropertyInfo(Variant::INT, "debugger")));
|
||||
ADD_SIGNAL(MethodInfo("open"));
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::_scene_tree_selected() {
|
||||
if (updating_scene_tree) {
|
||||
void EditorDebuggerTree::_scene_tree_selection_changed(TreeItem *p_item, int p_column, bool p_selected) {
|
||||
if (updating_scene_tree || !p_item) {
|
||||
return;
|
||||
}
|
||||
|
||||
TreeItem *item = get_selected();
|
||||
if (!item) {
|
||||
return;
|
||||
uint64_t id = uint64_t(p_item->get_metadata(0));
|
||||
if (p_selected) {
|
||||
if (inspected_object_ids.size() == (int)EDITOR_GET("debugger/max_node_selection")) {
|
||||
selection_surpassed_limit = true;
|
||||
p_item->deselect(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inspected_object_ids.has(id)) {
|
||||
inspected_object_ids.append(id);
|
||||
}
|
||||
} else if (inspected_object_ids.has(id)) {
|
||||
inspected_object_ids.erase(id);
|
||||
}
|
||||
|
||||
inspected_object_id = uint64_t(item->get_metadata(0));
|
||||
if (!notify_selection_queued) {
|
||||
callable_mp(this, &EditorDebuggerTree::_notify_selection_changed).call_deferred();
|
||||
notify_selection_queued = true;
|
||||
}
|
||||
}
|
||||
|
||||
emit_signal(SNAME("object_selected"), inspected_object_id, debugger_id);
|
||||
void EditorDebuggerTree::_scene_tree_nothing_selected() {
|
||||
deselect_all();
|
||||
inspected_object_ids.clear();
|
||||
emit_signal(SNAME("selection_cleared"), debugger_id);
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::_notify_selection_changed() {
|
||||
notify_selection_queued = false;
|
||||
|
||||
if (inspected_object_ids.is_empty()) {
|
||||
emit_signal(SNAME("selection_cleared"), debugger_id);
|
||||
} else {
|
||||
emit_signal(SNAME("objects_selected"), inspected_object_ids.duplicate(), debugger_id);
|
||||
}
|
||||
|
||||
if (selection_surpassed_limit) {
|
||||
selection_surpassed_limit = false;
|
||||
EditorToaster::get_singleton()->popup_str(vformat(TTR("Some remote nodes were not selected, as the configured maximum selection is %d. This can be changed at \"debugger/max_node_selection\" in the Editor Settings."), EDITOR_GET("debugger/max_node_selection")), EditorToaster::SEVERITY_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::_scene_tree_folded(Object *p_obj) {
|
||||
|
|
@ -124,7 +163,7 @@ void EditorDebuggerTree::_scene_tree_rmb_selected(const Vector2 &p_position, Mou
|
|||
item->select(0);
|
||||
|
||||
item_menu->clear();
|
||||
item_menu->add_icon_item(get_editor_theme_icon(SNAME("CreateNewSceneFrom")), TTR("Save Branch as Scene"), ITEM_MENU_SAVE_REMOTE_NODE);
|
||||
item_menu->add_icon_item(get_editor_theme_icon(SNAME("CreateNewSceneFrom")), TTR("Save Branch as Scene..."), ITEM_MENU_SAVE_REMOTE_NODE);
|
||||
item_menu->add_icon_item(get_editor_theme_icon(SNAME("CopyNodePath")), TTR("Copy Node Path"), ITEM_MENU_COPY_NODE_PATH);
|
||||
item_menu->add_icon_item(get_editor_theme_icon(SNAME("Collapse")), TTR("Expand/Collapse Branch"), ITEM_MENU_EXPAND_COLLAPSE);
|
||||
item_menu->set_position(get_screen_position() + get_local_mouse_position());
|
||||
|
|
@ -152,12 +191,13 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
updating_scene_tree = true;
|
||||
const String last_path = get_selected_path();
|
||||
const String filter = SceneTreeDock::get_singleton()->get_filter();
|
||||
TreeItem *select_item = nullptr;
|
||||
LocalVector<TreeItem *> select_items;
|
||||
bool hide_filtered_out_parents = EDITOR_GET("docks/scene_tree/hide_filtered_out_parents");
|
||||
|
||||
bool should_scroll = scrolling_to_item || filter != last_filter;
|
||||
scrolling_to_item = false;
|
||||
TreeItem *scroll_item = nullptr;
|
||||
TypedArray<uint64_t> ids_present;
|
||||
|
||||
// Nodes are in a flatten list, depth first. Use a stack of parents, avoid recursion.
|
||||
List<ParentItem> parents;
|
||||
|
|
@ -216,9 +256,11 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
}
|
||||
item->set_meta("node_path", current_path + "/" + item->get_text(0));
|
||||
|
||||
// Select previously selected node.
|
||||
// Select previously selected nodes.
|
||||
if (debugger_id == p_debugger) { // Can use remote id.
|
||||
if (node.id == inspected_object_id) {
|
||||
if (inspected_object_ids.has(uint64_t(node.id))) {
|
||||
ids_present.append(node.id);
|
||||
|
||||
if (selection_uncollapse_all) {
|
||||
selection_uncollapse_all = false;
|
||||
|
||||
|
|
@ -228,14 +270,14 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
updating_scene_tree = true;
|
||||
}
|
||||
|
||||
select_item = item;
|
||||
select_items.push_back(item);
|
||||
if (should_scroll) {
|
||||
scroll_item = item;
|
||||
}
|
||||
}
|
||||
} else if (last_path == (String)item->get_meta("node_path")) { // Must use path.
|
||||
updating_scene_tree = false; // Force emission of new selection.
|
||||
select_item = item;
|
||||
updating_scene_tree = false; // Force emission of new selections.
|
||||
select_items.push_back(item);
|
||||
if (should_scroll) {
|
||||
scroll_item = item;
|
||||
}
|
||||
|
|
@ -280,12 +322,12 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
break; // Filter matches, must survive.
|
||||
}
|
||||
|
||||
parent->remove_child(item);
|
||||
memdelete(item);
|
||||
if (select_item == item || scroll_item == item) {
|
||||
select_item = nullptr;
|
||||
if (select_items.has(item) || scroll_item == item) {
|
||||
select_items.resize(select_items.size() - 1);
|
||||
scroll_item = nullptr;
|
||||
}
|
||||
parent->remove_child(item);
|
||||
memdelete(item);
|
||||
|
||||
if (had_siblings) {
|
||||
break; // Parent must survive.
|
||||
|
|
@ -316,18 +358,20 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
|
||||
from->get_parent()->remove_child(from);
|
||||
memdelete(from);
|
||||
if (select_item == from || scroll_item == from) {
|
||||
select_item = nullptr;
|
||||
if (select_items.has(from) || scroll_item == from) {
|
||||
select_items.erase(from);
|
||||
scroll_item = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inspected_object_ids = ids_present;
|
||||
|
||||
debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree.
|
||||
|
||||
if (select_item) {
|
||||
select_item->select(0);
|
||||
for (TreeItem *item : select_items) {
|
||||
item->select(0);
|
||||
}
|
||||
if (scroll_item) {
|
||||
scroll_to_item(scroll_item, false);
|
||||
|
|
@ -337,12 +381,22 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
updating_scene_tree = false;
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::select_node(ObjectID p_id) {
|
||||
void EditorDebuggerTree::select_nodes(const TypedArray<int64_t> &p_ids) {
|
||||
// Manually select, as the tree control may be out-of-date for some reason (e.g. not shown yet).
|
||||
selection_uncollapse_all = true;
|
||||
inspected_object_id = uint64_t(p_id);
|
||||
inspected_object_ids = p_ids;
|
||||
scrolling_to_item = true;
|
||||
emit_signal(SNAME("object_selected"), inspected_object_id, debugger_id);
|
||||
|
||||
if (!updating_scene_tree) {
|
||||
// Request a tree refresh.
|
||||
EditorDebuggerNode::get_singleton()->request_remote_tree();
|
||||
}
|
||||
// Set the value immediately, so no update flooding happens and causes a crash.
|
||||
updating_scene_tree = true;
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::clear_selection() {
|
||||
inspected_object_ids.clear();
|
||||
|
||||
if (!updating_scene_tree) {
|
||||
// Request a tree refresh.
|
||||
|
|
@ -453,8 +507,11 @@ void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
|
|||
}
|
||||
|
||||
void EditorDebuggerTree::_file_selected(const String &p_file) {
|
||||
if (inspected_object_id.is_null()) {
|
||||
if (inspected_object_ids.size() != 1) {
|
||||
accept->set_text(vformat(TTR("Saving the branch as a scene requires selecting only one node, but you have selected %d nodes."), inspected_object_ids.size()));
|
||||
accept->popup_centered();
|
||||
return;
|
||||
}
|
||||
emit_signal(SNAME("save_node"), inspected_object_id, p_file, debugger_id);
|
||||
|
||||
emit_signal(SNAME("save_node"), inspected_object_ids[0], p_file, debugger_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_DEBUGGER_TREE_H
|
||||
#define EDITOR_DEBUGGER_TREE_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/tree.h"
|
||||
|
||||
class AcceptDialog;
|
||||
class SceneDebuggerTree;
|
||||
class EditorFileDialog;
|
||||
|
||||
|
|
@ -58,18 +58,23 @@ private:
|
|||
ITEM_MENU_EXPAND_COLLAPSE,
|
||||
};
|
||||
|
||||
ObjectID inspected_object_id;
|
||||
TypedArray<uint64_t> inspected_object_ids;
|
||||
int debugger_id = 0;
|
||||
bool updating_scene_tree = false;
|
||||
bool scrolling_to_item = false;
|
||||
bool notify_selection_queued = false;
|
||||
bool selection_surpassed_limit = false;
|
||||
bool selection_uncollapse_all = false;
|
||||
HashSet<ObjectID> unfold_cache;
|
||||
PopupMenu *item_menu = nullptr;
|
||||
EditorFileDialog *file_dialog = nullptr;
|
||||
AcceptDialog *accept = nullptr;
|
||||
String last_filter;
|
||||
|
||||
void _scene_tree_folded(Object *p_obj);
|
||||
void _scene_tree_selected();
|
||||
void _scene_tree_selection_changed(TreeItem *p_item, int p_column, bool p_selected);
|
||||
void _scene_tree_nothing_selected();
|
||||
void _notify_selection_changed();
|
||||
void _scene_tree_rmb_selected(const Vector2 &p_position, MouseButton p_button);
|
||||
void _item_menu_id_pressed(int p_option);
|
||||
void _file_selected(const String &p_file);
|
||||
|
|
@ -90,9 +95,10 @@ public:
|
|||
String get_selected_path();
|
||||
ObjectID get_selected_object();
|
||||
int get_current_debugger(); // Would love to have one tree for every debugger.
|
||||
inline TypedArray<uint64_t> get_selection() const { return inspected_object_ids.duplicate(); }
|
||||
void update_scene_tree(const SceneDebuggerTree *p_tree, int p_debugger);
|
||||
void select_node(ObjectID p_id);
|
||||
void select_nodes(const TypedArray<int64_t> &p_ids);
|
||||
void clear_selection();
|
||||
|
||||
EditorDebuggerTree();
|
||||
};
|
||||
|
||||
#endif // EDITOR_DEBUGGER_TREE_H
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@ void EditorExpressionEvaluator::_clear() {
|
|||
}
|
||||
|
||||
void EditorExpressionEvaluator::_remote_object_selected(ObjectID p_id) {
|
||||
editor_debugger->emit_signal(SNAME("remote_object_requested"), p_id);
|
||||
Array arr = { p_id };
|
||||
editor_debugger->emit_signal(SNAME("remote_objects_requested"), arr);
|
||||
}
|
||||
|
||||
void EditorExpressionEvaluator::_on_expression_input_changed(const String &p_expression) {
|
||||
|
|
@ -109,6 +110,7 @@ EditorExpressionEvaluator::EditorExpressionEvaluator() {
|
|||
expression_input = memnew(LineEdit);
|
||||
expression_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
expression_input->set_placeholder(TTR("Expression to evaluate"));
|
||||
expression_input->set_accessibility_name(TTRC("Expression"));
|
||||
expression_input->set_clear_button_enabled(true);
|
||||
expression_input->connect(SceneStringName(text_submitted), callable_mp(this, &EditorExpressionEvaluator::_evaluate).unbind(1));
|
||||
expression_input->connect(SceneStringName(text_changed), callable_mp(this, &EditorExpressionEvaluator::_on_expression_input_changed));
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_EXPRESSION_EVALUATOR_H
|
||||
#define EDITOR_EXPRESSION_EVALUATOR_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
|
||||
|
|
@ -73,5 +72,3 @@ public:
|
|||
|
||||
EditorExpressionEvaluator();
|
||||
};
|
||||
|
||||
#endif // EDITOR_EXPRESSION_EVALUATOR_H
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ void EditorFileServer::_scan_files_changed(EditorFileSystemDirectory *efd, const
|
|||
uint64_t mt = FileAccess::get_modified_time(remapped_path);
|
||||
_add_file(remapped_path, mt, files_to_send, cached_files);
|
||||
} else if (remap.begins_with("path.")) {
|
||||
String feature = remap.get_slice(".", 1);
|
||||
String feature = remap.get_slicec('.', 1);
|
||||
if (p_tags.has(feature)) {
|
||||
String remapped_path = cf->get_value("remap", remap);
|
||||
uint64_t mt = FileAccess::get_modified_time(remapped_path);
|
||||
|
|
@ -200,7 +200,7 @@ void EditorFileServer::poll() {
|
|||
// Scan files to send.
|
||||
_scan_files_changed(EditorFileSystem::get_singleton()->get_filesystem(), tags, files_to_send, cached_files);
|
||||
// Add forced export files
|
||||
Vector<String> forced_export = EditorExportPlatform::get_forced_export_files();
|
||||
Vector<String> forced_export = EditorExportPlatform::get_forced_export_files(Ref<EditorExportPreset>());
|
||||
for (int i = 0; i < forced_export.size(); i++) {
|
||||
_add_custom_file(forced_export[i], files_to_send, cached_files);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_FILE_SERVER_H
|
||||
#define EDITOR_FILE_SERVER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/tcp_server.h"
|
||||
#include "core/os/thread.h"
|
||||
|
|
@ -55,5 +54,3 @@ public:
|
|||
EditorFileServer();
|
||||
~EditorFileServer();
|
||||
};
|
||||
|
||||
#endif // EDITOR_FILE_SERVER_H
|
||||
|
|
|
|||
|
|
@ -37,8 +37,6 @@
|
|||
#include "editor/themes/editor_theme_manager.h"
|
||||
#include "main/performance.h"
|
||||
|
||||
EditorPerformanceProfiler::Monitor::Monitor() {}
|
||||
|
||||
EditorPerformanceProfiler::Monitor::Monitor(const String &p_name, const String &p_base, int p_frame_index, Performance::MonitorType p_type, TreeItem *p_item) {
|
||||
type = p_type;
|
||||
item = p_item;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_PERFORMANCE_PROFILER_H
|
||||
#define EDITOR_PERFORMANCE_PROFILER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "main/performance.h"
|
||||
|
|
@ -52,7 +51,7 @@ private:
|
|||
Performance::MonitorType type = Performance::MONITOR_TYPE_QUANTITY;
|
||||
int frame_index = 0;
|
||||
|
||||
Monitor();
|
||||
Monitor() {}
|
||||
Monitor(const String &p_name, const String &p_base, int p_frame_index, Performance::MonitorType p_type, TreeItem *p_item);
|
||||
void update_value(float p_value);
|
||||
void reset();
|
||||
|
|
@ -88,5 +87,3 @@ public:
|
|||
List<float> *get_monitor_data(const StringName &p_name);
|
||||
EditorPerformanceProfiler();
|
||||
};
|
||||
|
||||
#endif // EDITOR_PERFORMANCE_PROFILER_H
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ String EditorProfiler::_get_time_as_text(const Metric &m, float p_time, int p_ca
|
|||
|
||||
Color EditorProfiler::_get_color_from_signature(const StringName &p_signature) const {
|
||||
Color bc = get_theme_color(SNAME("error_color"), EditorStringName(Editor));
|
||||
double rot = ABS(double(p_signature.hash()) / double(0x7FFFFFFF));
|
||||
double rot = Math::abs(double(p_signature.hash()) / double(0x7FFFFFFF));
|
||||
Color c;
|
||||
c.set_hsv(rot, bc.get_s(), bc.get_v());
|
||||
return c.lerp(get_theme_color(SNAME("base_color"), EditorStringName(Editor)), 0.07);
|
||||
|
|
@ -694,6 +694,7 @@ EditorProfiler::EditorProfiler() {
|
|||
hb_measure->add_child(memnew(Label(TTR("Measure:"))));
|
||||
|
||||
display_mode = memnew(OptionButton);
|
||||
display_mode->set_accessibility_name(TTRC("Measure"));
|
||||
display_mode->add_item(TTR("Frame Time (ms)"));
|
||||
display_mode->add_item(TTR("Average Time (ms)"));
|
||||
display_mode->add_item(TTR("Frame %"));
|
||||
|
|
@ -709,6 +710,7 @@ EditorProfiler::EditorProfiler() {
|
|||
hb_time->add_child(memnew(Label(TTR("Time:"))));
|
||||
|
||||
display_time = memnew(OptionButton);
|
||||
display_time->set_accessibility_name(TTRC("Time"));
|
||||
// TRANSLATORS: This is an option in the profiler to display the time spent in a function, including the time spent in other functions called by that function.
|
||||
display_time->add_item(TTR("Inclusive"));
|
||||
// TRANSLATORS: This is an option in the profiler to display the time spent in a function, exincluding the time spent in other functions called by that function.
|
||||
|
|
@ -731,6 +733,7 @@ EditorProfiler::EditorProfiler() {
|
|||
hb_frame->add_child(memnew(Label(TTR("Frame #:"))));
|
||||
|
||||
cursor_metric_edit = memnew(SpinBox);
|
||||
cursor_metric_edit->set_accessibility_name(TTRC("Frame"));
|
||||
cursor_metric_edit->set_h_size_flags(SIZE_FILL);
|
||||
cursor_metric_edit->set_value(0);
|
||||
cursor_metric_edit->set_editable(false);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_PROFILER_H
|
||||
#define EDITOR_PROFILER_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
|
|
@ -186,5 +185,3 @@ public:
|
|||
|
||||
EditorProfiler();
|
||||
};
|
||||
|
||||
#endif // EDITOR_PROFILER_H
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ String EditorVisualProfiler::_get_time_as_text(float p_time) {
|
|||
|
||||
Color EditorVisualProfiler::_get_color_from_signature(const StringName &p_signature) const {
|
||||
Color bc = get_theme_color(SNAME("error_color"), EditorStringName(Editor));
|
||||
double rot = ABS(double(p_signature.hash()) / double(0x7FFFFFFF));
|
||||
double rot = Math::abs(double(p_signature.hash()) / double(0x7FFFFFFF));
|
||||
Color c;
|
||||
c.set_hsv(rot, bc.get_s(), bc.get_v());
|
||||
return c.lerp(get_theme_color(SNAME("base_color"), EditorStringName(Editor)), 0.07);
|
||||
|
|
@ -362,7 +362,7 @@ void EditorVisualProfiler::_update_frame(bool p_focus_selected) {
|
|||
stack.push_back(category);
|
||||
categories.push_back(category);
|
||||
|
||||
name = name.substr(1, name.length());
|
||||
name = name.substr(1);
|
||||
|
||||
category->set_text(0, name);
|
||||
category->set_metadata(1, cpu_time);
|
||||
|
|
@ -778,6 +778,7 @@ EditorVisualProfiler::EditorVisualProfiler() {
|
|||
hb_measure->add_child(memnew(Label(TTR("Measure:"))));
|
||||
|
||||
display_mode = memnew(OptionButton);
|
||||
display_mode->set_accessibility_name(TTRC("Measure"));
|
||||
display_mode->add_item(TTR("Frame Time (ms)"));
|
||||
display_mode->add_item(TTR("Frame %"));
|
||||
display_mode->connect(SceneStringName(item_selected), callable_mp(this, &EditorVisualProfiler::_combo_changed));
|
||||
|
|
@ -801,6 +802,7 @@ EditorVisualProfiler::EditorVisualProfiler() {
|
|||
hb_frame->add_child(memnew(Label(TTR("Frame #:"))));
|
||||
|
||||
cursor_metric_edit = memnew(SpinBox);
|
||||
cursor_metric_edit->set_accessibility_name(TTRC("Frame"));
|
||||
cursor_metric_edit->set_h_size_flags(SIZE_FILL);
|
||||
hb_frame->add_child(cursor_metric_edit);
|
||||
cursor_metric_edit->connect(SceneStringName(value_changed), callable_mp(this, &EditorVisualProfiler::_cursor_metric_changed));
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_VISUAL_PROFILER_H
|
||||
#define EDITOR_VISUAL_PROFILER_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
|
|
@ -153,5 +152,3 @@ public:
|
|||
|
||||
EditorVisualProfiler();
|
||||
};
|
||||
|
||||
#endif // EDITOR_VISUAL_PROFILER_H
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -28,17 +28,15 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef SCRIPT_EDITOR_DEBUGGER_H
|
||||
#define SCRIPT_EDITOR_DEBUGGER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/os/os.h"
|
||||
#include "editor/debugger/editor_debugger_inspector.h"
|
||||
#include "editor/debugger/editor_debugger_node.h"
|
||||
#include "editor/debugger/editor_debugger_server.h"
|
||||
#include "scene/gui/button.h"
|
||||
#include "scene/gui/margin_container.h"
|
||||
|
||||
class Button;
|
||||
class Tree;
|
||||
class LineEdit;
|
||||
class TabContainer;
|
||||
|
|
@ -115,6 +113,7 @@ private:
|
|||
int warning_count;
|
||||
|
||||
bool skip_breakpoints_value = false;
|
||||
bool ignore_error_breaks_value = false;
|
||||
Ref<Script> stack_script;
|
||||
|
||||
TabContainer *tabs = nullptr;
|
||||
|
|
@ -122,6 +121,7 @@ private:
|
|||
Label *reason = nullptr;
|
||||
|
||||
Button *skip_breakpoints = nullptr;
|
||||
Button *ignore_error_breaks = nullptr;
|
||||
Button *copy = nullptr;
|
||||
Button *step = nullptr;
|
||||
Button *next = nullptr;
|
||||
|
|
@ -147,7 +147,7 @@ private:
|
|||
Ref<RemoteDebuggerPeer> peer;
|
||||
|
||||
HashMap<NodePath, int> node_path_cache;
|
||||
int last_path_id;
|
||||
int last_path_id = 0;
|
||||
HashMap<String, int> res_path_cache;
|
||||
|
||||
EditorProfiler *profiler = nullptr;
|
||||
|
|
@ -159,7 +159,7 @@ private:
|
|||
bool move_to_foreground = true;
|
||||
bool can_request_idle_draw = false;
|
||||
|
||||
bool live_debug;
|
||||
bool live_debug = true;
|
||||
|
||||
uint64_t debugging_thread_id = Thread::UNASSIGNED_ID;
|
||||
|
||||
|
|
@ -183,16 +183,54 @@ private:
|
|||
|
||||
void _select_thread(int p_index);
|
||||
|
||||
bool debug_mute_audio = false;
|
||||
|
||||
EditorDebuggerNode::CameraOverride camera_override;
|
||||
|
||||
void _stack_dump_frame_selected();
|
||||
|
||||
void _file_selected(const String &p_file);
|
||||
|
||||
/// Message handler function for _parse_message.
|
||||
typedef void (ScriptEditorDebugger::*ParseMessageFunc)(uint64_t p_thread_id, const Array &p_data);
|
||||
static HashMap<String, ParseMessageFunc> parse_message_handlers;
|
||||
static void _init_parse_message_handlers();
|
||||
|
||||
void _msg_debug_enter(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_debug_exit(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_set_pid(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_scene_click_ctrl(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_scene_scene_tree(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_scene_inspect_objects(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_servers_memory_usage(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_servers_drawn(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_stack_dump(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_stack_frame_vars(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_stack_frame_var(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_output(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_performance_profile_frame(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_visual_hardware_info(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_visual_profile_frame(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_error(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_servers_function_signature(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_servers_profile_common(const Array &p_data, const bool p_final);
|
||||
void _msg_servers_profile_frame(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_servers_profile_total(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_request_quit(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_remote_objects_selected(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_remote_nothing_selected(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_remote_selection_invalidated(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_show_selection_limit_warning(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_performance_profile_names(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_filesystem_update_file(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_evaluation_return(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_window_title(uint64_t p_thread_id, const Array &p_data);
|
||||
|
||||
void _parse_message(const String &p_msg, uint64_t p_thread_id, const Array &p_data);
|
||||
void _set_reason_text(const String &p_reason, MessageType p_type);
|
||||
void _update_buttons_state();
|
||||
void _remote_object_selected(ObjectID p_object);
|
||||
void _remote_object_edited(ObjectID, const String &p_prop, const Variant &p_value);
|
||||
void _remote_objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field);
|
||||
void _remote_object_property_updated(ObjectID p_id, const String &p_property);
|
||||
|
||||
void _video_mem_request();
|
||||
|
|
@ -216,6 +254,8 @@ private:
|
|||
void _expand_errors_list();
|
||||
void _collapse_errors_list();
|
||||
|
||||
void _vmem_item_activated();
|
||||
|
||||
void _profiler_activate(bool p_enable, int p_profiler);
|
||||
void _profiler_seeked();
|
||||
|
||||
|
|
@ -246,9 +286,10 @@ protected:
|
|||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void request_remote_object(ObjectID p_obj_id);
|
||||
void update_remote_object(ObjectID p_obj_id, const String &p_prop, const Variant &p_value);
|
||||
Object *get_remote_object(ObjectID p_id);
|
||||
void request_remote_objects(const TypedArray<uint64_t> &p_obj_ids, bool p_update_selection = true);
|
||||
void update_remote_object(ObjectID p_obj_id, const String &p_prop, const Variant &p_value, const String &p_field = "");
|
||||
|
||||
void clear_inspector(bool p_send_msg = true);
|
||||
|
||||
// Needed by _live_edit_set, buttons state.
|
||||
void set_editor_remote_tree(const Tree *p_tree) { editor_remote_tree = p_tree; }
|
||||
|
|
@ -262,6 +303,7 @@ public:
|
|||
void stop();
|
||||
|
||||
void debug_skip_breakpoints();
|
||||
void debug_ignore_error_breaks();
|
||||
void debug_copy();
|
||||
|
||||
void debug_next();
|
||||
|
|
@ -299,6 +341,9 @@ public:
|
|||
void live_debug_duplicate_node(const NodePath &p_at, const String &p_new_name);
|
||||
void live_debug_reparent_node(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos);
|
||||
|
||||
bool get_debug_mute_audio() const;
|
||||
void set_debug_mute_audio(bool p_mute);
|
||||
|
||||
EditorDebuggerNode::CameraOverride get_camera_override() const;
|
||||
void set_camera_override(EditorDebuggerNode::CameraOverride p_override);
|
||||
|
||||
|
|
@ -309,7 +354,8 @@ public:
|
|||
void reload_all_scripts();
|
||||
void reload_scripts(const Vector<String> &p_script_paths);
|
||||
|
||||
bool is_skip_breakpoints();
|
||||
bool is_skip_breakpoints() const;
|
||||
bool is_ignore_error_breaks() const;
|
||||
|
||||
virtual Size2 get_minimum_size() const override;
|
||||
|
||||
|
|
@ -324,5 +370,3 @@ public:
|
|||
ScriptEditorDebugger();
|
||||
~ScriptEditorDebugger();
|
||||
};
|
||||
|
||||
#endif // SCRIPT_EDITOR_DEBUGGER_H
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue