fix: prevent crash when duplicating elements (#239)
- Guard _buildCache in merged-outline-node against stale/disposed Object3D refs that cause TypeError on .id access during render - Reset children array when duplicating roofs to prevent inconsistent parent-child relationships (matching existing stair behavior) - Use obj?.parent check in EditorOutlinerSync to ensure objects are still in the scene graph before adding to outliner arrays - Resume temporal state on parse failure to prevent undo/redo freeze Closes #232
This commit is contained in:
@@ -147,6 +147,7 @@ export function FloatingActionMenu() {
|
||||
duplicate.start = [duplicate.start[0] + 1, duplicate.start[1] + 1]
|
||||
duplicate.end = [duplicate.end[0] + 1, duplicate.end[1] + 1]
|
||||
} else if (node.type === 'roof') {
|
||||
duplicateInfo.children = []
|
||||
duplicate = RoofNode.parse(duplicateInfo)
|
||||
} else if (node.type === 'roof-segment') {
|
||||
duplicate = RoofSegmentNode.parse(duplicateInfo)
|
||||
@@ -160,6 +161,12 @@ export function FloatingActionMenu() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to parse duplicate', error)
|
||||
useScene.temporal.getState().resume()
|
||||
return
|
||||
}
|
||||
|
||||
if (!duplicate) {
|
||||
useScene.temporal.getState().resume()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -920,13 +920,13 @@ const EditorOutlinerSync = () => {
|
||||
outliner.selectedObjects.length = 0
|
||||
for (const id of idsToHighlight) {
|
||||
const obj = sceneRegistry.nodes.get(id)
|
||||
if (obj) outliner.selectedObjects.push(obj)
|
||||
if (obj?.parent) outliner.selectedObjects.push(obj)
|
||||
}
|
||||
|
||||
outliner.hoveredObjects.length = 0
|
||||
if (hoveredId) {
|
||||
const obj = sceneRegistry.nodes.get(hoveredId)
|
||||
if (obj) outliner.hoveredObjects.push(obj)
|
||||
if (obj?.parent) outliner.hoveredObjects.push(obj)
|
||||
}
|
||||
}, [phase, previewSelectedIds, selection, hoveredId, outliner])
|
||||
|
||||
|
||||
@@ -600,9 +600,14 @@ export class MergedOutlineNode extends TempNode {
|
||||
|
||||
private _buildCache(objects: Object3D[], cache: Set<Object3D>) {
|
||||
for (const obj of objects) {
|
||||
if (!obj || !obj.traverse) continue
|
||||
try {
|
||||
obj.traverse((child: any) => {
|
||||
if (child.isMesh || child.isSprite) cache.add(child)
|
||||
})
|
||||
} catch {
|
||||
// Skip objects that were disposed or removed from the scene graph
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user