public static int ApplyOutfitMaterial(Outfit outfit, OutfitMaterialType matType, Material material, 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(0); } if (singleUndo) { Undo.IncrementCurrentGroup(); } undoLabel = string.IsNullOrEmpty(undoLabel) ? "Set Outfit Material" : undoLabel; Undo.RecordObjects(Outfit.UnsafeGetUndoObjects(outfit).ToArray(), undoLabel); var count = outfit.ApplySharedMaterial(matType, material); if (singleUndo) { Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); } return(count); }
public static bool ApplyBodyPartLayer( Outfit outfit, int layer, 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 (outfit.BodyPartCount == 0) { return(false); } if (singleUndo) { Undo.IncrementCurrentGroup(); } undoLabel = string.IsNullOrEmpty(undoLabel) ? "Set Body Part Layer" : undoLabel; Undo.RecordObjects(Outfit.UnsafeGetUndoObjects(outfit).ToArray(), undoLabel); outfit.ApplyBodyPartLayer(layer); if (singleUndo) { Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); } return(true); }
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); }
/// <summary> /// Synchronize the body part state of all common body parts. /// </summary> /// <remarks> /// <para> /// The caller must properly collapse the undo records if <paramref name="singleUndo"/> is false. Otherwise /// performing an undo will result in an invalid outfit state. /// </para> /// </remarks> /// <param name="to">The outfit being synchonized to. (Required)</param> /// <param name="from">The outfit state is syncronzied from. (Required)</param> /// <param name="includeStatus">Persist collider status.</param> /// <param name="includeLayer">Persist the collider layer.</param> /// <param name="includeContext">Persist the context unless it is the previous outfit's GameObject.</param> /// <param name="singleUndo"> /// If true, collapse all undo records into a single undo, otherwise the caller will perform the collapse. /// </param> /// <param name="undoLabel">The label to use for all undo records. (Required)</param> /// <returns>True if the outfit state was altered.</returns> public static bool SynchronizeState(Outfit to, Outfit from, bool includeStatus = true, bool includeLayer = true, bool includeContext = true, bool singleUndo = true, string undoLabel = "Sync BodyPart State") { if (!(to && from && to.BodyPartCount > 0 && from.BodyPartCount > 0)) { return(false); } if (singleUndo) { Undo.IncrementCurrentGroup(); } // Need more than just the body part components... Undo.RecordObjects(Outfit.UnsafeGetUndoObjects(to).ToArray(), undoLabel); bool changed = false; for (int i = 0; i < from.BodyPartCount; i++) { var prevPart = from.GetBodyPart(i); if (prevPart) { var part = to.GetBodyPart(prevPart.PartType); if (part) { changed = true; // This is close enough. BodyPart.Synchronize( part, prevPart, includeStatus, includeLayer, includeContext, from.gameObject); } } } if (singleUndo) { Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); } return(changed); }
public static MountResult MountAccessory( Outfit outfit, Accessory accessory, 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(MountResult.FailedOnError); } if (singleUndo) { Undo.IncrementCurrentGroup(); } undoLabel = string.IsNullOrEmpty(undoLabel) ? "Add Accessory" : undoLabel; Undo.RecordObjects(Outfit.UnsafeGetUndoObjects(outfit).ToArray(), undoLabel); bool isNew = AssetDatabase.Contains(accessory); if (isNew) { var name = accessory.name; accessory = accessory.Instantiate(); accessory.name = name; // Record undo later. } else { Undo.RecordObjects(Accessory.UnsafeGetUndoObjects(accessory).ToArray(), undoLabel); } var origParent = accessory.transform.parent; var result = outfit.Mount(accessory); if (result.IsFailed()) { Debug.LogWarningFormat(outfit, "Accessory mount failed: {0}: {1}", accessory.name, result); if (isNew) { accessory.gameObject.SafeDestroy(); } accessory = null; } else { if (isNew) { Undo.RegisterCreatedObjectUndo(accessory.gameObject, undoLabel); } var parent = accessory.transform.parent; accessory.transform.parent = origParent; Undo.SetTransformParent(accessory.transform, parent, undoLabel); } if (singleUndo) { Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); } return(result); }
public void DrawBodyPartActions() { EditorGUILayout.LabelField("Body Parts"); LizEditorGUIUtil.BeginLabelWidth(70); m_ContextChoice = EditorGUILayout.ObjectField(ContextLabel, m_ContextChoice, typeof(GameObject), true) as GameObject; var outfit = Target; EditorGUILayout.BeginHorizontal(); m_PartTypeChoice = (BodyPartType)EditorGUILayout.EnumPopup(m_PartTypeChoice); if (m_ColliderPopup == null) { m_ColliderPopup = new LocalComponentPopup(typeof(Collider), false); } m_ColliderChoice = m_ColliderPopup.OnGUI( EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight * 1.1f), m_ColliderChoice, GUIContent.none, outfit.gameObject) as Collider; EditorGUILayout.EndHorizontal(); GUI.enabled = m_ColliderChoice; if (GUILayout.Button("Create Boby Part")) { if (m_ColliderChoice.gameObject.GetComponent <BodyPart>()) { Debug.LogError(m_ColliderChoice.name + " Already has a body part attached.", outfit); } else if (outfit.GetBodyPart(m_PartTypeChoice)) { Debug.LogError("Outfit already has a body part of type: " + m_PartTypeChoice, outfit); } else { // Note for prefabs: If there is a missing body part in the array before the action and the // user undoes the action, the mount point array may end up containing an invalid reference // to the prefab's asset. This appears to be some kind of prefab related bug. const string undoLabel = "Create Body Part"; Undo.IncrementCurrentGroup(); Undo.RecordObjects(Outfit.UnsafeGetUndoObjects(outfit).ToArray(), undoLabel); // For refresh. var bp = Undo.AddComponent <BodyPart>(m_ColliderChoice.gameObject); Undo.RecordObject(bp, undoLabel); bp.Collider = m_ColliderChoice; bp.PartType = m_PartTypeChoice; bp.Context = m_ContextChoice; StandardOutfit.UnsafeRefreshBodyParts(outfit); Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); m_ColliderChoice = null; } } GUI.enabled = true; EditorGUILayout.BeginHorizontal(); if (GUILayout.Button(ApplyBodyPartContextLabel)) { string undoLabel = "Apply Body Part Context"; Undo.IncrementCurrentGroup(); Undo.RecordObjects(Outfit.UnsafeGetUndoObjects(outfit).ToArray(), undoLabel); outfit.ApplyBodyPartContext(m_ContextChoice); Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); } if (GUILayout.Button(RefreshBodyPartsLabel)) { Undo.RecordObject(outfit, "Refresh Body Parts"); StandardOutfit.UnsafeRefreshBodyParts(outfit, false); } if (GUILayout.Button(ResetBodyPartsLabel)) { Undo.RecordObject(outfit, "Reset Body Parts"); StandardOutfit.UnsafeClearBodyParts(outfit); } EditorGUILayout.EndHorizontal(); LizEditorGUIUtil.EndLabelWidth(); }
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); }