unity-agentic-tools 0.4.0 → 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 +1200 -201
- package/dist/index.js +948 -137
- 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
|
@@ -2299,7 +2299,7 @@ var require_package = __commonJS((exports2, module2) => {
|
|
|
2299
2299
|
module2.exports = {
|
|
2300
2300
|
name: "unity-agentic-tools",
|
|
2301
2301
|
packageManager: "bun@latest",
|
|
2302
|
-
version: "0.4.
|
|
2302
|
+
version: "0.4.2",
|
|
2303
2303
|
description: "Fast, token-efficient Unity YAML parser for AI agents",
|
|
2304
2304
|
exports: {
|
|
2305
2305
|
".": {
|
|
@@ -2619,6 +2619,9 @@ function find_unity_project_root(startDir) {
|
|
|
2619
2619
|
}
|
|
2620
2620
|
return null;
|
|
2621
2621
|
}
|
|
2622
|
+
function resolve_project_path(project_path) {
|
|
2623
|
+
return import_path4.resolve(project_path || process.cwd());
|
|
2624
|
+
}
|
|
2622
2625
|
function ensure_parent_dir(file_path) {
|
|
2623
2626
|
const dir = import_path4.dirname(file_path);
|
|
2624
2627
|
if (dir && dir !== "." && !import_fs4.existsSync(dir)) {
|
|
@@ -3286,9 +3289,75 @@ function resolveScriptGuid(script, projectPath) {
|
|
|
3286
3289
|
}
|
|
3287
3290
|
} catch {}
|
|
3288
3291
|
}
|
|
3292
|
+
try {
|
|
3293
|
+
const assetsDir = path.join(projectPath, "Assets");
|
|
3294
|
+
if (import_fs6.existsSync(assetsDir)) {
|
|
3295
|
+
const entries = import_fs6.readdirSync(assetsDir, { recursive: true, withFileTypes: false });
|
|
3296
|
+
for (const entry of entries) {
|
|
3297
|
+
if (!entry.endsWith(".cs"))
|
|
3298
|
+
continue;
|
|
3299
|
+
const fileName = path.basename(entry, ".cs").toLowerCase();
|
|
3300
|
+
if (fileName === scriptNameLower || classNameOnly && fileName === classNameOnly) {
|
|
3301
|
+
const fullPath = path.join(assetsDir, entry);
|
|
3302
|
+
const guid = extractGuidFromMeta(fullPath + ".meta");
|
|
3303
|
+
if (guid) {
|
|
3304
|
+
return { guid, path: path.join("Assets", entry) };
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3309
|
+
} catch {}
|
|
3289
3310
|
}
|
|
3290
3311
|
return null;
|
|
3291
3312
|
}
|
|
3313
|
+
var ASSET_PPTR_MAP = {
|
|
3314
|
+
".inputactions": { fileID: 11400000, type: 2 },
|
|
3315
|
+
".asset": { fileID: 11400000, type: 2 },
|
|
3316
|
+
".mat": { fileID: 2100000, type: 2 },
|
|
3317
|
+
".prefab": { fileID: 100100000, type: 2 },
|
|
3318
|
+
".controller": { fileID: 9100000, type: 2 },
|
|
3319
|
+
".anim": { fileID: 7400000, type: 2 }
|
|
3320
|
+
};
|
|
3321
|
+
var ASSET_EXTENSIONS = new Set(Object.keys(ASSET_PPTR_MAP));
|
|
3322
|
+
function resolveAssetPathToPPtr(value, file_path, project_path) {
|
|
3323
|
+
if (value.startsWith("{fileID:") || value.startsWith("{"))
|
|
3324
|
+
return;
|
|
3325
|
+
const ext = path.extname(value).toLowerCase();
|
|
3326
|
+
if (!ASSET_EXTENSIONS.has(ext))
|
|
3327
|
+
return;
|
|
3328
|
+
const resolved_project = project_path || find_unity_project_root(path.dirname(file_path));
|
|
3329
|
+
if (!resolved_project)
|
|
3330
|
+
return null;
|
|
3331
|
+
const mapping = ASSET_PPTR_MAP[ext];
|
|
3332
|
+
let guid = null;
|
|
3333
|
+
const basename_val = path.basename(value, ext);
|
|
3334
|
+
if (value.includes("/") || value.includes("\\")) {
|
|
3335
|
+
const abs = path.isAbsolute(value) ? value : path.join(resolved_project, value);
|
|
3336
|
+
guid = extractGuidFromMeta(abs + ".meta");
|
|
3337
|
+
}
|
|
3338
|
+
if (!guid) {
|
|
3339
|
+
const cache = load_guid_cache_for_file(file_path, resolved_project);
|
|
3340
|
+
if (cache) {
|
|
3341
|
+
const found = cache.find_by_name(basename_val, ext);
|
|
3342
|
+
if (found)
|
|
3343
|
+
guid = found.guid;
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
if (!guid) {
|
|
3347
|
+
const candidates = [
|
|
3348
|
+
path.join(resolved_project, "Assets", value),
|
|
3349
|
+
path.join(resolved_project, value)
|
|
3350
|
+
];
|
|
3351
|
+
for (const candidate of candidates) {
|
|
3352
|
+
guid = extractGuidFromMeta(candidate + ".meta");
|
|
3353
|
+
if (guid)
|
|
3354
|
+
break;
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
if (!guid)
|
|
3358
|
+
return null;
|
|
3359
|
+
return `{fileID: ${mapping.fileID}, guid: ${guid}, type: ${mapping.type}}`;
|
|
3360
|
+
}
|
|
3292
3361
|
function resolve_script_with_fields(script, project_path) {
|
|
3293
3362
|
const resolved = resolveScriptGuid(script, project_path);
|
|
3294
3363
|
if (!resolved)
|
|
@@ -3392,8 +3461,8 @@ function build_type_lookup(project_path) {
|
|
|
3392
3461
|
const assetsDir = path.join(project_path, "Assets");
|
|
3393
3462
|
const csIndex = new Map;
|
|
3394
3463
|
try {
|
|
3395
|
-
const { readdirSync:
|
|
3396
|
-
const entries =
|
|
3464
|
+
const { readdirSync: readdirSync4 } = require("fs");
|
|
3465
|
+
const entries = readdirSync4(assetsDir, { recursive: true, withFileTypes: false });
|
|
3397
3466
|
for (const entry of entries) {
|
|
3398
3467
|
if (typeof entry === "string" && entry.endsWith(".cs")) {
|
|
3399
3468
|
const basename3 = entry.substring(entry.lastIndexOf("/") + 1).replace(/\.cs$/, "");
|
|
@@ -3845,7 +3914,9 @@ ${element_indent2}- ${value}`);
|
|
|
3845
3914
|
if (!header) {
|
|
3846
3915
|
throw new Error(`Invalid Unity YAML block header in replacement text: "${new_text.slice(0, 80)}"`);
|
|
3847
3916
|
}
|
|
3848
|
-
this._raw = new_text
|
|
3917
|
+
this._raw = new_text.endsWith(`
|
|
3918
|
+
`) ? new_text : new_text + `
|
|
3919
|
+
`;
|
|
3849
3920
|
this._header = header;
|
|
3850
3921
|
this._dirty = true;
|
|
3851
3922
|
this._format_cache.clear();
|
|
@@ -3855,6 +3926,11 @@ ${element_indent2}- ${value}`);
|
|
|
3855
3926
|
}
|
|
3856
3927
|
_check_dirty(old_raw) {
|
|
3857
3928
|
if (this._raw !== old_raw) {
|
|
3929
|
+
if (!this._raw.endsWith(`
|
|
3930
|
+
`)) {
|
|
3931
|
+
this._raw += `
|
|
3932
|
+
`;
|
|
3933
|
+
}
|
|
3858
3934
|
this._dirty = true;
|
|
3859
3935
|
return true;
|
|
3860
3936
|
}
|
|
@@ -4937,14 +5013,82 @@ function get_project_info(projectPath) {
|
|
|
4937
5013
|
}
|
|
4938
5014
|
|
|
4939
5015
|
// src/editor/create.ts
|
|
5016
|
+
function md4(data) {
|
|
5017
|
+
function F(x, y, z) {
|
|
5018
|
+
return x & y | ~x & z;
|
|
5019
|
+
}
|
|
5020
|
+
function G(x, y, z) {
|
|
5021
|
+
return x & y | x & z | y & z;
|
|
5022
|
+
}
|
|
5023
|
+
function H(x, y, z) {
|
|
5024
|
+
return x ^ y ^ z;
|
|
5025
|
+
}
|
|
5026
|
+
function rotl(x, n) {
|
|
5027
|
+
return (x << n | x >>> 32 - n) >>> 0;
|
|
5028
|
+
}
|
|
5029
|
+
const len = data.length;
|
|
5030
|
+
const bitLen = len * 8;
|
|
5031
|
+
const padded_len = len + 9 + 63 & ~63;
|
|
5032
|
+
const buf = Buffer.alloc(padded_len);
|
|
5033
|
+
data.copy(buf);
|
|
5034
|
+
buf[len] = 128;
|
|
5035
|
+
buf.writeUInt32LE(bitLen >>> 0, padded_len - 8);
|
|
5036
|
+
buf.writeUInt32LE(Math.floor(bitLen / 4294967296) >>> 0, padded_len - 4);
|
|
5037
|
+
let a0 = 1732584193;
|
|
5038
|
+
let b0 = 4023233417;
|
|
5039
|
+
let c0 = 2562383102;
|
|
5040
|
+
let d0 = 271733878;
|
|
5041
|
+
const R1_K = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
5042
|
+
const R1_S = [3, 7, 11, 19, 3, 7, 11, 19, 3, 7, 11, 19, 3, 7, 11, 19];
|
|
5043
|
+
const R2_K = [0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15];
|
|
5044
|
+
const R2_S = [3, 5, 9, 13, 3, 5, 9, 13, 3, 5, 9, 13, 3, 5, 9, 13];
|
|
5045
|
+
const R3_K = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15];
|
|
5046
|
+
const R3_S = [3, 9, 11, 15, 3, 9, 11, 15, 3, 9, 11, 15, 3, 9, 11, 15];
|
|
5047
|
+
for (let i = 0;i < padded_len; i += 64) {
|
|
5048
|
+
const X = [];
|
|
5049
|
+
for (let j = 0;j < 16; j++)
|
|
5050
|
+
X[j] = buf.readUInt32LE(i + j * 4);
|
|
5051
|
+
let a = a0, b = b0, c = c0, d = d0;
|
|
5052
|
+
for (let j = 0;j < 16; j++) {
|
|
5053
|
+
const t = a + F(b, c, d) + X[R1_K[j]] >>> 0;
|
|
5054
|
+
a = d;
|
|
5055
|
+
d = c;
|
|
5056
|
+
c = b;
|
|
5057
|
+
b = rotl(t, R1_S[j]);
|
|
5058
|
+
}
|
|
5059
|
+
for (let j = 0;j < 16; j++) {
|
|
5060
|
+
const t = a + G(b, c, d) + X[R2_K[j]] + 1518500249 >>> 0;
|
|
5061
|
+
a = d;
|
|
5062
|
+
d = c;
|
|
5063
|
+
c = b;
|
|
5064
|
+
b = rotl(t, R2_S[j]);
|
|
5065
|
+
}
|
|
5066
|
+
for (let j = 0;j < 16; j++) {
|
|
5067
|
+
const t = a + H(b, c, d) + X[R3_K[j]] + 1859775393 >>> 0;
|
|
5068
|
+
a = d;
|
|
5069
|
+
d = c;
|
|
5070
|
+
c = b;
|
|
5071
|
+
b = rotl(t, R3_S[j]);
|
|
5072
|
+
}
|
|
5073
|
+
a0 = a0 + a >>> 0;
|
|
5074
|
+
b0 = b0 + b >>> 0;
|
|
5075
|
+
c0 = c0 + c >>> 0;
|
|
5076
|
+
d0 = d0 + d >>> 0;
|
|
5077
|
+
}
|
|
5078
|
+
const result = Buffer.alloc(16);
|
|
5079
|
+
result.writeUInt32LE(a0, 0);
|
|
5080
|
+
result.writeUInt32LE(b0, 4);
|
|
5081
|
+
result.writeUInt32LE(c0, 8);
|
|
5082
|
+
result.writeUInt32LE(d0, 12);
|
|
5083
|
+
return result;
|
|
5084
|
+
}
|
|
4940
5085
|
function compute_dll_script_file_id(namespace, class_name) {
|
|
4941
|
-
const { createHash } = require("crypto");
|
|
4942
5086
|
const full_name = namespace ? `${namespace}.${class_name}` : class_name;
|
|
4943
5087
|
const name_bytes = Buffer.from(full_name, "utf-8");
|
|
4944
5088
|
const input = Buffer.alloc(4 + name_bytes.length);
|
|
4945
5089
|
input.writeInt32LE(114, 0);
|
|
4946
5090
|
name_bytes.copy(input, 4);
|
|
4947
|
-
const hash =
|
|
5091
|
+
const hash = md4(input);
|
|
4948
5092
|
const a = hash.readInt32LE(0);
|
|
4949
5093
|
const b = hash.readInt32LE(4);
|
|
4950
5094
|
const c = hash.readInt32LE(8);
|
|
@@ -4957,13 +5101,13 @@ function get_layer_from_parent(doc, parentTransformId) {
|
|
|
4957
5101
|
const parentTransform = doc.find_by_file_id(parentTransformId);
|
|
4958
5102
|
if (!parentTransform)
|
|
4959
5103
|
return 0;
|
|
4960
|
-
const goMatch = parentTransform.raw.match(/m_GameObject
|
|
5104
|
+
const goMatch = parentTransform.raw.match(/m_GameObject:[ \t]*\{fileID:[ \t]*(\d+)\}/);
|
|
4961
5105
|
if (!goMatch)
|
|
4962
5106
|
return 0;
|
|
4963
5107
|
const parentGo = doc.find_by_file_id(goMatch[1]);
|
|
4964
5108
|
if (!parentGo)
|
|
4965
5109
|
return 0;
|
|
4966
|
-
const layerMatch = parentGo.raw.match(/m_Layer
|
|
5110
|
+
const layerMatch = parentGo.raw.match(/m_Layer:[ \t]*(\d+)/);
|
|
4967
5111
|
return layerMatch ? parseInt(layerMatch[1], 10) : 0;
|
|
4968
5112
|
}
|
|
4969
5113
|
function createGameObjectYAML(gameObjectId, transformId, name, parentTransformId = "0", rootOrder = 0, layer = 0) {
|
|
@@ -5100,48 +5244,320 @@ function find_game_object_in_variant(doc, name, file_path, project_path) {
|
|
|
5100
5244
|
}
|
|
5101
5245
|
return null;
|
|
5102
5246
|
}
|
|
5103
|
-
function
|
|
5104
|
-
const
|
|
5105
|
-
if (!
|
|
5106
|
-
return;
|
|
5107
|
-
const
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5247
|
+
function parsePrefabRef(refText) {
|
|
5248
|
+
const fileIdMatch = refText.match(/fileID:[ \t]*(-?\d+)/i);
|
|
5249
|
+
if (!fileIdMatch)
|
|
5250
|
+
return null;
|
|
5251
|
+
const guidMatch = refText.match(/guid:[ \t]*([a-f0-9]{32})/i);
|
|
5252
|
+
const typeMatch = refText.match(/type:[ \t]*(-?\d+)/i);
|
|
5253
|
+
return {
|
|
5254
|
+
file_id: fileIdMatch[1],
|
|
5255
|
+
guid: guidMatch ? guidMatch[1].toLowerCase() : undefined,
|
|
5256
|
+
type: typeMatch ? typeMatch[1] : undefined
|
|
5257
|
+
};
|
|
5258
|
+
}
|
|
5259
|
+
function extractPrefabSourceGuid(prefabInstanceRaw) {
|
|
5260
|
+
const sourceMatch = prefabInstanceRaw.match(/m_SourcePrefab:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]{32})/i);
|
|
5261
|
+
return sourceMatch ? sourceMatch[1].toLowerCase() : null;
|
|
5262
|
+
}
|
|
5263
|
+
function normalizePrefabRef(refText, sourceGuid) {
|
|
5264
|
+
const parsed = parsePrefabRef(refText);
|
|
5265
|
+
if (!parsed) {
|
|
5266
|
+
return { error: `Invalid reference "${refText}". Expected format: {fileID: N, guid: ..., type: T}` };
|
|
5267
|
+
}
|
|
5268
|
+
const guid = parsed.guid ?? sourceGuid;
|
|
5269
|
+
if (!guid) {
|
|
5270
|
+
return { error: `Reference "${refText}" is missing guid and source prefab guid could not be inferred.` };
|
|
5271
|
+
}
|
|
5272
|
+
if (!/^[a-f0-9]{32}$/i.test(guid)) {
|
|
5273
|
+
return { error: `Invalid guid in reference "${refText}". Expected 32-character hex GUID.` };
|
|
5117
5274
|
}
|
|
5118
|
-
const
|
|
5119
|
-
if (
|
|
5120
|
-
|
|
5121
|
-
piBlock.replace_raw(raw);
|
|
5275
|
+
const type = parsed.type ?? "3";
|
|
5276
|
+
if (!/^-?\d+$/.test(type)) {
|
|
5277
|
+
return { error: `Invalid type in reference "${refText}". Expected an integer type value.` };
|
|
5122
5278
|
}
|
|
5279
|
+
return {
|
|
5280
|
+
ref: {
|
|
5281
|
+
file_id: parsed.file_id,
|
|
5282
|
+
guid,
|
|
5283
|
+
type
|
|
5284
|
+
}
|
|
5285
|
+
};
|
|
5123
5286
|
}
|
|
5124
|
-
function
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
const
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5287
|
+
function serializePrefabRef(ref) {
|
|
5288
|
+
return `{fileID: ${ref.file_id}, guid: ${ref.guid}, type: ${ref.type}}`;
|
|
5289
|
+
}
|
|
5290
|
+
function ensurePrefabModificationSerializedVersion(prefabInstanceBlock) {
|
|
5291
|
+
const raw = prefabInstanceBlock.raw;
|
|
5292
|
+
const updated = raw.replace(/(^([ \t]*)m_Modification:[ \t]*\n)(?!\2[ \t]+serializedVersion:[ \t]*\d+)/m, (_match, prefix, indent) => `${prefix}${indent} serializedVersion: 3
|
|
5293
|
+
`);
|
|
5294
|
+
if (updated === raw) {
|
|
5295
|
+
return false;
|
|
5296
|
+
}
|
|
5297
|
+
prefabInstanceBlock.replace_raw(updated);
|
|
5298
|
+
return true;
|
|
5299
|
+
}
|
|
5300
|
+
function addedOverrideEntryKey(entry) {
|
|
5301
|
+
return `${entry.target.file_id}|${entry.target.guid}|${entry.target.type}|${entry.insert_index}|${entry.added_object_file_id}`;
|
|
5302
|
+
}
|
|
5303
|
+
function splitPrefabArraySection(rawText, key) {
|
|
5304
|
+
const lines = rawText.split(`
|
|
5305
|
+
`);
|
|
5306
|
+
const keyPattern = new RegExp(`^([ ]*)${key}:[ ]*(.*)$`);
|
|
5307
|
+
let keyIndex = -1;
|
|
5308
|
+
let indent = "";
|
|
5309
|
+
for (let i = 0;i < lines.length; i++) {
|
|
5310
|
+
const match = lines[i].match(keyPattern);
|
|
5311
|
+
if (match) {
|
|
5312
|
+
keyIndex = i;
|
|
5313
|
+
indent = match[1];
|
|
5314
|
+
break;
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5317
|
+
if (keyIndex === -1) {
|
|
5318
|
+
return null;
|
|
5319
|
+
}
|
|
5320
|
+
const keyIndentLen = indent.length;
|
|
5321
|
+
let sectionEnd = keyIndex + 1;
|
|
5322
|
+
for (let i = keyIndex + 1;i < lines.length; i++) {
|
|
5323
|
+
const line = lines[i];
|
|
5324
|
+
const trimmed = line.trim();
|
|
5325
|
+
if (trimmed.length === 0) {
|
|
5326
|
+
sectionEnd = i + 1;
|
|
5327
|
+
continue;
|
|
5328
|
+
}
|
|
5329
|
+
const indentLen = (line.match(/^[ \t]*/) || [""])[0].length;
|
|
5330
|
+
if (indentLen < keyIndentLen) {
|
|
5331
|
+
break;
|
|
5332
|
+
}
|
|
5333
|
+
if (indentLen === keyIndentLen && !trimmed.startsWith("-") && /^[A-Za-z_][A-Za-z0-9_]*:/.test(trimmed)) {
|
|
5334
|
+
break;
|
|
5335
|
+
}
|
|
5336
|
+
sectionEnd = i + 1;
|
|
5337
|
+
}
|
|
5338
|
+
return {
|
|
5339
|
+
lines,
|
|
5340
|
+
key_index: keyIndex,
|
|
5341
|
+
section_end: sectionEnd,
|
|
5342
|
+
indent
|
|
5343
|
+
};
|
|
5344
|
+
}
|
|
5345
|
+
function collectAddedOverrideEntries(lines, key_index, section_end, sourceGuid) {
|
|
5346
|
+
const sectionLines = lines.slice(key_index + 1, section_end);
|
|
5347
|
+
const dedup = new Map;
|
|
5348
|
+
let i = 0;
|
|
5349
|
+
while (i < sectionLines.length) {
|
|
5350
|
+
const line = sectionLines[i];
|
|
5351
|
+
const trimmed = line.trimStart();
|
|
5352
|
+
if (!trimmed.startsWith("-")) {
|
|
5353
|
+
i++;
|
|
5354
|
+
continue;
|
|
5355
|
+
}
|
|
5356
|
+
const entryIndent = (line.match(/^[ \t]*/) || [""])[0].length;
|
|
5357
|
+
const entryLines = [line];
|
|
5358
|
+
i++;
|
|
5359
|
+
while (i < sectionLines.length) {
|
|
5360
|
+
const nextLine = sectionLines[i];
|
|
5361
|
+
const nextTrimmed = nextLine.trim();
|
|
5362
|
+
const nextIndent = (nextLine.match(/^[ \t]*/) || [""])[0].length;
|
|
5363
|
+
if (nextTrimmed.length > 0 && nextIndent === entryIndent && nextTrimmed.startsWith("-")) {
|
|
5364
|
+
break;
|
|
5365
|
+
}
|
|
5366
|
+
entryLines.push(nextLine);
|
|
5367
|
+
i++;
|
|
5368
|
+
}
|
|
5369
|
+
const entryText = entryLines.join(`
|
|
5370
|
+
`);
|
|
5371
|
+
const targetMatch = entryText.match(/targetCorrespondingSourceObject:[ \t]*(\{[^}]+\})/);
|
|
5372
|
+
const insertMatch = entryText.match(/insertIndex:[ \t]*(-?\d+)/);
|
|
5373
|
+
const addedObjectMatch = entryText.match(/addedObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)/);
|
|
5374
|
+
if (!targetMatch || !addedObjectMatch) {
|
|
5375
|
+
continue;
|
|
5376
|
+
}
|
|
5377
|
+
const normalizedTarget = normalizePrefabRef(targetMatch[1], sourceGuid).ref;
|
|
5378
|
+
if (!normalizedTarget) {
|
|
5379
|
+
continue;
|
|
5380
|
+
}
|
|
5381
|
+
const insertIndex = insertMatch ? Number.parseInt(insertMatch[1], 10) : -1;
|
|
5382
|
+
const entry = {
|
|
5383
|
+
target: normalizedTarget,
|
|
5384
|
+
insert_index: Number.isNaN(insertIndex) ? -1 : insertIndex,
|
|
5385
|
+
added_object_file_id: addedObjectMatch[1]
|
|
5386
|
+
};
|
|
5387
|
+
const dedupKey = addedOverrideEntryKey(entry);
|
|
5388
|
+
if (!dedup.has(dedupKey)) {
|
|
5389
|
+
dedup.set(dedupKey, entry);
|
|
5390
|
+
}
|
|
5138
5391
|
}
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5392
|
+
return [...dedup.values()];
|
|
5393
|
+
}
|
|
5394
|
+
function appendToAddedOverrideArray(doc, piId, key, targetSourceRef, newObjectId) {
|
|
5395
|
+
const piBlock = doc.find_by_file_id(piId);
|
|
5396
|
+
if (!piBlock) {
|
|
5397
|
+
return { success: false, error: `PrefabInstance with fileID ${piId} not found` };
|
|
5398
|
+
}
|
|
5399
|
+
ensurePrefabModificationSerializedVersion(piBlock);
|
|
5400
|
+
const split = splitPrefabArraySection(piBlock.raw, key);
|
|
5401
|
+
if (!split) {
|
|
5402
|
+
return { success: false, error: `${key} property not found in PrefabInstance ${piId}` };
|
|
5403
|
+
}
|
|
5404
|
+
const sourceGuid = extractPrefabSourceGuid(piBlock.raw);
|
|
5405
|
+
const normalizedTarget = normalizePrefabRef(targetSourceRef, sourceGuid);
|
|
5406
|
+
if (!normalizedTarget.ref) {
|
|
5407
|
+
return { success: false, error: normalizedTarget.error };
|
|
5408
|
+
}
|
|
5409
|
+
const candidate = {
|
|
5410
|
+
target: normalizedTarget.ref,
|
|
5411
|
+
insert_index: -1,
|
|
5412
|
+
added_object_file_id: newObjectId
|
|
5413
|
+
};
|
|
5414
|
+
const candidateKey = addedOverrideEntryKey(candidate);
|
|
5415
|
+
const existing = collectAddedOverrideEntries(split.lines, split.key_index, split.section_end, sourceGuid);
|
|
5416
|
+
if (existing.some((entry) => addedOverrideEntryKey(entry) === candidateKey)) {
|
|
5417
|
+
return { success: true, changed: false };
|
|
5418
|
+
}
|
|
5419
|
+
const entryLines = [
|
|
5420
|
+
`${split.indent}- targetCorrespondingSourceObject: ${serializePrefabRef(candidate.target)}`,
|
|
5421
|
+
`${split.indent} insertIndex: ${candidate.insert_index}`,
|
|
5422
|
+
`${split.indent} addedObject: {fileID: ${candidate.added_object_file_id}}`
|
|
5423
|
+
];
|
|
5424
|
+
const keyLine = split.lines[split.key_index].trim();
|
|
5425
|
+
let insertIndex = split.section_end;
|
|
5426
|
+
while (insertIndex > split.key_index + 1 && split.lines[insertIndex - 1].trim().length === 0) {
|
|
5427
|
+
insertIndex--;
|
|
5428
|
+
}
|
|
5429
|
+
let updatedLines;
|
|
5430
|
+
if (keyLine === `${key}: []`) {
|
|
5431
|
+
const replacement = [`${split.indent}${key}:`, ...entryLines];
|
|
5432
|
+
updatedLines = [
|
|
5433
|
+
...split.lines.slice(0, split.key_index),
|
|
5434
|
+
...replacement,
|
|
5435
|
+
...split.lines.slice(split.section_end)
|
|
5436
|
+
];
|
|
5437
|
+
} else {
|
|
5438
|
+
updatedLines = [
|
|
5439
|
+
...split.lines.slice(0, insertIndex),
|
|
5440
|
+
...entryLines,
|
|
5441
|
+
...split.lines.slice(insertIndex)
|
|
5442
|
+
];
|
|
5143
5443
|
}
|
|
5444
|
+
piBlock.replace_raw(updatedLines.join(`
|
|
5445
|
+
`));
|
|
5446
|
+
return { success: true, changed: true };
|
|
5447
|
+
}
|
|
5448
|
+
function appendToAddedGameObjects(doc, piId, targetSourceRef, newGoId) {
|
|
5449
|
+
return appendToAddedOverrideArray(doc, piId, "m_AddedGameObjects", targetSourceRef, newGoId);
|
|
5144
5450
|
}
|
|
5451
|
+
function appendToAddedComponents(doc, piId, targetSourceRef, newComponentId) {
|
|
5452
|
+
return appendToAddedOverrideArray(doc, piId, "m_AddedComponents", targetSourceRef, newComponentId);
|
|
5453
|
+
}
|
|
5454
|
+
var COMPONENT_FULL_TEMPLATES = {
|
|
5455
|
+
65: (gameObjectId) => ` m_GameObject: {fileID: ${gameObjectId}}
|
|
5456
|
+
m_Material: {fileID: 0}
|
|
5457
|
+
m_IncludeLayers:
|
|
5458
|
+
serializedVersion: 2
|
|
5459
|
+
m_Bits: 0
|
|
5460
|
+
m_ExcludeLayers:
|
|
5461
|
+
serializedVersion: 2
|
|
5462
|
+
m_Bits: 0
|
|
5463
|
+
m_LayerOverridePriority: 0
|
|
5464
|
+
m_IsTrigger: 0
|
|
5465
|
+
m_ProvidesContacts: 0
|
|
5466
|
+
m_Enabled: 1
|
|
5467
|
+
serializedVersion: 3
|
|
5468
|
+
m_Size: {x: 1, y: 1, z: 1}
|
|
5469
|
+
m_Center: {x: 0, y: 0, z: 0}`,
|
|
5470
|
+
82: (gameObjectId) => ` m_GameObject: {fileID: ${gameObjectId}}
|
|
5471
|
+
m_Enabled: 1
|
|
5472
|
+
serializedVersion: 4
|
|
5473
|
+
OutputAudioMixerGroup: {fileID: 0}
|
|
5474
|
+
m_audioClip: {fileID: 0}
|
|
5475
|
+
m_PlayOnAwake: 1
|
|
5476
|
+
m_Volume: 1
|
|
5477
|
+
m_Pitch: 1
|
|
5478
|
+
Loop: 0
|
|
5479
|
+
Mute: 0
|
|
5480
|
+
Spatialize: 0
|
|
5481
|
+
SpatializePostEffects: 0
|
|
5482
|
+
Priority: 128
|
|
5483
|
+
DopplerLevel: 1
|
|
5484
|
+
MinDistance: 1
|
|
5485
|
+
MaxDistance: 500
|
|
5486
|
+
Pan2D: 0
|
|
5487
|
+
rolloffMode: 0
|
|
5488
|
+
BypassEffects: 0
|
|
5489
|
+
BypassListenerEffects: 0
|
|
5490
|
+
BypassReverbZones: 0
|
|
5491
|
+
rolloffCustomCurve:
|
|
5492
|
+
serializedVersion: 2
|
|
5493
|
+
m_Curve:
|
|
5494
|
+
- serializedVersion: 3
|
|
5495
|
+
time: 0
|
|
5496
|
+
value: 1
|
|
5497
|
+
inSlope: 0
|
|
5498
|
+
outSlope: 0
|
|
5499
|
+
tangentMode: 0
|
|
5500
|
+
weightedMode: 0
|
|
5501
|
+
inWeight: 0.33333334
|
|
5502
|
+
outWeight: 0.33333334
|
|
5503
|
+
- serializedVersion: 3
|
|
5504
|
+
time: 1
|
|
5505
|
+
value: 0
|
|
5506
|
+
inSlope: 0
|
|
5507
|
+
outSlope: 0
|
|
5508
|
+
tangentMode: 0
|
|
5509
|
+
weightedMode: 0
|
|
5510
|
+
inWeight: 0.33333334
|
|
5511
|
+
outWeight: 0.33333334
|
|
5512
|
+
m_PreInfinity: 2
|
|
5513
|
+
m_PostInfinity: 2
|
|
5514
|
+
m_RotationOrder: 4
|
|
5515
|
+
panLevelCustomCurve:
|
|
5516
|
+
serializedVersion: 2
|
|
5517
|
+
m_Curve:
|
|
5518
|
+
- serializedVersion: 3
|
|
5519
|
+
time: 0
|
|
5520
|
+
value: 0
|
|
5521
|
+
inSlope: 0
|
|
5522
|
+
outSlope: 0
|
|
5523
|
+
tangentMode: 0
|
|
5524
|
+
weightedMode: 0
|
|
5525
|
+
inWeight: 0.33333334
|
|
5526
|
+
outWeight: 0.33333334
|
|
5527
|
+
m_PreInfinity: 2
|
|
5528
|
+
m_PostInfinity: 2
|
|
5529
|
+
m_RotationOrder: 4
|
|
5530
|
+
spreadCustomCurve:
|
|
5531
|
+
serializedVersion: 2
|
|
5532
|
+
m_Curve:
|
|
5533
|
+
- serializedVersion: 3
|
|
5534
|
+
time: 0
|
|
5535
|
+
value: 0
|
|
5536
|
+
inSlope: 0
|
|
5537
|
+
outSlope: 0
|
|
5538
|
+
tangentMode: 0
|
|
5539
|
+
weightedMode: 0
|
|
5540
|
+
inWeight: 0.33333334
|
|
5541
|
+
outWeight: 0.33333334
|
|
5542
|
+
m_PreInfinity: 2
|
|
5543
|
+
m_PostInfinity: 2
|
|
5544
|
+
m_RotationOrder: 4
|
|
5545
|
+
reverbZoneMixCustomCurve:
|
|
5546
|
+
serializedVersion: 2
|
|
5547
|
+
m_Curve:
|
|
5548
|
+
- serializedVersion: 3
|
|
5549
|
+
time: 0
|
|
5550
|
+
value: 1
|
|
5551
|
+
inSlope: 0
|
|
5552
|
+
outSlope: 0
|
|
5553
|
+
tangentMode: 0
|
|
5554
|
+
weightedMode: 0
|
|
5555
|
+
inWeight: 0.33333334
|
|
5556
|
+
outWeight: 0.33333334
|
|
5557
|
+
m_PreInfinity: 2
|
|
5558
|
+
m_PostInfinity: 2
|
|
5559
|
+
m_RotationOrder: 4`
|
|
5560
|
+
};
|
|
5145
5561
|
var COMPONENT_DEFAULTS = {
|
|
5146
5562
|
20: ` serializedVersion: 2
|
|
5147
5563
|
m_ClearFlags: 1
|
|
@@ -5268,6 +5684,17 @@ var COMPONENT_DEFAULTS = {
|
|
|
5268
5684
|
m_IgnoreParentGroups: 0`
|
|
5269
5685
|
};
|
|
5270
5686
|
function createGenericComponentYAML(componentName, classId, componentId, gameObjectId) {
|
|
5687
|
+
const fullTemplate = COMPONENT_FULL_TEMPLATES[classId];
|
|
5688
|
+
if (fullTemplate) {
|
|
5689
|
+
return `--- !u!${classId} &${componentId}
|
|
5690
|
+
${componentName}:
|
|
5691
|
+
m_ObjectHideFlags: 0
|
|
5692
|
+
m_CorrespondingSourceObject: {fileID: 0}
|
|
5693
|
+
m_PrefabInstance: {fileID: 0}
|
|
5694
|
+
m_PrefabAsset: {fileID: 0}
|
|
5695
|
+
${fullTemplate(gameObjectId)}
|
|
5696
|
+
`;
|
|
5697
|
+
}
|
|
5271
5698
|
const defaults = COMPONENT_DEFAULTS[classId] ? `
|
|
5272
5699
|
` + COMPONENT_DEFAULTS[classId] + `
|
|
5273
5700
|
` : "";
|
|
@@ -5284,11 +5711,14 @@ ${defaults}`;
|
|
|
5284
5711
|
function addComponentToGameObject(doc, gameObjectId, componentId) {
|
|
5285
5712
|
const goBlock = doc.find_by_file_id(gameObjectId);
|
|
5286
5713
|
if (!goBlock)
|
|
5287
|
-
return;
|
|
5288
|
-
|
|
5289
|
-
|
|
5714
|
+
return false;
|
|
5715
|
+
const raw = goBlock.raw;
|
|
5716
|
+
const updated = raw.replace(/(m_Component:[ \t]*\n(?:[ \t]*-[ \t]*component:[ \t]*\{fileID:[ \t]*\d+\}[ \t]*\n)*)/, `$1 - component: {fileID: ${componentId}}
|
|
5290
5717
|
`);
|
|
5291
|
-
|
|
5718
|
+
if (updated === raw)
|
|
5719
|
+
return false;
|
|
5720
|
+
goBlock.replace_raw(updated);
|
|
5721
|
+
return true;
|
|
5292
5722
|
}
|
|
5293
5723
|
function createMonoBehaviourYAML(componentId, gameObjectId, scriptGuid, fields, version, scriptFileId = 11500000, type_lookup) {
|
|
5294
5724
|
const field_yaml = fields && fields.length > 0 ? generate_field_yaml(fields, version, " ", type_lookup) : `
|
|
@@ -5360,7 +5790,7 @@ function createGameObject(options) {
|
|
|
5360
5790
|
if (parentBlock.class_id === 4) {
|
|
5361
5791
|
parentTransformIdStr = parentIdStr;
|
|
5362
5792
|
} else if (parentBlock.class_id === 1) {
|
|
5363
|
-
const compMatch = parentBlock.raw.match(/m_Component
|
|
5793
|
+
const compMatch = parentBlock.raw.match(/m_Component:[ \t]*\n[ \t]*-[ \t]*component:[ \t]*\{fileID:[ \t]*(\d+)\}/);
|
|
5364
5794
|
if (compMatch) {
|
|
5365
5795
|
parentTransformIdStr = compMatch[1];
|
|
5366
5796
|
} else {
|
|
@@ -5417,7 +5847,14 @@ function createGameObject(options) {
|
|
|
5417
5847
|
doc.add_child_to_parent(parentTransformIdStr, transformIdStr);
|
|
5418
5848
|
}
|
|
5419
5849
|
if (variantPiId && strippedSourceRef) {
|
|
5420
|
-
appendToAddedGameObjects(doc, variantPiId, strippedSourceRef, gameObjectIdStr);
|
|
5850
|
+
const appendResult = appendToAddedGameObjects(doc, variantPiId, strippedSourceRef, gameObjectIdStr);
|
|
5851
|
+
if (!appendResult.success) {
|
|
5852
|
+
return {
|
|
5853
|
+
success: false,
|
|
5854
|
+
file_path,
|
|
5855
|
+
error: appendResult.error || `Failed to update m_AddedGameObjects for PrefabInstance ${variantPiId}`
|
|
5856
|
+
};
|
|
5857
|
+
}
|
|
5421
5858
|
}
|
|
5422
5859
|
const saveResult = doc.save();
|
|
5423
5860
|
if (!saveResult.success) {
|
|
@@ -5900,6 +6337,7 @@ PrefabInstance:
|
|
|
5900
6337
|
m_ObjectHideFlags: 0
|
|
5901
6338
|
serializedVersion: 2
|
|
5902
6339
|
m_Modification:
|
|
6340
|
+
serializedVersion: 3
|
|
5903
6341
|
m_TransformParent: {fileID: 0}
|
|
5904
6342
|
m_Modifications:
|
|
5905
6343
|
- target: {fileID: ${rootInfo.game_object.file_id}, guid: ${sourceGuid}, type: 3}
|
|
@@ -6004,7 +6442,7 @@ function createPrefabInstance(options) {
|
|
|
6004
6442
|
if (parentBlock.class_id === 4) {
|
|
6005
6443
|
parentTransformIdStr = parentIdStr;
|
|
6006
6444
|
} else if (parentBlock.class_id === 1) {
|
|
6007
|
-
const compMatch = parentBlock.raw.match(/m_Component
|
|
6445
|
+
const compMatch = parentBlock.raw.match(/m_Component:[ \t]*\n[ \t]*-[ \t]*component:[ \t]*\{fileID:[ \t]*(\d+)\}/);
|
|
6008
6446
|
if (compMatch) {
|
|
6009
6447
|
parentTransformIdStr = compMatch[1];
|
|
6010
6448
|
} else {
|
|
@@ -6046,6 +6484,7 @@ PrefabInstance:
|
|
|
6046
6484
|
m_ObjectHideFlags: 0
|
|
6047
6485
|
serializedVersion: 2
|
|
6048
6486
|
m_Modification:
|
|
6487
|
+
serializedVersion: 3
|
|
6049
6488
|
m_TransformParent: {fileID: ${parentTransformIdStr}}
|
|
6050
6489
|
m_Modifications:
|
|
6051
6490
|
- target: {fileID: ${rootGoFileId}, guid: ${sourceGuid}, type: 3}
|
|
@@ -6350,6 +6789,8 @@ function is_valid_component_base(base_class, project_path, depth = 0) {
|
|
|
6350
6789
|
}
|
|
6351
6790
|
if (!fullPath.endsWith(".cs") || !import_fs8.existsSync(fullPath)) {
|
|
6352
6791
|
if (match.kind === "class") {
|
|
6792
|
+
if (fullPath.includes("Assembly-CSharp.dll"))
|
|
6793
|
+
return true;
|
|
6353
6794
|
return is_likely_component_base_name(base_class);
|
|
6354
6795
|
}
|
|
6355
6796
|
}
|
|
@@ -6434,7 +6875,7 @@ function addComponent(options) {
|
|
|
6434
6875
|
let duplicateWarning;
|
|
6435
6876
|
const goBlock = doc.find_by_file_id(gameObjectIdStr);
|
|
6436
6877
|
if (goBlock && classId !== null) {
|
|
6437
|
-
const compRefs = [...goBlock.raw.matchAll(/component
|
|
6878
|
+
const compRefs = [...goBlock.raw.matchAll(/component:[ \t]*\{fileID:[ \t]*(\d+)\}/g)].map((m) => m[1]);
|
|
6438
6879
|
for (const refId of compRefs) {
|
|
6439
6880
|
const compBlock = doc.find_by_file_id(refId);
|
|
6440
6881
|
if (compBlock && compBlock.class_id === classId) {
|
|
@@ -6494,11 +6935,11 @@ function addComponent(options) {
|
|
|
6494
6935
|
};
|
|
6495
6936
|
}
|
|
6496
6937
|
if (resolved.base_class && !COMPONENT_BASE_CLASSES.has(resolved.base_class) && !is_valid_component_base(resolved.base_class, project_path)) {
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6938
|
+
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).`;
|
|
6939
|
+
if (!extractionError)
|
|
6940
|
+
extractionError = warn;
|
|
6941
|
+
else
|
|
6942
|
+
extractionError += " " + warn;
|
|
6502
6943
|
}
|
|
6503
6944
|
let version;
|
|
6504
6945
|
if (project_path) {
|
|
@@ -6514,14 +6955,50 @@ function addComponent(options) {
|
|
|
6514
6955
|
componentYAML = createMonoBehaviourYAML(componentId, gameObjectId, resolved.guid, resolved.fields, version, scriptFileId, type_lookup_comp);
|
|
6515
6956
|
scriptGuid = resolved.guid;
|
|
6516
6957
|
scriptPath = resolved.path || undefined;
|
|
6517
|
-
|
|
6958
|
+
if (resolved.extraction_error) {
|
|
6959
|
+
if (!extractionError)
|
|
6960
|
+
extractionError = resolved.extraction_error;
|
|
6961
|
+
else
|
|
6962
|
+
extractionError += " " + resolved.extraction_error;
|
|
6963
|
+
}
|
|
6518
6964
|
}
|
|
6519
6965
|
if (variantInfo) {
|
|
6520
|
-
appendToAddedComponents(doc, variantInfo.prefab_instance_id, variantInfo.source_ref, componentIdStr);
|
|
6966
|
+
const appendResult = appendToAddedComponents(doc, variantInfo.prefab_instance_id, variantInfo.source_ref, componentIdStr);
|
|
6967
|
+
if (!appendResult.success) {
|
|
6968
|
+
return {
|
|
6969
|
+
success: false,
|
|
6970
|
+
file_path,
|
|
6971
|
+
error: appendResult.error || `Failed to update m_AddedComponents for PrefabInstance ${variantInfo.prefab_instance_id}`
|
|
6972
|
+
};
|
|
6973
|
+
}
|
|
6521
6974
|
} else {
|
|
6522
|
-
addComponentToGameObject(doc, gameObjectIdStr, componentIdStr);
|
|
6975
|
+
const added = addComponentToGameObject(doc, gameObjectIdStr, componentIdStr);
|
|
6976
|
+
if (!added) {
|
|
6977
|
+
return {
|
|
6978
|
+
success: false,
|
|
6979
|
+
file_path,
|
|
6980
|
+
error: `Failed to add component reference to GameObject ${gameObjectIdStr}: m_Component array not found or malformed`
|
|
6981
|
+
};
|
|
6982
|
+
}
|
|
6523
6983
|
}
|
|
6524
6984
|
doc.append_raw(componentYAML);
|
|
6985
|
+
if (!doc.validate()) {
|
|
6986
|
+
return {
|
|
6987
|
+
success: false,
|
|
6988
|
+
file_path,
|
|
6989
|
+
error: "Validation failed after adding component. The generated YAML may be malformed."
|
|
6990
|
+
};
|
|
6991
|
+
}
|
|
6992
|
+
if (!variantInfo) {
|
|
6993
|
+
const goBlockAfter = doc.find_by_file_id(gameObjectIdStr);
|
|
6994
|
+
if (!goBlockAfter || !goBlockAfter.raw.includes(`component: {fileID: ${componentIdStr}}`)) {
|
|
6995
|
+
return {
|
|
6996
|
+
success: false,
|
|
6997
|
+
file_path,
|
|
6998
|
+
error: `Component block appended but reference not found in GameObject ${gameObjectIdStr}'s m_Component list`
|
|
6999
|
+
};
|
|
7000
|
+
}
|
|
7001
|
+
}
|
|
6525
7002
|
const saveResult = doc.save();
|
|
6526
7003
|
if (!saveResult.success) {
|
|
6527
7004
|
return {
|
|
@@ -6577,8 +7054,11 @@ function copyComponent(options) {
|
|
|
6577
7054
|
const newIdStr = doc.generate_file_id();
|
|
6578
7055
|
const newId = parseInt(newIdStr, 10);
|
|
6579
7056
|
let clonedBlock = sourceBlock.raw.replace(new RegExp(`^(--- !u!${sourceBlock.class_id} &)${source_file_id}`), `$1${newId}`);
|
|
6580
|
-
clonedBlock = clonedBlock.replace(/m_GameObject
|
|
6581
|
-
addComponentToGameObject(doc, targetGoIdStr, newIdStr);
|
|
7057
|
+
clonedBlock = clonedBlock.replace(/m_GameObject:[ \t]*\{fileID:[ \t]*\d+\}/, `m_GameObject: {fileID: ${targetGoId}}`);
|
|
7058
|
+
const added = addComponentToGameObject(doc, targetGoIdStr, newIdStr);
|
|
7059
|
+
if (!added) {
|
|
7060
|
+
return { success: false, file_path, error: `Failed to wire component to target GameObject ${targetGoIdStr}: m_Component array not found or malformed` };
|
|
7061
|
+
}
|
|
6582
7062
|
doc.append_raw(clonedBlock);
|
|
6583
7063
|
if (!doc.validate()) {
|
|
6584
7064
|
return { success: false, file_path, error: "Validation failed after copying component" };
|
|
@@ -7235,7 +7715,17 @@ function validate_value_type(current_value, new_value) {
|
|
|
7235
7715
|
const incoming = new_value.trim();
|
|
7236
7716
|
if (/^\{fileID:/.test(current)) {
|
|
7237
7717
|
if (/^\{fileID:[ \t]*0[ \t]*\}$/.test(current)) {
|
|
7238
|
-
|
|
7718
|
+
if (/^\{fileID:/.test(incoming))
|
|
7719
|
+
return null;
|
|
7720
|
+
if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(incoming))
|
|
7721
|
+
return null;
|
|
7722
|
+
if (/^(true|false|yes|no|on|off)$/i.test(incoming))
|
|
7723
|
+
return null;
|
|
7724
|
+
if (/^'[^']*'$/.test(incoming) || /^"[^"]*"$/.test(incoming))
|
|
7725
|
+
return null;
|
|
7726
|
+
if (/^\{.*:.*\}$/.test(incoming))
|
|
7727
|
+
return null;
|
|
7728
|
+
return `Current value is a null reference ({fileID: 0}). New value "${incoming}" is not a valid reference, number, boolean, quoted string, or compound value.`;
|
|
7239
7729
|
}
|
|
7240
7730
|
if (!/^\{fileID:/.test(incoming)) {
|
|
7241
7731
|
return `Expected a reference value ({fileID: ...}), got "${incoming}"`;
|
|
@@ -7445,7 +7935,19 @@ function editProperty(options) {
|
|
|
7445
7935
|
return result;
|
|
7446
7936
|
}
|
|
7447
7937
|
function editComponentByFileId(options) {
|
|
7448
|
-
const { file_path, file_id, property,
|
|
7938
|
+
const { file_path, file_id, property, project_path } = options;
|
|
7939
|
+
let { new_value } = options;
|
|
7940
|
+
const resolved = resolveAssetPathToPPtr(new_value, file_path, project_path);
|
|
7941
|
+
if (resolved === null) {
|
|
7942
|
+
return {
|
|
7943
|
+
success: false,
|
|
7944
|
+
file_path,
|
|
7945
|
+
error: `Could not resolve "${new_value}" to asset reference. Ensure GUID cache exists (run "setup" first, or "setup -p <path>").`
|
|
7946
|
+
};
|
|
7947
|
+
}
|
|
7948
|
+
if (resolved !== undefined) {
|
|
7949
|
+
new_value = resolved;
|
|
7950
|
+
}
|
|
7449
7951
|
const pathError = validate_file_path(file_path, "write");
|
|
7450
7952
|
if (pathError) {
|
|
7451
7953
|
return { success: false, file_path, error: pathError };
|
|
@@ -8017,6 +8519,193 @@ function findPrefabInstanceBlock(doc, identifier) {
|
|
|
8017
8519
|
}
|
|
8018
8520
|
return null;
|
|
8019
8521
|
}
|
|
8522
|
+
function parsePrefabRef2(refText) {
|
|
8523
|
+
const fileIdMatch = refText.match(/fileID:[ \t]*(-?\d+)/i);
|
|
8524
|
+
if (!fileIdMatch)
|
|
8525
|
+
return null;
|
|
8526
|
+
const guidMatch = refText.match(/guid:[ \t]*([a-f0-9]{32})/i);
|
|
8527
|
+
const typeMatch = refText.match(/type:[ \t]*(-?\d+)/i);
|
|
8528
|
+
return {
|
|
8529
|
+
file_id: fileIdMatch[1],
|
|
8530
|
+
guid: guidMatch ? guidMatch[1].toLowerCase() : undefined,
|
|
8531
|
+
type: typeMatch ? typeMatch[1] : undefined
|
|
8532
|
+
};
|
|
8533
|
+
}
|
|
8534
|
+
function extractPrefabSourceGuid2(prefabInstanceRaw) {
|
|
8535
|
+
const sourceMatch = prefabInstanceRaw.match(/m_SourcePrefab:[ \t]*\{[^}]*guid:[ \t]*([a-f0-9]{32})/i);
|
|
8536
|
+
return sourceMatch ? sourceMatch[1].toLowerCase() : null;
|
|
8537
|
+
}
|
|
8538
|
+
function normalizePrefabRef2(refText, sourceGuid) {
|
|
8539
|
+
const parsed = parsePrefabRef2(refText);
|
|
8540
|
+
if (!parsed) {
|
|
8541
|
+
return { error: `Invalid reference "${refText}". Expected format: {fileID: N, guid: ..., type: T}` };
|
|
8542
|
+
}
|
|
8543
|
+
const guid = parsed.guid ?? sourceGuid;
|
|
8544
|
+
if (!guid) {
|
|
8545
|
+
return { error: `Reference "${refText}" is missing guid and source prefab guid could not be inferred.` };
|
|
8546
|
+
}
|
|
8547
|
+
if (!/^[a-f0-9]{32}$/i.test(guid)) {
|
|
8548
|
+
return { error: `Invalid guid in reference "${refText}". Expected 32-character hex GUID.` };
|
|
8549
|
+
}
|
|
8550
|
+
const type = parsed.type ?? "3";
|
|
8551
|
+
if (!/^-?\d+$/.test(type)) {
|
|
8552
|
+
return { error: `Invalid type in reference "${refText}". Expected an integer type value.` };
|
|
8553
|
+
}
|
|
8554
|
+
return {
|
|
8555
|
+
ref: {
|
|
8556
|
+
file_id: parsed.file_id,
|
|
8557
|
+
guid,
|
|
8558
|
+
type
|
|
8559
|
+
}
|
|
8560
|
+
};
|
|
8561
|
+
}
|
|
8562
|
+
function parsePrefabRefMatcher(refText) {
|
|
8563
|
+
const parsed = parsePrefabRef2(refText);
|
|
8564
|
+
if (!parsed) {
|
|
8565
|
+
return { error: `Invalid reference "${refText}". Expected format: {fileID: N, guid: ..., type: T}` };
|
|
8566
|
+
}
|
|
8567
|
+
if (parsed.guid && !/^[a-f0-9]{32}$/i.test(parsed.guid)) {
|
|
8568
|
+
return { error: `Invalid guid in reference "${refText}". Expected 32-character hex GUID.` };
|
|
8569
|
+
}
|
|
8570
|
+
if (parsed.type && !/^-?\d+$/.test(parsed.type)) {
|
|
8571
|
+
return { error: `Invalid type in reference "${refText}". Expected an integer type value.` };
|
|
8572
|
+
}
|
|
8573
|
+
return { matcher: parsed };
|
|
8574
|
+
}
|
|
8575
|
+
function prefabRefKey(ref) {
|
|
8576
|
+
return `${ref.file_id}|${ref.guid}|${ref.type}`;
|
|
8577
|
+
}
|
|
8578
|
+
function serializePrefabRef2(ref) {
|
|
8579
|
+
return `{fileID: ${ref.file_id}, guid: ${ref.guid}, type: ${ref.type}}`;
|
|
8580
|
+
}
|
|
8581
|
+
function splitPrefabArraySection2(rawText, key) {
|
|
8582
|
+
const lines = rawText.split(`
|
|
8583
|
+
`);
|
|
8584
|
+
const keyPattern = new RegExp(`^([ ]*)${key}:[ ]*(.*)$`);
|
|
8585
|
+
let keyIndex = -1;
|
|
8586
|
+
let indent = "";
|
|
8587
|
+
for (let i = 0;i < lines.length; i++) {
|
|
8588
|
+
const match = lines[i].match(keyPattern);
|
|
8589
|
+
if (match) {
|
|
8590
|
+
keyIndex = i;
|
|
8591
|
+
indent = match[1];
|
|
8592
|
+
break;
|
|
8593
|
+
}
|
|
8594
|
+
}
|
|
8595
|
+
if (keyIndex === -1) {
|
|
8596
|
+
return null;
|
|
8597
|
+
}
|
|
8598
|
+
const keyIndentLen = indent.length;
|
|
8599
|
+
let sectionEnd = keyIndex + 1;
|
|
8600
|
+
for (let i = keyIndex + 1;i < lines.length; i++) {
|
|
8601
|
+
const line = lines[i];
|
|
8602
|
+
const trimmed = line.trim();
|
|
8603
|
+
if (trimmed.length === 0) {
|
|
8604
|
+
sectionEnd = i + 1;
|
|
8605
|
+
continue;
|
|
8606
|
+
}
|
|
8607
|
+
const indentLen = (line.match(/^[ \t]*/) || [""])[0].length;
|
|
8608
|
+
if (indentLen < keyIndentLen) {
|
|
8609
|
+
break;
|
|
8610
|
+
}
|
|
8611
|
+
if (indentLen === keyIndentLen && !trimmed.startsWith("-") && /^[A-Za-z_][A-Za-z0-9_]*:/.test(trimmed)) {
|
|
8612
|
+
break;
|
|
8613
|
+
}
|
|
8614
|
+
sectionEnd = i + 1;
|
|
8615
|
+
}
|
|
8616
|
+
return {
|
|
8617
|
+
lines,
|
|
8618
|
+
key_index: keyIndex,
|
|
8619
|
+
section_end: sectionEnd,
|
|
8620
|
+
indent
|
|
8621
|
+
};
|
|
8622
|
+
}
|
|
8623
|
+
function collectNormalizedRefsFromSection(lines, key_index, section_end, sourceGuid) {
|
|
8624
|
+
const sectionText = lines.slice(key_index, section_end).join(`
|
|
8625
|
+
`);
|
|
8626
|
+
const refMatches = sectionText.match(/\{[^}]*\}/g) || [];
|
|
8627
|
+
const dedup = new Map;
|
|
8628
|
+
for (const token of refMatches) {
|
|
8629
|
+
const parsed = parsePrefabRef2(token);
|
|
8630
|
+
if (!parsed)
|
|
8631
|
+
continue;
|
|
8632
|
+
const guid = parsed.guid ?? sourceGuid;
|
|
8633
|
+
if (!guid || !/^[a-f0-9]{32}$/i.test(guid))
|
|
8634
|
+
continue;
|
|
8635
|
+
const type = parsed.type ?? "3";
|
|
8636
|
+
if (!/^-?\d+$/.test(type))
|
|
8637
|
+
continue;
|
|
8638
|
+
const normalized = {
|
|
8639
|
+
file_id: parsed.file_id,
|
|
8640
|
+
guid: guid.toLowerCase(),
|
|
8641
|
+
type
|
|
8642
|
+
};
|
|
8643
|
+
const key = prefabRefKey(normalized);
|
|
8644
|
+
if (!dedup.has(key)) {
|
|
8645
|
+
dedup.set(key, normalized);
|
|
8646
|
+
}
|
|
8647
|
+
}
|
|
8648
|
+
return [...dedup.values()];
|
|
8649
|
+
}
|
|
8650
|
+
function mutatePrefabReferenceList(options) {
|
|
8651
|
+
const { target_block, key, ref_text, action, item_label } = options;
|
|
8652
|
+
const split = splitPrefabArraySection2(target_block.raw, key);
|
|
8653
|
+
if (!split) {
|
|
8654
|
+
return { success: false, error: `${key} property not found in PrefabInstance` };
|
|
8655
|
+
}
|
|
8656
|
+
const sourceGuid = extractPrefabSourceGuid2(target_block.raw);
|
|
8657
|
+
const existing = collectNormalizedRefsFromSection(split.lines, split.key_index, split.section_end, sourceGuid);
|
|
8658
|
+
let next = existing;
|
|
8659
|
+
if (action === "add") {
|
|
8660
|
+
const normalized = normalizePrefabRef2(ref_text, sourceGuid);
|
|
8661
|
+
if (!normalized.ref) {
|
|
8662
|
+
return { success: false, error: normalized.error };
|
|
8663
|
+
}
|
|
8664
|
+
const keyText = prefabRefKey(normalized.ref);
|
|
8665
|
+
if (existing.some((entry) => prefabRefKey(entry) === keyText)) {
|
|
8666
|
+
return { success: true, changed: false };
|
|
8667
|
+
}
|
|
8668
|
+
next = [...existing, normalized.ref];
|
|
8669
|
+
} else {
|
|
8670
|
+
const matcherResult = parsePrefabRefMatcher(ref_text);
|
|
8671
|
+
const matcher = matcherResult.matcher;
|
|
8672
|
+
if (!matcher) {
|
|
8673
|
+
return { success: false, error: matcherResult.error };
|
|
8674
|
+
}
|
|
8675
|
+
next = existing.filter((entry) => {
|
|
8676
|
+
if (entry.file_id !== matcher.file_id)
|
|
8677
|
+
return true;
|
|
8678
|
+
if (matcher.guid && entry.guid !== matcher.guid.toLowerCase())
|
|
8679
|
+
return true;
|
|
8680
|
+
if (matcher.type && entry.type !== matcher.type)
|
|
8681
|
+
return true;
|
|
8682
|
+
return false;
|
|
8683
|
+
});
|
|
8684
|
+
if (next.length === existing.length) {
|
|
8685
|
+
return {
|
|
8686
|
+
success: false,
|
|
8687
|
+
error: `${item_label} reference "${ref_text}" not found in ${key}`
|
|
8688
|
+
};
|
|
8689
|
+
}
|
|
8690
|
+
}
|
|
8691
|
+
const replacement = [];
|
|
8692
|
+
if (next.length === 0) {
|
|
8693
|
+
replacement.push(`${split.indent}${key}: []`);
|
|
8694
|
+
} else {
|
|
8695
|
+
replacement.push(`${split.indent}${key}:`);
|
|
8696
|
+
for (const entry of next) {
|
|
8697
|
+
replacement.push(`${split.indent}- ${serializePrefabRef2(entry)}`);
|
|
8698
|
+
}
|
|
8699
|
+
}
|
|
8700
|
+
const updatedLines = [
|
|
8701
|
+
...split.lines.slice(0, split.key_index),
|
|
8702
|
+
...replacement,
|
|
8703
|
+
...split.lines.slice(split.section_end)
|
|
8704
|
+
];
|
|
8705
|
+
target_block.replace_raw(updatedLines.join(`
|
|
8706
|
+
`));
|
|
8707
|
+
return { success: true, changed: true };
|
|
8708
|
+
}
|
|
8020
8709
|
function editArray(options) {
|
|
8021
8710
|
const { file_path, file_id, array_property, action, value, index } = options;
|
|
8022
8711
|
if (!import_fs10.existsSync(file_path)) {
|
|
@@ -8227,9 +8916,6 @@ function addRemovedComponent(options) {
|
|
|
8227
8916
|
if (!import_fs10.existsSync(file_path)) {
|
|
8228
8917
|
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
8229
8918
|
}
|
|
8230
|
-
if (!/^\{fileID:\s*-?\d+/.test(component_ref)) {
|
|
8231
|
-
return { success: false, file_path, error: `Invalid component reference "${component_ref}". Expected format: {fileID: N, guid: ..., type: T}` };
|
|
8232
|
-
}
|
|
8233
8919
|
let doc;
|
|
8234
8920
|
try {
|
|
8235
8921
|
doc = UnityDocument.from_file(file_path);
|
|
@@ -8240,19 +8926,16 @@ function addRemovedComponent(options) {
|
|
|
8240
8926
|
if (!targetBlock) {
|
|
8241
8927
|
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
8242
8928
|
}
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
} else {
|
|
8253
|
-
return { success: false, file_path, error: "m_RemovedComponents property not found in PrefabInstance" };
|
|
8929
|
+
const mutation = mutatePrefabReferenceList({
|
|
8930
|
+
target_block: targetBlock,
|
|
8931
|
+
key: "m_RemovedComponents",
|
|
8932
|
+
ref_text: component_ref,
|
|
8933
|
+
action: "add",
|
|
8934
|
+
item_label: "Component"
|
|
8935
|
+
});
|
|
8936
|
+
if (!mutation.success) {
|
|
8937
|
+
return { success: false, file_path, error: mutation.error };
|
|
8254
8938
|
}
|
|
8255
|
-
targetBlock.replace_raw(rawText);
|
|
8256
8939
|
if (!doc.validate()) {
|
|
8257
8940
|
return { success: false, file_path, error: "Validation failed after adding removed component" };
|
|
8258
8941
|
}
|
|
@@ -8281,13 +8964,16 @@ function removeRemovedComponent(options) {
|
|
|
8281
8964
|
if (!targetBlock) {
|
|
8282
8965
|
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
8283
8966
|
}
|
|
8284
|
-
const
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8967
|
+
const mutation = mutatePrefabReferenceList({
|
|
8968
|
+
target_block: targetBlock,
|
|
8969
|
+
key: "m_RemovedComponents",
|
|
8970
|
+
ref_text: component_ref,
|
|
8971
|
+
action: "remove",
|
|
8972
|
+
item_label: "Component"
|
|
8973
|
+
});
|
|
8974
|
+
if (!mutation.success) {
|
|
8975
|
+
return { success: false, file_path, error: mutation.error };
|
|
8288
8976
|
}
|
|
8289
|
-
const updatedRaw = targetBlock.raw.replace(refPattern, "");
|
|
8290
|
-
targetBlock.replace_raw(updatedRaw);
|
|
8291
8977
|
if (!doc.validate()) {
|
|
8292
8978
|
return { success: false, file_path, error: "Validation failed after removing component" };
|
|
8293
8979
|
}
|
|
@@ -8306,9 +8992,6 @@ function addRemovedGameObject(options) {
|
|
|
8306
8992
|
if (!import_fs10.existsSync(file_path)) {
|
|
8307
8993
|
return { success: false, file_path, error: `File not found: ${file_path}` };
|
|
8308
8994
|
}
|
|
8309
|
-
if (!/^\{fileID:\s*-?\d+/.test(component_ref)) {
|
|
8310
|
-
return { success: false, file_path, error: `Invalid GameObject reference "${component_ref}". Expected format: {fileID: N, guid: ..., type: T}` };
|
|
8311
|
-
}
|
|
8312
8995
|
let doc;
|
|
8313
8996
|
try {
|
|
8314
8997
|
doc = UnityDocument.from_file(file_path);
|
|
@@ -8319,19 +9002,16 @@ function addRemovedGameObject(options) {
|
|
|
8319
9002
|
if (!targetBlock) {
|
|
8320
9003
|
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
8321
9004
|
}
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
} else {
|
|
8332
|
-
return { success: false, file_path, error: "m_RemovedGameObjects property not found in PrefabInstance" };
|
|
9005
|
+
const mutation = mutatePrefabReferenceList({
|
|
9006
|
+
target_block: targetBlock,
|
|
9007
|
+
key: "m_RemovedGameObjects",
|
|
9008
|
+
ref_text: component_ref,
|
|
9009
|
+
action: "add",
|
|
9010
|
+
item_label: "GameObject"
|
|
9011
|
+
});
|
|
9012
|
+
if (!mutation.success) {
|
|
9013
|
+
return { success: false, file_path, error: mutation.error };
|
|
8333
9014
|
}
|
|
8334
|
-
targetBlock.replace_raw(rawText);
|
|
8335
9015
|
if (!doc.validate()) {
|
|
8336
9016
|
return { success: false, file_path, error: "Validation failed after adding removed GameObject" };
|
|
8337
9017
|
}
|
|
@@ -8360,13 +9040,16 @@ function removeRemovedGameObject(options) {
|
|
|
8360
9040
|
if (!targetBlock) {
|
|
8361
9041
|
return { success: false, file_path, error: `PrefabInstance "${prefab_instance}" not found` };
|
|
8362
9042
|
}
|
|
8363
|
-
const
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
9043
|
+
const mutation = mutatePrefabReferenceList({
|
|
9044
|
+
target_block: targetBlock,
|
|
9045
|
+
key: "m_RemovedGameObjects",
|
|
9046
|
+
ref_text: component_ref,
|
|
9047
|
+
action: "remove",
|
|
9048
|
+
item_label: "GameObject"
|
|
9049
|
+
});
|
|
9050
|
+
if (!mutation.success) {
|
|
9051
|
+
return { success: false, file_path, error: mutation.error };
|
|
8367
9052
|
}
|
|
8368
|
-
const updatedRaw = targetBlock.raw.replace(refPattern, "");
|
|
8369
|
-
targetBlock.replace_raw(updatedRaw);
|
|
8370
9053
|
if (!doc.validate()) {
|
|
8371
9054
|
return { success: false, file_path, error: "Validation failed after removing GameObject" };
|
|
8372
9055
|
}
|
|
@@ -8853,6 +9536,7 @@ function search_project(options) {
|
|
|
8853
9536
|
const files = walk_project_files(project_path, extensions);
|
|
8854
9537
|
const scanner = new UnityScanner;
|
|
8855
9538
|
const matches = [];
|
|
9539
|
+
let files_with_errors = 0;
|
|
8856
9540
|
for (const file of files) {
|
|
8857
9541
|
try {
|
|
8858
9542
|
let gameObjects;
|
|
@@ -8939,6 +9623,7 @@ function search_project(options) {
|
|
|
8939
9623
|
if (max_matches !== undefined && matches.length >= max_matches)
|
|
8940
9624
|
break;
|
|
8941
9625
|
} catch {
|
|
9626
|
+
files_with_errors++;
|
|
8942
9627
|
continue;
|
|
8943
9628
|
}
|
|
8944
9629
|
}
|
|
@@ -8947,6 +9632,7 @@ function search_project(options) {
|
|
|
8947
9632
|
project_path,
|
|
8948
9633
|
total_files_scanned: files.length,
|
|
8949
9634
|
total_matches: matches.length,
|
|
9635
|
+
files_with_errors: files_with_errors > 0 ? files_with_errors : undefined,
|
|
8950
9636
|
cursor: 0,
|
|
8951
9637
|
truncated: max_matches !== undefined && matches.length >= max_matches,
|
|
8952
9638
|
matches
|
|
@@ -9220,7 +9906,8 @@ function removeComponent(options) {
|
|
|
9220
9906
|
return { success: false, file_path, error: "Cannot remove a Transform with remove-component. Use delete to remove the entire GameObject." };
|
|
9221
9907
|
}
|
|
9222
9908
|
const resolved_file_id = found.file_id;
|
|
9223
|
-
|
|
9909
|
+
let removed_added_component_overrides = 0;
|
|
9910
|
+
const goMatch = found.raw.match(/m_GameObject:[ \t]*\{fileID:[ \t]*(-?\d+)\}/);
|
|
9224
9911
|
if (goMatch) {
|
|
9225
9912
|
const parentGoId = goMatch[1];
|
|
9226
9913
|
const goBlock = doc.find_by_file_id(parentGoId);
|
|
@@ -9228,7 +9915,29 @@ function removeComponent(options) {
|
|
|
9228
9915
|
const escaped = resolved_file_id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9229
9916
|
const compLinePattern = new RegExp(`^[ \\t]*- component: \\{fileID: ${escaped}\\}[ \\t]*\\n`, "m");
|
|
9230
9917
|
const modifiedRaw = goBlock.raw.replace(compLinePattern, "");
|
|
9918
|
+
if (modifiedRaw === goBlock.raw) {}
|
|
9231
9919
|
goBlock.replace_raw(modifiedRaw);
|
|
9920
|
+
if (goBlock.is_stripped) {
|
|
9921
|
+
const piMatch = goBlock.raw.match(/m_PrefabInstance:[ \t]*\{fileID:[ \t]*(-?\d+)\}/);
|
|
9922
|
+
if (piMatch) {
|
|
9923
|
+
const piBlock = doc.find_by_file_id(piMatch[1]);
|
|
9924
|
+
if (piBlock && piBlock.class_id === 1001) {
|
|
9925
|
+
const updated = removeAddedComponentOverrideEntries(piBlock.raw, resolved_file_id);
|
|
9926
|
+
if (updated.removed_count > 0) {
|
|
9927
|
+
piBlock.replace_raw(updated.updated_raw);
|
|
9928
|
+
removed_added_component_overrides += updated.removed_count;
|
|
9929
|
+
}
|
|
9930
|
+
}
|
|
9931
|
+
}
|
|
9932
|
+
}
|
|
9933
|
+
}
|
|
9934
|
+
}
|
|
9935
|
+
const dangling = [];
|
|
9936
|
+
for (const block of doc.blocks) {
|
|
9937
|
+
if (block.file_id === resolved_file_id)
|
|
9938
|
+
continue;
|
|
9939
|
+
if (block.raw.includes(`{fileID: ${resolved_file_id}}`)) {
|
|
9940
|
+
dangling.push(block.file_id);
|
|
9232
9941
|
}
|
|
9233
9942
|
}
|
|
9234
9943
|
doc.remove_block(resolved_file_id);
|
|
@@ -9243,7 +9952,8 @@ function removeComponent(options) {
|
|
|
9243
9952
|
success: true,
|
|
9244
9953
|
file_path,
|
|
9245
9954
|
removed_file_id: resolved_file_id,
|
|
9246
|
-
removed_class_id: found.class_id
|
|
9955
|
+
removed_class_id: found.class_id,
|
|
9956
|
+
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
|
|
9247
9957
|
};
|
|
9248
9958
|
}
|
|
9249
9959
|
function removeComponentBatch(options) {
|
|
@@ -9304,7 +10014,7 @@ function deleteGameObject(options) {
|
|
|
9304
10014
|
const goBlock = goResult;
|
|
9305
10015
|
const goId = goBlock.file_id;
|
|
9306
10016
|
const componentIds = new Set;
|
|
9307
|
-
const compMatches = goBlock.raw.matchAll(/component
|
|
10017
|
+
const compMatches = goBlock.raw.matchAll(/component:[ \t]*\{fileID:[ \t]*(-?\d+)\}/g);
|
|
9308
10018
|
for (const cm of compMatches) {
|
|
9309
10019
|
componentIds.add(cm[1]);
|
|
9310
10020
|
}
|
|
@@ -9314,7 +10024,7 @@ function deleteGameObject(options) {
|
|
|
9314
10024
|
const block = doc.find_by_file_id(compId);
|
|
9315
10025
|
if (block && block.class_id === 4) {
|
|
9316
10026
|
transformId = compId;
|
|
9317
|
-
const fatherMatch = block.raw.match(/m_Father
|
|
10027
|
+
const fatherMatch = block.raw.match(/m_Father:[ \t]*\{fileID:[ \t]*(-?\d+)\}/);
|
|
9318
10028
|
if (fatherMatch) {
|
|
9319
10029
|
fatherId = fatherMatch[1];
|
|
9320
10030
|
}
|
|
@@ -9361,6 +10071,124 @@ function findPrefabInstanceBlock2(doc, identifier) {
|
|
|
9361
10071
|
}
|
|
9362
10072
|
return null;
|
|
9363
10073
|
}
|
|
10074
|
+
function splitPrefabArraySection3(rawText, key) {
|
|
10075
|
+
const lines = rawText.split(`
|
|
10076
|
+
`);
|
|
10077
|
+
const keyPattern = new RegExp(`^[ ]*${key}:[ ]*(.*)$`);
|
|
10078
|
+
let keyIndex = -1;
|
|
10079
|
+
let keyIndentLen = 0;
|
|
10080
|
+
for (let i = 0;i < lines.length; i++) {
|
|
10081
|
+
const match = lines[i].match(keyPattern);
|
|
10082
|
+
if (match) {
|
|
10083
|
+
keyIndex = i;
|
|
10084
|
+
keyIndentLen = (lines[i].match(/^[ \t]*/) || [""])[0].length;
|
|
10085
|
+
break;
|
|
10086
|
+
}
|
|
10087
|
+
}
|
|
10088
|
+
if (keyIndex === -1) {
|
|
10089
|
+
return null;
|
|
10090
|
+
}
|
|
10091
|
+
let sectionEnd = keyIndex + 1;
|
|
10092
|
+
for (let i = keyIndex + 1;i < lines.length; i++) {
|
|
10093
|
+
const line = lines[i];
|
|
10094
|
+
const trimmed = line.trim();
|
|
10095
|
+
if (trimmed.length === 0) {
|
|
10096
|
+
sectionEnd = i + 1;
|
|
10097
|
+
continue;
|
|
10098
|
+
}
|
|
10099
|
+
const indentLen = (line.match(/^[ \t]*/) || [""])[0].length;
|
|
10100
|
+
if (indentLen < keyIndentLen) {
|
|
10101
|
+
break;
|
|
10102
|
+
}
|
|
10103
|
+
if (indentLen === keyIndentLen && !trimmed.startsWith("-") && /^[A-Za-z_][A-Za-z0-9_]*:/.test(trimmed)) {
|
|
10104
|
+
break;
|
|
10105
|
+
}
|
|
10106
|
+
sectionEnd = i + 1;
|
|
10107
|
+
}
|
|
10108
|
+
return {
|
|
10109
|
+
lines,
|
|
10110
|
+
key_index: keyIndex,
|
|
10111
|
+
section_end: sectionEnd
|
|
10112
|
+
};
|
|
10113
|
+
}
|
|
10114
|
+
function collectAddedObjectFileIdsFromArray(rawText, key) {
|
|
10115
|
+
const section = splitPrefabArraySection3(rawText, key);
|
|
10116
|
+
if (!section)
|
|
10117
|
+
return [];
|
|
10118
|
+
const keyLine = section.lines[section.key_index].trim();
|
|
10119
|
+
if (new RegExp(`^${key}:[ ]*[]$`).test(keyLine)) {
|
|
10120
|
+
return [];
|
|
10121
|
+
}
|
|
10122
|
+
const sectionText = section.lines.slice(section.key_index, section.section_end).join(`
|
|
10123
|
+
`);
|
|
10124
|
+
const fileIds = new Set;
|
|
10125
|
+
const addedObjectPattern = /addedObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)/g;
|
|
10126
|
+
let match;
|
|
10127
|
+
while ((match = addedObjectPattern.exec(sectionText)) !== null) {
|
|
10128
|
+
fileIds.add(match[1]);
|
|
10129
|
+
}
|
|
10130
|
+
if (fileIds.size === 0) {
|
|
10131
|
+
const inlineEntryPattern = /^[ \t]*-[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)/gm;
|
|
10132
|
+
while ((match = inlineEntryPattern.exec(sectionText)) !== null) {
|
|
10133
|
+
fileIds.add(match[1]);
|
|
10134
|
+
}
|
|
10135
|
+
}
|
|
10136
|
+
return [...fileIds];
|
|
10137
|
+
}
|
|
10138
|
+
function removeAddedComponentOverrideEntries(rawText, componentId) {
|
|
10139
|
+
const section = splitPrefabArraySection3(rawText, "m_AddedComponents");
|
|
10140
|
+
if (!section)
|
|
10141
|
+
return { updated_raw: rawText, removed_count: 0 };
|
|
10142
|
+
const keyLine = section.lines[section.key_index].trim();
|
|
10143
|
+
if (/^m_AddedComponents:[ \t]*\[\]$/.test(keyLine)) {
|
|
10144
|
+
return { updated_raw: rawText, removed_count: 0 };
|
|
10145
|
+
}
|
|
10146
|
+
const bodyLines = section.lines.slice(section.key_index + 1, section.section_end);
|
|
10147
|
+
const keptEntries = [];
|
|
10148
|
+
let removed = 0;
|
|
10149
|
+
let i = 0;
|
|
10150
|
+
while (i < bodyLines.length) {
|
|
10151
|
+
const line = bodyLines[i];
|
|
10152
|
+
const trimmed = line.trimStart();
|
|
10153
|
+
if (!trimmed.startsWith("-")) {
|
|
10154
|
+
i++;
|
|
10155
|
+
continue;
|
|
10156
|
+
}
|
|
10157
|
+
const entryIndent = (line.match(/^[ \t]*/) || [""])[0].length;
|
|
10158
|
+
const entryLines = [line];
|
|
10159
|
+
i++;
|
|
10160
|
+
while (i < bodyLines.length) {
|
|
10161
|
+
const nextLine = bodyLines[i];
|
|
10162
|
+
const nextTrimmed = nextLine.trim();
|
|
10163
|
+
const nextIndent = (nextLine.match(/^[ \t]*/) || [""])[0].length;
|
|
10164
|
+
if (nextTrimmed.length > 0 && nextIndent === entryIndent && nextTrimmed.startsWith("-")) {
|
|
10165
|
+
break;
|
|
10166
|
+
}
|
|
10167
|
+
entryLines.push(nextLine);
|
|
10168
|
+
i++;
|
|
10169
|
+
}
|
|
10170
|
+
const entryText = entryLines.join(`
|
|
10171
|
+
`);
|
|
10172
|
+
const addedObjectMatch = entryText.match(/addedObject:[ \t]*\{[^}]*fileID:[ \t]*(-?\d+)/);
|
|
10173
|
+
if (addedObjectMatch && addedObjectMatch[1] === componentId) {
|
|
10174
|
+
removed++;
|
|
10175
|
+
continue;
|
|
10176
|
+
}
|
|
10177
|
+
keptEntries.push(entryLines);
|
|
10178
|
+
}
|
|
10179
|
+
if (removed === 0) {
|
|
10180
|
+
return { updated_raw: rawText, removed_count: 0 };
|
|
10181
|
+
}
|
|
10182
|
+
const keyIndent = (section.lines[section.key_index].match(/^[ \t]*/) || [""])[0];
|
|
10183
|
+
const replacement = keptEntries.length === 0 ? [`${keyIndent}m_AddedComponents: []`] : [`${keyIndent}m_AddedComponents:`, ...keptEntries.flat()];
|
|
10184
|
+
const updatedLines = [
|
|
10185
|
+
...section.lines.slice(0, section.key_index),
|
|
10186
|
+
...replacement,
|
|
10187
|
+
...section.lines.slice(section.section_end)
|
|
10188
|
+
];
|
|
10189
|
+
return { updated_raw: updatedLines.join(`
|
|
10190
|
+
`), removed_count: removed };
|
|
10191
|
+
}
|
|
9364
10192
|
function deletePrefabInstance(options) {
|
|
9365
10193
|
const { file_path, prefab_instance } = options;
|
|
9366
10194
|
const pathError = validate_file_path(file_path, "write");
|
|
@@ -9382,44 +10210,31 @@ function deletePrefabInstance(options) {
|
|
|
9382
10210
|
}
|
|
9383
10211
|
const piId = piBlock.file_id;
|
|
9384
10212
|
const allToRemove = new Set([piId]);
|
|
9385
|
-
const piRefPattern = new RegExp(`m_PrefabInstance
|
|
10213
|
+
const piRefPattern = new RegExp(`m_PrefabInstance:[ \\t]*\\{fileID:[ \\t]*${piId}\\}`);
|
|
9386
10214
|
for (const block of doc.blocks) {
|
|
9387
10215
|
if (block.is_stripped && piRefPattern.test(block.raw)) {
|
|
9388
10216
|
allToRemove.add(block.file_id);
|
|
9389
10217
|
}
|
|
9390
10218
|
}
|
|
9391
|
-
const
|
|
9392
|
-
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
|
|
9396
|
-
|
|
9397
|
-
|
|
9398
|
-
|
|
9399
|
-
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
if (compMatch) {
|
|
9403
|
-
const transformId = compMatch[1];
|
|
9404
|
-
allToRemove.add(transformId);
|
|
9405
|
-
const descendants = doc.collect_hierarchy(transformId);
|
|
9406
|
-
for (const id of descendants) {
|
|
9407
|
-
allToRemove.add(id);
|
|
9408
|
-
}
|
|
10219
|
+
for (const goId of collectAddedObjectFileIdsFromArray(piBlock.raw, "m_AddedGameObjects")) {
|
|
10220
|
+
allToRemove.add(goId);
|
|
10221
|
+
const goBlock = doc.find_by_file_id(goId);
|
|
10222
|
+
if (goBlock) {
|
|
10223
|
+
const compMatch = goBlock.raw.match(/component:[ \t]*\{fileID:[ \t]*(\d+)\}/);
|
|
10224
|
+
if (compMatch) {
|
|
10225
|
+
const transformId = compMatch[1];
|
|
10226
|
+
allToRemove.add(transformId);
|
|
10227
|
+
const descendants = doc.collect_hierarchy(transformId);
|
|
10228
|
+
for (const id of descendants) {
|
|
10229
|
+
allToRemove.add(id);
|
|
9409
10230
|
}
|
|
9410
10231
|
}
|
|
9411
10232
|
}
|
|
9412
10233
|
}
|
|
9413
|
-
const
|
|
9414
|
-
|
|
9415
|
-
if (addedCompMatch) {
|
|
9416
|
-
const addedCompSection = addedCompMatch[1];
|
|
9417
|
-
const compMatches = addedCompSection.matchAll(/fileID:\s*(\d+)/g);
|
|
9418
|
-
for (const match of compMatches) {
|
|
9419
|
-
allToRemove.add(match[1]);
|
|
9420
|
-
}
|
|
10234
|
+
for (const componentId of collectAddedObjectFileIdsFromArray(piBlock.raw, "m_AddedComponents")) {
|
|
10235
|
+
allToRemove.add(componentId);
|
|
9421
10236
|
}
|
|
9422
|
-
const parentMatch = piBlock.raw.match(/m_TransformParent
|
|
10237
|
+
const parentMatch = piBlock.raw.match(/m_TransformParent:[ \t]*\{fileID:[ \t]*(\d+)\}/);
|
|
9423
10238
|
const parentTransformId = parentMatch ? parentMatch[1] : "0";
|
|
9424
10239
|
let strippedRootTransformId = null;
|
|
9425
10240
|
for (const id of allToRemove) {
|
|
@@ -10427,10 +11242,11 @@ function build_create_command() {
|
|
|
10427
11242
|
if (!result.success)
|
|
10428
11243
|
process.exitCode = 1;
|
|
10429
11244
|
});
|
|
10430
|
-
cmd.command("build <
|
|
11245
|
+
cmd.command("build <scene_path>").description("Add a scene to build settings").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("--index <n>", "Insert at position (0-based)").option("-j, --json", "Output as JSON").action((scene_path, options) => {
|
|
10431
11246
|
try {
|
|
11247
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
10432
11248
|
const position = options.index !== undefined ? parseInt(options.index, 10) : undefined;
|
|
10433
|
-
const result = add_scene(
|
|
11249
|
+
const result = add_scene(resolvedProjectPath, scene_path, { position });
|
|
10434
11250
|
console.log(JSON.stringify(result, null, 2));
|
|
10435
11251
|
if (!result.success)
|
|
10436
11252
|
process.exitCode = 1;
|
|
@@ -10538,9 +11354,10 @@ NativeFormatImporter:
|
|
|
10538
11354
|
shader_guid
|
|
10539
11355
|
}, null, 2));
|
|
10540
11356
|
});
|
|
10541
|
-
cmd.command("package <
|
|
11357
|
+
cmd.command("package <name> <version>").description("Add a package to Packages/manifest.json").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("-j, --json", "Output as JSON").action((name, version, options) => {
|
|
10542
11358
|
try {
|
|
10543
|
-
const
|
|
11359
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
11360
|
+
const result = add_package(resolvedProjectPath, name, version);
|
|
10544
11361
|
if ("error" in result) {
|
|
10545
11362
|
console.log(JSON.stringify({ success: false, error: result.error }, null, 2));
|
|
10546
11363
|
process.exitCode = 1;
|
|
@@ -10844,6 +11661,116 @@ init_scanner();
|
|
|
10844
11661
|
var import_fs18 = require("fs");
|
|
10845
11662
|
var import_path8 = require("path");
|
|
10846
11663
|
var import_os = require("os");
|
|
11664
|
+
function parse_unity_ref(ref_text) {
|
|
11665
|
+
const file_id_match = ref_text.match(/fileID:[ \t]*(-?\d+)/i);
|
|
11666
|
+
if (!file_id_match)
|
|
11667
|
+
return null;
|
|
11668
|
+
const guid_match = ref_text.match(/guid:[ \t]*([a-f0-9]{32})/i);
|
|
11669
|
+
const type_match = ref_text.match(/type:[ \t]*(-?\d+)/i);
|
|
11670
|
+
const parsed = { file_id: file_id_match[1] };
|
|
11671
|
+
if (guid_match)
|
|
11672
|
+
parsed.guid = guid_match[1].toLowerCase();
|
|
11673
|
+
if (type_match)
|
|
11674
|
+
parsed.type = parseInt(type_match[1], 10);
|
|
11675
|
+
return parsed;
|
|
11676
|
+
}
|
|
11677
|
+
function extract_prefab_list_section(raw, key) {
|
|
11678
|
+
const lines = raw.split(`
|
|
11679
|
+
`);
|
|
11680
|
+
const key_pattern = new RegExp(`^(\\s*)${key}:[ \\t]*(.*)$`);
|
|
11681
|
+
let key_index = -1;
|
|
11682
|
+
let key_indent = 0;
|
|
11683
|
+
for (let i = 0;i < lines.length; i++) {
|
|
11684
|
+
const match = lines[i].match(key_pattern);
|
|
11685
|
+
if (match) {
|
|
11686
|
+
key_index = i;
|
|
11687
|
+
key_indent = match[1].length;
|
|
11688
|
+
break;
|
|
11689
|
+
}
|
|
11690
|
+
}
|
|
11691
|
+
if (key_index === -1)
|
|
11692
|
+
return null;
|
|
11693
|
+
const section_lines = [lines[key_index]];
|
|
11694
|
+
for (let i = key_index + 1;i < lines.length; i++) {
|
|
11695
|
+
const line = lines[i];
|
|
11696
|
+
const trimmed = line.trim();
|
|
11697
|
+
if (trimmed.length === 0) {
|
|
11698
|
+
section_lines.push(line);
|
|
11699
|
+
continue;
|
|
11700
|
+
}
|
|
11701
|
+
const indent = (line.match(/^\s*/) || [""])[0].length;
|
|
11702
|
+
if (indent < key_indent)
|
|
11703
|
+
break;
|
|
11704
|
+
if (indent === key_indent && !trimmed.startsWith("-") && /^[A-Za-z_][A-Za-z0-9_]*:/.test(trimmed)) {
|
|
11705
|
+
break;
|
|
11706
|
+
}
|
|
11707
|
+
section_lines.push(line);
|
|
11708
|
+
}
|
|
11709
|
+
return { key_indent, section_lines };
|
|
11710
|
+
}
|
|
11711
|
+
function parse_removed_list(raw, key) {
|
|
11712
|
+
const section = extract_prefab_list_section(raw, key);
|
|
11713
|
+
if (!section)
|
|
11714
|
+
return [];
|
|
11715
|
+
const key_line = section.section_lines[0].trim();
|
|
11716
|
+
if (key_line.endsWith("[]"))
|
|
11717
|
+
return [];
|
|
11718
|
+
const refs = section.section_lines.join(`
|
|
11719
|
+
`).match(/\{[^}]*fileID:[^}]*\}/g) || [];
|
|
11720
|
+
const dedup = new Map;
|
|
11721
|
+
for (const ref of refs) {
|
|
11722
|
+
const parsed = parse_unity_ref(ref);
|
|
11723
|
+
if (!parsed)
|
|
11724
|
+
continue;
|
|
11725
|
+
const key_text = `${parsed.file_id}|${parsed.guid ?? ""}|${parsed.type ?? ""}`;
|
|
11726
|
+
if (!dedup.has(key_text))
|
|
11727
|
+
dedup.set(key_text, parsed);
|
|
11728
|
+
}
|
|
11729
|
+
return [...dedup.values()];
|
|
11730
|
+
}
|
|
11731
|
+
function parse_added_list(raw, key) {
|
|
11732
|
+
const section = extract_prefab_list_section(raw, key);
|
|
11733
|
+
if (!section)
|
|
11734
|
+
return [];
|
|
11735
|
+
const key_line = section.section_lines[0].trim();
|
|
11736
|
+
if (key_line.endsWith("[]"))
|
|
11737
|
+
return [];
|
|
11738
|
+
const lines = section.section_lines.slice(1);
|
|
11739
|
+
const entries = [];
|
|
11740
|
+
let i = 0;
|
|
11741
|
+
while (i < lines.length) {
|
|
11742
|
+
const line = lines[i];
|
|
11743
|
+
const trimmed = line.trimStart();
|
|
11744
|
+
if (!trimmed.startsWith("-")) {
|
|
11745
|
+
i++;
|
|
11746
|
+
continue;
|
|
11747
|
+
}
|
|
11748
|
+
const entry_indent = (line.match(/^\s*/) || [""])[0].length;
|
|
11749
|
+
const entry_lines = [line];
|
|
11750
|
+
i++;
|
|
11751
|
+
while (i < lines.length) {
|
|
11752
|
+
const next = lines[i];
|
|
11753
|
+
const next_trimmed = next.trim();
|
|
11754
|
+
const next_indent = (next.match(/^\s*/) || [""])[0].length;
|
|
11755
|
+
if (next_trimmed.length > 0 && next_indent === entry_indent && next_trimmed.startsWith("-")) {
|
|
11756
|
+
break;
|
|
11757
|
+
}
|
|
11758
|
+
entry_lines.push(next);
|
|
11759
|
+
i++;
|
|
11760
|
+
}
|
|
11761
|
+
const entry_text = entry_lines.join(`
|
|
11762
|
+
`);
|
|
11763
|
+
const target_match = entry_text.match(/targetCorrespondingSourceObject:[ \t]*(\{[^}]+\})/);
|
|
11764
|
+
const insert_match = entry_text.match(/insertIndex:[ \t]*(-?\d+)/);
|
|
11765
|
+
const added_match = entry_text.match(/addedObject:[ \t]*(\{[^}]+\})/);
|
|
11766
|
+
entries.push({
|
|
11767
|
+
target_corresponding_source_object: target_match ? parse_unity_ref(target_match[1]) : null,
|
|
11768
|
+
insert_index: insert_match ? parseInt(insert_match[1], 10) : null,
|
|
11769
|
+
added_object: added_match ? parse_unity_ref(added_match[1]) : null
|
|
11770
|
+
});
|
|
11771
|
+
}
|
|
11772
|
+
return entries;
|
|
11773
|
+
}
|
|
10847
11774
|
function parse_material_yaml(content) {
|
|
10848
11775
|
const lines = content.replace(/\r/g, "").split(`
|
|
10849
11776
|
`);
|
|
@@ -11123,10 +12050,12 @@ function parse_log_line_timestamp(line) {
|
|
|
11123
12050
|
}
|
|
11124
12051
|
function parse_log_entries(lines) {
|
|
11125
12052
|
const entries = [];
|
|
11126
|
-
const error_re =
|
|
11127
|
-
const
|
|
12053
|
+
const error_re = /\b(error|exception)\b/i;
|
|
12054
|
+
const runtime_error_re = /\b(NullReferenceException|IndexOutOfRangeException|ArgumentException|MissingReferenceException|StackOverflowException|DivideByZeroException|InvalidOperationException|KeyNotFoundException|FormatException|ObjectDisposedException|MissingComponentException|UnassignedReferenceException)\b/;
|
|
12055
|
+
const warning_re = /\bwarning\b/i;
|
|
11128
12056
|
const compile_re = /Assets\/.*\.cs\(\d+,\d+\):\s*error\s+CS/;
|
|
11129
12057
|
const import_error_re = /Failed to import|Error while importing|Could not create asset|Unable to import|Shader error in|Import of asset .* failed/i;
|
|
12058
|
+
const assertion_re = /^Assertion failed/;
|
|
11130
12059
|
const stack_re = /^\s+at\s+|^\s*\(Filename:/;
|
|
11131
12060
|
for (let i = 0;i < lines.length; i++) {
|
|
11132
12061
|
const line = lines[i];
|
|
@@ -11135,7 +12064,9 @@ function parse_log_entries(lines) {
|
|
|
11135
12064
|
let level = "info";
|
|
11136
12065
|
if (import_error_re.test(line))
|
|
11137
12066
|
level = "import_error";
|
|
11138
|
-
else if (
|
|
12067
|
+
else if (compile_re.test(line))
|
|
12068
|
+
level = "error";
|
|
12069
|
+
else if (error_re.test(line) || runtime_error_re.test(line) || assertion_re.test(line))
|
|
11139
12070
|
level = "error";
|
|
11140
12071
|
else if (warning_re.test(line))
|
|
11141
12072
|
level = "warning";
|
|
@@ -11543,9 +12474,16 @@ function build_read_command(getScanner) {
|
|
|
11543
12474
|
}
|
|
11544
12475
|
if (result.total === 0 && !result.error) {
|
|
11545
12476
|
const prefabInstances = result.prefabInstances;
|
|
12477
|
+
let variantDetected = false;
|
|
12478
|
+
let variantResolvedFromSource = false;
|
|
11546
12479
|
if (prefabInstances && prefabInstances.length > 0) {
|
|
12480
|
+
variantDetected = true;
|
|
11547
12481
|
try {
|
|
11548
12482
|
const doc = UnityDocument.from_file(file);
|
|
12483
|
+
const strippedGoCount = doc.blocks.filter((b) => b.class_id === 1 && b.is_stripped).length;
|
|
12484
|
+
if (strippedGoCount > 0) {
|
|
12485
|
+
variantDetected = true;
|
|
12486
|
+
}
|
|
11549
12487
|
const projectPath = find_unity_project_root(import_path8.dirname(file));
|
|
11550
12488
|
const resolved = resolve_source_prefab(doc, file, projectPath ?? undefined);
|
|
11551
12489
|
if (resolved) {
|
|
@@ -11580,6 +12518,7 @@ function build_read_command(getScanner) {
|
|
|
11580
12518
|
resultRecord.resolvedFromSource = true;
|
|
11581
12519
|
resultRecord.sourcePrefab = resolved.source_path;
|
|
11582
12520
|
resultRecord.sourceGuid = resolved.source_guid;
|
|
12521
|
+
variantResolvedFromSource = true;
|
|
11583
12522
|
const variantNote = `PrefabVariant resolved from source prefab: ${resolved.source_path}`;
|
|
11584
12523
|
result.warning = result.warning ? `${result.warning}; ${variantNote}` : variantNote;
|
|
11585
12524
|
}
|
|
@@ -11590,8 +12529,13 @@ function build_read_command(getScanner) {
|
|
|
11590
12529
|
try {
|
|
11591
12530
|
const fileSize = import_fs18.statSync(file).size;
|
|
11592
12531
|
if (fileSize > 100) {
|
|
11593
|
-
|
|
11594
|
-
|
|
12532
|
+
if (variantDetected && !variantResolvedFromSource) {
|
|
12533
|
+
const variantWarning = "PrefabVariant detected but source prefab hierarchy could not be resolved (missing project context or GUID cache). Use --project or run setup to resolve source hierarchy.";
|
|
12534
|
+
result.warning = result.warning ? `${result.warning}; ${variantWarning}` : variantWarning;
|
|
12535
|
+
} else {
|
|
12536
|
+
const corruptWarning = "File has valid Unity YAML header but contains no parseable GameObjects -- file may be corrupt or malformed";
|
|
12537
|
+
result.warning = result.warning ? `${result.warning}; ${corruptWarning}` : corruptWarning;
|
|
12538
|
+
}
|
|
11595
12539
|
}
|
|
11596
12540
|
} catch {}
|
|
11597
12541
|
}
|
|
@@ -11864,38 +12808,41 @@ function build_read_command(getScanner) {
|
|
|
11864
12808
|
by_type: options.unresolved ? undefined : byType
|
|
11865
12809
|
};
|
|
11866
12810
|
if (!cache) {
|
|
11867
|
-
output._hint = "Run 'setup <
|
|
12811
|
+
output._hint = "Run 'setup' (or 'setup -p <path>') to resolve GUID paths";
|
|
11868
12812
|
}
|
|
11869
12813
|
console.log(JSON.stringify(output, null, 2));
|
|
11870
12814
|
});
|
|
11871
|
-
cmd.command("settings
|
|
12815
|
+
cmd.command("settings").description("Read Unity project settings (TagManager, DynamicsManager, QualitySettings, TimeManager, etc.)").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("-s, --setting <name>", "Setting name or alias (tags, physics, quality, time)", "TagManager").option("-j, --json", "Output as JSON").action((options) => {
|
|
12816
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
11872
12817
|
const result = read_settings({
|
|
11873
|
-
project_path,
|
|
12818
|
+
project_path: resolvedProjectPath,
|
|
11874
12819
|
setting: options.setting
|
|
11875
12820
|
});
|
|
11876
12821
|
console.log(JSON.stringify(result, null, 2));
|
|
11877
12822
|
if (!result.success)
|
|
11878
12823
|
process.exit(1);
|
|
11879
12824
|
});
|
|
11880
|
-
cmd.command("build
|
|
12825
|
+
cmd.command("build").description("Read build settings (scene list, build profiles)").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("-j, --json", "Output as JSON").action((options) => {
|
|
12826
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
11881
12827
|
try {
|
|
11882
|
-
const result = get_build_settings(
|
|
12828
|
+
const result = get_build_settings(resolvedProjectPath);
|
|
11883
12829
|
console.log(JSON.stringify(result, null, 2));
|
|
11884
12830
|
} catch (err) {
|
|
11885
12831
|
console.log(JSON.stringify({ success: false, error: err instanceof Error ? err.message : String(err) }, null, 2));
|
|
11886
12832
|
process.exitCode = 1;
|
|
11887
12833
|
}
|
|
11888
12834
|
});
|
|
11889
|
-
cmd.command("scenes
|
|
12835
|
+
cmd.command("scenes").description('Read build scenes (alias for "read build")').option("-p, --project <path>", "Unity project path (defaults to cwd)").option("-j, --json", "Output as JSON").action((options) => {
|
|
12836
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
11890
12837
|
try {
|
|
11891
|
-
const result = get_build_settings(
|
|
12838
|
+
const result = get_build_settings(resolvedProjectPath);
|
|
11892
12839
|
console.log(JSON.stringify(result, null, 2));
|
|
11893
12840
|
} catch (err) {
|
|
11894
12841
|
console.log(JSON.stringify({ success: false, error: err instanceof Error ? err.message : String(err) }, null, 2));
|
|
11895
12842
|
process.exitCode = 1;
|
|
11896
12843
|
}
|
|
11897
12844
|
});
|
|
11898
|
-
cmd.command("overrides <file> <prefab_instance>").description("Read PrefabInstance
|
|
12845
|
+
cmd.command("overrides <file> <prefab_instance>").description("Read PrefabInstance overrides (modifications + removed/added state)").option("--flat", "Output simplified list").option("-j, --json", "Output as JSON").action((file, prefab_instance, options) => {
|
|
11899
12846
|
try {
|
|
11900
12847
|
const doc = UnityDocument.from_file(file);
|
|
11901
12848
|
let block = null;
|
|
@@ -11958,6 +12905,10 @@ function build_read_command(getScanner) {
|
|
|
11958
12905
|
i++;
|
|
11959
12906
|
}
|
|
11960
12907
|
}
|
|
12908
|
+
const removed_components = parse_removed_list(block.raw, "m_RemovedComponents");
|
|
12909
|
+
const removed_gameobjects = parse_removed_list(block.raw, "m_RemovedGameObjects");
|
|
12910
|
+
const added_gameobjects = parse_added_list(block.raw, "m_AddedGameObjects");
|
|
12911
|
+
const added_components = parse_added_list(block.raw, "m_AddedComponents");
|
|
11961
12912
|
if (options.flat) {
|
|
11962
12913
|
const flat = modifications.map((m) => ({
|
|
11963
12914
|
property_path: m.property_path,
|
|
@@ -11966,7 +12917,14 @@ function build_read_command(getScanner) {
|
|
|
11966
12917
|
}));
|
|
11967
12918
|
console.log(JSON.stringify(flat, null, 2));
|
|
11968
12919
|
} else {
|
|
11969
|
-
console.log(JSON.stringify(
|
|
12920
|
+
console.log(JSON.stringify({
|
|
12921
|
+
prefab_instance_id: block.file_id,
|
|
12922
|
+
modifications,
|
|
12923
|
+
removed_components,
|
|
12924
|
+
removed_gameobjects,
|
|
12925
|
+
added_gameobjects,
|
|
12926
|
+
added_components
|
|
12927
|
+
}, null, 2));
|
|
11970
12928
|
}
|
|
11971
12929
|
} catch (err) {
|
|
11972
12930
|
console.log(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }, null, 2));
|
|
@@ -12226,9 +13184,7 @@ function build_read_command(getScanner) {
|
|
|
12226
13184
|
types: displayed
|
|
12227
13185
|
}, null, 2));
|
|
12228
13186
|
});
|
|
12229
|
-
cmd.command("log
|
|
12230
|
-
if (projectPath && !options.project)
|
|
12231
|
-
options.project = projectPath;
|
|
13187
|
+
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) => {
|
|
12232
13188
|
const logPath = options.path || get_editor_log_path();
|
|
12233
13189
|
if (!logPath || !import_fs18.existsSync(logPath)) {
|
|
12234
13190
|
console.log(JSON.stringify({ error: `Editor.log not found${logPath ? `: ${logPath}` : ". Could not detect platform log path."}` }, null, 2));
|
|
@@ -12237,9 +13193,9 @@ function build_read_command(getScanner) {
|
|
|
12237
13193
|
const content = import_fs18.readFileSync(logPath, "utf-8");
|
|
12238
13194
|
let lines = content.split(/\r?\n/);
|
|
12239
13195
|
if (options.project) {
|
|
12240
|
-
const
|
|
12241
|
-
const projectName = import_path8.basename(
|
|
12242
|
-
const escapedPath =
|
|
13196
|
+
const projectPath = import_path8.resolve(options.project);
|
|
13197
|
+
const projectName = import_path8.basename(projectPath);
|
|
13198
|
+
const escapedPath = projectPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12243
13199
|
const escapedName = projectName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12244
13200
|
const session_markers = [
|
|
12245
13201
|
new RegExp(`Loading project at '${escapedPath}'`),
|
|
@@ -12307,10 +13263,6 @@ function build_read_command(getScanner) {
|
|
|
12307
13263
|
}
|
|
12308
13264
|
}
|
|
12309
13265
|
}
|
|
12310
|
-
if (options.search) {
|
|
12311
|
-
const re = new RegExp(options.search, "i");
|
|
12312
|
-
lines = lines.filter((l) => re.test(l));
|
|
12313
|
-
}
|
|
12314
13266
|
if (options.errors || options.warnings || options.compileErrors || options.importErrors) {
|
|
12315
13267
|
const entries = parse_log_entries(lines);
|
|
12316
13268
|
let filtered = entries;
|
|
@@ -12324,6 +13276,10 @@ function build_read_command(getScanner) {
|
|
|
12324
13276
|
} else if (options.warnings) {
|
|
12325
13277
|
filtered = entries.filter((e) => e.level === "warning");
|
|
12326
13278
|
}
|
|
13279
|
+
if (options.search) {
|
|
13280
|
+
const re = new RegExp(options.search, "i");
|
|
13281
|
+
filtered = filtered.filter((e) => re.test(e.message) || e.stack_trace && e.stack_trace.some((s) => re.test(s)));
|
|
13282
|
+
}
|
|
12327
13283
|
const tail_filtered = parseInt(options.tail, 10);
|
|
12328
13284
|
if (isNaN(tail_filtered) || tail_filtered < 1) {
|
|
12329
13285
|
console.log(JSON.stringify({ error: `Invalid --tail value "${options.tail}". Must be a positive integer.` }, null, 2));
|
|
@@ -12339,6 +13295,10 @@ function build_read_command(getScanner) {
|
|
|
12339
13295
|
}, null, 2));
|
|
12340
13296
|
return;
|
|
12341
13297
|
}
|
|
13298
|
+
if (options.search) {
|
|
13299
|
+
const re = new RegExp(options.search, "i");
|
|
13300
|
+
lines = lines.filter((l) => re.test(l));
|
|
13301
|
+
}
|
|
12342
13302
|
const tail = parseInt(options.tail, 10);
|
|
12343
13303
|
if (isNaN(tail) || tail < 1) {
|
|
12344
13304
|
console.log(JSON.stringify({ error: `Invalid --tail value "${options.tail}". Must be a positive integer.` }, null, 2));
|
|
@@ -12680,7 +13640,7 @@ function build_read_command(getScanner) {
|
|
|
12680
13640
|
}
|
|
12681
13641
|
const states_out = { file, states_by_layer: by_layer };
|
|
12682
13642
|
if (needs_setup_hint)
|
|
12683
|
-
states_out._hint = "Run 'setup <
|
|
13643
|
+
states_out._hint = "Run 'setup' (or 'setup -p <path>') to resolve motion paths";
|
|
12684
13644
|
console.log(JSON.stringify(states_out, null, 2));
|
|
12685
13645
|
return;
|
|
12686
13646
|
}
|
|
@@ -12729,14 +13689,15 @@ function build_read_command(getScanner) {
|
|
|
12729
13689
|
}))
|
|
12730
13690
|
};
|
|
12731
13691
|
if (needs_setup_hint)
|
|
12732
|
-
default_out._hint = "Run 'setup <
|
|
13692
|
+
default_out._hint = "Run 'setup' (or 'setup -p <path>') to resolve motion paths";
|
|
12733
13693
|
console.log(JSON.stringify(default_out, null, 2));
|
|
12734
13694
|
});
|
|
12735
|
-
cmd.command("dependents <
|
|
13695
|
+
cmd.command("dependents <guid>").description("Find which files reference a given GUID (reverse dependency lookup)").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("--type <type>", "Filter to specific file types (scene, prefab, mat, etc.)").option("-j, --json", "Output as JSON").action((guid, options) => {
|
|
12736
13696
|
if (!/^[0-9a-f]{32}$/i.test(guid)) {
|
|
12737
13697
|
console.log(JSON.stringify({ error: "GUID must be a 32-character hexadecimal string" }, null, 2));
|
|
12738
13698
|
process.exit(1);
|
|
12739
13699
|
}
|
|
13700
|
+
const project_path = resolve_project_path(options.project);
|
|
12740
13701
|
const assetsDir = import_path8.join(import_path8.resolve(project_path), "Assets");
|
|
12741
13702
|
if (!import_fs18.existsSync(assetsDir)) {
|
|
12742
13703
|
console.log(JSON.stringify({ error: `Assets directory not found in "${project_path}"` }, null, 2));
|
|
@@ -12794,11 +13755,11 @@ function build_read_command(getScanner) {
|
|
|
12794
13755
|
by_type
|
|
12795
13756
|
}, null, 2));
|
|
12796
13757
|
});
|
|
12797
|
-
cmd.command("unused
|
|
12798
|
-
const resolvedProject =
|
|
13758
|
+
cmd.command("unused").description("Find potentially unused assets (zero inbound GUID references)").option("-p, --project <path>", "Unity project path (defaults to cwd)").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((options) => {
|
|
13759
|
+
const resolvedProject = resolve_project_path(options.project);
|
|
12799
13760
|
const assetsDir = import_path8.join(resolvedProject, "Assets");
|
|
12800
13761
|
if (!import_fs18.existsSync(assetsDir)) {
|
|
12801
|
-
console.log(JSON.stringify({ error: `Assets directory not found in "${
|
|
13762
|
+
console.log(JSON.stringify({ error: `Assets directory not found in "${resolvedProject}"` }, null, 2));
|
|
12802
13763
|
process.exit(1);
|
|
12803
13764
|
}
|
|
12804
13765
|
const guidCacheObj = load_guid_cache(resolvedProject);
|
|
@@ -12889,7 +13850,8 @@ function build_read_command(getScanner) {
|
|
|
12889
13850
|
by_type
|
|
12890
13851
|
}, null, 2));
|
|
12891
13852
|
});
|
|
12892
|
-
cmd.command("manifest
|
|
13853
|
+
cmd.command("manifest").description("List packages from Packages/manifest.json").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("--search <pattern>", "Filter packages by name pattern").option("-j, --json", "Output as JSON").action((options) => {
|
|
13854
|
+
const project_path = resolve_project_path(options.project);
|
|
12893
13855
|
const result = list_packages(project_path, options.search);
|
|
12894
13856
|
if ("error" in result) {
|
|
12895
13857
|
console.log(JSON.stringify({ success: false, error: result.error }, null, 2));
|
|
@@ -13126,7 +14088,7 @@ function build_update_command(getScanner) {
|
|
|
13126
14088
|
if (!result.success)
|
|
13127
14089
|
process.exitCode = 1;
|
|
13128
14090
|
});
|
|
13129
|
-
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,
|
|
14091
|
+
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").option("-p, --project <path>", "Unity project path (for asset reference resolution)").action((file, file_id, property, value, options) => {
|
|
13130
14092
|
if (property === "m_RootOrder") {
|
|
13131
14093
|
const num = Number(value);
|
|
13132
14094
|
if (!Number.isInteger(num) || num < 0) {
|
|
@@ -13139,7 +14101,8 @@ function build_update_command(getScanner) {
|
|
|
13139
14101
|
file_path: file,
|
|
13140
14102
|
file_id,
|
|
13141
14103
|
property,
|
|
13142
|
-
new_value: value
|
|
14104
|
+
new_value: value,
|
|
14105
|
+
project_path: options.project
|
|
13143
14106
|
});
|
|
13144
14107
|
console.log(JSON.stringify(result, null, 2));
|
|
13145
14108
|
if (!result.success)
|
|
@@ -13207,13 +14170,14 @@ function build_update_command(getScanner) {
|
|
|
13207
14170
|
if (!result.success)
|
|
13208
14171
|
process.exitCode = 1;
|
|
13209
14172
|
});
|
|
13210
|
-
cmd.command("settings
|
|
14173
|
+
cmd.command("settings").description("Edit a property in any ProjectSettings/*.asset file").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("-s, --setting <name>", "Setting name or alias").option("--property <name>", "Property name to edit").option("--value <value>", "New value").option("-j, --json", "Output as JSON").action((options) => {
|
|
13211
14174
|
if (!options.setting || !options.property || !options.value) {
|
|
13212
14175
|
console.log(JSON.stringify({ success: false, error: "Required: --setting, --property, --value" }, null, 2));
|
|
13213
14176
|
process.exit(1);
|
|
13214
14177
|
}
|
|
14178
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
13215
14179
|
const result = edit_settings({
|
|
13216
|
-
project_path,
|
|
14180
|
+
project_path: resolvedProjectPath,
|
|
13217
14181
|
setting: options.setting,
|
|
13218
14182
|
property: options.property,
|
|
13219
14183
|
value: options.value
|
|
@@ -13222,13 +14186,14 @@ function build_update_command(getScanner) {
|
|
|
13222
14186
|
if (!result.success)
|
|
13223
14187
|
process.exitCode = 1;
|
|
13224
14188
|
});
|
|
13225
|
-
cmd.command("tag <
|
|
14189
|
+
cmd.command("tag <action> <tag>").description("Add or remove a tag in the TagManager").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("-j, --json", "Output as JSON").action((action, tag, options) => {
|
|
13226
14190
|
if (action !== "add" && action !== "remove") {
|
|
13227
14191
|
console.log(JSON.stringify({ success: false, error: 'Action must be "add" or "remove"' }, null, 2));
|
|
13228
14192
|
process.exit(1);
|
|
13229
14193
|
}
|
|
14194
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
13230
14195
|
const result = edit_tag({
|
|
13231
|
-
project_path,
|
|
14196
|
+
project_path: resolvedProjectPath,
|
|
13232
14197
|
action,
|
|
13233
14198
|
tag
|
|
13234
14199
|
});
|
|
@@ -13236,9 +14201,10 @@ function build_update_command(getScanner) {
|
|
|
13236
14201
|
if (!result.success)
|
|
13237
14202
|
process.exitCode = 1;
|
|
13238
14203
|
});
|
|
13239
|
-
cmd.command("layer <
|
|
14204
|
+
cmd.command("layer <index> <name>").description("Set a named layer at a specific index (3-31)").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("-j, --json", "Output as JSON").action((index, name, options) => {
|
|
14205
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
13240
14206
|
const result = edit_layer({
|
|
13241
|
-
project_path,
|
|
14207
|
+
project_path: resolvedProjectPath,
|
|
13242
14208
|
index: parseInt(index, 10),
|
|
13243
14209
|
name
|
|
13244
14210
|
});
|
|
@@ -13246,13 +14212,14 @@ function build_update_command(getScanner) {
|
|
|
13246
14212
|
if (!result.success)
|
|
13247
14213
|
process.exitCode = 1;
|
|
13248
14214
|
});
|
|
13249
|
-
cmd.command("sorting-layer <
|
|
14215
|
+
cmd.command("sorting-layer <action> <name>").description("Add or remove a sorting layer").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("-j, --json", "Output as JSON").action((action, name, options) => {
|
|
13250
14216
|
if (action !== "add" && action !== "remove") {
|
|
13251
14217
|
console.log(JSON.stringify({ success: false, error: 'Action must be "add" or "remove"' }, null, 2));
|
|
13252
14218
|
process.exit(1);
|
|
13253
14219
|
}
|
|
14220
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
13254
14221
|
const result = edit_sorting_layer({
|
|
13255
|
-
project_path,
|
|
14222
|
+
project_path: resolvedProjectPath,
|
|
13256
14223
|
action,
|
|
13257
14224
|
name
|
|
13258
14225
|
});
|
|
@@ -13352,20 +14319,21 @@ function build_update_command(getScanner) {
|
|
|
13352
14319
|
if (!result.success)
|
|
13353
14320
|
process.exitCode = 1;
|
|
13354
14321
|
});
|
|
13355
|
-
cmd.command("build <
|
|
14322
|
+
cmd.command("build <scene_path>").description("Enable, disable, or move a scene in build settings").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("--enable", "Enable the scene").option("--disable", "Disable the scene").option("--move <index>", "Move scene to position").option("-j, --json", "Output as JSON").action((scene_path, options) => {
|
|
13356
14323
|
try {
|
|
14324
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
13357
14325
|
if (options.move !== undefined) {
|
|
13358
|
-
const result = move_scene(
|
|
14326
|
+
const result = move_scene(resolvedProjectPath, scene_path, parseInt(options.move, 10));
|
|
13359
14327
|
console.log(JSON.stringify(result, null, 2));
|
|
13360
14328
|
if (!result.success)
|
|
13361
14329
|
process.exitCode = 1;
|
|
13362
14330
|
} else if (options.enable) {
|
|
13363
|
-
const result = enable_scene(
|
|
14331
|
+
const result = enable_scene(resolvedProjectPath, scene_path);
|
|
13364
14332
|
console.log(JSON.stringify(result, null, 2));
|
|
13365
14333
|
if (!result.success)
|
|
13366
14334
|
process.exitCode = 1;
|
|
13367
14335
|
} else if (options.disable) {
|
|
13368
|
-
const result = disable_scene(
|
|
14336
|
+
const result = disable_scene(resolvedProjectPath, scene_path);
|
|
13369
14337
|
console.log(JSON.stringify(result, null, 2));
|
|
13370
14338
|
if (!result.success)
|
|
13371
14339
|
process.exitCode = 1;
|
|
@@ -15059,9 +16027,10 @@ function build_delete_command() {
|
|
|
15059
16027
|
process.exitCode = 1;
|
|
15060
16028
|
}
|
|
15061
16029
|
});
|
|
15062
|
-
cmd.command("build <
|
|
16030
|
+
cmd.command("build <scene_path>").description("Remove a scene from build settings").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("-j, --json", "Output as JSON").action((scene_path, options) => {
|
|
16031
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
15063
16032
|
try {
|
|
15064
|
-
const result = remove_scene(
|
|
16033
|
+
const result = remove_scene(resolvedProjectPath, scene_path);
|
|
15065
16034
|
console.log(JSON.stringify(result, null, 2));
|
|
15066
16035
|
if (!result.success)
|
|
15067
16036
|
process.exitCode = 1;
|
|
@@ -15079,9 +16048,10 @@ function build_delete_command() {
|
|
|
15079
16048
|
if (!result.success)
|
|
15080
16049
|
process.exitCode = 1;
|
|
15081
16050
|
});
|
|
15082
|
-
cmd.command("package <
|
|
16051
|
+
cmd.command("package <name>").description("Remove a package from Packages/manifest.json").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("-j, --json", "Output as JSON").action((name, options) => {
|
|
15083
16052
|
try {
|
|
15084
|
-
const
|
|
16053
|
+
const resolvedProjectPath = resolve_project_path(options.project);
|
|
16054
|
+
const result = remove_package(resolvedProjectPath, name);
|
|
15085
16055
|
if ("error" in result) {
|
|
15086
16056
|
console.log(JSON.stringify({ success: false, error: result.error }, null, 2));
|
|
15087
16057
|
process.exitCode = 1;
|
|
@@ -15322,6 +16292,30 @@ async function stream_editor(options) {
|
|
|
15322
16292
|
connect(`ws://127.0.0.1:${config.port}/unity-agentic`);
|
|
15323
16293
|
});
|
|
15324
16294
|
}
|
|
16295
|
+
async function ping_editor(port, timeout_ms = 2000) {
|
|
16296
|
+
return new Promise((resolve7) => {
|
|
16297
|
+
const timer = setTimeout(() => {
|
|
16298
|
+
resolve7({ reachable: false, error: `Timeout after ${timeout_ms}ms` });
|
|
16299
|
+
}, timeout_ms);
|
|
16300
|
+
try {
|
|
16301
|
+
const ws = new WebSocket(`ws://127.0.0.1:${port}/unity-agentic`);
|
|
16302
|
+
ws.onopen = () => {
|
|
16303
|
+
clearTimeout(timer);
|
|
16304
|
+
try {
|
|
16305
|
+
ws.close();
|
|
16306
|
+
} catch {}
|
|
16307
|
+
resolve7({ reachable: true });
|
|
16308
|
+
};
|
|
16309
|
+
ws.onerror = (err) => {
|
|
16310
|
+
clearTimeout(timer);
|
|
16311
|
+
resolve7({ reachable: false, error: String(err) });
|
|
16312
|
+
};
|
|
16313
|
+
} catch (err) {
|
|
16314
|
+
clearTimeout(timer);
|
|
16315
|
+
resolve7({ reachable: false, error: String(err) });
|
|
16316
|
+
}
|
|
16317
|
+
});
|
|
16318
|
+
}
|
|
15325
16319
|
function resolve_config(options) {
|
|
15326
16320
|
if (options.port) {
|
|
15327
16321
|
return { port: options.port, pid: 0, version: "unknown" };
|
|
@@ -15344,7 +16338,7 @@ function generate_id() {
|
|
|
15344
16338
|
var BRIDGE_PACKAGE_NAME = "com.unity-agentic-tools.editor-bridge";
|
|
15345
16339
|
var BRIDGE_PACKAGE_VERSION = "https://github.com/taconotsandwich/unity-agentic-tools.git?path=unity-package";
|
|
15346
16340
|
function get_common_options(cmd) {
|
|
15347
|
-
let current = cmd
|
|
16341
|
+
let current = cmd;
|
|
15348
16342
|
let project;
|
|
15349
16343
|
let timeout_str;
|
|
15350
16344
|
let port_str;
|
|
@@ -15394,11 +16388,14 @@ function build_editor_command() {
|
|
|
15394
16388
|
process.exitCode = 1;
|
|
15395
16389
|
return;
|
|
15396
16390
|
}
|
|
16391
|
+
const ping = await ping_editor(config.port, 2000);
|
|
15397
16392
|
console.log(JSON.stringify({
|
|
15398
16393
|
port: config.port,
|
|
15399
16394
|
pid: config.pid,
|
|
15400
16395
|
version: config.version,
|
|
15401
|
-
project_path
|
|
16396
|
+
project_path,
|
|
16397
|
+
bridge_reachable: ping.reachable,
|
|
16398
|
+
...ping.reachable ? {} : { bridge_error: ping.error }
|
|
15402
16399
|
}, null, 2));
|
|
15403
16400
|
});
|
|
15404
16401
|
cmd.command("play").description("Enter play mode").action(async function() {
|
|
@@ -15533,9 +16530,9 @@ function build_editor_command() {
|
|
|
15533
16530
|
params.mode = options.mode;
|
|
15534
16531
|
await handle_rpc(this, "editor.tests.run", params);
|
|
15535
16532
|
});
|
|
15536
|
-
cmd.command("install
|
|
15537
|
-
const
|
|
15538
|
-
const result = add_package(
|
|
16533
|
+
cmd.command("install").description("Install the editor bridge package into a Unity project").option("-p, --project <path>", "Path to Unity project (defaults to cwd)").action(function() {
|
|
16534
|
+
const { project_path } = get_common_options(this);
|
|
16535
|
+
const result = add_package(project_path, BRIDGE_PACKAGE_NAME, BRIDGE_PACKAGE_VERSION);
|
|
15539
16536
|
if ("error" in result) {
|
|
15540
16537
|
console.log(JSON.stringify({ success: false, error: result.error }, null, 2));
|
|
15541
16538
|
process.exitCode = 1;
|
|
@@ -15543,9 +16540,9 @@ function build_editor_command() {
|
|
|
15543
16540
|
}
|
|
15544
16541
|
console.log(JSON.stringify(result, null, 2));
|
|
15545
16542
|
});
|
|
15546
|
-
cmd.command("uninstall
|
|
15547
|
-
const
|
|
15548
|
-
const result = remove_package(
|
|
16543
|
+
cmd.command("uninstall").description("Remove the editor bridge package from a Unity project").option("-p, --project <path>", "Path to Unity project (defaults to cwd)").action(function() {
|
|
16544
|
+
const { project_path } = get_common_options(this);
|
|
16545
|
+
const result = remove_package(project_path, BRIDGE_PACKAGE_NAME);
|
|
15549
16546
|
if ("error" in result) {
|
|
15550
16547
|
console.log(JSON.stringify({ success: false, error: result.error }, null, 2));
|
|
15551
16548
|
process.exitCode = 1;
|
|
@@ -15876,11 +16873,12 @@ program.command("search <path> [pattern]").description("Search for GameObjects.
|
|
|
15876
16873
|
console.log(JSON.stringify(result, null, 2));
|
|
15877
16874
|
}
|
|
15878
16875
|
});
|
|
15879
|
-
program.command("grep <
|
|
16876
|
+
program.command("grep <pattern>").description("Search for a regex pattern across project files").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("--type <type>", "File type filter: cs, yaml, unity, prefab, asset, all", "all").option("-m, --max <n>", "Max results (default: 100)", "100").option("-C, --context <n>", "Context lines around matches", "0").option("-j, --json", "Output as JSON").action((pattern, options) => {
|
|
15880
16877
|
if (!pattern || pattern.trim() === "") {
|
|
15881
16878
|
console.log(JSON.stringify({ success: false, error: "Pattern must not be empty" }, null, 2));
|
|
15882
16879
|
process.exit(1);
|
|
15883
16880
|
}
|
|
16881
|
+
let project_path = resolve_project_path(options.project);
|
|
15884
16882
|
const abs_path = path9.resolve(project_path);
|
|
15885
16883
|
const project_root = find_unity_project_root(abs_path);
|
|
15886
16884
|
if (project_root) {
|
|
@@ -15908,8 +16906,9 @@ program.command("grep <project_path> <pattern>").description("Search for a regex
|
|
|
15908
16906
|
if (!result.success)
|
|
15909
16907
|
process.exitCode = 1;
|
|
15910
16908
|
});
|
|
15911
|
-
program.command("version
|
|
16909
|
+
program.command("version").description("Read Unity project version").option("-p, --project <path>", "Unity project path (defaults to cwd)").option("-j, --json", "Output as JSON").action((options) => {
|
|
15912
16910
|
try {
|
|
16911
|
+
const project_path = resolve_project_path(options.project);
|
|
15913
16912
|
const version = read_project_version(project_path);
|
|
15914
16913
|
console.log(JSON.stringify(version, null, 2));
|
|
15915
16914
|
} catch (err) {
|