925 lines
No EOL
37 KiB
C#
925 lines
No EOL
37 KiB
C#
using UnityEngine;
|
||
using UnityEditor;
|
||
using UnityEditor.PackageManager;
|
||
using UnityEditor.PackageManager.Requests;
|
||
using UnityEngine.Networking;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System;
|
||
using System.Linq;
|
||
using ShiroginSDK.Runtime.Core.SDK;
|
||
using ShiroginSDK.Editor.Core;
|
||
|
||
namespace ShiroginSDK.Editor.Bitbucket
|
||
{
|
||
// --- DATA STRUCTURES ---
|
||
[Serializable]
|
||
public class VersionData
|
||
{
|
||
public string version;
|
||
public string packageName; // NEW: Specific ID for this version (e.g., shirogin.sdk.appsflyer.6.17.72)
|
||
public string url;
|
||
public string docsWebUrl;
|
||
public string docsDownloadUrl;
|
||
public string releaseNotes;
|
||
public string fileSize;
|
||
public bool isExternal;
|
||
public bool isUpm;
|
||
public string upmId;
|
||
}
|
||
|
||
[Serializable]
|
||
public class PackageData
|
||
{
|
||
public string uniqueId;
|
||
public string displayName;
|
||
public string category;
|
||
public VersionData[] versions;
|
||
}
|
||
|
||
[Serializable]
|
||
public class PackageManifest
|
||
{
|
||
public PackageData[] packages;
|
||
}
|
||
|
||
// --- CONFIG EDITOR ---
|
||
[CustomEditor(typeof(ShiroginConfig))]
|
||
public class ShiroginConfigEditor : UnityEditor.Editor
|
||
{
|
||
public override void OnInspectorGUI()
|
||
{
|
||
base.OnInspectorGUI();
|
||
GUILayout.Space(20);
|
||
GUILayout.Label("SDK Compilation Control", EditorStyles.boldLabel);
|
||
|
||
GUI.backgroundColor = new Color(0.2f, 0.8f, 0.2f);
|
||
if (GUILayout.Button("✅ Apply Changes & Compile", GUILayout.Height(40)))
|
||
{
|
||
bool confirm = EditorUtility.DisplayDialog("Apply SDK Defines?",
|
||
"This will trigger a script recompilation.\nEnsure required packages are installed.",
|
||
"Yes, Compile", "Cancel");
|
||
|
||
if (confirm) ShiroginDefinesManager.UpdateDefines();
|
||
}
|
||
GUI.backgroundColor = Color.white;
|
||
|
||
GUILayout.Space(10);
|
||
|
||
GUI.backgroundColor = new Color(0.2f, 0.6f, 1f);
|
||
if (GUILayout.Button("OPEN ASSET MANAGER", GUILayout.Height(40)))
|
||
{
|
||
AssetRegistryEditor.ShowWindow();
|
||
}
|
||
GUI.backgroundColor = Color.white;
|
||
}
|
||
}
|
||
|
||
// --- EDITOR WINDOW ---
|
||
[InitializeOnLoad]
|
||
public class AssetRegistryEditor : EditorWindow
|
||
{
|
||
private ShiroginConfig _config;
|
||
|
||
private static AddRequest _upmAddRequest;
|
||
private static bool _isInstallingUpm;
|
||
|
||
// Essential Packages (Uses EXACT packageName from VersionData)
|
||
private readonly List<string> _essentialPackages = new List<string>
|
||
{
|
||
"shirogin.sdk.googleexternaldependencymanager.1.2.186.Shirogin",
|
||
"shirogin.sdk.dotweenpro.1.0.380.Shirogin",
|
||
"com.unity.purchasing.4.13.0",
|
||
"shirogin.sdk.applovinmax.8.5.1.Shirogin",
|
||
"shirogin.sdk.firebaseanalytics.13.6.0.Shirogin",
|
||
"shirogin.sdk.appsflyer.6.17.72.Shirogin",
|
||
"shirogin.sdk.facebooksdk.18.0.0.Shirogin",
|
||
"shirogin.sdk.firebaseremoteconfig.13.6.0.Shirogin"
|
||
};
|
||
|
||
private readonly List<string> _rootPackages = new List<string>
|
||
{
|
||
"Firebase", "Facebook", "AppLovin", "AppsFlyer", "External"
|
||
};
|
||
|
||
private Queue<PackageData> _downloadQueue = new Queue<PackageData>();
|
||
private PackageData _currentQueueItem;
|
||
private VersionData _currentQueueVersion;
|
||
private bool _isQueueRunning = false;
|
||
|
||
private List<PackageData> allPackages = new List<PackageData>();
|
||
private List<PackageData> filteredPackages = new List<PackageData>();
|
||
private HashSet<string> existingFolderNames = new HashSet<string>();
|
||
|
||
private bool _isSetupMode = false;
|
||
private string searchString = "";
|
||
private string selectedCategory = "All";
|
||
private string[] categories = new string[] { "All" };
|
||
private Vector2 scrollPos;
|
||
private bool showSettings = false;
|
||
|
||
private string jsonListUrl = "";
|
||
private string repoToken = "";
|
||
private Dictionary<string, int> packageVersionSelection = new Dictionary<string, int>();
|
||
|
||
private bool isWorking = false;
|
||
private string statusMessage = "Waiting for download...";
|
||
private float downloadProgress = 0f;
|
||
|
||
private EditorApplication.CallbackFunction downloadDelegate;
|
||
private UnityWebRequest currentRequest;
|
||
|
||
static AssetRegistryEditor()
|
||
{
|
||
EditorApplication.delayCall += CheckFirstTimeInstall;
|
||
EditorApplication.update += UpmProgressUpdate;
|
||
}
|
||
|
||
private static void CheckFirstTimeInstall()
|
||
{
|
||
if (!EditorPrefs.GetBool("ShiroginSDK_WelcomeShown_V2", false))
|
||
{
|
||
EditorPrefs.SetBool("ShiroginSDK_WelcomeShown_V2", true);
|
||
ShowWindow(true);
|
||
}
|
||
}
|
||
|
||
private static void UpmProgressUpdate()
|
||
{
|
||
if (_isInstallingUpm && _upmAddRequest != null)
|
||
{
|
||
if (_upmAddRequest.IsCompleted)
|
||
{
|
||
_isInstallingUpm = false;
|
||
var wnd = GetWindow<AssetRegistryEditor>();
|
||
|
||
if (_upmAddRequest.Status == StatusCode.Success)
|
||
{
|
||
Debug.Log($"[ShiroginSDK] UPM Package Installed: {_upmAddRequest.Result.packageId}");
|
||
if(wnd) wnd.RefreshFolderCache();
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError($"[ShiroginSDK] UPM Install Failed: {_upmAddRequest.Error.message}");
|
||
}
|
||
|
||
if(wnd)
|
||
{
|
||
wnd.ProcessNextQueueItem();
|
||
wnd.Repaint();
|
||
}
|
||
_upmAddRequest = null;
|
||
}
|
||
}
|
||
}
|
||
|
||
[MenuItem("ShiroginSDK/Shirogin Asset Manager")]
|
||
public static void ShowWindow() => ShowWindow(false);
|
||
|
||
public static void ShowWindow(bool forceSetupMode)
|
||
{
|
||
AssetRegistryEditor wnd = GetWindow<AssetRegistryEditor>("Asset Manager");
|
||
wnd.minSize = new Vector2(650, 750);
|
||
if (forceSetupMode) wnd.SetSetupMode(true);
|
||
wnd.Show();
|
||
}
|
||
|
||
public void SetSetupMode(bool active)
|
||
{
|
||
_isSetupMode = active;
|
||
ApplyFilters();
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
_config = ShiroginConfig.Load();
|
||
jsonListUrl = EditorPrefs.GetString("Shirogin_RepoUrl", "https://api.bitbucket.org/2.0/repositories/batud/studio-asset-registry/src/main/packages.json");
|
||
repoToken = EditorPrefs.GetString("Shirogin_RepoToken", _config != null ? _config.bitbucketAccessToken : "");
|
||
|
||
RefreshFolderCache();
|
||
|
||
if (!string.IsNullOrEmpty(jsonListUrl) && !string.IsNullOrEmpty(repoToken))
|
||
FetchPackageList();
|
||
else
|
||
showSettings = true;
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
AbortDownload();
|
||
_downloadQueue.Clear();
|
||
_isQueueRunning = false;
|
||
}
|
||
|
||
private void OnFocus() => RefreshFolderCache();
|
||
|
||
private void RefreshFolderCache()
|
||
{
|
||
existingFolderNames.Clear();
|
||
string internalSdkPath = Path.Combine(Application.dataPath, "ShiroginSDK", "ThirdPartySDKs");
|
||
if (Directory.Exists(internalSdkPath))
|
||
{
|
||
try
|
||
{
|
||
string[] dirs = Directory.GetDirectories(internalSdkPath, "*", SearchOption.AllDirectories);
|
||
foreach (var d in dirs) existingFolderNames.Add(new DirectoryInfo(d).Name.ToLower());
|
||
} catch {}
|
||
}
|
||
try
|
||
{
|
||
string[] rootDirs = Directory.GetDirectories(Application.dataPath, "*", SearchOption.TopDirectoryOnly);
|
||
foreach (var d in rootDirs) existingFolderNames.Add(new DirectoryInfo(d).Name.ToLower());
|
||
} catch {}
|
||
}
|
||
|
||
// --- GUI ---
|
||
private void OnGUI()
|
||
{
|
||
EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height), new Color(0.22f, 0.22f, 0.22f));
|
||
DrawModernHeader();
|
||
GUILayout.BeginVertical();
|
||
|
||
if (_isSetupMode) DrawSetupWizardUI();
|
||
else
|
||
{
|
||
DrawToolbar();
|
||
if (showSettings) DrawSettings();
|
||
GUILayout.Space(5);
|
||
DrawCategories();
|
||
GUILayout.Space(5);
|
||
DrawPackageList();
|
||
}
|
||
GUILayout.EndVertical();
|
||
GUILayout.FlexibleSpace();
|
||
DrawStaticStatusBar();
|
||
}
|
||
|
||
private void DrawModernHeader()
|
||
{
|
||
Rect headerRect = new Rect(0, 0, position.width, 60);
|
||
Color headerColor = _isSetupMode ? new Color(0.1f, 0.3f, 0.5f) : new Color(0.15f, 0.15f, 0.15f);
|
||
EditorGUI.DrawRect(headerRect, headerColor);
|
||
|
||
GUILayout.BeginArea(headerRect);
|
||
GUILayout.BeginVertical();
|
||
GUILayout.FlexibleSpace();
|
||
|
||
GUIStyle titleStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 18, normal = { textColor = new Color(0.95f, 0.95f, 0.95f) }, alignment = TextAnchor.MiddleCenter };
|
||
GUIStyle subStyle = new GUIStyle(EditorStyles.label) { fontSize = 11, normal = { textColor = new Color(0.8f, 0.8f, 0.8f) }, alignment = TextAnchor.MiddleCenter };
|
||
|
||
string title = _isSetupMode ? "WELCOME TO SHIROGIN SDK" : "SHIROGIN ASSET MANAGER";
|
||
string sub = _isSetupMode ? "Setup Wizard & Essential Packages" : "Package Management System";
|
||
|
||
GUILayout.Label(title, titleStyle);
|
||
GUILayout.Label(sub, subStyle);
|
||
GUILayout.FlexibleSpace();
|
||
GUILayout.EndVertical();
|
||
GUILayout.EndArea();
|
||
GUILayout.Space(65);
|
||
}
|
||
|
||
private void DrawSetupWizardUI()
|
||
{
|
||
GUILayout.Space(10);
|
||
|
||
// --- CORE MISSING CHECK ---
|
||
int missingCount = 0;
|
||
if(filteredPackages != null)
|
||
{
|
||
foreach(var p in filteredPackages)
|
||
{
|
||
// Find the REQUIRED version data
|
||
VersionData requiredVer = p.versions.FirstOrDefault(v => _essentialPackages.Contains(v.packageName));
|
||
if(requiredVer != null && !IsPackageInstalled(p, requiredVer))
|
||
missingCount++;
|
||
}
|
||
}
|
||
|
||
if (missingCount > 0)
|
||
{
|
||
GUI.backgroundColor = new Color(1f, 0.6f, 0.6f);
|
||
EditorGUILayout.HelpBox($"⚠ SDK CORE MISSING ({missingCount} packages). Please install essential packages below.", MessageType.Error);
|
||
GUI.backgroundColor = Color.white;
|
||
}
|
||
else
|
||
{
|
||
GUI.backgroundColor = Color.green;
|
||
EditorGUILayout.HelpBox("✅ SDK Core is fully installed and ready!", MessageType.Info);
|
||
GUI.backgroundColor = Color.white;
|
||
}
|
||
|
||
if (string.IsNullOrEmpty(repoToken))
|
||
{
|
||
if(GUILayout.Button("Open Settings to Enter Token")) showSettings = !showSettings;
|
||
if(showSettings) DrawSettings();
|
||
}
|
||
|
||
GUILayout.Space(10);
|
||
GUILayout.BeginHorizontal();
|
||
GUILayout.FlexibleSpace();
|
||
|
||
bool canDownloadAll = !isWorking && !_isInstallingUpm && missingCount > 0;
|
||
EditorGUI.BeginDisabledGroup(!canDownloadAll);
|
||
|
||
GUI.backgroundColor = missingCount > 0 ? new Color(0.2f, 0.6f, 1f) : Color.gray;
|
||
string btnLabel = missingCount > 0 ? $"⬇ Download & Install All Core ({missingCount})" : "All Core Installed ✓";
|
||
|
||
if (GUILayout.Button(btnLabel, GUILayout.Height(35), GUILayout.Width(300)))
|
||
{
|
||
StartDownloadAllQueue();
|
||
}
|
||
GUI.backgroundColor = Color.white;
|
||
|
||
EditorGUI.EndDisabledGroup();
|
||
GUILayout.FlexibleSpace();
|
||
GUILayout.EndHorizontal();
|
||
|
||
GUILayout.Space(10);
|
||
DrawPackageList();
|
||
GUILayout.Space(15);
|
||
|
||
GUILayout.BeginHorizontal();
|
||
GUILayout.FlexibleSpace();
|
||
if (GUILayout.Button("Continue to Full Dashboard ➔", GUILayout.Height(40), GUILayout.Width(250))) SetSetupMode(false);
|
||
GUILayout.FlexibleSpace();
|
||
GUILayout.EndHorizontal();
|
||
}
|
||
|
||
private void DrawToolbar()
|
||
{
|
||
GUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||
if (GUILayout.Button("⚙ Settings", EditorStyles.toolbarButton, GUILayout.Width(80))) showSettings = !showSettings;
|
||
if (GUILayout.Button("★ Setup Wizard", EditorStyles.toolbarButton, GUILayout.Width(100))) SetSetupMode(true);
|
||
if (GUILayout.Button("Refresh", EditorStyles.toolbarButton, GUILayout.Width(60))) { RefreshFolderCache(); FetchPackageList(); }
|
||
if (GUILayout.Button("Clear Cache", EditorStyles.toolbarButton, GUILayout.Width(80))) { ClearCache(); Repaint(); }
|
||
GUILayout.FlexibleSpace();
|
||
GUILayout.Label("Search:", GUILayout.Width(50));
|
||
string newSearch = EditorGUILayout.TextField(searchString, EditorStyles.toolbarTextField, GUILayout.Width(150));
|
||
if (newSearch != searchString) { searchString = newSearch; ApplyFilters(); }
|
||
if (GUILayout.Button("×", EditorStyles.toolbarButton, GUILayout.Width(25))) { searchString = ""; GUI.FocusControl(null); ApplyFilters(); }
|
||
GUILayout.EndHorizontal();
|
||
}
|
||
|
||
private void DrawCategories()
|
||
{
|
||
if (categories == null || categories.Length == 0) return;
|
||
GUILayout.BeginHorizontal();
|
||
GUILayout.Space(10);
|
||
foreach (var cat in categories)
|
||
{
|
||
bool isSelected = selectedCategory == cat;
|
||
GUIStyle btnStyle = new GUIStyle(EditorStyles.miniButton);
|
||
if (isSelected) GUI.backgroundColor = new Color(0.3f, 0.6f, 1f);
|
||
else if(cat.Contains("Core")) GUI.backgroundColor = new Color(1f, 0.8f, 0.8f);
|
||
|
||
if (GUILayout.Button(cat, btnStyle, GUILayout.MinWidth(80)))
|
||
{
|
||
selectedCategory = cat;
|
||
searchString = "";
|
||
GUI.FocusControl(null);
|
||
ApplyFilters();
|
||
}
|
||
GUI.backgroundColor = Color.white;
|
||
}
|
||
GUILayout.FlexibleSpace();
|
||
GUILayout.EndHorizontal();
|
||
}
|
||
|
||
private void DrawSettings()
|
||
{
|
||
GUILayout.BeginVertical(EditorStyles.helpBox);
|
||
GUILayout.Label("Connection Settings", EditorStyles.boldLabel);
|
||
EditorGUI.BeginChangeCheck();
|
||
jsonListUrl = EditorGUILayout.TextField("JSON List URL", jsonListUrl);
|
||
repoToken = EditorGUILayout.PasswordField("Access Token", repoToken);
|
||
if (EditorGUI.EndChangeCheck())
|
||
{
|
||
EditorPrefs.SetString("Shirogin_RepoUrl", jsonListUrl);
|
||
EditorPrefs.SetString("Shirogin_RepoToken", repoToken);
|
||
}
|
||
if (GUILayout.Button("Save Token to Config File"))
|
||
{
|
||
if (_config == null) _config = ShiroginConfig.Load();
|
||
if (_config != null)
|
||
{
|
||
_config.bitbucketAccessToken = repoToken;
|
||
EditorUtility.SetDirty(_config); AssetDatabase.SaveAssets();
|
||
}
|
||
}
|
||
GUILayout.EndVertical();
|
||
}
|
||
|
||
private void DrawStaticStatusBar()
|
||
{
|
||
Rect bar = GUILayoutUtility.GetRect(position.width, 30);
|
||
EditorGUI.DrawRect(bar, new Color(0.1f, 0.2f, 0.1f));
|
||
|
||
if (_isQueueRunning)
|
||
{
|
||
EditorGUI.DrawRect(bar, new Color(0.5f, 0.2f, 0.8f));
|
||
string qText = _currentQueueItem != null ? $"Batch Installing: {_currentQueueItem.displayName} ({_downloadQueue.Count} left)" : "Batch Processing...";
|
||
GUI.Label(bar, qText, new GUIStyle(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleCenter, normal = { textColor = Color.white } });
|
||
}
|
||
else if (_isInstallingUpm)
|
||
{
|
||
EditorGUI.DrawRect(bar, new Color(0.2f, 0.4f, 0.8f));
|
||
GUI.Label(bar, "Installing Package via Unity Package Manager...", new GUIStyle(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleCenter, normal = { textColor = Color.white } });
|
||
}
|
||
else if (isWorking && downloadProgress > 0)
|
||
{
|
||
float w = bar.width * downloadProgress;
|
||
EditorGUI.DrawRect(new Rect(bar.x, bar.y, w, bar.height), new Color(0.2f, 0.8f, 0.2f));
|
||
GUI.Label(bar, $"{statusMessage} {(downloadProgress * 100):F0}%", new GUIStyle(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleCenter, normal = { textColor = Color.white } });
|
||
}
|
||
else
|
||
{
|
||
GUI.Label(bar, "Ready", new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleCenter, normal = { textColor = Color.gray } });
|
||
}
|
||
|
||
if (isWorking || _isQueueRunning)
|
||
{
|
||
Rect btnRect = new Rect(bar.width - 85, bar.y + 2, 80, 26);
|
||
GUI.backgroundColor = new Color(0.9f, 0.3f, 0.3f);
|
||
if (GUI.Button(btnRect, "CANCEL"))
|
||
{
|
||
AbortDownload();
|
||
_downloadQueue.Clear();
|
||
_isQueueRunning = false;
|
||
}
|
||
GUI.backgroundColor = Color.white;
|
||
}
|
||
}
|
||
|
||
private void DrawPackageList()
|
||
{
|
||
if (filteredPackages == null || filteredPackages.Count == 0)
|
||
{
|
||
GUILayout.Label("No packages found.", EditorStyles.centeredGreyMiniLabel);
|
||
return;
|
||
}
|
||
scrollPos = GUILayout.BeginScrollView(scrollPos);
|
||
foreach (var pkg in filteredPackages) DrawPackageItem(pkg);
|
||
GUILayout.EndScrollView();
|
||
}
|
||
|
||
private void DrawPackageItem(PackageData pkg)
|
||
{
|
||
if (pkg.versions == null || pkg.versions.Length == 0) return;
|
||
|
||
// SETUP MODE LOGIC: Force specific version
|
||
int selectedIndex = 0;
|
||
bool forceVersion = false;
|
||
|
||
if (_isSetupMode)
|
||
{
|
||
for (int i = 0; i < pkg.versions.Length; i++)
|
||
{
|
||
if (_essentialPackages.Contains(pkg.versions[i].packageName))
|
||
{
|
||
selectedIndex = i;
|
||
forceVersion = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!packageVersionSelection.ContainsKey(pkg.uniqueId)) packageVersionSelection[pkg.uniqueId] = 0;
|
||
selectedIndex = packageVersionSelection[pkg.uniqueId];
|
||
if (selectedIndex >= pkg.versions.Length) selectedIndex = 0;
|
||
}
|
||
|
||
VersionData vData = pkg.versions[selectedIndex];
|
||
|
||
// Status Logic
|
||
bool isInstalled = IsPackageInstalled(pkg, vData);
|
||
string installedVer = EditorPrefs.GetString("RepoManager_Version_" + pkg.uniqueId, "");
|
||
bool isVersionMatch = isInstalled && (installedVer == vData.version);
|
||
|
||
// UPM Hack: Assume version match if folder exists because checking UPM version is slow
|
||
if (vData.isUpm && isInstalled) isVersionMatch = true;
|
||
|
||
string cachePath = Path.Combine(Application.temporaryCachePath, $"{pkg.uniqueId}_{vData.version}.unitypackage");
|
||
bool isCached = !vData.isUpm && File.Exists(cachePath);
|
||
|
||
// COLOR LOGIC
|
||
Color boxColor = Color.gray;
|
||
if (isInstalled)
|
||
{
|
||
if (isVersionMatch) boxColor = new Color(0.2f, 0.6f, 0.2f); // Green (Correct Version)
|
||
else boxColor = new Color(0.2f, 0.5f, 0.9f); // Blue (Wrong Version)
|
||
}
|
||
else if (isCached)
|
||
{
|
||
boxColor = new Color(0.2f, 0.8f, 0.8f); // Cyan (Cached)
|
||
}
|
||
else if (_isSetupMode)
|
||
{
|
||
boxColor = new Color(0.8f, 0.3f, 0.3f); // Red (Missing in Setup)
|
||
}
|
||
else
|
||
{
|
||
boxColor = new Color(0.3f, 0.3f, 0.3f); // Gray (Missing)
|
||
}
|
||
|
||
GUI.backgroundColor = boxColor;
|
||
GUILayout.BeginVertical(EditorStyles.helpBox);
|
||
GUI.backgroundColor = Color.white;
|
||
|
||
GUILayout.BeginHorizontal();
|
||
|
||
string icon = vData.isUpm ? "📦" : (vData.isExternal ? "🌍" : "📦");
|
||
GUIStyle labelStyle = new GUIStyle(EditorStyles.boldLabel);
|
||
labelStyle.normal.textColor = Color.white;
|
||
GUILayout.Label(new GUIContent($" {pkg.displayName}", icon), labelStyle, GUILayout.Width(200));
|
||
|
||
// Version Selection
|
||
if (forceVersion)
|
||
{
|
||
GUIStyle staticVerStyle = new GUIStyle(EditorStyles.label);
|
||
staticVerStyle.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
|
||
GUILayout.Label($"v{vData.version} (Required)", staticVerStyle, GUILayout.Width(200));
|
||
}
|
||
else
|
||
{
|
||
string[] options = pkg.versions.Select(v => v.version).ToArray();
|
||
int newIndex = EditorGUILayout.Popup(selectedIndex, options, GUILayout.Width(80));
|
||
if (newIndex != selectedIndex) packageVersionSelection[pkg.uniqueId] = newIndex;
|
||
}
|
||
|
||
// Docs
|
||
if (!string.IsNullOrEmpty(vData.docsWebUrl))
|
||
{
|
||
if (GUILayout.Button("🌐", EditorStyles.miniButton, GUILayout.Width(30)))
|
||
Application.OpenURL(vData.docsWebUrl);
|
||
}
|
||
if (!string.IsNullOrEmpty(vData.docsDownloadUrl))
|
||
{
|
||
if (GUILayout.Button("⬇", EditorStyles.miniButton, GUILayout.Width(30)))
|
||
StartDownloadDocs(vData.docsDownloadUrl, pkg.category, pkg.displayName, vData.version);
|
||
}
|
||
|
||
GUILayout.FlexibleSpace();
|
||
|
||
// Status Label
|
||
GUIStyle statusStyle = new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleRight, normal = { textColor = Color.white } };
|
||
if (isInstalled)
|
||
{
|
||
string statusText = isVersionMatch ? "✔ Installed" : $"⚠ v{installedVer}";
|
||
GUILayout.Label(statusText, statusStyle, GUILayout.Width(80));
|
||
}
|
||
else if (isCached)
|
||
{
|
||
GUILayout.Label("⬇ Cached", statusStyle, GUILayout.Width(80));
|
||
}
|
||
|
||
// ACTION BUTTON
|
||
EditorGUI.BeginDisabledGroup(isWorking || _isInstallingUpm);
|
||
|
||
string btnText = "Install";
|
||
if (isInstalled)
|
||
{
|
||
if (isVersionMatch) btnText = "Re-Install";
|
||
else btnText = "Update";
|
||
}
|
||
else if (isCached)
|
||
{
|
||
btnText = "Import (Cached)";
|
||
}
|
||
else
|
||
{
|
||
btnText = "Download";
|
||
}
|
||
|
||
if (GUILayout.Button(btnText, GUILayout.Width(110)))
|
||
{
|
||
_downloadQueue.Clear();
|
||
_isQueueRunning = false;
|
||
InstallSpecificPackage(pkg, vData);
|
||
}
|
||
EditorGUI.EndDisabledGroup();
|
||
|
||
// Delete / Verify
|
||
if (!vData.isUpm)
|
||
{
|
||
if (isInstalled || isCached)
|
||
{
|
||
if (GUILayout.Button("🗑", GUILayout.Width(25)))
|
||
{
|
||
if (isCached) try { File.Delete(cachePath); } catch {}
|
||
if (isInstalled) EditorPrefs.DeleteKey("RepoManager_Version_" + pkg.uniqueId);
|
||
RefreshFolderCache();
|
||
}
|
||
}
|
||
}
|
||
|
||
GUILayout.EndHorizontal();
|
||
|
||
if(!string.IsNullOrEmpty(vData.releaseNotes))
|
||
{
|
||
GUIStyle noteStyle = new GUIStyle(EditorStyles.miniLabel) { normal = { textColor = new Color(0.9f,0.9f,0.9f) } };
|
||
GUILayout.Label(vData.releaseNotes, noteStyle);
|
||
}
|
||
|
||
GUILayout.EndVertical();
|
||
}
|
||
|
||
// --- INSTALL LOGIC ---
|
||
|
||
private void InstallSpecificPackage(PackageData pkg, VersionData vData)
|
||
{
|
||
if (vData.isUpm)
|
||
{
|
||
InstallUpmPackage(vData.upmId, vData.version);
|
||
}
|
||
else
|
||
{
|
||
string cachePath = Path.Combine(Application.temporaryCachePath, $"{pkg.uniqueId}_{vData.version}.unitypackage");
|
||
if (File.Exists(cachePath)) InstallPackageLocal(cachePath, pkg.uniqueId, vData.version);
|
||
else StartDownloadPackage(vData.url, pkg.uniqueId, vData.version);
|
||
}
|
||
}
|
||
|
||
// --- QUEUE ---
|
||
|
||
private void StartDownloadAllQueue()
|
||
{
|
||
if (filteredPackages == null || filteredPackages.Count == 0) return;
|
||
|
||
_downloadQueue.Clear();
|
||
|
||
foreach (var pkg in filteredPackages)
|
||
{
|
||
VersionData targetVer = null;
|
||
|
||
// Setup Mode: Find exact version
|
||
if (_isSetupMode)
|
||
{
|
||
targetVer = pkg.versions.FirstOrDefault(v => _essentialPackages.Contains(v.packageName));
|
||
}
|
||
else
|
||
{
|
||
// Normal Mode: Selected version
|
||
int index = 0;
|
||
if(packageVersionSelection.ContainsKey(pkg.uniqueId)) index = packageVersionSelection[pkg.uniqueId];
|
||
if(index < pkg.versions.Length) targetVer = pkg.versions[index];
|
||
}
|
||
|
||
if (targetVer != null && !IsPackageInstalled(pkg, targetVer))
|
||
{
|
||
_downloadQueue.Enqueue(pkg);
|
||
}
|
||
}
|
||
|
||
if (_downloadQueue.Count > 0)
|
||
{
|
||
_isQueueRunning = true;
|
||
ProcessNextQueueItem();
|
||
}
|
||
else
|
||
{
|
||
EditorUtility.DisplayDialog("Setup Wizard", "All required packages are already installed!", "OK");
|
||
}
|
||
}
|
||
|
||
private void ProcessNextQueueItem()
|
||
{
|
||
if (!_isQueueRunning) return;
|
||
|
||
if (_downloadQueue.Count > 0)
|
||
{
|
||
_currentQueueItem = _downloadQueue.Dequeue();
|
||
|
||
// Determine Version again
|
||
VersionData vData = null;
|
||
if (_isSetupMode)
|
||
{
|
||
vData = _currentQueueItem.versions.FirstOrDefault(v => _essentialPackages.Contains(v.packageName));
|
||
}
|
||
else
|
||
{
|
||
int index = 0;
|
||
if(packageVersionSelection.ContainsKey(_currentQueueItem.uniqueId)) index = packageVersionSelection[_currentQueueItem.uniqueId];
|
||
vData = _currentQueueItem.versions[index];
|
||
}
|
||
|
||
if (vData != null)
|
||
{
|
||
Debug.Log($"[Queue] Processing: {_currentQueueItem.displayName} ({vData.version})");
|
||
InstallSpecificPackage(_currentQueueItem, vData);
|
||
}
|
||
else
|
||
{
|
||
ProcessNextQueueItem(); // Skip if invalid
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_isQueueRunning = false;
|
||
_currentQueueItem = null;
|
||
EditorUtility.DisplayDialog("Setup Wizard", "All packages have been installed!", "OK");
|
||
}
|
||
}
|
||
|
||
// --- HELPERS ---
|
||
|
||
private bool IsPackageInstalled(PackageData pkg, VersionData vData)
|
||
{
|
||
if (vData.isUpm && !string.IsNullOrEmpty(vData.upmId))
|
||
{
|
||
string upmPath = Path.Combine("Packages", vData.upmId);
|
||
if (AssetDatabase.IsValidFolder(upmPath)) return true;
|
||
|
||
string manifestPath = Path.Combine(Application.dataPath, "..", "Packages", "manifest.json");
|
||
if (File.Exists(manifestPath))
|
||
{
|
||
string content = File.ReadAllText(manifestPath);
|
||
if (content.Contains($"\"{vData.upmId}\"")) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool folderFound = IsPackageFolderFound(pkg);
|
||
string storedVer = EditorPrefs.GetString("RepoManager_Version_" + pkg.uniqueId, "");
|
||
return folderFound || !string.IsNullOrEmpty(storedVer);
|
||
}
|
||
|
||
private void InstallUpmPackage(string packageId, string version)
|
||
{
|
||
_isInstallingUpm = true;
|
||
string id = string.IsNullOrEmpty(version) ? packageId : $"{packageId}@{version}";
|
||
Debug.Log($"[Asset Manager] Requesting UPM Install: {id}");
|
||
_upmAddRequest = Client.Add(id);
|
||
}
|
||
|
||
private bool IsPackageFolderFound(PackageData pkg)
|
||
{
|
||
string simpleName = pkg.displayName.Replace(" SDK", "").Replace(" ", "").ToLower();
|
||
if (existingFolderNames.Contains(simpleName)) return true;
|
||
if (existingFolderNames.Contains(pkg.displayName.ToLower())) return true;
|
||
if (_rootPackages.Contains(pkg.displayName) && existingFolderNames.Contains(pkg.displayName.ToLower())) return true;
|
||
return false;
|
||
}
|
||
|
||
private void FetchPackageList()
|
||
{
|
||
if (isWorking) return;
|
||
StartWebOperation(jsonListUrl, OnJsonListDownloaded, null);
|
||
}
|
||
|
||
private void StartDownloadPackage(string url, string pkgId, string version)
|
||
{
|
||
if (isWorking) return;
|
||
string fileName = $"{pkgId}_{version}.unitypackage";
|
||
string tempPath = Path.Combine(Application.temporaryCachePath, fileName);
|
||
StartWebOperation(url, (data) => InstallPackageLocal(tempPath, pkgId, version), tempPath);
|
||
}
|
||
|
||
private void StartDownloadDocs(string url, string category, string pkgName, string version)
|
||
{
|
||
if (isWorking) return;
|
||
|
||
string safeName = string.Join("_", pkgName.Split(Path.GetInvalidFileNameChars()));
|
||
string docsRoot = Path.Combine(Application.dataPath, "ShiroginSDK", "ThirdPartySDKs");
|
||
string targetFolder = Path.Combine(docsRoot, category, safeName);
|
||
|
||
if (!Directory.Exists(targetFolder)) Directory.CreateDirectory(targetFolder);
|
||
string targetPath = Path.Combine(targetFolder, $"{safeName}_{version}.md");
|
||
|
||
StartWebOperation(url, (data) =>
|
||
{
|
||
if (data != null && data.Length > 0)
|
||
{
|
||
File.WriteAllBytes(targetPath, data);
|
||
EditorUtility.DisplayDialog("Download Complete", $"Documentation saved to:\n{targetPath}", "OK");
|
||
string relPath = "Assets" + targetPath.Substring(Application.dataPath.Length);
|
||
AssetDatabase.ImportAsset(relPath);
|
||
var obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(relPath);
|
||
EditorGUIUtility.PingObject(obj);
|
||
}
|
||
}, targetPath);
|
||
}
|
||
|
||
private void InstallPackageLocal(string path, string pkgId, string version)
|
||
{
|
||
if (!File.Exists(path)) return;
|
||
AssetDatabase.ImportPackage(path, true);
|
||
EditorPrefs.SetString("RepoManager_Version_" + pkgId, version);
|
||
RefreshFolderCache();
|
||
Repaint();
|
||
|
||
if (_isQueueRunning) ProcessNextQueueItem();
|
||
}
|
||
|
||
private void AbortDownload()
|
||
{
|
||
if (currentRequest != null) { currentRequest.Abort(); currentRequest.Dispose(); currentRequest = null; }
|
||
if (downloadDelegate != null) { EditorApplication.update -= downloadDelegate; downloadDelegate = null; }
|
||
isWorking = false; statusMessage = "Waiting..."; downloadProgress = 0f; Repaint();
|
||
}
|
||
|
||
private void StartWebOperation(string url, Action<byte[]> onComplete, string savePath = null)
|
||
{
|
||
AbortDownload(); isWorking = true; statusMessage = "Connecting..."; downloadProgress = 0f;
|
||
downloadDelegate = () => WebRequestRoutine(url, savePath, onComplete);
|
||
EditorApplication.update += downloadDelegate;
|
||
}
|
||
|
||
private void WebRequestRoutine(string url, string savePath, Action<byte[]> onComplete)
|
||
{
|
||
if (currentRequest == null)
|
||
{
|
||
currentRequest = UnityWebRequest.Get(url);
|
||
if (url.Contains("bitbucket.org") && !string.IsNullOrEmpty(repoToken))
|
||
currentRequest.SetRequestHeader("Authorization", "Bearer " + repoToken);
|
||
|
||
if (!string.IsNullOrEmpty(savePath))
|
||
currentRequest.downloadHandler = new DownloadHandlerFile(savePath);
|
||
else
|
||
currentRequest.downloadHandler = new DownloadHandlerBuffer();
|
||
|
||
currentRequest.SendWebRequest();
|
||
}
|
||
|
||
if (!currentRequest.isDone)
|
||
{
|
||
downloadProgress = currentRequest.downloadProgress;
|
||
statusMessage = "Downloading...";
|
||
Repaint();
|
||
return;
|
||
}
|
||
|
||
bool success = currentRequest.result == UnityWebRequest.Result.Success;
|
||
byte[] data = null;
|
||
|
||
if (success)
|
||
{
|
||
if (string.IsNullOrEmpty(savePath) && currentRequest.downloadHandler is DownloadHandlerBuffer)
|
||
{
|
||
data = currentRequest.downloadHandler.data;
|
||
}
|
||
if(!string.IsNullOrEmpty(savePath)) data = new byte[1];
|
||
}
|
||
else if (currentRequest.error != "Request aborted")
|
||
{
|
||
Debug.LogError($"Network Error: {currentRequest.error}");
|
||
EditorUtility.DisplayDialog("Download Failed", currentRequest.error, "OK");
|
||
if (!string.IsNullOrEmpty(savePath) && File.Exists(savePath)) try { File.Delete(savePath); } catch {}
|
||
}
|
||
|
||
currentRequest.Dispose(); currentRequest = null;
|
||
EditorApplication.update -= downloadDelegate; downloadDelegate = null;
|
||
isWorking = false; Repaint();
|
||
|
||
if(success) onComplete?.Invoke(data);
|
||
}
|
||
|
||
private void OnJsonListDownloaded(byte[] data)
|
||
{
|
||
if (data == null) return;
|
||
try
|
||
{
|
||
PackageManifest manifest = JsonUtility.FromJson<PackageManifest>(System.Text.Encoding.UTF8.GetString(data));
|
||
if (manifest != null && manifest.packages != null)
|
||
{
|
||
allPackages = new List<PackageData>(manifest.packages);
|
||
var catList = new HashSet<string> { "All" };
|
||
foreach (var p in allPackages) if (!string.IsNullOrEmpty(p.category)) catList.Add(p.category);
|
||
categories = catList.OrderBy(c => c).ToArray();
|
||
ApplyFilters();
|
||
Repaint();
|
||
}
|
||
}
|
||
catch (Exception e) { Debug.LogError("JSON Error: " + e.Message); }
|
||
}
|
||
|
||
private void ApplyFilters()
|
||
{
|
||
if (allPackages == null) return;
|
||
if (_isSetupMode)
|
||
{
|
||
// Check against packageName instead of uniqueId
|
||
filteredPackages = allPackages.Where(p =>
|
||
p.versions.Any(v => _essentialPackages.Contains(v.packageName))
|
||
).ToList();
|
||
}
|
||
else
|
||
{
|
||
filteredPackages = allPackages.Where(p =>
|
||
{
|
||
bool catMatch = selectedCategory == "All" || p.category == selectedCategory;
|
||
bool searchMatch = string.IsNullOrEmpty(searchString) || p.displayName.ToLower().Contains(searchString.ToLower());
|
||
return catMatch && searchMatch;
|
||
}).ToList();
|
||
}
|
||
}
|
||
|
||
private void ClearCache()
|
||
{
|
||
string path = Application.temporaryCachePath;
|
||
var info = new DirectoryInfo(path);
|
||
foreach (var f in info.GetFiles("*.unitypackage")) f.Delete();
|
||
Debug.Log("Cache cleared.");
|
||
}
|
||
}
|
||
} |