unity-agentic-tools 0.4.2 → 0.4.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 +20 -2
- package/dist/cli.js +1171 -494
- package/dist/index.js +475 -75
- 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.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -205,7 +205,7 @@ var require_package = __commonJS((exports2, module2) => {
|
|
|
205
205
|
module2.exports = {
|
|
206
206
|
name: "unity-agentic-tools",
|
|
207
207
|
packageManager: "bun@latest",
|
|
208
|
-
version: "0.4.
|
|
208
|
+
version: "0.4.3",
|
|
209
209
|
description: "Fast, token-efficient Unity YAML parser for AI agents",
|
|
210
210
|
exports: {
|
|
211
211
|
".": {
|
|
@@ -1848,6 +1848,19 @@ function build_guid_cache(project_path, raw) {
|
|
|
1848
1848
|
}
|
|
1849
1849
|
}
|
|
1850
1850
|
return substringMatch;
|
|
1851
|
+
},
|
|
1852
|
+
find_all_by_name_exact(name, extension) {
|
|
1853
|
+
const nameLower = name.toLowerCase().replace(/\.[^.]+$/, "");
|
|
1854
|
+
const matches = [];
|
|
1855
|
+
for (const [guid, assetPath] of Object.entries(raw)) {
|
|
1856
|
+
if (extension && !assetPath.endsWith(extension))
|
|
1857
|
+
continue;
|
|
1858
|
+
const fileName = import_path5.basename(assetPath, import_path5.extname(assetPath)).toLowerCase();
|
|
1859
|
+
if (fileName === nameLower) {
|
|
1860
|
+
matches.push({ guid, path: assetPath });
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
return matches;
|
|
1851
1864
|
}
|
|
1852
1865
|
};
|
|
1853
1866
|
}
|
|
@@ -1946,15 +1959,14 @@ var UNITY_CLASS_IDS = {
|
|
|
1946
1959
|
114: "MonoBehaviour",
|
|
1947
1960
|
115: "MonoScript",
|
|
1948
1961
|
117: "Texture3D",
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
126: "
|
|
1957
|
-
127: "NavMeshProjectSettings",
|
|
1962
|
+
118: "NewAnimationTrack",
|
|
1963
|
+
119: "Projector",
|
|
1964
|
+
120: "LineRenderer",
|
|
1965
|
+
121: "Flare",
|
|
1966
|
+
122: "Halo",
|
|
1967
|
+
123: "LensFlare",
|
|
1968
|
+
124: "FlareLayer",
|
|
1969
|
+
126: "NavMeshProjectSettings",
|
|
1958
1970
|
128: "Font",
|
|
1959
1971
|
129: "PlayerSettings",
|
|
1960
1972
|
130: "NamedObject",
|
|
@@ -1981,6 +1993,7 @@ var UNITY_CLASS_IDS = {
|
|
|
1981
1993
|
164: "AudioReverbFilter",
|
|
1982
1994
|
165: "AudioHighPassFilter",
|
|
1983
1995
|
166: "AudioChorusFilter",
|
|
1996
|
+
1660057539: "SceneRoots",
|
|
1984
1997
|
167: "AudioReverbZone",
|
|
1985
1998
|
168: "AudioEchoFilter",
|
|
1986
1999
|
169: "AudioLowPassFilter",
|
|
@@ -2051,29 +2064,41 @@ var UNITY_CLASS_IDS = {
|
|
|
2051
2064
|
257: "TargetJoint2D",
|
|
2052
2065
|
258: "LightProbes",
|
|
2053
2066
|
259: "LightProbeProxyVolume",
|
|
2054
|
-
260: "
|
|
2055
|
-
261: "
|
|
2056
|
-
262: "
|
|
2067
|
+
260: "SampleClipLegacy",
|
|
2068
|
+
261: "AudioMixerSnapshotLegacy",
|
|
2069
|
+
262: "AudioMixerGroupLegacy",
|
|
2057
2070
|
265: "NScreenBridge",
|
|
2058
|
-
271: "
|
|
2071
|
+
271: "SampleClip",
|
|
2059
2072
|
272: "UnityAdsManager",
|
|
2060
|
-
273: "
|
|
2061
|
-
280: "
|
|
2062
|
-
281: "
|
|
2063
|
-
290: "
|
|
2064
|
-
292: "
|
|
2065
|
-
293: "
|
|
2066
|
-
294: "
|
|
2067
|
-
298: "
|
|
2073
|
+
273: "AudioMixerGroup",
|
|
2074
|
+
280: "UnityConnectSettingsLegacy",
|
|
2075
|
+
281: "AvatarMaskLegacy",
|
|
2076
|
+
290: "AssetBundleManifest",
|
|
2077
|
+
292: "VideoPlayerLegacy",
|
|
2078
|
+
293: "VideoClipLegacy",
|
|
2079
|
+
294: "ParticleSystemForceFieldLegacy",
|
|
2080
|
+
298: "SpriteMaskLegacy",
|
|
2068
2081
|
300: "WorldAnchor",
|
|
2069
|
-
301: "
|
|
2070
|
-
310: "
|
|
2071
|
-
|
|
2072
|
-
|
|
2082
|
+
301: "OcclusionCullingDataLegacy",
|
|
2083
|
+
310: "UnityConnectSettings",
|
|
2084
|
+
1001: "PrefabInstance",
|
|
2085
|
+
319: "AvatarMask",
|
|
2086
|
+
320: "PlayableDirector",
|
|
2087
|
+
328: "VideoPlayer",
|
|
2088
|
+
329: "VideoClip",
|
|
2089
|
+
330: "ParticleSystemForceField",
|
|
2090
|
+
331: "SpriteMask",
|
|
2091
|
+
363: "OcclusionCullingData",
|
|
2092
|
+
1006: "TextureImporter",
|
|
2093
|
+
181963792: "Preset",
|
|
2073
2094
|
687078895: "SpriteAtlas",
|
|
2095
|
+
156049354: "Grid",
|
|
2096
|
+
1742807556: "GridLayout",
|
|
2074
2097
|
1839735485: "Tilemap",
|
|
2075
|
-
|
|
2076
|
-
|
|
2098
|
+
19719996: "TilemapCollider2D",
|
|
2099
|
+
483693784: "TilemapRenderer",
|
|
2100
|
+
1839735486: "TilemapCollider2DLegacy",
|
|
2101
|
+
1839735487: "TilemapRendererLegacy"
|
|
2077
2102
|
};
|
|
2078
2103
|
var UNITY_CLASS_NAMES = Object.fromEntries(Object.entries(UNITY_CLASS_IDS).map(([id, name]) => [name, parseInt(id, 10)]));
|
|
2079
2104
|
function get_class_id_name(class_id) {
|
|
@@ -2147,8 +2172,12 @@ function resolve_source_prefab(doc, file_path, project_path) {
|
|
|
2147
2172
|
prefab_instance_block: pi_block
|
|
2148
2173
|
};
|
|
2149
2174
|
}
|
|
2150
|
-
function resolveScriptGuid(script, projectPath) {
|
|
2175
|
+
function resolveScriptGuid(script, projectPath, options) {
|
|
2176
|
+
const strictExactName = options?.strict_exact_name === true;
|
|
2151
2177
|
if (/^[a-f0-9]{32}$/i.test(script)) {
|
|
2178
|
+
if (/^0{32}$/i.test(script)) {
|
|
2179
|
+
throw new Error(`Invalid script GUID "${script}": all-zero GUID is not allowed. Provide a real script GUID from a .meta file.`);
|
|
2180
|
+
}
|
|
2152
2181
|
return { guid: script.toLowerCase(), path: null };
|
|
2153
2182
|
}
|
|
2154
2183
|
if (script.endsWith(".cs")) {
|
|
@@ -2173,9 +2202,20 @@ function resolveScriptGuid(script, projectPath) {
|
|
|
2173
2202
|
if (projectPath) {
|
|
2174
2203
|
const guidCache = load_guid_cache(projectPath);
|
|
2175
2204
|
if (guidCache) {
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2205
|
+
if (strictExactName) {
|
|
2206
|
+
const exactMatches = guidCache.find_all_by_name_exact(script, ".cs");
|
|
2207
|
+
if (exactMatches.length === 1) {
|
|
2208
|
+
return exactMatches[0];
|
|
2209
|
+
}
|
|
2210
|
+
if (exactMatches.length > 1) {
|
|
2211
|
+
const paths = exactMatches.map((m) => m.path).join(", ");
|
|
2212
|
+
throw new Error(`Ambiguous type "${script}": found ${exactMatches.length} exact script name matches (${paths}). ` + 'Use a qualified name (e.g., "Namespace.TypeName") or provide the full script path.');
|
|
2213
|
+
}
|
|
2214
|
+
} else {
|
|
2215
|
+
const result = guidCache.find_by_name(script, ".cs");
|
|
2216
|
+
if (result)
|
|
2217
|
+
return result;
|
|
2218
|
+
}
|
|
2179
2219
|
}
|
|
2180
2220
|
const registryPath = path3.join(projectPath, ".unity-agentic", "type-registry.json");
|
|
2181
2221
|
if (import_fs8.existsSync(registryPath)) {
|
|
@@ -2326,15 +2366,30 @@ function resolveScriptGuid(script, projectPath) {
|
|
|
2326
2366
|
continue;
|
|
2327
2367
|
try {
|
|
2328
2368
|
const cache = JSON.parse(import_fs8.readFileSync(cachePath, "utf-8"));
|
|
2369
|
+
const exactMatches = [];
|
|
2329
2370
|
for (const [guid, assetPath] of Object.entries(cache)) {
|
|
2330
2371
|
if (!assetPath.endsWith(".cs"))
|
|
2331
2372
|
continue;
|
|
2332
2373
|
const fileName = path3.basename(assetPath, ".cs").toLowerCase();
|
|
2333
2374
|
if (fileName === scriptNameLower || classNameOnly && fileName === classNameOnly) {
|
|
2334
|
-
|
|
2375
|
+
exactMatches.push({ guid, path: assetPath });
|
|
2335
2376
|
}
|
|
2336
2377
|
}
|
|
2337
|
-
|
|
2378
|
+
if (exactMatches.length === 1) {
|
|
2379
|
+
return exactMatches[0];
|
|
2380
|
+
}
|
|
2381
|
+
if (exactMatches.length > 1) {
|
|
2382
|
+
const paths = exactMatches.map((m) => m.path).join(", ");
|
|
2383
|
+
throw new Error(`Ambiguous type "${script}": found ${exactMatches.length} exact script name matches (${paths}). ` + 'Use a qualified name (e.g., "Namespace.TypeName") or provide the full script path.');
|
|
2384
|
+
}
|
|
2385
|
+
} catch (err) {
|
|
2386
|
+
if (err instanceof Error && err.message.startsWith("Ambiguous type")) {
|
|
2387
|
+
throw err;
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
if (strictExactName) {
|
|
2392
|
+
return null;
|
|
2338
2393
|
}
|
|
2339
2394
|
try {
|
|
2340
2395
|
const assetsDir = path3.join(projectPath, "Assets");
|
|
@@ -2405,19 +2460,38 @@ function resolveAssetPathToPPtr(value, file_path, project_path) {
|
|
|
2405
2460
|
return null;
|
|
2406
2461
|
return `{fileID: ${mapping.fileID}, guid: ${guid}, type: ${mapping.type}}`;
|
|
2407
2462
|
}
|
|
2408
|
-
function
|
|
2409
|
-
|
|
2463
|
+
function detect_abstract_class_in_source(file_path, class_name) {
|
|
2464
|
+
try {
|
|
2465
|
+
const source = import_fs8.readFileSync(file_path, "utf-8");
|
|
2466
|
+
const escaped_name = class_name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2467
|
+
const pattern = new RegExp(`(^|[^\\w])abstract\\s+class\\s+${escaped_name}(?=$|[^\\w])`, "m");
|
|
2468
|
+
return pattern.test(source);
|
|
2469
|
+
} catch {
|
|
2470
|
+
return false;
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
function resolve_script_with_fields(script, project_path, options) {
|
|
2474
|
+
const resolved = resolveScriptGuid(script, project_path, options);
|
|
2410
2475
|
if (!resolved)
|
|
2411
2476
|
return null;
|
|
2412
2477
|
const result = {
|
|
2413
2478
|
guid: resolved.guid,
|
|
2414
2479
|
path: resolved.path
|
|
2415
2480
|
};
|
|
2481
|
+
if (resolved.path && resolved.path.endsWith(".cs")) {
|
|
2482
|
+
const full_path = path3.isAbsolute(resolved.path) ? resolved.path : project_path ? path3.join(project_path, resolved.path) : resolved.path;
|
|
2483
|
+
if (import_fs8.existsSync(full_path)) {
|
|
2484
|
+
const class_name = script.includes(".") ? script.split(".").pop() : script;
|
|
2485
|
+
if (class_name.length > 0) {
|
|
2486
|
+
result.is_abstract = detect_abstract_class_in_source(full_path, class_name);
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2416
2490
|
if (!project_path)
|
|
2417
2491
|
return result;
|
|
2418
2492
|
if (resolved.path) {
|
|
2419
2493
|
try {
|
|
2420
|
-
const full_path = resolved.path
|
|
2494
|
+
const full_path = path3.isAbsolute(resolved.path) ? resolved.path : path3.join(project_path, resolved.path);
|
|
2421
2495
|
if (!import_fs8.existsSync(full_path)) {
|
|
2422
2496
|
result.extraction_error = `Script file not found at resolved path: ${full_path}`;
|
|
2423
2497
|
} else if (resolved.path.endsWith(".cs")) {
|
|
@@ -2431,6 +2505,10 @@ function resolve_script_with_fields(script, project_path) {
|
|
|
2431
2505
|
result.fields = chosen.fields;
|
|
2432
2506
|
result.base_class = chosen.baseClass ?? undefined;
|
|
2433
2507
|
result.kind = chosen.kind;
|
|
2508
|
+
result.class_name = chosen.name;
|
|
2509
|
+
if (chosen.name) {
|
|
2510
|
+
result.is_abstract = detect_abstract_class_in_source(full_path, chosen.name);
|
|
2511
|
+
}
|
|
2434
2512
|
}
|
|
2435
2513
|
} else {
|
|
2436
2514
|
result.extraction_error = "Native extractSerializedFields function not available";
|
|
@@ -3530,7 +3608,21 @@ class UnityDocument {
|
|
|
3530
3608
|
}
|
|
3531
3609
|
}
|
|
3532
3610
|
}
|
|
3533
|
-
|
|
3611
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3612
|
+
const name_pattern = new RegExp(`propertyPath: m_Name\\s*\\n\\s*value:\\s*${escaped}\\s*$`, "m");
|
|
3613
|
+
for (const block of this._blocks) {
|
|
3614
|
+
if ((block.class_id === 1001 || block.class_id === 310) && name_pattern.test(block.raw)) {
|
|
3615
|
+
const pi_id = block.file_id;
|
|
3616
|
+
const pi_ref_pattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${pi_id}\\}`);
|
|
3617
|
+
const stripped_transform = this._blocks.find((b) => (b.class_id === 4 || b.class_id === 224) && b.is_stripped && pi_ref_pattern.test(b.raw));
|
|
3618
|
+
if (stripped_transform) {
|
|
3619
|
+
transform_ids.push(stripped_transform.file_id);
|
|
3620
|
+
} else {
|
|
3621
|
+
transform_ids.push(pi_id);
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
return Array.from(new Set(transform_ids));
|
|
3534
3626
|
}
|
|
3535
3627
|
require_unique_game_object(name_or_id) {
|
|
3536
3628
|
if (/^-?\d+$/.test(name_or_id)) {
|
|
@@ -3559,10 +3651,7 @@ class UnityDocument {
|
|
|
3559
3651
|
if (!block) {
|
|
3560
3652
|
return { error: `Block with fileID ${name_or_id} not found` };
|
|
3561
3653
|
}
|
|
3562
|
-
if (block.class_id === 4) {
|
|
3563
|
-
return block;
|
|
3564
|
-
}
|
|
3565
|
-
if (block.class_id === 224) {
|
|
3654
|
+
if (block.class_id === 4 || block.class_id === 224 || block.class_id === 1001 || block.class_id === 310) {
|
|
3566
3655
|
return block;
|
|
3567
3656
|
}
|
|
3568
3657
|
if (block.class_id === 1) {
|
|
@@ -3575,15 +3664,40 @@ class UnityDocument {
|
|
|
3575
3664
|
}
|
|
3576
3665
|
return { error: `Transform for GameObject fileID ${name_or_id} not found` };
|
|
3577
3666
|
}
|
|
3578
|
-
return { error: `fileID ${name_or_id} is not a GameObject or
|
|
3667
|
+
return { error: `fileID ${name_or_id} is not a GameObject, Transform, or PrefabInstance (class ${block.class_id})` };
|
|
3579
3668
|
}
|
|
3580
3669
|
const transform_ids = this.find_transforms_by_name(name_or_id);
|
|
3581
3670
|
if (transform_ids.length === 0) {
|
|
3582
|
-
return { error: `
|
|
3671
|
+
return { error: `Object "${name_or_id}" not found` };
|
|
3583
3672
|
}
|
|
3584
3673
|
if (transform_ids.length > 1) {
|
|
3585
|
-
const
|
|
3586
|
-
|
|
3674
|
+
const entity_ids = [];
|
|
3675
|
+
for (const tid of transform_ids) {
|
|
3676
|
+
const block = this.find_by_file_id(tid);
|
|
3677
|
+
if (block) {
|
|
3678
|
+
if (block.class_id === 4 || block.class_id === 224) {
|
|
3679
|
+
const go_match = block.raw.match(/m_GameObject:\s*\{fileID:\s*(-?\d+)\}/);
|
|
3680
|
+
if (go_match) {
|
|
3681
|
+
entity_ids.push(go_match[1]);
|
|
3682
|
+
} else {
|
|
3683
|
+
entity_ids.push(tid);
|
|
3684
|
+
}
|
|
3685
|
+
} else if (block.class_id === 1001 || block.class_id === 310) {
|
|
3686
|
+
entity_ids.push(tid);
|
|
3687
|
+
} else if (block.is_stripped) {
|
|
3688
|
+
const pi_match = block.raw.match(/m_PrefabInstance:\s*\{fileID:\s*(-?\d+)\}/);
|
|
3689
|
+
if (pi_match) {
|
|
3690
|
+
entity_ids.push(pi_match[1]);
|
|
3691
|
+
} else {
|
|
3692
|
+
entity_ids.push(tid);
|
|
3693
|
+
}
|
|
3694
|
+
} else {
|
|
3695
|
+
entity_ids.push(tid);
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
}
|
|
3699
|
+
const ids_str = Array.from(new Set(entity_ids)).join(", ");
|
|
3700
|
+
return { error: `Multiple GameObjects/PrefabInstances named "${name_or_id}" found (fileIDs: ${ids_str}). Use numeric fileID to specify which one.` };
|
|
3587
3701
|
}
|
|
3588
3702
|
const transform = this.find_by_file_id(transform_ids[0]);
|
|
3589
3703
|
if (!transform) {
|
|
@@ -3611,7 +3725,7 @@ class UnityDocument {
|
|
|
3611
3725
|
if (t_block.class_id === 4 && t_block.is_stripped) {
|
|
3612
3726
|
let name = "Variant";
|
|
3613
3727
|
for (const pi_block of this._blocks) {
|
|
3614
|
-
if (pi_block.class_id === 1001) {
|
|
3728
|
+
if (pi_block.class_id === 1001 || pi_block.class_id === 310) {
|
|
3615
3729
|
const name_mod = pi_block.raw.match(/propertyPath: m_Name\s*\n\s*value:\s*(.+)/);
|
|
3616
3730
|
if (name_mod) {
|
|
3617
3731
|
name = name_mod[1].trim();
|
|
@@ -3764,7 +3878,7 @@ class UnityDocument {
|
|
|
3764
3878
|
}
|
|
3765
3879
|
add_child_to_parent(parent_id, child_id) {
|
|
3766
3880
|
const parent = this.find_by_file_id(parent_id);
|
|
3767
|
-
if (!parent || parent.class_id !== 4)
|
|
3881
|
+
if (!parent || parent.class_id !== 4 && parent.class_id !== 224)
|
|
3768
3882
|
return false;
|
|
3769
3883
|
let raw = parent.raw;
|
|
3770
3884
|
const inline_empty = /m_Children:\s*\[\]/;
|
|
@@ -3800,7 +3914,7 @@ class UnityDocument {
|
|
|
3800
3914
|
}
|
|
3801
3915
|
remove_child_from_parent(parent_id, child_id) {
|
|
3802
3916
|
const parent = this.find_by_file_id(parent_id);
|
|
3803
|
-
if (!parent || parent.class_id !== 4)
|
|
3917
|
+
if (!parent || parent.class_id !== 4 && parent.class_id !== 224)
|
|
3804
3918
|
return false;
|
|
3805
3919
|
let raw = parent.raw;
|
|
3806
3920
|
const child_line = new RegExp(`\\n[ \\t]*- \\{fileID: ${child_id}\\}`);
|
|
@@ -3821,7 +3935,49 @@ class UnityDocument {
|
|
|
3821
3935
|
}
|
|
3822
3936
|
_collect_hierarchy_recursive(transform_id, result) {
|
|
3823
3937
|
const transform = this.find_by_file_id(transform_id);
|
|
3824
|
-
if (!transform
|
|
3938
|
+
if (!transform)
|
|
3939
|
+
return;
|
|
3940
|
+
if (transform.class_id === 1001 || transform.class_id === 310) {
|
|
3941
|
+
const pi_id = transform.file_id;
|
|
3942
|
+
const pi_ref_pattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${pi_id}\\}`);
|
|
3943
|
+
for (const block of this._blocks) {
|
|
3944
|
+
if (block.is_stripped && pi_ref_pattern.test(block.raw)) {
|
|
3945
|
+
result.add(block.file_id);
|
|
3946
|
+
if (block.class_id === 4 || block.class_id === 224) {
|
|
3947
|
+
this._collect_hierarchy_recursive(block.file_id, result);
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
}
|
|
3951
|
+
const added_go_matches = transform.raw.matchAll(/addedObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)\}/g);
|
|
3952
|
+
for (const match of added_go_matches) {
|
|
3953
|
+
const added_id = match[1];
|
|
3954
|
+
if (added_id !== "0" && !result.has(added_id)) {
|
|
3955
|
+
result.add(added_id);
|
|
3956
|
+
const added_block = this.find_by_file_id(added_id);
|
|
3957
|
+
if (added_block && added_block.class_id === 1) {
|
|
3958
|
+
const comp_matches = added_block.raw.matchAll(/component:[ \t]*\{fileID:[ \t]*(-?\d+)\}/g);
|
|
3959
|
+
for (const cm of comp_matches) {
|
|
3960
|
+
const comp_block = this.find_by_file_id(cm[1]);
|
|
3961
|
+
if (comp_block && (comp_block.class_id === 4 || comp_block.class_id === 224)) {
|
|
3962
|
+
if (!result.has(cm[1])) {
|
|
3963
|
+
result.add(cm[1]);
|
|
3964
|
+
this._collect_hierarchy_recursive(cm[1], result);
|
|
3965
|
+
}
|
|
3966
|
+
break;
|
|
3967
|
+
}
|
|
3968
|
+
}
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
const added_comp_matches = transform.raw.matchAll(/addedObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)\}/g);
|
|
3973
|
+
for (const match of added_comp_matches) {
|
|
3974
|
+
const added_id = match[1];
|
|
3975
|
+
if (added_id !== "0")
|
|
3976
|
+
result.add(added_id);
|
|
3977
|
+
}
|
|
3978
|
+
return;
|
|
3979
|
+
}
|
|
3980
|
+
if (transform.class_id !== 4 && transform.class_id !== 224)
|
|
3825
3981
|
return;
|
|
3826
3982
|
const children_section = transform.raw.match(/m_Children:[\s\S]*?(?=\s*m_Father:)/);
|
|
3827
3983
|
if (!children_section)
|
|
@@ -3856,14 +4012,21 @@ class UnityDocument {
|
|
|
3856
4012
|
if (parent_id === "0") {
|
|
3857
4013
|
let count = 0;
|
|
3858
4014
|
for (const block of this._blocks) {
|
|
3859
|
-
if (block.class_id === 4 && /m_Father:\s*\{fileID:\s*0\}/.test(block.raw)) {
|
|
4015
|
+
if ((block.class_id === 4 || block.class_id === 224) && /m_Father:\s*\{fileID:\s*0\}/.test(block.raw)) {
|
|
3860
4016
|
count++;
|
|
4017
|
+
} else if ((block.class_id === 1001 || block.class_id === 310) && /m_TransformParent:\s*\{fileID:\s*0\}/.test(block.raw)) {
|
|
4018
|
+
const pi_id = block.file_id;
|
|
4019
|
+
const pi_ref_pattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${pi_id}\\}`);
|
|
4020
|
+
const has_stripped = this._blocks.some((b) => (b.class_id === 4 || b.class_id === 224) && b.is_stripped && pi_ref_pattern.test(b.raw));
|
|
4021
|
+
if (!has_stripped) {
|
|
4022
|
+
count++;
|
|
4023
|
+
}
|
|
3861
4024
|
}
|
|
3862
4025
|
}
|
|
3863
4026
|
return count;
|
|
3864
4027
|
}
|
|
3865
4028
|
const parent = this.find_by_file_id(parent_id);
|
|
3866
|
-
if (!parent || parent.class_id !== 4)
|
|
4029
|
+
if (!parent || parent.class_id !== 4 && parent.class_id !== 224)
|
|
3867
4030
|
return 0;
|
|
3868
4031
|
const children_match = parent.raw.match(/m_Children:[\s\S]*?(?=\s*m_Father:)/);
|
|
3869
4032
|
if (children_match) {
|
|
@@ -3896,19 +4059,97 @@ ${new_children}`);
|
|
|
3896
4059
|
}
|
|
3897
4060
|
return false;
|
|
3898
4061
|
}
|
|
4062
|
+
add_root_to_scene_roots(root_id) {
|
|
4063
|
+
const pi_block = this.find_by_file_id(root_id);
|
|
4064
|
+
if (pi_block && (pi_block.class_id === 1001 || pi_block.class_id === 310)) {
|
|
4065
|
+
const pi_ref_pattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${root_id}\\}`);
|
|
4066
|
+
const stripped_root = this._blocks.find((b) => (b.class_id === 4 || b.class_id === 224) && b.is_stripped && pi_ref_pattern.test(b.raw) && /m_Father:\s*\{fileID:\s*0\}/.test(b.raw));
|
|
4067
|
+
if (stripped_root) {
|
|
4068
|
+
root_id = stripped_root.file_id;
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
const sr_blocks = [...this.find_by_class_id(166), ...this.find_by_class_id(1660057539)];
|
|
4072
|
+
if (sr_blocks.length === 0)
|
|
4073
|
+
return false;
|
|
4074
|
+
const sr_block = sr_blocks[0];
|
|
4075
|
+
let raw = sr_block.raw;
|
|
4076
|
+
const roots_pattern = /(m_Roots:\s*\n(?:\s*-\s*\{fileID:\s*-?\d+\}\s*\n)*)/;
|
|
4077
|
+
if (roots_pattern.test(raw)) {
|
|
4078
|
+
raw = raw.replace(roots_pattern, `$1 - {fileID: ${root_id}}
|
|
4079
|
+
`);
|
|
4080
|
+
sr_block.replace_raw(raw);
|
|
4081
|
+
return true;
|
|
4082
|
+
}
|
|
4083
|
+
const empty_roots = /m_Roots:\s*\[\]/;
|
|
4084
|
+
if (empty_roots.test(raw)) {
|
|
4085
|
+
raw = raw.replace(empty_roots, `m_Roots:
|
|
4086
|
+
- {fileID: ${root_id}}`);
|
|
4087
|
+
sr_block.replace_raw(raw);
|
|
4088
|
+
return true;
|
|
4089
|
+
}
|
|
4090
|
+
return false;
|
|
4091
|
+
}
|
|
4092
|
+
remove_root_from_scene_roots(root_id) {
|
|
4093
|
+
const pi_block = this.find_by_file_id(root_id);
|
|
4094
|
+
if (pi_block && (pi_block.class_id === 1001 || pi_block.class_id === 310)) {
|
|
4095
|
+
const pi_ref_pattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${root_id}\\}`);
|
|
4096
|
+
const stripped_root = this._blocks.find((b) => (b.class_id === 4 || b.class_id === 224) && b.is_stripped && pi_ref_pattern.test(b.raw));
|
|
4097
|
+
if (stripped_root) {
|
|
4098
|
+
this._remove_id_from_scene_roots(stripped_root.file_id);
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
return this._remove_id_from_scene_roots(root_id);
|
|
4102
|
+
}
|
|
4103
|
+
_remove_id_from_scene_roots(id) {
|
|
4104
|
+
const sr_blocks = [...this.find_by_class_id(166), ...this.find_by_class_id(1660057539)];
|
|
4105
|
+
if (sr_blocks.length === 0)
|
|
4106
|
+
return false;
|
|
4107
|
+
const sr_block = sr_blocks[0];
|
|
4108
|
+
let raw = sr_block.raw;
|
|
4109
|
+
const root_line = new RegExp(`\\n[ \\t]*- \\{fileID: ${id}\\}`);
|
|
4110
|
+
if (!root_line.test(raw))
|
|
4111
|
+
return false;
|
|
4112
|
+
raw = raw.replace(root_line, "");
|
|
4113
|
+
sr_block.replace_raw(raw);
|
|
4114
|
+
return true;
|
|
4115
|
+
}
|
|
3899
4116
|
reorder_entities(ordered_transform_ids) {
|
|
3900
4117
|
const entity_groups = [];
|
|
3901
4118
|
for (const transform_id of ordered_transform_ids) {
|
|
3902
|
-
const
|
|
3903
|
-
if (!
|
|
4119
|
+
const block = this.find_by_file_id(transform_id);
|
|
4120
|
+
if (!block)
|
|
4121
|
+
continue;
|
|
4122
|
+
let pi_block = null;
|
|
4123
|
+
if (block.class_id === 1001 || block.class_id === 310) {
|
|
4124
|
+
pi_block = block;
|
|
4125
|
+
} else if (block.is_stripped) {
|
|
4126
|
+
const pi_match = block.raw.match(/m_PrefabInstance:\s*\{fileID:\s*(-?\d+)\}/);
|
|
4127
|
+
if (pi_match) {
|
|
4128
|
+
const found = this.find_by_file_id(pi_match[1]);
|
|
4129
|
+
if (found && (found.class_id === 1001 || found.class_id === 310)) {
|
|
4130
|
+
pi_block = found;
|
|
4131
|
+
}
|
|
4132
|
+
}
|
|
4133
|
+
}
|
|
4134
|
+
if (pi_block) {
|
|
4135
|
+
const group = [pi_block.file_id];
|
|
4136
|
+
const hierarchy = this.collect_hierarchy(pi_block.file_id);
|
|
4137
|
+
for (const id of hierarchy)
|
|
4138
|
+
group.push(id);
|
|
4139
|
+
entity_groups.push(group);
|
|
3904
4140
|
continue;
|
|
3905
|
-
|
|
3906
|
-
|
|
4141
|
+
}
|
|
4142
|
+
const go_match = block.raw.match(/m_GameObject:\s*\{fileID:\s*(-?\d+)\}/);
|
|
4143
|
+
if (!go_match) {
|
|
4144
|
+
entity_groups.push([transform_id]);
|
|
3907
4145
|
continue;
|
|
4146
|
+
}
|
|
3908
4147
|
const go_id = go_match[1];
|
|
3909
4148
|
const go = this.find_by_file_id(go_id);
|
|
3910
|
-
if (!go)
|
|
4149
|
+
if (!go) {
|
|
4150
|
+
entity_groups.push([transform_id]);
|
|
3911
4151
|
continue;
|
|
4152
|
+
}
|
|
3912
4153
|
const comp_ids = [];
|
|
3913
4154
|
const comp_matches = go.raw.matchAll(/component:\s*\{fileID:\s*(-?\d+)\}/g);
|
|
3914
4155
|
for (const m of comp_matches) {
|
|
@@ -5450,6 +5691,9 @@ function createScriptableObject(options) {
|
|
|
5450
5691
|
if (resolved.kind === "enum" || resolved.kind === "interface") {
|
|
5451
5692
|
return { success: false, output_path, error: `"${script}" is ${resolved.kind === "enum" ? "an enum" : "an interface"}, not a ScriptableObject.` };
|
|
5452
5693
|
}
|
|
5694
|
+
if (resolved.is_abstract) {
|
|
5695
|
+
return { success: false, output_path, error: `"${script}" is abstract and cannot be instantiated as a ScriptableObject asset.` };
|
|
5696
|
+
}
|
|
5453
5697
|
if (resolved.base_class && resolved.base_class !== "ScriptableObject") {
|
|
5454
5698
|
return { success: false, output_path, error: `"${script}" extends ${resolved.base_class}, not ScriptableObject. Cannot create as a ScriptableObject asset.` };
|
|
5455
5699
|
}
|
|
@@ -5733,6 +5977,13 @@ function addComponent(options) {
|
|
|
5733
5977
|
}
|
|
5734
5978
|
const gameObjectId = gameObjectIdStr;
|
|
5735
5979
|
const classId = get_class_id(component_type);
|
|
5980
|
+
if (classId === 114 && component_type.toLowerCase() === "monobehaviour") {
|
|
5981
|
+
return {
|
|
5982
|
+
success: false,
|
|
5983
|
+
file_path,
|
|
5984
|
+
error: '"MonoBehaviour" is a base class, not a concrete component script. Provide a script type/path/GUID (for example, "PlayerController", "Assets/Scripts/PlayerController.cs", or a 32-char GUID).'
|
|
5985
|
+
};
|
|
5986
|
+
}
|
|
5736
5987
|
let duplicateWarning;
|
|
5737
5988
|
const goBlock = doc.find_by_file_id(gameObjectIdStr);
|
|
5738
5989
|
if (goBlock && classId !== null) {
|
|
@@ -5757,7 +6008,7 @@ function addComponent(options) {
|
|
|
5757
6008
|
} else {
|
|
5758
6009
|
let resolved;
|
|
5759
6010
|
try {
|
|
5760
|
-
resolved = resolve_script_with_fields(component_type, project_path);
|
|
6011
|
+
resolved = resolve_script_with_fields(component_type, project_path, { strict_exact_name: true });
|
|
5761
6012
|
} catch (e) {
|
|
5762
6013
|
return {
|
|
5763
6014
|
success: false,
|
|
@@ -5795,6 +6046,13 @@ function addComponent(options) {
|
|
|
5795
6046
|
error: `"${component_type}" is ${resolved.kind === "enum" ? "an enum" : "an interface"}, not a MonoBehaviour. Cannot add as a component.`
|
|
5796
6047
|
};
|
|
5797
6048
|
}
|
|
6049
|
+
if (resolved.is_abstract) {
|
|
6050
|
+
return {
|
|
6051
|
+
success: false,
|
|
6052
|
+
file_path,
|
|
6053
|
+
error: `"${component_type}" is abstract and cannot be added as a component.`
|
|
6054
|
+
};
|
|
6055
|
+
}
|
|
5798
6056
|
if (resolved.base_class && !COMPONENT_BASE_CLASSES.has(resolved.base_class) && !is_valid_component_base(resolved.base_class, project_path)) {
|
|
5799
6057
|
const warn = `"${component_type}" extends ${resolved.base_class}, which does not inherit from MonoBehaviour. Adding anyway, but ensure the script is a valid component. (Re-run "setup" if the inheritance graph is stale).`;
|
|
5800
6058
|
if (!extractionError)
|
|
@@ -6020,6 +6278,56 @@ function validate_value_type(current_value, new_value) {
|
|
|
6020
6278
|
}
|
|
6021
6279
|
return null;
|
|
6022
6280
|
}
|
|
6281
|
+
function findStrippedTransformForPrefabInstance(doc, prefabInstanceId) {
|
|
6282
|
+
const piRefPattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${prefabInstanceId}\\}`);
|
|
6283
|
+
for (const block of doc.blocks) {
|
|
6284
|
+
if ((block.class_id === 4 || block.class_id === 224) && block.is_stripped && piRefPattern.test(block.raw)) {
|
|
6285
|
+
return block;
|
|
6286
|
+
}
|
|
6287
|
+
}
|
|
6288
|
+
return null;
|
|
6289
|
+
}
|
|
6290
|
+
function resolvePrefabRootOrderTarget(prefabInstanceBlock) {
|
|
6291
|
+
const modificationPattern = /- target:\s*(\{[^}]+\})\s*\n\s*propertyPath:\s*('?)([^\n']+)\2/gm;
|
|
6292
|
+
const transformPropertyPattern = /^m_(?:RootOrder|LocalPosition|LocalRotation|LocalScale|ConstrainProportionsScale)(?:\.|$)/;
|
|
6293
|
+
let transformTarget = null;
|
|
6294
|
+
for (const match of prefabInstanceBlock.raw.matchAll(modificationPattern)) {
|
|
6295
|
+
const targetRef = match[1];
|
|
6296
|
+
const propertyPath = match[3].trim();
|
|
6297
|
+
if (propertyPath === "m_RootOrder") {
|
|
6298
|
+
return targetRef;
|
|
6299
|
+
}
|
|
6300
|
+
if (!transformTarget && transformPropertyPattern.test(propertyPath)) {
|
|
6301
|
+
transformTarget = targetRef;
|
|
6302
|
+
}
|
|
6303
|
+
}
|
|
6304
|
+
return transformTarget;
|
|
6305
|
+
}
|
|
6306
|
+
function upsertPrefabRootOrderOverride(prefabInstanceBlock, newRootOrder) {
|
|
6307
|
+
const existingRootOrderPattern = /(- target:\s*\{[^}]+\}\s*\n\s*propertyPath:\s*'?m_RootOrder'?\s*\n\s*value:\s*)([^\n]*)(\s*\n\s*objectReference:\s*\{[^}]+\})/m;
|
|
6308
|
+
if (existingRootOrderPattern.test(prefabInstanceBlock.raw)) {
|
|
6309
|
+
prefabInstanceBlock.replace_raw(prefabInstanceBlock.raw.replace(existingRootOrderPattern, `$1${newRootOrder}$3`));
|
|
6310
|
+
return true;
|
|
6311
|
+
}
|
|
6312
|
+
const targetRef = resolvePrefabRootOrderTarget(prefabInstanceBlock) ?? "{fileID: 400000}";
|
|
6313
|
+
const rootOrderOverride = ` - target: ${targetRef}
|
|
6314
|
+
` + ` propertyPath: m_RootOrder
|
|
6315
|
+
` + ` value: ${newRootOrder}
|
|
6316
|
+
` + " objectReference: {fileID: 0}";
|
|
6317
|
+
const removedPattern = /(\n\s*m_RemovedComponents:)/m;
|
|
6318
|
+
if (removedPattern.test(prefabInstanceBlock.raw)) {
|
|
6319
|
+
prefabInstanceBlock.replace_raw(prefabInstanceBlock.raw.replace(removedPattern, `
|
|
6320
|
+
${rootOrderOverride}$1`));
|
|
6321
|
+
return true;
|
|
6322
|
+
}
|
|
6323
|
+
const modsPattern = /(m_Modifications:\s*\n)/;
|
|
6324
|
+
if (modsPattern.test(prefabInstanceBlock.raw)) {
|
|
6325
|
+
prefabInstanceBlock.replace_raw(prefabInstanceBlock.raw.replace(modsPattern, `$1${rootOrderOverride}
|
|
6326
|
+
`));
|
|
6327
|
+
return true;
|
|
6328
|
+
}
|
|
6329
|
+
return false;
|
|
6330
|
+
}
|
|
6023
6331
|
function isAncestor(doc, childTransformId, candidateAncestorTransformId) {
|
|
6024
6332
|
let currentId = candidateAncestorTransformId;
|
|
6025
6333
|
const visited = new Set;
|
|
@@ -6030,17 +6338,34 @@ function isAncestor(doc, childTransformId, candidateAncestorTransformId) {
|
|
|
6030
6338
|
return false;
|
|
6031
6339
|
visited.add(currentId);
|
|
6032
6340
|
const block = doc.find_by_file_id(currentId);
|
|
6033
|
-
if (!block
|
|
6341
|
+
if (!block)
|
|
6034
6342
|
break;
|
|
6035
|
-
|
|
6036
|
-
|
|
6343
|
+
if (block.class_id === 1001 || block.class_id === 310) {
|
|
6344
|
+
const parentMatch = block.raw.match(/m_TransformParent:\s*\{fileID:\s*(-?\d+)\}/);
|
|
6345
|
+
currentId = parentMatch ? parentMatch[1] : "0";
|
|
6346
|
+
} else if (block.class_id === 4 || block.class_id === 224) {
|
|
6347
|
+
const fatherMatch = block.raw.match(/m_Father:\s*\{fileID:\s*(-?\d+)\}/);
|
|
6348
|
+
currentId = fatherMatch ? fatherMatch[1] : "0";
|
|
6349
|
+
} else {
|
|
6350
|
+
break;
|
|
6351
|
+
}
|
|
6037
6352
|
}
|
|
6038
6353
|
return false;
|
|
6039
6354
|
}
|
|
6040
6355
|
function resolveTransformByGameObjectId(doc, gameObjectFileId) {
|
|
6041
6356
|
const found = doc.find_by_file_id(gameObjectFileId);
|
|
6042
|
-
if (!found
|
|
6043
|
-
return { error: `
|
|
6357
|
+
if (!found) {
|
|
6358
|
+
return { error: `Block with fileID ${gameObjectFileId} not found` };
|
|
6359
|
+
}
|
|
6360
|
+
if (found.class_id === 4 || found.class_id === 224) {
|
|
6361
|
+
return { id: gameObjectFileId };
|
|
6362
|
+
}
|
|
6363
|
+
if (found.class_id === 1001 || found.class_id === 310) {
|
|
6364
|
+
const strippedTransform = findStrippedTransformForPrefabInstance(doc, gameObjectFileId);
|
|
6365
|
+
return { id: strippedTransform ? strippedTransform.file_id : gameObjectFileId };
|
|
6366
|
+
}
|
|
6367
|
+
if (found.class_id !== 1) {
|
|
6368
|
+
return { error: `fileID ${gameObjectFileId} is not a GameObject, Transform, or PrefabInstance (class ${found.class_id})` };
|
|
6044
6369
|
}
|
|
6045
6370
|
const componentMatch = found.raw.match(/m_Component:\s*\n\s*-\s*component:\s*\{fileID:\s*(-?\d+)\}/);
|
|
6046
6371
|
if (!componentMatch) {
|
|
@@ -6233,7 +6558,7 @@ function editComponentByFileId(options) {
|
|
|
6233
6558
|
}
|
|
6234
6559
|
const targetBlock = doc.find_by_file_id(file_id);
|
|
6235
6560
|
if (!targetBlock) {
|
|
6236
|
-
const hasPrefabInstance = doc.find_by_class_id(1001).length > 0;
|
|
6561
|
+
const hasPrefabInstance = doc.find_by_class_id(1001).length > 0 || doc.find_by_class_id(310).length > 0;
|
|
6237
6562
|
if (hasPrefabInstance) {
|
|
6238
6563
|
return {
|
|
6239
6564
|
success: false,
|
|
@@ -6586,10 +6911,26 @@ function reparentGameObject(options) {
|
|
|
6586
6911
|
}
|
|
6587
6912
|
const childBlock = doc.find_by_file_id(childTransformId);
|
|
6588
6913
|
if (!childBlock) {
|
|
6589
|
-
return { success: false, file_path, error: `Transform ${childTransformId} not found` };
|
|
6914
|
+
return { success: false, file_path, error: `Transform or PrefabInstance ${childTransformId} not found` };
|
|
6915
|
+
}
|
|
6916
|
+
const childHierarchyTransformId = (() => {
|
|
6917
|
+
if (childBlock.class_id === 4 || childBlock.class_id === 224) {
|
|
6918
|
+
return childBlock.file_id;
|
|
6919
|
+
}
|
|
6920
|
+
if (childBlock.class_id === 1001 || childBlock.class_id === 310) {
|
|
6921
|
+
const stripped = findStrippedTransformForPrefabInstance(doc, childBlock.file_id);
|
|
6922
|
+
return stripped ? stripped.file_id : null;
|
|
6923
|
+
}
|
|
6924
|
+
return null;
|
|
6925
|
+
})();
|
|
6926
|
+
let oldParentTransformId = "0";
|
|
6927
|
+
if (childBlock.class_id === 1001 || childBlock.class_id === 310) {
|
|
6928
|
+
const parentMatch = childBlock.raw.match(/m_TransformParent:\s*\{fileID:\s*(-?\d+)\}/);
|
|
6929
|
+
oldParentTransformId = parentMatch ? parentMatch[1] : "0";
|
|
6930
|
+
} else {
|
|
6931
|
+
const fatherMatch = childBlock.raw.match(/m_Father:\s*\{fileID:\s*(-?\d+)\}/);
|
|
6932
|
+
oldParentTransformId = fatherMatch ? fatherMatch[1] : "0";
|
|
6590
6933
|
}
|
|
6591
|
-
const fatherMatch = childBlock.raw.match(/m_Father:\s*\{fileID:\s*(-?\d+)\}/);
|
|
6592
|
-
const oldParentTransformId = fatherMatch ? fatherMatch[1] : "0";
|
|
6593
6934
|
let newParentTransformId = "0";
|
|
6594
6935
|
if (new_parent.toLowerCase() !== "root") {
|
|
6595
6936
|
if (by_id || /^-?\d+$/.test(new_parent)) {
|
|
@@ -6616,11 +6957,55 @@ function reparentGameObject(options) {
|
|
|
6616
6957
|
}
|
|
6617
6958
|
}
|
|
6618
6959
|
if (oldParentTransformId !== "0") {
|
|
6619
|
-
|
|
6960
|
+
if (childHierarchyTransformId) {
|
|
6961
|
+
doc.remove_child_from_parent(oldParentTransformId, childHierarchyTransformId);
|
|
6962
|
+
} else {
|
|
6963
|
+
doc.remove_child_from_parent(oldParentTransformId, childBlock.file_id);
|
|
6964
|
+
}
|
|
6965
|
+
} else {
|
|
6966
|
+
if (childHierarchyTransformId) {
|
|
6967
|
+
doc.remove_root_from_scene_roots(childHierarchyTransformId);
|
|
6968
|
+
} else {
|
|
6969
|
+
doc.remove_root_from_scene_roots(childBlock.file_id);
|
|
6970
|
+
}
|
|
6971
|
+
}
|
|
6972
|
+
if (childBlock.class_id === 1001 || childBlock.class_id === 310) {
|
|
6973
|
+
const tpPattern = new RegExp(`(m_TransformParent:\\s*)\\{fileID:\\s*(-?\\d+)\\}`);
|
|
6974
|
+
if (tpPattern.test(childBlock.raw)) {
|
|
6975
|
+
let updatedChildRaw = childBlock.raw.replace(tpPattern, `$1{fileID: ${newParentTransformId}}`);
|
|
6976
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
6977
|
+
} else {
|
|
6978
|
+
const modPattern = /(m_Modification:\s*\n)/;
|
|
6979
|
+
const modIndentMatch = childBlock.raw.match(/^([ \t]*)m_Modification:/m);
|
|
6980
|
+
const indent = modIndentMatch ? modIndentMatch[1] : "";
|
|
6981
|
+
let updatedChildRaw = childBlock.raw.replace(modPattern, `$1${indent} m_TransformParent: {fileID: ${newParentTransformId}}
|
|
6982
|
+
`);
|
|
6983
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
6984
|
+
}
|
|
6985
|
+
} else {
|
|
6986
|
+
const fatherPattern = new RegExp(`(m_Father:\\s*)\\{fileID:\\s*\\d+\\}`);
|
|
6987
|
+
if (fatherPattern.test(childBlock.raw)) {
|
|
6988
|
+
let updatedChildRaw = childBlock.raw.replace(fatherPattern, `$1{fileID: ${newParentTransformId}}`);
|
|
6989
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
6990
|
+
} else {
|
|
6991
|
+
const anchorPattern = /^([ \t]*(?:m_GameObject|m_CorrespondingSourceObject|m_PrefabInstance):[ \t]*\{fileID:[ \t]*(-?\d+)[^}]*\}.*)/m;
|
|
6992
|
+
const headerPattern = /(^--- !u!(?:4|224) &-?\d+ stripped\n(?:Rect)?Transform:)/m;
|
|
6993
|
+
if (anchorPattern.test(childBlock.raw)) {
|
|
6994
|
+
let updatedChildRaw = childBlock.raw.replace(anchorPattern, `$1
|
|
6995
|
+
m_Father: {fileID: ${newParentTransformId}}`);
|
|
6996
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
6997
|
+
} else if (headerPattern.test(childBlock.raw)) {
|
|
6998
|
+
let updatedChildRaw = childBlock.raw.replace(headerPattern, `$1
|
|
6999
|
+
m_Father: {fileID: ${newParentTransformId}}`);
|
|
7000
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
7001
|
+
} else {
|
|
7002
|
+
let updatedChildRaw = childBlock.raw.trimEnd() + `
|
|
7003
|
+
m_Father: {fileID: ${newParentTransformId}}
|
|
7004
|
+
`;
|
|
7005
|
+
childBlock.replace_raw(updatedChildRaw);
|
|
7006
|
+
}
|
|
7007
|
+
}
|
|
6620
7008
|
}
|
|
6621
|
-
const fatherPattern = new RegExp(`(m_Father:\\s*)\\{fileID:\\s*\\d+\\}`);
|
|
6622
|
-
let updatedChildRaw = childBlock.raw.replace(fatherPattern, `$1{fileID: ${newParentTransformId}}`);
|
|
6623
|
-
childBlock.replace_raw(updatedChildRaw);
|
|
6624
7009
|
{
|
|
6625
7010
|
let newRootOrder;
|
|
6626
7011
|
if (newParentTransformId === "0") {
|
|
@@ -6628,10 +7013,25 @@ function reparentGameObject(options) {
|
|
|
6628
7013
|
} else {
|
|
6629
7014
|
newRootOrder = doc.calculate_root_order(newParentTransformId);
|
|
6630
7015
|
}
|
|
6631
|
-
childBlock.
|
|
7016
|
+
if (childBlock.class_id === 1001 || childBlock.class_id === 310) {
|
|
7017
|
+
const stripped = doc.blocks.find((b) => (b.class_id === 4 || b.class_id === 224) && b.is_stripped && new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${childTransformId}\\}`).test(b.raw));
|
|
7018
|
+
if (stripped) {
|
|
7019
|
+
stripped.set_property("m_RootOrder", String(newRootOrder));
|
|
7020
|
+
} else {
|
|
7021
|
+
upsertPrefabRootOrderOverride(childBlock, newRootOrder);
|
|
7022
|
+
}
|
|
7023
|
+
} else {
|
|
7024
|
+
childBlock.set_property("m_RootOrder", String(newRootOrder));
|
|
7025
|
+
}
|
|
6632
7026
|
}
|
|
6633
7027
|
if (newParentTransformId !== "0") {
|
|
6634
|
-
|
|
7028
|
+
if (childHierarchyTransformId) {
|
|
7029
|
+
doc.add_child_to_parent(newParentTransformId, childHierarchyTransformId);
|
|
7030
|
+
}
|
|
7031
|
+
} else {
|
|
7032
|
+
if (childHierarchyTransformId) {
|
|
7033
|
+
doc.add_root_to_scene_roots(childHierarchyTransformId);
|
|
7034
|
+
}
|
|
6635
7035
|
}
|
|
6636
7036
|
if (!doc.validate()) {
|
|
6637
7037
|
return { success: false, file_path, error: "Validation failed after reparent" };
|
|
@@ -6650,9 +7050,9 @@ function reparentGameObject(options) {
|
|
|
6650
7050
|
}
|
|
6651
7051
|
function findPrefabInstanceBlock(doc, identifier) {
|
|
6652
7052
|
const asId = doc.find_by_file_id(identifier);
|
|
6653
|
-
if (asId && asId.class_id === 1001)
|
|
7053
|
+
if (asId && (asId.class_id === 1001 || asId.class_id === 310))
|
|
6654
7054
|
return asId;
|
|
6655
|
-
const piBlocks = doc.find_by_class_id(1001);
|
|
7055
|
+
const piBlocks = [...doc.find_by_class_id(1001), ...doc.find_by_class_id(310)];
|
|
6656
7056
|
const escaped = identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6657
7057
|
const namePattern = new RegExp(`propertyPath:\\s*m_Name\\s+value:\\s*${escaped}\\s`);
|
|
6658
7058
|
for (const block of piBlocks) {
|