Fix PrefabResource refCount was incorrect (#2864) (#2865)

* fix: prefab refcount error
This commit is contained in:
AZhan
2025-12-04 15:15:50 +08:00
committed by GitHub
parent 3ac26432ea
commit 85a5c7490b
3 changed files with 79 additions and 18 deletions

View File

@@ -1,7 +1,7 @@
import { Engine, Entity } from "@galacean/engine-core";
import { IEntity, IHierarchyFile, ParserContext, ParserType } from "../resource-deserialize";
import { HierarchyParser } from "../resource-deserialize/resources/parser/HierarchyParser";
import { PrefabResource } from "./PrefabResource";
import { IHierarchyFile, ParserContext, ParserType } from "../resource-deserialize";
export class PrefabParser extends HierarchyParser<PrefabResource, ParserContext<IHierarchyFile, Entity>> {
static parse(engine: Engine, url: string, data: IHierarchyFile): Promise<PrefabResource> {
@@ -20,6 +20,13 @@ export class PrefabParser extends HierarchyParser<PrefabResource, ParserContext<
super(data, context);
}
protected override _applyEntityData(entity: Entity, entityConfig: IEntity = {}): Entity {
super._applyEntityData(entity, entityConfig);
// @ts-ignore
entity._markAsTemplate(this.context.resource);
return entity;
}
protected override _handleRootEntity(id: string): void {
this.prefabResource._root = this.context.entityMap.get(id);
}

View File

@@ -62,6 +62,23 @@ export abstract class HierarchyParser<T extends Scene | PrefabResource, V extend
.catch(this._reject);
}
protected _applyEntityData(entity: Entity, entityConfig: IEntity = {}): Entity {
entity.isActive = entityConfig.isActive ?? entity.isActive;
entity.name = entityConfig.name ?? entity.name;
const transform = entity.transform;
const transformConfig = entityConfig.transform;
if (transformConfig) {
this._reflectionParser.parsePropsAndMethods(transform, transformConfig);
} else {
const { position, rotation, scale } = entityConfig;
if (position) transform.position.copyFrom(position);
if (rotation) transform.rotation.copyFrom(rotation);
if (scale) transform.scale.copyFrom(scale);
}
if (entityConfig.layer) entity.layer = entityConfig.layer;
return entity;
}
protected abstract _handleRootEntity(id: string): void;
protected abstract _clearAndResolve(): Scene | PrefabResource;
@@ -302,23 +319,6 @@ export abstract class HierarchyParser<T extends Scene | PrefabResource, V extend
}
}
private _applyEntityData(entity: Entity, entityConfig: IEntity = {}): Entity {
entity.isActive = entityConfig.isActive ?? entity.isActive;
entity.name = entityConfig.name ?? entity.name;
const transform = entity.transform;
const transformConfig = entityConfig.transform;
if (transformConfig) {
this._reflectionParser.parsePropsAndMethods(transform, transformConfig);
} else {
const { position, rotation, scale } = entityConfig;
if (position) transform.position.copyFrom(position);
if (rotation) transform.rotation.copyFrom(rotation);
if (scale) transform.scale.copyFrom(scale);
}
if (entityConfig.layer) entity.layer = entityConfig.layer;
return entity;
}
private _generateInstanceContext(entity: Entity, context: ParserContext<IHierarchyFile, Entity>, path: string) {
const { entityMap, components } = context;
const componentsMap = {};

View File

@@ -0,0 +1,54 @@
import { expect, beforeAll, afterAll, describe, it } from "vitest";
import { WebGLEngine } from "@galacean/engine-rhi-webgl";
import type { IHierarchyFile } from "@galacean/engine-loader";
import { PrefabParser } from "../../../packages/loader/src/prefab/PrefabParser";
let engine: WebGLEngine;
beforeAll(async () => {
const canvas = document.createElement("canvas");
canvas.width = 256;
canvas.height = 256;
engine = await WebGLEngine.create({ canvas });
});
afterAll(() => {
engine?.destroy();
});
describe("PrefabResource refCount", () => {
it("should increase and decrease with instantiated entities", async () => {
const prefabData: IHierarchyFile = {
entities: [
{
id: "0",
name: "root",
components: [],
children: ["1"]
},
{
id: "1",
name: "child",
parent: "0",
components: []
}
]
};
const prefab = await PrefabParser.parse(engine, "prefab.json", prefabData);
expect(prefab.refCount).toBe(0);
const instance1 = prefab.instantiate();
const instance2 = prefab.instantiate();
// One ref count per templated entity in each instance (root + child).
expect(prefab.refCount).toBe(4);
instance1.destroy();
expect(prefab.refCount).toBe(2);
instance2.destroy();
expect(prefab.refCount).toBe(0);
});
});