diff --git a/src/editor-api/entities.ts b/src/editor-api/entities.ts index a27083129..2ce8a0e83 100644 --- a/src/editor-api/entities.ts +++ b/src/editor-api/entities.ts @@ -317,7 +317,7 @@ class Entities extends Events { * await editor.entities.delete([entity1, entity2]); * ``` */ - async delete(entities: Entity[] | Entity, options: { history?: boolean } = {}) { + async delete(entities: Entity[] | Entity, options: { history?: boolean; preserveEntityReferences?: boolean } = {}) { await deleteEntities(entities, options); } diff --git a/src/editor-api/entities/delete.ts b/src/editor-api/entities/delete.ts index 03aaebc01..2f79a3b16 100644 --- a/src/editor-api/entities/delete.ts +++ b/src/editor-api/entities/delete.ts @@ -78,8 +78,11 @@ function rememberPrevious(entities: any[]) { * @param entities - The entities * @param options.history - Whether to record a history action. Defaults to true. * @param options.waitSubmitted - Whether to wait till ops submitted. + * @param options.preserveEntityReferences - Whether to skip nullifying entity references + * when entities are removed. Useful when entities are immediately re-created with the same + * resource_id (e.g. during template revert). Defaults to false. */ -async function deleteEntities(entities: Entity[] | Entity, options: { history?: boolean; waitSubmitted?: boolean } = {}) { +async function deleteEntities(entities: Entity[] | Entity, options: { history?: boolean; waitSubmitted?: boolean; preserveEntityReferences?: boolean } = {}) { if (options.history === undefined) { options.history = true; } @@ -139,8 +142,9 @@ async function deleteEntities(entities: Entity[] | Entity, options: { history?: previous = rememberPrevious(entities); } - // find entity references - const entityReferences = findEntityReferencesInComponents(api.entities.root); + // find entity references (skip when preserveEntityReferences is true, + // e.g. during template revert where entities are immediately re-created with same IDs) + const entityReferences = options.preserveEntityReferences ? null : findEntityReferencesInComponents(api.entities.root); entities.forEach((entity) => { api.entities.remove(entity, entityReferences); diff --git a/src/editor-api/entity.ts b/src/editor-api/entity.ts index e3268704c..c6c3003e3 100644 --- a/src/editor-api/entity.ts +++ b/src/editor-api/entity.ts @@ -499,7 +499,7 @@ class Entity extends Events { * ``` * */ - delete(options: { history?: boolean } = {}) { + delete(options: { history?: boolean; preserveEntityReferences?: boolean } = {}) { return api.entities.delete([this], options); } diff --git a/src/editor/templates/revert-overrides.ts b/src/editor/templates/revert-overrides.ts index c1208418f..fc0913880 100644 --- a/src/editor/templates/revert-overrides.ts +++ b/src/editor/templates/revert-overrides.ts @@ -593,7 +593,7 @@ editor.once('load', () => { } if (entityObserver) { - await entityObserver.apiEntity.delete({ history: false }); + await entityObserver.apiEntity.delete({ history: false, preserveEntityReferences: true }); const entity = editor.api.globals.entities.create(prev, { history: false, index: childIndex, select: true }); entityObserver = entity.observer; @@ -614,7 +614,7 @@ editor.once('load', () => { // use waitSubmitted to wait for scene operational transforms to be submitted to ShareDB - // delete() prepares Operations Transforms on the frontend but instantiateTemplate() // bakes them on the backend and we should wait till everything submitted after delete - await entityObserver.apiEntity.delete({ history: false, waitSubmitted: true }); + await entityObserver.apiEntity.delete({ history: false, waitSubmitted: true, preserveEntityReferences: true }); const newEntity = await asset.apiAsset.instantiateTemplate(parent.apiEntity, { history: false,