添加一个组件到prefab,需要通过将组件对应的对象存在磁盘种后,再标记为prefab的一个部分。这部分在prefab.cpp中
prefab删除一个对象的方式是分两种情况,第一种就是这个对象再prefab中还存在则通过放到PrefabModification::RemovedComponents的移除对象池中,并设置prefab是脏的状态。在之后的状态下移除。另一种就是missing的情况下通过BaseObject的DestroySingleObject来移除。他是通过加锁后在另一个线程删掉object的。
BaseObject的删除过程。
当要保存prefab的时候会执行PrefabCreation.cpp的SavePrefab_Internal。首先他会寻找是否存在这个名字和路径下的prefab了,如果存在会先删掉。
然后分几种情况保存,一个是在assets中的,一个在实例化树中的,还有一种在失去关联的时候保存的。
然后创建id和meta
然后保存的时候分两种情况。
一种是在实例化树中保存的或者是失去关联关系的,这种情况下直接拷贝出副本来执行。
另一种是在assets里保存的,这种他要在PersistentManager::GetInstanceIDsAtPath中遍历所有文件
找到所有相关的prefab都设置一遍
然后让实例化出来的prefab执行awake并且刷新属性,
然后会对克隆出来的对象设置属性。
在InheritGameObjectAndTransformProperties设置属性,包括gameobject属性,component属性以及transform属性
然后在InheritMonoBehaviours中保存脚本数据
然后把克隆的数据写objectsToWrite中,
最后写object,实际就是序列化文件。
在PrefabInstance.cpp中实现。实例化就相当于放在了场景中,这一步是需要拷贝源prefab的,在保存prefab的时候也会执行
将位置,大小,锚定点之类的拷贝一份到实例化文件。如果prefab源文件保存,这些实例化的文件需要重新awake,然后会更新数据。
instance还有回滚功能,在prefabInstance的RevertPrefabInstance实现,也就是在撤销的时候处理,先通过传进来的object转到prefabinstance来确定是否属于prefabinstance,通过GetObjectDataArrayFromPrefabRoot来收集哪些是已有的哪些是新增的,RevertInstantiatedAssetReferencesToParentObject回滚使用的material。
然后首先通过std::reverse逆转addObjects,然后对数据一个一个删除。最后通过RevertAllButDefaultPrefabOverrides来回滚rootTransform,rootRectTransform和rootGO。
如果是没链接上的则直接链接上的对象就可以了。他链接上的方法是找到源prefab,然后赋值一下prefab数据。
在启动场景的时候,构建app的时候,保存场景的时候都会链接prefab,比如在启动场景时执行LoadSceneOperation::CompleteAwakeSequence(),在editor下会会执行UnpackAllPrefabInstances
到PrefabConnection.cpp里执行UnpackAllPrefabInstances,获取所有prefab的实例,并对每个进行解压,
如果这个prefab是属于kPrefabUnpackMode_OuterRoot,也就是解析外层的模式下则执行TransferModifiedPropertiesForUnpack,执行到TransferModifiedPropertiesFromNestedInstancesInAssetToNewInstancesForUnpack。这里主要对prefab被修改的部分修正。
然后kPrefabUnpackMode_OuterRoot模式执行TransferRemovedComponentsForUnpack,执行到TransferRemovedComponentsFromNestedInstancesInAssetToNewInstancesForUnpack,对需要移除的对象放到移除队列。