Files
BABA_YAGA/Assets/Opsive/UltimateCharacterController/Editor/Managers/AddOnsManager.cs
2026-06-14 23:57:44 +07:00

335 lines
14 KiB
C#

/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.Editor.Managers
{
using Opsive.UltimateCharacterController.Editor.Inspectors.Utility;
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
/// <summary>
/// Draws the inspector for an add-on that has been installed.
/// </summary>
public abstract class AddOnInspector
{
protected MainManagerWindow m_MainManagerWindow;
public MainManagerWindow MainManagerWindow { set { m_MainManagerWindow = value; } }
/// <summary>
/// Draws the add-on inspector.
/// </summary>
public abstract void DrawInspector();
}
/// <summary>
/// Draws a list of all of the available add-ons.
/// </summary>
[OrderedEditorItem("Add-Ons", 11)]
public class AddOnsManager : Manager
{
private string[] m_ToolbarStrings = { "Installed Add-Ons", "Available Add-Ons" };
[SerializeField] private bool m_DrawInstalledAddOns;
[SerializeField] private bool m_Initialized;
private AddOnInspector[] m_AddOnInspectors;
private string[] m_AddOnNames;
private static GUIStyle s_AddOnTitle;
private static GUIStyle AddOnTitle
{
get
{
if (s_AddOnTitle == null) {
s_AddOnTitle = new GUIStyle(InspectorStyles.CenterBoldLabel);
s_AddOnTitle.fontSize = 14;
s_AddOnTitle.alignment = TextAnchor.MiddleLeft;
}
return s_AddOnTitle;
}
}
/// <summary>
/// Stores the information about the add-on.
/// </summary>
private class AvailableAddOn
{
private const int c_IconSize = 78;
private int m_ID;
private string m_Name;
private string m_AddOnURL;
private string m_Description;
private bool m_Installed;
private Texture2D m_Icon;
private MainManagerWindow m_MainManagerWindow;
#if UNITY_2018_3_OR_NEWER
private UnityEngine.Networking.UnityWebRequest m_IconRequest;
private UnityEngine.Networking.DownloadHandlerTexture m_TextureDownloadHandler;
#else
private WWW m_IconRequest;
#endif
/// <summary>
/// Constructor for the AvailableAddOn class.
/// </summary>
public AvailableAddOn(int id, string name, string iconURL, string addOnURL, string description, string type, MainManagerWindow mainManagerWindow)
{
m_ID = id;
m_Name = name;
m_AddOnURL = addOnURL;
m_Description = description;
// The add-on is installed if the type exists.
m_Installed = !string.IsNullOrEmpty(type) && UltimateCharacterController.Utility.UnityEngineUtility.GetType(type) != null;
m_MainManagerWindow = mainManagerWindow;
// Start loading the icon as soon as the url is retrieved.
#if UNITY_2018_3_OR_NEWER
m_TextureDownloadHandler = new UnityEngine.Networking.DownloadHandlerTexture();
m_IconRequest = UnityEngine.Networking.UnityWebRequest.Get(iconURL);
m_IconRequest.downloadHandler = m_TextureDownloadHandler;
m_IconRequest.SendWebRequest();
#else
m_IconRequest = new WWW(iconURL);
#endif
}
/// <summary>
/// Draws the inspector for the available add-on.
/// </summary>
public void DrawAddOn()
{
if (m_IconRequest != null) {
if (m_IconRequest.isDone) {
if (string.IsNullOrEmpty(m_IconRequest.error)) {
#if UNITY_2018_3_OR_NEWER
m_Icon = m_TextureDownloadHandler.texture;
#else
m_Icon = m_IconRequest.texture;
#endif
}
m_IconRequest = null;
} else {
m_MainManagerWindow.Repaint();
}
}
// Draw the add-on details.
EditorGUILayout.BeginHorizontal();
if (m_Icon != null) {
GUILayout.Label(m_Icon);
}
EditorGUILayout.BeginVertical();
var name = m_Name;
if (m_Installed) {
name += " (INSTALLED)";
}
EditorGUILayout.LabelField(name, InspectorStyles.BoldLabel, GUILayout.Height(20));
EditorGUILayout.BeginHorizontal();
if (!string.IsNullOrEmpty(m_AddOnURL) && GUILayout.Button("Overview", GUILayout.MaxWidth(150))) {
Application.OpenURL(m_AddOnURL);
}
if (m_ID > 0 && GUILayout.Button("Asset Store", GUILayout.MaxWidth(150))) {
Application.OpenURL("https://opsive.com/asset/UltimateCharacterController/AssetRedirect.php?asset=" + m_ID);
}
EditorGUILayout.EndHorizontal();
GUILayout.Space(5);
EditorGUILayout.LabelField(m_Description, InspectorStyles.WordWrapLabel);
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
}
}
private Vector2 m_InstalledScrollPosition;
private Vector2 m_AvailableScrollPosition;
#if UNITY_2018_3_OR_NEWER
private UnityEngine.Networking.UnityWebRequest m_AddOnsReqest;
#else
private WWW m_AddOnsReqest;
#endif
private AvailableAddOn[] m_AvailableAddOns;
/// <summary>
/// Initialize the manager after deserialization.
/// </summary>
public override void Initialize(MainManagerWindow mainManagerWindow)
{
base.Initialize(mainManagerWindow);
BuildInstalledAddOns();
if (!m_Initialized) {
m_DrawInstalledAddOns = m_AvailableAddOns != null && m_AvailableAddOns.Length > 0;
m_Initialized = true;
}
}
/// <summary>
/// Finds and create an instance of the inspectors for all of the installed add-ons.
/// </summary>
private void BuildInstalledAddOns()
{
var addOnInspectors = new List<Type>();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var addOnIndexes = new List<int>();
for (int i = 0; i < assemblies.Length; ++i) {
var assemblyTypes = assemblies[i].GetTypes();
for (int j = 0; j < assemblyTypes.Length; ++j) {
// Must implement AddOnInspector.
if (!typeof(AddOnInspector).IsAssignableFrom(assemblyTypes[j])) {
continue;
}
// Ignore abstract classes.
if (assemblyTypes[j].IsAbstract) {
continue;
}
// A valid inspector class.
addOnInspectors.Add(assemblyTypes[j]);
var index = addOnIndexes.Count;
if (assemblyTypes[j].GetCustomAttributes(typeof(OrderedEditorItem), true).Length > 0) {
var item = assemblyTypes[j].GetCustomAttributes(typeof(OrderedEditorItem), true)[0] as OrderedEditorItem;
index = item.Index;
}
addOnIndexes.Add(index);
}
}
// Do not reinitialize the inspectors if they are already initialized and there aren't any changes.
if (m_AddOnInspectors != null && m_AddOnInspectors.Length == addOnInspectors.Count) {
return;
}
// All of the manager types have been found. Sort by the index.
var inspectorTypes = addOnInspectors.ToArray();
Array.Sort(addOnIndexes.ToArray(), inspectorTypes);
m_AddOnInspectors = new AddOnInspector[addOnInspectors.Count];
m_AddOnNames = new string[addOnInspectors.Count];
// The inspector types have been found and sorted. Add them to the list.
for (int i = 0; i < inspectorTypes.Length; ++i) {
m_AddOnInspectors[i] = Activator.CreateInstance(inspectorTypes[i]) as AddOnInspector;
m_AddOnInspectors[i].MainManagerWindow = m_MainManagerWindow;
var name = InspectorUtility.SplitCamelCase(inspectorTypes[i].Name);
if (addOnInspectors[i].GetCustomAttributes(typeof(OrderedEditorItem), true).Length > 0) {
var item = inspectorTypes[i].GetCustomAttributes(typeof(OrderedEditorItem), true)[0] as OrderedEditorItem;
name = item.Name;
}
m_AddOnNames[i] = name;
}
}
/// <summary>
/// Draws the Manager.
/// </summary>
public override void OnGUI()
{
var toolbarSelection = GUILayout.Toolbar(m_DrawInstalledAddOns ? 0 : 1, m_ToolbarStrings, EditorStyles.toolbarButton);
m_DrawInstalledAddOns = toolbarSelection == 0;
GUILayout.Space(10);
if (m_DrawInstalledAddOns) {
DrawInstalledAddOns();
} else {
DrawAvailableAddOns();
}
}
/// <summary>
/// Draws the inspector for all installed add-ons.
/// </summary>
private void DrawInstalledAddOns()
{
if (m_AddOnInspectors == null || m_AddOnInspectors.Length == 0) {
GUILayout.Label("No add-ons are currently installed.\n\nSelect the \"Available Add-Ons\" tab to see a list of all of the available add-ons.");
return;
}
m_InstalledScrollPosition = EditorGUILayout.BeginScrollView(m_InstalledScrollPosition);
for (int i = 0; i < m_AddOnInspectors.Length; ++i) {
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
GUILayout.Label(m_AddOnNames[i], InspectorStyles.LargeBoldLabel);
GUILayout.Space(4);
m_AddOnInspectors[i].DrawInspector();
EditorGUILayout.EndVertical();
if (i != m_AddOnInspectors.Length - 1) {
GUILayout.Space(20);
}
}
EditorGUILayout.EndScrollView();
}
/// <summary>
/// Draws all of the add-ons that are currently available.
/// </summary>
private void DrawAvailableAddOns()
{
if (m_AvailableAddOns == null && m_AddOnsReqest == null) {
#if UNITY_2018_3_OR_NEWER
m_AddOnsReqest = UnityEngine.Networking.UnityWebRequest.Get("https://opsive.com/asset/UltimateCharacterController/AddOnsList.txt");
m_AddOnsReqest.SendWebRequest();
#else
m_AddOnsReqest = new WWW("https://opsive.com/asset/UltimateCharacterController/AddOnsList.txt");
#endif
} else if (m_AvailableAddOns == null && m_AddOnsReqest.isDone && string.IsNullOrEmpty(m_AddOnsReqest.error) && Event.current.type == EventType.Layout) {
#if UNITY_2018_3_OR_NEWER
var splitAddOns = m_AddOnsReqest.downloadHandler.text.Split('\n');
#else
var splitAddOns = m_AddOnsReqest.text.Split('\n');
#endif
m_AvailableAddOns = new AvailableAddOn[splitAddOns.Length];
var count = 0;
for (int i = 0; i < splitAddOns.Length; ++i) {
if (string.IsNullOrEmpty(splitAddOns[i])) {
continue;
}
// The data must contain info on the add-on name, id, icon, add-on url, description, and type.
var addOnData = splitAddOns[i].Split(',');
if (addOnData.Length < 6) {
continue;
}
m_AvailableAddOns[count] = new AvailableAddOn(int.Parse(addOnData[0].Trim()), addOnData[1].Trim(), addOnData[2].Trim(), addOnData[3].Trim(), addOnData[4].Trim(), addOnData[5].Trim(), m_MainManagerWindow);
count++;
}
if (count != m_AvailableAddOns.Length) {
Array.Resize(ref m_AvailableAddOns, count);
}
m_AddOnsReqest = null;
} else if (m_AddOnsReqest != null) {
m_MainManagerWindow.Repaint();
}
// Draw the add-ons once they are loaded.
if (m_AvailableAddOns != null && m_AvailableAddOns.Length > 0) {
m_AvailableScrollPosition = EditorGUILayout.BeginScrollView(m_AvailableScrollPosition);
// Draw each add-on.
for (int i = 0; i < m_AvailableAddOns.Length; ++i) {
m_AvailableAddOns[i].DrawAddOn();
if (i != m_AvailableAddOns.Length - 1) {
GUILayout.Space(20);
}
}
EditorGUILayout.EndScrollView();
} else {
if (m_AddOnsReqest != null && m_AddOnsReqest.isDone && !string.IsNullOrEmpty(m_AddOnsReqest.error)) {
EditorGUILayout.LabelField("Error: Unable to retrieve add-ons.");
} else {
EditorGUILayout.LabelField("Retrieveing the list of current add-ons...");
}
}
}
}
}