diff --git a/src/debugger/godot3/debug_session.ts b/src/debugger/godot3/debug_session.ts index 620bc8e22..66c029722 100644 --- a/src/debugger/godot3/debug_session.ts +++ b/src/debugger/godot3/debug_session.ts @@ -311,9 +311,24 @@ export class GodotDebugSession extends LoggingDebugSession { return; } - const reference = this.all_scopes[args.variablesReference]; + let reference = this.all_scopes[args.variablesReference]; let variables: DebugProtocol.Variable[]; + if (reference.value?.id !== undefined) { + const inspected_object: Subject = new Subject(); + + this.inspect_callbacks.set( + BigInt(reference.value.id), + (_class_name, _variable) => inspected_object.notify() + ); + + this.add_to_inspections([ reference ]); + + await inspected_object.wait(2000); + + reference = this.all_scopes[args.variablesReference]; + } + if (!reference.sub_values) { variables = []; } else { @@ -385,12 +400,7 @@ export class GodotDebugSession extends LoggingDebugSession { this.append_variable(va); }); - this.add_to_inspections(); - - if (this.ongoing_inspections.length === 0) { - this.previous_inspections = []; - this.got_scope.notify(); - } + this.got_scope.notify(); } public set_inspection(id: bigint, replacement: GodotVariable) { @@ -413,16 +423,14 @@ export class GodotDebugSession extends LoggingDebugSession { this.previous_inspections.push(id); - // this.add_to_inspections(); - if (this.ongoing_inspections.length === 0) { this.previous_inspections = []; this.got_scope.notify(); } } - private add_to_inspections() { - this.all_scopes.forEach((va) => { + public add_to_inspections(variables: GodotVariable[]) { + variables?.forEach((va) => { if (va && va.value instanceof ObjectId) { if ( !this.ongoing_inspections.includes(va.value.id) && @@ -543,7 +551,7 @@ export class GodotDebugSession extends LoggingDebugSession { if (variable.sub_values) { variable.sub_values.forEach((va, i) => { va.scope_path = base_path; - this.append_variable(va, index ? index + i + 1 : undefined); + this.append_variable(va); }); } } diff --git a/src/debugger/godot3/helpers.ts b/src/debugger/godot3/helpers.ts index e03e9ff31..60759b3a6 100644 --- a/src/debugger/godot3/helpers.ts +++ b/src/debugger/godot3/helpers.ts @@ -34,40 +34,6 @@ export function is_variable_built_in_type(va: GodotVariable) { return ["number", "bigint", "boolean", "string"].some(x => x == type); } -export function build_sub_values(va: GodotVariable) { - const value = va.value; - - let subValues: GodotVariable[] = undefined; - - if (value && Array.isArray(value)) { - subValues = value.map((va, i) => { - return { name: `${i}`, value: va } as GodotVariable; - }); - } else if (value instanceof Map) { - subValues = Array.from(value.keys()).map((va) => { - if (typeof va["stringify_value"] === "function") { - return { - name: `${va.type_name()}${va.stringify_value()}`, - value: value.get(va), - } as GodotVariable; - } else { - return { - name: `${va}`, - value: value.get(va), - } as GodotVariable; - } - }); - } else if (value && typeof value["sub_values"] === "function") { - subValues = value.sub_values().map((sva) => { - return { name: sva.name, value: sva.value } as GodotVariable; - }); - } - - va.sub_values = subValues; - - subValues?.forEach(build_sub_values); -} - export function parse_variable(va: GodotVariable, i?: number) { const value = va.value; let rendered_value = ""; diff --git a/src/debugger/godot3/server_controller.ts b/src/debugger/godot3/server_controller.ts index 4dda105ef..d9b244aa2 100644 --- a/src/debugger/godot3/server_controller.ts +++ b/src/debugger/godot3/server_controller.ts @@ -5,9 +5,9 @@ import { StoppedEvent, TerminatedEvent } from "@vscode/debugadapter"; import { VariantEncoder } from "./variables/variant_encoder"; import { VariantDecoder } from "./variables/variant_decoder"; import { RawObject } from "./variables/variants"; -import { GodotStackFrame, GodotStackVars } from "../debug_runtime"; +import { GodotStackFrame, GodotVariable, GodotStackVars } from "../debug_runtime"; import { GodotDebugSession } from "./debug_session"; -import { parse_next_scene_node, split_buffers, build_sub_values } from "./helpers"; +import { parse_next_scene_node, split_buffers } from "./helpers"; import { get_configuration, get_free_port, createLogger, verify_godot_version, get_project_version } from "../../utils"; import { prompt_for_godot_executable } from "../../utils/prompts"; import { subProcess, killSubProcesses } from "../../utils/subspawn"; @@ -392,7 +392,7 @@ export class ServerController { rawObject.set(prop[0], prop[5]); }); const inspectedVariable = { name: "", value: rawObject }; - build_sub_values(inspectedVariable); + ServerController.build_sub_values(inspectedVariable); if (this.session.inspect_callbacks.has(BigInt(id))) { this.session.inspect_callbacks.get(BigInt(id))( inspectedVariable.name, @@ -551,8 +551,48 @@ export class ServerController { stackVars.globals.push({ name: parameters[i++], value: parameters[i++] }); } - stackVars.forEach(item => build_sub_values(item)); + stackVars.forEach(item => ServerController.build_sub_values(item)); this.session.set_scopes(stackVars); } + + private static build_sub_values(va: GodotVariable) { + const value = va.value; + + let subValues: GodotVariable[] = undefined; + + if (value && Array.isArray(value)) { + subValues = value.map((va, i) => { + return { + name: `${i}`, + value: va, + } as GodotVariable; + }); + } else if (value instanceof Map) { + subValues = Array.from(value.keys()).map((va) => { + if (typeof va["stringify_value"] === "function") { + return { + name: `${va.type_name()}${va.stringify_value()}`, + value: value.get(va), + } as GodotVariable; + } else { + return { + name: `${va}`, + value: value.get(va), + } as GodotVariable; + } + }); + } else if (value && typeof value["sub_values"] === "function") { + subValues = value.sub_values().map((sva) => { + return { + name: sva.name, + value: sva.value, + } as GodotVariable; + }); + } + + va.sub_values = subValues; + + subValues?.forEach(ServerController.build_sub_values); + } } diff --git a/src/debugger/godot4/debug_session.ts b/src/debugger/godot4/debug_session.ts index f36159d4c..833f14bf7 100644 --- a/src/debugger/godot4/debug_session.ts +++ b/src/debugger/godot4/debug_session.ts @@ -311,9 +311,25 @@ export class GodotDebugSession extends LoggingDebugSession { return; } - const reference = this.all_scopes[args.variablesReference]; + let reference = this.all_scopes[args.variablesReference]; let variables: DebugProtocol.Variable[]; + if (reference.value?.id !== undefined) { + const inspected_object: Subject = new Subject(); + + this.inspect_callbacks.set( + BigInt(reference.value.id), + (_class_name, _variable) => inspected_object.notify() + ); + + this.add_to_inspections([ reference ]); + + await inspected_object.wait(2000); + + reference = this.all_scopes[args.variablesReference]; + } + + if (!reference.sub_values) { variables = []; } else { @@ -385,12 +401,7 @@ export class GodotDebugSession extends LoggingDebugSession { this.append_variable(va); }); - this.add_to_inspections(); - - if (this.ongoing_inspections.length === 0) { - this.previous_inspections = []; - this.got_scope.notify(); - } + this.got_scope.notify(); } public set_inspection(id: bigint, replacement: GodotVariable) { @@ -413,16 +424,14 @@ export class GodotDebugSession extends LoggingDebugSession { this.previous_inspections.push(id); - // this.add_to_inspections(); - if (this.ongoing_inspections.length === 0) { this.previous_inspections = []; this.got_scope.notify(); } } - private add_to_inspections() { - this.all_scopes.forEach((va) => { + public add_to_inspections(variables: GodotVariable[]) { + variables?.forEach((va) => { if (va && va.value instanceof ObjectId) { if ( !this.ongoing_inspections.includes(va.value.id) && @@ -544,7 +553,7 @@ export class GodotDebugSession extends LoggingDebugSession { if (variable.sub_values) { variable.sub_values.forEach((va, i) => { va.scope_path = base_path; - this.append_variable(va, index ? index + i + 1 : undefined); + this.append_variable(va); }); } } diff --git a/src/debugger/godot4/helpers.ts b/src/debugger/godot4/helpers.ts index 066a98590..999f29460 100644 --- a/src/debugger/godot4/helpers.ts +++ b/src/debugger/godot4/helpers.ts @@ -36,40 +36,6 @@ export function is_variable_built_in_type(va: GodotVariable) { return ["number", "bigint", "boolean", "string"].some(x => x == type); } -export function build_sub_values(va: GodotVariable) { - const value = va.value; - - let subValues: GodotVariable[] = undefined; - - if (value && Array.isArray(value)) { - subValues = value.map((va, i) => { - return { name: `${i}`, value: va } as GodotVariable; - }); - } else if (value instanceof Map) { - subValues = Array.from(value.keys()).map((va) => { - if (typeof va["stringify_value"] === "function") { - return { - name: `${va.type_name()}${va.stringify_value()}`, - value: value.get(va), - } as GodotVariable; - } else { - return { - name: `${va}`, - value: value.get(va), - } as GodotVariable; - } - }); - } else if (value && typeof value["sub_values"] === "function") { - subValues = value.sub_values().map((sva) => { - return { name: sva.name, value: sva.value } as GodotVariable; - }); - } - - va.sub_values = subValues; - - subValues?.forEach(build_sub_values); -} - export function parse_variable(va: GodotVariable, i?: number) { const value = va.value; let rendered_value = ""; diff --git a/src/debugger/godot4/server_controller.ts b/src/debugger/godot4/server_controller.ts index 724e11e97..113bd295a 100644 --- a/src/debugger/godot4/server_controller.ts +++ b/src/debugger/godot4/server_controller.ts @@ -7,7 +7,7 @@ import { VariantDecoder } from "./variables/variant_decoder"; import { RawObject } from "./variables/variants"; import { GodotStackFrame, GodotVariable, GodotStackVars } from "../debug_runtime"; import { GodotDebugSession } from "./debug_session"; -import { parse_next_scene_node, split_buffers, build_sub_values } from "./helpers"; +import { parse_next_scene_node, split_buffers } from "./helpers"; import { get_configuration, get_free_port, createLogger, verify_godot_version, get_project_version } from "../../utils"; import { prompt_for_godot_executable } from "../../utils/prompts"; import { subProcess, killSubProcesses } from "../../utils/subspawn"; @@ -386,12 +386,18 @@ export class ServerController { id = id + BigInt(2) ** BigInt(64); } + // message:inspect_object returns the id as an unsigned 64 bit integer, but it is decoded as a signed 64 bit integer, + // thus we need to convert it to its equivalent unsigned value here. + if (id < 0) { + id = id + BigInt(2) ** BigInt(64); + } + const rawObject = new RawObject(className); properties.forEach((prop) => { rawObject.set(prop[0], prop[5]); }); const inspectedVariable = { name: "", value: rawObject }; - build_sub_values(inspectedVariable); + ServerController.build_sub_values(inspectedVariable); if (this.session.inspect_callbacks.has(BigInt(id))) { this.session.inspect_callbacks.get(BigInt(id))( inspectedVariable.name, @@ -419,8 +425,12 @@ export class ServerController { break; } case "stack_frame_vars": { - this.partialStackVars.reset(command.parameters[0]); - this.session.set_scopes(this.partialStackVars); + const stack_var_count = command.parameters[0]; + this.partialStackVars.reset(stack_var_count); + + if(stack_var_count <= 0) + this.session.set_scopes(this.partialStackVars); + break; } case "stack_frame_var": { @@ -559,7 +569,7 @@ export class ServerController { } const variable: GodotVariable = { name, value, type }; - build_sub_values(variable); + ServerController.build_sub_values(variable); const scopeName = ["locals", "members", "globals"][scope]; this.partialStackVars[scopeName].push(variable); @@ -569,4 +579,44 @@ export class ServerController { this.session.set_scopes(this.partialStackVars); } } + + private static build_sub_values(va: GodotVariable) { + const value = va.value; + + let subValues: GodotVariable[] = undefined; + + if (value && Array.isArray(value)) { + subValues = value.map((va, i) => { + return { + name: `${i}`, + value: va, + } as GodotVariable; + }); + } else if (value instanceof Map) { + subValues = Array.from(value.keys()).map((va) => { + if (typeof va["stringify_value"] === "function") { + return { + name: `${va.type_name()}${va.stringify_value()}`, + value: value.get(va), + } as GodotVariable; + } else { + return { + name: `${va}`, + value: value.get(va), + } as GodotVariable; + } + }); + } else if (value && typeof value["sub_values"] === "function") { + subValues = value.sub_values().map((sva) => { + return { + name: sva.name, + value: sva.value, + } as GodotVariable; + }); + } + + va.sub_values = subValues; + + subValues?.forEach(ServerController.build_sub_values.bind(this)); + } }