/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.Editor.Managers
{
using Opsive.Shared.Game;
using Opsive.UltimateCharacterController.Camera;
using Opsive.UltimateCharacterController.Editor.Inspectors.Utility;
using Opsive.UltimateCharacterController.Game;
using Opsive.UltimateCharacterController.StateSystem;
using Opsive.UltimateCharacterController.Utility;
using Opsive.UltimateCharacterController.Utility.Builders;
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
///
/// The SetupManager shows any project or scene related setup options.
///
[OrderedEditorItem("Setup", 1)]
public class SetupManager : Manager
{
private const string c_MonitorsPrefabGUID = "b5bf2e4077598914b83fc5e4ca20f2f4";
private const string c_VirtualControlsPrefabGUID = "33d3d57ba5fc7484c8d09150e45066a4";
///
/// Specifies the perspective that the ViewType can change into.
///
private enum Perspective
{
First, // The ViewType can only be in first person perspective.
Third, // The ViewType can only be in third person perspective.
Both, // The ViewType can be in first or third person perspective.
None // Default value.
}
private string[] m_ToolbarStrings = { "Scene", "Project" };
[SerializeField] private bool m_DrawSceneSetup = true;
[SerializeField] private bool m_CanCreateCamera = true;
[SerializeField] private Perspective m_Perspective = Perspective.None;
[SerializeField] private string m_FirstPersonViewType;
[SerializeField] private string m_ThirdPersonViewType;
[SerializeField] private bool m_StartFirstPersonPerspective;
[SerializeField] private StateConfiguration m_StateConfiguration;
[SerializeField] private int m_ProfileIndex;
[SerializeField] private string m_ProfileName;
private List m_FirstPersonViewTypes = new List();
private string[] m_FirstPersonViewTypeStrings;
private List m_ThirdPersonViewTypes = new List();
private string[] m_ThirdPersonViewTypeStrings;
private string[] m_PerspectiveNames = { "First", "Third", "Both" };
///
/// Initialize the manager after deserialization.
///
public override void Initialize(MainManagerWindow mainManagerWindow)
{
base.Initialize(mainManagerWindow);
// Set the default perspective based on what asset is installed.
if (m_Perspective == Perspective.None) {
#if FIRST_PERSON_CONTROLLER
m_Perspective = Perspective.First;
#elif THIRD_PERSON_CONTROLLER
m_Perspective = Perspective.Third;
#endif
}
// Get a list of the available view types.
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int i = 0; i < assemblies.Length; ++i) {
var assemblyTypes = assemblies[i].GetTypes();
for (int j = 0; j < assemblyTypes.Length; ++j) {
// Must derive from ViewType.
if (!typeof(UltimateCharacterController.Camera.ViewTypes.ViewType).IsAssignableFrom(assemblyTypes[j])) {
continue;
}
// Ignore abstract classes.
if (assemblyTypes[j].IsAbstract) {
continue;
}
if (assemblyTypes[j].FullName.Contains("FirstPersonController")) {
m_FirstPersonViewTypes.Add(assemblyTypes[j]);
} else if (assemblyTypes[j].FullName.Contains("ThirdPersonController")) {
m_ThirdPersonViewTypes.Add(assemblyTypes[j]);
}
}
}
// Create an array of display names for the popup.
if (m_FirstPersonViewTypes.Count > 0) {
m_FirstPersonViewTypeStrings = new string[m_FirstPersonViewTypes.Count];
for (int i = 0; i < m_FirstPersonViewTypes.Count; ++i) {
m_FirstPersonViewTypeStrings[i] = InspectorUtility.DisplayTypeName(m_FirstPersonViewTypes[i], true);
}
}
if (m_ThirdPersonViewTypes.Count > 0) {
m_ThirdPersonViewTypeStrings = new string[m_ThirdPersonViewTypes.Count];
for (int i = 0; i < m_ThirdPersonViewTypes.Count; ++i) {
m_ThirdPersonViewTypeStrings[i] = InspectorUtility.DisplayTypeName(m_ThirdPersonViewTypes[i], true);
}
}
// Find the state configuration.
var stateConfiguration = ManagerUtility.FindStateConfiguration(m_MainManagerWindow);
if (stateConfiguration != null) {
if (m_StateConfiguration == null) {
m_StateConfiguration = stateConfiguration;
}
}
}
///
/// Draws the Manager.
///
public override void OnGUI()
{
var toolbarSelection = GUILayout.Toolbar(m_DrawSceneSetup ? 0 : 1, m_ToolbarStrings, EditorStyles.toolbarButton);
m_DrawSceneSetup = toolbarSelection == 0;
GUILayout.Space(10);
if (m_DrawSceneSetup) {
DrawSceneSetup();
} else {
DrawProjectSetup();
}
}
///
/// Draws the controls for setting up the scene.
///
private void DrawSceneSetup()
{
ManagerUtility.DrawControlBox("Manager Setup", null, "Adds the scene-level manager components to the scene.", true, "Add Managers", AddManagers, string.Empty);
ManagerUtility.DrawControlBox("Camera Setup", DrawCameraViewTypes, "Sets up the camera within the scene to use the Ultimate Character Controller Camera Controller component.",
m_CanCreateCamera, "Setup Camera", SetupCamera, string.Empty);
ManagerUtility.DrawControlBox("UI Setup", null, "Adds the UI monitors to the scene.", true, "Add UI", AddUI, string.Empty);
ManagerUtility.DrawControlBox("Virtual Controls Setup", null, "Adds the virtual controls to the scene.", true, "Add Virtual Controls", AddVirtualControls, string.Empty);
}
///
/// Draws the popup for the camera view types.
///
private void DrawCameraViewTypes()
{
// Draw the perspective.
var selectedPerspective = (Perspective)EditorGUILayout.Popup("Perspective", (int)m_Perspective, m_PerspectiveNames);
var isSupported = true;
// Determine if the selected perspective is supported.
#if !FIRST_PERSON_CONTROLLER
if (selectedPerspective == Perspective.First || selectedPerspective == Perspective.Both) {
EditorGUILayout.HelpBox("Unable to select the First Person Controller perspective. If you'd like to use a first person perspective ensure the " +
"First Person Controller is imported.", MessageType.Error);
isSupported = false;
}
#endif
#if !THIRD_PERSON_CONTROLLER
if (selectedPerspective == Perspective.Third || selectedPerspective == Perspective.Both) {
EditorGUILayout.HelpBox("Unable to select the Third Person Controller perspective. If you'd like to use a third person perspective ensure the " +
"Third Person Controller is imported.", MessageType.Error);
isSupported = false;
}
#endif
if (selectedPerspective != m_Perspective) {
m_Perspective = selectedPerspective;
}
m_CanCreateCamera = isSupported;
if (!isSupported) {
return;
}
// Show the available first person ViewTypes.
if (m_Perspective == Perspective.First || m_Perspective == Perspective.Both) {
var selectedViewType = -1;
for (int i = 0; i < m_FirstPersonViewTypes.Count; ++i) {
if (m_FirstPersonViewTypes[i].FullName == m_FirstPersonViewType) {
selectedViewType = i;
break;
}
}
var viewType = selectedViewType == -1 ? 0 : selectedViewType;
selectedViewType = EditorGUILayout.Popup("First Person View Type", viewType, m_FirstPersonViewTypeStrings);
if (viewType != selectedViewType || string.IsNullOrEmpty(m_FirstPersonViewType)) {
m_FirstPersonViewType = m_FirstPersonViewTypes[selectedViewType].FullName;
}
if (m_Perspective != Perspective.Both) {
m_ThirdPersonViewType = string.Empty;
}
}
// Show the available third person ViewTypes.
if (m_Perspective == Perspective.Third || m_Perspective == Perspective.Both) {
var selectedViewType = -1;
for (int i = 0; i < m_ThirdPersonViewTypes.Count; ++i) {
if (m_ThirdPersonViewTypes[i].FullName == m_ThirdPersonViewType) {
selectedViewType = i;
break;
}
}
var viewType = selectedViewType == -1 ? 0 : selectedViewType;
selectedViewType = EditorGUILayout.Popup("Third Person View Type", viewType, m_ThirdPersonViewTypeStrings);
if (viewType != selectedViewType || string.IsNullOrEmpty(m_ThirdPersonViewType)) {
m_ThirdPersonViewType = m_ThirdPersonViewTypes[selectedViewType].FullName;
}
if (m_Perspective != Perspective.Both) {
m_FirstPersonViewType = string.Empty;
}
}
if (m_Perspective == Perspective.Both) {
m_StartFirstPersonPerspective = EditorGUILayout.Popup("Start Perspective", m_StartFirstPersonPerspective ? 0 : 1, new string[] { "First Person", "Third Person" }) == 0;
} else {
m_StartFirstPersonPerspective = (m_Perspective == Perspective.First);
}
// Show the possible base configurations.
var updatedStateConfiguration = EditorGUILayout.ObjectField("State Configuration", m_StateConfiguration, typeof(StateConfiguration), false) as StateConfiguration;
if (updatedStateConfiguration != m_StateConfiguration) {
if (updatedStateConfiguration != null) {
EditorPrefs.SetString(ManagerUtility.LastStateConfigurationGUIDString, AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(updatedStateConfiguration)));
} else {
EditorPrefs.SetString(ManagerUtility.LastStateConfigurationGUIDString, string.Empty);
}
m_StateConfiguration = updatedStateConfiguration;
}
EditorGUI.indentLevel++;
if (m_StateConfiguration != null) {
var profiles = m_StateConfiguration.GetProfilesForGameObject(null, StateConfiguration.Profile.ProfileType.Camera);
// The character can be added without any profiles.
profiles.Insert(0, "(None)");
m_ProfileIndex = EditorGUILayout.Popup("Profile", m_ProfileIndex, profiles.ToArray());
m_ProfileName = profiles[m_ProfileIndex];
}
EditorGUI.indentLevel--;
GUILayout.Space(5);
}
///
/// Sets up the camera if it hasn't already been setup.
///
private void SetupCamera()
{
// Setup the camera.
GameObject cameraGameObject;
var addedCameraController = false;
var camera = UnityEngine.Camera.main;
if (camera == null) {
// If the main camera can't be found then use the first available camera.
var cameras = UnityEngine.Camera.allCameras;
if (cameras != null && cameras.Length > 0) {
// Prefer cameras that are at the root level.
for (int i = 0; i < cameras.Length; ++i) {
if (cameras[i].transform.parent == null) {
camera = cameras[i];
break;
}
}
// No cameras are at the root level. Set the first available camera.
if (camera == null) {
camera = cameras[0];
}
}
// A new camera should be created if there isn't a valid camera.
if (camera == null) {
cameraGameObject = new GameObject("Camera");
cameraGameObject.tag = "MainCamera";
camera = cameraGameObject.AddComponent();
cameraGameObject.AddComponent();
}
}
// The near clip plane should adjusted for viewing close objects.
camera.nearClipPlane = 0.01f;
// Add the CameraController if it isn't already added.
cameraGameObject = camera.gameObject;
if (cameraGameObject.GetComponent() == null) {
var cameraController = cameraGameObject.AddComponent();
if (m_Perspective == Perspective.Both) {
ViewTypeBuilder.AddViewType(cameraController, typeof(UltimateCharacterController.Camera.ViewTypes.Transition));
}
if (m_StartFirstPersonPerspective) {
if (!string.IsNullOrEmpty(m_ThirdPersonViewType)) {
ViewTypeBuilder.AddViewType(cameraController, UnityEngineUtility.GetType(m_ThirdPersonViewType));
}
if (!string.IsNullOrEmpty(m_FirstPersonViewType)) {
ViewTypeBuilder.AddViewType(cameraController, UnityEngineUtility.GetType(m_FirstPersonViewType));
}
} else {
if (!string.IsNullOrEmpty(m_FirstPersonViewType)) {
ViewTypeBuilder.AddViewType(cameraController, UnityEngineUtility.GetType(m_FirstPersonViewType));
}
if (!string.IsNullOrEmpty(m_ThirdPersonViewType)) {
ViewTypeBuilder.AddViewType(cameraController, UnityEngineUtility.GetType(m_ThirdPersonViewType));
}
}
// Detect if a character exists in the scene. Automatically add the character if it does.
var characters = GameObject.FindObjectsOfType();
if (characters != null && characters.Length == 1) {
cameraController.InitCharacterOnAwake = true;
cameraController.Character = characters[0].gameObject;
}
// Setup the components which help the Camera Controller.
Shared.Editor.Utility.InspectorUtility.AddComponent(cameraGameObject);
#if THIRD_PERSON_CONTROLLER
if (m_Perspective != Perspective.First) {
Shared.Editor.Utility.InspectorUtility.AddComponent(cameraGameObject);
}
#endif
addedCameraController = true;
if (m_StateConfiguration != null) {
if (m_ProfileIndex > 0) {
m_StateConfiguration.AddStatesToGameObject(m_ProfileName, cameraGameObject);
InspectorUtility.SetDirty(cameraGameObject);
}
}
}
if (addedCameraController) {
Debug.Log("The Camera Controller has been added.");
} else {
Debug.LogWarning("Warning: No action was performed, the Camera Controller component has already been added.");
}
}
///
/// Adds the singleton manager components.
///
private void AddManagers()
{
// Create the "Game" components if it doesn't already exists.
Scheduler scheduler;
GameObject gameGameObject;
if ((scheduler = GameObject.FindObjectOfType()) == null) {
gameGameObject = new GameObject("Game");
} else {
gameGameObject = scheduler.gameObject;
}
// Add the Singletons.
Shared.Editor.Utility.InspectorUtility.AddComponent(gameGameObject);
Shared.Editor.Utility.InspectorUtility.AddComponent(gameGameObject);
Shared.Editor.Utility.InspectorUtility.AddComponent(gameGameObject);
Shared.Editor.Utility.InspectorUtility.AddComponent(gameGameObject);
Shared.Editor.Utility.InspectorUtility.AddComponent(gameGameObject);
Shared.Editor.Utility.InspectorUtility.AddComponent(gameGameObject);
Shared.Editor.Utility.InspectorUtility.AddComponent(gameGameObject);
Shared.Editor.Utility.InspectorUtility.AddComponent(gameGameObject);
Shared.Editor.Utility.InspectorUtility.AddComponent(gameGameObject);
Debug.Log("The managers have been added.");
}
///
/// Adds the UI to the scene.
///
private void AddUI()
{
var canvas = GameObject.FindObjectOfType