gdharness 1.3.42 → 1.3.44
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 +383 -243
- package/build/godot/addons/auto_reload/auto_reload.gd +18 -19
- package/build/godot/addons/gdharness_editor/animation_reads.gd +55 -33
- 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 +83 -42
- package/build/godot/addons/gdharness_editor/file_walk.gd +12 -5
- package/build/godot/addons/gdharness_editor/headless_check.gd +68 -44
- 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 +51 -17
- package/build/godot/addons/gdharness_editor/same_values.gd +4 -4
- package/build/godot/addons/gdharness_editor/scene_file.gd +127 -80
- 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 +37 -27
- package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +79 -49
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +70 -40
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +65 -42
- 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 +166 -107
- package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -9
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +68 -41
- 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 +12 -5
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +113 -67
- 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 +51 -17
- package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +84 -63
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +149 -147
- 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 +34 -17
- 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 +15 -15
- 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 +55 -33
- 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 +190 -109
- package/build/godot/operations/editor_tools.gd +10 -10
- package/build/godot/operations/export_presets.gd +100 -54
- package/build/godot/operations/file_reads.gd +83 -42
- package/build/godot/operations/file_walk.gd +12 -5
- package/build/godot/operations/gdscript_analysis.gd +86 -65
- package/build/godot/operations/gdscript_authoring.gd +83 -36
- 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 +62 -39
- package/build/godot/operations/patterns.gd +3 -1
- package/build/godot/operations/plugins.gd +36 -16
- package/build/godot/operations/project_config.gd +61 -32
- 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 +51 -17
- 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/build/keeper.js +43 -43
- package/package.json +1 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
@tool
|
|
2
2
|
extends Node
|
|
3
|
-
|
|
4
3
|
## Resource files, shaders and themes, written through the open editor.
|
|
5
4
|
|
|
6
5
|
const GdhFileReads = preload("../file_reads.gd")
|
|
@@ -12,7 +11,6 @@ const GdhSame = preload("../same_values.gd")
|
|
|
12
11
|
const GdhSceneFile = preload("../scene_file.gd")
|
|
13
12
|
const GdhSceneUids = preload("../scene_uids.gd")
|
|
14
13
|
const GdhSerialisation = preload("../serialisation.gd")
|
|
15
|
-
|
|
16
14
|
# The minimal shader of a type: its declaration and the one function the engine calls for it.
|
|
17
15
|
const SHADER_EMPTY: String = """shader_type %s;
|
|
18
16
|
|
|
@@ -20,7 +18,11 @@ void %s() {
|
|
|
20
18
|
}
|
|
21
19
|
"""
|
|
22
20
|
const SHADER_ENTRY: Dictionary[String, String] = {
|
|
23
|
-
"canvas_item": "fragment",
|
|
21
|
+
"canvas_item": "fragment",
|
|
22
|
+
"spatial": "fragment",
|
|
23
|
+
"particles": "process",
|
|
24
|
+
"sky": "sky",
|
|
25
|
+
"fog": "fog",
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
var _editor_plugin: EditorPlugin = null
|
|
@@ -59,7 +61,10 @@ func _taken(path: String, op: String, remedy: String = "Change it with op=modify
|
|
|
59
61
|
if not FileAccess.file_exists(path):
|
|
60
62
|
return ""
|
|
61
63
|
return (
|
|
62
|
-
|
|
64
|
+
(
|
|
65
|
+
"%s already exists, and %s would replace everything in it. %s, or create the new one "
|
|
66
|
+
+ "under another path."
|
|
67
|
+
)
|
|
63
68
|
% [path, op, remedy]
|
|
64
69
|
)
|
|
65
70
|
|
|
@@ -84,7 +89,9 @@ func _parse_properties_dict(raw: Variant) -> Dictionary:
|
|
|
84
89
|
func _load_theme(theme_path: String) -> Theme:
|
|
85
90
|
if not ResourceLoader.exists(theme_path, "Theme"):
|
|
86
91
|
return null
|
|
87
|
-
var loaded: Resource = ResourceLoader.load(
|
|
92
|
+
var loaded: Resource = ResourceLoader.load(
|
|
93
|
+
theme_path, "Theme", ResourceLoader.CACHE_MODE_IGNORE
|
|
94
|
+
)
|
|
88
95
|
if loaded is Theme:
|
|
89
96
|
return loaded
|
|
90
97
|
return null
|
|
@@ -97,7 +104,9 @@ func _load_theme(theme_path: String) -> Theme:
|
|
|
97
104
|
## Read back because a property can be set and still not be saved: one without storage, a
|
|
98
105
|
## script variable that is not exported. Both were answered as changed.
|
|
99
106
|
func _save_checked(resource: Resource, path: String, names: Array, previous: Variant) -> String:
|
|
100
|
-
var carried: Dictionary = GdhHeadlessCheck.embedded_in(
|
|
107
|
+
var carried: Dictionary = GdhHeadlessCheck.embedded_in(
|
|
108
|
+
GdhHeadlessCheck.stored(resource).values(), {}
|
|
109
|
+
)
|
|
101
110
|
var saving: Error = GdhSceneUids.save_keeping_uid(resource, path)
|
|
102
111
|
if saving != OK:
|
|
103
112
|
return "Failed to save %s: %s" % [path, error_string(saving)]
|
|
@@ -117,8 +126,8 @@ func _save_checked(resource: Resource, path: String, names: Array, previous: Var
|
|
|
117
126
|
if not GdhSame.same(read, _properties.read_at(resource, property)):
|
|
118
127
|
lost = (
|
|
119
128
|
(
|
|
120
|
-
"%s.%s would load from the file as %s: it is not a property the file
|
|
121
|
-
+ "nothing was changed."
|
|
129
|
+
"%s.%s would load from the file as %s: it is not a property the file "
|
|
130
|
+
+ "keeps, so nothing was changed."
|
|
122
131
|
)
|
|
123
132
|
% [path, property, _properties.shown(read)]
|
|
124
133
|
)
|
|
@@ -145,8 +154,9 @@ func _unkept_headless(
|
|
|
145
154
|
return (
|
|
146
155
|
(
|
|
147
156
|
(
|
|
148
|
-
"%s is a binary resource with a script that is not a tool, and what that
|
|
149
|
-
+ "changed when a headless engine loaded it cannot be told apart
|
|
157
|
+
"%s is a binary resource with a script that is not a tool, and what that "
|
|
158
|
+
+ "script changed when a headless engine loaded it cannot be told apart "
|
|
159
|
+
+ "from the file here. "
|
|
150
160
|
)
|
|
151
161
|
% path
|
|
152
162
|
)
|
|
@@ -157,22 +167,23 @@ func _unkept_headless(
|
|
|
157
167
|
if previous is PackedByteArray:
|
|
158
168
|
var bytes: PackedByteArray = previous
|
|
159
169
|
before = bytes.get_string_from_utf8()
|
|
160
|
-
var asked: Dictionary = {"script": true}
|
|
170
|
+
var asked: Dictionary = { "script": true }
|
|
161
171
|
var reached: Dictionary = {}
|
|
162
172
|
for key: Variant in names:
|
|
163
173
|
var property: String = str(key)
|
|
164
174
|
asked[property] = true
|
|
165
175
|
asked[property.get_slice(":", 0)] = true
|
|
166
176
|
GdhHeadlessCheck.spare(reached, GdhHeadlessCheck.reached(resource, property))
|
|
177
|
+
var just_saved: GdhHeadlessCheck.GdhSaved = GdhHeadlessCheck.GdhSaved.new(
|
|
178
|
+
path, before, func() -> Error: return GdhSceneUids.save_keeping_uid(resource, path)
|
|
179
|
+
)
|
|
167
180
|
return GdhHeadlessCheck.settle_saved(
|
|
168
|
-
|
|
169
|
-
before,
|
|
181
|
+
just_saved,
|
|
170
182
|
GdhHeadlessCheck.stored(resource).values(),
|
|
171
183
|
resource if scripted else null,
|
|
172
184
|
asked,
|
|
173
185
|
reached,
|
|
174
|
-
carried
|
|
175
|
-
func() -> Error: return GdhSceneUids.save_keeping_uid(resource, path)
|
|
186
|
+
carried
|
|
176
187
|
)
|
|
177
188
|
|
|
178
189
|
|
|
@@ -180,17 +191,20 @@ func create_resource(args: Dictionary) -> Dictionary:
|
|
|
180
191
|
var res_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
181
192
|
var resource_type: String = str(args.get("resourceType", "Resource"))
|
|
182
193
|
if res_path == "res://":
|
|
183
|
-
return {"ok": false, "error": "resourcePath is required"}
|
|
194
|
+
return { "ok": false, "error": "resourcePath is required" }
|
|
184
195
|
var taken: String = _taken(res_path, "resource_edit op=create")
|
|
185
196
|
if not taken.is_empty():
|
|
186
|
-
return {"ok": false, "error": taken}
|
|
197
|
+
return { "ok": false, "error": taken }
|
|
187
198
|
|
|
188
199
|
var script_path: String = str(args.get("script", ""))
|
|
189
200
|
var made: Dictionary = GdhSceneFile.made_as(
|
|
190
|
-
resource_type,
|
|
201
|
+
resource_type,
|
|
202
|
+
"" if script_path == "" else _ensure_res_path(script_path),
|
|
203
|
+
"Resource",
|
|
204
|
+
"resourceType"
|
|
191
205
|
)
|
|
192
206
|
if made.has("error"):
|
|
193
|
-
return {"ok": false, "error": made["error"]}
|
|
207
|
+
return { "ok": false, "error": made["error"] }
|
|
194
208
|
resource_type = str(made["type"])
|
|
195
209
|
script_path = str(made["script"])
|
|
196
210
|
if not ClassDB.class_exists(resource_type):
|
|
@@ -200,10 +214,15 @@ func create_resource(args: Dictionary) -> Dictionary:
|
|
|
200
214
|
(
|
|
201
215
|
"%s is neither an engine class nor a class_name a script in this project declares."
|
|
202
216
|
% resource_type
|
|
203
|
-
)
|
|
217
|
+
),
|
|
218
|
+
}
|
|
219
|
+
if (
|
|
220
|
+
not ClassDB.is_parent_class(resource_type, "Resource")
|
|
221
|
+
or not ClassDB.can_instantiate(resource_type)
|
|
222
|
+
):
|
|
223
|
+
return {
|
|
224
|
+
"ok": false, "error": "%s is not a resource class that can be created." % resource_type,
|
|
204
225
|
}
|
|
205
|
-
if not ClassDB.is_parent_class(resource_type, "Resource") or not ClassDB.can_instantiate(resource_type):
|
|
206
|
-
return {"ok": false, "error": "%s is not a resource class that can be created." % resource_type}
|
|
207
226
|
var resource: Resource = ClassDB.instantiate(resource_type)
|
|
208
227
|
|
|
209
228
|
# A script that did not load was skipped, and a plain resource was saved in place of the custom
|
|
@@ -212,30 +231,37 @@ func create_resource(args: Dictionary) -> Dictionary:
|
|
|
212
231
|
var script_file: String = _ensure_res_path(script_path)
|
|
213
232
|
var script: Script = load(script_file) as Script
|
|
214
233
|
if script == null:
|
|
215
|
-
return {"ok": false, "error": "No script loads from " + script_file}
|
|
234
|
+
return { "ok": false, "error": "No script loads from " + script_file }
|
|
216
235
|
var uncompiled: String = GdhSceneFile.uncompiled(script, script_file)
|
|
217
236
|
if not uncompiled.is_empty():
|
|
218
|
-
return {"ok": false, "error": uncompiled}
|
|
237
|
+
return { "ok": false, "error": uncompiled }
|
|
219
238
|
var base: String = str(script.get_instance_base_type())
|
|
220
239
|
if not ClassDB.is_parent_class(resource_type, base):
|
|
221
240
|
return {
|
|
222
241
|
"ok": false,
|
|
223
|
-
"error":
|
|
242
|
+
"error":
|
|
243
|
+
"%s extends %s, so it cannot be on a %s." % [script_file, base, resource_type],
|
|
224
244
|
}
|
|
225
245
|
resource.set_script(script)
|
|
226
246
|
|
|
227
247
|
var properties: Dictionary = _parse_properties_dict(args.get("properties", {}))
|
|
228
248
|
var refused: String = _properties.write_all(resource, properties)
|
|
229
249
|
if not refused.is_empty():
|
|
230
|
-
return {
|
|
250
|
+
return {
|
|
251
|
+
"ok": false, "error": GdhHeadlessCheck.setter_ran(
|
|
252
|
+
resource,
|
|
253
|
+
_properties.unheld,
|
|
254
|
+
refused,
|
|
255
|
+
),
|
|
256
|
+
}
|
|
231
257
|
|
|
232
258
|
var folder: String = GdhSceneFile.make_folder_for(res_path)
|
|
233
259
|
if not folder.is_empty():
|
|
234
|
-
return {"ok": false, "error": folder}
|
|
235
|
-
# As a read names it, the engine class under resourceType and the script's class beside it,
|
|
236
|
-
# a create given resourceType Resource and a script answered nothing of the class it had
|
|
237
|
-
# one given a class_name answered it where a read of the same file answers Resource.
|
|
238
|
-
var answer: Dictionary = {"ok": true, "resourcePath": res_path, "resourceType": resource_type}
|
|
260
|
+
return { "ok": false, "error": folder }
|
|
261
|
+
# As a read names it, the engine class under resourceType and the script's class beside it,
|
|
262
|
+
# since a create given resourceType Resource and a script answered nothing of the class it had
|
|
263
|
+
# made, and one given a class_name answered it where a read of the same file answers Resource.
|
|
264
|
+
var answer: Dictionary = { "ok": true, "resourcePath": res_path, "resourceType": resource_type }
|
|
239
265
|
var scripted: Variant = resource.get_script()
|
|
240
266
|
if scripted is Script:
|
|
241
267
|
var attached: Script = scripted
|
|
@@ -245,7 +271,7 @@ func create_resource(args: Dictionary) -> Dictionary:
|
|
|
245
271
|
_properties.note_write(answer)
|
|
246
272
|
var failed: String = _save_checked(resource, res_path, properties.keys(), null)
|
|
247
273
|
if not failed.is_empty():
|
|
248
|
-
return {"ok": false, "error": failed}
|
|
274
|
+
return { "ok": false, "error": failed }
|
|
249
275
|
_note_put_back(answer, resource, res_path)
|
|
250
276
|
if not properties.is_empty():
|
|
251
277
|
answer["properties"] = _held(resource, properties.keys())
|
|
@@ -255,9 +281,9 @@ func create_resource(args: Dictionary) -> Dictionary:
|
|
|
255
281
|
func modify_resource(args: Dictionary) -> Dictionary:
|
|
256
282
|
var res_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
257
283
|
if res_path == "res://":
|
|
258
|
-
return {"ok": false, "error": "resourcePath is required"}
|
|
284
|
+
return { "ok": false, "error": "resourcePath is required" }
|
|
259
285
|
if not FileAccess.file_exists(res_path):
|
|
260
|
-
return {"ok": false, "error": "No resource at %s; op=create makes one there." % res_path}
|
|
286
|
+
return { "ok": false, "error": "No resource at %s; op=create makes one there." % res_path }
|
|
261
287
|
# The editor's copy of an imported file is rebuilt from the source on every import, and a save
|
|
262
288
|
# to it fails; edited through the cache, the editor kept the changed copy after the refusal.
|
|
263
289
|
if FileAccess.file_exists(res_path + ".import"):
|
|
@@ -266,17 +292,17 @@ func modify_resource(args: Dictionary) -> Dictionary:
|
|
|
266
292
|
"error":
|
|
267
293
|
(
|
|
268
294
|
(
|
|
269
|
-
"%s is imported, so what it holds comes from its source file and its import
|
|
270
|
-
+ "Change those with project_import op=set_options."
|
|
295
|
+
"%s is imported, so what it holds comes from its source file and its import "
|
|
296
|
+
+ "options. Change those with project_import op=set_options."
|
|
271
297
|
)
|
|
272
298
|
% res_path
|
|
273
|
-
)
|
|
299
|
+
),
|
|
274
300
|
}
|
|
275
301
|
|
|
276
302
|
# Past the cache, so a refusal leaves the copy open scenes hold as it was.
|
|
277
303
|
var resource: Resource = ResourceLoader.load(res_path, "", ResourceLoader.CACHE_MODE_IGNORE)
|
|
278
304
|
if resource == null:
|
|
279
|
-
return {"ok": false, "error": "%s did not load as a resource." % res_path}
|
|
305
|
+
return { "ok": false, "error": "%s did not load as a resource." % res_path }
|
|
280
306
|
# A scene's own properties are its packed bundle, so a property named for a scene is one of its
|
|
281
307
|
# nodes', and "PackedScene has no property" left the caller looking for the tool that sets it.
|
|
282
308
|
if resource is PackedScene:
|
|
@@ -284,9 +310,12 @@ func modify_resource(args: Dictionary) -> Dictionary:
|
|
|
284
310
|
"ok": false,
|
|
285
311
|
"error":
|
|
286
312
|
(
|
|
287
|
-
|
|
313
|
+
(
|
|
314
|
+
"%s is a scene: scene_node set changes one node's properties, the root's at "
|
|
315
|
+
+ "nodePath \".\"."
|
|
316
|
+
)
|
|
288
317
|
% res_path
|
|
289
|
-
)
|
|
318
|
+
),
|
|
290
319
|
}
|
|
291
320
|
|
|
292
321
|
var properties: Dictionary = _parse_properties_dict(args.get("properties", ""))
|
|
@@ -296,13 +325,13 @@ func modify_resource(args: Dictionary) -> Dictionary:
|
|
|
296
325
|
else:
|
|
297
326
|
refused = GdhHeadlessCheck.setter_ran(resource, _properties.unheld, refused)
|
|
298
327
|
if not refused.is_empty():
|
|
299
|
-
return {"ok": false, "error": refused}
|
|
300
|
-
var answer: Dictionary = {"ok": true, "resourcePath": res_path}
|
|
328
|
+
return { "ok": false, "error": refused }
|
|
329
|
+
var answer: Dictionary = { "ok": true, "resourcePath": res_path }
|
|
301
330
|
_properties.note_write(answer)
|
|
302
331
|
var previous: PackedByteArray = FileAccess.get_file_as_bytes(res_path)
|
|
303
332
|
var failed: String = _save_checked(resource, res_path, properties.keys(), previous)
|
|
304
333
|
if not failed.is_empty():
|
|
305
|
-
return {"ok": false, "error": failed}
|
|
334
|
+
return { "ok": false, "error": failed }
|
|
306
335
|
_note_put_back(answer, resource, res_path)
|
|
307
336
|
answer["properties"] = _held(resource, properties.keys())
|
|
308
337
|
return answer
|
|
@@ -328,12 +357,14 @@ func _note_put_back(answer: Dictionary, resource: Resource, path: String) -> voi
|
|
|
328
357
|
func _holding_itself(resource: Resource, path: String, names: Array) -> String:
|
|
329
358
|
for key: Variant in names:
|
|
330
359
|
var property: String = str(key)
|
|
331
|
-
for held: Resource in GdhHeadlessCheck.resources_in(
|
|
360
|
+
for held: Resource in GdhHeadlessCheck.resources_in(
|
|
361
|
+
_properties.read_at(resource, property)
|
|
362
|
+
):
|
|
332
363
|
if held == resource or held.resource_path == path:
|
|
333
364
|
return (
|
|
334
365
|
(
|
|
335
|
-
"%s.%s would hold %s itself, and a resource cannot hold the file it is
|
|
336
|
-
+ "Godot saves the reference as null. Nothing was written."
|
|
366
|
+
"%s.%s would hold %s itself, and a resource cannot hold the file it is "
|
|
367
|
+
+ "saved as: Godot saves the reference as null. Nothing was written."
|
|
337
368
|
)
|
|
338
369
|
% [GdhPropertyPaths.class_called(resource), property, path]
|
|
339
370
|
)
|
|
@@ -354,7 +385,7 @@ func _held(resource: Resource, asked: Array) -> Dictionary:
|
|
|
354
385
|
func read_resource(args: Dictionary) -> Dictionary:
|
|
355
386
|
var res_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
356
387
|
if res_path == "res://":
|
|
357
|
-
return {"ok": false, "error": "resourcePath is required"}
|
|
388
|
+
return { "ok": false, "error": "resourcePath is required" }
|
|
358
389
|
# The server takes a resource kept inside a file apart, so the boundary judges the file alone.
|
|
359
390
|
var inner: String = str(args.get("subResource", ""))
|
|
360
391
|
if not inner.is_empty():
|
|
@@ -366,10 +397,10 @@ func create_shader(args: Dictionary) -> Dictionary:
|
|
|
366
397
|
var shader_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
367
398
|
var shader_type: String = str(args.get("shaderType", "canvas_item"))
|
|
368
399
|
if shader_path == "res://":
|
|
369
|
-
return {"ok": false, "error": "resourcePath is required"}
|
|
400
|
+
return { "ok": false, "error": "resourcePath is required" }
|
|
370
401
|
var taken: String = _taken(shader_path, "resource_edit op=create_shader", "Edit its text")
|
|
371
402
|
if not taken.is_empty():
|
|
372
|
-
return {"ok": false, "error": taken}
|
|
403
|
+
return { "ok": false, "error": taken }
|
|
373
404
|
|
|
374
405
|
var code: String = str(args.get("code", ""))
|
|
375
406
|
if code == "":
|
|
@@ -377,21 +408,24 @@ func create_shader(args: Dictionary) -> Dictionary:
|
|
|
377
408
|
|
|
378
409
|
var folder: String = GdhSceneFile.make_folder_for(shader_path)
|
|
379
410
|
if not folder.is_empty():
|
|
380
|
-
return {"ok": false, "error": folder}
|
|
411
|
+
return { "ok": false, "error": folder }
|
|
381
412
|
var file: FileAccess = FileAccess.open(shader_path, FileAccess.WRITE)
|
|
382
413
|
if file == null:
|
|
383
414
|
return {
|
|
384
415
|
"ok": false,
|
|
385
416
|
"error":
|
|
386
|
-
|
|
417
|
+
(
|
|
418
|
+
"Could not open %s for writing: %s"
|
|
419
|
+
% [shader_path, error_string(FileAccess.get_open_error())]
|
|
420
|
+
),
|
|
387
421
|
}
|
|
388
422
|
var written: bool = file.store_string(code)
|
|
389
423
|
file.close()
|
|
390
424
|
if not written:
|
|
391
|
-
return {"ok": false, "error": "Failed to write the shader file " + shader_path}
|
|
425
|
+
return { "ok": false, "error": "Failed to write the shader file " + shader_path }
|
|
392
426
|
|
|
393
427
|
_written(shader_path)
|
|
394
|
-
var answer: Dictionary = {"ok": true, "shaderPath": shader_path, "shaderType": shader_type}
|
|
428
|
+
var answer: Dictionary = { "ok": true, "shaderPath": shader_path, "shaderType": shader_type }
|
|
395
429
|
var errors: Array[Dictionary] = _shader_errors(shader_path)
|
|
396
430
|
answer["compiles"] = errors.is_empty()
|
|
397
431
|
if not errors.is_empty():
|
|
@@ -405,42 +439,21 @@ func create_shader(args: Dictionary) -> Dictionary:
|
|
|
405
439
|
func _shader_errors(path: String) -> Array[Dictionary]:
|
|
406
440
|
var caught: GdhShaderErrors = GdhShaderErrors.new()
|
|
407
441
|
OS.add_logger(caught)
|
|
408
|
-
var shader: Shader =
|
|
442
|
+
var shader: Shader = (
|
|
443
|
+
ResourceLoader.load(path, "Shader", ResourceLoader.CACHE_MODE_IGNORE) as Shader
|
|
444
|
+
)
|
|
409
445
|
if shader != null:
|
|
410
446
|
var _uniforms: Array = shader.get_shader_uniform_list()
|
|
411
447
|
OS.remove_logger(caught)
|
|
412
448
|
return caught.raised
|
|
413
449
|
|
|
414
450
|
|
|
415
|
-
## Every shader error the engine raises while it is attached, in order.
|
|
416
|
-
class GdhShaderErrors:
|
|
417
|
-
extends Logger
|
|
418
|
-
|
|
419
|
-
var raised: Array[Dictionary] = []
|
|
420
|
-
|
|
421
|
-
func _log_message(_message: String, _error: bool) -> void:
|
|
422
|
-
pass
|
|
423
|
-
|
|
424
|
-
# The engine's own signature for a Logger, eight parameters and not this project's to shape.
|
|
425
|
-
# gdlint:ignore = function-arguments-number
|
|
426
|
-
func _log_error(
|
|
427
|
-
_function: String,
|
|
428
|
-
_file: String,
|
|
429
|
-
line: int,
|
|
430
|
-
code: String,
|
|
431
|
-
rationale: String,
|
|
432
|
-
_editor_notify: bool,
|
|
433
|
-
error_type: int,
|
|
434
|
-
_script_backtraces: Array[ScriptBacktrace],
|
|
435
|
-
) -> void:
|
|
436
|
-
if error_type == Logger.ERROR_TYPE_SHADER:
|
|
437
|
-
raised.append({"line": line, "message": code if rationale.is_empty() else rationale})
|
|
438
|
-
|
|
439
|
-
|
|
440
451
|
## Saves [param theme] over [param theme_path] with [param items] changed, answering "" or why not.
|
|
441
452
|
func _save_theme(theme: Theme, theme_path: String, items: Array) -> String:
|
|
442
453
|
var previous: PackedByteArray = FileAccess.get_file_as_bytes(theme_path)
|
|
443
|
-
var carried: Dictionary = GdhHeadlessCheck.embedded_in(
|
|
454
|
+
var carried: Dictionary = GdhHeadlessCheck.embedded_in(
|
|
455
|
+
GdhHeadlessCheck.stored(theme).values(), {}
|
|
456
|
+
)
|
|
444
457
|
var saving: Error = GdhSceneUids.save_keeping_uid(theme, theme_path)
|
|
445
458
|
if saving != OK:
|
|
446
459
|
return "Failed to save %s: %s" % [theme_path, error_string(saving)]
|
|
@@ -454,32 +467,37 @@ func _save_theme(theme: Theme, theme_path: String, items: Array) -> String:
|
|
|
454
467
|
func set_theme_color(args: Dictionary) -> Dictionary:
|
|
455
468
|
var theme_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
456
469
|
if theme_path == "res://":
|
|
457
|
-
return {"ok": false, "error": "resourcePath is required"}
|
|
470
|
+
return { "ok": false, "error": "resourcePath is required" }
|
|
458
471
|
|
|
459
472
|
var color_name: String = str(args.get("colorName", ""))
|
|
460
473
|
var control_type: String = str(args.get("controlType", ""))
|
|
461
474
|
if color_name.is_empty() or control_type.is_empty():
|
|
462
|
-
return {"ok": false, "error": "colorName and controlType are required"}
|
|
475
|
+
return { "ok": false, "error": "colorName and controlType are required" }
|
|
463
476
|
|
|
464
477
|
var theme: Theme = _load_theme(theme_path)
|
|
465
478
|
if theme == null:
|
|
466
|
-
return {"ok": false, "error": "No Theme at %s. Create one there first." % theme_path}
|
|
479
|
+
return { "ok": false, "error": "No Theme at %s. Create one there first." % theme_path }
|
|
467
480
|
|
|
468
481
|
# Read as a property write reads a colour, html code included, so a value scene_node takes for a
|
|
469
482
|
# Button's modulate is taken for its theme colour too; "#ff8000" was refused here alone.
|
|
470
483
|
var parsed: Array = _properties.colour_from(args.get("color", {}), "color")
|
|
471
484
|
if not parsed[0]:
|
|
472
|
-
return {"ok": false, "error": parsed[1]}
|
|
485
|
+
return { "ok": false, "error": parsed[1] }
|
|
473
486
|
var color: Color = parsed[1]
|
|
474
487
|
theme.set_color(color_name, control_type, color)
|
|
475
488
|
|
|
476
|
-
var unsaved: String = _save_theme(
|
|
489
|
+
var unsaved: String = _save_theme(
|
|
490
|
+
theme, theme_path, ["%s/colors/%s" % [control_type, color_name]]
|
|
491
|
+
)
|
|
477
492
|
if not unsaved.is_empty():
|
|
478
|
-
return {"ok": false, "error": unsaved}
|
|
493
|
+
return { "ok": false, "error": unsaved }
|
|
479
494
|
|
|
480
495
|
var saved: Theme = _load_theme(theme_path)
|
|
481
496
|
if saved == null or not saved.has_color(color_name, control_type):
|
|
482
|
-
return {
|
|
497
|
+
return {
|
|
498
|
+
"ok": false,
|
|
499
|
+
"error": "The theme saved without %s/%s" % [control_type, color_name],
|
|
500
|
+
}
|
|
483
501
|
|
|
484
502
|
var stored: Color = saved.get_color(color_name, control_type)
|
|
485
503
|
return _noting_variation(
|
|
@@ -488,7 +506,7 @@ func set_theme_color(args: Dictionary) -> Dictionary:
|
|
|
488
506
|
"resourcePath": theme_path,
|
|
489
507
|
"controlType": control_type,
|
|
490
508
|
"colorName": color_name,
|
|
491
|
-
"color": {"r": stored.r, "g": stored.g, "b": stored.b, "a": stored.a}
|
|
509
|
+
"color": { "r": stored.r, "g": stored.g, "b": stored.b, "a": stored.a },
|
|
492
510
|
}
|
|
493
511
|
)
|
|
494
512
|
|
|
@@ -496,33 +514,36 @@ func set_theme_color(args: Dictionary) -> Dictionary:
|
|
|
496
514
|
func set_theme_font_size(args: Dictionary) -> Dictionary:
|
|
497
515
|
var theme_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
498
516
|
if theme_path == "res://":
|
|
499
|
-
return {"ok": false, "error": "resourcePath is required"}
|
|
517
|
+
return { "ok": false, "error": "resourcePath is required" }
|
|
500
518
|
|
|
501
519
|
var font_size_name: String = str(args.get("fontSizeName", ""))
|
|
502
520
|
var control_type: String = str(args.get("controlType", ""))
|
|
503
521
|
if font_size_name.is_empty() or control_type.is_empty():
|
|
504
|
-
return {"ok": false, "error": "fontSizeName and controlType are required"}
|
|
522
|
+
return { "ok": false, "error": "fontSizeName and controlType are required" }
|
|
505
523
|
|
|
506
524
|
var theme: Theme = _load_theme(theme_path)
|
|
507
525
|
if theme == null:
|
|
508
|
-
return {"ok": false, "error": "No Theme at %s. Create one there first." % theme_path}
|
|
526
|
+
return { "ok": false, "error": "No Theme at %s. Create one there first." % theme_path }
|
|
509
527
|
|
|
510
528
|
# Godot reads a size of 0 or less as unset and answers the theme's default, so -3 would be read
|
|
511
529
|
# back as 16.
|
|
512
530
|
var pixels: float = GdhRead.as_float(args.get("size"), 0.0)
|
|
513
531
|
if not is_finite(pixels) or pixels != floorf(pixels):
|
|
514
|
-
return {
|
|
532
|
+
return {
|
|
533
|
+
"ok": false,
|
|
534
|
+
"error": "size is a whole number of pixels, and %s is not one." % str(pixels),
|
|
535
|
+
}
|
|
515
536
|
if pixels < 1:
|
|
516
537
|
return {
|
|
517
538
|
"ok": false,
|
|
518
539
|
"error":
|
|
519
540
|
(
|
|
520
541
|
(
|
|
521
|
-
"size must be 1 or more, not %d: the theme would hold it, and Godot reads a
|
|
522
|
-
+ "less as unset and draws the default size instead."
|
|
542
|
+
"size must be 1 or more, not %d: the theme would hold it, and Godot reads a "
|
|
543
|
+
+ "size of 0 or less as unset and draws the default size instead."
|
|
523
544
|
)
|
|
524
545
|
% int(pixels)
|
|
525
|
-
)
|
|
546
|
+
),
|
|
526
547
|
}
|
|
527
548
|
theme.set_font_size(font_size_name, control_type, int(pixels))
|
|
528
549
|
|
|
@@ -530,11 +551,13 @@ func set_theme_font_size(args: Dictionary) -> Dictionary:
|
|
|
530
551
|
theme, theme_path, ["%s/font_sizes/%s" % [control_type, font_size_name]]
|
|
531
552
|
)
|
|
532
553
|
if not unsaved.is_empty():
|
|
533
|
-
return {"ok": false, "error": unsaved}
|
|
554
|
+
return { "ok": false, "error": unsaved }
|
|
534
555
|
|
|
535
556
|
var saved: Theme = _load_theme(theme_path)
|
|
536
557
|
if saved == null or not saved.has_font_size(font_size_name, control_type):
|
|
537
|
-
return {
|
|
558
|
+
return {
|
|
559
|
+
"ok": false, "error": "The theme saved without %s/%s" % [control_type, font_size_name],
|
|
560
|
+
}
|
|
538
561
|
|
|
539
562
|
return _noting_variation(
|
|
540
563
|
{
|
|
@@ -542,7 +565,7 @@ func set_theme_font_size(args: Dictionary) -> Dictionary:
|
|
|
542
565
|
"resourcePath": theme_path,
|
|
543
566
|
"controlType": control_type,
|
|
544
567
|
"fontSizeName": font_size_name,
|
|
545
|
-
"size": saved.get_font_size(font_size_name, control_type)
|
|
568
|
+
"size": saved.get_font_size(font_size_name, control_type),
|
|
546
569
|
}
|
|
547
570
|
)
|
|
548
571
|
|
|
@@ -554,11 +577,11 @@ func remove_theme_item(args: Dictionary) -> Dictionary:
|
|
|
554
577
|
var control_type: String = str(args.get("controlType", ""))
|
|
555
578
|
var theme: Theme = _load_theme(theme_path)
|
|
556
579
|
if theme == null:
|
|
557
|
-
return {"ok": false, "error": "No Theme at %s." % theme_path}
|
|
580
|
+
return { "ok": false, "error": "No Theme at %s." % theme_path }
|
|
558
581
|
if not theme.get_type_list().has(control_type):
|
|
559
582
|
var types: PackedStringArray = theme.get_type_list()
|
|
560
583
|
var said: String = "%s holds no type %s" % [theme_path, control_type]
|
|
561
|
-
return {"ok": false, "error": GdhRead.offered(said, control_type, Array(types))}
|
|
584
|
+
return { "ok": false, "error": GdhRead.offered(said, control_type, Array(types)) }
|
|
562
585
|
var kinds: Array[String] = ["colors", "constants", "fonts", "font_sizes", "icons", "styles"]
|
|
563
586
|
var item: String = str(args.get("item", ""))
|
|
564
587
|
var removed: Array[String] = []
|
|
@@ -581,13 +604,21 @@ func remove_theme_item(args: Dictionary) -> Dictionary:
|
|
|
581
604
|
"%s holds no items, only the type it varies, %s; "
|
|
582
605
|
+ "without item, remove_theme_item takes it out."
|
|
583
606
|
)
|
|
584
|
-
return {"ok": false, "error": only % [control_type, base]}
|
|
607
|
+
return { "ok": false, "error": only % [control_type, base] }
|
|
585
608
|
elif removed.is_empty():
|
|
586
|
-
return {
|
|
609
|
+
return {
|
|
610
|
+
"ok": false,
|
|
611
|
+
"error": GdhRead.offered("%s has no item %s" % [control_type, item], item, held),
|
|
612
|
+
}
|
|
587
613
|
var unsaved: String = _save_theme(theme, theme_path, removed)
|
|
588
614
|
if not unsaved.is_empty():
|
|
589
|
-
return {"ok": false, "error": unsaved}
|
|
590
|
-
return {
|
|
615
|
+
return { "ok": false, "error": unsaved }
|
|
616
|
+
return {
|
|
617
|
+
"ok": true,
|
|
618
|
+
"resourcePath": theme_path,
|
|
619
|
+
"controlType": control_type,
|
|
620
|
+
"removed": removed,
|
|
621
|
+
}
|
|
591
622
|
|
|
592
623
|
|
|
593
624
|
## [param answer] with a note when its controlType names no class a theme styles. Any name is a
|
|
@@ -602,8 +633,8 @@ func _noting_variation(answer: Dictionary) -> Dictionary:
|
|
|
602
633
|
return answer
|
|
603
634
|
answer["note"] = (
|
|
604
635
|
(
|
|
605
|
-
"%s is not a Control or Window class, so this is a type variation: it styles only a
|
|
606
|
-
+ "whose theme_type_variation is %s."
|
|
636
|
+
"%s is not a Control or Window class, so this is a type variation: it styles only a "
|
|
637
|
+
+ "control whose theme_type_variation is %s."
|
|
607
638
|
)
|
|
608
639
|
% [type, type]
|
|
609
640
|
)
|
|
@@ -616,7 +647,35 @@ func _noting_variation(answer: Dictionary) -> Dictionary:
|
|
|
616
647
|
var close: PackedStringArray = GdhRead.nearest(type, themed)
|
|
617
648
|
if not close.is_empty():
|
|
618
649
|
answer["note"] += (
|
|
619
|
-
(
|
|
650
|
+
(
|
|
651
|
+
" If a class was meant, the nearest %s %s, and remove_theme_item with controlType "
|
|
652
|
+
+ "%s takes this out."
|
|
653
|
+
)
|
|
620
654
|
% ["is" if close.size() == 1 else "are", ", ".join(close), type]
|
|
621
655
|
)
|
|
622
656
|
return answer
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
## Every shader error the engine raises while it is attached, in order.
|
|
660
|
+
class GdhShaderErrors:
|
|
661
|
+
extends Logger
|
|
662
|
+
|
|
663
|
+
var raised: Array[Dictionary] = []
|
|
664
|
+
|
|
665
|
+
func _log_message(_message: String, _error: bool) -> void:
|
|
666
|
+
pass
|
|
667
|
+
|
|
668
|
+
# The engine's own signature for a Logger, eight parameters and not this project's to shape.
|
|
669
|
+
# gdstyle:ignore=quality/max-parameters
|
|
670
|
+
func _log_error(
|
|
671
|
+
_function: String,
|
|
672
|
+
_file: String,
|
|
673
|
+
line: int,
|
|
674
|
+
code: String,
|
|
675
|
+
rationale: String,
|
|
676
|
+
_editor_notify: bool,
|
|
677
|
+
error_type: int,
|
|
678
|
+
_script_backtraces: Array[ScriptBacktrace],
|
|
679
|
+
) -> void:
|
|
680
|
+
if error_type == Logger.ERROR_TYPE_SHADER:
|
|
681
|
+
raised.append({ "line": line, "message": code if rationale.is_empty() else rationale })
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
@tool
|
|
2
2
|
extends RefCounted
|
|
3
|
-
|
|
4
3
|
## The groups a node of a scene is in. A scene's own file puts a node in a group and can take it
|
|
5
4
|
## out of one it put it in; a group the scene that makes the node puts it in, the one it is
|
|
6
5
|
## instanced from or one this scene inherits, can be changed only there, as the editor's group dock
|
|
@@ -15,20 +14,20 @@ static func read(scene: GdhSceneFile, node: Node) -> Dictionary:
|
|
|
15
14
|
var all: Array = _sorted(node.get_groups())
|
|
16
15
|
if all.is_empty():
|
|
17
16
|
return {}
|
|
18
|
-
var answer: Dictionary = {"groups": all}
|
|
17
|
+
var answer: Dictionary = { "groups": all }
|
|
19
18
|
var here: Array = _sorted(scene.groups_at(scene.path_of(node)))
|
|
20
19
|
if here.size() != all.size():
|
|
21
20
|
answer["groupsHere"] = here
|
|
22
21
|
return answer
|
|
23
22
|
|
|
24
23
|
|
|
25
|
-
## The groups of [param node], just added to this scene and put in [param adding] there, in the
|
|
26
|
-
## [method read] answers: this scene's file does not hold the node until it is saved.
|
|
24
|
+
## The groups of [param node], just added to this scene and put in [param adding] there, in the
|
|
25
|
+
## shape [method read] answers: this scene's file does not hold the node until it is saved.
|
|
27
26
|
static func read_added(node: Node, adding: Array) -> Dictionary:
|
|
28
27
|
var all: Array = _sorted(node.get_groups())
|
|
29
28
|
if all.is_empty():
|
|
30
29
|
return {}
|
|
31
|
-
var answer: Dictionary = {"groups": all}
|
|
30
|
+
var answer: Dictionary = { "groups": all }
|
|
32
31
|
var here: Array = []
|
|
33
32
|
for group: String in _sorted(adding):
|
|
34
33
|
if not here.has(group):
|
|
@@ -65,19 +64,27 @@ static func change(scene: GdhSceneFile, node: Node, adding: Array, removing: Arr
|
|
|
65
64
|
var held: Array = _sorted(node.get_groups())
|
|
66
65
|
return (
|
|
67
66
|
"%s is in no group %s; %s."
|
|
68
|
-
% [
|
|
67
|
+
% [
|
|
68
|
+
node.name,
|
|
69
|
+
name,
|
|
70
|
+
"it is in " + ", ".join(held) if not held.is_empty() else "it is in none",
|
|
71
|
+
]
|
|
69
72
|
)
|
|
70
73
|
if not here.has(name):
|
|
71
74
|
var from: String = scene.values_from(node, at)
|
|
72
75
|
if from.is_empty():
|
|
73
76
|
return (
|
|
74
|
-
|
|
77
|
+
(
|
|
78
|
+
"%s is in %s, which no scene file puts it in: something puts it there as "
|
|
79
|
+
+ "it is made, such as its script."
|
|
80
|
+
)
|
|
75
81
|
% [node.name, name]
|
|
76
82
|
)
|
|
77
83
|
return (
|
|
78
84
|
(
|
|
79
|
-
"%s is in %s because %s puts it there, and no scene using that one can take it
|
|
80
|
-
+ "remove the group in %s, which takes it out in every scene using that
|
|
85
|
+
"%s is in %s because %s puts it there, and no scene using that one can take it "
|
|
86
|
+
+ "out: remove the group in %s, which takes it out in every scene using that "
|
|
87
|
+
+ "one."
|
|
81
88
|
)
|
|
82
89
|
% [node.name, name, from, from]
|
|
83
90
|
)
|