unity-agentic-tools 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +945 -170
- package/dist/index.js +740 -117
- package/native/unity-file-tools.darwin-arm64.node +0 -0
- package/native/unity-file-tools.darwin-x64.node +0 -0
- package/native/unity-file-tools.linux-x64-gnu.node +0 -0
- package/native/unity-file-tools.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -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.2",
|
|
209
209
|
description: "Fast, token-efficient Unity YAML parser for AI agents",
|
|
210
210
|
exports: {
|
|
211
211
|
".": {
|
|
@@ -2336,6 +2336,24 @@ function resolveScriptGuid(script, projectPath) {
|
|
|
2336
2336
|
}
|
|
2337
2337
|
} catch {}
|
|
2338
2338
|
}
|
|
2339
|
+
try {
|
|
2340
|
+
const assetsDir = path3.join(projectPath, "Assets");
|
|
2341
|
+
if (import_fs8.existsSync(assetsDir)) {
|
|
2342
|
+
const entries = import_fs8.readdirSync(assetsDir, { recursive: true, withFileTypes: false });
|
|
2343
|
+
for (const entry of entries) {
|
|
2344
|
+
if (!entry.endsWith(".cs"))
|
|
2345
|
+
continue;
|
|
2346
|
+
const fileName = path3.basename(entry, ".cs").toLowerCase();
|
|
2347
|
+
if (fileName === scriptNameLower || classNameOnly && fileName === classNameOnly) {
|
|
2348
|
+
const fullPath = path3.join(assetsDir, entry);
|
|
2349
|
+
const guid = extractGuidFromMeta(fullPath + ".meta");
|
|
2350
|
+
if (guid) {
|
|
2351
|
+
return { guid, path: path3.join("Assets", entry) };
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
} catch {}
|
|
2339
2357
|
}
|
|
2340
2358
|
return null;
|
|
2341
2359
|
}
|
|
@@ -2490,8 +2508,8 @@ function build_type_lookup(project_path) {
|
|
|
2490
2508
|
const assetsDir = path3.join(project_path, "Assets");
|
|
2491
2509
|
const csIndex = new Map;
|
|
2492
2510
|
try {
|
|
2493
|
-
const { readdirSync:
|
|
2494
|
-
const entries =
|
|
2511
|
+
const { readdirSync: readdirSync5 } = require("fs");
|
|
2512
|
+
const entries = readdirSync5(assetsDir, { recursive: true, withFileTypes: false });
|
|
2495
2513
|
for (const entry of entries) {
|
|
2496
2514
|
if (typeof entry === "string" && entry.endsWith(".cs")) {
|
|
2497
2515
|
const basename4 = entry.substring(entry.lastIndexOf("/") + 1).replace(/\.cs$/, "");
|
|
@@ -4252,48 +4270,320 @@ function find_game_object_in_variant(doc, name, file_path, project_path) {
|
|
|
4252
4270
|
}
|
|
4253
4271
|
return null;
|
|
4254
4272
|
}
|
|
4255
|
-
function
|
|
4256
|
-
const
|
|
4257
|
-
if (!
|
|
4258
|
-
return;
|
|
4259
|
-
const
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4273
|
+
function parsePrefabRef(refText) {
|
|
4274
|
+
const fileIdMatch = refText.match(/fileID:[ \t]*(-?\d+)/i);
|
|
4275
|
+
if (!fileIdMatch)
|
|
4276
|
+
return null;
|
|
4277
|
+
const guidMatch = refText.match(/guid:[ \t]*([a-f0-9]{32})/i);
|
|
4278
|
+
const typeMatch = refText.match(/type:[ \t]*(-?\d+)/i);
|
|
4279
|
+
return {
|
|
4280
|
+
file_id: fileIdMatch[1],
|
|
4281
|
+
guid: guidMatch ? guidMatch[1].toLowerCase() : undefined,
|
|
4282
|
+
type: typeMatch ? typeMatch[1] : undefined
|
|
4283
|
+
};
|
|
4284
|
+
}
|
|
4285
|
+
function extractPrefabSourceGuid(prefabInstanceRaw) {
|
|
4286
|
+
const sourceMatch = prefabInstanceRaw.match(/m_SourcePrefab:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]{32})/i);
|
|
4287
|
+
return sourceMatch ? sourceMatch[1].toLowerCase() : null;
|
|
4288
|
+
}
|
|
4289
|
+
function normalizePrefabRef(refText, sourceGuid) {
|
|
4290
|
+
const parsed = parsePrefabRef(refText);
|
|
4291
|
+
if (!parsed) {
|
|
4292
|
+
return { error: `Invalid reference "${refText}". Expected format: {fileID: N, guid: ..., type: T}` };
|
|
4293
|
+
}
|
|
4294
|
+
const guid = parsed.guid ?? sourceGuid;
|
|
4295
|
+
if (!guid) {
|
|
4296
|
+
return { error: `Reference "${refText}" is missing guid and source prefab guid could not be inferred.` };
|
|
4269
4297
|
}
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
raw = raw.replace(existingPattern, `$1${entry}`);
|
|
4273
|
-
piBlock.replace_raw(raw);
|
|
4298
|
+
if (!/^[a-f0-9]{32}$/i.test(guid)) {
|
|
4299
|
+
return { error: `Invalid guid in reference "${refText}". Expected 32-character hex GUID.` };
|
|
4274
4300
|
}
|
|
4301
|
+
const type = parsed.type ?? "3";
|
|
4302
|
+
if (!/^-?\d+$/.test(type)) {
|
|
4303
|
+
return { error: `Invalid type in reference "${refText}". Expected an integer type value.` };
|
|
4304
|
+
}
|
|
4305
|
+
return {
|
|
4306
|
+
ref: {
|
|
4307
|
+
file_id: parsed.file_id,
|
|
4308
|
+
guid,
|
|
4309
|
+
type
|
|
4310
|
+
}
|
|
4311
|
+
};
|
|
4275
4312
|
}
|
|
4276
|
-
function
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
const
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
const emptyPattern = /m_AddedComponents:[ \t]*\[\]/;
|
|
4286
|
-
if (emptyPattern.test(raw)) {
|
|
4287
|
-
raw = raw.replace(emptyPattern, `m_AddedComponents:${entry}`);
|
|
4288
|
-
piBlock.replace_raw(raw);
|
|
4289
|
-
return;
|
|
4313
|
+
function serializePrefabRef(ref) {
|
|
4314
|
+
return `{fileID: ${ref.file_id}, guid: ${ref.guid}, type: ${ref.type}}`;
|
|
4315
|
+
}
|
|
4316
|
+
function ensurePrefabModificationSerializedVersion(prefabInstanceBlock) {
|
|
4317
|
+
const raw = prefabInstanceBlock.raw;
|
|
4318
|
+
const updated = raw.replace(/(^([ \t]*)m_Modification:[ \t]*\n)(?!\2[ \t]+serializedVersion:[ \t]*\d+)/m, (_match, prefix, indent) => `${prefix}${indent} serializedVersion: 3
|
|
4319
|
+
`);
|
|
4320
|
+
if (updated === raw) {
|
|
4321
|
+
return false;
|
|
4290
4322
|
}
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4323
|
+
prefabInstanceBlock.replace_raw(updated);
|
|
4324
|
+
return true;
|
|
4325
|
+
}
|
|
4326
|
+
function addedOverrideEntryKey(entry) {
|
|
4327
|
+
return `${entry.target.file_id}|${entry.target.guid}|${entry.target.type}|${entry.insert_index}|${entry.added_object_file_id}`;
|
|
4328
|
+
}
|
|
4329
|
+
function splitPrefabArraySection(rawText, key) {
|
|
4330
|
+
const lines = rawText.split(`
|
|
4331
|
+
`);
|
|
4332
|
+
const keyPattern = new RegExp(`^([ ]*)${key}:[ ]*(.*)$`);
|
|
4333
|
+
let keyIndex = -1;
|
|
4334
|
+
let indent = "";
|
|
4335
|
+
for (let i = 0;i < lines.length; i++) {
|
|
4336
|
+
const match = lines[i].match(keyPattern);
|
|
4337
|
+
if (match) {
|
|
4338
|
+
keyIndex = i;
|
|
4339
|
+
indent = match[1];
|
|
4340
|
+
break;
|
|
4341
|
+
}
|
|
4295
4342
|
}
|
|
4343
|
+
if (keyIndex === -1) {
|
|
4344
|
+
return null;
|
|
4345
|
+
}
|
|
4346
|
+
const keyIndentLen = indent.length;
|
|
4347
|
+
let sectionEnd = keyIndex + 1;
|
|
4348
|
+
for (let i = keyIndex + 1;i < lines.length; i++) {
|
|
4349
|
+
const line = lines[i];
|
|
4350
|
+
const trimmed = line.trim();
|
|
4351
|
+
if (trimmed.length === 0) {
|
|
4352
|
+
sectionEnd = i + 1;
|
|
4353
|
+
continue;
|
|
4354
|
+
}
|
|
4355
|
+
const indentLen = (line.match(/^[ \t]*/) || [""])[0].length;
|
|
4356
|
+
if (indentLen < keyIndentLen) {
|
|
4357
|
+
break;
|
|
4358
|
+
}
|
|
4359
|
+
if (indentLen === keyIndentLen && !trimmed.startsWith("-") && /^[A-Za-z_][A-Za-z0-9_]*:/.test(trimmed)) {
|
|
4360
|
+
break;
|
|
4361
|
+
}
|
|
4362
|
+
sectionEnd = i + 1;
|
|
4363
|
+
}
|
|
4364
|
+
return {
|
|
4365
|
+
lines,
|
|
4366
|
+
key_index: keyIndex,
|
|
4367
|
+
section_end: sectionEnd,
|
|
4368
|
+
indent
|
|
4369
|
+
};
|
|
4296
4370
|
}
|
|
4371
|
+
function collectAddedOverrideEntries(lines, key_index, section_end, sourceGuid) {
|
|
4372
|
+
const sectionLines = lines.slice(key_index + 1, section_end);
|
|
4373
|
+
const dedup = new Map;
|
|
4374
|
+
let i = 0;
|
|
4375
|
+
while (i < sectionLines.length) {
|
|
4376
|
+
const line = sectionLines[i];
|
|
4377
|
+
const trimmed = line.trimStart();
|
|
4378
|
+
if (!trimmed.startsWith("-")) {
|
|
4379
|
+
i++;
|
|
4380
|
+
continue;
|
|
4381
|
+
}
|
|
4382
|
+
const entryIndent = (line.match(/^[ \t]*/) || [""])[0].length;
|
|
4383
|
+
const entryLines = [line];
|
|
4384
|
+
i++;
|
|
4385
|
+
while (i < sectionLines.length) {
|
|
4386
|
+
const nextLine = sectionLines[i];
|
|
4387
|
+
const nextTrimmed = nextLine.trim();
|
|
4388
|
+
const nextIndent = (nextLine.match(/^[ \t]*/) || [""])[0].length;
|
|
4389
|
+
if (nextTrimmed.length > 0 && nextIndent === entryIndent && nextTrimmed.startsWith("-")) {
|
|
4390
|
+
break;
|
|
4391
|
+
}
|
|
4392
|
+
entryLines.push(nextLine);
|
|
4393
|
+
i++;
|
|
4394
|
+
}
|
|
4395
|
+
const entryText = entryLines.join(`
|
|
4396
|
+
`);
|
|
4397
|
+
const targetMatch = entryText.match(/targetCorrespondingSourceObject:[ \t]*(\{[^}]+\})/);
|
|
4398
|
+
const insertMatch = entryText.match(/insertIndex:[ \t]*(-?\d+)/);
|
|
4399
|
+
const addedObjectMatch = entryText.match(/addedObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)/);
|
|
4400
|
+
if (!targetMatch || !addedObjectMatch) {
|
|
4401
|
+
continue;
|
|
4402
|
+
}
|
|
4403
|
+
const normalizedTarget = normalizePrefabRef(targetMatch[1], sourceGuid).ref;
|
|
4404
|
+
if (!normalizedTarget) {
|
|
4405
|
+
continue;
|
|
4406
|
+
}
|
|
4407
|
+
const insertIndex = insertMatch ? Number.parseInt(insertMatch[1], 10) : -1;
|
|
4408
|
+
const entry = {
|
|
4409
|
+
target: normalizedTarget,
|
|
4410
|
+
insert_index: Number.isNaN(insertIndex) ? -1 : insertIndex,
|
|
4411
|
+
added_object_file_id: addedObjectMatch[1]
|
|
4412
|
+
};
|
|
4413
|
+
const dedupKey = addedOverrideEntryKey(entry);
|
|
4414
|
+
if (!dedup.has(dedupKey)) {
|
|
4415
|
+
dedup.set(dedupKey, entry);
|
|
4416
|
+
}
|
|
4417
|
+
}
|
|
4418
|
+
return [...dedup.values()];
|
|
4419
|
+
}
|
|
4420
|
+
function appendToAddedOverrideArray(doc, piId, key, targetSourceRef, newObjectId) {
|
|
4421
|
+
const piBlock = doc.find_by_file_id(piId);
|
|
4422
|
+
if (!piBlock) {
|
|
4423
|
+
return { success: false, error: `PrefabInstance with fileID ${piId} not found` };
|
|
4424
|
+
}
|
|
4425
|
+
ensurePrefabModificationSerializedVersion(piBlock);
|
|
4426
|
+
const split = splitPrefabArraySection(piBlock.raw, key);
|
|
4427
|
+
if (!split) {
|
|
4428
|
+
return { success: false, error: `${key} property not found in PrefabInstance ${piId}` };
|
|
4429
|
+
}
|
|
4430
|
+
const sourceGuid = extractPrefabSourceGuid(piBlock.raw);
|
|
4431
|
+
const normalizedTarget = normalizePrefabRef(targetSourceRef, sourceGuid);
|
|
4432
|
+
if (!normalizedTarget.ref) {
|
|
4433
|
+
return { success: false, error: normalizedTarget.error };
|
|
4434
|
+
}
|
|
4435
|
+
const candidate = {
|
|
4436
|
+
target: normalizedTarget.ref,
|
|
4437
|
+
insert_index: -1,
|
|
4438
|
+
added_object_file_id: newObjectId
|
|
4439
|
+
};
|
|
4440
|
+
const candidateKey = addedOverrideEntryKey(candidate);
|
|
4441
|
+
const existing = collectAddedOverrideEntries(split.lines, split.key_index, split.section_end, sourceGuid);
|
|
4442
|
+
if (existing.some((entry) => addedOverrideEntryKey(entry) === candidateKey)) {
|
|
4443
|
+
return { success: true, changed: false };
|
|
4444
|
+
}
|
|
4445
|
+
const entryLines = [
|
|
4446
|
+
`${split.indent}- targetCorrespondingSourceObject: ${serializePrefabRef(candidate.target)}`,
|
|
4447
|
+
`${split.indent} insertIndex: ${candidate.insert_index}`,
|
|
4448
|
+
`${split.indent} addedObject: {fileID: ${candidate.added_object_file_id}}`
|
|
4449
|
+
];
|
|
4450
|
+
const keyLine = split.lines[split.key_index].trim();
|
|
4451
|
+
let insertIndex = split.section_end;
|
|
4452
|
+
while (insertIndex > split.key_index + 1 && split.lines[insertIndex - 1].trim().length === 0) {
|
|
4453
|
+
insertIndex--;
|
|
4454
|
+
}
|
|
4455
|
+
let updatedLines;
|
|
4456
|
+
if (keyLine === `${key}: []`) {
|
|
4457
|
+
const replacement = [`${split.indent}${key}:`, ...entryLines];
|
|
4458
|
+
updatedLines = [
|
|
4459
|
+
...split.lines.slice(0, split.key_index),
|
|
4460
|
+
...replacement,
|
|
4461
|
+
...split.lines.slice(split.section_end)
|
|
4462
|
+
];
|
|
4463
|
+
} else {
|
|
4464
|
+
updatedLines = [
|
|
4465
|
+
...split.lines.slice(0, insertIndex),
|
|
4466
|
+
...entryLines,
|
|
4467
|
+
...split.lines.slice(insertIndex)
|
|
4468
|
+
];
|
|
4469
|
+
}
|
|
4470
|
+
piBlock.replace_raw(updatedLines.join(`
|
|
4471
|
+
`));
|
|
4472
|
+
return { success: true, changed: true };
|
|
4473
|
+
}
|
|
4474
|
+
function appendToAddedGameObjects(doc, piId, targetSourceRef, newGoId) {
|
|
4475
|
+
return appendToAddedOverrideArray(doc, piId, "m_AddedGameObjects", targetSourceRef, newGoId);
|
|
4476
|
+
}
|
|
4477
|
+
function appendToAddedComponents(doc, piId, targetSourceRef, newComponentId) {
|
|
4478
|
+
return appendToAddedOverrideArray(doc, piId, "m_AddedComponents", targetSourceRef, newComponentId);
|
|
4479
|
+
}
|
|
4480
|
+
var COMPONENT_FULL_TEMPLATES = {
|
|
4481
|
+
65: (gameObjectId) => ` m_GameObject: {fileID: ${gameObjectId}}
|
|
4482
|
+
m_Material: {fileID: 0}
|
|
4483
|
+
m_IncludeLayers:
|
|
4484
|
+
serializedVersion: 2
|
|
4485
|
+
m_Bits: 0
|
|
4486
|
+
m_ExcludeLayers:
|
|
4487
|
+
serializedVersion: 2
|
|
4488
|
+
m_Bits: 0
|
|
4489
|
+
m_LayerOverridePriority: 0
|
|
4490
|
+
m_IsTrigger: 0
|
|
4491
|
+
m_ProvidesContacts: 0
|
|
4492
|
+
m_Enabled: 1
|
|
4493
|
+
serializedVersion: 3
|
|
4494
|
+
m_Size: {x: 1, y: 1, z: 1}
|
|
4495
|
+
m_Center: {x: 0, y: 0, z: 0}`,
|
|
4496
|
+
82: (gameObjectId) => ` m_GameObject: {fileID: ${gameObjectId}}
|
|
4497
|
+
m_Enabled: 1
|
|
4498
|
+
serializedVersion: 4
|
|
4499
|
+
OutputAudioMixerGroup: {fileID: 0}
|
|
4500
|
+
m_audioClip: {fileID: 0}
|
|
4501
|
+
m_PlayOnAwake: 1
|
|
4502
|
+
m_Volume: 1
|
|
4503
|
+
m_Pitch: 1
|
|
4504
|
+
Loop: 0
|
|
4505
|
+
Mute: 0
|
|
4506
|
+
Spatialize: 0
|
|
4507
|
+
SpatializePostEffects: 0
|
|
4508
|
+
Priority: 128
|
|
4509
|
+
DopplerLevel: 1
|
|
4510
|
+
MinDistance: 1
|
|
4511
|
+
MaxDistance: 500
|
|
4512
|
+
Pan2D: 0
|
|
4513
|
+
rolloffMode: 0
|
|
4514
|
+
BypassEffects: 0
|
|
4515
|
+
BypassListenerEffects: 0
|
|
4516
|
+
BypassReverbZones: 0
|
|
4517
|
+
rolloffCustomCurve:
|
|
4518
|
+
serializedVersion: 2
|
|
4519
|
+
m_Curve:
|
|
4520
|
+
- serializedVersion: 3
|
|
4521
|
+
time: 0
|
|
4522
|
+
value: 1
|
|
4523
|
+
inSlope: 0
|
|
4524
|
+
outSlope: 0
|
|
4525
|
+
tangentMode: 0
|
|
4526
|
+
weightedMode: 0
|
|
4527
|
+
inWeight: 0.33333334
|
|
4528
|
+
outWeight: 0.33333334
|
|
4529
|
+
- serializedVersion: 3
|
|
4530
|
+
time: 1
|
|
4531
|
+
value: 0
|
|
4532
|
+
inSlope: 0
|
|
4533
|
+
outSlope: 0
|
|
4534
|
+
tangentMode: 0
|
|
4535
|
+
weightedMode: 0
|
|
4536
|
+
inWeight: 0.33333334
|
|
4537
|
+
outWeight: 0.33333334
|
|
4538
|
+
m_PreInfinity: 2
|
|
4539
|
+
m_PostInfinity: 2
|
|
4540
|
+
m_RotationOrder: 4
|
|
4541
|
+
panLevelCustomCurve:
|
|
4542
|
+
serializedVersion: 2
|
|
4543
|
+
m_Curve:
|
|
4544
|
+
- serializedVersion: 3
|
|
4545
|
+
time: 0
|
|
4546
|
+
value: 0
|
|
4547
|
+
inSlope: 0
|
|
4548
|
+
outSlope: 0
|
|
4549
|
+
tangentMode: 0
|
|
4550
|
+
weightedMode: 0
|
|
4551
|
+
inWeight: 0.33333334
|
|
4552
|
+
outWeight: 0.33333334
|
|
4553
|
+
m_PreInfinity: 2
|
|
4554
|
+
m_PostInfinity: 2
|
|
4555
|
+
m_RotationOrder: 4
|
|
4556
|
+
spreadCustomCurve:
|
|
4557
|
+
serializedVersion: 2
|
|
4558
|
+
m_Curve:
|
|
4559
|
+
- serializedVersion: 3
|
|
4560
|
+
time: 0
|
|
4561
|
+
value: 0
|
|
4562
|
+
inSlope: 0
|
|
4563
|
+
outSlope: 0
|
|
4564
|
+
tangentMode: 0
|
|
4565
|
+
weightedMode: 0
|
|
4566
|
+
inWeight: 0.33333334
|
|
4567
|
+
outWeight: 0.33333334
|
|
4568
|
+
m_PreInfinity: 2
|
|
4569
|
+
m_PostInfinity: 2
|
|
4570
|
+
m_RotationOrder: 4
|
|
4571
|
+
reverbZoneMixCustomCurve:
|
|
4572
|
+
serializedVersion: 2
|
|
4573
|
+
m_Curve:
|
|
4574
|
+
- serializedVersion: 3
|
|
4575
|
+
time: 0
|
|
4576
|
+
value: 1
|
|
4577
|
+
inSlope: 0
|
|
4578
|
+
outSlope: 0
|
|
4579
|
+
tangentMode: 0
|
|
4580
|
+
weightedMode: 0
|
|
4581
|
+
inWeight: 0.33333334
|
|
4582
|
+
outWeight: 0.33333334
|
|
4583
|
+
m_PreInfinity: 2
|
|
4584
|
+
m_PostInfinity: 2
|
|
4585
|
+
m_RotationOrder: 4`
|
|
4586
|
+
};
|
|
4297
4587
|
var COMPONENT_DEFAULTS = {
|
|
4298
4588
|
20: ` serializedVersion: 2
|
|
4299
4589
|
m_ClearFlags: 1
|
|
@@ -4420,6 +4710,17 @@ var COMPONENT_DEFAULTS = {
|
|
|
4420
4710
|
m_IgnoreParentGroups: 0`
|
|
4421
4711
|
};
|
|
4422
4712
|
function createGenericComponentYAML(componentName, classId, componentId, gameObjectId) {
|
|
4713
|
+
const fullTemplate = COMPONENT_FULL_TEMPLATES[classId];
|
|
4714
|
+
if (fullTemplate) {
|
|
4715
|
+
return `--- !u!${classId} &${componentId}
|
|
4716
|
+
${componentName}:
|
|
4717
|
+
m_ObjectHideFlags: 0
|
|
4718
|
+
m_CorrespondingSourceObject: {fileID: 0}
|
|
4719
|
+
m_PrefabInstance: {fileID: 0}
|
|
4720
|
+
m_PrefabAsset: {fileID: 0}
|
|
4721
|
+
${fullTemplate(gameObjectId)}
|
|
4722
|
+
`;
|
|
4723
|
+
}
|
|
4423
4724
|
const defaults = COMPONENT_DEFAULTS[classId] ? `
|
|
4424
4725
|
` + COMPONENT_DEFAULTS[classId] + `
|
|
4425
4726
|
` : "";
|
|
@@ -4572,7 +4873,14 @@ function createGameObject(options) {
|
|
|
4572
4873
|
doc.add_child_to_parent(parentTransformIdStr, transformIdStr);
|
|
4573
4874
|
}
|
|
4574
4875
|
if (variantPiId && strippedSourceRef) {
|
|
4575
|
-
appendToAddedGameObjects(doc, variantPiId, strippedSourceRef, gameObjectIdStr);
|
|
4876
|
+
const appendResult = appendToAddedGameObjects(doc, variantPiId, strippedSourceRef, gameObjectIdStr);
|
|
4877
|
+
if (!appendResult.success) {
|
|
4878
|
+
return {
|
|
4879
|
+
success: false,
|
|
4880
|
+
file_path,
|
|
4881
|
+
error: appendResult.error || `Failed to update m_AddedGameObjects for PrefabInstance ${variantPiId}`
|
|
4882
|
+
};
|
|
4883
|
+
}
|
|
4576
4884
|
}
|
|
4577
4885
|
const saveResult = doc.save();
|
|
4578
4886
|
if (!saveResult.success) {
|
|
@@ -5055,6 +5363,7 @@ PrefabInstance:
|
|
|
5055
5363
|
m_ObjectHideFlags: 0
|
|
5056
5364
|
serializedVersion: 2
|
|
5057
5365
|
m_Modification:
|
|
5366
|
+
serializedVersion: 3
|
|
5058
5367
|
m_TransformParent: {fileID: 0}
|
|
5059
5368
|
m_Modifications:
|
|
5060
5369
|
- target: {fileID: ${rootInfo.game_object.file_id}, guid: ${sourceGuid}, type: 3}
|
|
@@ -5341,6 +5650,8 @@ function is_valid_component_base(base_class, project_path, depth = 0) {
|
|
|
5341
5650
|
}
|
|
5342
5651
|
if (!fullPath.endsWith(".cs") || !import_fs10.existsSync(fullPath)) {
|
|
5343
5652
|
if (match.kind === "class") {
|
|
5653
|
+
if (fullPath.includes("Assembly-CSharp.dll"))
|
|
5654
|
+
return true;
|
|
5344
5655
|
return is_likely_component_base_name(base_class);
|
|
5345
5656
|
}
|
|
5346
5657
|
}
|
|
@@ -5485,11 +5796,11 @@ function addComponent(options) {
|
|
|
5485
5796
|
};
|
|
5486
5797
|
}
|
|
5487
5798
|
if (resolved.base_class && !COMPONENT_BASE_CLASSES.has(resolved.base_class) && !is_valid_component_base(resolved.base_class, project_path)) {
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5799
|
+
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
|
+
if (!extractionError)
|
|
5801
|
+
extractionError = warn;
|
|
5802
|
+
else
|
|
5803
|
+
extractionError += " " + warn;
|
|
5493
5804
|
}
|
|
5494
5805
|
let version;
|
|
5495
5806
|
if (project_path) {
|
|
@@ -5505,10 +5816,22 @@ function addComponent(options) {
|
|
|
5505
5816
|
componentYAML = createMonoBehaviourYAML(componentId, gameObjectId, resolved.guid, resolved.fields, version, scriptFileId, type_lookup_comp);
|
|
5506
5817
|
scriptGuid = resolved.guid;
|
|
5507
5818
|
scriptPath = resolved.path || undefined;
|
|
5508
|
-
|
|
5819
|
+
if (resolved.extraction_error) {
|
|
5820
|
+
if (!extractionError)
|
|
5821
|
+
extractionError = resolved.extraction_error;
|
|
5822
|
+
else
|
|
5823
|
+
extractionError += " " + resolved.extraction_error;
|
|
5824
|
+
}
|
|
5509
5825
|
}
|
|
5510
5826
|
if (variantInfo) {
|
|
5511
|
-
appendToAddedComponents(doc, variantInfo.prefab_instance_id, variantInfo.source_ref, componentIdStr);
|
|
5827
|
+
const appendResult = appendToAddedComponents(doc, variantInfo.prefab_instance_id, variantInfo.source_ref, componentIdStr);
|
|
5828
|
+
if (!appendResult.success) {
|
|
5829
|
+
return {
|
|
5830
|
+
success: false,
|
|
5831
|
+
file_path,
|
|
5832
|
+
error: appendResult.error || `Failed to update m_AddedComponents for PrefabInstance ${variantInfo.prefab_instance_id}`
|
|
5833
|
+
};
|
|
5834
|
+
}
|
|
5512
5835
|
} else {
|
|
5513
5836
|
const added = addComponentToGameObject(doc, gameObjectIdStr, componentIdStr);
|
|
5514
5837
|
if (!added) {
|
|
@@ -5873,7 +6196,7 @@ function editComponentByFileId(options) {
|
|
|
5873
6196
|
return {
|
|
5874
6197
|
success: false,
|
|
5875
6198
|
file_path,
|
|
5876
|
-
error: `Could not resolve "${new_value}" to asset reference. Ensure GUID cache exists (run "setup <
|
|
6199
|
+
error: `Could not resolve "${new_value}" to asset reference. Ensure GUID cache exists (run "setup" first, or "setup -p <path>").`
|
|
5877
6200
|
};
|
|
5878
6201
|
}
|
|
5879
6202
|
if (resolved !== undefined) {
|
|
@@ -6338,6 +6661,193 @@ function findPrefabInstanceBlock(doc, identifier) {
|
|
|
6338
6661
|
}
|
|
6339
6662
|
return null;
|
|
6340
6663
|
}
|
|
6664
|
+
function parsePrefabRef2(refText) {
|
|
6665
|
+
const fileIdMatch = refText.match(/fileID:[ \t]*(-?\d+)/i);
|
|
6666
|
+
if (!fileIdMatch)
|
|
6667
|
+
return null;
|
|
6668
|
+
const guidMatch = refText.match(/guid:[ \t]*([a-f0-9]{32})/i);
|
|
6669
|
+
const typeMatch = refText.match(/type:[ \t]*(-?\d+)/i);
|
|
6670
|
+
return {
|
|
6671
|
+
file_id: fileIdMatch[1],
|
|
6672
|
+
guid: guidMatch ? guidMatch[1].toLowerCase() : undefined,
|
|
6673
|
+
type: typeMatch ? typeMatch[1] : undefined
|
|
6674
|
+
};
|
|
6675
|
+
}
|
|
6676
|
+
function extractPrefabSourceGuid2(prefabInstanceRaw) {
|
|
6677
|
+
const sourceMatch = prefabInstanceRaw.match(/m_SourcePrefab:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]{32})/i);
|
|
6678
|
+
return sourceMatch ? sourceMatch[1].toLowerCase() : null;
|
|
6679
|
+
}
|
|
6680
|
+
function normalizePrefabRef2(refText, sourceGuid) {
|
|
6681
|
+
const parsed = parsePrefabRef2(refText);
|
|
6682
|
+
if (!parsed) {
|
|
6683
|
+
return { error: `Invalid reference "${refText}". Expected format: {fileID: N, guid: ..., type: T}` };
|
|
6684
|
+
}
|
|
6685
|
+
const guid = parsed.guid ?? sourceGuid;
|
|
6686
|
+
if (!guid) {
|
|
6687
|
+
return { error: `Reference "${refText}" is missing guid and source prefab guid could not be inferred.` };
|
|
6688
|
+
}
|
|
6689
|
+
if (!/^[a-f0-9]{32}$/i.test(guid)) {
|
|
6690
|
+
return { error: `Invalid guid in reference "${refText}". Expected 32-character hex GUID.` };
|
|
6691
|
+
}
|
|
6692
|
+
const type = parsed.type ?? "3";
|
|
6693
|
+
if (!/^-?\d+$/.test(type)) {
|
|
6694
|
+
return { error: `Invalid type in reference "${refText}". Expected an integer type value.` };
|
|
6695
|
+
}
|
|
6696
|
+
return {
|
|
6697
|
+
ref: {
|
|
6698
|
+
file_id: parsed.file_id,
|
|
6699
|
+
guid,
|
|
6700
|
+
type
|
|
6701
|
+
}
|
|
6702
|
+
};
|
|
6703
|
+
}
|
|
6704
|
+
function parsePrefabRefMatcher(refText) {
|
|
6705
|
+
const parsed = parsePrefabRef2(refText);
|
|
6706
|
+
if (!parsed) {
|
|
6707
|
+
return { error: `Invalid reference "${refText}". Expected format: {fileID: N, guid: ..., type: T}` };
|
|
6708
|
+
}
|
|
6709
|
+
if (parsed.guid && !/^[a-f0-9]{32}$/i.test(parsed.guid)) {
|
|
6710
|
+
return { error: `Invalid guid in reference "${refText}". Expected 32-character hex GUID.` };
|
|
6711
|
+
}
|
|
6712
|
+
if (parsed.type && !/^-?\d+$/.test(parsed.type)) {
|
|
6713
|
+
return { error: `Invalid type in reference "${refText}". Expected an integer type value.` };
|
|
6714
|
+
}
|
|
6715
|
+
return { matcher: parsed };
|
|
6716
|
+
}
|
|
6717
|
+
function prefabRefKey(ref) {
|
|
6718
|
+
return `${ref.file_id}|${ref.guid}|${ref.type}`;
|
|
6719
|
+
}
|
|
6720
|
+
function serializePrefabRef2(ref) {
|
|
6721
|
+
return `{fileID: ${ref.file_id}, guid: ${ref.guid}, type: ${ref.type}}`;
|
|
6722
|
+
}
|
|
6723
|
+
function splitPrefabArraySection2(rawText, key) {
|
|
6724
|
+
const lines = rawText.split(`
|
|
6725
|
+
`);
|
|
6726
|
+
const keyPattern = new RegExp(`^([ ]*)${key}:[ ]*(.*)$`);
|
|
6727
|
+
let keyIndex = -1;
|
|
6728
|
+
let indent = "";
|
|
6729
|
+
for (let i = 0;i < lines.length; i++) {
|
|
6730
|
+
const match = lines[i].match(keyPattern);
|
|
6731
|
+
if (match) {
|
|
6732
|
+
keyIndex = i;
|
|
6733
|
+
indent = match[1];
|
|
6734
|
+
break;
|
|
6735
|
+
}
|
|
6736
|
+
}
|
|
6737
|
+
if (keyIndex === -1) {
|
|
6738
|
+
return null;
|
|
6739
|
+
}
|
|
6740
|
+
const keyIndentLen = indent.length;
|
|
6741
|
+
let sectionEnd = keyIndex + 1;
|
|
6742
|
+
for (let i = keyIndex + 1;i < lines.length; i++) {
|
|
6743
|
+
const line = lines[i];
|
|
6744
|
+
const trimmed = line.trim();
|
|
6745
|
+
if (trimmed.length === 0) {
|
|
6746
|
+
sectionEnd = i + 1;
|
|
6747
|
+
continue;
|
|
6748
|
+
}
|
|
6749
|
+
const indentLen = (line.match(/^[ \t]*/) || [""])[0].length;
|
|
6750
|
+
if (indentLen < keyIndentLen) {
|
|
6751
|
+
break;
|
|
6752
|
+
}
|
|
6753
|
+
if (indentLen === keyIndentLen && !trimmed.startsWith("-") && /^[A-Za-z_][A-Za-z0-9_]*:/.test(trimmed)) {
|
|
6754
|
+
break;
|
|
6755
|
+
}
|
|
6756
|
+
sectionEnd = i + 1;
|
|
6757
|
+
}
|
|
6758
|
+
return {
|
|
6759
|
+
lines,
|
|
6760
|
+
key_index: keyIndex,
|
|
6761
|
+
section_end: sectionEnd,
|
|
6762
|
+
indent
|
|
6763
|
+
};
|
|
6764
|
+
}
|
|
6765
|
+
function collectNormalizedRefsFromSection(lines, key_index, section_end, sourceGuid) {
|
|
6766
|
+
const sectionText = lines.slice(key_index, section_end).join(`
|
|
6767
|
+
`);
|
|
6768
|
+
const refMatches = sectionText.match(/\{[^}]*\}/g) || [];
|
|
6769
|
+
const dedup = new Map;
|
|
6770
|
+
for (const token of refMatches) {
|
|
6771
|
+
const parsed = parsePrefabRef2(token);
|
|
6772
|
+
if (!parsed)
|
|
6773
|
+
continue;
|
|
6774
|
+
const guid = parsed.guid ?? sourceGuid;
|
|
6775
|
+
if (!guid || !/^[a-f0-9]{32}$/i.test(guid))
|
|
6776
|
+
continue;
|
|
6777
|
+
const type = parsed.type ?? "3";
|
|
6778
|
+
if (!/^-?\d+$/.test(type))
|
|
6779
|
+
continue;
|
|
6780
|
+
const normalized = {
|
|
6781
|
+
file_id: parsed.file_id,
|
|
6782
|
+
guid: guid.toLowerCase(),
|
|
6783
|
+
type
|
|
6784
|
+
};
|
|
6785
|
+
const key = prefabRefKey(normalized);
|
|
6786
|
+
if (!dedup.has(key)) {
|
|
6787
|
+
dedup.set(key, normalized);
|
|
6788
|
+
}
|
|
6789
|
+
}
|
|
6790
|
+
return [...dedup.values()];
|
|
6791
|
+
}
|
|
6792
|
+
function mutatePrefabReferenceList(options) {
|
|
6793
|
+
const { target_block, key, ref_text, action, item_label } = options;
|
|
6794
|
+
const split = splitPrefabArraySection2(target_block.raw, key);
|
|
6795
|
+
if (!split) {
|
|
6796
|
+
return { success: false, error: `${key} property not found in PrefabInstance` };
|
|
6797
|
+
}
|
|
6798
|
+
const sourceGuid = extractPrefabSourceGuid2(target_block.raw);
|
|
6799
|
+
const existing = collectNormalizedRefsFromSection(split.lines, split.key_index, split.section_end, sourceGuid);
|
|
6800
|
+
let next = existing;
|
|
6801
|
+
if (action === "add") {
|
|
6802
|
+
const normalized = normalizePrefabRef2(ref_text, sourceGuid);
|
|
6803
|
+
if (!normalized.ref) {
|
|
6804
|
+
return { success: false, error: normalized.error };
|
|
6805
|
+
}
|
|
6806
|
+
const keyText = prefabRefKey(normalized.ref);
|
|
6807
|
+
if (existing.some((entry) => prefabRefKey(entry) === keyText)) {
|
|
6808
|
+
return { success: true, changed: false };
|
|
6809
|
+
}
|
|
6810
|
+
next = [...existing, normalized.ref];
|
|
6811
|
+
} else {
|
|
6812
|
+
const matcherResult = parsePrefabRefMatcher(ref_text);
|
|
6813
|
+
const matcher = matcherResult.matcher;
|
|
6814
|
+
if (!matcher) {
|
|
6815
|
+
return { success: false, error: matcherResult.error };
|
|
6816
|
+
}
|
|
6817
|
+
next = existing.filter((entry) => {
|
|
6818
|
+
if (entry.file_id !== matcher.file_id)
|
|
6819
|
+
return true;
|
|
6820
|
+
if (matcher.guid && entry.guid !== matcher.guid.toLowerCase())
|
|
6821
|
+
return true;
|
|
6822
|
+
if (matcher.type && entry.type !== matcher.type)
|
|
6823
|
+
return true;
|
|
6824
|
+
return false;
|
|
6825
|
+
});
|
|
6826
|
+
if (next.length === existing.length) {
|
|
6827
|
+
return {
|
|
6828
|
+
success: false,
|
|
6829
|
+
error: `${item_label} reference "${ref_text}" not found in ${key}`
|
|
6830
|
+
};
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6833
|
+
const replacement = [];
|
|
6834
|
+
if (next.length === 0) {
|
|
6835
|
+
replacement.push(`${split.indent}${key}: []`);
|
|
6836
|
+
} else {
|
|
6837
|
+
replacement.push(`${split.indent}${key}:`);
|
|
6838
|
+
for (const entry of next) {
|
|
6839
|
+
replacement.push(`${split.indent}- ${serializePrefabRef2(entry)}`);
|
|
6840
|
+
}
|
|
6841
|
+
}
|
|
6842
|
+
const updatedLines = [
|
|
6843
|
+
...split.lines.slice(0, split.key_index),
|
|
6844
|
+
...replacement,
|
|
6845
|
+
...split.lines.slice(split.section_end)
|
|
6846
|
+
];
|
|
6847
|
+
target_block.replace_raw(updatedLines.join(`
|
|
6848
|
+
`));
|
|
6849
|
+
return { success: true, changed: true };
|
|
6850
|
+
}
|
|
6341
6851
|
function editArray(options) {
|
|
6342
6852
|
const { file_path, file_id, array_property, action, value, index } = options;
|
|
6343
6853
|
if (!import_fs11.existsSync(file_path)) {
|
|
@@ -6548,9 +7058,6 @@ function addRemovedComponent(options) {
|
|
|
6548
7058
|
if (!import_fs11.existsSync(file_path)) {
|
|
6549
7059
|
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
6550
7060
|
}
|
|
6551
|
-
if (!/^\{fileID:\s*-?\d+/.test(component_ref)) {
|
|
6552
|
-
return { success: false, file_path, error: `Invalid component reference "${component_ref}". Expected format: {fileID: N, guid: ..., type: T}` };
|
|
6553
|
-
}
|
|
6554
7061
|
let doc;
|
|
6555
7062
|
try {
|
|
6556
7063
|
doc = UnityDocument.from_file(file_path);
|
|
@@ -6561,19 +7068,16 @@ function addRemovedComponent(options) {
|
|
|
6561
7068
|
if (!targetBlock) {
|
|
6562
7069
|
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
6563
7070
|
}
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
} else {
|
|
6574
|
-
return { success: false, file_path, error: "m_RemovedComponents property not found in PrefabInstance" };
|
|
7071
|
+
const mutation = mutatePrefabReferenceList({
|
|
7072
|
+
target_block: targetBlock,
|
|
7073
|
+
key: "m_RemovedComponents",
|
|
7074
|
+
ref_text: component_ref,
|
|
7075
|
+
action: "add",
|
|
7076
|
+
item_label: "Component"
|
|
7077
|
+
});
|
|
7078
|
+
if (!mutation.success) {
|
|
7079
|
+
return { success: false, file_path, error: mutation.error };
|
|
6575
7080
|
}
|
|
6576
|
-
targetBlock.replace_raw(rawText);
|
|
6577
7081
|
if (!doc.validate()) {
|
|
6578
7082
|
return { success: false, file_path, error: "Validation failed after adding removed component" };
|
|
6579
7083
|
}
|
|
@@ -6602,13 +7106,16 @@ function removeRemovedComponent(options) {
|
|
|
6602
7106
|
if (!targetBlock) {
|
|
6603
7107
|
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
6604
7108
|
}
|
|
6605
|
-
const
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
7109
|
+
const mutation = mutatePrefabReferenceList({
|
|
7110
|
+
target_block: targetBlock,
|
|
7111
|
+
key: "m_RemovedComponents",
|
|
7112
|
+
ref_text: component_ref,
|
|
7113
|
+
action: "remove",
|
|
7114
|
+
item_label: "Component"
|
|
7115
|
+
});
|
|
7116
|
+
if (!mutation.success) {
|
|
7117
|
+
return { success: false, file_path, error: mutation.error };
|
|
6609
7118
|
}
|
|
6610
|
-
const updatedRaw = targetBlock.raw.replace(refPattern, "");
|
|
6611
|
-
targetBlock.replace_raw(updatedRaw);
|
|
6612
7119
|
if (!doc.validate()) {
|
|
6613
7120
|
return { success: false, file_path, error: "Validation failed after removing component" };
|
|
6614
7121
|
}
|
|
@@ -6627,9 +7134,6 @@ function addRemovedGameObject(options) {
|
|
|
6627
7134
|
if (!import_fs11.existsSync(file_path)) {
|
|
6628
7135
|
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
6629
7136
|
}
|
|
6630
|
-
if (!/^\{fileID:\s*-?\d+/.test(component_ref)) {
|
|
6631
|
-
return { success: false, file_path, error: `Invalid GameObject reference "${component_ref}". Expected format: {fileID: N, guid: ..., type: T}` };
|
|
6632
|
-
}
|
|
6633
7137
|
let doc;
|
|
6634
7138
|
try {
|
|
6635
7139
|
doc = UnityDocument.from_file(file_path);
|
|
@@ -6640,19 +7144,16 @@ function addRemovedGameObject(options) {
|
|
|
6640
7144
|
if (!targetBlock) {
|
|
6641
7145
|
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
6642
7146
|
}
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
} else {
|
|
6653
|
-
return { success: false, file_path, error: "m_RemovedGameObjects property not found in PrefabInstance" };
|
|
7147
|
+
const mutation = mutatePrefabReferenceList({
|
|
7148
|
+
target_block: targetBlock,
|
|
7149
|
+
key: "m_RemovedGameObjects",
|
|
7150
|
+
ref_text: component_ref,
|
|
7151
|
+
action: "add",
|
|
7152
|
+
item_label: "GameObject"
|
|
7153
|
+
});
|
|
7154
|
+
if (!mutation.success) {
|
|
7155
|
+
return { success: false, file_path, error: mutation.error };
|
|
6654
7156
|
}
|
|
6655
|
-
targetBlock.replace_raw(rawText);
|
|
6656
7157
|
if (!doc.validate()) {
|
|
6657
7158
|
return { success: false, file_path, error: "Validation failed after adding removed GameObject" };
|
|
6658
7159
|
}
|
|
@@ -6681,13 +7182,16 @@ function removeRemovedGameObject(options) {
|
|
|
6681
7182
|
if (!targetBlock) {
|
|
6682
7183
|
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
6683
7184
|
}
|
|
6684
|
-
const
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
7185
|
+
const mutation = mutatePrefabReferenceList({
|
|
7186
|
+
target_block: targetBlock,
|
|
7187
|
+
key: "m_RemovedGameObjects",
|
|
7188
|
+
ref_text: component_ref,
|
|
7189
|
+
action: "remove",
|
|
7190
|
+
item_label: "GameObject"
|
|
7191
|
+
});
|
|
7192
|
+
if (!mutation.success) {
|
|
7193
|
+
return { success: false, file_path, error: mutation.error };
|
|
6688
7194
|
}
|
|
6689
|
-
const updatedRaw = targetBlock.raw.replace(refPattern, "");
|
|
6690
|
-
targetBlock.replace_raw(updatedRaw);
|
|
6691
7195
|
if (!doc.validate()) {
|
|
6692
7196
|
return { success: false, file_path, error: "Validation failed after removing GameObject" };
|
|
6693
7197
|
}
|
|
@@ -6786,6 +7290,7 @@ function removeComponent(options) {
|
|
|
6786
7290
|
return { success: false, file_path, error: "Cannot remove a Transform with remove-component. Use delete to remove the entire GameObject." };
|
|
6787
7291
|
}
|
|
6788
7292
|
const resolved_file_id = found.file_id;
|
|
7293
|
+
let removed_added_component_overrides = 0;
|
|
6789
7294
|
const goMatch = found.raw.match(/m_GameObject:[ \t]*\{fileID:[ \t]*(-?\d+)\}/);
|
|
6790
7295
|
if (goMatch) {
|
|
6791
7296
|
const parentGoId = goMatch[1];
|
|
@@ -6796,6 +7301,19 @@ function removeComponent(options) {
|
|
|
6796
7301
|
const modifiedRaw = goBlock.raw.replace(compLinePattern, "");
|
|
6797
7302
|
if (modifiedRaw === goBlock.raw) {}
|
|
6798
7303
|
goBlock.replace_raw(modifiedRaw);
|
|
7304
|
+
if (goBlock.is_stripped) {
|
|
7305
|
+
const piMatch = goBlock.raw.match(/m_PrefabInstance:[ \t]*\{fileID:[ \t]*(-?\d+)\}/);
|
|
7306
|
+
if (piMatch) {
|
|
7307
|
+
const piBlock = doc.find_by_file_id(piMatch[1]);
|
|
7308
|
+
if (piBlock && piBlock.class_id === 1001) {
|
|
7309
|
+
const updated = removeAddedComponentOverrideEntries(piBlock.raw, resolved_file_id);
|
|
7310
|
+
if (updated.removed_count > 0) {
|
|
7311
|
+
piBlock.replace_raw(updated.updated_raw);
|
|
7312
|
+
removed_added_component_overrides += updated.removed_count;
|
|
7313
|
+
}
|
|
7314
|
+
}
|
|
7315
|
+
}
|
|
7316
|
+
}
|
|
6799
7317
|
}
|
|
6800
7318
|
}
|
|
6801
7319
|
const dangling = [];
|
|
@@ -6819,7 +7337,7 @@ function removeComponent(options) {
|
|
|
6819
7337
|
file_path,
|
|
6820
7338
|
removed_file_id: resolved_file_id,
|
|
6821
7339
|
removed_class_id: found.class_id,
|
|
6822
|
-
warning: dangling.length > 0 ? `Dangling references to deleted component found in blocks: ${dangling.join(", ")}` : undefined
|
|
7340
|
+
warning: dangling.length > 0 ? `Dangling references to deleted component found in blocks: ${dangling.join(", ")}${removed_added_component_overrides > 0 ? ` (removed ${removed_added_component_overrides} m_AddedComponents override entr${removed_added_component_overrides === 1 ? "y" : "ies"})` : ""}` : undefined
|
|
6823
7341
|
};
|
|
6824
7342
|
}
|
|
6825
7343
|
function removeComponentBatch(options) {
|
|
@@ -6937,6 +7455,124 @@ function findPrefabInstanceBlock2(doc, identifier) {
|
|
|
6937
7455
|
}
|
|
6938
7456
|
return null;
|
|
6939
7457
|
}
|
|
7458
|
+
function splitPrefabArraySection3(rawText, key) {
|
|
7459
|
+
const lines = rawText.split(`
|
|
7460
|
+
`);
|
|
7461
|
+
const keyPattern = new RegExp(`^[ ]*${key}:[ ]*(.*)$`);
|
|
7462
|
+
let keyIndex = -1;
|
|
7463
|
+
let keyIndentLen = 0;
|
|
7464
|
+
for (let i = 0;i < lines.length; i++) {
|
|
7465
|
+
const match = lines[i].match(keyPattern);
|
|
7466
|
+
if (match) {
|
|
7467
|
+
keyIndex = i;
|
|
7468
|
+
keyIndentLen = (lines[i].match(/^[ \t]*/) || [""])[0].length;
|
|
7469
|
+
break;
|
|
7470
|
+
}
|
|
7471
|
+
}
|
|
7472
|
+
if (keyIndex === -1) {
|
|
7473
|
+
return null;
|
|
7474
|
+
}
|
|
7475
|
+
let sectionEnd = keyIndex + 1;
|
|
7476
|
+
for (let i = keyIndex + 1;i < lines.length; i++) {
|
|
7477
|
+
const line = lines[i];
|
|
7478
|
+
const trimmed = line.trim();
|
|
7479
|
+
if (trimmed.length === 0) {
|
|
7480
|
+
sectionEnd = i + 1;
|
|
7481
|
+
continue;
|
|
7482
|
+
}
|
|
7483
|
+
const indentLen = (line.match(/^[ \t]*/) || [""])[0].length;
|
|
7484
|
+
if (indentLen < keyIndentLen) {
|
|
7485
|
+
break;
|
|
7486
|
+
}
|
|
7487
|
+
if (indentLen === keyIndentLen && !trimmed.startsWith("-") && /^[A-Za-z_][A-Za-z0-9_]*:/.test(trimmed)) {
|
|
7488
|
+
break;
|
|
7489
|
+
}
|
|
7490
|
+
sectionEnd = i + 1;
|
|
7491
|
+
}
|
|
7492
|
+
return {
|
|
7493
|
+
lines,
|
|
7494
|
+
key_index: keyIndex,
|
|
7495
|
+
section_end: sectionEnd
|
|
7496
|
+
};
|
|
7497
|
+
}
|
|
7498
|
+
function collectAddedObjectFileIdsFromArray(rawText, key) {
|
|
7499
|
+
const section = splitPrefabArraySection3(rawText, key);
|
|
7500
|
+
if (!section)
|
|
7501
|
+
return [];
|
|
7502
|
+
const keyLine = section.lines[section.key_index].trim();
|
|
7503
|
+
if (new RegExp(`^${key}:[ ]*[]$`).test(keyLine)) {
|
|
7504
|
+
return [];
|
|
7505
|
+
}
|
|
7506
|
+
const sectionText = section.lines.slice(section.key_index, section.section_end).join(`
|
|
7507
|
+
`);
|
|
7508
|
+
const fileIds = new Set;
|
|
7509
|
+
const addedObjectPattern = /addedObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)/g;
|
|
7510
|
+
let match;
|
|
7511
|
+
while ((match = addedObjectPattern.exec(sectionText)) !== null) {
|
|
7512
|
+
fileIds.add(match[1]);
|
|
7513
|
+
}
|
|
7514
|
+
if (fileIds.size === 0) {
|
|
7515
|
+
const inlineEntryPattern = /^[ \t]*-[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)/gm;
|
|
7516
|
+
while ((match = inlineEntryPattern.exec(sectionText)) !== null) {
|
|
7517
|
+
fileIds.add(match[1]);
|
|
7518
|
+
}
|
|
7519
|
+
}
|
|
7520
|
+
return [...fileIds];
|
|
7521
|
+
}
|
|
7522
|
+
function removeAddedComponentOverrideEntries(rawText, componentId) {
|
|
7523
|
+
const section = splitPrefabArraySection3(rawText, "m_AddedComponents");
|
|
7524
|
+
if (!section)
|
|
7525
|
+
return { updated_raw: rawText, removed_count: 0 };
|
|
7526
|
+
const keyLine = section.lines[section.key_index].trim();
|
|
7527
|
+
if (/^m_AddedComponents:[ \t]*\[\]$/.test(keyLine)) {
|
|
7528
|
+
return { updated_raw: rawText, removed_count: 0 };
|
|
7529
|
+
}
|
|
7530
|
+
const bodyLines = section.lines.slice(section.key_index + 1, section.section_end);
|
|
7531
|
+
const keptEntries = [];
|
|
7532
|
+
let removed = 0;
|
|
7533
|
+
let i = 0;
|
|
7534
|
+
while (i < bodyLines.length) {
|
|
7535
|
+
const line = bodyLines[i];
|
|
7536
|
+
const trimmed = line.trimStart();
|
|
7537
|
+
if (!trimmed.startsWith("-")) {
|
|
7538
|
+
i++;
|
|
7539
|
+
continue;
|
|
7540
|
+
}
|
|
7541
|
+
const entryIndent = (line.match(/^[ \t]*/) || [""])[0].length;
|
|
7542
|
+
const entryLines = [line];
|
|
7543
|
+
i++;
|
|
7544
|
+
while (i < bodyLines.length) {
|
|
7545
|
+
const nextLine = bodyLines[i];
|
|
7546
|
+
const nextTrimmed = nextLine.trim();
|
|
7547
|
+
const nextIndent = (nextLine.match(/^[ \t]*/) || [""])[0].length;
|
|
7548
|
+
if (nextTrimmed.length > 0 && nextIndent === entryIndent && nextTrimmed.startsWith("-")) {
|
|
7549
|
+
break;
|
|
7550
|
+
}
|
|
7551
|
+
entryLines.push(nextLine);
|
|
7552
|
+
i++;
|
|
7553
|
+
}
|
|
7554
|
+
const entryText = entryLines.join(`
|
|
7555
|
+
`);
|
|
7556
|
+
const addedObjectMatch = entryText.match(/addedObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)/);
|
|
7557
|
+
if (addedObjectMatch && addedObjectMatch[1] === componentId) {
|
|
7558
|
+
removed++;
|
|
7559
|
+
continue;
|
|
7560
|
+
}
|
|
7561
|
+
keptEntries.push(entryLines);
|
|
7562
|
+
}
|
|
7563
|
+
if (removed === 0) {
|
|
7564
|
+
return { updated_raw: rawText, removed_count: 0 };
|
|
7565
|
+
}
|
|
7566
|
+
const keyIndent = (section.lines[section.key_index].match(/^[ \t]*/) || [""])[0];
|
|
7567
|
+
const replacement = keptEntries.length === 0 ? [`${keyIndent}m_AddedComponents: []`] : [`${keyIndent}m_AddedComponents:`, ...keptEntries.flat()];
|
|
7568
|
+
const updatedLines = [
|
|
7569
|
+
...section.lines.slice(0, section.key_index),
|
|
7570
|
+
...replacement,
|
|
7571
|
+
...section.lines.slice(section.section_end)
|
|
7572
|
+
];
|
|
7573
|
+
return { updated_raw: updatedLines.join(`
|
|
7574
|
+
`), removed_count: removed };
|
|
7575
|
+
}
|
|
6940
7576
|
function deletePrefabInstance(options) {
|
|
6941
7577
|
const { file_path, prefab_instance } = options;
|
|
6942
7578
|
const pathError = validate_file_path(file_path, "write");
|
|
@@ -6964,36 +7600,23 @@ function deletePrefabInstance(options) {
|
|
|
6964
7600
|
allToRemove.add(block.file_id);
|
|
6965
7601
|
}
|
|
6966
7602
|
}
|
|
6967
|
-
const
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
if (compMatch) {
|
|
6979
|
-
const transformId = compMatch[1];
|
|
6980
|
-
allToRemove.add(transformId);
|
|
6981
|
-
const descendants = doc.collect_hierarchy(transformId);
|
|
6982
|
-
for (const id of descendants) {
|
|
6983
|
-
allToRemove.add(id);
|
|
6984
|
-
}
|
|
7603
|
+
for (const goId of collectAddedObjectFileIdsFromArray(piBlock.raw, "m_AddedGameObjects")) {
|
|
7604
|
+
allToRemove.add(goId);
|
|
7605
|
+
const goBlock = doc.find_by_file_id(goId);
|
|
7606
|
+
if (goBlock) {
|
|
7607
|
+
const compMatch = goBlock.raw.match(/component:[ \t]*\{fileID:[ \t]*(\d+)\}/);
|
|
7608
|
+
if (compMatch) {
|
|
7609
|
+
const transformId = compMatch[1];
|
|
7610
|
+
allToRemove.add(transformId);
|
|
7611
|
+
const descendants = doc.collect_hierarchy(transformId);
|
|
7612
|
+
for (const id of descendants) {
|
|
7613
|
+
allToRemove.add(id);
|
|
6985
7614
|
}
|
|
6986
7615
|
}
|
|
6987
7616
|
}
|
|
6988
7617
|
}
|
|
6989
|
-
const
|
|
6990
|
-
|
|
6991
|
-
if (addedCompMatch) {
|
|
6992
|
-
const addedCompSection = addedCompMatch[1];
|
|
6993
|
-
const compMatches = addedCompSection.matchAll(/fileID:[ \t]*(\d+)/g);
|
|
6994
|
-
for (const match of compMatches) {
|
|
6995
|
-
allToRemove.add(match[1]);
|
|
6996
|
-
}
|
|
7618
|
+
for (const componentId of collectAddedObjectFileIdsFromArray(piBlock.raw, "m_AddedComponents")) {
|
|
7619
|
+
allToRemove.add(componentId);
|
|
6997
7620
|
}
|
|
6998
7621
|
const parentMatch = piBlock.raw.match(/m_TransformParent:[ \t]*\{fileID:[ \t]*(\d+)\}/);
|
|
6999
7622
|
const parentTransformId = parentMatch ? parentMatch[1] : "0";
|