gdharness 1.3.41 → 1.3.43
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 +131 -47
- package/build/godot/addons/auto_reload/auto_reload.gd +18 -19
- package/build/godot/addons/gdharness_editor/animation_reads.gd +84 -35
- package/build/godot/addons/gdharness_editor/bridge_client.gd +53 -58
- package/build/godot/addons/gdharness_editor/declared_values.gd +68 -32
- package/build/godot/addons/gdharness_editor/file_reads.gd +114 -39
- package/build/godot/addons/gdharness_editor/file_walk.gd +12 -5
- package/build/godot/addons/gdharness_editor/headless_check.gd +94 -41
- package/build/godot/addons/gdharness_editor/plugin.gd +2 -3
- package/build/godot/addons/gdharness_editor/property_paths.gd +22 -12
- package/build/godot/addons/gdharness_editor/property_values.gd +143 -78
- package/build/godot/addons/gdharness_editor/reading.gd +37 -12
- package/build/godot/addons/gdharness_editor/same_values.gd +4 -4
- package/build/godot/addons/gdharness_editor/scene_file.gd +136 -79
- package/build/godot/addons/gdharness_editor/scene_uids.gd +12 -6
- package/build/godot/addons/gdharness_editor/serialisation.gd +75 -51
- package/build/godot/addons/gdharness_editor/setting_reads.gd +7 -6
- package/build/godot/addons/gdharness_editor/tool_executor.gd +3 -6
- package/build/godot/addons/gdharness_editor/tools/animation_states.gd +41 -28
- package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +84 -50
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +70 -40
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +34 -30
- package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +24 -22
- package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +49 -29
- package/build/godot/addons/gdharness_editor/tools/play_tools.gd +26 -21
- package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +40 -40
- package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +181 -107
- package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -9
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +75 -43
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +35 -20
- package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +28 -13
- package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd +66 -0
- package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd.uid +1 -0
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +171 -62
- package/build/godot/addons/gdharness_editor/tools/script_paths.gd +20 -8
- package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +11 -8
- package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +47 -34
- package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +77 -50
- package/build/godot/addons/gdharness_editor/value_shapes.gd +5 -6
- package/build/godot/addons/gdharness_runtime/call_errors.gd +1 -2
- package/build/godot/addons/gdharness_runtime/declared_values.gd +68 -32
- package/build/godot/addons/gdharness_runtime/error_report.gd +1 -2
- package/build/godot/addons/gdharness_runtime/reading.gd +37 -12
- package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +84 -63
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +153 -148
- package/build/godot/addons/gdharness_runtime/runtime_capture.gd +64 -42
- package/build/godot/addons/gdharness_runtime/runtime_changes.gd +184 -122
- package/build/godot/addons/gdharness_runtime/runtime_frames.gd +2 -2
- package/build/godot/addons/gdharness_runtime/runtime_hover.gd +24 -20
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +134 -92
- package/build/godot/addons/gdharness_runtime/runtime_items.gd +29 -13
- package/build/godot/addons/gdharness_runtime/runtime_menus.gd +0 -1
- package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +38 -20
- package/build/godot/addons/gdharness_runtime/runtime_pad.gd +17 -13
- package/build/godot/addons/gdharness_runtime/runtime_paths.gd +84 -46
- package/build/godot/addons/gdharness_runtime/runtime_queries.gd +117 -79
- package/build/godot/addons/gdharness_runtime/runtime_says.gd +14 -17
- package/build/godot/addons/gdharness_runtime/runtime_screen.gd +23 -16
- package/build/godot/addons/gdharness_runtime/runtime_targets.gd +117 -66
- package/build/godot/addons/gdharness_runtime/runtime_touch.gd +211 -0
- package/build/godot/addons/gdharness_runtime/runtime_touch.gd.uid +1 -0
- package/build/godot/addons/gdharness_runtime/runtime_typing.gd +44 -27
- package/build/godot/addons/gdharness_runtime/runtime_values.gd +108 -73
- package/build/godot/addons/gdharness_runtime/runtime_waits.gd +111 -84
- package/build/godot/addons/gdharness_runtime/runtime_words.gd +10 -7
- package/build/godot/addons/gdharness_runtime/serialisation.gd +75 -51
- package/build/godot/addons/gdharness_runtime/value_shapes.gd +5 -6
- package/build/godot/addons/gdharness_tests/bench.gd +4 -5
- package/build/godot/addons/gdharness_tests/event.gd +10 -5
- package/build/godot/addons/gdharness_tests/share.gd +38 -18
- package/build/godot/addons/gdharness_tests/suites.gd +3 -3
- package/build/godot/addons/gdharness_tests/wait.gd +3 -2
- package/build/godot/loader/loader.gd +9 -9
- package/build/godot/operations/animation_reads.gd +84 -35
- package/build/godot/operations/audio_buses.gd +48 -19
- package/build/godot/operations/class_cache.gd +16 -11
- package/build/godot/operations/classdb_queries.gd +89 -44
- package/build/godot/operations/declared_values.gd +68 -32
- package/build/godot/operations/dependencies.gd +139 -93
- package/build/godot/operations/editor_tools.gd +9 -10
- package/build/godot/operations/export_presets.gd +100 -54
- package/build/godot/operations/file_reads.gd +114 -39
- package/build/godot/operations/file_walk.gd +12 -5
- package/build/godot/operations/gdscript_analysis.gd +105 -66
- package/build/godot/operations/gdscript_authoring.gd +138 -39
- package/build/godot/operations/godot_operations.gd +17 -11
- package/build/godot/operations/import_pipeline.gd +110 -59
- package/build/godot/operations/input_actions.gd +63 -39
- package/build/godot/operations/patterns.gd +3 -1
- package/build/godot/operations/plugins.gd +36 -16
- package/build/godot/operations/project_config.gd +144 -27
- package/build/godot/operations/project_diagnostics.gd +24 -11
- package/build/godot/operations/project_file.gd +16 -16
- package/build/godot/operations/project_validation.gd +71 -44
- package/build/godot/operations/property_paths.gd +22 -12
- package/build/godot/operations/property_values.gd +143 -78
- package/build/godot/operations/reading.gd +37 -12
- package/build/godot/operations/rename_checks.gd +2 -2
- package/build/godot/operations/resource_files.gd +11 -9
- package/build/godot/operations/same_values.gd +4 -4
- package/build/godot/operations/scene_connections.gd +27 -13
- package/build/godot/operations/script_check.gd +52 -49
- package/build/godot/operations/serialisation.gd +75 -51
- package/build/godot/operations/setting_reads.gd +7 -6
- package/build/godot/operations/value_shapes.gd +5 -6
- package/build/godot/tests/listed.gd +321 -268
- package/package.json +1 -1
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
extends RefCounted
|
|
2
|
-
|
|
3
2
|
## A picture of the running game, as a PNG written where the server asked for it.
|
|
4
3
|
|
|
5
4
|
const GdhRead = preload("reading.gd")
|
|
6
5
|
const GdhValues = preload("runtime_values.gd")
|
|
7
6
|
const GdhQueries = preload("runtime_queries.gd")
|
|
8
7
|
const GdhScreen = preload("runtime_screen.gd")
|
|
9
|
-
|
|
10
8
|
## How far zoom enlarges at most. Sixteen makes a 3-pixel ring 48 pixels across, past any need to
|
|
11
9
|
## see it, and a 200-pixel region 3200, past the size anybody reads a picture at.
|
|
12
10
|
const ZOOM_MOST: int = 16
|
|
@@ -37,7 +35,7 @@ func capture_viewport(params: Dictionary) -> Dictionary:
|
|
|
37
35
|
return standing
|
|
38
36
|
var node: Node = standing["node"]
|
|
39
37
|
if not node is Viewport:
|
|
40
|
-
return {"type": "error", "message": "Node is not a Viewport: " + viewport_path}
|
|
38
|
+
return { "type": "error", "message": "Node is not a Viewport: " + viewport_path }
|
|
41
39
|
var viewport: Viewport = node
|
|
42
40
|
# The root's own state is refused in _capture. Another window of the game's that is hidden or
|
|
43
41
|
# minimised holds no frame, and asking it for its image makes the engine log the empty read into
|
|
@@ -50,8 +48,8 @@ func capture_viewport(params: Dictionary) -> Dictionary:
|
|
|
50
48
|
"message":
|
|
51
49
|
(
|
|
52
50
|
(
|
|
53
|
-
"The Window at %s is hidden, so nothing is drawn to it. Show it (its
|
|
54
|
-
+ "property) and ask again."
|
|
51
|
+
"The Window at %s is hidden, so nothing is drawn to it. Show it (its "
|
|
52
|
+
+ "visible property) and ask again."
|
|
55
53
|
)
|
|
56
54
|
% viewport_path
|
|
57
55
|
),
|
|
@@ -62,8 +60,8 @@ func capture_viewport(params: Dictionary) -> Dictionary:
|
|
|
62
60
|
"message":
|
|
63
61
|
(
|
|
64
62
|
(
|
|
65
|
-
"Nothing is being drawn to the Window at %s, which is minimised. Restore
|
|
66
|
-
+ "ask again."
|
|
63
|
+
"Nothing is being drawn to the Window at %s, which is minimised. Restore "
|
|
64
|
+
+ "it and ask again."
|
|
67
65
|
)
|
|
68
66
|
% viewport_path
|
|
69
67
|
),
|
|
@@ -113,7 +111,9 @@ func _lay_native_windows(image: Image) -> void:
|
|
|
113
111
|
if drawn == null or drawn.is_empty():
|
|
114
112
|
continue
|
|
115
113
|
drawn.convert(image.get_format())
|
|
116
|
-
image.blend_rect(
|
|
114
|
+
image.blend_rect(
|
|
115
|
+
drawn, Rect2i(Vector2i.ZERO, drawn.get_size()), window.position - root.position
|
|
116
|
+
)
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
## The size a capture drawn at [param drawn] is scaled to, from the width and height asked for, 0
|
|
@@ -148,26 +148,29 @@ func _cut_asked(params: Dictionary, in_window: bool) -> Dictionary:
|
|
|
148
148
|
if (region_given != null or not node_path.is_empty()) and not in_window:
|
|
149
149
|
return _refused(
|
|
150
150
|
(
|
|
151
|
-
"region and nodePath are in the window's pixels, and this viewport's texture is in
|
|
152
|
-
+ "own: capture the screen with them, or this viewport whole"
|
|
151
|
+
"region and nodePath are in the window's pixels, and this viewport's texture is in "
|
|
152
|
+
+ "its own: capture the screen with them, or this viewport whole"
|
|
153
153
|
)
|
|
154
154
|
)
|
|
155
155
|
if zoom < 1 or zoom > ZOOM_MOST:
|
|
156
|
-
return _refused(
|
|
156
|
+
return _refused(
|
|
157
|
+
"zoom is a whole factor from 1 to %d, and %d was asked for" % [ZOOM_MOST, zoom]
|
|
158
|
+
)
|
|
157
159
|
if zoom > 1 and sized:
|
|
158
160
|
return _refused(
|
|
159
161
|
(
|
|
160
|
-
"zoom enlarges by a whole factor and keeps every pixel square, and width and
|
|
161
|
-
+ "scale to a size; give one or the other"
|
|
162
|
+
"zoom enlarges by a whole factor and keeps every pixel square, and width and "
|
|
163
|
+
+ "height scale to a size; give one or the other"
|
|
162
164
|
)
|
|
163
165
|
)
|
|
164
|
-
var asked: Dictionary = {"zoom": zoom}
|
|
166
|
+
var asked: Dictionary = { "zoom": zoom }
|
|
165
167
|
if region_given != null:
|
|
166
168
|
var region: Variant = region_of(_values, region_given)
|
|
167
169
|
if region == null:
|
|
168
170
|
var shape: String = (
|
|
169
|
-
"region is a rectangle in window pixels with an area: x, y, width and height, or
|
|
170
|
-
+ "window rectangle runtime_inspect rect answers, passed back as it came. %s
|
|
171
|
+
"region is a rectangle in window pixels with an area: x, y, width and height, or "
|
|
172
|
+
+ "the window rectangle runtime_inspect rect answers, passed back as it came. %s "
|
|
173
|
+
+ "is neither"
|
|
171
174
|
)
|
|
172
175
|
return _refused(shape % JSON.stringify(region_given))
|
|
173
176
|
asked["region"] = region
|
|
@@ -182,7 +185,7 @@ func _cut_asked(params: Dictionary, in_window: bool) -> Dictionary:
|
|
|
182
185
|
|
|
183
186
|
|
|
184
187
|
static func _refused(message: String) -> Dictionary:
|
|
185
|
-
return {"type": "error", "message": message}
|
|
188
|
+
return { "type": "error", "message": message }
|
|
186
189
|
|
|
187
190
|
|
|
188
191
|
## The rectangle [param given] names: the four numbers x, y, width and height, or a rectangle as the
|
|
@@ -210,8 +213,8 @@ static func region_of(values: GdhValues, given: Variant) -> Variant:
|
|
|
210
213
|
|
|
211
214
|
|
|
212
215
|
## Where [param node] is drawn, in window pixels, as runtime_inspect rect answers it: a Control's
|
|
213
|
-
## rectangle, what a 3D node's geometry covers, or what a 2D node that knows its own rectangle
|
|
214
|
-
## A refusal's message when it has no extent on screen.
|
|
216
|
+
## rectangle, what a 3D node's geometry covers, or what a 2D node that knows its own rectangle
|
|
217
|
+
## draws. A refusal's message when it has no extent on screen.
|
|
215
218
|
static func drawn_rect_of(node: Node) -> Variant:
|
|
216
219
|
if node is Control:
|
|
217
220
|
var control: Control = node
|
|
@@ -223,13 +226,18 @@ static func drawn_rect_of(node: Node) -> Variant:
|
|
|
223
226
|
var spatial: Node3D = node
|
|
224
227
|
var found: Dictionary = GdhQueries.in_frame(spatial)
|
|
225
228
|
if not found.has("rect"):
|
|
226
|
-
return
|
|
229
|
+
return (
|
|
230
|
+
"%s is not drawn by any current camera, so it covers nothing on screen"
|
|
231
|
+
% node.get_path()
|
|
232
|
+
)
|
|
227
233
|
var covered: Rect2 = found["rect"]
|
|
228
234
|
return GdhScreen.rect_in_window(spatial.get_viewport(), covered)
|
|
229
235
|
if node is Node2D and node.has_method("get_rect"):
|
|
230
236
|
var item: Node2D = node
|
|
231
237
|
var own: Rect2 = item.call("get_rect")
|
|
232
|
-
return GdhScreen.rect_in_window(
|
|
238
|
+
return GdhScreen.rect_in_window(
|
|
239
|
+
item.get_viewport(), item.get_global_transform_with_canvas() * own
|
|
240
|
+
)
|
|
233
241
|
var no_extent: String = (
|
|
234
242
|
"%s is a %s, which has a position on screen and no extent; give region around the point "
|
|
235
243
|
+ "runtime_inspect rect answers for it"
|
|
@@ -238,9 +246,10 @@ static func drawn_rect_of(node: Node) -> Variant:
|
|
|
238
246
|
|
|
239
247
|
|
|
240
248
|
## [param region], in window pixels, as pixels of a picture drawn at [param drawn] in a window
|
|
241
|
-
## [param window] pixels across: the same rectangle when the two match, scaled when the project
|
|
242
|
-
## at its own size and stretches that to the window. Widened to whole pixels, so an edge
|
|
243
|
-
## inside a pixel keeps that pixel, and cut to the picture. Without area when none of it is
|
|
249
|
+
## [param window] pixels across: the same rectangle when the two match, scaled when the project
|
|
250
|
+
## draws at its own size and stretches that to the window. Widened to whole pixels, so an edge
|
|
251
|
+
## falling inside a pixel keeps that pixel, and cut to the picture. Without area when none of it is
|
|
252
|
+
## in it.
|
|
244
253
|
static func in_picture(region: Rect2, window: Vector2i, drawn: Vector2i) -> Rect2i:
|
|
245
254
|
return widened(region, window, drawn).intersection(Rect2i(Vector2i.ZERO, drawn))
|
|
246
255
|
|
|
@@ -257,14 +266,15 @@ static func widened(region: Rect2, window: Vector2i, drawn: Vector2i) -> Rect2i:
|
|
|
257
266
|
|
|
258
267
|
|
|
259
268
|
## [param picture], pixels of a picture drawn at [param drawn], as the window pixels it covers in a
|
|
260
|
-
## window [param window] pixels across: what an answer names, since the region was asked for in
|
|
269
|
+
## window [param window] pixels across: what an answer names, since the region was asked for in
|
|
270
|
+
## them.
|
|
261
271
|
static func in_window_pixels(picture: Rect2i, window: Vector2i, drawn: Vector2i) -> Dictionary:
|
|
262
272
|
var scale: Vector2 = Vector2.ONE
|
|
263
273
|
if drawn.x > 0 and drawn.y > 0 and window.x > 0 and window.y > 0:
|
|
264
274
|
scale = Vector2(window) / Vector2(drawn)
|
|
265
275
|
var start: Vector2 = Vector2(picture.position) * scale
|
|
266
276
|
var size: Vector2 = Vector2(picture.size) * scale
|
|
267
|
-
return {"x": start.x, "y": start.y, "width": size.x, "height": size.y}
|
|
277
|
+
return { "x": start.x, "y": start.y, "width": size.x, "height": size.y }
|
|
268
278
|
|
|
269
279
|
|
|
270
280
|
## [param image] cut to [param picture] and enlarged [param zoom] times, each pixel made a square of
|
|
@@ -281,7 +291,7 @@ static func cut(image: Image, picture: Rect2i, zoom: int) -> Image:
|
|
|
281
291
|
func _capture(viewport: Viewport, params: Dictionary, with_windows: bool = false) -> Dictionary:
|
|
282
292
|
var requested_path: String = str(params.get("output_path", ""))
|
|
283
293
|
if requested_path.is_empty():
|
|
284
|
-
return {"type": "error", "message": "output_path required"}
|
|
294
|
+
return { "type": "error", "message": "output_path required" }
|
|
285
295
|
var asked: Dictionary = _cut_asked(params, with_windows)
|
|
286
296
|
if asked.has("message"):
|
|
287
297
|
return asked
|
|
@@ -296,8 +306,8 @@ func _capture(viewport: Viewport, params: Dictionary, with_windows: bool = false
|
|
|
296
306
|
"type": "error",
|
|
297
307
|
"message":
|
|
298
308
|
(
|
|
299
|
-
"This game runs headless, so it has no window and draws nothing to capture. Start
|
|
300
|
-
+ "with a window (editor_run start with headless false) to capture it."
|
|
309
|
+
"This game runs headless, so it has no window and draws nothing to capture. Start "
|
|
310
|
+
+ "it with a window (editor_run start with headless false) to capture it."
|
|
301
311
|
),
|
|
302
312
|
}
|
|
303
313
|
if not _host.get_tree().root.can_draw():
|
|
@@ -320,11 +330,11 @@ func _capture(viewport: Viewport, params: Dictionary, with_windows: bool = false
|
|
|
320
330
|
|
|
321
331
|
var viewport_texture: ViewportTexture = viewport.get_texture()
|
|
322
332
|
if viewport_texture == null:
|
|
323
|
-
return {"type": "error", "message": "No viewport texture available"}
|
|
333
|
+
return { "type": "error", "message": "No viewport texture available" }
|
|
324
334
|
|
|
325
335
|
var image: Image = viewport_texture.get_image()
|
|
326
336
|
if image == null:
|
|
327
|
-
return {"type": "error", "message": "Failed to capture viewport image"}
|
|
337
|
+
return { "type": "error", "message": "Failed to capture viewport image" }
|
|
328
338
|
if with_windows:
|
|
329
339
|
_lay_native_windows(image)
|
|
330
340
|
|
|
@@ -341,10 +351,12 @@ func _capture(viewport: Viewport, params: Dictionary, with_windows: bool = false
|
|
|
341
351
|
var why: String = placed
|
|
342
352
|
return _refused(why)
|
|
343
353
|
region = placed
|
|
344
|
-
# A hidden node's rectangle is still a place, and what is drawn there is whatever is behind
|
|
354
|
+
# A hidden node's rectangle is still a place, and what is drawn there is whatever is behind
|
|
355
|
+
# it.
|
|
345
356
|
if not GdhQueries.shown(node):
|
|
346
357
|
described["note"] = (
|
|
347
|
-
"%s is hidden, so this is what is drawn where it would be rather than the node"
|
|
358
|
+
"%s is hidden, so this is what is drawn where it would be rather than the node"
|
|
359
|
+
% node_path
|
|
348
360
|
)
|
|
349
361
|
if region != null:
|
|
350
362
|
var asked_region: Rect2 = region
|
|
@@ -355,7 +367,10 @@ func _capture(viewport: Viewport, params: Dictionary, with_windows: bool = false
|
|
|
355
367
|
if not picture.has_area():
|
|
356
368
|
return _refused(
|
|
357
369
|
(
|
|
358
|
-
|
|
370
|
+
(
|
|
371
|
+
"The region at %s, %s pixels across, is outside the window, which is %dx%d "
|
|
372
|
+
+ "pixels"
|
|
373
|
+
)
|
|
359
374
|
% [asked_region.position, asked_region.size, window.x, window.y]
|
|
360
375
|
)
|
|
361
376
|
)
|
|
@@ -363,10 +378,11 @@ func _capture(viewport: Viewport, params: Dictionary, with_windows: bool = false
|
|
|
363
378
|
described["region"] = in_window_pixels(picture, window, picture_size)
|
|
364
379
|
if picture != whole:
|
|
365
380
|
described["clipped"] = true
|
|
366
|
-
# The project draws at its own size and stretches that to the window, so the picture's
|
|
367
|
-
# are not the window's: said, because a caller sizing a region by window pixels gets
|
|
381
|
+
# The project draws at its own size and stretches that to the window, so the picture's
|
|
382
|
+
# pixels are not the window's: said, because a caller sizing a region by window pixels gets
|
|
383
|
+
# fewer.
|
|
368
384
|
if picture_size != window:
|
|
369
|
-
described["drawnAt"] = {"width": picture_size.x, "height": picture_size.y}
|
|
385
|
+
described["drawnAt"] = { "width": picture_size.x, "height": picture_size.y }
|
|
370
386
|
|
|
371
387
|
var zoom: int = asked["zoom"]
|
|
372
388
|
if zoom > 1:
|
|
@@ -384,12 +400,15 @@ func _capture(viewport: Viewport, params: Dictionary, with_windows: bool = false
|
|
|
384
400
|
if screenshot_path.begins_with("user://") or screenshot_path.begins_with("res://"):
|
|
385
401
|
screenshot_path = ProjectSettings.globalize_path(screenshot_path)
|
|
386
402
|
# The server makes the folder for each capture and takes it away when it stops waiting for one,
|
|
387
|
-
# and a server replaced since the capture was asked for took it with it. Saving into a folder
|
|
388
|
-
# is gone raises an engine error, which counts against a game that did nothing wrong.
|
|
403
|
+
# and a server replaced since the capture was asked for took it with it. Saving into a folder
|
|
404
|
+
# that is gone raises an engine error, which counts against a game that did nothing wrong.
|
|
389
405
|
if not DirAccess.dir_exists_absolute(screenshot_path.get_base_dir()):
|
|
390
406
|
return _refused(
|
|
391
407
|
(
|
|
392
|
-
|
|
408
|
+
(
|
|
409
|
+
"The folder to save the capture in, %s, is gone: the server that asked for it "
|
|
410
|
+
+ "stopped waiting"
|
|
411
|
+
)
|
|
393
412
|
% screenshot_path.get_base_dir()
|
|
394
413
|
)
|
|
395
414
|
)
|
|
@@ -405,13 +424,16 @@ func _capture(viewport: Viewport, params: Dictionary, with_windows: bool = false
|
|
|
405
424
|
static func saved(image: Image, png_path: String) -> Dictionary:
|
|
406
425
|
var save_error: Error = image.save_png(png_path)
|
|
407
426
|
if save_error != OK:
|
|
408
|
-
return {
|
|
427
|
+
return {
|
|
428
|
+
"type": "error",
|
|
429
|
+
"message": "Failed to save screenshot as PNG: " + str(save_error),
|
|
430
|
+
}
|
|
409
431
|
var answer: Dictionary = {
|
|
410
432
|
"type": "screenshot_file",
|
|
411
433
|
"format": "png",
|
|
412
434
|
"width": image.get_width(),
|
|
413
435
|
"height": image.get_height(),
|
|
414
|
-
"path": png_path
|
|
436
|
+
"path": png_path,
|
|
415
437
|
}
|
|
416
438
|
if image.detect_alpha() == Image.ALPHA_NONE:
|
|
417
439
|
var jpeg_path: String = png_path.get_basename() + ".jpg"
|