gdharness 1.3.2 → 1.3.4

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.
Files changed (46) hide show
  1. package/build/cli.js +163 -85
  2. package/build/godot/addons/gdharness_editor/animation_reads.gd +14 -11
  3. package/build/godot/addons/gdharness_editor/declared_values.gd +157 -4
  4. package/build/godot/addons/gdharness_editor/file_reads.gd +15 -3
  5. package/build/godot/addons/gdharness_editor/file_walk.gd +134 -0
  6. package/build/godot/addons/gdharness_editor/file_walk.gd.uid +1 -0
  7. package/build/godot/addons/gdharness_editor/headless_check.gd +44 -23
  8. package/build/godot/addons/gdharness_editor/property_paths.gd +225 -0
  9. package/build/godot/addons/gdharness_editor/property_paths.gd.uid +1 -0
  10. package/build/godot/addons/gdharness_editor/property_values.gd +249 -227
  11. package/build/godot/addons/gdharness_editor/reading.gd +15 -0
  12. package/build/godot/addons/gdharness_editor/same_values.gd +177 -0
  13. package/build/godot/addons/gdharness_editor/same_values.gd.uid +1 -0
  14. package/build/godot/addons/gdharness_editor/scene_file.gd +100 -15
  15. package/build/godot/addons/gdharness_editor/serialisation.gd +75 -3
  16. package/build/godot/addons/gdharness_editor/tool_executor.gd +12 -3
  17. package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +402 -55
  18. package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +3 -2
  19. package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +91 -0
  20. package/build/godot/addons/gdharness_editor/tools/scene_groups.gd.uid +1 -0
  21. package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +88 -5
  22. package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +102 -337
  23. package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +363 -0
  24. package/build/godot/addons/gdharness_editor/tools/signal_tools.gd.uid +1 -0
  25. package/build/godot/addons/gdharness_runtime/reading.gd +15 -0
  26. package/build/godot/addons/gdharness_runtime/runtime_input.gd +10 -26
  27. package/build/godot/addons/gdharness_runtime/runtime_pad.gd +3 -2
  28. package/build/godot/addons/gdharness_runtime/runtime_paths.gd +2 -1
  29. package/build/godot/addons/gdharness_runtime/runtime_values.gd +30 -0
  30. package/build/godot/addons/gdharness_runtime/serialisation.gd +75 -3
  31. package/build/godot/operations/animation_reads.gd +14 -11
  32. package/build/godot/operations/declared_values.gd +157 -4
  33. package/build/godot/operations/dependencies.gd +14 -39
  34. package/build/godot/operations/editor_tools.gd +7 -3
  35. package/build/godot/operations/file_reads.gd +15 -3
  36. package/build/godot/operations/file_walk.gd +1 -0
  37. package/build/godot/operations/gdscript_analysis.gd +229 -75
  38. package/build/godot/operations/gdscript_authoring.gd +142 -34
  39. package/build/godot/operations/import_pipeline.gd +17 -6
  40. package/build/godot/operations/logger.gd +7 -0
  41. package/build/godot/operations/property_paths.gd +225 -0
  42. package/build/godot/operations/property_values.gd +249 -227
  43. package/build/godot/operations/reading.gd +15 -0
  44. package/build/godot/operations/same_values.gd +177 -0
  45. package/build/godot/operations/serialisation.gd +75 -3
  46. package/package.json +1 -1
package/build/cli.js CHANGED
@@ -9222,6 +9222,19 @@ function withNotCompiled(note, entries) {
9222
9222
  const path = entries.map(notCompiledIn).find((found) => found !== undefined);
9223
9223
  return path === undefined ? note : `${note} ${path} did not compile, so every run of this project starts its autoloads without it until it is fixed; its errors are among these.`;
9224
9224
  }
9225
+ function withoutAsides(entries) {
9226
+ const kept = [];
9227
+ let aside = false;
9228
+ for (const entry of entries) {
9229
+ const mark = entry.source === "stderr" ? entry.text : "";
9230
+ if (mark === ASIDE || mark === RESUMED) {
9231
+ aside = mark === ASIDE;
9232
+ } else if (!aside) {
9233
+ kept.push(entry);
9234
+ }
9235
+ }
9236
+ return kept;
9237
+ }
9225
9238
  function problemsIn(log) {
9226
9239
  return problemsAmong(log.everything());
9227
9240
  }
@@ -9368,7 +9381,7 @@ async function runOperation(engine, operation, params, projectPath) {
9368
9381
  } finally {
9369
9382
  discard(paramsDir);
9370
9383
  }
9371
- const everything = ran.log.everything();
9384
+ const everything = withoutAsides(ran.log.everything());
9372
9385
  const marked = (text) => everything.findIndex((entry) => entry.source === "stderr" && entry.text === text);
9373
9386
  const answered = marked(ANSWERED);
9374
9387
  const waiting = marked(WAITING);
@@ -9452,7 +9465,7 @@ function answerIn(file) {
9452
9465
  };
9453
9466
  }
9454
9467
  }
9455
- var AFTER_ANSWER_NOTE = "Printed after this operation had written its answer, while the engine ran the project's autoloads and shut down: Godot starts a project's autoloads in every script run and cannot be told not to. An error raised in a project script here is that autoload's own, and none of these changes the answer.", BEFORE_OPERATION_NOTE = "Printed while the engine started the project's autoloads, before this operation ran: an operation that compiles the project's scripts waits for them, because the engine knows an autoload's name only once it is in the tree. An error raised in a project script here is that autoload's own.", OWN_ERROR = "[ERROR] ", ANSWERED = "[gdharness] answered", WAITING = "[gdharness] waiting for the autoloads", BEGUN = "[gdharness] begun", MESSAGES_KEPT = 200, ERRORS_NAMED = 3;
9468
+ var AFTER_ANSWER_NOTE = "Printed after this operation had written its answer, while the engine ran the project's autoloads and shut down: Godot starts a project's autoloads in every script run and cannot be told not to. An error raised in a project script here is that autoload's own, and none of these changes the answer.", BEFORE_OPERATION_NOTE = "Printed while the engine started the project's autoloads, before this operation ran: an operation that compiles the project's scripts waits for them, because the engine knows an autoload's name only once it is in the tree. An error raised in a project script here is that autoload's own.", OWN_ERROR = "[ERROR] ", ANSWERED = "[gdharness] answered", WAITING = "[gdharness] waiting for the autoloads", BEGUN = "[gdharness] begun", ASIDE = "[gdharness] aside", RESUMED = "[gdharness] resumed", MESSAGES_KEPT = 200, ERRORS_NAMED = 3;
9456
9469
  var init_headless = __esm(() => {
9457
9470
  init_doc_cache();
9458
9471
  init_engine_run();
@@ -11942,7 +11955,7 @@ var init_tool_definitions = __esm(() => {
11942
11955
  };
11943
11956
  PROPERTIES = {
11944
11957
  type: "object",
11945
- description: `Properties to set, keyed by Godot property name. Vectors, colours and the like may be written as {"x": 1, "y": 2} or tagged {"_type": "Vector2", "x": 1, "y": 2}, which is the form a read answers with, so a value read off one node can be written straight to another. One carrying a field its type has not, such as a z for a Vector2, is refused naming it. A colour may also be given as its html code, "#ff8000" or "#ff800080". A key may also be a colon path into one of the components of a vector, a colour, a rectangle or a transform, as GDScript names them, so one axis is written alone: "position:x", "modulate:a", "region_rect:size:y"; a component the value does not have is refused, naming the ones it has. A property holding a node takes the path to it from the node being set, such as "../Player". Each value is read back once set, and one the engine changed or refused is refused with what it holds. An enum property takes the name of a value, as the script spells it, or its number; a value past an export range, or a number no value of an enum has, is written as given and named under outsideDeclared. ${WHOLE_NUMBERS}`,
11958
+ description: `Properties to set, keyed by Godot property name. Vectors, colours and the like may be written as {"x": 1, "y": 2} or tagged {"_type": "Vector2", "x": 1, "y": 2}, which is the form a read answers with, so a value read off one node can be written straight to another. One carrying a field its type has not, such as a z for a Vector2, is refused naming it. A colour may also be given as its html code, "#ff8000" or "#ff800080". A key may also be a colon path into one of the components of a vector, a colour, a rectangle or a transform, as GDScript names them, so one axis is written alone: "position:x", "modulate:a", "region_rect:size:y"; a component the value does not have is refused, naming the ones it has. A property holding a node takes the path to it from the node being set, such as "../Player". A property holding a Resource takes the res:// path of a file, which a read answers with its class and, when its script declares one, scriptClass, or a resource built into the scene as {"_type": "CircleShape2D", "radius": 8}, its class (an engine class or a script's class_name) beside its properties. A typed list or map of resources or nodes, such as Array[Item], takes each in the same forms, a node by its path; a read answers a resource built into the scene in that form, with what it holds away from the defaults, so it too can be written to another node. script takes the res:// path of a script to attach, one with no class_name included, and is attached before the rest are set, so the properties it declares can be given beside it. Each value is read back once set, and one the engine changed or refused is refused with what it holds. An enum property takes its number or the name of a value: as the script spells it, as the inspector shows it, or for an engine enum as the class's constant, so Add or BLEND_MODE_ADD; a value past an export range, or a number no value of an enum has, is written as given and named under outsideDeclared. A key may reach into a resource built into this one: the property holding it, a slash, then one of its own, so a TileSet's first atlas source takes "sources/0/0:0/0/probability". A resource kept in a file of its own, or built into the scene an instance comes from, is written in that file, or replaced here by one of this file's own. The next element of a list is made by writing to it, as the inspector's Add Element makes it: physics_layer_0/collision_layer on a TileSet with no physics layer makes its first, and "sources/0/0:0/0/physics_layer_0/polygon_0/points" a tile's first collision polygon on that layer. ${WHOLE_NUMBERS}`,
11946
11959
  additionalProperties: true
11947
11960
  };
11948
11961
  XY = {
@@ -12095,7 +12108,7 @@ var init_tool_definitions = __esm(() => {
12095
12108
  {
12096
12109
  name: "project_settings",
12097
12110
  title: "Project settings",
12098
- description: "Reads or writes project.godot: settings, autoloads, the main scene, input actions, plugins and audio buses. A write with an editor open on the project is handed to the editor, which takes the settings the write changed or names from the file (named under editorAdopted), including a setting the file already held, since the editor can hold another value after the file was put back, or reloads the bus layout, so it answers the new values and does not save the old ones back over them. editorNote is an editor that could not take the write, or one on another release's addon that was not asked, which still holds the old values until editor_launch restart. An enabled plugin's code still loads on the editor's next start. set answers old_value and new_value, with was_new true when project.godot did not set the setting before, and was_default true when what it held was the engine's own default, which old_value then is. add_input_action on an action that exists, one of the engine's ui_ actions included, replaces its events and deadzone, and answers was_new false with what it held under old_events and old_deadzone. A set of the value the setting already holds, in the same type, writes nothing and answers unchanged true and saved false. Every write keeps the sections and keys of project.godot in the order the file had them, so a change moves no other line; the save is the engine's, and like the editor's it writes Godot's header and config/features into a file that lacks them. get answers exists, true for any setting the engine knows, and at_default, true when the value is the engine's own default and so has no line in project.godot. Each setting under prefix carries at_default too, so a family read separates what the project sets from the engine's defaults; it is absent for a setting the engine registers no default for, such as an input action the project added, which only the project can have set.",
12111
+ description: "Reads or writes project.godot: settings, autoloads, the main scene, input actions, plugins and audio buses. project_info include lists the autoloads, input actions and audio buses as the project holds them. A write with an editor open on the project is handed to the editor, which takes the settings the write changed or names from the file (named under editorAdopted), including a setting the file already held, since the editor can hold another value after the file was put back, or reloads the bus layout, so it answers the new values and does not save the old ones back over them. editorNote is an editor that could not take the write, or one on another release's addon that was not asked, which still holds the old values until editor_launch restart. An enabled plugin's code still loads on the editor's next start. set answers old_value and new_value, with was_new true when project.godot did not set the setting before, and was_default true when what it held was the engine's own default, which old_value then is. add_input_action on an action that exists, one of the engine's ui_ actions included, replaces its events and deadzone, and answers was_new false with what it held under old_events and old_deadzone. A set of the value the setting already holds, in the same type, writes nothing and answers unchanged true and saved false. Every write keeps the sections and keys of project.godot in the order the file had them, so a change moves no other line; the save is the engine's, and like the editor's it writes Godot's header and config/features into a file that lacks them. get answers exists, true for any setting the engine knows, and at_default, true when the value is the engine's own default and so has no line in project.godot. Each setting under prefix carries at_default too, so a family read separates what the project sets from the engine's defaults; it is absent for a setting the engine registers no default for, such as an input action the project added, which only the project can have set.",
12099
12112
  parameters: {
12100
12113
  projectPath: PROJECT_PATH,
12101
12114
  setting: {
@@ -12252,7 +12265,7 @@ var init_tool_definitions = __esm(() => {
12252
12265
  direction: {
12253
12266
  type: "string",
12254
12267
  enum: ["forward", "reverse"],
12255
- 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, total_references counts the entries in the tree, and missing names every file referenced that does not exist, with the files referring to it. reverse: every file that refers to it and how, for a file that is gone as well, answered with exists: false, 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."
12268
+ 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_resources is the file asked about, so 1; total_dependencies counts each file reached, directly or through another, once however many places load it; total_references counts the entries in the tree, and missing names every file referenced that does not exist, with the files referring to it. reverse: every file that refers to it and how, for a file that is gone as well while anything still refers to it, answered with exists: false (a missing file nothing refers to is refused, naming the nearest files), 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."
12256
12269
  },
12257
12270
  depth: { type: "number", description: "forward: how many levels to follow. Default unlimited." },
12258
12271
  includeBuiltin: {
@@ -12282,7 +12295,7 @@ var init_tool_definitions = __esm(() => {
12282
12295
  options: {
12283
12296
  type: "object",
12284
12297
  ops: ["set_options"],
12285
- description: `set_options: import options keyed as the .import file spells them, {"compress/mode": 1}. A dictionary option whose keys are numbers, a font's opentype_features or any option already holding number keys, takes them written as strings of digits, and opentype_features also takes an OpenType tag by its four-letter name: {"opentype_features": {"liga": 0}} turns ligatures off. Both are written as the numbers the engine reads.`,
12298
+ description: `set_options: import options keyed as the .import file spells them, {"compress/mode": 1}. A dictionary option whose keys are numbers, a font's opentype_features or any option already holding number keys, takes them written as strings of digits, and opentype_features also takes an OpenType tag by its four-letter name: {"opentype_features": {"liga": 0}} turns ligatures off. Both are written as the numbers the engine reads. One already holding the value given is answered under unchanged_options rather than updated_options, and when none changed nothing is written or reimported.`,
12286
12299
  additionalProperties: true
12287
12300
  },
12288
12301
  reimport: {
@@ -12317,7 +12330,7 @@ var init_tool_definitions = __esm(() => {
12317
12330
  },
12318
12331
  reimport: {
12319
12332
  effect: "destructive",
12320
- summary: "reimport what status says is outdated or failed, one resource with resourcePath, or what is current as well with force. Through the open editor when one serves the project, so it reloads what it holds, waiting for it to finish; otherwise through the engine's own import pass. The editor scans first, since its reimport passes over a file it has not taken in, such as one an installer has just written; what that scan imported is named under importedByTheScan and is not imported again unless force asks. Answered from a second status read: reimported lists what is current now, notReimported what is not, one entry per status and reason with the paths sharing them, and via says which of the two did the work. When nothing needs reimporting, nothing runs, and the answer has the two lists empty, a note saying so, and no via. A whole-project reimport also answers missingSource, the .import files whose source is not beside them, empty when there are none, whether or not anything needed reimporting; one resourcePath is not a walk of the project and leaves it out. stillImporting is an editor that had not finished within timeoutMs",
12333
+ summary: "reimport what status says is outdated or failed, one resource with resourcePath, or what is current as well with force. Through the open editor when one serves the project, so it reloads what it holds, waiting for it to finish; otherwise through the engine's own import pass. The editor scans first, since its reimport passes over a file it has not taken in, such as one an installer has just written; what that scan imported is named under importedByTheScan and is not imported again unless force asks. Answered from a second status read: reimported lists what is current now, notReimported what is not, one entry per status and reason with the paths sharing them, and via says which of the two did the work. Either takes in every file that is behind, so a reimport of one resourcePath names under alsoImported the others it imported. When nothing needs reimporting, nothing runs, and the answer has the two lists empty, a note saying so, and no via. A whole-project reimport also answers missingSource, the .import files whose source is not beside them, empty when there are none, whether or not anything needed reimporting; one resourcePath is not a walk of the project and leaves it out. stillImporting is an editor that had not finished within timeoutMs",
12321
12334
  requires: []
12322
12335
  },
12323
12336
  uid: {
@@ -12419,7 +12432,7 @@ var init_tool_definitions = __esm(() => {
12419
12432
  {
12420
12433
  name: "scene_create",
12421
12434
  title: "Create or save a scene",
12422
- description: `Creates a scene file where none is, saves one, or saves a copy under a new path. A save of a scene open in the editor saves the editor's copy, unsaved changes included. ${WITHOUT_AN_EDITOR}`,
12435
+ description: `Creates a scene file where none is, saves one, or saves a copy under a new path. create makes a folder the path names that is not there, and names it under madeFolder. A save of a scene open in the editor saves the editor's copy, unsaved changes included. ${WITHOUT_AN_EDITOR}`,
12423
12436
  parameters: {
12424
12437
  projectPath: PROJECT_PATH,
12425
12438
  scenePath: SCENE_PATH,
@@ -12457,7 +12470,7 @@ var init_tool_definitions = __esm(() => {
12457
12470
  name: "scene_tree",
12458
12471
  title: "Scene tree",
12459
12472
  effect: "read",
12460
- description: "The nodes of a scene file: names, classes and hierarchy, with properties when asked. A node that instances another scene names that file under instanceOf, and the nodes listed under it come from that file rather than this one; its editableChildren says whether this scene, or a scene it inherits, keeps values of its own for them (scene_node set editableChildren). Needs no editor: one serving the project answers and says whether it holds unsaved changes to the scene, and with none a headless engine reads the file without making its nodes, so no script of theirs runs (autoloads still start once it has answered, as in every headless call). For the nodes of a game that is running, runtime_inspect tree.",
12473
+ description: "The nodes of a scene file: names, classes and hierarchy, with properties when asked. A node that instances another scene names that file under instanceOf, and the nodes listed under it come from that file rather than this one; its editableChildren says whether this scene, or a scene it inherits, keeps values of its own for them (scene_node set editableChildren). A node in any group answers groups, sorted, from this file and every scene it comes from. Needs no editor: one serving the project answers and says whether it holds unsaved changes to the scene, and with none a headless engine reads the file without making its nodes, so no script of theirs runs (autoloads still start once it has answered, as in every headless call). For the nodes of a game that is running, runtime_inspect tree.",
12461
12474
  parameters: {
12462
12475
  projectPath: PROJECT_PATH,
12463
12476
  scenePath: SCENE_PATH,
@@ -12472,7 +12485,8 @@ var init_tool_definitions = __esm(() => {
12472
12485
  {
12473
12486
  name: "scene_node",
12474
12487
  title: "Scene nodes",
12475
- description: `One node in a scene file: add, read, set, duplicate, reparent or delete it, or paint TileMap cells. Any ClassDB node type or script class can be added, so a NavigationRegion2D, an AnimationTree or a Camera3D is an add with that nodeType and its properties, and another scene is instanced by an add with instancePath. A set with properties {"name": "Boss"} renames a node, and answers nodePath as its new path. A rename or a reparent carries the node paths naming the node, as the editor's rename does: NodePath values on nodes (in arrays, dictionaries, built-in resources, %unique paths) and the tracks its players' animations hold, saving a library kept in a .tres of its own. Each rewrite is listed under retargeted ({scenePath, nodePath, property or animation and track, from, to}), and under notRetargeted, with a reason, each left: a track kept in another scene or an imported file, or a value another scene gives that the move left naming nothing. The move is followed into every other .tscn that instances or inherits this scene at any depth: the editable children, values, added nodes and connections named by the old path are rewritten, since Godot finds a moved node's values by unique_id but editable children only by path and drops the values kept below them on the next save, and that scene's node paths and tracks are carried as above. A reparent also drops the node ids saved along each rewritten path, which ran through the old parent; the next save writes them again. The scenes rewritten are named under followed, and under notFollowed any left as they were, with why. A delete rewrites no path and lists under stillNaming each node path and track, here and in the scenes instancing or inheriting this one, that named the deleted node and now names nothing. A property holding a Resource takes the res:// path of one, so a texture, a material or a theme is a set like any other. Other properties the engine changed in step, as a Control's offsets with its size, come back under alsoChanged as {was, now}.A write is refused while the editor holds unsaved changes to the scene. A node this scene inherits takes values of this scene's own, and so does a node inside an instance of another scene once that instance's editableChildren is true; neither can be moved, renamed, copied or deleted, since the other scene makes it again on load. ${WITHOUT_AN_EDITOR}`,
12488
+ description: `One node in a scene file: add, read, set, duplicate, reparent or delete it, or paint TileMap cells. Any ClassDB node type or script class can be added, so a NavigationRegion2D, an AnimationTree or a Camera3D is an add with that nodeType and its properties, and another scene is instanced by an add with instancePath. A set with properties {"name": "Boss"} renames a node, and answers nodePath as its new path. A rename or a reparent carries the node paths naming the node, as the editor's rename does: NodePath values on nodes (in arrays, dictionaries, built-in resources, %unique paths) and the tracks its players' animations hold, saving a library kept in a .tres of its own, and answers each rewrite under retargeted and each path it left under notRetargeted. The move is followed into every other .tscn that instances or inherits this scene at any depth: the editable children, values, added nodes and connections named by the old path are rewritten, since Godot finds a moved node's values by unique_id but editable children only by path and drops the values kept below them on the next save, and that scene's node paths and tracks are carried as above. A delete rewrites no path, and answers under stillNaming what named the deleted node and now names nothing. A property holding a Resource takes the res:// path of one, so a texture, a material or a theme is a set like any other. A write is refused while the editor holds unsaved changes to the scene. A node this scene inherits takes values of this scene's own, and so does a node inside an instance of another scene once that instance's editableChildren is true; neither can be moved, renamed, copied or deleted, since the other scene makes it again on load. ${WITHOUT_AN_EDITOR}`,
12489
+ answer: "get answers nodeType, the node's engine class, with scriptClass when its script declares a class_name; nodePath, its path from the root however it was named; setHere, the properties this scene's own file sets on it; and valuesFrom, the scene every other value comes from, when another scene makes the node. retargeted lists each path a rename or a reparent rewrote, as {scenePath, nodePath, property or animation and track, from, to}, and notRetargeted each it left, with a reason: a track kept in another scene or an imported file, or a value another scene gives that the move left naming nothing. followed names the other scenes a move rewrote, and notFollowed any left as they were, with why. stillNaming lists each node path and track, here and in the scenes instancing or inheriting this one, that named a deleted node, and deletedWithIt each node of this scene's own that went with it, the nodes inside an instance going with the instance. groups lists, sorted, every group a node is in, on a get, an add that gave addGroups and every set that changes them; get adds groupsHere, the groups this file puts it in, when another scene puts it in others. Each of these lists is answered only when it names anything. alsoChanged gives the other properties the engine changed in step with a set, as a Control's offsets with its size, and those a reparent changed to keep the node where it is drawn, as {was, now}.",
12476
12490
  parameters: {
12477
12491
  projectPath: PROJECT_PATH,
12478
12492
  scenePath: SCENE_PATH,
@@ -12499,17 +12513,34 @@ var init_tool_definitions = __esm(() => {
12499
12513
  ops: ["set"],
12500
12514
  description: "set: on an instance of another scene, whether its children are editable here, as the editor's Editable Children makes them. True lets scene_node set give the nodes inside that instance values of this scene's own, which no other instance shares. An instance nested inside another takes it once the one around it has editable children. False drops every value this scene keeps for them, and every node it added below one of them. The answer names the nodes whose values went under droppedValues (they stay, with the instance's own values) and the added nodes that went under droppedNodes; a node added straight under the instance stays. The answer says editableChildren as the file now holds it."
12501
12515
  },
12516
+ addGroups: {
12517
+ type: "array",
12518
+ items: { type: "string" },
12519
+ ops: ["add", "set"],
12520
+ description: "add and set: groups to put the node in, saved in this scene's file as the editor's Groups dock saves them. One it is in already is kept as it is."
12521
+ },
12522
+ removeGroups: {
12523
+ type: "array",
12524
+ items: { type: "string" },
12525
+ ops: ["set"],
12526
+ description: "set: groups to take the node out of. One it is not in is refused, and so is one another scene puts it in (the scene that makes it, instances it or is inherited here), which only that scene can take it out of."
12527
+ },
12502
12528
  newName: { type: "string", ops: ["duplicate"], description: "duplicate: the copy's name." },
12503
12529
  newParentPath: {
12504
12530
  type: "string",
12505
12531
  ops: ["reparent"],
12506
- description: "reparent: the new parent, which may be the one it has, to move it among its siblings."
12532
+ description: "reparent: the new parent, which may be the one it has, to move it among its siblings. In the scenes the move is followed into, the parent_id_path, from_uid_path and to_uid_path saved beside each rewritten path are dropped, since their ids ran through the old parent; the node's own unique_id is kept, and the next save writes the dropped ones again."
12533
+ },
12534
+ keepGlobalTransform: {
12535
+ type: "boolean",
12536
+ ops: ["reparent"],
12537
+ description: "reparent: whether the node stays where it is drawn, its transform worked out again under the new parent, as the editor's reparent and Node.reparent keep it. A Control keeps its position only. Default true; false keeps its own transform, so it moves with the new parent."
12507
12538
  },
12508
12539
  index: {
12509
12540
  type: "integer",
12510
12541
  minimum: 0,
12511
- ops: ["add", "reparent"],
12512
- description: "add and reparent: where the node goes among the parent's children, 0 for first. Default last. Child order is draw order in a CanvasItem and layout order in a Container."
12542
+ ops: ["add", "duplicate", "reparent"],
12543
+ description: "add, duplicate and reparent: where the node goes among the parent's children, 0 for first. Default last, except for a copy under the original's own parent, which goes right after it. Child order is draw order in a CanvasItem and layout order in a Container."
12513
12544
  },
12514
12545
  includeDefaults: {
12515
12546
  type: "boolean",
@@ -12532,22 +12563,22 @@ var init_tool_definitions = __esm(() => {
12532
12563
  },
12533
12564
  get: {
12534
12565
  effect: "read",
12535
- summary: "read a node's properties, and a TileMapLayer's or TileMap's cells as set_tilemap_cells takes them, the first 1000 with cellCount for all. An instance of another scene also answers instanceOf and editableChildren, as scene_tree does",
12566
+ summary: "read a node's class, path, properties and where its values come from, and a TileMapLayer's or TileMap's cells as set_tilemap_cells takes them, the first 1000 with cellCount for all. An instance of another scene also answers instanceOf and editableChildren, as scene_tree does",
12536
12567
  requires: ["nodePath"]
12537
12568
  },
12538
12569
  set: {
12539
12570
  effect: "destructive",
12540
- summary: "set properties on a node, or make the children of an instance editable; give either or both",
12571
+ summary: "set properties on a node, make the children of an instance editable, or put it in groups or take it out of them; give any of them together",
12541
12572
  requires: ["nodePath"]
12542
12573
  },
12543
12574
  duplicate: {
12544
12575
  effect: "additive",
12545
- summary: "copy a node and its children, beside it or under parentNodePath, answering the copy's newNodePath, parentNodePath and index",
12576
+ summary: "copy a node and its children, right after it or under parentNodePath, answering the copy's newNodePath, parentNodePath and index",
12546
12577
  requires: ["nodePath", "newName"]
12547
12578
  },
12548
12579
  reparent: {
12549
12580
  effect: "destructive",
12550
- summary: "move a node under another parent, or to another place among its siblings",
12581
+ summary: "move a node under another parent, keeping where it is drawn, or to another place among its siblings",
12551
12582
  requires: ["nodePath", "newParentPath"]
12552
12583
  },
12553
12584
  delete: { effect: "destructive", summary: "remove a node and its children", requires: ["nodePath"] },
@@ -12561,7 +12592,7 @@ var init_tool_definitions = __esm(() => {
12561
12592
  {
12562
12593
  name: "scene_signal",
12563
12594
  title: "Scene signals",
12564
- description: `Signal connections in a scene file. Each connection answers with its flags as the number and as flagNames; persist is on every connection, since a scene saves no other kind. A connect of a pair already connected says alreadyConnected, with flagsBefore when it changed the flags. A connect to a method the target does not have is still written, as the editor's own dialog allows, since the method may be written next; methodFound false says so, and until the method exists the signal fails each time it is emitted. list marks editable false on a connection an instanced scene makes inside itself, which only that scene can change. ${WITHOUT_AN_EDITOR}`,
12595
+ description: `Signal connections in a scene file. Each connection answers with its flags as the number and as flagNames; persist is on every connection, since a scene saves no other kind. A connect of a pair already connected says alreadyConnected, with flagsBefore when it changed the flags. A connect to a method the target does not have is still written, as the editor's own dialog allows, since the method may be written next; methodFound false says so, and until the method exists the signal fails each time it is emitted. One whose method cannot take what the signal passes, with its binds and unbinds (too few or too many arguments, an object where the method takes a value or the reverse, or an engine class unrelated to the one it takes), is written too, and answers argumentsFit false with misfit saying why; list gives each connection its methodFound, and misfit when it has one. list marks editable false on a connection an instanced scene makes inside itself, which only that scene can change. ${WITHOUT_AN_EDITOR}`,
12565
12596
  parameters: {
12566
12597
  projectPath: PROJECT_PATH,
12567
12598
  scenePath: SCENE_PATH,
@@ -12606,31 +12637,40 @@ var init_tool_definitions = __esm(() => {
12606
12637
  {
12607
12638
  name: "scene_animation",
12608
12639
  title: "Animations",
12609
- description: "Animations in an AnimationPlayer and states in an AnimationTree state machine. read answers with every track of an animation in the shape add_track takes, so a track read off one animation can be added to another. read and read_states need no editor: one serving the project answers and says whether it holds unsaved changes to the scene, and with none a headless engine reads the file without running the scene's scripts. The ops that write go through the editor when one serves the project; with none, a headless engine runs the editor's own tool and the answer says so under writtenBy. That engine runs every script of the file, where the editor runs only tool scripts, so what a script changes as the file loads is put back before anything is saved, and a file where that cannot be done, such as a scene whose script does not compile, is refused and nothing is written. An editor of the project that is running and has not reached this server is waited for rather than written around.",
12640
+ description: "Animations in an AnimationPlayer and states in an AnimationTree state machine. read answers with every track of an animation in the shape add_track takes, so a track read off one animation can be added to another. add_track on a path the animation already has a track of that type for adds the keys to that track, as the editor keys a property it already animates, answering existingTrack true and keysAdded beside keys, the track's count; a key at a time that track already has a key at is refused. A key past the animation's end, where it never plays, is written and named under pastLength. remove clears the player's autoplay when it named the animation and names under statesPlayingNothing the states that played it. read and read_states need no editor: one serving the project answers and says whether it holds unsaved changes to the scene, and with none a headless engine reads the file without running the scene's scripts. The ops that write go through the editor when one serves the project; with none, a headless engine runs the editor's own tool and the answer says so under writtenBy. That engine runs every script of the file, where the editor runs only tool scripts, so what a script changes as the file loads is put back before anything is saved, and a file where that cannot be done, such as a scene whose script does not compile, is refused and nothing is written. An editor of the project that is running and has not reached this server is waited for rather than written around.",
12610
12641
  parameters: {
12611
12642
  projectPath: PROJECT_PATH,
12612
12643
  scenePath: SCENE_PATH,
12613
12644
  playerNodePath: {
12614
12645
  type: "string",
12615
- ops: ["read", "create", "add_track"],
12646
+ ops: ["read", "create", "add_track", "set", "rename", "remove"],
12616
12647
  description: "The AnimationPlayer node."
12617
12648
  },
12618
12649
  animationName: {
12619
12650
  type: "string",
12620
- ops: ["read", "create", "add_track", "add_state"],
12621
- description: "The animation in the player. read: the one to answer with whole, its tracks a list; without it, read lists them, each with the number of its tracks under tracks. add_state: the one that state plays."
12651
+ ops: ["read", "create", "add_track", "set", "rename", "remove", "add_state"],
12652
+ description: "The animation in the player. read: the one to answer with whole, its tracks a list; without it, read lists them, each with the number of its tracks under tracks. add_state: the one that state plays. One the player does not have yet is written all the same, answering animationFound false and why under animationMissing."
12653
+ },
12654
+ newName: {
12655
+ type: "string",
12656
+ ops: ["rename"],
12657
+ description: "rename: the animation's new name in the library it is in. The player's autoplay and every state of the scene's AnimationTrees that plays it are renamed with it, named under autoplay and statesFollowed."
12658
+ },
12659
+ length: {
12660
+ type: "number",
12661
+ ops: ["create", "set"],
12662
+ description: "create and set: seconds, more than 0. create: default 1. set: a key past the new end is kept, as the editor keeps it, and named under pastLength, since it never plays."
12622
12663
  },
12623
- length: { type: "number", ops: ["create"], description: "create: seconds. Default 1." },
12624
12664
  loopMode: {
12625
12665
  type: "string",
12626
- ops: ["create"],
12666
+ ops: ["create", "set"],
12627
12667
  enum: ["none", "linear", "pingpong"],
12628
12668
  description: "create: default none."
12629
12669
  },
12630
12670
  step: {
12631
12671
  type: "number",
12632
- ops: ["create"],
12633
- description: "create: keyframe snap in seconds. Default 0.1."
12672
+ ops: ["create", "set"],
12673
+ description: "create and set: keyframe snap in seconds, 0 or more. create: default 0.1."
12634
12674
  },
12635
12675
  track: { ...ANIMATION_TRACK, ops: ["add_track"] },
12636
12676
  animTreePath: {
@@ -12692,6 +12732,21 @@ var init_tool_definitions = __esm(() => {
12692
12732
  summary: "a property or method track with keyframes",
12693
12733
  requires: ["playerNodePath", "animationName", "track"]
12694
12734
  },
12735
+ set: {
12736
+ effect: "destructive",
12737
+ summary: "an animation's length, loop mode or step",
12738
+ requires: ["playerNodePath", "animationName"]
12739
+ },
12740
+ rename: {
12741
+ effect: "destructive",
12742
+ summary: "an animation, with what plays it",
12743
+ requires: ["playerNodePath", "animationName", "newName"]
12744
+ },
12745
+ remove: {
12746
+ effect: "destructive",
12747
+ summary: "an animation from its player",
12748
+ requires: ["playerNodePath", "animationName"]
12749
+ },
12695
12750
  add_state: {
12696
12751
  effect: "additive",
12697
12752
  summary: "a state playing an animation, in an AnimationTree",
@@ -12719,7 +12774,7 @@ var init_tool_definitions = __esm(() => {
12719
12774
  extends: {
12720
12775
  type: "string",
12721
12776
  ops: ["create"],
12722
- description: "create: the base class. Default Node. Not with content."
12777
+ description: "create: the base class. Default the class the template is written for, or Node with no template. Not with content."
12723
12778
  },
12724
12779
  content: {
12725
12780
  type: "string",
@@ -12730,13 +12785,13 @@ var init_tool_definitions = __esm(() => {
12730
12785
  type: "string",
12731
12786
  enum: ["singleton", "state_machine", "component", "resource"],
12732
12787
  ops: ["create"],
12733
- description: "create: a starting shape."
12788
+ description: "create: a starting shape. resource is written for a Resource and the others for a Node; an extends outside that class is refused."
12734
12789
  },
12735
12790
  modifications: { ...SCRIPT_MODIFICATIONS, ops: ["modify"] },
12736
12791
  symbol: {
12737
12792
  type: "string",
12738
12793
  ops: ["rename"],
12739
- description: "rename: what to rename, declared by the script at scriptPath: its class_name, or a method, variable, constant, signal, enum, enum value or inner class at its top level. A class is renamed from the files and needs no editor: every bare use in code, the declaration, doc links such as [Told] and [method Told.say], and the script_class a .tres records. A script that declares something of its own by the old name, and a use after a dot, are left alone, since which of those mean the class cannot be told from the text. A member is renamed from what the editor's language server resolves to it, so it needs the editor open on this project; a method is renamed together with every override of it in the classes inheriting it, and from the topmost class declaring it when scriptPath's is itself an override. Doc links naming the member through any class inheriting it are renamed too, and so are a scene's or resource's saved value of a variable on a node or resource whose script inherits it, and a connection naming the signal on its emitter or the method on its receiver. A name the engine itself declares on the native base, such as _ready, is refused, as is a new name already taken: by a class, an autoload, an identifier in code, a native class or built-in type, or a member anywhere in the class's chain."
12794
+ description: "rename: what to rename, declared by the script at scriptPath: its class_name, or a method, variable, constant, signal, enum, enum value or inner class at its top level. A class_name is renamed from the files and needs no editor: every bare use in code, the declaration, doc links such as [Told] and [method Told.say], and the script_class a .tres records. A script that declares something of its own by the old name, and a use after a dot, are left alone, since which of those mean the class cannot be told from the text. Everything else, an inner class and an enum value included, is renamed from what the editor's language server resolves to it, so it needs the editor open on this project; a method is renamed together with every override of it in the classes inheriting it, and from the topmost class declaring it when scriptPath's is itself an override. Doc links naming the member through any class inheriting it are renamed too, and so are a scene's or resource's saved value of a variable on a node or resource whose script inherits it, and a connection naming the signal on its emitter or the method on its receiver. A name the engine itself declares on the native base, such as _ready, is refused, as is a new name already taken: by a class, an autoload, an identifier in code, a native class or built-in type, or a member anywhere in the class's chain."
12740
12795
  },
12741
12796
  newName: { type: "string", ops: ["rename"], description: "rename: the new name." },
12742
12797
  newScriptPath: {
@@ -12790,7 +12845,7 @@ var init_tool_definitions = __esm(() => {
12790
12845
  operations: {
12791
12846
  structure: {
12792
12847
  effect: "read",
12793
- summary: "functions, variables, signals, constants, enums, inner_classes, class_name, extends and line_count, 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; autoloads_used names each autoload the code uses by its global name, with the autoload's script, which the project loads rather than this script, so it is not under dependencies",
12848
+ summary: "functions, variables (static ones marked is_static; one written with := has the type of a literal or built-in constructor it is given, marked inferred, as a constant always does), signals, constants, enums, inner_classes (each with its name, line and extends, and its own members in these same fields), class_name, extends and line_count, 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; autoloads_used names each autoload the code uses by its global name, with the autoload's script, which the project loads rather than this script, so it is not under dependencies",
12794
12849
  requires: []
12795
12850
  },
12796
12851
  symbols: {
@@ -12811,7 +12866,7 @@ var init_tool_definitions = __esm(() => {
12811
12866
  name: "script_diagnostics",
12812
12867
  title: "Script diagnostics",
12813
12868
  effect: "read",
12814
- 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, typesMissingFromTheClassCache naming a class the project declares that the engine could not resolve because the class cache lacks it, with staleAnalysis saying what rewrites the cache, 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.",
12869
+ 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 (a call to a method another class lacks is not one, since GDScript checks those only on self: the object may be a subclass that has it, so it fails at run time instead), dependenciesWithErrors naming the other scripts that failed while it loaded, typesMissingFromTheClassCache naming a class the project declares that the engine could not resolve because the class cache lacks it, with staleAnalysis saying what rewrites the cache, 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.",
12815
12870
  parameters: {
12816
12871
  projectPath: PROJECT_PATH,
12817
12872
  scriptPath: {
@@ -12868,7 +12923,7 @@ var init_tool_definitions = __esm(() => {
12868
12923
  preview: {
12869
12924
  type: "boolean",
12870
12925
  ops: ["move"],
12871
- description: "move: answer with what would move and change, and write nothing. Default false."
12926
+ description: "move: answer with what would move and change, and write nothing. A move that would be refused is refused here too, with the same reason. Default false."
12872
12927
  },
12873
12928
  controlType: {
12874
12929
  type: "string",
@@ -12904,7 +12959,7 @@ var init_tool_definitions = __esm(() => {
12904
12959
  create_shader: { effect: "destructive", summary: "a .gdshader file", requires: ["shaderType"] },
12905
12960
  create_tileset: {
12906
12961
  effect: "destructive",
12907
- summary: "a TileSet from texture atlases",
12962
+ summary: "a TileSet from texture atlases; its physics, terrain and custom data layers, and each tile's collision and other values, are written with modify after it",
12908
12963
  requires: ["sources"]
12909
12964
  },
12910
12965
  set_theme_color: {
@@ -12927,7 +12982,7 @@ var init_tool_definitions = __esm(() => {
12927
12982
  {
12928
12983
  name: "editor_launch",
12929
12984
  title: "Open, restart or close the editor",
12930
- description: "Opens the Godot editor on a project, or restarts or closes the one already connected. close saves open scenes, quits the editor and waits for its process to go, which is the only way to end a hidden one short of killing it; settingsDropped in its answer says what that save took out of project.godot. An editor this server opened that has not connected yet has nothing of this server's to save, so close stops its process instead and answers beforeConnecting. open answers once the process has started, and the editor dials in after its import; a call needing the editor made before then waits for the one this server opened, for as long as a restart waits, and is refused naming it if it has not arrived. open refuses while an editor of the project is already running and has not reached this server, naming its pid, rather than putting a second on the project. The editor is an ordinary visible one on the desktop in use, and on Windows it is shown without being activated, so opening or reopening it does not take the keyboard from whatever the user is typing in. hidden: true opens it headless instead and, on Windows, on a desktop of its own, where the games it plays go too; a hidden editor serves the bridge, the language server and the debug adapter as a visible one does. A game a visible editor plays opens as a window on the desktop in use. An editor goes on serving the addon it read at startup, so restart is what puts a gdharness upgrade into effect, and nothing else here restarts one; it saves open scenes on the way out and answers with the version that came back. An editor a server opened is started again by the server, visible unless hidden: true is passed again, once the old one has gone: it waits 90 seconds for that, or GDHARNESS_EDITOR_RESTART_TIMEOUT_MS, and an old editor still running after it is not replaced, since the new one would find its ports held. One opened by hand restarts itself, which only one with a window can do, because the engine hands back none of the arguments it was started with. editor_status says which editor is connected and whether it is holding an old addon. Opening a project is a save and so is closing one, which is the part that is not obvious from outside: the editor imports the project on open and writes project.godot back, and Godot writes only what differs from its own defaults, so a key named deliberately at its default value is dropped either way. A restart says which under settingsDropped in its own answer because it waits for the editor to return. An open cannot, since it answers as soon as the process exists and the save happens during the import minutes later, so editor_status carries that reading once the editor has connected. Nothing else will say a key went until something depends on one. A restart of an editor this server opened is a quit and then a launch, and this server can be ended between them, usually by the reconnect the restart was being taken for: the editor is gone and nothing replaces it. That is written down before the quit, so the next server says so under restartInterrupted in editor_status rather than waiting for an editor that is not coming, and open finishes it, saying so under finishesRestart. An open is refused when the editor it would start could never reach this server: a project other than the one this server serves, whose editor dials that project's own server; a project without the gdharness editor addon installed and enabled; and a project whose editor a restart is already bringing back.",
12985
+ description: "Opens the Godot editor on a project, or restarts or closes the one already connected. close saves open scenes, quits the editor and waits for its process to go, which is the only way to end a hidden one short of killing it; settingsDropped in its answer names what that save took out of project.godot, and is left out when it took nothing; settingsNote says so when the file could not be read to tell. An editor this server opened that has not connected yet has nothing of this server's to save, so close stops its process instead and answers beforeConnecting. open answers once the process has started, and the editor dials in after its import; a call needing the editor made before then waits for the one this server opened, for as long as a restart waits, and is refused naming it if it has not arrived. open refuses while an editor of the project is already running and has not reached this server, naming its pid, rather than putting a second on the project. The editor is an ordinary visible one on the desktop in use, and on Windows it is shown without being activated, so opening or reopening it does not take the keyboard from whatever the user is typing in. hidden: true opens it headless instead and, on Windows, on a desktop of its own, where the games it plays go too; a hidden editor serves the bridge, the language server and the debug adapter as a visible one does. A game a visible editor plays opens as a window on the desktop in use. An editor goes on serving the addon it read at startup, so restart is what puts a gdharness upgrade into effect, and nothing else here restarts one; it saves open scenes on the way out and answers with the version that came back. An editor a server opened is started again by the server, visible unless hidden: true is passed again, once the old one has gone: it waits 90 seconds for that, or GDHARNESS_EDITOR_RESTART_TIMEOUT_MS, and an old editor still running after it is not replaced, since the new one would find its ports held. One opened by hand restarts itself, which only one with a window can do, because the engine hands back none of the arguments it was started with. editor_status says which editor is connected and whether it is holding an old addon. Opening a project is a save and so is closing one, which is the part that is not obvious from outside: the editor imports the project on open and writes project.godot back, and Godot writes only what differs from its own defaults, so a key named deliberately at its default value is dropped either way. A restart says which under settingsDropped in its own answer because it waits for the editor to return. An open cannot, since it answers as soon as the process exists and the save happens during the import minutes later, so editor_status carries that reading once the editor has connected. Nothing else will say a key went until something depends on one. A restart of an editor this server opened is a quit and then a launch, and this server can be ended between them, usually by the reconnect the restart was being taken for: the editor is gone and nothing replaces it. That is written down before the quit, so the next server says so under restartInterrupted in editor_status rather than waiting for an editor that is not coming, and open finishes it, saying so under finishesRestart. An open is refused when the editor it would start could never reach this server: a project other than the one this server serves, whose editor dials that project's own server; a project without the gdharness editor addon installed and enabled; and a project whose editor a restart is already bringing back.",
12931
12986
  parameters: {
12932
12987
  projectPath: { ...PROJECT_PATH, ops: ["open"] },
12933
12988
  hidden: {
@@ -13164,7 +13219,7 @@ var init_tool_definitions = __esm(() => {
13164
13219
  title: "Editor status",
13165
13220
  effect: "read",
13166
13221
  description: "Whether the editor addon is connected, which Godot answers, whether the editor is playing something, and which games with the runtime addon are reachable, of this project and of every other on the machine. Read connected with mayYetConnect: the editor dials this server and backs off between tries, so for the first half-minute after a server starts false means not reached yet as often as no editor; mayYetConnect true is worth waiting out, false is final, and editorCannotConnect, restartInterrupted, restartUnderway, closedHere and editorsNotYetConnected say why. An editor that has connected and not yet greeted reports nothing about itself, and every other call made in that window waits up to ten seconds for it to settle. playingInEditor null means unanswered rather than nothing playing: processActive and runtimes do not depend on the editor answering. game.run names the run editor_output and editor_run stop answer for, and stays named after it ends. addonIsStale, on a connected editor and on each running game (absent with neither), says it runs addon code other than what this server ships, and staleNote says which half moves: the project, by a gdharness upgrade it spells out to run in a shell, the editor by a restart, or this server by a reconnect. A false editor.lspListening or editor.dapListening comes with serversNote, and editor_launch restart binds the port again. editor.scan says whether the editor is scanning, which editor_run waits out before starting a game. A game announced in a protocol this server does not speak is listed under unreadable, during an upgrade that moves the protocol, until the halves match.",
13167
- answer: "projectIs, when present, is the gdharness version of the addons in the project, which differs from this server's (project_info says which of the two to move), and configIs, when present, the version the project's MCP config starts, which differs from this server's, so the next connection runs that one. server names this server: its pid, its version, and lifecycleLog, the file every gdharness server of the user appends a line to when it starts, when its client first names itself, when it replaces another server of its project, and when it ends, with why it ended (the client closing its end as stdin:end, a signal by name, superseded with the successor's pid, an uncaught exception or rejection with its stack, or the exit code) and the calls it was answering then. The parent's command line follows on its own line a few seconds after the start. A server killed without warning writes no ended line, and on Windows every kill is that, so a started line with no ended line after it is a server something killed. " + "runtimeConnected counts the games of the project this server serves, and runtimes lists every game on the machine with ofThisProject saying which is which, since a game of another project is reached only by naming its projectPath. playingInEditor is null when the editor was not asked or did not answer, which is not the same as a no: with no editor connected there is nobody to ask, and an editor that does not serve the question is given a moment and then left. A game can be playing while this is null, so read it as unanswered rather than as nothing playing, and use processActive and runtimes, which come from elsewhere and do not depend on the editor answering. Its play says which play the editor is on: play.play counts the plays that editor has started since it opened, whoever started them, and play.editorPid is the editor, so two reads with different pairs are two plays even when both say playing. game.run names the run processActive is about, the one editor_output and editor_run stop answer for: its pid, its project, and adopted true when this server read it back from another server rather than starting it. It stays named after the run ends, beside processActive false, so editor_output can still read what that run printed; null when there is no run at all. startedAt says when it began, and endedAt when it ended, wherever something saw the end: a run adopted from a note another server wrote can have ended hours before this server started. editor.lspListening and editor.dapListening say whether anything accepts connections on the ports the editor names, lspPort and dapPort: Godot binds each once, as the editor starts, and reports a failure only in the log panel of the editor itself, so a false comes with serversNote, and editor_launch restart binds it again. editor.scan says whether the editor is scanning or importing and how many milliseconds ago its last scan finished (finishedMsAgo), or is null when it did not answer: the editor rewrites the class cache just after a scan, and editor_run waits that out before starting a game, saying so under waitedForEditorScanMs. Each game under runtimes is pinged with a short wait, so one held at a breakpoint is listed as unreachable rather than making this call wait out the runtime timeout; for the run this server is reporting on, heldAt says whether that is what it is, with the same three answers editor_output gives. A game the editor played announces the editor under editorPid, and so does whatever that game started for itself; a game some other server started announces none, which is how the two are told apart when both are running from one project. Each game also says which runtime addon it loaded, under addonVersion (null when it cannot say); addonIsStale is true when that code is not what this server ships, and staleNote says whether the project needs the gdharness upgrade command, spelled out to run in a shell, the game a restart, or this server a reconnect. A second checkout of a project, such as a git worktree, carries addons of its own and is where this shows. A runtime_* call to such a game is refused with the staleNote and not sent. When connected is false, mayYetConnect says whether that is final: the editor dials this server rather than the other way round and backs off between tries, so for the first half-minute after a server starts, false means \"not reached yet\" as often as it means \"no editor\". True is worth waiting out; false is an editor that is not there. False beside editorCannotConnect is a project without the gdharness editor addon installed or enabled, where no editor can ever dial in, however young the server or whichever editor is open; its remedies say how to install or enable it. False beside restartInterrupted is one that an editor_launch restart on a previous server asked to quit, where the launch half never ran because that server was ended in between, usually by the reconnect the restart was taken for; editor_launch open finishes it. True beside restartUnderway is a restart still in progress, its server alive and within the wait for the old editor to go: the editor is coming, and opening another would put two on one project. listeningSince is when this server took the bridge port, which is what that window is measured from and what a caller wanting its own window should read. An editor this server opened counts for as long as its process lives, however far past that window the import runs, and awaitingLaunchedEditor names its pid so the two reasons for true are told apart. Any editor of this project running and not yet connected, whoever opened it, makes it true as well and is named under editorsNotYetConnected with its pid and start time, so a restart a reconnect interrupted after its launch is not read as nothing being there. settingsDropped appears here once when the editor this server opened saved project.godot on its way in, which is the same reading editor_launch restart makes in its own answer. A game that has announced itself in a protocol this server does not speak is listed under unreadable rather than left out, with the protocol it speaks and whether the server or the addon is the older half. This happens during an upgrade that moves the runtime protocol, which most do not: installing replaces the addon on disk as soon as the pin moves, while a server that is already running stays on the version it started with, so the two speak different protocols until the server is reconnected. Those games are real and running, but no tool here can reach them until the halves match, so runtimes stays empty and runtimeConnected stays false. An upgrade that leaves the protocol alone opens no such window and this list stays empty through it. addonIsStale is decided by the code of the editor addons rather than their version, so an editor started before an upgrade that left that code alone reports the older addonVersion, is not stale, and addonNote says so: it needs no restart. A stale editor is asked nothing but to quit: every other call to it is refused with staleNote, which names editor_launch restart, the upgrade command or a reconnect. port is the one the editor bridge is on; when that is not the one this server was configured with, portWanted names the configured one and portNote says why it moved and, when it was the server this one replaced, which pid kept it. A server replacing another of its project that holds the configured port waits for it to stand down and takes the port over, which takes a few seconds; bridgeHandover says so while it waits, and it moves only if that server has not let go within the wait. An editor that has connected and not yet greeted, which lasts a frame and longer while it imports, reports nothing about itself: greeting says so, addonIsStale is absent rather than guessed, and a restart asked then waits for the greeting to learn who opened it. startedByAnEditor is an editor another editor started, by Godot's own restart or the project manager, which has none of the arguments a server gave the one before it; startedByAnEditorNote says what that costs. An engine run that loads the editor addon to do one job and quit, such as a gate's godot --headless --import, an export or a script, is not taken as the editor: a process that greets without a server's mark has its command line read first, and while that is read identifying is true and connected false; one started with such an option is turned away, and turnedAway names the last one, its pid and the option. Every other call made while an editor is arriving, before its greeting or while it is looked up, waits up to ten seconds for it to settle rather than acting on connected as it reads in that window. serverVersion is the gdharness version of this server. bridgeAvailable says the editor bridge is listening; when it failed to start, startupError gives the error, and retryingBridge is true while this server tries again. announcedAt is the file where this server told editors of its project which port to dial. connectedAt is when the editor connected, and lastPongAt when it last answered this server's keep-alive ping. addonDigest is a hash of the editor addon's code, which addonIsStale compares with what this server ships. debugPort is the port of the editor's remote debugger, the one games it plays connect to. openedByAServer says a gdharness server started this editor, and syncsBreakpoints that it keeps its breakpoints when a debug session opens, which Godot otherwise clears. pendingRequests counts the requests sent to the editor and not yet answered, and queuedResources the files with writes waiting behind another write to the same file.",
13222
+ answer: "projectIs, when present, is the gdharness version of the addons in the project, which differs from this server's (project_info says which of the two to move), and configIs, when present, the version the project's MCP config starts, which differs from this server's, so the next connection runs that one. server names this server: its pid, its version, and lifecycleLog, the file every gdharness server of the user appends a line to when it starts, when its client first names itself, when it replaces another server of its project, and when it ends, with why it ended (the client closing its end as stdin:end, a signal by name, superseded with the successor's pid, an uncaught exception or rejection with its stack, or the exit code) and the calls it was answering then. The parent's command line follows on its own line a few seconds after the start. A server killed without warning writes no ended line, and on Windows every kill is that, so a started line with no ended line after it is a server something killed. " + "runtimeConnected counts the games of the project this server serves, and runtimes lists every game on the machine with ofThisProject saying which is which, since a game of another project is reached only by naming its projectPath. playingInEditor is null when the editor was not asked or did not answer, which is not the same as a no: with no editor connected there is nobody to ask, and an editor that does not serve the question is given a moment and then left. A game can be playing while this is null, so read it as unanswered rather than as nothing playing, and use processActive and runtimes, which come from elsewhere and do not depend on the editor answering. Its play says which play the editor is on: play.play counts the plays that editor has started since it opened, whoever started them, and play.editorPid is the editor, so two reads with different pairs are two plays even when both say playing. game.run names the run processActive is about, the one editor_output and editor_run stop answer for: its pid, its project, and adopted true when this server read it back from another server rather than starting it. It stays named after the run ends, beside processActive false, so editor_output can still read what that run printed; null when there is no run at all. startedAt says when it began, and endedAt when it ended, wherever something saw the end: a run adopted from a note another server wrote can have ended hours before this server started. editor.lspListening and editor.dapListening say whether anything accepts connections on the ports the editor names, lspPort and dapPort: Godot binds each once, as the editor starts, and reports a failure only in the log panel of the editor itself, so a false comes with serversNote, and editor_launch restart binds it again. editor.scan says whether the editor is scanning or importing and how many milliseconds ago its last scan finished (finishedMsAgo), or is null when it did not answer: the editor rewrites the class cache just after a scan, and editor_run waits that out before starting a game, saying so under waitedForEditorScanMs. Each game under runtimes is pinged with a short wait, so one held at a breakpoint is listed as unreachable rather than making this call wait out the runtime timeout; for the run this server is reporting on, heldAt says whether that is what it is, with the same three answers editor_output gives. A game the editor played announces the editor under editorPid, and so does whatever that game started for itself; a game some other server started announces none, which is how the two are told apart when both are running from one project. Each game also says which runtime addon it loaded, under addonVersion (null when it cannot say); addonIsStale is true when that code is not what this server ships, and staleNote says whether the project needs the gdharness upgrade command, spelled out to run in a shell, the game a restart, or this server a reconnect. A second checkout of a project, such as a git worktree, carries addons of its own and is where this shows. A runtime_* call to such a game is refused with the staleNote and not sent. When connected is false, mayYetConnect says whether that is final: the editor dials this server rather than the other way round and backs off between tries, so for the first half-minute after a server starts, false means \"not reached yet\" as often as it means \"no editor\". True is worth waiting out; false is an editor that is not there. False beside editorCannotConnect is a project without the gdharness editor addon installed or enabled, where no editor can ever dial in, however young the server or whichever editor is open; its remedies say how to install or enable it. False beside restartInterrupted is one that an editor_launch restart on a previous server asked to quit, where the launch half never ran because that server was ended in between, usually by the reconnect the restart was taken for; editor_launch open finishes it. True beside restartUnderway is a restart still in progress, its server alive and within the wait for the old editor to go: the editor is coming, and opening another would put two on one project. listeningSince is when this server took the bridge port, which is what that window is measured from and what a caller wanting its own window should read. An editor this server opened counts for as long as its process lives, however far past that window the import runs, and awaitingLaunchedEditor names its pid so the two reasons for true are told apart. Any editor of this project running and not yet connected, whoever opened it, makes it true as well and is named under editorsNotYetConnected with its pid and start time, so a restart a reconnect interrupted after its launch is not read as nothing being there. settingsDropped appears here once when the editor this server opened saved project.godot on its way in and took a key out of it, which is the same reading editor_launch restart makes in its own answer. A game that has announced itself in a protocol this server does not speak is listed under unreadable rather than left out, with the protocol it speaks and whether the server or the addon is the older half. This happens during an upgrade that moves the runtime protocol, which most do not: installing replaces the addon on disk as soon as the pin moves, while a server that is already running stays on the version it started with, so the two speak different protocols until the server is reconnected. Those games are real and running, but no tool here can reach them until the halves match, so runtimes stays empty and runtimeConnected stays false. An upgrade that leaves the protocol alone opens no such window and this list stays empty through it. addonIsStale is decided by the code of the editor addons rather than their version, so an editor started before an upgrade that left that code alone reports the older addonVersion, is not stale, and addonNote says so: it needs no restart. A stale editor is asked nothing but to quit: every other call to it is refused with staleNote, which names editor_launch restart, the upgrade command or a reconnect. port is the one the editor bridge is on; when that is not the one this server was configured with, portWanted names the configured one and portNote says why it moved and, when it was the server this one replaced, which pid kept it. A server replacing another of its project that holds the configured port waits for it to stand down and takes the port over, which takes a few seconds; bridgeHandover says so while it waits, and it moves only if that server has not let go within the wait. An editor that has connected and not yet greeted, which lasts a frame and longer while it imports, reports nothing about itself: greeting says so, addonIsStale is absent rather than guessed, and a restart asked then waits for the greeting to learn who opened it. startedByAnEditor is an editor another editor started, by Godot's own restart or the project manager, which has none of the arguments a server gave the one before it; startedByAnEditorNote says what that costs. An engine run that loads the editor addon to do one job and quit, such as a gate's godot --headless --import, an export or a script, is not taken as the editor: a process that greets without a server's mark has its command line read first, and while that is read identifying is true and connected false; one started with such an option is turned away, and turnedAway names the last one, its pid and the option. Every other call made while an editor is arriving, before its greeting or while it is looked up, waits up to ten seconds for it to settle rather than acting on connected as it reads in that window. serverVersion is the gdharness version of this server. bridgeAvailable says the editor bridge is listening; when it failed to start, startupError gives the error, and retryingBridge is true while this server tries again. announcedAt is the file where this server told editors of its project which port to dial. connectedAt is when the editor connected, and lastPongAt when it last answered this server's keep-alive ping. addonDigest is a hash of the editor addon's code, which addonIsStale compares with what this server ships. debugPort is the port of the editor's remote debugger, the one games it plays connect to. openedByAServer says a gdharness server started this editor, and syncsBreakpoints that it keeps its breakpoints when a debug session opens, which Godot otherwise clears. pendingRequests counts the requests sent to the editor and not yet answered, and queuedResources the files with writes waiting behind another write to the same file.",
13168
13223
  parameters: {},
13169
13224
  requires: []
13170
13225
  },
@@ -13518,7 +13573,7 @@ var init_tool_definitions = __esm(() => {
13518
13573
  minimum: 1,
13519
13574
  maximum: 600,
13520
13575
  ops: ["action", "key", "mouse_click", "joypad_button"],
13521
- description: "action, key, mouse_click, joypad_button: hold a whole press down for this many process frames and then let go, both inside the game, so a pour, a charge or a long press runs to a set length. A press, a frames wait and a release sent as three calls hold it for the time between the calls as well. The answer says held_frames. Not with pressed, and not on a wheel step. Default 1."
13576
+ description: "action, key, mouse_click, joypad_button: hold a whole press down for this many process frames and then let go, both inside the game, so a pour, a charge or a long press runs to a set length. A press, a frames wait and a release sent as three calls hold it for the time between the calls as well. The answer says held_frames, and under held_for the seconds the hold lasted and the physics_frames that ran in it: a process frame is no set time, and a headless game, drawing nothing, runs them far faster than the sixty physics ticks a second that _physics_process sees. Not with pressed, and not on a wheel step. Default 1."
13522
13577
  },
13523
13578
  strength: {
13524
13579
  type: "number",
@@ -39511,7 +39566,8 @@ async function renameSymbol(request, services) {
39511
39566
  };
39512
39567
  }
39513
39568
  if (newName === symbol) {
39514
- return { ok: false, reason: `${symbol} is already called ${newName}; nothing to rename.` };
39569
+ const moving = request.newScriptPath === null ? "" : " resource_edit move moves the script alone, with every path in the project naming it.";
39570
+ return { ok: false, reason: `${symbol} is already called ${newName}; nothing to rename.${moving}` };
39515
39571
  }
39516
39572
  const declaringPath = resourcePathOf(projectPath, request.scriptPath);
39517
39573
  if (declaringPath === null) {
@@ -45685,19 +45741,37 @@ function describeValue(value) {
45685
45741
  return VALUE_NAMES[typeof value] ?? typeof value;
45686
45742
  }
45687
45743
  function wrongTypes(spec, args) {
45688
- const complaints = [];
45689
- for (const [name, value] of Object.entries(args)) {
45690
- if (value === undefined || value === null) {
45691
- continue;
45744
+ return Object.entries(args).flatMap(([name, value]) => misshapen(spec.parameters[name], value, name));
45745
+ }
45746
+ function misshapen(schema, value, path) {
45747
+ if (!isPlainObject3(schema) || value === undefined || value === null) {
45748
+ return [];
45749
+ }
45750
+ const declared = schema["type"];
45751
+ const wanted = typeof declared === "string" ? [declared] : Array.isArray(declared) ? declared.filter((kind) => typeof kind === "string") : [];
45752
+ if (wanted.length > 0 && !wanted.some((kind) => isOfType(value, kind))) {
45753
+ return [`${path} as ${wanted.join(" or ")}, not ${describeValue(value)}`];
45754
+ }
45755
+ if (Array.isArray(value)) {
45756
+ return value.flatMap((element, index) => misshapen(schema["items"], element, `${path}[${index}]`));
45757
+ }
45758
+ const properties = schema["properties"];
45759
+ if (!isPlainObject3(properties) || !isPlainObject3(value)) {
45760
+ return [];
45761
+ }
45762
+ return Object.entries(value).flatMap(([field, held]) => {
45763
+ if (Object.hasOwn(properties, field)) {
45764
+ return misshapen(properties[field], held, `${path}.${field}`);
45692
45765
  }
45693
- const declared = spec.parameters[name]?.["type"];
45694
- const wanted = typeof declared === "string" ? [declared] : Array.isArray(declared) ? declared.filter((kind) => typeof kind === "string") : [];
45695
- if (wanted.length === 0 || wanted.some((kind) => isOfType(value, kind))) {
45696
- continue;
45766
+ if (schema["additionalProperties"] !== false) {
45767
+ return [];
45697
45768
  }
45698
- complaints.push(`${name} as ${wanted.join(" or ")}, not ${describeValue(value)}`);
45699
- }
45700
- return complaints;
45769
+ const fields = Object.keys(properties);
45770
+ const close = nearest(field, fields);
45771
+ return [
45772
+ `${path} with only the fields ${fields.join(", ")}, and ${field} is none of them${close.length === 0 ? "" : ` (the nearest is ${close[0]})`}`
45773
+ ];
45774
+ });
45701
45775
  }
45702
45776
  function unlistedValues(schema, value, path) {
45703
45777
  if (typeof schema !== "object" || schema === null) {
@@ -47291,6 +47365,12 @@ class GodotServer {
47291
47365
  return await editorOrEngine("create_animation", "writes");
47292
47366
  case "add_track":
47293
47367
  return await editorOrEngine("add_animation_track", "writes");
47368
+ case "set":
47369
+ return await editorOrEngine("set_animation", "writes");
47370
+ case "rename":
47371
+ return await editorOrEngine("rename_animation", "writes");
47372
+ case "remove":
47373
+ return await editorOrEngine("remove_animation", "writes");
47294
47374
  case "add_state":
47295
47375
  return await editorOrEngine("add_animation_state", "writes");
47296
47376
  default:
@@ -47573,34 +47653,8 @@ class GodotServer {
47573
47653
  }
47574
47654
  return { ok: true, value: { path, file } };
47575
47655
  }
47576
- gameArguments(args) {
47577
- if (args["args"] === undefined) {
47578
- return { ok: true, value: [] };
47579
- }
47580
- const given = readStringArray(args, "args");
47581
- if (given === undefined) {
47582
- return {
47583
- ok: false,
47584
- response: this.createErrorResponse("args must be a list of strings.", [
47585
- `Pass the game's own flags, such as ["--level=2"]`
47586
- ])
47587
- };
47588
- }
47589
- return { ok: true, value: given };
47590
- }
47591
47656
  engineArguments(args) {
47592
- if (args["engineArgs"] === undefined) {
47593
- return { ok: true, value: [] };
47594
- }
47595
- const given = readStringArray(args, "engineArgs");
47596
- if (given === undefined) {
47597
- return {
47598
- ok: false,
47599
- response: this.createErrorResponse("engineArgs must be a list of strings.", [
47600
- 'Pass engine flags, such as ["--verbose"] or ["--fixed-fps", "60"]'
47601
- ])
47602
- };
47603
- }
47657
+ const given = readStringArray(args, "engineArgs") ?? [];
47604
47658
  const checked = engineFlags(given);
47605
47659
  if (!checked.ok) {
47606
47660
  return { ok: false, response: this.createErrorResponse(checked.reason) };
@@ -48002,6 +48056,16 @@ class GodotServer {
48002
48056
  ...params
48003
48057
  } = contained.value;
48004
48058
  const written = await this.operation("set_import_options", params, project.value.path);
48059
+ const changed = written.ok ? written.payload["updated_options"] : null;
48060
+ if (written.ok && Array.isArray(changed) && changed.length === 0) {
48061
+ return this.answer({
48062
+ ...written,
48063
+ payload: {
48064
+ ...written.payload,
48065
+ note: "Not reimported: every option given already held that value, so the import file was not written."
48066
+ }
48067
+ });
48068
+ }
48005
48069
  if (!written.ok || args["reimport"] === false) {
48006
48070
  return this.answer(written.ok ? {
48007
48071
  ...written,
@@ -48088,6 +48152,13 @@ class GodotServer {
48088
48152
  const viaEditor = this.editorHasOpen(projectPath);
48089
48153
  const extra = {};
48090
48154
  const statusAsk = resourcePath === undefined ? { includeUpToDate: true } : { resourcePath };
48155
+ let behindElsewhere = [];
48156
+ if (resourcePath !== undefined) {
48157
+ const whole = await this.operation("get_import_status", {}, projectPath);
48158
+ if (whole.ok) {
48159
+ behindElsewhere = importStatuses(whole.payload).filter((one) => one.status !== "up_to_date" && one.status !== "missing_source" && one.status !== "not_imported" && !targets.includes(one.path)).map((one) => one.path);
48160
+ }
48161
+ }
48091
48162
  if (viaEditor) {
48092
48163
  const scan = await this.handleRescanFilesystem({ projectPath, timeoutMs });
48093
48164
  if (scan.isError === true) {
@@ -48169,6 +48240,16 @@ class GodotServer {
48169
48240
  groups.set(key, group);
48170
48241
  }
48171
48242
  const notReimported = [...groups.values()];
48243
+ if (behindElsewhere.length > 0) {
48244
+ const whole = await this.operation("get_import_status", { includeUpToDate: true }, projectPath);
48245
+ if (whole.ok) {
48246
+ const current = new Set(importStatuses(whole.payload).filter((one) => one.status === "up_to_date").map((one) => one.path));
48247
+ const alsoImported = behindElsewhere.filter((path) => current.has(path));
48248
+ if (alsoImported.length > 0) {
48249
+ extra["alsoImported"] = alsoImported;
48250
+ }
48251
+ }
48252
+ }
48172
48253
  return {
48173
48254
  ok: true,
48174
48255
  payload: {
@@ -49859,10 +49940,7 @@ class GodotServer {
49859
49940
  if (exported !== null && readBoolean(args, "profile") === true) {
49860
49941
  return this.createErrorResponse("A profile is read through the debugger, and an exported build is started without one, since a release build quits when given --remote-debug. Profile the project without executable.");
49861
49942
  }
49862
- const given = this.gameArguments(args);
49863
- if (!given.ok) {
49864
- return given.response;
49865
- }
49943
+ const given = readStringArray(args, "args") ?? [];
49866
49944
  const flags = this.engineArguments(args);
49867
49945
  if (!flags.ok) {
49868
49946
  return flags.response;
@@ -49894,7 +49972,7 @@ class GodotServer {
49894
49972
  const scanned = await this.afterTheImport(project.value.path, waited, imported);
49895
49973
  const sceneArgument = sceneToRun?.ok ? sceneToRun.relativePath : null;
49896
49974
  if (op === "check") {
49897
- return await this.checkBoot(engine.value, project.value.path, sceneArgument, args, given.value, scanned, asked.value, flags.value);
49975
+ return await this.checkBoot(engine.value, project.value.path, sceneArgument, args, given, scanned, asked.value, flags.value);
49898
49976
  }
49899
49977
  await this.pickUpWhatTheEditorIsPlaying();
49900
49978
  let ended = null;
@@ -49923,14 +50001,14 @@ class GodotServer {
49923
50001
  const silent = resolveSilent(args["silent"]) && !headless;
49924
50002
  const silentOnlyHere = silent && !editorPlaysHeadless(project.value.file);
49925
50003
  const profiled = readBoolean(args, "profile") === true;
49926
- if (exported === null && this.godotBridge.isConnected() && editorWouldPlay && given.value.length === 0 && flags.value.length === 0 && !needsItsOwnProcess(asked.value) && !silentOnlyHere) {
50004
+ if (exported === null && this.godotBridge.isConnected() && editorWouldPlay && given.length === 0 && flags.value.length === 0 && !needsItsOwnProcess(asked.value) && !silentOnlyHere) {
49927
50005
  return await this.playThroughEditor(sceneArgument, refreshed.value, scanned, project.value.path, alreadyPlaying, runtimeWaitMs, ended, profiled);
49928
50006
  }
49929
50007
  const cmdArgs = runArguments({
49930
50008
  projectPath: exported === null ? project.value.path : null,
49931
50009
  headless,
49932
50010
  scene: sceneArgument,
49933
- userArgs: given.value,
50011
+ userArgs: given,
49934
50012
  engineArgs: flags.value,
49935
50013
  silent
49936
50014
  });
@@ -49944,7 +50022,7 @@ class GodotServer {
49944
50022
  started.announcedBefore = alreadyPlaying;
49945
50023
  started.bootScene = runtimeWaitMs.scene;
49946
50024
  this.activeProcess = started;
49947
- const spawnedInstead = exported !== null ? " An exported build is started without a debugger, since a release build quits when given one, so breakpoints and debug_state do not reach it." : this.godotBridge.isConnected() && editorWouldPlay && (given.value.length > 0 || flags.value.length > 0) ? ` The editor cannot be handed arguments for a game it plays, so this one was started here.${OWN_DEBUGGER}` : this.godotBridge.isConnected() && editorWouldPlay && needsItsOwnProcess(asked.value) ? ` The editor plays a game with its own environment, so a run given one was started here.${OWN_DEBUGGER}` : this.godotBridge.isConnected() && editorWouldPlay && silentOnlyHere ? " The editor cannot play a game silent, which takes an engine flag, so this one was " + `started here, silent as every run is unless asked otherwise, and silent: false plays it through the editor, with sound.${OWN_DEBUGGER}` : "";
50025
+ const spawnedInstead = exported !== null ? " An exported build is started without a debugger, since a release build quits when given one, so breakpoints and debug_state do not reach it." : this.godotBridge.isConnected() && editorWouldPlay && (given.length > 0 || flags.value.length > 0) ? ` The editor cannot be handed arguments for a game it plays, so this one was started here.${OWN_DEBUGGER}` : this.godotBridge.isConnected() && editorWouldPlay && needsItsOwnProcess(asked.value) ? ` The editor plays a game with its own environment, so a run given one was started here.${OWN_DEBUGGER}` : this.godotBridge.isConnected() && editorWouldPlay && silentOnlyHere ? " The editor cannot play a game silent, which takes an engine flag, so this one was " + `started here, silent as every run is unless asked otherwise, and silent: false plays it through the editor, with sound.${OWN_DEBUGGER}` : "";
49948
50026
  const endedForThis = endedToStartThis(ended);
49949
50027
  const stranded = wereHereFirst.filter((one) => one.pid !== ended?.pid && alive(one.pid));
49950
50028
  const handed = this.dapHoldingBreakpointsOf(project.value.path).breakpointsHeld();
@@ -49957,7 +50035,7 @@ class GodotServer {
49957
50035
  executable: exported?.ok === true ? exported.relativePath : undefined,
49958
50036
  scene: exported !== null ? undefined : sceneArgument === null ? mainSceneOf(project.value.file) : `res://${sceneArgument}`,
49959
50037
  arguments: cmdArgs,
49960
- argsNote: engineFlagsNote(given.value),
50038
+ argsNote: engineFlagsNote(given),
49961
50039
  transcript: started.transcript,
49962
50040
  breakpoints: started.keeper === undefined || handed.length === 0 ? undefined : this.breakpointsAsProjectSpells(project.value.path, handed),
49963
50041
  profile: profileOnStart(profiled, "gdharness", runtimeAddonRegistered(project.value.path)),
@@ -49967,7 +50045,7 @@ class GodotServer {
49967
50045
  endedPreviousRun: endedPreviousRun(ended),
49968
50046
  previousRunLeft: previousRunLeft(ended),
49969
50047
  ...previousRunHow(ended),
49970
- runtime: exported !== null ? undefined : await this.runtimeUp(project.value.path, alreadyPlaying, runtimeWaitMs, given.value.length > 0),
50048
+ runtime: exported !== null ? undefined : await this.runtimeUp(project.value.path, alreadyPlaying, runtimeWaitMs, given.length > 0),
49971
50049
  message: `Use editor_output for what it prints and editor_run stop to end it.${started.keeper !== undefined && handed.length > 0 ? " It stops at the lines under breakpoints, and debug_state stack reads where it is held." : ""}${spawnedInstead}${endedForThis}${alsoRunning}`
49972
50050
  });
49973
50051
  }