-
-
Notifications
You must be signed in to change notification settings - Fork 406
[codex] preserve Transform replacement dependencies #3073
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev/2.0
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,11 @@ import { DisorderedArray } from "./utils/DisorderedArray"; | |
| export class Entity extends EngineObject { | ||
| /** @internal */ | ||
| static _tempComponentConstructors: ComponentConstructor[] = []; | ||
|
|
||
| private static _isTransformType(type: ComponentConstructor): boolean { | ||
| return type === Transform || type.prototype instanceof Transform; | ||
| } | ||
|
|
||
| /** | ||
| * @internal | ||
| */ | ||
|
|
@@ -236,10 +241,22 @@ export class Entity extends EngineObject { | |
| constructor(engine: Engine, name?: string, ...components: ComponentConstructor[]) { | ||
| super(engine); | ||
| this.name = name ?? "Entity"; | ||
| for (let i = 0, n = components.length; i < n; i++) { | ||
| this.addComponent(components[i]); | ||
| let transformType: ComponentConstructor = Transform; | ||
| const n = components.length; | ||
| for (let i = n - 1; i >= 0; i--) { | ||
| const componentType = components[i]; | ||
| if (Entity._isTransformType(componentType)) { | ||
| transformType = componentType; | ||
| break; | ||
| } | ||
| } | ||
| this._transform = <Transform>this.addComponent(transformType); | ||
| for (let i = 0; i < n; i++) { | ||
| const componentType = components[i]; | ||
| if (!Entity._isTransformType(componentType)) { | ||
| this.addComponent(componentType); | ||
| } | ||
| } | ||
| !this._transform && this.addComponent(Transform); | ||
| this._inverseWorldMatFlag = this.registerWorldChangeFlag(); | ||
| } | ||
|
|
||
|
|
@@ -250,12 +267,17 @@ export class Entity extends EngineObject { | |
| * @returns The component which has been added | ||
| */ | ||
| addComponent<T extends ComponentConstructor>(type: T, ...args: ComponentArguments<T>): InstanceType<T> { | ||
| const needReplaceTransform = Entity._isTransformType(type) && this._transform; | ||
| if (needReplaceTransform) { | ||
| ComponentsDependencies._removeCheck(this, <ComponentConstructor>this._transform.constructor, type); | ||
| } | ||
| ComponentsDependencies._addCheck(this, type); | ||
| const component = new type(this, ...args) as InstanceType<T>; | ||
| this._components.push(component); | ||
|
|
||
| // @todo: temporary solution | ||
| if (component instanceof Transform) this._setTransform(component); | ||
| if (needReplaceTransform) { | ||
| this._replaceTransform(<Transform>component); | ||
| } else { | ||
| this._components.push(component); | ||
| } | ||
| component._setActive(true, ActiveChangeFlag.All); | ||
| return component; | ||
| } | ||
|
|
@@ -422,7 +444,7 @@ export class Entity extends EngineObject { | |
| */ | ||
| clone(): Entity { | ||
| const cloneEntity = this._createCloneEntity(); | ||
| this._parseCloneEntity(this, cloneEntity, this, cloneEntity, new Map<Object, Object>()); | ||
| this._parseCloneEntity(this, cloneEntity, this, cloneEntity, new Map<object, object>()); | ||
| return cloneEntity; | ||
| } | ||
|
|
||
|
|
@@ -477,7 +499,7 @@ export class Entity extends EngineObject { | |
| target: Entity, | ||
| srcRoot: Entity, | ||
| targetRoot: Entity, | ||
| deepInstanceMap: Map<Object, Object> | ||
| deepInstanceMap: Map<object, object> | ||
| ): void { | ||
| const srcChildren = src._children; | ||
| const targetChildren = target._children; | ||
|
|
@@ -529,9 +551,13 @@ export class Entity extends EngineObject { | |
| * @internal | ||
| */ | ||
| _removeComponent(component: Component): void { | ||
| ComponentsDependencies._removeCheck(this, component.constructor as ComponentConstructor); | ||
| const components = this._components; | ||
| components.splice(components.indexOf(component), 1); | ||
| const index = components.indexOf(component); | ||
| // A replaced Transform is detached from the component slot immediately but | ||
| // can still reach here later because object destruction may be deferred. | ||
| if (index < 0) return; | ||
| ComponentsDependencies._removeCheck(this, component.constructor as ComponentConstructor); | ||
| components.splice(index, 1); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -762,9 +788,18 @@ export class Entity extends EngineObject { | |
| } | ||
| } | ||
|
|
||
| private _setTransform(value: Transform): void { | ||
| this._transform?.destroy(); | ||
| private _replaceTransform(value: Transform): void { | ||
| const previous = this._transform; | ||
| value.position.copyFrom(previous.position); | ||
| value.rotationQuaternion.copyFrom(previous.rotationQuaternion); | ||
| value.scale.copyFrom(previous.scale); | ||
| // Keep the unique Transform in the same component slot. Detach the old | ||
| // instance before destroy because destroy can be deferred during a frame. | ||
| const components = this._components; | ||
| const previousIndex = components.indexOf(previous); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Severity: medium 🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage. |
||
| components[previousIndex] = value; | ||
| this._transform = value; | ||
| previous.destroy(); | ||
| const children = this._children; | ||
| for (let i = 0, n = children.length; i < n; i++) { | ||
| children[i].transform?._parentChange(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Preserve constructor-supplied Transform dependencies before validation.
Line 253 installs the Transform before queued components.
new Entity(engine, "x", MeshRenderer, CheckOnlyDependentTransform)now throws becauseMeshRendereris not installed yet. WithAutoAddDependentTransform, auto-add insertsMeshRendererbefore the Transform, and the loop then adds the requested renderer again—also moving the Transform out of slot 0.Resolve Transform dependencies against pending constructor component types and avoid auto-adding dependencies already queued; add CheckOnly and AutoAdd constructor regressions.
🤖 Prompt for AI Agents