public override void OnInspectorGUI() { DrawPropertiesExcluding(serializedObject, "m_Script", nameof(ThunderstoreManifest.dependencies)); var property = serializedObject.FindProperty(nameof(ThunderstoreManifest.dependencies)); var thunderManifest = serializedObject.targetObject as ThunderstoreManifest; var manifest = AssetDatabase.LoadAssetAtPath <Manifest>(AssetDatabase.GetAssetPath(thunderManifest)); if (thunderManifest) { using (new VerticalScope(GUI.skin.box)) { Label("Dependencies"); for (int i = 0; i < thunderManifest.dependencies.Count; i++) { var depName = thunderManifest.dependencies[i]; Label(depName); var bp = GUILayoutUtility.GetLastRect(); bp = new Rect(bp.width + 4, bp.y + 1, 13, bp.height - 2); if (Event.current.type == EventType.Repaint) { GUI.skin.box.Draw(bp, new GUIContent(""), 0); GUIContent content = new GUIContent("x"); var contentSize = GUIStyle.none.CalcSize(content); GUIStyle.none.Draw(new Rect(bp.x + 3, bp.y - 1, bp.width, bp.height), content, 0); } if (Event.current.type == EventType.MouseUp && bp.Contains(Event.current.mousePosition)) { var dependencyPath = Path.Combine(Packages, depName); if (Directory.Exists(dependencyPath)) { Directory.Delete(dependencyPath, true); } var listed = thunderManifest.dependencies.ToList(); listed.RemoveAt(i); thunderManifest.dependencies = new DependencyList(listed); property.serializedObject.SetIsDifferentCacheDirty(); property.serializedObject.ApplyModifiedProperties(); AssetDatabase.Refresh(); } } var suggestRect = GUILayoutUtility.GetRect(currentViewWidth, singleLineHeight); suggestRect.x++; suggestRect.width -= 4; suggestor.OnSuggestionGUI = RenderSuggestion; suggestor.OnSuggestGUI(suggestRect, "Dependency Search"); Space(2); } } switch (Event.current.type) { case EventType.Repaint: dragDropRect = GUILayoutUtility.GetLastRect(); break; case EventType.DragUpdated: if (!dragDropRect.Contains(Event.current.mousePosition)) { break; } if (DragAndDrop.objectReferences.OfType <Manifest>().Any()) { var canDrop = false; var manifests = DragAndDrop.objectReferences.OfType <Manifest>().ToArray(); foreach (var droppedManifest in manifests) { foreach (var depThunderManifest in droppedManifest.Data.OfType <ThunderstoreManifest>()) { string thisGuid = $"{thunderManifest.author}-{manifest.name}"; if (!depThunderManifest.dependencies.Any(dp => dp.StartsWith(thisGuid)) && !thisGuid.StartsWith($"{depThunderManifest.author}-{droppedManifest.name}")) { canDrop = true; break; } if (canDrop) { break; } } } if (canDrop) { DragAndDrop.visualMode = DragAndDropVisualMode.Link; Event.current.Use(); return; } } if (DragAndDrop.paths.Any(path => Path.GetExtension(path).Equals(".zip"))) { var canDrop = false; foreach (var path in DragAndDrop.paths.Where(path => Path.GetExtension(path).Equals(".zip"))) { using (var archive = new ZipArchive(File.OpenRead(path))) { foreach (var entry in archive.Entries) { if (!"manifest.json".Equals(Path.GetFileName(entry.FullName), System.StringComparison.OrdinalIgnoreCase)) { continue; } canDrop = true; break; } } } if (canDrop) { DragAndDrop.visualMode = DragAndDropVisualMode.Link; Event.current.Use(); return; } } break; case EventType.DragPerform: if (DragAndDrop.objectReferences.OfType <Manifest>().Any()) { //Debug.Log("Dropping Manifests"); var manifests = DragAndDrop.objectReferences.OfType <Manifest>(); foreach (var droppedManifest in manifests) { foreach (var dependence in droppedManifest.Data.OfType <ThunderstoreManifest>()) { string dependency = $"{dependence.author}-{droppedManifest.name}-{dependence.versionNumber}"; if (thunderManifest.dependencies.Any(dp => dp.StartsWith($"{dependence.author}-{droppedManifest.name}"))) { thunderManifest.dependencies.RemoveAll(dp => dp.StartsWith($"{dependence.author}-{droppedManifest.name}")); } if (thunderManifest.dependencies == null || !thunderManifest.dependencies.Any()) { thunderManifest.dependencies = new DependencyList(); } thunderManifest.dependencies.Add(dependency); property.serializedObject.SetIsDifferentCacheDirty(); property.serializedObject.ApplyModifiedProperties(); DragAndDrop.AcceptDrag(); Event.current.Use(); return; } } } if (DragAndDrop.paths.Any(path => Path.GetExtension(path).Equals(".zip"))) { bool refresh = false; foreach (var path in DragAndDrop.paths.Where(path => Path.GetExtension(path).Equals(".zip"))) { using (var archive = new ZipArchive(File.OpenRead(path))) { var entry = archive.Entries.FirstOrDefault(e => "manifest.json".Equals(Path.GetFileName(e.FullName), System.StringComparison.OrdinalIgnoreCase)); if (entry == null) { continue; } var archiveName = Path.GetFileNameWithoutExtension(path); var outputDir = Path.Combine("Packages", archiveName); refresh = true; Directory.CreateDirectory(outputDir); archive.ExtractToDirectory(outputDir); foreach (var assemblyPath in Directory.EnumerateFiles(outputDir, "*.dll", SearchOption.AllDirectories)) { PackageHelper.WriteAssemblyMetaData(assemblyPath, $"{assemblyPath}.meta"); } using (var reader = new StreamReader(entry.Open())) { var stubManifest = JsonUtility.FromJson <ThunderstoreManifestStub>(reader.ReadToEnd()); string author = stubManifest.author ?? archiveName.Substring(0, archiveName.IndexOf('-')); string guid = $"{author}-{stubManifest.name}-{stubManifest.version_number}"; Debug.Log($"Added {guid} to {manifest.name} dependencies"); thunderManifest.dependencies.Add(guid); PackageHelper.GeneratePackageManifest( stubManifest.name.ToLower(), outputDir, stubManifest.name, author, stubManifest.version_number, stubManifest.description, stubManifest.website_url); } } } if (refresh) { AssetDatabase.Refresh(ImportAssetOptions.ImportRecursive); } } break; } bool RenderSuggestion(int arg1, Package package) { if (thunderManifest.dependencies.Contains(package.latest.full_name)) { return(false); } if (Button(package.name)) { thunderManifest.dependencies.Add(package.latest.full_name); property.serializedObject.SetIsDifferentCacheDirty(); property.serializedObject.ApplyModifiedProperties(); suggestor.Cleanup(); if (!Directory.Exists(TempDir)) { Directory.CreateDirectory(TempDir); } var packages = RecurseDependencies(thunderManifest.dependencies) .GroupBy(dep => dep.latest.full_name).Select(g => g.First()).ToArray(); foreach (var pack in packages) { ThunderstoreAPI.DownloadPackage(pack, Path.Combine(TempDir, GetZipFileName(pack))); } return(true); } return(false); } }
public void InstallPackage(PackageGroup group, string version) { if (EditorApplication.isCompiling) { return; } var package = group[version]; var installSet = EnumerateDependencies(package).Where(dep => !dep.group.Installed).ToArray(); var progress = 0.01f; var stepSize = 0.33f / installSet.Length; //Wait till all files are put in place to load new assemblies to make installation more consistent and faster EditorApplication.LockReloadAssemblies(); try { EditorUtility.DisplayProgressBar("Creating Packages", $"{installSet.Length} packages", progress); foreach (var installable in installSet) { //This will cause repeated installation of dependencies string packageDirectory = installable.group.InstallDirectory; if (Directory.Exists(packageDirectory)) { Directory.Delete(packageDirectory, true); } Directory.CreateDirectory(packageDirectory); EditorUtility.DisplayProgressBar("Creating Packages", $"Creating package.json for {installable.group.PackageName}", progress += stepSize / 2); PackageHelper.GeneratePackageManifest( installable.group.DependencyId.ToLower(), installable.group.InstallDirectory, installable.group.PackageName, installable.group.Author, installable.version, installable.group.Description); } AssetDatabase.SaveAssets(); try { //Refresh here to update the AssetDatabase so that it can manage the creation of Manifests in the packages via the Unity Package path notation //e.g Packages/com.passivepicasso.thunderkit/Editor AssetDatabase.Refresh(); } catch { } EditorUtility.DisplayProgressBar("Creating Package Manifests", $"Creating {installSet.Length} manifests", progress); foreach (var installable in installSet) { var installableGroup = installable.group; var manifestPath = PathExtensions.Combine(installableGroup.PackageDirectory, $"{installableGroup.PackageName}.asset"); if (AssetDatabase.LoadAssetAtPath <Manifest>(manifestPath)) { AssetDatabase.DeleteAsset(manifestPath); } EditorUtility.DisplayProgressBar("Creating Package Manifests", $"Creating manifest for {installable.group.PackageName}", progress += stepSize); var manifest = ScriptableObject.CreateInstance <Manifest>(); AssetDatabase.CreateAsset(manifest, manifestPath); PackageHelper.WriteAssetMetaData(manifestPath); AssetDatabase.Refresh(); manifest = AssetDatabase.LoadAssetAtPath <Manifest>(manifestPath); var identity = ScriptableObject.CreateInstance <ManifestIdentity>(); identity.name = nameof(ManifestIdentity); identity.Author = installableGroup.Author; identity.Description = installableGroup.Description; identity.Name = installableGroup.PackageName; identity.Version = version; manifest.InsertElement(identity, 0); manifest.Identity = identity; } //Refresh here to update the AssetDatabase's representation of the Assets with ThunderKit managed Meta files AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); EditorUtility.DisplayProgressBar("Defining Package Dependencies", $"Assigning dependencies for {installSet.Length} manifests", progress); foreach (var installable in installSet) { var manifestPath = PathExtensions.Combine(installable.group.PackageDirectory, $"{installable.group.PackageName}.asset"); var installableManifest = AssetDatabase.LoadAssetAtPath <Manifest>(manifestPath); var identity = installableManifest.Identity; EditorUtility.DisplayProgressBar("Defining Package Dependencies", $"Assigning dependencies for {installable.group.PackageName}", progress); identity.Dependencies = new Manifest[installable.dependencies.Length]; for (int i = 0; i < installable.dependencies.Length; i++) { var installableDependency = installable.dependencies[i]; EditorUtility.DisplayProgressBar("Defining Package Dependencies", $"Assigning {installableDependency.group.PackageName} to {identity.Name}", progress += stepSize / installable.dependencies.Length); var manifestFileName = $"{installableDependency.group.PackageName}.asset"; var dependencyAssetTempPath = PathExtensions.Combine(installableDependency.group.PackageDirectory, manifestFileName); var manifest = AssetDatabase.LoadAssetAtPath <Manifest>(dependencyAssetTempPath); if (!manifest) { var packageManifests = AssetDatabase.FindAssets($"t:{nameof(Manifest)}", new string[] { "Assets", "Packages" }).Select(x => AssetDatabase.GUIDToAssetPath(x)).ToArray(); manifest = packageManifests.Where(x => x.Contains(manifestFileName)).Select(x => AssetDatabase.LoadAssetAtPath <Manifest>(x)).FirstOrDefault(); } identity.Dependencies[i] = manifest; } EditorUtility.SetDirty(installableManifest); EditorUtility.SetDirty(identity); } EditorUtility.DisplayProgressBar("Installing Package Files", $"{installSet.Length} packages", progress); foreach (var installable in installSet) { string packageDirectory = installable.group.InstallDirectory; EditorUtility.DisplayProgressBar("Installing Package Files", $"Downloading {installable.group.PackageName}", progress += stepSize / 2); installable.group.Source.OnInstallPackageFiles(installable, packageDirectory); foreach (var assemblyPath in Directory.GetFiles(packageDirectory, "*.dll", SearchOption.AllDirectories)) { PackageHelper.WriteAssemblyMetaData(assemblyPath, $"{assemblyPath}.meta"); } } } finally { EditorUtility.ClearProgressBar(); AssetDatabase.SaveAssets(); EditorApplication.update += OneRefresh; RefreshWait = EditorApplication.timeSinceStartup; EditorApplication.UnlockReloadAssemblies(); } }
private static void PackagesWatcher_Created(object sender, FileSystemEventArgs e) { string filePath = e.FullPath; EditorApplication.update += InstallPackage; void InstallPackage() { try { EditorApplication.update -= InstallPackage; AssetDatabase.StartAssetEditing(); string fileNameNoExt = Path.GetFileNameWithoutExtension(filePath); var dependencyPath = Path.Combine(Packages, fileNameNoExt); if (Directory.Exists(dependencyPath)) { Directory.Delete(dependencyPath, true); } if (File.Exists($"{dependencyPath}.meta")) { File.Delete($"{dependencyPath}.meta"); } Directory.CreateDirectory(dependencyPath); using (var fileStream = File.OpenRead(filePath)) using (var archive = new ZipArchive(fileStream)) foreach (var entry in archive.Entries) { if (entry.FullName.ToLower().EndsWith("/") || entry.FullName.ToLower().EndsWith("\\")) { continue; } var outputPath = Path.Combine(dependencyPath, entry.FullName); var outputDir = Path.GetDirectoryName(outputPath); var fileName = Path.GetFileName(outputPath); if (!Directory.Exists(outputDir)) { Directory.CreateDirectory(outputDir); } entry.ExtractToFile(outputPath); if (Path.GetExtension(fileName).Equals(".dll")) { string assemblyPath = outputPath; PackageHelper.WriteAssemblyMetaData(assemblyPath, $"{assemblyPath}.meta"); } if ("manifest.json".Equals(fileName.ToLower())) { var stubManifest = CreateThunderstoreManifest.LoadStub(outputPath); var authorAlias = fileNameNoExt.Substring(0, fileNameNoExt.IndexOf('-')); PackageHelper.GeneratePackageManifest( stubManifest.name.ToLower(), outputDir, stubManifest.name, authorAlias, stubManifest.version_number, stubManifest.description, stubManifest.website_url); } } File.Delete(filePath); } finally { AssetDatabase.StopAssetEditing(); AssetDatabase.Refresh(); } } }