gdharness 1.1.39 → 1.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/cli.js
CHANGED
|
@@ -17399,7 +17399,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17399
17399
|
},
|
|
17400
17400
|
{
|
|
17401
17401
|
name: "project_settings",
|
|
17402
|
-
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 from the file (named under editorAdopted), 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, one on an addon from before this, which still holds the old values until editor_launch restart. An enabled plugin's code still loads on the editor's next start.",
|
|
17402
|
+
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, one on an addon from before this, which still holds the old values until editor_launch restart. An enabled plugin's code still loads on the editor's next start.",
|
|
17403
17403
|
parameters: {
|
|
17404
17404
|
projectPath: PROJECT_PATH,
|
|
17405
17405
|
setting: { type: "string", description: 'Setting path, such as "display/window/size/viewport_width".' },
|
|
@@ -17769,7 +17769,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17769
17769
|
},
|
|
17770
17770
|
{
|
|
17771
17771
|
name: "script_edit",
|
|
17772
|
-
description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none. A new name already taken is refused with nothing written, a member's included when a class inheriting it already uses the name in code, as a local or a parameter. changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene, text, or ignored for a file under a .gdignore directory, which is never changed) and, where it is not plain, why: a string that is the old name whole, such as find_children's type or a call's method name, which nothing renames or compiles and which is listed first; a node named like the class; a call on a value whose type the analyser could not tell. A member rename answers under languageServer how many requests it made and how long they took. A comment, documentation line, string or text file line with nothing more to say is given under leftAloneInProse by file, kind and line instead, and code that is certainly another symbol of the same name, a bare name in a file where nothing inherits the member or one the language server resolved to another declaration, under leftAloneOtherSymbols as each why with the files and lines it covers. summary.leftAlone counts each of the three lists beside the total. When those two grouped lists run past 300 lines, they are written with each line's text to a file under the project's .godot directory instead, and leftAloneDetail names the file and counts what is in it. Read both before calling the rename done; nothing in them was changed. Afterwards an open editor scans the changed files and reloads every changed script, which is also the compile check, and its answer comes back under editor; with no editor the class cache is rebuilt and the changed scripts are compiled in a fresh engine, under classCache and compiled. written is true once the files are written, and ok is false when what came after the write failed: the files are left changed, and note says so.",
|
|
17772
|
+
description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none. A new name already taken is refused with nothing written, a member's included when a class inheriting it already uses the name in code, as a local or a parameter. changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene, text, or ignored for a file under a .gdignore directory, which is never changed) and, where it is not plain, why: a string that is the old name whole, such as find_children's type or a call's method name, which nothing renames or compiles and which is listed first; a node named like the class; a call on a value whose type the analyser could not tell. A member rename answers under languageServer how many requests it made and how long they took. A comment, documentation line, string or text file line with nothing more to say is given under leftAloneInProse by file, kind and line instead, and code that is certainly another symbol of the same name, a bare name in a file where nothing inherits the member or one the language server resolved to another declaration, under leftAloneOtherSymbols as each why with the files and lines it covers. summary.leftAlone counts each of the three lists beside the total. When those two grouped lists run past 300 lines, they are written with each line's text to a file under the project's .godot directory instead, of which the newest ten are kept, and leftAloneDetail names the file and counts what is in it. Read both before calling the rename done; nothing in them was changed. Afterwards an open editor scans the changed files and reloads every changed script, which is also the compile check, and its answer comes back under editor; with no editor the class cache is rebuilt and the changed scripts are compiled in a fresh engine, under classCache and compiled. written is true once the files are written, and ok is false when what came after the write failed: the files are left changed, and note says so.",
|
|
17773
17773
|
parameters: {
|
|
17774
17774
|
projectPath: PROJECT_PATH,
|
|
17775
17775
|
scriptPath: SCRIPT_PATH,
|
|
@@ -40178,7 +40178,7 @@ function planMemberRename(args) {
|
|
|
40178
40178
|
} else if (occurrence.kind === "doc" && docLinkAt(script.text, one.offset) !== null) {
|
|
40179
40179
|
plan.edit(one.file, one.offset, "doc link");
|
|
40180
40180
|
} else {
|
|
40181
|
-
plan.mention(one.file, script.lines, one.offset, occurrence.kind, `the language server resolved this to the ${kind === "func" ? "method" : "member"},
|
|
40181
|
+
plan.mention(one.file, script.lines, one.offset, occurrence.kind, `the language server resolved this word to the ${kind === "func" ? "method" : "member"}, but it is inside ${occurrence.kind === "string" ? "a string" : occurrence.kind === "nodePath" ? "a node path" : "a comment"}, which no rename changes: read it, and change the word by hand if it names the ${kind === "func" ? "method" : "member"}`);
|
|
40182
40182
|
}
|
|
40183
40183
|
}
|
|
40184
40184
|
for (const script of scripts.values()) {
|
|
@@ -41977,6 +41977,25 @@ function changedSettings(before, after) {
|
|
|
41977
41977
|
const names = new Set([...before.keys(), ...after.keys()]);
|
|
41978
41978
|
return [...names].filter((name) => JSON.stringify(before.get(name)) !== JSON.stringify(after.get(name))).sort();
|
|
41979
41979
|
}
|
|
41980
|
+
function settingsNamedBy(op, args) {
|
|
41981
|
+
const text = (key) => readString(args, key) ?? "";
|
|
41982
|
+
switch (op) {
|
|
41983
|
+
case "set":
|
|
41984
|
+
return text("setting") === "" ? [] : [text("setting")];
|
|
41985
|
+
case "add_autoload":
|
|
41986
|
+
case "remove_autoload":
|
|
41987
|
+
return text("name") === "" ? [] : [`autoload/${text("name")}`];
|
|
41988
|
+
case "set_main_scene":
|
|
41989
|
+
return ["application/run/main_scene"];
|
|
41990
|
+
case "add_input_action":
|
|
41991
|
+
return text("actionName") === "" ? [] : [`input/${text("actionName")}`];
|
|
41992
|
+
case "enable_plugin":
|
|
41993
|
+
case "disable_plugin":
|
|
41994
|
+
return ["editor_plugins/enabled"];
|
|
41995
|
+
default:
|
|
41996
|
+
return [];
|
|
41997
|
+
}
|
|
41998
|
+
}
|
|
41980
41999
|
function scriptErrorsNote(errors) {
|
|
41981
42000
|
const causes = new Map;
|
|
41982
42001
|
for (const error of errors) {
|
|
@@ -43199,7 +43218,8 @@ class GodotServer {
|
|
|
43199
43218
|
if (AUDIO_BUS_OPS.has(op)) {
|
|
43200
43219
|
return this.jsonTextResponse({ ...answer, ...await this.editorTakes("adopt_audio_bus_layout", {}) });
|
|
43201
43220
|
}
|
|
43202
|
-
const
|
|
43221
|
+
const diffed = changedSettings(before, this.settingKeysOf(projectPath));
|
|
43222
|
+
const changed = diffed === null ? null : [...new Set([...diffed, ...settingsNamedBy(op, args)])].sort();
|
|
43203
43223
|
if (changed === null) {
|
|
43204
43224
|
return this.jsonTextResponse({
|
|
43205
43225
|
...answer,
|
|
@@ -46172,7 +46192,7 @@ class GodotServer {
|
|
|
46172
46192
|
const folded = asParams(outcome.report["leftAloneDetail"]);
|
|
46173
46193
|
outcome.report["leftAloneDetail"] = {
|
|
46174
46194
|
file,
|
|
46175
|
-
note: `Too many lines were left alone to list here, and none of them is a use: every comment, documentation line, string and text file line that only shares the word, and every other symbol of the same name, is in ${file} with its text.`,
|
|
46195
|
+
note: `Too many lines were left alone to list here, and none of them is a use: every comment, documentation line, string and text file line that only shares the word, and every other symbol of the same name, is in ${file} with its text. The newest ten of these files are kept and older ones removed as new ones are written.`,
|
|
46176
46196
|
...folded
|
|
46177
46197
|
};
|
|
46178
46198
|
}
|
|
@@ -288,6 +288,10 @@ static func _areas_of(drawn: Array[Node]) -> Array[Rect2]:
|
|
|
288
288
|
## the click scrolls it into view first: what is drawn over its place now is not what it will land
|
|
289
289
|
## under. Judged not covered at all instead, a button below the fold of a roster that a full-screen
|
|
290
290
|
## page covered was picked over the ones in view, scrolled up under the page and pressed there.
|
|
291
|
+
## Whatever else the scroll holds moves with it and is judged where it goes. Judged where it sat, the
|
|
292
|
+
## card at the top of a tray scrolled down was drawn over a button above the view, because a later
|
|
293
|
+
## card is drawn over an earlier one, and a button below the view was passed by the same card only
|
|
294
|
+
## because the cards beside the bottom edge come before it.
|
|
291
295
|
##
|
|
292
296
|
## [param areas] holds the box around each of [param drawn], so everything whose box misses the
|
|
293
297
|
## point is passed over before anything costlier is asked of it. A window's box is in the space of
|
|
@@ -295,7 +299,8 @@ static func _areas_of(drawn: Array[Node]) -> Array[Rect2]:
|
|
|
295
299
|
## so a window is judged by [method _window_over] instead.
|
|
296
300
|
static func _cover_of(target: Control, drawn: Array[Node], areas: Array[Rect2]) -> Node:
|
|
297
301
|
var viewport: Viewport = target.get_viewport()
|
|
298
|
-
var
|
|
302
|
+
var moves: Dictionary[ScrollContainer, Vector2] = _scrolls_for(target)
|
|
303
|
+
var point: Vector2 = _centre_of(target) + _moved_by(target, moves)
|
|
299
304
|
var layer: int = _layer_of(target)
|
|
300
305
|
for at: int in drawn.size():
|
|
301
306
|
var other: Node = drawn[at]
|
|
@@ -304,9 +309,11 @@ static func _cover_of(target: Control, drawn: Array[Node], areas: Array[Rect2])
|
|
|
304
309
|
if _window_over(target, point, window):
|
|
305
310
|
return window
|
|
306
311
|
continue
|
|
307
|
-
if not areas[at].has_point(point):
|
|
308
|
-
continue
|
|
309
312
|
var control: Control = other
|
|
313
|
+
# The point where this control is now, which is where the scroll will carry it to the point.
|
|
314
|
+
var before: Vector2 = point - _moved_by(control, moves)
|
|
315
|
+
if not areas[at].has_point(before):
|
|
316
|
+
continue
|
|
310
317
|
if control == target or control.is_ancestor_of(target) or target.is_ancestor_of(control):
|
|
311
318
|
continue
|
|
312
319
|
if control.get_viewport() != viewport:
|
|
@@ -314,18 +321,34 @@ static func _cover_of(target: Control, drawn: Array[Node], areas: Array[Rect2])
|
|
|
314
321
|
var its_layer: int = _layer_of(control)
|
|
315
322
|
if its_layer < layer or (its_layer == layer and not control.is_greater_than(target)):
|
|
316
323
|
continue
|
|
317
|
-
if _holds(control,
|
|
324
|
+
if _holds(control, before) and not _clipped_away(control, point, moves):
|
|
318
325
|
return control
|
|
319
326
|
return null
|
|
320
327
|
|
|
321
328
|
|
|
322
|
-
##
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
+
## [param target]'s centre in its viewport, where it is now.
|
|
330
|
+
static func _centre_of(target: Control) -> Vector2:
|
|
331
|
+
return target.get_global_transform_with_canvas() * (target.size * 0.5)
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
## How far the click moves what each ScrollContainer holding [param target] holds, to bring it into
|
|
335
|
+
## view: empty when no container clips it away, as nothing is scrolled then.
|
|
336
|
+
static func _scrolls_for(target: Control) -> Dictionary[ScrollContainer, Vector2]:
|
|
337
|
+
var none: Dictionary[ScrollContainer, Vector2] = {}
|
|
338
|
+
var centre: Vector2 = _centre_of(target)
|
|
339
|
+
if not _clipped_away(target, centre, none):
|
|
340
|
+
return none
|
|
341
|
+
return _where_it_lands(target, centre)
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
## How far the scrolls in [param moves] carry [param node]: the sum over the containers holding it,
|
|
345
|
+
## and nothing for a container itself, which stays where it is while what it holds moves.
|
|
346
|
+
static func _moved_by(node: Node, moves: Dictionary[ScrollContainer, Vector2]) -> Vector2:
|
|
347
|
+
var moved: Vector2 = Vector2.ZERO
|
|
348
|
+
for holder: ScrollContainer in moves:
|
|
349
|
+
if holder.is_ancestor_of(node):
|
|
350
|
+
moved += moves[holder]
|
|
351
|
+
return moved
|
|
329
352
|
|
|
330
353
|
|
|
331
354
|
## Whether the embedded [param window] is drawn over [param point], [param target]'s centre in its
|
|
@@ -366,14 +389,15 @@ static func _holds(control: Control, point: Vector2) -> bool:
|
|
|
366
389
|
return Rect2(Vector2.ZERO, control.size).has_point(placed.affine_inverse() * point)
|
|
367
390
|
|
|
368
391
|
|
|
369
|
-
##
|
|
370
|
-
## view:
|
|
371
|
-
## first, which is how one brings a control into view. A target larger than a
|
|
372
|
-
## in it. Only a ScrollContainer, because that is all a click scrolls: another
|
|
373
|
-
## what it holds, a collapsed section for one, leaves the target where it is.
|
|
374
|
-
static func _where_it_lands(target: Control, point: Vector2) -> Vector2:
|
|
392
|
+
## How far each ScrollContainer holding [param target] moves what it holds once the click has
|
|
393
|
+
## scrolled [param target], centred at [param point], into view: as little as puts the whole of it
|
|
394
|
+
## inside each, innermost first, which is how one brings a control into view. A target larger than a
|
|
395
|
+
## container is centred in it. Only a ScrollContainer, because that is all a click scrolls: another
|
|
396
|
+
## container clipping what it holds, a collapsed section for one, leaves the target where it is.
|
|
397
|
+
static func _where_it_lands(target: Control, point: Vector2) -> Dictionary[ScrollContainer, Vector2]:
|
|
375
398
|
var drawn: Transform2D = target.get_global_transform_with_canvas()
|
|
376
399
|
var half: Vector2 = (drawn * Rect2(Vector2.ZERO, target.size)).size * 0.5
|
|
400
|
+
var moves: Dictionary[ScrollContainer, Vector2] = {}
|
|
377
401
|
var landed: Vector2 = point
|
|
378
402
|
var walk: Node = target.get_parent()
|
|
379
403
|
while walk != null and not (walk is Viewport):
|
|
@@ -382,12 +406,15 @@ static func _where_it_lands(target: Control, point: Vector2) -> Vector2:
|
|
|
382
406
|
var shown: Rect2 = holder.get_global_transform_with_canvas() * Rect2(Vector2.ZERO, holder.size)
|
|
383
407
|
var low: Vector2 = shown.position + half
|
|
384
408
|
var high: Vector2 = shown.end - half
|
|
385
|
-
|
|
409
|
+
var next: Vector2 = Vector2(
|
|
386
410
|
shown.get_center().x if low.x > high.x else clampf(landed.x, low.x, high.x),
|
|
387
411
|
shown.get_center().y if low.y > high.y else clampf(landed.y, low.y, high.y)
|
|
388
412
|
)
|
|
413
|
+
if next != landed:
|
|
414
|
+
moves[holder] = next - landed
|
|
415
|
+
landed = next
|
|
389
416
|
walk = walk.get_parent()
|
|
390
|
-
return
|
|
417
|
+
return moves
|
|
391
418
|
|
|
392
419
|
|
|
393
420
|
## Whether a click could not reach [param target] however it scrolled: its centre, where the click
|
|
@@ -395,8 +422,9 @@ static func _where_it_lands(target: Control, point: Vector2) -> Vector2:
|
|
|
395
422
|
## container the click does not scroll. A drawer parked off the side of the screen, or anything
|
|
396
423
|
## outside the 64 by 64 viewport of a game with no window, was listed among the controls on screen.
|
|
397
424
|
static func _off_screen(target: Control) -> bool:
|
|
398
|
-
var
|
|
399
|
-
|
|
425
|
+
var moves: Dictionary[ScrollContainer, Vector2] = _scrolls_for(target)
|
|
426
|
+
var point: Vector2 = _centre_of(target) + _moved_by(target, moves)
|
|
427
|
+
if _clipped_away(target, point, moves) or not target.get_viewport().get_visible_rect().has_point(point):
|
|
400
428
|
return true
|
|
401
429
|
var reached: Dictionary = Screen.reach(target.get_viewport(), point)
|
|
402
430
|
var viewport: Viewport = reached["viewport"]
|
|
@@ -404,16 +432,19 @@ static func _off_screen(target: Control) -> bool:
|
|
|
404
432
|
return not viewport.get_visible_rect().has_point(there)
|
|
405
433
|
|
|
406
434
|
|
|
407
|
-
## Whether a container clipping what it holds cuts [param point] off from [param control]
|
|
435
|
+
## Whether a container clipping what it holds cuts [param point] off from [param control], once the
|
|
436
|
+
## scrolls in [param moves] have carried each container wherever they carry it.
|
|
408
437
|
##
|
|
409
438
|
## Only up to the viewport [param control] is in. A dialog is a window, and the containers the game
|
|
410
439
|
## added it under are in another space: judged against a clipping one of those, every button of a
|
|
411
440
|
## confirmation was refused as off the screen while it sat in plain view.
|
|
412
|
-
static func _clipped_away(
|
|
441
|
+
static func _clipped_away(
|
|
442
|
+
control: Control, point: Vector2, moves: Dictionary[ScrollContainer, Vector2]
|
|
443
|
+
) -> bool:
|
|
413
444
|
var walk: Node = control.get_parent()
|
|
414
445
|
while walk != null and not (walk is Viewport):
|
|
415
446
|
var holder: Control = walk as Control
|
|
416
|
-
if holder != null and holder.clip_contents and not _holds(holder, point):
|
|
447
|
+
if holder != null and holder.clip_contents and not _holds(holder, point - _moved_by(holder, moves)):
|
|
417
448
|
return true
|
|
418
449
|
walk = walk.get_parent()
|
|
419
450
|
return false
|
package/build/index.js
CHANGED
|
@@ -30900,7 +30900,7 @@ function planMemberRename(args) {
|
|
|
30900
30900
|
} else if (occurrence.kind === "doc" && docLinkAt(script.text, one.offset) !== null) {
|
|
30901
30901
|
plan.edit(one.file, one.offset, "doc link");
|
|
30902
30902
|
} else {
|
|
30903
|
-
plan.mention(one.file, script.lines, one.offset, occurrence.kind, `the language server resolved this to the ${kind === "func" ? "method" : "member"},
|
|
30903
|
+
plan.mention(one.file, script.lines, one.offset, occurrence.kind, `the language server resolved this word to the ${kind === "func" ? "method" : "member"}, but it is inside ${occurrence.kind === "string" ? "a string" : occurrence.kind === "nodePath" ? "a node path" : "a comment"}, which no rename changes: read it, and change the word by hand if it names the ${kind === "func" ? "method" : "member"}`);
|
|
30904
30904
|
}
|
|
30905
30905
|
}
|
|
30906
30906
|
for (const script of scripts.values()) {
|
|
@@ -32820,7 +32820,7 @@ var TOOL_SPECS = [
|
|
|
32820
32820
|
},
|
|
32821
32821
|
{
|
|
32822
32822
|
name: "project_settings",
|
|
32823
|
-
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 from the file (named under editorAdopted), 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, one on an addon from before this, which still holds the old values until editor_launch restart. An enabled plugin's code still loads on the editor's next start.",
|
|
32823
|
+
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, one on an addon from before this, which still holds the old values until editor_launch restart. An enabled plugin's code still loads on the editor's next start.",
|
|
32824
32824
|
parameters: {
|
|
32825
32825
|
projectPath: PROJECT_PATH,
|
|
32826
32826
|
setting: { type: "string", description: 'Setting path, such as "display/window/size/viewport_width".' },
|
|
@@ -33190,7 +33190,7 @@ var TOOL_SPECS = [
|
|
|
33190
33190
|
},
|
|
33191
33191
|
{
|
|
33192
33192
|
name: "script_edit",
|
|
33193
|
-
description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none. A new name already taken is refused with nothing written, a member's included when a class inheriting it already uses the name in code, as a local or a parameter. changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene, text, or ignored for a file under a .gdignore directory, which is never changed) and, where it is not plain, why: a string that is the old name whole, such as find_children's type or a call's method name, which nothing renames or compiles and which is listed first; a node named like the class; a call on a value whose type the analyser could not tell. A member rename answers under languageServer how many requests it made and how long they took. A comment, documentation line, string or text file line with nothing more to say is given under leftAloneInProse by file, kind and line instead, and code that is certainly another symbol of the same name, a bare name in a file where nothing inherits the member or one the language server resolved to another declaration, under leftAloneOtherSymbols as each why with the files and lines it covers. summary.leftAlone counts each of the three lists beside the total. When those two grouped lists run past 300 lines, they are written with each line's text to a file under the project's .godot directory instead, and leftAloneDetail names the file and counts what is in it. Read both before calling the rename done; nothing in them was changed. Afterwards an open editor scans the changed files and reloads every changed script, which is also the compile check, and its answer comes back under editor; with no editor the class cache is rebuilt and the changed scripts are compiled in a fresh engine, under classCache and compiled. written is true once the files are written, and ok is false when what came after the write failed: the files are left changed, and note says so.",
|
|
33193
|
+
description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none. A new name already taken is refused with nothing written, a member's included when a class inheriting it already uses the name in code, as a local or a parameter. changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene, text, or ignored for a file under a .gdignore directory, which is never changed) and, where it is not plain, why: a string that is the old name whole, such as find_children's type or a call's method name, which nothing renames or compiles and which is listed first; a node named like the class; a call on a value whose type the analyser could not tell. A member rename answers under languageServer how many requests it made and how long they took. A comment, documentation line, string or text file line with nothing more to say is given under leftAloneInProse by file, kind and line instead, and code that is certainly another symbol of the same name, a bare name in a file where nothing inherits the member or one the language server resolved to another declaration, under leftAloneOtherSymbols as each why with the files and lines it covers. summary.leftAlone counts each of the three lists beside the total. When those two grouped lists run past 300 lines, they are written with each line's text to a file under the project's .godot directory instead, of which the newest ten are kept, and leftAloneDetail names the file and counts what is in it. Read both before calling the rename done; nothing in them was changed. Afterwards an open editor scans the changed files and reloads every changed script, which is also the compile check, and its answer comes back under editor; with no editor the class cache is rebuilt and the changed scripts are compiled in a fresh engine, under classCache and compiled. written is true once the files are written, and ok is false when what came after the write failed: the files are left changed, and note says so.",
|
|
33194
33194
|
parameters: {
|
|
33195
33195
|
projectPath: PROJECT_PATH,
|
|
33196
33196
|
scriptPath: SCRIPT_PATH,
|
|
@@ -34517,6 +34517,25 @@ function changedSettings(before, after) {
|
|
|
34517
34517
|
const names = new Set([...before.keys(), ...after.keys()]);
|
|
34518
34518
|
return [...names].filter((name) => JSON.stringify(before.get(name)) !== JSON.stringify(after.get(name))).sort();
|
|
34519
34519
|
}
|
|
34520
|
+
function settingsNamedBy(op, args) {
|
|
34521
|
+
const text = (key) => readString(args, key) ?? "";
|
|
34522
|
+
switch (op) {
|
|
34523
|
+
case "set":
|
|
34524
|
+
return text("setting") === "" ? [] : [text("setting")];
|
|
34525
|
+
case "add_autoload":
|
|
34526
|
+
case "remove_autoload":
|
|
34527
|
+
return text("name") === "" ? [] : [`autoload/${text("name")}`];
|
|
34528
|
+
case "set_main_scene":
|
|
34529
|
+
return ["application/run/main_scene"];
|
|
34530
|
+
case "add_input_action":
|
|
34531
|
+
return text("actionName") === "" ? [] : [`input/${text("actionName")}`];
|
|
34532
|
+
case "enable_plugin":
|
|
34533
|
+
case "disable_plugin":
|
|
34534
|
+
return ["editor_plugins/enabled"];
|
|
34535
|
+
default:
|
|
34536
|
+
return [];
|
|
34537
|
+
}
|
|
34538
|
+
}
|
|
34520
34539
|
var STALLED_AFTER_MS = 30000;
|
|
34521
34540
|
var DEPENDED_FAILED = "Failed to compile depended scripts";
|
|
34522
34541
|
function scriptErrorsNote(errors) {
|
|
@@ -35773,7 +35792,8 @@ class GodotServer {
|
|
|
35773
35792
|
if (AUDIO_BUS_OPS.has(op)) {
|
|
35774
35793
|
return this.jsonTextResponse({ ...answer, ...await this.editorTakes("adopt_audio_bus_layout", {}) });
|
|
35775
35794
|
}
|
|
35776
|
-
const
|
|
35795
|
+
const diffed = changedSettings(before, this.settingKeysOf(projectPath));
|
|
35796
|
+
const changed = diffed === null ? null : [...new Set([...diffed, ...settingsNamedBy(op, args)])].sort();
|
|
35777
35797
|
if (changed === null) {
|
|
35778
35798
|
return this.jsonTextResponse({
|
|
35779
35799
|
...answer,
|
|
@@ -38746,7 +38766,7 @@ class GodotServer {
|
|
|
38746
38766
|
const folded = asParams(outcome.report["leftAloneDetail"]);
|
|
38747
38767
|
outcome.report["leftAloneDetail"] = {
|
|
38748
38768
|
file,
|
|
38749
|
-
note: `Too many lines were left alone to list here, and none of them is a use: every comment, documentation line, string and text file line that only shares the word, and every other symbol of the same name, is in ${file} with its text.`,
|
|
38769
|
+
note: `Too many lines were left alone to list here, and none of them is a use: every comment, documentation line, string and text file line that only shares the word, and every other symbol of the same name, is in ${file} with its text. The newest ten of these files are kept and older ones removed as new ones are written.`,
|
|
38750
38770
|
...folded
|
|
38751
38771
|
};
|
|
38752
38772
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.41",
|
|
4
4
|
"mcpName": "io.github.Aureliolo/gdharness",
|
|
5
5
|
"description": "A harness for driving a Godot 4 project from an agent: editor addons, a runtime bridge into the running game, an MCP server in front of them, and a CLI that installs and diagnoses the Godot side.",
|
|
6
6
|
"type": "module",
|