unity-agentic-tools 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -12
- package/dist/cli.js +6843 -13203
- package/dist/doc-indexer-cli.js +5 -42
- package/dist/index.js +906 -381
- package/native/unity-file-tools.darwin-arm64.node +0 -0
- package/native/unity-file-tools.darwin-x64.node +0 -0
- package/native/unity-file-tools.linux-x64-gnu.node +0 -0
- package/native/unity-file-tools.win32-x64-msvc.node +0 -0
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -205,7 +205,7 @@ var require_package = __commonJS((exports2, module2) => {
|
|
|
205
205
|
module2.exports = {
|
|
206
206
|
name: "unity-agentic-tools",
|
|
207
207
|
packageManager: "bun@latest",
|
|
208
|
-
version: "0.
|
|
208
|
+
version: "0.5.0",
|
|
209
209
|
description: "Fast, token-efficient Unity YAML parser for AI agents",
|
|
210
210
|
exports: {
|
|
211
211
|
".": {
|
|
@@ -232,7 +232,8 @@ var require_package = __commonJS((exports2, module2) => {
|
|
|
232
232
|
rebuild: "bun run clean && bun run build",
|
|
233
233
|
test: "bun test",
|
|
234
234
|
"test:watch": "bun test --watch",
|
|
235
|
-
"test:coverage": "bun test --coverage"
|
|
235
|
+
"test:coverage": "bun test --coverage",
|
|
236
|
+
"test:unity-headless": "bun test/run-headless-validation.ts"
|
|
236
237
|
},
|
|
237
238
|
dependencies: {
|
|
238
239
|
commander: "^14.0.2"
|
|
@@ -383,11 +384,11 @@ function setup(options = {}) {
|
|
|
383
384
|
const nativeLocalPkgBuild = getNativeBuildLocalPackageGuidCache();
|
|
384
385
|
if (nativeLocalPkgBuild) {
|
|
385
386
|
try {
|
|
386
|
-
const
|
|
387
|
-
const localPkgCount = Object.keys(
|
|
387
|
+
const localPackageCache = nativeLocalPkgBuild(projectPath);
|
|
388
|
+
const localPkgCount = Object.keys(localPackageCache).length;
|
|
388
389
|
if (localPkgCount > 0) {
|
|
389
390
|
const localPkgCachePath = import_path2.join(configPath, LOCAL_PACKAGE_CACHE_FILE);
|
|
390
|
-
import_fs2.writeFileSync(localPkgCachePath, JSON.stringify(
|
|
391
|
+
import_fs2.writeFileSync(localPkgCachePath, JSON.stringify(localPackageCache, null, 2));
|
|
391
392
|
}
|
|
392
393
|
} catch {}
|
|
393
394
|
}
|
|
@@ -473,6 +474,8 @@ var CONFIG_DIR2 = ".unity-agentic";
|
|
|
473
474
|
var CONFIG_FILE2 = "config.json";
|
|
474
475
|
var GUID_CACHE_FILE2 = "guid-cache.json";
|
|
475
476
|
var DOC_INDEX_FILE2 = "doc-index.json";
|
|
477
|
+
var EDITOR_LOCK_FILE = "editor.json";
|
|
478
|
+
var LAST_EDITOR_CONFIG_FILE = "editor.last.json";
|
|
476
479
|
function cleanup(options = {}) {
|
|
477
480
|
const projectPath = import_path3.resolve(options.project || process.cwd());
|
|
478
481
|
const configPath = import_path3.join(projectPath, CONFIG_DIR2);
|
|
@@ -481,8 +484,7 @@ function cleanup(options = {}) {
|
|
|
481
484
|
success: true,
|
|
482
485
|
project_path: projectPath,
|
|
483
486
|
files_removed: [],
|
|
484
|
-
directory_removed: false
|
|
485
|
-
error: `No ${CONFIG_DIR2} directory found`
|
|
487
|
+
directory_removed: false
|
|
486
488
|
};
|
|
487
489
|
}
|
|
488
490
|
const filesRemoved = [];
|
|
@@ -502,7 +504,12 @@ function cleanup(options = {}) {
|
|
|
502
504
|
};
|
|
503
505
|
}
|
|
504
506
|
} else {
|
|
505
|
-
const filesToRemove = [
|
|
507
|
+
const filesToRemove = [
|
|
508
|
+
GUID_CACHE_FILE2,
|
|
509
|
+
DOC_INDEX_FILE2,
|
|
510
|
+
EDITOR_LOCK_FILE,
|
|
511
|
+
LAST_EDITOR_CONFIG_FILE
|
|
512
|
+
];
|
|
506
513
|
for (const file of filesToRemove) {
|
|
507
514
|
const filePath = import_path3.join(configPath, file);
|
|
508
515
|
if (import_fs3.existsSync(filePath)) {
|
|
@@ -1806,75 +1813,6 @@ function grep_project_js(options) {
|
|
|
1806
1813
|
var import_fs10 = require("fs");
|
|
1807
1814
|
var path5 = __toESM(require("path"));
|
|
1808
1815
|
|
|
1809
|
-
// src/guid-cache.ts
|
|
1810
|
-
var import_fs7 = require("fs");
|
|
1811
|
-
var import_path5 = require("path");
|
|
1812
|
-
var _cache_store = new Map;
|
|
1813
|
-
function build_guid_cache(project_path, raw) {
|
|
1814
|
-
return {
|
|
1815
|
-
project_path,
|
|
1816
|
-
cache: raw,
|
|
1817
|
-
count: Object.keys(raw).length,
|
|
1818
|
-
resolve(guid) {
|
|
1819
|
-
return raw[guid] ?? null;
|
|
1820
|
-
},
|
|
1821
|
-
resolve_absolute(guid) {
|
|
1822
|
-
const rel = raw[guid];
|
|
1823
|
-
if (!rel)
|
|
1824
|
-
return null;
|
|
1825
|
-
if (import_path5.isAbsolute(rel))
|
|
1826
|
-
return rel;
|
|
1827
|
-
return import_path5.join(project_path, rel);
|
|
1828
|
-
},
|
|
1829
|
-
resolve_many(guids) {
|
|
1830
|
-
const result = {};
|
|
1831
|
-
for (const guid of guids) {
|
|
1832
|
-
result[guid] = raw[guid] ?? null;
|
|
1833
|
-
}
|
|
1834
|
-
return result;
|
|
1835
|
-
},
|
|
1836
|
-
find_by_name(name, extension) {
|
|
1837
|
-
const nameLower = name.toLowerCase().replace(/\.[^.]+$/, "");
|
|
1838
|
-
let substringMatch = null;
|
|
1839
|
-
for (const [guid, assetPath] of Object.entries(raw)) {
|
|
1840
|
-
if (extension && !assetPath.endsWith(extension))
|
|
1841
|
-
continue;
|
|
1842
|
-
const fileName = import_path5.basename(assetPath, import_path5.extname(assetPath)).toLowerCase();
|
|
1843
|
-
if (fileName === nameLower) {
|
|
1844
|
-
return { guid, path: assetPath };
|
|
1845
|
-
}
|
|
1846
|
-
if (!substringMatch && assetPath.toLowerCase().includes(nameLower)) {
|
|
1847
|
-
substringMatch = { guid, path: assetPath };
|
|
1848
|
-
}
|
|
1849
|
-
}
|
|
1850
|
-
return substringMatch;
|
|
1851
|
-
}
|
|
1852
|
-
};
|
|
1853
|
-
}
|
|
1854
|
-
function load_guid_cache(project_path) {
|
|
1855
|
-
const resolved = project_path;
|
|
1856
|
-
const existing = _cache_store.get(resolved);
|
|
1857
|
-
if (existing)
|
|
1858
|
-
return existing;
|
|
1859
|
-
const cachePath = import_path5.join(resolved, ".unity-agentic", "guid-cache.json");
|
|
1860
|
-
if (!import_fs7.existsSync(cachePath))
|
|
1861
|
-
return null;
|
|
1862
|
-
try {
|
|
1863
|
-
const raw = JSON.parse(import_fs7.readFileSync(cachePath, "utf-8"));
|
|
1864
|
-
const cache = build_guid_cache(resolved, raw);
|
|
1865
|
-
_cache_store.set(resolved, cache);
|
|
1866
|
-
return cache;
|
|
1867
|
-
} catch {
|
|
1868
|
-
return null;
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
function load_guid_cache_for_file(file_path, explicit_project) {
|
|
1872
|
-
const project_path = explicit_project || find_unity_project_root(import_path5.dirname(file_path));
|
|
1873
|
-
if (!project_path)
|
|
1874
|
-
return null;
|
|
1875
|
-
return load_guid_cache(project_path);
|
|
1876
|
-
}
|
|
1877
|
-
|
|
1878
1816
|
// src/class-ids.ts
|
|
1879
1817
|
var UNITY_CLASS_IDS = {
|
|
1880
1818
|
1: "GameObject",
|
|
@@ -1946,15 +1884,14 @@ var UNITY_CLASS_IDS = {
|
|
|
1946
1884
|
114: "MonoBehaviour",
|
|
1947
1885
|
115: "MonoScript",
|
|
1948
1886
|
117: "Texture3D",
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
126: "
|
|
1957
|
-
127: "NavMeshProjectSettings",
|
|
1887
|
+
118: "NewAnimationTrack",
|
|
1888
|
+
119: "Projector",
|
|
1889
|
+
120: "LineRenderer",
|
|
1890
|
+
121: "Flare",
|
|
1891
|
+
122: "Halo",
|
|
1892
|
+
123: "LensFlare",
|
|
1893
|
+
124: "FlareLayer",
|
|
1894
|
+
126: "NavMeshProjectSettings",
|
|
1958
1895
|
128: "Font",
|
|
1959
1896
|
129: "PlayerSettings",
|
|
1960
1897
|
130: "NamedObject",
|
|
@@ -1981,6 +1918,7 @@ var UNITY_CLASS_IDS = {
|
|
|
1981
1918
|
164: "AudioReverbFilter",
|
|
1982
1919
|
165: "AudioHighPassFilter",
|
|
1983
1920
|
166: "AudioChorusFilter",
|
|
1921
|
+
1660057539: "SceneRoots",
|
|
1984
1922
|
167: "AudioReverbZone",
|
|
1985
1923
|
168: "AudioEchoFilter",
|
|
1986
1924
|
169: "AudioLowPassFilter",
|
|
@@ -2051,50 +1989,365 @@ var UNITY_CLASS_IDS = {
|
|
|
2051
1989
|
257: "TargetJoint2D",
|
|
2052
1990
|
258: "LightProbes",
|
|
2053
1991
|
259: "LightProbeProxyVolume",
|
|
2054
|
-
260: "
|
|
2055
|
-
261: "
|
|
2056
|
-
262: "
|
|
1992
|
+
260: "SampleClipLegacy",
|
|
1993
|
+
261: "AudioMixerSnapshotLegacy",
|
|
1994
|
+
262: "AudioMixerGroupLegacy",
|
|
2057
1995
|
265: "NScreenBridge",
|
|
2058
|
-
271: "
|
|
1996
|
+
271: "SampleClip",
|
|
2059
1997
|
272: "UnityAdsManager",
|
|
2060
|
-
273: "
|
|
2061
|
-
280: "
|
|
2062
|
-
281: "
|
|
2063
|
-
290: "
|
|
2064
|
-
292: "
|
|
2065
|
-
293: "
|
|
2066
|
-
294: "
|
|
2067
|
-
298: "
|
|
1998
|
+
273: "AudioMixerGroup",
|
|
1999
|
+
280: "UnityConnectSettingsLegacy",
|
|
2000
|
+
281: "AvatarMaskLegacy",
|
|
2001
|
+
290: "AssetBundleManifest",
|
|
2002
|
+
292: "VideoPlayerLegacy",
|
|
2003
|
+
293: "VideoClipLegacy",
|
|
2004
|
+
294: "ParticleSystemForceFieldLegacy",
|
|
2005
|
+
298: "SpriteMaskLegacy",
|
|
2068
2006
|
300: "WorldAnchor",
|
|
2069
|
-
301: "
|
|
2070
|
-
310: "
|
|
2071
|
-
|
|
2072
|
-
|
|
2007
|
+
301: "OcclusionCullingDataLegacy",
|
|
2008
|
+
310: "UnityConnectSettings",
|
|
2009
|
+
1001: "PrefabInstance",
|
|
2010
|
+
319: "AvatarMask",
|
|
2011
|
+
320: "PlayableDirector",
|
|
2012
|
+
328: "VideoPlayer",
|
|
2013
|
+
329: "VideoClip",
|
|
2014
|
+
330: "ParticleSystemForceField",
|
|
2015
|
+
331: "SpriteMask",
|
|
2016
|
+
363: "OcclusionCullingData",
|
|
2017
|
+
1006: "TextureImporter",
|
|
2018
|
+
181963792: "Preset",
|
|
2073
2019
|
687078895: "SpriteAtlas",
|
|
2020
|
+
156049354: "Grid",
|
|
2021
|
+
1742807556: "GridLayout",
|
|
2074
2022
|
1839735485: "Tilemap",
|
|
2075
|
-
|
|
2076
|
-
|
|
2023
|
+
19719996: "TilemapCollider2D",
|
|
2024
|
+
483693784: "TilemapRenderer",
|
|
2025
|
+
1839735486: "TilemapCollider2DLegacy",
|
|
2026
|
+
1839735487: "TilemapRendererLegacy"
|
|
2077
2027
|
};
|
|
2078
2028
|
var UNITY_CLASS_NAMES = Object.fromEntries(Object.entries(UNITY_CLASS_IDS).map(([id, name]) => [name, parseInt(id, 10)]));
|
|
2079
|
-
|
|
2080
|
-
|
|
2029
|
+
var UNITY_COMPONENT_CLASS_IDS = new Set([
|
|
2030
|
+
4,
|
|
2031
|
+
8,
|
|
2032
|
+
20,
|
|
2033
|
+
23,
|
|
2034
|
+
25,
|
|
2035
|
+
33,
|
|
2036
|
+
50,
|
|
2037
|
+
53,
|
|
2038
|
+
54,
|
|
2039
|
+
56,
|
|
2040
|
+
57,
|
|
2041
|
+
58,
|
|
2042
|
+
59,
|
|
2043
|
+
60,
|
|
2044
|
+
61,
|
|
2045
|
+
64,
|
|
2046
|
+
65,
|
|
2047
|
+
66,
|
|
2048
|
+
68,
|
|
2049
|
+
70,
|
|
2050
|
+
75,
|
|
2051
|
+
81,
|
|
2052
|
+
82,
|
|
2053
|
+
95,
|
|
2054
|
+
96,
|
|
2055
|
+
102,
|
|
2056
|
+
108,
|
|
2057
|
+
111,
|
|
2058
|
+
114,
|
|
2059
|
+
119,
|
|
2060
|
+
120,
|
|
2061
|
+
124,
|
|
2062
|
+
135,
|
|
2063
|
+
136,
|
|
2064
|
+
137,
|
|
2065
|
+
138,
|
|
2066
|
+
143,
|
|
2067
|
+
144,
|
|
2068
|
+
145,
|
|
2069
|
+
146,
|
|
2070
|
+
153,
|
|
2071
|
+
154,
|
|
2072
|
+
164,
|
|
2073
|
+
165,
|
|
2074
|
+
166,
|
|
2075
|
+
167,
|
|
2076
|
+
168,
|
|
2077
|
+
169,
|
|
2078
|
+
170,
|
|
2079
|
+
180,
|
|
2080
|
+
181,
|
|
2081
|
+
182,
|
|
2082
|
+
183,
|
|
2083
|
+
191,
|
|
2084
|
+
192,
|
|
2085
|
+
193,
|
|
2086
|
+
195,
|
|
2087
|
+
198,
|
|
2088
|
+
199,
|
|
2089
|
+
205,
|
|
2090
|
+
208,
|
|
2091
|
+
210,
|
|
2092
|
+
212,
|
|
2093
|
+
215,
|
|
2094
|
+
220,
|
|
2095
|
+
222,
|
|
2096
|
+
223,
|
|
2097
|
+
224,
|
|
2098
|
+
225,
|
|
2099
|
+
229,
|
|
2100
|
+
230,
|
|
2101
|
+
231,
|
|
2102
|
+
232,
|
|
2103
|
+
233,
|
|
2104
|
+
234,
|
|
2105
|
+
235,
|
|
2106
|
+
247,
|
|
2107
|
+
248,
|
|
2108
|
+
249,
|
|
2109
|
+
250,
|
|
2110
|
+
251,
|
|
2111
|
+
252,
|
|
2112
|
+
253,
|
|
2113
|
+
254,
|
|
2114
|
+
255,
|
|
2115
|
+
256,
|
|
2116
|
+
257,
|
|
2117
|
+
259,
|
|
2118
|
+
300,
|
|
2119
|
+
320,
|
|
2120
|
+
328,
|
|
2121
|
+
330,
|
|
2122
|
+
331,
|
|
2123
|
+
156049354,
|
|
2124
|
+
1742807556,
|
|
2125
|
+
1839735485,
|
|
2126
|
+
19719996,
|
|
2127
|
+
483693784,
|
|
2128
|
+
1839735486,
|
|
2129
|
+
1839735487
|
|
2130
|
+
]);
|
|
2131
|
+
var UNITY_ADDABLE_COMPONENT_CLASS_IDS = new Set([
|
|
2132
|
+
20,
|
|
2133
|
+
23,
|
|
2134
|
+
33,
|
|
2135
|
+
50,
|
|
2136
|
+
54,
|
|
2137
|
+
58,
|
|
2138
|
+
59,
|
|
2139
|
+
60,
|
|
2140
|
+
61,
|
|
2141
|
+
64,
|
|
2142
|
+
65,
|
|
2143
|
+
66,
|
|
2144
|
+
68,
|
|
2145
|
+
70,
|
|
2146
|
+
75,
|
|
2147
|
+
81,
|
|
2148
|
+
82,
|
|
2149
|
+
95,
|
|
2150
|
+
96,
|
|
2151
|
+
102,
|
|
2152
|
+
108,
|
|
2153
|
+
111,
|
|
2154
|
+
119,
|
|
2155
|
+
120,
|
|
2156
|
+
124,
|
|
2157
|
+
135,
|
|
2158
|
+
136,
|
|
2159
|
+
137,
|
|
2160
|
+
138,
|
|
2161
|
+
143,
|
|
2162
|
+
144,
|
|
2163
|
+
145,
|
|
2164
|
+
146,
|
|
2165
|
+
153,
|
|
2166
|
+
154,
|
|
2167
|
+
164,
|
|
2168
|
+
165,
|
|
2169
|
+
166,
|
|
2170
|
+
167,
|
|
2171
|
+
168,
|
|
2172
|
+
169,
|
|
2173
|
+
170,
|
|
2174
|
+
182,
|
|
2175
|
+
183,
|
|
2176
|
+
191,
|
|
2177
|
+
192,
|
|
2178
|
+
193,
|
|
2179
|
+
195,
|
|
2180
|
+
198,
|
|
2181
|
+
199,
|
|
2182
|
+
205,
|
|
2183
|
+
208,
|
|
2184
|
+
210,
|
|
2185
|
+
212,
|
|
2186
|
+
215,
|
|
2187
|
+
220,
|
|
2188
|
+
222,
|
|
2189
|
+
223,
|
|
2190
|
+
225,
|
|
2191
|
+
231,
|
|
2192
|
+
232,
|
|
2193
|
+
233,
|
|
2194
|
+
234,
|
|
2195
|
+
235,
|
|
2196
|
+
247,
|
|
2197
|
+
249,
|
|
2198
|
+
250,
|
|
2199
|
+
251,
|
|
2200
|
+
252,
|
|
2201
|
+
253,
|
|
2202
|
+
254,
|
|
2203
|
+
255,
|
|
2204
|
+
256,
|
|
2205
|
+
257,
|
|
2206
|
+
259,
|
|
2207
|
+
300,
|
|
2208
|
+
320,
|
|
2209
|
+
328,
|
|
2210
|
+
330,
|
|
2211
|
+
331,
|
|
2212
|
+
156049354,
|
|
2213
|
+
1742807556,
|
|
2214
|
+
1839735485,
|
|
2215
|
+
19719996,
|
|
2216
|
+
483693784
|
|
2217
|
+
]);
|
|
2218
|
+
var UNITY_BUILTIN_NAMESPACE_PREFIXES = ["UnityEngine", "UnityEditor"];
|
|
2219
|
+
function find_namespaced_class_id(component_name, allowed_class_ids) {
|
|
2220
|
+
const dot_index = component_name.lastIndexOf(".");
|
|
2221
|
+
if (dot_index <= 0)
|
|
2222
|
+
return null;
|
|
2223
|
+
const namespace_name = component_name.slice(0, dot_index);
|
|
2224
|
+
const short_name = component_name.slice(dot_index + 1);
|
|
2225
|
+
const is_unity_namespace = UNITY_BUILTIN_NAMESPACE_PREFIXES.some((prefix) => namespace_name === prefix || namespace_name.startsWith(`${prefix}.`));
|
|
2226
|
+
if (!is_unity_namespace || short_name.length === 0) {
|
|
2227
|
+
return null;
|
|
2228
|
+
}
|
|
2229
|
+
return find_class_id(short_name, allowed_class_ids);
|
|
2081
2230
|
}
|
|
2082
|
-
function
|
|
2231
|
+
function find_class_id(component_name, allowed_class_ids) {
|
|
2232
|
+
const matches_allowed = (class_id) => {
|
|
2233
|
+
return allowed_class_ids ? allowed_class_ids.has(class_id) : true;
|
|
2234
|
+
};
|
|
2083
2235
|
if (UNITY_CLASS_NAMES[component_name] !== undefined) {
|
|
2084
|
-
|
|
2236
|
+
const class_id = UNITY_CLASS_NAMES[component_name];
|
|
2237
|
+
return matches_allowed(class_id) ? class_id : null;
|
|
2085
2238
|
}
|
|
2086
2239
|
const lowerName = component_name.toLowerCase();
|
|
2087
2240
|
for (const [name, id] of Object.entries(UNITY_CLASS_NAMES)) {
|
|
2088
2241
|
if (name.toLowerCase() === lowerName) {
|
|
2089
|
-
return id;
|
|
2242
|
+
return matches_allowed(id) ? id : null;
|
|
2090
2243
|
}
|
|
2091
2244
|
}
|
|
2245
|
+
const namespaced_match = find_namespaced_class_id(component_name, allowed_class_ids);
|
|
2246
|
+
if (namespaced_match !== null) {
|
|
2247
|
+
return namespaced_match;
|
|
2248
|
+
}
|
|
2092
2249
|
return null;
|
|
2093
2250
|
}
|
|
2251
|
+
function get_class_id_name(class_id) {
|
|
2252
|
+
return UNITY_CLASS_IDS[class_id] || `Unknown_${class_id}`;
|
|
2253
|
+
}
|
|
2254
|
+
function get_class_id(component_name) {
|
|
2255
|
+
return find_class_id(component_name);
|
|
2256
|
+
}
|
|
2257
|
+
function get_component_class_id(component_name) {
|
|
2258
|
+
return find_class_id(component_name, UNITY_COMPONENT_CLASS_IDS);
|
|
2259
|
+
}
|
|
2260
|
+
function get_addable_component_class_id(component_name) {
|
|
2261
|
+
return find_class_id(component_name, UNITY_ADDABLE_COMPONENT_CLASS_IDS);
|
|
2262
|
+
}
|
|
2094
2263
|
|
|
2095
2264
|
// src/editor/shared.ts
|
|
2096
2265
|
var import_fs8 = require("fs");
|
|
2097
2266
|
var path3 = __toESM(require("path"));
|
|
2267
|
+
|
|
2268
|
+
// src/guid-cache.ts
|
|
2269
|
+
var import_fs7 = require("fs");
|
|
2270
|
+
var import_path5 = require("path");
|
|
2271
|
+
var _cache_store = new Map;
|
|
2272
|
+
function build_guid_cache(project_path, raw) {
|
|
2273
|
+
return {
|
|
2274
|
+
project_path,
|
|
2275
|
+
cache: raw,
|
|
2276
|
+
count: Object.keys(raw).length,
|
|
2277
|
+
resolve(guid) {
|
|
2278
|
+
return raw[guid] ?? null;
|
|
2279
|
+
},
|
|
2280
|
+
resolve_absolute(guid) {
|
|
2281
|
+
const rel = raw[guid];
|
|
2282
|
+
if (!rel)
|
|
2283
|
+
return null;
|
|
2284
|
+
if (import_path5.isAbsolute(rel))
|
|
2285
|
+
return rel;
|
|
2286
|
+
return import_path5.join(project_path, rel);
|
|
2287
|
+
},
|
|
2288
|
+
resolve_many(guids) {
|
|
2289
|
+
const result = {};
|
|
2290
|
+
for (const guid of guids) {
|
|
2291
|
+
result[guid] = raw[guid] ?? null;
|
|
2292
|
+
}
|
|
2293
|
+
return result;
|
|
2294
|
+
},
|
|
2295
|
+
find_by_name(name, extension) {
|
|
2296
|
+
const nameLower = name.toLowerCase().replace(/\.[^.]+$/, "");
|
|
2297
|
+
let substringMatch = null;
|
|
2298
|
+
for (const [guid, assetPath] of Object.entries(raw)) {
|
|
2299
|
+
if (extension && !assetPath.endsWith(extension))
|
|
2300
|
+
continue;
|
|
2301
|
+
const fileName = import_path5.basename(assetPath, import_path5.extname(assetPath)).toLowerCase();
|
|
2302
|
+
if (fileName === nameLower) {
|
|
2303
|
+
return { guid, path: assetPath };
|
|
2304
|
+
}
|
|
2305
|
+
if (!substringMatch && assetPath.toLowerCase().includes(nameLower)) {
|
|
2306
|
+
substringMatch = { guid, path: assetPath };
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
return substringMatch;
|
|
2310
|
+
},
|
|
2311
|
+
find_all_by_name_exact(name, extension) {
|
|
2312
|
+
const nameLower = name.toLowerCase().replace(/\.[^.]+$/, "");
|
|
2313
|
+
const matches = [];
|
|
2314
|
+
for (const [guid, assetPath] of Object.entries(raw)) {
|
|
2315
|
+
if (extension && !assetPath.endsWith(extension))
|
|
2316
|
+
continue;
|
|
2317
|
+
const fileName = import_path5.basename(assetPath, import_path5.extname(assetPath)).toLowerCase();
|
|
2318
|
+
if (fileName === nameLower) {
|
|
2319
|
+
matches.push({ guid, path: assetPath });
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
return matches;
|
|
2323
|
+
}
|
|
2324
|
+
};
|
|
2325
|
+
}
|
|
2326
|
+
function load_guid_cache(project_path) {
|
|
2327
|
+
const resolved = project_path;
|
|
2328
|
+
const existing = _cache_store.get(resolved);
|
|
2329
|
+
if (existing)
|
|
2330
|
+
return existing;
|
|
2331
|
+
const cachePath = import_path5.join(resolved, ".unity-agentic", "guid-cache.json");
|
|
2332
|
+
if (!import_fs7.existsSync(cachePath))
|
|
2333
|
+
return null;
|
|
2334
|
+
try {
|
|
2335
|
+
const raw = JSON.parse(import_fs7.readFileSync(cachePath, "utf-8"));
|
|
2336
|
+
const cache = build_guid_cache(resolved, raw);
|
|
2337
|
+
_cache_store.set(resolved, cache);
|
|
2338
|
+
return cache;
|
|
2339
|
+
} catch {
|
|
2340
|
+
return null;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
function load_guid_cache_for_file(file_path, explicit_project) {
|
|
2344
|
+
const project_path = explicit_project || find_unity_project_root(import_path5.dirname(file_path));
|
|
2345
|
+
if (!project_path)
|
|
2346
|
+
return null;
|
|
2347
|
+
return load_guid_cache(project_path);
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
// src/editor/shared.ts
|
|
2098
2351
|
function validateUnityYAML(content) {
|
|
2099
2352
|
if (!content.startsWith("%YAML 1.1")) {
|
|
2100
2353
|
return "Missing or invalid YAML header";
|
|
@@ -2147,8 +2400,104 @@ function resolve_source_prefab(doc, file_path, project_path) {
|
|
|
2147
2400
|
prefab_instance_block: pi_block
|
|
2148
2401
|
};
|
|
2149
2402
|
}
|
|
2150
|
-
function
|
|
2403
|
+
function load_type_registry(projectPath) {
|
|
2404
|
+
const registryPath = path3.join(projectPath, ".unity-agentic", "type-registry.json");
|
|
2405
|
+
if (!import_fs8.existsSync(registryPath))
|
|
2406
|
+
return null;
|
|
2407
|
+
try {
|
|
2408
|
+
return JSON.parse(import_fs8.readFileSync(registryPath, "utf-8"));
|
|
2409
|
+
} catch {
|
|
2410
|
+
return null;
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
function parse_type_query(script) {
|
|
2414
|
+
const dotIndex = script.lastIndexOf(".");
|
|
2415
|
+
if (dotIndex > 0) {
|
|
2416
|
+
return {
|
|
2417
|
+
targetNamespace: script.substring(0, dotIndex),
|
|
2418
|
+
targetName: script.substring(dotIndex + 1)
|
|
2419
|
+
};
|
|
2420
|
+
}
|
|
2421
|
+
return { targetName: script, targetNamespace: null };
|
|
2422
|
+
}
|
|
2423
|
+
function format_qualified_type(entry) {
|
|
2424
|
+
return entry.namespace ? `${entry.namespace}.${entry.name}` : entry.name;
|
|
2425
|
+
}
|
|
2426
|
+
function resolve_registry_entry_guid(match, projectPath) {
|
|
2427
|
+
if (match.guid) {
|
|
2428
|
+
return match.guid;
|
|
2429
|
+
}
|
|
2430
|
+
if (!match.filePath)
|
|
2431
|
+
return null;
|
|
2432
|
+
const fullFilePath = path3.isAbsolute(match.filePath) ? match.filePath : path3.join(projectPath, match.filePath);
|
|
2433
|
+
const metaPath = fullFilePath + ".meta";
|
|
2434
|
+
if (import_fs8.existsSync(metaPath)) {
|
|
2435
|
+
const guid = extractGuidFromMeta(metaPath);
|
|
2436
|
+
if (guid)
|
|
2437
|
+
return guid;
|
|
2438
|
+
}
|
|
2439
|
+
return null;
|
|
2440
|
+
}
|
|
2441
|
+
function materialize_registry_match(match, guid) {
|
|
2442
|
+
return { guid, path: match.filePath };
|
|
2443
|
+
}
|
|
2444
|
+
function dedupe_script_resolutions(resolutions) {
|
|
2445
|
+
const unique = new Map;
|
|
2446
|
+
for (const resolution of resolutions) {
|
|
2447
|
+
unique.set(`${resolution.guid}|${resolution.path ?? ""}`, resolution);
|
|
2448
|
+
}
|
|
2449
|
+
return [...unique.values()];
|
|
2450
|
+
}
|
|
2451
|
+
function resolve_script_guid_from_registry(script, projectPath, registry) {
|
|
2452
|
+
const { targetName, targetNamespace } = parse_type_query(script);
|
|
2453
|
+
const targetNameLower = targetName.toLowerCase();
|
|
2454
|
+
const matchingEntries = registry.filter((entry) => {
|
|
2455
|
+
if (entry.name.toLowerCase() !== targetNameLower)
|
|
2456
|
+
return false;
|
|
2457
|
+
if (targetNamespace && entry.namespace?.toLowerCase() !== targetNamespace.toLowerCase())
|
|
2458
|
+
return false;
|
|
2459
|
+
return true;
|
|
2460
|
+
});
|
|
2461
|
+
if (matchingEntries.length === 0) {
|
|
2462
|
+
return null;
|
|
2463
|
+
}
|
|
2464
|
+
const qualifiedMatches = [...new Set(matchingEntries.map(format_qualified_type))];
|
|
2465
|
+
if (!targetNamespace && qualifiedMatches.length > 1) {
|
|
2466
|
+
throw new Error(`Ambiguous type "${script}": found multiple qualified matches (${qualifiedMatches.join(", ")}). ` + `Specify which ${targetName} to use by qualified name (for example, "${qualifiedMatches[0]}") or provide the full script path.`);
|
|
2467
|
+
}
|
|
2468
|
+
const resolvedEntries = matchingEntries.map((entry) => ({
|
|
2469
|
+
entry,
|
|
2470
|
+
guid: resolve_registry_entry_guid(entry, projectPath)
|
|
2471
|
+
}));
|
|
2472
|
+
const sourceGuidCandidates = [...new Set(resolvedEntries.filter(({ entry, guid }) => entry.filePath && !entry.filePath.endsWith(".dll") && guid).map(({ guid }) => guid))];
|
|
2473
|
+
const dllMaterializedMatches = dedupe_script_resolutions(resolvedEntries.filter(({ entry }) => entry.filePath?.endsWith(".dll")).flatMap(({ entry, guid }) => {
|
|
2474
|
+
if (guid) {
|
|
2475
|
+
return [materialize_registry_match(entry, guid)];
|
|
2476
|
+
}
|
|
2477
|
+
return sourceGuidCandidates.map((sourceGuid) => materialize_registry_match(entry, sourceGuid));
|
|
2478
|
+
}));
|
|
2479
|
+
if (dllMaterializedMatches.length === 1) {
|
|
2480
|
+
return dllMaterializedMatches[0];
|
|
2481
|
+
}
|
|
2482
|
+
if (dllMaterializedMatches.length > 1) {
|
|
2483
|
+
const paths = dllMaterializedMatches.map((match) => match.path ?? match.guid).join(", ");
|
|
2484
|
+
throw new Error(`Ambiguous type "${script}": found ${dllMaterializedMatches.length} matches (${paths}). ` + `Use a qualified name (e.g., "Namespace.${targetName}") or provide the full path.`);
|
|
2485
|
+
}
|
|
2486
|
+
const materializedMatches = dedupe_script_resolutions(resolvedEntries.filter(({ entry, guid }) => !entry.filePath?.endsWith(".dll") && guid).map(({ entry, guid }) => materialize_registry_match(entry, guid)));
|
|
2487
|
+
if (materializedMatches.length === 1) {
|
|
2488
|
+
return materializedMatches[0];
|
|
2489
|
+
}
|
|
2490
|
+
if (materializedMatches.length > 1) {
|
|
2491
|
+
const paths = materializedMatches.map((match) => match.path ?? match.guid).join(", ");
|
|
2492
|
+
throw new Error(`Ambiguous type "${script}": found ${materializedMatches.length} matches (${paths}). ` + `Use a qualified name (e.g., "Namespace.${targetName}") or provide the full path.`);
|
|
2493
|
+
}
|
|
2494
|
+
return null;
|
|
2495
|
+
}
|
|
2496
|
+
function resolveScriptGuid(script, projectPath, _options) {
|
|
2151
2497
|
if (/^[a-f0-9]{32}$/i.test(script)) {
|
|
2498
|
+
if (/^0{32}$/i.test(script)) {
|
|
2499
|
+
throw new Error(`Invalid script GUID "${script}": all-zero GUID is not allowed. Provide a real script GUID from a .meta file.`);
|
|
2500
|
+
}
|
|
2152
2501
|
return { guid: script.toLowerCase(), path: null };
|
|
2153
2502
|
}
|
|
2154
2503
|
if (script.endsWith(".cs")) {
|
|
@@ -2171,189 +2520,14 @@ function resolveScriptGuid(script, projectPath) {
|
|
|
2171
2520
|
}
|
|
2172
2521
|
}
|
|
2173
2522
|
if (projectPath) {
|
|
2174
|
-
const
|
|
2175
|
-
if (
|
|
2176
|
-
const
|
|
2177
|
-
if (
|
|
2178
|
-
return
|
|
2179
|
-
}
|
|
2180
|
-
const registryPath = path3.join(projectPath, ".unity-agentic", "type-registry.json");
|
|
2181
|
-
if (import_fs8.existsSync(registryPath)) {
|
|
2182
|
-
try {
|
|
2183
|
-
const registry = JSON.parse(import_fs8.readFileSync(registryPath, "utf-8"));
|
|
2184
|
-
let targetName = script;
|
|
2185
|
-
let targetNamespace = null;
|
|
2186
|
-
const dotIndex = script.lastIndexOf(".");
|
|
2187
|
-
if (dotIndex > 0) {
|
|
2188
|
-
targetNamespace = script.substring(0, dotIndex);
|
|
2189
|
-
targetName = script.substring(dotIndex + 1);
|
|
2190
|
-
}
|
|
2191
|
-
const targetNameLower = targetName.toLowerCase();
|
|
2192
|
-
const matches = registry.filter((t) => {
|
|
2193
|
-
if (t.name.toLowerCase() !== targetNameLower)
|
|
2194
|
-
return false;
|
|
2195
|
-
if (targetNamespace && t.namespace?.toLowerCase() !== targetNamespace.toLowerCase())
|
|
2196
|
-
return false;
|
|
2197
|
-
return true;
|
|
2198
|
-
});
|
|
2199
|
-
if (matches.length === 1) {
|
|
2200
|
-
if (matches[0].guid) {
|
|
2201
|
-
return { guid: matches[0].guid, path: matches[0].filePath };
|
|
2202
|
-
}
|
|
2203
|
-
if (matches[0].filePath && projectPath) {
|
|
2204
|
-
const fullFilePath = path3.isAbsolute(matches[0].filePath) ? matches[0].filePath : path3.join(projectPath, matches[0].filePath);
|
|
2205
|
-
const metaPath = fullFilePath + ".meta";
|
|
2206
|
-
if (import_fs8.existsSync(metaPath)) {
|
|
2207
|
-
const guid = extractGuidFromMeta(metaPath);
|
|
2208
|
-
if (guid)
|
|
2209
|
-
return { guid, path: matches[0].filePath };
|
|
2210
|
-
}
|
|
2211
|
-
if (matches[0].filePath.startsWith("Packages/")) {
|
|
2212
|
-
const pkgPath = path3.join(projectPath, matches[0].filePath);
|
|
2213
|
-
const pkgMetaPath = pkgPath + ".meta";
|
|
2214
|
-
if (import_fs8.existsSync(pkgMetaPath)) {
|
|
2215
|
-
const guid = extractGuidFromMeta(pkgMetaPath);
|
|
2216
|
-
if (guid)
|
|
2217
|
-
return { guid, path: matches[0].filePath };
|
|
2218
|
-
}
|
|
2219
|
-
}
|
|
2220
|
-
if (matches[0].filePath?.endsWith(".dll")) {
|
|
2221
|
-
const classNameLower = targetName.toLowerCase();
|
|
2222
|
-
const dllBasename = path3.basename(matches[0].filePath).toLowerCase();
|
|
2223
|
-
for (const cacheName of ["package-cache.json", "local-package-cache.json"]) {
|
|
2224
|
-
const cachePath = path3.join(projectPath, ".unity-agentic", cacheName);
|
|
2225
|
-
if (!import_fs8.existsSync(cachePath))
|
|
2226
|
-
continue;
|
|
2227
|
-
try {
|
|
2228
|
-
const cache = JSON.parse(import_fs8.readFileSync(cachePath, "utf-8"));
|
|
2229
|
-
for (const [guid, assetPath] of Object.entries(cache)) {
|
|
2230
|
-
if (assetPath.endsWith(".cs") && path3.basename(assetPath, ".cs").toLowerCase() === classNameLower) {
|
|
2231
|
-
return { guid, path: assetPath };
|
|
2232
|
-
}
|
|
2233
|
-
}
|
|
2234
|
-
for (const [guid, assetPath] of Object.entries(cache)) {
|
|
2235
|
-
if (assetPath.toLowerCase().endsWith(".dll") && path3.basename(assetPath).toLowerCase() === dllBasename) {
|
|
2236
|
-
return { guid, path: assetPath };
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
} catch {}
|
|
2240
|
-
}
|
|
2241
|
-
}
|
|
2242
|
-
}
|
|
2243
|
-
}
|
|
2244
|
-
if (matches.length > 1) {
|
|
2245
|
-
const withGuid = matches.filter((m) => m.guid);
|
|
2246
|
-
if (withGuid.length === 1) {
|
|
2247
|
-
return { guid: withGuid[0].guid, path: withGuid[0].filePath };
|
|
2248
|
-
}
|
|
2249
|
-
const resolvedFromMeta = matches.filter((m) => !m.guid && m.filePath).map((m) => {
|
|
2250
|
-
const fullPath = path3.isAbsolute(m.filePath) ? m.filePath : path3.join(projectPath, m.filePath);
|
|
2251
|
-
let guid = import_fs8.existsSync(fullPath + ".meta") ? extractGuidFromMeta(fullPath + ".meta") : null;
|
|
2252
|
-
if (!guid && m.filePath.startsWith("Packages/")) {
|
|
2253
|
-
const pkgPath = path3.join(projectPath, m.filePath);
|
|
2254
|
-
if (import_fs8.existsSync(pkgPath + ".meta")) {
|
|
2255
|
-
guid = extractGuidFromMeta(pkgPath + ".meta");
|
|
2256
|
-
}
|
|
2257
|
-
}
|
|
2258
|
-
if (!guid && m.filePath?.endsWith(".dll")) {
|
|
2259
|
-
const clsLower = (m.name ?? targetName).toLowerCase();
|
|
2260
|
-
const dllBase = path3.basename(m.filePath).toLowerCase();
|
|
2261
|
-
for (const cn of ["package-cache.json", "local-package-cache.json"]) {
|
|
2262
|
-
const cp = path3.join(projectPath, ".unity-agentic", cn);
|
|
2263
|
-
if (!import_fs8.existsSync(cp))
|
|
2264
|
-
continue;
|
|
2265
|
-
try {
|
|
2266
|
-
const c = JSON.parse(import_fs8.readFileSync(cp, "utf-8"));
|
|
2267
|
-
for (const [g, p] of Object.entries(c)) {
|
|
2268
|
-
if (p.endsWith(".cs") && path3.basename(p, ".cs").toLowerCase() === clsLower) {
|
|
2269
|
-
guid = g;
|
|
2270
|
-
break;
|
|
2271
|
-
}
|
|
2272
|
-
}
|
|
2273
|
-
if (!guid) {
|
|
2274
|
-
for (const [g, p] of Object.entries(c)) {
|
|
2275
|
-
if (p.toLowerCase().endsWith(".dll") && path3.basename(p).toLowerCase() === dllBase) {
|
|
2276
|
-
guid = g;
|
|
2277
|
-
break;
|
|
2278
|
-
}
|
|
2279
|
-
}
|
|
2280
|
-
}
|
|
2281
|
-
} catch {}
|
|
2282
|
-
if (guid)
|
|
2283
|
-
break;
|
|
2284
|
-
}
|
|
2285
|
-
}
|
|
2286
|
-
return guid ? { guid, path: m.filePath } : null;
|
|
2287
|
-
}).filter((r) => r !== null);
|
|
2288
|
-
const allResolved = [...withGuid.map((m) => ({ guid: m.guid, path: m.filePath })), ...resolvedFromMeta];
|
|
2289
|
-
if (allResolved.length === 1) {
|
|
2290
|
-
return allResolved[0];
|
|
2291
|
-
}
|
|
2292
|
-
if (allResolved.length > 1) {
|
|
2293
|
-
const pkgCachePaths = [
|
|
2294
|
-
path3.join(projectPath, ".unity-agentic", "package-cache.json"),
|
|
2295
|
-
path3.join(projectPath, ".unity-agentic", "local-package-cache.json")
|
|
2296
|
-
];
|
|
2297
|
-
for (const cachePath of pkgCachePaths) {
|
|
2298
|
-
if (!import_fs8.existsSync(cachePath))
|
|
2299
|
-
continue;
|
|
2300
|
-
try {
|
|
2301
|
-
const cache = JSON.parse(import_fs8.readFileSync(cachePath, "utf-8"));
|
|
2302
|
-
const inCache = allResolved.filter((r) => (r.guid in cache));
|
|
2303
|
-
if (inCache.length === 1)
|
|
2304
|
-
return inCache[0];
|
|
2305
|
-
} catch {}
|
|
2306
|
-
}
|
|
2307
|
-
const paths = allResolved.map((m) => m.path).join(", ");
|
|
2308
|
-
throw new Error(`Ambiguous type "${script}": found ${allResolved.length} matches (${paths}). ` + `Use a qualified name (e.g., "Namespace.${targetName}") or provide the full path.`);
|
|
2309
|
-
}
|
|
2310
|
-
}
|
|
2311
|
-
} catch (err) {
|
|
2312
|
-
if (err instanceof Error && err.message.startsWith("Ambiguous type")) {
|
|
2313
|
-
throw err;
|
|
2314
|
-
}
|
|
2523
|
+
const registry = load_type_registry(projectPath);
|
|
2524
|
+
if (registry) {
|
|
2525
|
+
const resolvedFromRegistry = resolve_script_guid_from_registry(script, projectPath, registry);
|
|
2526
|
+
if (resolvedFromRegistry) {
|
|
2527
|
+
return resolvedFromRegistry;
|
|
2315
2528
|
}
|
|
2529
|
+
return null;
|
|
2316
2530
|
}
|
|
2317
|
-
const scriptNameLower = script.toLowerCase().replace(/\.cs$/, "");
|
|
2318
|
-
const dotIdx = scriptNameLower.lastIndexOf(".");
|
|
2319
|
-
const classNameOnly = dotIdx > 0 ? scriptNameLower.substring(dotIdx + 1) : null;
|
|
2320
|
-
const cachePaths = [
|
|
2321
|
-
path3.join(projectPath, ".unity-agentic", "package-cache.json"),
|
|
2322
|
-
path3.join(projectPath, ".unity-agentic", "local-package-cache.json")
|
|
2323
|
-
];
|
|
2324
|
-
for (const cachePath of cachePaths) {
|
|
2325
|
-
if (!import_fs8.existsSync(cachePath))
|
|
2326
|
-
continue;
|
|
2327
|
-
try {
|
|
2328
|
-
const cache = JSON.parse(import_fs8.readFileSync(cachePath, "utf-8"));
|
|
2329
|
-
for (const [guid, assetPath] of Object.entries(cache)) {
|
|
2330
|
-
if (!assetPath.endsWith(".cs"))
|
|
2331
|
-
continue;
|
|
2332
|
-
const fileName = path3.basename(assetPath, ".cs").toLowerCase();
|
|
2333
|
-
if (fileName === scriptNameLower || classNameOnly && fileName === classNameOnly) {
|
|
2334
|
-
return { guid, path: assetPath };
|
|
2335
|
-
}
|
|
2336
|
-
}
|
|
2337
|
-
} catch {}
|
|
2338
|
-
}
|
|
2339
|
-
try {
|
|
2340
|
-
const assetsDir = path3.join(projectPath, "Assets");
|
|
2341
|
-
if (import_fs8.existsSync(assetsDir)) {
|
|
2342
|
-
const entries = import_fs8.readdirSync(assetsDir, { recursive: true, withFileTypes: false });
|
|
2343
|
-
for (const entry of entries) {
|
|
2344
|
-
if (!entry.endsWith(".cs"))
|
|
2345
|
-
continue;
|
|
2346
|
-
const fileName = path3.basename(entry, ".cs").toLowerCase();
|
|
2347
|
-
if (fileName === scriptNameLower || classNameOnly && fileName === classNameOnly) {
|
|
2348
|
-
const fullPath = path3.join(assetsDir, entry);
|
|
2349
|
-
const guid = extractGuidFromMeta(fullPath + ".meta");
|
|
2350
|
-
if (guid) {
|
|
2351
|
-
return { guid, path: path3.join("Assets", entry) };
|
|
2352
|
-
}
|
|
2353
|
-
}
|
|
2354
|
-
}
|
|
2355
|
-
}
|
|
2356
|
-
} catch {}
|
|
2357
2531
|
}
|
|
2358
2532
|
return null;
|
|
2359
2533
|
}
|
|
@@ -2405,19 +2579,38 @@ function resolveAssetPathToPPtr(value, file_path, project_path) {
|
|
|
2405
2579
|
return null;
|
|
2406
2580
|
return `{fileID: ${mapping.fileID}, guid: ${guid}, type: ${mapping.type}}`;
|
|
2407
2581
|
}
|
|
2408
|
-
function
|
|
2409
|
-
|
|
2582
|
+
function detect_abstract_class_in_source(file_path, class_name) {
|
|
2583
|
+
try {
|
|
2584
|
+
const source = import_fs8.readFileSync(file_path, "utf-8");
|
|
2585
|
+
const escaped_name = class_name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2586
|
+
const pattern = new RegExp(`(^|[^\\w])abstract\\s+class\\s+${escaped_name}(?=$|[^\\w])`, "m");
|
|
2587
|
+
return pattern.test(source);
|
|
2588
|
+
} catch {
|
|
2589
|
+
return false;
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
function resolve_script_with_fields(script, project_path, options) {
|
|
2593
|
+
const resolved = resolveScriptGuid(script, project_path, options);
|
|
2410
2594
|
if (!resolved)
|
|
2411
2595
|
return null;
|
|
2412
2596
|
const result = {
|
|
2413
2597
|
guid: resolved.guid,
|
|
2414
2598
|
path: resolved.path
|
|
2415
2599
|
};
|
|
2600
|
+
if (resolved.path && resolved.path.endsWith(".cs")) {
|
|
2601
|
+
const full_path = path3.isAbsolute(resolved.path) ? resolved.path : project_path ? path3.join(project_path, resolved.path) : resolved.path;
|
|
2602
|
+
if (import_fs8.existsSync(full_path)) {
|
|
2603
|
+
const class_name = script.includes(".") ? script.split(".").pop() : script;
|
|
2604
|
+
if (class_name.length > 0) {
|
|
2605
|
+
result.is_abstract = detect_abstract_class_in_source(full_path, class_name);
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2416
2609
|
if (!project_path)
|
|
2417
2610
|
return result;
|
|
2418
2611
|
if (resolved.path) {
|
|
2419
2612
|
try {
|
|
2420
|
-
const full_path = resolved.path
|
|
2613
|
+
const full_path = path3.isAbsolute(resolved.path) ? resolved.path : path3.join(project_path, resolved.path);
|
|
2421
2614
|
if (!import_fs8.existsSync(full_path)) {
|
|
2422
2615
|
result.extraction_error = `Script file not found at resolved path: ${full_path}`;
|
|
2423
2616
|
} else if (resolved.path.endsWith(".cs")) {
|
|
@@ -2431,6 +2624,10 @@ function resolve_script_with_fields(script, project_path) {
|
|
|
2431
2624
|
result.fields = chosen.fields;
|
|
2432
2625
|
result.base_class = chosen.baseClass ?? undefined;
|
|
2433
2626
|
result.kind = chosen.kind;
|
|
2627
|
+
result.class_name = chosen.name;
|
|
2628
|
+
if (chosen.name) {
|
|
2629
|
+
result.is_abstract = detect_abstract_class_in_source(full_path, chosen.name);
|
|
2630
|
+
}
|
|
2434
2631
|
}
|
|
2435
2632
|
} else {
|
|
2436
2633
|
result.extraction_error = "Native extractSerializedFields function not available";
|
|
@@ -2508,8 +2705,8 @@ function build_type_lookup(project_path) {
|
|
|
2508
2705
|
const assetsDir = path3.join(project_path, "Assets");
|
|
2509
2706
|
const csIndex = new Map;
|
|
2510
2707
|
try {
|
|
2511
|
-
const { readdirSync:
|
|
2512
|
-
const entries =
|
|
2708
|
+
const { readdirSync: readdirSync4 } = require("fs");
|
|
2709
|
+
const entries = readdirSync4(assetsDir, { recursive: true, withFileTypes: false });
|
|
2513
2710
|
for (const entry of entries) {
|
|
2514
2711
|
if (typeof entry === "string" && entry.endsWith(".cs")) {
|
|
2515
2712
|
const basename4 = entry.substring(entry.lastIndexOf("/") + 1).replace(/\.cs$/, "");
|
|
@@ -3530,7 +3727,21 @@ class UnityDocument {
|
|
|
3530
3727
|
}
|
|
3531
3728
|
}
|
|
3532
3729
|
}
|
|
3533
|
-
|
|
3730
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3731
|
+
const name_pattern = new RegExp(`propertyPath: m_Name\\s*\\n\\s*value:\\s*${escaped}\\s*$`, "m");
|
|
3732
|
+
for (const block of this._blocks) {
|
|
3733
|
+
if ((block.class_id === 1001 || block.class_id === 310) && name_pattern.test(block.raw)) {
|
|
3734
|
+
const pi_id = block.file_id;
|
|
3735
|
+
const pi_ref_pattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${pi_id}\\}`);
|
|
3736
|
+
const stripped_transform = this._blocks.find((b) => (b.class_id === 4 || b.class_id === 224) && b.is_stripped && pi_ref_pattern.test(b.raw));
|
|
3737
|
+
if (stripped_transform) {
|
|
3738
|
+
transform_ids.push(stripped_transform.file_id);
|
|
3739
|
+
} else {
|
|
3740
|
+
transform_ids.push(pi_id);
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3744
|
+
return Array.from(new Set(transform_ids));
|
|
3534
3745
|
}
|
|
3535
3746
|
require_unique_game_object(name_or_id) {
|
|
3536
3747
|
if (/^-?\d+$/.test(name_or_id)) {
|
|
@@ -3559,10 +3770,7 @@ class UnityDocument {
|
|
|
3559
3770
|
if (!block) {
|
|
3560
3771
|
return { error: `Block with fileID ${name_or_id} not found` };
|
|
3561
3772
|
}
|
|
3562
|
-
if (block.class_id === 4) {
|
|
3563
|
-
return block;
|
|
3564
|
-
}
|
|
3565
|
-
if (block.class_id === 224) {
|
|
3773
|
+
if (block.class_id === 4 || block.class_id === 224 || block.class_id === 1001 || block.class_id === 310) {
|
|
3566
3774
|
return block;
|
|
3567
3775
|
}
|
|
3568
3776
|
if (block.class_id === 1) {
|
|
@@ -3575,15 +3783,40 @@ class UnityDocument {
|
|
|
3575
3783
|
}
|
|
3576
3784
|
return { error: `Transform for GameObject fileID ${name_or_id} not found` };
|
|
3577
3785
|
}
|
|
3578
|
-
return { error: `fileID ${name_or_id} is not a GameObject or
|
|
3786
|
+
return { error: `fileID ${name_or_id} is not a GameObject, Transform, or PrefabInstance (class ${block.class_id})` };
|
|
3579
3787
|
}
|
|
3580
3788
|
const transform_ids = this.find_transforms_by_name(name_or_id);
|
|
3581
3789
|
if (transform_ids.length === 0) {
|
|
3582
|
-
return { error: `
|
|
3790
|
+
return { error: `Object "${name_or_id}" not found` };
|
|
3583
3791
|
}
|
|
3584
3792
|
if (transform_ids.length > 1) {
|
|
3585
|
-
const
|
|
3586
|
-
|
|
3793
|
+
const entity_ids = [];
|
|
3794
|
+
for (const tid of transform_ids) {
|
|
3795
|
+
const block = this.find_by_file_id(tid);
|
|
3796
|
+
if (block) {
|
|
3797
|
+
if (block.class_id === 4 || block.class_id === 224) {
|
|
3798
|
+
const go_match = block.raw.match(/m_GameObject:\s*\{fileID:\s*(-?\d+)\}/);
|
|
3799
|
+
if (go_match) {
|
|
3800
|
+
entity_ids.push(go_match[1]);
|
|
3801
|
+
} else {
|
|
3802
|
+
entity_ids.push(tid);
|
|
3803
|
+
}
|
|
3804
|
+
} else if (block.class_id === 1001 || block.class_id === 310) {
|
|
3805
|
+
entity_ids.push(tid);
|
|
3806
|
+
} else if (block.is_stripped) {
|
|
3807
|
+
const pi_match = block.raw.match(/m_PrefabInstance:\s*\{fileID:\s*(-?\d+)\}/);
|
|
3808
|
+
if (pi_match) {
|
|
3809
|
+
entity_ids.push(pi_match[1]);
|
|
3810
|
+
} else {
|
|
3811
|
+
entity_ids.push(tid);
|
|
3812
|
+
}
|
|
3813
|
+
} else {
|
|
3814
|
+
entity_ids.push(tid);
|
|
3815
|
+
}
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3818
|
+
const ids_str = Array.from(new Set(entity_ids)).join(", ");
|
|
3819
|
+
return { error: `Multiple GameObjects/PrefabInstances named "${name_or_id}" found (fileIDs: ${ids_str}). Use numeric fileID to specify which one.` };
|
|
3587
3820
|
}
|
|
3588
3821
|
const transform = this.find_by_file_id(transform_ids[0]);
|
|
3589
3822
|
if (!transform) {
|
|
@@ -3611,7 +3844,7 @@ class UnityDocument {
|
|
|
3611
3844
|
if (t_block.class_id === 4 && t_block.is_stripped) {
|
|
3612
3845
|
let name = "Variant";
|
|
3613
3846
|
for (const pi_block of this._blocks) {
|
|
3614
|
-
if (pi_block.class_id === 1001) {
|
|
3847
|
+
if (pi_block.class_id === 1001 || pi_block.class_id === 310) {
|
|
3615
3848
|
const name_mod = pi_block.raw.match(/propertyPath: m_Name\s*\n\s*value:\s*(.+)/);
|
|
3616
3849
|
if (name_mod) {
|
|
3617
3850
|
name = name_mod[1].trim();
|
|
@@ -3764,7 +3997,7 @@ class UnityDocument {
|
|
|
3764
3997
|
}
|
|
3765
3998
|
add_child_to_parent(parent_id, child_id) {
|
|
3766
3999
|
const parent = this.find_by_file_id(parent_id);
|
|
3767
|
-
if (!parent || parent.class_id !== 4)
|
|
4000
|
+
if (!parent || parent.class_id !== 4 && parent.class_id !== 224)
|
|
3768
4001
|
return false;
|
|
3769
4002
|
let raw = parent.raw;
|
|
3770
4003
|
const inline_empty = /m_Children:\s*\[\]/;
|
|
@@ -3800,7 +4033,7 @@ class UnityDocument {
|
|
|
3800
4033
|
}
|
|
3801
4034
|
remove_child_from_parent(parent_id, child_id) {
|
|
3802
4035
|
const parent = this.find_by_file_id(parent_id);
|
|
3803
|
-
if (!parent || parent.class_id !== 4)
|
|
4036
|
+
if (!parent || parent.class_id !== 4 && parent.class_id !== 224)
|
|
3804
4037
|
return false;
|
|
3805
4038
|
let raw = parent.raw;
|
|
3806
4039
|
const child_line = new RegExp(`\\n[ \\t]*- \\{fileID: ${child_id}\\}`);
|
|
@@ -3821,7 +4054,49 @@ class UnityDocument {
|
|
|
3821
4054
|
}
|
|
3822
4055
|
_collect_hierarchy_recursive(transform_id, result) {
|
|
3823
4056
|
const transform = this.find_by_file_id(transform_id);
|
|
3824
|
-
if (!transform
|
|
4057
|
+
if (!transform)
|
|
4058
|
+
return;
|
|
4059
|
+
if (transform.class_id === 1001 || transform.class_id === 310) {
|
|
4060
|
+
const pi_id = transform.file_id;
|
|
4061
|
+
const pi_ref_pattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${pi_id}\\}`);
|
|
4062
|
+
for (const block of this._blocks) {
|
|
4063
|
+
if (block.is_stripped && pi_ref_pattern.test(block.raw)) {
|
|
4064
|
+
result.add(block.file_id);
|
|
4065
|
+
if (block.class_id === 4 || block.class_id === 224) {
|
|
4066
|
+
this._collect_hierarchy_recursive(block.file_id, result);
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
const added_go_matches = transform.raw.matchAll(/addedObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)\}/g);
|
|
4071
|
+
for (const match of added_go_matches) {
|
|
4072
|
+
const added_id = match[1];
|
|
4073
|
+
if (added_id !== "0" && !result.has(added_id)) {
|
|
4074
|
+
result.add(added_id);
|
|
4075
|
+
const added_block = this.find_by_file_id(added_id);
|
|
4076
|
+
if (added_block && added_block.class_id === 1) {
|
|
4077
|
+
const comp_matches = added_block.raw.matchAll(/component:[ \t]*\{fileID:[ \t]*(-?\d+)\}/g);
|
|
4078
|
+
for (const cm of comp_matches) {
|
|
4079
|
+
const comp_block = this.find_by_file_id(cm[1]);
|
|
4080
|
+
if (comp_block && (comp_block.class_id === 4 || comp_block.class_id === 224)) {
|
|
4081
|
+
if (!result.has(cm[1])) {
|
|
4082
|
+
result.add(cm[1]);
|
|
4083
|
+
this._collect_hierarchy_recursive(cm[1], result);
|
|
4084
|
+
}
|
|
4085
|
+
break;
|
|
4086
|
+
}
|
|
4087
|
+
}
|
|
4088
|
+
}
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
const added_comp_matches = transform.raw.matchAll(/addedObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)\}/g);
|
|
4092
|
+
for (const match of added_comp_matches) {
|
|
4093
|
+
const added_id = match[1];
|
|
4094
|
+
if (added_id !== "0")
|
|
4095
|
+
result.add(added_id);
|
|
4096
|
+
}
|
|
4097
|
+
return;
|
|
4098
|
+
}
|
|
4099
|
+
if (transform.class_id !== 4 && transform.class_id !== 224)
|
|
3825
4100
|
return;
|
|
3826
4101
|
const children_section = transform.raw.match(/m_Children:[\s\S]*?(?=\s*m_Father:)/);
|
|
3827
4102
|
if (!children_section)
|
|
@@ -3856,14 +4131,21 @@ class UnityDocument {
|
|
|
3856
4131
|
if (parent_id === "0") {
|
|
3857
4132
|
let count = 0;
|
|
3858
4133
|
for (const block of this._blocks) {
|
|
3859
|
-
if (block.class_id === 4 && /m_Father:\s*\{fileID:\s*0\}/.test(block.raw)) {
|
|
4134
|
+
if ((block.class_id === 4 || block.class_id === 224) && /m_Father:\s*\{fileID:\s*0\}/.test(block.raw)) {
|
|
3860
4135
|
count++;
|
|
4136
|
+
} else if ((block.class_id === 1001 || block.class_id === 310) && /m_TransformParent:\s*\{fileID:\s*0\}/.test(block.raw)) {
|
|
4137
|
+
const pi_id = block.file_id;
|
|
4138
|
+
const pi_ref_pattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${pi_id}\\}`);
|
|
4139
|
+
const has_stripped = this._blocks.some((b) => (b.class_id === 4 || b.class_id === 224) && b.is_stripped && pi_ref_pattern.test(b.raw));
|
|
4140
|
+
if (!has_stripped) {
|
|
4141
|
+
count++;
|
|
4142
|
+
}
|
|
3861
4143
|
}
|
|
3862
4144
|
}
|
|
3863
4145
|
return count;
|
|
3864
4146
|
}
|
|
3865
4147
|
const parent = this.find_by_file_id(parent_id);
|
|
3866
|
-
if (!parent || parent.class_id !== 4)
|
|
4148
|
+
if (!parent || parent.class_id !== 4 && parent.class_id !== 224)
|
|
3867
4149
|
return 0;
|
|
3868
4150
|
const children_match = parent.raw.match(/m_Children:[\s\S]*?(?=\s*m_Father:)/);
|
|
3869
4151
|
if (children_match) {
|
|
@@ -3896,19 +4178,97 @@ ${new_children}`);
|
|
|
3896
4178
|
}
|
|
3897
4179
|
return false;
|
|
3898
4180
|
}
|
|
4181
|
+
add_root_to_scene_roots(root_id) {
|
|
4182
|
+
const pi_block = this.find_by_file_id(root_id);
|
|
4183
|
+
if (pi_block && (pi_block.class_id === 1001 || pi_block.class_id === 310)) {
|
|
4184
|
+
const pi_ref_pattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${root_id}\\}`);
|
|
4185
|
+
const stripped_root = this._blocks.find((b) => (b.class_id === 4 || b.class_id === 224) && b.is_stripped && pi_ref_pattern.test(b.raw) && /m_Father:\s*\{fileID:\s*0\}/.test(b.raw));
|
|
4186
|
+
if (stripped_root) {
|
|
4187
|
+
root_id = stripped_root.file_id;
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4190
|
+
const sr_blocks = [...this.find_by_class_id(166), ...this.find_by_class_id(1660057539)];
|
|
4191
|
+
if (sr_blocks.length === 0)
|
|
4192
|
+
return false;
|
|
4193
|
+
const sr_block = sr_blocks[0];
|
|
4194
|
+
let raw = sr_block.raw;
|
|
4195
|
+
const roots_pattern = /(m_Roots:\s*\n(?:\s*-\s*\{fileID:\s*-?\d+\}\s*\n)*)/;
|
|
4196
|
+
if (roots_pattern.test(raw)) {
|
|
4197
|
+
raw = raw.replace(roots_pattern, `$1 - {fileID: ${root_id}}
|
|
4198
|
+
`);
|
|
4199
|
+
sr_block.replace_raw(raw);
|
|
4200
|
+
return true;
|
|
4201
|
+
}
|
|
4202
|
+
const empty_roots = /m_Roots:\s*\[\]/;
|
|
4203
|
+
if (empty_roots.test(raw)) {
|
|
4204
|
+
raw = raw.replace(empty_roots, `m_Roots:
|
|
4205
|
+
- {fileID: ${root_id}}`);
|
|
4206
|
+
sr_block.replace_raw(raw);
|
|
4207
|
+
return true;
|
|
4208
|
+
}
|
|
4209
|
+
return false;
|
|
4210
|
+
}
|
|
4211
|
+
remove_root_from_scene_roots(root_id) {
|
|
4212
|
+
const pi_block = this.find_by_file_id(root_id);
|
|
4213
|
+
if (pi_block && (pi_block.class_id === 1001 || pi_block.class_id === 310)) {
|
|
4214
|
+
const pi_ref_pattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${root_id}\\}`);
|
|
4215
|
+
const stripped_root = this._blocks.find((b) => (b.class_id === 4 || b.class_id === 224) && b.is_stripped && pi_ref_pattern.test(b.raw));
|
|
4216
|
+
if (stripped_root) {
|
|
4217
|
+
this._remove_id_from_scene_roots(stripped_root.file_id);
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4220
|
+
return this._remove_id_from_scene_roots(root_id);
|
|
4221
|
+
}
|
|
4222
|
+
_remove_id_from_scene_roots(id) {
|
|
4223
|
+
const sr_blocks = [...this.find_by_class_id(166), ...this.find_by_class_id(1660057539)];
|
|
4224
|
+
if (sr_blocks.length === 0)
|
|
4225
|
+
return false;
|
|
4226
|
+
const sr_block = sr_blocks[0];
|
|
4227
|
+
let raw = sr_block.raw;
|
|
4228
|
+
const root_line = new RegExp(`\\n[ \\t]*- \\{fileID: ${id}\\}`);
|
|
4229
|
+
if (!root_line.test(raw))
|
|
4230
|
+
return false;
|
|
4231
|
+
raw = raw.replace(root_line, "");
|
|
4232
|
+
sr_block.replace_raw(raw);
|
|
4233
|
+
return true;
|
|
4234
|
+
}
|
|
3899
4235
|
reorder_entities(ordered_transform_ids) {
|
|
3900
4236
|
const entity_groups = [];
|
|
3901
4237
|
for (const transform_id of ordered_transform_ids) {
|
|
3902
|
-
const
|
|
3903
|
-
if (!
|
|
4238
|
+
const block = this.find_by_file_id(transform_id);
|
|
4239
|
+
if (!block)
|
|
3904
4240
|
continue;
|
|
3905
|
-
|
|
3906
|
-
if (
|
|
4241
|
+
let pi_block = null;
|
|
4242
|
+
if (block.class_id === 1001 || block.class_id === 310) {
|
|
4243
|
+
pi_block = block;
|
|
4244
|
+
} else if (block.is_stripped) {
|
|
4245
|
+
const pi_match = block.raw.match(/m_PrefabInstance:\s*\{fileID:\s*(-?\d+)\}/);
|
|
4246
|
+
if (pi_match) {
|
|
4247
|
+
const found = this.find_by_file_id(pi_match[1]);
|
|
4248
|
+
if (found && (found.class_id === 1001 || found.class_id === 310)) {
|
|
4249
|
+
pi_block = found;
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
}
|
|
4253
|
+
if (pi_block) {
|
|
4254
|
+
const group = [pi_block.file_id];
|
|
4255
|
+
const hierarchy = this.collect_hierarchy(pi_block.file_id);
|
|
4256
|
+
for (const id of hierarchy)
|
|
4257
|
+
group.push(id);
|
|
4258
|
+
entity_groups.push(group);
|
|
3907
4259
|
continue;
|
|
4260
|
+
}
|
|
4261
|
+
const go_match = block.raw.match(/m_GameObject:\s*\{fileID:\s*(-?\d+)\}/);
|
|
4262
|
+
if (!go_match) {
|
|
4263
|
+
entity_groups.push([transform_id]);
|
|
4264
|
+
continue;
|
|
4265
|
+
}
|
|
3908
4266
|
const go_id = go_match[1];
|
|
3909
4267
|
const go = this.find_by_file_id(go_id);
|
|
3910
|
-
if (!go)
|
|
4268
|
+
if (!go) {
|
|
4269
|
+
entity_groups.push([transform_id]);
|
|
3911
4270
|
continue;
|
|
4271
|
+
}
|
|
3912
4272
|
const comp_ids = [];
|
|
3913
4273
|
const comp_matches = go.raw.matchAll(/component:\s*\{fileID:\s*(-?\d+)\}/g);
|
|
3914
4274
|
for (const m of comp_matches) {
|
|
@@ -5435,11 +5795,8 @@ function createScriptableObject(options) {
|
|
|
5435
5795
|
if (!resolved) {
|
|
5436
5796
|
const hints = [];
|
|
5437
5797
|
if (project_path) {
|
|
5438
|
-
const cacheExists = load_guid_cache(project_path) !== null;
|
|
5439
5798
|
const registryExists = import_fs10.existsSync(path5.join(project_path, ".unity-agentic", "type-registry.json"));
|
|
5440
|
-
if (!
|
|
5441
|
-
hints.push(`No GUID cache or type registry found at ${path5.join(project_path, ".unity-agentic/")}. Run "unity-agentic-tools setup" first.`);
|
|
5442
|
-
} else if (!registryExists) {
|
|
5799
|
+
if (!registryExists) {
|
|
5443
5800
|
hints.push('Type registry not found. Re-run "unity-agentic-tools setup" to rebuild.');
|
|
5444
5801
|
}
|
|
5445
5802
|
} else {
|
|
@@ -5450,6 +5807,9 @@ function createScriptableObject(options) {
|
|
|
5450
5807
|
if (resolved.kind === "enum" || resolved.kind === "interface") {
|
|
5451
5808
|
return { success: false, output_path, error: `"${script}" is ${resolved.kind === "enum" ? "an enum" : "an interface"}, not a ScriptableObject.` };
|
|
5452
5809
|
}
|
|
5810
|
+
if (resolved.is_abstract) {
|
|
5811
|
+
return { success: false, output_path, error: `"${script}" is abstract and cannot be instantiated as a ScriptableObject asset.` };
|
|
5812
|
+
}
|
|
5453
5813
|
if (resolved.base_class && resolved.base_class !== "ScriptableObject") {
|
|
5454
5814
|
return { success: false, output_path, error: `"${script}" extends ${resolved.base_class}, not ScriptableObject. Cannot create as a ScriptableObject asset.` };
|
|
5455
5815
|
}
|
|
@@ -5732,7 +6092,39 @@ function addComponent(options) {
|
|
|
5732
6092
|
gameObjectIdStr = goResult.file_id;
|
|
5733
6093
|
}
|
|
5734
6094
|
const gameObjectId = gameObjectIdStr;
|
|
5735
|
-
const
|
|
6095
|
+
const shortComponentType = component_type.includes(".") ? component_type.slice(component_type.lastIndexOf(".") + 1) : component_type;
|
|
6096
|
+
const explicitBuiltInClassId = component_type.includes(".") ? get_addable_component_class_id(component_type) : null;
|
|
6097
|
+
const fallbackBuiltInClassId = component_type.includes(".") ? null : get_addable_component_class_id(component_type);
|
|
6098
|
+
const serializedTypeId = get_class_id(component_type) ?? get_class_id(shortComponentType);
|
|
6099
|
+
if (serializedTypeId === 114 && shortComponentType.toLowerCase() === "monobehaviour") {
|
|
6100
|
+
return {
|
|
6101
|
+
success: false,
|
|
6102
|
+
file_path,
|
|
6103
|
+
error: '"MonoBehaviour" is a base class, not a concrete component script. Provide a script type/path/GUID (for example, "PlayerController", "Assets/Scripts/PlayerController.cs", or a 32-char GUID).'
|
|
6104
|
+
};
|
|
6105
|
+
}
|
|
6106
|
+
const componentIdStr = doc.generate_file_id();
|
|
6107
|
+
const componentId = componentIdStr;
|
|
6108
|
+
let componentYAML;
|
|
6109
|
+
let scriptGuid;
|
|
6110
|
+
let scriptPath;
|
|
6111
|
+
let extractionError;
|
|
6112
|
+
let classId = explicitBuiltInClassId;
|
|
6113
|
+
let resolved = null;
|
|
6114
|
+
if (classId === null) {
|
|
6115
|
+
try {
|
|
6116
|
+
resolved = resolve_script_with_fields(component_type, project_path, { strict_exact_name: true });
|
|
6117
|
+
} catch (e) {
|
|
6118
|
+
return {
|
|
6119
|
+
success: false,
|
|
6120
|
+
file_path,
|
|
6121
|
+
error: e instanceof Error ? e.message : String(e)
|
|
6122
|
+
};
|
|
6123
|
+
}
|
|
6124
|
+
}
|
|
6125
|
+
if (!resolved && classId === null) {
|
|
6126
|
+
classId = fallbackBuiltInClassId;
|
|
6127
|
+
}
|
|
5736
6128
|
let duplicateWarning;
|
|
5737
6129
|
const goBlock = doc.find_by_file_id(gameObjectIdStr);
|
|
5738
6130
|
if (goBlock && classId !== null) {
|
|
@@ -5745,39 +6137,20 @@ function addComponent(options) {
|
|
|
5745
6137
|
}
|
|
5746
6138
|
}
|
|
5747
6139
|
}
|
|
5748
|
-
const componentIdStr = doc.generate_file_id();
|
|
5749
|
-
const componentId = componentIdStr;
|
|
5750
|
-
let componentYAML;
|
|
5751
|
-
let scriptGuid;
|
|
5752
|
-
let scriptPath;
|
|
5753
|
-
let extractionError;
|
|
5754
6140
|
if (classId !== null) {
|
|
5755
6141
|
const componentName = UNITY_CLASS_IDS[classId] || component_type;
|
|
5756
6142
|
componentYAML = createGenericComponentYAML(componentName, classId, componentId, gameObjectId);
|
|
5757
6143
|
} else {
|
|
5758
|
-
let resolved;
|
|
5759
|
-
try {
|
|
5760
|
-
resolved = resolve_script_with_fields(component_type, project_path);
|
|
5761
|
-
} catch (e) {
|
|
5762
|
-
return {
|
|
5763
|
-
success: false,
|
|
5764
|
-
file_path,
|
|
5765
|
-
error: e instanceof Error ? e.message : String(e)
|
|
5766
|
-
};
|
|
5767
|
-
}
|
|
5768
6144
|
if (!resolved) {
|
|
5769
6145
|
const hints = [];
|
|
6146
|
+
if (serializedTypeId !== null) {
|
|
6147
|
+
hints.push(`"${component_type}" matches Unity serialized type class ${serializedTypeId}, but that type is not an addable GameObject component.`);
|
|
6148
|
+
}
|
|
5770
6149
|
if (project_path) {
|
|
5771
6150
|
const agenticDir = path5.join(project_path, ".unity-agentic");
|
|
5772
|
-
const cacheExists = load_guid_cache(project_path) !== null;
|
|
5773
6151
|
const registryExists = import_fs10.existsSync(path5.join(agenticDir, "type-registry.json"));
|
|
5774
|
-
|
|
5775
|
-
if (!cacheExists && !registryExists) {
|
|
5776
|
-
hints.push(`No GUID cache or type registry found at ${agenticDir}/. Run "unity-agentic-tools setup" first.`);
|
|
5777
|
-
} else if (!registryExists) {
|
|
6152
|
+
if (!registryExists) {
|
|
5778
6153
|
hints.push('Type registry not found. Re-run "unity-agentic-tools setup" to rebuild.');
|
|
5779
|
-
} else if (!pkgCacheExists) {
|
|
5780
|
-
hints.push('Package cache not found. Re-run "unity-agentic-tools setup" to index package scripts.');
|
|
5781
6154
|
}
|
|
5782
6155
|
} else {
|
|
5783
6156
|
hints.push("No Unity project detected. Provide --project or run from inside a Unity project directory.");
|
|
@@ -5795,6 +6168,13 @@ function addComponent(options) {
|
|
|
5795
6168
|
error: `"${component_type}" is ${resolved.kind === "enum" ? "an enum" : "an interface"}, not a MonoBehaviour. Cannot add as a component.`
|
|
5796
6169
|
};
|
|
5797
6170
|
}
|
|
6171
|
+
if (resolved.is_abstract) {
|
|
6172
|
+
return {
|
|
6173
|
+
success: false,
|
|
6174
|
+
file_path,
|
|
6175
|
+
error: `"${component_type}" is abstract and cannot be added as a component.`
|
|
6176
|
+
};
|
|
6177
|
+
}
|
|
5798
6178
|
if (resolved.base_class && !COMPONENT_BASE_CLASSES.has(resolved.base_class) && !is_valid_component_base(resolved.base_class, project_path)) {
|
|
5799
6179
|
const warn = `"${component_type}" extends ${resolved.base_class}, which does not inherit from MonoBehaviour. Adding anyway, but ensure the script is a valid component. (Re-run "setup" if the inheritance graph is stale).`;
|
|
5800
6180
|
if (!extractionError)
|
|
@@ -6020,6 +6400,56 @@ function validate_value_type(current_value, new_value) {
|
|
|
6020
6400
|
}
|
|
6021
6401
|
return null;
|
|
6022
6402
|
}
|
|
6403
|
+
function findStrippedTransformForPrefabInstance(doc, prefabInstanceId) {
|
|
6404
|
+
const piRefPattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${prefabInstanceId}\\}`);
|
|
6405
|
+
for (const block of doc.blocks) {
|
|
6406
|
+
if ((block.class_id === 4 || block.class_id === 224) && block.is_stripped && piRefPattern.test(block.raw)) {
|
|
6407
|
+
return block;
|
|
6408
|
+
}
|
|
6409
|
+
}
|
|
6410
|
+
return null;
|
|
6411
|
+
}
|
|
6412
|
+
function resolvePrefabRootOrderTarget(prefabInstanceBlock) {
|
|
6413
|
+
const modificationPattern = /- target:\s*(\{[^}]+\})\s*\n\s*propertyPath:\s*('?)([^\n']+)\2/gm;
|
|
6414
|
+
const transformPropertyPattern = /^m_(?:RootOrder|LocalPosition|LocalRotation|LocalScale|ConstrainProportionsScale)(?:\.|$)/;
|
|
6415
|
+
let transformTarget = null;
|
|
6416
|
+
for (const match of prefabInstanceBlock.raw.matchAll(modificationPattern)) {
|
|
6417
|
+
const targetRef = match[1];
|
|
6418
|
+
const propertyPath = match[3].trim();
|
|
6419
|
+
if (propertyPath === "m_RootOrder") {
|
|
6420
|
+
return targetRef;
|
|
6421
|
+
}
|
|
6422
|
+
if (!transformTarget && transformPropertyPattern.test(propertyPath)) {
|
|
6423
|
+
transformTarget = targetRef;
|
|
6424
|
+
}
|
|
6425
|
+
}
|
|
6426
|
+
return transformTarget;
|
|
6427
|
+
}
|
|
6428
|
+
function upsertPrefabRootOrderOverride(prefabInstanceBlock, newRootOrder) {
|
|
6429
|
+
const existingRootOrderPattern = /(- target:\s*\{[^}]+\}\s*\n\s*propertyPath:\s*'?m_RootOrder'?\s*\n\s*value:\s*)([^\n]*)(\s*\n\s*objectReference:\s*\{[^}]+\})/m;
|
|
6430
|
+
if (existingRootOrderPattern.test(prefabInstanceBlock.raw)) {
|
|
6431
|
+
prefabInstanceBlock.replace_raw(prefabInstanceBlock.raw.replace(existingRootOrderPattern, `$1${newRootOrder}$3`));
|
|
6432
|
+
return true;
|
|
6433
|
+
}
|
|
6434
|
+
const targetRef = resolvePrefabRootOrderTarget(prefabInstanceBlock) ?? "{fileID: 400000}";
|
|
6435
|
+
const rootOrderOverride = ` - target: ${targetRef}
|
|
6436
|
+
` + ` propertyPath: m_RootOrder
|
|
6437
|
+
` + ` value: ${newRootOrder}
|
|
6438
|
+
` + " objectReference: {fileID: 0}";
|
|
6439
|
+
const removedPattern = /(\n\s*m_RemovedComponents:)/m;
|
|
6440
|
+
if (removedPattern.test(prefabInstanceBlock.raw)) {
|
|
6441
|
+
prefabInstanceBlock.replace_raw(prefabInstanceBlock.raw.replace(removedPattern, `
|
|
6442
|
+
${rootOrderOverride}$1`));
|
|
6443
|
+
return true;
|
|
6444
|
+
}
|
|
6445
|
+
const modsPattern = /(m_Modifications:\s*\n)/;
|
|
6446
|
+
if (modsPattern.test(prefabInstanceBlock.raw)) {
|
|
6447
|
+
prefabInstanceBlock.replace_raw(prefabInstanceBlock.raw.replace(modsPattern, `$1${rootOrderOverride}
|
|
6448
|
+
`));
|
|
6449
|
+
return true;
|
|
6450
|
+
}
|
|
6451
|
+
return false;
|
|
6452
|
+
}
|
|
6023
6453
|
function isAncestor(doc, childTransformId, candidateAncestorTransformId) {
|
|
6024
6454
|
let currentId = candidateAncestorTransformId;
|
|
6025
6455
|
const visited = new Set;
|
|
@@ -6030,17 +6460,34 @@ function isAncestor(doc, childTransformId, candidateAncestorTransformId) {
|
|
|
6030
6460
|
return false;
|
|
6031
6461
|
visited.add(currentId);
|
|
6032
6462
|
const block = doc.find_by_file_id(currentId);
|
|
6033
|
-
if (!block
|
|
6463
|
+
if (!block)
|
|
6034
6464
|
break;
|
|
6035
|
-
|
|
6036
|
-
|
|
6465
|
+
if (block.class_id === 1001 || block.class_id === 310) {
|
|
6466
|
+
const parentMatch = block.raw.match(/m_TransformParent:\s*\{fileID:\s*(-?\d+)\}/);
|
|
6467
|
+
currentId = parentMatch ? parentMatch[1] : "0";
|
|
6468
|
+
} else if (block.class_id === 4 || block.class_id === 224) {
|
|
6469
|
+
const fatherMatch = block.raw.match(/m_Father:\s*\{fileID:\s*(-?\d+)\}/);
|
|
6470
|
+
currentId = fatherMatch ? fatherMatch[1] : "0";
|
|
6471
|
+
} else {
|
|
6472
|
+
break;
|
|
6473
|
+
}
|
|
6037
6474
|
}
|
|
6038
6475
|
return false;
|
|
6039
6476
|
}
|
|
6040
6477
|
function resolveTransformByGameObjectId(doc, gameObjectFileId) {
|
|
6041
6478
|
const found = doc.find_by_file_id(gameObjectFileId);
|
|
6042
|
-
if (!found
|
|
6043
|
-
return { error: `
|
|
6479
|
+
if (!found) {
|
|
6480
|
+
return { error: `Block with fileID ${gameObjectFileId} not found` };
|
|
6481
|
+
}
|
|
6482
|
+
if (found.class_id === 4 || found.class_id === 224) {
|
|
6483
|
+
return { id: gameObjectFileId };
|
|
6484
|
+
}
|
|
6485
|
+
if (found.class_id === 1001 || found.class_id === 310) {
|
|
6486
|
+
const strippedTransform = findStrippedTransformForPrefabInstance(doc, gameObjectFileId);
|
|
6487
|
+
return { id: strippedTransform ? strippedTransform.file_id : gameObjectFileId };
|
|
6488
|
+
}
|
|
6489
|
+
if (found.class_id !== 1) {
|
|
6490
|
+
return { error: `fileID ${gameObjectFileId} is not a GameObject, Transform, or PrefabInstance (class ${found.class_id})` };
|
|
6044
6491
|
}
|
|
6045
6492
|
const componentMatch = found.raw.match(/m_Component:\s*\n\s*-\s*component:\s*\{fileID:\s*(-?\d+)\}/);
|
|
6046
6493
|
if (!componentMatch) {
|
|
@@ -6233,12 +6680,12 @@ function editComponentByFileId(options) {
|
|
|
6233
6680
|
}
|
|
6234
6681
|
const targetBlock = doc.find_by_file_id(file_id);
|
|
6235
6682
|
if (!targetBlock) {
|
|
6236
|
-
const hasPrefabInstance = doc.find_by_class_id(1001).length > 0;
|
|
6683
|
+
const hasPrefabInstance = doc.find_by_class_id(1001).length > 0 || doc.find_by_class_id(310).length > 0;
|
|
6237
6684
|
if (hasPrefabInstance) {
|
|
6238
6685
|
return {
|
|
6239
6686
|
success: false,
|
|
6240
6687
|
file_path,
|
|
6241
|
-
error: `Component with file ID ${file_id} not found. This file contains prefab instances \u2014 the fileID may be from the source prefab. Use \`
|
|
6688
|
+
error: `Component with file ID ${file_id} not found. This file contains prefab instances \u2014 the fileID may be from the source prefab. Use \`unity-agentic-tools editor invoke UnityAgenticTools.Update.Prefabs PrefabOverride ...\` to edit variant properties.`
|
|
6242
6689
|
};
|
|
6243
6690
|
}
|
|
6244
6691
|
return {
|
|
@@ -6251,7 +6698,7 @@ function editComponentByFileId(options) {
|
|
|
6251
6698
|
return {
|
|
6252
6699
|
success: false,
|
|
6253
6700
|
file_path,
|
|
6254
|
-
error: `Component ${file_id} is a stripped reference in a prefab variant. Use \`
|
|
6701
|
+
error: `Component ${file_id} is a stripped reference in a prefab variant. Use \`unity-agentic-tools editor invoke UnityAgenticTools.Update.Prefabs PrefabOverride ...\` to modify overrides.`
|
|
6255
6702
|
};
|
|
6256
6703
|
}
|
|
6257
6704
|
const classId = targetBlock.class_id;
|
|
@@ -6474,7 +6921,7 @@ function editTransform(options) {
|
|
|
6474
6921
|
return {
|
|
6475
6922
|
success: false,
|
|
6476
6923
|
file_path,
|
|
6477
|
-
error: `Transform ${transform_id} is a stripped reference in a prefab variant. Use \`
|
|
6924
|
+
error: `Transform ${transform_id} is a stripped reference in a prefab variant. Use \`unity-agentic-tools editor invoke UnityAgenticTools.Update.Prefabs PrefabOverride ...\` to modify transform overrides (for example, "m_LocalPosition.x").`
|
|
6478
6925
|
};
|
|
6479
6926
|
}
|
|
6480
6927
|
let blockText = targetBlock.raw;
|
|
@@ -6586,10 +7033,26 @@ function reparentGameObject(options) {
|
|
|
6586
7033
|
}
|
|
6587
7034
|
const childBlock = doc.find_by_file_id(childTransformId);
|
|
6588
7035
|
if (!childBlock) {
|
|
6589
|
-
return { success: false, file_path, error: `Transform ${childTransformId} not found` };
|
|
7036
|
+
return { success: false, file_path, error: `Transform or PrefabInstance ${childTransformId} not found` };
|
|
7037
|
+
}
|
|
7038
|
+
const childHierarchyTransformId = (() => {
|
|
7039
|
+
if (childBlock.class_id === 4 || childBlock.class_id === 224) {
|
|
7040
|
+
return childBlock.file_id;
|
|
7041
|
+
}
|
|
7042
|
+
if (childBlock.class_id === 1001 || childBlock.class_id === 310) {
|
|
7043
|
+
const stripped = findStrippedTransformForPrefabInstance(doc, childBlock.file_id);
|
|
7044
|
+
return stripped ? stripped.file_id : null;
|
|
7045
|
+
}
|
|
7046
|
+
return null;
|
|
7047
|
+
})();
|
|
7048
|
+
let oldParentTransformId = "0";
|
|
7049
|
+
if (childBlock.class_id === 1001 || childBlock.class_id === 310) {
|
|
7050
|
+
const parentMatch = childBlock.raw.match(/m_TransformParent:\s*\{fileID:\s*(-?\d+)\}/);
|
|
7051
|
+
oldParentTransformId = parentMatch ? parentMatch[1] : "0";
|
|
7052
|
+
} else {
|
|
7053
|
+
const fatherMatch = childBlock.raw.match(/m_Father:\s*\{fileID:\s*(-?\d+)\}/);
|
|
7054
|
+
oldParentTransformId = fatherMatch ? fatherMatch[1] : "0";
|
|
6590
7055
|
}
|
|
6591
|
-
const fatherMatch = childBlock.raw.match(/m_Father:\s*\{fileID:\s*(-?\d+)\}/);
|
|
6592
|
-
const oldParentTransformId = fatherMatch ? fatherMatch[1] : "0";
|
|
6593
7056
|
let newParentTransformId = "0";
|
|
6594
7057
|
if (new_parent.toLowerCase() !== "root") {
|
|
6595
7058
|
if (by_id || /^-?\d+$/.test(new_parent)) {
|
|
@@ -6616,11 +7079,55 @@ function reparentGameObject(options) {
|
|
|
6616
7079
|
}
|
|
6617
7080
|
}
|
|
6618
7081
|
if (oldParentTransformId !== "0") {
|
|
6619
|
-
|
|
7082
|
+
if (childHierarchyTransformId) {
|
|
7083
|
+
doc.remove_child_from_parent(oldParentTransformId, childHierarchyTransformId);
|
|
7084
|
+
} else {
|
|
7085
|
+
doc.remove_child_from_parent(oldParentTransformId, childBlock.file_id);
|
|
7086
|
+
}
|
|
7087
|
+
} else {
|
|
7088
|
+
if (childHierarchyTransformId) {
|
|
7089
|
+
doc.remove_root_from_scene_roots(childHierarchyTransformId);
|
|
7090
|
+
} else {
|
|
7091
|
+
doc.remove_root_from_scene_roots(childBlock.file_id);
|
|
7092
|
+
}
|
|
7093
|
+
}
|
|
7094
|
+
if (childBlock.class_id === 1001 || childBlock.class_id === 310) {
|
|
7095
|
+
const tpPattern = new RegExp(`(m_TransformParent:\\s*)\\{fileID:\\s*(-?\\d+)\\}`);
|
|
7096
|
+
if (tpPattern.test(childBlock.raw)) {
|
|
7097
|
+
let updatedChildRaw = childBlock.raw.replace(tpPattern, `$1{fileID: ${newParentTransformId}}`);
|
|
7098
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
7099
|
+
} else {
|
|
7100
|
+
const modPattern = /(m_Modification:\s*\n)/;
|
|
7101
|
+
const modIndentMatch = childBlock.raw.match(/^([ \t]*)m_Modification:/m);
|
|
7102
|
+
const indent = modIndentMatch ? modIndentMatch[1] : "";
|
|
7103
|
+
let updatedChildRaw = childBlock.raw.replace(modPattern, `$1${indent} m_TransformParent: {fileID: ${newParentTransformId}}
|
|
7104
|
+
`);
|
|
7105
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
7106
|
+
}
|
|
7107
|
+
} else {
|
|
7108
|
+
const fatherPattern = new RegExp(`(m_Father:\\s*)\\{fileID:\\s*\\d+\\}`);
|
|
7109
|
+
if (fatherPattern.test(childBlock.raw)) {
|
|
7110
|
+
let updatedChildRaw = childBlock.raw.replace(fatherPattern, `$1{fileID: ${newParentTransformId}}`);
|
|
7111
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
7112
|
+
} else {
|
|
7113
|
+
const anchorPattern = /^([ \t]*(?:m_GameObject|m_CorrespondingSourceObject|m_PrefabInstance):[ \t]*\{fileID:[ \t]*(-?\d+)[^}]*\}.*)/m;
|
|
7114
|
+
const headerPattern = /(^--- !u!(?:4|224) &-?\d+ stripped\n(?:Rect)?Transform:)/m;
|
|
7115
|
+
if (anchorPattern.test(childBlock.raw)) {
|
|
7116
|
+
let updatedChildRaw = childBlock.raw.replace(anchorPattern, `$1
|
|
7117
|
+
m_Father: {fileID: ${newParentTransformId}}`);
|
|
7118
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
7119
|
+
} else if (headerPattern.test(childBlock.raw)) {
|
|
7120
|
+
let updatedChildRaw = childBlock.raw.replace(headerPattern, `$1
|
|
7121
|
+
m_Father: {fileID: ${newParentTransformId}}`);
|
|
7122
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
7123
|
+
} else {
|
|
7124
|
+
let updatedChildRaw = childBlock.raw.trimEnd() + `
|
|
7125
|
+
m_Father: {fileID: ${newParentTransformId}}
|
|
7126
|
+
`;
|
|
7127
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
6620
7130
|
}
|
|
6621
|
-
const fatherPattern = new RegExp(`(m_Father:\\s*)\\{fileID:\\s*\\d+\\}`);
|
|
6622
|
-
let updatedChildRaw = childBlock.raw.replace(fatherPattern, `$1{fileID: ${newParentTransformId}}`);
|
|
6623
|
-
childBlock.replace_raw(updatedChildRaw);
|
|
6624
7131
|
{
|
|
6625
7132
|
let newRootOrder;
|
|
6626
7133
|
if (newParentTransformId === "0") {
|
|
@@ -6628,10 +7135,25 @@ function reparentGameObject(options) {
|
|
|
6628
7135
|
} else {
|
|
6629
7136
|
newRootOrder = doc.calculate_root_order(newParentTransformId);
|
|
6630
7137
|
}
|
|
6631
|
-
childBlock.
|
|
7138
|
+
if (childBlock.class_id === 1001 || childBlock.class_id === 310) {
|
|
7139
|
+
const stripped = doc.blocks.find((b) => (b.class_id === 4 || b.class_id === 224) && b.is_stripped && new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${childTransformId}\\}`).test(b.raw));
|
|
7140
|
+
if (stripped) {
|
|
7141
|
+
stripped.set_property("m_RootOrder", String(newRootOrder));
|
|
7142
|
+
} else {
|
|
7143
|
+
upsertPrefabRootOrderOverride(childBlock, newRootOrder);
|
|
7144
|
+
}
|
|
7145
|
+
} else {
|
|
7146
|
+
childBlock.set_property("m_RootOrder", String(newRootOrder));
|
|
7147
|
+
}
|
|
6632
7148
|
}
|
|
6633
7149
|
if (newParentTransformId !== "0") {
|
|
6634
|
-
|
|
7150
|
+
if (childHierarchyTransformId) {
|
|
7151
|
+
doc.add_child_to_parent(newParentTransformId, childHierarchyTransformId);
|
|
7152
|
+
}
|
|
7153
|
+
} else {
|
|
7154
|
+
if (childHierarchyTransformId) {
|
|
7155
|
+
doc.add_root_to_scene_roots(childHierarchyTransformId);
|
|
7156
|
+
}
|
|
6635
7157
|
}
|
|
6636
7158
|
if (!doc.validate()) {
|
|
6637
7159
|
return { success: false, file_path, error: "Validation failed after reparent" };
|
|
@@ -6650,9 +7172,9 @@ function reparentGameObject(options) {
|
|
|
6650
7172
|
}
|
|
6651
7173
|
function findPrefabInstanceBlock(doc, identifier) {
|
|
6652
7174
|
const asId = doc.find_by_file_id(identifier);
|
|
6653
|
-
if (asId && asId.class_id === 1001)
|
|
7175
|
+
if (asId && (asId.class_id === 1001 || asId.class_id === 310))
|
|
6654
7176
|
return asId;
|
|
6655
|
-
const piBlocks = doc.find_by_class_id(1001);
|
|
7177
|
+
const piBlocks = [...doc.find_by_class_id(1001), ...doc.find_by_class_id(310)];
|
|
6656
7178
|
const escaped = identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6657
7179
|
const namePattern = new RegExp(`propertyPath:\\s*m_Name\\s+value:\\s*${escaped}\\s`);
|
|
6658
7180
|
for (const block of piBlocks) {
|
|
@@ -7222,29 +7744,32 @@ function find_component_by_type(doc, type_name, game_object, project_path) {
|
|
|
7222
7744
|
scope_blocks = doc.blocks.filter((b) => b.class_id !== 1 && b.class_id !== 4 && b.class_id !== 224);
|
|
7223
7745
|
}
|
|
7224
7746
|
const candidates = [];
|
|
7225
|
-
const
|
|
7747
|
+
const explicit_class_id = type_name.includes(".") ? get_component_class_id(type_name) : null;
|
|
7748
|
+
let resolved = null;
|
|
7749
|
+
if (explicit_class_id === null) {
|
|
7750
|
+
try {
|
|
7751
|
+
resolved = resolveScriptGuid(type_name, project_path, { strict_exact_name: true });
|
|
7752
|
+
} catch (error) {
|
|
7753
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
7754
|
+
}
|
|
7755
|
+
}
|
|
7756
|
+
const class_id = resolved ? null : explicit_class_id ?? (!type_name.includes(".") ? get_component_class_id(type_name) : null);
|
|
7226
7757
|
if (class_id !== null) {
|
|
7227
7758
|
for (const block of scope_blocks) {
|
|
7228
7759
|
if (block.class_id === class_id)
|
|
7229
7760
|
candidates.push(block);
|
|
7230
7761
|
}
|
|
7231
|
-
} else {
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
if (block.class_id !== 114)
|
|
7239
|
-
continue;
|
|
7240
|
-
const scriptMatch = block.raw.match(/m_Script:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]+)/);
|
|
7241
|
-
if (scriptMatch && scriptMatch[1] === resolved.guid) {
|
|
7242
|
-
candidates.push(block);
|
|
7243
|
-
}
|
|
7762
|
+
} else if (resolved) {
|
|
7763
|
+
for (const block of scope_blocks) {
|
|
7764
|
+
if (block.class_id !== 114)
|
|
7765
|
+
continue;
|
|
7766
|
+
const scriptMatch = block.raw.match(/m_Script:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]+)/);
|
|
7767
|
+
if (scriptMatch && scriptMatch[1] === resolved.guid) {
|
|
7768
|
+
candidates.push(block);
|
|
7244
7769
|
}
|
|
7245
|
-
} else {
|
|
7246
|
-
return { error: `Component type "${type_name}" not found. For MonoBehaviour scripts, ensure "unity-agentic-tools setup" has been run.` };
|
|
7247
7770
|
}
|
|
7771
|
+
} else {
|
|
7772
|
+
return { error: `Component type "${type_name}" not found. For MonoBehaviour scripts, ensure the type registry has been built with "unity-agentic-tools setup".` };
|
|
7248
7773
|
}
|
|
7249
7774
|
if (candidates.length === 0) {
|
|
7250
7775
|
return { error: `No "${type_name}" component found${game_object ? ` on "${game_object}"` : ""} in ${doc.file_path}` };
|
|
@@ -7675,7 +8200,7 @@ function duplicateGameObject(options) {
|
|
|
7675
8200
|
if ("error" in goResult) {
|
|
7676
8201
|
const piMatch = findPrefabInstanceByName(doc, object_name);
|
|
7677
8202
|
if (piMatch) {
|
|
7678
|
-
return { success: false, file_path, error: `"${object_name}" is a PrefabInstance (fileID: ${piMatch.id}). Cloning PrefabInstances is not yet supported. Consider unpacking it first with \`
|
|
8203
|
+
return { success: false, file_path, error: `"${object_name}" is a PrefabInstance (fileID: ${piMatch.id}). Cloning PrefabInstances is not yet supported. Consider unpacking it first with \`unity-agentic-tools editor invoke UnityAgenticTools.Update.Prefabs PrefabUnpack ...\`.` };
|
|
7679
8204
|
}
|
|
7680
8205
|
return { success: false, file_path, error: goResult.error };
|
|
7681
8206
|
}
|