gdharness 1.3.34 → 1.3.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cli.js +288 -59
- package/build/godot/addons/gdharness_editor/animation_reads.gd +17 -1
- package/build/godot/addons/gdharness_editor/reading.gd +10 -2
- package/build/godot/addons/gdharness_editor/scene_file.gd +12 -6
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +57 -0
- package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +16 -0
- package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +81 -4
- package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +3 -3
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +4 -2
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +59 -0
- package/build/godot/addons/gdharness_editor/tools/script_paths.gd +148 -0
- package/build/godot/addons/gdharness_editor/tools/script_paths.gd.uid +1 -0
- package/build/godot/addons/gdharness_runtime/reading.gd +10 -2
- package/build/godot/addons/gdharness_runtime/runtime_hover.gd +70 -0
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +223 -248
- package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +128 -5
- package/build/godot/addons/gdharness_runtime/runtime_screen.gd +107 -0
- package/build/godot/addons/gdharness_runtime/runtime_targets.gd +15 -1
- package/build/godot/addons/gdharness_runtime/runtime_waits.gd +8 -0
- package/build/godot/addons/gdharness_runtime/runtime_words.gd +22 -0
- package/build/godot/operations/animation_reads.gd +17 -1
- package/build/godot/operations/classdb_queries.gd +16 -0
- package/build/godot/operations/dependencies.gd +46 -4
- package/build/godot/operations/editor_tools.gd +5 -5
- package/build/godot/operations/gdscript_authoring.gd +7 -3
- package/build/godot/operations/input_actions.gd +105 -0
- package/build/godot/operations/project_diagnostics.gd +4 -0
- package/build/godot/operations/project_validation.gd +15 -0
- package/build/godot/operations/reading.gd +10 -2
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -8159,7 +8159,8 @@ function resolveWithinProject(projectPath, candidatePath, options = {}) {
|
|
|
8159
8159
|
}
|
|
8160
8160
|
if (withoutScheme.startsWith("/") || withoutScheme.startsWith("\\") || isAbsolute(withoutScheme)) {
|
|
8161
8161
|
const tail = withoutScheme.split(/[\\/]+/).filter((step) => step !== "" && !step.endsWith(":"));
|
|
8162
|
-
const
|
|
8162
|
+
const besideIt = isAbsolute(trimmed) && isWithinRoot(realAsFarAsItExists(dirname2(resolve(trimmed))), realAsFarAsItExists(root));
|
|
8163
|
+
const example = tail.slice(besideIt ? -1 : -2).join("/") || "scenes/main.tscn";
|
|
8163
8164
|
return {
|
|
8164
8165
|
ok: false,
|
|
8165
8166
|
reason: `Path '${trimmed}' is absolute and outside the project; give a path inside it, such as '${example}'.`
|
|
@@ -11712,7 +11713,16 @@ var init_whole_file = __esm(() => {
|
|
|
11712
11713
|
});
|
|
11713
11714
|
|
|
11714
11715
|
// src/engine-slots.ts
|
|
11715
|
-
import {
|
|
11716
|
+
import {
|
|
11717
|
+
closeSync as closeSync3,
|
|
11718
|
+
mkdirSync as mkdirSync3,
|
|
11719
|
+
openSync as openSync3,
|
|
11720
|
+
readFileSync as readFileSync7,
|
|
11721
|
+
rmSync as rmSync6,
|
|
11722
|
+
statSync as statSync6,
|
|
11723
|
+
watch,
|
|
11724
|
+
writeSync as writeSync2
|
|
11725
|
+
} from "node:fs";
|
|
11716
11726
|
import { availableParallelism as availableParallelism2, homedir as homedir2 } from "node:os";
|
|
11717
11727
|
import { join as join8, resolve as resolve4 } from "node:path";
|
|
11718
11728
|
import process7 from "node:process";
|
|
@@ -11746,14 +11756,62 @@ function machineSlots(asked = {
|
|
|
11746
11756
|
function nonEmpty(value) {
|
|
11747
11757
|
return value === undefined || value === "" ? undefined : value;
|
|
11748
11758
|
}
|
|
11759
|
+
|
|
11760
|
+
class FolderChanges {
|
|
11761
|
+
changed = false;
|
|
11762
|
+
wake = null;
|
|
11763
|
+
watcher;
|
|
11764
|
+
constructor(directory) {
|
|
11765
|
+
let watcher = null;
|
|
11766
|
+
try {
|
|
11767
|
+
watcher = watch(directory, () => {
|
|
11768
|
+
this.changed = true;
|
|
11769
|
+
this.wake?.();
|
|
11770
|
+
});
|
|
11771
|
+
watcher.on("error", () => {
|
|
11772
|
+
watcher?.close();
|
|
11773
|
+
});
|
|
11774
|
+
} catch {
|
|
11775
|
+
watcher = null;
|
|
11776
|
+
}
|
|
11777
|
+
this.watcher = watcher;
|
|
11778
|
+
}
|
|
11779
|
+
async next(lookMs, settleMs, signal) {
|
|
11780
|
+
if (!this.changed) {
|
|
11781
|
+
await new Promise((resolve) => {
|
|
11782
|
+
const done = () => {
|
|
11783
|
+
clearTimeout(timer);
|
|
11784
|
+
this.wake = null;
|
|
11785
|
+
signal?.removeEventListener("abort", done);
|
|
11786
|
+
resolve();
|
|
11787
|
+
};
|
|
11788
|
+
const timer = setTimeout(done, lookMs);
|
|
11789
|
+
this.wake = done;
|
|
11790
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
11791
|
+
});
|
|
11792
|
+
}
|
|
11793
|
+
if (this.changed && signal?.aborted !== true) {
|
|
11794
|
+
await delay3(settleMs, undefined, signal === undefined ? {} : { signal }).catch(() => {
|
|
11795
|
+
return;
|
|
11796
|
+
});
|
|
11797
|
+
}
|
|
11798
|
+
this.changed = false;
|
|
11799
|
+
}
|
|
11800
|
+
close() {
|
|
11801
|
+
this.watcher?.close();
|
|
11802
|
+
}
|
|
11803
|
+
}
|
|
11749
11804
|
function holderOf(content) {
|
|
11750
11805
|
try {
|
|
11751
11806
|
const parsed = JSON.parse(content);
|
|
11752
11807
|
if (typeof parsed !== "object" || parsed === null) {
|
|
11753
11808
|
return null;
|
|
11754
11809
|
}
|
|
11755
|
-
const { pid, started } = parsed;
|
|
11756
|
-
|
|
11810
|
+
const { pid, started, by } = parsed;
|
|
11811
|
+
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || typeof started !== "number") {
|
|
11812
|
+
return null;
|
|
11813
|
+
}
|
|
11814
|
+
return typeof by === "string" && by !== "" ? { pid, started, by } : { pid, started };
|
|
11757
11815
|
} catch {
|
|
11758
11816
|
return null;
|
|
11759
11817
|
}
|
|
@@ -11794,6 +11852,7 @@ class EngineSlots {
|
|
|
11794
11852
|
const began = Date.now();
|
|
11795
11853
|
let said = Number.NEGATIVE_INFINITY;
|
|
11796
11854
|
let mark;
|
|
11855
|
+
let changes;
|
|
11797
11856
|
try {
|
|
11798
11857
|
for (;; ) {
|
|
11799
11858
|
signal?.throwIfAborted();
|
|
@@ -11810,11 +11869,16 @@ class EngineSlots {
|
|
|
11810
11869
|
}
|
|
11811
11870
|
} else if (this.say !== undefined && this.held.size === 0 && now - began >= COMMAND_WAIT_SAID_MS && now - this.saidAt >= WAIT_SAID_MS) {
|
|
11812
11871
|
this.saidAt = now;
|
|
11813
|
-
this.say(slotWaitSaid(now - began, this.count, this.directory));
|
|
11872
|
+
this.say(slotWaitSaid(now - began, this.count, this.directory, this.holders()));
|
|
11814
11873
|
}
|
|
11815
|
-
|
|
11874
|
+
if (changes === undefined) {
|
|
11875
|
+
changes = new FolderChanges(this.directory);
|
|
11876
|
+
continue;
|
|
11877
|
+
}
|
|
11878
|
+
await changes.next(SLOT_LOOK_MS, SLOT_SETTLE_MS, signal);
|
|
11816
11879
|
}
|
|
11817
11880
|
} finally {
|
|
11881
|
+
changes?.close();
|
|
11818
11882
|
if (mark !== undefined && this.marks.delete(mark)) {
|
|
11819
11883
|
removeWhole(mark);
|
|
11820
11884
|
}
|
|
@@ -11846,6 +11910,18 @@ class EngineSlots {
|
|
|
11846
11910
|
this.marks.add(mark);
|
|
11847
11911
|
return mark;
|
|
11848
11912
|
}
|
|
11913
|
+
holders() {
|
|
11914
|
+
const found = [];
|
|
11915
|
+
for (let slot = 0;slot < this.count; slot += 1) {
|
|
11916
|
+
try {
|
|
11917
|
+
const holder = holderOf(readFileSync7(join8(this.directory, `${String(slot)}.lock`), "utf8"));
|
|
11918
|
+
if (holder !== null) {
|
|
11919
|
+
found.push(holder);
|
|
11920
|
+
}
|
|
11921
|
+
} catch {}
|
|
11922
|
+
}
|
|
11923
|
+
return found;
|
|
11924
|
+
}
|
|
11849
11925
|
releaseAll() {
|
|
11850
11926
|
for (const lock of this.held) {
|
|
11851
11927
|
this.release(lock);
|
|
@@ -11934,21 +12010,42 @@ function sayWaitsTo(say) {
|
|
|
11934
12010
|
function processSlots() {
|
|
11935
12011
|
ours ??= ownStart().then((started) => {
|
|
11936
12012
|
const chosen = machineSlots();
|
|
11937
|
-
|
|
12013
|
+
const holder = { pid: process7.pid, started, ...takenBy === undefined ? {} : { by: takenBy } };
|
|
12014
|
+
return new EngineSlots(chosen.directory, chosen.count, holder, (line) => {
|
|
11938
12015
|
saidTo?.(line);
|
|
11939
12016
|
});
|
|
11940
12017
|
});
|
|
11941
12018
|
return ours;
|
|
11942
12019
|
}
|
|
11943
|
-
function
|
|
12020
|
+
function nameSlotTaker(by) {
|
|
12021
|
+
takenBy = by;
|
|
12022
|
+
}
|
|
12023
|
+
function slotWaitSaid(waitedMs, count, directory, holders = []) {
|
|
11944
12024
|
const slots = count === 1 ? `the one engine slot on this machine (${directory}) is in use` : `all ${String(count)} engine slots on this machine (${directory}) are in use`;
|
|
11945
|
-
|
|
12025
|
+
const held = new Map;
|
|
12026
|
+
for (const holder of holders) {
|
|
12027
|
+
const known = held.get(holder.pid);
|
|
12028
|
+
held.set(holder.pid, { by: known?.by ?? holder.by, slots: (known?.slots ?? 0) + 1 });
|
|
12029
|
+
}
|
|
12030
|
+
const named = [...held].map(([pid, { by, slots: taken }]) => {
|
|
12031
|
+
const who = pid === process7.pid ? `this process (pid ${String(pid)})` : by === undefined ? `pid ${String(pid)}` : `${by} (pid ${String(pid)})`;
|
|
12032
|
+
return count === 1 ? who : `${String(taken)} by ${who}`;
|
|
12033
|
+
});
|
|
12034
|
+
const waiting = `Waiting${waitedMs >= 1000 ? ` ${String(Math.round(waitedMs / 1000))} s so far` : ""} for an engine: ${slots}`;
|
|
12035
|
+
if (named.length === 0) {
|
|
12036
|
+
return `${waiting}, by a gate or another tool, and the engine starts when one is given back.`;
|
|
12037
|
+
}
|
|
12038
|
+
if (count === 1) {
|
|
12039
|
+
return `${waiting}, by ${named.join(", ")}, and the engine starts when it is given back.`;
|
|
12040
|
+
}
|
|
12041
|
+
const list = named.length === 1 ? named.join("") : `${named.slice(0, -1).join(", ")} and ${named.at(-1) ?? ""}`;
|
|
12042
|
+
return `${waiting}: ${list}. The engine starts when one is given back.`;
|
|
11946
12043
|
}
|
|
11947
12044
|
async function slotForCall() {
|
|
11948
12045
|
const slots = await processSlots();
|
|
11949
12046
|
const progress = callProgress();
|
|
11950
12047
|
const lock = await slots.take(callSignal(), progress === undefined ? undefined : (waitedMs) => {
|
|
11951
|
-
progress(waitedMs / 1000, slotWaitSaid(waitedMs, slots.count, slots.directory));
|
|
12048
|
+
progress(waitedMs / 1000, slotWaitSaid(waitedMs, slots.count, slots.directory, slots.holders()));
|
|
11952
12049
|
});
|
|
11953
12050
|
return {
|
|
11954
12051
|
release: () => {
|
|
@@ -11964,7 +12061,7 @@ async function inASlot(body) {
|
|
|
11964
12061
|
held.release();
|
|
11965
12062
|
}
|
|
11966
12063
|
}
|
|
11967
|
-
var SLOTS_VARIABLE = "GODOT_ENGINE_SLOTS", SLOT_COUNT_VARIABLE = "GODOT_ENGINE_SLOT_COUNT", PROCESSORS_A_SLOT = 5, START_TOLERANCE_MS = 2000, UNWRITTEN_MS = 1e4,
|
|
12064
|
+
var SLOTS_VARIABLE = "GODOT_ENGINE_SLOTS", SLOT_COUNT_VARIABLE = "GODOT_ENGINE_SLOT_COUNT", PROCESSORS_A_SLOT = 5, START_TOLERANCE_MS = 2000, UNWRITTEN_MS = 1e4, SLOT_LOOK_MS = 1000, SLOT_SETTLE_MS = 50, WAIT_SAID_MS = 20000, COMMAND_WAIT_SAID_MS = 2000, START_READ_MS = 1e4, WAITING_FOLDER = "waiting", waitsMarked = 0, ours, saidTo, takenBy;
|
|
11968
12065
|
var init_engine_slots = __esm(() => {
|
|
11969
12066
|
init_alive();
|
|
11970
12067
|
init_call_signal();
|
|
@@ -12771,6 +12868,39 @@ function projectFiles(projectPath, extensions) {
|
|
|
12771
12868
|
function folderFiles(directory, extensions) {
|
|
12772
12869
|
return gdignored(directory) ? [] : filesBelow(directory, extensions);
|
|
12773
12870
|
}
|
|
12871
|
+
function underGdignore(projectPath, relative) {
|
|
12872
|
+
const folders = relative.split("/").slice(0, -1);
|
|
12873
|
+
for (let depth = 1;depth <= folders.length; depth += 1) {
|
|
12874
|
+
if (gdignored(join11(projectPath, ...folders.slice(0, depth)))) {
|
|
12875
|
+
return true;
|
|
12876
|
+
}
|
|
12877
|
+
}
|
|
12878
|
+
return false;
|
|
12879
|
+
}
|
|
12880
|
+
function steppedOverIn(directory) {
|
|
12881
|
+
if (gdignored(directory)) {
|
|
12882
|
+
return [{ folder: "", why: "gdignore" }];
|
|
12883
|
+
}
|
|
12884
|
+
const found = [];
|
|
12885
|
+
const visit = (at, prefix) => {
|
|
12886
|
+
for (const entry of readdirSync6(at, { withFileTypes: true })) {
|
|
12887
|
+
if (!entry.isDirectory() || skipped(entry.name)) {
|
|
12888
|
+
continue;
|
|
12889
|
+
}
|
|
12890
|
+
const spelled = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
|
|
12891
|
+
const path = join11(at, entry.name);
|
|
12892
|
+
if (gdignored(path)) {
|
|
12893
|
+
found.push({ folder: spelled, why: "gdignore" });
|
|
12894
|
+
} else if (installedByUs(path)) {
|
|
12895
|
+
found.push({ folder: spelled, why: "gdharness" });
|
|
12896
|
+
} else {
|
|
12897
|
+
visit(path, spelled);
|
|
12898
|
+
}
|
|
12899
|
+
}
|
|
12900
|
+
};
|
|
12901
|
+
visit(directory, "");
|
|
12902
|
+
return found.sort((a, b) => a.folder.localeCompare(b.folder));
|
|
12903
|
+
}
|
|
12774
12904
|
function filesBelow(root, extensions) {
|
|
12775
12905
|
const found = [];
|
|
12776
12906
|
const visit = (directory, prefix) => {
|
|
@@ -16088,7 +16218,7 @@ function annotationsOf(spec) {
|
|
|
16088
16218
|
openWorldHint: false
|
|
16089
16219
|
};
|
|
16090
16220
|
}
|
|
16091
|
-
var PROJECT_INFO_SECTIONS, PROJECT_PATH, RUNNING_PROJECT_PATH, RUNNING_PID, SCENE_PATH, WITHOUT_AN_EDITOR = "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, or readBy for a read. That engine runs every script of the file, where the editor runs only tool scripts, so what a script changes as the file loads or as a property is set 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. Each file the written one refers to is named by its uid, as the editor names it, except a file the project's uid cache has no uid for yet (one made since the project was last scanned), which is named by path and listed under namedByPath with the call that scans it. An editor of the project that is running and has not reached this server is waited for rather than written around.", ALSO_SAVED = "A scene is saved as the engine holds it once the file has loaded, and one property can set others as it loads, as anchors_preset gives a centred Control both its grow directions, so a scene not last saved by an editor can gain, change or lose lines
|
|
16221
|
+
var PROJECT_INFO_SECTIONS, PROJECT_PATH, RUNNING_PROJECT_PATH, RUNNING_PID, SCENE_PATH, WITHOUT_AN_EDITOR = "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, or readBy for a read. That engine runs every script of the file, where the editor runs only tool scripts, so what a script changes as the file loads or as a property is set 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. Each file the written one refers to is named by its uid, as the editor names it, except a file the project's uid cache has no uid for yet (one made since the project was last scanned), which is named by path and listed under namedByPath with the call that scans it. An editor of the project that is running and has not reached this server is waited for rather than written around.", ALSO_SAVED = "A scene is saved as the engine holds it once the file has loaded, and one property can set others as it loads, as anchors_preset gives a centred Control both its grow directions, so a scene not last saved by an editor can gain, change or lose lines the call did not ask for, on any node the file held, the one it names among them: alsoSaved lists each as {node, property, was, saved}, was left out where the file set nothing and saved where it now sets nothing. What a set itself moved on its node is under alsoChanged rather than here, and a node the call adds, saved as the engine saves any new one, is not listed. The scene loads as it did; only its text changed.", IMPORTED_FIRST = "importedFirst names the files whose import was behind them on disk, such as a picture changed since it was imported or one never imported, which were imported before the run through project_import reimport, so the run reads them as they are now; it is left out when every import was current. notImportedFirst lists, as project_import reimport does, any it could not import, and importNote says that the run reads those as they were. The import gives every script without a .uid sidecar one, as the editor's scan does, writing it beside the script in the project, and uidsWrittenFirst names those scripts. The files inside an addon are counted per addon rather than named, under importedInAddons and uidsWrittenInAddons. importTookMs is how long the import took; it is outside the run's own time limit, so a call that imported can take that much longer than the limit it was given.", WHOLE_NUMBERS = 'A whole number of 2^53 or more, such as a 64-bit seed or a resource uid, is written as its digits, {"_type": "int", "value": "9007199254740993"}, the form a read answers with: a JSON number that large can arrive as a neighbour of the one sent, so sent as a number it is refused.', SCRIPT_PATH, RESOURCE_FILE = 'File inside the project, such as "sprites/hero.png" or "materials/steel.tres".', EXPORT_PLATFORMS, RESOURCE_PATH, NODE_PATH, PROPERTIES, XY, ANIMATION_TRACK, SCRIPT_MODIFICATIONS, INPUT_EVENTS, TILESET_SOURCES, TILEMAP_CELLS, COLOUR2, TOOL_SPECS, SPECS_BY_NAME;
|
|
16092
16222
|
var init_tool_definitions = __esm(() => {
|
|
16093
16223
|
init_launch();
|
|
16094
16224
|
PROJECT_INFO_SECTIONS = [
|
|
@@ -16300,7 +16430,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16300
16430
|
include: {
|
|
16301
16431
|
type: "array",
|
|
16302
16432
|
items: { type: "string", enum: [...PROJECT_INFO_SECTIONS] },
|
|
16303
|
-
description: "Extra sections: registered autoloads, the classes the project's scripts declare with class_name, each with its script, read from the files, the input actions project.godot holds with their events (an engine ui_ action only when the project rebinds it, as engineAction), addons and whether each is enabled, export presets, the audio bus layout, a health report, or export validation. health and validation compile every script of the project in headless engines and name each that fails with its first error, each file a scene, resource or script refers to that does not exist, and each signal connection in a scene whose method or signal the node at its end does not have, judged from the node's type and scripts as their files are written."
|
|
16433
|
+
description: "Extra sections: registered autoloads, the classes the project's scripts declare with class_name, each with its script, read from the files, the input actions project.godot holds with their events (an engine ui_ action only when the project rebinds it, as engineAction), addons and whether each is enabled, export presets, the audio bus layout, a health report, or export validation. health and validation compile every script of the project in headless engines and name each that fails with its first error, each file a scene, resource or script refers to that does not exist, each input action a script reads by a name written in the call that neither the project nor the engine defines, with every line reading it, and each signal connection in a scene whose method or signal the node at its end does not have, judged from the node's type and scripts as their files are written."
|
|
16304
16434
|
},
|
|
16305
16435
|
preset: { type: "string", description: "For validation: the export preset to validate against." },
|
|
16306
16436
|
detail: {
|
|
@@ -16677,7 +16807,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16677
16807
|
title: "Run tests",
|
|
16678
16808
|
effect: "additive",
|
|
16679
16809
|
description: "Runs the project's gdUnit4 tests and answers with every case that did not pass: where it is, and what the assertion said. Each entry under failed carries its first report as message and detail, and, when it has more than one, its reports under reports in the order the case met them: gdUnit4 goes on past a failed assertion, and a case can fail several and then stop on a runtime error, which makes its status error. Identical reports fold into one with times, at most twenty different ones are kept (reportsLeftOut counts the rest), and past about a megabyte the largest cases keep only their first message (failedWithoutDetail). failures counts the cases that failed an assertion and errors the cases that hit an error, so such a case counts in both. Suites where everything passed are counted, not listed, and an engine message keeps the frames above gdUnit4, not the twenty inside it; identical engine messages come back once under engineEntries, with times saying how often they were printed, and with script, line and function for the project script one points at, as editor_output's entries have. The class list is rebuilt first, so a suite written a moment ago is found, and the rebuild's answer is under classes. What changed on disk since it was imported is then imported before any suite runs, and named under importedFirst. On Windows and Linux the run gets a user:// of its own, away from a player's saves; on macOS the engine reads user:// off HOME, so it writes where the player keeps theirs, and savesNote says so. The run is headless unless a suite in it needs a window as gdharness test reads it, and then has one, on a desktop of its own on Windows. A run that found nothing to run is never called a pass, and names the path it looked in. A script that does not load stops gdUnit4 before any suite runs: its errors come back in full under scriptErrors, and the scripts that failed only because one they depend on did are listed by path under failedThroughDependency. When they failed on a class whose own script has a parser error, which gdUnit4 never names, that script is checked by the engine and its error comes first under scriptErrors, with the class it declares under declares, and the errors a script has only because that class did not resolve, which the engine reads as Variant, are kept apart under followFromUnresolved. An autoload that does not compile stops the run at once, its errors listed the same way. A client sending a progress token is told as each suite finishes, and at least every twenty seconds. A run that ends without a report, at its timeout or otherwise, names the suites it finished under suitesFinished, the failing ones with their failed cases under suitesFailing, and the one it was in under suiteRunning. When a client cuts a run off, that is kept in the project and the next project_test there carries it under previousRunCut. A run where nothing failed but orphan nodes were left comes back under warnings, with the count per suite: gdUnit4 decides its verdict on those and keeps them out of its report, so they are read off what it printed. A run whose every case passed is still not called passed when it printed a script error that no case failed on: gdUnit4 fails a case on the script errors its logger sees, and it cannot see a stack overflow, so the cases pass on whatever the faulted calls returned. Those errors come back under uncaughtScriptErrors, and under engineEntries by index with detailUnder rather than with their backtrace a second time; a backtrace that repeats, as a recursion's does, has each repeated frame or cycle of frames written once with the frames it covers and how many times. One raised inside assert_error(...).is_runtime_error is the test's own and is not listed there, and none are when the project turns off gdUnit4's report/godot/script_error setting; a suite declares them all the same. Needs gdUnit4 under addons/gdUnit4.",
|
|
16680
|
-
answer: "passed is the verdict to read. exitCode is the engine's own exit, gdUnit4's code for what it saw, and is 0 beside passed false when the run is failed for something gdUnit4 does not judge, such as an engine error no suite declared. time is gdUnit4's own sum of the seconds its cases took, from its report. tookMs is the whole call in milliseconds, from the class rebuild to the engine's exit, which is what a caller waits for, and tookMsBy splits it into the class rebuild (classes), the import after it (import) and the engine running the suites (engine), each with any wait for an engine slot or the editor's scan in it. The run is judged as gdharness test judges it: undeclaredErrors names each engine error that no suite declared in its GDHARNESS_EXPECTED_ERRORS constant, and each engine warning a suite printed and did not declare in its GDHARNESS_EXPECTED_WARNINGS, marked warning true, with the suite and the case that printed it, and declaredNotPrinted each declared error or warning its case did not print. A declared text must be the whole line after ERROR: or WARNING: and its space, so a longer one its case printed holding the text is named under printedInstead. Either fails the run, and each suite holding one is listed with its count. leakedAtExit holds the engine's lines saying it exited still holding objects, resources, memory pages or a server's RIDs, which fail the run too, and the note names any script of the project Godot itself never frees and, on a run with engineArgs [\"--verbose\"], what the engine held. engineErrors counts every engine error the run printed but those a suite declared. orphans totals the orphan nodes gdUnit4 counted, and each suite that left some has its count, and a warning saying how to free them, under warnings, with left naming each case that left some (before or after for one of the suite's hooks, or the one value \"before or after\" where no case began and the two cannot be told apart) and the nodes, by class, name and script. suites lists only the suites with something to say (a case that failed, erred or was skipped, a hook that failed, orphans, or an error undeclared or declared and not printed), and suitesPassed counts the rest. Under classes, the classes each addon declares are counted under addedInAddons and changedInAddons rather than named, and a class the rebuild puts back that the cache had after the last rebuild is named under classes.lostSinceLastRebuild, which is the editor writing its shorter list over the file on every save until restarted. A suite needs a window when it declares const GDHARNESS_NEEDS_WINDOW: bool = true, or calls scene_runner and declares nothing; a run holding one has a window, at the size project.godot gives its viewport and with no sound, and windowed is true and windowNote names those suites and any saying it runs headless that shared the window. On a machine with no display such a run is headless, windowed is false, and windowNote says so. " + IMPORTED_FIRST,
|
|
16810
|
+
answer: "passed is the verdict to read. exitCode is the engine's own exit, gdUnit4's code for what it saw (100 a case failed, 101 only warnings, 105 script errors it detected), and is 0 beside passed false when the run is failed for something gdUnit4 does not judge, such as an engine error no suite declared. time is gdUnit4's own sum of the seconds its cases took, from its report. tookMs is the whole call in milliseconds, from the class rebuild to the engine's exit, which is what a caller waits for, and tookMsBy splits it into the class rebuild (classes), the import after it (import) and the engine running the suites (engine), each with any wait for an engine slot or the editor's scan in it. The run is judged as gdharness test judges it: undeclaredErrors names each engine error that no suite declared in its GDHARNESS_EXPECTED_ERRORS constant, and each engine warning a suite printed and did not declare in its GDHARNESS_EXPECTED_WARNINGS, marked warning true, with the suite and the case that printed it, and declaredNotPrinted each declared error or warning its case did not print. gdUnit4 does not fail a case on push_error or push_warning, so a case that printed one undeclared is in neither failed nor errors: it is named here, and the run is failed for it. A declared text must be the whole line after ERROR: or WARNING: and its space, so a longer one its case printed holding the text is named under printedInstead. Either fails the run, and each suite holding one is listed with its count. leakedAtExit holds the engine's lines saying it exited still holding objects, resources, memory pages or a server's RIDs, which fail the run too, and the note names any script of the project Godot itself never frees and, on a run with engineArgs [\"--verbose\"], what the engine held. engineErrors counts every engine error the run printed but those a suite declared. orphans totals the orphan nodes gdUnit4 counted, and each suite that left some has its count, and a warning saying how to free them, under warnings, with left naming each case that left some (before or after for one of the suite's hooks, or the one value \"before or after\" where no case began and the two cannot be told apart) and the nodes, by class, name and script. suites lists only the suites with something to say (a case that failed, erred or was skipped, a hook that failed, orphans, or an error undeclared or declared and not printed), and suitesPassed counts the rest. Under classes, the classes each addon declares are counted under addedInAddons and changedInAddons rather than named, and a class the rebuild puts back that the cache had after the last rebuild is named under classes.lostSinceLastRebuild, which is the editor writing its shorter list over the file on every save until restarted. A suite needs a window when it declares const GDHARNESS_NEEDS_WINDOW: bool = true, or calls scene_runner and declares nothing; a run holding one has a window, at the size project.godot gives its viewport and with no sound, and windowed is true and windowNote names those suites and any saying it runs headless that shared the window. On a machine with no display such a run is headless, windowed is false, and windowNote says so. " + IMPORTED_FIRST,
|
|
16681
16811
|
parameters: {
|
|
16682
16812
|
projectPath: PROJECT_PATH,
|
|
16683
16813
|
path: {
|
|
@@ -16780,7 +16910,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16780
16910
|
name: "scene_node",
|
|
16781
16911
|
title: "Scene nodes",
|
|
16782
16912
|
description: `One node in a scene file: add, read, set, duplicate, reparent or delete it, paint TileMap cells, or bake a navigation region. 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}`,
|
|
16783
|
-
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. A set that gives a property the value the node has without it (what the scene it comes from gives, or its default) leaves it out of the file, as the editor does, and answers it under notStored, with notStoredNote saying what it follows now. 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, and layers, each layer mask it answers (collision_layer, collision_mask, visibility_layer) as the layers it holds, {layer, name} with the name project.godot gives the layer. Each of these lists is answered only when it names anything. add and set answer each property given under properties as the node holds it once written; 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}; namesNoNode, each node path written naming no node. get adds placement, a Node3D's position, rotation_degrees and scale from its transform. " + ALSO_SAVED,
|
|
16913
|
+
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. A set that gives a property the value the node has without it (what the scene it comes from gives, or its default) leaves it out of the file, as the editor does, and answers it under notStored, with notStoredNote saying what it follows now. 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. scriptsNaming lists each line of a script that reads a node a rename, a reparent or a delete took by the path it had, as {scenePath, nodePath, script, line, from, to}: the script is on the node at nodePath, or is one that node's script extends, in this scene or one instancing or inheriting it, and to is the path that reaches the node from there now, absent after a delete. It reads $Path, %Unique, and a string handed to get_node, get_node_or_null or has_node on the node itself; a path built at run time is not seen. Scripts are left as they were, as the editor's own rename leaves them, so each line listed fails until it is changed. A 2D bake_navigation that read no obstacle says in its note that all its outlines enclose is walkable, and names the nodes giving obstacles that sit under no region. 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, and layers, each layer mask it answers (collision_layer, collision_mask, visibility_layer) as the layers it holds, {layer, name} with the name project.godot gives the layer. Each of these lists is answered only when it names anything. add and set answer each property given under properties as the node holds it once written; 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}; namesNoNode, each node path written naming no node. get adds placement, a Node3D's position, rotation_degrees and scale from its transform. " + ALSO_SAVED,
|
|
16784
16914
|
parameters: {
|
|
16785
16915
|
projectPath: PROJECT_PATH,
|
|
16786
16916
|
scenePath: SCENE_PATH,
|
|
@@ -16986,6 +17116,12 @@ var init_tool_definitions = __esm(() => {
|
|
|
16986
17116
|
description: "create and set: keyframe snap in seconds, 0 or more. create: default 0.1."
|
|
16987
17117
|
},
|
|
16988
17118
|
track: { ...ANIMATION_TRACK, ops: ["add_track", "remove_track"] },
|
|
17119
|
+
times: {
|
|
17120
|
+
type: "array",
|
|
17121
|
+
items: { type: "number" },
|
|
17122
|
+
ops: ["remove_track"],
|
|
17123
|
+
description: "remove_track: the times in seconds of the keys to remove, keeping the rest of the track; a track left with no key goes too. A time no key is at refuses the call, naming the times the keys are at. To move a key, remove it and add_track it at the new time. Default every key."
|
|
17124
|
+
},
|
|
16989
17125
|
replaceKeys: {
|
|
16990
17126
|
type: "boolean",
|
|
16991
17127
|
ops: ["add_track"],
|
|
@@ -17101,7 +17237,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17101
17237
|
{
|
|
17102
17238
|
name: "script_edit",
|
|
17103
17239
|
title: "Edit scripts",
|
|
17104
|
-
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; a class_name another script or an engine class holds, or an extends naming no class, is refused with nothing written. modify makes every addition or none, refuses with nothing changed additions that would stop a script that parses from parsing, giving the engine's reasons, and answers with the line each one is on in the file written; with an editor serving the project it reloads the script there too, so the editor's answers read what was written, and editorReloaded says so (editorNote when it could not, or when a script tab holds unsaved edits that saving would write over the file). 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.",
|
|
17240
|
+
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 (class_name null for a script declaring none), and a script declaring a class_name is put in the project's class list, with registered saying whether it is there, and an editor serving the project scans for it, so it resolves the class at once (editorRescanned); a class_name another script or an engine class holds, or an extends naming no class, is refused with nothing written. modify makes every addition or none, refuses with nothing changed additions that would stop a script that parses from parsing, giving the engine's reasons, and answers with the line each one is on in the file written; with an editor serving the project it reloads the script there too, so the editor's answers read what was written, and editorReloaded says so (editorNote when it could not, or when a script tab holds unsaved edits that saving would write over the file). 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.",
|
|
17105
17241
|
parameters: {
|
|
17106
17242
|
projectPath: PROJECT_PATH,
|
|
17107
17243
|
scriptPath: SCRIPT_PATH,
|
|
@@ -17205,13 +17341,13 @@ var init_tool_definitions = __esm(() => {
|
|
|
17205
17341
|
name: "script_diagnostics",
|
|
17206
17342
|
title: "Script diagnostics",
|
|
17207
17343
|
effect: "read",
|
|
17208
|
-
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, up to its first syntax error, 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.",
|
|
17344
|
+
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 rather than language server: every error that stops a script compiling, up to its first syntax error, 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. Of several scripts, a language server that stops answering partway leaves the rest to the engine, and checkedBy then says language server, then engine, with checkedByLanguageServer counting the scripts it answered. 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.",
|
|
17209
17345
|
parameters: {
|
|
17210
17346
|
projectPath: PROJECT_PATH,
|
|
17211
17347
|
scriptPath: {
|
|
17212
17348
|
type: ["string", "array"],
|
|
17213
17349
|
items: { type: "string" },
|
|
17214
|
-
description: 'A script inside the project, a folder, or a list of either, such as "scripts/player.gd" or ["scripts/economy", "ui/shop.gd"]. A folder is its .gd files at any depth, skipping what the engine skips. One script is answered on its own. Several are answered together, with clean, errors and warnings for all of them: a script with nothing to report is named in nothingReported, and every other is answered under scripts in that same shape, including a script that could not be read, named with why while the rest are still asked about. Any number of scripts is one call, which reports progress as it goes.'
|
|
17350
|
+
description: 'A script inside the project, a folder, or a list of either, such as "scripts/player.gd" or ["scripts/economy", "ui/shop.gd"]. A folder is its .gd files at any depth, skipping what the engine skips and the addons gdharness installed; a folder whose scripts all sit in those is refused, naming each. A script named that sits under a folder holding a .gdignore is checked as asked and listed under underGdignore, since the engine never loads it and its errors do not stop the project. One script is answered on its own. Several are answered together, with clean, errors and warnings for all of them: a script with nothing to report is named in nothingReported, and every other is answered under scripts in that same shape, including a script that could not be read, named with why while the rest are still asked about. Any number of scripts is one call, which reports progress as it goes.'
|
|
17215
17351
|
}
|
|
17216
17352
|
},
|
|
17217
17353
|
requires: ["projectPath", "scriptPath"]
|
|
@@ -17219,7 +17355,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17219
17355
|
{
|
|
17220
17356
|
name: "resource_edit",
|
|
17221
17357
|
title: "Edit resources",
|
|
17222
|
-
description: 'Resource files: read one, create any ClassDB resource as .tres, change one, write a shader, build a TileSet, or set a Theme colour or font size. A material is a create with resourceType StandardMaterial3D, ShaderMaterial or CanvasItemMaterial. read answers with the properties the file sets, in the form modify takes, with resourceType the engine class and scriptClass the class_name of its script when it declares one, and a Theme lists its items there as "Button/colors/font_color". A Curve, Curve2D or Curve3D reads as the inspector shows it, point_count and point_0/position and the rest, rather than the _data list the file stores, and so does one built into a resource or a scene. create and modify answer each property given under properties as the file holds it once saved, in the same form. A create or modify whose properties made the engine change others, as a Gradient given more colours than offsets gives each new point an offset of 0, names each of those under alsoChanged with what it held before and holds now. A property holding a resource takes its res:// path; a file never imported is refused with the reimport that imports it. move takes any file of the project, a script or an image as much as a resource, or a directory, and works from the files, so it needs no editor; one serving the project is brought up to it as after a move in its own FileSystem dock, its open scenes and cached resources named for the new paths and the project settings the move rewrote taken from the file. read needs no editor either: with none serving the project, a headless engine reads the file. The ops that write a resource go through the editor when one serves the project; with none, a headless engine runs the tool the editor would and the answer says so under writtenBy. That engine runs the script of the resource, where the editor runs only tool scripts, so what a script changes as the file loads or as a property is set is put back before the save, and a resource where that cannot be done is refused and the file left as it was.',
|
|
17358
|
+
description: 'Resource files: read one, create any ClassDB resource as .tres, change one, write a shader, build a TileSet, or set a Theme colour or font size. A material is a create with resourceType StandardMaterial3D, ShaderMaterial or CanvasItemMaterial. read answers with the properties the file sets, in the form modify takes, with resourceType the engine class and scriptClass the class_name of its script when it declares one, and a Theme lists its items there as "Button/colors/font_color", so a style box, a font or a constant is set through modify by that name, as "Button/styles/normal" given the res:// path of a StyleBox. A Curve, Curve2D or Curve3D reads as the inspector shows it, point_count and point_0/position and the rest, rather than the _data list the file stores, and so does one built into a resource or a scene. create and modify answer each property given under properties as the file holds it once saved, in the same form. A create or modify whose properties made the engine change others, as a Gradient given more colours than offsets gives each new point an offset of 0, names each of those under alsoChanged with what it held before and holds now. A property holding a resource takes its res:// path; a file never imported is refused with the reimport that imports it. move takes any file of the project, a script or an image as much as a resource, or a directory, and works from the files, so it needs no editor; one serving the project is brought up to it as after a move in its own FileSystem dock, its open scenes and cached resources named for the new paths and the project settings the move rewrote taken from the file. read needs no editor either: with none serving the project, a headless engine reads the file. The ops that write a resource go through the editor when one serves the project; with none, a headless engine runs the tool the editor would and the answer says so under writtenBy. That engine runs the script of the resource, where the editor runs only tool scripts, so what a script changes as the file loads or as a property is set is put back before the save, and a resource where that cannot be done is refused and the file left as it was.',
|
|
17223
17359
|
parameters: {
|
|
17224
17360
|
projectPath: PROJECT_PATH,
|
|
17225
17361
|
resourcePath: {
|
|
@@ -17343,7 +17479,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17343
17479
|
silent: {
|
|
17344
17480
|
type: "boolean",
|
|
17345
17481
|
ops: ["open", "restart"],
|
|
17346
|
-
description: "Open the editor with no sound out of the machine, started with --audio-driver Dummy, so a tool script, a preview or a scene playing in its viewport is heard by nobody. Default true on open, and on restart how the editor being replaced was started: pass false to hear it. The answer's arguments are what the editor was started with. The editor hands no audio driver to a game it plays, so editor_run's own silent decides that game's sound. A hidden editor is headless and silent either way. On restart only for an editor a server opened; one opened by hand comes back as it was."
|
|
17482
|
+
description: "Open the editor with no sound out of the machine, started with --audio-driver Dummy, so a tool script, a preview or a scene playing in its viewport is heard by nobody. Default true on open, and on restart how the editor being replaced was started: pass false to hear it. The answer's arguments are what the editor was started with. The editor hands no audio driver to a game it plays, so editor_run's own silent decides that game's sound. A hidden editor is headless and silent either way, so its arguments carry no --audio-driver. On restart only for an editor a server opened; one opened by hand comes back as it was."
|
|
17347
17483
|
}
|
|
17348
17484
|
},
|
|
17349
17485
|
requires: [],
|
|
@@ -17520,7 +17656,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17520
17656
|
requires: []
|
|
17521
17657
|
}
|
|
17522
17658
|
},
|
|
17523
|
-
answer: "start: through is gdharness for a game this server started itself, and editor for one the editor plays. scene is the scene the game started in, the project's main scene when none was given. runtime carries addonIsStale and staleNote when the game announced on a runtime addon other than this server's, which no runtime_* call is then sent to, and staleNote says what brings it into step. refreshedClasses names the class_name declarations on disk that the engine's class cache was missing, which were added to it before the game started so the game could resolve them; it is empty when the cache was current. stop: endedPid is, for a run the editor plays, the number its game announced under, read at the stop rather than remembered, and the operating system hands a freed number to the next process, so it can equal the game before it. stopped is false, with the number under notSignalled, when that number no longer answers as the process the run was started as and nothing was signalled, the note naming which property it failed on, and false with the number under stillGoing when what was told to end was still running ten seconds later. endedThrough says how the stop ended a run that was going: close (the game was asked to close and exited, so exitCode is its own), keeper (the process that started the game ended it through the handle it holds), signal (its pid was signalled once shown to still be the run), or editor (the editor playing it was asked). exitedBeforeStop is true when the run was already over when the stop came, so nothing was ended and exitCode, when anything collected it, is the one it ended with. A start that ends the run before it says how under endedPreviousRunThrough, with the same values, and one that refused to signal that run names the property it failed on under previousRunLeftBecause. check: hung is a run killed at timeoutMs, and errors and warnings count what it printed, which comes back under entries with repeats folded together. entries holds the errors and warnings and
|
|
17659
|
+
answer: "start: through is gdharness for a game this server started itself, and editor for one the editor plays. scene is the scene the game started in, the project's main scene when none was given. runtime carries addonIsStale and staleNote when the game announced on a runtime addon other than this server's, which no runtime_* call is then sent to, and staleNote says what brings it into step. refreshedClasses names the class_name declarations on disk that the engine's class cache was missing, which were added to it before the game started so the game could resolve them; it is empty when the cache was current. stop: endedPid is, for a run the editor plays, the number its game announced under, read at the stop rather than remembered, and the operating system hands a freed number to the next process, so it can equal the game before it. stopped is false, with the number under notSignalled, when that number no longer answers as the process the run was started as and nothing was signalled, the note naming which property it failed on, and false with the number under stillGoing when what was told to end was still running ten seconds later. endedThrough says how the stop ended a run that was going: close (the game was asked to close and exited, so exitCode is its own), keeper (the process that started the game ended it through the handle it holds), signal (its pid was signalled once shown to still be the run), or editor (the editor playing it was asked). exitedBeforeStop is true when the run was already over when the stop came, so nothing was ended and exitCode, when anything collected it, is the one it ended with. A start that ends the run before it says how under endedPreviousRunThrough, with the same values, and one that refused to signal that run names the property it failed on under previousRunLeftBecause. check: hung is a run killed at timeoutMs, and errors and warnings count what it printed, which comes back under entries with repeats folded together. entries holds the errors and warnings, and printed the ordinary lines the run printed, in the same shape with repeats folded, the newest 50 kept and printedLinesNotShown counting those left out. A check keeps no run for editor_output to read afterwards; editor_run start then editor_output reads everything. A check given --verbose puts the ordinary lines in entries, with what the engine adds, and has no printed. An engine crash is an error whatever it prints after: the crash handler's report is the entry, and the engine version and the native and GDScript backtraces are its detail, so a crashed run is never booted or clean. arguments is the engine command line the check ran, as a start's is, and durationMs runs from that engine's start to the check's answer, after its exit, so it holds no import that came first. start and check: " + IMPORTED_FIRST + " An exported build carries its own imports and is not asked. waitedForEditorScanMs and scanNote are left out when no editor scan was waited for. A silent windowed run has --audio-driver Dummy in its arguments; a headless run is silent without it, and one the editor plays with sound has no arguments of its own. profile: per function its script, the function (Class.name when the script declares a class_name), the line its body's first statement is on, for a lambda the named function it is written in (within), calls, and self and total milliseconds, with functionsCounted, scriptMs (the self time of them all) and coveredMs. The functions of gdharness's own runtime are not among them: the runtime addon's, which answer its tools inside the game, and those of res://gdharness/loader.gd, which starts it. Their self time is runtimeAddonMs, over runtimeAddonFunctions functions. complete is true when the engine's own totals arrived, which it sends only when the profiler is switched off: the runtime addon does that as a game quits, so a scene that does its work in _ready and quits is covered whole; otherwise the answer is the frames summed so far and the note says what that misses. frames counts the frames of the profile that arrived, and the engine's totals also hold the work after the last of them, so once complete a function run every frame can show a call more than frames. firstFrame and lastFrame are the game's own numbers, counted from 0, for the first and the last of them, in a run this server started; a firstFrame above 0 is frames run before the profiler came on, and a gap between the two is frames that never arrived, which the note says. Self time counts a call into the engine's own methods as the caller's, and a call through super too, while the overridden function's row counts it again: such a row carries selfIncludesSuper, so self times along an override chain overlap. The profiler's own cost of timing a call lands in the self time of the function called; with the runtime addon it is measured each run on an empty function, as perCallOverheadUs, and a row with at least half its selfMs in it carries overheadMs, since a small function called often costs that much less without the profiler. A function the profiler started inside is left out, since its time would be counted from the engine's start. The milliseconds are time passed while the function ran, not processor time given to it, so they grow when other processes compete for the processor: compare two profiles taken under the same load. They are also summed over every thread: a function run by WorkerThreadPool or a Thread on several threads at once counts each thread's time, the engine does not say which thread a call ran on, and a function waiting for them has the wait in its own self time, so selfMs is not time taken from frames, and scriptMs can exceed coveredMs, which the note then says. A property's get and set blocks are named Class.@name_getter and Class.@name_setter, as the engine names them, and their rows carry property, the property's name. A game the editor plays that was not started with profile: true says, in the answer, that it was profiled from the moment it was asked. A profile with mark answers marked: true; one with since answers since: \"mark\" and markSetMsAgo, and lessThanAtMark counts the functions left out for reading less than at the mark, which the engine's own totals, capped, can do when they replace the frames' sum.",
|
|
17524
17660
|
defaultOperation: "start"
|
|
17525
17661
|
},
|
|
17526
17662
|
{
|
|
@@ -17584,7 +17720,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17584
17720
|
title: "Editor status",
|
|
17585
17721
|
effect: "read",
|
|
17586
17722
|
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: editor_launch rebind binds the debug adapter again in place, and editor_launch restart the language server. 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.",
|
|
17587
|
-
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, and userDir, the directory its user:// is, where its saves and settings are read. 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: editor_launch rebind binds the debug adapter again in place, and editor_launch restart the language server. 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 from the socket opening until its greeting and that read are done, 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, syncsBreakpoints that it keeps its breakpoints when a debug session opens, which Godot otherwise clears, and hidden that it runs headless with no window anybody can see. 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.",
|
|
17723
|
+
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, and userDir, the directory its user:// is, where its saves and settings are read. 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: editor_launch rebind binds the debug adapter again in place, and editor_launch restart the language server. 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. editor.openScenes lists the scenes open in the editor's tabs, leaving out a tab of a scene never saved, editor.editedScene the one it is showing (null when none is, or when that scene was never saved), and editor.unsavedScenes those with changes not yet written to disk, where an empty entry is a scene never saved; all three come with scan and are absent when it is null. 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 from the socket opening until its greeting and that read are done, 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, syncsBreakpoints that it keeps its breakpoints when a debug session opens, which Godot otherwise clears, and hidden that it runs headless with no window anybody can see. 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.",
|
|
17588
17724
|
parameters: {},
|
|
17589
17725
|
requires: []
|
|
17590
17726
|
},
|
|
@@ -17722,7 +17858,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17722
17858
|
namePattern: {
|
|
17723
17859
|
type: "string",
|
|
17724
17860
|
ops: ["find"],
|
|
17725
|
-
description: 'find: a case-insensitive glob on the node name, such as "Enemy*", or several separated by | the way says takes them, such as "Enemy*|Boss", with \\| for a bar in a name. Matched against the whole name, so a bare word finds only a node called exactly that; an answer of none
|
|
17861
|
+
description: 'find: a case-insensitive glob on the node name, such as "Enemy*", or several separated by | the way says takes them, such as "Enemy*|Boss", with \\| for a bar in a name. Matched against the whole name, so a bare word finds only a node called exactly that; an answer of none for a bare word that names contain says how many do and what glob would have found them, and a glob that finds nothing answers a plain none.'
|
|
17726
17862
|
},
|
|
17727
17863
|
group: { type: "string", ops: ["find"], description: "find: a group the node is in." },
|
|
17728
17864
|
says: {
|
|
@@ -17918,14 +18054,14 @@ var init_tool_definitions = __esm(() => {
|
|
|
17918
18054
|
name: "runtime_input",
|
|
17919
18055
|
title: "Send input to the game",
|
|
17920
18056
|
description: "Input to the running game: a whole click on a Control or a 3D node named by path or on a control named by the words on it, an item chosen out of a menu, typing into whatever has the focus, or a raw action, key, mouse button, mouse motion or drag. All of it works headless, where the viewport is the project's window size and the GUI only takes what is inside it. On gdharness's own desktop, where a windowed run goes, Windows refuses to say where the pointer is: every pointer answer there carries pointer_on_hidden_desktop, and the first of the run pointer_note saying why it matters: get_mouse_position() on the root window, and the mouse positions derived from it, read a meaningless position, while what reads the event itself (the control under it, hover, tooltips, input handlers) gets the injected position. A native window no real pointer has entered gets no hover from Godot, so the runtime supplies it there and the answers say hover_supplied.",
|
|
17921
|
-
answer: `click: what was under the pointer, and what became of the control: in_tree, removed or freed. Named by says, found says which match it was, its index being the index argument that presses the same match again, found.item names the tab, list entry, tree row or menu bar title pressed (kind; index, the item's own number in its control, which is not found.index; says; and for a row the column of the cell saying the words), and found.pressedOn says "the words" for words in a RichTextLabel pressed where they are drawn, or "the middle of the label" with a note saying why they could not be placed; on a rich label link_pressed says whether the press reached a link, with link_meta giving the meta the label reports clicked, an empty one included. A control scrolled into view first is scrolled each container out from it a frame after the one inside, and scrolled_into_view says whether a scroll value changed. A button in toggle mode, a CheckBox or CheckButton included, answers pressed with before and after, its button_pressed either side of the click: the same value twice is a click the game undid, and after is null when the click freed it. A refusal for a pointer turned off names where mouse_behavior_recursive was set. On a 3D node landed says the interface did not swallow the press: no control under the pointer stopped it, a control letting the pointer pass included, and every viewport on the way out from the room had the pointer over what shows the room. choose: what was chosen, read before the press, which is heard rather than assumed; what became of the control named (in_tree, removed or freed, since a game can rebuild its screen on the pick); and what the button in front of the menu shows now when it is still there. A menu is opened rather than clicked because its items are drawn rather than built, and the item is looked for as the menu stands once open, since a game can fill a menu as it opens. action, key, mouse_click and joypad_button: the event as it was sent, with whole saying whether the press was let go of again and pressed whether it is left held down (true only after pressed true), for a key the keycode, physical_keycode and unicode it carried, and for a controller button its number, its name and the device. mouse_motion: the position and the relative movement sent. mouse_drag: from, to, motions sent and relative_total. joypad_motion: the axis by number and name, the value and the device. key, mouse_click, click, joypad_button and joypad_motion answer actions, the InputMap actions the event also presses; for a motion, those its direction reaches past their deadzone, and none for one inside it. mouse_click
|
|
18057
|
+
answer: `click: what was under the pointer, and what became of the control: in_tree, removed or freed. A button answers pressed_signal, whether its pressed signal fired during the click. Named by says, found says which match it was, its index being the index argument that presses the same match again, found.item names the tab, list entry, tree row or menu bar title pressed (kind; index, the item's own number in its control, which is not found.index; says; and for a row the column of the cell saying the words), and found.pressedOn says "the words" for words in a RichTextLabel pressed where they are drawn, or "the middle of the label" with a note saying why they could not be placed; on a rich label link_pressed says whether the press reached a link, with link_meta giving the meta the label reports clicked, an empty one included. A control scrolled into view first is scrolled each container out from it a frame after the one inside, and scrolled_into_view says whether a scroll value changed. A button in toggle mode, a CheckBox or CheckButton included, answers pressed with before and after, its button_pressed either side of the click: the same value twice is a click the game undid, and after is null when the click freed it. A refusal for a pointer turned off names where mouse_behavior_recursive was set. On a 3D node landed says the interface did not swallow the press: no control under the pointer stopped it, a control letting the pointer pass included, and every viewport on the way out from the room had the pointer over what shows the room. choose: what was chosen, read before the press, which is heard rather than assumed; what became of the control named (in_tree, removed or freed, since a game can rebuild its screen on the pick); and what the button in front of the menu shows now when it is still there. A menu is opened rather than clicked because its items are drawn rather than built, and the item is looked for as the menu stands once open, since a game can fill a menu as it opens. action, key, mouse_click and joypad_button: the event as it was sent, with whole saying whether the press was let go of again and pressed whether it is left held down (true only after pressed true), for a key the keycode, physical_keycode and unicode it carried, and for a controller button its number, its name and the device. mouse_motion: the position and the relative movement sent. mouse_drag: from, to, motions sent and relative_total. joypad_motion: the axis by number and name, the value and the device. key, mouse_click, click, joypad_button and joypad_motion answer actions, the InputMap actions the event also presses; for a motion, those its direction reaches past their deadzone, and none for one inside it. mouse_click, mouse_motion and mouse_drag answer hovered, the control under the pointer once the events are handled, or null over none; the other events are aimed at nothing. mouse_click with a press, and mouse_drag, answer press_went_to, the path of what the press went to (a control, or a window embedded over the point), read before it, or null when nothing there takes the pointer; given nodePath naming a Control, landed says whether that is the control or inside it. A click that did not land on a control whose mouse_filter is ignore, as a Label's is, says so under why_not_landed, and one on a control with something drawn over it names that, a window stacked above the one the control is in among them. An action, a key, a joypad_button or a joypad_motion answers focused with the path of the Control holding the keyboard focus when it went in, since that Control gets it before the game's _unhandled_input: Space or Enter on a focused button presses the button, and a stick or dpad pressing ui_down moves a focused list's selection, or the focus, and never reaches the game's handler. Where the press moved the focus, focused_after names the Control holding it once the event was handled, or null when nothing does. A mouse_click, mouse_motion or mouse_drag given nodePath answers it under path, its points in the pixels of the window they went to, and that window under window when it is not the game's own. One with a point outside the viewport it went to says so under outside_viewport, with the viewport's rectangle, since no control there receives it.`,
|
|
17922
18058
|
parameters: {
|
|
17923
18059
|
projectPath: RUNNING_PROJECT_PATH,
|
|
17924
18060
|
pid: RUNNING_PID,
|
|
17925
18061
|
nodePath: {
|
|
17926
18062
|
type: "string",
|
|
17927
|
-
ops: ["click", "choose"],
|
|
17928
|
-
description: "click: the Control to click, at its centre, or at the middle of the part on screen when no scroll brings its centre into view (said under pressed_on), or the 3D node to click, where it is drawn; with says, where to look for the control instead, default the whole tree. choose: the PopupMenu, or the OptionButton or MenuButton in front of one."
|
|
18063
|
+
ops: ["click", "choose", "mouse_click", "mouse_motion", "mouse_drag"],
|
|
18064
|
+
description: "click: the Control to click, at its centre, at x and y in its own space when those are given, or at the middle of the part on screen when no scroll brings its centre into view (said under pressed_on), or the 3D node to click, where it is drawn; with says, where to look for the control instead, default the whole tree. choose: the PopupMenu, or the OptionButton or MenuButton in front of one. mouse_click, mouse_motion, mouse_drag: the Control, Node2D or Window whose own space the points are in, a Window's being its own pixels; the events go to the window that shows it, a native one included, which the game's window pixels cannot reach, and the answer names it under window when it is not the game's own. Default the game's window."
|
|
17929
18065
|
},
|
|
17930
18066
|
says: {
|
|
17931
18067
|
type: "string",
|
|
@@ -17982,25 +18118,25 @@ var init_tool_definitions = __esm(() => {
|
|
|
17982
18118
|
alt: { type: "boolean", ops: ["key"], description: "key: hold Alt with it. Default false." },
|
|
17983
18119
|
x: {
|
|
17984
18120
|
type: "number",
|
|
17985
|
-
ops: ["mouse_click", "mouse_motion", "mouse_drag"],
|
|
17986
|
-
description: "mouse_click, mouse_motion: window pixels. mouse_drag: where the press is."
|
|
18121
|
+
ops: ["click", "mouse_click", "mouse_motion", "mouse_drag"],
|
|
18122
|
+
description: "click: with y, the point to press in the control's own space instead of its centre, for a control that draws its parts itself; not with a 3D node, nor with says finding an item the control draws. mouse_click, mouse_motion: window pixels, or nodePath's own space when that is given. mouse_drag: where the press is, in the same space."
|
|
17987
18123
|
},
|
|
17988
18124
|
y: {
|
|
17989
18125
|
type: "number",
|
|
17990
|
-
ops: ["mouse_click", "mouse_motion", "mouse_drag"],
|
|
17991
|
-
description: "mouse_click, mouse_motion
|
|
18126
|
+
ops: ["click", "mouse_click", "mouse_motion", "mouse_drag"],
|
|
18127
|
+
description: "click, mouse_click, mouse_motion, mouse_drag: as x."
|
|
17992
18128
|
},
|
|
17993
18129
|
toX: {
|
|
17994
18130
|
type: "number",
|
|
17995
18131
|
ops: ["mouse_drag"],
|
|
17996
|
-
description: "mouse_drag: where the release is, in window pixels."
|
|
18132
|
+
description: "mouse_drag: where the release is, in window pixels or nodePath's own space."
|
|
17997
18133
|
},
|
|
17998
18134
|
toY: { type: "number", ops: ["mouse_drag"], description: "mouse_drag: as toX." },
|
|
17999
18135
|
via: {
|
|
18000
18136
|
type: "array",
|
|
18001
18137
|
items: { type: "array", items: { type: "number" }, minItems: 2, maxItems: 2 },
|
|
18002
18138
|
ops: ["mouse_drag"],
|
|
18003
|
-
description: "mouse_drag: points the stroke passes through on the way, in order, each [x, y]. The motions are spread along the whole stroke by distance. Default none: a straight line."
|
|
18139
|
+
description: "mouse_drag: points the stroke passes through on the way, in order, each [x, y] in the space x and y are in. The motions are spread along the whole stroke by distance. Default none: a straight line."
|
|
18004
18140
|
},
|
|
18005
18141
|
frames: {
|
|
18006
18142
|
type: "integer",
|
|
@@ -18102,7 +18238,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
18102
18238
|
name: "runtime_wait",
|
|
18103
18239
|
title: "Wait in the running game",
|
|
18104
18240
|
description: "Lets the running game get on with it and answers when something has happened: a number of frames, a signal, a property reaching a value, or words appearing on a screen. Records a signal or a property from before the call that sets it off, so a change over before the next call arrives is still seen. Needs the game running with the runtime addon.",
|
|
18105
|
-
answer: "recorded: changes, each with frame (process frames since the watch was armed, 0 the reading at arming: 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, so game_time is the clock), elapsed_ms, game_time (the seconds of process time the game had been given
|
|
18241
|
+
answer: "recorded: changes, each with frame (process frames since the watch was armed, 0 the reading at arming: 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, so game_time is the clock), elapsed_ms (wall-clock milliseconds since the arming), game_time (the seconds of process time the game had been given between the arming and that frame, scaled by Engine.time_scale as a tween is; like frame, it counts from the watch, not from the start of the game) and value; frames and elapsed_ms say how long it recorded. calls lists each runtime_invoke set or call and runtime_input sent while it recorded, in order, with call (the tool and op), what it was given of path, method, property, action, keycode, button, pressed and says, and frame, the last reading taken before it ran, so what it changed shows from the next reading at the earliest. Two calls sent one after the other arrive frames apart, which frame tells apart from a delay in the game itself; calls_dropped counts any past 1000. dropped says so when more than 1000 changes came, and ended when recording stopped before it was collected: the node was freed, the path stopped reading, or 120000 ms passed.",
|
|
18106
18242
|
parameters: {
|
|
18107
18243
|
projectPath: RUNNING_PROJECT_PATH,
|
|
18108
18244
|
pid: RUNNING_PID,
|
|
@@ -18127,7 +18263,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
18127
18263
|
type: "integer",
|
|
18128
18264
|
minimum: 1,
|
|
18129
18265
|
ops: ["signal", "recorded"],
|
|
18130
|
-
description: "signal: the watch an earlier watch of a signal answered, in place of nodePath and signal. Answers at once, with fired_before_wait, when the signal fired after the watch was armed, and otherwise waits for it; times counts how often it fired,
|
|
18266
|
+
description: "signal: the watch an earlier watch of a signal answered, in place of nodePath and signal. Answers at once, with fired_before_wait, when the signal fired after the watch was armed, and otherwise waits for it; times counts how often it fired, args is what the first carried, fired_after_ms the milliseconds from the arming to the first, and elapsed_ms how long the wait itself took. recorded: the watch an earlier watch of a property answered. The watch goes with the answer either way."
|
|
18131
18267
|
},
|
|
18132
18268
|
property: {
|
|
18133
18269
|
type: "string",
|
|
@@ -18177,7 +18313,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
18177
18313
|
},
|
|
18178
18314
|
recorded: {
|
|
18179
18315
|
effect: "read",
|
|
18180
|
-
summary: "answer what a watch of a property recorded since it was armed, at once: changes holds the reading at arming and every later one that differed, each with the frame, elapsed_ms and game_time it was read at, and calls every runtime_invoke set or call and runtime_input sent while it recorded, each with the frame of the last reading before it ran",
|
|
18316
|
+
summary: "answer what a watch of a property recorded since it was armed, at once: changes holds the reading at arming and every later one that differed, each with the frame, elapsed_ms and game_time it was read at, and calls every runtime_invoke set or call and runtime_input sent while it recorded, each with the frame of the last reading before it ran. A property that changes every frame, such as the position of something moving, records one change a frame up to 1000, an answer of tens of thousands of characters; for the moment it crosses a value, until with compare answers that alone",
|
|
18181
18317
|
requires: ["watch"]
|
|
18182
18318
|
},
|
|
18183
18319
|
until: {
|
|
@@ -43291,18 +43427,19 @@ async function renameSymbol(request, services) {
|
|
|
43291
43427
|
}
|
|
43292
43428
|
}
|
|
43293
43429
|
const heirs = graph.descendants(root);
|
|
43430
|
+
const declaresNewName = (body) => [body, ...graph.ancestors(body)].some((id) => graph.declaration(id, newName) !== undefined);
|
|
43294
43431
|
const inUse = [];
|
|
43295
43432
|
for (const script of scripts.values()) {
|
|
43296
43433
|
for (const occurrence of script.occurrences(newName)) {
|
|
43297
43434
|
const body = graph.bodyAt(script.path, occurrence.offset);
|
|
43298
|
-
if (occurrence.kind === "code" && !occurrence.afterDot && heirs.has(body) &&
|
|
43435
|
+
if (occurrence.kind === "code" && !occurrence.afterDot && heirs.has(body) && !declaresNewName(body)) {
|
|
43299
43436
|
inUse.push({ file: script.path, line: script.lines.positionOf(occurrence.offset).line + 1 });
|
|
43300
43437
|
}
|
|
43301
43438
|
}
|
|
43302
43439
|
}
|
|
43303
43440
|
if (inUse.length > 0) {
|
|
43304
43441
|
const places = inUse.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line).slice(0, 10).map((place) => `${place.file}:${place.line}`);
|
|
43305
|
-
conflicts.push(`${newName} is already used in code
|
|
43442
|
+
conflicts.push(`${newName} is already used in code in a class that declares or inherits ${symbol}, as a local, a parameter or another name the renamed ${what} would shadow or be shadowed by, at ${places.join(", ")}${inUse.length > places.length ? ` and ${inUse.length - places.length} more` : ""}`);
|
|
43306
43443
|
}
|
|
43307
43444
|
if (conflicts.length > 0) {
|
|
43308
43445
|
return {
|
|
@@ -43379,8 +43516,8 @@ async function renameSymbol(request, services) {
|
|
|
43379
43516
|
}, plan);
|
|
43380
43517
|
}
|
|
43381
43518
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), symbol, moveTo === null ? [] : [declaringPath]);
|
|
43382
|
-
const left = leftAloneReport(plan.mentions);
|
|
43383
43519
|
const rewrites = rewritesOf(plan, texts, moveTo === null || request.newScriptPath === null ? null : { from: declaringPath, to: moveTo, absoluteTo: request.newScriptPath });
|
|
43520
|
+
const left = leftAloneReport(asWritten(plan.mentions, rewrites));
|
|
43384
43521
|
const graph = new ClassGraph(scripts, declared);
|
|
43385
43522
|
const rank = (path) => (declaringFiles.includes(path) ? 0 : 1000) + graph.ancestors(`${path}#`).length;
|
|
43386
43523
|
const scriptsInOrder = rewrites.map((rewrite) => rewrite.path).filter((path) => path.endsWith(".gd")).sort((a, b) => rank(a) - rank(b) || a.localeCompare(b)).map((path) => path === declaringPath && moveTo !== null ? moveTo : path);
|
|
@@ -43493,6 +43630,14 @@ function changedReport(edits, rewrites) {
|
|
|
43493
43630
|
};
|
|
43494
43631
|
});
|
|
43495
43632
|
}
|
|
43633
|
+
function asWritten(mentions, rewrites) {
|
|
43634
|
+
const after = new Map(rewrites.map((rewrite) => [rewrite.path, rewrite.after.split(`
|
|
43635
|
+
`)]));
|
|
43636
|
+
return mentions.map((mention) => {
|
|
43637
|
+
const line = mention.line < 1 ? undefined : after.get(mention.file)?.[mention.line - 1];
|
|
43638
|
+
return line === undefined ? mention : { ...mention, text: line.replace(/\r$/, "").trim() };
|
|
43639
|
+
});
|
|
43640
|
+
}
|
|
43496
43641
|
function leftAloneReport(mentions) {
|
|
43497
43642
|
const full = [];
|
|
43498
43643
|
const prose = new Map;
|
|
@@ -43799,12 +43944,12 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
43799
43944
|
}
|
|
43800
43945
|
}
|
|
43801
43946
|
const afterwards = (path) => moves.get(path) ?? path;
|
|
43802
|
-
const
|
|
43947
|
+
const rewrites = rewritesOf(plan, texts, null);
|
|
43948
|
+
const mentions = asWritten([...plan.mentions, ...binaries], rewrites).map((mention) => ({
|
|
43803
43949
|
...mention,
|
|
43804
43950
|
file: afterwards(mention.file)
|
|
43805
43951
|
}));
|
|
43806
43952
|
const left = leftAloneReport(mentions);
|
|
43807
|
-
const rewrites = rewritesOf(plan, texts, null);
|
|
43808
43953
|
const absoluteOf = (path) => join37(projectPath, path.slice("res://".length));
|
|
43809
43954
|
const rewritten = new Map(rewrites.map((rewrite) => [rewrite.path, rewrite]));
|
|
43810
43955
|
const moved = [...moves].map(([source, target]) => {
|
|
@@ -50214,16 +50359,31 @@ function scriptsToDiagnose(projectPath, given) {
|
|
|
50214
50359
|
}
|
|
50215
50360
|
const inside = folderFiles(location.absolutePath, [".gd"]).map((script) => relative === "" ? script : `${relative}/${script}`);
|
|
50216
50361
|
if (inside.length === 0) {
|
|
50217
|
-
empty.push(entry);
|
|
50362
|
+
empty.push(noScriptUnder(entry, location.absolutePath, relative));
|
|
50218
50363
|
}
|
|
50219
50364
|
found.push(...inside);
|
|
50220
50365
|
}
|
|
50221
50366
|
const unique = [...new Set(found)];
|
|
50222
50367
|
if (unique.length === 0) {
|
|
50223
|
-
return { ok: false, reason:
|
|
50368
|
+
return { ok: false, reason: empty.join(" ") };
|
|
50224
50369
|
}
|
|
50225
50370
|
return { ok: true, value: unique };
|
|
50226
50371
|
}
|
|
50372
|
+
function scriptsUnderGdignore(projectPath, scripts) {
|
|
50373
|
+
const ignored = scripts.map((script) => script.replace(/^res:\/\//, "")).filter((script) => underGdignore(projectPath, script)).map((script) => `res://${script}`);
|
|
50374
|
+
return ignored.length === 0 ? {} : {
|
|
50375
|
+
underGdignore: ignored,
|
|
50376
|
+
underGdignoreNote: "The engine never loads a script under a folder holding a .gdignore, so what is reported for these does not stop the project from compiling or running."
|
|
50377
|
+
};
|
|
50378
|
+
}
|
|
50379
|
+
function noScriptUnder(entry, absolute, relative) {
|
|
50380
|
+
const said = (stepped) => {
|
|
50381
|
+
const folder = [relative, stepped.folder].filter((step) => step !== "").join("/") || entry;
|
|
50382
|
+
return stepped.why === "gdharness" ? `${folder} is an addon gdharness installed, whose scripts are checked when it is named` : `${folder} holds a .gdignore, so the engine never loads what is under it, and a script there is checked when the script is named`;
|
|
50383
|
+
};
|
|
50384
|
+
const stepped = steppedOverIn(absolute);
|
|
50385
|
+
return stepped.length === 0 ? `No .gd script is under ${entry}.` : `No .gd script is under ${entry} that a folder walk takes in: ${stepped.map(said).join("; ")}.`;
|
|
50386
|
+
}
|
|
50227
50387
|
function engineChecked(why) {
|
|
50228
50388
|
return {
|
|
50229
50389
|
checkedBy: "engine",
|
|
@@ -50269,6 +50429,7 @@ class GodotServer {
|
|
|
50269
50429
|
godotBridge;
|
|
50270
50430
|
tools = buildToolDefinitions();
|
|
50271
50431
|
activeProcess = null;
|
|
50432
|
+
lastCheckAt = null;
|
|
50272
50433
|
updates = new UpdateCheck(SERVER_VERSION);
|
|
50273
50434
|
noticedUpdate = false;
|
|
50274
50435
|
callsSinceNotice = 0;
|
|
@@ -51255,7 +51416,9 @@ class GodotServer {
|
|
|
51255
51416
|
button: args["button"] ?? "left",
|
|
51256
51417
|
double: readBoolean(args, "doubleClick") ?? false,
|
|
51257
51418
|
...readNonEmptyString(args, "says") === undefined ? {} : { says: readNonEmptyString(args, "says") },
|
|
51258
|
-
...args["index"] === undefined ? {} : { index: args["index"] }
|
|
51419
|
+
...args["index"] === undefined ? {} : { index: args["index"] },
|
|
51420
|
+
...args["x"] === undefined ? {} : { x: args["x"] },
|
|
51421
|
+
...args["y"] === undefined ? {} : { y: args["y"] }
|
|
51259
51422
|
}, { tool: "runtime_input", op });
|
|
51260
51423
|
}
|
|
51261
51424
|
if (op === "choose") {
|
|
@@ -52954,6 +53117,7 @@ ${error.text}`;
|
|
|
52954
53117
|
}
|
|
52955
53118
|
if (scripts?.value == null) {
|
|
52956
53119
|
const asked = readString(args, "scriptPath");
|
|
53120
|
+
let ignored = {};
|
|
52957
53121
|
if (project.ok && asked !== undefined) {
|
|
52958
53122
|
const location = resolveWithinProject(project.value.path, asked);
|
|
52959
53123
|
if (!location.ok) {
|
|
@@ -52962,13 +53126,22 @@ ${error.text}`;
|
|
|
52962
53126
|
if (!existsSync34(location.absolutePath)) {
|
|
52963
53127
|
return this.missingScript(project.value.path, location.relativePath);
|
|
52964
53128
|
}
|
|
53129
|
+
ignored = scriptsUnderGdignore(project.value.path, [location.relativePath]);
|
|
52965
53130
|
}
|
|
52966
53131
|
const one = await this.diagnosticsOf(args);
|
|
52967
53132
|
if ("noLanguageServer" in one) {
|
|
52968
53133
|
const checked = project.ok ? await this.engineDiagnostics(project.value.path, [readString(args, "scriptPath") ?? ""], one.noLanguageServer) : { refusal: project.response };
|
|
52969
|
-
return "refusal" in checked ? checked.refusal : this.jsonTextResponse({
|
|
53134
|
+
return "refusal" in checked ? checked.refusal : this.jsonTextResponse({
|
|
53135
|
+
...checked.answers[0],
|
|
53136
|
+
...engineChecked(one.noLanguageServer.reason),
|
|
53137
|
+
...ignored
|
|
53138
|
+
});
|
|
52970
53139
|
}
|
|
52971
|
-
return "refusal" in one ? one.refusal : this.jsonTextResponse(
|
|
53140
|
+
return "refusal" in one ? one.refusal : this.jsonTextResponse({
|
|
53141
|
+
...one.answer,
|
|
53142
|
+
checkedBy: "language server",
|
|
53143
|
+
...ignored
|
|
53144
|
+
});
|
|
52972
53145
|
}
|
|
52973
53146
|
const progress = callProgress();
|
|
52974
53147
|
const cancelled = callSignal();
|
|
@@ -52978,6 +53151,7 @@ ${error.text}`;
|
|
|
52978
53151
|
let warnings = 0;
|
|
52979
53152
|
let unread = 0;
|
|
52980
53153
|
let byEngine = null;
|
|
53154
|
+
let byServer = 0;
|
|
52981
53155
|
for (const [at, scriptPath] of scripts.value.entries()) {
|
|
52982
53156
|
if (cancelled?.aborted === true) {
|
|
52983
53157
|
return this.createErrorResponse(`Cancelled after ${at} of ${scripts.value.length} scripts.`);
|
|
@@ -53010,6 +53184,7 @@ ${error.text}`;
|
|
|
53010
53184
|
reported.push({ scriptPath, error: one.refusal.content[0]?.text ?? "not read" });
|
|
53011
53185
|
continue;
|
|
53012
53186
|
}
|
|
53187
|
+
byServer += 1;
|
|
53013
53188
|
errors += Number(one.answer["errors"]);
|
|
53014
53189
|
warnings += Number(one.answer["warnings"]);
|
|
53015
53190
|
if (readArray(one.answer, "diagnostics")?.length === 0) {
|
|
@@ -53026,7 +53201,9 @@ ${error.text}`;
|
|
|
53026
53201
|
...unread > 0 ? { scriptsNotRead: unread } : {},
|
|
53027
53202
|
scripts: reported,
|
|
53028
53203
|
nothingReported,
|
|
53029
|
-
...byEngine === null ? {} : engineChecked(byEngine)
|
|
53204
|
+
...byEngine === null ? { checkedBy: "language server" } : engineChecked(byEngine),
|
|
53205
|
+
...byEngine !== null && byServer > 0 ? { checkedBy: "language server, then engine", checkedByLanguageServer: byServer } : {},
|
|
53206
|
+
...project.ok ? scriptsUnderGdignore(project.value.path, scripts.value) : {}
|
|
53030
53207
|
});
|
|
53031
53208
|
}
|
|
53032
53209
|
missingScript(projectPath, relativePath) {
|
|
@@ -53568,10 +53745,19 @@ ${error.text}`;
|
|
|
53568
53745
|
return null;
|
|
53569
53746
|
}
|
|
53570
53747
|
const since = readNumber(asParams(answer), "sinceScanFinishedMs");
|
|
53748
|
+
const open = readStringArray(asParams(answer), "openScenes");
|
|
53749
|
+
const edited = readString(asParams(answer), "editedScene");
|
|
53571
53750
|
return {
|
|
53572
53751
|
scanning: readBoolean(asParams(answer), "scanning") ?? false,
|
|
53573
53752
|
importing: readBoolean(asParams(answer), "importing") ?? false,
|
|
53574
|
-
finishedMsAgo: since === undefined || since < 0 ? null : since
|
|
53753
|
+
finishedMsAgo: since === undefined || since < 0 ? null : since,
|
|
53754
|
+
...open === undefined ? {} : {
|
|
53755
|
+
scenes: {
|
|
53756
|
+
openScenes: open,
|
|
53757
|
+
editedScene: edited === undefined || edited === "" ? null : edited,
|
|
53758
|
+
unsavedScenes: readStringArray(asParams(answer), "unsavedScenes") ?? []
|
|
53759
|
+
}
|
|
53760
|
+
}
|
|
53575
53761
|
};
|
|
53576
53762
|
} catch {
|
|
53577
53763
|
return null;
|
|
@@ -53613,7 +53799,7 @@ ${error.text}`;
|
|
|
53613
53799
|
problem: reply.ok ? null : reply.message
|
|
53614
53800
|
};
|
|
53615
53801
|
}));
|
|
53616
|
-
const
|
|
53802
|
+
const askEditor = async () => {
|
|
53617
53803
|
const playing = await this.editorPlayingState();
|
|
53618
53804
|
await this.pickUpWhatTheEditorIsPlaying();
|
|
53619
53805
|
const current = await this.currentRun();
|
|
@@ -53624,14 +53810,20 @@ ${error.text}`;
|
|
|
53624
53810
|
run: current === null ? null : this.runNamed(current),
|
|
53625
53811
|
hold: current === null ? {} : await this.holdOf(current, active)
|
|
53626
53812
|
};
|
|
53627
|
-
}
|
|
53628
|
-
const
|
|
53813
|
+
};
|
|
53814
|
+
const connectedBefore = this.godotBridge.getStatus().connected;
|
|
53815
|
+
const [games, askedFirst, scanFirst, editorStatus, serversFirst] = await Promise.all([
|
|
53629
53816
|
pinged,
|
|
53630
|
-
|
|
53817
|
+
askEditor(),
|
|
53631
53818
|
this.editorScanState(),
|
|
53632
53819
|
this.getEditorStatusPayload(),
|
|
53633
53820
|
this.editorServersListening()
|
|
53634
53821
|
]);
|
|
53822
|
+
const askAgain = !connectedBefore && editorStatus.connected;
|
|
53823
|
+
if (askAgain) {
|
|
53824
|
+
this.logDebug("editor_status: the editor connected during the call, so it is asked again");
|
|
53825
|
+
}
|
|
53826
|
+
const [{ playing, active, run, hold }, scan, servers] = askAgain ? await Promise.all([askEditor(), this.editorScanState(), this.editorServersListening()]) : [askedFirst, scanFirst, serversFirst];
|
|
53635
53827
|
const answeredAt = Date.now();
|
|
53636
53828
|
const inFlight = this.godotBridge.requestsInFlight().map((request) => ({ tool: request.tool, forMs: answeredAt - request.startedAt }));
|
|
53637
53829
|
return this.jsonTextResponse({
|
|
@@ -53641,7 +53833,8 @@ ${error.text}`;
|
|
|
53641
53833
|
pendingRequests: inFlight.length,
|
|
53642
53834
|
pendingRequestTools: inFlight.length === 0 ? undefined : inFlight,
|
|
53643
53835
|
debugPort: playing?.debugPort ?? this.godotBridge.getStatus().debugPort,
|
|
53644
|
-
scan
|
|
53836
|
+
scan: scan === null ? null : { scanning: scan.scanning, importing: scan.importing, finishedMsAgo: scan.finishedMsAgo },
|
|
53837
|
+
...scan?.scenes
|
|
53645
53838
|
},
|
|
53646
53839
|
godot: {
|
|
53647
53840
|
path: located.ok ? located.path : null,
|
|
@@ -54391,8 +54584,16 @@ ${error.text}`;
|
|
|
54391
54584
|
return answer;
|
|
54392
54585
|
}
|
|
54393
54586
|
const startedAt = Date.now();
|
|
54587
|
+
const steps = [];
|
|
54588
|
+
let stepFrom = startedAt;
|
|
54589
|
+
const step = (name) => {
|
|
54590
|
+
const now = Date.now();
|
|
54591
|
+
steps.push(`${name} ${now - stepFrom}ms`);
|
|
54592
|
+
stepFrom = now;
|
|
54593
|
+
};
|
|
54394
54594
|
const transcript = openTranscript(startedAt);
|
|
54395
54595
|
closeSync5(transcript.fd);
|
|
54596
|
+
step("transcript");
|
|
54396
54597
|
const playAnswer = asParams(JSON.parse(answer.content[0]?.text ?? "{}"));
|
|
54397
54598
|
const which = playOf(playAnswer);
|
|
54398
54599
|
const played = {
|
|
@@ -54413,6 +54614,7 @@ ${error.text}`;
|
|
|
54413
54614
|
};
|
|
54414
54615
|
this.activeProcess = played;
|
|
54415
54616
|
this.noteTheLatestRun({ projectPath, pid: null, startedAt });
|
|
54617
|
+
step("latest run");
|
|
54416
54618
|
this.watchThePlayedConsole();
|
|
54417
54619
|
writeEditorRunNote({
|
|
54418
54620
|
projectPath,
|
|
@@ -54420,7 +54622,10 @@ ${error.text}`;
|
|
|
54420
54622
|
startedAt,
|
|
54421
54623
|
...which === null ? {} : { play: which }
|
|
54422
54624
|
});
|
|
54625
|
+
step("run note");
|
|
54423
54626
|
sweepTranscripts();
|
|
54627
|
+
step("sweep");
|
|
54628
|
+
this.logDebug(`After the play: ${steps.join(", ")}`);
|
|
54424
54629
|
return this.jsonTextResponse({
|
|
54425
54630
|
started: true,
|
|
54426
54631
|
through: "editor",
|
|
@@ -55139,7 +55344,8 @@ ${error.text}`;
|
|
|
55139
55344
|
const mine = this.ourProject();
|
|
55140
55345
|
const record = everyRunRecord().find((one) => mine === null || !isSameDirectory(one.projectPath, mine)) ?? null;
|
|
55141
55346
|
if (record === null) {
|
|
55142
|
-
|
|
55347
|
+
const checked = this.lastCheckAt === null ? "" : ` The editor_run check ${Math.round((Date.now() - this.lastCheckAt) / 1000)}s ago kept no run: its answer held what the game printed, under entries and printed.`;
|
|
55348
|
+
return `No game is running.${checked}${noEditor} Start one with editor_run.`;
|
|
55143
55349
|
}
|
|
55144
55350
|
const ours = mine === null ? "this server was started without GDHARNESS_PROJECT and has no editor connected, so it cannot say whose that run is" : `this server serves ${mine}`;
|
|
55145
55351
|
return `No game of this server's is running.${noEditor} A run started from ${record.projectPath} is recorded on this machine, and ${ours}, so it is not this server's to answer for or to end. Start one with editor_run.`;
|
|
@@ -55225,7 +55431,10 @@ ${error.text}`;
|
|
|
55225
55431
|
const errors = boot.log.count("error");
|
|
55226
55432
|
const warnings = boot.log.count("warning");
|
|
55227
55433
|
const floor = engineArgs.includes("--verbose") ? "info" : "warning";
|
|
55228
|
-
const
|
|
55434
|
+
const ordinary = boot.log.all.filter((entry) => entry.severity === "info");
|
|
55435
|
+
const printed = floor === "warning" ? foldedRepeats(ordinary).slice(-MOST_PRINTED_LINES) : [];
|
|
55436
|
+
const shown = printed.reduce((sum, entry) => sum + (entry.times ?? 1), 0);
|
|
55437
|
+
this.lastCheckAt = Date.now();
|
|
55229
55438
|
return this.jsonTextResponse({
|
|
55230
55439
|
booted: !hung && boot.exitCode === 0 && errors === 0,
|
|
55231
55440
|
hung,
|
|
@@ -55239,7 +55448,8 @@ ${error.text}`;
|
|
|
55239
55448
|
argsNote: engineFlagsNote(userArgs),
|
|
55240
55449
|
...scanWaitAnswer(scanned),
|
|
55241
55450
|
savesNote: asked.savesIn !== undefined && savesStayPut() ? SAVES_NOT_MOVED_NOTE : undefined,
|
|
55242
|
-
|
|
55451
|
+
printed: printed.length > 0 ? printed : undefined,
|
|
55452
|
+
printedLinesNotShown: floor === "warning" && ordinary.length > shown ? ordinary.length - shown : undefined,
|
|
55243
55453
|
...foldedEntriesAnswer(boot.log, floor)
|
|
55244
55454
|
});
|
|
55245
55455
|
}
|
|
@@ -56404,7 +56614,24 @@ ${error.text}`;
|
|
|
56404
56614
|
}
|
|
56405
56615
|
}
|
|
56406
56616
|
});
|
|
56407
|
-
|
|
56617
|
+
if (!this.godotBridge.isConnected()) {
|
|
56618
|
+
return answered;
|
|
56619
|
+
}
|
|
56620
|
+
const scanned = answered.isError === true || this.editorWritesAShortList(project.value.path) ? null : await this.handleRescanFilesystem({ projectPath: project.value.path });
|
|
56621
|
+
return await this.alsoSayWhatTheEditorCannotSee(scanned === null ? answered : this.withEditorScan(answered, scanned), args);
|
|
56622
|
+
}
|
|
56623
|
+
withEditorScan(answered, scanned) {
|
|
56624
|
+
const payload = asParams(JSON.parse(answered.content[0]?.text ?? "{}"));
|
|
56625
|
+
const scan = scanned.isError === true ? null : asParams(JSON.parse(scanned.content[0]?.text ?? "{}"));
|
|
56626
|
+
const broughtIn = scan === null ? undefined : readStringArray(scan, "broughtIn");
|
|
56627
|
+
return this.jsonTextResponse({
|
|
56628
|
+
...payload,
|
|
56629
|
+
editorRescanned: scan !== null && readBoolean(scan, "ok") === true,
|
|
56630
|
+
...broughtIn === undefined ? {} : { broughtIn },
|
|
56631
|
+
...scan === null ? {
|
|
56632
|
+
editorRescanNote: `The editor was asked to scan for the new class and answered: ${scanned.content[0]?.text ?? "nothing"}`
|
|
56633
|
+
} : readBoolean(scan, "ok") === true ? {} : { editorRescanNote: readString(scan, "note") ?? JSON.stringify(scan) }
|
|
56634
|
+
});
|
|
56408
56635
|
}
|
|
56409
56636
|
async handleModifyScript(args) {
|
|
56410
56637
|
const written = await this.headless("modify_script", args);
|
|
@@ -57385,7 +57612,7 @@ async function runGodotServer() {
|
|
|
57385
57612
|
const server = new GodotServer;
|
|
57386
57613
|
await server.run();
|
|
57387
57614
|
}
|
|
57388
|
-
var UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, FAILED_BUDGET = 1e6, ANSWER_BUDGET = 4000000, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, SUCCESSOR_SOUGHT_WITHIN_MS = 20000, CLOSE_ASK_MS = 3000, CONSOLE_WRAPPER, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_SETTLED_MS = 500, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", LOOPING_AFTER = 100, WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, PATH_SOLUTIONS, DESTINATION_ARGUMENTS, OUTPUT_PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, MOST_UNDECLARED_ERRORS = 20, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
|
|
57615
|
+
var UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, FAILED_BUDGET = 1e6, ANSWER_BUDGET = 4000000, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, SUCCESSOR_SOUGHT_WITHIN_MS = 20000, CLOSE_ASK_MS = 3000, CONSOLE_WRAPPER, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_SETTLED_MS = 500, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", LOOPING_AFTER = 100, WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, PATH_SOLUTIONS, DESTINATION_ARGUMENTS, OUTPUT_PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, MOST_PRINTED_LINES = 50, MOST_UNDECLARED_ERRORS = 20, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
|
|
57389
57616
|
var init_server = __esm(() => {
|
|
57390
57617
|
init_dist2();
|
|
57391
57618
|
init_stdio();
|
|
@@ -58220,7 +58447,7 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
58220
58447
|
mkdirSync8(shareDirectory, { recursive: true });
|
|
58221
58448
|
const chosen = machineSlots({ directory: options.slotsDirectory, count: options.slotCount });
|
|
58222
58449
|
const slotCount = chosen.count;
|
|
58223
|
-
const slots = new EngineSlots(chosen.directory, slotCount, { pid: process13.pid, started: await ownStart() }, (line) => {
|
|
58450
|
+
const slots = new EngineSlots(chosen.directory, slotCount, { pid: process13.pid, started: await ownStart(), by: `gdharness spread of ${options.projectPath}` }, (line) => {
|
|
58224
58451
|
console.log(`[spread] ${line}`);
|
|
58225
58452
|
});
|
|
58226
58453
|
const launch = {
|
|
@@ -58770,7 +58997,7 @@ async function runTestCommand(options, godotPath) {
|
|
|
58770
58997
|
mkdirSync10(runDirectory, { recursive: true });
|
|
58771
58998
|
const logs = new RunLogs(runDirectory, keptRuns === testRuns ? null : join27(keptRuns, runName));
|
|
58772
58999
|
const chosen = machineSlots({ directory: options.slotsDirectory, count: options.slotCount });
|
|
58773
|
-
const slots = new EngineSlots(chosen.directory, chosen.count, { pid: process14.pid, started: await ownStart() }, (line) => {
|
|
59000
|
+
const slots = new EngineSlots(chosen.directory, chosen.count, { pid: process14.pid, started: await ownStart(), by: `gdharness test of ${options.projectPath}` }, (line) => {
|
|
58774
59001
|
console.log(line);
|
|
58775
59002
|
});
|
|
58776
59003
|
const running = new Set;
|
|
@@ -59768,6 +59995,8 @@ async function main() {
|
|
|
59768
59995
|
console.error(`gdharness: ${line}`);
|
|
59769
59996
|
});
|
|
59770
59997
|
}
|
|
59998
|
+
const served = process.env["GDHARNESS_PROJECT"];
|
|
59999
|
+
nameSlotTaker(command !== undefined ? `gdharness ${command}` : `a gdharness server${served === undefined || served === "" ? "" : ` of ${served}`}`);
|
|
59771
60000
|
if (command === "test") {
|
|
59772
60001
|
await test();
|
|
59773
60002
|
return;
|