gdharness 1.2.42 → 1.3.1
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 +571 -363
- package/build/godot/addons/gdharness_editor/animation_reads.gd +7 -19
- package/build/godot/addons/gdharness_editor/bridge_client.gd +9 -9
- package/build/godot/addons/gdharness_editor/file_reads.gd +60 -25
- package/build/godot/addons/gdharness_editor/headless_check.gd +7 -7
- package/build/godot/addons/gdharness_editor/plugin.gd +6 -6
- package/build/godot/addons/gdharness_editor/property_values.gd +124 -62
- package/build/godot/addons/gdharness_editor/reading.gd +28 -0
- package/build/godot/addons/gdharness_editor/scene_file.gd +28 -23
- package/build/godot/addons/gdharness_editor/serialisation.gd +45 -94
- package/build/godot/addons/gdharness_editor/tool_executor.gd +24 -24
- package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +52 -41
- package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +4 -4
- package/build/godot/addons/gdharness_editor/tools/play_tools.gd +2 -2
- package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +14 -14
- package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +57 -50
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +17 -17
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +14 -12
- package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +7 -7
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +82 -78
- package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +4 -4
- package/build/godot/addons/gdharness_editor/value_shapes.gd +111 -0
- package/build/godot/addons/gdharness_editor/value_shapes.gd.uid +1 -0
- package/build/godot/addons/gdharness_runtime/reading.gd +28 -0
- package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +18 -18
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +32 -32
- package/build/godot/addons/gdharness_runtime/runtime_capture.gd +50 -18
- package/build/godot/addons/gdharness_runtime/runtime_changes.gd +86 -80
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +65 -69
- package/build/godot/addons/gdharness_runtime/runtime_items.gd +6 -6
- package/build/godot/addons/gdharness_runtime/runtime_menus.gd +8 -8
- package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +13 -21
- package/build/godot/addons/gdharness_runtime/runtime_pad.gd +10 -10
- package/build/godot/addons/gdharness_runtime/runtime_paths.gd +7 -7
- package/build/godot/addons/gdharness_runtime/runtime_queries.gd +41 -41
- package/build/godot/addons/gdharness_runtime/runtime_says.gd +3 -3
- package/build/godot/addons/gdharness_runtime/runtime_targets.gd +33 -33
- package/build/godot/addons/gdharness_runtime/runtime_typing.gd +20 -20
- package/build/godot/addons/gdharness_runtime/runtime_values.gd +25 -24
- package/build/godot/addons/gdharness_runtime/runtime_waits.gd +56 -50
- package/build/godot/addons/gdharness_runtime/serialisation.gd +45 -94
- package/build/godot/addons/gdharness_runtime/value_shapes.gd +111 -0
- package/build/godot/addons/gdharness_runtime/value_shapes.gd.uid +1 -0
- package/build/godot/operations/animation_reads.gd +7 -19
- package/build/godot/operations/audio_buses.gd +10 -10
- package/build/godot/operations/class_cache.gd +16 -16
- package/build/godot/operations/classdb_queries.gd +12 -12
- package/build/godot/operations/dependencies.gd +33 -29
- package/build/godot/operations/editor_tools.gd +12 -12
- package/build/godot/operations/export_presets.gd +10 -8
- package/build/godot/operations/file_reads.gd +60 -25
- package/build/godot/operations/gdscript_analysis.gd +20 -20
- package/build/godot/operations/gdscript_authoring.gd +17 -15
- package/build/godot/operations/godot_operations.gd +64 -63
- package/build/godot/operations/import_pipeline.gd +20 -20
- package/build/godot/operations/input_actions.gd +17 -17
- package/build/godot/operations/logger.gd +1 -1
- package/build/godot/operations/plugins.gd +8 -8
- package/build/godot/operations/project_config.gd +24 -17
- package/build/godot/operations/project_diagnostics.gd +9 -9
- package/build/godot/operations/property_values.gd +124 -62
- package/build/godot/operations/reading.gd +28 -0
- package/build/godot/operations/rename_checks.gd +3 -3
- package/build/godot/operations/resource_files.gd +5 -5
- package/build/godot/operations/script_check.gd +7 -7
- package/build/godot/operations/serialisation.gd +45 -94
- package/build/godot/operations/value_shapes.gd +111 -0
- package/build/keeper.js +10 -4
- package/package.json +1 -2
- package/build/index.js +0 -45101
|
@@ -10,7 +10,7 @@ extends Node
|
|
|
10
10
|
## `debug_data` signal every ScriptEditorDebugger emits for every message, on a node Godot does not
|
|
11
11
|
## expose to scripts: found by its class in the editor's tree and connected to by name.
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const GdhRead = preload("../reading.gd")
|
|
14
14
|
|
|
15
15
|
## The most functions a frame may carry when the server does not say. The engine names a function
|
|
16
16
|
## once, as it first appears, and the game's debugger queue drops those messages past its size, so
|
|
@@ -28,7 +28,7 @@ const PROFILE_FROM_START: String = "GDHARNESS_PROFILE_FROM_START"
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
## The editor's debugger sessions, numbered as the editor numbers its debugger tabs.
|
|
31
|
-
class
|
|
31
|
+
class GdhSessions:
|
|
32
32
|
extends EditorDebuggerPlugin
|
|
33
33
|
|
|
34
34
|
signal session_started(session_id: int)
|
|
@@ -53,7 +53,7 @@ class Sessions:
|
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
var _editor_plugin: EditorPlugin = null
|
|
56
|
-
var _sessions:
|
|
56
|
+
var _sessions: GdhSessions = null
|
|
57
57
|
## The debugger tabs connected to, by instance id, so none is connected twice.
|
|
58
58
|
var _hooked: Dictionary[int, bool] = {}
|
|
59
59
|
|
|
@@ -75,7 +75,7 @@ var _totals: Dictionary[String, PackedFloat64Array] = {}
|
|
|
75
75
|
|
|
76
76
|
func set_editor_plugin(plugin: EditorPlugin) -> void:
|
|
77
77
|
_editor_plugin = plugin
|
|
78
|
-
_sessions =
|
|
78
|
+
_sessions = GdhSessions.new()
|
|
79
79
|
var joined: int = _sessions.session_started.connect(_on_session_started)
|
|
80
80
|
if joined != OK:
|
|
81
81
|
push_error("gdharness could not watch debugger sessions start: %d" % joined)
|
|
@@ -105,9 +105,9 @@ func profile_start(args: Dictionary) -> Dictionary:
|
|
|
105
105
|
),
|
|
106
106
|
}
|
|
107
107
|
_reset()
|
|
108
|
-
var asked: int =
|
|
108
|
+
var asked: int = GdhRead.as_int(args.get("frameFunctions", FRAME_FUNCTIONS))
|
|
109
109
|
_frame_functions = asked if asked > 0 else FRAME_FUNCTIONS
|
|
110
|
-
if
|
|
110
|
+
if GdhRead.as_bool(args.get("arm", false)):
|
|
111
111
|
_armed = true
|
|
112
112
|
# The game the editor starts next inherits the editor's environment, and this tells its
|
|
113
113
|
# runtime addon to hold its start until the profiler is on, which the session's start
|
|
@@ -206,7 +206,7 @@ func _on_debug_data(message: String, data: Array, session_id: int) -> void:
|
|
|
206
206
|
if session_id != _session:
|
|
207
207
|
return
|
|
208
208
|
if message == "servers:function_signature" and data.size() >= 2:
|
|
209
|
-
_names[
|
|
209
|
+
_names[GdhRead.as_int(data[1])] = str(data[0])
|
|
210
210
|
elif message == "servers:profile_frame":
|
|
211
211
|
var carried: int = _add(data, _totals)
|
|
212
212
|
if carried >= 0:
|
|
@@ -231,28 +231,28 @@ func _add(data: Array, into: Dictionary[String, PackedFloat64Array]) -> int:
|
|
|
231
231
|
var at: int = 6
|
|
232
232
|
if data.size() <= at:
|
|
233
233
|
return -1
|
|
234
|
-
var servers: int =
|
|
234
|
+
var servers: int = GdhRead.as_int(data[at])
|
|
235
235
|
at += 1
|
|
236
236
|
for _server: int in servers:
|
|
237
237
|
if data.size() <= at + 1:
|
|
238
238
|
return -1
|
|
239
|
-
at += 2 +
|
|
239
|
+
at += 2 + GdhRead.as_int(data[at + 1])
|
|
240
240
|
if data.size() <= at:
|
|
241
241
|
return -1
|
|
242
|
-
var values: int =
|
|
242
|
+
var values: int = GdhRead.as_int(data[at])
|
|
243
243
|
at += 1
|
|
244
244
|
if values % 5 != 0 or data.size() < at + values:
|
|
245
245
|
return -1
|
|
246
246
|
var carried: int = 0
|
|
247
247
|
for index: int in range(at, at + values, 5):
|
|
248
|
-
var id: int =
|
|
248
|
+
var id: int = GdhRead.as_int(data[index])
|
|
249
249
|
var signature: String = _names[id] if _names.has(id) else "#%d" % id
|
|
250
250
|
var sum: PackedFloat64Array = (
|
|
251
251
|
into[signature] if into.has(signature) else PackedFloat64Array([0, 0, 0])
|
|
252
252
|
)
|
|
253
|
-
sum[0] +=
|
|
254
|
-
sum[1] +=
|
|
255
|
-
sum[2] +=
|
|
253
|
+
sum[0] += GdhRead.as_float(data[index + 1])
|
|
254
|
+
sum[1] += GdhRead.as_float(data[index + 2])
|
|
255
|
+
sum[2] += GdhRead.as_float(data[index + 3])
|
|
256
256
|
into[signature] = sum
|
|
257
257
|
carried += 1
|
|
258
258
|
return carried
|
|
@@ -3,11 +3,11 @@ extends Node
|
|
|
3
3
|
|
|
4
4
|
## Resource files, shaders, tilesets and themes, written through the open editor.
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
6
|
+
const GdhFileReads = preload("../file_reads.gd")
|
|
7
|
+
const GdhHeadlessCheck = preload("../headless_check.gd")
|
|
8
|
+
const GdhPropertyValues = preload("../property_values.gd")
|
|
9
|
+
const GdhRead = preload("../reading.gd")
|
|
10
|
+
const GdhSceneFile = preload("../scene_file.gd")
|
|
11
11
|
|
|
12
12
|
# The minimal shader of a type: its declaration and the one function the engine calls for it.
|
|
13
13
|
const SHADER_EMPTY: String = """shader_type %s;
|
|
@@ -23,7 +23,7 @@ const SHADER_ENTRY: Dictionary[String, String] = {
|
|
|
23
23
|
const CELLS_SHOWN: int = 1000
|
|
24
24
|
|
|
25
25
|
var _editor_plugin: EditorPlugin = null
|
|
26
|
-
var _properties:
|
|
26
|
+
var _properties: GdhPropertyValues = GdhPropertyValues.new()
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
func set_editor_plugin(plugin: EditorPlugin) -> void:
|
|
@@ -48,7 +48,7 @@ func _written(path: String) -> void:
|
|
|
48
48
|
if ResourceLoader.has_cached(path):
|
|
49
49
|
var _replaced: Resource = ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_REPLACE)
|
|
50
50
|
if _editor_plugin:
|
|
51
|
-
|
|
51
|
+
GdhSceneFile.scan_later()
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
## Why a tool that creates [param path] must not write there, or "". Saving over a file that was
|
|
@@ -89,12 +89,15 @@ func _xy(value: Variant, label: String) -> Array:
|
|
|
89
89
|
x = pair[0]
|
|
90
90
|
y = pair[1]
|
|
91
91
|
for number: Variant in [x, y]:
|
|
92
|
-
if
|
|
92
|
+
if (
|
|
93
|
+
not (number is float or number is int)
|
|
94
|
+
or GdhRead.as_float(number) != floorf(GdhRead.as_float(number))
|
|
95
|
+
):
|
|
93
96
|
return [
|
|
94
97
|
false,
|
|
95
98
|
'%s must be two whole numbers, {"x": .., "y": ..}, not %s.' % [label, JSON.stringify(value)]
|
|
96
99
|
]
|
|
97
|
-
return [true, Vector2i(
|
|
100
|
+
return [true, Vector2i(GdhRead.as_int(x), GdhRead.as_int(y))]
|
|
98
101
|
|
|
99
102
|
|
|
100
103
|
## The theme on disk at this path, or null when there is not one.
|
|
@@ -119,12 +122,12 @@ func _load_theme(theme_path: String) -> Theme:
|
|
|
119
122
|
## Read back because a property can be set and still not be saved: one without storage, a
|
|
120
123
|
## script variable that is not exported. Both were answered as changed.
|
|
121
124
|
func _save_checked(resource: Resource, path: String, names: Array, previous: Variant) -> String:
|
|
122
|
-
var saving: Error =
|
|
125
|
+
var saving: Error = GdhSceneFile.save_keeping_uid(resource, path)
|
|
123
126
|
if saving != OK:
|
|
124
127
|
return "Failed to save %s: %s" % [path, error_string(saving)]
|
|
125
128
|
var unkept: String = _unkept_headless(resource, path, names, previous)
|
|
126
129
|
if not unkept.is_empty():
|
|
127
|
-
return "Nothing was written: " + unkept +
|
|
130
|
+
return "Nothing was written: " + unkept + GdhHeadlessCheck.put_back(path, previous)
|
|
128
131
|
var loaded: Resource = ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_IGNORE)
|
|
129
132
|
var lost: String = ""
|
|
130
133
|
if loaded == null:
|
|
@@ -133,7 +136,7 @@ func _save_checked(resource: Resource, path: String, names: Array, previous: Var
|
|
|
133
136
|
for key: Variant in names:
|
|
134
137
|
var property: String = str(key)
|
|
135
138
|
var read: Variant = _properties.read_at(loaded, property)
|
|
136
|
-
if not
|
|
139
|
+
if not GdhPropertyValues.same(read, _properties.read_at(resource, property)):
|
|
137
140
|
lost = (
|
|
138
141
|
(
|
|
139
142
|
"%s.%s would load from the file as %s: it is not a property the file keeps, so "
|
|
@@ -145,19 +148,19 @@ func _save_checked(resource: Resource, path: String, names: Array, previous: Var
|
|
|
145
148
|
if lost.is_empty():
|
|
146
149
|
_written(path)
|
|
147
150
|
return ""
|
|
148
|
-
return lost +
|
|
151
|
+
return lost + GdhHeadlessCheck.put_back(path, previous)
|
|
149
152
|
|
|
150
153
|
|
|
151
154
|
## Outside the editor, puts back in the file just saved at [param path] what a script that is not a
|
|
152
155
|
## tool changed and the call did not ask for, [param names] being what it asked for, and answers ""
|
|
153
|
-
## or why that did not hold. See [
|
|
156
|
+
## or why that did not hold. See [GdhHeadlessCheck].
|
|
154
157
|
func _unkept_headless(resource: Resource, path: String, names: Array, previous: Variant) -> String:
|
|
155
158
|
if Engine.is_editor_hint():
|
|
156
159
|
return ""
|
|
157
160
|
var script: Script = resource.get_script()
|
|
158
161
|
var scripted: bool = script != null and not script.is_tool()
|
|
159
162
|
if not path.ends_with(".tres"):
|
|
160
|
-
if scripted or
|
|
163
|
+
if scripted or GdhHeadlessCheck.holds_scripted_embedded(resource, {}):
|
|
161
164
|
return (
|
|
162
165
|
(
|
|
163
166
|
(
|
|
@@ -166,7 +169,7 @@ func _unkept_headless(resource: Resource, path: String, names: Array, previous:
|
|
|
166
169
|
)
|
|
167
170
|
% path
|
|
168
171
|
)
|
|
169
|
-
+
|
|
172
|
+
+ GdhHeadlessCheck.REMEDY
|
|
170
173
|
)
|
|
171
174
|
return ""
|
|
172
175
|
var before: String = ""
|
|
@@ -179,15 +182,15 @@ func _unkept_headless(resource: Resource, path: String, names: Array, previous:
|
|
|
179
182
|
var property: String = str(key)
|
|
180
183
|
asked[property] = true
|
|
181
184
|
asked[property.get_slice(":", 0)] = true
|
|
182
|
-
reached.merge(
|
|
183
|
-
return
|
|
185
|
+
reached.merge(GdhHeadlessCheck.reached(resource, property))
|
|
186
|
+
return GdhHeadlessCheck.settle_saved(
|
|
184
187
|
path,
|
|
185
188
|
before,
|
|
186
|
-
|
|
189
|
+
GdhHeadlessCheck.stored(resource).values(),
|
|
187
190
|
resource if scripted else null,
|
|
188
191
|
asked,
|
|
189
192
|
reached,
|
|
190
|
-
func() -> Error: return
|
|
193
|
+
func() -> Error: return GdhSceneFile.save_keeping_uid(resource, path)
|
|
191
194
|
)
|
|
192
195
|
|
|
193
196
|
|
|
@@ -202,7 +205,7 @@ func create_resource(args: Dictionary) -> Dictionary:
|
|
|
202
205
|
return {"ok": false, "error": taken}
|
|
203
206
|
|
|
204
207
|
var script_path: String = str(args.get("script", ""))
|
|
205
|
-
var made: Dictionary =
|
|
208
|
+
var made: Dictionary = GdhSceneFile.made_as(
|
|
206
209
|
resource_type, "" if script_path == "" else _ensure_res_path(script_path), "Resource", "resourceType"
|
|
207
210
|
)
|
|
208
211
|
if made.has("error"):
|
|
@@ -229,7 +232,7 @@ func create_resource(args: Dictionary) -> Dictionary:
|
|
|
229
232
|
var script: Script = load(script_file) as Script
|
|
230
233
|
if script == null:
|
|
231
234
|
return {"ok": false, "error": "No script loads from " + script_file}
|
|
232
|
-
var uncompiled: String =
|
|
235
|
+
var uncompiled: String = GdhSceneFile.uncompiled(script, script_file)
|
|
233
236
|
if not uncompiled.is_empty():
|
|
234
237
|
return {"ok": false, "error": uncompiled}
|
|
235
238
|
var base: String = str(script.get_instance_base_type())
|
|
@@ -245,13 +248,15 @@ func create_resource(args: Dictionary) -> Dictionary:
|
|
|
245
248
|
if not refused.is_empty():
|
|
246
249
|
return {"ok": false, "error": refused}
|
|
247
250
|
|
|
248
|
-
var folder: String =
|
|
251
|
+
var folder: String = GdhSceneFile.make_folder_for(res_path)
|
|
249
252
|
if not folder.is_empty():
|
|
250
253
|
return {"ok": false, "error": folder}
|
|
254
|
+
var answer: Dictionary = {"ok": true, "resourcePath": res_path, "resourceType": asked_type}
|
|
255
|
+
_properties.note_also_changed(answer)
|
|
251
256
|
var failed: String = _save_checked(resource, res_path, properties.keys(), null)
|
|
252
257
|
if not failed.is_empty():
|
|
253
258
|
return {"ok": false, "error": failed}
|
|
254
|
-
return
|
|
259
|
+
return answer
|
|
255
260
|
|
|
256
261
|
|
|
257
262
|
func modify_resource(args: Dictionary) -> Dictionary:
|
|
@@ -284,11 +289,13 @@ func modify_resource(args: Dictionary) -> Dictionary:
|
|
|
284
289
|
var refused: String = _properties.write_all(resource, properties)
|
|
285
290
|
if not refused.is_empty():
|
|
286
291
|
return {"ok": false, "error": refused}
|
|
292
|
+
var answer: Dictionary = {"ok": true, "resourcePath": res_path}
|
|
293
|
+
_properties.note_also_changed(answer)
|
|
287
294
|
var previous: PackedByteArray = FileAccess.get_file_as_bytes(res_path)
|
|
288
295
|
var failed: String = _save_checked(resource, res_path, properties.keys(), previous)
|
|
289
296
|
if not failed.is_empty():
|
|
290
297
|
return {"ok": false, "error": failed}
|
|
291
|
-
return
|
|
298
|
+
return answer
|
|
292
299
|
|
|
293
300
|
|
|
294
301
|
## What a resource file holds, read as a headless engine reads it with no editor connected.
|
|
@@ -300,14 +307,14 @@ func read_resource(args: Dictionary) -> Dictionary:
|
|
|
300
307
|
var inner: String = str(args.get("subResource", ""))
|
|
301
308
|
if not inner.is_empty():
|
|
302
309
|
res_path += "::" + inner
|
|
303
|
-
return
|
|
310
|
+
return GdhFileReads.resource(res_path, GdhRead.as_bool(args.get("includeDefaults", false)))
|
|
304
311
|
|
|
305
312
|
|
|
306
313
|
func create_shader(args: Dictionary) -> Dictionary:
|
|
307
|
-
var shader_path: String = _ensure_res_path(str(args.get("
|
|
314
|
+
var shader_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
308
315
|
var shader_type: String = str(args.get("shaderType", "canvas_item"))
|
|
309
316
|
if shader_path == "res://":
|
|
310
|
-
return {"ok": false, "error": "
|
|
317
|
+
return {"ok": false, "error": "resourcePath is required"}
|
|
311
318
|
var taken: String = _taken(shader_path, "resource_edit op=create_shader", "Edit its text")
|
|
312
319
|
if not taken.is_empty():
|
|
313
320
|
return {"ok": false, "error": taken}
|
|
@@ -316,7 +323,7 @@ func create_shader(args: Dictionary) -> Dictionary:
|
|
|
316
323
|
if code == "":
|
|
317
324
|
code = SHADER_EMPTY % [shader_type, SHADER_ENTRY.get(shader_type, "fragment")]
|
|
318
325
|
|
|
319
|
-
var folder: String =
|
|
326
|
+
var folder: String = GdhSceneFile.make_folder_for(shader_path)
|
|
320
327
|
if not folder.is_empty():
|
|
321
328
|
return {"ok": false, "error": folder}
|
|
322
329
|
var file: FileAccess = FileAccess.open(shader_path, FileAccess.WRITE)
|
|
@@ -336,9 +343,9 @@ func create_shader(args: Dictionary) -> Dictionary:
|
|
|
336
343
|
|
|
337
344
|
|
|
338
345
|
func create_tileset(args: Dictionary) -> Dictionary:
|
|
339
|
-
var tileset_path: String = _ensure_res_path(str(args.get("
|
|
346
|
+
var tileset_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
340
347
|
if tileset_path == "res://":
|
|
341
|
-
return {"ok": false, "error": "
|
|
348
|
+
return {"ok": false, "error": "resourcePath is required"}
|
|
342
349
|
var taken: String = _taken(tileset_path, "resource_edit op=create_tileset")
|
|
343
350
|
if not taken.is_empty():
|
|
344
351
|
return {"ok": false, "error": taken}
|
|
@@ -371,10 +378,10 @@ func create_tileset(args: Dictionary) -> Dictionary:
|
|
|
371
378
|
{"sourceId": added, "texture": atlas.texture.resource_path, "tiles": atlas.get_tiles_count()}
|
|
372
379
|
)
|
|
373
380
|
|
|
374
|
-
var folder: String =
|
|
381
|
+
var folder: String = GdhSceneFile.make_folder_for(tileset_path)
|
|
375
382
|
if not folder.is_empty():
|
|
376
383
|
return {"ok": false, "error": folder}
|
|
377
|
-
var saving: Error =
|
|
384
|
+
var saving: Error = GdhSceneFile.save_keeping_uid(tileset, tileset_path)
|
|
378
385
|
if saving != OK:
|
|
379
386
|
return {"ok": false, "error": "Failed to save %s: %s" % [tileset_path, error_string(saving)]}
|
|
380
387
|
|
|
@@ -478,7 +485,7 @@ func _source_ids(tile_set: TileSet) -> Array[int]:
|
|
|
478
485
|
|
|
479
486
|
func set_tilemap_cells(args: Dictionary) -> Dictionary:
|
|
480
487
|
var scene_path: String = _ensure_res_path(str(args.get("scenePath", "")))
|
|
481
|
-
var node_path: String = str(args.get("
|
|
488
|
+
var node_path: String = str(args.get("nodePath", ""))
|
|
482
489
|
if scene_path == "res://":
|
|
483
490
|
return {"ok": false, "error": "scenePath is required"}
|
|
484
491
|
|
|
@@ -491,12 +498,12 @@ func set_tilemap_cells(args: Dictionary) -> Dictionary:
|
|
|
491
498
|
if placed.is_empty():
|
|
492
499
|
return {"ok": false, "error": "cells is empty, so there is nothing to place"}
|
|
493
500
|
|
|
494
|
-
var scene:
|
|
501
|
+
var scene: GdhSceneFile = GdhSceneFile.new()
|
|
495
502
|
var refused: Dictionary = scene.open(scene_path, true)
|
|
496
503
|
if not refused.is_empty():
|
|
497
504
|
return refused
|
|
498
505
|
|
|
499
|
-
var layer: int =
|
|
506
|
+
var layer: int = GdhRead.as_int(args.get("layer", 0))
|
|
500
507
|
var found: Array = _tile_node(scene, node_path, layer)
|
|
501
508
|
if found[0] == null:
|
|
502
509
|
return scene.refuse(str(found[1]))
|
|
@@ -544,7 +551,7 @@ func set_tilemap_cells(args: Dictionary) -> Dictionary:
|
|
|
544
551
|
|
|
545
552
|
## The node at [param node_path] cells are painted on, with a TileSet, as [node, why not].
|
|
546
553
|
## TileMapLayer is the node since 4.3, and TileMap the one it replaced, which keeps its layers.
|
|
547
|
-
func _tile_node(scene:
|
|
554
|
+
func _tile_node(scene: GdhSceneFile, node_path: String, layer: int) -> Array:
|
|
548
555
|
var node: Node = (
|
|
549
556
|
scene.root if node_path == "." or node_path == "" else scene.root.get_node_or_null(node_path)
|
|
550
557
|
)
|
|
@@ -582,12 +589,12 @@ func _cell(entry: Variant, index: int, tile_set: TileSet) -> Array:
|
|
|
582
589
|
var atlas_at: Array = _xy(cell["atlasCoords"], "cells[%d].atlasCoords" % index)
|
|
583
590
|
if not atlas_at[0]:
|
|
584
591
|
return atlas_at
|
|
585
|
-
var source_id: int =
|
|
592
|
+
var source_id: int = GdhRead.as_int(cell["sourceId"], -1)
|
|
586
593
|
if not tile_set.has_source(source_id):
|
|
587
594
|
return [false, "The TileSet has no source %d; it has %s" % [source_id, _source_ids(tile_set)]]
|
|
588
595
|
var source: TileSetSource = tile_set.get_source(source_id)
|
|
589
596
|
var atlas_coords: Vector2i = atlas_at[1]
|
|
590
|
-
var alternative: int =
|
|
597
|
+
var alternative: int = GdhRead.as_int(cell.get("alternativeTile", 0))
|
|
591
598
|
if not source.has_tile(atlas_coords):
|
|
592
599
|
return [
|
|
593
600
|
false,
|
|
@@ -691,20 +698,20 @@ func _cell_at(node: Node, layer: int, at: Vector2i) -> Array:
|
|
|
691
698
|
## Saves [param theme] over [param theme_path] with [param item] changed, answering "" or why not.
|
|
692
699
|
func _save_theme(theme: Theme, theme_path: String, item: String) -> String:
|
|
693
700
|
var previous: PackedByteArray = FileAccess.get_file_as_bytes(theme_path)
|
|
694
|
-
var saving: Error =
|
|
701
|
+
var saving: Error = GdhSceneFile.save_keeping_uid(theme, theme_path)
|
|
695
702
|
if saving != OK:
|
|
696
703
|
return "Failed to save %s: %s" % [theme_path, error_string(saving)]
|
|
697
704
|
var unkept: String = _unkept_headless(theme, theme_path, [item], previous)
|
|
698
705
|
if not unkept.is_empty():
|
|
699
|
-
return "Nothing was written: " + unkept +
|
|
706
|
+
return "Nothing was written: " + unkept + GdhHeadlessCheck.put_back(theme_path, previous)
|
|
700
707
|
_written(theme_path)
|
|
701
708
|
return ""
|
|
702
709
|
|
|
703
710
|
|
|
704
711
|
func set_theme_color(args: Dictionary) -> Dictionary:
|
|
705
|
-
var theme_path: String = _ensure_res_path(str(args.get("
|
|
712
|
+
var theme_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
706
713
|
if theme_path == "res://":
|
|
707
|
-
return {"ok": false, "error": "
|
|
714
|
+
return {"ok": false, "error": "resourcePath is required"}
|
|
708
715
|
|
|
709
716
|
var color_name: String = str(args.get("colorName", ""))
|
|
710
717
|
var control_type: String = str(args.get("controlType", ""))
|
|
@@ -717,10 +724,10 @@ func set_theme_color(args: Dictionary) -> Dictionary:
|
|
|
717
724
|
|
|
718
725
|
var c: Dictionary = args.get("color", {})
|
|
719
726
|
var color: Color = Color(
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
727
|
+
GdhRead.as_float(c.get("r", 1.0), 1.0),
|
|
728
|
+
GdhRead.as_float(c.get("g", 1.0), 1.0),
|
|
729
|
+
GdhRead.as_float(c.get("b", 1.0), 1.0),
|
|
730
|
+
GdhRead.as_float(c.get("a", 1.0), 1.0)
|
|
724
731
|
)
|
|
725
732
|
theme.set_color(color_name, control_type, color)
|
|
726
733
|
|
|
@@ -745,9 +752,9 @@ func set_theme_color(args: Dictionary) -> Dictionary:
|
|
|
745
752
|
|
|
746
753
|
|
|
747
754
|
func set_theme_font_size(args: Dictionary) -> Dictionary:
|
|
748
|
-
var theme_path: String = _ensure_res_path(str(args.get("
|
|
755
|
+
var theme_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
749
756
|
if theme_path == "res://":
|
|
750
|
-
return {"ok": false, "error": "
|
|
757
|
+
return {"ok": false, "error": "resourcePath is required"}
|
|
751
758
|
|
|
752
759
|
var font_size_name: String = str(args.get("fontSizeName", ""))
|
|
753
760
|
var control_type: String = str(args.get("controlType", ""))
|
|
@@ -760,7 +767,7 @@ func set_theme_font_size(args: Dictionary) -> Dictionary:
|
|
|
760
767
|
|
|
761
768
|
# Godot reads a size of 0 or less as unset and answers the theme's default, so -3 would be read
|
|
762
769
|
# back as 16.
|
|
763
|
-
var pixels: float =
|
|
770
|
+
var pixels: float = GdhRead.as_float(args.get("size"), 0.0)
|
|
764
771
|
if not is_finite(pixels) or pixels < 1 or pixels != floorf(pixels):
|
|
765
772
|
var shown: String = str(int(pixels)) if pixels == floorf(pixels) else str(pixels)
|
|
766
773
|
return {
|
|
@@ -4,9 +4,9 @@ extends RefCounted
|
|
|
4
4
|
## The two ways a scene keeps its own values for nodes another scene makes: by inheriting that scene,
|
|
5
5
|
## or by instancing it with its children editable.
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
7
|
+
const GdhFileReads = preload("../file_reads.gd")
|
|
8
|
+
const GdhPaths = preload("scene_paths.gd")
|
|
9
|
+
const GdhSceneFile = preload("../scene_file.gd")
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
## Why a create at [param scene_path] is refused when a file is there already, which saving over
|
|
@@ -45,7 +45,7 @@ static func inherited(
|
|
|
45
45
|
script = load(script_path) as Script
|
|
46
46
|
if script == null:
|
|
47
47
|
return {"ok": false, "error": "No script loads from " + script_path}
|
|
48
|
-
var uncompiled: String =
|
|
48
|
+
var uncompiled: String = GdhSceneFile.uncompiled(script, script_path)
|
|
49
49
|
if not uncompiled.is_empty():
|
|
50
50
|
return {"ok": false, "error": uncompiled}
|
|
51
51
|
return inherit(scene_path, base_path, str(args.get("rootNodeName", "")), script)
|
|
@@ -59,12 +59,12 @@ static func inherited(
|
|
|
59
59
|
## the base: a headless engine making that instance runs every script in the base, and the pack would
|
|
60
60
|
## keep what they set as this scene's own values.
|
|
61
61
|
static func inherit(scene_path: String, base_path: String, root_name: String, script: Script) -> Dictionary:
|
|
62
|
-
var base: Dictionary =
|
|
62
|
+
var base: Dictionary = GdhFileReads.scene_node(base_path, ".")
|
|
63
63
|
if not base.get("ok", false):
|
|
64
64
|
return {"ok": false, "error": "inherits: " + str(base.get("error", "%s holds no nodes" % base_path))}
|
|
65
65
|
var root_type: String = str(base["type"])
|
|
66
66
|
var name: String = str(base["name"]) if root_name.is_empty() else root_name
|
|
67
|
-
var unfit: String =
|
|
67
|
+
var unfit: String = GdhSceneFile.unfit_name(name)
|
|
68
68
|
if not unfit.is_empty():
|
|
69
69
|
return {"ok": false, "error": unfit}
|
|
70
70
|
if script != null:
|
|
@@ -78,7 +78,7 @@ static func inherit(scene_path: String, base_path: String, root_name: String, sc
|
|
|
78
78
|
% [script.resource_path, extended, root_type, base_path]
|
|
79
79
|
)
|
|
80
80
|
}
|
|
81
|
-
var folder: String =
|
|
81
|
+
var folder: String = GdhSceneFile.make_folder_for(scene_path)
|
|
82
82
|
if not folder.is_empty():
|
|
83
83
|
return {"ok": false, "error": folder}
|
|
84
84
|
|
|
@@ -87,14 +87,14 @@ static func inherit(scene_path: String, base_path: String, root_name: String, sc
|
|
|
87
87
|
"",
|
|
88
88
|
(
|
|
89
89
|
'[ext_resource type="PackedScene"%s path="%s" id="1_base"]'
|
|
90
|
-
% [
|
|
90
|
+
% [GdhSceneFile.reference_uid(base_path), base_path]
|
|
91
91
|
),
|
|
92
92
|
]
|
|
93
93
|
if script != null:
|
|
94
94
|
var _resourced: bool = lines.append(
|
|
95
95
|
(
|
|
96
96
|
'[ext_resource type="Script"%s path="%s" id="2_script"]'
|
|
97
|
-
% [
|
|
97
|
+
% [GdhSceneFile.reference_uid(script.resource_path), script.resource_path]
|
|
98
98
|
)
|
|
99
99
|
)
|
|
100
100
|
lines.append_array(["", '[node name="%s" instance=ExtResource("1_base")]' % name])
|
|
@@ -117,7 +117,7 @@ static func inherit(scene_path: String, base_path: String, root_name: String, sc
|
|
|
117
117
|
"error":
|
|
118
118
|
"%s did not load back as a scene inheriting %s, so it was removed." % [scene_path, base_path]
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
GdhSceneFile.refresh(scene_path)
|
|
121
121
|
return {
|
|
122
122
|
"ok": true,
|
|
123
123
|
"scenePath": scene_path,
|
|
@@ -130,8 +130,8 @@ static func inherit(scene_path: String, base_path: String, root_name: String, sc
|
|
|
130
130
|
## Makes the children of [param node], an instance in [param scene], editable or not, answering why
|
|
131
131
|
## it cannot or "". With them editable the scene keeps its own values for them, as the editor's
|
|
132
132
|
## Editable Children does; made not editable again, the values it kept for them are dropped. The
|
|
133
|
-
## caller has had [method
|
|
134
|
-
static func set_editable(scene:
|
|
133
|
+
## caller has had [method GdhSceneFile.foreign] refuse a node inside an instance that is not editable.
|
|
134
|
+
static func set_editable(scene: GdhSceneFile, node: Node, editable: bool) -> String:
|
|
135
135
|
if node.owner == null or node.scene_file_path.is_empty():
|
|
136
136
|
return (
|
|
137
137
|
"editableChildren is a setting of an instance in this scene, and %s is not one."
|
|
@@ -152,7 +152,7 @@ static func set_editable(scene: SceneFile, node: Node, editable: bool) -> String
|
|
|
152
152
|
## for a node deleted, they are only named. Answers followed, the scenes rewritten, and
|
|
153
153
|
## notFollowed, each one left as it was with why, each only when it names any, with what
|
|
154
154
|
## [param carried] gives.
|
|
155
|
-
static func follow(changed: String, old_path: String, new_path: String, carried:
|
|
155
|
+
static func follow(changed: String, old_path: String, new_path: String, carried: GdhPaths) -> Dictionary:
|
|
156
156
|
var texts: Dictionary = {}
|
|
157
157
|
_read_scenes("res://", texts)
|
|
158
158
|
var kin: Array[String] = [changed]
|
|
@@ -176,14 +176,14 @@ static func follow(changed: String, old_path: String, new_path: String, carried:
|
|
|
176
176
|
var moves: Dictionary = {}
|
|
177
177
|
if _inherits(scene_path, changed, texts):
|
|
178
178
|
moves[old_path] = new_path
|
|
179
|
-
var read: Dictionary =
|
|
179
|
+
var read: Dictionary = GdhFileReads.scene_tree(scene_path, -1, false)
|
|
180
180
|
if not read.get("ok", false):
|
|
181
181
|
not_followed.append({"scenePath": scene_path, "reason": str(read.get("error", ""))})
|
|
182
182
|
continue
|
|
183
183
|
var tree: Dictionary = read["tree"]
|
|
184
184
|
_instances_of(tree, changed, old_path, new_path, moves)
|
|
185
185
|
var text: String = texts[scene_path]
|
|
186
|
-
var unsaved: String =
|
|
186
|
+
var unsaved: String = GdhSceneFile.unsaved_in_editor(scene_path)
|
|
187
187
|
var rewritten: String = text
|
|
188
188
|
if not new_path.is_empty():
|
|
189
189
|
rewritten = _rewritten(text, moves, old_path.get_base_dir() != new_path.get_base_dir())
|
|
@@ -198,7 +198,7 @@ static func follow(changed: String, old_path: String, new_path: String, carried:
|
|
|
198
198
|
)
|
|
199
199
|
continue
|
|
200
200
|
file.close()
|
|
201
|
-
|
|
201
|
+
GdhSceneFile.refresh(scene_path)
|
|
202
202
|
followed.append(scene_path)
|
|
203
203
|
if moves.is_empty() or not text.contains("NodePath("):
|
|
204
204
|
continue
|
|
@@ -335,7 +335,7 @@ static func _attribute_moved(
|
|
|
335
335
|
var found: RegExMatch = RegEx.create_from_string(' %s="([^"]*)"' % attribute).search(line)
|
|
336
336
|
if found == null:
|
|
337
337
|
return line
|
|
338
|
-
var moved: String =
|
|
338
|
+
var moved: String = GdhPaths.moved(found.get_string(1), moves)
|
|
339
339
|
if moved == found.get_string(1):
|
|
340
340
|
return line
|
|
341
341
|
var placed: String = _attribute_set(line, attribute, moved)
|
|
@@ -11,9 +11,9 @@ extends RefCounted
|
|
|
11
11
|
|
|
12
12
|
enum { UNCHANGED, REWRITTEN, DELETED }
|
|
13
13
|
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
14
|
+
const GdhHeadlessCheck = preload("../headless_check.gd")
|
|
15
|
+
const GdhRead = preload("../reading.gd")
|
|
16
|
+
const GdhSceneFile = preload("../scene_file.gd")
|
|
17
17
|
## PROPERTY_HINT_NO_NODEPATH, which marks a property the editor's rename skips. It is not bound for
|
|
18
18
|
## scripts, and follows PROPERTY_HINT_ONESHOT in the engine's list.
|
|
19
19
|
const HINT_NO_NODEPATH: int = PROPERTY_HINT_ONESHOT + 1
|
|
@@ -30,7 +30,7 @@ var _homes: Dictionary = {}
|
|
|
30
30
|
## it had, its record, the file]. The editor shares such a resource with every scene using it, so a
|
|
31
31
|
## rewrite that is not saved is put back.
|
|
32
32
|
var _outside: Array[Array] = []
|
|
33
|
-
var _scene:
|
|
33
|
+
var _scene: GdhSceneFile = null
|
|
34
34
|
var _moves: Dictionary = {}
|
|
35
35
|
var _back: Dictionary = {}
|
|
36
36
|
var _seen: Dictionary = {}
|
|
@@ -50,7 +50,7 @@ static func moved(given: String, moves: Dictionary) -> String:
|
|
|
50
50
|
|
|
51
51
|
## Carries [param moves], from the root of [param scene], into the paths it holds. Called after the
|
|
52
52
|
## move and before the write. Answers how many paths it rewrote.
|
|
53
|
-
func carry(scene:
|
|
53
|
+
func carry(scene: GdhSceneFile, moves: Dictionary) -> int:
|
|
54
54
|
if moves.is_empty():
|
|
55
55
|
return 0
|
|
56
56
|
_scene = scene
|
|
@@ -92,7 +92,7 @@ func carry(scene: SceneFile, moves: Dictionary) -> int:
|
|
|
92
92
|
## Opens [param scene_path], carries [param moves] into it, and writes it when that rewrote a path.
|
|
93
93
|
## Answers "" or why it was left as it was.
|
|
94
94
|
func carry_into(scene_path: String, moves: Dictionary) -> String:
|
|
95
|
-
var scene:
|
|
95
|
+
var scene: GdhSceneFile = GdhSceneFile.new()
|
|
96
96
|
var refused: Dictionary = scene.open(scene_path, true)
|
|
97
97
|
if not refused.is_empty():
|
|
98
98
|
return str(refused.get("error", ""))
|
|
@@ -127,7 +127,7 @@ func put_back(scene_path: String, why: String = "") -> void:
|
|
|
127
127
|
func answer() -> Dictionary:
|
|
128
128
|
for file: String in _homes:
|
|
129
129
|
var resource: Resource = _homes[file]
|
|
130
|
-
var saving: Error =
|
|
130
|
+
var saving: Error = GdhSceneFile.save_keeping_uid(resource, file)
|
|
131
131
|
if saving == OK:
|
|
132
132
|
if Engine.is_editor_hint():
|
|
133
133
|
EditorInterface.get_resource_filesystem().update_file(file)
|
|
@@ -181,11 +181,13 @@ static func _left(record: Dictionary, why: String) -> Dictionary:
|
|
|
181
181
|
## Whether [param property] can hold a node path the editor's rename would follow: one saved or
|
|
182
182
|
## shown, of a type that holds paths, and not marked as holding none.
|
|
183
183
|
static func _may_hold_paths(property: Dictionary) -> bool:
|
|
184
|
-
if not
|
|
184
|
+
if not GdhRead.as_int(property.get("usage")) & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR):
|
|
185
185
|
return false
|
|
186
|
-
if
|
|
186
|
+
if GdhRead.as_int(property.get("hint")) == HINT_NO_NODEPATH:
|
|
187
187
|
return false
|
|
188
|
-
return [TYPE_OBJECT, TYPE_NODE_PATH, TYPE_ARRAY, TYPE_DICTIONARY].has(
|
|
188
|
+
return [TYPE_OBJECT, TYPE_NODE_PATH, TYPE_ARRAY, TYPE_DICTIONARY].has(
|
|
189
|
+
GdhRead.as_int(property.get("type"))
|
|
190
|
+
)
|
|
189
191
|
|
|
190
192
|
|
|
191
193
|
## [param value], held by the node that was at [param was] and is at [param now], with each path in
|
|
@@ -421,7 +423,7 @@ func _home_of(animation: Animation, library: AnimationLibrary) -> Dictionary:
|
|
|
421
423
|
}
|
|
422
424
|
if not Engine.is_editor_hint():
|
|
423
425
|
var script: Script = home.get_script()
|
|
424
|
-
if (script != null and not script.is_tool()) or
|
|
426
|
+
if (script != null and not script.is_tool()) or GdhHeadlessCheck.holds_scripted_embedded(home, {}):
|
|
425
427
|
return {
|
|
426
428
|
"why":
|
|
427
429
|
(
|
|
@@ -432,7 +434,7 @@ func _home_of(animation: Animation, library: AnimationLibrary) -> Dictionary:
|
|
|
432
434
|
)
|
|
433
435
|
% file
|
|
434
436
|
)
|
|
435
|
-
+
|
|
437
|
+
+ GdhHeadlessCheck.REMEDY
|
|
436
438
|
)
|
|
437
439
|
}
|
|
438
440
|
return {"file": file, "home": home, "why": ""}
|