unity-agentic-tools 0.3.1 → 0.3.2
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 +1 -1
- package/dist/cli.js +1444 -282
- package/dist/index.js +570 -74
- package/native/index.d.ts +10 -1
- package/native/index.js +2 -1
- 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 +1 -1
package/dist/index.js
CHANGED
|
@@ -76,6 +76,7 @@ __export(exports_scanner, {
|
|
|
76
76
|
getNativeExtractCsharpTypes: () => getNativeExtractCsharpTypes,
|
|
77
77
|
getNativeBuildTypeRegistry: () => getNativeBuildTypeRegistry,
|
|
78
78
|
getNativeBuildPackageGuidCache: () => getNativeBuildPackageGuidCache,
|
|
79
|
+
getNativeBuildLocalPackageGuidCache: () => getNativeBuildLocalPackageGuidCache,
|
|
79
80
|
getNativeBuildGuidCache: () => getNativeBuildGuidCache,
|
|
80
81
|
UnityScanner: () => UnityScanner
|
|
81
82
|
});
|
|
@@ -156,13 +157,16 @@ function getNativeExtractDllTypes() {
|
|
|
156
157
|
function getNativeBuildPackageGuidCache() {
|
|
157
158
|
return nativeBuildPackageGuidCache;
|
|
158
159
|
}
|
|
160
|
+
function getNativeBuildLocalPackageGuidCache() {
|
|
161
|
+
return nativeBuildLocalPackageGuidCache;
|
|
162
|
+
}
|
|
159
163
|
function getNativeExtractSerializedFields() {
|
|
160
164
|
return nativeExtractSerializedFields;
|
|
161
165
|
}
|
|
162
166
|
function getNativeExtractDllFields() {
|
|
163
167
|
return nativeExtractDllFields;
|
|
164
168
|
}
|
|
165
|
-
var import_module, import_fs, import_path, __dirname = "/home/runner/work/unity-agentic-tools/unity-agentic-tools/unity-agentic-tools/src", RustScanner = null, nativeModuleError = null, nativeWalkProjectFiles = null, nativeGrepProject = null, nativeBuildGuidCache = null, nativeExtractCsharpTypes = null, nativeBuildTypeRegistry = null, nativeExtractDllTypes = null, nativeBuildPackageGuidCache = null, nativeExtractSerializedFields = null, nativeExtractDllFields = null;
|
|
169
|
+
var import_module, import_fs, import_path, __dirname = "/home/runner/work/unity-agentic-tools/unity-agentic-tools/unity-agentic-tools/src", RustScanner = null, nativeModuleError = null, nativeWalkProjectFiles = null, nativeGrepProject = null, nativeBuildGuidCache = null, nativeExtractCsharpTypes = null, nativeBuildTypeRegistry = null, nativeExtractDllTypes = null, nativeBuildPackageGuidCache = null, nativeBuildLocalPackageGuidCache = null, nativeExtractSerializedFields = null, nativeExtractDllFields = null;
|
|
166
170
|
var init_scanner = __esm(() => {
|
|
167
171
|
import_module = require("module");
|
|
168
172
|
import_fs = require("fs");
|
|
@@ -186,6 +190,7 @@ var init_scanner = __esm(() => {
|
|
|
186
190
|
nativeBuildTypeRegistry = rustModule.buildTypeRegistry || null;
|
|
187
191
|
nativeExtractDllTypes = rustModule.extractDllTypes || null;
|
|
188
192
|
nativeBuildPackageGuidCache = rustModule.buildPackageGuidCache || null;
|
|
193
|
+
nativeBuildLocalPackageGuidCache = rustModule.buildLocalPackageGuidCache || null;
|
|
189
194
|
nativeExtractSerializedFields = rustModule.extractSerializedFields || null;
|
|
190
195
|
nativeExtractDllFields = rustModule.extractDllFields || null;
|
|
191
196
|
} catch (err) {
|
|
@@ -200,7 +205,7 @@ var require_package = __commonJS((exports2, module2) => {
|
|
|
200
205
|
module2.exports = {
|
|
201
206
|
name: "unity-agentic-tools",
|
|
202
207
|
packageManager: "bun@latest",
|
|
203
|
-
version: "0.3.
|
|
208
|
+
version: "0.3.2",
|
|
204
209
|
description: "Fast, token-efficient Unity YAML parser for AI agents",
|
|
205
210
|
exports: {
|
|
206
211
|
".": {
|
|
@@ -330,6 +335,7 @@ var CONFIG_DIR = ".unity-agentic";
|
|
|
330
335
|
var CONFIG_FILE = "config.json";
|
|
331
336
|
var GUID_CACHE_FILE = "guid-cache.json";
|
|
332
337
|
var PACKAGE_CACHE_FILE = "package-cache.json";
|
|
338
|
+
var LOCAL_PACKAGE_CACHE_FILE = "local-package-cache.json";
|
|
333
339
|
var TYPE_REGISTRY_FILE = "type-registry.json";
|
|
334
340
|
var DOC_INDEX_FILE = "doc-index.json";
|
|
335
341
|
function setup(options = {}) {
|
|
@@ -373,6 +379,17 @@ function setup(options = {}) {
|
|
|
373
379
|
packageGuidCount = Object.keys(packageCache).length;
|
|
374
380
|
} catch {}
|
|
375
381
|
}
|
|
382
|
+
const nativeLocalPkgBuild = getNativeBuildLocalPackageGuidCache();
|
|
383
|
+
if (nativeLocalPkgBuild) {
|
|
384
|
+
try {
|
|
385
|
+
const localPkgCache = nativeLocalPkgBuild(projectPath);
|
|
386
|
+
const localPkgCount = Object.keys(localPkgCache).length;
|
|
387
|
+
if (localPkgCount > 0) {
|
|
388
|
+
const localPkgCachePath = import_path2.join(configPath, LOCAL_PACKAGE_CACHE_FILE);
|
|
389
|
+
import_fs2.writeFileSync(localPkgCachePath, JSON.stringify(localPkgCache, null, 2));
|
|
390
|
+
}
|
|
391
|
+
} catch {}
|
|
392
|
+
}
|
|
376
393
|
let typeRegistryCreated = false;
|
|
377
394
|
let typeCount;
|
|
378
395
|
const nativeRegistryBuild = getNativeBuildTypeRegistry();
|
|
@@ -555,31 +572,44 @@ function atomicWrite(filePath, content) {
|
|
|
555
572
|
};
|
|
556
573
|
}
|
|
557
574
|
}
|
|
558
|
-
const
|
|
575
|
+
const suffix = `${process.pid}-${Math.random().toString(36).slice(2, 8)}`;
|
|
576
|
+
const tmpPath = `${filePath}.${suffix}.tmp`;
|
|
577
|
+
const bakPath = `${filePath}.${suffix}.bak`;
|
|
578
|
+
let bakCreated = false;
|
|
559
579
|
try {
|
|
560
580
|
import_fs4.writeFileSync(tmpPath, content, "utf-8");
|
|
561
|
-
if (import_fs4.existsSync(filePath)) {
|
|
562
|
-
import_fs4.renameSync(filePath, `${filePath}.bak`);
|
|
563
|
-
}
|
|
564
|
-
import_fs4.renameSync(tmpPath, filePath);
|
|
565
581
|
try {
|
|
566
|
-
|
|
567
|
-
|
|
582
|
+
import_fs4.renameSync(filePath, bakPath);
|
|
583
|
+
bakCreated = true;
|
|
584
|
+
} catch (err) {
|
|
585
|
+
if (is_enoent(err)) {
|
|
586
|
+
bakCreated = false;
|
|
587
|
+
} else {
|
|
588
|
+
throw err;
|
|
568
589
|
}
|
|
569
|
-
}
|
|
590
|
+
}
|
|
591
|
+
import_fs4.renameSync(tmpPath, filePath);
|
|
592
|
+
if (bakCreated) {
|
|
593
|
+
try {
|
|
594
|
+
import_fs4.unlinkSync(bakPath);
|
|
595
|
+
} catch {}
|
|
596
|
+
}
|
|
570
597
|
return {
|
|
571
598
|
success: true,
|
|
572
599
|
file_path: filePath,
|
|
573
600
|
bytes_written: Buffer.byteLength(content, "utf-8")
|
|
574
601
|
};
|
|
575
602
|
} catch (error) {
|
|
576
|
-
if (
|
|
603
|
+
if (bakCreated) {
|
|
577
604
|
try {
|
|
578
|
-
import_fs4.renameSync(
|
|
605
|
+
import_fs4.renameSync(bakPath, filePath);
|
|
579
606
|
} catch (restoreError) {
|
|
580
607
|
console.error("Failed to restore backup:", restoreError);
|
|
581
608
|
}
|
|
582
609
|
}
|
|
610
|
+
try {
|
|
611
|
+
import_fs4.unlinkSync(tmpPath);
|
|
612
|
+
} catch {}
|
|
583
613
|
return {
|
|
584
614
|
success: false,
|
|
585
615
|
file_path: filePath,
|
|
@@ -587,6 +617,12 @@ function atomicWrite(filePath, content) {
|
|
|
587
617
|
};
|
|
588
618
|
}
|
|
589
619
|
}
|
|
620
|
+
function is_enoent(err) {
|
|
621
|
+
return err instanceof Error && "code" in err && err.code === "ENOENT";
|
|
622
|
+
}
|
|
623
|
+
function normalize_property_path(path) {
|
|
624
|
+
return path.replace(/\.Array\.data\.(\d+)/g, ".Array.data[$1]");
|
|
625
|
+
}
|
|
590
626
|
function is_match_all(pattern) {
|
|
591
627
|
return pattern === "*" || pattern === "." || pattern === "**" || pattern === ".*";
|
|
592
628
|
}
|
|
@@ -2076,6 +2112,31 @@ function extractGuidFromMeta(metaPath) {
|
|
|
2076
2112
|
return null;
|
|
2077
2113
|
}
|
|
2078
2114
|
}
|
|
2115
|
+
function resolve_source_prefab(doc, file_path, project_path) {
|
|
2116
|
+
const pi_blocks = doc.find_by_class_id(1001);
|
|
2117
|
+
if (pi_blocks.length === 0)
|
|
2118
|
+
return null;
|
|
2119
|
+
const pi_block = pi_blocks[0];
|
|
2120
|
+
const source_match = pi_block.raw.match(/m_SourcePrefab:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]{32})/);
|
|
2121
|
+
if (!source_match)
|
|
2122
|
+
return null;
|
|
2123
|
+
const source_guid = source_match[1];
|
|
2124
|
+
const resolved_project = project_path || find_unity_project_root(path3.dirname(file_path));
|
|
2125
|
+
if (!resolved_project)
|
|
2126
|
+
return null;
|
|
2127
|
+
const cache = load_guid_cache_for_file(file_path, resolved_project);
|
|
2128
|
+
if (!cache)
|
|
2129
|
+
return null;
|
|
2130
|
+
const source_path = cache.resolve_absolute(source_guid);
|
|
2131
|
+
if (!source_path || !import_fs8.existsSync(source_path))
|
|
2132
|
+
return null;
|
|
2133
|
+
return {
|
|
2134
|
+
source_guid,
|
|
2135
|
+
source_path,
|
|
2136
|
+
prefab_instance_id: pi_block.file_id,
|
|
2137
|
+
prefab_instance_block: pi_block
|
|
2138
|
+
};
|
|
2139
|
+
}
|
|
2079
2140
|
function resolveScriptGuid(script, projectPath) {
|
|
2080
2141
|
if (/^[a-f0-9]{32}$/i.test(script)) {
|
|
2081
2142
|
return { guid: script.toLowerCase(), path: null };
|
|
@@ -2125,27 +2186,122 @@ function resolveScriptGuid(script, projectPath) {
|
|
|
2125
2186
|
return false;
|
|
2126
2187
|
return true;
|
|
2127
2188
|
});
|
|
2128
|
-
if (matches.length === 1
|
|
2129
|
-
|
|
2189
|
+
if (matches.length === 1) {
|
|
2190
|
+
if (matches[0].guid) {
|
|
2191
|
+
return { guid: matches[0].guid, path: matches[0].filePath };
|
|
2192
|
+
}
|
|
2193
|
+
if (matches[0].filePath && projectPath) {
|
|
2194
|
+
const fullFilePath = path3.isAbsolute(matches[0].filePath) ? matches[0].filePath : path3.join(projectPath, matches[0].filePath);
|
|
2195
|
+
const metaPath = fullFilePath + ".meta";
|
|
2196
|
+
if (import_fs8.existsSync(metaPath)) {
|
|
2197
|
+
const guid = extractGuidFromMeta(metaPath);
|
|
2198
|
+
if (guid)
|
|
2199
|
+
return { guid, path: matches[0].filePath };
|
|
2200
|
+
}
|
|
2201
|
+
if (matches[0].filePath.startsWith("Packages/")) {
|
|
2202
|
+
const pkgPath = path3.join(projectPath, matches[0].filePath);
|
|
2203
|
+
const pkgMetaPath = pkgPath + ".meta";
|
|
2204
|
+
if (import_fs8.existsSync(pkgMetaPath)) {
|
|
2205
|
+
const guid = extractGuidFromMeta(pkgMetaPath);
|
|
2206
|
+
if (guid)
|
|
2207
|
+
return { guid, path: matches[0].filePath };
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
if (matches[0].filePath?.endsWith(".dll")) {
|
|
2211
|
+
const dllBasename = path3.basename(matches[0].filePath).toLowerCase();
|
|
2212
|
+
for (const cacheName of ["package-cache.json", "local-package-cache.json"]) {
|
|
2213
|
+
const cachePath = path3.join(projectPath, ".unity-agentic", cacheName);
|
|
2214
|
+
if (!import_fs8.existsSync(cachePath))
|
|
2215
|
+
continue;
|
|
2216
|
+
try {
|
|
2217
|
+
const cache = JSON.parse(import_fs8.readFileSync(cachePath, "utf-8"));
|
|
2218
|
+
for (const [guid, assetPath] of Object.entries(cache)) {
|
|
2219
|
+
if (assetPath.toLowerCase().endsWith(".dll") && path3.basename(assetPath).toLowerCase() === dllBasename) {
|
|
2220
|
+
return { guid, path: assetPath };
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
} catch {}
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2130
2227
|
}
|
|
2131
2228
|
if (matches.length > 1) {
|
|
2132
2229
|
const withGuid = matches.filter((m) => m.guid);
|
|
2133
2230
|
if (withGuid.length === 1) {
|
|
2134
2231
|
return { guid: withGuid[0].guid, path: withGuid[0].filePath };
|
|
2135
2232
|
}
|
|
2233
|
+
const resolvedFromMeta = matches.filter((m) => !m.guid && m.filePath).map((m) => {
|
|
2234
|
+
const fullPath = path3.isAbsolute(m.filePath) ? m.filePath : path3.join(projectPath, m.filePath);
|
|
2235
|
+
let guid = import_fs8.existsSync(fullPath + ".meta") ? extractGuidFromMeta(fullPath + ".meta") : null;
|
|
2236
|
+
if (!guid && m.filePath.startsWith("Packages/")) {
|
|
2237
|
+
const pkgPath = path3.join(projectPath, m.filePath);
|
|
2238
|
+
if (import_fs8.existsSync(pkgPath + ".meta")) {
|
|
2239
|
+
guid = extractGuidFromMeta(pkgPath + ".meta");
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
if (!guid && m.filePath?.endsWith(".dll")) {
|
|
2243
|
+
const dllBase = path3.basename(m.filePath).toLowerCase();
|
|
2244
|
+
for (const cn of ["package-cache.json", "local-package-cache.json"]) {
|
|
2245
|
+
const cp = path3.join(projectPath, ".unity-agentic", cn);
|
|
2246
|
+
if (!import_fs8.existsSync(cp))
|
|
2247
|
+
continue;
|
|
2248
|
+
try {
|
|
2249
|
+
const c = JSON.parse(import_fs8.readFileSync(cp, "utf-8"));
|
|
2250
|
+
for (const [g, p] of Object.entries(c)) {
|
|
2251
|
+
if (p.toLowerCase().endsWith(".dll") && path3.basename(p).toLowerCase() === dllBase) {
|
|
2252
|
+
guid = g;
|
|
2253
|
+
break;
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
} catch {}
|
|
2257
|
+
if (guid)
|
|
2258
|
+
break;
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
return guid ? { guid, path: m.filePath } : null;
|
|
2262
|
+
}).filter((r) => r !== null);
|
|
2263
|
+
const allResolved = [...withGuid.map((m) => ({ guid: m.guid, path: m.filePath })), ...resolvedFromMeta];
|
|
2264
|
+
if (allResolved.length === 1) {
|
|
2265
|
+
return allResolved[0];
|
|
2266
|
+
}
|
|
2267
|
+
if (allResolved.length > 1) {
|
|
2268
|
+
const pkgCachePaths = [
|
|
2269
|
+
path3.join(projectPath, ".unity-agentic", "package-cache.json"),
|
|
2270
|
+
path3.join(projectPath, ".unity-agentic", "local-package-cache.json")
|
|
2271
|
+
];
|
|
2272
|
+
for (const cachePath of pkgCachePaths) {
|
|
2273
|
+
if (!import_fs8.existsSync(cachePath))
|
|
2274
|
+
continue;
|
|
2275
|
+
try {
|
|
2276
|
+
const cache = JSON.parse(import_fs8.readFileSync(cachePath, "utf-8"));
|
|
2277
|
+
const inCache = allResolved.filter((r) => (r.guid in cache));
|
|
2278
|
+
if (inCache.length === 1)
|
|
2279
|
+
return inCache[0];
|
|
2280
|
+
} catch {}
|
|
2281
|
+
}
|
|
2282
|
+
const paths = allResolved.map((m) => m.path).join(", ");
|
|
2283
|
+
throw new Error(`Ambiguous type "${script}": found ${allResolved.length} matches (${paths}). ` + `Use a qualified name (e.g., "Namespace.${targetName}") or provide the full path.`);
|
|
2284
|
+
}
|
|
2136
2285
|
}
|
|
2137
2286
|
} catch {}
|
|
2138
2287
|
}
|
|
2139
|
-
const
|
|
2140
|
-
|
|
2288
|
+
const scriptNameLower = script.toLowerCase().replace(/\.cs$/, "");
|
|
2289
|
+
const dotIdx = scriptNameLower.lastIndexOf(".");
|
|
2290
|
+
const classNameOnly = dotIdx > 0 ? scriptNameLower.substring(dotIdx + 1) : null;
|
|
2291
|
+
const cachePaths = [
|
|
2292
|
+
path3.join(projectPath, ".unity-agentic", "package-cache.json"),
|
|
2293
|
+
path3.join(projectPath, ".unity-agentic", "local-package-cache.json")
|
|
2294
|
+
];
|
|
2295
|
+
for (const cachePath of cachePaths) {
|
|
2296
|
+
if (!import_fs8.existsSync(cachePath))
|
|
2297
|
+
continue;
|
|
2141
2298
|
try {
|
|
2142
|
-
const
|
|
2143
|
-
const
|
|
2144
|
-
for (const [guid, assetPath] of Object.entries(packageCache)) {
|
|
2299
|
+
const cache = JSON.parse(import_fs8.readFileSync(cachePath, "utf-8"));
|
|
2300
|
+
for (const [guid, assetPath] of Object.entries(cache)) {
|
|
2145
2301
|
if (!assetPath.endsWith(".cs"))
|
|
2146
2302
|
continue;
|
|
2147
2303
|
const fileName = path3.basename(assetPath, ".cs").toLowerCase();
|
|
2148
|
-
if (fileName === scriptNameLower) {
|
|
2304
|
+
if (fileName === scriptNameLower || classNameOnly && fileName === classNameOnly) {
|
|
2149
2305
|
return { guid, path: assetPath };
|
|
2150
2306
|
}
|
|
2151
2307
|
}
|
|
@@ -2196,6 +2352,8 @@ function resolve_script_with_fields(script, project_path) {
|
|
|
2196
2352
|
result.fields = chosen.fields;
|
|
2197
2353
|
result.base_class = chosen.baseClass ?? undefined;
|
|
2198
2354
|
result.kind = chosen.kind;
|
|
2355
|
+
result.namespace = chosen.namespace ?? undefined;
|
|
2356
|
+
result.class_name = chosen.name;
|
|
2199
2357
|
}
|
|
2200
2358
|
} else {
|
|
2201
2359
|
result.extraction_error = "Native extractDllFields function not available";
|
|
@@ -2391,6 +2549,16 @@ function yaml_default_for_type(csharp_type, version) {
|
|
|
2391
2549
|
function generate_field_yaml(fields, version, indent = " ") {
|
|
2392
2550
|
const lines = [];
|
|
2393
2551
|
for (const field of fields) {
|
|
2552
|
+
if (field.hasSerializeReference) {
|
|
2553
|
+
const t = field.typeName;
|
|
2554
|
+
if (t.endsWith("[]") || t.startsWith("List<") && t.endsWith(">")) {
|
|
2555
|
+
lines.push(`${indent}${field.name}: []`);
|
|
2556
|
+
} else {
|
|
2557
|
+
lines.push(`${indent}${field.name}:`);
|
|
2558
|
+
lines.push(`${indent} rid: 0`);
|
|
2559
|
+
}
|
|
2560
|
+
continue;
|
|
2561
|
+
}
|
|
2394
2562
|
const default_value = yaml_default_for_type(field.typeName, version);
|
|
2395
2563
|
if (default_value === null) {
|
|
2396
2564
|
continue;
|
|
@@ -2434,6 +2602,17 @@ function parse_header(raw) {
|
|
|
2434
2602
|
function escape_regex(str) {
|
|
2435
2603
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2436
2604
|
}
|
|
2605
|
+
function yaml_quote_if_needed(value) {
|
|
2606
|
+
if (value === "")
|
|
2607
|
+
return value;
|
|
2608
|
+
if (value.startsWith("{") && value.endsWith("}") || value.startsWith("[") && value.endsWith("]")) {
|
|
2609
|
+
return value;
|
|
2610
|
+
}
|
|
2611
|
+
if (value.includes(": ") || value.includes(" #") || /^[#\{\[*&!|>'"]/.test(value) || value !== value.trim()) {
|
|
2612
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
2613
|
+
}
|
|
2614
|
+
return value;
|
|
2615
|
+
}
|
|
2437
2616
|
|
|
2438
2617
|
class UnityBlock {
|
|
2439
2618
|
_raw;
|
|
@@ -2469,6 +2648,7 @@ class UnityBlock {
|
|
|
2469
2648
|
return this._dirty;
|
|
2470
2649
|
}
|
|
2471
2650
|
get_property(path4) {
|
|
2651
|
+
path4 = normalize_property_path(path4);
|
|
2472
2652
|
if (path4.includes("Array.data[")) {
|
|
2473
2653
|
return this._get_array_element(path4);
|
|
2474
2654
|
}
|
|
@@ -2495,13 +2675,17 @@ class UnityBlock {
|
|
|
2495
2675
|
return match ? match[1].trim() : null;
|
|
2496
2676
|
}
|
|
2497
2677
|
set_property(path4, value, object_reference) {
|
|
2678
|
+
path4 = normalize_property_path(path4);
|
|
2498
2679
|
const old_raw = this._raw;
|
|
2499
2680
|
const effective_ref = object_reference && object_reference !== "{fileID: 0}" ? object_reference : undefined;
|
|
2500
2681
|
if (!path4.includes(".") && !path4.includes("Array")) {
|
|
2501
2682
|
const prop_pattern = new RegExp(`(^\\s*${escape_regex(path4)}:\\s*)(.*)$`, "m");
|
|
2502
2683
|
if (prop_pattern.test(this._raw)) {
|
|
2503
|
-
const replacement_value = effective_ref ?? value;
|
|
2504
|
-
this._raw = this._raw.replace(prop_pattern,
|
|
2684
|
+
const replacement_value = effective_ref ?? yaml_quote_if_needed(value);
|
|
2685
|
+
this._raw = this._raw.replace(prop_pattern, (_match, prefix) => prefix + replacement_value);
|
|
2686
|
+
} else {
|
|
2687
|
+
const insert_value = effective_ref ?? yaml_quote_if_needed(value);
|
|
2688
|
+
this._insert_property(path4, insert_value);
|
|
2505
2689
|
}
|
|
2506
2690
|
return this._check_dirty(old_raw);
|
|
2507
2691
|
}
|
|
@@ -2516,8 +2700,8 @@ class UnityBlock {
|
|
|
2516
2700
|
const fields = inline_match[2];
|
|
2517
2701
|
const field_pattern = new RegExp(`(${escape_regex(sub_field)}:\\s*)([^,}]+)`);
|
|
2518
2702
|
if (field_pattern.test(fields)) {
|
|
2519
|
-
const updated_fields = fields.replace(field_pattern,
|
|
2520
|
-
this._raw = this._raw.replace(inline_pattern,
|
|
2703
|
+
const updated_fields = fields.replace(field_pattern, (_m, prefix) => prefix + value);
|
|
2704
|
+
this._raw = this._raw.replace(inline_pattern, (_m, g1, _g2, g3) => g1 + updated_fields + g3);
|
|
2521
2705
|
inline_applied = true;
|
|
2522
2706
|
}
|
|
2523
2707
|
}
|
|
@@ -2526,6 +2710,8 @@ class UnityBlock {
|
|
|
2526
2710
|
const block_result = this._resolve_block_style_path(parts, effective_value);
|
|
2527
2711
|
if (block_result !== null) {
|
|
2528
2712
|
this._raw = block_result;
|
|
2713
|
+
} else if (parts.length === 2) {
|
|
2714
|
+
this._insert_struct_property(parent_prop, sub_field, effective_value);
|
|
2529
2715
|
}
|
|
2530
2716
|
}
|
|
2531
2717
|
return this._check_dirty(old_raw);
|
|
@@ -2543,7 +2729,7 @@ class UnityBlock {
|
|
|
2543
2729
|
`).filter((l) => l.trim().startsWith("-"));
|
|
2544
2730
|
if (index < lines.length) {
|
|
2545
2731
|
const old_line = lines[index];
|
|
2546
|
-
const new_line = old_line.replace(/-\s*.*/, `- ${ref_value}`);
|
|
2732
|
+
const new_line = old_line.replace(/-\s*.*/, () => `- ${ref_value}`);
|
|
2547
2733
|
this._raw = this._raw.replace(old_line, new_line);
|
|
2548
2734
|
}
|
|
2549
2735
|
}
|
|
@@ -2552,6 +2738,44 @@ class UnityBlock {
|
|
|
2552
2738
|
}
|
|
2553
2739
|
return false;
|
|
2554
2740
|
}
|
|
2741
|
+
_insert_property(path4, value) {
|
|
2742
|
+
const alt = path4.startsWith("m_") ? path4.slice(2) : "m_" + path4;
|
|
2743
|
+
const alt_pattern = new RegExp(`^\\s*${escape_regex(alt)}:`, "m");
|
|
2744
|
+
if (alt_pattern.test(this._raw)) {
|
|
2745
|
+
return;
|
|
2746
|
+
}
|
|
2747
|
+
const indented_line = ` ${path4}: ${value}`;
|
|
2748
|
+
const eci_pattern = /^([ \t]*m_EditorClassIdentifier:[ \t]*[^\n]*)/m;
|
|
2749
|
+
const eci_match = this._raw.match(eci_pattern);
|
|
2750
|
+
if (eci_match && eci_match.index !== undefined) {
|
|
2751
|
+
const insert_after = eci_match.index + eci_match[0].length;
|
|
2752
|
+
this._raw = this._raw.slice(0, insert_after) + `
|
|
2753
|
+
` + indented_line + this._raw.slice(insert_after);
|
|
2754
|
+
return;
|
|
2755
|
+
}
|
|
2756
|
+
this._raw = this._raw.trimEnd() + `
|
|
2757
|
+
` + indented_line + `
|
|
2758
|
+
`;
|
|
2759
|
+
}
|
|
2760
|
+
_insert_struct_property(parent, child, value) {
|
|
2761
|
+
const parent_pattern = new RegExp(`^[ ]*${escape_regex(parent)}:`, "m");
|
|
2762
|
+
if (parent_pattern.test(this._raw)) {
|
|
2763
|
+
return;
|
|
2764
|
+
}
|
|
2765
|
+
const struct_block = ` ${parent}:
|
|
2766
|
+
${child}: ${value}`;
|
|
2767
|
+
const eci_pattern = /^([ \t]*m_EditorClassIdentifier:[ \t]*[^\n]*)/m;
|
|
2768
|
+
const eci_match = this._raw.match(eci_pattern);
|
|
2769
|
+
if (eci_match && eci_match.index !== undefined) {
|
|
2770
|
+
const insert_after = eci_match.index + eci_match[0].length;
|
|
2771
|
+
this._raw = this._raw.slice(0, insert_after) + `
|
|
2772
|
+
` + struct_block + this._raw.slice(insert_after);
|
|
2773
|
+
return;
|
|
2774
|
+
}
|
|
2775
|
+
this._raw = this._raw.trimEnd() + `
|
|
2776
|
+
` + struct_block + `
|
|
2777
|
+
`;
|
|
2778
|
+
}
|
|
2555
2779
|
has_property(path4) {
|
|
2556
2780
|
return this.get_property(path4) !== null;
|
|
2557
2781
|
}
|
|
@@ -2607,7 +2831,7 @@ class UnityBlock {
|
|
|
2607
2831
|
if (empty_match) {
|
|
2608
2832
|
const base_indent = empty_match[2];
|
|
2609
2833
|
const element_indent2 = base_indent + " ";
|
|
2610
|
-
this._raw = this._raw.replace(empty_pattern, `$
|
|
2834
|
+
this._raw = this._raw.replace(empty_pattern, (_m, g1) => `${g1}
|
|
2611
2835
|
${element_indent2}- ${value}`);
|
|
2612
2836
|
return this._check_dirty(old_raw);
|
|
2613
2837
|
}
|
|
@@ -3531,6 +3755,20 @@ function read_project_version(projectPath) {
|
|
|
3531
3755
|
}
|
|
3532
3756
|
|
|
3533
3757
|
// src/editor/create.ts
|
|
3758
|
+
function compute_dll_script_file_id(namespace, class_name) {
|
|
3759
|
+
const { createHash } = require("crypto");
|
|
3760
|
+
const full_name = namespace ? `${namespace}.${class_name}` : class_name;
|
|
3761
|
+
const name_bytes = Buffer.from(full_name, "utf-8");
|
|
3762
|
+
const input = Buffer.alloc(4 + name_bytes.length);
|
|
3763
|
+
input.writeInt32LE(114, 0);
|
|
3764
|
+
name_bytes.copy(input, 4);
|
|
3765
|
+
const hash = createHash("md4").update(input).digest();
|
|
3766
|
+
const a = hash.readInt32LE(0);
|
|
3767
|
+
const b = hash.readInt32LE(4);
|
|
3768
|
+
const c = hash.readInt32LE(8);
|
|
3769
|
+
const d = hash.readInt32LE(12);
|
|
3770
|
+
return a ^ b ^ c ^ d;
|
|
3771
|
+
}
|
|
3534
3772
|
function get_layer_from_parent(doc, parentTransformId) {
|
|
3535
3773
|
if (parentTransformId === "0")
|
|
3536
3774
|
return 0;
|
|
@@ -3546,7 +3784,7 @@ function get_layer_from_parent(doc, parentTransformId) {
|
|
|
3546
3784
|
const layerMatch = parentGo.raw.match(/m_Layer:\s*(\d+)/);
|
|
3547
3785
|
return layerMatch ? parseInt(layerMatch[1], 10) : 0;
|
|
3548
3786
|
}
|
|
3549
|
-
function createGameObjectYAML(gameObjectId, transformId, name, parentTransformId = 0, rootOrder = 0, layer = 0) {
|
|
3787
|
+
function createGameObjectYAML(gameObjectId, transformId, name, parentTransformId = "0", rootOrder = 0, layer = 0) {
|
|
3550
3788
|
return `--- !u!1 &${gameObjectId}
|
|
3551
3789
|
GameObject:
|
|
3552
3790
|
m_ObjectHideFlags: 0
|
|
@@ -3607,9 +3845,9 @@ function findStrippedRootTransform(doc, prefabInstanceId) {
|
|
|
3607
3845
|
for (const block of doc.blocks) {
|
|
3608
3846
|
if (block.class_id !== 4 || !block.is_stripped)
|
|
3609
3847
|
continue;
|
|
3610
|
-
const piMatch = block.raw.match(/m_PrefabInstance
|
|
3848
|
+
const piMatch = block.raw.match(/m_PrefabInstance:[ \t]*\{fileID:[ \t]*(-?\d+)\}/);
|
|
3611
3849
|
if (piMatch && piMatch[1] === prefabInstanceId) {
|
|
3612
|
-
const sourceMatch = block.raw.match(/m_CorrespondingSourceObject
|
|
3850
|
+
const sourceMatch = block.raw.match(/m_CorrespondingSourceObject:[ \t]*(\{[^}]+\})/);
|
|
3613
3851
|
if (sourceMatch) {
|
|
3614
3852
|
return {
|
|
3615
3853
|
transformId: block.file_id,
|
|
@@ -3620,6 +3858,66 @@ function findStrippedRootTransform(doc, prefabInstanceId) {
|
|
|
3620
3858
|
}
|
|
3621
3859
|
return null;
|
|
3622
3860
|
}
|
|
3861
|
+
function find_game_object_in_variant(doc, name, file_path, project_path) {
|
|
3862
|
+
const pi_blocks = doc.find_by_class_id(1001);
|
|
3863
|
+
for (const pi_block of pi_blocks) {
|
|
3864
|
+
const mod_pattern = /- target:[ \t]*(\{[^}]+\})\s*propertyPath:[ \t]*m_Name\s*value:[ \t]*([^\n]*)/g;
|
|
3865
|
+
let mod_match;
|
|
3866
|
+
while ((mod_match = mod_pattern.exec(pi_block.raw)) !== null) {
|
|
3867
|
+
const target_ref = mod_match[1];
|
|
3868
|
+
const mod_value = mod_match[2].trim();
|
|
3869
|
+
if (mod_value !== name)
|
|
3870
|
+
continue;
|
|
3871
|
+
for (const block of doc.blocks) {
|
|
3872
|
+
if (block.class_id !== 1 || !block.is_stripped)
|
|
3873
|
+
continue;
|
|
3874
|
+
const source_match = block.raw.match(/m_CorrespondingSourceObject:[ \t]*(\{[^}]+\})/);
|
|
3875
|
+
if (!source_match)
|
|
3876
|
+
continue;
|
|
3877
|
+
const normalized_source = source_match[1].replace(/\s+/g, " ");
|
|
3878
|
+
const normalized_target = target_ref.replace(/\s+/g, " ");
|
|
3879
|
+
if (normalized_source === normalized_target) {
|
|
3880
|
+
return {
|
|
3881
|
+
stripped_go_id: block.file_id,
|
|
3882
|
+
source_ref: target_ref,
|
|
3883
|
+
prefab_instance_id: pi_block.file_id
|
|
3884
|
+
};
|
|
3885
|
+
}
|
|
3886
|
+
}
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
const source_info = resolve_source_prefab(doc, file_path, project_path);
|
|
3890
|
+
if (!source_info)
|
|
3891
|
+
return null;
|
|
3892
|
+
let source_doc;
|
|
3893
|
+
try {
|
|
3894
|
+
source_doc = UnityDocument.from_file(source_info.source_path);
|
|
3895
|
+
} catch {
|
|
3896
|
+
return null;
|
|
3897
|
+
}
|
|
3898
|
+
const source_gos = source_doc.find_game_objects_by_name(name);
|
|
3899
|
+
if (source_gos.length !== 1)
|
|
3900
|
+
return null;
|
|
3901
|
+
const source_go = source_gos[0];
|
|
3902
|
+
const source_go_file_id = source_go.file_id;
|
|
3903
|
+
const source_guid = source_info.source_guid;
|
|
3904
|
+
for (const block of doc.blocks) {
|
|
3905
|
+
if (block.class_id !== 1 || !block.is_stripped)
|
|
3906
|
+
continue;
|
|
3907
|
+
const source_match = block.raw.match(/m_CorrespondingSourceObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)[^}]*guid:[ \t]*([a-f0-9]{32})/);
|
|
3908
|
+
if (!source_match)
|
|
3909
|
+
continue;
|
|
3910
|
+
if (source_match[1] === source_go_file_id && source_match[2] === source_guid) {
|
|
3911
|
+
const source_ref = `{fileID: ${source_go_file_id}, guid: ${source_guid}, type: 3}`;
|
|
3912
|
+
return {
|
|
3913
|
+
stripped_go_id: block.file_id,
|
|
3914
|
+
source_ref,
|
|
3915
|
+
prefab_instance_id: source_info.prefab_instance_id
|
|
3916
|
+
};
|
|
3917
|
+
}
|
|
3918
|
+
}
|
|
3919
|
+
return null;
|
|
3920
|
+
}
|
|
3623
3921
|
function appendToAddedGameObjects(doc, piId, targetSourceRef, newGoId) {
|
|
3624
3922
|
const piBlock = doc.find_by_file_id(piId);
|
|
3625
3923
|
if (!piBlock)
|
|
@@ -3629,13 +3927,34 @@ function appendToAddedGameObjects(doc, piId, targetSourceRef, newGoId) {
|
|
|
3629
3927
|
insertIndex: -1
|
|
3630
3928
|
addedObject: {fileID: ${newGoId}}`;
|
|
3631
3929
|
let raw = piBlock.raw;
|
|
3632
|
-
const emptyPattern = /m_AddedGameObjects
|
|
3930
|
+
const emptyPattern = /m_AddedGameObjects:[ \t]*\[\]/;
|
|
3633
3931
|
if (emptyPattern.test(raw)) {
|
|
3634
3932
|
raw = raw.replace(emptyPattern, `m_AddedGameObjects:${entry}`);
|
|
3635
3933
|
piBlock.replace_raw(raw);
|
|
3636
3934
|
return;
|
|
3637
3935
|
}
|
|
3638
|
-
const existingPattern = /(m_AddedGameObjects
|
|
3936
|
+
const existingPattern = /(m_AddedGameObjects:[ \t]*\n(?:[ \t]+-[\s\S]*?(?=\n[ \t]+m_|$))*)/;
|
|
3937
|
+
if (existingPattern.test(raw)) {
|
|
3938
|
+
raw = raw.replace(existingPattern, `$1${entry}`);
|
|
3939
|
+
piBlock.replace_raw(raw);
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
function appendToAddedComponents(doc, piId, targetSourceRef, newComponentId) {
|
|
3943
|
+
const piBlock = doc.find_by_file_id(piId);
|
|
3944
|
+
if (!piBlock)
|
|
3945
|
+
return;
|
|
3946
|
+
const entry = `
|
|
3947
|
+
- targetCorrespondingSourceObject: ${targetSourceRef}
|
|
3948
|
+
insertIndex: -1
|
|
3949
|
+
addedObject: {fileID: ${newComponentId}}`;
|
|
3950
|
+
let raw = piBlock.raw;
|
|
3951
|
+
const emptyPattern = /m_AddedComponents:[ \t]*\[\]/;
|
|
3952
|
+
if (emptyPattern.test(raw)) {
|
|
3953
|
+
raw = raw.replace(emptyPattern, `m_AddedComponents:${entry}`);
|
|
3954
|
+
piBlock.replace_raw(raw);
|
|
3955
|
+
return;
|
|
3956
|
+
}
|
|
3957
|
+
const existingPattern = /(m_AddedComponents:[ \t]*\n(?:[ \t]+-[\s\S]*?(?=\n[ \t]+m_|$))*)/;
|
|
3639
3958
|
if (existingPattern.test(raw)) {
|
|
3640
3959
|
raw = raw.replace(existingPattern, `$1${entry}`);
|
|
3641
3960
|
piBlock.replace_raw(raw);
|
|
@@ -3658,11 +3977,31 @@ var COMPONENT_DEFAULTS = {
|
|
|
3658
3977
|
m_Materials:
|
|
3659
3978
|
- {fileID: 0}`,
|
|
3660
3979
|
33: ` m_Mesh: {fileID: 0}`,
|
|
3980
|
+
50: ` m_BodyType: 0
|
|
3981
|
+
m_Mass: 1
|
|
3982
|
+
m_LinearDrag: 0
|
|
3983
|
+
m_AngularDrag: 0.05
|
|
3984
|
+
m_GravityScale: 1
|
|
3985
|
+
m_Interpolate: 0
|
|
3986
|
+
m_SleepingMode: 1
|
|
3987
|
+
m_CollisionDetection: 0`,
|
|
3661
3988
|
54: ` m_Mass: 1
|
|
3662
3989
|
m_Drag: 0
|
|
3663
3990
|
m_AngularDrag: 0.05
|
|
3664
3991
|
m_UseGravity: 1
|
|
3665
3992
|
m_IsKinematic: 0`,
|
|
3993
|
+
58: ` m_IsTrigger: 0
|
|
3994
|
+
m_Material: {fileID: 0}
|
|
3995
|
+
m_Offset: {x: 0, y: 0}
|
|
3996
|
+
m_Radius: 0.5`,
|
|
3997
|
+
60: ` m_IsTrigger: 0
|
|
3998
|
+
m_Material: {fileID: 0}
|
|
3999
|
+
m_Offset: {x: 0, y: 0}
|
|
4000
|
+
m_Points: []`,
|
|
4001
|
+
61: ` m_IsTrigger: 0
|
|
4002
|
+
m_Material: {fileID: 0}
|
|
4003
|
+
m_Offset: {x: 0, y: 0}
|
|
4004
|
+
m_Size: {x: 1, y: 1}`,
|
|
3666
4005
|
64: ` m_IsTrigger: 0
|
|
3667
4006
|
m_Convex: 0
|
|
3668
4007
|
m_CookingOptions: 30
|
|
@@ -3671,6 +4010,19 @@ var COMPONENT_DEFAULTS = {
|
|
|
3671
4010
|
m_Material: {fileID: 0}
|
|
3672
4011
|
m_Center: {x: 0, y: 0, z: 0}
|
|
3673
4012
|
m_Size: {x: 1, y: 1, z: 1}`,
|
|
4013
|
+
66: ` m_IsTrigger: 0
|
|
4014
|
+
m_Material: {fileID: 0}
|
|
4015
|
+
m_Offset: {x: 0, y: 0}
|
|
4016
|
+
m_GeometryType: 0`,
|
|
4017
|
+
68: ` m_IsTrigger: 0
|
|
4018
|
+
m_Material: {fileID: 0}
|
|
4019
|
+
m_Offset: {x: 0, y: 0}
|
|
4020
|
+
m_Points: []`,
|
|
4021
|
+
70: ` m_IsTrigger: 0
|
|
4022
|
+
m_Material: {fileID: 0}
|
|
4023
|
+
m_Offset: {x: 0, y: 0}
|
|
4024
|
+
m_Size: {x: 1, y: 1}
|
|
4025
|
+
m_Direction: 0`,
|
|
3674
4026
|
82: ` m_PlayOnAwake: 1
|
|
3675
4027
|
m_Volume: 1
|
|
3676
4028
|
m_Pitch: 1
|
|
@@ -3756,9 +4108,14 @@ function addComponentToGameObject(doc, gameObjectId, componentId) {
|
|
|
3756
4108
|
`);
|
|
3757
4109
|
goBlock.replace_raw(raw);
|
|
3758
4110
|
}
|
|
3759
|
-
function createMonoBehaviourYAML(componentId, gameObjectId, scriptGuid, fields, version) {
|
|
4111
|
+
function createMonoBehaviourYAML(componentId, gameObjectId, scriptGuid, fields, version, scriptFileId = 11500000) {
|
|
3760
4112
|
const field_yaml = fields && fields.length > 0 ? generate_field_yaml(fields, version) : `
|
|
3761
4113
|
`;
|
|
4114
|
+
const has_serialize_ref = fields?.some((f) => f.hasSerializeReference) ?? false;
|
|
4115
|
+
const references_section = has_serialize_ref ? ` references:
|
|
4116
|
+
version: 2
|
|
4117
|
+
RefIds: []
|
|
4118
|
+
` : "";
|
|
3762
4119
|
return `--- !u!114 &${componentId}
|
|
3763
4120
|
MonoBehaviour:
|
|
3764
4121
|
m_ObjectHideFlags: 0
|
|
@@ -3768,9 +4125,9 @@ MonoBehaviour:
|
|
|
3768
4125
|
m_GameObject: {fileID: ${gameObjectId}}
|
|
3769
4126
|
m_Enabled: 1
|
|
3770
4127
|
m_EditorHideFlags: 0
|
|
3771
|
-
m_Script: {fileID:
|
|
4128
|
+
m_Script: {fileID: ${scriptFileId}, guid: ${scriptGuid}, type: 3}
|
|
3772
4129
|
m_Name:
|
|
3773
|
-
m_EditorClassIdentifier:${field_yaml}`;
|
|
4130
|
+
m_EditorClassIdentifier:${field_yaml}${references_section}`;
|
|
3774
4131
|
}
|
|
3775
4132
|
function createGameObject(options) {
|
|
3776
4133
|
const { file_path, name, parent } = options;
|
|
@@ -3869,9 +4226,9 @@ function createGameObject(options) {
|
|
|
3869
4226
|
const layer = get_layer_from_parent(doc, parentTransformIdStr);
|
|
3870
4227
|
const gameObjectIdStr = doc.generate_file_id();
|
|
3871
4228
|
const transformIdStr = doc.generate_file_id();
|
|
3872
|
-
const gameObjectId =
|
|
3873
|
-
const transformId =
|
|
3874
|
-
const parentTransformId =
|
|
4229
|
+
const gameObjectId = gameObjectIdStr;
|
|
4230
|
+
const transformId = transformIdStr;
|
|
4231
|
+
const parentTransformId = parentTransformIdStr;
|
|
3875
4232
|
const newBlocks = createGameObjectYAML(gameObjectId, transformId, name.trim(), parentTransformId, rootOrder, layer);
|
|
3876
4233
|
doc.append_raw(newBlocks);
|
|
3877
4234
|
if (parentTransformIdStr !== "0" && !variantPiId) {
|
|
@@ -3893,7 +4250,7 @@ function createGameObject(options) {
|
|
|
3893
4250
|
file_path,
|
|
3894
4251
|
game_object_id: gameObjectId,
|
|
3895
4252
|
transform_id: transformId,
|
|
3896
|
-
prefab_instance_id: variantPiId
|
|
4253
|
+
prefab_instance_id: variantPiId || undefined
|
|
3897
4254
|
};
|
|
3898
4255
|
}
|
|
3899
4256
|
function createScene(options) {
|
|
@@ -4339,9 +4696,9 @@ function createPrefabVariant(options) {
|
|
|
4339
4696
|
const tempDoc = UnityDocument.from_string(`%YAML 1.1
|
|
4340
4697
|
%TAG !u! tag:unity3d.com,2011:
|
|
4341
4698
|
`);
|
|
4342
|
-
const prefabInstanceId =
|
|
4343
|
-
const strippedGoId =
|
|
4344
|
-
const strippedTransformId =
|
|
4699
|
+
const prefabInstanceId = tempDoc.generate_file_id();
|
|
4700
|
+
const strippedGoId = tempDoc.generate_file_id();
|
|
4701
|
+
const strippedTransformId = tempDoc.generate_file_id();
|
|
4345
4702
|
const finalName = variant_name || `${rootInfo.name} Variant`;
|
|
4346
4703
|
const variantYaml = `%YAML 1.1
|
|
4347
4704
|
%TAG !u! tag:unity3d.com,2011:
|
|
@@ -4457,7 +4814,7 @@ function createScriptableObject(options) {
|
|
|
4457
4814
|
const baseName = path5.basename(output_path, ".asset");
|
|
4458
4815
|
const field_yaml = resolved.fields && resolved.fields.length > 0 ? generate_field_yaml(resolved.fields, version) : `
|
|
4459
4816
|
`;
|
|
4460
|
-
|
|
4817
|
+
let assetYaml = `%YAML 1.1
|
|
4461
4818
|
%TAG !u! tag:unity3d.com,2011:
|
|
4462
4819
|
--- !u!114 &11400000
|
|
4463
4820
|
MonoBehaviour:
|
|
@@ -4471,6 +4828,16 @@ MonoBehaviour:
|
|
|
4471
4828
|
m_Script: {fileID: 11500000, guid: ${resolved.guid}, type: 3}
|
|
4472
4829
|
m_Name: ${baseName}
|
|
4473
4830
|
m_EditorClassIdentifier:${field_yaml}`;
|
|
4831
|
+
if (options.initial_values && Object.keys(options.initial_values).length > 0) {
|
|
4832
|
+
const doc = UnityDocument.from_string(assetYaml);
|
|
4833
|
+
const block = doc.blocks[0];
|
|
4834
|
+
if (block) {
|
|
4835
|
+
for (const [key, val] of Object.entries(options.initial_values)) {
|
|
4836
|
+
block.set_property(key, val);
|
|
4837
|
+
}
|
|
4838
|
+
assetYaml = doc.serialize();
|
|
4839
|
+
}
|
|
4840
|
+
}
|
|
4474
4841
|
try {
|
|
4475
4842
|
import_fs10.writeFileSync(output_path, assetYaml, "utf-8");
|
|
4476
4843
|
} catch (err) {
|
|
@@ -4551,6 +4918,80 @@ MonoImporter:
|
|
|
4551
4918
|
guid
|
|
4552
4919
|
};
|
|
4553
4920
|
}
|
|
4921
|
+
var COMPONENT_BASE_CLASSES = new Set([
|
|
4922
|
+
"MonoBehaviour",
|
|
4923
|
+
"NetworkBehaviour",
|
|
4924
|
+
"StateMachineBehaviour"
|
|
4925
|
+
]);
|
|
4926
|
+
function is_valid_component_base(base_class, project_path, depth = 0) {
|
|
4927
|
+
if (depth > 5)
|
|
4928
|
+
return false;
|
|
4929
|
+
if (COMPONENT_BASE_CLASSES.has(base_class))
|
|
4930
|
+
return true;
|
|
4931
|
+
if (!project_path)
|
|
4932
|
+
return false;
|
|
4933
|
+
const registryPath = path5.join(project_path, ".unity-agentic", "type-registry.json");
|
|
4934
|
+
if (import_fs10.existsSync(registryPath)) {
|
|
4935
|
+
try {
|
|
4936
|
+
const registry = JSON.parse(import_fs10.readFileSync(registryPath, "utf-8"));
|
|
4937
|
+
const match = registry.find((t) => t.name === base_class && t.kind === "class");
|
|
4938
|
+
if (match?.filePath) {
|
|
4939
|
+
const fullPath = path5.isAbsolute(match.filePath) ? match.filePath : path5.join(project_path, match.filePath);
|
|
4940
|
+
if (fullPath.endsWith(".cs") && import_fs10.existsSync(fullPath)) {
|
|
4941
|
+
const { getNativeExtractSerializedFields: getNativeExtractSerializedFields2 } = (init_scanner(), __toCommonJS(exports_scanner));
|
|
4942
|
+
const extract = getNativeExtractSerializedFields2();
|
|
4943
|
+
if (extract) {
|
|
4944
|
+
const typeInfos = extract(fullPath);
|
|
4945
|
+
const info = typeInfos?.find((t) => t.name === base_class);
|
|
4946
|
+
if (info?.baseClass) {
|
|
4947
|
+
return is_valid_component_base(info.baseClass, project_path, depth + 1);
|
|
4948
|
+
}
|
|
4949
|
+
}
|
|
4950
|
+
}
|
|
4951
|
+
if (!fullPath.endsWith(".cs") || !import_fs10.existsSync(fullPath)) {
|
|
4952
|
+
if (match.kind === "class") {
|
|
4953
|
+
return is_likely_component_base_name(base_class);
|
|
4954
|
+
}
|
|
4955
|
+
}
|
|
4956
|
+
}
|
|
4957
|
+
} catch {}
|
|
4958
|
+
}
|
|
4959
|
+
const cachePaths = [
|
|
4960
|
+
path5.join(project_path, ".unity-agentic", "package-cache.json"),
|
|
4961
|
+
path5.join(project_path, ".unity-agentic", "local-package-cache.json")
|
|
4962
|
+
];
|
|
4963
|
+
for (const cachePath of cachePaths) {
|
|
4964
|
+
if (!import_fs10.existsSync(cachePath))
|
|
4965
|
+
continue;
|
|
4966
|
+
try {
|
|
4967
|
+
const cache = JSON.parse(import_fs10.readFileSync(cachePath, "utf-8"));
|
|
4968
|
+
const baseClassLower = base_class.toLowerCase();
|
|
4969
|
+
for (const [, assetPath] of Object.entries(cache)) {
|
|
4970
|
+
if (!assetPath.endsWith(".cs"))
|
|
4971
|
+
continue;
|
|
4972
|
+
if (path5.basename(assetPath, ".cs").toLowerCase() !== baseClassLower)
|
|
4973
|
+
continue;
|
|
4974
|
+
const fullPath = path5.join(project_path, assetPath);
|
|
4975
|
+
if (!import_fs10.existsSync(fullPath))
|
|
4976
|
+
continue;
|
|
4977
|
+
const { getNativeExtractSerializedFields: getNativeExtractSerializedFields2 } = (init_scanner(), __toCommonJS(exports_scanner));
|
|
4978
|
+
const extract = getNativeExtractSerializedFields2();
|
|
4979
|
+
if (!extract)
|
|
4980
|
+
continue;
|
|
4981
|
+
const typeInfos = extract(fullPath);
|
|
4982
|
+
const info = typeInfos?.find((t) => t.name === base_class);
|
|
4983
|
+
if (info?.baseClass) {
|
|
4984
|
+
return is_valid_component_base(info.baseClass, project_path, depth + 1);
|
|
4985
|
+
}
|
|
4986
|
+
}
|
|
4987
|
+
} catch {}
|
|
4988
|
+
}
|
|
4989
|
+
return false;
|
|
4990
|
+
}
|
|
4991
|
+
function is_likely_component_base_name(name) {
|
|
4992
|
+
const lower = name.toLowerCase();
|
|
4993
|
+
return lower.endsWith("behaviour") || lower.endsWith("behavior") || lower.includes("monobehaviour") || lower.includes("networkbehaviour");
|
|
4994
|
+
}
|
|
4554
4995
|
function addComponent(options) {
|
|
4555
4996
|
const { file_path, game_object_name, component_type } = options;
|
|
4556
4997
|
const project_path = options.project_path || find_unity_project_root(path5.dirname(file_path)) || undefined;
|
|
@@ -4576,11 +5017,19 @@ function addComponent(options) {
|
|
|
4576
5017
|
};
|
|
4577
5018
|
}
|
|
4578
5019
|
const goResult = doc.require_unique_game_object(game_object_name);
|
|
5020
|
+
let gameObjectIdStr;
|
|
5021
|
+
let variantInfo = null;
|
|
4579
5022
|
if ("error" in goResult) {
|
|
4580
|
-
|
|
5023
|
+
const vResult = find_game_object_in_variant(doc, game_object_name, file_path, project_path);
|
|
5024
|
+
if (!vResult) {
|
|
5025
|
+
return { success: false, file_path, error: goResult.error };
|
|
5026
|
+
}
|
|
5027
|
+
gameObjectIdStr = vResult.stripped_go_id;
|
|
5028
|
+
variantInfo = { source_ref: vResult.source_ref, prefab_instance_id: vResult.prefab_instance_id };
|
|
5029
|
+
} else {
|
|
5030
|
+
gameObjectIdStr = goResult.file_id;
|
|
4581
5031
|
}
|
|
4582
|
-
const
|
|
4583
|
-
const gameObjectId = parseInt(gameObjectIdStr, 10);
|
|
5032
|
+
const gameObjectId = gameObjectIdStr;
|
|
4584
5033
|
const classId = get_class_id(component_type);
|
|
4585
5034
|
let duplicateWarning;
|
|
4586
5035
|
const goBlock = doc.find_by_file_id(gameObjectIdStr);
|
|
@@ -4595,7 +5044,7 @@ function addComponent(options) {
|
|
|
4595
5044
|
}
|
|
4596
5045
|
}
|
|
4597
5046
|
const componentIdStr = doc.generate_file_id();
|
|
4598
|
-
const componentId =
|
|
5047
|
+
const componentId = componentIdStr;
|
|
4599
5048
|
let componentYAML;
|
|
4600
5049
|
let scriptGuid;
|
|
4601
5050
|
let scriptPath;
|
|
@@ -4604,7 +5053,16 @@ function addComponent(options) {
|
|
|
4604
5053
|
const componentName = UNITY_CLASS_IDS[classId] || component_type;
|
|
4605
5054
|
componentYAML = createGenericComponentYAML(componentName, classId, componentId, gameObjectId);
|
|
4606
5055
|
} else {
|
|
4607
|
-
|
|
5056
|
+
let resolved;
|
|
5057
|
+
try {
|
|
5058
|
+
resolved = resolve_script_with_fields(component_type, project_path);
|
|
5059
|
+
} catch (e) {
|
|
5060
|
+
return {
|
|
5061
|
+
success: false,
|
|
5062
|
+
file_path,
|
|
5063
|
+
error: e instanceof Error ? e.message : String(e)
|
|
5064
|
+
};
|
|
5065
|
+
}
|
|
4608
5066
|
if (!resolved) {
|
|
4609
5067
|
const hints = [];
|
|
4610
5068
|
if (project_path) {
|
|
@@ -4631,11 +5089,11 @@ function addComponent(options) {
|
|
|
4631
5089
|
error: `"${component_type}" is ${resolved.kind === "enum" ? "an enum" : "an interface"}, not a MonoBehaviour. Cannot add as a component.`
|
|
4632
5090
|
};
|
|
4633
5091
|
}
|
|
4634
|
-
if (resolved.base_class && !
|
|
5092
|
+
if (resolved.base_class && !COMPONENT_BASE_CLASSES.has(resolved.base_class) && !is_valid_component_base(resolved.base_class, project_path)) {
|
|
4635
5093
|
return {
|
|
4636
5094
|
success: false,
|
|
4637
5095
|
file_path,
|
|
4638
|
-
error: `"${component_type}" extends ${resolved.base_class}, not MonoBehaviour. Cannot add as a component.`
|
|
5096
|
+
error: `"${component_type}" extends ${resolved.base_class}, which does not inherit from MonoBehaviour. Cannot add as a component. If this is incorrect, ensure the type registry is up to date ("setup" command).`
|
|
4639
5097
|
};
|
|
4640
5098
|
}
|
|
4641
5099
|
let version;
|
|
@@ -4644,12 +5102,20 @@ function addComponent(options) {
|
|
|
4644
5102
|
version = read_project_version(project_path);
|
|
4645
5103
|
} catch {}
|
|
4646
5104
|
}
|
|
4647
|
-
|
|
5105
|
+
let scriptFileId = 11500000;
|
|
5106
|
+
if (resolved.path?.endsWith(".dll") && resolved.class_name) {
|
|
5107
|
+
scriptFileId = compute_dll_script_file_id(resolved.namespace ?? "", resolved.class_name);
|
|
5108
|
+
}
|
|
5109
|
+
componentYAML = createMonoBehaviourYAML(componentId, gameObjectId, resolved.guid, resolved.fields, version, scriptFileId);
|
|
4648
5110
|
scriptGuid = resolved.guid;
|
|
4649
5111
|
scriptPath = resolved.path || undefined;
|
|
4650
5112
|
extractionError = resolved.extraction_error;
|
|
4651
5113
|
}
|
|
4652
|
-
|
|
5114
|
+
if (variantInfo) {
|
|
5115
|
+
appendToAddedComponents(doc, variantInfo.prefab_instance_id, variantInfo.source_ref, componentIdStr);
|
|
5116
|
+
} else {
|
|
5117
|
+
addComponentToGameObject(doc, gameObjectIdStr, componentIdStr);
|
|
5118
|
+
}
|
|
4653
5119
|
doc.append_raw(componentYAML);
|
|
4654
5120
|
const saveResult = doc.save();
|
|
4655
5121
|
if (!saveResult.success) {
|
|
@@ -4726,6 +5192,14 @@ function copyComponent(options) {
|
|
|
4726
5192
|
}
|
|
4727
5193
|
// src/editor/update.ts
|
|
4728
5194
|
var import_fs11 = require("fs");
|
|
5195
|
+
function enrich_target_ref(targetRef, blockRaw) {
|
|
5196
|
+
if (/guid:/.test(targetRef))
|
|
5197
|
+
return targetRef;
|
|
5198
|
+
const sourceMatch = blockRaw.match(/m_SourcePrefab:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]{32})/);
|
|
5199
|
+
if (!sourceMatch)
|
|
5200
|
+
return null;
|
|
5201
|
+
return targetRef.replace(/\}$/, `, guid: ${sourceMatch[1]}, type: 3}`);
|
|
5202
|
+
}
|
|
4729
5203
|
function eulerToQuaternion(euler) {
|
|
4730
5204
|
const deg2rad = Math.PI / 180;
|
|
4731
5205
|
const x = euler.x * deg2rad;
|
|
@@ -4748,6 +5222,9 @@ function validate_value_type(current_value, new_value) {
|
|
|
4748
5222
|
const current = current_value.trim();
|
|
4749
5223
|
const incoming = new_value.trim();
|
|
4750
5224
|
if (/^\{fileID:/.test(current)) {
|
|
5225
|
+
if (/^\{fileID:[ \t]*0[ \t]*\}$/.test(current)) {
|
|
5226
|
+
return null;
|
|
5227
|
+
}
|
|
4751
5228
|
if (!/^\{fileID:/.test(incoming)) {
|
|
4752
5229
|
return `Expected a reference value ({fileID: ...}), got "${incoming}"`;
|
|
4753
5230
|
}
|
|
@@ -4932,10 +5409,10 @@ function safeUnityYAMLEdit(filePath, objectName, propertyName, newValue, project
|
|
|
4932
5409
|
const propertyPattern = new RegExp(`(^\\s*m_${normalizedProperty}:\\s*)([^\\n]*)`, "m");
|
|
4933
5410
|
let updatedRaw = targetBlock.raw;
|
|
4934
5411
|
if (propertyPattern.test(updatedRaw)) {
|
|
4935
|
-
updatedRaw = updatedRaw.replace(propertyPattern,
|
|
5412
|
+
updatedRaw = updatedRaw.replace(propertyPattern, (_m, prefix) => prefix + newValue);
|
|
4936
5413
|
} else {
|
|
4937
|
-
updatedRaw = updatedRaw.replace(/(\n)(--- !u!|$)/, `
|
|
4938
|
-
m_${normalizedProperty}: ${newValue}$
|
|
5414
|
+
updatedRaw = updatedRaw.replace(/(\n)(--- !u!|$)/, (_m, g1, g2) => `
|
|
5415
|
+
m_${normalizedProperty}: ${newValue}${g1}${g2}`);
|
|
4939
5416
|
}
|
|
4940
5417
|
targetBlock.replace_raw(updatedRaw);
|
|
4941
5418
|
const saveResult = doc.save();
|
|
@@ -5021,7 +5498,9 @@ function editComponentByFileId(options) {
|
|
|
5021
5498
|
};
|
|
5022
5499
|
}
|
|
5023
5500
|
}
|
|
5024
|
-
const
|
|
5501
|
+
const exactValue = targetBlock.get_property(exactProperty);
|
|
5502
|
+
const resolvedProperty = exactValue !== null ? exactProperty : exactProperty !== prefixedProperty && targetBlock.get_property(prefixedProperty) !== null ? prefixedProperty : null;
|
|
5503
|
+
const currentValue = exactValue ?? (resolvedProperty === prefixedProperty ? targetBlock.get_property(prefixedProperty) : null);
|
|
5025
5504
|
if (currentValue !== null) {
|
|
5026
5505
|
const typeError = validate_value_type(currentValue, new_value);
|
|
5027
5506
|
if (typeError) {
|
|
@@ -5032,9 +5511,14 @@ function editComponentByFileId(options) {
|
|
|
5032
5511
|
};
|
|
5033
5512
|
}
|
|
5034
5513
|
}
|
|
5035
|
-
let modified
|
|
5036
|
-
if (
|
|
5037
|
-
modified = targetBlock.set_property(
|
|
5514
|
+
let modified;
|
|
5515
|
+
if (resolvedProperty) {
|
|
5516
|
+
modified = targetBlock.set_property(resolvedProperty, new_value, "{fileID: 0}");
|
|
5517
|
+
} else {
|
|
5518
|
+
modified = targetBlock.set_property(exactProperty, new_value, "{fileID: 0}");
|
|
5519
|
+
if (!modified && exactProperty !== prefixedProperty) {
|
|
5520
|
+
modified = targetBlock.set_property(prefixedProperty, new_value, "{fileID: 0}");
|
|
5521
|
+
}
|
|
5038
5522
|
}
|
|
5039
5523
|
if (!modified) {
|
|
5040
5524
|
if (currentValue !== null) {
|
|
@@ -5071,8 +5555,10 @@ function editComponentByFileId(options) {
|
|
|
5071
5555
|
};
|
|
5072
5556
|
}
|
|
5073
5557
|
function editPrefabOverride(options) {
|
|
5074
|
-
const { file_path, prefab_instance,
|
|
5075
|
-
const
|
|
5558
|
+
const { file_path, prefab_instance, new_value, object_reference, target, managed_reference } = options;
|
|
5559
|
+
const property_path = /[\[\]]/.test(options.property_path) && !options.property_path.startsWith("'") ? `'${options.property_path}'` : options.property_path;
|
|
5560
|
+
const effectiveValue = managed_reference ?? new_value;
|
|
5561
|
+
const objRef = managed_reference ? "{fileID: 0}" : object_reference ?? "{fileID: 0}";
|
|
5076
5562
|
if (!import_fs11.existsSync(file_path)) {
|
|
5077
5563
|
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
5078
5564
|
}
|
|
@@ -5086,11 +5572,16 @@ function editPrefabOverride(options) {
|
|
|
5086
5572
|
if (!targetBlock) {
|
|
5087
5573
|
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
5088
5574
|
}
|
|
5089
|
-
const
|
|
5090
|
-
const
|
|
5575
|
+
const unquotedPath = property_path.replace(/^'|'$/g, "");
|
|
5576
|
+
const quotedPath = `'${unquotedPath}'`;
|
|
5577
|
+
const escapedUnquoted = unquotedPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5578
|
+
const escapedQuoted = quotedPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5579
|
+
const pathAlternation = escapedUnquoted === escapedQuoted ? escapedUnquoted : `(?:${escapedQuoted}|${escapedUnquoted})`;
|
|
5580
|
+
const entryPattern = new RegExp(`(- target:\\s*\\{[^}]+\\}\\s*\\n\\s*propertyPath:\\s*)${pathAlternation}(\\s*\\n\\s*value:\\s*)(.*)(\\s*\\n\\s*objectReference:\\s*)(.*)`, "m");
|
|
5091
5581
|
const entryMatch = targetBlock.raw.match(entryPattern);
|
|
5092
5582
|
if (entryMatch) {
|
|
5093
|
-
const
|
|
5583
|
+
const quotedValue = yaml_quote_if_needed(effectiveValue);
|
|
5584
|
+
const updatedText2 = targetBlock.raw.replace(entryPattern, (_m, g1, g2, _g3, g4) => g1 + property_path + g2 + quotedValue + g4 + objRef);
|
|
5094
5585
|
targetBlock.replace_raw(updatedText2);
|
|
5095
5586
|
const saveResult2 = doc.save();
|
|
5096
5587
|
if (!saveResult2.success) {
|
|
@@ -5127,9 +5618,13 @@ function editPrefabOverride(options) {
|
|
|
5127
5618
|
error: `Invalid target reference "${targetRef}". Expected format: {fileID: N, guid: ..., type: T}`
|
|
5128
5619
|
};
|
|
5129
5620
|
}
|
|
5621
|
+
const enriched = enrich_target_ref(targetRef, targetBlock.raw);
|
|
5622
|
+
if (enriched)
|
|
5623
|
+
targetRef = enriched;
|
|
5624
|
+
const quotedNewValue = yaml_quote_if_needed(effectiveValue);
|
|
5130
5625
|
const newEntry = ` - target: ${targetRef}
|
|
5131
5626
|
propertyPath: ${property_path}
|
|
5132
|
-
value: ${
|
|
5627
|
+
value: ${quotedNewValue}
|
|
5133
5628
|
objectReference: ${objRef}`;
|
|
5134
5629
|
const removedPattern = /(\n\s*m_RemovedComponents:)/m;
|
|
5135
5630
|
const removedMatch = targetBlock.raw.match(removedPattern);
|
|
@@ -5272,10 +5767,10 @@ function batchEditProperties(filePath, edits) {
|
|
|
5272
5767
|
const propertyPattern = new RegExp(`(^\\s*m_${normalizedProperty}:\\s*)([^\\n]*)`, "m");
|
|
5273
5768
|
let updatedRaw = targetBlock.raw;
|
|
5274
5769
|
if (propertyPattern.test(updatedRaw)) {
|
|
5275
|
-
updatedRaw = updatedRaw.replace(propertyPattern,
|
|
5770
|
+
updatedRaw = updatedRaw.replace(propertyPattern, (_m, prefix) => prefix + edit.new_value);
|
|
5276
5771
|
} else {
|
|
5277
|
-
updatedRaw = updatedRaw.replace(/(\n)(--- !u!|$)/, `
|
|
5278
|
-
m_${normalizedProperty}: ${edit.new_value}$
|
|
5772
|
+
updatedRaw = updatedRaw.replace(/(\n)(--- !u!|$)/, (_m, g1, g2) => `
|
|
5773
|
+
m_${normalizedProperty}: ${edit.new_value}${g1}${g2}`);
|
|
5279
5774
|
}
|
|
5280
5775
|
targetBlock.replace_raw(updatedRaw);
|
|
5281
5776
|
}
|
|
@@ -5380,9 +5875,9 @@ function reparentGameObject(options) {
|
|
|
5380
5875
|
return {
|
|
5381
5876
|
success: true,
|
|
5382
5877
|
file_path,
|
|
5383
|
-
child_transform_id:
|
|
5384
|
-
old_parent_transform_id:
|
|
5385
|
-
new_parent_transform_id:
|
|
5878
|
+
child_transform_id: childTransformId,
|
|
5879
|
+
old_parent_transform_id: oldParentTransformId,
|
|
5880
|
+
new_parent_transform_id: newParentTransformId
|
|
5386
5881
|
};
|
|
5387
5882
|
}
|
|
5388
5883
|
function findPrefabInstanceBlock(doc, identifier) {
|
|
@@ -5751,9 +6246,9 @@ function removeRemovedGameObject(options) {
|
|
|
5751
6246
|
if (!doc.validate()) {
|
|
5752
6247
|
return { success: false, file_path, error: "Validation failed after removing GameObject" };
|
|
5753
6248
|
}
|
|
5754
|
-
const
|
|
5755
|
-
if (!
|
|
5756
|
-
return { success: false, file_path, error:
|
|
6249
|
+
const restoreGoSaveResult = doc.save();
|
|
6250
|
+
if (!restoreGoSaveResult.success) {
|
|
6251
|
+
return { success: false, file_path, error: restoreGoSaveResult.error };
|
|
5757
6252
|
}
|
|
5758
6253
|
return {
|
|
5759
6254
|
success: true,
|
|
@@ -5793,7 +6288,8 @@ function removeComponent(options) {
|
|
|
5793
6288
|
const parentGoId = goMatch[1];
|
|
5794
6289
|
const goBlock = doc.find_by_file_id(parentGoId);
|
|
5795
6290
|
if (goBlock) {
|
|
5796
|
-
const
|
|
6291
|
+
const escaped = file_id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6292
|
+
const compLinePattern = new RegExp(`^[ \\t]*- component: \\{fileID: ${escaped}\\}[ \\t]*\\n`, "m");
|
|
5797
6293
|
const modifiedRaw = goBlock.raw.replace(compLinePattern, "");
|
|
5798
6294
|
goBlock.replace_raw(modifiedRaw);
|
|
5799
6295
|
}
|