Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
        }
Beispiel #5
0
        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();
        }
Beispiel #7
0
        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);
        }