@satelliteoflove/godot-mcp 3.10.0 → 3.11.0
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/addon/commands/input_commands.gd +33 -3
- package/addon/core/mcp_debugger_plugin.gd +29 -2
- package/addon/game_bridge/mcp_game_bridge.gd +167 -9
- package/addon/plugin.cfg +1 -1
- package/dist/__tests__/tools/input.test.js +80 -0
- package/dist/__tests__/tools/input.test.js.map +1 -1
- package/dist/tools/input.d.ts +1 -0
- package/dist/tools/input.d.ts.map +1 -1
- package/dist/tools/input.js +46 -3
- package/dist/tools/input.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,6 +3,11 @@ extends MCPBaseCommand
|
|
|
3
3
|
class_name MCPInputCommands
|
|
4
4
|
|
|
5
5
|
const INPUT_TIMEOUT := 30.0
|
|
6
|
+
# How long to wait for the game bridge to report it is ready to receive input
|
|
7
|
+
# before giving up. The natural workflow is run -> immediately drive the game;
|
|
8
|
+
# the session connects before the scene loads, so this short wait absorbs that
|
|
9
|
+
# gap (usually under a second) instead of dispatching input into a void (#241).
|
|
10
|
+
const READY_TIMEOUT := 10.0
|
|
6
11
|
|
|
7
12
|
var _input_map_result: Dictionary = {}
|
|
8
13
|
var _input_map_pending: bool = false
|
|
@@ -15,6 +20,9 @@ var _type_text_result: Dictionary = {}
|
|
|
15
20
|
var _type_text_pending: bool = false
|
|
16
21
|
|
|
17
22
|
|
|
23
|
+
const _BRIDGE_NOT_READY_MSG := "Game is running but its MCP bridge is not ready to receive input yet (no scene up, or the game just launched). This usually clears within a second of run — retry shortly."
|
|
24
|
+
|
|
25
|
+
|
|
18
26
|
func get_commands() -> Dictionary:
|
|
19
27
|
return {
|
|
20
28
|
"get_input_map": get_input_map,
|
|
@@ -23,6 +31,23 @@ func get_commands() -> Dictionary:
|
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
|
|
34
|
+
# Block until the running game's bridge reports it can consume input, bounded by
|
|
35
|
+
# READY_TIMEOUT. Returns true once ready, false if the game stops or never comes
|
|
36
|
+
# up in time. In the common case (game already running) this returns immediately
|
|
37
|
+
# without waiting a frame. Gating input on this is the fix for #241: the debug
|
|
38
|
+
# session connects before the main scene loads, so input dispatched on
|
|
39
|
+
# has_active_session() alone lands in a game with nothing to receive it.
|
|
40
|
+
func _await_bridge_ready(debugger_plugin) -> bool:
|
|
41
|
+
var start_time := Time.get_ticks_msec()
|
|
42
|
+
while not debugger_plugin.is_bridge_ready():
|
|
43
|
+
if not EditorInterface.is_playing_scene():
|
|
44
|
+
return false # game stopped or crashed while we waited
|
|
45
|
+
await Engine.get_main_loop().process_frame
|
|
46
|
+
if (Time.get_ticks_msec() - start_time) / 1000.0 > READY_TIMEOUT:
|
|
47
|
+
return false
|
|
48
|
+
return true
|
|
49
|
+
|
|
50
|
+
|
|
26
51
|
func get_input_map(_params: Dictionary) -> Dictionary:
|
|
27
52
|
if not EditorInterface.is_playing_scene():
|
|
28
53
|
return _get_editor_input_map()
|
|
@@ -106,6 +131,7 @@ func _on_input_map_received(actions: Array, error: String) -> void:
|
|
|
106
131
|
|
|
107
132
|
func execute_input_sequence(params: Dictionary) -> Dictionary:
|
|
108
133
|
var inputs: Array = params.get("inputs", [])
|
|
134
|
+
var report: Array = params.get("report", [])
|
|
109
135
|
if inputs.is_empty():
|
|
110
136
|
return _error("INVALID_PARAMS", "inputs array is required and must not be empty")
|
|
111
137
|
|
|
@@ -113,8 +139,10 @@ func execute_input_sequence(params: Dictionary) -> Dictionary:
|
|
|
113
139
|
return _error("NOT_RUNNING", "No game is currently running")
|
|
114
140
|
|
|
115
141
|
var debugger_plugin = _plugin.get_debugger_plugin() if _plugin else null
|
|
116
|
-
if debugger_plugin == null
|
|
142
|
+
if debugger_plugin == null:
|
|
117
143
|
return _error("NO_SESSION", "No active debug session")
|
|
144
|
+
if not await _await_bridge_ready(debugger_plugin):
|
|
145
|
+
return _error("BRIDGE_NOT_READY", _BRIDGE_NOT_READY_MSG)
|
|
118
146
|
|
|
119
147
|
var max_end_time: float = 0.0
|
|
120
148
|
for input in inputs:
|
|
@@ -128,7 +156,7 @@ func execute_input_sequence(params: Dictionary) -> Dictionary:
|
|
|
128
156
|
_sequence_result = {}
|
|
129
157
|
|
|
130
158
|
debugger_plugin.input_sequence_completed.connect(_on_sequence_completed, CONNECT_ONE_SHOT)
|
|
131
|
-
debugger_plugin.request_input_sequence(inputs)
|
|
159
|
+
debugger_plugin.request_input_sequence(inputs, report)
|
|
132
160
|
|
|
133
161
|
var start_time := Time.get_ticks_msec()
|
|
134
162
|
while _sequence_pending:
|
|
@@ -162,8 +190,10 @@ func type_text(params: Dictionary) -> Dictionary:
|
|
|
162
190
|
return _error("NOT_RUNNING", "No game is currently running")
|
|
163
191
|
|
|
164
192
|
var debugger_plugin = _plugin.get_debugger_plugin() if _plugin else null
|
|
165
|
-
if debugger_plugin == null
|
|
193
|
+
if debugger_plugin == null:
|
|
166
194
|
return _error("NO_SESSION", "No active debug session")
|
|
195
|
+
if not await _await_bridge_ready(debugger_plugin):
|
|
196
|
+
return _error("BRIDGE_NOT_READY", _BRIDGE_NOT_READY_MSG)
|
|
167
197
|
|
|
168
198
|
var timeout := max(INPUT_TIMEOUT, (text.length() * delay_ms / 1000.0) + 5.0)
|
|
169
199
|
|
|
@@ -10,8 +10,13 @@ signal input_map_received(actions: Array, error: String)
|
|
|
10
10
|
signal input_sequence_completed(result: Dictionary)
|
|
11
11
|
signal type_text_completed(result: Dictionary)
|
|
12
12
|
signal game_response(message_type: String, data: Variant)
|
|
13
|
+
signal bridge_ready()
|
|
13
14
|
|
|
14
15
|
var _active_session_id: int = -1
|
|
16
|
+
# True once the running game's bridge has announced it is ready to receive input
|
|
17
|
+
# (its main scene is up). The debug session connects before the scene loads, so
|
|
18
|
+
# has_active_session() alone is not enough to know input will land (#241).
|
|
19
|
+
var _bridge_ready: bool = false
|
|
15
20
|
var _pending_screenshot: bool = false
|
|
16
21
|
var _pending_debug_output: bool = false
|
|
17
22
|
var _pending_performance_metrics: bool = false
|
|
@@ -53,15 +58,30 @@ func _capture(message: String, data: Array, session_id: int) -> bool:
|
|
|
53
58
|
"godot_mcp:game_response":
|
|
54
59
|
_handle_game_response(data)
|
|
55
60
|
return true
|
|
61
|
+
"godot_mcp:bridge_ready":
|
|
62
|
+
_handle_bridge_ready(session_id)
|
|
63
|
+
return true
|
|
56
64
|
return false
|
|
57
65
|
|
|
58
66
|
|
|
67
|
+
func _handle_bridge_ready(session_id: int) -> void:
|
|
68
|
+
# Only the active session's bridge counts; ignore a late message from a prior
|
|
69
|
+
# run (a new _setup_session has already reset the flag for the current one).
|
|
70
|
+
if session_id != _active_session_id:
|
|
71
|
+
return
|
|
72
|
+
_bridge_ready = true
|
|
73
|
+
bridge_ready.emit()
|
|
74
|
+
|
|
75
|
+
|
|
59
76
|
func _setup_session(session_id: int) -> void:
|
|
60
77
|
_active_session_id = session_id
|
|
78
|
+
# New game session: its bridge has not announced readiness yet.
|
|
79
|
+
_bridge_ready = false
|
|
61
80
|
|
|
62
81
|
|
|
63
82
|
func _session_stopped() -> void:
|
|
64
83
|
_active_session_id = -1
|
|
84
|
+
_bridge_ready = false
|
|
65
85
|
if _pending_screenshot:
|
|
66
86
|
_pending_screenshot = false
|
|
67
87
|
screenshot_received.emit(false, "", 0, 0, "Game session ended")
|
|
@@ -97,6 +117,13 @@ func has_active_session() -> bool:
|
|
|
97
117
|
return true
|
|
98
118
|
|
|
99
119
|
|
|
120
|
+
# True only once the running game's bridge has reported its main scene is up and
|
|
121
|
+
# can consume input. Input commands gate on this (not just has_active_session) so
|
|
122
|
+
# a sequence injected right after run is not dispatched into a half-booted game.
|
|
123
|
+
func is_bridge_ready() -> bool:
|
|
124
|
+
return _bridge_ready and has_active_session()
|
|
125
|
+
|
|
126
|
+
|
|
100
127
|
func request_screenshot(max_width: int = 1024, quality: float = 0.75) -> void:
|
|
101
128
|
if _active_session_id < 0:
|
|
102
129
|
screenshot_received.emit(false, "", 0, 0, "No active game session")
|
|
@@ -202,14 +229,14 @@ func _handle_input_map_result(data: Array) -> void:
|
|
|
202
229
|
input_map_received.emit(actions, error)
|
|
203
230
|
|
|
204
231
|
|
|
205
|
-
func request_input_sequence(inputs: Array) -> void:
|
|
232
|
+
func request_input_sequence(inputs: Array, report: Array = []) -> void:
|
|
206
233
|
if _active_session_id < 0:
|
|
207
234
|
input_sequence_completed.emit({"error": "No active game session"})
|
|
208
235
|
return
|
|
209
236
|
_pending_input_sequence = true
|
|
210
237
|
var session := get_session(_active_session_id)
|
|
211
238
|
if session:
|
|
212
|
-
session.send_message("godot_mcp:execute_input_sequence", [inputs])
|
|
239
|
+
session.send_message("godot_mcp:execute_input_sequence", [inputs, report])
|
|
213
240
|
else:
|
|
214
241
|
_pending_input_sequence = false
|
|
215
242
|
input_sequence_completed.emit({"error": "Could not get debugger session"})
|
|
@@ -5,10 +5,20 @@ const DEFAULT_MAX_WIDTH := 1024
|
|
|
5
5
|
const DEFAULT_JPEG_QUALITY := 0.75
|
|
6
6
|
const Onscreen := preload("onscreen.gd")
|
|
7
7
|
|
|
8
|
+
# Cap on frames waited for the main scene to appear before announcing ready
|
|
9
|
+
# anyway. The scene is normally added within a frame or two of the bridge
|
|
10
|
+
# autoload's _ready; the cap only matters for a scene-less run (a SceneTree-only
|
|
11
|
+
# tool), so it never blocks readiness forever. ~10s at 60 fps.
|
|
12
|
+
const READY_SCENE_WAIT_FRAMES := 600
|
|
13
|
+
|
|
8
14
|
var _logger: _MCPGameLogger
|
|
9
15
|
var _profiler: MCPFrameProfiler
|
|
10
16
|
var _sampler: MCPRuntimeStateSampler
|
|
11
17
|
|
|
18
|
+
# Set once the bridge has told the editor the game is ready to drive. Guards the
|
|
19
|
+
# announcement against firing twice and lets the headless test observe it.
|
|
20
|
+
var _ready_announced := false
|
|
21
|
+
|
|
12
22
|
|
|
13
23
|
func _ready() -> void:
|
|
14
24
|
# The bridge must keep processing while the scene tree is paused. Input
|
|
@@ -39,6 +49,10 @@ func _ready() -> void:
|
|
|
39
49
|
_engage_freeze()
|
|
40
50
|
MCPLog.info("Game bridge: launched frozen")
|
|
41
51
|
|
|
52
|
+
# Tell the editor when the game is actually drivable, so input injected right
|
|
53
|
+
# after `run` is not silently dropped into a half-booted game (see #241).
|
|
54
|
+
_announce_bridge_ready_when_drivable()
|
|
55
|
+
|
|
42
56
|
|
|
43
57
|
func _exit_tree() -> void:
|
|
44
58
|
# Guaranteed cleanup: never leave an action latched when the bridge node
|
|
@@ -50,9 +64,38 @@ func _exit_tree() -> void:
|
|
|
50
64
|
EngineDebugger.unregister_profiler("mcp_frame_profiler")
|
|
51
65
|
|
|
52
66
|
|
|
67
|
+
# The bridge autoload's _ready runs BEFORE the main scene is added to the tree,
|
|
68
|
+
# so the debug session is live (and the editor sees has_active_session) while
|
|
69
|
+
# current_scene is still null. Input injected in that window is dispatched into a
|
|
70
|
+
# game that has nothing to consume it — reported as executed, but a silent no-op
|
|
71
|
+
# (#241). Wait for the scene to exist plus one frame (so its own _ready/input
|
|
72
|
+
# wiring has run), then announce readiness; the editor gates input on this signal.
|
|
73
|
+
func _announce_bridge_ready_when_drivable() -> void:
|
|
74
|
+
var tree := get_tree()
|
|
75
|
+
if tree == null:
|
|
76
|
+
return
|
|
77
|
+
var frames := 0
|
|
78
|
+
while tree.current_scene == null and frames < READY_SCENE_WAIT_FRAMES:
|
|
79
|
+
await tree.process_frame
|
|
80
|
+
frames += 1
|
|
81
|
+
# One more frame so a freshly-added scene has had its first _ready/process pass.
|
|
82
|
+
# process_frame fires even while paused, so launch-frozen runs still report ready.
|
|
83
|
+
await tree.process_frame
|
|
84
|
+
var scene_path := tree.current_scene.scene_file_path if tree.current_scene else ""
|
|
85
|
+
_emit_bridge_ready(scene_path)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
func _emit_bridge_ready(scene_path: String) -> void:
|
|
89
|
+
if _ready_announced:
|
|
90
|
+
return
|
|
91
|
+
_ready_announced = true
|
|
92
|
+
EngineDebugger.send_message("godot_mcp:bridge_ready", [scene_path])
|
|
93
|
+
MCPLog.info("Game bridge: ready to drive (%s)" % scene_path)
|
|
94
|
+
|
|
95
|
+
|
|
53
96
|
func _process(delta: float) -> void:
|
|
54
97
|
_game_time_process(delta)
|
|
55
|
-
_sequence_process()
|
|
98
|
+
_sequence_process(delta)
|
|
56
99
|
|
|
57
100
|
|
|
58
101
|
# Processing is needed by three independent features; only switch it off when
|
|
@@ -62,10 +105,31 @@ func _update_processing() -> void:
|
|
|
62
105
|
set_process(_sequence_running or _frozen or _step_active)
|
|
63
106
|
|
|
64
107
|
|
|
65
|
-
func _sequence_process() -> void:
|
|
66
|
-
if not _sequence_running
|
|
108
|
+
func _sequence_process(delta: float) -> void:
|
|
109
|
+
if not _sequence_running:
|
|
67
110
|
return
|
|
68
111
|
|
|
112
|
+
var tree := get_tree()
|
|
113
|
+
|
|
114
|
+
# Drain phase: the timeline is exhausted, but a requested effect probe still
|
|
115
|
+
# needs its `after` reading. The bridge runs BEFORE the scene and injected
|
|
116
|
+
# events flush at the top of the NEXT frame, so a snapshot taken the instant
|
|
117
|
+
# the queue empties would precede gameplay processing the final input — a real
|
|
118
|
+
# effect would read as a no-op. Let a couple of gameplay frames elapse first.
|
|
119
|
+
if _sequence_draining:
|
|
120
|
+
if tree and not tree.paused:
|
|
121
|
+
_sequence_gameplay_ms += delta * 1000.0
|
|
122
|
+
_sequence_settle_remaining -= 1
|
|
123
|
+
if _sequence_settle_remaining <= 0:
|
|
124
|
+
_emit_sequence_result()
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
# Game time the sequence actually advanced (unpaused, scaled) vs. wall time
|
|
128
|
+
# is a no-setup no-op signal: a sequence that ran entirely under a pause or
|
|
129
|
+
# freeze shows gameplay_ms ~= 0 against a full wall_ms.
|
|
130
|
+
if tree and not tree.paused:
|
|
131
|
+
_sequence_gameplay_ms += delta * 1000.0
|
|
132
|
+
|
|
69
133
|
var elapsed := Time.get_ticks_msec() - _sequence_start_time
|
|
70
134
|
|
|
71
135
|
while _sequence_events.size() > 0 and _sequence_events[0].time <= elapsed:
|
|
@@ -82,12 +146,61 @@ func _sequence_process() -> void:
|
|
|
82
146
|
_actions_completed += 1
|
|
83
147
|
|
|
84
148
|
if _sequence_events.is_empty():
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
149
|
+
if _sequence_report.is_empty():
|
|
150
|
+
_emit_sequence_result()
|
|
151
|
+
else:
|
|
152
|
+
# Defer the result so the effect probe's `after` reflects the final input.
|
|
153
|
+
_sequence_draining = true
|
|
154
|
+
_sequence_settle_remaining = SEQUENCE_SETTLE_FRAMES
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# Assemble and send the input-sequence result, then reset probe state. Carries an
|
|
158
|
+
# effect signal (#240): always-on context (scene / pause / freeze / game-vs-wall
|
|
159
|
+
# time) plus, when the caller attached a `report`, the per-expression before->after
|
|
160
|
+
# delta and an `any_changed` summary — enough to tell "inputs changed the world"
|
|
161
|
+
# from "inputs fell into the void" in one round-trip.
|
|
162
|
+
func _emit_sequence_result() -> void:
|
|
163
|
+
_sequence_running = false
|
|
164
|
+
_sequence_draining = false
|
|
165
|
+
_update_processing()
|
|
166
|
+
|
|
167
|
+
var tree := get_tree()
|
|
168
|
+
var result: Dictionary = {
|
|
169
|
+
"completed": true,
|
|
170
|
+
"actions_executed": _actions_completed,
|
|
171
|
+
"scene": tree.current_scene.scene_file_path if tree and tree.current_scene else "",
|
|
172
|
+
"tree_paused": tree.paused if tree else false,
|
|
173
|
+
"frozen": _frozen,
|
|
174
|
+
"gameplay_ms": roundi(_sequence_gameplay_ms),
|
|
175
|
+
"wall_ms": Time.get_ticks_msec() - _sequence_start_time,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if not _sequence_report.is_empty():
|
|
179
|
+
var after := _evaluate_report(_sequence_report, _sequence_report_inputs)
|
|
180
|
+
result.merge(_compute_report_deltas(_sequence_report_before, after))
|
|
181
|
+
|
|
182
|
+
_sequence_report = []
|
|
183
|
+
_sequence_report_inputs = []
|
|
184
|
+
_sequence_report_before = {}
|
|
185
|
+
|
|
186
|
+
EngineDebugger.send_message("godot_mcp:input_sequence_result", [result])
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# Pure before/after diff over the probe expressions: {report: {src: {before, after,
|
|
190
|
+
# changed}}, any_changed}. A missing `after` (expression started erroring) reads as
|
|
191
|
+
# null and so counts as changed — the world did move. Kept side-effect-free so the
|
|
192
|
+
# headless test can assert it directly.
|
|
193
|
+
func _compute_report_deltas(before: Dictionary, after: Dictionary) -> Dictionary:
|
|
194
|
+
var deltas: Dictionary = {}
|
|
195
|
+
var any_changed := false
|
|
196
|
+
for src in before:
|
|
197
|
+
var b: Variant = before[src]
|
|
198
|
+
var a: Variant = after.get(src, null)
|
|
199
|
+
var changed: bool = b != a
|
|
200
|
+
if changed:
|
|
201
|
+
any_changed = true
|
|
202
|
+
deltas[src] = {"before": b, "after": a, "changed": changed}
|
|
203
|
+
return {"report": deltas, "any_changed": any_changed}
|
|
91
204
|
|
|
92
205
|
|
|
93
206
|
var _sequence_events: Array = []
|
|
@@ -95,6 +208,20 @@ var _sequence_start_time: int = 0
|
|
|
95
208
|
var _sequence_running: bool = false
|
|
96
209
|
var _actions_completed: int = 0
|
|
97
210
|
var _actions_total: int = 0
|
|
211
|
+
# Game time (unpaused, scaled) accumulated across the sequence window — compared
|
|
212
|
+
# against wall time in the result to flag a sequence that ran under a pause/freeze.
|
|
213
|
+
var _sequence_gameplay_ms: float = 0.0
|
|
214
|
+
# Drain phase: after the timeline empties, hold for a few frames so an effect
|
|
215
|
+
# probe's `after` reflects the final input before the result is sent.
|
|
216
|
+
var _sequence_draining: bool = false
|
|
217
|
+
var _sequence_settle_remaining: int = 0
|
|
218
|
+
const SEQUENCE_SETTLE_FRAMES := 2
|
|
219
|
+
# Optional effect probe (#240): compiled GDScript expressions [{src, expr}]
|
|
220
|
+
# evaluated in the step_until predicate context, once before the first input and
|
|
221
|
+
# again after the last, to prove the sequence changed something.
|
|
222
|
+
var _sequence_report: Array = []
|
|
223
|
+
var _sequence_report_inputs: Array = []
|
|
224
|
+
var _sequence_report_before: Dictionary = {}
|
|
98
225
|
# Actions whose press has been injected but whose paired release has not yet
|
|
99
226
|
# fired. Used to guarantee a release even if the queue is cleared mid-flight
|
|
100
227
|
# (new sequence) or the node leaves the tree — otherwise the dropped release
|
|
@@ -956,6 +1083,7 @@ func _event_to_string(event: InputEvent) -> String:
|
|
|
956
1083
|
|
|
957
1084
|
func _handle_execute_input_sequence(data: Array) -> void:
|
|
958
1085
|
var inputs: Array = data[0] if data.size() > 0 else []
|
|
1086
|
+
var report: Array = data[1] if data.size() > 1 and data[1] is Array else []
|
|
959
1087
|
|
|
960
1088
|
if inputs.is_empty():
|
|
961
1089
|
EngineDebugger.send_message("godot_mcp:input_sequence_result", [{
|
|
@@ -963,6 +1091,22 @@ func _handle_execute_input_sequence(data: Array) -> void:
|
|
|
963
1091
|
}])
|
|
964
1092
|
return
|
|
965
1093
|
|
|
1094
|
+
# Compile the optional effect probe up front, before touching any input state,
|
|
1095
|
+
# so a bad expression rejects the call cleanly (same contract as step_until's
|
|
1096
|
+
# report). Reuses the predicate context: autoloads by name, plus `tree`/`root`.
|
|
1097
|
+
var report_compiled: Array = []
|
|
1098
|
+
var report_inputs: Array = []
|
|
1099
|
+
if not report.is_empty():
|
|
1100
|
+
var ctx := _build_predicate_context()
|
|
1101
|
+
var rr := _compile_report(report, ctx["names"], ctx["inputs"])
|
|
1102
|
+
if rr.has("error"):
|
|
1103
|
+
EngineDebugger.send_message("godot_mcp:input_sequence_result", [{
|
|
1104
|
+
"error": rr["error"],
|
|
1105
|
+
}])
|
|
1106
|
+
return
|
|
1107
|
+
report_compiled = rr["report"]
|
|
1108
|
+
report_inputs = ctx["inputs"]
|
|
1109
|
+
|
|
966
1110
|
# Release anything still held from a prior, interrupted sequence BEFORE
|
|
967
1111
|
# clearing the queue — otherwise that sequence's unfired releases are dropped
|
|
968
1112
|
# and its actions stay latched (stuck-held bug).
|
|
@@ -970,6 +1114,15 @@ func _handle_execute_input_sequence(data: Array) -> void:
|
|
|
970
1114
|
_sequence_events.clear()
|
|
971
1115
|
_actions_completed = 0
|
|
972
1116
|
_actions_total = inputs.size()
|
|
1117
|
+
_sequence_gameplay_ms = 0.0
|
|
1118
|
+
_sequence_draining = false
|
|
1119
|
+
_sequence_settle_remaining = 0
|
|
1120
|
+
# Clear probe state up front so an early return below (unknown action) cannot
|
|
1121
|
+
# leave a stale report to be drained against an interrupted window. It is
|
|
1122
|
+
# re-armed from report_compiled once the timeline is validated.
|
|
1123
|
+
_sequence_report = []
|
|
1124
|
+
_sequence_report_inputs = []
|
|
1125
|
+
_sequence_report_before = {}
|
|
973
1126
|
|
|
974
1127
|
for input in inputs:
|
|
975
1128
|
var action_name: String = input.get("action_name", "")
|
|
@@ -1000,6 +1153,11 @@ func _handle_execute_input_sequence(data: Array) -> void:
|
|
|
1000
1153
|
return a.time < b.time
|
|
1001
1154
|
)
|
|
1002
1155
|
|
|
1156
|
+
# Baseline the effect probe at the last possible moment before any input fires.
|
|
1157
|
+
_sequence_report = report_compiled
|
|
1158
|
+
_sequence_report_inputs = report_inputs
|
|
1159
|
+
_sequence_report_before = _evaluate_report(report_compiled, report_inputs) if not report_compiled.is_empty() else {}
|
|
1160
|
+
|
|
1003
1161
|
_sequence_start_time = Time.get_ticks_msec()
|
|
1004
1162
|
_sequence_running = true
|
|
1005
1163
|
_update_processing()
|
package/addon/plugin.cfg
CHANGED
|
@@ -31,6 +31,19 @@ describe('input tool', () => {
|
|
|
31
31
|
delay_ms: -1,
|
|
32
32
|
}).success).toBe(false);
|
|
33
33
|
});
|
|
34
|
+
it('accepts an optional report array of expression strings', () => {
|
|
35
|
+
expect(input.schema.safeParse({
|
|
36
|
+
action: 'sequence',
|
|
37
|
+
inputs: [{ action_name: 'fire' }],
|
|
38
|
+
report: ['G.shots', 'G.wave'],
|
|
39
|
+
}).success).toBe(true);
|
|
40
|
+
// report must be strings, not arbitrary values
|
|
41
|
+
expect(input.schema.safeParse({
|
|
42
|
+
action: 'sequence',
|
|
43
|
+
inputs: [{ action_name: 'fire' }],
|
|
44
|
+
report: [1, 2],
|
|
45
|
+
}).success).toBe(false);
|
|
46
|
+
});
|
|
34
47
|
});
|
|
35
48
|
describe('get_map', () => {
|
|
36
49
|
it('returns formatted action list', async () => {
|
|
@@ -88,6 +101,73 @@ describe('input tool', () => {
|
|
|
88
101
|
inputs: [{ action_name: 'invalid', start_ms: 0, duration_ms: 0 }],
|
|
89
102
|
}, ctx)).rejects.toThrow('Unknown action: invalid');
|
|
90
103
|
});
|
|
104
|
+
it('passes report expressions through and surfaces before -> after deltas', async () => {
|
|
105
|
+
mock.mockResponse({
|
|
106
|
+
completed: true,
|
|
107
|
+
actions_executed: 1,
|
|
108
|
+
scene: 'res://arena.tscn',
|
|
109
|
+
tree_paused: false,
|
|
110
|
+
frozen: false,
|
|
111
|
+
gameplay_ms: 210,
|
|
112
|
+
wall_ms: 212,
|
|
113
|
+
report: {
|
|
114
|
+
'G.shots': { before: 42, after: 47, changed: true },
|
|
115
|
+
'G.wave': { before: 2, after: 2, changed: false },
|
|
116
|
+
},
|
|
117
|
+
any_changed: true,
|
|
118
|
+
});
|
|
119
|
+
const ctx = createToolContext(mock);
|
|
120
|
+
const result = await input.execute({
|
|
121
|
+
action: 'sequence',
|
|
122
|
+
inputs: [{ action_name: 'fire', start_ms: 0, duration_ms: 100 }],
|
|
123
|
+
report: ['G.shots', 'G.wave'],
|
|
124
|
+
}, ctx);
|
|
125
|
+
expect(mock.calls[0].params.report).toEqual(['G.shots', 'G.wave']);
|
|
126
|
+
expect(result).toContain('G.shots: 42 -> 47 (changed)');
|
|
127
|
+
expect(result).toContain('G.wave: 2 -> 2 (no change)');
|
|
128
|
+
expect(result).toContain('scene res://arena.tscn');
|
|
129
|
+
expect(result).not.toContain('may have had no effect');
|
|
130
|
+
});
|
|
131
|
+
it('flags a probable no-op when nothing the probe watched changed', async () => {
|
|
132
|
+
// The headline #240 case: a long sequence that ran while the player was dead.
|
|
133
|
+
mock.mockResponse({
|
|
134
|
+
completed: true,
|
|
135
|
+
actions_executed: 12,
|
|
136
|
+
scene: 'res://arena.tscn',
|
|
137
|
+
tree_paused: false,
|
|
138
|
+
frozen: false,
|
|
139
|
+
gameplay_ms: 12700,
|
|
140
|
+
wall_ms: 12710,
|
|
141
|
+
report: { 'G.shots': { before: 99, after: 99, changed: false } },
|
|
142
|
+
any_changed: false,
|
|
143
|
+
});
|
|
144
|
+
const ctx = createToolContext(mock);
|
|
145
|
+
const result = await input.execute({
|
|
146
|
+
action: 'sequence',
|
|
147
|
+
inputs: [{ action_name: 'fire', start_ms: 0, duration_ms: 12000 }],
|
|
148
|
+
report: ['G.shots'],
|
|
149
|
+
}, ctx);
|
|
150
|
+
expect(result).toContain('G.shots: 99 -> 99 (no change)');
|
|
151
|
+
expect(result).toContain('may have had no effect');
|
|
152
|
+
});
|
|
153
|
+
it('warns when the tree was paused for the sequence (no gameplay advanced)', async () => {
|
|
154
|
+
mock.mockResponse({
|
|
155
|
+
completed: true,
|
|
156
|
+
actions_executed: 2,
|
|
157
|
+
scene: 'res://arena.tscn',
|
|
158
|
+
tree_paused: true,
|
|
159
|
+
frozen: false,
|
|
160
|
+
gameplay_ms: 0,
|
|
161
|
+
wall_ms: 2000,
|
|
162
|
+
});
|
|
163
|
+
const ctx = createToolContext(mock);
|
|
164
|
+
const result = await input.execute({
|
|
165
|
+
action: 'sequence',
|
|
166
|
+
inputs: [{ action_name: 'move_left', start_ms: 0, duration_ms: 1000 }],
|
|
167
|
+
}, ctx);
|
|
168
|
+
expect(result).toContain('PAUSED');
|
|
169
|
+
expect(result).toContain('gameplay 0ms / wall 2000ms');
|
|
170
|
+
});
|
|
91
171
|
});
|
|
92
172
|
describe('type_text', () => {
|
|
93
173
|
it('types text and returns character count', async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.test.js","sourceRoot":"","sources":["../../../src/__tests__/tools/input.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"input.test.js","sourceRoot":"","sources":["../../../src/__tests__/tools/input.test.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/input.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare const input: import("../core/types.js").ToolDefinition<z.ZodDiscr
|
|
|
14
14
|
start_ms: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
15
15
|
duration_ms: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
16
16
|
}, z.core.$strip>>;
|
|
17
|
+
report: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
17
18
|
}, z.core.$strip>, z.ZodObject<{
|
|
18
19
|
action: z.ZodLiteral<"type_text">;
|
|
19
20
|
text: z.ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/tools/input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,eAAO,MAAM,iBAAiB;;;;iBAI5B,CAAC;
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/tools/input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,eAAO,MAAM,iBAAiB;;;;iBAI5B,CAAC;AAuDH,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;8BAwGhB,CAAC;AAEH,eAAO,MAAM,UAAU,EAAc,iBAAiB,EAAE,CAAC"}
|
package/dist/tools/input.js
CHANGED
|
@@ -15,6 +15,18 @@ const InputSchema = z.discriminatedUnion('action', [
|
|
|
15
15
|
.array(InputActionSchema)
|
|
16
16
|
.min(1)
|
|
17
17
|
.describe('Array of inputs to execute'),
|
|
18
|
+
report: z
|
|
19
|
+
.array(z.string())
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Optional effect probe: GDScript expressions evaluated once before the first input and ' +
|
|
22
|
+
'again after the last, to prove the inputs actually changed something (vs. falling into ' +
|
|
23
|
+
'the void — player dead, UI focus elsewhere, wrong action). Reference autoloads by name ' +
|
|
24
|
+
'(e.g. "G.shots", "G.wave") plus `tree`/`root` (e.g. ' +
|
|
25
|
+
'"tree.get_nodes_in_group(\'enemies\').size()"), same context as godot_game_time step_until. ' +
|
|
26
|
+
'Each expression returns {before, after, changed}; the result also carries any_changed. ' +
|
|
27
|
+
'Expressions do NOT short-circuit and a parse/eval error rejects the call. The after-reading ' +
|
|
28
|
+
'is sampled a couple frames past the final input, so only near-immediate effects register — ' +
|
|
29
|
+
'for slower effects use godot_game_time or runtime_state watch.'),
|
|
18
30
|
}),
|
|
19
31
|
z.object({
|
|
20
32
|
action: z.literal('type_text').describe('Type text into the focused UI element'),
|
|
@@ -39,7 +51,7 @@ const InputSchema = z.discriminatedUnion('action', [
|
|
|
39
51
|
export const input = defineTool({
|
|
40
52
|
name: 'godot_input',
|
|
41
53
|
annotations: { title: 'Input Injection', readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
42
|
-
description: 'Inject input into a running Godot game for testing. Use get_map to discover available input actions, sequence to execute inputs with precise timing, or type_text to type into UI elements. Note: Mouse/coordinate input not yet supported.',
|
|
54
|
+
description: 'Inject input into a running Godot game for testing. Use get_map to discover available input actions, sequence to execute inputs with precise timing (optionally with an effect probe that proves the inputs changed game state), or type_text to type into UI elements. Note: Mouse/coordinate input not yet supported.',
|
|
43
55
|
schema: InputSchema,
|
|
44
56
|
async execute(args, { godot }) {
|
|
45
57
|
switch (args.action) {
|
|
@@ -57,13 +69,44 @@ export const input = defineTool({
|
|
|
57
69
|
}
|
|
58
70
|
case 'sequence': {
|
|
59
71
|
const inputs = args.inputs;
|
|
60
|
-
const result = await godot.sendCommand('execute_input_sequence', { inputs });
|
|
72
|
+
const result = await godot.sendCommand('execute_input_sequence', { inputs, report: args.report });
|
|
61
73
|
if (result.error) {
|
|
62
74
|
throw new Error(result.error);
|
|
63
75
|
}
|
|
64
76
|
const totalDuration = Math.max(...inputs.map((i) => (i.start_ms ?? 0) + (i.duration_ms ?? 0)));
|
|
65
77
|
const actionNames = [...new Set(inputs.map((i) => i.action_name))].join(', ');
|
|
66
|
-
|
|
78
|
+
const lines = [
|
|
79
|
+
`Input sequence completed: ${result.actions_executed} action(s) executed [${actionNames}] over ${totalDuration}ms.`,
|
|
80
|
+
];
|
|
81
|
+
// Always-on context: a sequence that ran under a pause/freeze advanced no
|
|
82
|
+
// gameplay, so its inputs almost certainly did nothing — surface that
|
|
83
|
+
// without the caller having to ask.
|
|
84
|
+
const ctx = [];
|
|
85
|
+
if (result.scene !== undefined)
|
|
86
|
+
ctx.push(`scene ${result.scene || '(none)'}`);
|
|
87
|
+
if (result.gameplay_ms !== undefined && result.wall_ms !== undefined) {
|
|
88
|
+
ctx.push(`gameplay ${result.gameplay_ms}ms / wall ${result.wall_ms}ms`);
|
|
89
|
+
}
|
|
90
|
+
if (ctx.length > 0)
|
|
91
|
+
lines.push(`Context: ${ctx.join(', ')}.`);
|
|
92
|
+
if (result.tree_paused) {
|
|
93
|
+
lines.push(`WARNING: the scene tree was PAUSED at completion${result.frozen ? ' (godot_game_time freeze active)' : ''} — ` +
|
|
94
|
+
`gameplay did not advance, so these inputs likely had no effect. Thaw/unpause first, or drive a paused ` +
|
|
95
|
+
`tree with godot_game_time step inputs.`);
|
|
96
|
+
}
|
|
97
|
+
// Effect probe (#240): the headline "did it do anything" signal.
|
|
98
|
+
if (result.report) {
|
|
99
|
+
lines.push('Effect probe (before -> after):');
|
|
100
|
+
for (const [expr, d] of Object.entries(result.report)) {
|
|
101
|
+
const tag = d.changed ? 'changed' : 'no change';
|
|
102
|
+
lines.push(` ${expr}: ${JSON.stringify(d.before)} -> ${JSON.stringify(d.after)} (${tag})`);
|
|
103
|
+
}
|
|
104
|
+
if (result.any_changed === false) {
|
|
105
|
+
lines.push('No probed expression changed — the inputs may have had no effect (player dead/disabled, ' +
|
|
106
|
+
'UI focus elsewhere, wrong action, or the effect is slower than the probe window).');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return lines.join('\n');
|
|
67
110
|
}
|
|
68
111
|
case 'type_text': {
|
|
69
112
|
const result = await godot.sendCommand('type_text', { text: args.text, delay_ms: args.delay_ms, submit: args.submit });
|
package/dist/tools/input.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/tools/input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC;IACpF,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,4DAA4D,CAAC;IAC9H,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,8CAA8C,CAAC;CACpH,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE;IACjD,CAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,yDAAyD,CAAC;KACjG,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QACnE,MAAM,EAAE,CAAC;aACN,KAAK,CAAC,iBAAiB,CAAC;aACxB,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CAAC,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/tools/input.ts"],"names":[],"mappings":"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"}
|