using System; using System.Collections; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; namespace AppCenterEditor { public class AppCenterEditor : EditorWindow { private Vector2 scrollPosition = Vector2.zero; private const string EditorExtensionsDownloadFormat = "https://github.com/Microsoft/AppCenter-SDK-Unity-Extension/releases/download/{0}/AppCenterEditorExtensions-v{0}.unitypackage"; public enum EdExStates { OnMenuItemClicked, OnHttpReq, OnHttpRes, OnError, OnSuccess, OnWarning } public delegate void AppCenterEdExStateHandler(EdExStates state, string status, string misc); public static event AppCenterEdExStateHandler EdExStateUpdate; public static Dictionary blockingRequests = new Dictionary(); // key and blockingRequest start time private static float blockingRequestTimeOut = 10f; // abandon the block after this many seconds. public static string latestEdExVersion = string.Empty; private static Rect scrollInnerContainer; public static float InnerContainerWidth { get { return scrollInnerContainer.width; } } internal static AppCenterEditor window; void OnEnable() { if (window == null) { window = this; window.minSize = new Vector2(320, 0); } if (!IsEventHandlerRegistered(StateUpdateHandler)) { EdExStateUpdate += StateUpdateHandler; } GetLatestEdExVersion(); } void OnDisable() { AppCenterEditorPrefsSO.Instance.PanelIsShown = false; if (IsEventHandlerRegistered(StateUpdateHandler)) { EdExStateUpdate -= StateUpdateHandler; } } void OnFocus() { OnEnable(); } [MenuItem("Window/App Center/Editor Extensions")] static void AppCenterServices() { var editorAsm = typeof(Editor).Assembly; var inspWndType = editorAsm.GetType("UnityEditor.SceneHierarchyWindow"); if (inspWndType == null) { inspWndType = editorAsm.GetType("UnityEditor.InspectorWindow"); } window = GetWindow(inspWndType); window.titleContent = new GUIContent("App Center"); AppCenterEditorPrefsSO.Instance.PanelIsShown = true; } [InitializeOnLoad] public class Startup { static Startup() { if (AppCenterEditorPrefsSO.Instance.PanelIsShown || !AppCenterEditorSDKTools.IsInstalled) { Coroutiner.StartCoroutine(OpenAppCenterServices()); } } } static IEnumerator OpenAppCenterServices() { yield return new WaitForSeconds(1f); if (!Application.isPlaying) { AppCenterServices(); } } private void OnGUI() { HideRepaintErrors(OnGuiInternal); } private static void HideRepaintErrors(Action action) { try { action(); } catch (Exception e) { if (!e.Message.ToLower().Contains("repaint")) throw; // Hide any repaint issues when recompiling } } private void OnGuiInternal() { GUI.skin = AppCenterEditorHelper.uiStyle; scrollPosition = GUILayout.BeginScrollView(scrollPosition, false, false, GUILayout.Width(window.position.width), GUILayout.Height(window.position.height)); // Gets a rectangle with size of inner scroll area. scrollInnerContainer = EditorGUILayout.BeginHorizontal(GUILayout.ExpandHeight(true), GUILayout.ExpandWidth(true)); using (new AppCenterGuiFieldHelper.UnityVertical( GUILayout.Width(scrollInnerContainer.width), GUILayout.MaxWidth(scrollInnerContainer.width), GUILayout.Height(scrollInnerContainer.height))) { GUI.enabled = IsGUIEnabled(); AppCenterEditorHeader.DrawHeader(); AppCenterEditorMenu.DrawMenu(); AppCenterEditorSDKTools.DrawSdkPanel(); foreach (var package in AppCenterSDKPackage.SupportedPackages) { AppCenterEditorSDKTools.DisplayPackagePanel(package); } AppCenterEditorSDKTools.SDKState state = AppCenterEditorSDKTools.GetSDKState(); if (state == AppCenterEditorSDKTools.SDKState.SDKIsFull || state == AppCenterEditorSDKTools.SDKState.SDKNotFull) { AppCenterEditorSDKTools.ShowUpgradePanel(); } DisplayEditorExtensionHelpMenu(); } EditorGUILayout.EndHorizontal(); GUILayout.EndScrollView(); PruneBlockingRequests(); Repaint(); } public static bool IsGUIEnabled() { if (blockingRequests.Count > 0 || EditorApplication.isCompiling) { return false; } AppCenterEditorSDKTools.SDKState state = AppCenterEditorSDKTools.GetSDKState(); return !AppCenterEditorSDKTools.IsUpgrading && state != AppCenterEditorSDKTools.SDKState.SDKNotFullAndInstalling && state != AppCenterEditorSDKTools.SDKState.SDKNotInstalledAndInstalling; } private static void DisplayEditorExtensionHelpMenu() { using (new AppCenterGuiFieldHelper.UnityVertical(AppCenterEditorHelper.uiStyle.GetStyle("gpStyleGray1"))) { using (new AppCenterGuiFieldHelper.UnityHorizontal(AppCenterEditorHelper.uiStyle.GetStyle("gpStyleClear"))) { GUILayout.FlexibleSpace(); EditorGUILayout.LabelField("App Center Editor Extensions: " + AppCenterEditorHelper.EDEX_VERSION, AppCenterEditorHelper.uiStyle.GetStyle("versionText")); GUILayout.FlexibleSpace(); } if (ShowEdExUpgrade()) { using (new AppCenterGuiFieldHelper.UnityHorizontal()) { GUILayout.FlexibleSpace(); if (GUILayout.Button("UPGRADE EDITOR EXTENSION", AppCenterEditorHelper.uiStyle.GetStyle("textButtonMagenta"))) { UpgradeEdEx(); } GUILayout.FlexibleSpace(); } } if (!string.IsNullOrEmpty(AppCenterEditorHelper.EDEX_ROOT)) { using (new AppCenterGuiFieldHelper.UnityHorizontal()) { GUILayout.FlexibleSpace(); if (GUILayout.Button("UNINSTALL EDITOR EXTENSION", AppCenterEditorHelper.uiStyle.GetStyle("textButton"))) { RemoveEdEx(); } GUILayout.FlexibleSpace(); } } } } #region menu and helper methods public static void RaiseStateUpdate(EdExStates state, string status = null, string json = null) { if (EdExStateUpdate != null) { EdExStateUpdate(state, status, json); } } private static void PruneBlockingRequests() { List itemsToRemove = new List(); foreach (var req in blockingRequests) if (req.Value + blockingRequestTimeOut < (float)EditorApplication.timeSinceStartup) itemsToRemove.Add(req.Key); foreach (var item in itemsToRemove) { ClearBlockingRequest(item); RaiseStateUpdate(EdExStates.OnWarning, string.Format(" Request {0} has timed out after {1} seconds.", item, blockingRequestTimeOut)); } } private static void AddBlockingRequest(string state) { blockingRequests[state] = (float)EditorApplication.timeSinceStartup; } private static void ClearBlockingRequest(string state = null) { if (state == null) { blockingRequests.Clear(); } else if (blockingRequests.ContainsKey(state)) { blockingRequests.Remove(state); } } /// /// Handles state updates within the editor extension. /// /// the state that triggered this event. /// a generic message about the status. /// a generic container for additional JSON encoded info. private void StateUpdateHandler(EdExStates state, string status, string json) { switch (state) { case EdExStates.OnMenuItemClicked: break; case EdExStates.OnHttpReq: break; case EdExStates.OnHttpRes: break; case EdExStates.OnError: ProgressBar.UpdateState(ProgressBar.ProgressBarStates.error); EdExLogger.LoggerInstance.LogError(string.Format("App Center Editor Extensions: {0}", status)); break; case EdExStates.OnWarning: ProgressBar.UpdateState(ProgressBar.ProgressBarStates.warning); EdExLogger.LoggerInstance.LogWarning(string.Format("App Center Editor Extensions: {0}", status)); break; case EdExStates.OnSuccess: ProgressBar.UpdateState(ProgressBar.ProgressBarStates.success); break; } } public static bool IsEventHandlerRegistered(AppCenterEdExStateHandler prospectiveHandler) { if (EdExStateUpdate == null) return false; foreach (AppCenterEdExStateHandler existingHandler in EdExStateUpdate.GetInvocationList()) if (existingHandler == prospectiveHandler) return true; return false; } #endregion private static void GetLatestEdExVersion() { var threshold = AppCenterEditorPrefsSO.Instance.EdSet_lastEdExVersionCheck != DateTime.MinValue ? AppCenterEditorPrefsSO.Instance.EdSet_lastEdExVersionCheck.AddHours(1) : DateTime.MinValue; if (DateTime.Today > threshold) { AppCenterEditorHttp.MakeGitHubApiCall("https://api.github.com/repos/Microsoft/AppCenter-SDK-Unity-Extension/git/refs/tags", (version) => { latestEdExVersion = version ?? Constants.UnknownVersion; AppCenterEditorPrefsSO.Instance.EdSet_latestEdExVersion = latestEdExVersion; }); } else { latestEdExVersion = AppCenterEditorPrefsSO.Instance.EdSet_latestEdExVersion; } } private static bool ShowEdExUpgrade() { if (string.IsNullOrEmpty(latestEdExVersion) || latestEdExVersion == Constants.UnknownVersion) return false; if (string.IsNullOrEmpty(AppCenterEditorHelper.EDEX_VERSION) || AppCenterEditorHelper.EDEX_VERSION == Constants.UnknownVersion) return true; string[] currrent = AppCenterEditorHelper.EDEX_VERSION.Split('.'); if (currrent.Length != 3) return true; string[] latest = latestEdExVersion.Split('.'); return latest.Length != 3 || int.Parse(latest[0]) > int.Parse(currrent[0]) || int.Parse(latest[1]) > int.Parse(currrent[1]) || int.Parse(latest[2]) > int.Parse(currrent[2]); } private static void RemoveEdEx(bool prompt = true) { if (prompt && !EditorUtility.DisplayDialog("Confirm Editor Extensions Removal", "This action will remove App Center Editor Extensions from the current project.", "Confirm", "Cancel")) return; try { window.Close(); var edExDirectory = new DirectoryInfo(AppCenterEditorHelper.EDEX_ROOT).Parent.FullName; EdExLogger.LoggerInstance.LogWithTimeStamp("Deleting directory: " + edExDirectory); FileUtil.DeleteFileOrDirectory(edExDirectory); var edExDirectoryMeta = edExDirectory + ".meta"; EdExLogger.LoggerInstance.LogWithTimeStamp("Deleting file: " + edExDirectoryMeta); FileUtil.DeleteFileOrDirectory(edExDirectoryMeta); if (prompt) { AssetDatabase.Refresh(); } PlayerPrefs.DeleteKey(AppCenterEditorPrefsSO.SdkLastCheckDateKey); PlayerPrefs.DeleteKey(AppCenterEditorPrefsSO.EdExLastCheckDateKey); } catch (Exception ex) { EdExLogger.LoggerInstance.LogError("Failed to remove App Center Editor Extensions: " + ex); } } private static void UpgradeEdEx() { if (EditorUtility.DisplayDialog("Confirm EdEx Upgrade", "This action will remove the current App Center Editor Extensions and install the lastet version.", "Confirm", "Cancel")) { RemoveEdEx(false); ImportLatestEdEx(); } } private static void ImportLatestEdEx() { var downloadUrl = string.Format(EditorExtensionsDownloadFormat, latestEdExVersion); AppCenterEditorHttp.MakeDownloadCall(downloadUrl, file => { EdExLogger.LoggerInstance.LogWithTimeStamp("Importing package: " + file); AssetDatabase.ImportPackage(file, false); EdExLogger.LoggerInstance.LogWithTimeStamp("Deleteing file: " + file); FileUtil.DeleteFileOrDirectory(file); EdExLogger.LoggerInstance.LogWithTimeStamp("App Center Editor Extensions upgrade complete"); }); } } }