/// --------------------------------------------- /// Ultimate Character Controller /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- #if !ULTIMATE_CHARACTER_CONTROLLER_EXTENSION_DEBUG namespace Opsive.UltimateCharacterController.Editor.References { #if !FIRST_PERSON_CONTROLLER || !THIRD_PERSON_CONTROLLER using Opsive.Shared.Utility; using Opsive.UltimateCharacterController.Camera.ViewTypes; using Opsive.UltimateCharacterController.Character.MovementTypes; using Opsive.UltimateCharacterController.Character.Abilities; using Opsive.UltimateCharacterController.Character.Abilities.Items; using Opsive.UltimateCharacterController.Editor.Inspectors.Utility; using Opsive.UltimateCharacterController.Editor.Managers; using Opsive.UltimateCharacterController.StateSystem; using System.Collections.Generic; #endif using Opsive.UltimateCharacterController.Demo.References; using UnityEditor; using UnityEngine; using UnityEngine.SceneManagement; [InitializeOnLoad] public class ObjectRemover { private static Scene s_ActiveScene; /// /// Registers for the scene change callback. /// static ObjectRemover() { EditorApplication.update += Update; } /// /// The scene has been changed. /// private static void Update() { var scene = SceneManager.GetActiveScene(); if (scene == s_ActiveScene || Application.isPlaying) { return; } s_ActiveScene = scene; // Only the add-ons and integrations demo scene should be affected. var scenePath = s_ActiveScene.path.Replace("\\", "/"); if (!scenePath.Contains("UltimateCharacterController/Add-Ons") && !scenePath.Contains("UltimateCharacterController/Integrations")) { return; } // Find the object which contains the objects that should be removed. var objectReferences = GameObject.FindObjectOfType(); ProcessObjectReferences(objectReferences, true); } /// /// Removes the objects specified by the object references object. /// private static void ProcessObjectReferences(ObjectReferences objectReferences, bool fromScene) { if (objectReferences == null) { return; } RemoveObjects(objectReferences.RemoveObjects); objectReferences.RemoveObjects = null; #if !FIRST_PERSON_CONTROLLER RemoveObjects(objectReferences.FirstPersonObjects); objectReferences.FirstPersonObjects = null; #endif #if !THIRD_PERSON_CONTROLLER RemoveObjects(objectReferences.ThirdPersonObjects); objectReferences.ThirdPersonObjects = null; #endif #if !ULTIMATE_CHARACTER_CONTROLLER_SHOOTER RemoveObjects(objectReferences.ShooterObjects); objectReferences.ShooterObjects = null; #endif #if !ULTIMATE_CHARACTER_CONTROLLER_MELEE RemoveObjects(objectReferences.MeleeObjects); objectReferences.MeleeObjects = null; #endif #if !FIRST_PERSON_CONTROLLER || !THIRD_PERSON_CONTROLLER // Remove any view types and states that are no longer valid. Opsive.UltimateCharacterController.Camera.CameraController cameraController; if (fromScene) { cameraController = GameObject.FindObjectOfType(); } else { cameraController = objectReferences.GetComponent(); } if (cameraController != null) { cameraController.DeserializeViewTypes(); var viewTypes = new List(cameraController.ViewTypes); for (int i = viewTypes.Count - 1; i > -1; --i) { if (viewTypes[i] == null) { viewTypes.RemoveAt(i); continue; } viewTypes[i].States = RemoveUnusedStates(viewTypes[i].States); } cameraController.ViewTypeData = Serialization.Serialize(viewTypes); cameraController.ViewTypes = viewTypes.ToArray(); InspectorUtility.SetDirty(cameraController); } // Remove any movement types and states that are no longer valid. Character.UltimateCharacterLocomotion characterLocomotion; if (fromScene) { characterLocomotion = GameObject.FindObjectOfType(); } else { characterLocomotion = objectReferences.GetComponent(); } if (characterLocomotion != null) { characterLocomotion.DeserializeMovementTypes(); var movementTypes = new List(characterLocomotion.MovementTypes); for (int i = movementTypes.Count - 1; i > -1; --i) { if (movementTypes[i] == null) { movementTypes.RemoveAt(i); continue; } movementTypes[i].States = RemoveUnusedStates(movementTypes[i].States); } characterLocomotion.MovementTypeData = Serialization.Serialize(movementTypes); characterLocomotion.MovementTypes = movementTypes.ToArray(); #if FIRST_PERSON_CONTROLLER characterLocomotion.SetMovementType(UltimateCharacterController.Utility.UnityEngineUtility.GetType(characterLocomotion.FirstPersonMovementTypeFullName)); #else characterLocomotion.SetMovementType(UltimateCharacterController.Utility.UnityEngineUtility.GetType(characterLocomotion.ThirdPersonMovementTypeFullName)); #endif // Ensure the animator is pointing to the correct reference. var animator = characterLocomotion.GetComponent(); if (animator != null && animator.runtimeAnimatorController == null) { animator.runtimeAnimatorController = ManagerUtility.FindAnimatorController(null); InspectorUtility.SetDirty(animator); } // Check for unused ability states. var abilities = new List(characterLocomotion.GetSerializedAbilities()); for (int i = abilities.Count - 1; i > -1; --i) { if (abilities[i] == null) { abilities.RemoveAt(i); continue; } abilities[i].States = RemoveUnusedStates(abilities[i].States); } characterLocomotion.AbilityData = Serialization.Serialize(abilities); characterLocomotion.Abilities = abilities.ToArray(); // Check for unused item ability states. var itemAbilities = new List(characterLocomotion.GetSerializedItemAbilities()); for (int i = itemAbilities.Count - 1; i > -1; --i) { if (itemAbilities[i] == null) { itemAbilities.RemoveAt(i); continue; } itemAbilities[i].States = RemoveUnusedStates(itemAbilities[i].States); } characterLocomotion.ItemAbilityData = Serialization.Serialize(itemAbilities); characterLocomotion.ItemAbilities = itemAbilities.ToArray(); InspectorUtility.SetDirty(characterLocomotion); // Update the inventory. var inventory = characterLocomotion.GetComponent(); if (inventory != null) { var loadout = new List(inventory.DefaultLoadout); for (int i = loadout.Count - 1; i > -1; --i) { if (loadout[i].ItemDefinition == null) { loadout.RemoveAt(i); } } inventory.DefaultLoadout = loadout.ToArray(); InspectorUtility.SetDirty(inventory); } var itemSetManager = characterLocomotion.GetComponent(); if (itemSetManager != null) { var categoryItemSets = itemSetManager.CategoryItemSets; for (int i = 0; i < categoryItemSets.Length; ++i) { for (int j = categoryItemSets[i].ItemSetList.Count - 1; j > -1; --j) { var nullItemIdentifier = true; for (int k = 0; k < categoryItemSets[i].ItemSetList[j].Slots.Length; ++k) { if (categoryItemSets[i].ItemSetList[j].Slots[k] != null) { nullItemIdentifier = false; break; } } if (nullItemIdentifier) { categoryItemSets[i].ItemSetList.RemoveAt(j); } } }; InspectorUtility.SetDirty(itemSetManager); } } #if !THIRD_PERSON_CONTROLLER // Set the shadow caster for the first person only objects. var shadowCaster = ManagerUtility.FindInvisibleShadowCaster(null); if (shadowCaster != null) { for (int i = 0; i < objectReferences.ShadowCasterObjects.Length; ++i) { if (objectReferences.ShadowCasterObjects[i] == null) { continue; } var renderers = objectReferences.ShadowCasterObjects[i].GetComponentsInChildren(); for (int j = 0; j < renderers.Length; ++j) { var materials = renderers[j].sharedMaterials; for (int k = 0; k < materials.Length; ++k) { materials[k] = shadowCaster; } renderers[j].sharedMaterials = materials; InspectorUtility.SetDirty(renderers[j]); } } } #endif var items = objectReferences.GetComponentsInChildren(); for (int i = 0; i < items.Length; ++i) { CheckItem(items[i].gameObject); } // Ensure all of the states point to a preset StateBehavior[] stateBehaviors; if (fromScene) { stateBehaviors = GameObject.FindObjectsOfType(); } else { stateBehaviors = objectReferences.GetComponentsInChildren(true); } if (stateBehaviors != null) { for (int i = 0; i < stateBehaviors.Length; ++i) { stateBehaviors[i].States = RemoveUnusedStates(stateBehaviors[i].States); InspectorUtility.SetDirty(stateBehaviors[i]); } } #endif // Some doors should be locked. #if !FIRST_PERSON_CONTROLLER LockDoors(objectReferences.FirstPersonDoors); #endif #if !THIRD_PERSON_CONTROLLER LockDoors(objectReferences.ThirdPersonDoors); #endif for (int i = 0; i < objectReferences.NestedReferences.Length; ++i) { var nestedObject = objectReferences.NestedReferences[i]; if (nestedObject == null) { continue; } GameObject nestedRoot = null; if (PrefabUtility.IsPartOfPrefabAsset(nestedObject)) { nestedRoot = PrefabUtility.LoadPrefabContents(AssetDatabase.GetAssetPath(objectReferences.NestedReferences[i])); nestedObject = nestedRoot.GetComponent(); } ProcessObjectReferences(nestedObject, false); if (nestedRoot != null) { PrefabUtility.SaveAsPrefabAsset(nestedRoot, AssetDatabase.GetAssetPath(objectReferences.NestedReferences[i])); PrefabUtility.UnloadPrefabContents(nestedRoot); } } UnpackPrefab(objectReferences); Object.DestroyImmediate(objectReferences, true); } /// /// Removes the specified objects. /// private static void RemoveObjects(Object[] objects) { if (objects == null) { return; } for (int i = objects.Length - 1; i > -1; --i) { if (objects[i] == null || PrefabUtility.GetPrefabAssetType(objects[i]) == PrefabAssetType.MissingAsset) { continue; } if (objects[i] is GameObject && (objects[i] as GameObject).transform.parent == null && AssetDatabase.GetAssetPath(objects[i]).Length > 0 && PrefabUtility.GetPrefabAssetType(objects[i]) == PrefabAssetType.Regular) { AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(objects[i])); } else { UnpackPrefab(objects[i]); Object.DestroyImmediate(objects[i], true); } } } #if !FIRST_PERSON_CONTROLLER || !THIRD_PERSON_CONTROLLER /// /// Ensure the item only has the valid states. /// private static void CheckItem(GameObject gameObject) { if (gameObject == null || gameObject.GetComponent() == null) { return; } var magicItems = gameObject.GetComponents(); for (int i = 0; i < magicItems.Length; ++i) { magicItems[i].DeserializeBeginActions(false); var beginActions = magicItems[i].BeginActions; if (beginActions != null) { for (int j = 0; j < beginActions.Length; ++j) { beginActions[j].States = RemoveUnusedStates(beginActions[j].States); } magicItems[i].BeginActionData = Serialization.Serialize(beginActions); } magicItems[i].DeserializeCastActions(false); var castActions = magicItems[i].CastActions; if (castActions != null) { for (int j = 0; j < castActions.Length; ++j) { castActions[j].States = RemoveUnusedStates(castActions[j].States); } magicItems[i].CastActionData = Serialization.Serialize(castActions); } magicItems[i].DeserializeImpactActions(false); var impactActions = magicItems[i].ImpactActions; if (impactActions != null) { for (int j = 0; j < impactActions.Length; ++j) { impactActions[j].States = RemoveUnusedStates(impactActions[j].States); } magicItems[i].ImpactActionData = Serialization.Serialize(impactActions); } magicItems[i].DeserializeEndActions(false); var endActions = magicItems[i].EndActions; if (endActions != null) { for (int j = 0; j < endActions.Length; ++j) { endActions[j].States = RemoveUnusedStates(endActions[j].States); } magicItems[i].EndActionData = Serialization.Serialize(endActions); } InspectorUtility.SetDirty(magicItems[i]); } } #endif /// /// Unpacks the prefab root. /// /// The object that should be unpacked. private static void UnpackPrefab(Object obj) { if (obj != null && PrefabUtility.IsPartOfAnyPrefab(obj)) { var root = PrefabUtility.GetNearestPrefabInstanceRoot(obj); if (root != null) { PrefabUtility.UnpackPrefabInstance(root, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); } } } #if !FIRST_PERSON_CONTROLLER || !THIRD_PERSON_CONTROLLER /// /// Removes any states whose preset will be exlcluded. /// private static State[] RemoveUnusedStates(State[] stateArray) { var states = new List(stateArray); var stateRemovals = new HashSet(); for (int i = states.Count - 2; i > -1; --i) { var preset = states[i].Preset; if (preset == null) { stateRemovals.Add(states[i].Name); states.RemoveAt(i); } } for (int i = 0; i < states.Count; ++i) { if (states[i].BlockList == null) { continue; } var blockList = new List(states[i].BlockList); for (int j = blockList.Count - 1; j > -1; --j) { if (stateRemovals.Contains(blockList[j])) { blockList.RemoveAt(j); } } states[i].BlockList = blockList.ToArray(); } return states.ToArray(); } /// /// Locks the unused doors. /// private static void LockDoors(GameObject[] doors) { if (doors == null) { return; } for (int i = 0; i < doors.Length; ++i) { if (doors[i] == null) { continue; } var door = doors[i].GetComponent(); if (door == null) { continue; } door.PermanentlyLocked = true; InspectorUtility.SetDirty(door); } } #endif } } #endif