public static bool ReleaseAccessory(Outfit outfit, Accessory accessory, float offsetDistance = 0, RemoveActionType removeType = RemoveActionType.Undefined, bool singleUndo = true, string undoLabel = null) { if (AssetDatabase.Contains(outfit)) { Debug.LogError("Can't modify an outfit asset. Outfit must be in the scene.", outfit); return(false); } if (removeType == RemoveActionType.Undefined) { removeType = (RemoveActionType)EditorUtility.DisplayDialogComplex("Remove accessory from body?", string.Format("Remove '{0}' from '{1}'?", accessory.name, outfit.name), "Remove only", "Remove and destroy", "Do not remove"); } if (removeType == RemoveActionType.Cancel) { return(false); } undoLabel = string.IsNullOrEmpty(undoLabel) ? "Remove Accessory" : undoLabel; if (singleUndo) { Undo.IncrementCurrentGroup(); } Undo.RecordObjects(Outfit.UnsafeGetUndoObjects(outfit).ToArray(), undoLabel); var parent = accessory.transform.parent; outfit.Release(accessory); accessory.transform.parent = parent; Undo.SetTransformParent(accessory.transform, null, undoLabel); if (removeType == RemoveActionType.RemoveAndDestroy) { accessory.Destroy(DestroyType.GameObject, true); Undo.DestroyObjectImmediate(accessory.gameObject); } else if (offsetDistance > 0) { // This extra record call is needed for some reason. Otherwise only **part** of the translation // is recorded. Maybe the problem has to do with the unpartenting? Anyway, more fun with undo... Undo.RecordObject(accessory.transform, undoLabel); accessory.transform.position += outfit.transform.right * -offsetDistance; } if (singleUndo) { Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); } return(true); }
private static RemoveActionType GetRemoveType(Body body, RemoveActionType removeType) { if (removeType == RemoveActionType.Undefined) { return((RemoveActionType)EditorUtility.DisplayDialogComplex("Remove the outfit from its body?", string.Format("Remove '{0}' from '{1}'?", body.Outfit.name, body.name), "Remove only", "Remove and destroy", "Do not remove")); } return(removeType); }
private void DrawOutfitApplyRemove() { var body = Target; GUIContent label; bool isApplyMode; RemoveActionType removeType = RemoveActionType.Undefined; var btnStyle = GUI.skin.button; if (body.Outfit) { m_OutfitApplyRemoveChoice = body.Outfit; isApplyMode = false; label = new GUIContent("Remove", "Remove the outfit from the body."); if (OutfitterEditorUtil.IsNonDestructiveConfirmed) { btnStyle = LizEditorGUIUtil.YellowButton; removeType = RemoveActionType.RemoveOnly; } else if (OutfitterEditorUtil.IsDestructiveConfirmed) { btnStyle = LizEditorGUIUtil.RedButton; removeType = RemoveActionType.RemoveAndDestroy; } } else { isApplyMode = true; label = new GUIContent("Apply", "Apply the outfit to the body."); if (m_OutfitApplyRemoveChoice && m_OutfitApplyRemoveChoice.Owner) { label.tooltip += " (Current outfit owner: " + m_OutfitApplyRemoveChoice.Owner.name + ")"; btnStyle = LizEditorGUIUtil.YellowButton; } } EditorGUILayout.BeginHorizontal(); GUI.enabled = isApplyMode; var noutfit = EditorGUILayout.ObjectField( m_OutfitApplyRemoveChoice, typeof(Outfit), true, GUILayout.ExpandWidth(true)) as Outfit; if (noutfit != m_OutfitApplyRemoveChoice) { // Can only happen in apply mode. if (noutfit && noutfit.IsManaged) { // Undo will become too complex if this is allowed. Debug.LogErrorFormat(body, "Can't take control of an outfit that is already managed by another object." + " Outfit: {0}, Owner: {1}", noutfit.name, noutfit.Owner.name); } else { m_OutfitApplyRemoveChoice = noutfit; } } GUI.enabled = m_OutfitApplyRemoveChoice; if (GUILayout.Button(label, btnStyle, GUILayout.MaxWidth(70))) { if (isApplyMode) { SetOutfit(body, m_OutfitApplyRemoveChoice, OutfitterEditorUtil.AutoOffset, removeType); } else { SetOutfit(body, null, OutfitterEditorUtil.AutoOffset, removeType); } } GUI.enabled = true; EditorGUILayout.EndHorizontal(); }
private void DrawOutfitSwap() { var body = Target; if (!body.Outfit) { // Nothing to do. m_OutfitSwapChoice = null; return; } EditorGUILayout.BeginHorizontal(); var noutfit = EditorGUILayout.ObjectField( m_OutfitSwapChoice, typeof(Outfit), true, GUILayout.ExpandWidth(true)) as Outfit; if (noutfit != m_OutfitSwapChoice) { if (noutfit == body.Outfit) { Debug.LogWarning("Outfit is already assigned to the body: " + noutfit.name, body); } else if (noutfit && noutfit.IsManaged) { // Undo will become too complex if this is allowed. Debug.LogErrorFormat(body, "Can't take control of an outfit that is already managed by another object." + " Outfit: {0}, Owner: {1}", noutfit.name, noutfit.Owner.name); } else { m_OutfitSwapChoice = noutfit; } } RemoveActionType removeType = RemoveActionType.Undefined; var btnStyle = GUI.skin.button; if (OutfitterEditorUtil.IsNonDestructiveConfirmed) { btnStyle = LizEditorGUIUtil.YellowButton; removeType = RemoveActionType.RemoveOnly; } else if (OutfitterEditorUtil.IsDestructiveConfirmed) { btnStyle = LizEditorGUIUtil.RedButton; removeType = RemoveActionType.RemoveAndDestroy; } GUI.enabled = m_OutfitSwapChoice; if (GUILayout.Button(m_SwapLabel, btnStyle, GUILayout.MaxWidth(70))) { if (SetOutfit(body, m_OutfitSwapChoice, OutfitterEditorUtil.AutoOffset, removeType, false)) { var item = m_OutfitSwapChoice; m_OutfitSwapChoice = m_OutfitApplyRemoveChoice ? m_OutfitApplyRemoveChoice : null; m_OutfitApplyRemoveChoice = item; } // else there should have been an error message for the body. } GUI.enabled = true; EditorGUILayout.EndHorizontal(); }
public static bool SetOutfit(Body body, Outfit outfit, float repoOffset = 0, RemoveActionType removeType = RemoveActionType.Undefined, bool singleUndo = true, string undoLabel = "Set Outfit") { // Design note: It would be much simpler to just remove and add in separate transactions. But that // sends the wrong type of event to observers, so have to go the messy route in order to properly // mimic runtime behavior. // Validations if (!CheckValidAction(body)) { return(false); } if (outfit == body.Outfit) { Debug.LogWarning("No action taken. Outfit is the same as the body's current outfit: " + (outfit ? outfit.name : "null"), body); return(true); // This is the correct behavior. } if (outfit && outfit.IsManaged) { Debug.LogError("Can't set outfit. The outfit is already managed by: " + outfit.Owner.name, body); return(false); } // Keep last since it may involve a dialog box. Transform origParent = null; if (body.Outfit) { removeType = GetRemoveType(body, removeType); if (removeType == RemoveActionType.Cancel) { return(false); } origParent = body.Outfit.transform.parent; } // Prepare for transaction. if (singleUndo) { Undo.IncrementCurrentGroup(); } bool isNew = false; Transform outfitParent = null; if (outfit) { isNew = AssetDatabase.Contains(outfit); if (isNew) { var name = outfit.name; outfit = outfit.Instantiate(); outfit.name = name; // Will register the undo after success has been determined. } else { Undo.RecordObjects(Outfit.UnsafeGetUndoObjects(outfit).ToArray(), undoLabel); } outfitParent = outfit.transform.parent; } Undo.RecordObjects(Body.UnsafeGetUndoObjects(body).ToArray(), undoLabel); // Set the outfit. var orig = body.SetOutfit(outfit); var success = (orig != outfit); if (success) { if (orig) { // Finalize the original outfit. orig.transform.parent = origParent; Undo.SetTransformParent(orig.transform, null, undoLabel); if (removeType == RemoveActionType.RemoveAndDestroy) { orig.Destroy(DestroyType.GameObject, true); Undo.DestroyObjectImmediate(orig.gameObject); } else if (repoOffset > 0) { // This extra call is needed, otherwise only **part** of the translation is recorded. The // problem might be due to the change in the parent. Anyway, more fun with undo... Undo.RecordObject(orig.transform, undoLabel); orig.transform.position += body.transform.right * repoOffset; } } if (outfit) { // Finalize the outfit that was set. if (isNew) { Undo.RegisterCreatedObjectUndo(outfit.gameObject, undoLabel); } var parent = outfit.transform.parent; outfit.transform.parent = outfitParent; Undo.SetTransformParent(outfit.transform, parent, undoLabel); if (body is StandardBody) { // HACK: Addition of body as outfit observer is not being recorded for serialization. // This fixes it until the cause and proper fix can be determined. StandardOutfitEditor.AddObserverWithUndo(outfit, (StandardBody)body); } } success = true; } else { if (isNew) { outfit.gameObject.SafeDestroy(); } success = false; } if (singleUndo) { Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); } return(success); }