Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/core/src/2d/sprite/MaskRenderable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,6 @@ export function MaskRenderable<T extends RendererConstructor>(
}

/** @internal */
@ignoreClone
_onSpriteChange(type: SpriteModifyFlags): void {
switch (type) {
case SpriteModifyFlags.texture:
Expand Down
4 changes: 0 additions & 4 deletions packages/core/src/2d/sprite/Sprite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { BoundingBox, MathUtil, Rect, Vector2, Vector4 } from "@galacean/engine-
import { Engine } from "../../Engine";
import { UpdateFlagManager } from "../../UpdateFlagManager";
import { ReferResource } from "../../asset/ReferResource";
import { ignoreClone } from "../../clone/CloneDecorators";
import { Texture2D } from "../../texture/Texture2D";
import { SpriteAtlas } from "../atlas/SpriteAtlas";
import { SpriteModifyFlags } from "../enums/SpriteModifyFlags";
Expand Down Expand Up @@ -382,7 +381,6 @@ export class Sprite extends ReferResource {
this._updateFlagManager.dispatch(type);
}

@ignoreClone
private _onRegionChange(): void {
const { _region: region } = this;
// @ts-ignore
Expand All @@ -398,12 +396,10 @@ export class Sprite extends ReferResource {
region._onValueChanged = this._onRegionChange;
}

@ignoreClone
private _onPivotChange(): void {
this._dispatchSpriteChange(SpriteModifyFlags.pivot);
}

@ignoreClone
private _onBorderChange(): void {
const { _border: border } = this;
// @ts-ignore
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/2d/sprite/SpriteRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,6 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer {
this._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.AutomaticSize;
}

@ignoreClone
private _onSpriteChange(type: SpriteModifyFlags): void {
switch (type) {
case SpriteModifyFlags.texture:
Expand Down Expand Up @@ -547,7 +546,6 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer {
}
}

@ignoreClone
private _onColorChanged(): void {
this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.Color;
}
Expand Down
3 changes: 0 additions & 3 deletions packages/core/src/2d/text/TextRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,6 @@ export class TextRenderer extends Renderer implements ITextRenderer {
charRenderInfos.length = 0;
}

@ignoreClone
protected override _onTransformChanged(bit: TransformModifyFlags): void {
super._onTransformChanged(bit);
this._setDirtyFlagTrue(DirtyFlag.WorldPosition | DirtyFlag.WorldBounds);
Expand Down Expand Up @@ -797,12 +796,10 @@ export class TextRenderer extends Renderer implements ITextRenderer {
textChunks.length = 0;
}

@ignoreClone
private _onColorChanged(): void {
this._setDirtyFlagTrue(DirtyFlag.Color);
}

@ignoreClone
private _onOutlineColorChanged(): void {
this.shaderData.setColor(TextRenderer._outlineColorProperty, this._outlineColor);
}
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/Camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,6 @@ export class Camera extends Component {
return this._inverseProjectionMatrix;
}

@ignoreClone
private _onPixelViewportChanged(): void {
this._updatePixelViewport();
this._customAspectRatio ?? this._projectionMatrixChange();
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/Renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,6 @@ export class Renderer extends Component implements ICloneHook<Renderer> {
}
}

@ignoreClone
protected _onTransformChanged(type: TransformModifyFlags): void {
this._dirtyUpdateFlag |= RendererUpdateFlags.WorldVolume;
}
Expand Down
7 changes: 0 additions & 7 deletions packages/core/src/Transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,13 +659,11 @@ export class Transform extends Component implements ICloneHook<Transform> {
return parentCache;
}

@ignoreClone
protected _onPositionChanged(): void {
this._setDirtyFlagTrue(TransformModifyFlags.LocalMatrix);
this._updateWorldPositionFlag();
}

@ignoreClone
protected _onWorldPositionChanged(): void {
const worldPosition = this._worldPosition;
const parent = this._getParentTransform();
Expand Down Expand Up @@ -821,14 +819,12 @@ export class Transform extends Component implements ICloneHook<Transform> {
this._rotateByQuat(rotQuat, relativeToLocal);
}

@ignoreClone
private _onRotationChanged(): void {
this._setDirtyFlagTrue(TransformModifyFlags.LocalMatrix | TransformModifyFlags.LocalQuat);
this._setDirtyFlagFalse(TransformModifyFlags.LocalEuler);
this._updateWorldRotationFlag();
}

@ignoreClone
private _onWorldRotationChanged(): void {
const worldRotation = this._worldRotation;
Quaternion.rotationEuler(
Expand All @@ -840,14 +836,12 @@ export class Transform extends Component implements ICloneHook<Transform> {
this._setDirtyFlagFalse(TransformModifyFlags.WorldEuler);
}

@ignoreClone
private _onRotationQuaternionChanged(): void {
this._setDirtyFlagTrue(TransformModifyFlags.LocalMatrix | TransformModifyFlags.LocalEuler);
this._setDirtyFlagFalse(TransformModifyFlags.LocalQuat);
this._updateWorldRotationFlag();
}

@ignoreClone
private _onWorldRotationQuaternionChanged(): void {
const worldRotationQuaternion = this._worldRotationQuaternion;
const parent = this._getParentTransform();
Expand All @@ -861,7 +855,6 @@ export class Transform extends Component implements ICloneHook<Transform> {
this._setDirtyFlagFalse(TransformModifyFlags.WorldQuat);
}

@ignoreClone
private _onScaleChanged(): void {
const { x, y, z } = this._scale;
this._setDirtyFlagTrue(TransformModifyFlags.LocalMatrix);
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/audio/AudioSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ export class AudioSource extends Component {
this.clip = null;
}

@ignoreClone
private _onPlayEnd(): void {
this.stop();
}
Expand Down
101 changes: 81 additions & 20 deletions packages/core/src/clone/CloneDecorators.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
/** @internal */
export const defaultCloneModeKey = Symbol("defaultCloneMode");
/** @internal */
export const fieldCloneModesKey = Symbol("fieldCloneModes");
const fieldCloneModesKey = Symbol("fieldCloneModes");
const symbolConstructor = Symbol as SymbolConstructor & { readonly metadata?: symbol };
const decoratorMetadataKey = symbolConstructor.metadata ?? Symbol.for("Symbol.metadata");
const resolvedFieldCloneModes = new WeakMap<Function, Readonly<Record<string, CloneMode>> | null>();

if (!symbolConstructor.metadata) {
Object.defineProperty(symbolConstructor, "metadata", { value: decoratorMetadataKey });
}

/**
* @internal
Expand All @@ -14,30 +20,61 @@ export const enum CloneMode {
Deep
}

function registerDecoratorFieldMode<This extends object, Value>(
context: ClassFieldDecoratorContext<This, Value>,
mode: CloneMode
): void {
if (context.kind !== "field" || context.static || context.private || typeof context.name !== "string") {
throw new TypeError("Clone decorators only support public instance fields with string keys.");
}

const metadata = context.metadata;
if (!metadata) {
throw new TypeError("Clone decorators require standard decorator metadata support.");
}

if (!Object.prototype.hasOwnProperty.call(metadata, fieldCloneModesKey)) {
const inheritedFieldModes = metadata[fieldCloneModesKey] as Record<string, CloneMode> | undefined;
Object.defineProperty(metadata, fieldCloneModesKey, {
value: Object.create(inheritedFieldModes ?? null)
});
}
(<Record<string, CloneMode>>metadata[fieldCloneModesKey])[context.name] = mode;
}

/**
* Property decorator — deep clone this field's whole subtree, overriding the value type's default
* Field decorator — deep clone this field's whole subtree, overriding the value type's default
* clone mode (field-level decorators have the highest priority). The deep intent carries into
* field-cloneable members; engine-bound and platform objects keep their defaults. A decorator is
* an explicit intent: if the decorated value itself can't be deep cloned (an entity reference,
* asset, function, or object with opaque internal state), cloning throws rather than falling back.
* Field-cloned classes reproduce only their own enumerable string-keyed properties.
*/
export function deepClone(target: object, propertyKey: string): void {
CloneMetadata.registerFieldMode(target, propertyKey, CloneMode.Deep);
export function deepClone<This extends object, Value>(
_value: undefined,
context: ClassFieldDecoratorContext<This, Value>
): void {
registerDecoratorFieldMode(context, CloneMode.Deep);
}

/**
* Property decorator — assign (share the reference) this field, overriding the value type's default clone mode.
* Field decorator — assign (share the reference) this field, overriding the value type's default clone mode.
*/
export function assignmentClone(target: object, propertyKey: string): void {
CloneMetadata.registerFieldMode(target, propertyKey, CloneMode.Assignment);
export function assignmentClone<This extends object, Value>(
_value: undefined,
context: ClassFieldDecoratorContext<This, Value>
): void {
registerDecoratorFieldMode(context, CloneMode.Assignment);
}

/**
* Property decorator — ignore this field when cloning; keep the clone's own constructor-built value.
* Field decorator — ignore this field when cloning; keep the clone's own constructor-built value.
*/
export function ignoreClone(target: object, propertyKey: string): void {
CloneMetadata.registerFieldMode(target, propertyKey, CloneMode.Ignore);
export function ignoreClone<This extends object, Value>(
_value: undefined,
context: ClassFieldDecoratorContext<This, Value>
): void {
registerDecoratorFieldMode(context, CloneMode.Ignore);
}

/**
Expand All @@ -47,14 +84,38 @@ export function registerDefaultCloneMode(target: { prototype: object }, mode: Cl
Object.defineProperty(target.prototype, defaultCloneModeKey, { value: mode });
}

class CloneMetadata {
static registerFieldMode(target: any, propertyKey: string, mode: CloneMode): void {
if (!Object.prototype.hasOwnProperty.call(target, fieldCloneModesKey)) {
Object.defineProperty(target, fieldCloneModesKey, {
value: Object.create(target[fieldCloneModesKey] ?? null),
configurable: true
});
}
target[fieldCloneModesKey][propertyKey] = mode;
/**
* @internal
*/
export function getFieldCloneModes(target: object): Readonly<Record<string, CloneMode>> | undefined {
const constructor = Object.getPrototypeOf(target)?.constructor as
| (Function & Record<symbol, Record<PropertyKey, unknown>>)
| undefined;
return constructor ? resolveFieldCloneModes(constructor) : undefined;
}

function resolveFieldCloneModes(
constructor: Function & Record<symbol, Record<PropertyKey, unknown>>
): Readonly<Record<string, CloneMode>> | undefined {
const cached = resolvedFieldCloneModes.get(constructor);
if (cached !== undefined) {
return cached ?? undefined;
}

const parentConstructor = Object.getPrototypeOf(constructor);
const parentModes =
typeof parentConstructor === "function" && parentConstructor !== Function.prototype
? resolveFieldCloneModes(parentConstructor)
: undefined;
const metadata = Object.prototype.hasOwnProperty.call(constructor, decoratorMetadataKey)
? constructor[decoratorMetadataKey]
: undefined;
const ownModes =
metadata && Object.prototype.hasOwnProperty.call(metadata, fieldCloneModesKey)
? (metadata[fieldCloneModesKey] as Record<string, CloneMode>)
: undefined;
const resolvedModes = ownModes ? Object.assign(Object.create(parentModes ?? null), ownModes) : parentModes;

resolvedFieldCloneModes.set(constructor, resolvedModes ?? null);
return resolvedModes;
}
4 changes: 2 additions & 2 deletions packages/core/src/clone/CloneUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { Component } from "../Component";
import { Entity } from "../Entity";
import { UpdateFlag } from "../UpdateFlag";
import { UpdateFlagManager } from "../UpdateFlagManager";
import { CloneMode, defaultCloneModeKey, fieldCloneModesKey, registerDefaultCloneMode } from "./CloneDecorators";
import { CloneMode, defaultCloneModeKey, getFieldCloneModes, registerDefaultCloneMode } from "./CloneDecorators";
import type { ICloneHook } from "./ICloneHook";

/**
Expand All @@ -38,7 +38,7 @@ export class CloneUtil {
cloneMap: Map<object, object>,
deepCloneSubtree = false
): void {
const fieldModes = source[fieldCloneModesKey];
const fieldModes = getFieldCloneModes(source);
const keys = Object.keys(source);
for (let i = 0, n = keys.length; i < n; i++) {
const k = keys[i];
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/clone/ComponentCloner.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component } from "../Component";
import { CloneUtil } from "./CloneUtil";
import { CloneMode, fieldCloneModesKey } from "./CloneDecorators";
import { CloneMode, getFieldCloneModes } from "./CloneDecorators";
import type { ICloneHook } from "./ICloneHook";

/**
Expand All @@ -12,7 +12,7 @@ export class ComponentCloner {
* @internal
*/
static cloneComponent(source: Component, target: Component, cloneMap: Map<object, object>): void {
const fieldModes = (<any>source)[fieldCloneModesKey];
const fieldModes = getFieldCloneModes(source);
const keys = Object.keys(source);
for (let i = 0, n = keys.length; i < n; i++) {
const k = keys[i];
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/mesh/MeshRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ export class MeshRenderer extends Renderer {
this._mesh = mesh;
}

@ignoreClone
private _onMeshChanged(type: MeshModifyFlags): void {
type & MeshModifyFlags.Bounds && (this._dirtyUpdateFlag |= RendererUpdateFlags.WorldVolume);
type & MeshModifyFlags.VertexElements && (this._dirtyUpdateFlag |= MeshRendererUpdateFlags.VertexElementMacro);
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/mesh/SkinnedMeshRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,10 @@ export class SkinnedMeshRenderer extends MeshRenderer {
}
}

@ignoreClone
private _onLocalBoundsChanged(): void {
this._dirtyUpdateFlag |= RendererUpdateFlags.WorldVolume;
}

@ignoreClone
private _onSkinUpdated(type: SkinUpdateFlag, value: number | Entity): void {
switch (type) {
case SkinUpdateFlag.BoneCountChanged:
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/particle/ParticleRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,6 @@ export class ParticleRenderer extends Renderer {
/**
* @internal
*/
@ignoreClone
_onGeneratorParamsChanged(): void {
this._dirtyUpdateFlag |=
ParticleUpdateFlags.GeneratorVolume | ParticleUpdateFlags.TransformVolume | RendererUpdateFlags.WorldVolume;
Expand All @@ -309,7 +308,6 @@ export class ParticleRenderer extends Renderer {
/**
* @internal
*/
@ignoreClone
override _onTransformChanged(type: TransformModifyFlags): void {
this._dirtyUpdateFlag |= ParticleUpdateFlags.TransformVolume | RendererUpdateFlags.WorldVolume;
}
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/particle/modules/ParticleGradient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,10 @@ export class ParticleGradient extends DataObject {
keys.splice(index, 1);
}

@ignoreClone
private _setColorTypeArrayDirty(): void {
this._colorTypeArrayDirty = true;
}

@ignoreClone
private _setAlphaTypeArrayDirty(): void {
this._alphaTypeArrayDirty = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ export class TextureSheetAnimationModule extends ParticleGeneratorModule {
this._frameOverTimeRand.reset(randomSeed, ParticleRandomSubSeeds.TextureSheetAnimation);
}

@ignoreClone
private _onTilingChanged(): void {
const tiling = this.tiling;
this._tillingInfo.set(1.0 / tiling.x, 1.0 / tiling.y, tiling.x * tiling.y);
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/particle/modules/shape/MeshShape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ export class MeshShape extends BaseShape implements ICloneHook<MeshShape> {
return typedBuffer;
}

@ignoreClone
private _onMeshChanged(type: MeshModifyFlags): void {
if (type & MeshModifyFlags.VertexElements) {
const mesh = this._mesh;
Expand Down
Loading
Loading