gdharness 1.2.34 → 1.2.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cli.js +251 -48
- package/build/godot/addons/gdharness_runtime/call_errors.gd +7 -2
- package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +9 -5
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +33 -0
- package/build/godot/addons/gdharness_runtime/runtime_changes.gd +12 -4
- package/build/godot/addons/gdharness_runtime/runtime_targets.gd +7 -5
- package/build/godot/addons/gdharness_runtime/runtime_waits.gd +113 -3
- package/build/godot/operations/classdb_queries.gd +22 -0
- package/build/godot/operations/dependencies.gd +90 -20
- package/build/godot/operations/export_presets.gd +232 -0
- package/build/godot/operations/gdscript_analysis.gd +19 -0
- package/build/godot/operations/godot_operations.gd +6 -2
- package/build/godot/operations/import_pipeline.gd +4 -60
- package/build/godot/operations/project_diagnostics.gd +3 -1
- package/build/godot/operations/rename_checks.gd +0 -19
- package/build/godot/operations/script_check.gd +98 -0
- package/build/index.js +247 -46
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -8141,9 +8141,14 @@ class GameLog {
|
|
|
8141
8141
|
const owner = this.lastHeadline[source];
|
|
8142
8142
|
if (owner !== null && /^\s/.test(line)) {
|
|
8143
8143
|
owner.detail.push(line.trim());
|
|
8144
|
+
owner.continues = false;
|
|
8144
8145
|
return;
|
|
8145
8146
|
}
|
|
8146
8147
|
const headline = announced(line);
|
|
8148
|
+
if (owner?.continues === true && headline === null) {
|
|
8149
|
+
owner.detail.push(line.trim());
|
|
8150
|
+
return;
|
|
8151
|
+
}
|
|
8147
8152
|
const detail = [];
|
|
8148
8153
|
const entry = {
|
|
8149
8154
|
index: this.entries.length,
|
|
@@ -8156,7 +8161,7 @@ class GameLog {
|
|
|
8156
8161
|
if (headline?.byScript === true) {
|
|
8157
8162
|
this.byScript.add(entry.index);
|
|
8158
8163
|
}
|
|
8159
|
-
this.lastHeadline[source] = headline ? { detail } : null;
|
|
8164
|
+
this.lastHeadline[source] = headline ? { detail, continues: source === "stderr" && headline.text.endsWith(":") } : null;
|
|
8160
8165
|
}
|
|
8161
8166
|
raisedByScript(entry) {
|
|
8162
8167
|
return this.byScript.has(entry.index);
|
|
@@ -11478,7 +11483,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
11478
11483
|
direction: {
|
|
11479
11484
|
type: "string",
|
|
11480
11485
|
enum: ["forward", "reverse"],
|
|
11481
|
-
description: "forward: what this resource loads, with cycles reported. reverse: every file that refers to it and how, a scene instancing it, a script extending, preloading or loading it, and for a script with a class_name every use of that name. Each reference carries a kind, and
|
|
11486
|
+
description: "forward: what this resource loads, with cycles reported, a script's dependencies including every script whose class_name it uses, marked by_class with the name. summary.total_dependencies counts each file once however many places load it, and total_references counts the entries in the tree. reverse: every file that refers to it and how, a scene instancing it, a script extending, preloading or loading it, and for a script with a class_name every use of that name. Each reference carries a kind: ext_resource, extends, preload, load or path for a reference by path; setting, plugin, export_preset and import for one in project.godot, a plugin.cfg, export_presets.cfg or an import sidecar; class_name for a use of the declared name, the declaration itself being the script asked about. Two kinds are mentions rather than uses: doc is a name inside a ## documentation comment, which renaming would break in the generated docs, and comment is one in ordinary prose, which it would only make stale. summary.in_code is the count with both of those left out, which is the number to read when the question is whether anything still uses this. Default forward."
|
|
11482
11487
|
},
|
|
11483
11488
|
depth: { type: "number", description: "forward: how many levels to follow. Default unlimited." },
|
|
11484
11489
|
includeBuiltin: {
|
|
@@ -11558,20 +11563,36 @@ var init_tool_definitions = __esm(() => {
|
|
|
11558
11563
|
{
|
|
11559
11564
|
name: "project_export",
|
|
11560
11565
|
title: "Export",
|
|
11561
|
-
description: "Export presets and exports.",
|
|
11566
|
+
description: "Export presets and exports. add_preset writes a preset to export_presets.cfg with the keys the editor's Project > Export writes for a new one, every platform option left at its default, and makes it the platform's runnable preset when the platform has none. It answers where this engine's export templates belong and whether the preset's platform has them, since an export needs them; list says the same for every preset. An editor open on the project does not see a preset added this way until it restarts. run names, as alsoWritten, what else the export wrote beside its output, such as the .pck a Windows or Linux build cannot start without.",
|
|
11562
11567
|
parameters: {
|
|
11563
11568
|
projectPath: PROJECT_PATH,
|
|
11564
|
-
preset: {
|
|
11569
|
+
preset: {
|
|
11570
|
+
type: "string",
|
|
11571
|
+
ops: ["run", "add_preset"],
|
|
11572
|
+
description: "Preset name from export_presets.cfg. add_preset: the name of the new one."
|
|
11573
|
+
},
|
|
11574
|
+
platform: {
|
|
11575
|
+
type: "string",
|
|
11576
|
+
ops: ["add_preset"],
|
|
11577
|
+
enum: ["Windows Desktop", "Linux", "macOS", "Android", "iOS", "Web"],
|
|
11578
|
+
description: "add_preset: the platform the preset exports for."
|
|
11579
|
+
},
|
|
11565
11580
|
outputPath: {
|
|
11566
11581
|
type: "string",
|
|
11567
|
-
|
|
11582
|
+
ops: ["run", "add_preset"],
|
|
11583
|
+
description: `Where the export is written, inside the project. The directory is created if it is not there: Godot's command-line exporter refuses a missing one with "The given export path doesn't exist", which reads as a wrong path in the preset. add_preset: the path the preset exports to from the editor, optional.`
|
|
11568
11584
|
},
|
|
11569
|
-
debug: { type: "boolean", description: "run: a debug export. Default false." }
|
|
11585
|
+
debug: { type: "boolean", ops: ["run"], description: "run: a debug export. Default false." }
|
|
11570
11586
|
},
|
|
11571
11587
|
requires: ["projectPath"],
|
|
11572
11588
|
operations: {
|
|
11573
11589
|
list: { effect: "read", summary: "the presets in export_presets.cfg", requires: [] },
|
|
11574
|
-
run: { effect: "destructive", summary: "export with a preset", requires: ["preset", "outputPath"] }
|
|
11590
|
+
run: { effect: "destructive", summary: "export with a preset", requires: ["preset", "outputPath"] },
|
|
11591
|
+
add_preset: {
|
|
11592
|
+
effect: "additive",
|
|
11593
|
+
summary: "add an export preset to export_presets.cfg",
|
|
11594
|
+
requires: ["preset", "platform"]
|
|
11595
|
+
}
|
|
11575
11596
|
}
|
|
11576
11597
|
},
|
|
11577
11598
|
{
|
|
@@ -11939,7 +11960,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
11939
11960
|
operations: {
|
|
11940
11961
|
structure: {
|
|
11941
11962
|
effect: "read",
|
|
11942
|
-
summary: "functions, variables, signals, class_name and extends, read from the file",
|
|
11963
|
+
summary: "functions, variables, signals, class_name and extends, read from the file, and dependencies: the paths it loads or preloads as written, then the scripts declaring each project class_name its code uses, which classes_used names with the class",
|
|
11943
11964
|
requires: []
|
|
11944
11965
|
},
|
|
11945
11966
|
symbols: {
|
|
@@ -11960,7 +11981,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
11960
11981
|
name: "script_diagnostics",
|
|
11961
11982
|
title: "Script diagnostics",
|
|
11962
11983
|
effect: "read",
|
|
11963
|
-
description: "Errors and warnings for a script, or for several, from the editor's language server, and whether each is clean.
|
|
11984
|
+
description: "Errors and warnings for a script, or for several, from the editor's language server, and whether each is clean. With no editor of this project open, so no language server of it to ask, a short headless engine compiles the scripts instead and the answer says checkedBy: engine: every error that stops a script compiling, with its line and no column, dependenciesWithErrors naming the other scripts that failed while it loaded, and warnings null, since the engine reports warnings only to an editor. Each diagnostic carries its severity (error or warning), its message, and where it is as the editor shows it: line and column counted from 1, and endLine and endColumn just past its end. Diagnostics are checked against the project's own files, and the two that the files disprove are named rather than passed on: a member the class cache's file declares, or a project class it extends does, a method, property, constant, static function or enum member, comes back under contradictedByTheFile with the script declaring it, and so does one a diagnostic names alone as an external class member, read against the class it is looked up on in the line it is on; and a class this project declares that the diagnostic could not resolve comes back under typesTheEditorHasNotLoaded, with inTheClassCache saying whether a launched game would resolve it. staleAnalysis then says what to do, and for both states it is editor_rescan first: it asks the editor already running, starts nothing, and has cleared each in every reproduction measured. Two exceptions are named when they apply. For an enum member, constant or static function of a global class the reload comes first: in the one project that has reproduced a stale enum member, editor_rescan with reloadScript on the declaring script cleared it and a plain rescan did not. And an editor whose last scan wrote the class cache shorter than the file holds a list behind the files and writes it on every scan, so on that editor the rescan loads nothing and staleAnalysis says editor_launch restart instead. What follows differs: for a stale analysed type, editor_rescan with reloadScript recompiles the held copy and editor_launch restart is the last resort that costs a window; for a class missing from the cache, project_import refresh_classes rewrites the cache from disk at the cost of a short headless engine, which matters beside a running bench.",
|
|
11964
11985
|
parameters: {
|
|
11965
11986
|
projectPath: PROJECT_PATH,
|
|
11966
11987
|
scriptPath: {
|
|
@@ -12418,7 +12439,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
12418
12439
|
says: {
|
|
12419
12440
|
type: "string",
|
|
12420
12441
|
ops: ["find", "accessibility"],
|
|
12421
|
-
description: 'accessibility: only the elements whose name or
|
|
12442
|
+
description: 'accessibility: only the elements whose name, value or value_text says these words, matched as find matches them, with what they hold. find: part of what the node has written on it as drawn, the way the text op reads it, case-insensitively and with a typed space matching any space the game draws (a non-breaking one included), which is how a button is reached by the word on it rather than by a generated path. Its own text, so a row is found by the label in it, and hidden nodes match. A bare word is a contains; write a glob and it is one, matched against the whole of what the node says, the same as namePattern, and a glob that finds nothing says under note how many nodes it would find open at both ends. A label with a line break is matched with the break in the words, and a backslash followed by n counts as one. Alternatives separated by | match when any one of them does, each by these rules ("*won*|*lost*"); write \\| for a bar that is part of the words.'
|
|
12422
12443
|
},
|
|
12423
12444
|
limit: {
|
|
12424
12445
|
type: "integer",
|
|
@@ -12449,7 +12470,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
12449
12470
|
tree: { effect: "read", summary: "the live scene tree", requires: [] },
|
|
12450
12471
|
text: {
|
|
12451
12472
|
effect: "read",
|
|
12452
|
-
summary: "every line of text under nodePath, the values in its fields included, in
|
|
12473
|
+
summary: "every line of text under nodePath, the values in its fields included, in reading order, leaving out what is hidden and everything under it. Every line reads as drawn: rich text without its tags, text only as far as it has been typed out, a translation rather than its key, an upper-case label in capitals and a secret field as its mask. Tab titles, menu bar titles, list items, a tree's column titles and rows, and an open menu's items and the titles of its separators read a line each",
|
|
12453
12474
|
requires: []
|
|
12454
12475
|
},
|
|
12455
12476
|
find: {
|
|
@@ -12469,12 +12490,12 @@ var init_tool_definitions = __esm(() => {
|
|
|
12469
12490
|
},
|
|
12470
12491
|
metrics: {
|
|
12471
12492
|
effect: "read",
|
|
12472
|
-
summary: "frame time, memory, draw calls and the rest. frame_time is the mean wall time of a frame over the last frames_timed frames (up to 120, timed by the game
|
|
12493
|
+
summary: "frame time, memory, draw calls and the rest. frame_time is the mean wall time of a frame over the last frames_timed frames (up to 120, timed by the game, physics and the wait for the display included), frame_time_max the slowest of them, both in seconds and null before a frame has passed; vsync says whether a frame waits for the display, and max_fps is the game's frame-rate cap, 0 for none. physics_steps_per_second is the physics steps taken a second over those frames, fewer than physics_ticks_per_second when a frame needs more than max_physics_steps_per_frame or the editor's Game view slows it. fps, process_time_max and physics_time are the engine's monitors, which it sets once a second: the frames counted in the last second, and the slowest process and physics step in it, so they trail a change by up to a second and the last two are a worst case rather than the frame. Memory, object and render counts are read as asked. memory_static is what the engine allocated on the CPU side, in bytes; render_video_mem_used, render_texture_mem_used and render_buffer_mem_used are what the renderer has on the GPU, in bytes, which memory_static does not count",
|
|
12473
12494
|
requires: []
|
|
12474
12495
|
},
|
|
12475
12496
|
accessibility: {
|
|
12476
12497
|
effect: "read",
|
|
12477
|
-
summary:
|
|
12498
|
+
summary: `what the game tells a screen reader, read through UI Automation as a Windows screen reader does, under windows: one tree per window, each element with its role (text for static text, button, check_box, group for a control holding others), name, value, value_text (a range's spoken words, such as "75%"), description, placeholder, bounds in the window's pixels, the actions a reader is offered (click, focus, toggle, set_value, select, expand_collapse, scroll_into_view), and focused on the focused one. node is the node that made the element; a part a node made of itself has part_of, the node drawn around it that holds its words, or part_of_candidates where several are, and part: announcement marks the text a window announces through. An empty name reads as nothing: static text takes it from accessibility_update_set_value, and _note counts the text elements on screen with none. tooltip is the node's tooltip_text, which a Windows reader is not told. With nothing focused, the engine calls GdharnessRuntime focused. Needs a windowed Windows run started with engineArgs ["--accessibility", "always"] or accessibility_support at Always Active, since the engine builds the tree only when asked; reading takes a second or two`,
|
|
12478
12499
|
requires: []
|
|
12479
12500
|
}
|
|
12480
12501
|
},
|
|
@@ -12483,7 +12504,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
12483
12504
|
{
|
|
12484
12505
|
name: "runtime_invoke",
|
|
12485
12506
|
title: "Set or call in the running game",
|
|
12486
|
-
description: "Sets a property or calls a method on a node, or on one of the engine singletons nodePath names, in the running game. Needs the game running with the runtime addon. The answer carries elapsed_usec, how long the call or the write took inside the game, measured around it there: the round trip to the game is a second or more, so timing from outside measures that instead. Errors
|
|
12507
|
+
description: "Sets a property or calls a method on a node, or on one of the engine singletons nodePath names, in the running game. Needs the game running with the runtime addon. The answer carries elapsed_usec, how long the call or the write took inside the game, measured around it there: the round trip to the game is a second or more, so timing from outside measures that instead. Errors the engine reported while a called method ran come back under errors and warnings under warnings, the first 20 of each, with errors_not_shown and warnings_not_shown counting the rest. A call that takes longer than timeoutMs is not cancelled: the answer is pending: true with a requestId, the call goes on and does everything it was asked, and op result with that requestId collects its reply once it comes.",
|
|
12487
12508
|
parameters: {
|
|
12488
12509
|
projectPath: RUNNING_PROJECT_PATH,
|
|
12489
12510
|
pid: RUNNING_PID,
|
|
@@ -12603,7 +12624,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
12603
12624
|
{
|
|
12604
12625
|
name: "runtime_input",
|
|
12605
12626
|
title: "Send input to the game",
|
|
12606
|
-
description: "Input to the running game: a whole click on a Control or a 3D node named by path or on a control named by the words on it, an item chosen out of a menu, typing into whatever has the focus, or a raw action, key, mouse button, mouse motion or drag. All of it works headless, where the
|
|
12627
|
+
description: "Input to the running game: a whole click on a Control or a 3D node named by path or on a control named by the words on it, an item chosen out of a menu, typing into whatever has the focus, or a raw action, key, mouse button, mouse motion or drag. All of it works headless, where the viewport is the project's window size and the GUI only takes what is inside it. On gdharness's own desktop, where a windowed run goes, Windows refuses to say where the pointer is: every pointer answer there carries pointer_on_hidden_desktop, and the first of the run pointer_note saying why it matters: get_mouse_position() on the root window, and the mouse positions derived from it, read a meaningless position, while what reads the event itself (the control under it, hover, tooltips, input handlers) gets the injected position. A native window no real pointer has entered gets no hover from Godot, so the runtime supplies it there and the answers say hover_supplied.",
|
|
12607
12628
|
answer: 'click: what was under the pointer, and what became of the control: in_tree, removed or freed. Named by says, found says which match it was, and found.pressedOn says "the words" for words in a RichTextLabel pressed where they are drawn, or "the middle of the label" with a note saying why they could not be placed; on a rich label link_pressed says whether the press reached a link, with link_meta giving the meta the label reports clicked, an empty one included. A control scrolled into view first is scrolled each container out from it a frame after the one inside, and scrolled_into_view says whether a scroll value changed. A button in toggle mode, a CheckBox or CheckButton included, answers pressed with before and after, its button_pressed either side of the click: the same value twice is a click the game undid, and after is null when the click freed it. A refusal for a pointer turned off names where mouse_behavior_recursive was set. On a 3D node landed says the interface did not swallow the press: no control under the pointer stopped it, a control letting the pointer pass included, and every viewport on the way out from the room had the pointer over what shows the room. choose: what was chosen, read before the press, which is heard rather than assumed; what became of the control named (in_tree, removed or freed, since a game can rebuild its screen on the pick); and what the button in front of the menu shows now when it is still there. A menu is opened rather than clicked because its items are drawn rather than built, and the item is looked for as the menu stands once open, since a game can fill a menu as it opens. action, key, mouse_click and joypad_button: the event as it was sent, with whole saying whether the press was let go of again, for a key the keycode, physical_keycode and unicode it carried, and for a controller button its number, its name and the device. mouse_motion: the position and the relative movement sent. mouse_drag: from, to, motions sent and relative_total. joypad_motion: the axis by number and name, the value and the device. None of these is aimed at anything, so none says what the event reached: click on a nodePath or says answers what was under the pointer.',
|
|
12608
12629
|
parameters: {
|
|
12609
12630
|
projectPath: RUNNING_PROJECT_PATH,
|
|
@@ -12800,10 +12821,16 @@ var init_tool_definitions = __esm(() => {
|
|
|
12800
12821
|
},
|
|
12801
12822
|
nodePath: {
|
|
12802
12823
|
type: "string",
|
|
12803
|
-
ops: ["signal", "until"],
|
|
12804
|
-
description: "signal, until: the node. Needed for a signal
|
|
12824
|
+
ops: ["signal", "watch", "until"],
|
|
12825
|
+
description: "signal, watch, until: the node. Needed for a signal without a watch, a watch and a property; for says it defaults to /root, the whole screen."
|
|
12826
|
+
},
|
|
12827
|
+
signal: { type: "string", ops: ["signal", "watch"], description: "signal, watch: the signal name." },
|
|
12828
|
+
watch: {
|
|
12829
|
+
type: "integer",
|
|
12830
|
+
minimum: 1,
|
|
12831
|
+
ops: ["signal"],
|
|
12832
|
+
description: "signal: the watch an earlier watch answered, in place of nodePath and signal. Answers at once, with fired_before_wait, when the signal fired after the watch was armed, and otherwise waits for it; times counts how often it fired, and args is what the first carried. The watch goes with the answer."
|
|
12805
12833
|
},
|
|
12806
|
-
signal: { type: "string", ops: ["signal"], description: "signal: the signal name." },
|
|
12807
12834
|
property: {
|
|
12808
12835
|
type: "string",
|
|
12809
12836
|
ops: ["until"],
|
|
@@ -12843,6 +12870,11 @@ var init_tool_definitions = __esm(() => {
|
|
|
12843
12870
|
signal: {
|
|
12844
12871
|
effect: "read",
|
|
12845
12872
|
summary: "wait for a signal and answer with what it carried",
|
|
12873
|
+
requires: []
|
|
12874
|
+
},
|
|
12875
|
+
watch: {
|
|
12876
|
+
effect: "read",
|
|
12877
|
+
summary: "start recording a signal and answer at once with a watch; arm it before the call meant to set the signal off, then collect it with signal and the watch. A client can run a call sent beside a wait only after the wait answers, so a wait sent with the call misses it",
|
|
12846
12878
|
requires: ["nodePath", "signal"]
|
|
12847
12879
|
},
|
|
12848
12880
|
until: {
|
|
@@ -12946,7 +12978,7 @@ var init_headless_operations = __esm(() => {
|
|
|
12946
12978
|
uid: "get_uid",
|
|
12947
12979
|
refresh_classes: "refresh_class_cache"
|
|
12948
12980
|
}),
|
|
12949
|
-
project_export: dictionary({ list: "list_export_presets" }),
|
|
12981
|
+
project_export: dictionary({ list: "list_export_presets", add_preset: "add_export_preset" }),
|
|
12950
12982
|
script_edit: dictionary({ create: "create_script", modify: "modify_script" }),
|
|
12951
12983
|
script_info: dictionary({ structure: "get_script_info" }),
|
|
12952
12984
|
editor_classes: dictionary({
|
|
@@ -44574,6 +44606,12 @@ function endedWithoutACode(run) {
|
|
|
44574
44606
|
}
|
|
44575
44607
|
return `The editor stopped playing this run. ${kept} What it printed is below.`;
|
|
44576
44608
|
}
|
|
44609
|
+
function ourRunEnded(run, now) {
|
|
44610
|
+
const which = `${run.throughEditor ? "played in the editor" : "started"}${run.pid === null ? "" : ` (pid ${run.pid})`}`;
|
|
44611
|
+
const when = run.endedAt === undefined ? "" : ` ${Math.max(0, Math.round((now - run.endedAt) / 1000))}s ago`;
|
|
44612
|
+
const how = run.endedThrough === "close" ? "this server asked it to close" : run.endedThrough === "keeper" ? "this server ended it through the keeper holding it" : run.endedThrough === "signal" ? "this server signalled it" : run.endedThrough === "editor" ? "this server asked the editor to stop it" : run.exitCode !== null ? `it exited by itself with code ${run.exitCode}` : run.exitSignal === null ? "it is no longer running" : `it was ended by ${run.exitSignal}`;
|
|
44613
|
+
return `No game with the runtime addon is running: the game this server ${which} ended${when}, and ${how}. editor_output has what it printed, and editor_run start runs it again.`;
|
|
44614
|
+
}
|
|
44577
44615
|
function stopVerdict(stop) {
|
|
44578
44616
|
const notClosed = stop.notClosedBecause === undefined ? "" : ` It was asked to close first and was not ended by that: ${stop.notClosedBecause}.`;
|
|
44579
44617
|
if (!stop.wasRunning) {
|
|
@@ -44892,7 +44930,7 @@ function exportPresetRefusal(projectPath, preset) {
|
|
|
44892
44930
|
try {
|
|
44893
44931
|
text = readFileSync26(join30(projectPath, "export_presets.cfg"), "utf8");
|
|
44894
44932
|
} catch {
|
|
44895
|
-
return `This project has no export_presets.cfg, so it has no preset '${preset}' to export with.
|
|
44933
|
+
return `This project has no export_presets.cfg, so it has no preset '${preset}' to export with. project_export add_preset writes one, as the editor's Project > Export does.`;
|
|
44896
44934
|
}
|
|
44897
44935
|
const names = [];
|
|
44898
44936
|
let inPreset = false;
|
|
@@ -44910,9 +44948,9 @@ function exportPresetRefusal(projectPath, preset) {
|
|
|
44910
44948
|
if (names.includes(preset)) {
|
|
44911
44949
|
return null;
|
|
44912
44950
|
}
|
|
44913
|
-
return names.length === 0 ? `export_presets.cfg names no preset, so there is no '${preset}' to export with.
|
|
44951
|
+
return names.length === 0 ? `export_presets.cfg names no preset, so there is no '${preset}' to export with. project_export add_preset adds one.` : `This project has no export preset named '${preset}'. Its presets are ${names.map((name) => `'${name}'`).join(", ")}.`;
|
|
44914
44952
|
}
|
|
44915
|
-
function exportAnswer(ending, asked, before, after) {
|
|
44953
|
+
function exportAnswer(ending, asked, before, after, beside = []) {
|
|
44916
44954
|
const { log } = ending;
|
|
44917
44955
|
const written = after !== null && after !== before;
|
|
44918
44956
|
const notCopied = librariesNotCopied(log.all);
|
|
@@ -44924,6 +44962,7 @@ function exportAnswer(ending, asked, before, after) {
|
|
|
44924
44962
|
failure: ending.failure ?? undefined,
|
|
44925
44963
|
errors: log.count("error"),
|
|
44926
44964
|
warnings: log.count("warning"),
|
|
44965
|
+
...beside.length === 0 ? {} : { alsoWritten: beside },
|
|
44927
44966
|
...notCopied.length === 0 ? {} : {
|
|
44928
44967
|
librariesNotLoaded: notCopied,
|
|
44929
44968
|
extensionNote: `The export could not load ${notCopied.join(" and ")}: on Windows an engine running as the editor, which an export is, loads a GDExtension from a ~ copy beside the library, and another engine on this project held that copy: it could not be moved aside before the export, or another engine made a new one in between. Export again once that engine has loaded or exited.`
|
|
@@ -44946,6 +44985,20 @@ function exportAnswer(ending, asked, before, after) {
|
|
|
44946
44985
|
isError: true
|
|
44947
44986
|
};
|
|
44948
44987
|
}
|
|
44988
|
+
function writtenBeside(before, after, output, within) {
|
|
44989
|
+
return [...after].filter(([name, at]) => name !== output && before.get(name) !== at).map(([name]) => within === "." ? name : `${within}/${name}`).sort();
|
|
44990
|
+
}
|
|
44991
|
+
function filesIn(folder) {
|
|
44992
|
+
const found = new Map;
|
|
44993
|
+
try {
|
|
44994
|
+
for (const entry of readdirSync13(folder, { withFileTypes: true })) {
|
|
44995
|
+
if (entry.isFile()) {
|
|
44996
|
+
found.set(entry.name, statSync13(join30(folder, entry.name)).mtimeMs);
|
|
44997
|
+
}
|
|
44998
|
+
}
|
|
44999
|
+
} catch {}
|
|
45000
|
+
return found;
|
|
45001
|
+
}
|
|
44949
45002
|
function scanWaitAnswer(scanned, started = "game") {
|
|
44950
45003
|
if (scanned.waitedMs === 0) {
|
|
44951
45004
|
return {};
|
|
@@ -45485,6 +45538,13 @@ function scriptsToDiagnose(projectPath, given) {
|
|
|
45485
45538
|
}
|
|
45486
45539
|
return { ok: true, value: unique };
|
|
45487
45540
|
}
|
|
45541
|
+
function engineChecked(why) {
|
|
45542
|
+
return {
|
|
45543
|
+
checkedBy: "engine",
|
|
45544
|
+
languageServer: why,
|
|
45545
|
+
note: "No editor of this project is open to ask, so a headless engine compiled the scripts the way loading them does. It reports every error that stops a script compiling, at its line and without a column, and no warnings, which the engine tells only an editor: warnings is null rather than 0. editor_launch with hidden: true opens this project's editor without a window, and its language server reports both."
|
|
45546
|
+
};
|
|
45547
|
+
}
|
|
45488
45548
|
function isDirectory(path) {
|
|
45489
45549
|
try {
|
|
45490
45550
|
return statSync13(path).isDirectory();
|
|
@@ -46180,6 +46240,9 @@ class GodotServer {
|
|
|
46180
46240
|
if (tool === "project_import" && op === "set_options") {
|
|
46181
46241
|
return await this.handleSetImportOptions(args);
|
|
46182
46242
|
}
|
|
46243
|
+
if (tool === "project_export" && op === "add_preset") {
|
|
46244
|
+
return await this.handleAddExportPreset(args);
|
|
46245
|
+
}
|
|
46183
46246
|
const headless = HEADLESS_OPERATIONS[tool]?.[op];
|
|
46184
46247
|
if (headless !== undefined) {
|
|
46185
46248
|
const { from: asked, ...answerable } = args;
|
|
@@ -47243,6 +47306,30 @@ class GodotServer {
|
|
|
47243
47306
|
return this.createErrorResponse(`Search failed: ${errorMessage(error)}`);
|
|
47244
47307
|
}
|
|
47245
47308
|
}
|
|
47309
|
+
async handleAddExportPreset(args) {
|
|
47310
|
+
const project = this.project(args);
|
|
47311
|
+
if (!project.ok) {
|
|
47312
|
+
return project.response;
|
|
47313
|
+
}
|
|
47314
|
+
const given = readNonEmptyString(args, "outputPath");
|
|
47315
|
+
const output = given === undefined ? null : resolveWithinProject(project.value.path, given);
|
|
47316
|
+
if (output !== null && !output.ok) {
|
|
47317
|
+
return this.createErrorResponse(output.reason, OUTPUT_PATH_SOLUTIONS);
|
|
47318
|
+
}
|
|
47319
|
+
const outcome = await this.operation("add_export_preset", {
|
|
47320
|
+
preset: readString(args, "preset") ?? "",
|
|
47321
|
+
platform: readString(args, "platform") ?? "",
|
|
47322
|
+
outputPath: output?.relativePath ?? ""
|
|
47323
|
+
}, project.value.path);
|
|
47324
|
+
if (!outcome.ok || !this.editorHasOpen(project.value.path)) {
|
|
47325
|
+
return this.answer(outcome);
|
|
47326
|
+
}
|
|
47327
|
+
return this.jsonTextResponse({
|
|
47328
|
+
...outcome.payload,
|
|
47329
|
+
editorNote: "The editor open on this project read export_presets.cfg when it started and does not list this preset, and saving presets in its Export dialog writes its own list over the file. editor_launch restart loads the file; an export through project_export run reads the file and needs no restart.",
|
|
47330
|
+
...engineExtras(outcome)
|
|
47331
|
+
});
|
|
47332
|
+
}
|
|
47246
47333
|
async handleExportProject(args) {
|
|
47247
47334
|
const project = this.project(args);
|
|
47248
47335
|
if (!project.ok) {
|
|
@@ -47251,11 +47338,14 @@ class GodotServer {
|
|
|
47251
47338
|
const preset = readNonEmptyString(args, "preset") ?? "";
|
|
47252
47339
|
const output = resolveWithinProject(project.value.path, readString(args, "outputPath") ?? "");
|
|
47253
47340
|
if (!output.ok) {
|
|
47254
|
-
return this.createErrorResponse(output.reason,
|
|
47341
|
+
return this.createErrorResponse(output.reason, OUTPUT_PATH_SOLUTIONS);
|
|
47255
47342
|
}
|
|
47256
47343
|
const noPreset = exportPresetRefusal(project.value.path, preset);
|
|
47257
47344
|
if (noPreset !== null) {
|
|
47258
|
-
return this.createErrorResponse(noPreset, [
|
|
47345
|
+
return this.createErrorResponse(noPreset, [
|
|
47346
|
+
"project_export list reads the presets the project has",
|
|
47347
|
+
"project_export add_preset adds one"
|
|
47348
|
+
]);
|
|
47259
47349
|
}
|
|
47260
47350
|
const engine = await this.engine();
|
|
47261
47351
|
if (!engine.ok) {
|
|
@@ -47282,6 +47372,7 @@ class GodotServer {
|
|
|
47282
47372
|
this.logDebug(`Exporting: ${engine.value} ${exportArgs.join(" ")}`);
|
|
47283
47373
|
const writtenAt = () => existsSync23(output.absolutePath) ? statSync13(output.absolutePath).mtimeMs : null;
|
|
47284
47374
|
const before = writtenAt();
|
|
47375
|
+
const listedBefore = filesIn(folder);
|
|
47285
47376
|
const freed = freeLibraryCopies(project.value.path);
|
|
47286
47377
|
if (freed.setAside.length > 0 || freed.swept.length > 0) {
|
|
47287
47378
|
this.logDebug(`Before the export: set aside ${freed.setAside.join(", ")}; swept ${freed.swept.join(", ")}`);
|
|
@@ -47295,7 +47386,8 @@ class GodotServer {
|
|
|
47295
47386
|
if (ending.exitSignal === null && ending.exitCode === null) {
|
|
47296
47387
|
return this.createErrorResponse(`Export could not be run: ${ending.failure ?? "the engine gave no exit status"}`);
|
|
47297
47388
|
}
|
|
47298
|
-
|
|
47389
|
+
const beside = writtenBeside(listedBefore, filesIn(folder), basename9(output.absolutePath), dirname22(output.relativePath).replaceAll("\\", "/"));
|
|
47390
|
+
return exportAnswer(ending, { preset, outputPath: output.relativePath, debug }, before, writtenAt(), beside);
|
|
47299
47391
|
}
|
|
47300
47392
|
reportTestProgress(log) {
|
|
47301
47393
|
const progress = callProgress();
|
|
@@ -47641,6 +47733,10 @@ class GodotServer {
|
|
|
47641
47733
|
}
|
|
47642
47734
|
if (scripts?.value == null) {
|
|
47643
47735
|
const one = await this.diagnosticsOf(args);
|
|
47736
|
+
if ("noLanguageServer" in one) {
|
|
47737
|
+
const checked = project.ok ? await this.engineDiagnostics(project.value.path, [readString(args, "scriptPath") ?? ""], one.noLanguageServer) : { refusal: project.response };
|
|
47738
|
+
return "refusal" in checked ? checked.refusal : this.jsonTextResponse({ ...checked.answers[0], ...engineChecked(one.noLanguageServer.reason) });
|
|
47739
|
+
}
|
|
47644
47740
|
return "refusal" in one ? one.refusal : this.jsonTextResponse(this.markedIfStale(one.answer));
|
|
47645
47741
|
}
|
|
47646
47742
|
const progress = callProgress();
|
|
@@ -47650,12 +47746,31 @@ class GodotServer {
|
|
|
47650
47746
|
let errors = 0;
|
|
47651
47747
|
let warnings = 0;
|
|
47652
47748
|
let unread = 0;
|
|
47749
|
+
let byEngine = null;
|
|
47653
47750
|
for (const [at, scriptPath] of scripts.value.entries()) {
|
|
47654
47751
|
if (cancelled?.aborted === true) {
|
|
47655
47752
|
return this.createErrorResponse(`Cancelled after ${at} of ${scripts.value.length} scripts.`);
|
|
47656
47753
|
}
|
|
47657
47754
|
progress?.(at + 1, `${at + 1} of ${scripts.value.length}: ${scriptPath}`);
|
|
47658
47755
|
const one = await this.diagnosticsOf({ ...args, scriptPath });
|
|
47756
|
+
if ("noLanguageServer" in one) {
|
|
47757
|
+
const rest = scripts.value.slice(at);
|
|
47758
|
+
progress?.(at + 1, `${rest.length} script(s) left, compiled by a headless engine`);
|
|
47759
|
+
const checked = await this.engineDiagnostics(project.ok ? project.value.path : "", rest, one.noLanguageServer);
|
|
47760
|
+
if ("refusal" in checked) {
|
|
47761
|
+
return checked.refusal;
|
|
47762
|
+
}
|
|
47763
|
+
for (const answer of checked.answers) {
|
|
47764
|
+
errors += Number(answer["errors"]);
|
|
47765
|
+
if (readArray(answer, "diagnostics")?.length === 0) {
|
|
47766
|
+
nothingReported.push(String(answer["scriptPath"]));
|
|
47767
|
+
} else {
|
|
47768
|
+
reported.push(answer);
|
|
47769
|
+
}
|
|
47770
|
+
}
|
|
47771
|
+
byEngine = one.noLanguageServer.reason;
|
|
47772
|
+
break;
|
|
47773
|
+
}
|
|
47659
47774
|
if ("refusal" in one) {
|
|
47660
47775
|
if (!one.perScript) {
|
|
47661
47776
|
return one.refusal;
|
|
@@ -47676,12 +47791,68 @@ class GodotServer {
|
|
|
47676
47791
|
clean: errors === 0 && unread === 0,
|
|
47677
47792
|
scriptsChecked: scripts.value.length,
|
|
47678
47793
|
errors,
|
|
47679
|
-
warnings,
|
|
47794
|
+
warnings: byEngine === null ? warnings : null,
|
|
47680
47795
|
...unread > 0 ? { scriptsNotRead: unread } : {},
|
|
47681
47796
|
scripts: reported,
|
|
47682
|
-
nothingReported
|
|
47797
|
+
nothingReported,
|
|
47798
|
+
...byEngine === null ? {} : engineChecked(byEngine)
|
|
47683
47799
|
}));
|
|
47684
47800
|
}
|
|
47801
|
+
async compileScripts(projectPath, paths) {
|
|
47802
|
+
const payload = { checked: [], failed: [], scripts: [] };
|
|
47803
|
+
const messages = [];
|
|
47804
|
+
let left = [...paths];
|
|
47805
|
+
while (left.length > 0) {
|
|
47806
|
+
const ran = await this.operation("check_scripts", { paths: left }, projectPath);
|
|
47807
|
+
if (!ran.ok) {
|
|
47808
|
+
return { ok: false, message: ran.message };
|
|
47809
|
+
}
|
|
47810
|
+
const checked = (readArray(ran.payload, "checked") ?? []).map(String);
|
|
47811
|
+
if (checked.length === 0) {
|
|
47812
|
+
return { ok: false, message: `check_scripts read none of ${left.length} script(s)` };
|
|
47813
|
+
}
|
|
47814
|
+
payload.checked.push(...checked);
|
|
47815
|
+
payload.failed.push(...(readArray(ran.payload, "failed") ?? []).map(String));
|
|
47816
|
+
payload.scripts.push(...readArray(ran.payload, "scripts") ?? []);
|
|
47817
|
+
messages.push(...ran.messages);
|
|
47818
|
+
left = left.slice(checked.length);
|
|
47819
|
+
}
|
|
47820
|
+
return { ok: true, payload, extras: engineExtras({ messages }) };
|
|
47821
|
+
}
|
|
47822
|
+
async engineDiagnostics(projectPath, scripts, why) {
|
|
47823
|
+
const named = scripts.map((script) => {
|
|
47824
|
+
const contained = resolveWithinProject(projectPath, script);
|
|
47825
|
+
return contained.ok ? `res://${contained.relativePath}` : script;
|
|
47826
|
+
});
|
|
47827
|
+
const checked = await this.compileScripts(projectPath, named);
|
|
47828
|
+
if (!checked.ok) {
|
|
47829
|
+
return {
|
|
47830
|
+
refusal: this.createErrorResponse(`Diagnostics unavailable: ${why.reason.replace(/\.?$/, ".")} No headless engine could compile the scripts instead: ${checked.message}`, why.solutions)
|
|
47831
|
+
};
|
|
47832
|
+
}
|
|
47833
|
+
const failures = new Map((readArray(checked.payload, "scripts") ?? []).map((entry) => [
|
|
47834
|
+
String(asParams(entry)["path"]),
|
|
47835
|
+
asParams(entry)
|
|
47836
|
+
]));
|
|
47837
|
+
return {
|
|
47838
|
+
answers: scripts.map((scriptPath, at) => {
|
|
47839
|
+
const failure = failures.get(named[at] ?? "");
|
|
47840
|
+
const diagnostics = (readArray(failure ?? {}, "errors") ?? []).map((entry) => {
|
|
47841
|
+
const { line, message } = asParams(entry);
|
|
47842
|
+
return { severity: "error", message, ...typeof line === "number" && line > 0 ? { line } : {} };
|
|
47843
|
+
});
|
|
47844
|
+
const dependencies = readArray(failure ?? {}, "dependencies_with_errors");
|
|
47845
|
+
return {
|
|
47846
|
+
scriptPath,
|
|
47847
|
+
clean: diagnostics.length === 0,
|
|
47848
|
+
errors: diagnostics.length,
|
|
47849
|
+
warnings: null,
|
|
47850
|
+
diagnostics,
|
|
47851
|
+
...dependencies === undefined ? {} : { dependenciesWithErrors: dependencies }
|
|
47852
|
+
};
|
|
47853
|
+
})
|
|
47854
|
+
};
|
|
47855
|
+
}
|
|
47685
47856
|
markedIfStale(answer) {
|
|
47686
47857
|
return markIfStale(answer, this.godotBridge.getStatus().addonVersion, SERVER_VERSION, this.godotBridge.getStatus().addonDigest, shippedEditorDigest(), this.editorCodeOnDisk());
|
|
47687
47858
|
}
|
|
@@ -47693,6 +47864,16 @@ class GodotServer {
|
|
|
47693
47864
|
const answer = await this.handleLSP("lsp_get_diagnostics", args);
|
|
47694
47865
|
const payload = asParams(JSON.parse(answer.content[0]?.text ?? "{}"));
|
|
47695
47866
|
const refused = this.languageServerRefusal(payload, "Diagnostics");
|
|
47867
|
+
const project = this.project(args);
|
|
47868
|
+
const ownEditor = project.ok && this.editorHasOpen(project.value.path);
|
|
47869
|
+
if (refused !== null && !refused.perScript && payload["stillReading"] !== true && !ownEditor) {
|
|
47870
|
+
return {
|
|
47871
|
+
noLanguageServer: {
|
|
47872
|
+
reason: typeof payload["error"] === "string" ? payload["error"] : JSON.stringify(payload["error"]),
|
|
47873
|
+
solutions: this.languageServerSolutions(payload)
|
|
47874
|
+
}
|
|
47875
|
+
};
|
|
47876
|
+
}
|
|
47696
47877
|
if (refused !== null) {
|
|
47697
47878
|
return refused;
|
|
47698
47879
|
}
|
|
@@ -47852,24 +48033,24 @@ class GodotServer {
|
|
|
47852
48033
|
if (payload["stillReading"] === true) {
|
|
47853
48034
|
return { refusal: this.createErrorResponse(`${asked} unavailable: ${reason}`), perScript: false };
|
|
47854
48035
|
}
|
|
47855
|
-
if (typeof payload["serves"] === "string") {
|
|
47856
|
-
return {
|
|
47857
|
-
refusal: this.createErrorResponse(`${asked} unavailable: ${reason}`, [
|
|
47858
|
-
"editor_status names the editor on the bridge and the port it says it serves",
|
|
47859
|
-
"editor_launch opens this project's own editor, on a language server port of its own",
|
|
47860
|
-
"GDHARNESS_LSP_PORT points this server at the right one"
|
|
47861
|
-
]),
|
|
47862
|
-
perScript: false
|
|
47863
|
-
};
|
|
47864
|
-
}
|
|
47865
48036
|
return {
|
|
47866
|
-
refusal: this.createErrorResponse(`${asked} unavailable: ${reason}`,
|
|
47867
|
-
|
|
47868
|
-
"GDHARNESS_LSP_PORT points this server at another one"
|
|
47869
|
-
]),
|
|
47870
|
-
perScript: payload["aboutThisFile"] === true
|
|
48037
|
+
refusal: this.createErrorResponse(`${asked} unavailable: ${reason}`, this.languageServerSolutions(payload)),
|
|
48038
|
+
perScript: typeof payload["serves"] !== "string" && payload["aboutThisFile"] === true
|
|
47871
48039
|
};
|
|
47872
48040
|
}
|
|
48041
|
+
languageServerSolutions(payload) {
|
|
48042
|
+
if (typeof payload["serves"] === "string") {
|
|
48043
|
+
return [
|
|
48044
|
+
...this.godotBridge.getStatus().connected ? ["editor_status names the editor on the bridge and the port it says it serves"] : [],
|
|
48045
|
+
"editor_launch opens this project's own editor, on a language server port of its own",
|
|
48046
|
+
"GDHARNESS_LSP_PORT points this server at the right one"
|
|
48047
|
+
];
|
|
48048
|
+
}
|
|
48049
|
+
return [
|
|
48050
|
+
`Ensure the Godot editor is running with its language server enabled, on port ${this.editorServes("lspPort", "GDHARNESS_LSP_PORT", DEFAULT_LSP_PORT)}`,
|
|
48051
|
+
"GDHARNESS_LSP_PORT points this server at another one"
|
|
48052
|
+
];
|
|
48053
|
+
}
|
|
47873
48054
|
async lsp() {
|
|
47874
48055
|
const port = this.editorServes("lspPort", "GDHARNESS_LSP_PORT", DEFAULT_LSP_PORT);
|
|
47875
48056
|
if (this.lspClient !== null && this.lspClient.port !== port) {
|
|
@@ -50923,9 +51104,9 @@ class GodotServer {
|
|
|
50923
51104
|
ok &&= rebuilt.ok;
|
|
50924
51105
|
}
|
|
50925
51106
|
if (changed.length > 0) {
|
|
50926
|
-
const compiled = await this.
|
|
50927
|
-
report["compiled"] = compiled.ok ? { ...compiled.payload, ...
|
|
50928
|
-
ok &&= compiled.ok &&
|
|
51107
|
+
const compiled = await this.compileScripts(projectPath, [...changed]);
|
|
51108
|
+
report["compiled"] = compiled.ok ? { ...compiled.payload, ...compiled.extras } : { problem: compiled.message };
|
|
51109
|
+
ok &&= compiled.ok && compiled.payload.failed.length === 0;
|
|
50929
51110
|
}
|
|
50930
51111
|
return { ok, report };
|
|
50931
51112
|
}
|
|
@@ -51191,6 +51372,11 @@ class GodotServer {
|
|
|
51191
51372
|
const own = typeof pid === "number" ? undefined : await this.ownGameAmong(announced.running, wanted) ?? await this.ownGameThroughTheTree(announced.running, wanted);
|
|
51192
51373
|
const choice = chooseRuntime(announced.running, wanted, announced.unspoken, typeof pid === "number" ? pid : own);
|
|
51193
51374
|
if ("problem" in choice) {
|
|
51375
|
+
const ended = this.activeProcess;
|
|
51376
|
+
const nothingAnnounced = typeof pid !== "number" && announced.unspoken.length === 0 && !announced.running.some((one) => wanted === undefined || isSameDirectory(one.project.path, wanted));
|
|
51377
|
+
if (nothingAnnounced && ended !== null && !stillRunning(ended) && (wanted === undefined || ended.projectPath === null || isSameDirectory(ended.projectPath, wanted))) {
|
|
51378
|
+
return this.createErrorResponse(ourRunEnded({ ...ended, pid: ended.pid ?? ended.announcedPid ?? null }, Date.now()));
|
|
51379
|
+
}
|
|
51194
51380
|
return this.createErrorResponse(choice.problem);
|
|
51195
51381
|
}
|
|
51196
51382
|
const ofProject = announced.running.filter((one) => wanted === undefined || isSameDirectory(one.project.path, wanted));
|
|
@@ -51356,7 +51542,18 @@ ${staleNote}`}`
|
|
|
51356
51542
|
const waited = patienceForFrames(frames, this.runtimeTimeoutMs());
|
|
51357
51543
|
return await this.handleRuntimeCommand("wait_frames", { ...whichGame(args), frames }, { tool: "runtime_wait", op, patience: waited });
|
|
51358
51544
|
}
|
|
51545
|
+
if (op === "watch") {
|
|
51546
|
+
return await this.handleRuntimeCommand("watch_signal", {
|
|
51547
|
+
...whichGame(args),
|
|
51548
|
+
path: readNonEmptyString(args, "nodePath") ?? "",
|
|
51549
|
+
signal: readString(args, "signal") ?? ""
|
|
51550
|
+
}, { tool: "runtime_wait", op });
|
|
51551
|
+
}
|
|
51359
51552
|
const timeoutMs = readPositiveNumber(args, "timeoutMs") ?? 5000;
|
|
51553
|
+
const watch = readPositiveNumber(args, "watch");
|
|
51554
|
+
if (op === "signal" && watch === undefined && (readNonEmptyString(args, "nodePath") === undefined || readNonEmptyString(args, "signal") === undefined)) {
|
|
51555
|
+
return this.createErrorResponse("runtime_wait signal needs nodePath and signal, or the watch an earlier runtime_wait watch answered.");
|
|
51556
|
+
}
|
|
51360
51557
|
const asked = readNonEmptyString(args, "nodePath");
|
|
51361
51558
|
if (asked === undefined && op === "until" && readNonEmptyString(args, "says") === undefined) {
|
|
51362
51559
|
return this.createErrorResponse("runtime_wait until needs nodePath to wait for a property: the property belongs to that node.", ["With says instead of property, nodePath can be left out and the whole game is searched"]);
|
|
@@ -51367,7 +51564,8 @@ ${staleNote}`}`
|
|
|
51367
51564
|
...whichGame(args),
|
|
51368
51565
|
path: nodePath,
|
|
51369
51566
|
signal: readString(args, "signal") ?? "",
|
|
51370
|
-
timeout_ms: timeoutMs
|
|
51567
|
+
timeout_ms: timeoutMs,
|
|
51568
|
+
...watch === undefined ? {} : { watch }
|
|
51371
51569
|
}, { tool: "runtime_wait", op, patience }) : await this.handleRuntimeCommand("wait_until", {
|
|
51372
51570
|
...whichGame(args),
|
|
51373
51571
|
path: nodePath,
|
|
@@ -51385,7 +51583,7 @@ async function runGodotServer() {
|
|
|
51385
51583
|
const server = new GodotServer;
|
|
51386
51584
|
await server.run();
|
|
51387
51585
|
}
|
|
51388
|
-
var UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, CLOSE_ASK_MS = 3000, CONSOLE_WRAPPER, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_START_MS = 2000, SCAN_SETTLED_MS = 500, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
|
|
51586
|
+
var UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, CLOSE_ASK_MS = 3000, CONSOLE_WRAPPER, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_START_MS = 2000, SCAN_SETTLED_MS = 500, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, PATH_SOLUTIONS, OUTPUT_PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
|
|
51389
51587
|
var init_server = __esm(() => {
|
|
51390
51588
|
init_dist();
|
|
51391
51589
|
init_stdio();
|
|
@@ -51467,6 +51665,9 @@ var init_server = __esm(() => {
|
|
|
51467
51665
|
'Give the path relative to the project, such as "scenes/main.tscn" or "res://scenes/main.tscn"',
|
|
51468
51666
|
"Point projectPath at the project the file belongs to"
|
|
51469
51667
|
];
|
|
51668
|
+
OUTPUT_PATH_SOLUTIONS = [
|
|
51669
|
+
'Give outputPath inside the project, relative to it, such as "build/game.exe" or "res://build/game.exe"; copy the build elsewhere once it is exported'
|
|
51670
|
+
];
|
|
51470
51671
|
PROJECT_FILE_ARGUMENTS = [
|
|
51471
51672
|
"scenePath",
|
|
51472
51673
|
"instancePath",
|
|
@@ -52600,7 +52801,9 @@ so take it off when the question it was for is answered.
|
|
|
52600
52801
|
\`resource_edit read\` for a resource: both read the file through the editor when one serves the
|
|
52601
52802
|
project and through a headless engine when none does, with the same answer. \`scene_node\`,
|
|
52602
52803
|
\`scene_signal\` and the other \`resource_edit\` ops but \`move\` change it through the editor, so the
|
|
52603
|
-
files keep their formatting. \`
|
|
52804
|
+
files keep their formatting. \`script_info\` comes from the editor's own language server, and so does
|
|
52805
|
+
\`script_diagnostics\` when this project's editor is open; without it a headless engine compiles the
|
|
52806
|
+
scripts and reports their errors, with lines but no columns and no warnings.
|
|
52604
52807
|
|
|
52605
52808
|
\`project_info\`, \`project_dependencies\`, \`project_settings\`, \`project_import\`,
|
|
52606
52809
|
\`project_export\`, \`project_test\`, \`script_edit\`, \`script_info structure\` and
|