I want create my new custom decorator

Hello, I am a Korean developer.

I’m making a casino game.

I have a ts casino engine that works without a cocos creator.

I put this casino engine in a cocos creator.

It is a structure in which the elements of the cocos creator detect an event when it occurs in a casino engine and change what is drawn on the screen.

Now let me tell you my problem.

There’s a data class in the casino engine that contains information about the game

The properties of this data class have a property decorator named @EmitWhenChanged

There are parts that automatically generate events when the value of the property changes.

But this isn’t working normally with Cocos creators!

I’ve been using it well on other platforms,

Not in Cocos Creator!

I found the cause!

@EmitWhenChanged The decorator is creating getter/setter using the function ‘Object.defineProperty’,

Since then, by the function ‘_applyDecoratedDescriptor’ of the Cocos creator, recall ‘Object.defineProperty’ again to override the value.

Is there a way to solve this problem?

Casino engines should be converted to js as they are, regardless of the cocos creator!

Is there a way for me?

Please provide a screenshot of your error code or provide a demo to illustrate the issue.

@zzf520
It’s not an error. The problem is that, after I call my own ‘Object.defineProperty’ function, Cocos Creator is making another ‘Object.defineProperty’ call, effectively overwriting my code.

//EmitWhenChanged.ts
import ChangeableData from '../data/ChangeableData';

export function EmitWhenChanged(key: string) {
    return function (target: any, propertyKey: string) {
        Object.defineProperty(target, propertyKey, {
            get(): any {
                return this[`_${String(propertyKey)}`];
            },
            set(newValue: any): void {
                console.log('new!');
                const oldValue = this[`_${String(propertyKey)}`];
                this[`_${String(propertyKey)}`] = newValue;

                if (oldValue !== newValue) {
                    console.log(this);
                    this.eventEmitter?.Emit(ChangeableData.EVENT_TYPE.PROPERTY_UPDATED, key, newValue);
                }
            },
            enumerable: true,
            configurable: true,
        });
    };
}
//testData.ts
class TestData extends ChangeableData {
    @EmitWhenChanged('test')
    public test: number = 32;
}
//testComponent.ts
import * as cc from 'cc';
import TestData from './TestData';
const { ccclass, property } = cc._decorator;

@ccclass('Test')
export class Test extends cc.Component {
    start() {
        const data = new TestData();
        data.eventEmitter.On(TestData.EVENT_TYPE.PROPERTY_UPDATED, (key, value) => {
            console.log(`on changed! ${key} = ${value}`);
            console.log(data.test);
        });

        data.test = 11;
    }
}

compile result

Sure, thank you for the description. I will ask the engineers to take a look.

Im Solved!!!

I made return the description and it’s working!

//EmitWhenChanged.ts

import ChangeableData from '../data/ChangeableData';

export function EmitWhenChanged(key: string) {
    return function (target: any, propertyKey: string) : any {
        const desc = {
            get(): any {
                return this[`_${String(propertyKey)}`];
            },
            set(newValue: any): void {
                const oldValue = this[`_${String(propertyKey)}`];
                this[`_${String(propertyKey)}`] = newValue;

                if (oldValue !== newValue) {
                    this.eventEmitter?.Emit(ChangeableData.EVENT_TYPE.PROPERTY_UPDATED, key, newValue);
                }
            },
            enumerable: true,
            configurable: true,
        };
        Object.defineProperty(target, propertyKey, desc);
        return desc;
    };
}

1 Like