gdharness 1.1.14 → 1.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/cli.js
CHANGED
|
@@ -605,8 +605,18 @@ function resolveHeadless(requested, host) {
|
|
|
605
605
|
}
|
|
606
606
|
return envValue("DISPLAY", host.variables) === undefined && envValue("WAYLAND_DISPLAY", host.variables) === undefined;
|
|
607
607
|
}
|
|
608
|
+
function resolveSilent(requested, variables) {
|
|
609
|
+
if (typeof requested === "boolean") {
|
|
610
|
+
return requested;
|
|
611
|
+
}
|
|
612
|
+
const said = envValue("GDHARNESS_SILENT", variables)?.toLowerCase();
|
|
613
|
+
return said !== undefined && said !== "0" && said !== "false";
|
|
614
|
+
}
|
|
608
615
|
function runArguments(options) {
|
|
609
616
|
const args = options.headless ? ["--headless", "--path", options.projectPath] : ["--path", options.projectPath];
|
|
617
|
+
if (options.silent === true && !options.headless) {
|
|
618
|
+
args.push("--audio-driver", "Dummy");
|
|
619
|
+
}
|
|
610
620
|
if (options.quitAfter !== undefined && options.quitAfter !== null) {
|
|
611
621
|
args.push("--quit-after", String(options.quitAfter));
|
|
612
622
|
}
|
|
@@ -17137,6 +17147,11 @@ var init_tool_definitions = __esm(() => {
|
|
|
17137
17147
|
ops: ["start"],
|
|
17138
17148
|
description: "start: on Windows, show the window on the desktop in use. By default a windowed run this server starts goes on a desktop of its own, where it renders and runtime_capture works but the window never shows and never takes the keyboard. A game a visible editor plays opens on the desktop in use, and one a hidden editor (editor_launch hidden: true) plays goes on its desktop. Elsewhere than Windows the window shows either way. Default false."
|
|
17139
17149
|
},
|
|
17150
|
+
silent: {
|
|
17151
|
+
type: "boolean",
|
|
17152
|
+
ops: ["start"],
|
|
17153
|
+
description: "start: run the game with no sound out of the machine, by starting the engine with --audio-driver Dummy: every stream still plays and every playback position still advances, so what is playing can still be asked. The editor takes no engine flags for a game it plays, so a silent windowed run is started by this server, and the debug_* tools do not answer for it. A headless run, check's included, is silent already. Default false, or true when GDHARNESS_SILENT is set in the server's environment to anything but 0 or false; silent: false then plays through the editor as before."
|
|
17154
|
+
},
|
|
17140
17155
|
savesIn: {
|
|
17141
17156
|
type: "string",
|
|
17142
17157
|
ops: ["start", "check"],
|
|
@@ -41722,14 +41737,16 @@ class GodotServer {
|
|
|
41722
41737
|
});
|
|
41723
41738
|
const runtimeWaitMs = this.announceBudget(args, project.value.path);
|
|
41724
41739
|
const editorWouldPlay = !headless || editorPlaysHeadless(project.value.file);
|
|
41725
|
-
|
|
41740
|
+
const silent = resolveSilent(args["silent"], process.env) && !headless;
|
|
41741
|
+
if (this.godotBridge.isConnected() && editorWouldPlay && given.value.length === 0 && !needsItsOwnProcess(asked.value) && !silent) {
|
|
41726
41742
|
return await this.playThroughEditor(sceneArgument, refreshed.value, scanned, project.value.path, alreadyPlaying, runtimeWaitMs, ended);
|
|
41727
41743
|
}
|
|
41728
41744
|
const cmdArgs = runArguments({
|
|
41729
41745
|
projectPath: project.value.path,
|
|
41730
41746
|
headless,
|
|
41731
41747
|
scene: sceneArgument,
|
|
41732
|
-
userArgs: given.value
|
|
41748
|
+
userArgs: given.value,
|
|
41749
|
+
silent
|
|
41733
41750
|
});
|
|
41734
41751
|
this.logDebug(`Running Godot project: ${engine.value} ${cmdArgs.join(" ")}`);
|
|
41735
41752
|
const started = await this.launchKeptGame(engine.value, cmdArgs, project.value.path, needsItsOwnProcess(asked.value) ? environmentFor({ ...asked.value, runtimeDirectory: runtimeDirectory() }) : undefined, headless || args["visible"] === true ? undefined : HIDDEN_DESKTOP);
|
|
@@ -41740,7 +41757,7 @@ class GodotServer {
|
|
|
41740
41757
|
}
|
|
41741
41758
|
started.announcedBefore = alreadyPlaying;
|
|
41742
41759
|
this.activeProcess = started;
|
|
41743
|
-
const spawnedInstead = this.godotBridge.isConnected() && editorWouldPlay && given.value.length > 0 ? " The editor cannot be handed arguments for a game it plays, so this one was started " + "here: the debug_* tools answer only for a game the editor is playing." : this.godotBridge.isConnected() && editorWouldPlay && needsItsOwnProcess(asked.value) ? " The editor plays a game with its own environment, so a run given one was started " + "here: the debug_* tools answer only for a game the editor is playing." : "";
|
|
41760
|
+
const spawnedInstead = this.godotBridge.isConnected() && editorWouldPlay && given.value.length > 0 ? " The editor cannot be handed arguments for a game it plays, so this one was started " + "here: the debug_* tools answer only for a game the editor is playing." : this.godotBridge.isConnected() && editorWouldPlay && needsItsOwnProcess(asked.value) ? " The editor plays a game with its own environment, so a run given one was started " + "here: the debug_* tools answer only for a game the editor is playing." : this.godotBridge.isConnected() && editorWouldPlay && silent ? " The editor cannot play a game silent, which takes an engine flag, so this one was " + `started here${args["silent"] === true ? "" : ", silent because GDHARNESS_SILENT says so"}: the debug_* tools answer only for a game the editor is playing, and silent: false plays it through the editor.` : "";
|
|
41744
41761
|
const endedForThis = endedToStartThis(ended);
|
|
41745
41762
|
const stranded = wereHereFirst.filter((one) => one.pid !== ended?.pid && alive(one.pid));
|
|
41746
41763
|
const alsoRunning = leftRunningNote(stranded);
|
|
@@ -39,6 +39,11 @@ var _values: Values
|
|
|
39
39
|
var _pointer: Vector2 = Vector2.ZERO
|
|
40
40
|
var _pointer_placed: bool = false
|
|
41
41
|
|
|
42
|
+
## When the pointer last arrived, and how long it took over the arrival before that, in seconds: what
|
|
43
|
+
## turns a motion's distance into the speed a real one carries.
|
|
44
|
+
var _pointer_at_usec: int = 0
|
|
45
|
+
var _arrival_seconds: float = 1.0 / 60.0
|
|
46
|
+
|
|
42
47
|
|
|
43
48
|
func _init(host: Node, values: Values) -> void:
|
|
44
49
|
_host = host
|
|
@@ -46,9 +51,15 @@ func _init(host: Node, values: Values) -> void:
|
|
|
46
51
|
|
|
47
52
|
|
|
48
53
|
## The movement a pointer arriving at [param position] carries, which is the distance from where
|
|
49
|
-
## the last injected event put it, and none at all for the first. The arrival is recorded
|
|
54
|
+
## the last injected event put it, and none at all for the first. The arrival is recorded, with how
|
|
55
|
+
## long it took: at least a frame, since two motions sent in one frame did not cross the screen in
|
|
56
|
+
## no time at all.
|
|
50
57
|
func _arrive(position: Vector2) -> Vector2:
|
|
58
|
+
var now: int = Time.get_ticks_usec()
|
|
51
59
|
var relative: Vector2 = position - _pointer if _pointer_placed else Vector2.ZERO
|
|
60
|
+
var took: float = float(now - _pointer_at_usec) / 1_000_000.0 if _pointer_placed else 0.0
|
|
61
|
+
_arrival_seconds = maxf(took, 1.0 / 60.0)
|
|
62
|
+
_pointer_at_usec = now
|
|
52
63
|
_pointer = position
|
|
53
64
|
_pointer_placed = true
|
|
54
65
|
return relative
|
|
@@ -839,12 +850,19 @@ func _click_in_the_world(node_path: String, item: Node3D, params: Dictionary) ->
|
|
|
839
850
|
## The buttons a real pointer event carries are the ones held as it happens, and Input keeps that
|
|
840
851
|
## from every button event it is given, injected ones included, so a motion between a held click
|
|
841
852
|
## and its release is a drag to a control that reads the mask rather than remembering the click.
|
|
853
|
+
##
|
|
854
|
+
## And the speed, the distance over the time the pointer took, which only the platform fills in. A
|
|
855
|
+
## menu ignores a motion with none, so that one opening under a resting pointer lights nothing: a
|
|
856
|
+
## motion over an open drop-down's item answered as injected and the menu highlighted nothing. A
|
|
857
|
+
## motion that goes nowhere still has none, as a resting pointer does.
|
|
842
858
|
func _motion(position: Vector2, relative: Vector2) -> InputEventMouseMotion:
|
|
843
859
|
var event: InputEventMouseMotion = InputEventMouseMotion.new()
|
|
844
860
|
event.position = position
|
|
845
861
|
event.global_position = position
|
|
846
862
|
event.relative = relative
|
|
847
863
|
event.screen_relative = relative
|
|
864
|
+
event.velocity = relative / _arrival_seconds
|
|
865
|
+
event.screen_velocity = event.velocity
|
|
848
866
|
event.button_mask = Input.get_mouse_button_mask()
|
|
849
867
|
return event
|
|
850
868
|
|
package/build/index.js
CHANGED
|
@@ -24825,8 +24825,18 @@ function resolveHeadless(requested, host) {
|
|
|
24825
24825
|
}
|
|
24826
24826
|
return envValue("DISPLAY", host.variables) === undefined && envValue("WAYLAND_DISPLAY", host.variables) === undefined;
|
|
24827
24827
|
}
|
|
24828
|
+
function resolveSilent(requested, variables) {
|
|
24829
|
+
if (typeof requested === "boolean") {
|
|
24830
|
+
return requested;
|
|
24831
|
+
}
|
|
24832
|
+
const said = envValue("GDHARNESS_SILENT", variables)?.toLowerCase();
|
|
24833
|
+
return said !== undefined && said !== "0" && said !== "false";
|
|
24834
|
+
}
|
|
24828
24835
|
function runArguments(options) {
|
|
24829
24836
|
const args = options.headless ? ["--headless", "--path", options.projectPath] : ["--path", options.projectPath];
|
|
24837
|
+
if (options.silent === true && !options.headless) {
|
|
24838
|
+
args.push("--audio-driver", "Dummy");
|
|
24839
|
+
}
|
|
24830
24840
|
if (options.quitAfter !== undefined && options.quitAfter !== null) {
|
|
24831
24841
|
args.push("--quit-after", String(options.quitAfter));
|
|
24832
24842
|
}
|
|
@@ -30794,6 +30804,11 @@ var TOOL_SPECS = [
|
|
|
30794
30804
|
ops: ["start"],
|
|
30795
30805
|
description: "start: on Windows, show the window on the desktop in use. By default a windowed run this server starts goes on a desktop of its own, where it renders and runtime_capture works but the window never shows and never takes the keyboard. A game a visible editor plays opens on the desktop in use, and one a hidden editor (editor_launch hidden: true) plays goes on its desktop. Elsewhere than Windows the window shows either way. Default false."
|
|
30796
30806
|
},
|
|
30807
|
+
silent: {
|
|
30808
|
+
type: "boolean",
|
|
30809
|
+
ops: ["start"],
|
|
30810
|
+
description: "start: run the game with no sound out of the machine, by starting the engine with --audio-driver Dummy: every stream still plays and every playback position still advances, so what is playing can still be asked. The editor takes no engine flags for a game it plays, so a silent windowed run is started by this server, and the debug_* tools do not answer for it. A headless run, check's included, is silent already. Default false, or true when GDHARNESS_SILENT is set in the server's environment to anything but 0 or false; silent: false then plays through the editor as before."
|
|
30811
|
+
},
|
|
30797
30812
|
savesIn: {
|
|
30798
30813
|
type: "string",
|
|
30799
30814
|
ops: ["start", "check"],
|
|
@@ -34182,14 +34197,16 @@ class GodotServer {
|
|
|
34182
34197
|
});
|
|
34183
34198
|
const runtimeWaitMs = this.announceBudget(args, project.value.path);
|
|
34184
34199
|
const editorWouldPlay = !headless || editorPlaysHeadless(project.value.file);
|
|
34185
|
-
|
|
34200
|
+
const silent = resolveSilent(args["silent"], process.env) && !headless;
|
|
34201
|
+
if (this.godotBridge.isConnected() && editorWouldPlay && given.value.length === 0 && !needsItsOwnProcess(asked.value) && !silent) {
|
|
34186
34202
|
return await this.playThroughEditor(sceneArgument, refreshed.value, scanned, project.value.path, alreadyPlaying, runtimeWaitMs, ended);
|
|
34187
34203
|
}
|
|
34188
34204
|
const cmdArgs = runArguments({
|
|
34189
34205
|
projectPath: project.value.path,
|
|
34190
34206
|
headless,
|
|
34191
34207
|
scene: sceneArgument,
|
|
34192
|
-
userArgs: given.value
|
|
34208
|
+
userArgs: given.value,
|
|
34209
|
+
silent
|
|
34193
34210
|
});
|
|
34194
34211
|
this.logDebug(`Running Godot project: ${engine.value} ${cmdArgs.join(" ")}`);
|
|
34195
34212
|
const started = await this.launchKeptGame(engine.value, cmdArgs, project.value.path, needsItsOwnProcess(asked.value) ? environmentFor({ ...asked.value, runtimeDirectory: runtimeDirectory() }) : undefined, headless || args["visible"] === true ? undefined : HIDDEN_DESKTOP);
|
|
@@ -34200,7 +34217,7 @@ class GodotServer {
|
|
|
34200
34217
|
}
|
|
34201
34218
|
started.announcedBefore = alreadyPlaying;
|
|
34202
34219
|
this.activeProcess = started;
|
|
34203
|
-
const spawnedInstead = this.godotBridge.isConnected() && editorWouldPlay && given.value.length > 0 ? " The editor cannot be handed arguments for a game it plays, so this one was started " + "here: the debug_* tools answer only for a game the editor is playing." : this.godotBridge.isConnected() && editorWouldPlay && needsItsOwnProcess(asked.value) ? " The editor plays a game with its own environment, so a run given one was started " + "here: the debug_* tools answer only for a game the editor is playing." : "";
|
|
34220
|
+
const spawnedInstead = this.godotBridge.isConnected() && editorWouldPlay && given.value.length > 0 ? " The editor cannot be handed arguments for a game it plays, so this one was started " + "here: the debug_* tools answer only for a game the editor is playing." : this.godotBridge.isConnected() && editorWouldPlay && needsItsOwnProcess(asked.value) ? " The editor plays a game with its own environment, so a run given one was started " + "here: the debug_* tools answer only for a game the editor is playing." : this.godotBridge.isConnected() && editorWouldPlay && silent ? " The editor cannot play a game silent, which takes an engine flag, so this one was " + `started here${args["silent"] === true ? "" : ", silent because GDHARNESS_SILENT says so"}: the debug_* tools answer only for a game the editor is playing, and silent: false plays it through the editor.` : "";
|
|
34204
34221
|
const endedForThis = endedToStartThis(ended);
|
|
34205
34222
|
const stranded = wereHereFirst.filter((one) => one.pid !== ended?.pid && alive(one.pid));
|
|
34206
34223
|
const alsoRunning = leftRunningNote(stranded);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.15",
|
|
4
4
|
"mcpName": "io.github.Aureliolo/gdharness",
|
|
5
5
|
"description": "A harness for driving a Godot 4 project from an agent: editor addons, a runtime bridge into the running game, an MCP server in front of them, and a CLI that installs and diagnoses the Godot side.",
|
|
6
6
|
"type": "module",
|