unity-agentic-tools 0.3.1 → 0.3.3
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 +4 -4
- package/dist/cli.js +2155 -546
- package/dist/index.js +1036 -306
- 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/cli.js
CHANGED
|
@@ -2170,6 +2170,7 @@ __export(exports_scanner, {
|
|
|
2170
2170
|
getNativeExtractCsharpTypes: () => getNativeExtractCsharpTypes,
|
|
2171
2171
|
getNativeBuildTypeRegistry: () => getNativeBuildTypeRegistry,
|
|
2172
2172
|
getNativeBuildPackageGuidCache: () => getNativeBuildPackageGuidCache,
|
|
2173
|
+
getNativeBuildLocalPackageGuidCache: () => getNativeBuildLocalPackageGuidCache,
|
|
2173
2174
|
getNativeBuildGuidCache: () => getNativeBuildGuidCache,
|
|
2174
2175
|
UnityScanner: () => UnityScanner
|
|
2175
2176
|
});
|
|
@@ -2250,13 +2251,16 @@ function getNativeExtractDllTypes() {
|
|
|
2250
2251
|
function getNativeBuildPackageGuidCache() {
|
|
2251
2252
|
return nativeBuildPackageGuidCache;
|
|
2252
2253
|
}
|
|
2254
|
+
function getNativeBuildLocalPackageGuidCache() {
|
|
2255
|
+
return nativeBuildLocalPackageGuidCache;
|
|
2256
|
+
}
|
|
2253
2257
|
function getNativeExtractSerializedFields() {
|
|
2254
2258
|
return nativeExtractSerializedFields;
|
|
2255
2259
|
}
|
|
2256
2260
|
function getNativeExtractDllFields() {
|
|
2257
2261
|
return nativeExtractDllFields;
|
|
2258
2262
|
}
|
|
2259
|
-
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;
|
|
2263
|
+
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;
|
|
2260
2264
|
var init_scanner = __esm(() => {
|
|
2261
2265
|
import_module = require("module");
|
|
2262
2266
|
import_fs = require("fs");
|
|
@@ -2280,6 +2284,7 @@ var init_scanner = __esm(() => {
|
|
|
2280
2284
|
nativeBuildTypeRegistry = rustModule.buildTypeRegistry || null;
|
|
2281
2285
|
nativeExtractDllTypes = rustModule.extractDllTypes || null;
|
|
2282
2286
|
nativeBuildPackageGuidCache = rustModule.buildPackageGuidCache || null;
|
|
2287
|
+
nativeBuildLocalPackageGuidCache = rustModule.buildLocalPackageGuidCache || null;
|
|
2283
2288
|
nativeExtractSerializedFields = rustModule.extractSerializedFields || null;
|
|
2284
2289
|
nativeExtractDllFields = rustModule.extractDllFields || null;
|
|
2285
2290
|
} catch (err) {
|
|
@@ -2294,7 +2299,7 @@ var require_package = __commonJS((exports2, module2) => {
|
|
|
2294
2299
|
module2.exports = {
|
|
2295
2300
|
name: "unity-agentic-tools",
|
|
2296
2301
|
packageManager: "bun@latest",
|
|
2297
|
-
version: "0.3.
|
|
2302
|
+
version: "0.3.3",
|
|
2298
2303
|
description: "Fast, token-efficient Unity YAML parser for AI agents",
|
|
2299
2304
|
exports: {
|
|
2300
2305
|
".": {
|
|
@@ -2386,6 +2391,7 @@ var CONFIG_DIR = ".unity-agentic";
|
|
|
2386
2391
|
var CONFIG_FILE = "config.json";
|
|
2387
2392
|
var GUID_CACHE_FILE = "guid-cache.json";
|
|
2388
2393
|
var PACKAGE_CACHE_FILE = "package-cache.json";
|
|
2394
|
+
var LOCAL_PACKAGE_CACHE_FILE = "local-package-cache.json";
|
|
2389
2395
|
var TYPE_REGISTRY_FILE = "type-registry.json";
|
|
2390
2396
|
var DOC_INDEX_FILE = "doc-index.json";
|
|
2391
2397
|
function setup(options = {}) {
|
|
@@ -2429,6 +2435,17 @@ function setup(options = {}) {
|
|
|
2429
2435
|
packageGuidCount = Object.keys(packageCache).length;
|
|
2430
2436
|
} catch {}
|
|
2431
2437
|
}
|
|
2438
|
+
const nativeLocalPkgBuild = getNativeBuildLocalPackageGuidCache();
|
|
2439
|
+
if (nativeLocalPkgBuild) {
|
|
2440
|
+
try {
|
|
2441
|
+
const localPkgCache = nativeLocalPkgBuild(projectPath);
|
|
2442
|
+
const localPkgCount = Object.keys(localPkgCache).length;
|
|
2443
|
+
if (localPkgCount > 0) {
|
|
2444
|
+
const localPkgCachePath = import_path2.join(configPath, LOCAL_PACKAGE_CACHE_FILE);
|
|
2445
|
+
import_fs2.writeFileSync(localPkgCachePath, JSON.stringify(localPkgCache, null, 2));
|
|
2446
|
+
}
|
|
2447
|
+
} catch {}
|
|
2448
|
+
}
|
|
2432
2449
|
let typeRegistryCreated = false;
|
|
2433
2450
|
let typeCount;
|
|
2434
2451
|
const nativeRegistryBuild = getNativeBuildTypeRegistry();
|
|
@@ -2578,7 +2595,7 @@ function removeDirectoryRecursive(dir) {
|
|
|
2578
2595
|
}
|
|
2579
2596
|
|
|
2580
2597
|
// src/cmd-create.ts
|
|
2581
|
-
var
|
|
2598
|
+
var import_fs16 = require("fs");
|
|
2582
2599
|
var import_path7 = require("path");
|
|
2583
2600
|
var import_crypto2 = require("crypto");
|
|
2584
2601
|
|
|
@@ -2622,31 +2639,44 @@ function atomicWrite(filePath, content) {
|
|
|
2622
2639
|
};
|
|
2623
2640
|
}
|
|
2624
2641
|
}
|
|
2625
|
-
const
|
|
2642
|
+
const suffix = `${process.pid}-${Math.random().toString(36).slice(2, 8)}`;
|
|
2643
|
+
const tmpPath = `${filePath}.${suffix}.tmp`;
|
|
2644
|
+
const bakPath = `${filePath}.${suffix}.bak`;
|
|
2645
|
+
let bakCreated = false;
|
|
2626
2646
|
try {
|
|
2627
2647
|
import_fs4.writeFileSync(tmpPath, content, "utf-8");
|
|
2628
|
-
if (import_fs4.existsSync(filePath)) {
|
|
2629
|
-
import_fs4.renameSync(filePath, `${filePath}.bak`);
|
|
2630
|
-
}
|
|
2631
|
-
import_fs4.renameSync(tmpPath, filePath);
|
|
2632
2648
|
try {
|
|
2633
|
-
|
|
2634
|
-
|
|
2649
|
+
import_fs4.renameSync(filePath, bakPath);
|
|
2650
|
+
bakCreated = true;
|
|
2651
|
+
} catch (err) {
|
|
2652
|
+
if (is_enoent(err)) {
|
|
2653
|
+
bakCreated = false;
|
|
2654
|
+
} else {
|
|
2655
|
+
throw err;
|
|
2635
2656
|
}
|
|
2636
|
-
}
|
|
2657
|
+
}
|
|
2658
|
+
import_fs4.renameSync(tmpPath, filePath);
|
|
2659
|
+
if (bakCreated) {
|
|
2660
|
+
try {
|
|
2661
|
+
import_fs4.unlinkSync(bakPath);
|
|
2662
|
+
} catch {}
|
|
2663
|
+
}
|
|
2637
2664
|
return {
|
|
2638
2665
|
success: true,
|
|
2639
2666
|
file_path: filePath,
|
|
2640
2667
|
bytes_written: Buffer.byteLength(content, "utf-8")
|
|
2641
2668
|
};
|
|
2642
2669
|
} catch (error) {
|
|
2643
|
-
if (
|
|
2670
|
+
if (bakCreated) {
|
|
2644
2671
|
try {
|
|
2645
|
-
import_fs4.renameSync(
|
|
2672
|
+
import_fs4.renameSync(bakPath, filePath);
|
|
2646
2673
|
} catch (restoreError) {
|
|
2647
2674
|
console.error("Failed to restore backup:", restoreError);
|
|
2648
2675
|
}
|
|
2649
2676
|
}
|
|
2677
|
+
try {
|
|
2678
|
+
import_fs4.unlinkSync(tmpPath);
|
|
2679
|
+
} catch {}
|
|
2650
2680
|
return {
|
|
2651
2681
|
success: false,
|
|
2652
2682
|
file_path: filePath,
|
|
@@ -2654,6 +2684,12 @@ function atomicWrite(filePath, content) {
|
|
|
2654
2684
|
};
|
|
2655
2685
|
}
|
|
2656
2686
|
}
|
|
2687
|
+
function is_enoent(err) {
|
|
2688
|
+
return err instanceof Error && "code" in err && err.code === "ENOENT";
|
|
2689
|
+
}
|
|
2690
|
+
function normalize_property_path(path) {
|
|
2691
|
+
return path.replace(/\.Array\.data\.(\d+)/g, ".Array.data[$1]");
|
|
2692
|
+
}
|
|
2657
2693
|
function is_match_all(pattern) {
|
|
2658
2694
|
return pattern === "*" || pattern === "." || pattern === "**" || pattern === ".*";
|
|
2659
2695
|
}
|
|
@@ -3032,6 +3068,31 @@ function extractGuidFromMeta(metaPath) {
|
|
|
3032
3068
|
return null;
|
|
3033
3069
|
}
|
|
3034
3070
|
}
|
|
3071
|
+
function resolve_source_prefab(doc, file_path, project_path) {
|
|
3072
|
+
const pi_blocks = doc.find_by_class_id(1001);
|
|
3073
|
+
if (pi_blocks.length === 0)
|
|
3074
|
+
return null;
|
|
3075
|
+
const pi_block = pi_blocks[0];
|
|
3076
|
+
const source_match = pi_block.raw.match(/m_SourcePrefab:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]{32})/);
|
|
3077
|
+
if (!source_match)
|
|
3078
|
+
return null;
|
|
3079
|
+
const source_guid = source_match[1];
|
|
3080
|
+
const resolved_project = project_path || find_unity_project_root(path.dirname(file_path));
|
|
3081
|
+
if (!resolved_project)
|
|
3082
|
+
return null;
|
|
3083
|
+
const cache = load_guid_cache_for_file(file_path, resolved_project);
|
|
3084
|
+
if (!cache)
|
|
3085
|
+
return null;
|
|
3086
|
+
const source_path = cache.resolve_absolute(source_guid);
|
|
3087
|
+
if (!source_path || !import_fs6.existsSync(source_path))
|
|
3088
|
+
return null;
|
|
3089
|
+
return {
|
|
3090
|
+
source_guid,
|
|
3091
|
+
source_path,
|
|
3092
|
+
prefab_instance_id: pi_block.file_id,
|
|
3093
|
+
prefab_instance_block: pi_block
|
|
3094
|
+
};
|
|
3095
|
+
}
|
|
3035
3096
|
function resolveScriptGuid(script, projectPath) {
|
|
3036
3097
|
if (/^[a-f0-9]{32}$/i.test(script)) {
|
|
3037
3098
|
return { guid: script.toLowerCase(), path: null };
|
|
@@ -3081,27 +3142,122 @@ function resolveScriptGuid(script, projectPath) {
|
|
|
3081
3142
|
return false;
|
|
3082
3143
|
return true;
|
|
3083
3144
|
});
|
|
3084
|
-
if (matches.length === 1
|
|
3085
|
-
|
|
3145
|
+
if (matches.length === 1) {
|
|
3146
|
+
if (matches[0].guid) {
|
|
3147
|
+
return { guid: matches[0].guid, path: matches[0].filePath };
|
|
3148
|
+
}
|
|
3149
|
+
if (matches[0].filePath && projectPath) {
|
|
3150
|
+
const fullFilePath = path.isAbsolute(matches[0].filePath) ? matches[0].filePath : path.join(projectPath, matches[0].filePath);
|
|
3151
|
+
const metaPath = fullFilePath + ".meta";
|
|
3152
|
+
if (import_fs6.existsSync(metaPath)) {
|
|
3153
|
+
const guid = extractGuidFromMeta(metaPath);
|
|
3154
|
+
if (guid)
|
|
3155
|
+
return { guid, path: matches[0].filePath };
|
|
3156
|
+
}
|
|
3157
|
+
if (matches[0].filePath.startsWith("Packages/")) {
|
|
3158
|
+
const pkgPath = path.join(projectPath, matches[0].filePath);
|
|
3159
|
+
const pkgMetaPath = pkgPath + ".meta";
|
|
3160
|
+
if (import_fs6.existsSync(pkgMetaPath)) {
|
|
3161
|
+
const guid = extractGuidFromMeta(pkgMetaPath);
|
|
3162
|
+
if (guid)
|
|
3163
|
+
return { guid, path: matches[0].filePath };
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
if (matches[0].filePath?.endsWith(".dll")) {
|
|
3167
|
+
const dllBasename = path.basename(matches[0].filePath).toLowerCase();
|
|
3168
|
+
for (const cacheName of ["package-cache.json", "local-package-cache.json"]) {
|
|
3169
|
+
const cachePath = path.join(projectPath, ".unity-agentic", cacheName);
|
|
3170
|
+
if (!import_fs6.existsSync(cachePath))
|
|
3171
|
+
continue;
|
|
3172
|
+
try {
|
|
3173
|
+
const cache = JSON.parse(import_fs6.readFileSync(cachePath, "utf-8"));
|
|
3174
|
+
for (const [guid, assetPath] of Object.entries(cache)) {
|
|
3175
|
+
if (assetPath.toLowerCase().endsWith(".dll") && path.basename(assetPath).toLowerCase() === dllBasename) {
|
|
3176
|
+
return { guid, path: assetPath };
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
} catch {}
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3086
3183
|
}
|
|
3087
3184
|
if (matches.length > 1) {
|
|
3088
3185
|
const withGuid = matches.filter((m) => m.guid);
|
|
3089
3186
|
if (withGuid.length === 1) {
|
|
3090
3187
|
return { guid: withGuid[0].guid, path: withGuid[0].filePath };
|
|
3091
3188
|
}
|
|
3189
|
+
const resolvedFromMeta = matches.filter((m) => !m.guid && m.filePath).map((m) => {
|
|
3190
|
+
const fullPath = path.isAbsolute(m.filePath) ? m.filePath : path.join(projectPath, m.filePath);
|
|
3191
|
+
let guid = import_fs6.existsSync(fullPath + ".meta") ? extractGuidFromMeta(fullPath + ".meta") : null;
|
|
3192
|
+
if (!guid && m.filePath.startsWith("Packages/")) {
|
|
3193
|
+
const pkgPath = path.join(projectPath, m.filePath);
|
|
3194
|
+
if (import_fs6.existsSync(pkgPath + ".meta")) {
|
|
3195
|
+
guid = extractGuidFromMeta(pkgPath + ".meta");
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
if (!guid && m.filePath?.endsWith(".dll")) {
|
|
3199
|
+
const dllBase = path.basename(m.filePath).toLowerCase();
|
|
3200
|
+
for (const cn of ["package-cache.json", "local-package-cache.json"]) {
|
|
3201
|
+
const cp = path.join(projectPath, ".unity-agentic", cn);
|
|
3202
|
+
if (!import_fs6.existsSync(cp))
|
|
3203
|
+
continue;
|
|
3204
|
+
try {
|
|
3205
|
+
const c = JSON.parse(import_fs6.readFileSync(cp, "utf-8"));
|
|
3206
|
+
for (const [g, p] of Object.entries(c)) {
|
|
3207
|
+
if (p.toLowerCase().endsWith(".dll") && path.basename(p).toLowerCase() === dllBase) {
|
|
3208
|
+
guid = g;
|
|
3209
|
+
break;
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
} catch {}
|
|
3213
|
+
if (guid)
|
|
3214
|
+
break;
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
return guid ? { guid, path: m.filePath } : null;
|
|
3218
|
+
}).filter((r) => r !== null);
|
|
3219
|
+
const allResolved = [...withGuid.map((m) => ({ guid: m.guid, path: m.filePath })), ...resolvedFromMeta];
|
|
3220
|
+
if (allResolved.length === 1) {
|
|
3221
|
+
return allResolved[0];
|
|
3222
|
+
}
|
|
3223
|
+
if (allResolved.length > 1) {
|
|
3224
|
+
const pkgCachePaths = [
|
|
3225
|
+
path.join(projectPath, ".unity-agentic", "package-cache.json"),
|
|
3226
|
+
path.join(projectPath, ".unity-agentic", "local-package-cache.json")
|
|
3227
|
+
];
|
|
3228
|
+
for (const cachePath of pkgCachePaths) {
|
|
3229
|
+
if (!import_fs6.existsSync(cachePath))
|
|
3230
|
+
continue;
|
|
3231
|
+
try {
|
|
3232
|
+
const cache = JSON.parse(import_fs6.readFileSync(cachePath, "utf-8"));
|
|
3233
|
+
const inCache = allResolved.filter((r) => (r.guid in cache));
|
|
3234
|
+
if (inCache.length === 1)
|
|
3235
|
+
return inCache[0];
|
|
3236
|
+
} catch {}
|
|
3237
|
+
}
|
|
3238
|
+
const paths = allResolved.map((m) => m.path).join(", ");
|
|
3239
|
+
throw new Error(`Ambiguous type "${script}": found ${allResolved.length} matches (${paths}). ` + `Use a qualified name (e.g., "Namespace.${targetName}") or provide the full path.`);
|
|
3240
|
+
}
|
|
3092
3241
|
}
|
|
3093
3242
|
} catch {}
|
|
3094
3243
|
}
|
|
3095
|
-
const
|
|
3096
|
-
|
|
3244
|
+
const scriptNameLower = script.toLowerCase().replace(/\.cs$/, "");
|
|
3245
|
+
const dotIdx = scriptNameLower.lastIndexOf(".");
|
|
3246
|
+
const classNameOnly = dotIdx > 0 ? scriptNameLower.substring(dotIdx + 1) : null;
|
|
3247
|
+
const cachePaths = [
|
|
3248
|
+
path.join(projectPath, ".unity-agentic", "package-cache.json"),
|
|
3249
|
+
path.join(projectPath, ".unity-agentic", "local-package-cache.json")
|
|
3250
|
+
];
|
|
3251
|
+
for (const cachePath of cachePaths) {
|
|
3252
|
+
if (!import_fs6.existsSync(cachePath))
|
|
3253
|
+
continue;
|
|
3097
3254
|
try {
|
|
3098
|
-
const
|
|
3099
|
-
const
|
|
3100
|
-
for (const [guid, assetPath] of Object.entries(packageCache)) {
|
|
3255
|
+
const cache = JSON.parse(import_fs6.readFileSync(cachePath, "utf-8"));
|
|
3256
|
+
for (const [guid, assetPath] of Object.entries(cache)) {
|
|
3101
3257
|
if (!assetPath.endsWith(".cs"))
|
|
3102
3258
|
continue;
|
|
3103
3259
|
const fileName = path.basename(assetPath, ".cs").toLowerCase();
|
|
3104
|
-
if (fileName === scriptNameLower) {
|
|
3260
|
+
if (fileName === scriptNameLower || classNameOnly && fileName === classNameOnly) {
|
|
3105
3261
|
return { guid, path: assetPath };
|
|
3106
3262
|
}
|
|
3107
3263
|
}
|
|
@@ -3152,6 +3308,8 @@ function resolve_script_with_fields(script, project_path) {
|
|
|
3152
3308
|
result.fields = chosen.fields;
|
|
3153
3309
|
result.base_class = chosen.baseClass ?? undefined;
|
|
3154
3310
|
result.kind = chosen.kind;
|
|
3311
|
+
result.namespace = chosen.namespace ?? undefined;
|
|
3312
|
+
result.class_name = chosen.name;
|
|
3155
3313
|
}
|
|
3156
3314
|
} else {
|
|
3157
3315
|
result.extraction_error = "Native extractDllFields function not available";
|
|
@@ -3200,178 +3358,61 @@ function resolve_enum_fields(fields, project_path) {
|
|
|
3200
3358
|
}
|
|
3201
3359
|
} catch {}
|
|
3202
3360
|
}
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
String: "",
|
|
3224
|
-
Byte: "0",
|
|
3225
|
-
SByte: "0",
|
|
3226
|
-
Int16: "0",
|
|
3227
|
-
UInt16: "0",
|
|
3228
|
-
UInt32: "0",
|
|
3229
|
-
Int64: "0",
|
|
3230
|
-
UInt64: "0",
|
|
3231
|
-
Char: "0"
|
|
3232
|
-
};
|
|
3233
|
-
var STRUCT_DEFAULTS = {
|
|
3234
|
-
Vector2: "{x: 0, y: 0}",
|
|
3235
|
-
Vector3: "{x: 0, y: 0, z: 0}",
|
|
3236
|
-
Vector4: "{x: 0, y: 0, z: 0, w: 0}",
|
|
3237
|
-
Vector2Int: "{x: 0, y: 0}",
|
|
3238
|
-
Vector3Int: "{x: 0, y: 0, z: 0}",
|
|
3239
|
-
Quaternion: "{x: 0, y: 0, z: 0, w: 1}",
|
|
3240
|
-
Color: "{r: 0, g: 0, b: 0, a: 0}",
|
|
3241
|
-
Color32: "{r: 0, g: 0, b: 0, a: 0}",
|
|
3242
|
-
Rect: `serializedVersion: 2
|
|
3243
|
-
x: 0
|
|
3244
|
-
y: 0
|
|
3245
|
-
width: 0
|
|
3246
|
-
height: 0`,
|
|
3247
|
-
RectInt: "{x: 0, y: 0, width: 0, height: 0}",
|
|
3248
|
-
RectOffset: "{m_Left: 0, m_Right: 0, m_Top: 0, m_Bottom: 0}",
|
|
3249
|
-
Matrix4x4: "{e00: 1, e01: 0, e02: 0, e03: 0, e10: 0, e11: 1, e12: 0, e13: 0, e20: 0, e21: 0, e22: 1, e23: 0, e30: 0, e31: 0, e32: 0, e33: 1}",
|
|
3250
|
-
LayerMask: `serializedVersion: 2
|
|
3251
|
-
m_Bits: 0`
|
|
3252
|
-
};
|
|
3253
|
-
var VERSION_GATED_STRUCT_DEFAULTS = {
|
|
3254
|
-
Hash128: { value: `serializedVersion: 2
|
|
3255
|
-
Hash: 00000000000000000000000000000000`, min_major: 2021, min_minor: 1 },
|
|
3256
|
-
RenderingLayerMask: { value: `serializedVersion: 2
|
|
3257
|
-
m_Bits: 0`, min_major: 6000, min_minor: 0 }
|
|
3258
|
-
};
|
|
3259
|
-
var BLOCK_STRUCT_DEFAULTS = {
|
|
3260
|
-
Bounds: `m_Center: {x: 0, y: 0, z: 0}
|
|
3261
|
-
m_Extent: {x: 0, y: 0, z: 0}`,
|
|
3262
|
-
BoundsInt: `m_Position: {x: 0, y: 0, z: 0}
|
|
3263
|
-
m_Size: {x: 0, y: 0, z: 0}`
|
|
3264
|
-
};
|
|
3265
|
-
var OBJECT_REF_TYPES = new Set([
|
|
3266
|
-
"GameObject",
|
|
3267
|
-
"Transform",
|
|
3268
|
-
"RectTransform",
|
|
3269
|
-
"Material",
|
|
3270
|
-
"Texture",
|
|
3271
|
-
"Texture2D",
|
|
3272
|
-
"Texture3D",
|
|
3273
|
-
"RenderTexture",
|
|
3274
|
-
"Sprite",
|
|
3275
|
-
"AudioClip",
|
|
3276
|
-
"VideoClip",
|
|
3277
|
-
"Mesh",
|
|
3278
|
-
"Shader",
|
|
3279
|
-
"ComputeShader",
|
|
3280
|
-
"AnimationClip",
|
|
3281
|
-
"AnimatorController",
|
|
3282
|
-
"RuntimeAnimatorController",
|
|
3283
|
-
"PhysicMaterial",
|
|
3284
|
-
"PhysicsMaterial",
|
|
3285
|
-
"PhysicsMaterial2D",
|
|
3286
|
-
"Font",
|
|
3287
|
-
"TMP_FontAsset",
|
|
3288
|
-
"Object",
|
|
3289
|
-
"Component",
|
|
3290
|
-
"Behaviour",
|
|
3291
|
-
"MonoBehaviour",
|
|
3292
|
-
"ScriptableObject",
|
|
3293
|
-
"Rigidbody",
|
|
3294
|
-
"Rigidbody2D",
|
|
3295
|
-
"Collider",
|
|
3296
|
-
"Collider2D",
|
|
3297
|
-
"Camera",
|
|
3298
|
-
"Light",
|
|
3299
|
-
"Canvas",
|
|
3300
|
-
"CanvasGroup",
|
|
3301
|
-
"EventSystem",
|
|
3302
|
-
"AudioSource",
|
|
3303
|
-
"ParticleSystem",
|
|
3304
|
-
"TextAsset",
|
|
3305
|
-
"TerrainData"
|
|
3306
|
-
]);
|
|
3307
|
-
function version_at_least(version, min_major, min_minor) {
|
|
3308
|
-
if (!version)
|
|
3309
|
-
return false;
|
|
3310
|
-
if (version.major > min_major)
|
|
3311
|
-
return true;
|
|
3312
|
-
if (version.major === min_major)
|
|
3313
|
-
return version.minor >= min_minor;
|
|
3314
|
-
return false;
|
|
3315
|
-
}
|
|
3316
|
-
function yaml_default_for_type(csharp_type, version) {
|
|
3317
|
-
if (csharp_type.endsWith("?")) {
|
|
3318
|
-
return null;
|
|
3319
|
-
}
|
|
3320
|
-
if (csharp_type in PRIMITIVE_DEFAULTS) {
|
|
3321
|
-
return PRIMITIVE_DEFAULTS[csharp_type];
|
|
3322
|
-
}
|
|
3323
|
-
if (csharp_type in STRUCT_DEFAULTS) {
|
|
3324
|
-
return STRUCT_DEFAULTS[csharp_type];
|
|
3325
|
-
}
|
|
3326
|
-
if (csharp_type in VERSION_GATED_STRUCT_DEFAULTS) {
|
|
3327
|
-
const gated = VERSION_GATED_STRUCT_DEFAULTS[csharp_type];
|
|
3328
|
-
if (version_at_least(version, gated.min_major, gated.min_minor)) {
|
|
3329
|
-
return gated.value;
|
|
3361
|
+
function build_type_lookup(project_path) {
|
|
3362
|
+
let extractFn = null;
|
|
3363
|
+
try {
|
|
3364
|
+
const { getNativeExtractSerializedFields: getNativeExtractSerializedFields2 } = (init_scanner(), __toCommonJS(exports_scanner));
|
|
3365
|
+
extractFn = getNativeExtractSerializedFields2();
|
|
3366
|
+
} catch {}
|
|
3367
|
+
if (!extractFn)
|
|
3368
|
+
return () => null;
|
|
3369
|
+
const assetsDir = path.join(project_path, "Assets");
|
|
3370
|
+
const csIndex = new Map;
|
|
3371
|
+
try {
|
|
3372
|
+
const { readdirSync: readdirSync3 } = require("fs");
|
|
3373
|
+
const entries = readdirSync3(assetsDir, { recursive: true, withFileTypes: false });
|
|
3374
|
+
for (const entry of entries) {
|
|
3375
|
+
if (typeof entry === "string" && entry.endsWith(".cs")) {
|
|
3376
|
+
const basename3 = entry.substring(entry.lastIndexOf("/") + 1).replace(/\.cs$/, "");
|
|
3377
|
+
if (!csIndex.has(basename3)) {
|
|
3378
|
+
csIndex.set(basename3, path.join(assetsDir, entry));
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
3330
3381
|
}
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
return "{fileID: 0}";
|
|
3344
|
-
}
|
|
3345
|
-
return "{fileID: 0}";
|
|
3346
|
-
}
|
|
3347
|
-
function generate_field_yaml(fields, version, indent = " ") {
|
|
3348
|
-
const lines = [];
|
|
3349
|
-
for (const field of fields) {
|
|
3350
|
-
const default_value = yaml_default_for_type(field.typeName, version);
|
|
3351
|
-
if (default_value === null) {
|
|
3352
|
-
continue;
|
|
3382
|
+
} catch {}
|
|
3383
|
+
if (csIndex.size === 0)
|
|
3384
|
+
return () => null;
|
|
3385
|
+
const cache = new Map;
|
|
3386
|
+
return (typeName) => {
|
|
3387
|
+
if (cache.has(typeName))
|
|
3388
|
+
return cache.get(typeName) ?? null;
|
|
3389
|
+
const shortName = typeName.includes(".") ? typeName.substring(typeName.lastIndexOf(".") + 1) : typeName;
|
|
3390
|
+
const csPath = csIndex.get(shortName);
|
|
3391
|
+
if (!csPath || !import_fs6.existsSync(csPath)) {
|
|
3392
|
+
cache.set(typeName, null);
|
|
3393
|
+
return null;
|
|
3353
3394
|
}
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
lines.push(`${indent}${sub_line}`);
|
|
3395
|
+
try {
|
|
3396
|
+
const typeInfos = extractFn(csPath);
|
|
3397
|
+
if (!typeInfos || typeInfos.length === 0) {
|
|
3398
|
+
cache.set(typeName, null);
|
|
3399
|
+
return null;
|
|
3360
3400
|
}
|
|
3361
|
-
|
|
3362
|
-
|
|
3401
|
+
const match = typeInfos.find((t) => t.name === shortName);
|
|
3402
|
+
if (match && match.fields && match.fields.length > 0) {
|
|
3403
|
+
resolve_enum_fields(match.fields, project_path);
|
|
3404
|
+
cache.set(typeName, match.fields);
|
|
3405
|
+
return match.fields;
|
|
3406
|
+
}
|
|
3407
|
+
cache.set(typeName, null);
|
|
3408
|
+
return null;
|
|
3409
|
+
} catch {
|
|
3410
|
+
cache.set(typeName, null);
|
|
3411
|
+
return null;
|
|
3363
3412
|
}
|
|
3364
|
-
}
|
|
3365
|
-
return lines.length > 0 ? `
|
|
3366
|
-
` + lines.join(`
|
|
3367
|
-
`) + `
|
|
3368
|
-
` : `
|
|
3369
|
-
`;
|
|
3413
|
+
};
|
|
3370
3414
|
}
|
|
3371
3415
|
|
|
3372
|
-
// src/editor/unity-document.ts
|
|
3373
|
-
var import_fs7 = require("fs");
|
|
3374
|
-
|
|
3375
3416
|
// src/editor/unity-block.ts
|
|
3376
3417
|
var HEADER_PATTERN = /^--- !u!(\d+) &(-?\d+)(\s+stripped)?/;
|
|
3377
3418
|
function parse_header(raw) {
|
|
@@ -3390,6 +3431,17 @@ function parse_header(raw) {
|
|
|
3390
3431
|
function escape_regex(str) {
|
|
3391
3432
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3392
3433
|
}
|
|
3434
|
+
function yaml_quote_if_needed(value) {
|
|
3435
|
+
if (value === "")
|
|
3436
|
+
return value;
|
|
3437
|
+
if (value.startsWith("{") && value.endsWith("}") || value.startsWith("[") && value.endsWith("]")) {
|
|
3438
|
+
return value;
|
|
3439
|
+
}
|
|
3440
|
+
if (value.includes(": ") || value.includes(" #") || /^[#\{\[*&!|>'"]/.test(value) || value !== value.trim()) {
|
|
3441
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
3442
|
+
}
|
|
3443
|
+
return value;
|
|
3444
|
+
}
|
|
3393
3445
|
|
|
3394
3446
|
class UnityBlock {
|
|
3395
3447
|
_raw;
|
|
@@ -3425,6 +3477,7 @@ class UnityBlock {
|
|
|
3425
3477
|
return this._dirty;
|
|
3426
3478
|
}
|
|
3427
3479
|
get_property(path2) {
|
|
3480
|
+
path2 = normalize_property_path(path2);
|
|
3428
3481
|
if (path2.includes("Array.data[")) {
|
|
3429
3482
|
return this._get_array_element(path2);
|
|
3430
3483
|
}
|
|
@@ -3451,13 +3504,43 @@ class UnityBlock {
|
|
|
3451
3504
|
return match ? match[1].trim() : null;
|
|
3452
3505
|
}
|
|
3453
3506
|
set_property(path2, value, object_reference) {
|
|
3507
|
+
path2 = normalize_property_path(path2);
|
|
3454
3508
|
const old_raw = this._raw;
|
|
3455
3509
|
const effective_ref = object_reference && object_reference !== "{fileID: 0}" ? object_reference : undefined;
|
|
3456
3510
|
if (!path2.includes(".") && !path2.includes("Array")) {
|
|
3457
|
-
const prop_pattern = new RegExp(`(^\\s*${escape_regex(path2)}
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3511
|
+
const prop_pattern = new RegExp(`(^\\s*${escape_regex(path2)}:[ \\t]*)(.*)$`, "m");
|
|
3512
|
+
const match = this._raw.match(prop_pattern);
|
|
3513
|
+
if (match && match.index !== undefined) {
|
|
3514
|
+
const replacement_value = effective_ref ?? yaml_quote_if_needed(value);
|
|
3515
|
+
const current_inline = match[2];
|
|
3516
|
+
if (current_inline.trim() === "") {
|
|
3517
|
+
const key_indent = (match[0].match(/^[ \t]*/)?.[0] || "").length;
|
|
3518
|
+
const after = match.index + match[0].length;
|
|
3519
|
+
let end = after;
|
|
3520
|
+
const rest = this._raw.slice(after);
|
|
3521
|
+
const rest_lines = rest.split(`
|
|
3522
|
+
`);
|
|
3523
|
+
for (let i = 1;i < rest_lines.length; i++) {
|
|
3524
|
+
const line = rest_lines[i];
|
|
3525
|
+
if (line.trim() === "") {
|
|
3526
|
+
end += 1 + line.length;
|
|
3527
|
+
continue;
|
|
3528
|
+
}
|
|
3529
|
+
const line_indent = (line.match(/^[ \t]*/)?.[0] || "").length;
|
|
3530
|
+
if (line_indent > key_indent) {
|
|
3531
|
+
end += 1 + line.length;
|
|
3532
|
+
} else {
|
|
3533
|
+
break;
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3536
|
+
const prefix = match[1].trimEnd() + " ";
|
|
3537
|
+
this._raw = this._raw.slice(0, match.index) + prefix + replacement_value + this._raw.slice(end);
|
|
3538
|
+
} else {
|
|
3539
|
+
this._raw = this._raw.replace(prop_pattern, (_match, prefix) => prefix + replacement_value);
|
|
3540
|
+
}
|
|
3541
|
+
} else {
|
|
3542
|
+
const insert_value = effective_ref ?? yaml_quote_if_needed(value);
|
|
3543
|
+
this._insert_property(path2, insert_value);
|
|
3461
3544
|
}
|
|
3462
3545
|
return this._check_dirty(old_raw);
|
|
3463
3546
|
}
|
|
@@ -3472,8 +3555,8 @@ class UnityBlock {
|
|
|
3472
3555
|
const fields = inline_match[2];
|
|
3473
3556
|
const field_pattern = new RegExp(`(${escape_regex(sub_field)}:\\s*)([^,}]+)`);
|
|
3474
3557
|
if (field_pattern.test(fields)) {
|
|
3475
|
-
const updated_fields = fields.replace(field_pattern,
|
|
3476
|
-
this._raw = this._raw.replace(inline_pattern,
|
|
3558
|
+
const updated_fields = fields.replace(field_pattern, (_m, prefix) => prefix + value);
|
|
3559
|
+
this._raw = this._raw.replace(inline_pattern, (_m, g1, _g2, g3) => g1 + updated_fields + g3);
|
|
3477
3560
|
inline_applied = true;
|
|
3478
3561
|
}
|
|
3479
3562
|
}
|
|
@@ -3482,6 +3565,8 @@ class UnityBlock {
|
|
|
3482
3565
|
const block_result = this._resolve_block_style_path(parts, effective_value);
|
|
3483
3566
|
if (block_result !== null) {
|
|
3484
3567
|
this._raw = block_result;
|
|
3568
|
+
} else if (parts.length === 2) {
|
|
3569
|
+
this._insert_struct_property(parent_prop, sub_field, effective_value);
|
|
3485
3570
|
}
|
|
3486
3571
|
}
|
|
3487
3572
|
return this._check_dirty(old_raw);
|
|
@@ -3499,7 +3584,7 @@ class UnityBlock {
|
|
|
3499
3584
|
`).filter((l) => l.trim().startsWith("-"));
|
|
3500
3585
|
if (index < lines.length) {
|
|
3501
3586
|
const old_line = lines[index];
|
|
3502
|
-
const new_line = old_line.replace(/-\s*.*/, `- ${ref_value}`);
|
|
3587
|
+
const new_line = old_line.replace(/-\s*.*/, () => `- ${ref_value}`);
|
|
3503
3588
|
this._raw = this._raw.replace(old_line, new_line);
|
|
3504
3589
|
}
|
|
3505
3590
|
}
|
|
@@ -3508,6 +3593,49 @@ class UnityBlock {
|
|
|
3508
3593
|
}
|
|
3509
3594
|
return false;
|
|
3510
3595
|
}
|
|
3596
|
+
_insert_property(path2, value) {
|
|
3597
|
+
const alt = path2.startsWith("m_") ? path2.slice(2) : "m_" + path2;
|
|
3598
|
+
const alt_pattern = new RegExp(`^\\s*${escape_regex(alt)}:`, "m");
|
|
3599
|
+
if (alt_pattern.test(this._raw)) {
|
|
3600
|
+
return;
|
|
3601
|
+
}
|
|
3602
|
+
const indented_line = ` ${path2}: ${value}`;
|
|
3603
|
+
const eci_pattern = /^([ \t]*m_EditorClassIdentifier:[ \t]*[^\n]*)/m;
|
|
3604
|
+
const eci_match = this._raw.match(eci_pattern);
|
|
3605
|
+
if (eci_match && eci_match.index !== undefined) {
|
|
3606
|
+
const insert_after = eci_match.index + eci_match[0].length;
|
|
3607
|
+
this._raw = this._raw.slice(0, insert_after) + `
|
|
3608
|
+
` + indented_line + this._raw.slice(insert_after);
|
|
3609
|
+
return;
|
|
3610
|
+
}
|
|
3611
|
+
this._raw = this._raw.trimEnd() + `
|
|
3612
|
+
` + indented_line + `
|
|
3613
|
+
`;
|
|
3614
|
+
}
|
|
3615
|
+
_insert_struct_property(parent, child, value) {
|
|
3616
|
+
const parent_pattern = new RegExp(`^[ ]*${escape_regex(parent)}:`, "m");
|
|
3617
|
+
if (parent_pattern.test(this._raw)) {
|
|
3618
|
+
return;
|
|
3619
|
+
}
|
|
3620
|
+
const alt = parent.startsWith("m_") ? parent.slice(2) : "m_" + parent;
|
|
3621
|
+
const alt_pattern = new RegExp(`^[ \\t]*${escape_regex(alt)}:`, "m");
|
|
3622
|
+
if (alt_pattern.test(this._raw)) {
|
|
3623
|
+
return;
|
|
3624
|
+
}
|
|
3625
|
+
const struct_block = ` ${parent}:
|
|
3626
|
+
${child}: ${value}`;
|
|
3627
|
+
const eci_pattern = /^([ \t]*m_EditorClassIdentifier:[ \t]*[^\n]*)/m;
|
|
3628
|
+
const eci_match = this._raw.match(eci_pattern);
|
|
3629
|
+
if (eci_match && eci_match.index !== undefined) {
|
|
3630
|
+
const insert_after = eci_match.index + eci_match[0].length;
|
|
3631
|
+
this._raw = this._raw.slice(0, insert_after) + `
|
|
3632
|
+
` + struct_block + this._raw.slice(insert_after);
|
|
3633
|
+
return;
|
|
3634
|
+
}
|
|
3635
|
+
this._raw = this._raw.trimEnd() + `
|
|
3636
|
+
` + struct_block + `
|
|
3637
|
+
`;
|
|
3638
|
+
}
|
|
3511
3639
|
has_property(path2) {
|
|
3512
3640
|
return this.get_property(path2) !== null;
|
|
3513
3641
|
}
|
|
@@ -3563,7 +3691,7 @@ class UnityBlock {
|
|
|
3563
3691
|
if (empty_match) {
|
|
3564
3692
|
const base_indent = empty_match[2];
|
|
3565
3693
|
const element_indent2 = base_indent + " ";
|
|
3566
|
-
this._raw = this._raw.replace(empty_pattern, `$
|
|
3694
|
+
this._raw = this._raw.replace(empty_pattern, (_m, g1) => `${g1}
|
|
3567
3695
|
${element_indent2}- ${value}`);
|
|
3568
3696
|
return this._check_dirty(old_raw);
|
|
3569
3697
|
}
|
|
@@ -3794,83 +3922,361 @@ ${element_indent2}- ${value}`);
|
|
|
3794
3922
|
return match[1].trim();
|
|
3795
3923
|
}
|
|
3796
3924
|
}
|
|
3797
|
-
return null;
|
|
3798
|
-
}
|
|
3799
|
-
_resolve_block_style_path(segments, value) {
|
|
3800
|
-
const lines = this._raw.split(`
|
|
3925
|
+
return null;
|
|
3926
|
+
}
|
|
3927
|
+
_resolve_block_style_path(segments, value) {
|
|
3928
|
+
const lines = this._raw.split(`
|
|
3929
|
+
`);
|
|
3930
|
+
let search_start = 0;
|
|
3931
|
+
let search_end = lines.length;
|
|
3932
|
+
for (let seg = 0;seg < segments.length - 1; seg++) {
|
|
3933
|
+
const segment = segments[seg];
|
|
3934
|
+
let parent_idx = -1;
|
|
3935
|
+
let parent_indent = -1;
|
|
3936
|
+
for (let i = search_start;i < search_end; i++) {
|
|
3937
|
+
const match = lines[i].match(new RegExp(`^(\\s*)${escape_regex(segment)}:\\s*(.*)$`));
|
|
3938
|
+
if (match) {
|
|
3939
|
+
const trailing = match[2].trim();
|
|
3940
|
+
if (trailing === "") {
|
|
3941
|
+
parent_idx = i;
|
|
3942
|
+
parent_indent = match[1].length;
|
|
3943
|
+
break;
|
|
3944
|
+
}
|
|
3945
|
+
for (let j = i + 1;j < search_end; j++) {
|
|
3946
|
+
if (lines[j].trim() === "")
|
|
3947
|
+
continue;
|
|
3948
|
+
const nextLeading = lines[j].match(/^(\s*)/);
|
|
3949
|
+
if (nextLeading && nextLeading[1].length > match[1].length) {
|
|
3950
|
+
parent_idx = i;
|
|
3951
|
+
parent_indent = match[1].length;
|
|
3952
|
+
}
|
|
3953
|
+
break;
|
|
3954
|
+
}
|
|
3955
|
+
if (parent_idx !== -1)
|
|
3956
|
+
break;
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
if (parent_idx === -1)
|
|
3960
|
+
return null;
|
|
3961
|
+
let child_indent = -1;
|
|
3962
|
+
for (let i = parent_idx + 1;i < search_end; i++) {
|
|
3963
|
+
if (lines[i].trim() === "")
|
|
3964
|
+
continue;
|
|
3965
|
+
const leading_spaces = lines[i].match(/^(\s*)/);
|
|
3966
|
+
if (leading_spaces) {
|
|
3967
|
+
const indent = leading_spaces[1].length;
|
|
3968
|
+
if (indent > parent_indent) {
|
|
3969
|
+
child_indent = indent;
|
|
3970
|
+
break;
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3973
|
+
break;
|
|
3974
|
+
}
|
|
3975
|
+
if (child_indent === -1)
|
|
3976
|
+
return null;
|
|
3977
|
+
search_start = parent_idx + 1;
|
|
3978
|
+
for (let i = parent_idx + 1;i < search_end; i++) {
|
|
3979
|
+
if (lines[i].trim() === "")
|
|
3980
|
+
continue;
|
|
3981
|
+
const leading_spaces = lines[i].match(/^(\s*)/);
|
|
3982
|
+
if (leading_spaces && leading_spaces[1].length < child_indent) {
|
|
3983
|
+
search_end = i;
|
|
3984
|
+
break;
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
}
|
|
3988
|
+
const final_prop = segments[segments.length - 1];
|
|
3989
|
+
for (let i = search_start;i < search_end; i++) {
|
|
3990
|
+
const match = lines[i].match(new RegExp(`^(\\s*${escape_regex(final_prop)}:\\s*).+$`));
|
|
3991
|
+
if (match) {
|
|
3992
|
+
lines[i] = match[1] + value;
|
|
3993
|
+
return lines.join(`
|
|
3994
|
+
`);
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
return null;
|
|
3998
|
+
}
|
|
3999
|
+
}
|
|
4000
|
+
|
|
4001
|
+
// src/editor/yaml-fields.ts
|
|
4002
|
+
var PRIMITIVE_DEFAULTS = {
|
|
4003
|
+
int: "0",
|
|
4004
|
+
float: "0",
|
|
4005
|
+
double: "0",
|
|
4006
|
+
bool: "0",
|
|
4007
|
+
string: "",
|
|
4008
|
+
byte: "0",
|
|
4009
|
+
sbyte: "0",
|
|
4010
|
+
short: "0",
|
|
4011
|
+
ushort: "0",
|
|
4012
|
+
uint: "0",
|
|
4013
|
+
long: "0",
|
|
4014
|
+
ulong: "0",
|
|
4015
|
+
char: "0",
|
|
4016
|
+
Int32: "0",
|
|
4017
|
+
Single: "0",
|
|
4018
|
+
Double: "0",
|
|
4019
|
+
Boolean: "0",
|
|
4020
|
+
String: "",
|
|
4021
|
+
Byte: "0",
|
|
4022
|
+
SByte: "0",
|
|
4023
|
+
Int16: "0",
|
|
4024
|
+
UInt16: "0",
|
|
4025
|
+
UInt32: "0",
|
|
4026
|
+
Int64: "0",
|
|
4027
|
+
UInt64: "0",
|
|
4028
|
+
Char: "0"
|
|
4029
|
+
};
|
|
4030
|
+
var STRUCT_DEFAULTS = {
|
|
4031
|
+
Vector2: "{x: 0, y: 0}",
|
|
4032
|
+
Vector3: "{x: 0, y: 0, z: 0}",
|
|
4033
|
+
Vector4: "{x: 0, y: 0, z: 0, w: 0}",
|
|
4034
|
+
Vector2Int: "{x: 0, y: 0}",
|
|
4035
|
+
Vector3Int: "{x: 0, y: 0, z: 0}",
|
|
4036
|
+
Quaternion: "{x: 0, y: 0, z: 0, w: 1}",
|
|
4037
|
+
Color: "{r: 0, g: 0, b: 0, a: 0}",
|
|
4038
|
+
Color32: "{r: 0, g: 0, b: 0, a: 0}",
|
|
4039
|
+
Rect: `serializedVersion: 2
|
|
4040
|
+
x: 0
|
|
4041
|
+
y: 0
|
|
4042
|
+
width: 0
|
|
4043
|
+
height: 0`,
|
|
4044
|
+
RectInt: "{x: 0, y: 0, width: 0, height: 0}",
|
|
4045
|
+
RectOffset: "{m_Left: 0, m_Right: 0, m_Top: 0, m_Bottom: 0}",
|
|
4046
|
+
Matrix4x4: "{e00: 1, e01: 0, e02: 0, e03: 0, e10: 0, e11: 1, e12: 0, e13: 0, e20: 0, e21: 0, e22: 1, e23: 0, e30: 0, e31: 0, e32: 0, e33: 1}",
|
|
4047
|
+
LayerMask: `serializedVersion: 2
|
|
4048
|
+
m_Bits: 0`
|
|
4049
|
+
};
|
|
4050
|
+
var VERSION_GATED_STRUCT_DEFAULTS = {
|
|
4051
|
+
Hash128: { value: `serializedVersion: 2
|
|
4052
|
+
Hash: 00000000000000000000000000000000`, min_major: 2021, min_minor: 1 },
|
|
4053
|
+
RenderingLayerMask: { value: `serializedVersion: 2
|
|
4054
|
+
m_Bits: 0`, min_major: 6000, min_minor: 0 }
|
|
4055
|
+
};
|
|
4056
|
+
var BLOCK_STRUCT_DEFAULTS = {
|
|
4057
|
+
Bounds: `m_Center: {x: 0, y: 0, z: 0}
|
|
4058
|
+
m_Extent: {x: 0, y: 0, z: 0}`,
|
|
4059
|
+
BoundsInt: `m_Position: {x: 0, y: 0, z: 0}
|
|
4060
|
+
m_Size: {x: 0, y: 0, z: 0}`
|
|
4061
|
+
};
|
|
4062
|
+
var OBJECT_REF_TYPES = new Set([
|
|
4063
|
+
"GameObject",
|
|
4064
|
+
"Transform",
|
|
4065
|
+
"RectTransform",
|
|
4066
|
+
"Material",
|
|
4067
|
+
"Texture",
|
|
4068
|
+
"Texture2D",
|
|
4069
|
+
"Texture3D",
|
|
4070
|
+
"RenderTexture",
|
|
4071
|
+
"Sprite",
|
|
4072
|
+
"AudioClip",
|
|
4073
|
+
"VideoClip",
|
|
4074
|
+
"Mesh",
|
|
4075
|
+
"Shader",
|
|
4076
|
+
"ComputeShader",
|
|
4077
|
+
"AnimationClip",
|
|
4078
|
+
"AnimatorController",
|
|
4079
|
+
"RuntimeAnimatorController",
|
|
4080
|
+
"PhysicMaterial",
|
|
4081
|
+
"PhysicsMaterial",
|
|
4082
|
+
"PhysicsMaterial2D",
|
|
4083
|
+
"Font",
|
|
4084
|
+
"TMP_FontAsset",
|
|
4085
|
+
"Object",
|
|
4086
|
+
"Component",
|
|
4087
|
+
"Behaviour",
|
|
4088
|
+
"MonoBehaviour",
|
|
4089
|
+
"ScriptableObject",
|
|
4090
|
+
"Rigidbody",
|
|
4091
|
+
"Rigidbody2D",
|
|
4092
|
+
"Collider",
|
|
4093
|
+
"Collider2D",
|
|
4094
|
+
"Camera",
|
|
4095
|
+
"Light",
|
|
4096
|
+
"Canvas",
|
|
4097
|
+
"CanvasGroup",
|
|
4098
|
+
"EventSystem",
|
|
4099
|
+
"AudioSource",
|
|
4100
|
+
"ParticleSystem",
|
|
4101
|
+
"TextAsset",
|
|
4102
|
+
"TerrainData"
|
|
4103
|
+
]);
|
|
4104
|
+
function version_at_least(version, min_major, min_minor) {
|
|
4105
|
+
if (!version)
|
|
4106
|
+
return false;
|
|
4107
|
+
if (version.major > min_major)
|
|
4108
|
+
return true;
|
|
4109
|
+
if (version.major === min_major)
|
|
4110
|
+
return version.minor >= min_minor;
|
|
4111
|
+
return false;
|
|
4112
|
+
}
|
|
4113
|
+
function yaml_default_for_type(csharp_type, version) {
|
|
4114
|
+
if (csharp_type.endsWith("?")) {
|
|
4115
|
+
return null;
|
|
4116
|
+
}
|
|
4117
|
+
if (csharp_type in PRIMITIVE_DEFAULTS) {
|
|
4118
|
+
return PRIMITIVE_DEFAULTS[csharp_type];
|
|
4119
|
+
}
|
|
4120
|
+
if (csharp_type in STRUCT_DEFAULTS) {
|
|
4121
|
+
return STRUCT_DEFAULTS[csharp_type];
|
|
4122
|
+
}
|
|
4123
|
+
if (csharp_type in VERSION_GATED_STRUCT_DEFAULTS) {
|
|
4124
|
+
const gated = VERSION_GATED_STRUCT_DEFAULTS[csharp_type];
|
|
4125
|
+
if (version_at_least(version, gated.min_major, gated.min_minor)) {
|
|
4126
|
+
return gated.value;
|
|
4127
|
+
}
|
|
4128
|
+
return null;
|
|
4129
|
+
}
|
|
4130
|
+
if (csharp_type in BLOCK_STRUCT_DEFAULTS) {
|
|
4131
|
+
return BLOCK_STRUCT_DEFAULTS[csharp_type];
|
|
4132
|
+
}
|
|
4133
|
+
if (csharp_type.endsWith("[]")) {
|
|
4134
|
+
return "[]";
|
|
4135
|
+
}
|
|
4136
|
+
if (csharp_type.startsWith("List<") && csharp_type.endsWith(">")) {
|
|
4137
|
+
return "[]";
|
|
4138
|
+
}
|
|
4139
|
+
if (OBJECT_REF_TYPES.has(csharp_type)) {
|
|
4140
|
+
return "{fileID: 0}";
|
|
4141
|
+
}
|
|
4142
|
+
return "{fileID: 0}";
|
|
4143
|
+
}
|
|
4144
|
+
function generate_field_yaml(fields, version, indent = " ", type_lookup) {
|
|
4145
|
+
const lines = [];
|
|
4146
|
+
for (const field of fields) {
|
|
4147
|
+
if (field.hasSerializeReference) {
|
|
4148
|
+
const t = field.typeName;
|
|
4149
|
+
if (t.endsWith("[]") || t.startsWith("List<") && t.endsWith(">")) {
|
|
4150
|
+
lines.push(`${indent}${field.name}: []`);
|
|
4151
|
+
} else {
|
|
4152
|
+
lines.push(`${indent}${field.name}:`);
|
|
4153
|
+
lines.push(`${indent} rid: 0`);
|
|
4154
|
+
}
|
|
4155
|
+
continue;
|
|
4156
|
+
}
|
|
4157
|
+
const default_value = yaml_default_for_type(field.typeName, version);
|
|
4158
|
+
if (default_value === null) {
|
|
4159
|
+
continue;
|
|
4160
|
+
}
|
|
4161
|
+
if (default_value === "{fileID: 0}" && type_lookup) {
|
|
4162
|
+
const struct_fields = type_lookup(field.typeName);
|
|
4163
|
+
if (struct_fields && struct_fields.length > 0) {
|
|
4164
|
+
lines.push(`${indent}${field.name}:`);
|
|
4165
|
+
const nested = generate_field_yaml(struct_fields, version, indent + " ", type_lookup);
|
|
4166
|
+
const nested_lines = nested.slice(1).replace(/\n$/, "").split(`
|
|
3801
4167
|
`);
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
for (let seg = 0;seg < segments.length - 1; seg++) {
|
|
3805
|
-
const segment = segments[seg];
|
|
3806
|
-
let parent_idx = -1;
|
|
3807
|
-
let parent_indent = -1;
|
|
3808
|
-
for (let i = search_start;i < search_end; i++) {
|
|
3809
|
-
const match = lines[i].match(new RegExp(`^(\\s*)${escape_regex(segment)}:\\s*(.*)$`));
|
|
3810
|
-
if (match) {
|
|
3811
|
-
const trailing = match[2].trim();
|
|
3812
|
-
if (trailing === "") {
|
|
3813
|
-
parent_idx = i;
|
|
3814
|
-
parent_indent = match[1].length;
|
|
3815
|
-
break;
|
|
3816
|
-
}
|
|
3817
|
-
for (let j = i + 1;j < search_end; j++) {
|
|
3818
|
-
if (lines[j].trim() === "")
|
|
3819
|
-
continue;
|
|
3820
|
-
const nextLeading = lines[j].match(/^(\s*)/);
|
|
3821
|
-
if (nextLeading && nextLeading[1].length > match[1].length) {
|
|
3822
|
-
parent_idx = i;
|
|
3823
|
-
parent_indent = match[1].length;
|
|
3824
|
-
}
|
|
3825
|
-
break;
|
|
3826
|
-
}
|
|
3827
|
-
if (parent_idx !== -1)
|
|
3828
|
-
break;
|
|
3829
|
-
}
|
|
3830
|
-
}
|
|
3831
|
-
if (parent_idx === -1)
|
|
3832
|
-
return null;
|
|
3833
|
-
let child_indent = -1;
|
|
3834
|
-
for (let i = parent_idx + 1;i < search_end; i++) {
|
|
3835
|
-
if (lines[i].trim() === "")
|
|
3836
|
-
continue;
|
|
3837
|
-
const leading_spaces = lines[i].match(/^(\s*)/);
|
|
3838
|
-
if (leading_spaces) {
|
|
3839
|
-
const indent = leading_spaces[1].length;
|
|
3840
|
-
if (indent > parent_indent) {
|
|
3841
|
-
child_indent = indent;
|
|
3842
|
-
break;
|
|
3843
|
-
}
|
|
4168
|
+
for (const nl of nested_lines) {
|
|
4169
|
+
lines.push(nl);
|
|
3844
4170
|
}
|
|
3845
|
-
|
|
4171
|
+
continue;
|
|
3846
4172
|
}
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
if (leading_spaces && leading_spaces[1].length < child_indent) {
|
|
3855
|
-
search_end = i;
|
|
3856
|
-
break;
|
|
3857
|
-
}
|
|
4173
|
+
}
|
|
4174
|
+
if (default_value.includes(`
|
|
4175
|
+
`)) {
|
|
4176
|
+
lines.push(`${indent}${field.name}:`);
|
|
4177
|
+
for (const sub_line of default_value.split(`
|
|
4178
|
+
`)) {
|
|
4179
|
+
lines.push(`${indent}${sub_line}`);
|
|
3858
4180
|
}
|
|
4181
|
+
} else {
|
|
4182
|
+
lines.push(`${indent}${field.name}: ${default_value}`);
|
|
3859
4183
|
}
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
4184
|
+
}
|
|
4185
|
+
return lines.length > 0 ? `
|
|
4186
|
+
` + lines.join(`
|
|
4187
|
+
`) + `
|
|
4188
|
+
` : `
|
|
4189
|
+
`;
|
|
4190
|
+
}
|
|
4191
|
+
function json_value_to_yaml_lines(value, indent = " ") {
|
|
4192
|
+
if (value === null || value === undefined) {
|
|
4193
|
+
return [""];
|
|
4194
|
+
}
|
|
4195
|
+
if (typeof value === "string") {
|
|
4196
|
+
return [yaml_quote_if_needed(value)];
|
|
4197
|
+
}
|
|
4198
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
4199
|
+
return [String(value)];
|
|
4200
|
+
}
|
|
4201
|
+
if (Array.isArray(value)) {
|
|
4202
|
+
if (value.length === 0)
|
|
4203
|
+
return ["[]"];
|
|
4204
|
+
const lines = [];
|
|
4205
|
+
for (const item of value) {
|
|
4206
|
+
if (is_scalar(item) || is_empty_collection(item)) {
|
|
4207
|
+
const scalar = json_value_to_yaml_lines(item);
|
|
4208
|
+
lines.push(`${indent}- ${scalar[0]}`);
|
|
4209
|
+
} else if (is_flow_mappable(item)) {
|
|
4210
|
+
lines.push(`${indent}- ${to_flow_mapping(item)}`);
|
|
4211
|
+
} else {
|
|
4212
|
+
const child_lines = json_value_to_yaml_lines(item, indent + " ");
|
|
4213
|
+
lines.push(`${indent}- ${child_lines[0].trimStart()}`);
|
|
4214
|
+
for (let i = 1;i < child_lines.length; i++) {
|
|
4215
|
+
lines.push(child_lines[i]);
|
|
4216
|
+
}
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
return lines;
|
|
4220
|
+
}
|
|
4221
|
+
if (typeof value === "object") {
|
|
4222
|
+
const entries = Object.entries(value);
|
|
4223
|
+
if (entries.length === 0)
|
|
4224
|
+
return ["{}"];
|
|
4225
|
+
const lines = [];
|
|
4226
|
+
for (const [key, val] of entries) {
|
|
4227
|
+
if (is_scalar(val) || is_empty_collection(val)) {
|
|
4228
|
+
const scalar = json_value_to_yaml_lines(val);
|
|
4229
|
+
lines.push(`${indent}${key}: ${scalar[0]}`);
|
|
4230
|
+
} else if (is_flow_mappable(val)) {
|
|
4231
|
+
lines.push(`${indent}${key}: ${to_flow_mapping(val)}`);
|
|
4232
|
+
} else {
|
|
4233
|
+
const child_indent = Array.isArray(val) ? indent : indent + " ";
|
|
4234
|
+
lines.push(`${indent}${key}:`);
|
|
4235
|
+
const child_lines = json_value_to_yaml_lines(val, child_indent);
|
|
4236
|
+
for (const cl of child_lines) {
|
|
4237
|
+
lines.push(cl);
|
|
4238
|
+
}
|
|
3867
4239
|
}
|
|
3868
4240
|
}
|
|
3869
|
-
return
|
|
4241
|
+
return lines;
|
|
3870
4242
|
}
|
|
4243
|
+
return [String(value)];
|
|
4244
|
+
}
|
|
4245
|
+
function is_scalar(value) {
|
|
4246
|
+
return value === null || value === undefined || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
4247
|
+
}
|
|
4248
|
+
function is_empty_collection(value) {
|
|
4249
|
+
if (Array.isArray(value))
|
|
4250
|
+
return value.length === 0;
|
|
4251
|
+
if (typeof value === "object" && value !== null)
|
|
4252
|
+
return Object.keys(value).length === 0;
|
|
4253
|
+
return false;
|
|
4254
|
+
}
|
|
4255
|
+
function is_flow_mappable(value) {
|
|
4256
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
4257
|
+
return false;
|
|
4258
|
+
const entries = Object.entries(value);
|
|
4259
|
+
if (entries.length === 0)
|
|
4260
|
+
return false;
|
|
4261
|
+
return entries.every(([, v]) => is_scalar(v) || is_empty_collection(v));
|
|
4262
|
+
}
|
|
4263
|
+
function to_flow_mapping(obj) {
|
|
4264
|
+
const parts = Object.entries(obj).map(([k, v]) => {
|
|
4265
|
+
if (v === null || v === undefined)
|
|
4266
|
+
return `${k}: `;
|
|
4267
|
+
if (typeof v === "string")
|
|
4268
|
+
return `${k}: ${yaml_quote_if_needed(v)}`;
|
|
4269
|
+
if (Array.isArray(v) && v.length === 0)
|
|
4270
|
+
return `${k}: []`;
|
|
4271
|
+
if (typeof v === "object" && v !== null && Object.keys(v).length === 0)
|
|
4272
|
+
return `${k}: {}`;
|
|
4273
|
+
return `${k}: ${String(v)}`;
|
|
4274
|
+
});
|
|
4275
|
+
return `{${parts.join(", ")}}`;
|
|
3871
4276
|
}
|
|
3872
4277
|
|
|
3873
4278
|
// src/editor/unity-document.ts
|
|
4279
|
+
var import_fs7 = require("fs");
|
|
3874
4280
|
class UnityDocument {
|
|
3875
4281
|
file_path;
|
|
3876
4282
|
_header;
|
|
@@ -4508,6 +4914,20 @@ function get_project_info(projectPath) {
|
|
|
4508
4914
|
}
|
|
4509
4915
|
|
|
4510
4916
|
// src/editor/create.ts
|
|
4917
|
+
function compute_dll_script_file_id(namespace, class_name) {
|
|
4918
|
+
const { createHash } = require("crypto");
|
|
4919
|
+
const full_name = namespace ? `${namespace}.${class_name}` : class_name;
|
|
4920
|
+
const name_bytes = Buffer.from(full_name, "utf-8");
|
|
4921
|
+
const input = Buffer.alloc(4 + name_bytes.length);
|
|
4922
|
+
input.writeInt32LE(114, 0);
|
|
4923
|
+
name_bytes.copy(input, 4);
|
|
4924
|
+
const hash = createHash("md4").update(input).digest();
|
|
4925
|
+
const a = hash.readInt32LE(0);
|
|
4926
|
+
const b = hash.readInt32LE(4);
|
|
4927
|
+
const c = hash.readInt32LE(8);
|
|
4928
|
+
const d = hash.readInt32LE(12);
|
|
4929
|
+
return a ^ b ^ c ^ d;
|
|
4930
|
+
}
|
|
4511
4931
|
function get_layer_from_parent(doc, parentTransformId) {
|
|
4512
4932
|
if (parentTransformId === "0")
|
|
4513
4933
|
return 0;
|
|
@@ -4523,7 +4943,7 @@ function get_layer_from_parent(doc, parentTransformId) {
|
|
|
4523
4943
|
const layerMatch = parentGo.raw.match(/m_Layer:\s*(\d+)/);
|
|
4524
4944
|
return layerMatch ? parseInt(layerMatch[1], 10) : 0;
|
|
4525
4945
|
}
|
|
4526
|
-
function createGameObjectYAML(gameObjectId, transformId, name, parentTransformId = 0, rootOrder = 0, layer = 0) {
|
|
4946
|
+
function createGameObjectYAML(gameObjectId, transformId, name, parentTransformId = "0", rootOrder = 0, layer = 0) {
|
|
4527
4947
|
return `--- !u!1 &${gameObjectId}
|
|
4528
4948
|
GameObject:
|
|
4529
4949
|
m_ObjectHideFlags: 0
|
|
@@ -4584,9 +5004,9 @@ function findStrippedRootTransform(doc, prefabInstanceId) {
|
|
|
4584
5004
|
for (const block of doc.blocks) {
|
|
4585
5005
|
if (block.class_id !== 4 || !block.is_stripped)
|
|
4586
5006
|
continue;
|
|
4587
|
-
const piMatch = block.raw.match(/m_PrefabInstance
|
|
5007
|
+
const piMatch = block.raw.match(/m_PrefabInstance:[ \t]*\{fileID:[ \t]*(-?\d+)\}/);
|
|
4588
5008
|
if (piMatch && piMatch[1] === prefabInstanceId) {
|
|
4589
|
-
const sourceMatch = block.raw.match(/m_CorrespondingSourceObject
|
|
5009
|
+
const sourceMatch = block.raw.match(/m_CorrespondingSourceObject:[ \t]*(\{[^}]+\})/);
|
|
4590
5010
|
if (sourceMatch) {
|
|
4591
5011
|
return {
|
|
4592
5012
|
transformId: block.file_id,
|
|
@@ -4597,6 +5017,66 @@ function findStrippedRootTransform(doc, prefabInstanceId) {
|
|
|
4597
5017
|
}
|
|
4598
5018
|
return null;
|
|
4599
5019
|
}
|
|
5020
|
+
function find_game_object_in_variant(doc, name, file_path, project_path) {
|
|
5021
|
+
const pi_blocks = doc.find_by_class_id(1001);
|
|
5022
|
+
for (const pi_block of pi_blocks) {
|
|
5023
|
+
const mod_pattern = /- target:[ \t]*(\{[^}]+\})\s*propertyPath:[ \t]*m_Name\s*value:[ \t]*([^\n]*)/g;
|
|
5024
|
+
let mod_match;
|
|
5025
|
+
while ((mod_match = mod_pattern.exec(pi_block.raw)) !== null) {
|
|
5026
|
+
const target_ref = mod_match[1];
|
|
5027
|
+
const mod_value = mod_match[2].trim();
|
|
5028
|
+
if (mod_value !== name)
|
|
5029
|
+
continue;
|
|
5030
|
+
for (const block of doc.blocks) {
|
|
5031
|
+
if (block.class_id !== 1 || !block.is_stripped)
|
|
5032
|
+
continue;
|
|
5033
|
+
const source_match = block.raw.match(/m_CorrespondingSourceObject:[ \t]*(\{[^}]+\})/);
|
|
5034
|
+
if (!source_match)
|
|
5035
|
+
continue;
|
|
5036
|
+
const normalized_source = source_match[1].replace(/\s+/g, " ");
|
|
5037
|
+
const normalized_target = target_ref.replace(/\s+/g, " ");
|
|
5038
|
+
if (normalized_source === normalized_target) {
|
|
5039
|
+
return {
|
|
5040
|
+
stripped_go_id: block.file_id,
|
|
5041
|
+
source_ref: target_ref,
|
|
5042
|
+
prefab_instance_id: pi_block.file_id
|
|
5043
|
+
};
|
|
5044
|
+
}
|
|
5045
|
+
}
|
|
5046
|
+
}
|
|
5047
|
+
}
|
|
5048
|
+
const source_info = resolve_source_prefab(doc, file_path, project_path);
|
|
5049
|
+
if (!source_info)
|
|
5050
|
+
return null;
|
|
5051
|
+
let source_doc;
|
|
5052
|
+
try {
|
|
5053
|
+
source_doc = UnityDocument.from_file(source_info.source_path);
|
|
5054
|
+
} catch {
|
|
5055
|
+
return null;
|
|
5056
|
+
}
|
|
5057
|
+
const source_gos = source_doc.find_game_objects_by_name(name);
|
|
5058
|
+
if (source_gos.length !== 1)
|
|
5059
|
+
return null;
|
|
5060
|
+
const source_go = source_gos[0];
|
|
5061
|
+
const source_go_file_id = source_go.file_id;
|
|
5062
|
+
const source_guid = source_info.source_guid;
|
|
5063
|
+
for (const block of doc.blocks) {
|
|
5064
|
+
if (block.class_id !== 1 || !block.is_stripped)
|
|
5065
|
+
continue;
|
|
5066
|
+
const source_match = block.raw.match(/m_CorrespondingSourceObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)[^}]*guid:[ \t]*([a-f0-9]{32})/);
|
|
5067
|
+
if (!source_match)
|
|
5068
|
+
continue;
|
|
5069
|
+
if (source_match[1] === source_go_file_id && source_match[2] === source_guid) {
|
|
5070
|
+
const source_ref = `{fileID: ${source_go_file_id}, guid: ${source_guid}, type: 3}`;
|
|
5071
|
+
return {
|
|
5072
|
+
stripped_go_id: block.file_id,
|
|
5073
|
+
source_ref,
|
|
5074
|
+
prefab_instance_id: source_info.prefab_instance_id
|
|
5075
|
+
};
|
|
5076
|
+
}
|
|
5077
|
+
}
|
|
5078
|
+
return null;
|
|
5079
|
+
}
|
|
4600
5080
|
function appendToAddedGameObjects(doc, piId, targetSourceRef, newGoId) {
|
|
4601
5081
|
const piBlock = doc.find_by_file_id(piId);
|
|
4602
5082
|
if (!piBlock)
|
|
@@ -4606,13 +5086,34 @@ function appendToAddedGameObjects(doc, piId, targetSourceRef, newGoId) {
|
|
|
4606
5086
|
insertIndex: -1
|
|
4607
5087
|
addedObject: {fileID: ${newGoId}}`;
|
|
4608
5088
|
let raw = piBlock.raw;
|
|
4609
|
-
const emptyPattern = /m_AddedGameObjects
|
|
5089
|
+
const emptyPattern = /m_AddedGameObjects:[ \t]*\[\]/;
|
|
4610
5090
|
if (emptyPattern.test(raw)) {
|
|
4611
5091
|
raw = raw.replace(emptyPattern, `m_AddedGameObjects:${entry}`);
|
|
4612
5092
|
piBlock.replace_raw(raw);
|
|
4613
5093
|
return;
|
|
4614
5094
|
}
|
|
4615
|
-
const existingPattern = /(m_AddedGameObjects
|
|
5095
|
+
const existingPattern = /(m_AddedGameObjects:[ \t]*\n(?:[ \t]+-[\s\S]*?(?=\n[ \t]+m_|$))*)/;
|
|
5096
|
+
if (existingPattern.test(raw)) {
|
|
5097
|
+
raw = raw.replace(existingPattern, `$1${entry}`);
|
|
5098
|
+
piBlock.replace_raw(raw);
|
|
5099
|
+
}
|
|
5100
|
+
}
|
|
5101
|
+
function appendToAddedComponents(doc, piId, targetSourceRef, newComponentId) {
|
|
5102
|
+
const piBlock = doc.find_by_file_id(piId);
|
|
5103
|
+
if (!piBlock)
|
|
5104
|
+
return;
|
|
5105
|
+
const entry = `
|
|
5106
|
+
- targetCorrespondingSourceObject: ${targetSourceRef}
|
|
5107
|
+
insertIndex: -1
|
|
5108
|
+
addedObject: {fileID: ${newComponentId}}`;
|
|
5109
|
+
let raw = piBlock.raw;
|
|
5110
|
+
const emptyPattern = /m_AddedComponents:[ \t]*\[\]/;
|
|
5111
|
+
if (emptyPattern.test(raw)) {
|
|
5112
|
+
raw = raw.replace(emptyPattern, `m_AddedComponents:${entry}`);
|
|
5113
|
+
piBlock.replace_raw(raw);
|
|
5114
|
+
return;
|
|
5115
|
+
}
|
|
5116
|
+
const existingPattern = /(m_AddedComponents:[ \t]*\n(?:[ \t]+-[\s\S]*?(?=\n[ \t]+m_|$))*)/;
|
|
4616
5117
|
if (existingPattern.test(raw)) {
|
|
4617
5118
|
raw = raw.replace(existingPattern, `$1${entry}`);
|
|
4618
5119
|
piBlock.replace_raw(raw);
|
|
@@ -4635,11 +5136,31 @@ var COMPONENT_DEFAULTS = {
|
|
|
4635
5136
|
m_Materials:
|
|
4636
5137
|
- {fileID: 0}`,
|
|
4637
5138
|
33: ` m_Mesh: {fileID: 0}`,
|
|
5139
|
+
50: ` m_BodyType: 0
|
|
5140
|
+
m_Mass: 1
|
|
5141
|
+
m_LinearDrag: 0
|
|
5142
|
+
m_AngularDrag: 0.05
|
|
5143
|
+
m_GravityScale: 1
|
|
5144
|
+
m_Interpolate: 0
|
|
5145
|
+
m_SleepingMode: 1
|
|
5146
|
+
m_CollisionDetection: 0`,
|
|
4638
5147
|
54: ` m_Mass: 1
|
|
4639
5148
|
m_Drag: 0
|
|
4640
5149
|
m_AngularDrag: 0.05
|
|
4641
5150
|
m_UseGravity: 1
|
|
4642
5151
|
m_IsKinematic: 0`,
|
|
5152
|
+
58: ` m_IsTrigger: 0
|
|
5153
|
+
m_Material: {fileID: 0}
|
|
5154
|
+
m_Offset: {x: 0, y: 0}
|
|
5155
|
+
m_Radius: 0.5`,
|
|
5156
|
+
60: ` m_IsTrigger: 0
|
|
5157
|
+
m_Material: {fileID: 0}
|
|
5158
|
+
m_Offset: {x: 0, y: 0}
|
|
5159
|
+
m_Points: []`,
|
|
5160
|
+
61: ` m_IsTrigger: 0
|
|
5161
|
+
m_Material: {fileID: 0}
|
|
5162
|
+
m_Offset: {x: 0, y: 0}
|
|
5163
|
+
m_Size: {x: 1, y: 1}`,
|
|
4643
5164
|
64: ` m_IsTrigger: 0
|
|
4644
5165
|
m_Convex: 0
|
|
4645
5166
|
m_CookingOptions: 30
|
|
@@ -4648,6 +5169,19 @@ var COMPONENT_DEFAULTS = {
|
|
|
4648
5169
|
m_Material: {fileID: 0}
|
|
4649
5170
|
m_Center: {x: 0, y: 0, z: 0}
|
|
4650
5171
|
m_Size: {x: 1, y: 1, z: 1}`,
|
|
5172
|
+
66: ` m_IsTrigger: 0
|
|
5173
|
+
m_Material: {fileID: 0}
|
|
5174
|
+
m_Offset: {x: 0, y: 0}
|
|
5175
|
+
m_GeometryType: 0`,
|
|
5176
|
+
68: ` m_IsTrigger: 0
|
|
5177
|
+
m_Material: {fileID: 0}
|
|
5178
|
+
m_Offset: {x: 0, y: 0}
|
|
5179
|
+
m_Points: []`,
|
|
5180
|
+
70: ` m_IsTrigger: 0
|
|
5181
|
+
m_Material: {fileID: 0}
|
|
5182
|
+
m_Offset: {x: 0, y: 0}
|
|
5183
|
+
m_Size: {x: 1, y: 1}
|
|
5184
|
+
m_Direction: 0`,
|
|
4651
5185
|
82: ` m_PlayOnAwake: 1
|
|
4652
5186
|
m_Volume: 1
|
|
4653
5187
|
m_Pitch: 1
|
|
@@ -4733,9 +5267,14 @@ function addComponentToGameObject(doc, gameObjectId, componentId) {
|
|
|
4733
5267
|
`);
|
|
4734
5268
|
goBlock.replace_raw(raw);
|
|
4735
5269
|
}
|
|
4736
|
-
function createMonoBehaviourYAML(componentId, gameObjectId, scriptGuid, fields, version) {
|
|
4737
|
-
const field_yaml = fields && fields.length > 0 ? generate_field_yaml(fields, version) : `
|
|
5270
|
+
function createMonoBehaviourYAML(componentId, gameObjectId, scriptGuid, fields, version, scriptFileId = 11500000, type_lookup) {
|
|
5271
|
+
const field_yaml = fields && fields.length > 0 ? generate_field_yaml(fields, version, " ", type_lookup) : `
|
|
4738
5272
|
`;
|
|
5273
|
+
const has_serialize_ref = fields?.some((f) => f.hasSerializeReference) ?? false;
|
|
5274
|
+
const references_section = has_serialize_ref ? ` references:
|
|
5275
|
+
version: 2
|
|
5276
|
+
RefIds: []
|
|
5277
|
+
` : "";
|
|
4739
5278
|
return `--- !u!114 &${componentId}
|
|
4740
5279
|
MonoBehaviour:
|
|
4741
5280
|
m_ObjectHideFlags: 0
|
|
@@ -4745,9 +5284,9 @@ MonoBehaviour:
|
|
|
4745
5284
|
m_GameObject: {fileID: ${gameObjectId}}
|
|
4746
5285
|
m_Enabled: 1
|
|
4747
5286
|
m_EditorHideFlags: 0
|
|
4748
|
-
m_Script: {fileID:
|
|
5287
|
+
m_Script: {fileID: ${scriptFileId}, guid: ${scriptGuid}, type: 3}
|
|
4749
5288
|
m_Name:
|
|
4750
|
-
m_EditorClassIdentifier:${field_yaml}`;
|
|
5289
|
+
m_EditorClassIdentifier:${field_yaml}${references_section}`;
|
|
4751
5290
|
}
|
|
4752
5291
|
function createGameObject(options) {
|
|
4753
5292
|
const { file_path, name, parent } = options;
|
|
@@ -4846,9 +5385,9 @@ function createGameObject(options) {
|
|
|
4846
5385
|
const layer = get_layer_from_parent(doc, parentTransformIdStr);
|
|
4847
5386
|
const gameObjectIdStr = doc.generate_file_id();
|
|
4848
5387
|
const transformIdStr = doc.generate_file_id();
|
|
4849
|
-
const gameObjectId =
|
|
4850
|
-
const transformId =
|
|
4851
|
-
const parentTransformId =
|
|
5388
|
+
const gameObjectId = gameObjectIdStr;
|
|
5389
|
+
const transformId = transformIdStr;
|
|
5390
|
+
const parentTransformId = parentTransformIdStr;
|
|
4852
5391
|
const newBlocks = createGameObjectYAML(gameObjectId, transformId, name.trim(), parentTransformId, rootOrder, layer);
|
|
4853
5392
|
doc.append_raw(newBlocks);
|
|
4854
5393
|
if (parentTransformIdStr !== "0" && !variantPiId) {
|
|
@@ -4870,7 +5409,7 @@ function createGameObject(options) {
|
|
|
4870
5409
|
file_path,
|
|
4871
5410
|
game_object_id: gameObjectId,
|
|
4872
5411
|
transform_id: transformId,
|
|
4873
|
-
prefab_instance_id: variantPiId
|
|
5412
|
+
prefab_instance_id: variantPiId || undefined
|
|
4874
5413
|
};
|
|
4875
5414
|
}
|
|
4876
5415
|
function createScene(options) {
|
|
@@ -5316,20 +5855,165 @@ function createPrefabVariant(options) {
|
|
|
5316
5855
|
const tempDoc = UnityDocument.from_string(`%YAML 1.1
|
|
5317
5856
|
%TAG !u! tag:unity3d.com,2011:
|
|
5318
5857
|
`);
|
|
5319
|
-
const prefabInstanceId =
|
|
5320
|
-
const strippedGoId =
|
|
5321
|
-
const strippedTransformId =
|
|
5858
|
+
const prefabInstanceId = tempDoc.generate_file_id();
|
|
5859
|
+
const strippedGoId = tempDoc.generate_file_id();
|
|
5860
|
+
const strippedTransformId = tempDoc.generate_file_id();
|
|
5322
5861
|
const finalName = variant_name || `${rootInfo.name} Variant`;
|
|
5323
5862
|
const variantYaml = `%YAML 1.1
|
|
5324
5863
|
%TAG !u! tag:unity3d.com,2011:
|
|
5325
5864
|
--- !u!1 &${strippedGoId} stripped
|
|
5326
5865
|
GameObject:
|
|
5327
|
-
m_CorrespondingSourceObject: {fileID: ${rootInfo.game_object.file_id}, guid: ${sourceGuid}, type: 3}
|
|
5866
|
+
m_CorrespondingSourceObject: {fileID: ${rootInfo.game_object.file_id}, guid: ${sourceGuid}, type: 3}
|
|
5867
|
+
m_PrefabInstance: {fileID: ${prefabInstanceId}}
|
|
5868
|
+
m_PrefabAsset: {fileID: 0}
|
|
5869
|
+
--- !u!4 &${strippedTransformId} stripped
|
|
5870
|
+
Transform:
|
|
5871
|
+
m_CorrespondingSourceObject: {fileID: ${rootInfo.transform.file_id}, guid: ${sourceGuid}, type: 3}
|
|
5872
|
+
m_PrefabInstance: {fileID: ${prefabInstanceId}}
|
|
5873
|
+
m_PrefabAsset: {fileID: 0}
|
|
5874
|
+
--- !u!1001 &${prefabInstanceId}
|
|
5875
|
+
PrefabInstance:
|
|
5876
|
+
m_ObjectHideFlags: 0
|
|
5877
|
+
serializedVersion: 2
|
|
5878
|
+
m_Modification:
|
|
5879
|
+
m_TransformParent: {fileID: 0}
|
|
5880
|
+
m_Modifications:
|
|
5881
|
+
- target: {fileID: ${rootInfo.game_object.file_id}, guid: ${sourceGuid}, type: 3}
|
|
5882
|
+
propertyPath: m_Name
|
|
5883
|
+
value: ${finalName}
|
|
5884
|
+
objectReference: {fileID: 0}
|
|
5885
|
+
m_RemovedComponents: []
|
|
5886
|
+
m_RemovedGameObjects: []
|
|
5887
|
+
m_AddedGameObjects: []
|
|
5888
|
+
m_AddedComponents: []
|
|
5889
|
+
m_SourcePrefab: {fileID: 100100000, guid: ${sourceGuid}, type: 3}
|
|
5890
|
+
`;
|
|
5891
|
+
try {
|
|
5892
|
+
import_fs8.writeFileSync(output_path, variantYaml, "utf-8");
|
|
5893
|
+
} catch (err) {
|
|
5894
|
+
return {
|
|
5895
|
+
success: false,
|
|
5896
|
+
output_path,
|
|
5897
|
+
error: `Failed to write variant prefab: ${err instanceof Error ? err.message : String(err)}`
|
|
5898
|
+
};
|
|
5899
|
+
}
|
|
5900
|
+
const variantGuid = generateGuid();
|
|
5901
|
+
const variantMetaContent = `fileFormatVersion: 2
|
|
5902
|
+
guid: ${variantGuid}
|
|
5903
|
+
PrefabImporter:
|
|
5904
|
+
externalObjects: {}
|
|
5905
|
+
userData:
|
|
5906
|
+
assetBundleName:
|
|
5907
|
+
assetBundleVariant:
|
|
5908
|
+
`;
|
|
5909
|
+
try {
|
|
5910
|
+
import_fs8.writeFileSync(output_path + ".meta", variantMetaContent, "utf-8");
|
|
5911
|
+
} catch (err) {
|
|
5912
|
+
try {
|
|
5913
|
+
const fs2 = require("fs");
|
|
5914
|
+
fs2.unlinkSync(output_path);
|
|
5915
|
+
} catch {}
|
|
5916
|
+
return {
|
|
5917
|
+
success: false,
|
|
5918
|
+
output_path,
|
|
5919
|
+
error: `Failed to write .meta file: ${err instanceof Error ? err.message : String(err)}`
|
|
5920
|
+
};
|
|
5921
|
+
}
|
|
5922
|
+
return {
|
|
5923
|
+
success: true,
|
|
5924
|
+
output_path,
|
|
5925
|
+
source_guid: sourceGuid,
|
|
5926
|
+
prefab_instance_id: prefabInstanceId
|
|
5927
|
+
};
|
|
5928
|
+
}
|
|
5929
|
+
function createPrefabInstance(options) {
|
|
5930
|
+
const { scene_path, prefab_path, name, parent, position } = options;
|
|
5931
|
+
const pathError = validate_file_path(scene_path, "write");
|
|
5932
|
+
if (pathError) {
|
|
5933
|
+
return { success: false, file_path: scene_path, error: pathError };
|
|
5934
|
+
}
|
|
5935
|
+
if (!scene_path.endsWith(".unity")) {
|
|
5936
|
+
return { success: false, file_path: scene_path, error: "Scene path must be a .unity file" };
|
|
5937
|
+
}
|
|
5938
|
+
if (!prefab_path.endsWith(".prefab")) {
|
|
5939
|
+
return { success: false, file_path: scene_path, error: "Prefab path must be a .prefab file" };
|
|
5940
|
+
}
|
|
5941
|
+
if (!import_fs8.existsSync(scene_path)) {
|
|
5942
|
+
return { success: false, file_path: scene_path, error: `Scene file not found: ${scene_path}` };
|
|
5943
|
+
}
|
|
5944
|
+
if (!import_fs8.existsSync(prefab_path)) {
|
|
5945
|
+
return { success: false, file_path: scene_path, error: `Prefab file not found: ${prefab_path}` };
|
|
5946
|
+
}
|
|
5947
|
+
const metaPath = prefab_path + ".meta";
|
|
5948
|
+
const sourceGuid = extractGuidFromMeta(metaPath);
|
|
5949
|
+
if (!sourceGuid) {
|
|
5950
|
+
return { success: false, file_path: scene_path, error: `Could not find or read .meta file for prefab: ${metaPath}` };
|
|
5951
|
+
}
|
|
5952
|
+
let prefabDoc;
|
|
5953
|
+
try {
|
|
5954
|
+
prefabDoc = UnityDocument.from_file(prefab_path);
|
|
5955
|
+
} catch (err) {
|
|
5956
|
+
return { success: false, file_path: scene_path, error: `Failed to read prefab: ${err instanceof Error ? err.message : String(err)}` };
|
|
5957
|
+
}
|
|
5958
|
+
const rootInfo = prefabDoc.find_prefab_root();
|
|
5959
|
+
if (!rootInfo) {
|
|
5960
|
+
return { success: false, file_path: scene_path, error: "Could not find root GameObject in source prefab" };
|
|
5961
|
+
}
|
|
5962
|
+
let doc;
|
|
5963
|
+
try {
|
|
5964
|
+
doc = UnityDocument.from_file(scene_path);
|
|
5965
|
+
} catch (err) {
|
|
5966
|
+
return { success: false, file_path: scene_path, error: `Failed to read scene: ${err instanceof Error ? err.message : String(err)}` };
|
|
5967
|
+
}
|
|
5968
|
+
let parentTransformIdStr = "0";
|
|
5969
|
+
if (parent !== undefined) {
|
|
5970
|
+
if (typeof parent === "number") {
|
|
5971
|
+
const parentIdStr = String(parent);
|
|
5972
|
+
const parentBlock = doc.find_by_file_id(parentIdStr);
|
|
5973
|
+
if (!parentBlock) {
|
|
5974
|
+
return { success: false, file_path: scene_path, error: `Parent with fileID ${parent} not found. Provide a GameObject or Transform fileID.` };
|
|
5975
|
+
}
|
|
5976
|
+
if (parentBlock.is_stripped) {
|
|
5977
|
+
return { success: false, file_path: scene_path, error: `Parent with fileID ${parent} is a stripped block (inside a PrefabInstance). Cannot parent to stripped transforms.` };
|
|
5978
|
+
}
|
|
5979
|
+
if (parentBlock.class_id === 4) {
|
|
5980
|
+
parentTransformIdStr = parentIdStr;
|
|
5981
|
+
} else if (parentBlock.class_id === 1) {
|
|
5982
|
+
const compMatch = parentBlock.raw.match(/m_Component:\s*\n\s*-\s*component:\s*\{fileID:\s*(\d+)\}/);
|
|
5983
|
+
if (compMatch) {
|
|
5984
|
+
parentTransformIdStr = compMatch[1];
|
|
5985
|
+
} else {
|
|
5986
|
+
return { success: false, file_path: scene_path, error: `Parent with fileID ${parent} has no Transform component.` };
|
|
5987
|
+
}
|
|
5988
|
+
} else {
|
|
5989
|
+
return { success: false, file_path: scene_path, error: `Parent with fileID ${parent} is not a GameObject or Transform.` };
|
|
5990
|
+
}
|
|
5991
|
+
} else {
|
|
5992
|
+
const foundResult = findTransformIdByName(doc, parent);
|
|
5993
|
+
if (foundResult === null) {
|
|
5994
|
+
return { success: false, file_path: scene_path, error: `Parent GameObject "${parent}" not found` };
|
|
5995
|
+
}
|
|
5996
|
+
if (typeof foundResult === "object") {
|
|
5997
|
+
return { success: false, file_path: scene_path, error: foundResult.error };
|
|
5998
|
+
}
|
|
5999
|
+
parentTransformIdStr = foundResult;
|
|
6000
|
+
}
|
|
6001
|
+
}
|
|
6002
|
+
const prefabInstanceId = doc.generate_file_id();
|
|
6003
|
+
const strippedGoId = doc.generate_file_id();
|
|
6004
|
+
const strippedTransformId = doc.generate_file_id();
|
|
6005
|
+
const instanceName = name || path3.basename(prefab_path, ".prefab");
|
|
6006
|
+
const pos = position ?? { x: 0, y: 0, z: 0 };
|
|
6007
|
+
const rootGoFileId = rootInfo.game_object.file_id;
|
|
6008
|
+
const rootTransformFileId = rootInfo.transform.file_id;
|
|
6009
|
+
const yaml = `--- !u!1 &${strippedGoId} stripped
|
|
6010
|
+
GameObject:
|
|
6011
|
+
m_CorrespondingSourceObject: {fileID: ${rootGoFileId}, guid: ${sourceGuid}, type: 3}
|
|
5328
6012
|
m_PrefabInstance: {fileID: ${prefabInstanceId}}
|
|
5329
6013
|
m_PrefabAsset: {fileID: 0}
|
|
5330
6014
|
--- !u!4 &${strippedTransformId} stripped
|
|
5331
6015
|
Transform:
|
|
5332
|
-
m_CorrespondingSourceObject: {fileID: ${
|
|
6016
|
+
m_CorrespondingSourceObject: {fileID: ${rootTransformFileId}, guid: ${sourceGuid}, type: 3}
|
|
5333
6017
|
m_PrefabInstance: {fileID: ${prefabInstanceId}}
|
|
5334
6018
|
m_PrefabAsset: {fileID: 0}
|
|
5335
6019
|
--- !u!1001 &${prefabInstanceId}
|
|
@@ -5337,11 +6021,51 @@ PrefabInstance:
|
|
|
5337
6021
|
m_ObjectHideFlags: 0
|
|
5338
6022
|
serializedVersion: 2
|
|
5339
6023
|
m_Modification:
|
|
5340
|
-
m_TransformParent: {fileID:
|
|
6024
|
+
m_TransformParent: {fileID: ${parentTransformIdStr}}
|
|
5341
6025
|
m_Modifications:
|
|
5342
|
-
- target: {fileID: ${
|
|
6026
|
+
- target: {fileID: ${rootGoFileId}, guid: ${sourceGuid}, type: 3}
|
|
5343
6027
|
propertyPath: m_Name
|
|
5344
|
-
value: ${
|
|
6028
|
+
value: ${instanceName}
|
|
6029
|
+
objectReference: {fileID: 0}
|
|
6030
|
+
- target: {fileID: ${rootTransformFileId}, guid: ${sourceGuid}, type: 3}
|
|
6031
|
+
propertyPath: m_LocalPosition.x
|
|
6032
|
+
value: ${pos.x}
|
|
6033
|
+
objectReference: {fileID: 0}
|
|
6034
|
+
- target: {fileID: ${rootTransformFileId}, guid: ${sourceGuid}, type: 3}
|
|
6035
|
+
propertyPath: m_LocalPosition.y
|
|
6036
|
+
value: ${pos.y}
|
|
6037
|
+
objectReference: {fileID: 0}
|
|
6038
|
+
- target: {fileID: ${rootTransformFileId}, guid: ${sourceGuid}, type: 3}
|
|
6039
|
+
propertyPath: m_LocalPosition.z
|
|
6040
|
+
value: ${pos.z}
|
|
6041
|
+
objectReference: {fileID: 0}
|
|
6042
|
+
- target: {fileID: ${rootTransformFileId}, guid: ${sourceGuid}, type: 3}
|
|
6043
|
+
propertyPath: m_LocalRotation.w
|
|
6044
|
+
value: 1
|
|
6045
|
+
objectReference: {fileID: 0}
|
|
6046
|
+
- target: {fileID: ${rootTransformFileId}, guid: ${sourceGuid}, type: 3}
|
|
6047
|
+
propertyPath: m_LocalRotation.x
|
|
6048
|
+
value: 0
|
|
6049
|
+
objectReference: {fileID: 0}
|
|
6050
|
+
- target: {fileID: ${rootTransformFileId}, guid: ${sourceGuid}, type: 3}
|
|
6051
|
+
propertyPath: m_LocalRotation.y
|
|
6052
|
+
value: 0
|
|
6053
|
+
objectReference: {fileID: 0}
|
|
6054
|
+
- target: {fileID: ${rootTransformFileId}, guid: ${sourceGuid}, type: 3}
|
|
6055
|
+
propertyPath: m_LocalRotation.z
|
|
6056
|
+
value: 0
|
|
6057
|
+
objectReference: {fileID: 0}
|
|
6058
|
+
- target: {fileID: ${rootTransformFileId}, guid: ${sourceGuid}, type: 3}
|
|
6059
|
+
propertyPath: m_LocalEulerAnglesHint.x
|
|
6060
|
+
value: 0
|
|
6061
|
+
objectReference: {fileID: 0}
|
|
6062
|
+
- target: {fileID: ${rootTransformFileId}, guid: ${sourceGuid}, type: 3}
|
|
6063
|
+
propertyPath: m_LocalEulerAnglesHint.y
|
|
6064
|
+
value: 0
|
|
6065
|
+
objectReference: {fileID: 0}
|
|
6066
|
+
- target: {fileID: ${rootTransformFileId}, guid: ${sourceGuid}, type: 3}
|
|
6067
|
+
propertyPath: m_LocalEulerAnglesHint.z
|
|
6068
|
+
value: 0
|
|
5345
6069
|
objectReference: {fileID: 0}
|
|
5346
6070
|
m_RemovedComponents: []
|
|
5347
6071
|
m_RemovedGameObjects: []
|
|
@@ -5349,42 +6073,21 @@ PrefabInstance:
|
|
|
5349
6073
|
m_AddedComponents: []
|
|
5350
6074
|
m_SourcePrefab: {fileID: 100100000, guid: ${sourceGuid}, type: 3}
|
|
5351
6075
|
`;
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
return {
|
|
5356
|
-
success: false,
|
|
5357
|
-
output_path,
|
|
5358
|
-
error: `Failed to write variant prefab: ${err instanceof Error ? err.message : String(err)}`
|
|
5359
|
-
};
|
|
6076
|
+
doc.append_raw(yaml);
|
|
6077
|
+
if (parentTransformIdStr !== "0") {
|
|
6078
|
+
doc.add_child_to_parent(parentTransformIdStr, strippedTransformId);
|
|
5360
6079
|
}
|
|
5361
|
-
const variantGuid = generateGuid();
|
|
5362
|
-
const variantMetaContent = `fileFormatVersion: 2
|
|
5363
|
-
guid: ${variantGuid}
|
|
5364
|
-
PrefabImporter:
|
|
5365
|
-
externalObjects: {}
|
|
5366
|
-
userData:
|
|
5367
|
-
assetBundleName:
|
|
5368
|
-
assetBundleVariant:
|
|
5369
|
-
`;
|
|
5370
6080
|
try {
|
|
5371
|
-
|
|
6081
|
+
doc.save();
|
|
5372
6082
|
} catch (err) {
|
|
5373
|
-
|
|
5374
|
-
const fs2 = require("fs");
|
|
5375
|
-
fs2.unlinkSync(output_path);
|
|
5376
|
-
} catch {}
|
|
5377
|
-
return {
|
|
5378
|
-
success: false,
|
|
5379
|
-
output_path,
|
|
5380
|
-
error: `Failed to write .meta file: ${err instanceof Error ? err.message : String(err)}`
|
|
5381
|
-
};
|
|
6083
|
+
return { success: false, file_path: scene_path, error: `Failed to save scene: ${err instanceof Error ? err.message : String(err)}` };
|
|
5382
6084
|
}
|
|
5383
6085
|
return {
|
|
5384
6086
|
success: true,
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
6087
|
+
file_path: scene_path,
|
|
6088
|
+
prefab_instance_id: prefabInstanceId,
|
|
6089
|
+
game_object_id: strippedGoId,
|
|
6090
|
+
transform_id: strippedTransformId
|
|
5388
6091
|
};
|
|
5389
6092
|
}
|
|
5390
6093
|
function createScriptableObject(options) {
|
|
@@ -5432,9 +6135,10 @@ function createScriptableObject(options) {
|
|
|
5432
6135
|
} catch {}
|
|
5433
6136
|
}
|
|
5434
6137
|
const baseName = path3.basename(output_path, ".asset");
|
|
5435
|
-
const
|
|
6138
|
+
const type_lookup = project_path ? build_type_lookup(project_path) : undefined;
|
|
6139
|
+
const field_yaml = resolved.fields && resolved.fields.length > 0 ? generate_field_yaml(resolved.fields, version, " ", type_lookup) : `
|
|
5436
6140
|
`;
|
|
5437
|
-
|
|
6141
|
+
let assetYaml = `%YAML 1.1
|
|
5438
6142
|
%TAG !u! tag:unity3d.com,2011:
|
|
5439
6143
|
--- !u!114 &11400000
|
|
5440
6144
|
MonoBehaviour:
|
|
@@ -5448,6 +6152,66 @@ MonoBehaviour:
|
|
|
5448
6152
|
m_Script: {fileID: 11500000, guid: ${resolved.guid}, type: 3}
|
|
5449
6153
|
m_Name: ${baseName}
|
|
5450
6154
|
m_EditorClassIdentifier:${field_yaml}`;
|
|
6155
|
+
if (options.initial_values && Object.keys(options.initial_values).length > 0) {
|
|
6156
|
+
const doc = UnityDocument.from_string(assetYaml);
|
|
6157
|
+
const block = doc.blocks[0];
|
|
6158
|
+
if (block) {
|
|
6159
|
+
const complex_entries = [];
|
|
6160
|
+
for (const [key, val] of Object.entries(options.initial_values)) {
|
|
6161
|
+
if (val === null || val === undefined || typeof val === "string" || typeof val === "number" || typeof val === "boolean") {
|
|
6162
|
+
block.set_property(key, String(val ?? ""));
|
|
6163
|
+
} else if (Array.isArray(val) && val.length === 0) {
|
|
6164
|
+
block.set_property(key, "[]");
|
|
6165
|
+
} else if (typeof val === "object" && val !== null && !Array.isArray(val) && Object.keys(val).length === 0) {
|
|
6166
|
+
block.set_property(key, "{}");
|
|
6167
|
+
} else {
|
|
6168
|
+
complex_entries.push([key, val]);
|
|
6169
|
+
}
|
|
6170
|
+
}
|
|
6171
|
+
if (complex_entries.length > 0) {
|
|
6172
|
+
let raw = block.raw;
|
|
6173
|
+
for (const [key, val] of complex_entries) {
|
|
6174
|
+
const yaml_lines = json_value_to_yaml_lines(val, " ");
|
|
6175
|
+
const key_pattern = new RegExp(`^([ \\t]*${key}:)[^\\n]*$`, "m");
|
|
6176
|
+
const key_match = raw.match(key_pattern);
|
|
6177
|
+
if (key_match && key_match.index !== undefined) {
|
|
6178
|
+
const key_indent = key_match[0].match(/^[ \t]*/)?.[0].length ?? 0;
|
|
6179
|
+
const after_key = key_match.index + key_match[0].length;
|
|
6180
|
+
let end = after_key;
|
|
6181
|
+
const remaining = raw.slice(after_key);
|
|
6182
|
+
const remaining_lines = remaining.split(`
|
|
6183
|
+
`);
|
|
6184
|
+
for (let i = 1;i < remaining_lines.length; i++) {
|
|
6185
|
+
const line = remaining_lines[i];
|
|
6186
|
+
if (line.trim() === "") {
|
|
6187
|
+
end += 1 + line.length;
|
|
6188
|
+
continue;
|
|
6189
|
+
}
|
|
6190
|
+
const line_indent = line.match(/^[ \t]*/)?.[0].length ?? 0;
|
|
6191
|
+
if (line_indent > key_indent) {
|
|
6192
|
+
end += 1 + line.length;
|
|
6193
|
+
} else {
|
|
6194
|
+
break;
|
|
6195
|
+
}
|
|
6196
|
+
}
|
|
6197
|
+
const block_yaml = ` ${key}:
|
|
6198
|
+
${yaml_lines.join(`
|
|
6199
|
+
`)}`;
|
|
6200
|
+
raw = raw.slice(0, key_match.index) + block_yaml + raw.slice(end);
|
|
6201
|
+
} else {
|
|
6202
|
+
const block_yaml = ` ${key}:
|
|
6203
|
+
${yaml_lines.join(`
|
|
6204
|
+
`)}`;
|
|
6205
|
+
raw = raw.trimEnd() + `
|
|
6206
|
+
` + block_yaml + `
|
|
6207
|
+
`;
|
|
6208
|
+
}
|
|
6209
|
+
}
|
|
6210
|
+
block.replace_raw(raw);
|
|
6211
|
+
}
|
|
6212
|
+
assetYaml = doc.serialize();
|
|
6213
|
+
}
|
|
6214
|
+
}
|
|
5451
6215
|
try {
|
|
5452
6216
|
import_fs8.writeFileSync(output_path, assetYaml, "utf-8");
|
|
5453
6217
|
} catch (err) {
|
|
@@ -5528,6 +6292,80 @@ MonoImporter:
|
|
|
5528
6292
|
guid
|
|
5529
6293
|
};
|
|
5530
6294
|
}
|
|
6295
|
+
var COMPONENT_BASE_CLASSES = new Set([
|
|
6296
|
+
"MonoBehaviour",
|
|
6297
|
+
"NetworkBehaviour",
|
|
6298
|
+
"StateMachineBehaviour"
|
|
6299
|
+
]);
|
|
6300
|
+
function is_valid_component_base(base_class, project_path, depth = 0) {
|
|
6301
|
+
if (depth > 5)
|
|
6302
|
+
return false;
|
|
6303
|
+
if (COMPONENT_BASE_CLASSES.has(base_class))
|
|
6304
|
+
return true;
|
|
6305
|
+
if (!project_path)
|
|
6306
|
+
return false;
|
|
6307
|
+
const registryPath = path3.join(project_path, ".unity-agentic", "type-registry.json");
|
|
6308
|
+
if (import_fs8.existsSync(registryPath)) {
|
|
6309
|
+
try {
|
|
6310
|
+
const registry = JSON.parse(import_fs8.readFileSync(registryPath, "utf-8"));
|
|
6311
|
+
const match = registry.find((t) => t.name === base_class && t.kind === "class");
|
|
6312
|
+
if (match?.filePath) {
|
|
6313
|
+
const fullPath = path3.isAbsolute(match.filePath) ? match.filePath : path3.join(project_path, match.filePath);
|
|
6314
|
+
if (fullPath.endsWith(".cs") && import_fs8.existsSync(fullPath)) {
|
|
6315
|
+
const { getNativeExtractSerializedFields: getNativeExtractSerializedFields2 } = (init_scanner(), __toCommonJS(exports_scanner));
|
|
6316
|
+
const extract = getNativeExtractSerializedFields2();
|
|
6317
|
+
if (extract) {
|
|
6318
|
+
const typeInfos = extract(fullPath);
|
|
6319
|
+
const info = typeInfos?.find((t) => t.name === base_class);
|
|
6320
|
+
if (info?.baseClass) {
|
|
6321
|
+
return is_valid_component_base(info.baseClass, project_path, depth + 1);
|
|
6322
|
+
}
|
|
6323
|
+
}
|
|
6324
|
+
}
|
|
6325
|
+
if (!fullPath.endsWith(".cs") || !import_fs8.existsSync(fullPath)) {
|
|
6326
|
+
if (match.kind === "class") {
|
|
6327
|
+
return is_likely_component_base_name(base_class);
|
|
6328
|
+
}
|
|
6329
|
+
}
|
|
6330
|
+
}
|
|
6331
|
+
} catch {}
|
|
6332
|
+
}
|
|
6333
|
+
const cachePaths = [
|
|
6334
|
+
path3.join(project_path, ".unity-agentic", "package-cache.json"),
|
|
6335
|
+
path3.join(project_path, ".unity-agentic", "local-package-cache.json")
|
|
6336
|
+
];
|
|
6337
|
+
for (const cachePath of cachePaths) {
|
|
6338
|
+
if (!import_fs8.existsSync(cachePath))
|
|
6339
|
+
continue;
|
|
6340
|
+
try {
|
|
6341
|
+
const cache = JSON.parse(import_fs8.readFileSync(cachePath, "utf-8"));
|
|
6342
|
+
const baseClassLower = base_class.toLowerCase();
|
|
6343
|
+
for (const [, assetPath] of Object.entries(cache)) {
|
|
6344
|
+
if (!assetPath.endsWith(".cs"))
|
|
6345
|
+
continue;
|
|
6346
|
+
if (path3.basename(assetPath, ".cs").toLowerCase() !== baseClassLower)
|
|
6347
|
+
continue;
|
|
6348
|
+
const fullPath = path3.join(project_path, assetPath);
|
|
6349
|
+
if (!import_fs8.existsSync(fullPath))
|
|
6350
|
+
continue;
|
|
6351
|
+
const { getNativeExtractSerializedFields: getNativeExtractSerializedFields2 } = (init_scanner(), __toCommonJS(exports_scanner));
|
|
6352
|
+
const extract = getNativeExtractSerializedFields2();
|
|
6353
|
+
if (!extract)
|
|
6354
|
+
continue;
|
|
6355
|
+
const typeInfos = extract(fullPath);
|
|
6356
|
+
const info = typeInfos?.find((t) => t.name === base_class);
|
|
6357
|
+
if (info?.baseClass) {
|
|
6358
|
+
return is_valid_component_base(info.baseClass, project_path, depth + 1);
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
} catch {}
|
|
6362
|
+
}
|
|
6363
|
+
return false;
|
|
6364
|
+
}
|
|
6365
|
+
function is_likely_component_base_name(name) {
|
|
6366
|
+
const lower = name.toLowerCase();
|
|
6367
|
+
return lower.endsWith("behaviour") || lower.endsWith("behavior") || lower.includes("monobehaviour") || lower.includes("networkbehaviour");
|
|
6368
|
+
}
|
|
5531
6369
|
function addComponent(options) {
|
|
5532
6370
|
const { file_path, game_object_name, component_type } = options;
|
|
5533
6371
|
const project_path = options.project_path || find_unity_project_root(path3.dirname(file_path)) || undefined;
|
|
@@ -5553,11 +6391,19 @@ function addComponent(options) {
|
|
|
5553
6391
|
};
|
|
5554
6392
|
}
|
|
5555
6393
|
const goResult = doc.require_unique_game_object(game_object_name);
|
|
6394
|
+
let gameObjectIdStr;
|
|
6395
|
+
let variantInfo = null;
|
|
5556
6396
|
if ("error" in goResult) {
|
|
5557
|
-
|
|
6397
|
+
const vResult = find_game_object_in_variant(doc, game_object_name, file_path, project_path);
|
|
6398
|
+
if (!vResult) {
|
|
6399
|
+
return { success: false, file_path, error: goResult.error };
|
|
6400
|
+
}
|
|
6401
|
+
gameObjectIdStr = vResult.stripped_go_id;
|
|
6402
|
+
variantInfo = { source_ref: vResult.source_ref, prefab_instance_id: vResult.prefab_instance_id };
|
|
6403
|
+
} else {
|
|
6404
|
+
gameObjectIdStr = goResult.file_id;
|
|
5558
6405
|
}
|
|
5559
|
-
const
|
|
5560
|
-
const gameObjectId = parseInt(gameObjectIdStr, 10);
|
|
6406
|
+
const gameObjectId = gameObjectIdStr;
|
|
5561
6407
|
const classId = get_class_id(component_type);
|
|
5562
6408
|
let duplicateWarning;
|
|
5563
6409
|
const goBlock = doc.find_by_file_id(gameObjectIdStr);
|
|
@@ -5572,7 +6418,7 @@ function addComponent(options) {
|
|
|
5572
6418
|
}
|
|
5573
6419
|
}
|
|
5574
6420
|
const componentIdStr = doc.generate_file_id();
|
|
5575
|
-
const componentId =
|
|
6421
|
+
const componentId = componentIdStr;
|
|
5576
6422
|
let componentYAML;
|
|
5577
6423
|
let scriptGuid;
|
|
5578
6424
|
let scriptPath;
|
|
@@ -5581,7 +6427,16 @@ function addComponent(options) {
|
|
|
5581
6427
|
const componentName = UNITY_CLASS_IDS[classId] || component_type;
|
|
5582
6428
|
componentYAML = createGenericComponentYAML(componentName, classId, componentId, gameObjectId);
|
|
5583
6429
|
} else {
|
|
5584
|
-
|
|
6430
|
+
let resolved;
|
|
6431
|
+
try {
|
|
6432
|
+
resolved = resolve_script_with_fields(component_type, project_path);
|
|
6433
|
+
} catch (e) {
|
|
6434
|
+
return {
|
|
6435
|
+
success: false,
|
|
6436
|
+
file_path,
|
|
6437
|
+
error: e instanceof Error ? e.message : String(e)
|
|
6438
|
+
};
|
|
6439
|
+
}
|
|
5585
6440
|
if (!resolved) {
|
|
5586
6441
|
const hints = [];
|
|
5587
6442
|
if (project_path) {
|
|
@@ -5608,11 +6463,11 @@ function addComponent(options) {
|
|
|
5608
6463
|
error: `"${component_type}" is ${resolved.kind === "enum" ? "an enum" : "an interface"}, not a MonoBehaviour. Cannot add as a component.`
|
|
5609
6464
|
};
|
|
5610
6465
|
}
|
|
5611
|
-
if (resolved.base_class && !
|
|
6466
|
+
if (resolved.base_class && !COMPONENT_BASE_CLASSES.has(resolved.base_class) && !is_valid_component_base(resolved.base_class, project_path)) {
|
|
5612
6467
|
return {
|
|
5613
6468
|
success: false,
|
|
5614
6469
|
file_path,
|
|
5615
|
-
error: `"${component_type}" extends ${resolved.base_class}, not MonoBehaviour. Cannot add as a component.`
|
|
6470
|
+
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).`
|
|
5616
6471
|
};
|
|
5617
6472
|
}
|
|
5618
6473
|
let version;
|
|
@@ -5621,12 +6476,21 @@ function addComponent(options) {
|
|
|
5621
6476
|
version = read_project_version(project_path);
|
|
5622
6477
|
} catch {}
|
|
5623
6478
|
}
|
|
5624
|
-
|
|
6479
|
+
let scriptFileId = 11500000;
|
|
6480
|
+
if (resolved.path?.endsWith(".dll") && resolved.class_name) {
|
|
6481
|
+
scriptFileId = compute_dll_script_file_id(resolved.namespace ?? "", resolved.class_name);
|
|
6482
|
+
}
|
|
6483
|
+
const type_lookup_comp = project_path ? build_type_lookup(project_path) : undefined;
|
|
6484
|
+
componentYAML = createMonoBehaviourYAML(componentId, gameObjectId, resolved.guid, resolved.fields, version, scriptFileId, type_lookup_comp);
|
|
5625
6485
|
scriptGuid = resolved.guid;
|
|
5626
6486
|
scriptPath = resolved.path || undefined;
|
|
5627
6487
|
extractionError = resolved.extraction_error;
|
|
5628
6488
|
}
|
|
5629
|
-
|
|
6489
|
+
if (variantInfo) {
|
|
6490
|
+
appendToAddedComponents(doc, variantInfo.prefab_instance_id, variantInfo.source_ref, componentIdStr);
|
|
6491
|
+
} else {
|
|
6492
|
+
addComponentToGameObject(doc, gameObjectIdStr, componentIdStr);
|
|
6493
|
+
}
|
|
5630
6494
|
doc.append_raw(componentYAML);
|
|
5631
6495
|
const saveResult = doc.save();
|
|
5632
6496
|
if (!saveResult.success) {
|
|
@@ -5703,6 +6567,7 @@ function copyComponent(options) {
|
|
|
5703
6567
|
}
|
|
5704
6568
|
// src/editor/update.ts
|
|
5705
6569
|
var import_fs10 = require("fs");
|
|
6570
|
+
var import_fs11 = require("fs");
|
|
5706
6571
|
|
|
5707
6572
|
// src/settings.ts
|
|
5708
6573
|
var import_fs9 = require("fs");
|
|
@@ -6309,6 +7174,14 @@ function edit_sorting_layer(options) {
|
|
|
6309
7174
|
}
|
|
6310
7175
|
|
|
6311
7176
|
// src/editor/update.ts
|
|
7177
|
+
function enrich_target_ref(targetRef, blockRaw) {
|
|
7178
|
+
if (/guid:/.test(targetRef))
|
|
7179
|
+
return targetRef;
|
|
7180
|
+
const sourceMatch = blockRaw.match(/m_SourcePrefab:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]{32})/);
|
|
7181
|
+
if (!sourceMatch)
|
|
7182
|
+
return null;
|
|
7183
|
+
return targetRef.replace(/\}$/, `, guid: ${sourceMatch[1]}, type: 3}`);
|
|
7184
|
+
}
|
|
6312
7185
|
function eulerToQuaternion(euler) {
|
|
6313
7186
|
const deg2rad = Math.PI / 180;
|
|
6314
7187
|
const x = euler.x * deg2rad;
|
|
@@ -6331,6 +7204,9 @@ function validate_value_type(current_value, new_value) {
|
|
|
6331
7204
|
const current = current_value.trim();
|
|
6332
7205
|
const incoming = new_value.trim();
|
|
6333
7206
|
if (/^\{fileID:/.test(current)) {
|
|
7207
|
+
if (/^\{fileID:[ \t]*0[ \t]*\}$/.test(current)) {
|
|
7208
|
+
return null;
|
|
7209
|
+
}
|
|
6334
7210
|
if (!/^\{fileID:/.test(incoming)) {
|
|
6335
7211
|
return `Expected a reference value ({fileID: ...}), got "${incoming}"`;
|
|
6336
7212
|
}
|
|
@@ -6515,10 +7391,10 @@ function safeUnityYAMLEdit(filePath, objectName, propertyName, newValue, project
|
|
|
6515
7391
|
const propertyPattern = new RegExp(`(^\\s*m_${normalizedProperty}:\\s*)([^\\n]*)`, "m");
|
|
6516
7392
|
let updatedRaw = targetBlock.raw;
|
|
6517
7393
|
if (propertyPattern.test(updatedRaw)) {
|
|
6518
|
-
updatedRaw = updatedRaw.replace(propertyPattern,
|
|
7394
|
+
updatedRaw = updatedRaw.replace(propertyPattern, (_m, prefix) => prefix + newValue);
|
|
6519
7395
|
} else {
|
|
6520
|
-
updatedRaw = updatedRaw.replace(/(\n)(--- !u!|$)/, `
|
|
6521
|
-
m_${normalizedProperty}: ${newValue}$
|
|
7396
|
+
updatedRaw = updatedRaw.replace(/(\n)(--- !u!|$)/, (_m, g1, g2) => `
|
|
7397
|
+
m_${normalizedProperty}: ${newValue}${g1}${g2}`);
|
|
6522
7398
|
}
|
|
6523
7399
|
targetBlock.replace_raw(updatedRaw);
|
|
6524
7400
|
const saveResult = doc.save();
|
|
@@ -6604,7 +7480,9 @@ function editComponentByFileId(options) {
|
|
|
6604
7480
|
};
|
|
6605
7481
|
}
|
|
6606
7482
|
}
|
|
6607
|
-
const
|
|
7483
|
+
const exactValue = targetBlock.get_property(exactProperty);
|
|
7484
|
+
const resolvedProperty = exactValue !== null ? exactProperty : exactProperty !== prefixedProperty && targetBlock.get_property(prefixedProperty) !== null ? prefixedProperty : null;
|
|
7485
|
+
const currentValue = exactValue ?? (resolvedProperty === prefixedProperty ? targetBlock.get_property(prefixedProperty) : null);
|
|
6608
7486
|
if (currentValue !== null) {
|
|
6609
7487
|
const typeError = validate_value_type(currentValue, new_value);
|
|
6610
7488
|
if (typeError) {
|
|
@@ -6615,9 +7493,14 @@ function editComponentByFileId(options) {
|
|
|
6615
7493
|
};
|
|
6616
7494
|
}
|
|
6617
7495
|
}
|
|
6618
|
-
let modified
|
|
6619
|
-
if (
|
|
6620
|
-
modified = targetBlock.set_property(
|
|
7496
|
+
let modified;
|
|
7497
|
+
if (resolvedProperty) {
|
|
7498
|
+
modified = targetBlock.set_property(resolvedProperty, new_value, "{fileID: 0}");
|
|
7499
|
+
} else {
|
|
7500
|
+
modified = targetBlock.set_property(exactProperty, new_value, "{fileID: 0}");
|
|
7501
|
+
if (!modified && exactProperty !== prefixedProperty) {
|
|
7502
|
+
modified = targetBlock.set_property(prefixedProperty, new_value, "{fileID: 0}");
|
|
7503
|
+
}
|
|
6621
7504
|
}
|
|
6622
7505
|
if (!modified) {
|
|
6623
7506
|
if (currentValue !== null) {
|
|
@@ -6654,8 +7537,10 @@ function editComponentByFileId(options) {
|
|
|
6654
7537
|
};
|
|
6655
7538
|
}
|
|
6656
7539
|
function editPrefabOverride(options) {
|
|
6657
|
-
const { file_path, prefab_instance,
|
|
6658
|
-
const
|
|
7540
|
+
const { file_path, prefab_instance, new_value, object_reference, target, managed_reference } = options;
|
|
7541
|
+
const property_path = /[\[\]]/.test(options.property_path) && !options.property_path.startsWith("'") ? `'${options.property_path}'` : options.property_path;
|
|
7542
|
+
const effectiveValue = managed_reference ?? new_value;
|
|
7543
|
+
const objRef = managed_reference ? "{fileID: 0}" : object_reference ?? "{fileID: 0}";
|
|
6659
7544
|
if (!import_fs10.existsSync(file_path)) {
|
|
6660
7545
|
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
6661
7546
|
}
|
|
@@ -6669,11 +7554,16 @@ function editPrefabOverride(options) {
|
|
|
6669
7554
|
if (!targetBlock) {
|
|
6670
7555
|
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
6671
7556
|
}
|
|
6672
|
-
const
|
|
6673
|
-
const
|
|
7557
|
+
const unquotedPath = property_path.replace(/^'|'$/g, "");
|
|
7558
|
+
const quotedPath = `'${unquotedPath}'`;
|
|
7559
|
+
const escapedUnquoted = unquotedPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7560
|
+
const escapedQuoted = quotedPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7561
|
+
const pathAlternation = escapedUnquoted === escapedQuoted ? escapedUnquoted : `(?:${escapedQuoted}|${escapedUnquoted})`;
|
|
7562
|
+
const entryPattern = new RegExp(`(- target:\\s*\\{[^}]+\\}\\s*\\n\\s*propertyPath:\\s*)${pathAlternation}(\\s*\\n\\s*value:\\s*)(.*)(\\s*\\n\\s*objectReference:\\s*)(.*)`, "m");
|
|
6674
7563
|
const entryMatch = targetBlock.raw.match(entryPattern);
|
|
6675
7564
|
if (entryMatch) {
|
|
6676
|
-
const
|
|
7565
|
+
const quotedValue = yaml_quote_if_needed(effectiveValue);
|
|
7566
|
+
const updatedText2 = targetBlock.raw.replace(entryPattern, (_m, g1, g2, _g3, g4) => g1 + property_path + g2 + quotedValue + g4 + objRef);
|
|
6677
7567
|
targetBlock.replace_raw(updatedText2);
|
|
6678
7568
|
const saveResult2 = doc.save();
|
|
6679
7569
|
if (!saveResult2.success) {
|
|
@@ -6710,9 +7600,13 @@ function editPrefabOverride(options) {
|
|
|
6710
7600
|
error: `Invalid target reference "${targetRef}". Expected format: {fileID: N, guid: ..., type: T}`
|
|
6711
7601
|
};
|
|
6712
7602
|
}
|
|
7603
|
+
const enriched = enrich_target_ref(targetRef, targetBlock.raw);
|
|
7604
|
+
if (enriched)
|
|
7605
|
+
targetRef = enriched;
|
|
7606
|
+
const quotedNewValue = yaml_quote_if_needed(effectiveValue);
|
|
6713
7607
|
const newEntry = ` - target: ${targetRef}
|
|
6714
7608
|
propertyPath: ${property_path}
|
|
6715
|
-
value: ${
|
|
7609
|
+
value: ${quotedNewValue}
|
|
6716
7610
|
objectReference: ${objRef}`;
|
|
6717
7611
|
const removedPattern = /(\n\s*m_RemovedComponents:)/m;
|
|
6718
7612
|
const removedMatch = targetBlock.raw.match(removedPattern);
|
|
@@ -6759,6 +7653,118 @@ ${newEntry}$1`);
|
|
|
6759
7653
|
action: "added"
|
|
6760
7654
|
};
|
|
6761
7655
|
}
|
|
7656
|
+
function batchEditPrefabOverrides(file_path, prefab_instance, edits) {
|
|
7657
|
+
if (!import_fs10.existsSync(file_path)) {
|
|
7658
|
+
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
7659
|
+
}
|
|
7660
|
+
let doc;
|
|
7661
|
+
try {
|
|
7662
|
+
doc = UnityDocument.from_file(file_path);
|
|
7663
|
+
} catch (err) {
|
|
7664
|
+
return { success: false, file_path, error: `Failed to read file: ${err instanceof Error ? err.message : String(err)}` };
|
|
7665
|
+
}
|
|
7666
|
+
const targetBlock = findPrefabInstanceBlock(doc, prefab_instance);
|
|
7667
|
+
if (!targetBlock) {
|
|
7668
|
+
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
7669
|
+
}
|
|
7670
|
+
const actions = [];
|
|
7671
|
+
for (const edit of edits) {
|
|
7672
|
+
const { value, object_reference, target, managed_reference } = edit;
|
|
7673
|
+
const property_path = /[\[\]]/.test(edit.property_path) && !edit.property_path.startsWith("'") ? `'${edit.property_path}'` : edit.property_path;
|
|
7674
|
+
const effectiveValue = managed_reference ?? value;
|
|
7675
|
+
const objRef = managed_reference ? "{fileID: 0}" : object_reference ?? "{fileID: 0}";
|
|
7676
|
+
const unquotedPath = property_path.replace(/^'|'$/g, "");
|
|
7677
|
+
const quotedPathStr = `'${unquotedPath}'`;
|
|
7678
|
+
const batchEscapedUnquoted = unquotedPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7679
|
+
const batchEscapedQuoted = quotedPathStr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7680
|
+
const batchPathAlt = batchEscapedUnquoted === batchEscapedQuoted ? batchEscapedUnquoted : `(?:${batchEscapedQuoted}|${batchEscapedUnquoted})`;
|
|
7681
|
+
const entryPattern = new RegExp(`(- target:\\s*\\{[^}]+\\}\\s*\\n\\s*propertyPath:\\s*)${batchPathAlt}(\\s*\\n\\s*value:\\s*)(.*)(\\s*\\n\\s*objectReference:\\s*)(.*)`, "m");
|
|
7682
|
+
const entryMatch = targetBlock.raw.match(entryPattern);
|
|
7683
|
+
if (entryMatch) {
|
|
7684
|
+
const quotedValue = yaml_quote_if_needed(effectiveValue);
|
|
7685
|
+
const updatedText = targetBlock.raw.replace(entryPattern, (_m, g1, g2, _g3, g4) => g1 + property_path + g2 + quotedValue + g4 + objRef);
|
|
7686
|
+
targetBlock.replace_raw(updatedText);
|
|
7687
|
+
actions.push({ property_path, action: "updated" });
|
|
7688
|
+
} else {
|
|
7689
|
+
let targetRef = target;
|
|
7690
|
+
if (!targetRef) {
|
|
7691
|
+
const rootProp = property_path.split(".")[0];
|
|
7692
|
+
const siblingPattern = new RegExp(`- target:\\s*(\\{[^}]+\\})\\s*\\n\\s*propertyPath:\\s*${rootProp.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`, "m");
|
|
7693
|
+
const siblingMatch = targetBlock.raw.match(siblingPattern);
|
|
7694
|
+
if (siblingMatch) {
|
|
7695
|
+
targetRef = siblingMatch[1];
|
|
7696
|
+
}
|
|
7697
|
+
}
|
|
7698
|
+
if (!targetRef) {
|
|
7699
|
+
return {
|
|
7700
|
+
success: false,
|
|
7701
|
+
file_path,
|
|
7702
|
+
error: `Cannot infer target for new override "${property_path}". Provide "target" in the edit entry (e.g., "{fileID: 400000, guid: ..., type: 3}").`
|
|
7703
|
+
};
|
|
7704
|
+
}
|
|
7705
|
+
if (!/^\{fileID:\s*-?\d+/.test(targetRef)) {
|
|
7706
|
+
return {
|
|
7707
|
+
success: false,
|
|
7708
|
+
file_path,
|
|
7709
|
+
error: `Invalid target reference "${targetRef}" for "${property_path}". Expected format: {fileID: N, guid: ..., type: T}`
|
|
7710
|
+
};
|
|
7711
|
+
}
|
|
7712
|
+
const enriched = enrich_target_ref(targetRef, targetBlock.raw);
|
|
7713
|
+
if (enriched)
|
|
7714
|
+
targetRef = enriched;
|
|
7715
|
+
const quotedNewValue = yaml_quote_if_needed(effectiveValue);
|
|
7716
|
+
const newEntry = ` - target: ${targetRef}
|
|
7717
|
+
propertyPath: ${property_path}
|
|
7718
|
+
value: ${quotedNewValue}
|
|
7719
|
+
objectReference: ${objRef}`;
|
|
7720
|
+
const removedPattern = /(\n\s*m_RemovedComponents:)/m;
|
|
7721
|
+
const removedMatch = targetBlock.raw.match(removedPattern);
|
|
7722
|
+
let updatedText;
|
|
7723
|
+
if (removedMatch) {
|
|
7724
|
+
updatedText = targetBlock.raw.replace(removedPattern, `
|
|
7725
|
+
${newEntry}$1`);
|
|
7726
|
+
} else {
|
|
7727
|
+
const lines = targetBlock.raw.split(`
|
|
7728
|
+
`);
|
|
7729
|
+
let lastObjRefIdx = -1;
|
|
7730
|
+
let inModifications = false;
|
|
7731
|
+
for (let i = 0;i < lines.length; i++) {
|
|
7732
|
+
if (/m_Modifications:/.test(lines[i])) {
|
|
7733
|
+
inModifications = true;
|
|
7734
|
+
continue;
|
|
7735
|
+
}
|
|
7736
|
+
if (inModifications && /^\s*objectReference:/.test(lines[i])) {
|
|
7737
|
+
lastObjRefIdx = i;
|
|
7738
|
+
}
|
|
7739
|
+
if (inModifications && /^\s*m_\w+:/.test(lines[i]) && !/objectReference/.test(lines[i]) && !/propertyPath/.test(lines[i])) {
|
|
7740
|
+
if (lastObjRefIdx !== -1)
|
|
7741
|
+
break;
|
|
7742
|
+
}
|
|
7743
|
+
}
|
|
7744
|
+
if (lastObjRefIdx !== -1) {
|
|
7745
|
+
lines.splice(lastObjRefIdx + 1, 0, newEntry);
|
|
7746
|
+
updatedText = lines.join(`
|
|
7747
|
+
`);
|
|
7748
|
+
} else {
|
|
7749
|
+
return { success: false, file_path, error: `Could not find insertion point in m_Modifications for "${property_path}"` };
|
|
7750
|
+
}
|
|
7751
|
+
}
|
|
7752
|
+
targetBlock.replace_raw(updatedText);
|
|
7753
|
+
actions.push({ property_path, action: "added" });
|
|
7754
|
+
}
|
|
7755
|
+
}
|
|
7756
|
+
const saveResult = doc.save();
|
|
7757
|
+
if (!saveResult.success) {
|
|
7758
|
+
return { success: false, file_path, error: saveResult.error };
|
|
7759
|
+
}
|
|
7760
|
+
return {
|
|
7761
|
+
success: true,
|
|
7762
|
+
file_path,
|
|
7763
|
+
prefab_instance_id: prefab_instance,
|
|
7764
|
+
applied: actions.length,
|
|
7765
|
+
actions
|
|
7766
|
+
};
|
|
7767
|
+
}
|
|
6762
7768
|
function editTransform(options) {
|
|
6763
7769
|
const { file_path, transform_id, position, rotation, scale } = options;
|
|
6764
7770
|
const pathError = validate_file_path(file_path, "write");
|
|
@@ -6855,10 +7861,10 @@ function batchEditProperties(filePath, edits) {
|
|
|
6855
7861
|
const propertyPattern = new RegExp(`(^\\s*m_${normalizedProperty}:\\s*)([^\\n]*)`, "m");
|
|
6856
7862
|
let updatedRaw = targetBlock.raw;
|
|
6857
7863
|
if (propertyPattern.test(updatedRaw)) {
|
|
6858
|
-
updatedRaw = updatedRaw.replace(propertyPattern,
|
|
7864
|
+
updatedRaw = updatedRaw.replace(propertyPattern, (_m, prefix) => prefix + edit.new_value);
|
|
6859
7865
|
} else {
|
|
6860
|
-
updatedRaw = updatedRaw.replace(/(\n)(--- !u!|$)/, `
|
|
6861
|
-
m_${normalizedProperty}: ${edit.new_value}$
|
|
7866
|
+
updatedRaw = updatedRaw.replace(/(\n)(--- !u!|$)/, (_m, g1, g2) => `
|
|
7867
|
+
m_${normalizedProperty}: ${edit.new_value}${g1}${g2}`);
|
|
6862
7868
|
}
|
|
6863
7869
|
targetBlock.replace_raw(updatedRaw);
|
|
6864
7870
|
}
|
|
@@ -6963,9 +7969,9 @@ function reparentGameObject(options) {
|
|
|
6963
7969
|
return {
|
|
6964
7970
|
success: true,
|
|
6965
7971
|
file_path,
|
|
6966
|
-
child_transform_id:
|
|
6967
|
-
old_parent_transform_id:
|
|
6968
|
-
new_parent_transform_id:
|
|
7972
|
+
child_transform_id: childTransformId,
|
|
7973
|
+
old_parent_transform_id: oldParentTransformId,
|
|
7974
|
+
new_parent_transform_id: newParentTransformId
|
|
6969
7975
|
};
|
|
6970
7976
|
}
|
|
6971
7977
|
function findPrefabInstanceBlock(doc, identifier) {
|
|
@@ -7329,30 +8335,277 @@ function removeRemovedGameObject(options) {
|
|
|
7329
8335
|
if (!refPattern.test(targetBlock.raw)) {
|
|
7330
8336
|
return { success: false, file_path, error: `GameObject reference "${component_ref}" not found in m_RemovedGameObjects` };
|
|
7331
8337
|
}
|
|
7332
|
-
const updatedRaw = targetBlock.raw.replace(refPattern, "");
|
|
7333
|
-
targetBlock.replace_raw(updatedRaw);
|
|
7334
|
-
if (!doc.validate()) {
|
|
7335
|
-
return { success: false, file_path, error: "Validation failed after removing GameObject" };
|
|
8338
|
+
const updatedRaw = targetBlock.raw.replace(refPattern, "");
|
|
8339
|
+
targetBlock.replace_raw(updatedRaw);
|
|
8340
|
+
if (!doc.validate()) {
|
|
8341
|
+
return { success: false, file_path, error: "Validation failed after removing GameObject" };
|
|
8342
|
+
}
|
|
8343
|
+
const restoreGoSaveResult = doc.save();
|
|
8344
|
+
if (!restoreGoSaveResult.success) {
|
|
8345
|
+
return { success: false, file_path, error: restoreGoSaveResult.error };
|
|
8346
|
+
}
|
|
8347
|
+
return {
|
|
8348
|
+
success: true,
|
|
8349
|
+
file_path,
|
|
8350
|
+
prefab_instance_id: targetBlock.file_id
|
|
8351
|
+
};
|
|
8352
|
+
}
|
|
8353
|
+
function generate_managed_reference_id(existing_raw, count = 1) {
|
|
8354
|
+
const { randomBytes } = require("crypto");
|
|
8355
|
+
const existingIds = new Set;
|
|
8356
|
+
const idPattern = /\b(\d{1,19})\b/g;
|
|
8357
|
+
for (const line of existing_raw.split(`
|
|
8358
|
+
`)) {
|
|
8359
|
+
if (line.includes("managedReferences[") || line.includes("rid:") || line.includes("objectReference:") && /\d{10,}/.test(line) || line.includes("value:") && /\d{16,}/.test(line)) {
|
|
8360
|
+
let m;
|
|
8361
|
+
while ((m = idPattern.exec(line)) !== null) {
|
|
8362
|
+
const val = BigInt(m[1]);
|
|
8363
|
+
if (val > 0n)
|
|
8364
|
+
existingIds.add(val);
|
|
8365
|
+
}
|
|
8366
|
+
}
|
|
8367
|
+
}
|
|
8368
|
+
const buf = randomBytes(8);
|
|
8369
|
+
const raw64 = buf.readBigUInt64BE();
|
|
8370
|
+
const mask46 = (1n << 46n) - 1n;
|
|
8371
|
+
let base = (raw64 & mask46 | 1n) << 18n;
|
|
8372
|
+
const INT64_MAX = 9223372036854775807n;
|
|
8373
|
+
if (base > INT64_MAX)
|
|
8374
|
+
base = base & INT64_MAX >> 18n << 18n;
|
|
8375
|
+
if (base <= 0n)
|
|
8376
|
+
base = 1n << 18n;
|
|
8377
|
+
const results = [];
|
|
8378
|
+
for (let i = 0;i < count; i++) {
|
|
8379
|
+
let id = base + BigInt(i);
|
|
8380
|
+
while (id <= 0n || id > INT64_MAX || existingIds.has(id)) {
|
|
8381
|
+
id += 1n;
|
|
8382
|
+
}
|
|
8383
|
+
existingIds.add(id);
|
|
8384
|
+
results.push(id.toString());
|
|
8385
|
+
}
|
|
8386
|
+
return results;
|
|
8387
|
+
}
|
|
8388
|
+
function addPrefabManagedReference(options) {
|
|
8389
|
+
const { file_path, prefab_instance, field_path, type_name, target, project_path } = options;
|
|
8390
|
+
const index = options.index ?? 0;
|
|
8391
|
+
if (!import_fs10.existsSync(file_path)) {
|
|
8392
|
+
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
8393
|
+
}
|
|
8394
|
+
const typeInfo = resolve_managed_type(type_name, project_path);
|
|
8395
|
+
let finalTypeInfo;
|
|
8396
|
+
if (typeInfo) {
|
|
8397
|
+
finalTypeInfo = typeInfo;
|
|
8398
|
+
} else {
|
|
8399
|
+
const spaceIdx = type_name.indexOf(" ");
|
|
8400
|
+
if (spaceIdx > 0) {
|
|
8401
|
+
const asm = type_name.substring(0, spaceIdx);
|
|
8402
|
+
const fullType = type_name.substring(spaceIdx + 1);
|
|
8403
|
+
const lastDot = fullType.lastIndexOf(".");
|
|
8404
|
+
finalTypeInfo = {
|
|
8405
|
+
assembly: asm,
|
|
8406
|
+
namespace: lastDot >= 0 ? fullType.substring(0, lastDot) : "",
|
|
8407
|
+
class_name: lastDot >= 0 ? fullType.substring(lastDot + 1) : fullType
|
|
8408
|
+
};
|
|
8409
|
+
} else {
|
|
8410
|
+
return {
|
|
8411
|
+
success: false,
|
|
8412
|
+
file_path,
|
|
8413
|
+
error: `Type "${type_name}" not found in type registry. Use "Assembly Namespace.ClassName" format or run "setup" to rebuild.`
|
|
8414
|
+
};
|
|
8415
|
+
}
|
|
8416
|
+
}
|
|
8417
|
+
let doc;
|
|
8418
|
+
try {
|
|
8419
|
+
doc = UnityDocument.from_file(file_path);
|
|
8420
|
+
} catch (err) {
|
|
8421
|
+
return { success: false, file_path, error: `Failed to read file: ${err instanceof Error ? err.message : String(err)}` };
|
|
8422
|
+
}
|
|
8423
|
+
const piBlock = findPrefabInstanceBlock(doc, prefab_instance);
|
|
8424
|
+
if (!piBlock) {
|
|
8425
|
+
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
8426
|
+
}
|
|
8427
|
+
const [rid] = generate_managed_reference_id(piBlock.raw);
|
|
8428
|
+
const typeValue = finalTypeInfo.namespace ? `${finalTypeInfo.assembly} ${finalTypeInfo.namespace}.${finalTypeInfo.class_name}` : `${finalTypeInfo.assembly} ${finalTypeInfo.class_name}`;
|
|
8429
|
+
const basePath = field_path.replace(/\.Array$/, "");
|
|
8430
|
+
const overrides = [
|
|
8431
|
+
{
|
|
8432
|
+
property_path: `${basePath}.Array.data[${index}].managedReferenceType`,
|
|
8433
|
+
value: typeValue,
|
|
8434
|
+
target
|
|
8435
|
+
},
|
|
8436
|
+
{
|
|
8437
|
+
property_path: `${basePath}.Array.data[${index}].managedReferenceValue`,
|
|
8438
|
+
value: rid,
|
|
8439
|
+
target
|
|
8440
|
+
},
|
|
8441
|
+
{
|
|
8442
|
+
property_path: `managedReferences[-2]`,
|
|
8443
|
+
value: "2",
|
|
8444
|
+
target
|
|
8445
|
+
}
|
|
8446
|
+
];
|
|
8447
|
+
const result = batchEditPrefabOverrides(file_path, prefab_instance, overrides);
|
|
8448
|
+
if (!result.success) {
|
|
8449
|
+
return { success: false, file_path, error: result.error };
|
|
8450
|
+
}
|
|
8451
|
+
return {
|
|
8452
|
+
success: true,
|
|
8453
|
+
file_path,
|
|
8454
|
+
rid,
|
|
8455
|
+
type_info: finalTypeInfo,
|
|
8456
|
+
overrides_created: overrides.map((o) => o.property_path)
|
|
8457
|
+
};
|
|
8458
|
+
}
|
|
8459
|
+
function resolve_managed_type(type_name, project_path) {
|
|
8460
|
+
if (!project_path)
|
|
8461
|
+
return null;
|
|
8462
|
+
const { join: join10 } = require("path");
|
|
8463
|
+
const registryPath = join10(project_path, ".unity-agentic", "type-registry.json");
|
|
8464
|
+
if (!import_fs10.existsSync(registryPath))
|
|
8465
|
+
return null;
|
|
8466
|
+
try {
|
|
8467
|
+
const registry = JSON.parse(import_fs11.readFileSync(registryPath, "utf-8"));
|
|
8468
|
+
let targetName = type_name;
|
|
8469
|
+
let targetNs = null;
|
|
8470
|
+
const dotIndex = type_name.lastIndexOf(".");
|
|
8471
|
+
if (dotIndex > 0) {
|
|
8472
|
+
targetNs = type_name.substring(0, dotIndex);
|
|
8473
|
+
targetName = type_name.substring(dotIndex + 1);
|
|
8474
|
+
}
|
|
8475
|
+
const matches = registry.filter((t) => {
|
|
8476
|
+
if (t.name.toLowerCase() !== targetName.toLowerCase())
|
|
8477
|
+
return false;
|
|
8478
|
+
if (targetNs && t.namespace?.toLowerCase() !== targetNs.toLowerCase())
|
|
8479
|
+
return false;
|
|
8480
|
+
return true;
|
|
8481
|
+
});
|
|
8482
|
+
if (matches.length === 0)
|
|
8483
|
+
return null;
|
|
8484
|
+
const match = matches[0];
|
|
8485
|
+
let assembly = "Assembly-CSharp";
|
|
8486
|
+
if (match.filePath && (match.filePath.includes("Packages/") || match.filePath.includes("PackageCache/"))) {
|
|
8487
|
+
const pkgMatch = match.filePath.match(/(?:Packages|PackageCache)\/([^/]+)/);
|
|
8488
|
+
if (pkgMatch)
|
|
8489
|
+
assembly = pkgMatch[1].replace(/@.*$/, "");
|
|
8490
|
+
}
|
|
8491
|
+
return { class_name: match.name, namespace: match.namespace || "", assembly };
|
|
8492
|
+
} catch {
|
|
8493
|
+
return null;
|
|
8494
|
+
}
|
|
8495
|
+
}
|
|
8496
|
+
function editManagedReference(options) {
|
|
8497
|
+
const { file_path, file_id, field_path, type_name, project_path, append, initial_values } = options;
|
|
8498
|
+
if (!import_fs10.existsSync(file_path)) {
|
|
8499
|
+
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
8500
|
+
}
|
|
8501
|
+
let doc;
|
|
8502
|
+
try {
|
|
8503
|
+
doc = UnityDocument.from_file(file_path);
|
|
8504
|
+
} catch (err) {
|
|
8505
|
+
return { success: false, file_path, error: `Failed to read file: ${err instanceof Error ? err.message : String(err)}` };
|
|
8506
|
+
}
|
|
8507
|
+
const block = doc.find_by_file_id(file_id);
|
|
8508
|
+
if (!block) {
|
|
8509
|
+
return { success: false, file_path, error: `Component with fileID ${file_id} not found` };
|
|
8510
|
+
}
|
|
8511
|
+
if (block.class_id !== 114) {
|
|
8512
|
+
return { success: false, file_path, error: `fileID ${file_id} is not a MonoBehaviour (class ${block.class_id}). Managed references only apply to MonoBehaviours.` };
|
|
8513
|
+
}
|
|
8514
|
+
const typeInfo = resolve_managed_type(type_name, project_path);
|
|
8515
|
+
if (!typeInfo) {
|
|
8516
|
+
const spaceIdx = type_name.indexOf(" ");
|
|
8517
|
+
if (spaceIdx > 0) {
|
|
8518
|
+
const asm = type_name.substring(0, spaceIdx);
|
|
8519
|
+
const fullType = type_name.substring(spaceIdx + 1);
|
|
8520
|
+
const lastDot = fullType.lastIndexOf(".");
|
|
8521
|
+
const manual = {
|
|
8522
|
+
assembly: asm,
|
|
8523
|
+
namespace: lastDot >= 0 ? fullType.substring(0, lastDot) : "",
|
|
8524
|
+
class_name: lastDot >= 0 ? fullType.substring(lastDot + 1) : fullType
|
|
8525
|
+
};
|
|
8526
|
+
return applyManagedReference(doc, block, file_path, field_path, manual, append, initial_values);
|
|
8527
|
+
}
|
|
8528
|
+
return {
|
|
8529
|
+
success: false,
|
|
8530
|
+
file_path,
|
|
8531
|
+
error: `Type "${type_name}" not found in type registry. Use "Assembly Namespace.ClassName" format or run "setup" to rebuild.`
|
|
8532
|
+
};
|
|
8533
|
+
}
|
|
8534
|
+
return applyManagedReference(doc, block, file_path, field_path, typeInfo, append, initial_values);
|
|
8535
|
+
}
|
|
8536
|
+
function applyManagedReference(doc, block, file_path, field_path, typeInfo, append, initial_values) {
|
|
8537
|
+
let raw = block.raw;
|
|
8538
|
+
const ridMatches = [...raw.matchAll(/rid:[ \t]*(\d+)/g)];
|
|
8539
|
+
const existingRids = ridMatches.map((m) => parseInt(m[1], 10)).filter((n) => !isNaN(n));
|
|
8540
|
+
const nextRid = existingRids.length > 0 ? Math.max(...existingRids) + 1 : 1;
|
|
8541
|
+
let dataBlock = "{}";
|
|
8542
|
+
if (initial_values && Object.keys(initial_values).length > 0) {
|
|
8543
|
+
const lines = Object.entries(initial_values).map(([k, v]) => ` ${k}: ${v}`);
|
|
8544
|
+
dataBlock = `
|
|
8545
|
+
` + lines.join(`
|
|
8546
|
+
`);
|
|
8547
|
+
}
|
|
8548
|
+
const refEntry = ` - rid: ${nextRid}
|
|
8549
|
+
type: {class: ${typeInfo.class_name}, ns: ${typeInfo.namespace}, asm: ${typeInfo.assembly}}
|
|
8550
|
+
data: ${dataBlock}`;
|
|
8551
|
+
const refIdsBlockPattern = /(\s*RefIds:\s*\n)/;
|
|
8552
|
+
const refIdsEmptyPattern = /(\s*RefIds:)[ \t]*\[\]/;
|
|
8553
|
+
const referencesPattern = /(\s*references:\s*\n\s*version:\s*\d+\s*\n)/;
|
|
8554
|
+
if (refIdsBlockPattern.test(raw)) {
|
|
8555
|
+
raw = raw.replace(refIdsBlockPattern, `$1${refEntry}
|
|
8556
|
+
`);
|
|
8557
|
+
} else if (refIdsEmptyPattern.test(raw)) {
|
|
8558
|
+
raw = raw.replace(refIdsEmptyPattern, `$1
|
|
8559
|
+
${refEntry}`);
|
|
8560
|
+
} else if (referencesPattern.test(raw)) {
|
|
8561
|
+
raw = raw.replace(referencesPattern, `$1 RefIds:
|
|
8562
|
+
${refEntry}
|
|
8563
|
+
`);
|
|
8564
|
+
} else {
|
|
8565
|
+
raw = raw.trimEnd() + `
|
|
8566
|
+
references:
|
|
8567
|
+
version: 2
|
|
8568
|
+
RefIds:
|
|
8569
|
+
${refEntry}
|
|
8570
|
+
`;
|
|
8571
|
+
}
|
|
8572
|
+
const escaped_field = field_path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8573
|
+
if (append) {
|
|
8574
|
+
const fieldLineMatch = raw.match(new RegExp(`^([ \\t]*)${escaped_field}:`, "m"));
|
|
8575
|
+
const fieldIndent = fieldLineMatch ? fieldLineMatch[1] : " ";
|
|
8576
|
+
const ridEntry = `
|
|
8577
|
+
${fieldIndent} - rid: ${nextRid}`;
|
|
8578
|
+
const emptyArrayPattern = new RegExp(`(${escaped_field}:)[ \\t]*\\[\\]`, "m");
|
|
8579
|
+
if (emptyArrayPattern.test(raw)) {
|
|
8580
|
+
raw = raw.replace(emptyArrayPattern, `$1${ridEntry}`);
|
|
8581
|
+
} else {
|
|
8582
|
+
const lastRidPattern = new RegExp(`(^[ \\t]*${escaped_field}:[\\s\\S]*?- rid: \\d+)`, "m");
|
|
8583
|
+
if (lastRidPattern.test(raw)) {
|
|
8584
|
+
raw = raw.replace(lastRidPattern, `$1${ridEntry}`);
|
|
8585
|
+
}
|
|
8586
|
+
}
|
|
8587
|
+
} else {
|
|
8588
|
+
const fieldRidPattern = new RegExp(`(${escaped_field}:\\s*\\n\\s*rid:[ \\t]*)\\d+`, "m");
|
|
8589
|
+
if (fieldRidPattern.test(raw)) {
|
|
8590
|
+
raw = raw.replace(fieldRidPattern, `$1${nextRid}`);
|
|
8591
|
+
}
|
|
7336
8592
|
}
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
8593
|
+
block.replace_raw(raw);
|
|
8594
|
+
const mrSave = doc.save();
|
|
8595
|
+
if (!mrSave.success) {
|
|
8596
|
+
return { success: false, file_path, error: mrSave.error };
|
|
7340
8597
|
}
|
|
7341
|
-
return {
|
|
7342
|
-
success: true,
|
|
7343
|
-
file_path,
|
|
7344
|
-
prefab_instance_id: targetBlock.file_id
|
|
7345
|
-
};
|
|
8598
|
+
return { success: true, file_path, rid: nextRid, type_info: typeInfo };
|
|
7346
8599
|
}
|
|
7347
8600
|
// src/editor/delete.ts
|
|
7348
|
-
var
|
|
8601
|
+
var import_fs12 = require("fs");
|
|
7349
8602
|
function removeComponent(options) {
|
|
7350
8603
|
const { file_path, file_id } = options;
|
|
7351
8604
|
const pathError = validate_file_path(file_path, "write");
|
|
7352
8605
|
if (pathError) {
|
|
7353
8606
|
return { success: false, file_path, error: pathError };
|
|
7354
8607
|
}
|
|
7355
|
-
if (!
|
|
8608
|
+
if (!import_fs12.existsSync(file_path)) {
|
|
7356
8609
|
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
7357
8610
|
}
|
|
7358
8611
|
let doc;
|
|
@@ -7376,7 +8629,8 @@ function removeComponent(options) {
|
|
|
7376
8629
|
const parentGoId = goMatch[1];
|
|
7377
8630
|
const goBlock = doc.find_by_file_id(parentGoId);
|
|
7378
8631
|
if (goBlock) {
|
|
7379
|
-
const
|
|
8632
|
+
const escaped = file_id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8633
|
+
const compLinePattern = new RegExp(`^[ \\t]*- component: \\{fileID: ${escaped}\\}[ \\t]*\\n`, "m");
|
|
7380
8634
|
const modifiedRaw = goBlock.raw.replace(compLinePattern, "");
|
|
7381
8635
|
goBlock.replace_raw(modifiedRaw);
|
|
7382
8636
|
}
|
|
@@ -7402,7 +8656,7 @@ function deleteGameObject(options) {
|
|
|
7402
8656
|
if (pathError) {
|
|
7403
8657
|
return { success: false, file_path, error: pathError };
|
|
7404
8658
|
}
|
|
7405
|
-
if (!
|
|
8659
|
+
if (!import_fs12.existsSync(file_path)) {
|
|
7406
8660
|
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
7407
8661
|
}
|
|
7408
8662
|
let doc;
|
|
@@ -7481,7 +8735,7 @@ function deletePrefabInstance(options) {
|
|
|
7481
8735
|
if (pathError) {
|
|
7482
8736
|
return { success: false, file_path, error: pathError };
|
|
7483
8737
|
}
|
|
7484
|
-
if (!
|
|
8738
|
+
if (!import_fs12.existsSync(file_path)) {
|
|
7485
8739
|
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
7486
8740
|
}
|
|
7487
8741
|
let doc;
|
|
@@ -7561,7 +8815,7 @@ function deletePrefabInstance(options) {
|
|
|
7561
8815
|
};
|
|
7562
8816
|
}
|
|
7563
8817
|
// src/editor/duplicate.ts
|
|
7564
|
-
var
|
|
8818
|
+
var import_fs13 = require("fs");
|
|
7565
8819
|
var path5 = __toESM(require("path"));
|
|
7566
8820
|
init_scanner();
|
|
7567
8821
|
function findPrefabInstanceByName(doc, name) {
|
|
@@ -7577,7 +8831,7 @@ function findPrefabInstanceByName(doc, name) {
|
|
|
7577
8831
|
}
|
|
7578
8832
|
function duplicateGameObject(options) {
|
|
7579
8833
|
const { file_path, object_name, new_name } = options;
|
|
7580
|
-
if (!
|
|
8834
|
+
if (!import_fs13.existsSync(file_path)) {
|
|
7581
8835
|
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
7582
8836
|
}
|
|
7583
8837
|
let doc;
|
|
@@ -7710,7 +8964,7 @@ function duplicateGameObject(options) {
|
|
|
7710
8964
|
}
|
|
7711
8965
|
function unpackPrefab(options) {
|
|
7712
8966
|
const { file_path, prefab_instance, project_path } = options;
|
|
7713
|
-
if (!
|
|
8967
|
+
if (!import_fs13.existsSync(file_path)) {
|
|
7714
8968
|
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
7715
8969
|
}
|
|
7716
8970
|
let sceneDoc;
|
|
@@ -7756,7 +9010,7 @@ function unpackPrefab(options) {
|
|
|
7756
9010
|
sourcePrefabPath = resolvedPath;
|
|
7757
9011
|
}
|
|
7758
9012
|
}
|
|
7759
|
-
if (!sourcePrefabPath || !
|
|
9013
|
+
if (!sourcePrefabPath || !import_fs13.existsSync(sourcePrefabPath)) {
|
|
7760
9014
|
const inferredProject = project_path || find_unity_project_root(path5.dirname(file_path));
|
|
7761
9015
|
if (inferredProject) {
|
|
7762
9016
|
const nativeBuild = getNativeBuildGuidCache();
|
|
@@ -7770,7 +9024,7 @@ function unpackPrefab(options) {
|
|
|
7770
9024
|
}
|
|
7771
9025
|
}
|
|
7772
9026
|
}
|
|
7773
|
-
if (!sourcePrefabPath || !
|
|
9027
|
+
if (!sourcePrefabPath || !import_fs13.existsSync(sourcePrefabPath)) {
|
|
7774
9028
|
const searchedPaths = [];
|
|
7775
9029
|
if (project_path)
|
|
7776
9030
|
searchedPaths.push(`GUID cache: ${path5.join(project_path, ".unity-agentic", "guid-cache.json")}`);
|
|
@@ -8203,15 +9457,15 @@ function move_scene(projectPath, scenePath, newPosition) {
|
|
|
8203
9457
|
}
|
|
8204
9458
|
|
|
8205
9459
|
// src/packages.ts
|
|
8206
|
-
var
|
|
9460
|
+
var import_fs14 = require("fs");
|
|
8207
9461
|
var import_path6 = require("path");
|
|
8208
9462
|
function load_manifest(project_path) {
|
|
8209
9463
|
const manifest_path = import_path6.join(project_path, "Packages", "manifest.json");
|
|
8210
|
-
if (!
|
|
9464
|
+
if (!import_fs14.existsSync(manifest_path)) {
|
|
8211
9465
|
return { error: `manifest.json not found at ${manifest_path}` };
|
|
8212
9466
|
}
|
|
8213
9467
|
try {
|
|
8214
|
-
const raw =
|
|
9468
|
+
const raw = import_fs14.readFileSync(manifest_path, "utf-8");
|
|
8215
9469
|
const parsed = JSON.parse(raw);
|
|
8216
9470
|
if (!parsed.dependencies || typeof parsed.dependencies !== "object") {
|
|
8217
9471
|
return { error: `Invalid manifest.json: missing "dependencies" object` };
|
|
@@ -8227,7 +9481,7 @@ function save_manifest(manifest_path, manifest) {
|
|
|
8227
9481
|
sorted_deps[key] = manifest.dependencies[key];
|
|
8228
9482
|
}
|
|
8229
9483
|
const output = { ...manifest, dependencies: sorted_deps };
|
|
8230
|
-
|
|
9484
|
+
import_fs14.writeFileSync(manifest_path, JSON.stringify(output, null, 2) + `
|
|
8231
9485
|
`, "utf-8");
|
|
8232
9486
|
}
|
|
8233
9487
|
function list_packages(project_path, search) {
|
|
@@ -8281,7 +9535,7 @@ function remove_package(project_path, name) {
|
|
|
8281
9535
|
}
|
|
8282
9536
|
|
|
8283
9537
|
// src/input-actions.ts
|
|
8284
|
-
var
|
|
9538
|
+
var import_fs15 = require("fs");
|
|
8285
9539
|
var import_crypto = require("crypto");
|
|
8286
9540
|
function generate_action_id() {
|
|
8287
9541
|
const bytes = import_crypto.randomBytes(16);
|
|
@@ -8295,18 +9549,18 @@ function generate_action_id() {
|
|
|
8295
9549
|
].join("-");
|
|
8296
9550
|
}
|
|
8297
9551
|
function load_input_actions(file) {
|
|
8298
|
-
if (!
|
|
9552
|
+
if (!import_fs15.existsSync(file)) {
|
|
8299
9553
|
return { error: `File not found: ${file}` };
|
|
8300
9554
|
}
|
|
8301
9555
|
try {
|
|
8302
|
-
const raw =
|
|
9556
|
+
const raw = import_fs15.readFileSync(file, "utf-8");
|
|
8303
9557
|
return JSON.parse(raw);
|
|
8304
9558
|
} catch (err) {
|
|
8305
9559
|
return { error: `Failed to parse input actions: ${err instanceof Error ? err.message : String(err)}` };
|
|
8306
9560
|
}
|
|
8307
9561
|
}
|
|
8308
9562
|
function save_input_actions(file, data) {
|
|
8309
|
-
|
|
9563
|
+
import_fs15.writeFileSync(file, JSON.stringify(data, null, 4) + `
|
|
8310
9564
|
`, "utf-8");
|
|
8311
9565
|
}
|
|
8312
9566
|
function add_map(data, name) {
|
|
@@ -8460,11 +9714,52 @@ function build_create_command() {
|
|
|
8460
9714
|
if (!result.success)
|
|
8461
9715
|
process.exitCode = 1;
|
|
8462
9716
|
});
|
|
8463
|
-
cmd.command("
|
|
9717
|
+
cmd.command("prefab-instance <scene_file> <prefab_path>").description("Instantiate a prefab into a scene file").option("-n, --name <name>", "Instance name (defaults to prefab filename)").option("-p, --parent <name|id>", "Parent GameObject name or Transform fileID").option("--position <x,y,z>", "Local position (default: 0,0,0)").option("-j, --json", "Output as JSON").action((scene_file, prefab_path_arg, options) => {
|
|
9718
|
+
let position;
|
|
9719
|
+
if (options.position) {
|
|
9720
|
+
const parts = options.position.split(",").map(Number);
|
|
9721
|
+
if (parts.length !== 3 || parts.some(isNaN)) {
|
|
9722
|
+
console.log(JSON.stringify({
|
|
9723
|
+
success: false,
|
|
9724
|
+
error: "--position must be three comma-separated numbers, e.g. 1,2,3"
|
|
9725
|
+
}, null, 2));
|
|
9726
|
+
process.exitCode = 1;
|
|
9727
|
+
return;
|
|
9728
|
+
}
|
|
9729
|
+
position = { x: parts[0], y: parts[1], z: parts[2] };
|
|
9730
|
+
}
|
|
9731
|
+
let parent;
|
|
9732
|
+
if (options.parent) {
|
|
9733
|
+
const asNumber = parseInt(options.parent, 10);
|
|
9734
|
+
parent = isNaN(asNumber) ? options.parent : asNumber;
|
|
9735
|
+
}
|
|
9736
|
+
const result = createPrefabInstance({
|
|
9737
|
+
scene_path: scene_file,
|
|
9738
|
+
prefab_path: prefab_path_arg,
|
|
9739
|
+
name: options.name,
|
|
9740
|
+
parent,
|
|
9741
|
+
position
|
|
9742
|
+
});
|
|
9743
|
+
console.log(JSON.stringify(result, null, 2));
|
|
9744
|
+
if (!result.success)
|
|
9745
|
+
process.exitCode = 1;
|
|
9746
|
+
});
|
|
9747
|
+
cmd.command("scriptable-object <output_path> <script>").description("Create a new ScriptableObject .asset file").option("-p, --project <path>", "Unity project path (for script GUID lookup)").option("--set <json>", `Initial field values as JSON object (e.g. '{"damage": "10", "targetScope": "1"}')`).option("-j, --json", "Output as JSON").action((output_path, script, options) => {
|
|
9748
|
+
let initial_values;
|
|
9749
|
+
if (options.set) {
|
|
9750
|
+
try {
|
|
9751
|
+
initial_values = JSON.parse(options.set);
|
|
9752
|
+
} catch {
|
|
9753
|
+
console.log(JSON.stringify({ success: false, error: `Invalid JSON for --set: ${options.set}` }, null, 2));
|
|
9754
|
+
process.exitCode = 1;
|
|
9755
|
+
return;
|
|
9756
|
+
}
|
|
9757
|
+
}
|
|
8464
9758
|
const result = createScriptableObject({
|
|
8465
9759
|
output_path,
|
|
8466
9760
|
script,
|
|
8467
|
-
project_path: options.project
|
|
9761
|
+
project_path: options.project,
|
|
9762
|
+
initial_values
|
|
8468
9763
|
});
|
|
8469
9764
|
console.log(JSON.stringify(result, null, 2));
|
|
8470
9765
|
if (!result.success)
|
|
@@ -8521,7 +9816,7 @@ function build_create_command() {
|
|
|
8521
9816
|
console.log(JSON.stringify({ success: false, error: "--shader <guid> is required" }, null, 2));
|
|
8522
9817
|
process.exit(1);
|
|
8523
9818
|
}
|
|
8524
|
-
if (
|
|
9819
|
+
if (import_fs16.existsSync(output_path)) {
|
|
8525
9820
|
console.log(JSON.stringify({ success: false, error: `File already exists: ${output_path}` }, null, 2));
|
|
8526
9821
|
process.exit(1);
|
|
8527
9822
|
}
|
|
@@ -8593,7 +9888,7 @@ Material:
|
|
|
8593
9888
|
m_Colors: ${color_section}
|
|
8594
9889
|
m_BuildTextureStacks: []
|
|
8595
9890
|
`;
|
|
8596
|
-
|
|
9891
|
+
import_fs16.writeFileSync(output_path, mat_content, "utf-8");
|
|
8597
9892
|
const guid = import_crypto2.randomBytes(16).toString("hex");
|
|
8598
9893
|
const meta_content = `fileFormatVersion: 2
|
|
8599
9894
|
guid: ${guid}
|
|
@@ -8604,7 +9899,7 @@ NativeFormatImporter:
|
|
|
8604
9899
|
assetBundleName:
|
|
8605
9900
|
assetBundleVariant:
|
|
8606
9901
|
`;
|
|
8607
|
-
|
|
9902
|
+
import_fs16.writeFileSync(`${output_path}.meta`, meta_content, "utf-8");
|
|
8608
9903
|
console.log(JSON.stringify({
|
|
8609
9904
|
success: true,
|
|
8610
9905
|
file: output_path,
|
|
@@ -8634,7 +9929,7 @@ NativeFormatImporter:
|
|
|
8634
9929
|
process.exitCode = 1;
|
|
8635
9930
|
return;
|
|
8636
9931
|
}
|
|
8637
|
-
if (
|
|
9932
|
+
if (import_fs16.existsSync(output_path)) {
|
|
8638
9933
|
console.log(JSON.stringify({ success: false, error: `File already exists: ${output_path}` }, null, 2));
|
|
8639
9934
|
process.exitCode = 1;
|
|
8640
9935
|
return;
|
|
@@ -8661,7 +9956,7 @@ ScriptedImporter:
|
|
|
8661
9956
|
wrapperClassName:
|
|
8662
9957
|
wrapperCodeNamespace:
|
|
8663
9958
|
`;
|
|
8664
|
-
|
|
9959
|
+
import_fs16.writeFileSync(`${output_path}.meta`, meta_content, "utf-8");
|
|
8665
9960
|
console.log(JSON.stringify({
|
|
8666
9961
|
success: true,
|
|
8667
9962
|
file: output_path,
|
|
@@ -8677,7 +9972,7 @@ ScriptedImporter:
|
|
|
8677
9972
|
return;
|
|
8678
9973
|
}
|
|
8679
9974
|
const name = name_arg || import_path7.basename(output_path).replace(/\.anim$/i, "");
|
|
8680
|
-
if (
|
|
9975
|
+
if (import_fs16.existsSync(output_path)) {
|
|
8681
9976
|
console.log(JSON.stringify({ success: false, error: `File already exists: ${output_path}` }, null, 2));
|
|
8682
9977
|
process.exitCode = 1;
|
|
8683
9978
|
return;
|
|
@@ -8744,7 +10039,7 @@ AnimationClip:
|
|
|
8744
10039
|
m_HasMotionFloatCurves: 0
|
|
8745
10040
|
m_Events: []
|
|
8746
10041
|
`;
|
|
8747
|
-
|
|
10042
|
+
import_fs16.writeFileSync(output_path, anim_content, "utf-8");
|
|
8748
10043
|
const guid = import_crypto2.randomBytes(16).toString("hex");
|
|
8749
10044
|
const meta_content = `fileFormatVersion: 2
|
|
8750
10045
|
guid: ${guid}
|
|
@@ -8755,7 +10050,7 @@ NativeFormatImporter:
|
|
|
8755
10050
|
assetBundleName:
|
|
8756
10051
|
assetBundleVariant:
|
|
8757
10052
|
`;
|
|
8758
|
-
|
|
10053
|
+
import_fs16.writeFileSync(`${output_path}.meta`, meta_content, "utf-8");
|
|
8759
10054
|
console.log(JSON.stringify({
|
|
8760
10055
|
success: true,
|
|
8761
10056
|
file: output_path,
|
|
@@ -8773,7 +10068,7 @@ NativeFormatImporter:
|
|
|
8773
10068
|
process.exitCode = 1;
|
|
8774
10069
|
return;
|
|
8775
10070
|
}
|
|
8776
|
-
if (
|
|
10071
|
+
if (import_fs16.existsSync(output_path)) {
|
|
8777
10072
|
console.log(JSON.stringify({ success: false, error: `File already exists: ${output_path}` }, null, 2));
|
|
8778
10073
|
process.exitCode = 1;
|
|
8779
10074
|
return;
|
|
@@ -8823,7 +10118,7 @@ AnimatorStateMachine:
|
|
|
8823
10118
|
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
|
8824
10119
|
m_DefaultState: {fileID: 0}
|
|
8825
10120
|
`;
|
|
8826
|
-
|
|
10121
|
+
import_fs16.writeFileSync(output_path, ctrl_content, "utf-8");
|
|
8827
10122
|
const guid = import_crypto2.randomBytes(16).toString("hex");
|
|
8828
10123
|
const meta_content = `fileFormatVersion: 2
|
|
8829
10124
|
guid: ${guid}
|
|
@@ -8834,7 +10129,7 @@ NativeFormatImporter:
|
|
|
8834
10129
|
assetBundleName:
|
|
8835
10130
|
assetBundleVariant:
|
|
8836
10131
|
`;
|
|
8837
|
-
|
|
10132
|
+
import_fs16.writeFileSync(`${output_path}.meta`, meta_content, "utf-8");
|
|
8838
10133
|
console.log(JSON.stringify({
|
|
8839
10134
|
success: true,
|
|
8840
10135
|
file: output_path,
|
|
@@ -8851,7 +10146,7 @@ NativeFormatImporter:
|
|
|
8851
10146
|
process.exitCode = 1;
|
|
8852
10147
|
return;
|
|
8853
10148
|
}
|
|
8854
|
-
if (
|
|
10149
|
+
if (import_fs16.existsSync(output_path)) {
|
|
8855
10150
|
console.log(JSON.stringify({ success: false, error: `File already exists: ${output_path}` }, null, 2));
|
|
8856
10151
|
process.exitCode = 1;
|
|
8857
10152
|
return;
|
|
@@ -8890,7 +10185,7 @@ Transform:
|
|
|
8890
10185
|
m_Father: {fileID: 0}
|
|
8891
10186
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
8892
10187
|
`;
|
|
8893
|
-
|
|
10188
|
+
import_fs16.writeFileSync(output_path, prefab_content, "utf-8");
|
|
8894
10189
|
const guid = import_crypto2.randomBytes(16).toString("hex");
|
|
8895
10190
|
const meta_content = `fileFormatVersion: 2
|
|
8896
10191
|
guid: ${guid}
|
|
@@ -8900,7 +10195,7 @@ PrefabImporter:
|
|
|
8900
10195
|
assetBundleName:
|
|
8901
10196
|
assetBundleVariant:
|
|
8902
10197
|
`;
|
|
8903
|
-
|
|
10198
|
+
import_fs16.writeFileSync(`${output_path}.meta`, meta_content, "utf-8");
|
|
8904
10199
|
console.log(JSON.stringify({
|
|
8905
10200
|
success: true,
|
|
8906
10201
|
file: output_path,
|
|
@@ -8914,7 +10209,7 @@ PrefabImporter:
|
|
|
8914
10209
|
|
|
8915
10210
|
// src/cmd-read.ts
|
|
8916
10211
|
init_scanner();
|
|
8917
|
-
var
|
|
10212
|
+
var import_fs17 = require("fs");
|
|
8918
10213
|
var import_path8 = require("path");
|
|
8919
10214
|
var import_os = require("os");
|
|
8920
10215
|
function parse_material_yaml(content) {
|
|
@@ -9161,7 +10456,7 @@ function categorize_asset(filePath) {
|
|
|
9161
10456
|
function find_project_root_from_file(filePath) {
|
|
9162
10457
|
let dir = import_path8.dirname(import_path8.resolve(filePath));
|
|
9163
10458
|
for (let i = 0;i < 20; i++) {
|
|
9164
|
-
if (
|
|
10459
|
+
if (import_fs17.existsSync(import_path8.join(dir, "Assets")) && import_fs17.existsSync(import_path8.join(dir, "ProjectSettings"))) {
|
|
9165
10460
|
return dir;
|
|
9166
10461
|
}
|
|
9167
10462
|
const parent = import_path8.dirname(dir);
|
|
@@ -9507,7 +10802,7 @@ function walk_files(dir, extensions) {
|
|
|
9507
10802
|
const current = stack.pop();
|
|
9508
10803
|
let entries;
|
|
9509
10804
|
try {
|
|
9510
|
-
entries =
|
|
10805
|
+
entries = import_fs17.readdirSync(current);
|
|
9511
10806
|
} catch {
|
|
9512
10807
|
continue;
|
|
9513
10808
|
}
|
|
@@ -9516,7 +10811,7 @@ function walk_files(dir, extensions) {
|
|
|
9516
10811
|
continue;
|
|
9517
10812
|
const full = import_path8.join(current, entry);
|
|
9518
10813
|
try {
|
|
9519
|
-
const stat =
|
|
10814
|
+
const stat = import_fs17.statSync(full);
|
|
9520
10815
|
if (stat.isDirectory()) {
|
|
9521
10816
|
stack.push(full);
|
|
9522
10817
|
} else if (extensions.has(import_path8.extname(full).toLowerCase())) {
|
|
@@ -9530,7 +10825,7 @@ function walk_files(dir, extensions) {
|
|
|
9530
10825
|
return results;
|
|
9531
10826
|
}
|
|
9532
10827
|
function validate_unity_yaml(file) {
|
|
9533
|
-
if (!
|
|
10828
|
+
if (!import_fs17.existsSync(file)) {
|
|
9534
10829
|
return `File not found: ${file}`;
|
|
9535
10830
|
}
|
|
9536
10831
|
try {
|
|
@@ -9615,13 +10910,59 @@ function build_read_command(getScanner) {
|
|
|
9615
10910
|
result.warning = result.warning ? `${result.warning}; ${maxDepthWarning}` : maxDepthWarning;
|
|
9616
10911
|
}
|
|
9617
10912
|
if (result.total === 0 && !result.error) {
|
|
9618
|
-
|
|
9619
|
-
|
|
9620
|
-
|
|
9621
|
-
const
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
10913
|
+
const prefabInstances = result.prefabInstances;
|
|
10914
|
+
if (prefabInstances && prefabInstances.length > 0) {
|
|
10915
|
+
try {
|
|
10916
|
+
const doc = UnityDocument.from_file(file);
|
|
10917
|
+
const projectPath = find_unity_project_root(import_path8.dirname(file));
|
|
10918
|
+
const resolved = resolve_source_prefab(doc, file, projectPath ?? undefined);
|
|
10919
|
+
if (resolved) {
|
|
10920
|
+
const sourceResult = getScanner().inspect_all_paginated({
|
|
10921
|
+
file: resolved.source_path,
|
|
10922
|
+
include_properties: options.properties === true,
|
|
10923
|
+
verbose: options.verbose === true,
|
|
10924
|
+
page_size: pageSize,
|
|
10925
|
+
cursor: 0,
|
|
10926
|
+
max_depth: maxDepth,
|
|
10927
|
+
filter_component: options.filterComponent
|
|
10928
|
+
});
|
|
10929
|
+
if (sourceResult.total > 0 && sourceResult.gameobjects) {
|
|
10930
|
+
const piBlock = resolved.prefab_instance_block;
|
|
10931
|
+
const nameOverrides = new Map;
|
|
10932
|
+
const namePattern = /- target:[ \t]*\{fileID:[ \t]*(-?\d+)[^}]*\}\s*\n\s*propertyPath:[ \t]*m_Name\s*\n\s*value:[ \t]*(.*)/g;
|
|
10933
|
+
let nameMatch;
|
|
10934
|
+
while ((nameMatch = namePattern.exec(piBlock.raw)) !== null) {
|
|
10935
|
+
nameOverrides.set(nameMatch[1], nameMatch[2].trim());
|
|
10936
|
+
}
|
|
10937
|
+
for (const go of sourceResult.gameobjects) {
|
|
10938
|
+
const goRecord = go;
|
|
10939
|
+
const override = nameOverrides.get(goRecord.fileId);
|
|
10940
|
+
if (override) {
|
|
10941
|
+
goRecord.name = override;
|
|
10942
|
+
}
|
|
10943
|
+
}
|
|
10944
|
+
const resultRecord = result;
|
|
10945
|
+
resultRecord.gameobjects = sourceResult.gameobjects;
|
|
10946
|
+
resultRecord.total = sourceResult.total;
|
|
10947
|
+
resultRecord.totalInScene = sourceResult.totalInScene;
|
|
10948
|
+
resultRecord.resolvedFromSource = true;
|
|
10949
|
+
resultRecord.sourcePrefab = resolved.source_path;
|
|
10950
|
+
resultRecord.sourceGuid = resolved.source_guid;
|
|
10951
|
+
const variantNote = `PrefabVariant resolved from source prefab: ${resolved.source_path}`;
|
|
10952
|
+
result.warning = result.warning ? `${result.warning}; ${variantNote}` : variantNote;
|
|
10953
|
+
}
|
|
10954
|
+
}
|
|
10955
|
+
} catch {}
|
|
10956
|
+
}
|
|
10957
|
+
if (result.total === 0) {
|
|
10958
|
+
try {
|
|
10959
|
+
const fileSize = import_fs17.statSync(file).size;
|
|
10960
|
+
if (fileSize > 100) {
|
|
10961
|
+
const corruptWarning = "File has valid Unity YAML header but contains no parseable GameObjects -- file may be corrupt or malformed";
|
|
10962
|
+
result.warning = result.warning ? `${result.warning}; ${corruptWarning}` : corruptWarning;
|
|
10963
|
+
}
|
|
10964
|
+
} catch {}
|
|
10965
|
+
}
|
|
9625
10966
|
}
|
|
9626
10967
|
if (options.summary) {
|
|
9627
10968
|
const component_counts = {};
|
|
@@ -9718,12 +11059,6 @@ function build_read_command(getScanner) {
|
|
|
9718
11059
|
};
|
|
9719
11060
|
console.log(JSON.stringify(output, null, 2));
|
|
9720
11061
|
});
|
|
9721
|
-
cmd.command("scriptable-object").description('(Deprecated: renamed to "read asset")').argument("[file]").allowUnknownOption().action(() => {
|
|
9722
|
-
console.log(JSON.stringify({
|
|
9723
|
-
error: 'Command "read scriptable-object" has been renamed to "read asset". Use: unity-agentic-tools read asset <file>'
|
|
9724
|
-
}, null, 2));
|
|
9725
|
-
process.exit(1);
|
|
9726
|
-
});
|
|
9727
11062
|
cmd.command("material <file>").description("Read a Unity Material file (.mat) with structured property output").option("--project <path>", "Unity project root (for GUID resolution)").option("--summary", "Show shader name, property count, texture count only").option("-j, --json", "Output as JSON").action((file, options) => {
|
|
9728
11063
|
if (!file.toLowerCase().endsWith(".mat")) {
|
|
9729
11064
|
console.log(JSON.stringify({ error: `File must be a .mat file: ${file}` }, null, 2));
|
|
@@ -9734,7 +11069,7 @@ function build_read_command(getScanner) {
|
|
|
9734
11069
|
console.log(JSON.stringify({ error: matValidationError }, null, 2));
|
|
9735
11070
|
process.exit(1);
|
|
9736
11071
|
}
|
|
9737
|
-
const content =
|
|
11072
|
+
const content = import_fs17.readFileSync(file, "utf-8");
|
|
9738
11073
|
if (!content.includes("Material:")) {
|
|
9739
11074
|
console.log(JSON.stringify({ error: `File "${file}" does not contain a Material block. Use 'read asset' for generic Unity YAML files.` }, null, 2));
|
|
9740
11075
|
process.exit(1);
|
|
@@ -9776,13 +11111,13 @@ function build_read_command(getScanner) {
|
|
|
9776
11111
|
}, null, 2));
|
|
9777
11112
|
});
|
|
9778
11113
|
cmd.command("dependencies <file>").description("List asset dependencies (GUIDs referenced by this file)").option("--project <path>", "Unity project root (for GUID resolution)").option("--unresolved", "Show only GUIDs that could not be resolved").option("--recursive [depth]", "Follow dependency chain N levels deep (default: 3)").option("-j, --json", "Output as JSON").action((file, options) => {
|
|
9779
|
-
if (!
|
|
11114
|
+
if (!import_fs17.existsSync(file)) {
|
|
9780
11115
|
console.log(JSON.stringify({ error: `File not found: ${file}` }, null, 2));
|
|
9781
11116
|
process.exit(1);
|
|
9782
11117
|
}
|
|
9783
11118
|
let content;
|
|
9784
11119
|
try {
|
|
9785
|
-
content =
|
|
11120
|
+
content = import_fs17.readFileSync(file, "utf-8");
|
|
9786
11121
|
} catch {
|
|
9787
11122
|
console.log(JSON.stringify({ error: `Cannot read file: ${file}` }, null, 2));
|
|
9788
11123
|
process.exit(1);
|
|
@@ -9823,7 +11158,7 @@ function build_read_command(getScanner) {
|
|
|
9823
11158
|
const result = [];
|
|
9824
11159
|
let fileContent;
|
|
9825
11160
|
try {
|
|
9826
|
-
fileContent =
|
|
11161
|
+
fileContent = import_fs17.readFileSync(filePath, "utf-8");
|
|
9827
11162
|
} catch {
|
|
9828
11163
|
return [];
|
|
9829
11164
|
}
|
|
@@ -9840,7 +11175,7 @@ function build_read_command(getScanner) {
|
|
|
9840
11175
|
const rAbsPath = cache.resolve_absolute(g);
|
|
9841
11176
|
const rType = rPath ? categorize_asset(rPath) : "unknown";
|
|
9842
11177
|
const dep = { guid: g, path: rPath, type: rType, depth };
|
|
9843
|
-
if (rAbsPath && depth < max_depth &&
|
|
11178
|
+
if (rAbsPath && depth < max_depth && import_fs17.existsSync(rAbsPath)) {
|
|
9844
11179
|
const subs = traverse_file(rAbsPath, depth + 1);
|
|
9845
11180
|
if (subs.length > 0)
|
|
9846
11181
|
dep.sub_dependencies = subs;
|
|
@@ -9869,7 +11204,7 @@ function build_read_command(getScanner) {
|
|
|
9869
11204
|
const rDep = { guid: dep.guid, path: dep.path, type: dep.type, depth: 0 };
|
|
9870
11205
|
if (dep.path) {
|
|
9871
11206
|
const absPath = cache.resolve_absolute(dep.guid);
|
|
9872
|
-
if (absPath &&
|
|
11207
|
+
if (absPath && import_fs17.existsSync(absPath)) {
|
|
9873
11208
|
const subs = traverse_file(absPath, 1);
|
|
9874
11209
|
if (subs.length > 0)
|
|
9875
11210
|
rDep.sub_dependencies = subs;
|
|
@@ -9960,14 +11295,31 @@ function build_read_command(getScanner) {
|
|
|
9960
11295
|
const target_match = lines[i].match(/\{fileID:\s*(-?\d+)/);
|
|
9961
11296
|
const property_match = i + 1 < lines.length ? lines[i + 1].match(/propertyPath:\s*(.+)/) : null;
|
|
9962
11297
|
const value_match = i + 2 < lines.length ? lines[i + 2].match(/value:\s*(.*)/) : null;
|
|
9963
|
-
const obj_ref_match = i + 3 < lines.length ? lines[i + 3].match(/objectReference
|
|
11298
|
+
const obj_ref_match = i + 3 < lines.length ? lines[i + 3].match(/objectReference:[ \t]*(.+)/) : null;
|
|
9964
11299
|
if (target_match && property_match) {
|
|
9965
|
-
|
|
11300
|
+
const mod = {
|
|
9966
11301
|
target_file_id: target_match[1],
|
|
9967
11302
|
property_path: property_match[1].trim(),
|
|
9968
11303
|
value: value_match ? value_match[1].trim() : "",
|
|
9969
|
-
object_reference: obj_ref_match ? obj_ref_match[1] : null
|
|
9970
|
-
}
|
|
11304
|
+
object_reference: obj_ref_match ? obj_ref_match[1].trim() : null
|
|
11305
|
+
};
|
|
11306
|
+
const propPath = mod.property_path;
|
|
11307
|
+
const modValue = mod.value;
|
|
11308
|
+
if (propPath.endsWith(".managedReferenceType") && modValue) {
|
|
11309
|
+
const spaceIdx = modValue.indexOf(" ");
|
|
11310
|
+
if (spaceIdx > 0) {
|
|
11311
|
+
const assembly = modValue.substring(0, spaceIdx);
|
|
11312
|
+
const full_type = modValue.substring(spaceIdx + 1);
|
|
11313
|
+
const lastDot = full_type.lastIndexOf(".");
|
|
11314
|
+
mod.managed_reference_type = {
|
|
11315
|
+
assembly,
|
|
11316
|
+
full_type,
|
|
11317
|
+
namespace: lastDot >= 0 ? full_type.substring(0, lastDot) : "",
|
|
11318
|
+
class_name: lastDot >= 0 ? full_type.substring(lastDot + 1) : full_type
|
|
11319
|
+
};
|
|
11320
|
+
}
|
|
11321
|
+
}
|
|
11322
|
+
modifications.push(mod);
|
|
9971
11323
|
}
|
|
9972
11324
|
i += 4;
|
|
9973
11325
|
} else {
|
|
@@ -10035,8 +11387,129 @@ function build_read_command(getScanner) {
|
|
|
10035
11387
|
process.exit(1);
|
|
10036
11388
|
}
|
|
10037
11389
|
});
|
|
11390
|
+
cmd.command("target <file> <gameobject_name> [component_type]").description("Build a --target reference string for prefab override commands").option("-p, --project <path>", "Unity project path").option("-j, --json", "Output as JSON").action((file, gameobject_name, component_type, options) => {
|
|
11391
|
+
try {
|
|
11392
|
+
if (!import_fs17.existsSync(file)) {
|
|
11393
|
+
console.log(JSON.stringify({ error: `File not found: ${file}` }, null, 2));
|
|
11394
|
+
process.exit(1);
|
|
11395
|
+
}
|
|
11396
|
+
const doc = UnityDocument.from_file(file);
|
|
11397
|
+
let guid;
|
|
11398
|
+
const piBlocks = doc.find_by_class_id(1001);
|
|
11399
|
+
if (piBlocks.length > 0) {
|
|
11400
|
+
const sourceMatch = piBlocks[0].raw.match(/m_SourcePrefab:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]{32})/);
|
|
11401
|
+
guid = sourceMatch ? sourceMatch[1] : null;
|
|
11402
|
+
if (!guid) {
|
|
11403
|
+
console.log(JSON.stringify({ error: "Cannot extract source GUID from PrefabInstance m_SourcePrefab." }, null, 2));
|
|
11404
|
+
process.exit(1);
|
|
11405
|
+
}
|
|
11406
|
+
} else {
|
|
11407
|
+
const metaPath = file + ".meta";
|
|
11408
|
+
guid = extractGuidFromMeta(metaPath);
|
|
11409
|
+
if (!guid) {
|
|
11410
|
+
console.log(JSON.stringify({ error: `Cannot read GUID from ${metaPath}. Ensure the .meta file exists.` }, null, 2));
|
|
11411
|
+
process.exit(1);
|
|
11412
|
+
}
|
|
11413
|
+
}
|
|
11414
|
+
const goResult = doc.require_unique_game_object(gameobject_name);
|
|
11415
|
+
let targetFileId;
|
|
11416
|
+
if ("error" in goResult) {
|
|
11417
|
+
let found = false;
|
|
11418
|
+
for (const block of doc.blocks) {
|
|
11419
|
+
if (block.class_id !== 1001)
|
|
11420
|
+
continue;
|
|
11421
|
+
const nameMatch = block.raw.match(new RegExp(`- target:[ \\t]*\\{fileID:[ \\t]*(-?\\d+)[^}]*\\}\\s*\\n\\s*propertyPath:[ \\t]*m_Name\\s*\\n\\s*value:[ \\t]*${gameobject_name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*$`, "m"));
|
|
11422
|
+
if (nameMatch) {
|
|
11423
|
+
targetFileId = nameMatch[1];
|
|
11424
|
+
found = true;
|
|
11425
|
+
break;
|
|
11426
|
+
}
|
|
11427
|
+
}
|
|
11428
|
+
if (!found) {
|
|
11429
|
+
console.log(JSON.stringify({ error: goResult.error }, null, 2));
|
|
11430
|
+
process.exit(1);
|
|
11431
|
+
}
|
|
11432
|
+
} else {
|
|
11433
|
+
targetFileId = goResult.file_id;
|
|
11434
|
+
}
|
|
11435
|
+
if (component_type) {
|
|
11436
|
+
const classId = get_class_id(component_type);
|
|
11437
|
+
const goBlock = doc.find_by_file_id(targetFileId);
|
|
11438
|
+
if (goBlock && !goBlock.is_stripped) {
|
|
11439
|
+
const compRefs = [...goBlock.raw.matchAll(/component:[ \t]*\{fileID:[ \t]*(-?\d+)\}/g)].map((m) => m[1]);
|
|
11440
|
+
let compFound = false;
|
|
11441
|
+
for (const refId of compRefs) {
|
|
11442
|
+
const compBlock = doc.find_by_file_id(refId);
|
|
11443
|
+
if (!compBlock)
|
|
11444
|
+
continue;
|
|
11445
|
+
if (classId !== null && compBlock.class_id === classId) {
|
|
11446
|
+
targetFileId = refId;
|
|
11447
|
+
compFound = true;
|
|
11448
|
+
break;
|
|
11449
|
+
}
|
|
11450
|
+
if (classId === null && compBlock.class_id === 114) {
|
|
11451
|
+
const scriptMatch = compBlock.raw.match(/m_Script:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]{32})/);
|
|
11452
|
+
if (scriptMatch) {
|
|
11453
|
+
const project = options.project || find_unity_project_root(import_path8.dirname(file));
|
|
11454
|
+
if (project) {
|
|
11455
|
+
const cache = load_guid_cache(project);
|
|
11456
|
+
if (cache) {
|
|
11457
|
+
const scriptPath = cache.resolve(scriptMatch[1]);
|
|
11458
|
+
if (scriptPath && import_path8.basename(scriptPath, ".cs").toLowerCase() === component_type.toLowerCase().replace(/\.cs$/, "")) {
|
|
11459
|
+
targetFileId = refId;
|
|
11460
|
+
compFound = true;
|
|
11461
|
+
break;
|
|
11462
|
+
}
|
|
11463
|
+
}
|
|
11464
|
+
}
|
|
11465
|
+
}
|
|
11466
|
+
}
|
|
11467
|
+
}
|
|
11468
|
+
if (!compFound) {
|
|
11469
|
+
console.log(JSON.stringify({ error: `Component "${component_type}" not found on GameObject "${gameobject_name}"` }, null, 2));
|
|
11470
|
+
process.exit(1);
|
|
11471
|
+
}
|
|
11472
|
+
} else {
|
|
11473
|
+
const project = options.project || find_unity_project_root(import_path8.dirname(file));
|
|
11474
|
+
const resolved = resolve_source_prefab(doc, file, project ?? undefined);
|
|
11475
|
+
if (resolved) {
|
|
11476
|
+
const sourceDoc = UnityDocument.from_file(resolved.source_path);
|
|
11477
|
+
const sourceGo = sourceDoc.require_unique_game_object(gameobject_name);
|
|
11478
|
+
if (!("error" in sourceGo)) {
|
|
11479
|
+
const compRefs = [...sourceGo.raw.matchAll(/component:[ \t]*\{fileID:[ \t]*(-?\d+)\}/g)].map((m) => m[1]);
|
|
11480
|
+
let compFound = false;
|
|
11481
|
+
for (const refId of compRefs) {
|
|
11482
|
+
const compBlock = sourceDoc.find_by_file_id(refId);
|
|
11483
|
+
if (!compBlock)
|
|
11484
|
+
continue;
|
|
11485
|
+
if (classId !== null && compBlock.class_id === classId) {
|
|
11486
|
+
targetFileId = refId;
|
|
11487
|
+
compFound = true;
|
|
11488
|
+
break;
|
|
11489
|
+
}
|
|
11490
|
+
}
|
|
11491
|
+
if (!compFound) {
|
|
11492
|
+
console.log(JSON.stringify({ error: `Component "${component_type}" not found on "${gameobject_name}" in source prefab` }, null, 2));
|
|
11493
|
+
process.exit(1);
|
|
11494
|
+
}
|
|
11495
|
+
}
|
|
11496
|
+
}
|
|
11497
|
+
}
|
|
11498
|
+
}
|
|
11499
|
+
const target = `{fileID: ${targetFileId}, guid: ${guid}, type: 3}`;
|
|
11500
|
+
console.log(JSON.stringify({
|
|
11501
|
+
target,
|
|
11502
|
+
file_id: targetFileId,
|
|
11503
|
+
guid,
|
|
11504
|
+
type: 3
|
|
11505
|
+
}, null, 2));
|
|
11506
|
+
} catch (err) {
|
|
11507
|
+
console.log(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }, null, 2));
|
|
11508
|
+
process.exit(1);
|
|
11509
|
+
}
|
|
11510
|
+
});
|
|
10038
11511
|
cmd.command("script <file>").description("Extract C# type declarations from a .cs file or .NET DLL").option("-j, --json", "Output as JSON").action((file, _options) => {
|
|
10039
|
-
if (!
|
|
11512
|
+
if (!import_fs17.existsSync(file)) {
|
|
10040
11513
|
console.log(JSON.stringify({ error: `File not found: ${file}` }, null, 2));
|
|
10041
11514
|
process.exit(1);
|
|
10042
11515
|
}
|
|
@@ -10121,18 +11594,20 @@ function build_read_command(getScanner) {
|
|
|
10121
11594
|
types: displayed
|
|
10122
11595
|
}, null, 2));
|
|
10123
11596
|
});
|
|
10124
|
-
cmd.command("log").description("Read and filter the Unity Editor.log").option("--path <file>", "Path to Editor.log (auto-detected if omitted)").option("--project <path>", "Filter to log entries from a specific Unity project session").option("--tail <n>", "Show last N lines (default 50)", "50").option("--errors", "Show only error entries").option("--warnings", "Show only warning entries").option("--compile-errors", "Show only C# compilation errors").option("--import-errors", "Show only asset import errors").option("--since <timestamp>", "Filter entries after this timestamp (YYYY-MM-DD or HH:MM:SS)").option("--search <pattern>", "Regex filter on log content").option("-j, --json", "Output as JSON").action((options) => {
|
|
11597
|
+
cmd.command("log [project-path]").description("Read and filter the Unity Editor.log").option("--path <file>", "Path to Editor.log (auto-detected if omitted)").option("--project <path>", "Filter to log entries from a specific Unity project session").option("--tail <n>", "Show last N lines (default 50)", "50").option("--errors", "Show only error entries").option("--warnings", "Show only warning entries").option("--compile-errors", "Show only C# compilation errors").option("--import-errors", "Show only asset import errors").option("--since <timestamp>", "Filter entries after this timestamp (YYYY-MM-DD or HH:MM:SS)").option("--search <pattern>", "Regex filter on log content").option("-j, --json", "Output as JSON").action((projectPath, options) => {
|
|
11598
|
+
if (projectPath && !options.project)
|
|
11599
|
+
options.project = projectPath;
|
|
10125
11600
|
const logPath = options.path || get_editor_log_path();
|
|
10126
|
-
if (!logPath || !
|
|
11601
|
+
if (!logPath || !import_fs17.existsSync(logPath)) {
|
|
10127
11602
|
console.log(JSON.stringify({ error: `Editor.log not found${logPath ? `: ${logPath}` : ". Could not detect platform log path."}` }, null, 2));
|
|
10128
11603
|
process.exit(1);
|
|
10129
11604
|
}
|
|
10130
|
-
const content =
|
|
11605
|
+
const content = import_fs17.readFileSync(logPath, "utf-8");
|
|
10131
11606
|
let lines = content.split(/\r?\n/);
|
|
10132
11607
|
if (options.project) {
|
|
10133
|
-
const
|
|
10134
|
-
const projectName = import_path8.basename(
|
|
10135
|
-
const escapedPath =
|
|
11608
|
+
const projectPath2 = import_path8.resolve(options.project);
|
|
11609
|
+
const projectName = import_path8.basename(projectPath2);
|
|
11610
|
+
const escapedPath = projectPath2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10136
11611
|
const escapedName = projectName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10137
11612
|
const session_markers = [
|
|
10138
11613
|
new RegExp(`Loading project at '${escapedPath}'`),
|
|
@@ -10248,11 +11723,11 @@ function build_read_command(getScanner) {
|
|
|
10248
11723
|
});
|
|
10249
11724
|
cmd.command("meta <file>").description("Read a Unity .meta file and show importer settings").option("--summary", "Show importer type and key settings only").option("-j, --json", "Output as JSON").action((file, options) => {
|
|
10250
11725
|
const metaPath = file.endsWith(".meta") ? file : `${file}.meta`;
|
|
10251
|
-
if (!
|
|
11726
|
+
if (!import_fs17.existsSync(metaPath)) {
|
|
10252
11727
|
console.log(JSON.stringify({ error: `Meta file not found: ${metaPath}` }, null, 2));
|
|
10253
11728
|
process.exit(1);
|
|
10254
11729
|
}
|
|
10255
|
-
const content =
|
|
11730
|
+
const content = import_fs17.readFileSync(metaPath, "utf-8");
|
|
10256
11731
|
const lines = content.split(/\r?\n/);
|
|
10257
11732
|
let guid = "";
|
|
10258
11733
|
let importer_type = "Unknown";
|
|
@@ -10340,7 +11815,7 @@ function build_read_command(getScanner) {
|
|
|
10340
11815
|
console.log(JSON.stringify({ error: animValidationError }, null, 2));
|
|
10341
11816
|
process.exit(1);
|
|
10342
11817
|
}
|
|
10343
|
-
const content =
|
|
11818
|
+
const content = import_fs17.readFileSync(file, "utf-8");
|
|
10344
11819
|
const clip = parse_animation_yaml(content, options.curves === true);
|
|
10345
11820
|
if (!clip) {
|
|
10346
11821
|
console.log(JSON.stringify({ error: `No AnimationClip found in "${file}". Is this an .anim file?` }, null, 2));
|
|
@@ -10401,7 +11876,7 @@ function build_read_command(getScanner) {
|
|
|
10401
11876
|
console.log(JSON.stringify({ error: ctrlValidationError }, null, 2));
|
|
10402
11877
|
process.exit(1);
|
|
10403
11878
|
}
|
|
10404
|
-
const content =
|
|
11879
|
+
const content = import_fs17.readFileSync(file, "utf-8");
|
|
10405
11880
|
const blocks = split_yaml_blocks(content);
|
|
10406
11881
|
const controller_block = blocks.find((b) => b.class_id === 91);
|
|
10407
11882
|
if (!controller_block) {
|
|
@@ -10631,7 +12106,7 @@ function build_read_command(getScanner) {
|
|
|
10631
12106
|
process.exit(1);
|
|
10632
12107
|
}
|
|
10633
12108
|
const assetsDir = import_path8.join(import_path8.resolve(project_path), "Assets");
|
|
10634
|
-
if (!
|
|
12109
|
+
if (!import_fs17.existsSync(assetsDir)) {
|
|
10635
12110
|
console.log(JSON.stringify({ error: `Assets directory not found in "${project_path}"` }, null, 2));
|
|
10636
12111
|
process.exit(1);
|
|
10637
12112
|
}
|
|
@@ -10660,7 +12135,7 @@ function build_read_command(getScanner) {
|
|
|
10660
12135
|
const guid_pattern = `guid: ${guid}`;
|
|
10661
12136
|
for (const f of files) {
|
|
10662
12137
|
try {
|
|
10663
|
-
const fc =
|
|
12138
|
+
const fc = import_fs17.readFileSync(f, "utf-8");
|
|
10664
12139
|
if (fc.includes(guid_pattern)) {
|
|
10665
12140
|
const rel = import_path8.relative(import_path8.resolve(project_path), f);
|
|
10666
12141
|
const ftype = categorize_asset(f);
|
|
@@ -10690,7 +12165,7 @@ function build_read_command(getScanner) {
|
|
|
10690
12165
|
cmd.command("unused <project_path>").description("Find potentially unused assets (zero inbound GUID references)").option("--type <type>", "Filter to specific asset types").option("--ignore <glob>", "Exclude paths matching this pattern").option("--max <n>", "Maximum results to return (default 200)", "200").option("-j, --json", "Output as JSON").action((project_path, options) => {
|
|
10691
12166
|
const resolvedProject = import_path8.resolve(project_path);
|
|
10692
12167
|
const assetsDir = import_path8.join(resolvedProject, "Assets");
|
|
10693
|
-
if (!
|
|
12168
|
+
if (!import_fs17.existsSync(assetsDir)) {
|
|
10694
12169
|
console.log(JSON.stringify({ error: `Assets directory not found in "${project_path}"` }, null, 2));
|
|
10695
12170
|
process.exit(1);
|
|
10696
12171
|
}
|
|
@@ -10718,7 +12193,7 @@ function build_read_command(getScanner) {
|
|
|
10718
12193
|
const guid_re = /guid:\s*([a-f0-9]{32})/g;
|
|
10719
12194
|
for (const f of files) {
|
|
10720
12195
|
try {
|
|
10721
|
-
const fc =
|
|
12196
|
+
const fc = import_fs17.readFileSync(f, "utf-8");
|
|
10722
12197
|
let gm;
|
|
10723
12198
|
while ((gm = guid_re.exec(fc)) !== null) {
|
|
10724
12199
|
referenced_guids.add(gm[1]);
|
|
@@ -10729,8 +12204,8 @@ function build_read_command(getScanner) {
|
|
|
10729
12204
|
}
|
|
10730
12205
|
const buildSettingsPath = import_path8.join(resolvedProject, "ProjectSettings", "EditorBuildSettings.asset");
|
|
10731
12206
|
const build_scene_guids = new Set;
|
|
10732
|
-
if (
|
|
10733
|
-
const bsc =
|
|
12207
|
+
if (import_fs17.existsSync(buildSettingsPath)) {
|
|
12208
|
+
const bsc = import_fs17.readFileSync(buildSettingsPath, "utf-8");
|
|
10734
12209
|
let bm;
|
|
10735
12210
|
while ((bm = guid_re.exec(bsc)) !== null) {
|
|
10736
12211
|
build_scene_guids.add(bm[1]);
|
|
@@ -10848,19 +12323,11 @@ function build_read_command(getScanner) {
|
|
|
10848
12323
|
}
|
|
10849
12324
|
console.log(JSON.stringify({ file, ...ia }, null, 2));
|
|
10850
12325
|
});
|
|
10851
|
-
cmd.command("prefab").argument("[file]").allowUnknownOption().action(() => {
|
|
10852
|
-
console.log(JSON.stringify({
|
|
10853
|
-
success: false,
|
|
10854
|
-
error: '"read prefab" does not exist. Use "read scene" -- it handles both .unity and .prefab files.',
|
|
10855
|
-
correct_usage: "unity-agentic-tools read scene <file.prefab>"
|
|
10856
|
-
}, null, 2));
|
|
10857
|
-
process.exitCode = 1;
|
|
10858
|
-
});
|
|
10859
12326
|
return cmd;
|
|
10860
12327
|
}
|
|
10861
12328
|
|
|
10862
12329
|
// src/cmd-update.ts
|
|
10863
|
-
var
|
|
12330
|
+
var import_fs18 = require("fs");
|
|
10864
12331
|
var import_path9 = require("path");
|
|
10865
12332
|
|
|
10866
12333
|
// src/animator-utils.ts
|
|
@@ -11006,10 +12473,10 @@ function resolve_transform_id(scanner, file, identifier) {
|
|
|
11006
12473
|
if (result && !result.is_error) {
|
|
11007
12474
|
const transform = result.components?.find((c) => c.class_id === 4 || c.class_id === 224);
|
|
11008
12475
|
if (transform)
|
|
11009
|
-
return { transform_id:
|
|
12476
|
+
return { transform_id: transform.file_id };
|
|
11010
12477
|
}
|
|
11011
12478
|
if (/^-?\d+$/.test(identifier)) {
|
|
11012
|
-
return { transform_id:
|
|
12479
|
+
return { transform_id: identifier };
|
|
11013
12480
|
}
|
|
11014
12481
|
return { error: `Could not resolve "${identifier}" to a Transform component. Use a GameObject name or transform fileID.` };
|
|
11015
12482
|
}
|
|
@@ -11027,7 +12494,7 @@ function build_update_command(getScanner) {
|
|
|
11027
12494
|
if (!result.success)
|
|
11028
12495
|
process.exitCode = 1;
|
|
11029
12496
|
});
|
|
11030
|
-
cmd.command("component <file> <file_id> <property> <value>").description("Edit any component property by file ID. Supports dotted paths (m_LocalPosition.x) and array paths (m_Materials.Array.data[0])").option("-j, --json", "Output as JSON").action((file, file_id, property, value, _options) => {
|
|
12497
|
+
cmd.command("component <file> <file_id> <property> <value>").description("Edit any component property by file ID. Supports dotted paths (m_LocalPosition.x) and array paths (m_Materials.Array.data[0]). Quote paths with brackets or use dot notation (data.0) to avoid shell glob expansion").option("-j, --json", "Output as JSON").action((file, file_id, property, value, _options) => {
|
|
11031
12498
|
if (property === "m_RootOrder") {
|
|
11032
12499
|
const num = Number(value);
|
|
11033
12500
|
if (!Number.isInteger(num) || num < 0) {
|
|
@@ -11183,14 +12650,71 @@ function build_update_command(getScanner) {
|
|
|
11183
12650
|
if (!result.success)
|
|
11184
12651
|
process.exitCode = 1;
|
|
11185
12652
|
});
|
|
11186
|
-
prefab_cmd.command("override <file> <prefab_instance> <property_path> <value>").description("Edit or add a property override in a PrefabInstance m_Modifications list").option("--object-reference <ref>", "Object reference value (default: {fileID: 0})").option("--target <target>", 'Target reference for new entries (e.g., "{fileID: 400000, guid: abc, type: 3}")').option("-j, --json", "Output as JSON").action((file, prefab_instance, property_path, value, options) => {
|
|
12653
|
+
prefab_cmd.command("override <file> <prefab_instance> <property_path> <value>").description("Edit or add a property override in a PrefabInstance m_Modifications list. Quote paths with brackets or use dot notation (data.0) to avoid shell glob expansion").option("--object-reference <ref>", "Object reference value (default: {fileID: 0})").option("--managed-reference <id>", "Managed reference ID -- placed in value: field, forces objectReference: {fileID: 0}").option("--target <target>", 'Target reference for new entries (e.g., "{fileID: 400000, guid: abc, type: 3}")').option("-j, --json", "Output as JSON").action((file, prefab_instance, property_path, value, options) => {
|
|
12654
|
+
if (options.objectReference && !/^\{fileID:/.test(options.objectReference)) {
|
|
12655
|
+
console.error(`Warning: --object-reference "${options.objectReference}" does not look like a Unity object reference ({fileID: ...}). For managed reference IDs, use --managed-reference instead or pass the ID as the <value> argument.`);
|
|
12656
|
+
}
|
|
11187
12657
|
const result = editPrefabOverride({
|
|
11188
12658
|
file_path: file,
|
|
11189
12659
|
prefab_instance,
|
|
11190
12660
|
property_path,
|
|
11191
12661
|
new_value: value,
|
|
11192
12662
|
object_reference: options.objectReference,
|
|
11193
|
-
target: options.target
|
|
12663
|
+
target: options.target,
|
|
12664
|
+
managed_reference: options.managedReference
|
|
12665
|
+
});
|
|
12666
|
+
console.log(JSON.stringify(result, null, 2));
|
|
12667
|
+
if (!result.success)
|
|
12668
|
+
process.exitCode = 1;
|
|
12669
|
+
});
|
|
12670
|
+
prefab_cmd.command("batch-overrides <file> <prefab_instance> <edits_json>").description('Batch edit multiple property overrides in a PrefabInstance. JSON format: [{"property_path":"...","value":"...","target":"...","object_reference":"..."}]').option("-j, --json", "Output as JSON").action((file, prefab_instance, edits_json, _options) => {
|
|
12671
|
+
let raw_edits;
|
|
12672
|
+
try {
|
|
12673
|
+
const parsed = JSON.parse(edits_json);
|
|
12674
|
+
if (!Array.isArray(parsed)) {
|
|
12675
|
+
console.log(JSON.stringify({ success: false, error: 'Edits must be a JSON array. Format: [{"property_path":"...","value":"..."}]' }, null, 2));
|
|
12676
|
+
process.exit(1);
|
|
12677
|
+
}
|
|
12678
|
+
raw_edits = parsed;
|
|
12679
|
+
} catch {
|
|
12680
|
+
console.log(JSON.stringify({ success: false, error: "Invalid JSON for edits" }, null, 2));
|
|
12681
|
+
process.exit(1);
|
|
12682
|
+
}
|
|
12683
|
+
const edits = raw_edits.map((e) => ({
|
|
12684
|
+
property_path: String(e.property_path ?? ""),
|
|
12685
|
+
value: String(e.new_value ?? e.value ?? ""),
|
|
12686
|
+
object_reference: e.object_reference != null ? String(e.object_reference) : undefined,
|
|
12687
|
+
target: e.target != null ? String(e.target) : undefined,
|
|
12688
|
+
managed_reference: e.managed_reference != null ? String(e.managed_reference) : undefined
|
|
12689
|
+
}));
|
|
12690
|
+
if (edits.length === 0) {
|
|
12691
|
+
console.log(JSON.stringify({ success: false, error: 'Empty edits array. Provide at least one edit: [{"property_path":"...","value":"..."}]' }, null, 2));
|
|
12692
|
+
process.exit(1);
|
|
12693
|
+
}
|
|
12694
|
+
for (const edit of edits) {
|
|
12695
|
+
if (!edit.property_path) {
|
|
12696
|
+
console.log(JSON.stringify({ success: false, error: 'Missing "property_path" in edit entry. JSON format: [{"property_path":"...","value":"..."}]' }, null, 2));
|
|
12697
|
+
process.exit(1);
|
|
12698
|
+
}
|
|
12699
|
+
if (!edit.value && !edit.object_reference && !edit.managed_reference) {
|
|
12700
|
+
console.log(JSON.stringify({ success: false, error: `Missing "value" for override "${edit.property_path}". Provide "value", "object_reference", or "managed_reference".` }, null, 2));
|
|
12701
|
+
process.exit(1);
|
|
12702
|
+
}
|
|
12703
|
+
}
|
|
12704
|
+
const result = batchEditPrefabOverrides(file, prefab_instance, edits);
|
|
12705
|
+
console.log(JSON.stringify(result, null, 2));
|
|
12706
|
+
if (!result.success)
|
|
12707
|
+
process.exitCode = 1;
|
|
12708
|
+
});
|
|
12709
|
+
prefab_cmd.command("managed-reference <file> <prefab_instance> <field_path> <type_name>").description("Add a [SerializeReference] managed reference to a prefab override. Auto-generates rid and creates type/data/version override entries.").requiredOption("--target <ref>", 'Target reference (e.g., "{fileID: 400000, guid: ..., type: 3}")').option("--index <n>", "Array index (default: 0)", "0").option("-p, --project <path>", "Unity project path (for type registry)").option("-j, --json", "Output as JSON").action((file, prefab_instance, field_path, type_name, options) => {
|
|
12710
|
+
const result = addPrefabManagedReference({
|
|
12711
|
+
file_path: file,
|
|
12712
|
+
prefab_instance,
|
|
12713
|
+
field_path,
|
|
12714
|
+
type_name,
|
|
12715
|
+
target: options.target,
|
|
12716
|
+
index: parseInt(options.index, 10),
|
|
12717
|
+
project_path: options.project
|
|
11194
12718
|
});
|
|
11195
12719
|
console.log(JSON.stringify(result, null, 2));
|
|
11196
12720
|
if (!result.success)
|
|
@@ -11222,7 +12746,7 @@ function build_update_command(getScanner) {
|
|
|
11222
12746
|
process.exitCode = 1;
|
|
11223
12747
|
}
|
|
11224
12748
|
});
|
|
11225
|
-
cmd.command("array <file> <file_id> <array_property> <action> [args...]").description("Insert, append, or remove array elements in a component. Insert: <index> <value> or <value> --index <n>. Append: <value>. Remove: <index> or --index <n>.").option("--index <n>", "Index for insert/remove").option("-j, --json", "Output as JSON").action((file, file_id, array_property, action, args, options) => {
|
|
12749
|
+
cmd.command("array <file> <file_id> <array_property> <action> [args...]").description("Insert, append, or remove array elements in a component. Insert: <index> <value> or <value> --index <n>. Append: <value>. Remove: <index> or --index <n>. Quote paths with brackets or use dot notation (data.0) to avoid shell glob expansion").option("--index <n>", "Index for insert/remove").option("-j, --json", "Output as JSON").action((file, file_id, array_property, action, args, options) => {
|
|
11226
12750
|
if (action !== "insert" && action !== "append" && action !== "remove") {
|
|
11227
12751
|
console.log(JSON.stringify({ success: false, error: 'Action must be "insert", "append", or "remove"' }, null, 2));
|
|
11228
12752
|
process.exit(1);
|
|
@@ -11357,7 +12881,7 @@ function build_update_command(getScanner) {
|
|
|
11357
12881
|
if (!result.success)
|
|
11358
12882
|
process.exitCode = 1;
|
|
11359
12883
|
});
|
|
11360
|
-
prefab_cmd.command("remove-override <file> <prefab_instance> <property_path>").description("Remove a property override from a PrefabInstance").option("--target <ref>", "Target reference to match (for disambiguation)").option("-j, --json", "Output as JSON").action((file, prefab_instance, property_path, options) => {
|
|
12884
|
+
prefab_cmd.command("remove-override <file> <prefab_instance> <property_path>").description("Remove a property override from a PrefabInstance. Quote paths with brackets or use dot notation (data.0) to avoid shell glob expansion").option("--target <ref>", "Target reference to match (for disambiguation)").option("-j, --json", "Output as JSON").action((file, prefab_instance, property_path, options) => {
|
|
11361
12885
|
const result = removePrefabOverride({
|
|
11362
12886
|
file_path: file,
|
|
11363
12887
|
prefab_instance,
|
|
@@ -11418,11 +12942,11 @@ function build_update_command(getScanner) {
|
|
|
11418
12942
|
}
|
|
11419
12943
|
}
|
|
11420
12944
|
}).action((file, options) => {
|
|
11421
|
-
if (!
|
|
12945
|
+
if (!import_fs18.existsSync(file)) {
|
|
11422
12946
|
console.log(JSON.stringify({ success: false, error: `File not found: ${file}` }, null, 2));
|
|
11423
12947
|
process.exit(1);
|
|
11424
12948
|
}
|
|
11425
|
-
let content =
|
|
12949
|
+
let content = import_fs18.readFileSync(file, "utf-8");
|
|
11426
12950
|
const changes = [];
|
|
11427
12951
|
if (options.shader) {
|
|
11428
12952
|
const guid = options.shader;
|
|
@@ -11571,7 +13095,7 @@ ${lm[1]} - ${kw}
|
|
|
11571
13095
|
process.exitCode = 1;
|
|
11572
13096
|
return;
|
|
11573
13097
|
}
|
|
11574
|
-
|
|
13098
|
+
import_fs18.writeFileSync(file, content, "utf-8");
|
|
11575
13099
|
console.log(JSON.stringify({ success: true, file, changes }, null, 2));
|
|
11576
13100
|
});
|
|
11577
13101
|
cmd.command("meta [file]").description("Edit Unity .meta file importer settings").option("--set <key=value>", "Set an importer setting (e.g., isReadable=1)", (v, p) => [...p, v], []).option("--max-size <n>", "Set TextureImporter maxTextureSize").option("--compression <type>", "Set textureCompression (0=None, 1=LowQuality, 2=Normal, 3=HighQuality)").option("--filter-mode <mode>", "Set filterMode (0=Point, 1=Bilinear, 2=Trilinear)").option("--read-write", "Enable isReadable").option("--no-read-write", "Disable isReadable").option("--batch <glob>", "Apply to all matching files").option("--dry-run", "Preview changes without writing").option("-j, --json", "Output as JSON").action((file, options) => {
|
|
@@ -11632,9 +13156,9 @@ ${lm[1]} - ${kw}
|
|
|
11632
13156
|
const suffix = import_path9.basename(pattern).replace(/^\*+/, "");
|
|
11633
13157
|
const meta_files = [];
|
|
11634
13158
|
const scan = (d) => {
|
|
11635
|
-
for (const entry of
|
|
13159
|
+
for (const entry of import_fs18.readdirSync(d)) {
|
|
11636
13160
|
const full = import_path9.join(d, entry);
|
|
11637
|
-
if (
|
|
13161
|
+
if (import_fs18.statSync(full).isDirectory()) {
|
|
11638
13162
|
if (pattern.includes("**"))
|
|
11639
13163
|
scan(full);
|
|
11640
13164
|
} else if (entry.endsWith(suffix)) {
|
|
@@ -11642,7 +13166,7 @@ ${lm[1]} - ${kw}
|
|
|
11642
13166
|
}
|
|
11643
13167
|
}
|
|
11644
13168
|
};
|
|
11645
|
-
if (
|
|
13169
|
+
if (import_fs18.existsSync(dir))
|
|
11646
13170
|
scan(dir);
|
|
11647
13171
|
if (meta_files.length === 0) {
|
|
11648
13172
|
console.log(JSON.stringify({ success: false, error: `No files matched pattern: ${glob_pattern}` }, null, 2));
|
|
@@ -11650,7 +13174,7 @@ ${lm[1]} - ${kw}
|
|
|
11650
13174
|
}
|
|
11651
13175
|
const results = [];
|
|
11652
13176
|
for (const mf of meta_files) {
|
|
11653
|
-
let mc =
|
|
13177
|
+
let mc = import_fs18.readFileSync(mf, "utf-8");
|
|
11654
13178
|
const file_changes = [];
|
|
11655
13179
|
for (const edit of edits) {
|
|
11656
13180
|
const re = new RegExp(`^(\\s*${edit.key}:)[ \\t]*.*$`, "m");
|
|
@@ -11661,7 +13185,7 @@ ${lm[1]} - ${kw}
|
|
|
11661
13185
|
}
|
|
11662
13186
|
if (file_changes.length > 0) {
|
|
11663
13187
|
if (!options.dryRun)
|
|
11664
|
-
|
|
13188
|
+
import_fs18.writeFileSync(mf, mc, "utf-8");
|
|
11665
13189
|
results.push({ file: mf, changes: file_changes });
|
|
11666
13190
|
}
|
|
11667
13191
|
}
|
|
@@ -11674,11 +13198,11 @@ ${lm[1]} - ${kw}
|
|
|
11674
13198
|
}, null, 2));
|
|
11675
13199
|
return;
|
|
11676
13200
|
}
|
|
11677
|
-
if (!
|
|
13201
|
+
if (!import_fs18.existsSync(metaPath)) {
|
|
11678
13202
|
console.log(JSON.stringify({ success: false, error: `Meta file not found: ${metaPath}` }, null, 2));
|
|
11679
13203
|
process.exit(1);
|
|
11680
13204
|
}
|
|
11681
|
-
let content =
|
|
13205
|
+
let content = import_fs18.readFileSync(metaPath, "utf-8");
|
|
11682
13206
|
const changes = [];
|
|
11683
13207
|
for (const edit of edits) {
|
|
11684
13208
|
const re = new RegExp(`^(\\s*${edit.key}:)[ \\t]*.*$`, "m");
|
|
@@ -11693,11 +13217,11 @@ ${lm[1]} - ${kw}
|
|
|
11693
13217
|
console.log(JSON.stringify({ success: true, dry_run: true, file: metaPath, changes }, null, 2));
|
|
11694
13218
|
return;
|
|
11695
13219
|
}
|
|
11696
|
-
|
|
13220
|
+
import_fs18.writeFileSync(metaPath, content, "utf-8");
|
|
11697
13221
|
console.log(JSON.stringify({ success: true, file: metaPath, changes }, null, 2));
|
|
11698
13222
|
});
|
|
11699
13223
|
cmd.command("animation <file>").description("Edit AnimationClip settings and events").option("--set <property=value>", "Set a clip property (e.g., wrap-mode=2 for Loop)", (v, p) => [...p, v], []).option("--add-event <time,function[,data]>", "Add an animation event (e.g., 0.5,OnFootstep,left)", (v, p) => [...p, v], []).option("--remove-event <index>", "Remove an animation event by index (0-based)").option("-j, --json", "Output as JSON").action((file, options) => {
|
|
11700
|
-
if (!
|
|
13224
|
+
if (!import_fs18.existsSync(file)) {
|
|
11701
13225
|
console.log(JSON.stringify({ success: false, error: `File not found: ${file}` }, null, 2));
|
|
11702
13226
|
process.exit(1);
|
|
11703
13227
|
}
|
|
@@ -11705,7 +13229,7 @@ ${lm[1]} - ${kw}
|
|
|
11705
13229
|
console.log(JSON.stringify({ success: false, error: `File is not an AnimationClip (.anim): ${file}` }, null, 2));
|
|
11706
13230
|
process.exit(1);
|
|
11707
13231
|
}
|
|
11708
|
-
let content =
|
|
13232
|
+
let content = import_fs18.readFileSync(file, "utf-8");
|
|
11709
13233
|
const changes = [];
|
|
11710
13234
|
const property_map = {
|
|
11711
13235
|
"wrap-mode": "m_WrapMode",
|
|
@@ -11866,16 +13390,16 @@ ${event_yaml}
|
|
|
11866
13390
|
process.exitCode = 1;
|
|
11867
13391
|
return;
|
|
11868
13392
|
}
|
|
11869
|
-
|
|
13393
|
+
import_fs18.writeFileSync(file, content, "utf-8");
|
|
11870
13394
|
console.log(JSON.stringify({ success: true, file, changes }, null, 2));
|
|
11871
13395
|
});
|
|
11872
13396
|
const PARAM_TYPE_MAP = { float: 1, int: 3, bool: 4, trigger: 9 };
|
|
11873
13397
|
cmd.command("animator <file>").description("Edit AnimatorController parameters").option("--add-parameter <name>", "Add a new parameter").option("--type <float|int|bool|trigger>", "Parameter type (required with --add-parameter)").option("--remove-parameter <name>", "Remove a parameter by name").option("--set-default <param=value>", "Set parameter default value (e.g., Speed=1.5)", (v, p) => [...p, v], []).option("-j, --json", "Output as JSON").action((file, options) => {
|
|
11874
|
-
if (!
|
|
13398
|
+
if (!import_fs18.existsSync(file)) {
|
|
11875
13399
|
console.log(JSON.stringify({ success: false, error: `File not found: ${file}` }, null, 2));
|
|
11876
13400
|
process.exit(1);
|
|
11877
13401
|
}
|
|
11878
|
-
let content =
|
|
13402
|
+
let content = import_fs18.readFileSync(file, "utf-8");
|
|
11879
13403
|
const had_crlf = content.includes(`\r
|
|
11880
13404
|
`);
|
|
11881
13405
|
if (had_crlf)
|
|
@@ -11977,7 +13501,7 @@ $1`);
|
|
|
11977
13501
|
if (had_crlf)
|
|
11978
13502
|
content = content.replace(/\n/g, `\r
|
|
11979
13503
|
`);
|
|
11980
|
-
|
|
13504
|
+
import_fs18.writeFileSync(file, content, "utf-8");
|
|
11981
13505
|
console.log(JSON.stringify({ success: true, file, changes }, null, 2));
|
|
11982
13506
|
});
|
|
11983
13507
|
cmd.command("sibling-index <file> <object_name> <index>").description("Set the sibling index of a GameObject, renumbering all siblings").option("-j, --json", "Output as JSON").action((file, object_name, index_str, _options) => {
|
|
@@ -11987,7 +13511,7 @@ $1`);
|
|
|
11987
13511
|
process.exitCode = 1;
|
|
11988
13512
|
return;
|
|
11989
13513
|
}
|
|
11990
|
-
if (!
|
|
13514
|
+
if (!import_fs18.existsSync(file)) {
|
|
11991
13515
|
console.log(JSON.stringify({ success: false, error: `File not found: ${file}` }, null, 2));
|
|
11992
13516
|
process.exitCode = 1;
|
|
11993
13517
|
return;
|
|
@@ -12182,7 +13706,7 @@ $1`);
|
|
|
12182
13706
|
console.log(JSON.stringify({ success: true, file, changes }, null, 2));
|
|
12183
13707
|
});
|
|
12184
13708
|
cmd.command("animation-curves <file>").description("Add, remove, or modify animation curves in an .anim file").option("--add-curve <json>", 'Add a curve (JSON: {"type":"float","path":"Body","attribute":"m_Alpha","classID":23,"keyframes":[{"time":0,"value":1}]})').option("--remove-curve <spec>", "Remove a curve by path:attribute (e.g., Body/Mesh:m_Alpha)").option("--set-keyframes <json>", 'Replace keyframes (JSON: {"curve":"path:attribute","keyframes":[{"time":0,"value":10}]})').option("-j, --json", "Output as JSON").action((file, options) => {
|
|
12185
|
-
if (!
|
|
13709
|
+
if (!import_fs18.existsSync(file)) {
|
|
12186
13710
|
console.log(JSON.stringify({ success: false, error: `File not found: ${file}` }, null, 2));
|
|
12187
13711
|
process.exitCode = 1;
|
|
12188
13712
|
return;
|
|
@@ -12192,7 +13716,7 @@ $1`);
|
|
|
12192
13716
|
process.exitCode = 1;
|
|
12193
13717
|
return;
|
|
12194
13718
|
}
|
|
12195
|
-
let content =
|
|
13719
|
+
let content = import_fs18.readFileSync(file, "utf-8");
|
|
12196
13720
|
const had_crlf = content.includes(`\r
|
|
12197
13721
|
`);
|
|
12198
13722
|
if (had_crlf)
|
|
@@ -12490,16 +14014,16 @@ ${curve_yaml}`);
|
|
|
12490
14014
|
if (had_crlf)
|
|
12491
14015
|
content = content.replace(/\n/g, `\r
|
|
12492
14016
|
`);
|
|
12493
|
-
|
|
14017
|
+
import_fs18.writeFileSync(file, content, "utf-8");
|
|
12494
14018
|
console.log(JSON.stringify({ success: true, file, changes }, null, 2));
|
|
12495
14019
|
});
|
|
12496
14020
|
cmd.command("animator-state <file>").description("Add/remove states and transitions in an AnimatorController").option("--add-state <name>", "Add a new AnimatorState").option("--motion <guid-or-path>", "Motion clip GUID or file path (companion to --add-state)").option("--layer <name>", "Target layer name (default: first layer)").option("--speed <n>", "State speed (companion to --add-state, default: 1)").option("--remove-state <name>", "Remove a state and all its transitions").option("--add-transition <src:dst>", 'Add a transition (use "any" for AnyState source)').option("--condition <param,mode,threshold>", "Transition condition (repeatable)", (v, p) => [...p, v], []).option("--has-exit-time", "Enable exit time on transition").option("--exit-time <n>", "Exit time value (default: 0.75)").option("--duration <n>", "Transition duration (default: 0.25)").option("--remove-transition <src:dst>", "Remove a transition by source:destination state names").option("--set-default-state <name>", "Set the default state in the state machine").option("-j, --json", "Output as JSON").action((file, options) => {
|
|
12497
|
-
if (!
|
|
14021
|
+
if (!import_fs18.existsSync(file)) {
|
|
12498
14022
|
console.log(JSON.stringify({ success: false, error: `File not found: ${file}` }, null, 2));
|
|
12499
14023
|
process.exitCode = 1;
|
|
12500
14024
|
return;
|
|
12501
14025
|
}
|
|
12502
|
-
let content =
|
|
14026
|
+
let content = import_fs18.readFileSync(file, "utf-8");
|
|
12503
14027
|
const had_crlf = content.includes(`\r
|
|
12504
14028
|
`);
|
|
12505
14029
|
if (had_crlf)
|
|
@@ -12838,10 +14362,34 @@ $1`);
|
|
|
12838
14362
|
if (had_crlf)
|
|
12839
14363
|
content = content.replace(/\n/g, `\r
|
|
12840
14364
|
`);
|
|
12841
|
-
|
|
14365
|
+
import_fs18.writeFileSync(file, content, "utf-8");
|
|
12842
14366
|
console.log(JSON.stringify({ success: true, file, changes }, null, 2));
|
|
12843
14367
|
});
|
|
12844
14368
|
cmd.addCommand(prefab_cmd);
|
|
14369
|
+
cmd.command("managed-reference <file> <component_id> <field_path> <type_name>").description('Add a managed reference (SerializeReference) to a component field. Type can be "Namespace.ClassName" (registry lookup) or "Assembly Namespace.ClassName" (manual).').option("-p, --project <path>", "Unity project path (for type registry)").option("--append", "Append to array (do not update field rid)").option("--properties <json>", `JSON object of initial field values for the data block (e.g. '{"damage": "10"}')`).option("-j, --json", "Output as JSON").action((file, component_id, field_path, type_name, options) => {
|
|
14370
|
+
let initial_values;
|
|
14371
|
+
if (options.properties) {
|
|
14372
|
+
try {
|
|
14373
|
+
initial_values = JSON.parse(options.properties);
|
|
14374
|
+
} catch {
|
|
14375
|
+
console.log(JSON.stringify({ success: false, error: `Invalid JSON for --properties: ${options.properties}` }, null, 2));
|
|
14376
|
+
process.exitCode = 1;
|
|
14377
|
+
return;
|
|
14378
|
+
}
|
|
14379
|
+
}
|
|
14380
|
+
const result = editManagedReference({
|
|
14381
|
+
file_path: file,
|
|
14382
|
+
file_id: component_id,
|
|
14383
|
+
field_path,
|
|
14384
|
+
type_name,
|
|
14385
|
+
project_path: options.project,
|
|
14386
|
+
append: options.append === true,
|
|
14387
|
+
initial_values
|
|
14388
|
+
});
|
|
14389
|
+
console.log(JSON.stringify(result, null, 2));
|
|
14390
|
+
if (!result.success)
|
|
14391
|
+
process.exitCode = 1;
|
|
14392
|
+
});
|
|
12845
14393
|
return cmd;
|
|
12846
14394
|
}
|
|
12847
14395
|
|
|
@@ -12907,16 +14455,16 @@ function build_delete_command() {
|
|
|
12907
14455
|
var import_path11 = require("path");
|
|
12908
14456
|
|
|
12909
14457
|
// src/editor-client.ts
|
|
12910
|
-
var
|
|
14458
|
+
var import_fs19 = require("fs");
|
|
12911
14459
|
var import_path10 = require("path");
|
|
12912
14460
|
function read_editor_config(project_path) {
|
|
12913
14461
|
const config_path = import_path10.join(project_path, ".unity-agentic", "editor.json");
|
|
12914
|
-
if (!
|
|
14462
|
+
if (!import_fs19.existsSync(config_path)) {
|
|
12915
14463
|
return { error: `Editor bridge not found at ${config_path}. Is the Unity Editor running with the bridge package installed?` };
|
|
12916
14464
|
}
|
|
12917
14465
|
let config;
|
|
12918
14466
|
try {
|
|
12919
|
-
const raw =
|
|
14467
|
+
const raw = import_fs19.readFileSync(config_path, "utf-8");
|
|
12920
14468
|
config = JSON.parse(raw);
|
|
12921
14469
|
} catch (err) {
|
|
12922
14470
|
return { error: `Failed to parse editor.json: ${err instanceof Error ? err.message : String(err)}` };
|
|
@@ -12929,23 +14477,45 @@ function read_editor_config(project_path) {
|
|
|
12929
14477
|
}
|
|
12930
14478
|
return config;
|
|
12931
14479
|
}
|
|
14480
|
+
var RETRYABLE_CODES = new Set([-32000, -32002, -32003]);
|
|
14481
|
+
var RETRY_DELAYS = [500, 1000, 2000];
|
|
12932
14482
|
async function call_editor(options) {
|
|
12933
|
-
const
|
|
14483
|
+
const maxRetries = options.retries ?? 2;
|
|
14484
|
+
let lastResponse;
|
|
14485
|
+
for (let attempt = 0;attempt <= maxRetries; attempt++) {
|
|
14486
|
+
lastResponse = await call_editor_once(options);
|
|
14487
|
+
if (!lastResponse.error || !RETRYABLE_CODES.has(lastResponse.error.code)) {
|
|
14488
|
+
return lastResponse;
|
|
14489
|
+
}
|
|
14490
|
+
if (attempt < maxRetries) {
|
|
14491
|
+
const delay = RETRY_DELAYS[Math.min(attempt, RETRY_DELAYS.length - 1)];
|
|
14492
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
14493
|
+
}
|
|
14494
|
+
}
|
|
14495
|
+
return lastResponse;
|
|
14496
|
+
}
|
|
14497
|
+
function call_editor_once(options) {
|
|
14498
|
+
const { method, params, timeout = 1e4, no_wait } = options;
|
|
12934
14499
|
const config = resolve_config(options);
|
|
12935
14500
|
if ("error" in config) {
|
|
12936
|
-
return {
|
|
14501
|
+
return Promise.resolve({
|
|
12937
14502
|
jsonrpc: "2.0",
|
|
12938
14503
|
id: "0",
|
|
12939
14504
|
error: { code: -32000, message: config.error }
|
|
12940
|
-
};
|
|
14505
|
+
});
|
|
12941
14506
|
}
|
|
12942
14507
|
const url = `ws://127.0.0.1:${config.port}/unity-agentic`;
|
|
12943
14508
|
const request_id = generate_id();
|
|
14509
|
+
const wire_params = { ...params };
|
|
14510
|
+
if (timeout !== 1e4)
|
|
14511
|
+
wire_params._timeout = timeout;
|
|
14512
|
+
if (no_wait)
|
|
14513
|
+
wire_params.no_wait = true;
|
|
12944
14514
|
const request = {
|
|
12945
14515
|
jsonrpc: "2.0",
|
|
12946
14516
|
id: request_id,
|
|
12947
14517
|
method,
|
|
12948
|
-
...
|
|
14518
|
+
...Object.keys(wire_params).length > 0 ? { params: wire_params } : {}
|
|
12949
14519
|
};
|
|
12950
14520
|
return new Promise((resolve7) => {
|
|
12951
14521
|
let resolved = false;
|
|
@@ -12967,6 +14537,20 @@ async function call_editor(options) {
|
|
|
12967
14537
|
ws = new WebSocket(url);
|
|
12968
14538
|
ws.onopen = () => {
|
|
12969
14539
|
ws.send(JSON.stringify(request));
|
|
14540
|
+
if (no_wait && !resolved) {
|
|
14541
|
+
resolved = true;
|
|
14542
|
+
clearTimeout(timer);
|
|
14543
|
+
setTimeout(() => {
|
|
14544
|
+
try {
|
|
14545
|
+
ws.close();
|
|
14546
|
+
} catch {}
|
|
14547
|
+
}, 200);
|
|
14548
|
+
resolve7({
|
|
14549
|
+
jsonrpc: "2.0",
|
|
14550
|
+
id: request_id,
|
|
14551
|
+
result: { queued: true }
|
|
14552
|
+
});
|
|
14553
|
+
}
|
|
12970
14554
|
};
|
|
12971
14555
|
ws.onmessage = (event) => {
|
|
12972
14556
|
try {
|
|
@@ -13022,42 +14606,75 @@ async function stream_editor(options) {
|
|
|
13022
14606
|
if ("error" in config) {
|
|
13023
14607
|
throw new Error(config.error);
|
|
13024
14608
|
}
|
|
13025
|
-
const
|
|
13026
|
-
|
|
13027
|
-
|
|
13028
|
-
jsonrpc: "2.0",
|
|
13029
|
-
id: request_id,
|
|
13030
|
-
method,
|
|
13031
|
-
...params ? { params } : {}
|
|
13032
|
-
};
|
|
14609
|
+
const MAX_RECONNECTS = 5;
|
|
14610
|
+
let reconnect_count = 0;
|
|
14611
|
+
let stopped = false;
|
|
13033
14612
|
return new Promise((resolve7, reject) => {
|
|
13034
|
-
let
|
|
13035
|
-
|
|
13036
|
-
|
|
13037
|
-
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13043
|
-
|
|
13044
|
-
|
|
13045
|
-
|
|
13046
|
-
|
|
13047
|
-
|
|
13048
|
-
try {
|
|
13049
|
-
const data = JSON.parse(String(event.data));
|
|
13050
|
-
if ("method" in data && !("id" in data)) {
|
|
13051
|
-
on_event(data);
|
|
14613
|
+
let resolved = false;
|
|
14614
|
+
function connect(url) {
|
|
14615
|
+
const ws = new WebSocket(url);
|
|
14616
|
+
const request_id = generate_id();
|
|
14617
|
+
const request = {
|
|
14618
|
+
jsonrpc: "2.0",
|
|
14619
|
+
id: request_id,
|
|
14620
|
+
method,
|
|
14621
|
+
...params ? { params } : {}
|
|
14622
|
+
};
|
|
14623
|
+
let connected = false;
|
|
14624
|
+
const timer = !resolved ? setTimeout(() => {
|
|
14625
|
+
if (!connected && !resolved) {
|
|
14626
|
+
reject(new Error(`Timeout connecting to ${url}`));
|
|
13052
14627
|
}
|
|
13053
|
-
}
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
|
|
13059
|
-
|
|
13060
|
-
|
|
14628
|
+
}, timeout) : null;
|
|
14629
|
+
ws.onopen = () => {
|
|
14630
|
+
connected = true;
|
|
14631
|
+
if (timer)
|
|
14632
|
+
clearTimeout(timer);
|
|
14633
|
+
reconnect_count = 0;
|
|
14634
|
+
ws.send(JSON.stringify(request));
|
|
14635
|
+
if (!resolved) {
|
|
14636
|
+
resolved = true;
|
|
14637
|
+
resolve7({ close: () => {
|
|
14638
|
+
stopped = true;
|
|
14639
|
+
ws.close();
|
|
14640
|
+
} });
|
|
14641
|
+
}
|
|
14642
|
+
};
|
|
14643
|
+
ws.onmessage = (event) => {
|
|
14644
|
+
try {
|
|
14645
|
+
const data = JSON.parse(String(event.data));
|
|
14646
|
+
if ("method" in data && !("id" in data)) {
|
|
14647
|
+
on_event(data);
|
|
14648
|
+
}
|
|
14649
|
+
} catch {}
|
|
14650
|
+
};
|
|
14651
|
+
ws.onerror = () => {
|
|
14652
|
+
if (!connected && !resolved) {
|
|
14653
|
+
if (timer)
|
|
14654
|
+
clearTimeout(timer);
|
|
14655
|
+
reject(new Error(`WebSocket connection failed to ${url}`));
|
|
14656
|
+
}
|
|
14657
|
+
};
|
|
14658
|
+
ws.onclose = () => {
|
|
14659
|
+
if (stopped)
|
|
14660
|
+
return;
|
|
14661
|
+
if (!connected && !resolved)
|
|
14662
|
+
return;
|
|
14663
|
+
if (reconnect_count >= MAX_RECONNECTS)
|
|
14664
|
+
return;
|
|
14665
|
+
reconnect_count++;
|
|
14666
|
+
const delay = Math.min(500 * reconnect_count, 3000);
|
|
14667
|
+
setTimeout(() => {
|
|
14668
|
+
if (stopped)
|
|
14669
|
+
return;
|
|
14670
|
+
const fresh_config = resolve_config(options);
|
|
14671
|
+
if ("error" in fresh_config)
|
|
14672
|
+
return;
|
|
14673
|
+
connect(`ws://127.0.0.1:${fresh_config.port}/unity-agentic`);
|
|
14674
|
+
}, delay);
|
|
14675
|
+
};
|
|
14676
|
+
}
|
|
14677
|
+
connect(`ws://127.0.0.1:${config.port}/unity-agentic`);
|
|
13061
14678
|
});
|
|
13062
14679
|
}
|
|
13063
14680
|
function resolve_config(options) {
|
|
@@ -13101,12 +14718,12 @@ function get_common_options(cmd) {
|
|
|
13101
14718
|
const port = port_str ? parseInt(port_str, 10) : undefined;
|
|
13102
14719
|
return { project_path, timeout, port };
|
|
13103
14720
|
}
|
|
13104
|
-
function build_call_options(cmd, method, params) {
|
|
14721
|
+
function build_call_options(cmd, method, params, extra) {
|
|
13105
14722
|
const { project_path, timeout, port } = get_common_options(cmd);
|
|
13106
|
-
return { project_path, method, params, timeout, port };
|
|
14723
|
+
return { project_path, method, params, timeout, port, ...extra?.no_wait ? { no_wait: true } : {} };
|
|
13107
14724
|
}
|
|
13108
|
-
async function handle_rpc(cmd, method, params) {
|
|
13109
|
-
const options = build_call_options(cmd, method, params);
|
|
14725
|
+
async function handle_rpc(cmd, method, params, extra) {
|
|
14726
|
+
const options = build_call_options(cmd, method, params, extra);
|
|
13110
14727
|
const response = await call_editor(options);
|
|
13111
14728
|
output_response(response);
|
|
13112
14729
|
}
|
|
@@ -13183,24 +14800,27 @@ function build_editor_command() {
|
|
|
13183
14800
|
console.log(JSON.stringify(response.result, null, 2));
|
|
13184
14801
|
}
|
|
13185
14802
|
});
|
|
13186
|
-
cmd.command("invoke <type> <member> [args...]").description("Call a static Unity Editor API method or read/set a static property").option("--set <value>", "Set a static property value").option("--args <json>", "JSON array of method arguments (overrides positional args)").action(async function(type, member, args, options) {
|
|
14803
|
+
cmd.command("invoke <type> <member> [args...]").description("Call a static Unity Editor API method or read/set a static property").option("--set <value>", "Set a static property value").option("--args <json>", "JSON array of method arguments (overrides positional args)").option("--no-wait", "Fire and forget -- return immediately without waiting for result").action(async function(type, member, args, options) {
|
|
13187
14804
|
const params = { type, member };
|
|
13188
14805
|
if (options.set !== undefined) {
|
|
13189
14806
|
params.set = options.set;
|
|
13190
14807
|
} else if (options.args) {
|
|
13191
14808
|
params.args = options.args;
|
|
14809
|
+
} else if (args.length === 1 && args[0].startsWith("[")) {
|
|
14810
|
+
params.args = args[0];
|
|
13192
14811
|
} else if (args.length > 0) {
|
|
13193
14812
|
params.args = JSON.stringify(args);
|
|
13194
14813
|
}
|
|
13195
|
-
await handle_rpc(this, "editor.invoke", params);
|
|
14814
|
+
await handle_rpc(this, "editor.invoke", params, { no_wait: options.noWait });
|
|
13196
14815
|
});
|
|
13197
|
-
cmd.command("console-logs").description("Get recent console log entries").option("-c, --count <n>", "Number of log entries to retrieve", "50").option("--limit <n>", "Alias for --count").option("-t, --type <type>", "Filter by log type (Log, Warning, Error, Assert, Exception)").action(async function(options) {
|
|
14816
|
+
cmd.command("console-logs").description("Get recent console log entries").option("-c, --count <n>", "Number of log entries to retrieve", "50").option("--limit <n>", "Alias for --count").option("-t, --type <type>", "Filter by log type (Log, Warning, Error, Assert, Exception)").option("-s, --severity <type>", "Alias for --type").action(async function(options) {
|
|
13198
14817
|
const params = {};
|
|
13199
14818
|
const count = options.limit || options.count;
|
|
13200
14819
|
if (count)
|
|
13201
14820
|
params.count = parseInt(count, 10);
|
|
13202
|
-
|
|
13203
|
-
|
|
14821
|
+
const typeFilter = options.severity || options.type;
|
|
14822
|
+
if (typeFilter)
|
|
14823
|
+
params.type = typeFilter;
|
|
13204
14824
|
await handle_rpc(this, "editor.console.getLogs", params);
|
|
13205
14825
|
});
|
|
13206
14826
|
cmd.command("console-clear").description("Clear the console log buffer").action(async function() {
|
|
@@ -13217,7 +14837,7 @@ function build_editor_command() {
|
|
|
13217
14837
|
port,
|
|
13218
14838
|
method: "editor.console.subscribe",
|
|
13219
14839
|
on_event: (event) => {
|
|
13220
|
-
if (event.method === "editor.console.logReceived"
|
|
14840
|
+
if (event.method === "editor.console.logReceived") {
|
|
13221
14841
|
const params = event.params ?? {};
|
|
13222
14842
|
if (type_filter && typeof params.type === "string" && params.type.toLowerCase() !== type_filter) {
|
|
13223
14843
|
return;
|
|
@@ -13475,23 +15095,12 @@ function build_editor_command() {
|
|
|
13475
15095
|
process.exitCode = 1;
|
|
13476
15096
|
}
|
|
13477
15097
|
});
|
|
13478
|
-
cmd.command("log").allowUnknownOption().argument("[args...]").action(() => {
|
|
13479
|
-
console.log(JSON.stringify({
|
|
13480
|
-
success: false,
|
|
13481
|
-
error: '"editor log" does not exist. Use one of:',
|
|
13482
|
-
alternatives: [
|
|
13483
|
-
{ command: "editor console-logs", description: "Get recent console entries from the running Editor (live bridge)" },
|
|
13484
|
-
{ command: "read log", description: "Read and filter the Unity Editor.log file on disk (no bridge needed)" }
|
|
13485
|
-
]
|
|
13486
|
-
}, null, 2));
|
|
13487
|
-
process.exitCode = 1;
|
|
13488
|
-
});
|
|
13489
15098
|
return cmd;
|
|
13490
15099
|
}
|
|
13491
15100
|
|
|
13492
15101
|
// src/project-search.ts
|
|
13493
15102
|
init_scanner();
|
|
13494
|
-
var
|
|
15103
|
+
var import_fs20 = require("fs");
|
|
13495
15104
|
var path8 = __toESM(require("path"));
|
|
13496
15105
|
var BINARY_EXTENSIONS = new Set([
|
|
13497
15106
|
".png",
|
|
@@ -13554,7 +15163,7 @@ function walk_project_files_js(project_path, extensions, exclude_dirs) {
|
|
|
13554
15163
|
function walk(dir) {
|
|
13555
15164
|
let entries;
|
|
13556
15165
|
try {
|
|
13557
|
-
entries =
|
|
15166
|
+
entries = import_fs20.readdirSync(dir);
|
|
13558
15167
|
} catch {
|
|
13559
15168
|
return;
|
|
13560
15169
|
}
|
|
@@ -13562,7 +15171,7 @@ function walk_project_files_js(project_path, extensions, exclude_dirs) {
|
|
|
13562
15171
|
const full = path8.join(dir, entry);
|
|
13563
15172
|
let stat;
|
|
13564
15173
|
try {
|
|
13565
|
-
stat =
|
|
15174
|
+
stat = import_fs20.statSync(full);
|
|
13566
15175
|
} catch {
|
|
13567
15176
|
continue;
|
|
13568
15177
|
}
|
|
@@ -13579,14 +15188,14 @@ function walk_project_files_js(project_path, extensions, exclude_dirs) {
|
|
|
13579
15188
|
}
|
|
13580
15189
|
}
|
|
13581
15190
|
const assetsDir = path8.join(project_path, "Assets");
|
|
13582
|
-
if (
|
|
15191
|
+
if (import_fs20.existsSync(assetsDir)) {
|
|
13583
15192
|
walk(assetsDir);
|
|
13584
15193
|
} else {
|
|
13585
15194
|
walk(project_path);
|
|
13586
15195
|
}
|
|
13587
15196
|
if (extSet.has(".asset")) {
|
|
13588
15197
|
const settingsDir = path8.join(project_path, "ProjectSettings");
|
|
13589
|
-
if (
|
|
15198
|
+
if (import_fs20.existsSync(settingsDir)) {
|
|
13590
15199
|
walk(settingsDir);
|
|
13591
15200
|
}
|
|
13592
15201
|
}
|
|
@@ -13627,7 +15236,7 @@ function search_project(options) {
|
|
|
13627
15236
|
error: "Name pattern must not be empty"
|
|
13628
15237
|
};
|
|
13629
15238
|
}
|
|
13630
|
-
if (!
|
|
15239
|
+
if (!import_fs20.existsSync(project_path)) {
|
|
13631
15240
|
return {
|
|
13632
15241
|
success: false,
|
|
13633
15242
|
project_path,
|
|
@@ -13669,7 +15278,7 @@ function search_project(options) {
|
|
|
13669
15278
|
}
|
|
13670
15279
|
let display_name = fileName;
|
|
13671
15280
|
try {
|
|
13672
|
-
const content =
|
|
15281
|
+
const content = import_fs20.readFileSync(file, "utf-8");
|
|
13673
15282
|
const nameMatch = /^\s*m_Name:\s*(.+)$/m.exec(content.slice(0, 2000));
|
|
13674
15283
|
if (nameMatch)
|
|
13675
15284
|
display_name = nameMatch[1].trim();
|
|
@@ -13850,7 +15459,7 @@ function grep_project_js(options) {
|
|
|
13850
15459
|
max_results = 100,
|
|
13851
15460
|
context_lines = 0
|
|
13852
15461
|
} = options;
|
|
13853
|
-
if (!
|
|
15462
|
+
if (!import_fs20.existsSync(project_path)) {
|
|
13854
15463
|
return {
|
|
13855
15464
|
success: false,
|
|
13856
15465
|
project_path,
|
|
@@ -13940,7 +15549,7 @@ function grep_project_js(options) {
|
|
|
13940
15549
|
totalFilesScanned++;
|
|
13941
15550
|
let content;
|
|
13942
15551
|
try {
|
|
13943
|
-
content =
|
|
15552
|
+
content = import_fs20.readFileSync(file, "utf-8");
|
|
13944
15553
|
} catch {
|
|
13945
15554
|
continue;
|
|
13946
15555
|
}
|
|
@@ -14219,9 +15828,9 @@ program.command("status").description("Show current configuration and status").o
|
|
|
14219
15828
|
let config = null;
|
|
14220
15829
|
let guidCacheCount = 0;
|
|
14221
15830
|
try {
|
|
14222
|
-
const { existsSync: existsSync22, readFileSync:
|
|
15831
|
+
const { existsSync: existsSync22, readFileSync: readFileSync17 } = require("fs");
|
|
14223
15832
|
if (existsSync22(configFile)) {
|
|
14224
|
-
config = JSON.parse(
|
|
15833
|
+
config = JSON.parse(readFileSync17(configFile, "utf-8"));
|
|
14225
15834
|
}
|
|
14226
15835
|
const guidCacheObj = load_guid_cache(projectPath);
|
|
14227
15836
|
guidCacheCount = guidCacheObj?.count ?? 0;
|