├── .github ├── FUNDING.yml └── workflows │ └── release.yml ├── .gitignore ├── LICENSE ├── Packages └── com.varneon.package-exporter │ ├── Editor.meta │ ├── Editor │ ├── ExporterWindow.cs │ ├── ExporterWindow.cs.meta │ ├── PackageExportConfiguration.cs │ ├── PackageExportConfiguration.cs.meta │ ├── PackageExportConfigurationExclusions.cs │ ├── PackageExportConfigurationExclusions.cs.meta │ ├── PackageExportConfigurationInclusions.cs │ ├── PackageExportConfigurationInclusions.cs.meta │ ├── PackageExporterConfigurationStorage.cs │ ├── PackageExporterConfigurationStorage.cs.meta │ ├── PackageExporterConfigurationStorageEditor.cs │ ├── PackageExporterConfigurationStorageEditor.cs.meta │ ├── PackageFileNameUtility.cs │ ├── PackageFileNameUtility.cs.meta │ ├── Varneon.PackageExporter.Editor.asmdef │ └── Varneon.PackageExporter.Editor.asmdef.meta │ ├── LICENSE.md │ ├── LICENSE.md.meta │ ├── Resources.meta │ ├── Resources │ ├── AssetExclusionField.uxml │ ├── AssetExclusionField.uxml.meta │ ├── AssetInclusionField.uxml │ ├── AssetInclusionField.uxml.meta │ ├── ConfigurationBlock.uxml │ ├── ConfigurationBlock.uxml.meta │ ├── ConfigurationsWindow.uss │ ├── ConfigurationsWindow.uss.meta │ ├── ConfigurationsWindow.uxml │ ├── ConfigurationsWindow.uxml.meta │ ├── ExporterWindow.uss │ ├── ExporterWindow.uss.meta │ ├── ExporterWindow.uxml │ ├── ExporterWindow.uxml.meta │ ├── FolderExclusionField.uxml │ ├── FolderExclusionField.uxml.meta │ ├── FolderInclusionField.uxml │ ├── FolderInclusionField.uxml.meta │ ├── Icons.meta │ ├── Icons │ │ ├── Icon_Add.png │ │ ├── Icon_Add.png.meta │ │ ├── Icon_Dots.png │ │ ├── Icon_Dots.png.meta │ │ ├── Icon_Gear.png │ │ ├── Icon_Gear.png.meta │ │ ├── Icon_QuestionMark.png │ │ ├── Icon_QuestionMark.png.meta │ │ ├── Icon_Reload.png │ │ ├── Icon_Reload.png.meta │ │ ├── Icon_Remove.png │ │ └── Icon_Remove.png.meta │ ├── NoConfigurationFileMessage.uxml │ ├── NoConfigurationFileMessage.uxml.meta │ ├── NoConfigurationsMessage.uxml │ ├── NoConfigurationsMessage.uxml.meta │ ├── UPMPackageExporter.uss │ ├── UPMPackageExporter.uss.meta │ ├── UPMPackageGenerator.uxml │ └── UPMPackageGenerator.uxml.meta │ ├── Samples~ │ ├── Self-Export Configuration.meta │ └── Self-Export Configuration │ │ ├── PackageExporter_SelfExportConfiguration.asset │ │ └── PackageExporter_SelfExportConfiguration.asset.meta │ ├── package.json │ └── package.json.meta └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: Varneon 2 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Build Release 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | packageName: "com.varneon.package-exporter" 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | 17 | - name: get version 18 | id: version 19 | uses: notiz-dev/github-action-json-property@7c8cf5cc36eb85d8d287a8086a39dac59628eb31 20 | with: 21 | path: "Packages/${{env.packageName}}/package.json" 22 | prop_path: "version" 23 | 24 | - run: echo ${{steps.version.outputs.prop}} 25 | 26 | - name: Set Environment Variables 27 | run: | 28 | echo "zipFile=${{ env.packageName }}-${{ steps.version.outputs.prop }}".zip >> $GITHUB_ENV 29 | echo "unityPackage=${{ env.packageName }}-${{ steps.version.outputs.prop }}.unitypackage" >> $GITHUB_ENV 30 | 31 | - name: Create Zip 32 | uses: thedoctor0/zip-release@09336613be18a8208dfa66bd57efafd9e2685657 33 | with: 34 | type: "zip" 35 | directory: "Packages/${{env.packageName}}/" 36 | filename: "../../${{env.zipFile}}" # make the zip file two directories up, since we start two directories in above 37 | 38 | - run: find "Packages/${{env.packageName}}/" -name \*.meta >> metaList 39 | 40 | - name: Create UnityPackage 41 | uses: pCYSl5EDgo/create-unitypackage@e28c7a4616b2754c564b0a959a03b3c89b756fdb 42 | with: 43 | package-path: ${{ env.unityPackage }} 44 | include-files: metaList 45 | 46 | 47 | - name: Make Release 48 | uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5 49 | with: 50 | tag_name: ${{ steps.version.outputs.prop }} 51 | draft: true 52 | files: | 53 | ${{ env.zipFile }} 54 | ${{ env.unityPackage }} 55 | Packages/${{ env.packageName }}/package.json -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/.git 3 | !/.github 4 | !/.gitignore 5 | !/.LICENCE 6 | !/.README.md 7 | !/Packages 8 | /Packages/* 9 | !/Packages/com.varneon.package-exporter 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Varneon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ffb0b9a36f0a1714b89ddda44fe7f146 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/ExporterWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using UnityEditor; 6 | using UnityEditor.UIElements; 7 | using UnityEngine; 8 | using UnityEngine.UIElements; 9 | 10 | namespace Varneon.PackageExporter 11 | { 12 | /// 13 | /// The main package exporter window 14 | /// 15 | internal class ExporterWindow : EditorWindow 16 | { 17 | /// 18 | /// UXML assets for the editor window 19 | /// 20 | [SerializeField] 21 | private VisualTreeAsset mainWindowUxml, noConfigurationsFileUxml, noConfigurationsUxml; 22 | 23 | /// 24 | /// All available configuration storages in the project 25 | /// 26 | private PackageExporterConfigurationStorage[] packageExporterConfigurationStorages; 27 | 28 | /// 29 | /// List of all available export configurations in the project 30 | /// 31 | private List packageExportConfigurations; 32 | 33 | /// 34 | /// The active package export configuration 35 | /// 36 | private PackageExportConfiguration activeConfiguration; 37 | 38 | /// 39 | /// Current version of the package for exporting 40 | /// 41 | private string packageVersion; 42 | 43 | /// 44 | /// Current version of the package for exporting 45 | /// 46 | private string PackageVersion 47 | { 48 | set 49 | { 50 | packageVersion = value; 51 | 52 | UpdateOutputFileName(); 53 | 54 | bool dirty = lastPackageVersion != value; 55 | 56 | if (isVersionDirty != dirty) 57 | { 58 | isVersionDirty = dirty; 59 | 60 | lastVersionIndicator.style.display = dirty ? DisplayStyle.Flex : DisplayStyle.None; 61 | } 62 | } 63 | get => packageVersion; 64 | } 65 | 66 | /// 67 | /// Has the version been modified 68 | /// 69 | private bool isVersionDirty; 70 | 71 | /// 72 | /// Last known version of the package 73 | /// 74 | private string lastPackageVersion; 75 | 76 | /// 77 | /// Is the provided version valid 78 | /// 79 | private bool isPackageVersionValid = true; 80 | 81 | /// 82 | /// Is the provided version valid 83 | /// 84 | private bool IsPackageVersionValid 85 | { 86 | set 87 | { 88 | if (isPackageVersionValid != value) 89 | { 90 | isPackageVersionValid = value; 91 | 92 | invalidVersionNotification.style.display = value ? DisplayStyle.None : DisplayStyle.Flex; 93 | } 94 | 95 | exportButton.SetEnabled(value && isFileNameValid); 96 | } 97 | get => isPackageVersionValid; 98 | } 99 | 100 | /// 101 | /// Name of the unitypackage to be exported 102 | /// 103 | private string fileName; 104 | 105 | /// 106 | /// Name of the unitypackage to be exported 107 | /// 108 | private string FileName 109 | { 110 | set 111 | { 112 | isFileNameValid = PackageFileNameUtility.IsNameValid(value); 113 | 114 | invalidFileNameNotification.style.display = isFileNameValid ? DisplayStyle.None : DisplayStyle.Flex; 115 | 116 | exportButton.SetEnabled(isFileNameValid && IsPackageVersionValid); 117 | 118 | fileName = value; 119 | } 120 | get => fileName; 121 | } 122 | 123 | /// 124 | /// Is the current package file name valid 125 | /// 126 | private bool isFileNameValid; 127 | 128 | /// 129 | /// Has the user modified the name 130 | /// 131 | private bool isPackageNameDirty; 132 | 133 | /// 134 | /// Has the user modified the name 135 | /// 136 | private bool IsPackageNameDirty 137 | { 138 | set 139 | { 140 | if (isPackageNameDirty != value) 141 | { 142 | isPackageNameDirty = value; 143 | 144 | resetPackageNameButton.style.display = value ? DisplayStyle.Flex : DisplayStyle.None; 145 | } 146 | } 147 | } 148 | 149 | /// 150 | /// Names for all of the available package configurations 151 | /// 152 | private string[] packageConfigurationNames; 153 | 154 | /// 155 | /// Index of the selected package export configuration 156 | /// 157 | private int activeConfigurationIndex; 158 | 159 | /// 160 | /// Are there no configurations available for exporting packages 161 | /// 162 | private bool noConfigurationsAvailable; 163 | 164 | /// 165 | /// Is there no PackageExporterConfigurations scriptable object available 166 | /// 167 | private bool noConfigurationFileAvailable; 168 | 169 | /// 170 | /// The paths of the asset that will be exported in the package 171 | /// 172 | private HashSet pathsToExport = new HashSet(); 173 | 174 | /// 175 | /// ToolbarMenu for selecting the active configuration 176 | /// 177 | private ToolbarMenu configurationMenu; 178 | 179 | /// 180 | /// The underlying DropdownMenu which contains the configuration menu elements 181 | /// 182 | private DropdownMenu configurationDropdown; 183 | 184 | /// 185 | /// Package tree preview's loading screen 186 | /// 187 | private VisualElement packagePreviewLoadingScreen; 188 | 189 | /// 190 | /// Package tree preview's loading screen's progress bar 191 | /// 192 | private VisualElement packagePreviewProgressBar; 193 | 194 | /// 195 | /// ListView for previewing the package contents 196 | /// 197 | private ListView packagePreview; 198 | 199 | /// 200 | /// TextField for specifying the package version 201 | /// 202 | private TextField packageVersionField; 203 | 204 | /// 205 | /// TextField for previewing and modifying the final package name 206 | /// 207 | private TextField packageNameField; 208 | 209 | /// 210 | /// Notification for indicating that the file name of the package is invalid 211 | /// 212 | private VisualElement invalidFileNameNotification; 213 | 214 | /// 215 | /// Button for resetting the package name to origican naming pattern 216 | /// 217 | private Button resetPackageNameButton; 218 | 219 | /// 220 | /// Root VisualElement for the last package version indicator 221 | /// 222 | private VisualElement lastVersionIndicator; 223 | 224 | /// 225 | /// Underlying Label element for displaying the previous package version 226 | /// 227 | private Label lastVersionLabel; 228 | 229 | /// 230 | /// Root VisualElement for invalid package version notification 231 | /// 232 | private VisualElement invalidVersionNotification; 233 | 234 | /// 235 | /// Button for exporting the package 236 | /// 237 | private Button exportButton; 238 | 239 | /// 240 | /// Is this window currently focused 241 | /// 242 | private bool isWindowFocused = true; 243 | 244 | private PackagePreviewDirectoryWalker packagePreviewDirectoryWalker; 245 | 246 | private struct PackagePreviewDirectoryWalker 247 | { 248 | internal bool Active; 249 | 250 | internal int PathCount; 251 | 252 | internal int CurrentPathIndex; 253 | 254 | internal string CurrentDirectory; 255 | 256 | internal int DirectoryDepth; 257 | 258 | internal Foldout CurrentFoldout; 259 | 260 | internal PackagePreviewDirectoryWalker(int exportedPathCount) 261 | { 262 | Active = true; 263 | 264 | PathCount = exportedPathCount; 265 | 266 | CurrentPathIndex = 0; 267 | 268 | CurrentDirectory = string.Empty; 269 | 270 | DirectoryDepth = 0; 271 | 272 | CurrentFoldout = null; 273 | } 274 | } 275 | 276 | /// 277 | /// Which page the editor window is currently on 278 | /// 279 | private Page currentPage; 280 | 281 | /// 282 | /// Enum for describing different pages of the editor window 283 | /// 284 | private enum Page 285 | { 286 | None, 287 | Main, 288 | NoConfigurationsFile, 289 | NoConfigurations 290 | } 291 | 292 | #region Editor Window Methods 293 | [MenuItem("Varneon/Package Exporter/Exporter")] 294 | private static void OpenWindow() 295 | { 296 | ExporterWindow window = GetWindow(); 297 | window.titleContent.text = "Package Exporter"; 298 | window.minSize = new Vector2(300, 300); 299 | window.Show(); 300 | } 301 | 302 | private void OnEnable() 303 | { 304 | currentPage = Page.None; 305 | 306 | LoadPage(Page.Main); 307 | 308 | LoadPackageConfigurationStorages(); 309 | } 310 | 311 | private void OnDestroy() 312 | { 313 | if (packagePreviewDirectoryWalker.Active) 314 | { 315 | Debug.Log("Still building package preview, aborting..."); 316 | 317 | EditorApplication.update -= IteratePackageTreePreviewBuilder; 318 | } 319 | } 320 | 321 | private void OnLostFocus() 322 | { 323 | isWindowFocused = false; 324 | } 325 | 326 | private void OnFocus() 327 | { 328 | if (isWindowFocused) { return; } 329 | 330 | if (noConfigurationFileAvailable || noConfigurationsAvailable) 331 | { 332 | LoadPackageConfigurationStorages(false); 333 | 334 | return; 335 | } 336 | 337 | if (!packageConfigurationNames.SequenceEqual(GetAvailablePackageConfigurationNames())) 338 | { 339 | activeConfigurationIndex = 0; 340 | 341 | LoadPackageConfigurations(); 342 | } 343 | } 344 | #endregion 345 | 346 | /// 347 | /// Generates the UI for the main page 348 | /// 349 | private void InitializeMainPage() 350 | { 351 | mainWindowUxml.CloneTree(rootVisualElement); 352 | 353 | configurationMenu = rootVisualElement.Q("ConfigurationMenu"); 354 | 355 | configurationMenu.RegisterCallback(a => 356 | { 357 | GenericMenu menu = new GenericMenu(); 358 | 359 | menu.AddItem(new GUIContent("Open Export Directory"), false, () => EditorUtility.RevealInFinder(activeConfiguration.ExportDirectory)); 360 | 361 | menu.ShowAsContext(); 362 | }); 363 | 364 | configurationDropdown = configurationMenu.menu; 365 | 366 | rootVisualElement.Q("Button_OpenConfigurations").clicked += () => SelectPackageConfigurationsFile(); 367 | 368 | rootVisualElement.Q("Button_ReloadConfiguration").clicked += () => SetActiveConfiguration(activeConfiguration.Name); 369 | 370 | rootVisualElement.Q("Button_UPMVersionHelp").clicked += () => Application.OpenURL("https://docs.unity3d.com/Manual/upm-semver.html"); 371 | 372 | packageVersionField = rootVisualElement.Q("TextField_Version"); 373 | 374 | packageVersionField.RegisterValueChangedCallback(a => { IsPackageVersionValid = Version.TryParse(PackageVersion = a.newValue, out _); }); 375 | 376 | lastVersionIndicator = rootVisualElement.Q("LastVersionIndicator"); 377 | 378 | lastVersionLabel = lastVersionIndicator.Q("Label_LastVersion"); 379 | 380 | packageNameField = rootVisualElement.Q("TextField_PackageName"); 381 | 382 | packageNameField.RegisterValueChangedCallback(a => { FileName = a.newValue; IsPackageNameDirty = true; }); 383 | 384 | invalidFileNameNotification = rootVisualElement.Q("Notification_InvalidFileName"); 385 | 386 | resetPackageNameButton = rootVisualElement.Q("Button_ResetPackageName"); 387 | 388 | resetPackageNameButton.clicked += () => UpdateOutputFileName(); 389 | 390 | packagePreviewLoadingScreen = rootVisualElement.Q("PackagePreviewLoadingScreen"); 391 | 392 | packagePreviewProgressBar = packagePreviewLoadingScreen.Q("ProgressBar_Fill"); 393 | 394 | packagePreview = rootVisualElement.Q("PackagePreview"); 395 | 396 | invalidVersionNotification = rootVisualElement.Q("Notification_InvalidVersion"); 397 | 398 | exportButton = rootVisualElement.Q("Button_Export"); 399 | 400 | exportButton.clicked += () => ExportPackage(); 401 | } 402 | 403 | /// 404 | /// Loads the specified page 405 | /// 406 | /// 407 | private void LoadPage(Page page) 408 | { 409 | if(currentPage == page) { return; } 410 | 411 | rootVisualElement.Clear(); 412 | 413 | currentPage = page; 414 | 415 | switch (page) 416 | { 417 | case Page.Main: 418 | InitializeMainPage(); 419 | return; 420 | case Page.NoConfigurationsFile: 421 | noConfigurationsFileUxml.CloneTree(rootVisualElement); 422 | rootVisualElement.Q("Button_CreateConfigurationsFile").clicked += () => LoadPackageConfigurationStorages(); 423 | return; 424 | case Page.NoConfigurations: 425 | noConfigurationsUxml.CloneTree(rootVisualElement); 426 | rootVisualElement.Q("Button_SelectConfigurationsFile").clicked += () => SelectPackageConfigurationsFile(); 427 | return; 428 | } 429 | } 430 | 431 | /// 432 | /// Selects the package configurations file 433 | /// 434 | private void SelectPackageConfigurationsFile() 435 | { 436 | Selection.SetActiveObjectWithContext(activeConfiguration?.ParentStorage ?? packageExporterConfigurationStorages?[0], this); 437 | } 438 | 439 | /// 440 | /// Loads the package configurations scriptable object 441 | /// 442 | private void LoadPackageConfigurationStorages(bool createNewIfNoneFound = true) 443 | { 444 | packageExporterConfigurationStorages = PackageExporterConfigurationStorage.LoadAllConfigurationStorages(createNewIfNoneFound); 445 | 446 | if (packageExporterConfigurationStorages == null || packageExporterConfigurationStorages.Length == 0) 447 | { 448 | noConfigurationFileAvailable = true; 449 | 450 | LoadPage(Page.NoConfigurationsFile); 451 | 452 | return; 453 | } 454 | 455 | // After allowing multiple storages in a project, reference to the storage that the configuration is stored in is required 456 | foreach(PackageExporterConfigurationStorage storage in packageExporterConfigurationStorages) 457 | { 458 | foreach(PackageExportConfiguration configuration in storage.Configurations) 459 | { 460 | if(configuration.ParentStorage == null) 461 | { 462 | configuration.ParentStorage = storage; 463 | 464 | EditorUtility.SetDirty(storage); 465 | } 466 | } 467 | } 468 | 469 | packageExportConfigurations = new List(packageExporterConfigurationStorages.SelectMany(s => s.Configurations)); 470 | 471 | noConfigurationFileAvailable = false; 472 | 473 | LoadPackageConfigurations(); 474 | } 475 | 476 | /// 477 | /// Loads all package configurations 478 | /// 479 | private void LoadPackageConfigurations() 480 | { 481 | if (packageExportConfigurations.Count == 0) 482 | { 483 | noConfigurationsAvailable = true; 484 | 485 | LoadPage(Page.NoConfigurations); 486 | 487 | return; 488 | } 489 | 490 | noConfigurationsAvailable = false; 491 | 492 | LoadPage(Page.Main); 493 | 494 | packageConfigurationNames = GetAvailablePackageConfigurationNames(); 495 | 496 | for(int i = 0; i < packageConfigurationNames.Length; i++) 497 | { 498 | configurationDropdown.AppendAction(packageConfigurationNames[i], a => { SetActiveConfiguration(a.name); }, a => DropdownMenuAction.Status.Normal); 499 | } 500 | 501 | SetActiveConfiguration(packageConfigurationNames[0]); 502 | } 503 | 504 | /// 505 | /// Sets the active configuration based on the name of the configuration 506 | /// 507 | private void SetActiveConfiguration(string name) 508 | { 509 | configurationMenu.text = name; 510 | 511 | activeConfigurationIndex = Array.IndexOf(packageConfigurationNames, name); 512 | 513 | activeConfiguration = packageExportConfigurations[activeConfigurationIndex]; 514 | 515 | lastPackageVersion = packageVersion = activeConfiguration.GetCurrentVersion(); 516 | 517 | packageVersionField.value = packageVersion; 518 | 519 | lastVersionLabel.text = lastPackageVersion; 520 | 521 | IsPackageVersionValid = true; 522 | 523 | pathsToExport.Clear(); 524 | 525 | HashSet exclusionLookup = new HashSet(); 526 | 527 | activeConfiguration.FolderExclusions.ForEach(e => exclusionLookup.UnionWith(e.GetPaths())); 528 | activeConfiguration.AssetExclusions.ForEach(e => exclusionLookup.UnionWith(e.GetPaths())); 529 | 530 | activeConfiguration.FolderInclusions.ForEach(e => pathsToExport.UnionWith(e.GetPaths())); 531 | activeConfiguration.AssetInclusions.ForEach(e => pathsToExport.UnionWith(e.GetPaths())); 532 | 533 | pathsToExport.RemoveWhere(s => exclusionLookup.Contains(s)); 534 | 535 | rootVisualElement.Q("Label_FileSizePreview").text = $"Included files: {pathsToExport.Count} ({ParseFileSize(pathsToExport.Select(c => new FileInfo(c).Length).Sum())})"; 536 | 537 | BuildPackageTreePreview(); 538 | 539 | UpdateOutputFileName(); 540 | } 541 | 542 | /// 543 | /// Starts the package tree preview builder based on the active configuration 544 | /// 545 | private void BuildPackageTreePreview() 546 | { 547 | SetPackagePreviewLoadingScreenActive(true); 548 | 549 | packagePreview.Clear(); 550 | 551 | if (!packagePreviewDirectoryWalker.Active) 552 | { 553 | EditorApplication.update += IteratePackageTreePreviewBuilder; 554 | } 555 | 556 | packagePreviewDirectoryWalker = new PackagePreviewDirectoryWalker(pathsToExport.Count); 557 | 558 | pathsToExport = new HashSet(pathsToExport.OrderBy(s => s)); 559 | } 560 | 561 | /// 562 | /// Finishes the package tree preview building 563 | /// 564 | private void FinishPackageTreePreviewBuild() 565 | { 566 | EditorApplication.update -= IteratePackageTreePreviewBuilder; 567 | 568 | packagePreviewDirectoryWalker.Active = false; 569 | 570 | SetPackagePreviewLoadingScreenActive(false); 571 | } 572 | 573 | /// 574 | /// Iterates the package tree preview builder one asset path at a time 575 | /// 576 | private void IteratePackageTreePreviewBuilder() 577 | { 578 | try 579 | { 580 | if (packagePreviewDirectoryWalker.CurrentPathIndex >= packagePreviewDirectoryWalker.PathCount) 581 | { 582 | FinishPackageTreePreviewBuild(); 583 | 584 | return; 585 | } 586 | 587 | string path = pathsToExport.ElementAt(packagePreviewDirectoryWalker.CurrentPathIndex); 588 | 589 | string directoryName = Path.GetDirectoryName(path).Replace('\\', '/'); 590 | 591 | string[] folders = directoryName.Split('/'); 592 | 593 | int newDirectoryDepth = folders.Length; 594 | 595 | if (!DoesDirectoryContainDirectory(directoryName, packagePreviewDirectoryWalker.CurrentDirectory)) 596 | { 597 | packagePreviewDirectoryWalker.CurrentFoldout = packagePreview.Q(directoryName); 598 | 599 | packagePreviewDirectoryWalker.DirectoryDepth = GetDeepestCommonFolderIndex(directoryName, packagePreviewDirectoryWalker.CurrentDirectory); 600 | 601 | packagePreviewDirectoryWalker.CurrentDirectory = string.Join("/", folders, 0, packagePreviewDirectoryWalker.DirectoryDepth); 602 | } 603 | 604 | while (newDirectoryDepth > packagePreviewDirectoryWalker.DirectoryDepth) 605 | { 606 | string folderName = folders[packagePreviewDirectoryWalker.DirectoryDepth]; 607 | 608 | string tempDirectory = Path.Combine(packagePreviewDirectoryWalker.CurrentDirectory, folderName).Replace('\\', '/'); 609 | 610 | Foldout foldout = new Foldout() 611 | { 612 | text = folderName, 613 | name = tempDirectory 614 | }; 615 | 616 | foldout.AddToClassList("folderFoldout"); 617 | 618 | foldout.style.marginLeft = packagePreviewDirectoryWalker.DirectoryDepth > 0 ? 20 : 0; 619 | 620 | if (packagePreviewDirectoryWalker.DirectoryDepth == 0) 621 | { 622 | packagePreview.Add(foldout); 623 | } 624 | else 625 | { 626 | if (packagePreviewDirectoryWalker.CurrentFoldout == null) 627 | { 628 | packagePreviewDirectoryWalker.CurrentFoldout = packagePreview.Q(packagePreviewDirectoryWalker.CurrentDirectory); 629 | } 630 | 631 | packagePreviewDirectoryWalker.CurrentFoldout.Add(foldout); 632 | } 633 | 634 | packagePreviewDirectoryWalker.CurrentFoldout = foldout; 635 | 636 | packagePreviewDirectoryWalker.CurrentDirectory = tempDirectory; 637 | 638 | packagePreviewDirectoryWalker.DirectoryDepth++; 639 | } 640 | 641 | Label fileLabel = new Label(Path.GetFileName(path)); 642 | fileLabel.AddToClassList("assetLabel"); 643 | fileLabel.style.marginLeft = 20; 644 | packagePreviewDirectoryWalker.CurrentFoldout.Add(fileLabel); 645 | 646 | packagePreviewDirectoryWalker.CurrentDirectory = directoryName; 647 | 648 | packagePreviewDirectoryWalker.CurrentPathIndex++; 649 | 650 | packagePreviewProgressBar.style.width = Length.Percent((float)packagePreviewDirectoryWalker.CurrentPathIndex / (float)packagePreviewDirectoryWalker.PathCount * 100f); 651 | } 652 | catch(Exception e) 653 | { 654 | Debug.LogError($"Error occured while building the package preview:\n{e}"); 655 | 656 | FinishPackageTreePreviewBuild(); 657 | } 658 | } 659 | 660 | /// 661 | /// Checks if fullDirectory contains partialDirectory 662 | /// 663 | /// 664 | /// 665 | /// 666 | private bool DoesDirectoryContainDirectory(string fullDirectory, string partialDirectory) 667 | { 668 | string[] dir1Folders = fullDirectory.Split('/'); 669 | string[] dir2Folders = partialDirectory.Split('/'); 670 | 671 | int dir1Length = dir1Folders.Length; 672 | int dir2Length = dir2Folders.Length; 673 | 674 | // If the number of folders on the full directory is smaller than the partial, return false immediately 675 | if (dir1Length < dir2Length) { return false; } 676 | 677 | for (int i = 0; i < dir2Length; i++) 678 | { 679 | string s1 = dir1Folders[i]; 680 | string s2 = dir2Folders[i]; 681 | 682 | if (s1 != s2) { return false; } 683 | } 684 | 685 | return true; 686 | } 687 | 688 | /// 689 | /// Sets the package tree preview active 690 | /// 691 | /// 692 | private void SetPackagePreviewLoadingScreenActive(bool active) 693 | { 694 | packagePreviewLoadingScreen.style.display = active ? DisplayStyle.Flex : DisplayStyle.None; 695 | } 696 | 697 | /// 698 | /// Gets the index of the deepest common folder between two directories 699 | /// 700 | /// 701 | /// 702 | /// 703 | private int GetDeepestCommonFolderIndex(string directory1, string directory2) 704 | { 705 | string[] dir1Folders = directory1.Split('/'); 706 | string[] dir2Folders = directory2.Split('/'); 707 | 708 | int min = Math.Min(dir1Folders.Length, dir2Folders.Length); 709 | 710 | for (int i = 0; i < min; i++) 711 | { 712 | string s1 = dir1Folders[i]; 713 | string s2 = dir2Folders[i]; 714 | 715 | if (s1 != s2) { return i; } 716 | 717 | if (i == min - 1) { return i + 1; } 718 | } 719 | 720 | return 0; 721 | } 722 | 723 | /// 724 | /// Parses raw FileInfo.Length into pretty format 725 | /// 726 | /// 727 | /// 728 | private static string ParseFileSize(long fileLength) 729 | { 730 | string[] sizes = { "bytes", "KB", "MB", "GB" }; 731 | int i = 0; 732 | 733 | while (fileLength > 1024 && i < sizes.Length) 734 | { 735 | fileLength /= 1024; 736 | 737 | i++; 738 | } 739 | return ($"{fileLength} {sizes[i]}"); 740 | } 741 | 742 | /// 743 | /// Gets the names of all of the available package export configurations 744 | /// 745 | /// 746 | private string[] GetAvailablePackageConfigurationNames() 747 | { 748 | return packageExportConfigurations.Select(c => c.Name).ToArray(); 749 | } 750 | 751 | /// 752 | /// Updates the name of the output file name 753 | /// 754 | private void UpdateOutputFileName() 755 | { 756 | FileName = activeConfiguration.GenerateFileName(packageVersion); 757 | 758 | packageNameField.SetValueWithoutNotify(FileName); 759 | 760 | IsPackageNameDirty = false; 761 | } 762 | 763 | /// 764 | /// Exports the unitypackage using the active configuration 765 | /// 766 | /// 767 | private void ExportPackage() 768 | { 769 | if(pathsToExport.Count == 0) 770 | { 771 | throw new Exception("No exported paths have been defined!"); 772 | } 773 | 774 | bool versionFileModified = false, manifestModified = false; 775 | 776 | #region Write Version To File 777 | string versionPath = activeConfiguration.GetVersionPath(); 778 | 779 | if (!string.IsNullOrEmpty(versionPath)) 780 | { 781 | try 782 | { 783 | using (StreamWriter writer = new StreamWriter(versionPath)) 784 | { 785 | writer.Write(packageVersion); 786 | } 787 | 788 | versionFileModified = true; 789 | } 790 | catch(Exception e) 791 | { 792 | Debug.LogError(e, this); 793 | } 794 | } 795 | #endregion 796 | 797 | #region Modify Manifest Version 798 | string manifestPath = activeConfiguration.GetManifestPath(); 799 | 800 | if (!string.IsNullOrEmpty(manifestPath)) 801 | { 802 | try 803 | { 804 | string json; 805 | 806 | using (StreamReader reader = new StreamReader(manifestPath)) 807 | { 808 | json = reader.ReadToEnd(); 809 | } 810 | 811 | // Get the first index of the version value in the JSON file 812 | int versionPosition = json.IndexOf("\"version\":") + 12; 813 | 814 | // Get the last index of the version value 815 | int versionEndPosition = json.IndexOf("\"", versionPosition); 816 | 817 | // Replace the existing version value with the current version 818 | json = json.Remove(versionPosition, versionEndPosition - versionPosition).Insert(versionPosition, packageVersion); 819 | 820 | using (StreamWriter writer = new StreamWriter(manifestPath)) 821 | { 822 | writer.Write(json); 823 | } 824 | 825 | manifestModified = true; 826 | } 827 | catch(Exception e) 828 | { 829 | Debug.LogError(e, this); 830 | } 831 | } 832 | #endregion 833 | 834 | bool shouldSaveAndRefresh = versionFileModified || manifestModified; 835 | 836 | if (shouldSaveAndRefresh) 837 | { 838 | AssetDatabase.SaveAssets(); 839 | 840 | AssetDatabase.Refresh(); 841 | } 842 | 843 | AssetDatabase.ExportPackage(pathsToExport.ToArray(), $"{Path.Combine(activeConfiguration.ExportDirectory, FileName)}.unitypackage", activeConfiguration.ShowPackageInFileBrowserAfterExport ? ExportPackageOptions.Interactive : ExportPackageOptions.Default); 844 | 845 | if (manifestModified) 846 | { 847 | AssetDatabase.ImportAsset(manifestPath); 848 | } 849 | 850 | SetActiveConfiguration(packageConfigurationNames[activeConfigurationIndex]); 851 | } 852 | } 853 | } 854 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/ExporterWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 067d0603c60021d4dba0ca6c6439dd29 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: 7 | - m_ViewDataDictionary: {instanceID: 0} 8 | - mainWindowUxml: {fileID: 9197481963319205126, guid: 39ecb2d2f0a5009408d5d0e0b89e7ae5, 9 | type: 3} 10 | - noConfigurationsFileUxml: {fileID: 9197481963319205126, guid: 97489d465461ef24bb7b62894e3355a9, 11 | type: 3} 12 | - noConfigurationsUxml: {fileID: 9197481963319205126, guid: c77c7c7c5b04cab4d86103f7d1497726, 13 | type: 3} 14 | executionOrder: 0 15 | icon: {instanceID: 0} 16 | userData: 17 | assetBundleName: 18 | assetBundleVariant: 19 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageExportConfiguration.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using UnityEditor; 6 | using UnityEditorInternal; 7 | using UnityEngine; 8 | using PackageInfo = UnityEditor.PackageManager.PackageInfo; 9 | 10 | namespace Varneon.PackageExporter 11 | { 12 | /// 13 | /// Configuration definition for exporting a package 14 | /// 15 | [Serializable] 16 | public partial class PackageExportConfiguration 17 | { 18 | /// 19 | /// Name of the export configuration 20 | /// 21 | public string Name; 22 | 23 | /// 24 | /// Directory where the package will be exported 25 | /// 26 | public string ExportDirectory = "Assets"; 27 | 28 | /// 29 | /// Template for the exported package name 30 | /// 31 | public string FileNameTemplate = "{n}_v{v}"; 32 | 33 | /// 34 | /// [UPM Package Only] Package Manifest of the UPM package (package.json) 35 | /// 36 | public PackageManifest PackageManifest; 37 | 38 | /// 39 | /// Version file of the package 40 | /// 41 | public TextAsset VersionFile; 42 | 43 | /// 44 | /// Assets that will be exported 45 | /// 46 | public List AssetInclusions = new List(); 47 | 48 | /// 49 | /// Folders that will be exported 50 | /// 51 | public List FolderInclusions = new List(); 52 | 53 | /// 54 | /// Assets that will be excluded from the export 55 | /// 56 | public List AssetExclusions = new List(); 57 | 58 | /// 59 | /// Folders that will be excluded from the export 60 | /// 61 | public List FolderExclusions = new List(); 62 | 63 | /// 64 | /// Should the package directory be opened in file browser after export 65 | /// 66 | public bool ShowPackageInFileBrowserAfterExport = true; 67 | 68 | /// 69 | /// Should the configuration block be expanded in the inspector 70 | /// 71 | [HideInInspector] 72 | public bool ExpandInInspector = true; 73 | 74 | /// 75 | /// Parent configuration storage that this configuration is attached to 76 | /// 77 | public PackageExporterConfigurationStorage ParentStorage; 78 | 79 | public enum DependencyOptions 80 | { 81 | None, 82 | Direct, 83 | Recursive 84 | } 85 | 86 | public PackageExportConfiguration(string name) 87 | { 88 | Name = name; 89 | } 90 | 91 | /// 92 | /// Gets the latest version of the package based on package manifest and version file 93 | /// 94 | /// Version string 95 | public string GetCurrentVersion() 96 | { 97 | Version manifestVersion = new Version(); 98 | 99 | string manifestPath = GetManifestPath(); 100 | 101 | if (!string.IsNullOrEmpty(manifestPath)) 102 | { 103 | PackageInfo info = PackageInfo.FindForAssetPath(manifestPath); 104 | 105 | manifestVersion = new Version(info?.version); 106 | } 107 | 108 | Version fileVersion = new Version(); 109 | 110 | string versionPath = GetVersionPath(); 111 | 112 | if (!string.IsNullOrEmpty(versionPath)) 113 | { 114 | using (StreamReader reader = new StreamReader(versionPath)) 115 | { 116 | fileVersion = new Version(reader.ReadToEnd().ToLower().Trim('v')); 117 | } 118 | } 119 | 120 | return ((manifestVersion >= fileVersion) ? manifestVersion : fileVersion).ToString(); 121 | } 122 | 123 | /// 124 | /// Validates the package manifest file path 125 | /// 126 | /// File path to the package manifest if it's valid 127 | public string GetManifestPath() 128 | { 129 | if(PackageManifest != null) 130 | { 131 | return AssetDatabase.GetAssetPath(PackageManifest); 132 | } 133 | 134 | return string.Empty; 135 | } 136 | 137 | /// 138 | /// Validates the version file path 139 | /// 140 | /// File path to the version file if it's valid 141 | public string GetVersionPath() 142 | { 143 | if(VersionFile != null) 144 | { 145 | return AssetDatabase.GetAssetPath(VersionFile); 146 | } 147 | 148 | return string.Empty; 149 | } 150 | 151 | public string GenerateFileName(string versionString) 152 | { 153 | return PackageFileNameUtility.GenerateName(this, versionString); 154 | } 155 | 156 | public bool IsFileNameTemplateValid() 157 | { 158 | return PackageFileNameUtility.IsNameValid(FileNameTemplate); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageExportConfiguration.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5d0c7ee451b77bc45b5cbbc20b509e5f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageExportConfigurationExclusions.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using UnityEditor; 7 | using UnityEditor.UIElements; 8 | using UnityEngine.UIElements; 9 | using Object = UnityEngine.Object; 10 | 11 | namespace Varneon.PackageExporter 12 | { 13 | /// 14 | /// Inclusion classes for configurations 15 | /// 16 | public partial class PackageExportConfiguration 17 | { 18 | public interface IExclusion 19 | { 20 | List GetPaths(); 21 | 22 | void BindConfigurationBlockElement(VisualElement block, Action markConfigurationsDirtyAction); 23 | } 24 | 25 | [Serializable] 26 | public class AssetExclusion : IExclusion 27 | { 28 | public Object Asset; 29 | 30 | public bool Expanded = true; 31 | 32 | public string PathPreview 33 | { 34 | get 35 | { 36 | return $"Asset: {AssetDatabase.GetAssetPath(Asset)}"; 37 | } 38 | } 39 | 40 | public List GetPaths() 41 | { 42 | List paths = new List(); 43 | 44 | if (Asset == null) { return paths; } 45 | 46 | string assetPath = AssetDatabase.GetAssetPath(Asset); 47 | 48 | paths.Add(assetPath); 49 | 50 | return paths; 51 | } 52 | 53 | public void BindConfigurationBlockElement(VisualElement block, Action markConfigurationsDirtyAction) 54 | { 55 | Foldout foldout = block.Q("Foldout_Data"); 56 | foldout.value = Expanded; 57 | foldout.RegisterValueChangedCallback(a => Expanded = a.newValue); 58 | 59 | Label foldoutLabel = foldout.Q().Q(); 60 | foldoutLabel.text = PathPreview; 61 | 62 | ObjectField assetField = block.Q("ObjectField_Asset"); 63 | assetField.objectType = typeof(Object); 64 | assetField.RegisterValueChangedCallback(a => { 65 | Asset = a.newValue; 66 | foldoutLabel.text = PathPreview; 67 | }); 68 | assetField.SetValueWithoutNotify(Asset); 69 | } 70 | } 71 | 72 | [Serializable] 73 | public class FolderExclusion : IExclusion 74 | { 75 | public DefaultAsset Folder; 76 | 77 | public bool Expanded = true; 78 | 79 | public string PathPreview 80 | { 81 | get 82 | { 83 | return $"Folder: {AssetDatabase.GetAssetPath(Folder)}"; 84 | } 85 | } 86 | 87 | public List GetPaths() 88 | { 89 | List paths = new List(); 90 | 91 | if (Folder == null) { return paths; } 92 | 93 | string folderPath = AssetDatabase.GetAssetPath(Folder); 94 | 95 | paths.AddRange(Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories).Where(p => !p.EndsWith(".meta")).Select(p => p.Replace('\\', '/'))); 96 | 97 | return paths; 98 | } 99 | 100 | public void BindConfigurationBlockElement(VisualElement block, Action markConfigurationsDirtyAction) 101 | { 102 | Foldout foldout = block.Q("Foldout_Data"); 103 | foldout.value = Expanded; 104 | foldout.RegisterValueChangedCallback(a => Expanded = a.newValue); 105 | 106 | Label foldoutLabel = foldout.Q().Q(); 107 | foldoutLabel.text = PathPreview; 108 | 109 | ObjectField folderField = block.Q("ObjectField_Folder"); 110 | folderField.objectType = typeof(Object); 111 | folderField.RegisterValueChangedCallback(a => { 112 | Folder = a.newValue as DefaultAsset; 113 | if (Folder == null) { folderField.SetValueWithoutNotify(null); } 114 | foldoutLabel.text = PathPreview; 115 | }); 116 | folderField.SetValueWithoutNotify(Folder); 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageExportConfigurationExclusions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 122771f28f8001c4b812920184ea4b2f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageExportConfigurationInclusions.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using UnityEditor; 7 | using UnityEditor.UIElements; 8 | using UnityEngine.UIElements; 9 | using Object = UnityEngine.Object; 10 | 11 | namespace Varneon.PackageExporter 12 | { 13 | /// 14 | /// Inclusion classes for configurations 15 | /// 16 | public partial class PackageExportConfiguration 17 | { 18 | public interface IInclusion 19 | { 20 | List GetPaths(); 21 | 22 | void BindConfigurationBlockElement(VisualElement block, Action markConfigurationsDirtyAction); 23 | } 24 | 25 | [Serializable] 26 | public class AssetInclusion : IInclusion 27 | { 28 | public Object Asset; 29 | 30 | public DependencyOptions DependencyOptions; 31 | 32 | public bool Expanded = true; 33 | 34 | public string PathPreview 35 | { 36 | get 37 | { 38 | return $"Asset: {AssetDatabase.GetAssetPath(Asset)}"; 39 | } 40 | } 41 | 42 | public List GetPaths() 43 | { 44 | List paths = new List(); 45 | 46 | if (Asset == null) { return paths; } 47 | 48 | string assetPath = AssetDatabase.GetAssetPath(Asset); 49 | 50 | paths.Add(assetPath); 51 | 52 | if (DependencyOptions != DependencyOptions.None) 53 | { 54 | string[] dependencies = AssetDatabase.GetDependencies(assetPath, DependencyOptions == DependencyOptions.Recursive); 55 | 56 | paths.AddRange(dependencies); 57 | } 58 | 59 | return paths; 60 | } 61 | 62 | public void BindConfigurationBlockElement(VisualElement block, Action markConfigurationsDirtyAction) 63 | { 64 | Foldout foldout = block.Q("Foldout_Data"); 65 | foldout.value = Expanded; 66 | foldout.RegisterValueChangedCallback(a => Expanded = a.newValue); 67 | 68 | Label foldoutLabel = foldout.Q().Q(); 69 | foldoutLabel.text = PathPreview; 70 | 71 | ObjectField assetField = block.Q("ObjectField_Asset"); 72 | assetField.objectType = typeof(Object); 73 | assetField.RegisterValueChangedCallback(a => { 74 | Asset = a.newValue; 75 | foldoutLabel.text = PathPreview; 76 | }); 77 | assetField.SetValueWithoutNotify(Asset); 78 | 79 | EnumField dependencyOptionsField = block.Q("EnumField_DependencyOptions"); 80 | dependencyOptionsField.Init(DependencyOptions); 81 | dependencyOptionsField.RegisterValueChangedCallback(a => { 82 | DependencyOptions = (DependencyOptions)a.newValue; 83 | }); 84 | } 85 | } 86 | 87 | [Serializable] 88 | public class FolderInclusion : IInclusion 89 | { 90 | public DefaultAsset Folder; 91 | 92 | public bool IncludeSubfolders = true; 93 | 94 | public DependencyOptions DependencyOptions; 95 | 96 | public bool Expanded = true; 97 | 98 | public string PathPreview 99 | { 100 | get 101 | { 102 | return $"Folder: {AssetDatabase.GetAssetPath(Folder)}"; 103 | } 104 | } 105 | 106 | public List GetPaths() 107 | { 108 | List paths = new List(); 109 | 110 | if (Folder == null) { return paths; } 111 | 112 | string folderPath = AssetDatabase.GetAssetPath(Folder); 113 | 114 | string[] files = (IncludeSubfolders ? Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories) : Directory.GetFiles(folderPath)).Where(d => !d.EndsWith(".meta")).Select(c => c.Replace('\\', '/')).ToArray(); 115 | 116 | paths.AddRange(files); 117 | 118 | if (DependencyOptions != DependencyOptions.None) 119 | { 120 | string[] dependencies = AssetDatabase.GetDependencies(files, DependencyOptions == DependencyOptions.Recursive); 121 | 122 | paths.AddRange(dependencies); 123 | } 124 | 125 | return paths; 126 | } 127 | 128 | public void BindConfigurationBlockElement(VisualElement block, Action markConfigurationsDirtyAction) 129 | { 130 | Foldout foldout = block.Q("Foldout_Data"); 131 | foldout.value = Expanded; 132 | foldout.RegisterValueChangedCallback(a => Expanded = a.newValue); 133 | 134 | Label foldoutLabel = foldout.Q().Q(); 135 | foldoutLabel.text = PathPreview; 136 | 137 | ObjectField folderField = block.Q("ObjectField_Folder"); 138 | folderField.objectType = typeof(Object); 139 | folderField.RegisterValueChangedCallback(a => { 140 | Folder = a.newValue as DefaultAsset; 141 | if (Folder == null) { folderField.SetValueWithoutNotify(null); } 142 | foldoutLabel.text = PathPreview; 143 | }); 144 | folderField.SetValueWithoutNotify(Folder); 145 | 146 | Toggle subfoldersToggle = block.Q("Toggle_Subfolders"); 147 | subfoldersToggle.RegisterValueChangedCallback(a => { 148 | IncludeSubfolders = a.newValue; 149 | }); 150 | subfoldersToggle.SetValueWithoutNotify(IncludeSubfolders); 151 | 152 | EnumField dependencyOptionsField = block.Q("EnumField_DependencyOptions"); 153 | dependencyOptionsField.Init(DependencyOptions); 154 | dependencyOptionsField.RegisterValueChangedCallback(a => { 155 | DependencyOptions = (DependencyOptions)a.newValue; 156 | }); 157 | } 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageExportConfigurationInclusions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 642177713d594de4cb6ed73a6295d8ce 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageExporterConfigurationStorage.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.Linq; 4 | using System.Collections.Generic; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | namespace Varneon.PackageExporter 9 | { 10 | /// 11 | /// Configuration storage asset for storing definitions for the packages that will be exported from the active Unity project 12 | /// 13 | [CreateAssetMenu(menuName = "PackageExporter/Configuration Storage", fileName = "PackageExporterConfigurationStorage.asset", order = 100)] 14 | public class PackageExporterConfigurationStorage : ScriptableObject 15 | { 16 | public List Configurations = new List(); 17 | 18 | public static PackageExporterConfigurationStorage[] LoadAllConfigurationStorages(bool createNewIfNoneFound = true) 19 | { 20 | PackageExporterConfigurationStorage[] storages = AssetDatabase.FindAssets("t:PackageExporterConfigurationStorage").Select(a => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(a))).ToArray(); 21 | 22 | if (storages.Length == 0 && createNewIfNoneFound) 23 | { 24 | string path = EditorUtility.SaveFilePanelInProject("Create Package Exporter Configuration Storage", "PackageExporterConfigurationStorage", "asset", string.Empty, "Assets"); 25 | 26 | if (string.IsNullOrEmpty(path)) 27 | { 28 | return null; 29 | } 30 | 31 | PackageExporterConfigurationStorage storage = CreateInstance(); 32 | 33 | storage.AddConfiguration(); 34 | 35 | AssetDatabase.CreateAsset(storage, path); 36 | 37 | AssetDatabase.SaveAssets(); 38 | 39 | AssetDatabase.Refresh(); 40 | 41 | try 42 | { 43 | EditorWindow.GetWindow(typeof(Editor).Assembly.GetType("UnityEditor.InspectorWindow")); 44 | 45 | AssetDatabase.OpenAsset(storage); 46 | } 47 | catch(Exception e) 48 | { 49 | Debug.LogError(e); 50 | } 51 | 52 | return new PackageExporterConfigurationStorage[] { storage }; 53 | } 54 | else 55 | { 56 | return storages; 57 | } 58 | } 59 | 60 | /// 61 | /// Adds a new configuration to the storage 62 | /// 63 | /// 64 | /// 65 | public PackageExportConfiguration AddConfiguration(PackageExportConfiguration configuration = null) 66 | { 67 | if (configuration == null) { configuration = new PackageExportConfiguration($"Configuration{Configurations.Count + 1}") { ParentStorage = this }; } 68 | 69 | Configurations.Add(configuration); 70 | 71 | return configuration; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageExporterConfigurationStorage.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5b9200ff32d5b6b4a8662912ce248828 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageExporterConfigurationStorageEditor.cs: -------------------------------------------------------------------------------- 1 | 2 | using UnityEditor; 3 | using UnityEngine; 4 | using UnityEditor.UIElements; 5 | using UnityEngine.UIElements; 6 | using System.IO; 7 | 8 | namespace Varneon.PackageExporter 9 | { 10 | [CustomEditor(typeof(PackageExporterConfigurationStorage))] 11 | internal class PackageExporterConfigurationStorageEditor : Editor 12 | { 13 | [SerializeField] 14 | private VisualTreeAsset 15 | mainWindowUxml, 16 | configurationBlockUxml, 17 | folderInclusionBlockUxml, 18 | assetInclusionBlockUxml, 19 | folderExclusionBlockUxml, 20 | assetExclusionBlockUxml; 21 | 22 | private VisualElement rootVisualElement; 23 | 24 | private ListView configurationListView; 25 | 26 | private PackageExporterConfigurationStorage configurations; 27 | 28 | private ScrollView inspectorScrollView; 29 | 30 | private void OnEnable() 31 | { 32 | configurations = (PackageExporterConfigurationStorage)target; 33 | } 34 | 35 | private void FindInspectorScrollView() 36 | { 37 | inspectorScrollView = rootVisualElement.GetFirstAncestorOfType(); 38 | 39 | if(inspectorScrollView != null) 40 | { 41 | UpdateRootElementHeight(); 42 | 43 | inspectorScrollView.RegisterCallback(a => UpdateRootElementHeight()); 44 | } 45 | 46 | EditorApplication.update -= FindInspectorScrollView; 47 | } 48 | 49 | private void UpdateRootElementHeight() 50 | { 51 | rootVisualElement.style.height = inspectorScrollView.layout.height - 64; 52 | } 53 | 54 | public override VisualElement CreateInspectorGUI() 55 | { 56 | rootVisualElement = new VisualElement(); 57 | 58 | rootVisualElement.Clear(); 59 | 60 | mainWindowUxml.CloneTree(rootVisualElement); 61 | 62 | rootVisualElement.Q("Button_AddConfiguration").clicked += () => AddConfiguration(); 63 | 64 | configurationListView = rootVisualElement.Q("ListView_Configurations"); 65 | 66 | for(int i = 0; i < configurations.Configurations.Count; i++) 67 | { 68 | AddConfigurationBlock(configurations.Configurations[i]); 69 | } 70 | 71 | EditorApplication.update += FindInspectorScrollView; 72 | 73 | return rootVisualElement; 74 | } 75 | 76 | private void AddConfigurationBlock(PackageExportConfiguration configuration) 77 | { 78 | TemplateContainer container = configurationBlockUxml.CloneTree(); 79 | 80 | VisualElement propertyContainer = container.Q("PropertyContainer"); 81 | 82 | Label headerLabel = container.Q("Label_ConfigurationName"); 83 | headerLabel.text = configuration.Name; 84 | headerLabel.RegisterCallback(a => 85 | { 86 | bool expanded = propertyContainer.style.display == DisplayStyle.Flex; 87 | configuration.ExpandInInspector = !expanded; 88 | propertyContainer.style.display = configuration.ExpandInInspector ? DisplayStyle.Flex : DisplayStyle.None; 89 | }); 90 | propertyContainer.style.display = configuration.ExpandInInspector ? DisplayStyle.Flex : DisplayStyle.None; 91 | 92 | TextField configurationNameTextField = container.Q("TextField_ConfigurationName"); 93 | configurationNameTextField.value = configuration.Name; 94 | configurationNameTextField.RegisterValueChangedCallback(a => { 95 | configuration.Name = a.newValue; 96 | headerLabel.text = a.newValue; 97 | MarkConfigurationsDirty(); 98 | }); 99 | 100 | TextField exportDirectoryTextField = container.Q("TextField_ExportDirectory"); 101 | exportDirectoryTextField.value = configuration.ExportDirectory; 102 | exportDirectoryTextField.RegisterValueChangedCallback(a => { 103 | configuration.ExportDirectory = a.newValue; 104 | MarkConfigurationsDirty(); 105 | }); 106 | 107 | container.Q("Button_BrowseExportDirectory").clicked += () => 108 | { 109 | string directory = EditorUtility.OpenFolderPanel("Select package export folder", exportDirectoryTextField.value, string.Empty); 110 | 111 | if (Directory.Exists(directory)) 112 | { 113 | exportDirectoryTextField.value = directory; 114 | } 115 | }; 116 | 117 | VisualElement invalidFileNameTemplateNotifcation = container.Q("InvalidNameTemplateNotifcation"); 118 | 119 | TextField fileNameTemplateTextField = container.Q("TextField_NameTemplate"); 120 | fileNameTemplateTextField.value = configuration.FileNameTemplate; 121 | fileNameTemplateTextField.RegisterValueChangedCallback(a => { 122 | configuration.FileNameTemplate = a.newValue; 123 | invalidFileNameTemplateNotifcation.style.display = configuration.IsFileNameTemplateValid() ? DisplayStyle.None : DisplayStyle.Flex; 124 | MarkConfigurationsDirty(); 125 | }); 126 | 127 | container.Q("Button_ResetNameTemplate").clicked += () => fileNameTemplateTextField.value = "{n}_v{v}"; 128 | 129 | ObjectField versionField = container.Q("ObjectField_VersionFile"); 130 | versionField.objectType = typeof(TextAsset); 131 | versionField.RegisterValueChangedCallback(a => configuration.VersionFile = a.newValue as TextAsset); 132 | versionField.SetValueWithoutNotify(configuration.VersionFile); 133 | 134 | ObjectField manifestField = container.Q("ObjectField_PackageManifest"); 135 | manifestField.objectType = typeof(UnityEditorInternal.PackageManifest); 136 | manifestField.RegisterValueChangedCallback(a => configuration.PackageManifest = a.newValue as UnityEditorInternal.PackageManifest); 137 | manifestField.SetValueWithoutNotify(configuration.PackageManifest); 138 | 139 | container.Q("Button_RemoveConfiguration").clicked += () => { 140 | if(EditorUtility.DisplayDialog("Remove export configuration?", $"Are you sure you want to remove the following package export configuration:\n\n{configuration.Name}", "Yes", "No")) 141 | { 142 | configurations.Configurations.Remove(configuration); 143 | configurationListView.Remove(container); 144 | MarkConfigurationsDirty(); 145 | } 146 | }; 147 | 148 | VisualElement pathInclusionRoot = container.Q("PathInclusionRoot"); 149 | VisualElement pathExclusionRoot = container.Q("PathExclusionRoot"); 150 | 151 | container.Q("Button_AddPathInclusion").clicked += () => { 152 | GenericMenu menu = new GenericMenu(); 153 | menu.AddItem(new GUIContent("Asset"), false, () => { 154 | PackageExportConfiguration.AssetInclusion inclusion = new PackageExportConfiguration.AssetInclusion(); 155 | configuration.AssetInclusions.Add(inclusion); 156 | AddAssetInclusionBlock(pathInclusionRoot, configuration, inclusion); 157 | MarkConfigurationsDirty(); 158 | }); 159 | menu.AddItem(new GUIContent("Folder"), false, () => { 160 | PackageExportConfiguration.FolderInclusion inclusion = new PackageExportConfiguration.FolderInclusion(); 161 | configuration.FolderInclusions.Add(inclusion); 162 | AddFolderInclusionBlock(pathInclusionRoot, configuration, inclusion); 163 | MarkConfigurationsDirty(); 164 | }); 165 | menu.ShowAsContext(); 166 | }; 167 | 168 | container.Q("Button_AddPathExclusion").clicked += () => 169 | { 170 | GenericMenu menu = new GenericMenu(); 171 | menu.AddItem(new GUIContent("Asset"), false, () => { 172 | PackageExportConfiguration.AssetExclusion exclusion = new PackageExportConfiguration.AssetExclusion(); 173 | configuration.AssetExclusions.Add(exclusion); 174 | AddAssetExclusionBlock(pathExclusionRoot, configuration, exclusion); 175 | MarkConfigurationsDirty(); 176 | }); 177 | menu.AddItem(new GUIContent("Folder"), false, () => { 178 | PackageExportConfiguration.FolderExclusion exclusion = new PackageExportConfiguration.FolderExclusion(); 179 | configuration.FolderExclusions.Add(exclusion); 180 | AddFolderExclusionBlock(pathExclusionRoot, configuration, exclusion); 181 | MarkConfigurationsDirty(); 182 | }); 183 | menu.ShowAsContext(); 184 | }; 185 | 186 | for (int i = 0; i < configuration.FolderInclusions.Count; i++) 187 | { 188 | AddFolderInclusionBlock(pathInclusionRoot, configuration, configuration.FolderInclusions[i]); 189 | } 190 | 191 | for (int i = 0; i < configuration.AssetInclusions.Count; i++) 192 | { 193 | AddAssetInclusionBlock(pathInclusionRoot, configuration, configuration.AssetInclusions[i]); 194 | } 195 | 196 | for (int i = 0; i < configuration.FolderExclusions.Count; i++) 197 | { 198 | AddFolderExclusionBlock(pathExclusionRoot, configuration, configuration.FolderExclusions[i]); 199 | } 200 | 201 | for (int i = 0; i < configuration.AssetExclusions.Count; i++) 202 | { 203 | AddAssetExclusionBlock(pathExclusionRoot, configuration, configuration.AssetExclusions[i]); 204 | } 205 | 206 | configurationListView.Add(container); 207 | } 208 | 209 | private void AddConfiguration() 210 | { 211 | PackageExportConfiguration configuration = configurations.AddConfiguration(); 212 | 213 | AddConfigurationBlock(configuration); 214 | 215 | MarkConfigurationsDirty(); 216 | } 217 | 218 | private void AddFolderInclusionBlock(VisualElement root, PackageExportConfiguration configuration, PackageExportConfiguration.FolderInclusion inclusion) 219 | { 220 | TemplateContainer container = folderInclusionBlockUxml.CloneTree(); 221 | 222 | inclusion.BindConfigurationBlockElement(container, () => MarkConfigurationsDirty()); 223 | 224 | container.Q("Button_Remove").clicked += () => { 225 | configuration.FolderInclusions.Remove(inclusion); 226 | root.Remove(container); 227 | }; 228 | 229 | root.Add(container); 230 | } 231 | 232 | private void AddAssetInclusionBlock(VisualElement root, PackageExportConfiguration configuration, PackageExportConfiguration.AssetInclusion inclusion) 233 | { 234 | TemplateContainer container = assetInclusionBlockUxml.CloneTree(); 235 | 236 | inclusion.BindConfigurationBlockElement(container, () => MarkConfigurationsDirty()); 237 | 238 | container.Q("Button_Remove").clicked += () => { 239 | configuration.AssetInclusions.Remove(inclusion); 240 | root.Remove(container); 241 | }; 242 | 243 | root.Add(container); 244 | } 245 | 246 | private void AddFolderExclusionBlock(VisualElement root, PackageExportConfiguration configuration, PackageExportConfiguration.FolderExclusion exclusion) 247 | { 248 | TemplateContainer container = folderExclusionBlockUxml.CloneTree(); 249 | 250 | exclusion.BindConfigurationBlockElement(container, () => MarkConfigurationsDirty()); 251 | 252 | container.Q("Button_Remove").clicked += () => { 253 | configuration.FolderExclusions.Remove(exclusion); 254 | root.Remove(container); 255 | }; 256 | 257 | root.Add(container); 258 | } 259 | 260 | private void AddAssetExclusionBlock(VisualElement root, PackageExportConfiguration configuration, PackageExportConfiguration.AssetExclusion exclusion) 261 | { 262 | TemplateContainer container = assetExclusionBlockUxml.CloneTree(); 263 | 264 | exclusion.BindConfigurationBlockElement(container, () => MarkConfigurationsDirty()); 265 | 266 | container.Q("Button_Remove").clicked += () => { 267 | configuration.AssetExclusions.Remove(exclusion); 268 | root.Remove(container); 269 | }; 270 | 271 | root.Add(container); 272 | } 273 | 274 | private void MarkConfigurationsDirty() 275 | { 276 | EditorUtility.SetDirty(configurations); 277 | } 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageExporterConfigurationStorageEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7cec05466790455429d3439e92a16586 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: 7 | - mainWindowUxml: {fileID: 9197481963319205126, guid: 1768deaf244d04747bd9f6a536da9aae, 8 | type: 3} 9 | - configurationBlockUxml: {fileID: 9197481963319205126, guid: 0b70702c102958948a38ed0bcd297daf, 10 | type: 3} 11 | - folderInclusionBlockUxml: {fileID: 9197481963319205126, guid: 17e602155fae74542b77eeff5c8ff187, 12 | type: 3} 13 | - assetInclusionBlockUxml: {fileID: 9197481963319205126, guid: bc7aaa205dd8a5145855755dd5ab9533, 14 | type: 3} 15 | - folderExclusionBlockUxml: {fileID: 9197481963319205126, guid: f83ec37e87f2fb9459f646d1ef3a2a0d, 16 | type: 3} 17 | - assetExclusionBlockUxml: {fileID: 9197481963319205126, guid: a4bef5d7bcec78e4c9ea1c1fc06c50ea, 18 | type: 3} 19 | executionOrder: 0 20 | icon: {instanceID: 0} 21 | userData: 22 | assetBundleName: 23 | assetBundleVariant: 24 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageFileNameUtility.cs: -------------------------------------------------------------------------------- 1 | 2 | using System.IO; 3 | 4 | namespace Varneon.PackageExporter 5 | { 6 | internal static class PackageFileNameUtility 7 | { 8 | private const string 9 | NamePlaceholder = "{n}", 10 | VersionPlaceholder = "{v}"; 11 | 12 | internal static string GenerateName(PackageExportConfiguration configuration, string versionString) 13 | { 14 | return configuration.FileNameTemplate.Replace(NamePlaceholder, configuration.Name).Replace(VersionPlaceholder, versionString); 15 | } 16 | 17 | internal static bool IsNameValid(string name) 18 | { 19 | return !string.IsNullOrEmpty(name) && name.IndexOfAny(Path.GetInvalidFileNameChars()) < 0; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/PackageFileNameUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e55aa9cffe415104a8a7c0038650f37c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/Varneon.PackageExporter.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Varneon.PackageExporter.Editor", 3 | "references": [], 4 | "includePlatforms": [ 5 | "Editor" 6 | ], 7 | "excludePlatforms": [], 8 | "allowUnsafeCode": false, 9 | "overrideReferences": false, 10 | "precompiledReferences": [], 11 | "autoReferenced": true, 12 | "defineConstraints": [], 13 | "versionDefines": [], 14 | "noEngineReferences": false 15 | } -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Editor/Varneon.PackageExporter.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f6b1d3e226e9b9341967271f2952ecc3 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Varneon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8dba0d4a01d97804abaa130cd6793c30 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62b905ca23a359141aac27d2ec667b11 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/AssetExclusionField.uxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/AssetExclusionField.uxml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a4bef5d7bcec78e4c9ea1c1fc06c50ea 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} 11 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/AssetInclusionField.uxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/AssetInclusionField.uxml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bc7aaa205dd8a5145855755dd5ab9533 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} 11 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/ConfigurationBlock.uxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/ConfigurationBlock.uxml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0b70702c102958948a38ed0bcd297daf 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} 11 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/ConfigurationsWindow.uss: -------------------------------------------------------------------------------- 1 | .configurationHeader { 2 | border-top-color: rgba(143, 150, 190, 255); 3 | border-bottom-color: rgba(47, 50, 63, 255); 4 | background-color: rgba(96, 101, 128, 255); 5 | border-top-width: 1px; 6 | border-bottom-width: 1px; 7 | height: 26px; 8 | flex-direction: row; 9 | align-items: center; 10 | justify-content: space-between; 11 | padding-right: 2px; 12 | } 13 | 14 | .button { 15 | margin-left: 0; 16 | margin-right: 0; 17 | margin-top: 0; 18 | margin-bottom: 0; 19 | border-top-left-radius: 0; 20 | border-bottom-left-radius: 0; 21 | border-top-right-radius: 0; 22 | border-bottom-right-radius: 0; 23 | } 24 | 25 | .button.addButton { 26 | background-image: resource('Icons/Icon_Add'); 27 | width: 14px; 28 | height: 14px; 29 | position: absolute; 30 | top: 0; 31 | right: 0; 32 | } 33 | 34 | .button.browseButton { 35 | margin-left: 5px; 36 | width: 50px; 37 | position: absolute; 38 | right: 0; 39 | top: 0; 40 | } 41 | 42 | .button.resetButton { 43 | margin-left: 5px; 44 | width: 50px; 45 | position: absolute; 46 | right: 0; 47 | top: 0; 48 | } 49 | 50 | .button.removeButton { 51 | background-image: resource('Icons/Icon_Remove'); 52 | } 53 | 54 | .fieldContainer { 55 | margin-left: 3px; 56 | margin-right: 3px; 57 | margin-top: 5px; 58 | margin-bottom: 1px; 59 | flex-direction: row; 60 | justify-content: space-between; 61 | height: 19px; 62 | } 63 | 64 | .textField { 65 | overflow: hidden; 66 | } 67 | 68 | .textField.browseTextField { 69 | position: absolute; 70 | left: 0; 71 | top: 0; 72 | bottom: 0; 73 | right: 55px; 74 | } 75 | 76 | .foldout { 77 | flex-basis: 100%; 78 | } 79 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/ConfigurationsWindow.uss.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4322ac7283fe7d14aab2105fd99701dd 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} 11 | disableValidation: 0 12 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/ConfigurationsWindow.uxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/ConfigurationsWindow.uxml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1768deaf244d04747bd9f6a536da9aae 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} 11 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/ExporterWindow.uss: -------------------------------------------------------------------------------- 1 | .defaultMargin { 2 | margin-left: 5px; 3 | margin-right: 5px; 4 | margin-top: 5px; 5 | margin-bottom: 1px; 6 | } 7 | 8 | #Button_Export { 9 | background-color: rgb(42, 42, 42); 10 | border-left-width: 0; 11 | border-right-width: 0; 12 | border-top-width: 0; 13 | border-bottom-width: 0; 14 | border-top-left-radius: 0; 15 | border-bottom-left-radius: 0; 16 | border-top-right-radius: 0; 17 | border-bottom-right-radius: 0; 18 | } 19 | 20 | #Button_Export:hover { 21 | background-color: rgb(64, 117, 128); 22 | } 23 | 24 | .folderFoldout { 25 | color: rgb(128, 128, 128); 26 | -unity-font-style: bold; 27 | } 28 | 29 | .assetLabel { 30 | margin-left: 20px; 31 | -unity-font-style: normal; 32 | padding-left: 0; 33 | padding-right: 0; 34 | padding-top: 0; 35 | padding-bottom: 0; 36 | } 37 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/ExporterWindow.uss.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e08733bbd2f36c45a657d1d8ec87abb 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} 11 | disableValidation: 0 12 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/ExporterWindow.uxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/ExporterWindow.uxml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 39ecb2d2f0a5009408d5d0e0b89e7ae5 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} 11 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/FolderExclusionField.uxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/FolderExclusionField.uxml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f83ec37e87f2fb9459f646d1ef3a2a0d 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} 11 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/FolderInclusionField.uxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/FolderInclusionField.uxml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 17e602155fae74542b77eeff5c8ff187 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} 11 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ec34983b2c227cc458867b2302aa1961 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_Add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Varneon/Unitypackage-Exporter/a431351e8cff47ce388f4224e25bd05d838fba7c/Packages/com.varneon.package-exporter/Resources/Icons/Icon_Add.png -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_Add.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dc2694d9a1bb1d548ac660ce569870e6 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: 1 35 | aniso: 1 36 | mipBias: 0 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: 0 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 32 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 32 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: Android 88 | maxTextureSize: 32 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | spriteSheet: 99 | serializedVersion: 2 100 | sprites: [] 101 | outline: [] 102 | physicsShape: [] 103 | bones: [] 104 | spriteID: 105 | internalID: 0 106 | vertices: [] 107 | indices: 108 | edges: [] 109 | weights: [] 110 | secondaryTextures: [] 111 | spritePackingTag: 112 | pSDRemoveMatte: 0 113 | pSDShowRemoveMatteOption: 0 114 | userData: 115 | assetBundleName: 116 | assetBundleVariant: 117 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_Dots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Varneon/Unitypackage-Exporter/a431351e8cff47ce388f4224e25bd05d838fba7c/Packages/com.varneon.package-exporter/Resources/Icons/Icon_Dots.png -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_Dots.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e633bed834b1c14408cb543bc7b768c1 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: 1 35 | aniso: 1 36 | mipBias: 0 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: 0 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 128 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 128 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: Android 88 | maxTextureSize: 128 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | spriteSheet: 99 | serializedVersion: 2 100 | sprites: [] 101 | outline: [] 102 | physicsShape: [] 103 | bones: [] 104 | spriteID: 105 | internalID: 0 106 | vertices: [] 107 | indices: 108 | edges: [] 109 | weights: [] 110 | secondaryTextures: [] 111 | spritePackingTag: 112 | pSDRemoveMatte: 0 113 | pSDShowRemoveMatteOption: 0 114 | userData: 115 | assetBundleName: 116 | assetBundleVariant: 117 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_Gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Varneon/Unitypackage-Exporter/a431351e8cff47ce388f4224e25bd05d838fba7c/Packages/com.varneon.package-exporter/Resources/Icons/Icon_Gear.png -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_Gear.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cc7667c9fded027469ed4def30906b80 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: 1 35 | aniso: 1 36 | mipBias: 0 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: 0 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 128 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 128 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: Android 88 | maxTextureSize: 128 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | spriteSheet: 99 | serializedVersion: 2 100 | sprites: [] 101 | outline: [] 102 | physicsShape: [] 103 | bones: [] 104 | spriteID: 105 | internalID: 0 106 | vertices: [] 107 | indices: 108 | edges: [] 109 | weights: [] 110 | secondaryTextures: [] 111 | spritePackingTag: 112 | pSDRemoveMatte: 0 113 | pSDShowRemoveMatteOption: 0 114 | userData: 115 | assetBundleName: 116 | assetBundleVariant: 117 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_QuestionMark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Varneon/Unitypackage-Exporter/a431351e8cff47ce388f4224e25bd05d838fba7c/Packages/com.varneon.package-exporter/Resources/Icons/Icon_QuestionMark.png -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_QuestionMark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e75ed06a194c9c84da94d533d03e481e 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: 1 35 | aniso: 1 36 | mipBias: 0 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: 0 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 128 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 128 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: Android 88 | maxTextureSize: 128 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | spriteSheet: 99 | serializedVersion: 2 100 | sprites: [] 101 | outline: [] 102 | physicsShape: [] 103 | bones: [] 104 | spriteID: 105 | internalID: 0 106 | vertices: [] 107 | indices: 108 | edges: [] 109 | weights: [] 110 | secondaryTextures: [] 111 | spritePackingTag: 112 | pSDRemoveMatte: 0 113 | pSDShowRemoveMatteOption: 0 114 | userData: 115 | assetBundleName: 116 | assetBundleVariant: 117 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_Reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Varneon/Unitypackage-Exporter/a431351e8cff47ce388f4224e25bd05d838fba7c/Packages/com.varneon.package-exporter/Resources/Icons/Icon_Reload.png -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_Reload.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7512cfab720985e4f8efae68675b51d7 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: 1 35 | aniso: 1 36 | mipBias: 0 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: 0 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 128 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 128 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: Android 88 | maxTextureSize: 128 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | spriteSheet: 99 | serializedVersion: 2 100 | sprites: [] 101 | outline: [] 102 | physicsShape: [] 103 | bones: [] 104 | spriteID: 105 | internalID: 0 106 | vertices: [] 107 | indices: 108 | edges: [] 109 | weights: [] 110 | secondaryTextures: [] 111 | spritePackingTag: 112 | pSDRemoveMatte: 0 113 | pSDShowRemoveMatteOption: 0 114 | userData: 115 | assetBundleName: 116 | assetBundleVariant: 117 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_Remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Varneon/Unitypackage-Exporter/a431351e8cff47ce388f4224e25bd05d838fba7c/Packages/com.varneon.package-exporter/Resources/Icons/Icon_Remove.png -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/Icons/Icon_Remove.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5621674af1ea57b499df990407ee7ee3 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: 1 35 | aniso: 1 36 | mipBias: 0 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: 0 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 32 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 32 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: Android 88 | maxTextureSize: 32 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | spriteSheet: 99 | serializedVersion: 2 100 | sprites: [] 101 | outline: [] 102 | physicsShape: [] 103 | bones: [] 104 | spriteID: 105 | internalID: 0 106 | vertices: [] 107 | indices: 108 | edges: [] 109 | weights: [] 110 | secondaryTextures: [] 111 | spritePackingTag: 112 | pSDRemoveMatte: 0 113 | pSDShowRemoveMatteOption: 0 114 | userData: 115 | assetBundleName: 116 | assetBundleVariant: 117 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/NoConfigurationFileMessage.uxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/NoConfigurationFileMessage.uxml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 97489d465461ef24bb7b62894e3355a9 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} 11 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/NoConfigurationsMessage.uxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/NoConfigurationsMessage.uxml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c77c7c7c5b04cab4d86103f7d1497726 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} 11 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/UPMPackageExporter.uss: -------------------------------------------------------------------------------- 1 | .defaultMargin { 2 | margin-left: 5px; 3 | margin-right: 5px; 4 | margin-top: 5px; 5 | margin-bottom: 1px; 6 | } 7 | 8 | #Button_Generate { 9 | background-color: rgb(42, 42, 42); 10 | border-left-width: 0; 11 | border-right-width: 0; 12 | border-top-width: 0; 13 | border-bottom-width: 0; 14 | border-top-left-radius: 0; 15 | border-bottom-left-radius: 0; 16 | border-top-right-radius: 0; 17 | border-bottom-right-radius: 0; 18 | } 19 | 20 | #Button_Generate:hover { 21 | background-color: rgb(64, 117, 128); 22 | } 23 | 24 | .folderFoldout { 25 | color: rgb(128, 128, 128); 26 | -unity-font-style: bold; 27 | } 28 | 29 | .assetLabel { 30 | margin-left: 20px; 31 | -unity-font-style: normal; 32 | padding-left: 0; 33 | padding-right: 0; 34 | padding-top: 0; 35 | padding-bottom: 0; 36 | } 37 | 38 | #Button_NamingHelpURL { 39 | color: rgba(82, 143, 204, 255); 40 | -unity-font-style: bold; 41 | background-color: rgba(0, 0, 0, 0); 42 | border-left-color: rgba(0, 0, 0, 0); 43 | border-right-color: rgba(0, 0, 0, 0); 44 | border-top-color: rgba(0, 0, 0, 0); 45 | border-bottom-color: rgba(0, 0, 0, 0); 46 | border-left-width: 0; 47 | border-right-width: 0; 48 | border-top-width: 0; 49 | border-bottom-width: 0; 50 | border-top-left-radius: 0; 51 | border-bottom-left-radius: 0; 52 | border-top-right-radius: 0; 53 | border-bottom-right-radius: 0; 54 | } 55 | 56 | #Button_NamingHelpURL:hover { 57 | color: rgb(102, 178, 255); 58 | } 59 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/UPMPackageExporter.uss.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2091544d5211e414fb143839e230a7d9 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} 11 | disableValidation: 0 12 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/UPMPackageGenerator.uxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Resources/UPMPackageGenerator.uxml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0db0ffa5e297b7a468794a9153700ef1 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} 11 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Samples~/Self-Export Configuration.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7c5ec5578120b5045af5ca7365d17f10 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Samples~/Self-Export Configuration/PackageExporter_SelfExportConfiguration.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 5b9200ff32d5b6b4a8662912ce248828, type: 3} 13 | m_Name: PackageExporter_SelfExportConfiguration 14 | m_EditorClassIdentifier: 15 | Configurations: 16 | - Name: PackageExporter 17 | ExportDirectory: Assets 18 | FileNameTemplate: '{n}_v{v}' 19 | PackageManifest: {fileID: 8385607101436470782, guid: 58005686e7e69244bbcdf8450a2234e1, 20 | type: 3} 21 | VersionFile: {fileID: 0} 22 | AssetInclusions: [] 23 | FolderInclusions: 24 | - Folder: {fileID: 102900000, guid: 388c363fcf6ad98f030c02ea557e1ff6, type: 3} 25 | IncludeSubfolders: 1 26 | DependencyOptions: 0 27 | Expanded: 1 28 | AssetExclusions: [] 29 | FolderExclusions: [] 30 | ShowPackageInFileBrowserAfterExport: 1 31 | ExpandInInspector: 1 32 | ParentStorage: {fileID: 11400000} 33 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/Samples~/Self-Export Configuration/PackageExporter_SelfExportConfiguration.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c338bac94cdbc7f41bd76fbd21bb3df4 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.varneon.package-exporter", 3 | "version": "0.3.0", 4 | "description": "Unity Editor extension for exporting consistent revisions of unitypackages with custom configurations.", 5 | "displayName": "Package Exporter", 6 | "unity": "2019.4", 7 | "author": { 8 | "name": "Varneon", 9 | "url": "https://github.com/Varneon" 10 | }, 11 | "samples": [ 12 | { 13 | "displayName": "Self-Export Configuration", 14 | "description": "Export configuration for exporting Unitypackage Exporter", 15 | "path": "Samples~/Self-Export Configuration" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /Packages/com.varneon.package-exporter/package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 58005686e7e69244bbcdf8450a2234e1 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > # :warning: Unitypackage Exporter is not compatible with Unity 2022.3! 2 | > Fixing this package will take longer than expected and should not be used in said Unity version! 3 | > 4 | > Please see this [Milestone](https://github.com/Varneon/Unitypackage-Exporter/milestone/2) to check the current status of the compatibility. 5 | 6 | 7 | 8 | # Unitypackage Exporter [](https://github.com/Varneon/Unitypackage-Exporter/stargazers) [](https://github.com/Varneon/Unitypackage-Exporter/releases) [](https://github.com/Varneon/Unitypackage-Exporter/releases/latest) 9 | 10 | 11 | 12 | Unity Editor extension for exporting consistent revisions of unitypackages with custom configurations 13 | 14 | ## Existing Features 15 | * Pre-configured package export configurations for exporting consistently versioned and managed unitypackages 16 | * Automatically managed UPM package manifest versions and version files 17 | 18 | > Want to speed up the creation of new UPM packages? Try my [UPM Package Generator](https://github.com/Varneon/UPM-Package-Generator)! 19 | 20 | |Configuration Editor|Exporter Window| 21 | :-:|:-: 22 | |Create and edit package export configurations using the configuration editor|Modify the version and the name of the package and preview contents of the package| 23 | | 24 | 25 | > ## Unity version compatibility notice: This extension has so far only been tested in Unity 2019.4.31f1 (VRChat focused development), support for other versions will be added at a later date if there are errors caused by compatibility issues 26 | 27 | # Installation 28 | 29 | 30 | 31 | ### Import with [VRChat Creator Companion](https://vcc.docs.vrchat.com/vpm/packages#user-packages): 32 | 33 | > 1. Download `com.varneon.package-exporter.zip` from [here](https://github.com/Varneon/Unitypackage-Exporter/releases/latest) 34 | > 2. Unpack the .zip somewhere 35 | > 3. In VRChat Creator Companion, navigate to `Settings` > `User Packages` > `Add` 36 | > 4. Navigate to the unpacked folder, `com.varneon.package-exporter` and click `Select Folder` 37 | > 5. `Package Exporter` should now be visible under `Local User Packages` in the project view in VRChat Creator Companion 38 | > 6. Click `Add` 39 | 40 | 41 | 42 | ### Import with [Unity Package Manager (git)](https://docs.unity3d.com/2019.4/Documentation/Manual/upm-ui-giturl.html): 43 | 44 | > 1. In the Unity toolbar, select `Window` > `Package Manager` > `[+]` > `Add package from git URL...` 45 | > 2. Paste the following link: `https://github.com/Varneon/Unitypackage-Exporter.git?path=/Packages/com.varneon.package-exporter` 46 | 47 | 48 | 49 | ### Import from [Unitypackage](https://docs.unity3d.com/2019.4/Documentation/Manual/AssetPackagesImport.html): 50 | 51 | > 1. Download latest `com.varneon.package-exporter.unitypackage` from [here](https://github.com/Varneon/Unitypackage-Exporter/releases/latest) 52 | > 2. Import the downloaded .unitypackage into your Unity project 53 | 54 | 55 | 56 | 57 | 58 | ## Developed by Varneon with :hearts: 59 | 60 | [](https://twitter.com/Varneon) 61 | [](https://www.youtube.com/Varneon) 62 | [](https://github.com/Varneon) 63 | 64 | 65 | --------------------------------------------------------------------------------