using System; using System.Linq; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; using UnityEngine.Networking; using Label = HIKKY.VketCloudSDK.UI.EditorWindow.GUIHelper.Label; using Unity.Plastic.Newtonsoft.Json; using System.Threading.Tasks; using static HIKKY.VketCloudSDK.AddOn.ExternalPackageImporter; using System.Diagnostics; using System.IO; using UnityEditor.PackageManager; using static HIKKY.VketCloudSDK.AddOn.LanguageSetting; using Unity.Plastic.Newtonsoft.Json.Linq; using UnityEditor.Compilation; namespace HIKKY.VketCloudSDK.AddOn { public class VersionManagerWindow : EditorWindow { private const int TOTAL_PAGES = 2; private static int _currentPage; private Texture2D _initialTopImage; private Texture2D _logoImage; private Texture2D _logoLightImage; private float _buttonWidth = 80; private string _nextString = string.Empty; // Language Settings private LanguageSetting.Language _currentLanguage; private string[] _languageOptions = { "English", "日本語" }; private int _selectedLanguageIndex = 0; private static LocalizationManager _localizationManager; private string _stableVersion = ""; private string _latestVersion = ""; private List _archivedVersions = new List { "" }; private string _selectedVersion = ""; private const string SELECTED_VERSION = "VKETCLOUDSDK_SELECTED_VERSION"; private string _latestETSVersion = ""; private static string npmjsURL = "https://registry.npmjs.org/com.hikky.vketcloudsdk"; private static string npmjsETSURL = "https://registry.npmjs.org/com.hikky.editortutorialsystem"; private static UnityWebRequest www; private static string json; private static string jsonETS; private float _progress = 0f; private float _progressSpeed = 0.00005f; private bool _progressForward = true; // Frames private Texture2D[] frames; private Texture2D[] frames_Light; private int currentFrame = 0; private float frameRate = 10.0f; // Adjust the frame rate as needed private float lastFrameTime; private string framesDarkPath = ""; private string framesLightPath = ""; private static readonly string manualURL = "https://vrhikky.github.io/VketCloudSDK_Documents/"; private static readonly string discordURL = "https://discord.gg/VrsA26bDyP"; private Texture2D _versionImage; private GUIContent manualbutton = null; private GUIContent discordButton = null; Texture textIcon = null; GUIStyle buttonStyle = null; private Vector2 _scrollPosition; [MenuItem("VketCloudSDK_Wizard/ SDK Version Manager", true)] public static bool ValidateShowStartup() { return CheckForPackage("com.hikky.vketcloudsdk"); } [MenuItem("VketCloudSDK_Wizard/ SDK Version Manager")] public static void ShowStartup() { VersionManagerWindow window = (VersionManagerWindow)GetWindow(typeof(VersionManagerWindow), true, "VketCloudSDK Install Wizard"); window.minSize = new Vector2(650, 360); window.maxSize = new Vector2(650, 360); _currentPage = 0; window.titleContent = new GUIContent($"{GetLocalizedString("VersionManager_WindowTitle")} ({_currentPage + 1}/{TOTAL_PAGES})"); window.Show(); } public static void ShowForPreventing() { var window = GetWindow(); if (window == null) { VersionManagerWindow newWindow = (VersionManagerWindow)GetWindow(typeof(VersionManagerWindow), true, "VketCloudSDK Install Wizard"); newWindow.minSize = new Vector2(650, 360); newWindow.maxSize = new Vector2(650, 360); _currentPage = 0; newWindow.titleContent = new GUIContent($"{GetLocalizedString("VersionManager_WindowTitle")} ({_currentPage + 1}/{TOTAL_PAGES})"); newWindow.Show(); } } [InitializeOnLoadMethod] public static void Initialize() { StartBackgroundTask(StartRequest(npmjsURL, () => { var temp = www.downloadHandler.text; if (temp != null) { json = temp; } })); StartBackgroundTask(StartRequest(npmjsETSURL, () => { var temp = www.downloadHandler.text; if (temp != null) { jsonETS = temp; } })); } public static bool CheckForPackage(string packageName) { string path = Path.Combine(Application.dataPath, "..", "Packages", "manifest.json"); if (File.Exists(path)) { string jsonText = File.ReadAllText(path); try { JObject json = JObject.Parse(jsonText); JToken dependencies = json["dependencies"]; return dependencies[packageName] != null; } catch (JsonException e) { UnityEngine.Debug.LogError("Failed to parse manifest.json: " + e.Message); } } else { UnityEngine.Debug.LogError("manifest.json not found."); } return false; } public static bool CheckForPackageAndVersion(string packageName, string desiredVersion) { string path = Path.Combine(Application.dataPath, "..", "Packages", "manifest.json"); if (File.Exists(path)) { string jsonText = File.ReadAllText(path); try { JObject json = JObject.Parse(jsonText); JToken dependencies = json["dependencies"]; JToken version = dependencies[packageName]; if (version != null && version.ToString() == desiredVersion) { return true; } } catch (JsonException e) { UnityEngine.Debug.LogError("Failed to parse manifest.json: " + e.Message); } } else { UnityEngine.Debug.LogError("manifest.json not found."); } return false; } public async void OnEnable() { if (CheckForPackageAndVersion("com.hikky.vketcloudsdk", PlayerPrefs.GetString(SELECTED_VERSION, "0.0.0"))) { _currentPage = 2; UpdateWindowTitle(); } _logoImage = AssetDatabase.LoadAssetAtPath(PathManager.GetWizardLogoImage); _logoLightImage = AssetDatabase.LoadAssetAtPath(PathManager.GetWizardLogoLightImage); _versionImage = AssetDatabase.LoadAssetAtPath(PathManager.GetWizardVersionImage); _currentLanguage = LanguageSetting.GetLanguage(); _selectedLanguageIndex = (int)_currentLanguage; _localizationManager = AssetDatabase.LoadAssetAtPath(PathManager.GetLocalizationManagerSetting); if (_localizationManager != null) { _localizationManager.LoadLanguage(_currentLanguage); } _progress = 0f; UpdateWindowTitle(); try { json = await FetchVersions(); } catch (Exception e) { UnityEngine.Debug.LogError(e.Message); } StartBackgroundTask(StartRequest(npmjsURL, () => { var temp = www.downloadHandler.text; if (temp != null) { json = temp; } })); ParseJsonData(json); try { jsonETS = await FetchETSVersions(); } catch (Exception e) { UnityEngine.Debug.LogError(e.Message); } StartBackgroundTask(StartRequest(npmjsETSURL, () => { var temp = www.downloadHandler.text; if (temp != null) { jsonETS = temp; } })); ParseETSJsonData(jsonETS); if (buttonStyle == null) { buttonStyle = new GUIStyle("ButtonLeft"); buttonStyle.alignment = TextAnchor.MiddleCenter; buttonStyle.margin = buttonStyle.margin; buttonStyle.margin.right = 0; } manualbutton = new GUIContent(GetLocalizedString("VersionSelectionPage_Manual"), textIcon); discordButton = new GUIContent(GetLocalizedString("VersionSelectionPage_Discord"), textIcon); framesDarkPath = PathManager.GetLoadingDarkImageFolder; LoadDarkFrames(); framesLightPath = PathManager.GetLoadingLightImageFolder; LoadLightFrames(); EditorApplication.update += UpdateAnimation; } public void OnDisable() { EditorApplication.update -= UpdateAnimation; } private void UpdateAnimation() { // Use EditorApplication.timeSinceStartup to get the current time double timeSinceStartup = EditorApplication.timeSinceStartup; if (timeSinceStartup - lastFrameTime >= 1.0f / frameRate) { currentFrame = (currentFrame + 1) % frames.Length; // Loop back to the first frame after the last lastFrameTime = (float)timeSinceStartup; // Request the window to repaint itself Repaint(); } } private async Task FetchVersions() { using (UnityWebRequest www = UnityWebRequest.Get(npmjsURL)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Delay(100); // Delay for a short period before checking if the request is done } return www.downloadHandler.text; } } private async Task FetchETSVersions() { using (UnityWebRequest www = UnityWebRequest.Get(npmjsETSURL)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Delay(100); // Delay for a short period before checking if the request is done } return www.downloadHandler.text; } } private void LoadDarkFrames() { var guids = AssetDatabase.FindAssets("t:Texture2D", new[] { framesDarkPath }); frames = new Texture2D[guids.Length]; for (int i = 0; i < guids.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(guids[i]); frames[i] = AssetDatabase.LoadAssetAtPath(path); } } private void LoadLightFrames() { var guids = AssetDatabase.FindAssets("t:Texture2D", new[] { framesLightPath }); frames_Light = new Texture2D[guids.Length]; for (int i = 0; i < guids.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(guids[i]); frames_Light[i] = AssetDatabase.LoadAssetAtPath(path); } } private void ParseETSJsonData(string json) { var settings = new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Ignore }; if (json != null) { var jsonData = JsonConvert.DeserializeObject(json, settings); _latestETSVersion = jsonData.distTags.latest; } } private void UpdateWindowTitle() { string title = $"{GetLocalizedString("VersionManager_WindowTitle")} ({_currentPage + 1}/{TOTAL_PAGES})"; titleContent = new GUIContent(title); } private void OnGUI() { switch (_currentPage) { case 0: DrawVersionSelectionPage(); break; case 1: DrawProgressBarPage(); break; case 2: DrawCompletionPage(); break; default: GUILayout.Label($"Page {_currentPage}"); GUILayout.FlexibleSpace(); break; } using (new EditorGUILayout.HorizontalScope(GUILayout.Height(30), GUILayout.ExpandWidth(true))) { DrawBottomBarLogo(); GUILayout.FlexibleSpace(); DrawBottomBarPageButton(); } } private void DrawCompletionPage() { GUILayout.Space(25); using (new EditorGUILayout.HorizontalScope()) { GUILayout.Space(25); using (new EditorGUILayout.VerticalScope()) { Label.Title(GetLocalizedString("VersionManager_CompletedTitle")); Label.Header1(GetLocalizedString("VersionManager_CompletedText1")); Label.WrappedText(GetLocalizedString("VersionManager_CompletedText2")); DrawVersionTopImage(); DrawLearningResourcesButtons(); } GUILayout.Space(25); } GUILayout.FlexibleSpace(); } private void DrawVersionTopImage() { using (new EditorGUILayout.HorizontalScope()) { GUILayout.FlexibleSpace(); EditorGUILayout.LabelField(new GUIContent(_versionImage), GUILayout.Height(180), GUILayout.Width(500)); GUILayout.FlexibleSpace(); } } public void DrawLearningResourcesButtons() { using (new EditorGUILayout.HorizontalScope()) { if (GUILayout.Button(manualbutton)) { // バージョン、言語とマッチしたドキュメントを返す場合 var packageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssembly(System.Reflection.Assembly.Load("HIKKY.VketCloudSDK")); var currentVersion = GetSubstringUntilFirstPeriod(packageInfo.version); if (_currentLanguage == Language.English) { Application.OpenURL(manualURL + currentVersion + "/"); } else if (_currentLanguage == Language.Japanese) { Application.OpenURL(manualURL + currentVersion + "/" + "ja"); } } if (GUILayout.Button(discordButton)) { Application.OpenURL(discordURL); } } } private static string GetSubstringUntilFirstPeriod(string input) { int indexOfFirstPeriod = input.IndexOf('.'); if (indexOfFirstPeriod >= 0) { int indexOfSecondPeriod = input.IndexOf('.', indexOfFirstPeriod + 1); if (indexOfSecondPeriod >= 0) { return input.Substring(0, indexOfSecondPeriod); } else { return input; } } else { return input; } } private void DrawBottomBarLogo() { using (new EditorGUILayout.VerticalScope(GUILayout.Height(30), GUILayout.Width(81), GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false))) { GUILayout.FlexibleSpace(); using (new EditorGUILayout.HorizontalScope(GUILayout.Height(18), GUILayout.Width(81), GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false))) { if (EditorGUIUtility.isProSkin) { EditorGUILayout.LabelField(new GUIContent(_logoImage), GUILayout.Height(18), GUILayout.Width(81)); } else { EditorGUILayout.LabelField(new GUIContent(_logoLightImage), GUILayout.Height(18), GUILayout.Width(81)); } GUILayout.Label("©HIKKY All rights reserved."); } GUILayout.FlexibleSpace(); } } private void DrawBottomBarPageButton() { using (new EditorGUILayout.VerticalScope(GUILayout.Height(30), GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false))) { GUILayout.FlexibleSpace(); using (new EditorGUILayout.HorizontalScope(GUILayout.Height(25), GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(false))) { if (_currentPage != 1) // Check if it's not the fifth page { if (_currentPage > 0) { if (_currentPage != 2) { // Back button GUI.enabled = _currentPage > 0; if (GUILayout.Button(GetLocalizedString("Page_Back"), GUILayout.Width(_buttonWidth), GUILayout.Height(25))) { _currentPage--; UpdateWindowTitle(); } } } // Next button GUI.enabled = _currentPage < TOTAL_PAGES + 1; if (_currentPage == 0) { _nextString = GetLocalizedString("VersionManager_Install"); } else if (_currentPage == 2) { _nextString = GetLocalizedString("VersionSelectionPage_Completion"); } else { _nextString = GetLocalizedString("Page_Next"); } if (GUILayout.Button(_nextString, GUILayout.Width(_buttonWidth), GUILayout.Height(25))) { if (_currentPage == 2) { this.Close(); } else { _currentPage++; UpdateWindowTitle(); } } GUI.enabled = true; } } GUILayout.FlexibleSpace(); } } private void DrawVersionSelectionPage() { GUILayout.Space(25); using (new EditorGUILayout.HorizontalScope()) { GUILayout.Space(25); // Left Box - Stable Version using (new EditorGUILayout.VerticalScope()) { using (new EditorGUILayout.HorizontalScope()) { Label.Title(GetLocalizedString("VersionSelectionPage_Title"), GUILayout.Height(30), GUILayout.Width(220)); GUILayout.FlexibleSpace(); int newSelectedLanguageIndex = EditorGUILayout.Popup("Language/言語", _selectedLanguageIndex, _languageOptions, GUILayout.Width(220)); if (newSelectedLanguageIndex != _selectedLanguageIndex) { _selectedLanguageIndex = newSelectedLanguageIndex; LanguageSetting.SetLanguage((LanguageSetting.Language)_selectedLanguageIndex); _currentLanguage = LanguageSetting.GetLanguage(); _localizationManager.LoadLanguage(_currentLanguage); UpdateWindowTitle(); if (_currentLanguage == Language.Japanese) { _initialTopImage = AssetDatabase.LoadAssetAtPath(PathManager.GetWizardTopImageJa); } } } using (new EditorGUILayout.HorizontalScope()) { using (new EditorGUILayout.VerticalScope(GUILayout.Width(285), GUILayout.Height(260))) { using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox, GUILayout.Width(285), GUILayout.Height(117f))) { Label.Header1(GetLocalizedString("StableVersion")); Label.TextArea(GetLocalizedString("StableSupport")); Label.TextArea(GetLocalizedString("StableUser")); GUILayout.FlexibleSpace(); bool stableToggle = EditorGUILayout.ToggleLeft(_stableVersion, _selectedVersion == _stableVersion); if (stableToggle && _selectedVersion != _stableVersion) { _selectedVersion = _stableVersion; } GUILayout.FlexibleSpace(); } GUILayout.FlexibleSpace(); using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox, GUILayout.Width(285), GUILayout.Height(117f))) { Label.Header1(GetLocalizedString("LatetstVersion")); Label.TextArea(GetLocalizedString("LatetstTextOne")); Label.TextArea(GetLocalizedString("LatetstTextTwo")); GUILayout.FlexibleSpace(); bool stableToggle = EditorGUILayout.ToggleLeft(_latestVersion, _selectedVersion == _latestVersion); if (stableToggle && _selectedVersion != _latestVersion) { _selectedVersion = _latestVersion; } GUILayout.FlexibleSpace(); } } GUILayout.FlexibleSpace(); // Right Box - Version Archive using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox, GUILayout.Width(285), GUILayout.Height(260))) { Label.Header1(GetLocalizedString("VersionArchive")); Label.TextArea(GetLocalizedString("VersionArchiveTextOne")); Label.TextArea(GetLocalizedString("VersionArchiveTextTwo")); GUILayout.FlexibleSpace(); _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, GUILayout.Height(150)); foreach (var version in _archivedVersions) { bool versionToggle = EditorGUILayout.ToggleLeft(version, _selectedVersion == version); if (versionToggle && _selectedVersion != version) { _selectedVersion = version; } } EditorGUILayout.EndScrollView(); } } } GUILayout.Space(25); } GUILayout.FlexibleSpace(); } private void AddPackages() { var res = Client.Add("com.unity.editorcoroutines"); while (!res.IsCompleted) { } AddScopedRegistry(new ScopedRegistry { name = "VketCloudSDK", url = "https://registry.npmjs.org", scopes = new string[] { "com.hikky.vketcloudsdk" } }, "com.hikky.vketcloudsdk", _selectedVersion); // Deeplink AddScopedRegistry(new ScopedRegistry { name = "Deeplink", url = "https://package.openupm.com", scopes = new string[] { "com.needle.deeplink" } }, "com.needle.deeplink", "1.2.1"); AddSymbol("DEEPLINK"); string etsVersion = string.IsNullOrEmpty(_latestETSVersion) ? "1.0.1" : _latestETSVersion; // EditorTutorialSystem AddScopedRegistry(new ScopedRegistry { name = "EditorTutorialSystem", url = "https://registry.npmjs.org", scopes = new string[] { "com.hikky.editortutorialsystem" } }, "com.hikky.editortutorialsystem", etsVersion); AddSymbol("EDITORTUTORIALSYSTEM"); SetPackageVersion("com.hikky.vketcloudsdk", _selectedVersion); CompilationPipeline.RequestScriptCompilation(); PlayerPrefs.SetString(SELECTED_VERSION, _selectedVersion); PlayerPrefs.Save(); } public static void AddSymbol(string name) { BuildTargetGroup targetGroup = EditorUserBuildSettings.selectedBuildTargetGroup; string settingSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup); if (Array.Find(settingSymbols.Split(';'), n => n == name) != null) return; settingSymbols += $";{name}"; PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, settingSymbols); } private void DrawProgressBarPage() { // Update progress if (_progressForward) { _progress += _progressSpeed; if (_progress >= 1f) { _progress = 1f; _progressForward = false; } } else { _progress -= _progressSpeed; if (_progress <= 0f) { _progress = 0f; _progressForward = true; } } GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal(); // Begin horizontal grouping GUILayout.FlexibleSpace(); // Centers the progress bar horizontally if (frames != null && frames.Length > 0) { if (EditorGUIUtility.isProSkin) { GUILayout.Label(frames[currentFrame], GUILayout.Width(200), GUILayout.Height(200)); } else { GUILayout.Label(frames_Light[currentFrame], GUILayout.Width(200), GUILayout.Height(200)); } } if (Time.realtimeSinceStartup - lastFrameTime >= 1.0f / frameRate) { currentFrame = (currentFrame + 1) % frames.Length; // Loop back to the first frame after the last lastFrameTime = Time.realtimeSinceStartup; Repaint(); } GUILayout.FlexibleSpace(); // Ends centering horizontally GUILayout.EndHorizontal(); // End horizontal grouping GUILayout.FlexibleSpace(); AddPackages(); } private static string GetLocalizedString(string key) { if (_localizationManager != null) { return _localizationManager.GetString(key); } return key; } public static string GetLightmapEncoding(BuildTargetGroup platformGroup) { var getLightmapEncodingMethod = typeof(PlayerSettings).GetMethod("GetLightmapEncodingQualityForPlatformGroup", BindingFlags.Static | BindingFlags.NonPublic); if (getLightmapEncodingMethod != null) { var result = getLightmapEncodingMethod.Invoke(null, new object[] { platformGroup }); if (result != null) { return result.ToString(); } } return string.Empty; } public static IEnumerator StartRequest(string url, Action success = null) { using (www = UnityWebRequest.Get(url)) { #if UNITY_2017_2_OR_NEWER yield return www.SendWebRequest(); #else yield return www.Send(); #endif while (www.isDone == false) yield return null; if (success != null) success(); } } public static void StartBackgroundTask(IEnumerator update, Action end = null) { EditorApplication.CallbackFunction closureCallback = null; closureCallback = () => { try { if (update.MoveNext() == false) { if (end != null) end(); EditorApplication.update -= closureCallback; } } catch (Exception ex) { if (end != null) end(); UnityEngine.Debug.LogException(ex); EditorApplication.update -= closureCallback; } }; EditorApplication.update += closureCallback; } private void ParseJsonData(string json) { var settings = new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Ignore }; if (json != null) { var jsonData = JsonConvert.DeserializeObject(json, settings); _stableVersion = jsonData.distTags.stable; _latestVersion = jsonData.distTags.latest; _archivedVersions = jsonData.versions .Where(v => string.IsNullOrEmpty(v.Value.deprecated)) .Select(v => v.Key) .ToList(); FilterMaxPatchVersions(); _archivedVersions.Remove(_stableVersion); _archivedVersions.Remove(_latestVersion); SortVersionsDescending(); _selectedVersion = _stableVersion; } } private void SortVersionsDescending() { _archivedVersions = _archivedVersions.OrderByDescending(v => { var versionParts = v.Split('.'); int major = int.Parse(versionParts[0]); int minor = int.Parse(versionParts[1]); int patch = versionParts.Length > 2 ? int.Parse(versionParts[2]) : 0; return (major, minor, patch); }).ToList(); } private void FilterMaxPatchVersions() { var maxPatchVersions = new Dictionary<(int Major, int Minor), int>(); foreach (var version in _archivedVersions) { var versionParts = version.Split('.'); int major = int.Parse(versionParts[0]); int minor = int.Parse(versionParts[1]); int patch = versionParts.Length > 2 ? int.Parse(versionParts[2]) : 0; var key = (Major: major, Minor: minor); if (maxPatchVersions.TryGetValue(key, out var existingMaxPatch) && patch > existingMaxPatch) { maxPatchVersions[key] = patch; } else { maxPatchVersions[key] = patch; } } _archivedVersions = maxPatchVersions.Select(kvp => $"{kvp.Key.Major}.{kvp.Key.Minor}.{kvp.Value}").ToList(); } } }