@babylonjs/shared-ui-components 9.16.1 → 9.17.0
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/package.json
CHANGED
|
@@ -23,7 +23,7 @@ export interface IOverrideEntry {
|
|
|
23
23
|
/**
|
|
24
24
|
* The types of scene objects that can be targeted by overrides.
|
|
25
25
|
*/
|
|
26
|
-
export type OverrideTargetType = "meshes" | "materials" | "textures" | "lights" | "cameras" | "animationGroups" | "scene";
|
|
26
|
+
export type OverrideTargetType = "meshes" | "transformNodes" | "materials" | "textures" | "lights" | "cameras" | "animationGroups" | "scene";
|
|
27
27
|
/**
|
|
28
28
|
* An override value. Supports scalars, color/vector arrays, object references,
|
|
29
29
|
* and null (used to clear a slot, e.g. removing a material assignment).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overrideEntry.js","sourceRoot":"","sources":["../../../../dev/sharedUiComponents/src/projects/overrideEntry.ts"],"names":[],"mappings":"","sourcesContent":["/**\r\n * Defines the shape of an override entry — a property diff applied to a\r\n * scene object identified by name. Overrides target any object in the\r\n * scene's standard collections (meshes, materials, lights, etc.) regardless\r\n * of how that object was created.\r\n */\r\nexport interface IOverrideEntry {\r\n /** The type of object to target (e.g., \"meshes\", \"materials\", \"lights\"). */\r\n readonly targetType: OverrideTargetType;\r\n\r\n /** The name of the target object. Use \"\" for scene-level overrides. */\r\n readonly targetName: string;\r\n\r\n /**\r\n * Disambiguator for when multiple objects in `scene[targetType]` share the\r\n * same `targetName`. The override applies to the N-th match (0-based) at\r\n * apply time. When names are unique, use 0.\r\n */\r\n readonly targetIndex: number;\r\n\r\n /** Dot-separated property path on the target (e.g., \"albedoColor\", \"position.x\"). */\r\n readonly propertyPath: string;\r\n\r\n /** The override value. */\r\n readonly value: OverrideValue;\r\n}\r\n\r\n/**\r\n * The types of scene objects that can be targeted by overrides.\r\n */\r\nexport type OverrideTargetType = \"meshes\" | \"materials\" | \"textures\" | \"lights\" | \"cameras\" | \"animationGroups\" | \"scene\";\r\n\r\n/**\r\n * An override value. Supports scalars, color/vector arrays, object references,\r\n * and null (used to clear a slot, e.g. removing a material assignment).\r\n * - number: scalar property (e.g., intensity, alpha)\r\n * - string: string property, or \"ref:name\" / \"samTexture:key\" / \"texture:name\" object reference\r\n * - boolean: boolean property\r\n * - number[]: array property mapped to Vector3, Color3, Color4, etc.\r\n * - null: explicitly clear an object-typed slot\r\n */\r\nexport type OverrideValue = number | string | boolean | number[] | null;\r\n"]}
|
|
1
|
+
{"version":3,"file":"overrideEntry.js","sourceRoot":"","sources":["../../../../dev/sharedUiComponents/src/projects/overrideEntry.ts"],"names":[],"mappings":"","sourcesContent":["/**\r\n * Defines the shape of an override entry — a property diff applied to a\r\n * scene object identified by name. Overrides target any object in the\r\n * scene's standard collections (meshes, materials, lights, etc.) regardless\r\n * of how that object was created.\r\n */\r\nexport interface IOverrideEntry {\r\n /** The type of object to target (e.g., \"meshes\", \"materials\", \"lights\"). */\r\n readonly targetType: OverrideTargetType;\r\n\r\n /** The name of the target object. Use \"\" for scene-level overrides. */\r\n readonly targetName: string;\r\n\r\n /**\r\n * Disambiguator for when multiple objects in `scene[targetType]` share the\r\n * same `targetName`. The override applies to the N-th match (0-based) at\r\n * apply time. When names are unique, use 0.\r\n */\r\n readonly targetIndex: number;\r\n\r\n /** Dot-separated property path on the target (e.g., \"albedoColor\", \"position.x\"). */\r\n readonly propertyPath: string;\r\n\r\n /** The override value. */\r\n readonly value: OverrideValue;\r\n}\r\n\r\n/**\r\n * The types of scene objects that can be targeted by overrides.\r\n */\r\nexport type OverrideTargetType = \"meshes\" | \"transformNodes\" | \"materials\" | \"textures\" | \"lights\" | \"cameras\" | \"animationGroups\" | \"scene\";\r\n\r\n/**\r\n * An override value. Supports scalars, color/vector arrays, object references,\r\n * and null (used to clear a slot, e.g. removing a material assignment).\r\n * - number: scalar property (e.g., intensity, alpha)\r\n * - string: string property, or \"ref:name\" / \"samTexture:key\" / \"texture:name\" object reference\r\n * - boolean: boolean property\r\n * - number[]: array property mapped to Vector3, Color3, Color4, etc.\r\n * - null: explicitly clear an object-typed slot\r\n */\r\nexport type OverrideValue = number | string | boolean | number[] | null;\r\n"]}
|
|
@@ -244,9 +244,38 @@ export function RenameOverrideValueReferences(scene, valueScheme, oldName, newNa
|
|
|
244
244
|
export function ApplyAllOverrides(scene) {
|
|
245
245
|
const manager = GetOverrideManager(scene);
|
|
246
246
|
const internal = GetOverrideInternals(manager);
|
|
247
|
-
for (const entry of internal.overrides) {
|
|
248
|
-
|
|
247
|
+
for (const entry of SortNameOverridesFirst(internal.overrides)) {
|
|
248
|
+
// Apply each override in isolation: a single failing entry (e.g. a
|
|
249
|
+
// stale property path, or a target whose shape changed) must not abort
|
|
250
|
+
// the remaining overrides.
|
|
251
|
+
try {
|
|
252
|
+
ApplyOverrideEntry(manager, internal, entry);
|
|
253
|
+
}
|
|
254
|
+
catch (e) {
|
|
255
|
+
Logger.Warn(`OverrideManager: failed to apply override type="${entry.targetType}" name="${entry.targetName}" prop="${entry.propertyPath}": ${e}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Returns a copy of the entries ordered so that `name` overrides are applied
|
|
261
|
+
* first. Renames must run before other overrides because targets (and
|
|
262
|
+
* reference values like `ref:<name>`) are resolved by name: applying a rename
|
|
263
|
+
* first ensures subsequent overrides resolve against the new names.
|
|
264
|
+
* @param entries - The override entries to order.
|
|
265
|
+
* @returns A new array with `name` overrides first, otherwise stable order.
|
|
266
|
+
*/
|
|
267
|
+
function SortNameOverridesFirst(entries) {
|
|
268
|
+
const nameOverrides = [];
|
|
269
|
+
const rest = [];
|
|
270
|
+
for (const entry of entries) {
|
|
271
|
+
if (entry.propertyPath === "name") {
|
|
272
|
+
nameOverrides.push(entry);
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
rest.push(entry);
|
|
276
|
+
}
|
|
249
277
|
}
|
|
278
|
+
return [...nameOverrides, ...rest];
|
|
250
279
|
}
|
|
251
280
|
// ── Serialization ──
|
|
252
281
|
/**
|
|
@@ -268,7 +297,7 @@ export function DeserializeAndApplyOverrides(scene, data) {
|
|
|
268
297
|
if (!Array.isArray(data)) {
|
|
269
298
|
throw new Error("OverrideManager: Expected an array of override entries.");
|
|
270
299
|
}
|
|
271
|
-
for (const entry of data) {
|
|
300
|
+
for (const entry of SortNameOverridesFirst(data)) {
|
|
272
301
|
if (!entry.targetType || entry.targetName === undefined || typeof entry.targetIndex !== "number" || !entry.propertyPath || entry.value === undefined) {
|
|
273
302
|
Logger.Warn("OverrideManager: Skipping invalid override entry.");
|
|
274
303
|
continue;
|
|
@@ -368,6 +397,8 @@ function GetCollection(scene, targetType) {
|
|
|
368
397
|
switch (targetType) {
|
|
369
398
|
case "meshes":
|
|
370
399
|
return scene.meshes;
|
|
400
|
+
case "transformNodes":
|
|
401
|
+
return scene.transformNodes;
|
|
371
402
|
case "materials":
|
|
372
403
|
return scene.materials;
|
|
373
404
|
case "textures":
|
|
@@ -407,24 +438,20 @@ function ResolveOverrideValue(scene, value) {
|
|
|
407
438
|
return value;
|
|
408
439
|
}
|
|
409
440
|
/**
|
|
410
|
-
* Resolves a "ref:name" value by looking up a
|
|
411
|
-
*
|
|
441
|
+
* Resolves a "ref:name" value by looking up a scene object by name. Materials,
|
|
442
|
+
* lights, and cameras are searched first, then transform nodes and meshes
|
|
443
|
+
* (both valid parent references).
|
|
412
444
|
* @param scene - The scene to search.
|
|
413
445
|
* @param name - The object name to resolve.
|
|
414
|
-
* @returns The matching
|
|
446
|
+
* @returns The matching object, or undefined if not found.
|
|
415
447
|
*/
|
|
416
448
|
function ResolveObjectReference(scene, name) {
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
return light;
|
|
424
|
-
}
|
|
425
|
-
const camera = scene.cameras.find((c) => c.name === name);
|
|
426
|
-
if (camera) {
|
|
427
|
-
return camera;
|
|
449
|
+
const collections = [scene.materials, scene.lights, scene.cameras, scene.transformNodes, scene.meshes];
|
|
450
|
+
for (const collection of collections) {
|
|
451
|
+
const match = collection.find((item) => item.name === name);
|
|
452
|
+
if (match) {
|
|
453
|
+
return match;
|
|
454
|
+
}
|
|
428
455
|
}
|
|
429
456
|
Logger.Warn(`OverrideManager: Object reference "${name}" not found in scene.`);
|
|
430
457
|
return undefined;
|
|
@@ -524,6 +551,12 @@ function GetNestedProperty(obj, path) {
|
|
|
524
551
|
* `fromArray` method to mutate it in place — preserving the live instance
|
|
525
552
|
* identity that consumers may already hold references to. Otherwise falls
|
|
526
553
|
* back to direct property replacement.
|
|
554
|
+
*
|
|
555
|
+
* Getter-only accessors (e.g. `Texture.invertY`) cannot be assigned directly —
|
|
556
|
+
* doing so throws in strict mode. For those, the backing field (`_<name>`) is
|
|
557
|
+
* written instead when present, and load-time texture properties are re-applied
|
|
558
|
+
* via a re-upload (see {@link ReapplyLoadTimeTextureProperty}). Truly read-only
|
|
559
|
+
* properties with no backing field are skipped with a warning.
|
|
527
560
|
* @param obj - The root object to mutate.
|
|
528
561
|
* @param path - The dot-separated property path.
|
|
529
562
|
* @param value - The new value to assign.
|
|
@@ -540,13 +573,73 @@ function SetNestedProperty(obj, path, value) {
|
|
|
540
573
|
if (current === null || current === undefined || typeof current !== "object") {
|
|
541
574
|
return;
|
|
542
575
|
}
|
|
576
|
+
const target = current;
|
|
543
577
|
const lastPart = parts[parts.length - 1];
|
|
544
|
-
const existing =
|
|
578
|
+
const existing = target[lastPart];
|
|
545
579
|
if (Array.isArray(value) && existing && typeof existing === "object" && typeof existing.fromArray === "function") {
|
|
546
580
|
existing.fromArray(value);
|
|
547
581
|
return;
|
|
548
582
|
}
|
|
549
|
-
|
|
583
|
+
// Guard against getter-only accessors: assigning to one throws in strict
|
|
584
|
+
// mode (ES modules are strict), which would otherwise abort the whole apply
|
|
585
|
+
// batch. Write the backing field instead, then re-apply if it is a
|
|
586
|
+
// load-time texture property.
|
|
587
|
+
const accessor = FindAccessorDescriptor(target, lastPart);
|
|
588
|
+
if (accessor && accessor.get && !accessor.set) {
|
|
589
|
+
const backingField = `_${lastPart}`;
|
|
590
|
+
if (backingField in target) {
|
|
591
|
+
target[backingField] = value;
|
|
592
|
+
ReapplyLoadTimeTextureProperty(target, lastPart);
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
Logger.Warn(`OverrideManager: property "${lastPart}" is read-only and has no backing field; skipping.`);
|
|
596
|
+
}
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
target[lastPart] = value;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Walks the prototype chain to find the property descriptor for `key`, so
|
|
603
|
+
* accessor (getter/setter) properties defined on a class prototype can be
|
|
604
|
+
* detected. Returns undefined if the property is a plain data field.
|
|
605
|
+
* @param obj - The object to inspect.
|
|
606
|
+
* @param key - The property name.
|
|
607
|
+
* @returns The property descriptor, or undefined if none is found.
|
|
608
|
+
*/
|
|
609
|
+
function FindAccessorDescriptor(obj, key) {
|
|
610
|
+
let proto = obj;
|
|
611
|
+
while (proto) {
|
|
612
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, key);
|
|
613
|
+
if (descriptor) {
|
|
614
|
+
return descriptor;
|
|
615
|
+
}
|
|
616
|
+
proto = Object.getPrototypeOf(proto);
|
|
617
|
+
}
|
|
618
|
+
return undefined;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Re-applies a texture property that only takes effect at upload time (such as
|
|
622
|
+
* `invertY`, which is baked into the GPU texel data via `UNPACK_FLIP_Y`).
|
|
623
|
+
* Writing the backing field alone does not re-flip an already-loaded texture,
|
|
624
|
+
* so this re-uploads the source via `updateURL`, which releases only the GPU
|
|
625
|
+
* texture and reuses the same texture instance (all scene references stay
|
|
626
|
+
* intact). Duck-typed so this module stays decoupled from the Texture class,
|
|
627
|
+
* and a no-op for anything that is not a URL-loaded texture.
|
|
628
|
+
* @param target - The object whose property was written.
|
|
629
|
+
* @param propertyName - The property that was written.
|
|
630
|
+
*/
|
|
631
|
+
function ReapplyLoadTimeTextureProperty(target, propertyName) {
|
|
632
|
+
if (propertyName !== "invertY") {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
if (typeof target.updateURL === "function" && typeof target.url === "string" && target.url) {
|
|
636
|
+
try {
|
|
637
|
+
target.updateURL(target.url, target._buffer ?? null);
|
|
638
|
+
}
|
|
639
|
+
catch (e) {
|
|
640
|
+
Logger.Warn(`OverrideManager: failed to re-upload texture to apply "${propertyName}": ${e}`);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
550
643
|
}
|
|
551
644
|
/**
|
|
552
645
|
* Snapshots a value for original-value tracking.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overrideManager.js","sourceRoot":"","sources":["../../../../dev/sharedUiComponents/src/projects/overrideManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Scene } from \"core/scene\";\r\nimport { Observable, type Observer } from \"core/Misc/observable\";\r\nimport { Logger } from \"core/Misc/logger\";\r\nimport { FindSmartAssetKeyForObject } from \"core/SmartAssets/smartAssetManager.pure\";\r\nimport { type IOverrideEntry, type OverrideTargetType, type OverrideValue } from \"./overrideEntry\";\r\n\r\nconst OverrideManagerKey = Symbol(\"babylonjs:overrideManager\");\r\n\r\n/**\r\n * Stateful handle for a scene's property override registry.\r\n *\r\n * Override behavior is exposed through module-level functions rather than\r\n * class methods so callers can import only the operations they need.\r\n *\r\n * Overrides are property diffs applied to scene objects identified by name.\r\n * They persist across reloads and are typically saved alongside a project\r\n * file. The override manager is fully independent of any other scene\r\n * subsystem (SmartAssetManager, loaders, etc.) — it works with any object\r\n * in the scene's standard collections (meshes, materials, lights, …)\r\n * regardless of how that object was created.\r\n *\r\n * When multiple objects share a name (e.g. two materials both called\r\n * \"Default\" loaded from different glTFs), {@link IOverrideEntry.targetIndex}\r\n * disambiguates: it stores the object's position among same-named siblings\r\n * at capture time and is used to pick the correct one at apply time.\r\n *\r\n * @example\r\n * ```typescript\r\n * AddOverride(scene, {\r\n * targetType: \"materials\",\r\n * targetName: \"canPaint\",\r\n * targetIndex: 0,\r\n * propertyPath: \"albedoColor\",\r\n * value: [1, 0, 0],\r\n * });\r\n * ```\r\n */\r\nexport type OverrideManager = {\r\n /**\r\n * The scene this manager is attached to.\r\n */\r\n readonly scene: Scene;\r\n\r\n /**\r\n * Fires whenever the override registry or applied state changes.\r\n */\r\n readonly onChangedObservable: Observable<void>;\r\n};\r\n\r\ntype OverrideManagerInternals = {\r\n overrides: IOverrideEntry[];\r\n originalValues: Map<string, unknown>;\r\n sceneDisposeObserver: ReturnType<Scene[\"onDisposeObservable\"][\"add\"]> | null;\r\n};\r\n\r\nconst OverrideManagerInternals = new WeakMap<OverrideManager, OverrideManagerInternals>();\r\nconst OnOverrideManagerCreatedObservable = new Observable<OverrideManager>();\r\n\r\n/**\r\n * Creates a new OverrideManager state object and attaches it to the scene.\r\n *\r\n * Internal: callers should use {@link GetOverrideManager} which returns the\r\n * existing manager when one is already attached.\r\n * @param scene - The scene this manager operates on.\r\n * @returns The created override manager state.\r\n */\r\nfunction CreateOverrideManager(scene: Scene): OverrideManager {\r\n const manager: OverrideManager = {\r\n scene,\r\n onChangedObservable: new Observable<void>(),\r\n };\r\n\r\n const internal: OverrideManagerInternals = {\r\n overrides: [],\r\n originalValues: new Map(),\r\n sceneDisposeObserver: null,\r\n };\r\n OverrideManagerInternals.set(manager, internal);\r\n\r\n if (!scene.metadata) {\r\n scene.metadata = {};\r\n }\r\n scene.metadata[OverrideManagerKey] = manager;\r\n\r\n // Auto-dispose when the scene is disposed so the manager doesn't outlive it.\r\n internal.sceneDisposeObserver = scene.onDisposeObservable.add(() => DisposeOverrideManager(manager));\r\n\r\n OnOverrideManagerCreatedObservable.notifyObservers(manager);\r\n\r\n return manager;\r\n}\r\n\r\n/**\r\n * Returns the OverrideManager attached to the given scene, creating and\r\n * attaching one if none exists.\r\n * @param scene - The scene to look up or attach a manager to.\r\n * @returns The existing or newly created OverrideManager.\r\n */\r\nexport function GetOverrideManager(scene: Scene): OverrideManager {\r\n const existing = scene.metadata?.[OverrideManagerKey] as OverrideManager | undefined;\r\n if (existing) {\r\n return existing;\r\n }\r\n return CreateOverrideManager(scene);\r\n}\r\n\r\n/**\r\n * Adds an observer that is notified whenever an OverrideManager is created.\r\n * @param callback - The callback to invoke with each newly created manager.\r\n * @returns The observer registration.\r\n */\r\nexport function AddOverrideManagerCreatedObserver(callback: (manager: OverrideManager) => void): Observer<OverrideManager> {\r\n return OnOverrideManagerCreatedObservable.add((manager) => callback(manager));\r\n}\r\n\r\n// ── Override CRUD ──\r\n\r\n/**\r\n * Options for {@link AddOverride}.\r\n */\r\nexport type AddOverrideOptions = {\r\n /**\r\n * If the `originalValue` field is present, the override is recorded *without*\r\n * re-applying it (the caller is presumed to have already mutated the entity)\r\n * and the field's content is captured as the property's pre-override\r\n * \"original\" so {@link RemoveOverride} can restore it later.\r\n *\r\n * Inspector-driven edits use this: by the time `onPropertyChanged` fires,\r\n * the binding has already written the new value, but it still has the prior\r\n * value in hand. Without this seeding path, an override created via\r\n * Inspector could never be reverted (the manager would have no record of\r\n * the pre-edit value).\r\n *\r\n * If the field is absent, the override is applied normally and the original\r\n * is captured by reading the property's current value on first apply.\r\n */\r\n readonly originalValue?: unknown;\r\n};\r\n\r\n/**\r\n * Adds an override entry and immediately applies it.\r\n * If an override with the same target coordinates already exists, it is replaced.\r\n *\r\n * When the caller has already mutated the target (e.g. an Inspector edit),\r\n * pass `{ originalValue }` containing the property's prior value — this seeds\r\n * the original-value map (so {@link RemoveOverride} can restore it) and skips\r\n * the redundant apply step.\r\n * @param scene - The scene whose override registry to update.\r\n * @param entry - The override to add.\r\n * @param options - Optional behavior modifiers; see {@link AddOverrideOptions}.\r\n */\r\nexport function AddOverride(scene: Scene, entry: IOverrideEntry, options?: AddOverrideOptions): void {\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n\r\n RemoveMatchingOverride(internal, entry.targetType, entry.targetName, entry.targetIndex, entry.propertyPath);\r\n internal.overrides.push(entry);\r\n\r\n if (options && \"originalValue\" in options) {\r\n // Caller already applied the new value. Seed the captured original from\r\n // their pre-edit snapshot — otherwise ApplyOverrideEntry would capture\r\n // the post-edit value and RemoveOverride would have nothing to restore.\r\n const origKey = MakeOriginalValueKey(entry.targetType, entry.targetName, entry.targetIndex, entry.propertyPath);\r\n if (!internal.originalValues.has(origKey)) {\r\n internal.originalValues.set(origKey, CloneValue(options.originalValue));\r\n }\r\n } else {\r\n ApplyOverrideEntry(manager, internal, entry);\r\n }\r\n\r\n manager.onChangedObservable.notifyObservers();\r\n}\r\n\r\n/**\r\n * Removes a single override matching the given coordinates. Restores the\r\n * original value if one was captured.\r\n * @param scene - The scene whose override registry to update.\r\n * @param targetType - The target type.\r\n * @param targetName - The target object name.\r\n * @param targetIndex - The target index among same-named siblings.\r\n * @param propertyPath - The property path to un-override.\r\n * @returns True if an override was removed.\r\n */\r\nexport function RemoveOverride(scene: Scene, targetType: OverrideTargetType, targetName: string, targetIndex: number, propertyPath: string): boolean {\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n\r\n const idx = FindOverrideIndex(internal, targetType, targetName, targetIndex, propertyPath);\r\n if (idx < 0) {\r\n return false;\r\n }\r\n\r\n internal.overrides.splice(idx, 1);\r\n\r\n const origKey = MakeOriginalValueKey(targetType, targetName, targetIndex, propertyPath);\r\n const original = internal.originalValues.get(origKey);\r\n if (original !== undefined) {\r\n const target = ResolveTarget(manager.scene, targetType, targetName, targetIndex);\r\n if (target) {\r\n SetNestedProperty(target, propertyPath, original);\r\n }\r\n internal.originalValues.delete(origKey);\r\n }\r\n\r\n manager.onChangedObservable.notifyObservers();\r\n return true;\r\n}\r\n\r\n/**\r\n * Returns all overrides currently registered with the scene.\r\n * @param scene - The scene whose override registry to read.\r\n * @returns A read-only array of override entries.\r\n */\r\nexport function GetOverrides(scene: Scene): readonly IOverrideEntry[] {\r\n return GetOverrideInternals(GetOverrideManager(scene)).overrides;\r\n}\r\n\r\n/**\r\n * Removes all overrides, optionally restoring original values.\r\n * @param scene - The scene whose override registry to clear.\r\n * @param restoreOriginals - If true, restores all captured original values.\r\n */\r\nexport function ClearOverrides(scene: Scene, restoreOriginals: boolean = false): void {\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n\r\n if (restoreOriginals) {\r\n // Snapshot the entries so we can restore each original without firing\r\n // an onChangedObservable notification per entry; consumers only need\r\n // one signal that the registry was emptied.\r\n const entries = [...internal.overrides];\r\n internal.overrides.length = 0;\r\n for (const entry of entries) {\r\n const origKey = MakeOriginalValueKey(entry.targetType, entry.targetName, entry.targetIndex, entry.propertyPath);\r\n const original = internal.originalValues.get(origKey);\r\n if (original !== undefined) {\r\n const target = ResolveTarget(manager.scene, entry.targetType, entry.targetName, entry.targetIndex);\r\n if (target) {\r\n SetNestedProperty(target, entry.propertyPath, original);\r\n }\r\n }\r\n }\r\n internal.originalValues.clear();\r\n manager.onChangedObservable.notifyObservers();\r\n return;\r\n }\r\n\r\n internal.overrides.length = 0;\r\n internal.originalValues.clear();\r\n manager.onChangedObservable.notifyObservers();\r\n}\r\n\r\n/**\r\n * Updates the target coordinates on the override matching a specific (type,\r\n * old-name, old-index) so it follows an entity rename. Used by capture services\r\n * to keep overrides attached to a specific object after the user renames it.\r\n *\r\n * Only the override at the exact `(targetType, oldName, oldIndex)` slot is\r\n * updated, so other same-named siblings keep their own overrides untouched.\r\n *\r\n * @param scene - The scene whose override registry to update.\r\n * @param targetType - The target type.\r\n * @param oldName - The previous name of the renamed entity.\r\n * @param oldIndex - The previous index of the renamed entity among same-named siblings.\r\n * @param newName - The new name of the renamed entity.\r\n * @param newIndex - The new index of the renamed entity among same-named siblings.\r\n */\r\nexport function RenameOverrideTarget(scene: Scene, targetType: OverrideTargetType, oldName: string, oldIndex: number, newName: string, newIndex: number): void {\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n\r\n let changed = false;\r\n for (let i = 0; i < internal.overrides.length; i++) {\r\n const entry = internal.overrides[i];\r\n if (entry.targetType === targetType && entry.targetName === oldName && entry.targetIndex === oldIndex) {\r\n internal.overrides[i] = { ...entry, targetName: newName, targetIndex: newIndex };\r\n changed = true;\r\n }\r\n }\r\n\r\n // Update original-value keys to match the new identity\r\n const oldPrefix = `${targetType}::${oldName}::${oldIndex}::`;\r\n const newPrefix = `${targetType}::${newName}::${newIndex}::`;\r\n for (const [origKey, value] of Array.from(internal.originalValues.entries())) {\r\n if (origKey.startsWith(oldPrefix)) {\r\n const propertyPath = origKey.substring(oldPrefix.length);\r\n internal.originalValues.set(newPrefix + propertyPath, value);\r\n internal.originalValues.delete(origKey);\r\n }\r\n }\r\n\r\n if (changed) {\r\n manager.onChangedObservable.notifyObservers();\r\n }\r\n}\r\n\r\n/**\r\n * Rewrites override *values* that reference an entity by name when that entity\r\n * has been renamed. Mirrors {@link RenameOverrideTarget} but operates on the\r\n * `value` field rather than the `targetName` field, so overrides whose value\r\n * is `\"ref:oldName\"` (material/light/camera references) or `\"texture:oldName\"`\r\n * (non-SmartAsset texture references) follow the rename instead of silently\r\n * pointing at a non-existent entity.\r\n *\r\n * SmartAsset texture references (`\"samTexture:<key>\"`) are unaffected because\r\n * the SmartAsset key is decoupled from the texture's runtime `name` field.\r\n *\r\n * @param scene - The scene whose override registry to update.\r\n * @param valueScheme - Which encoded-reference prefix to rewrite: `\"ref\"` for\r\n * material/light/camera references, `\"texture\"` for non-SAM textures.\r\n * @param oldName - The previous name embedded in the reference.\r\n * @param newName - The new name embedded in the reference.\r\n */\r\nexport function RenameOverrideValueReferences(scene: Scene, valueScheme: \"ref\" | \"texture\", oldName: string, newName: string): void {\r\n if (oldName === newName) {\r\n return;\r\n }\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n\r\n const oldValue = `${valueScheme}:${oldName}`;\r\n const newValue = `${valueScheme}:${newName}`;\r\n\r\n let changed = false;\r\n for (let i = 0; i < internal.overrides.length; i++) {\r\n const entry = internal.overrides[i];\r\n if (entry.value === oldValue) {\r\n internal.overrides[i] = { ...entry, value: newValue };\r\n changed = true;\r\n }\r\n }\r\n\r\n if (changed) {\r\n manager.onChangedObservable.notifyObservers();\r\n }\r\n}\r\n\r\n// ── Application ──\r\n\r\n/**\r\n * Applies all overrides to their current targets in the scene.\r\n *\r\n * Call this after any scene mutation that might have invalidated previously\r\n * applied state (asset reload, object recreation, project load). The override\r\n * manager does not auto-subscribe to other scene subsystems — coordination is\r\n * the caller's responsibility, which keeps the override system independent.\r\n * @param scene - The scene whose overrides to apply.\r\n */\r\nexport function ApplyAllOverrides(scene: Scene): void {\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n for (const entry of internal.overrides) {\r\n ApplyOverrideEntry(manager, internal, entry);\r\n }\r\n}\r\n\r\n// ── Serialization ──\r\n\r\n/**\r\n * Serializes all overrides to a JSON-compatible array.\r\n * The on-disk shape is identical to the in-memory `IOverrideEntry`.\r\n * @param scene - The scene whose overrides to serialize.\r\n * @returns An array of override entries (shallow copies).\r\n */\r\nexport function SerializeOverrides(scene: Scene): IOverrideEntry[] {\r\n const internal = GetOverrideInternals(GetOverrideManager(scene));\r\n return internal.overrides.map((o) => ({ ...o }));\r\n}\r\n\r\n/**\r\n * Loads overrides from a serialized array and applies them.\r\n * @param scene - The scene whose override registry to populate.\r\n * @param data - Array of override entries.\r\n */\r\nexport function DeserializeAndApplyOverrides(scene: Scene, data: IOverrideEntry[]): void {\r\n if (!Array.isArray(data)) {\r\n throw new Error(\"OverrideManager: Expected an array of override entries.\");\r\n }\r\n\r\n for (const entry of data) {\r\n if (!entry.targetType || entry.targetName === undefined || typeof entry.targetIndex !== \"number\" || !entry.propertyPath || entry.value === undefined) {\r\n Logger.Warn(\"OverrideManager: Skipping invalid override entry.\");\r\n continue;\r\n }\r\n AddOverride(scene, entry);\r\n }\r\n}\r\n\r\n// ── Lifecycle ──\r\n\r\n/**\r\n * Disposes the manager, clearing all overrides and detaching it from its scene.\r\n * Safe to call multiple times; subsequent calls are no-ops. Automatically invoked when the\r\n * owning scene is disposed.\r\n * @param manager - The override manager state.\r\n */\r\nexport function DisposeOverrideManager(manager: OverrideManager): void {\r\n const internal = OverrideManagerInternals.get(manager);\r\n if (!internal) {\r\n return;\r\n }\r\n OverrideManagerInternals.delete(manager);\r\n\r\n if (internal.sceneDisposeObserver) {\r\n manager.scene.onDisposeObservable.remove(internal.sceneDisposeObserver);\r\n internal.sceneDisposeObserver = null;\r\n }\r\n\r\n internal.overrides.length = 0;\r\n internal.originalValues.clear();\r\n\r\n manager.onChangedObservable.clear();\r\n\r\n if (manager.scene.metadata) {\r\n delete manager.scene.metadata[OverrideManagerKey];\r\n }\r\n}\r\n\r\n// ── Private ──\r\n\r\nfunction GetOverrideInternals(manager: OverrideManager): OverrideManagerInternals {\r\n const internal = OverrideManagerInternals.get(manager);\r\n if (!internal) {\r\n throw new Error(\"OverrideManager: Unknown manager state.\");\r\n }\r\n return internal;\r\n}\r\n\r\n/**\r\n * Applies a single override entry to its target, capturing the original value\r\n * on the first application so {@link RemoveOverride} can restore it later.\r\n * @param manager - The override manager owning the entry.\r\n * @param internal - The manager's internal state.\r\n * @param entry - The override to apply.\r\n */\r\nfunction ApplyOverrideEntry(manager: OverrideManager, internal: OverrideManagerInternals, entry: IOverrideEntry): void {\r\n const target = ResolveTarget(manager.scene, entry.targetType, entry.targetName, entry.targetIndex);\r\n if (!target) {\r\n Logger.Warn(`OverrideManager: target not found for type=\"${entry.targetType}\" name=\"${entry.targetName}\" index=${entry.targetIndex} prop=\"${entry.propertyPath}\"`);\r\n return; // Target not loaded yet — override will be applied on next ApplyAllOverrides\r\n }\r\n\r\n // Capture original value before first override\r\n const origKey = MakeOriginalValueKey(entry.targetType, entry.targetName, entry.targetIndex, entry.propertyPath);\r\n if (!internal.originalValues.has(origKey)) {\r\n const currentValue = GetNestedProperty(target, entry.propertyPath);\r\n if (currentValue !== undefined) {\r\n internal.originalValues.set(origKey, CloneValue(currentValue));\r\n }\r\n }\r\n\r\n const resolvedValue = ResolveOverrideValue(manager.scene, entry.value);\r\n SetNestedProperty(target, entry.propertyPath, resolvedValue);\r\n}\r\n\r\n/**\r\n * Locates a scene object by (targetType, targetName, targetIndex). The scene\r\n * collection is filtered to objects matching `targetName`; the N-th survivor\r\n * (per `targetIndex`) is returned. Falls back to the first match if the index\r\n * is out of range — useful when the scene shape has changed since capture.\r\n * @param scene - The scene to search.\r\n * @param targetType - The override target type.\r\n * @param targetName - The target object name (or \"\" for scene-level).\r\n * @param targetIndex - The target's position among same-named siblings.\r\n * @returns The matching scene object, or null if not found.\r\n */\r\nfunction ResolveTarget(scene: Scene, targetType: OverrideTargetType, targetName: string, targetIndex: number): object | null {\r\n // Scene-level overrides target the scene itself\r\n if (targetType === \"scene\") {\r\n return scene as unknown as object;\r\n }\r\n\r\n const collection = GetCollection(scene, targetType);\r\n if (!collection) {\r\n return null;\r\n }\r\n\r\n const matches = collection.filter((obj) => (obj as { name?: string }).name === targetName);\r\n if (matches.length === 0) {\r\n return null;\r\n }\r\n return (matches[targetIndex] ?? matches[0]) as object;\r\n}\r\n\r\n/**\r\n * Returns the scene collection corresponding to an override target type.\r\n * @param scene - The scene to inspect.\r\n * @param targetType - The target type.\r\n * @returns The collection, or null if the type has no collection.\r\n */\r\nfunction GetCollection(scene: Scene, targetType: OverrideTargetType): readonly unknown[] | null {\r\n switch (targetType) {\r\n case \"meshes\":\r\n return scene.meshes;\r\n case \"materials\":\r\n return scene.materials;\r\n case \"textures\":\r\n return scene.textures;\r\n case \"lights\":\r\n return scene.lights;\r\n case \"cameras\":\r\n return scene.cameras;\r\n case \"animationGroups\":\r\n return scene.animationGroups;\r\n default:\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Resolves an override value, expanding string references like \"ref:name\",\r\n * \"samTexture:key\", or \"texture:name\" into the actual scene object they refer to.\r\n * @param scene - The scene used to look up references.\r\n * @param value - The serialized override value.\r\n * @returns The runtime value to assign to the target property.\r\n */\r\nfunction ResolveOverrideValue(scene: Scene, value: OverrideValue): unknown {\r\n if (typeof value === \"string\") {\r\n if (value.startsWith(\"ref:\")) {\r\n return ResolveObjectReference(scene, value.substring(4));\r\n }\r\n if (value.startsWith(\"samTexture:\")) {\r\n return ResolveSamTextureReference(scene, value.substring(11));\r\n }\r\n if (value.startsWith(\"texture:\")) {\r\n return ResolveTextureReference(scene, value.substring(8));\r\n }\r\n }\r\n\r\n // Number arrays are passed through as-is. SetNestedProperty will use\r\n // the live target's `fromArray` method (Vector3, Color3, etc.) to push\r\n // values in-place, preserving the math instance identity.\r\n return value;\r\n}\r\n\r\n/**\r\n * Resolves a \"ref:name\" value by looking up a material, light, or camera\r\n * in the scene by name.\r\n * @param scene - The scene to search.\r\n * @param name - The object name to resolve.\r\n * @returns The matching material, light, or camera, or undefined if not found.\r\n */\r\nfunction ResolveObjectReference(scene: Scene, name: string): unknown {\r\n const mat = scene.materials.find((m) => m.name === name);\r\n if (mat) {\r\n return mat;\r\n }\r\n const light = scene.lights.find((l) => l.name === name);\r\n if (light) {\r\n return light;\r\n }\r\n const camera = scene.cameras.find((c) => c.name === name);\r\n if (camera) {\r\n return camera;\r\n }\r\n Logger.Warn(`OverrideManager: Object reference \"${name}\" not found in scene.`);\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Resolves a \"texture:name\" value by looking up a texture in the scene by name.\r\n * @param scene - The scene to search.\r\n * @param name - The texture name to resolve.\r\n * @returns The matching texture, or undefined if not found.\r\n */\r\nfunction ResolveTextureReference(scene: Scene, name: string): unknown {\r\n const tex = scene.textures.find((t) => t.name === name);\r\n if (tex) {\r\n return tex;\r\n }\r\n Logger.Warn(`OverrideManager: Texture reference \"${name}\" not found.`);\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Resolves a \"samTexture:key\" value by looking up a SmartAsset-tracked texture\r\n * by its registry key. The SAM key is stable across save/load whereas the\r\n * texture's `name` (for SAM textures, the blob URL) changes on every reload,\r\n * so this is the only reliable way to round-trip texture references on\r\n * user-uploaded SmartAsset textures.\r\n * @param scene - The scene to search.\r\n * @param key - The SmartAsset key to resolve.\r\n * @returns The matching texture, or undefined if not found.\r\n */\r\nfunction ResolveSamTextureReference(scene: Scene, key: string): unknown {\r\n const tex = scene.textures.find((t) => FindSmartAssetKeyForObject(scene, t) === key);\r\n if (tex) {\r\n return tex;\r\n }\r\n Logger.Warn(`OverrideManager: SmartAsset texture \"${key}\" not found.`);\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Finds the index of an override matching the given coordinates.\r\n * @param internal - The manager's internal state.\r\n * @param targetType - The target type.\r\n * @param targetName - The target object name.\r\n * @param targetIndex - The target index among same-named siblings.\r\n * @param propertyPath - The property path.\r\n * @returns The matching index, or -1 if none found.\r\n */\r\nfunction FindOverrideIndex(internal: OverrideManagerInternals, targetType: OverrideTargetType, targetName: string, targetIndex: number, propertyPath: string): number {\r\n return internal.overrides.findIndex((o) => o.targetType === targetType && o.targetName === targetName && o.targetIndex === targetIndex && o.propertyPath === propertyPath);\r\n}\r\n\r\n/**\r\n * Removes any existing override that matches the given coordinates. Used by\r\n * {@link AddOverride} to enforce one entry per (type, name, index, property).\r\n * @param internal - The manager's internal state.\r\n * @param targetType - The target type.\r\n * @param targetName - The target object name.\r\n * @param targetIndex - The target index among same-named siblings.\r\n * @param propertyPath - The property path.\r\n */\r\nfunction RemoveMatchingOverride(internal: OverrideManagerInternals, targetType: OverrideTargetType, targetName: string, targetIndex: number, propertyPath: string): void {\r\n const idx = FindOverrideIndex(internal, targetType, targetName, targetIndex, propertyPath);\r\n if (idx >= 0) {\r\n internal.overrides.splice(idx, 1);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a unique key for storing original values.\r\n * @param targetType - The override target type.\r\n * @param targetName - The target object name.\r\n * @param targetIndex - The target index among same-named siblings.\r\n * @param propertyPath - The property path.\r\n * @returns A composite string key uniquely identifying the original value slot.\r\n */\r\nfunction MakeOriginalValueKey(targetType: OverrideTargetType, targetName: string, targetIndex: number, propertyPath: string): string {\r\n return `${targetType}::${targetName}::${targetIndex}::${propertyPath}`;\r\n}\r\n\r\n/**\r\n * Gets a nested property from an object using a dot-separated path.\r\n * @param obj - The root object to traverse.\r\n * @param path - The dot-separated property path.\r\n * @returns The value at the path, or undefined if any segment is missing.\r\n */\r\nfunction GetNestedProperty(obj: object, path: string): unknown {\r\n const parts = path.split(\".\");\r\n let current: unknown = obj;\r\n\r\n for (const part of parts) {\r\n if (current === null || current === undefined || typeof current !== \"object\") {\r\n return undefined;\r\n }\r\n current = (current as Record<string, unknown>)[part];\r\n }\r\n\r\n return current;\r\n}\r\n\r\n/**\r\n * Sets a nested property on an object using a dot-separated path.\r\n *\r\n * When the value is a number array and the existing property is a Babylon\r\n * math type (Vector*, Quaternion, Color3/4, Matrix), uses the math type's\r\n * `fromArray` method to mutate it in place — preserving the live instance\r\n * identity that consumers may already hold references to. Otherwise falls\r\n * back to direct property replacement.\r\n * @param obj - The root object to mutate.\r\n * @param path - The dot-separated property path.\r\n * @param value - The new value to assign.\r\n */\r\nfunction SetNestedProperty(obj: object, path: string, value: unknown): void {\r\n const parts = path.split(\".\");\r\n let current: unknown = obj;\r\n\r\n for (let i = 0; i < parts.length - 1; i++) {\r\n if (current === null || current === undefined || typeof current !== \"object\") {\r\n return;\r\n }\r\n current = (current as Record<string, unknown>)[parts[i]];\r\n }\r\n\r\n if (current === null || current === undefined || typeof current !== \"object\") {\r\n return;\r\n }\r\n\r\n const lastPart = parts[parts.length - 1];\r\n const existing = (current as Record<string, unknown>)[lastPart];\r\n\r\n if (Array.isArray(value) && existing && typeof existing === \"object\" && typeof (existing as any).fromArray === \"function\") {\r\n (existing as any).fromArray(value);\r\n return;\r\n }\r\n\r\n (current as Record<string, unknown>)[lastPart] = value;\r\n}\r\n\r\n/**\r\n * Snapshots a value for original-value tracking.\r\n *\r\n * Scene entities (textures, materials, meshes, etc.) are stored by reference\r\n * because cloning them would register unwanted duplicates in the scene.\r\n * Plain math types (Vector3, Color3, etc.) are cloned so mutations to the\r\n * live object don't corrupt the saved original.\r\n * @param value - The value to snapshot.\r\n * @returns The snapshot value (cloned for plain math types, by reference for entities).\r\n */\r\nfunction CloneValue(value: unknown): unknown {\r\n if (value === null || value === undefined) {\r\n return value;\r\n }\r\n if (typeof value !== \"object\") {\r\n return value;\r\n }\r\n if (typeof (value as any).getScene === \"function\") {\r\n return value;\r\n }\r\n if (\"clone\" in (value as object) && typeof (value as any).clone === \"function\") {\r\n return (value as any).clone();\r\n }\r\n return { ...value };\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"overrideManager.js","sourceRoot":"","sources":["../../../../dev/sharedUiComponents/src/projects/overrideManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Scene } from \"core/scene\";\r\nimport { Observable, type Observer } from \"core/Misc/observable\";\r\nimport { Logger } from \"core/Misc/logger\";\r\nimport { FindSmartAssetKeyForObject } from \"core/SmartAssets/smartAssetManager.pure\";\r\nimport { type IOverrideEntry, type OverrideTargetType, type OverrideValue } from \"./overrideEntry\";\r\n\r\nconst OverrideManagerKey = Symbol(\"babylonjs:overrideManager\");\r\n\r\n/**\r\n * Stateful handle for a scene's property override registry.\r\n *\r\n * Override behavior is exposed through module-level functions rather than\r\n * class methods so callers can import only the operations they need.\r\n *\r\n * Overrides are property diffs applied to scene objects identified by name.\r\n * They persist across reloads and are typically saved alongside a project\r\n * file. The override manager is fully independent of any other scene\r\n * subsystem (SmartAssetManager, loaders, etc.) — it works with any object\r\n * in the scene's standard collections (meshes, materials, lights, …)\r\n * regardless of how that object was created.\r\n *\r\n * When multiple objects share a name (e.g. two materials both called\r\n * \"Default\" loaded from different glTFs), {@link IOverrideEntry.targetIndex}\r\n * disambiguates: it stores the object's position among same-named siblings\r\n * at capture time and is used to pick the correct one at apply time.\r\n *\r\n * @example\r\n * ```typescript\r\n * AddOverride(scene, {\r\n * targetType: \"materials\",\r\n * targetName: \"canPaint\",\r\n * targetIndex: 0,\r\n * propertyPath: \"albedoColor\",\r\n * value: [1, 0, 0],\r\n * });\r\n * ```\r\n */\r\nexport type OverrideManager = {\r\n /**\r\n * The scene this manager is attached to.\r\n */\r\n readonly scene: Scene;\r\n\r\n /**\r\n * Fires whenever the override registry or applied state changes.\r\n */\r\n readonly onChangedObservable: Observable<void>;\r\n};\r\n\r\ntype OverrideManagerInternals = {\r\n overrides: IOverrideEntry[];\r\n originalValues: Map<string, unknown>;\r\n sceneDisposeObserver: ReturnType<Scene[\"onDisposeObservable\"][\"add\"]> | null;\r\n};\r\n\r\nconst OverrideManagerInternals = new WeakMap<OverrideManager, OverrideManagerInternals>();\r\nconst OnOverrideManagerCreatedObservable = new Observable<OverrideManager>();\r\n\r\n/**\r\n * Creates a new OverrideManager state object and attaches it to the scene.\r\n *\r\n * Internal: callers should use {@link GetOverrideManager} which returns the\r\n * existing manager when one is already attached.\r\n * @param scene - The scene this manager operates on.\r\n * @returns The created override manager state.\r\n */\r\nfunction CreateOverrideManager(scene: Scene): OverrideManager {\r\n const manager: OverrideManager = {\r\n scene,\r\n onChangedObservable: new Observable<void>(),\r\n };\r\n\r\n const internal: OverrideManagerInternals = {\r\n overrides: [],\r\n originalValues: new Map(),\r\n sceneDisposeObserver: null,\r\n };\r\n OverrideManagerInternals.set(manager, internal);\r\n\r\n if (!scene.metadata) {\r\n scene.metadata = {};\r\n }\r\n scene.metadata[OverrideManagerKey] = manager;\r\n\r\n // Auto-dispose when the scene is disposed so the manager doesn't outlive it.\r\n internal.sceneDisposeObserver = scene.onDisposeObservable.add(() => DisposeOverrideManager(manager));\r\n\r\n OnOverrideManagerCreatedObservable.notifyObservers(manager);\r\n\r\n return manager;\r\n}\r\n\r\n/**\r\n * Returns the OverrideManager attached to the given scene, creating and\r\n * attaching one if none exists.\r\n * @param scene - The scene to look up or attach a manager to.\r\n * @returns The existing or newly created OverrideManager.\r\n */\r\nexport function GetOverrideManager(scene: Scene): OverrideManager {\r\n const existing = scene.metadata?.[OverrideManagerKey] as OverrideManager | undefined;\r\n if (existing) {\r\n return existing;\r\n }\r\n return CreateOverrideManager(scene);\r\n}\r\n\r\n/**\r\n * Adds an observer that is notified whenever an OverrideManager is created.\r\n * @param callback - The callback to invoke with each newly created manager.\r\n * @returns The observer registration.\r\n */\r\nexport function AddOverrideManagerCreatedObserver(callback: (manager: OverrideManager) => void): Observer<OverrideManager> {\r\n return OnOverrideManagerCreatedObservable.add((manager) => callback(manager));\r\n}\r\n\r\n// ── Override CRUD ──\r\n\r\n/**\r\n * Options for {@link AddOverride}.\r\n */\r\nexport type AddOverrideOptions = {\r\n /**\r\n * If the `originalValue` field is present, the override is recorded *without*\r\n * re-applying it (the caller is presumed to have already mutated the entity)\r\n * and the field's content is captured as the property's pre-override\r\n * \"original\" so {@link RemoveOverride} can restore it later.\r\n *\r\n * Inspector-driven edits use this: by the time `onPropertyChanged` fires,\r\n * the binding has already written the new value, but it still has the prior\r\n * value in hand. Without this seeding path, an override created via\r\n * Inspector could never be reverted (the manager would have no record of\r\n * the pre-edit value).\r\n *\r\n * If the field is absent, the override is applied normally and the original\r\n * is captured by reading the property's current value on first apply.\r\n */\r\n readonly originalValue?: unknown;\r\n};\r\n\r\n/**\r\n * Adds an override entry and immediately applies it.\r\n * If an override with the same target coordinates already exists, it is replaced.\r\n *\r\n * When the caller has already mutated the target (e.g. an Inspector edit),\r\n * pass `{ originalValue }` containing the property's prior value — this seeds\r\n * the original-value map (so {@link RemoveOverride} can restore it) and skips\r\n * the redundant apply step.\r\n * @param scene - The scene whose override registry to update.\r\n * @param entry - The override to add.\r\n * @param options - Optional behavior modifiers; see {@link AddOverrideOptions}.\r\n */\r\nexport function AddOverride(scene: Scene, entry: IOverrideEntry, options?: AddOverrideOptions): void {\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n\r\n RemoveMatchingOverride(internal, entry.targetType, entry.targetName, entry.targetIndex, entry.propertyPath);\r\n internal.overrides.push(entry);\r\n\r\n if (options && \"originalValue\" in options) {\r\n // Caller already applied the new value. Seed the captured original from\r\n // their pre-edit snapshot — otherwise ApplyOverrideEntry would capture\r\n // the post-edit value and RemoveOverride would have nothing to restore.\r\n const origKey = MakeOriginalValueKey(entry.targetType, entry.targetName, entry.targetIndex, entry.propertyPath);\r\n if (!internal.originalValues.has(origKey)) {\r\n internal.originalValues.set(origKey, CloneValue(options.originalValue));\r\n }\r\n } else {\r\n ApplyOverrideEntry(manager, internal, entry);\r\n }\r\n\r\n manager.onChangedObservable.notifyObservers();\r\n}\r\n\r\n/**\r\n * Removes a single override matching the given coordinates. Restores the\r\n * original value if one was captured.\r\n * @param scene - The scene whose override registry to update.\r\n * @param targetType - The target type.\r\n * @param targetName - The target object name.\r\n * @param targetIndex - The target index among same-named siblings.\r\n * @param propertyPath - The property path to un-override.\r\n * @returns True if an override was removed.\r\n */\r\nexport function RemoveOverride(scene: Scene, targetType: OverrideTargetType, targetName: string, targetIndex: number, propertyPath: string): boolean {\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n\r\n const idx = FindOverrideIndex(internal, targetType, targetName, targetIndex, propertyPath);\r\n if (idx < 0) {\r\n return false;\r\n }\r\n\r\n internal.overrides.splice(idx, 1);\r\n\r\n const origKey = MakeOriginalValueKey(targetType, targetName, targetIndex, propertyPath);\r\n const original = internal.originalValues.get(origKey);\r\n if (original !== undefined) {\r\n const target = ResolveTarget(manager.scene, targetType, targetName, targetIndex);\r\n if (target) {\r\n SetNestedProperty(target, propertyPath, original);\r\n }\r\n internal.originalValues.delete(origKey);\r\n }\r\n\r\n manager.onChangedObservable.notifyObservers();\r\n return true;\r\n}\r\n\r\n/**\r\n * Returns all overrides currently registered with the scene.\r\n * @param scene - The scene whose override registry to read.\r\n * @returns A read-only array of override entries.\r\n */\r\nexport function GetOverrides(scene: Scene): readonly IOverrideEntry[] {\r\n return GetOverrideInternals(GetOverrideManager(scene)).overrides;\r\n}\r\n\r\n/**\r\n * Removes all overrides, optionally restoring original values.\r\n * @param scene - The scene whose override registry to clear.\r\n * @param restoreOriginals - If true, restores all captured original values.\r\n */\r\nexport function ClearOverrides(scene: Scene, restoreOriginals: boolean = false): void {\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n\r\n if (restoreOriginals) {\r\n // Snapshot the entries so we can restore each original without firing\r\n // an onChangedObservable notification per entry; consumers only need\r\n // one signal that the registry was emptied.\r\n const entries = [...internal.overrides];\r\n internal.overrides.length = 0;\r\n for (const entry of entries) {\r\n const origKey = MakeOriginalValueKey(entry.targetType, entry.targetName, entry.targetIndex, entry.propertyPath);\r\n const original = internal.originalValues.get(origKey);\r\n if (original !== undefined) {\r\n const target = ResolveTarget(manager.scene, entry.targetType, entry.targetName, entry.targetIndex);\r\n if (target) {\r\n SetNestedProperty(target, entry.propertyPath, original);\r\n }\r\n }\r\n }\r\n internal.originalValues.clear();\r\n manager.onChangedObservable.notifyObservers();\r\n return;\r\n }\r\n\r\n internal.overrides.length = 0;\r\n internal.originalValues.clear();\r\n manager.onChangedObservable.notifyObservers();\r\n}\r\n\r\n/**\r\n * Updates the target coordinates on the override matching a specific (type,\r\n * old-name, old-index) so it follows an entity rename. Used by capture services\r\n * to keep overrides attached to a specific object after the user renames it.\r\n *\r\n * Only the override at the exact `(targetType, oldName, oldIndex)` slot is\r\n * updated, so other same-named siblings keep their own overrides untouched.\r\n *\r\n * @param scene - The scene whose override registry to update.\r\n * @param targetType - The target type.\r\n * @param oldName - The previous name of the renamed entity.\r\n * @param oldIndex - The previous index of the renamed entity among same-named siblings.\r\n * @param newName - The new name of the renamed entity.\r\n * @param newIndex - The new index of the renamed entity among same-named siblings.\r\n */\r\nexport function RenameOverrideTarget(scene: Scene, targetType: OverrideTargetType, oldName: string, oldIndex: number, newName: string, newIndex: number): void {\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n\r\n let changed = false;\r\n for (let i = 0; i < internal.overrides.length; i++) {\r\n const entry = internal.overrides[i];\r\n if (entry.targetType === targetType && entry.targetName === oldName && entry.targetIndex === oldIndex) {\r\n internal.overrides[i] = { ...entry, targetName: newName, targetIndex: newIndex };\r\n changed = true;\r\n }\r\n }\r\n\r\n // Update original-value keys to match the new identity\r\n const oldPrefix = `${targetType}::${oldName}::${oldIndex}::`;\r\n const newPrefix = `${targetType}::${newName}::${newIndex}::`;\r\n for (const [origKey, value] of Array.from(internal.originalValues.entries())) {\r\n if (origKey.startsWith(oldPrefix)) {\r\n const propertyPath = origKey.substring(oldPrefix.length);\r\n internal.originalValues.set(newPrefix + propertyPath, value);\r\n internal.originalValues.delete(origKey);\r\n }\r\n }\r\n\r\n if (changed) {\r\n manager.onChangedObservable.notifyObservers();\r\n }\r\n}\r\n\r\n/**\r\n * Rewrites override *values* that reference an entity by name when that entity\r\n * has been renamed. Mirrors {@link RenameOverrideTarget} but operates on the\r\n * `value` field rather than the `targetName` field, so overrides whose value\r\n * is `\"ref:oldName\"` (material/light/camera references) or `\"texture:oldName\"`\r\n * (non-SmartAsset texture references) follow the rename instead of silently\r\n * pointing at a non-existent entity.\r\n *\r\n * SmartAsset texture references (`\"samTexture:<key>\"`) are unaffected because\r\n * the SmartAsset key is decoupled from the texture's runtime `name` field.\r\n *\r\n * @param scene - The scene whose override registry to update.\r\n * @param valueScheme - Which encoded-reference prefix to rewrite: `\"ref\"` for\r\n * material/light/camera references, `\"texture\"` for non-SAM textures.\r\n * @param oldName - The previous name embedded in the reference.\r\n * @param newName - The new name embedded in the reference.\r\n */\r\nexport function RenameOverrideValueReferences(scene: Scene, valueScheme: \"ref\" | \"texture\", oldName: string, newName: string): void {\r\n if (oldName === newName) {\r\n return;\r\n }\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n\r\n const oldValue = `${valueScheme}:${oldName}`;\r\n const newValue = `${valueScheme}:${newName}`;\r\n\r\n let changed = false;\r\n for (let i = 0; i < internal.overrides.length; i++) {\r\n const entry = internal.overrides[i];\r\n if (entry.value === oldValue) {\r\n internal.overrides[i] = { ...entry, value: newValue };\r\n changed = true;\r\n }\r\n }\r\n\r\n if (changed) {\r\n manager.onChangedObservable.notifyObservers();\r\n }\r\n}\r\n\r\n// ── Application ──\r\n\r\n/**\r\n * Applies all overrides to their current targets in the scene.\r\n *\r\n * Call this after any scene mutation that might have invalidated previously\r\n * applied state (asset reload, object recreation, project load). The override\r\n * manager does not auto-subscribe to other scene subsystems — coordination is\r\n * the caller's responsibility, which keeps the override system independent.\r\n * @param scene - The scene whose overrides to apply.\r\n */\r\nexport function ApplyAllOverrides(scene: Scene): void {\r\n const manager = GetOverrideManager(scene);\r\n const internal = GetOverrideInternals(manager);\r\n for (const entry of SortNameOverridesFirst(internal.overrides)) {\r\n // Apply each override in isolation: a single failing entry (e.g. a\r\n // stale property path, or a target whose shape changed) must not abort\r\n // the remaining overrides.\r\n try {\r\n ApplyOverrideEntry(manager, internal, entry);\r\n } catch (e) {\r\n Logger.Warn(`OverrideManager: failed to apply override type=\"${entry.targetType}\" name=\"${entry.targetName}\" prop=\"${entry.propertyPath}\": ${e}`);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Returns a copy of the entries ordered so that `name` overrides are applied\r\n * first. Renames must run before other overrides because targets (and\r\n * reference values like `ref:<name>`) are resolved by name: applying a rename\r\n * first ensures subsequent overrides resolve against the new names.\r\n * @param entries - The override entries to order.\r\n * @returns A new array with `name` overrides first, otherwise stable order.\r\n */\r\nfunction SortNameOverridesFirst<T extends { propertyPath: string }>(entries: readonly T[]): T[] {\r\n const nameOverrides: T[] = [];\r\n const rest: T[] = [];\r\n for (const entry of entries) {\r\n if (entry.propertyPath === \"name\") {\r\n nameOverrides.push(entry);\r\n } else {\r\n rest.push(entry);\r\n }\r\n }\r\n return [...nameOverrides, ...rest];\r\n}\r\n\r\n// ── Serialization ──\r\n\r\n/**\r\n * Serializes all overrides to a JSON-compatible array.\r\n * The on-disk shape is identical to the in-memory `IOverrideEntry`.\r\n * @param scene - The scene whose overrides to serialize.\r\n * @returns An array of override entries (shallow copies).\r\n */\r\nexport function SerializeOverrides(scene: Scene): IOverrideEntry[] {\r\n const internal = GetOverrideInternals(GetOverrideManager(scene));\r\n return internal.overrides.map((o) => ({ ...o }));\r\n}\r\n\r\n/**\r\n * Loads overrides from a serialized array and applies them.\r\n * @param scene - The scene whose override registry to populate.\r\n * @param data - Array of override entries.\r\n */\r\nexport function DeserializeAndApplyOverrides(scene: Scene, data: IOverrideEntry[]): void {\r\n if (!Array.isArray(data)) {\r\n throw new Error(\"OverrideManager: Expected an array of override entries.\");\r\n }\r\n\r\n for (const entry of SortNameOverridesFirst(data)) {\r\n if (!entry.targetType || entry.targetName === undefined || typeof entry.targetIndex !== \"number\" || !entry.propertyPath || entry.value === undefined) {\r\n Logger.Warn(\"OverrideManager: Skipping invalid override entry.\");\r\n continue;\r\n }\r\n AddOverride(scene, entry);\r\n }\r\n}\r\n\r\n// ── Lifecycle ──\r\n\r\n/**\r\n * Disposes the manager, clearing all overrides and detaching it from its scene.\r\n * Safe to call multiple times; subsequent calls are no-ops. Automatically invoked when the\r\n * owning scene is disposed.\r\n * @param manager - The override manager state.\r\n */\r\nexport function DisposeOverrideManager(manager: OverrideManager): void {\r\n const internal = OverrideManagerInternals.get(manager);\r\n if (!internal) {\r\n return;\r\n }\r\n OverrideManagerInternals.delete(manager);\r\n\r\n if (internal.sceneDisposeObserver) {\r\n manager.scene.onDisposeObservable.remove(internal.sceneDisposeObserver);\r\n internal.sceneDisposeObserver = null;\r\n }\r\n\r\n internal.overrides.length = 0;\r\n internal.originalValues.clear();\r\n\r\n manager.onChangedObservable.clear();\r\n\r\n if (manager.scene.metadata) {\r\n delete manager.scene.metadata[OverrideManagerKey];\r\n }\r\n}\r\n\r\n// ── Private ──\r\n\r\nfunction GetOverrideInternals(manager: OverrideManager): OverrideManagerInternals {\r\n const internal = OverrideManagerInternals.get(manager);\r\n if (!internal) {\r\n throw new Error(\"OverrideManager: Unknown manager state.\");\r\n }\r\n return internal;\r\n}\r\n\r\n/**\r\n * Applies a single override entry to its target, capturing the original value\r\n * on the first application so {@link RemoveOverride} can restore it later.\r\n * @param manager - The override manager owning the entry.\r\n * @param internal - The manager's internal state.\r\n * @param entry - The override to apply.\r\n */\r\nfunction ApplyOverrideEntry(manager: OverrideManager, internal: OverrideManagerInternals, entry: IOverrideEntry): void {\r\n const target = ResolveTarget(manager.scene, entry.targetType, entry.targetName, entry.targetIndex);\r\n if (!target) {\r\n Logger.Warn(`OverrideManager: target not found for type=\"${entry.targetType}\" name=\"${entry.targetName}\" index=${entry.targetIndex} prop=\"${entry.propertyPath}\"`);\r\n return; // Target not loaded yet — override will be applied on next ApplyAllOverrides\r\n }\r\n\r\n // Capture original value before first override\r\n const origKey = MakeOriginalValueKey(entry.targetType, entry.targetName, entry.targetIndex, entry.propertyPath);\r\n if (!internal.originalValues.has(origKey)) {\r\n const currentValue = GetNestedProperty(target, entry.propertyPath);\r\n if (currentValue !== undefined) {\r\n internal.originalValues.set(origKey, CloneValue(currentValue));\r\n }\r\n }\r\n\r\n const resolvedValue = ResolveOverrideValue(manager.scene, entry.value);\r\n SetNestedProperty(target, entry.propertyPath, resolvedValue);\r\n}\r\n\r\n/**\r\n * Locates a scene object by (targetType, targetName, targetIndex). The scene\r\n * collection is filtered to objects matching `targetName`; the N-th survivor\r\n * (per `targetIndex`) is returned. Falls back to the first match if the index\r\n * is out of range — useful when the scene shape has changed since capture.\r\n * @param scene - The scene to search.\r\n * @param targetType - The override target type.\r\n * @param targetName - The target object name (or \"\" for scene-level).\r\n * @param targetIndex - The target's position among same-named siblings.\r\n * @returns The matching scene object, or null if not found.\r\n */\r\nfunction ResolveTarget(scene: Scene, targetType: OverrideTargetType, targetName: string, targetIndex: number): object | null {\r\n // Scene-level overrides target the scene itself\r\n if (targetType === \"scene\") {\r\n return scene as unknown as object;\r\n }\r\n\r\n const collection = GetCollection(scene, targetType);\r\n if (!collection) {\r\n return null;\r\n }\r\n\r\n const matches = collection.filter((obj) => (obj as { name?: string }).name === targetName);\r\n if (matches.length === 0) {\r\n return null;\r\n }\r\n return (matches[targetIndex] ?? matches[0]) as object;\r\n}\r\n\r\n/**\r\n * Returns the scene collection corresponding to an override target type.\r\n * @param scene - The scene to inspect.\r\n * @param targetType - The target type.\r\n * @returns The collection, or null if the type has no collection.\r\n */\r\nfunction GetCollection(scene: Scene, targetType: OverrideTargetType): readonly unknown[] | null {\r\n switch (targetType) {\r\n case \"meshes\":\r\n return scene.meshes;\r\n case \"transformNodes\":\r\n return scene.transformNodes;\r\n case \"materials\":\r\n return scene.materials;\r\n case \"textures\":\r\n return scene.textures;\r\n case \"lights\":\r\n return scene.lights;\r\n case \"cameras\":\r\n return scene.cameras;\r\n case \"animationGroups\":\r\n return scene.animationGroups;\r\n default:\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Resolves an override value, expanding string references like \"ref:name\",\r\n * \"samTexture:key\", or \"texture:name\" into the actual scene object they refer to.\r\n * @param scene - The scene used to look up references.\r\n * @param value - The serialized override value.\r\n * @returns The runtime value to assign to the target property.\r\n */\r\nfunction ResolveOverrideValue(scene: Scene, value: OverrideValue): unknown {\r\n if (typeof value === \"string\") {\r\n if (value.startsWith(\"ref:\")) {\r\n return ResolveObjectReference(scene, value.substring(4));\r\n }\r\n if (value.startsWith(\"samTexture:\")) {\r\n return ResolveSamTextureReference(scene, value.substring(11));\r\n }\r\n if (value.startsWith(\"texture:\")) {\r\n return ResolveTextureReference(scene, value.substring(8));\r\n }\r\n }\r\n\r\n // Number arrays are passed through as-is. SetNestedProperty will use\r\n // the live target's `fromArray` method (Vector3, Color3, etc.) to push\r\n // values in-place, preserving the math instance identity.\r\n return value;\r\n}\r\n\r\n/**\r\n * Resolves a \"ref:name\" value by looking up a scene object by name. Materials,\r\n * lights, and cameras are searched first, then transform nodes and meshes\r\n * (both valid parent references).\r\n * @param scene - The scene to search.\r\n * @param name - The object name to resolve.\r\n * @returns The matching object, or undefined if not found.\r\n */\r\nfunction ResolveObjectReference(scene: Scene, name: string): unknown {\r\n const collections: readonly (readonly { name: string }[])[] = [scene.materials, scene.lights, scene.cameras, scene.transformNodes, scene.meshes];\r\n for (const collection of collections) {\r\n const match = collection.find((item) => item.name === name);\r\n if (match) {\r\n return match;\r\n }\r\n }\r\n Logger.Warn(`OverrideManager: Object reference \"${name}\" not found in scene.`);\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Resolves a \"texture:name\" value by looking up a texture in the scene by name.\r\n * @param scene - The scene to search.\r\n * @param name - The texture name to resolve.\r\n * @returns The matching texture, or undefined if not found.\r\n */\r\nfunction ResolveTextureReference(scene: Scene, name: string): unknown {\r\n const tex = scene.textures.find((t) => t.name === name);\r\n if (tex) {\r\n return tex;\r\n }\r\n Logger.Warn(`OverrideManager: Texture reference \"${name}\" not found.`);\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Resolves a \"samTexture:key\" value by looking up a SmartAsset-tracked texture\r\n * by its registry key. The SAM key is stable across save/load whereas the\r\n * texture's `name` (for SAM textures, the blob URL) changes on every reload,\r\n * so this is the only reliable way to round-trip texture references on\r\n * user-uploaded SmartAsset textures.\r\n * @param scene - The scene to search.\r\n * @param key - The SmartAsset key to resolve.\r\n * @returns The matching texture, or undefined if not found.\r\n */\r\nfunction ResolveSamTextureReference(scene: Scene, key: string): unknown {\r\n const tex = scene.textures.find((t) => FindSmartAssetKeyForObject(scene, t) === key);\r\n if (tex) {\r\n return tex;\r\n }\r\n Logger.Warn(`OverrideManager: SmartAsset texture \"${key}\" not found.`);\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Finds the index of an override matching the given coordinates.\r\n * @param internal - The manager's internal state.\r\n * @param targetType - The target type.\r\n * @param targetName - The target object name.\r\n * @param targetIndex - The target index among same-named siblings.\r\n * @param propertyPath - The property path.\r\n * @returns The matching index, or -1 if none found.\r\n */\r\nfunction FindOverrideIndex(internal: OverrideManagerInternals, targetType: OverrideTargetType, targetName: string, targetIndex: number, propertyPath: string): number {\r\n return internal.overrides.findIndex((o) => o.targetType === targetType && o.targetName === targetName && o.targetIndex === targetIndex && o.propertyPath === propertyPath);\r\n}\r\n\r\n/**\r\n * Removes any existing override that matches the given coordinates. Used by\r\n * {@link AddOverride} to enforce one entry per (type, name, index, property).\r\n * @param internal - The manager's internal state.\r\n * @param targetType - The target type.\r\n * @param targetName - The target object name.\r\n * @param targetIndex - The target index among same-named siblings.\r\n * @param propertyPath - The property path.\r\n */\r\nfunction RemoveMatchingOverride(internal: OverrideManagerInternals, targetType: OverrideTargetType, targetName: string, targetIndex: number, propertyPath: string): void {\r\n const idx = FindOverrideIndex(internal, targetType, targetName, targetIndex, propertyPath);\r\n if (idx >= 0) {\r\n internal.overrides.splice(idx, 1);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a unique key for storing original values.\r\n * @param targetType - The override target type.\r\n * @param targetName - The target object name.\r\n * @param targetIndex - The target index among same-named siblings.\r\n * @param propertyPath - The property path.\r\n * @returns A composite string key uniquely identifying the original value slot.\r\n */\r\nfunction MakeOriginalValueKey(targetType: OverrideTargetType, targetName: string, targetIndex: number, propertyPath: string): string {\r\n return `${targetType}::${targetName}::${targetIndex}::${propertyPath}`;\r\n}\r\n\r\n/**\r\n * Gets a nested property from an object using a dot-separated path.\r\n * @param obj - The root object to traverse.\r\n * @param path - The dot-separated property path.\r\n * @returns The value at the path, or undefined if any segment is missing.\r\n */\r\nfunction GetNestedProperty(obj: object, path: string): unknown {\r\n const parts = path.split(\".\");\r\n let current: unknown = obj;\r\n\r\n for (const part of parts) {\r\n if (current === null || current === undefined || typeof current !== \"object\") {\r\n return undefined;\r\n }\r\n current = (current as Record<string, unknown>)[part];\r\n }\r\n\r\n return current;\r\n}\r\n\r\n/**\r\n * Sets a nested property on an object using a dot-separated path.\r\n *\r\n * When the value is a number array and the existing property is a Babylon\r\n * math type (Vector*, Quaternion, Color3/4, Matrix), uses the math type's\r\n * `fromArray` method to mutate it in place — preserving the live instance\r\n * identity that consumers may already hold references to. Otherwise falls\r\n * back to direct property replacement.\r\n *\r\n * Getter-only accessors (e.g. `Texture.invertY`) cannot be assigned directly —\r\n * doing so throws in strict mode. For those, the backing field (`_<name>`) is\r\n * written instead when present, and load-time texture properties are re-applied\r\n * via a re-upload (see {@link ReapplyLoadTimeTextureProperty}). Truly read-only\r\n * properties with no backing field are skipped with a warning.\r\n * @param obj - The root object to mutate.\r\n * @param path - The dot-separated property path.\r\n * @param value - The new value to assign.\r\n */\r\nfunction SetNestedProperty(obj: object, path: string, value: unknown): void {\r\n const parts = path.split(\".\");\r\n let current: unknown = obj;\r\n\r\n for (let i = 0; i < parts.length - 1; i++) {\r\n if (current === null || current === undefined || typeof current !== \"object\") {\r\n return;\r\n }\r\n current = (current as Record<string, unknown>)[parts[i]];\r\n }\r\n\r\n if (current === null || current === undefined || typeof current !== \"object\") {\r\n return;\r\n }\r\n\r\n const target = current as Record<string, unknown>;\r\n const lastPart = parts[parts.length - 1];\r\n const existing = target[lastPart];\r\n\r\n if (Array.isArray(value) && existing && typeof existing === \"object\" && typeof (existing as any).fromArray === \"function\") {\r\n (existing as any).fromArray(value);\r\n return;\r\n }\r\n\r\n // Guard against getter-only accessors: assigning to one throws in strict\r\n // mode (ES modules are strict), which would otherwise abort the whole apply\r\n // batch. Write the backing field instead, then re-apply if it is a\r\n // load-time texture property.\r\n const accessor = FindAccessorDescriptor(target, lastPart);\r\n if (accessor && accessor.get && !accessor.set) {\r\n const backingField = `_${lastPart}`;\r\n if (backingField in target) {\r\n target[backingField] = value;\r\n ReapplyLoadTimeTextureProperty(target, lastPart);\r\n } else {\r\n Logger.Warn(`OverrideManager: property \"${lastPart}\" is read-only and has no backing field; skipping.`);\r\n }\r\n return;\r\n }\r\n\r\n target[lastPart] = value;\r\n}\r\n\r\n/**\r\n * Walks the prototype chain to find the property descriptor for `key`, so\r\n * accessor (getter/setter) properties defined on a class prototype can be\r\n * detected. Returns undefined if the property is a plain data field.\r\n * @param obj - The object to inspect.\r\n * @param key - The property name.\r\n * @returns The property descriptor, or undefined if none is found.\r\n */\r\nfunction FindAccessorDescriptor(obj: object, key: string): PropertyDescriptor | undefined {\r\n let proto: object | null = obj;\r\n while (proto) {\r\n const descriptor = Object.getOwnPropertyDescriptor(proto, key);\r\n if (descriptor) {\r\n return descriptor;\r\n }\r\n proto = Object.getPrototypeOf(proto);\r\n }\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Re-applies a texture property that only takes effect at upload time (such as\r\n * `invertY`, which is baked into the GPU texel data via `UNPACK_FLIP_Y`).\r\n * Writing the backing field alone does not re-flip an already-loaded texture,\r\n * so this re-uploads the source via `updateURL`, which releases only the GPU\r\n * texture and reuses the same texture instance (all scene references stay\r\n * intact). Duck-typed so this module stays decoupled from the Texture class,\r\n * and a no-op for anything that is not a URL-loaded texture.\r\n * @param target - The object whose property was written.\r\n * @param propertyName - The property that was written.\r\n */\r\nfunction ReapplyLoadTimeTextureProperty(target: Record<string, unknown>, propertyName: string): void {\r\n if (propertyName !== \"invertY\") {\r\n return;\r\n }\r\n if (typeof target.updateURL === \"function\" && typeof target.url === \"string\" && target.url) {\r\n try {\r\n (target.updateURL as (url: string, buffer?: unknown) => void)(target.url, target._buffer ?? null);\r\n } catch (e) {\r\n Logger.Warn(`OverrideManager: failed to re-upload texture to apply \"${propertyName}\": ${e}`);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Snapshots a value for original-value tracking.\r\n *\r\n * Scene entities (textures, materials, meshes, etc.) are stored by reference\r\n * because cloning them would register unwanted duplicates in the scene.\r\n * Plain math types (Vector3, Color3, etc.) are cloned so mutations to the\r\n * live object don't corrupt the saved original.\r\n * @param value - The value to snapshot.\r\n * @returns The snapshot value (cloned for plain math types, by reference for entities).\r\n */\r\nfunction CloneValue(value: unknown): unknown {\r\n if (value === null || value === undefined) {\r\n return value;\r\n }\r\n if (typeof value !== \"object\") {\r\n return value;\r\n }\r\n if (typeof (value as any).getScene === \"function\") {\r\n return value;\r\n }\r\n if (\"clone\" in (value as object) && typeof (value as any).clone === \"function\") {\r\n return (value as any).clone();\r\n }\r\n return { ...value };\r\n}\r\n"]}
|