static KeyValuePair<GUIContent, System.Action>[] GetButtonsData(PEPrefabScript prefabInstance, SerializedProperty prefabProperty, SerializedProperty instanceProperty) { var buttons = new KeyValuePair<GUIContent, System.Action>[] { new KeyValuePair<GUIContent, System.Action>(new GUIContent("Revert", "Revert property to prefab value"), () => { if (prefabProperty == null) return; if (instanceProperty.propertyType == SerializedPropertyType.ObjectReference) { var link = prefabInstance.GetDiffWith().Links[prefabProperty.objectReferenceValue]; if (link == null) instanceProperty.SetPropertyValue(prefabProperty.GetPropertyValue()); else { var instanceLink = prefabInstance.Links[link]; if (instanceLink != null) instanceProperty.SetPropertyValue(prefabInstance.Links[link].InstanceTarget); else { if (PEPrefs.DebugLevel > 0) Debug.Log("Link null"); instanceProperty.SetPropertyValue(prefabProperty.GetPropertyValue()); } } } else { instanceProperty.SetPropertyValue(prefabProperty.GetPropertyValue()); } instanceProperty.serializedObject.ApplyModifiedProperties(); }), new KeyValuePair<GUIContent, System.Action>(new GUIContent("Update", "Update changes"), () => EditorApplication.delayCall += prefabInstance.BuildModifications), }; return buttons; }
static internal void BuildLinks(this PEPrefabScript _this, bool force = false) { if (force || _this.Prefab == _this.gameObject) { _this.Links.BuildLinks(_this.gameObject); EditorUtility.SetDirty(_this); } else { if (_this == null) { Debug.LogError("PEPrefabScriptExt.BuildLinks() - _this == null"); return; } if (_this.Prefab == null) { Debug.LogError(string.Format("PEPrefabScriptExt.BuildLinks(_this.name='{0}') - _this.Prefab == null. PrefabPath:{1}", _this.name, AssetDatabase.GetAssetOrScenePath(_this))); return; } PEPrefabScript pePrefabScript = _this.Prefab.GetComponent <PEPrefabScript>(); if (pePrefabScript == null) { Debug.LogError(string.Format("PEPrefabScriptExt.BuildLinks(_this.name='{0}') - expecting prefab with _this.Prefab.name='{1}' to have attached PEPrefabScript Component. PrefabPath:{2} (Click on this message to show this prefab in Project window)", _this.name, _this.Prefab.name, AssetDatabase.GetAssetPath(_this.Prefab)), _this.Prefab); return; } pePrefabScript.BuildLinks(); EditorUtility.SetDirty(pePrefabScript); } }
static void ApplyModifications(this PEPrefabScript _this, PEPrefabScript targetInstance) { targetInstance.Modifications = _this.Modifications; var modificatedList = new List <SerializedObject>(); foreach (var modification in _this.Modifications.Modificated) { if (modification.Mode == PEModifications.PropertyData.PropertyMode.Ignore) { continue; } if (modification.Object == null) { continue; } var selfObject = new SerializedObject(modification.Object); var linkedObject = targetInstance.Links[modification.ObjeckLink]; if (linkedObject == null || linkedObject.InstanceTarget == null) { continue; } var targetObject = new SerializedObject(linkedObject.InstanceTarget); var selfProperty = selfObject.FindProperty(modification.PropertyPath); var targetProperty = targetObject.FindProperty(modification.PropertyPath); if (targetProperty == null) { Debug.Log("Property not found " + modification.PropertyPath); } else { var value = selfProperty.GetPropertyValue(); if (selfProperty.propertyType == SerializedPropertyType.ObjectReference) { var selfValue = selfProperty.GetPropertyValue(); var selfLink = _this.Links[selfValue as Object]; var targetLink = targetInstance.Links[selfLink]; if (targetLink != null) { value = targetLink.InstanceTarget; } } targetProperty.SetPropertyValue(value); targetObject.ApplyModifiedProperties(); } } foreach (var po in modificatedList) { po.ApplyModifiedProperties(); } }
public void Fill(PEPrefabScript script) { script.Properties = this.Properties; script.Links = this.Links; script.Modifications = this.Modifications; script.ParentPrefabGUID = this.ParentPrefabGUID; script.PrefabGUID = this.PrefabGUID; }
public PrefabInternalData(PEPrefabScript script) { this.Properties = script.Properties; this.Links = script.Links; this.Modifications = script.Modifications; this.ParentPrefabGUID = script.ParentPrefabGUID; this.PrefabGUID = script.PrefabGUID; }
static internal PEPrefabScript GetDiffWith(this PEPrefabScript _this) { var go = _this.ParentPrefab != null && (PrefabUtility.GetPrefabParent(_this.gameObject) == _this.Prefab || PEUtils.FindRootPrefab(_this.gameObject) == _this.Prefab) ? _this.ParentPrefab : _this.Prefab; return(go != null?go.GetComponent <PEPrefabScript>() : null); }
static internal void RevertToParent(this PEPrefabScript _this) { _this.Modifications = new PEModifications(); var thisPrefab = _this.Prefab; var thisParentPrefab = _this.ParentPrefab; var newInstance = _this.ReplaceInPlace(_this.ParentPrefab, false); newInstance.Prefab = thisPrefab; newInstance.ParentPrefab = thisParentPrefab; }
static internal void BuildLinks(this PEPrefabScript _this, bool force = false) { if (force || _this.Prefab == _this.gameObject) { _this.Links.BuildLinks(_this.gameObject); EditorUtility.SetDirty(_this); } else { _this.Prefab.GetComponent <PEPrefabScript>().BuildLinks(); EditorUtility.SetDirty(_this.Prefab.GetComponent <PEPrefabScript>()); } }
static internal void DoApply(PEPrefabScript script) { if (PEPrefs.DebugLevel > 0) { Debug.Log("DoApply Start"); } script.ApplyChanges(true); if (PEPrefs.DebugLevel > 0) { Debug.Log("DoApply Completed"); } DoAutoSave(); }
static IEnumerator SelectObjectRoutine(PEPrefabScript prefabInstance) { EditorGUIUtility.ShowObjectPicker <GameObject>(null, false, "t:Prefab", 1); Object obj = null; while (EditorGUIUtility.GetObjectPickerControlID() == 1) { obj = EditorGUIUtility.GetObjectPickerObject(); yield return(null); } if (obj != null && EditorUtility.DisplayDialog("Replace", string.Format("Do you want to replace {0} with {1}", prefabInstance.gameObject.name, obj.name), "Replace", "Cancel")) { prefabInstance.ReplaceInPlace(obj as GameObject, EditorUtility.DisplayDialog("Replace", "Apply modifications from current instance?", "Apply", "Don't apply"), false); } }
static public bool CheckPrefab(this PEPrefabScript prefabScript) { if (prefabScript == null) { return(true); } var prefabAsset = prefabScript.Prefab; if (prefabAsset == null) { if (!string.IsNullOrEmpty(prefabScript.PrefabGUID)) { Debug.LogErrorFormat(prefabScript.gameObject, "Prefab asset is missing. Prefab has a reference to missing prefab asset. Asset GUID:{0}, PrefabPath:{1}", prefabScript.PrefabGUID, AssetDatabase.GetAssetOrScenePath(prefabScript)); } return(false); } var prefabAssetScript = prefabAsset.GetComponent <PEPrefabScript>(); if (prefabAssetScript == null) { Debug.LogErrorFormat(prefabAsset, "Prefab asset script is missing. Prefab has a reference to prefab asset, that must have attached PrefabScript. Asset GUID:{0}, AssetPath:{1} PrefabPath:{2}", prefabScript.PrefabGUID, AssetDatabase.GetAssetPath(prefabAsset), AssetDatabase.GetAssetOrScenePath(prefabScript)); return(false); } if (!string.IsNullOrEmpty(prefabScript.ParentPrefabGUID)) { var parentPrefabAsset = prefabScript.ParentPrefab; if (parentPrefabAsset == null) { Debug.LogErrorFormat(prefabScript.gameObject, "Parent Prefab asset is missing. Prefab has a reference to missing prefab asset. Asset GUID:{0}, PrefabPath:{1}", prefabScript.ParentPrefabGUID, AssetDatabase.GetAssetOrScenePath(prefabScript)); return(false); } var parentPrefabAssetScript = parentPrefabAsset.GetComponent <PEPrefabScript>(); if (parentPrefabAssetScript == null) { Debug.LogErrorFormat(parentPrefabAsset, "Parent Prefab asset script is missing. Prefab has a reference to prefab asset, that must have attached PrefabScript. Asset GUID:{0}, AssetPath:{1} PrefabPath:{2}", prefabScript.ParentPrefabGUID, AssetDatabase.GetAssetPath(parentPrefabAsset), AssetDatabase.GetAssetOrScenePath(prefabScript)); return(false); } } return(true); }
static void OnValidate(this PEPrefabScript _this) { if (PrefabUtility.GetPrefabType(_this.gameObject) == PrefabType.Prefab) { EditorApplication.delayCall += () => { if (_this == null) { return; } if (_this.Prefab != _this.gameObject && _this.transform == _this.transform.root) { _this.Prefab = _this.gameObject; _this.BuildLinks(); } }; } }
static internal void BuildModifications(this PEPrefabScript _this) { var type = PrefabUtility.GetPrefabType(_this.gameObject); if (type != PrefabType.ModelPrefab) { var diff = _this.GetDiffWith(); if (diff == null) { Debug.LogError(_this.name + " : " + "Diff Object is not exists"); return; } _this.Modifications.CalculateModifications(_this.GetDiffWith(), _this); } _this.InvokeOnBuildModifications(); }
static KeyValuePair <GUIContent, System.Action>[] GetButtonsData(PEPrefabScript prefabInstance, SerializedProperty prefabProperty, SerializedProperty instanceProperty) { var buttons = new KeyValuePair <GUIContent, System.Action>[] { new KeyValuePair <GUIContent, System.Action>(new GUIContent("Revert", "Revert property to prefab value"), () => { if (prefabProperty == null) { return; } if (instanceProperty.propertyType == SerializedPropertyType.ObjectReference) { var link = prefabInstance.GetDiffWith().Links[prefabProperty.objectReferenceValue]; if (link == null) { instanceProperty.SetPropertyValue(prefabProperty.GetPropertyValue()); } else { var instanceLink = prefabInstance.Links[link]; if (instanceLink != null) { instanceProperty.SetPropertyValue(prefabInstance.Links[link].InstanceTarget); } else { if (PEPrefs.DebugLevel > 0) { Debug.Log("Link null"); } instanceProperty.SetPropertyValue(prefabProperty.GetPropertyValue()); } } } else { instanceProperty.SetPropertyValue(prefabProperty.GetPropertyValue()); } instanceProperty.serializedObject.ApplyModifiedProperties(); }), new KeyValuePair <GUIContent, System.Action>(new GUIContent("Update", "Update changes"), () => EditorApplication.delayCall += prefabInstance.BuildModifications), }; return(buttons); }
static internal void GetProperties(this PEModifications.PropertyData _this, out SerializedProperty prefabProperty, out SerializedProperty objectProperty, PEPrefabScript script) { var couple = _this.UserData as PropertyCouple; if (couple == null) { couple = new PropertyCouple(); if (couple.objectProperty == null) { var so = new SerializedObject(_this.Object); if (so != null) couple.objectProperty = so.FindProperty(_this.PropertyPath); if (couple.objectProperty == null) { if (PEPrefs.DebugLevel > 0) Debug.Log(string.Format("Property {0} not found on Object {1}", _this.PropertyPath, _this.Object)); } } if (couple.prefabProperty == null) { var prefabObject = script.Links.GetPrefabObject(script.GetDiffWith().gameObject, _this.Object); if (prefabObject != null) { var so = new SerializedObject(prefabObject); if (so != null) couple.prefabProperty = so.FindProperty(_this.PropertyPath); } else { Debug.LogWarning("Prefab object for prefab property modifications is not found"); } } } prefabProperty = couple.prefabProperty; objectProperty = couple.objectProperty; _this.UserData = couple; }
static internal void DoApply(PEPrefabScript script) { if (PEPrefs.DebugLevel > 0) { Debug.Log("DoApply Start"); } try { AssetDatabase.StartAssetEditing(); script.ApplyChanges(true); } finally { AssetDatabase.StopAssetEditing(); } if (PEPrefs.DebugLevel > 0) { Debug.Log("DoApply Completed"); } DoAutoSave(); }
static internal void InjectChild(PEPrefabScript obj, GameObject[] children) { var path = AssetDatabase.GenerateUniqueAssetPath(System.IO.Path.ChangeExtension(AssetDatabase.GUIDToAssetPath(obj.PrefabGUID), null) + "_Child_Injected.prefab"); var go = PrefabUtility.CreatePrefab(path, obj.gameObject, ReplacePrefabOptions.Default); var prefabInstance = go.GetComponent <PEPrefabScript>(); prefabInstance.Prefab = go; prefabInstance.ParentPrefabGUID = obj.PrefabGUID; prefabInstance.BuildModifications(); Selection.activeObject = PrefabUtility.InstantiatePrefab(go); AssetDatabase.ImportAsset(path); PECache.Instance.CheckPrefab(path); foreach (var child in children) { child.GetComponent <PEPrefabScript>().ParentPrefabGUID = AssetDatabase.AssetPathToGUID(path); PECache.Instance.CheckPrefab(AssetDatabase.GUIDToAssetPath(child.GetComponent <PEPrefabScript>().PrefabGUID)); } }
static IEnumerable<Object> GetRemovedObjects(Object go, PEPrefabScript prefabInstance) { foreach (var liif in prefabInstance.Modifications.RemovedObjects) { var instanceObj = prefabInstance.GetDiffWith().Links[liif]; if (instanceObj == null) continue; var removedGO = instanceObj.InstanceTarget as GameObject; var removedComponent = instanceObj.InstanceTarget as Component; if (removedComponent is PEPrefabScript) continue; var remoteParent = (removedGO != null) ? (removedGO.transform.parent == null ? removedGO.transform.gameObject : removedGO.transform.parent.gameObject) : (removedComponent != null ? removedComponent.gameObject : null); var localLink = prefabInstance.Links[prefabInstance.GetDiffWith().Links[remoteParent]]; if (localLink == null) continue; var localParent = localLink.InstanceTarget; if (localParent == go) yield return instanceObj.InstanceTarget; } }
internal static void CalculateModifications(this PEModifications _this, PEPrefabScript prefab, PEPrefabScript instance) { instance.Modifications.Modificated.RemoveAll(m => m.Mode == PEModifications.PropertyData.PropertyMode.Default); var counter = 0; foreach (var link in instance.Links.Links) { if (link == null || link.InstanceTarget == null || link.InstanceTarget == instance || link.InstanceTarget is PEPrefabScript) continue; var so = new SerializedObject(link.InstanceTarget); var property = so.GetIterator(); var prefabObjectLink = prefab.Links[link]; if (prefabObjectLink == null) continue; var prefabObject = prefabObjectLink.InstanceTarget; if (prefabObject == null) continue; var prefabSerializedObject = new SerializedObject(prefabObject); while (property.Next(CheckChild(property))) { counter++; if (PEUtils.PropertyFilter(property)) { continue; } var prefabProperty = prefabSerializedObject.FindProperty(property.propertyPath); var isArray = property.propertyPath.Contains(".Array.data["); if (prefabProperty == null && !isArray) { if (PEPrefs.DebugLevel > 0) Debug.Log("Property not found(Some times its happens) " + property.propertyPath); continue; } var instanceValue = property.GetPropertyValue(); var prefabValue = prefabProperty == null ? null : prefabProperty.GetPropertyValue(); var isChanged = !object.Equals(instanceValue, prefabValue); if (isChanged) { if (property.propertyType == SerializedPropertyType.ObjectReference) { var instanceLink = instance.Links[instanceValue as Object]; var prefabLink = prefab.Links[prefabValue as Object]; if (prefabLink != null && instanceLink != null) isChanged = prefabLink.LIIF != instanceLink.LIIF; } else { var animationCurve = instanceValue as AnimationCurve; if (animationCurve != null) { isChanged = !PEUtils.Compare(animationCurve, prefabValue as AnimationCurve); } } } if (!isChanged) continue; instance.Modifications.AddModification(new PEModifications.PropertyData { Object = link.InstanceTarget, PropertyPath = property.propertyPath, ObjeckLink = link.LIIF, }); } } instance.Modifications.CalculateStructureDiff(prefab, instance); }
private static void CalculateStructureDiff(this PEModifications _this, PEPrefabScript prefab, PEPrefabScript instance) { _this.NonPrefabObjects.Clear(); var hierarchy = EditorUtility.CollectDeepHierarchy(new[] { instance }); foreach (var transform in hierarchy.OfType<Transform>()) { if (transform.parent == null) continue; var link = prefab.Links[instance.Links[transform]]; if (link != null) continue; _this.NonPrefabObjects.Add(new PEModifications.HierarchyData { child = transform, parent = transform.parent }); } _this.NonPrefabComponents.Clear(); foreach (var component in hierarchy.Where(obj => !(obj is Transform)).OfType<Component>()) { var link = prefab.Links[instance.Links[component]]; if (link != null || prefab.Links[instance.Links[component.gameObject.transform]] == null) continue; _this.NonPrefabComponents.Add(new PEModifications.ComponentsData { child = component, parent = component.gameObject }); } _this.RemovedObjects.Clear(); foreach (var link in prefab.Links.Links) { if (link.InstanceTarget is Transform) continue; if (instance.Links[link] == null || instance.Links[link].InstanceTarget == null) _this.RemovedObjects.Add(link.LIIF); } _this.TransformParentChanges.Clear(); foreach (var link in instance.Links.Links) { var transform = link.InstanceTarget as Transform; if (transform == null) continue; var currentTransform = transform; if (currentTransform == instance.transform) continue; var currentTransformParent = currentTransform.parent; if (prefab.Links[link] == null) continue; var otherTransform = prefab.Links[link].InstanceTarget as Transform; var otherTransformParent = otherTransform.parent; if (prefab.Links[otherTransformParent] == null || instance.Links[currentTransformParent] == null || prefab.Links[otherTransformParent].LIIF != instance.Links[currentTransformParent].LIIF) _this.TransformParentChanges.Add(new PEModifications.HierarchyData { child = currentTransform, parent = currentTransformParent }); } }
static internal PEPrefabScript ReplaceInPlace(this PEPrefabScript _this, GameObject prefabObject, bool applyModifications = true, bool keepPrefabLink = true) { var newObject = PrefabUtility.InstantiatePrefab(prefabObject) as GameObject; PEUtils.SetParentAndSaveLocalTransform(newObject.transform, _this.transform.parent); newObject.transform.SetSiblingIndex(_this.transform.GetSiblingIndex()); PrefabUtility.DisconnectPrefabInstance(newObject); PrefabUtility.DisconnectPrefabInstance(_this.gameObject); var newObjectPrefabInstance = newObject.GetComponent <PEPrefabScript>(); if (newObjectPrefabInstance == null) { Debug.LogWarning("EvolvePrefab not found on replacing object"); } newObject.transform.localPosition = _this.transform.localPosition; if (prefabObject == _this.ParentPrefab || !applyModifications) { foreach (var link in _this.Links.Links) { if (newObjectPrefabInstance.Links[link] == null) { newObjectPrefabInstance.Links.Links.Add(link); } } } if (applyModifications && newObjectPrefabInstance) { _this.ApplyModifications(newObjectPrefabInstance); } var replaceDict = new Dictionary <Object, Object>(); replaceDict.Add(_this.gameObject, newObject); replaceDict.Add(_this.transform, newObject.transform); if (newObjectPrefabInstance) { foreach (var link in _this.Links.Links) { var from = link.InstanceTarget; var to = newObjectPrefabInstance.Links[link.LIIF]; if (from == null || to == null) { continue; } if (from == _this.gameObject || from == _this.transform) { continue; } replaceDict.Add(from, to.InstanceTarget); } } var destroyList = new List <GameObject>(); foreach (var link in _this.Links.Links) { if (link == null || link.InstanceTarget is Component) { continue; } var go = link.InstanceTarget as GameObject; if (!go) { continue; } if (_this.Modifications.NonPrefabObjects.Any(m => m.child == go.transform)) { continue; } destroyList.Add(go); } PEUtils.ReplaceReference(_this.transform.root, replaceDict); var npo = _this.Modifications.NonPrefabObjects.Where(tm => tm != null && tm.child != null && tm.parent != null); { var indID = 0; var indexes = new List <int>(npo.Select(n => n.child.GetSiblingIndex())); npo.Foreach(transformModification => PEUtils.SetParentAndSaveLocalTransform(transformModification.child, transformModification.parent)); npo.Foreach(transformModification => transformModification.child.SetSiblingIndex(indexes [indID++])); } var reversedComponents = _this.Modifications.NonPrefabComponents.Reverse <PEModifications.ComponentsData> (); var newComponents = new List <Component> (); foreach (var nonPrefabComponent in reversedComponents) { Component newComponent; newComponents.Add(newComponent = nonPrefabComponent.child.CopyComponentTo(nonPrefabComponent.parent)); PEUtils.CopyPrefabInternalData(nonPrefabComponent.child, newComponent); } var i = 0; foreach (var nonPrefabComponent in reversedComponents) { var newComponent = newComponents[i++]; if (newComponent) { PEUtils.ReplaceReference(nonPrefabComponent.parent.transform.root, nonPrefabComponent.child, newComponent); replaceDict.Add(nonPrefabComponent.child, newComponent); } } if (applyModifications) { foreach (var transformModification in _this.Modifications.TransformParentChanges) { var index = transformModification.child.GetSiblingIndex(); PEUtils.SetParentAndSaveLocalTransform(transformModification.child, transformModification.parent); transformModification.child.SetSiblingIndex(index); } foreach (var id in _this.Modifications.RemovedObjects) { var link = newObjectPrefabInstance.Links[id]; if (PEPrefs.DebugLevel > 0 && link != null) { Debug.Log(string.Format("Object to remove: {0} {1}", id, link.InstanceTarget)); } if (link != null && link.InstanceTarget) { if (PEPrefs.DebugLevel > 0) { Debug.Log(string.Format("Destroy Object: {0}", link.InstanceTarget)); } if (link.InstanceTarget == newObject || link.InstanceTarget == newObjectPrefabInstance) { Debug.LogError("Inconsistent Destroying while replacing"); continue; } Object.DestroyImmediate(link.InstanceTarget); } } } if (keepPrefabLink) { newObjectPrefabInstance.ParentPrefab = _this.ParentPrefab; newObjectPrefabInstance.Prefab = _this.Prefab; } foreach (var kv in replaceDict) { PEUtils.CopyPrefabInternalData(kv.Key, kv.Value); } newObject.name = _this.gameObject.name; Object.DestroyImmediate(_this.gameObject); foreach (var go in destroyList) { if (go == null) { continue; } if (go == newObject) { Debug.LogError("Inconsistend Destroying while replacing"); continue; } Object.DestroyImmediate(go); } if (newObjectPrefabInstance) { newObjectPrefabInstance.BuildModifications(); EditorUtility.SetDirty(newObjectPrefabInstance); if (prefabObject == _this.ParentPrefab) { newObjectPrefabInstance.Properties = _this.Properties; } if (newObjectPrefabInstance.gameObject == null) { Debug.LogError("New GameObject is destroyed while replacing... o_O"); } } try { newObjectPrefabInstance.gameObject.name = newObjectPrefabInstance.gameObject.name; } catch (MissingReferenceException) { Debug.LogError("New EvolvePrefabScript is destroyed while replacing"); } catch (System.NullReferenceException) { } return(newObjectPrefabInstance); }
static internal void Revert(this PEPrefabScript _this) { _this.Modifications = new PEModifications(); _this.ReplaceInPlace(_this.Prefab, false); }
static internal void CalculateModifications(this PEModifications _this, PEPrefabScript prefab, PEPrefabScript instance) { instance.Modifications.Modificated.RemoveAll(m => m.Mode == PEModifications.PropertyData.PropertyMode.Default); var counter = 0; foreach (var link in instance.Links.Links) { if (link == null || link.InstanceTarget == null || link.InstanceTarget == instance || link.InstanceTarget is PEPrefabScript) { continue; } var so = new SerializedObject(link.InstanceTarget); var property = so.GetIterator(); var prefabObjectLink = prefab.Links[link]; if (prefabObjectLink == null) { continue; } var prefabObject = prefabObjectLink.InstanceTarget; if (prefabObject == null) { continue; } var prefabSerializedObject = new SerializedObject(prefabObject); while (property.Next(CheckChild(property))) { counter++; if (PEUtils.PropertyFilter(property)) { continue; } var prefabProperty = prefabSerializedObject.FindProperty(property.propertyPath); var isArray = property.propertyPath.Contains(".Array.data["); var isInherited = link.InstanceTarget.GetType().IsSubclassOf(prefabObject.GetType()); if (prefabProperty == null && !isArray && !isInherited) { if (PEPrefs.DebugLevel > 0) { Debug.Log("Property not found(Some times its happens) " + property.propertyPath); } continue; } var instanceValue = property.GetPropertyValue(); var prefabValue = prefabProperty == null ? null : prefabProperty.GetPropertyValue(); var isChanged = !object.Equals(instanceValue, prefabValue); if (isChanged) { if (property.propertyType == SerializedPropertyType.ObjectReference) { var instanceLink = instance.Links[instanceValue as Object]; var prefabLink = prefab.Links[prefabValue as Object]; if (prefabLink != null && instanceLink != null) { isChanged = prefabLink.LIIF != instanceLink.LIIF; } } else { var animationCurve = instanceValue as AnimationCurve; if (animationCurve != null) { isChanged = !PEUtils.Compare(animationCurve, prefabValue as AnimationCurve); } } } if (!isChanged) { continue; } instance.Modifications.AddModification(new PEModifications.PropertyData { Object = link.InstanceTarget, PropertyPath = property.propertyPath, ObjeckLink = link.LIIF, }); } } instance.Modifications.CalculateStructureDiff(prefab, instance); }
static private void CalculateStructureDiff(this PEModifications _this, PEPrefabScript prefab, PEPrefabScript instance) { _this.NonPrefabObjects.Clear(); var hierarchy = EditorUtility.CollectDeepHierarchy(new[] { instance }); foreach (var transform in hierarchy.OfType <Transform>()) { if (transform.parent == null) { continue; } var link = prefab.Links[instance.Links[transform]]; if (link != null) { continue; } _this.NonPrefabObjects.Add(new PEModifications.HierarchyData { child = transform, parent = transform.parent }); } _this.NonPrefabComponents.Clear(); foreach (var component in hierarchy.Where(obj => !(obj is Transform)).OfType <Component>()) { var link = prefab.Links[instance.Links[component]]; if (link != null || prefab.Links[instance.Links[component.gameObject.transform]] == null) { continue; } _this.NonPrefabComponents.Add(new PEModifications.ComponentsData { child = component, parent = component.gameObject }); } _this.RemovedObjects.Clear(); foreach (var link in prefab.Links.Links) { if (link.InstanceTarget is Transform) { continue; } if (instance.Links[link] == null || instance.Links[link].InstanceTarget == null) { _this.RemovedObjects.Add(link.LIIF); } } _this.TransformParentChanges.Clear(); foreach (var link in instance.Links.Links) { var transform = link.InstanceTarget as Transform; if (transform == null) { continue; } var currentTransform = transform; if (currentTransform == instance.transform) { continue; } var currentTransformParent = currentTransform.parent; if (prefab.Links[link] == null) { continue; } var otherTransform = prefab.Links[link].InstanceTarget as Transform; var otherTransformParent = otherTransform.parent; if (prefab.Links[otherTransformParent] == null || instance.Links[currentTransformParent] == null || prefab.Links[otherTransformParent].LIIF != instance.Links[currentTransformParent].LIIF) { _this.TransformParentChanges.Add(new PEModifications.HierarchyData { child = currentTransform, parent = currentTransformParent }); } } }
static internal IEnumerable <GameObject> GetPrefabsWithInstances(this PEPrefabScript _this) { return(PECache.Instance.GetPrefabsWithInstances(_this.PrefabGUID)); }
static internal void ApplyChanges(this PEPrefabScript _this, bool buildModifications = false) { if (!_this) { return; } if (PEPrefs.DebugLevel > 0) { Debug.Log(string.Format("[Begin Apply] {0}", _this.name)); } EditorUtility.DisplayProgressBar("Apply changes", _this.name, 0f); if (buildModifications) { foreach (var pi in _this.GetComponentsInChildren <PEPrefabScript>(true)) { pi.BuildModifications(); } } if (recursionCounter++ > 100) { Debug.LogError("Recursion"); recursionCounter = 0; EditorUtility.ClearProgressBar(); return; } _this.BuildLinks(true); _this.BuildModifications(); var newPrefab = !AssetDatabase.Contains(_this.gameObject) ? PrefabUtility.ReplacePrefab(_this.gameObject, _this.Prefab, ReplacePrefabOptions.ConnectToPrefab) : _this.gameObject; var prefabs = _this.GetPrefabsWithInstances(); foreach (var prefab in prefabs) { if (PEPrefs.DebugLevel > 0) { Debug.Log("[Apply] Found Nested instance:" + prefab.name); } var instantiatedPrefabsList = new List <GameObject>(); var instances = new List <PEPrefabScript>(); if (prefab == null) { continue; } var pi = (GameObject)PrefabUtility.InstantiatePrefab(prefab); PrefabUtility.DisconnectPrefabInstance(pi); var nestedInstances = PEUtils.GetNestedInstances(pi).Where(p => p.PrefabGUID == _this.PrefabGUID && p.enabled).ToArray(); instances.AddRange(nestedInstances); var rootInstance = pi.GetComponent <PEPrefabScript>(); if (rootInstance && rootInstance.ParentPrefabGUID == _this.PrefabGUID) { instances.Insert(0, rootInstance); } instantiatedPrefabsList.Add(pi); var counter = 0; foreach (var instance in instances) { if (instance == null || instance.gameObject == null) { Debug.LogWarning("[Apply] Huston we have a problem. Prefab is destroyed before replace"); continue; } instantiatedPrefabsList.Remove(instance.gameObject); var newObject = instance.ReplaceInPlace(newPrefab); if (newObject == null || newObject.gameObject == null) { Debug.LogWarning("[Apply] Huston we have a problem. Prefab is destroyed after replace"); continue; } if (newObject.ParentPrefab == newPrefab) { instantiatedPrefabsList.Add(newObject.gameObject); } PrefabUtility.RecordPrefabInstancePropertyModifications(newObject); EditorUtility.DisplayProgressBar("Apply changes", _this.name + " replaced in " + newObject.gameObject, ((float)counter++) / (float)instances.Count); } foreach (var instantiatedPrefab in instantiatedPrefabsList) { if (instantiatedPrefab == null) { continue; } var instance = instantiatedPrefab.GetComponent <PEPrefabScript>(); if (instance) { instance.ApplyChanges(); } else { PrefabUtility.ReplacePrefab(instantiatedPrefab, PrefabUtility.GetPrefabParent(instantiatedPrefab), ReplacePrefabOptions.ConnectToPrefab); } Object.DestroyImmediate(instantiatedPrefab); } } recursionCounter--; if (PEPrefs.DebugLevel > 0) { Debug.Log(string.Format("[End Apply] {0}", _this.name)); } }
static internal void BuildMenu(GenericMenu menu, PEPrefabScript prefabInstance, bool rootPrefab, string path = "", bool showParent = true, bool showInstances = true) { if (buildMenuRecursionList.Contains(prefabInstance.Prefab)) { buildMenuRecursionList.AddLast(prefabInstance.Prefab); var prefabsArray = buildMenuRecursionList.Select(p => AssetDatabase.GetAssetPath(p)).ToArray(); buildMenuRecursionList.Clear(); throw new System.Exception("Prefab recursion detected:\n" + string.Join("\n", prefabsArray)); } buildMenuRecursionList.AddLast(prefabInstance.Prefab); if (prefabInstance.ParentPrefab == null || !showParent) { menu.AddItem(new GUIContent(path + prefabInstance.Prefab.name), false, () => { }); } else { BuildMenu(menu, prefabInstance.ParentPrefab.GetComponent <PEPrefabScript>(), false, path + prefabInstance.Prefab.name + "/", true, false); menu.AddItem(new GUIContent(path + prefabInstance.Prefab.name), false, () => { }); } menu.AddSeparator(path + ""); var isPrefab = prefabInstance.gameObject == prefabInstance.Prefab.gameObject; menu.AddItem(new GUIContent(path + "Select"), false, SelectPrefab, prefabInstance); var prefabType = PrefabUtility.GetPrefabType(prefabInstance.gameObject); var canApply = rootPrefab && prefabType != PrefabType.ModelPrefab && prefabType != PrefabType.ModelPrefabInstance && prefabType != PrefabType.DisconnectedModelPrefabInstance; if (canApply) { menu.AddItem(new GUIContent(path + "Apply"), false, Apply, prefabInstance); } if (!AssetDatabase.Contains(prefabInstance) || !isPrefab) { menu.AddItem(new GUIContent(path + "Revert"), false, Revert, prefabInstance); if (prefabInstance.ParentPrefab != null) { menu.AddItem(new GUIContent(path + "Revert To Parent"), false, RevertToParent, prefabInstance); } } menu.AddSeparator(path + ""); menu.AddItem(new GUIContent(path + "Create Child"), false, CreateChild, prefabInstance); #if INJECTION if (prefabInstance.ParentPrefab != null) { menu.AddItem(new GUIContent(path + "Insert Parent"), false, InjectParent, prefabInstance); } #endif if (!rootPrefab && !AssetDatabase.Contains(prefabInstance)) { menu.AddSeparator(path); if (prefabInstance.enabled) { menu.AddItem(new GUIContent(path + "Disable"), false, obj => (obj as PEPrefabScript).enabled = false, prefabInstance); } else { menu.AddItem(new GUIContent(path + "Enable"), false, obj => (obj as PEPrefabScript).enabled = true, prefabInstance); } } menu.AddSeparator(path); if (prefabInstance.GetPrefabsWithInstances().Any()) { menu.AddItem(new GUIContent(path + "Instances/Select All Instances"), false, SelectInstances, prefabInstance); } if (showInstances) { foreach (var prefab in prefabInstance.GetPrefabsWithInstances()) { if (prefab == null) { continue; } var pi = prefab.GetComponent <PEPrefabScript>(); var name = prefab.name; name = (pi != null && pi.ParentPrefab == prefabInstance.Prefab) ? "Child: " + name : "Contains in: " + name; if (pi != null) { BuildMenu(menu, prefab.GetComponent <PEPrefabScript>(), false, path + "Instances/" + name + "/", false); } var current = prefab; menu.AddItem(new GUIContent(path + "Instances/" + name), false, () => { Selection.activeObject = current; }); } } menu.AddItem(new GUIContent(path + "Instantiate"), false, pi => Selection.activeObject = PrefabUtility.InstantiatePrefab(((PEPrefabScript)pi).Prefab), prefabInstance); if (!AssetDatabase.Contains(prefabInstance)) { menu.AddItem(new GUIContent(path + "Replace"), false, Replace, prefabInstance); } buildMenuRecursionList.Remove(prefabInstance.Prefab); }
static void ApplyModifications(this PEPrefabScript _this, PEPrefabScript targetInstance) { targetInstance.Modifications = _this.Modifications; var modificatedList = new List <SerializedObject>(); foreach (var modification in _this.Modifications.Modificated) { if (modification.Mode == PEModifications.PropertyData.PropertyMode.Ignore) { continue; } if (modification.Object == null) { continue; } var selfObject = new SerializedObject(modification.Object); var linkedObject = targetInstance.Links[modification.ObjeckLink]; if (linkedObject == null || linkedObject.InstanceTarget == null) { continue; } var targetObject = new SerializedObject(linkedObject.InstanceTarget); var selfProperty = selfObject.FindProperty(modification.PropertyPath); var targetProperty = targetObject.FindProperty(modification.PropertyPath); if (targetProperty == null) { Debug.Log("Property not found " + modification.PropertyPath); } else { var target = targetProperty.serializedObject.targetObject; var propertyPath = selfProperty.propertyPath; var targetTransform = target as Transform; if (propertyPath == "m_Father" && targetTransform) { PEUtils.SetParentAndSaveLocalTransform(targetTransform, selfProperty.objectReferenceValue as Transform); } else if (propertyPath == "m_RootOrder" && targetTransform) { targetTransform.SetSiblingIndex(selfProperty.intValue); } else { var value = selfProperty.GetPropertyValue(); if (selfProperty.propertyType == SerializedPropertyType.ObjectReference) { var selfValue = selfProperty.GetPropertyValue(); var selfLink = _this.Links[selfValue as Object]; var targetLink = targetInstance.Links[selfLink]; if (targetLink != null) { value = targetLink.InstanceTarget; } } targetProperty.SetPropertyValue(value); targetObject.ApplyModifiedProperties(); } } } foreach (var po in modificatedList) { po.ApplyModifiedProperties(); } }
static void ApplyModifications(this PEPrefabScript _this, PEPrefabScript targetInstance) { targetInstance.Modifications = _this.Modifications; var modificatedList = new List<SerializedObject>(); foreach (var modification in _this.Modifications.Modificated) { if (modification.Mode == PEModifications.PropertyData.PropertyMode.Ignore) continue; if (modification.Object == null) continue; var selfObject = new SerializedObject(modification.Object); var linkedObject = targetInstance.Links[modification.ObjeckLink]; if (linkedObject == null || linkedObject.InstanceTarget == null) continue; var targetObject = new SerializedObject(linkedObject.InstanceTarget); var selfProperty = selfObject.FindProperty(modification.PropertyPath); var targetProperty = targetObject.FindProperty(modification.PropertyPath); if (targetProperty == null) { Debug.Log("Property not found " + modification.PropertyPath); } else { if (selfProperty.propertyPath.Contains("m_Father")) { PEUtils.SetParentAndSaveLocalTransform((targetProperty.serializedObject.targetObject as Transform), (selfProperty.GetPropertyValue() as Transform)); } else { var value = selfProperty.GetPropertyValue(); if (selfProperty.propertyType == SerializedPropertyType.ObjectReference) { var selfValue = selfProperty.GetPropertyValue(); var selfLink = _this.Links[selfValue as Object]; var targetLink = targetInstance.Links[selfLink]; if (targetLink != null) value = targetLink.InstanceTarget; } targetProperty.SetPropertyValue(value); targetObject.ApplyModifiedProperties(); } } } foreach (var po in modificatedList) po.ApplyModifiedProperties(); }
static void ApplyModifications(this PEPrefabScript _this, PEPrefabScript targetInstance) { targetInstance.Modifications = _this.Modifications; foreach (var modification in _this.Modifications.Modificated) { if (modification.Mode == PEModifications.PropertyData.PropertyMode.Ignore) { continue; } if (modification.Object == null) { continue; } var selfObject = new SerializedObject(modification.Object); var linkedObject = targetInstance.Links[modification.ObjeckLink]; if (linkedObject == null || linkedObject.InstanceTarget == null) { continue; } var targetObject = new SerializedObject(linkedObject.InstanceTarget); var selfProperty = selfObject.FindProperty(modification.PropertyPath); var targetProperty = targetObject.FindProperty(modification.PropertyPath); if (targetProperty == null) { Debug.Log("Property not found " + modification.PropertyPath); } else { if (selfProperty.propertyType == SerializedPropertyType.ObjectReference) { var selfValue = selfProperty.GetPropertyValue(); var selfLink = _this.Links[selfValue as Object]; var targetLink = targetInstance.Links[selfLink]; if (targetLink != null) { targetProperty.SetPropertyValue(targetLink.InstanceTarget); } else { targetProperty.SetPropertyValue(selfProperty.GetPropertyValue()); } } else { targetProperty.SetPropertyValue(selfProperty.GetPropertyValue()); } targetObject.ApplyModifiedProperties(); //In some cases unity can destroy prev object, just fix runtime references... linkedObject.InstanceTarget = targetObject.targetObject; } } }
static internal void DrawView(PEPrefabScript script) { GUILayout.Space(3); var icon = EditorGUIUtility.ObjectContent(null, typeof(GameObject)); GUILayout.BeginHorizontal(); if (!string.IsNullOrEmpty(script.ParentPrefabGUID)) { var c = GUI.backgroundColor; if (!script.ParentPrefab) GUI.backgroundColor = Color.red; var content = new GUIContent(script.ParentPrefab ? script.ParentPrefab.name : "Missing:" + script.ParentPrefabGUID, icon.image); GUILayout.Label("Parent:", GUILayout.Width(50)); if (GUILayout.Button(content, EditorStyles.miniButton, GUILayout.Height(16), GUILayout.MinWidth(0))) EditorGUIUtility.PingObject(script.ParentPrefab); GUI.backgroundColor = c; } if (!string.IsNullOrEmpty(script.PrefabGUID)) { var c = GUI.backgroundColor; if (!script.Prefab) GUI.backgroundColor = Color.red; var content = new GUIContent(script.Prefab ? script.Prefab.name : "Missing:" + script.PrefabGUID, icon.image); GUILayout.Label("Prefab:", GUILayout.Width(50)); if (GUILayout.Button(content, EditorStyles.miniButton, GUILayout.Height(16), GUILayout.MinWidth(0))) EditorGUIUtility.PingObject(script.Prefab); GUI.backgroundColor = c; } GUILayout.EndHorizontal(); GUILayout.Space(1); DrawCommands(script); EditorGUIUtility.labelWidth = 150; }
static internal bool IsNonPrefabObject(this PEPrefabScript _this, Object obj) { return(_this.Links[obj] == null); }
static void DrawCommands(PEPrefabScript prefabScript) { var e = GUI.enabled; GUI.enabled = true; if (GUILayout.Button("Menu", EditorStyles.miniButton)) { var menu = new GenericMenu(); PEUtils.BuildMenu(menu, prefabScript, PrefabUtility.GetPrefabParent(prefabScript.gameObject) == prefabScript.Prefab); menu.ShowAsContext(); } GUI.enabled = e; }
static void ApplyModifications(this PEPrefabScript _this, PEPrefabScript targetInstance) { targetInstance.Modifications = _this.Modifications; var modificatedList = new List<SerializedObject>(); foreach (var modification in _this.Modifications.Modificated) { if (modification.Mode == PEModifications.PropertyData.PropertyMode.Ignore) continue; if (modification.Object == null) continue; var selfObject = new SerializedObject(modification.Object); var linkedObject = targetInstance.Links[modification.ObjeckLink]; if (linkedObject == null || linkedObject.InstanceTarget == null) continue; var targetObject = new SerializedObject(linkedObject.InstanceTarget); var selfProperty = selfObject.FindProperty(modification.PropertyPath); var targetProperty = targetObject.FindProperty(modification.PropertyPath); if (targetProperty == null) { Debug.Log("Property not found " + modification.PropertyPath); } else { var value = selfProperty.GetPropertyValue(); if (selfProperty.propertyType == SerializedPropertyType.ObjectReference) { var selfValue = selfProperty.GetPropertyValue(); var selfLink = _this.Links[selfValue as Object]; var targetLink = targetInstance.Links[selfLink]; if (targetLink != null) value = targetLink.InstanceTarget; } targetProperty.SetPropertyValue(value); targetObject.ApplyModifiedProperties(); //In some cases unity can destroy prev object, just fix runtime references... linkedObject.InstanceTarget = targetObject.targetObject; } } foreach (var po in modificatedList) po.ApplyModifiedProperties(); }
static internal void GetProperties(this PEModifications.PropertyData _this, out SerializedProperty prefabProperty, out SerializedProperty objectProperty, PEPrefabScript script) { var couple = _this.UserData as PropertyCouple; if (couple == null) { couple = new PropertyCouple(); if (couple.objectProperty == null) { var so = new SerializedObject(_this.Object); if (so != null) { couple.objectProperty = so.FindProperty(_this.PropertyPath); } if (couple.objectProperty == null) { if (PEPrefs.DebugLevel > 0) { Debug.Log(string.Format("Property {0} not found on Object {1}", _this.PropertyPath, _this.Object)); } } } if (couple.prefabProperty == null) { var prefabObject = script.Links.GetPrefabObject(script.GetDiffWith().gameObject, _this.Object); if (prefabObject != null) { var so = new SerializedObject(prefabObject); if (so != null) { couple.prefabProperty = so.FindProperty(_this.PropertyPath); } } else { Debug.LogWarning("Prefab object for prefab property modifications is not found"); } } } prefabProperty = couple.prefabProperty; objectProperty = couple.objectProperty; _this.UserData = couple; }