gdharness 1.3.39 → 1.3.41
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 +315 -112
- package/build/godot/addons/gdharness_editor/animation_reads.gd +7 -6
- package/build/godot/addons/gdharness_editor/file_reads.gd +2 -1
- package/build/godot/addons/gdharness_editor/file_walk.gd +33 -1
- package/build/godot/addons/gdharness_editor/property_values.gd +6 -9
- package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +6 -3
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +1 -1
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +11 -10
- package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +77 -22
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +5 -3
- package/build/godot/addons/gdharness_runtime/runtime_typing.gd +15 -8
- package/build/godot/operations/animation_reads.gd +7 -6
- package/build/godot/operations/dependencies.gd +5 -2
- package/build/godot/operations/file_reads.gd +2 -1
- package/build/godot/operations/file_walk.gd +33 -1
- package/build/godot/operations/gdscript_authoring.gd +10 -1
- package/build/godot/operations/import_pipeline.gd +1 -1
- package/build/godot/operations/plugins.gd +39 -1
- package/build/godot/operations/project_config.gd +11 -1
- package/build/godot/operations/property_values.gd +6 -9
- package/build/keeper.js +38 -5
- package/package.json +1 -1
|
@@ -107,7 +107,45 @@ func enable_plugin(params: Dictionary) -> Dictionary:
|
|
|
107
107
|
if err != OK:
|
|
108
108
|
return _log.failure("Failed to save project.godot: " + error_string(err))
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
var answer: Dictionary = {
|
|
111
|
+
"plugin_name": plugin_name, "action": "enabled", "enabled_plugins": _names_of(enabled_paths)
|
|
112
|
+
}
|
|
113
|
+
var unloadable: String = _why_not_loaded(plugin_cfg_path)
|
|
114
|
+
if not unloadable.is_empty():
|
|
115
|
+
answer["note"] = unloadable
|
|
116
|
+
return answer
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# What the editor finds wrong with the plugin at [param plugin_cfg_path] when it loads it, the checks
|
|
120
|
+
# EditorNode::set_addon_plugin_enabled makes, or "" when it would load. Written all the same, since
|
|
121
|
+
# the script can be put right before the editor next starts.
|
|
122
|
+
static func _why_not_loaded(plugin_cfg_path: String) -> String:
|
|
123
|
+
var config: ConfigFile = ConfigFile.new()
|
|
124
|
+
if config.load(plugin_cfg_path) != OK:
|
|
125
|
+
return "The editor cannot read %s, so it will not enable the plugin." % plugin_cfg_path
|
|
126
|
+
if not config.has_section_key("plugin", "script"):
|
|
127
|
+
return "%s has no script field, so the editor will not enable the plugin." % plugin_cfg_path
|
|
128
|
+
var script_name: String = str(config.get_value("plugin", "script"))
|
|
129
|
+
if script_name.is_empty():
|
|
130
|
+
return ""
|
|
131
|
+
var script_path: String = plugin_cfg_path.get_base_dir().path_join(script_name)
|
|
132
|
+
if not FileAccess.file_exists(script_path):
|
|
133
|
+
return "%s does not exist, so the editor will not enable the plugin." % script_path
|
|
134
|
+
# Loaded only to learn whether the editor could; what the engine says of a script that does not
|
|
135
|
+
# parse is about a file the answer does not describe.
|
|
136
|
+
printerr(GdhLog.ASIDE)
|
|
137
|
+
var script: Script = ResourceLoader.load(script_path, "Script", ResourceLoader.CACHE_MODE_IGNORE)
|
|
138
|
+
printerr(GdhLog.RESUMED)
|
|
139
|
+
if script == null or script.get_instance_base_type() == &"":
|
|
140
|
+
return (
|
|
141
|
+
"%s does not compile, so the editor disables the plugin again at its next start." % script_path
|
|
142
|
+
+ " script_diagnostics names the error."
|
|
143
|
+
)
|
|
144
|
+
if not ClassDB.is_parent_class(script.get_instance_base_type(), "EditorPlugin"):
|
|
145
|
+
return "%s does not extend EditorPlugin, so the editor loads nothing for it." % script_path
|
|
146
|
+
if not script.is_tool():
|
|
147
|
+
return "%s is not a @tool script, so the editor loads nothing for it." % script_path
|
|
148
|
+
return ""
|
|
111
149
|
|
|
112
150
|
|
|
113
151
|
# Disable a plugin
|
|
@@ -194,6 +194,12 @@ func unset_project_setting(params: Dictionary) -> Dictionary:
|
|
|
194
194
|
answer["removed"] = false
|
|
195
195
|
answer["saved"] = false
|
|
196
196
|
answer["note"] = "project.godot does not set %s, so there was nothing to take out." % setting_path
|
|
197
|
+
var near: PackedStringArray = PackedStringArray() if held else _settings_near(setting_path)
|
|
198
|
+
if not near.is_empty():
|
|
199
|
+
answer["note"] += (
|
|
200
|
+
" Nor does the engine declare it; the nearest %s %s."
|
|
201
|
+
% ["setting is" if near.size() == 1 else "settings are", ", ".join(near)]
|
|
202
|
+
)
|
|
197
203
|
return _with_what_holds(answer, setting_path)
|
|
198
204
|
answer["old_value"] = _values.serialize_value(value)
|
|
199
205
|
# The default rather than null for a setting the engine declares: null takes the declaration away
|
|
@@ -221,8 +227,12 @@ func _with_what_holds(answer: Dictionary, setting_path: String) -> Dictionary:
|
|
|
221
227
|
|
|
222
228
|
|
|
223
229
|
# The settings in the same section as [param setting_path] named nearest it, for a new one that is
|
|
224
|
-
# likely a misspelt one: a setting nothing declares is written all the same, and is never read.
|
|
230
|
+
# likely a misspelt one: a setting nothing declares is written all the same, and is never read. None
|
|
231
|
+
# for an override of a setting the engine has, which its feature's builds read in the base's place.
|
|
225
232
|
static func _settings_near(setting_path: String) -> PackedStringArray:
|
|
233
|
+
var base: String = GdhSettingReads.override_base(setting_path)
|
|
234
|
+
if not base.is_empty() and ProjectSettings.has_setting(base):
|
|
235
|
+
return PackedStringArray()
|
|
226
236
|
var section: String = setting_path.get_slice("/", 0) + "/"
|
|
227
237
|
var names: PackedStringArray = []
|
|
228
238
|
for info: Dictionary in ProjectSettings.get_property_list():
|
|
@@ -383,19 +383,16 @@ func _readable(value: Variant, relative_to: Node) -> Variant:
|
|
|
383
383
|
return _values.serialize_value(value)
|
|
384
384
|
|
|
385
385
|
|
|
386
|
-
## What [param target] stores, by name, but its script and the properties in [param leave]
|
|
387
|
-
##
|
|
386
|
+
## What [param target] stores, by name, but its script and the properties in [param leave], in the
|
|
387
|
+
## names a read answers with: a Curve's points as point_0/position and the rest rather than the _data
|
|
388
|
+
## list every point write changes. A list or a map is copied, since a setter can change the one it
|
|
389
|
+
## holds in place.
|
|
388
390
|
func _stored(target: Object, leave: Dictionary) -> Dictionary:
|
|
389
391
|
var held: Dictionary = {}
|
|
390
|
-
for entry: Dictionary in
|
|
392
|
+
for entry: Dictionary in GdhShapes.read_properties(target):
|
|
391
393
|
var name: String = str(entry["name"])
|
|
392
394
|
var usage: int = GdhRead.as_int(entry["usage"])
|
|
393
|
-
if (
|
|
394
|
-
usage & PROPERTY_USAGE_STORAGE == 0
|
|
395
|
-
or usage & HEADINGS != 0
|
|
396
|
-
or name == "script"
|
|
397
|
-
or leave.has(name)
|
|
398
|
-
):
|
|
395
|
+
if usage & HEADINGS != 0 or name == "script" or leave.has(name):
|
|
399
396
|
continue
|
|
400
397
|
var value: Variant = target.get(name)
|
|
401
398
|
if value is Array:
|
package/build/keeper.js
CHANGED
|
@@ -7053,7 +7053,18 @@ public static class GdharnessDesktop {
|
|
|
7053
7053
|
}
|
|
7054
7054
|
|
|
7055
7055
|
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
|
7056
|
-
static extern IntPtr
|
|
7056
|
+
static extern IntPtr CreateDesktopExW(string name, IntPtr device, IntPtr mode, uint flags, uint access, IntPtr attributes, uint heapKilobytes, IntPtr reserved);
|
|
7057
|
+
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
|
7058
|
+
static extern IntPtr CreateWindowStationW(string name, uint flags, uint access, IntPtr attributes);
|
|
7059
|
+
[DllImport("user32.dll", SetLastError = true)] static extern IntPtr GetProcessWindowStation();
|
|
7060
|
+
[DllImport("user32.dll", SetLastError = true)] static extern bool SetProcessWindowStation(IntPtr station);
|
|
7061
|
+
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
|
7062
|
+
static extern bool GetUserObjectInformationW(IntPtr handle, int index, StringBuilder into, int size, out int needed);
|
|
7063
|
+
const uint WindowStationAllAccess = 0x37F;
|
|
7064
|
+
const int ObjectName = 2;
|
|
7065
|
+
// What Windows gives an interactive desktop. A non-interactive station's desktops get a small
|
|
7066
|
+
// fraction of that by default, and one desktop here holds every engine a run starts.
|
|
7067
|
+
const uint DesktopHeapKilobytes = 20480;
|
|
7057
7068
|
|
|
7058
7069
|
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
|
7059
7070
|
static extern bool CreateProcessW(string application, StringBuilder commandLine, IntPtr processAttributes, IntPtr threadAttributes, bool inherit, uint flags, IntPtr environment, string directory, ref StartupInfo startup, out Started started);
|
|
@@ -7144,12 +7155,34 @@ public static class GdharnessDesktop {
|
|
|
7144
7155
|
StartupInfo startup = new StartupInfo();
|
|
7145
7156
|
startup.cb = Marshal.SizeOf(typeof(StartupInfo));
|
|
7146
7157
|
if (desktop.Length > 0) {
|
|
7147
|
-
Step(stepFile, "
|
|
7148
|
-
IntPtr
|
|
7158
|
+
Step(stepFile, "opening the session's own window station");
|
|
7159
|
+
IntPtr station = CreateWindowStationW(null, 0, WindowStationAllAccess, IntPtr.Zero);
|
|
7160
|
+
if (station == IntPtr.Zero) {
|
|
7161
|
+
throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateWindowStationW");
|
|
7162
|
+
}
|
|
7163
|
+
StringBuilder stationName = new StringBuilder(256);
|
|
7164
|
+
int needed;
|
|
7165
|
+
if (!GetUserObjectInformationW(station, ObjectName, stationName, stationName.Capacity * 2, out needed)) {
|
|
7166
|
+
throw new Win32Exception(Marshal.GetLastWin32Error(), "GetUserObjectInformationW");
|
|
7167
|
+
}
|
|
7168
|
+
// A desktop is made in the calling process's station, so this one is the caller's while it is.
|
|
7169
|
+
IntPtr own = GetProcessWindowStation();
|
|
7170
|
+
if (!SetProcessWindowStation(station)) {
|
|
7171
|
+
throw new Win32Exception(Marshal.GetLastWin32Error(), "SetProcessWindowStation");
|
|
7172
|
+
}
|
|
7173
|
+
IntPtr held;
|
|
7174
|
+
int made;
|
|
7175
|
+
try {
|
|
7176
|
+
Step(stepFile, "creating the " + desktop + " desktop");
|
|
7177
|
+
held = CreateDesktopExW(desktop, IntPtr.Zero, IntPtr.Zero, 0, GenericAll, IntPtr.Zero, DesktopHeapKilobytes, IntPtr.Zero);
|
|
7178
|
+
made = Marshal.GetLastWin32Error();
|
|
7179
|
+
} finally {
|
|
7180
|
+
SetProcessWindowStation(own);
|
|
7181
|
+
}
|
|
7149
7182
|
if (held == IntPtr.Zero) {
|
|
7150
|
-
throw new Win32Exception(
|
|
7183
|
+
throw new Win32Exception(made, "CreateDesktopExW " + stationName + "\\\\" + desktop);
|
|
7151
7184
|
}
|
|
7152
|
-
startup.desktop = desktop;
|
|
7185
|
+
startup.desktop = stationName + "\\\\" + desktop;
|
|
7153
7186
|
}
|
|
7154
7187
|
startup.flags = UseStdHandles;
|
|
7155
7188
|
if (noActivate) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.41",
|
|
4
4
|
"mcpName": "io.github.Aureliolo/gdharness",
|
|
5
5
|
"description": "A harness for driving a Godot 4 project from an agent: editor addons, a runtime bridge into the running game, an MCP server in front of them, and a CLI that installs and diagnoses the Godot side.",
|
|
6
6
|
"type": "module",
|