[LayaAir3]自定义Laya.Component,经代码修改其属性(不是人手修改)之后,保存prefab无变化,重新打开prefab发现改动丢失

一.猜测可能是需要调用某个api来标记prefab脏了,这样才能在prefab保存的时候对变动了的属性进行序列化; 但是我查文档和查社区都没有看到类似的描述; 全局搜索dirty相关的内容,也没有看到明显相关的api
 
二.用代码来修改自定义Laya.Component的思路是:
1.先定义这个组件
const {regClass, property, classInfo} = Laya;
@regClass()
exporty class TextComp extends Laya.Component {
     // 无意义的成员变量,只是为了在属性设置里画一个按钮
    @property({type : "number", inspector : "TextCompButtonInspector", private : false})
    private test_number: number;
 
    //准备使用自己写的编辑器窗口来修改的属性,专门指定inspector = null以在属性设置中隐藏默认的inspector
    @property({type : [TextCompSubData]}, inspector = null)
     public sub_datas?: TextCompSubData[] = []; 
}
 
2.画按钮
@IEditor.inspectorField("TextCompButtonInspector")
export class TextCompButtonInspector extends IEditor.PropertyField {
    // 按照文档说的要先加载widget资源
    @IEditor.onLoad
    static async onLoad() {
        await gui.UIPackage.resourtceMgr.load("editorResources/myWidget.widget");
    }
    // 画一个按钮
    create(){
        const input: gui.Widget = gui.UIPackage.createWidgetSync("editorResources/myWidget.widget");
        // 提前在widget里画好一个叫open_btn的按钮
        const open_btn: gui.Button = input.getChild("open_btn");
        open_btn.on("click", () => {
             Editor.panelManager.showPanel("TextCompEditEditor"); // 打开真正用来编辑组件属性的编辑器窗口
 
             // 需要把TextComp对象传到刚刚打开的编辑器窗口里,方便在窗口里修改TextComp的属性
             // 但是按文档说,场景进程和UI进程不互通,所以当按下"open_btn"按钮时,只能找到当前选择的node_id: string
             // 然后异步执行Edition.scene.runScript去让场景进程下的代码,根据node_id找到对应的TextComp
             const selection_obj = Editor.scene.getSelection()[0];
             const node_id: string = selection_obj.id; // 
             Edition.scene.runScript("TextCompSceneProcess.InitMyComp", node_id);
        })
    }
}
3.场景进程里根据node_id找到TextComp
@IEditorEnv.regClass()
export class TextCompSceneProcess {
    static async InitMyComp(this: IEditorEnv.IGameScene, node_id: string) {
        const node = <Laya.Node>this.getNodeById(node_id);
        if (node == undefined) {
            throw Error("未找到节点");
        }
        const myComp: TextComp = node.getComponent(TextComp);
        // 再转发到UI进程, 但是测试没有办法直接传MyComponent到编辑器窗口下,所以曲线救国,把用于展示的内容以string形式传过去
        // 再把node_id也传过去,在编辑器窗口有任何试图对属性的操作,继续使用Edition.scene.runScript再绕到本场景进程里来操作TextComp的属性
        EditorEnv.sendMessageToPanel("TextCompEditEditor", "SetMyComp", myComp:GenShowInfoString(), node_id);
    }
}
 
三.bug描述:
1.当使用上面第二大点里的流程,来在自己绘制的TextCompEditEditor窗口中修改TextComp的属性,是有效果的; 鼠标左键点其他节点再点回来,依然能在编辑器窗口上看到修改后的值。但是保存prefab的时候并没有保存这个内容,查看.lh文件无变化.
2.倘若执行了三.1的操作时先不急着保存prefab退出,而是在属性设置窗口里,把TextComp先disable一下,再enable起来,这样保存prefab,就能观察到.lh文件发生了变化,重新打开prefab也能看到TextComp的属性是修改后的属性
3.对照实验,倘若去掉'inspctor = null', 改成使用默认的inspector
    @property({type : [TextCompSubData]})
     public sub_datas?: TextCompSubData[] = []; 
则直接在属性设置中,添加、删除、修改这个数组的属性,再保存prefab,是能正常保存prefab的
4.猜测:可能默认的inspector对属性的操作,会标记这个component脏了,在保存prefab的时候才会重新序列化它; 而我自己写的编辑器窗口,是使用代码去修改TextComp的属性,就遗漏了上面那个标记dirty的api,从而保存prefab不会重新序列TextComp,导致改动无保存,得手动disable 再enable一下整个TextComp才能正常保存。
5.所以我的猜测对吗?如果是对的,有哪个api能标记Compoent为脏呢?
已邀请:

谷主

赞同来自: 峰竹百回

没看到你贴的代码有修改组件属性的地方。我假设你是在场景进程直接修改组件的属性了,这样是不会产生修改标记的,当然也没法保存。
正确的方式是
1、在UI进程修改数据
2、如果确实想在场景进程修改,那么要使用EditorEnv.scene.recordObject,标记你在修改的属性。
3、如果不想用2,只想无脑告诉IDE场景已经发生修改,可以直接用EditorEnv.scene.setModified。

该问题目前已经被锁定, 无法添加新回复

商务合作
商务合作