Playvoi/Assets/ShiroginSDK/Editor/Bitbucket/AssetRegistryEditor.cs

925 lines
No EOL
37 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.");
}
}
}