震惊,序列化的数组没有长度信息,并且editor中不支持null元素

在开发编辑器插件,3.8.2,有个bug困扰我一下午,仔细研究了一下,真的是有些无奈。

上一个让我无奈的问题是 ui-color 组件的 value 格式,它输入要求[r, g, b, a] ,输出 {r:r, g:g, b:b, a:a},引擎大大们就没有考虑可以增加一种输入格式为{r:r, g:g, b:b, a:a} 可以与输出匹配起来吗?

这次的问题是 编辑一个含null对象数组。
首先你有一个类:

@ccclass("CustomElement")
export class CustomElement{
	@property(CCFloat)
	p:number;
}

然后你有个component ,有个CustomElement 数组:

@ccclass("ElementContainer")
export class ElementContainer extens Component{
	
	@property({type:[CustomElement]})
	elements:CustomElement[] = [];

}

然后你以为在编辑器里把 elements 的 length 调成,比如10,就万事大吉了?
你保存,然后reload,你会发现 elements 的长度依旧是 0
这个操作在Unity 的 list 中很常见,有很多时候就是需要有null元素存在,请问缘何设计的时候不实现这个特性?

有可能是为了简洁,比如 Color 的序列化是这样:

"color": {
      "__type__": "cc.Color",
      "r": 255,
      "g": 255,
      "b": 255,
      "a": 255
    },

你们不想这样:

"lineColor": {
  "__type__": "cc.Color",
  value: [255, 255, 255, 255],
},

因为会多一层value。这是个问题吗?可能是的,因为在dump中你经常会写出 a.value[0].value.b.value.x.value 如此的路径。不过这点不便远不及类似Color带来的这种不变,它们是不一样的性质。

再说回数组,上面的 ElementContainer序列化后大致如下:

{
  "__type__": "ElementContainer ",
  "id": 0,
  "elements": []
}

一个空数组,在编辑器中如果调整了长度,会自动给你生成所有的元素。但是,如果我在一个 @executeInEditMode 的start() 里写上一个:

elements.length = 10;

那就会出现下面这样:

image

看起来是10个 null元素,但是你保存 reload,依旧一个也没有。

  • 并且1,那个Create 按钮不起作用;
  • 并且2,后边那个删除按钮是真的删除了那个元素,长度减一,并不支持置null操作。

为啥这样搞?是不是还是因为只有一个 [] 根本无法保存信息?这和 Color 的问题是不是很像?假如这样序列化会不会好些?

{
  "__type__": "ElementContainer ",
  "id": 0,
  "elements": {
    "__type__": "Array"
    length: 10,
    value: [null, null, null, null, null, null, null, null, null, null]
  }
},

有人说了,你在插件代码里直接对 dump 的 elements 操作不就行了?
我试过了,我试过先push一堆 null 后然后 [] , splice 都确实是可以在dump里变成类似:

[
  null,
  {
    "__id__": 298
  },
  null
]

然而但是,你修改完 dump是需要 dispatch(‘change-dump’) 的吧,然而,cocos 却给出了如下错误:
image

为这个错误我调试了一下午,我模板里确实用了几个 v-for,我左调右调上调下调就是没有发现到底是哪块出了问题,直到,我想明白了,这是 cocos 就是这样设计的!它不允许有 null 元素 的数组!这真是出人意料,你说不给数组序列化 length还说得过去,不让数组的dump 刷新 null 元素,这到底是人性的扭曲还是道德的沦丧,还是简单的一个bug?

另外,那个

"__id__": 298

对象引用毫无可读性可言,我上哪找这个对象去?就不舍得给每个对象也加个 id?又占用反序列化时间了?

还有个痛苦:
image

每次写完编辑器的code,run build后要开关一下这个扩展。然而这个删除插件的图标就在那里,像午夜的幽灵,默默勾引或静静等待你 点她,你得小心翼翼抵抗她的诱惑,真的是揪心!

揪心的地方还不少,这次就先到这吧。

2赞