Switches to Bootstrapper
This commit is contained in:
parent
2269e76d82
commit
8f3aae926c
33 changed files with 103 additions and 850 deletions
3
Packages/.gitignore
vendored
3
Packages/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
/*/
|
||||
com.vrchat.*/
|
||||
!com.vrchat.core.*/
|
||||
!com.vrchat.core.*/
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1058b5946fb23674cad310b1f4bd5b61
|
||||
guid: 5ee5eebf1b35bbd49ae7983db316180a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
92
Packages/com.vrchat.core.bootstrap/Editor/Bootstrap.cs
Normal file
92
Packages/com.vrchat.core.bootstrap/Editor/Bootstrap.cs
Normal file
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.PackageManagement.Core
|
||||
{
|
||||
public class Bootstrap
|
||||
{
|
||||
// JSON property names in Project Manifest
|
||||
public const string UNITY_PACKAGES_FOLDER = "Packages";
|
||||
public const string UNITY_MANIFEST_FILENAME = "manifest.json";
|
||||
|
||||
// VRC Values
|
||||
public const string VRC_CONFIG = "https://api.vrchat.cloud/api/1/config";
|
||||
public const string VRC_AGENT = "VCCBootstrap 1.0";
|
||||
public const string VRC_RESOLVER_PACKAGE = "com.vrchat.core.vpm-resolver";
|
||||
|
||||
// Finds url for bootstrap package without using JSON
|
||||
private static Regex _bootstrapRegex = new Regex("\"bootstrap\"\\s*:\\s*\"(.+?(?=\"))\"");
|
||||
public static string ManifestPath => Path.Combine(Directory.GetCurrentDirectory(), UNITY_PACKAGES_FOLDER, UNITY_MANIFEST_FILENAME);
|
||||
|
||||
// Path where we expect the target package to exist
|
||||
public static string ResolverPath =>
|
||||
Path.Combine(Directory.GetCurrentDirectory(), UNITY_PACKAGES_FOLDER, VRC_RESOLVER_PACKAGE);
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
public static async void CheckForRestore()
|
||||
{
|
||||
if (!new DirectoryInfo(ResolverPath).Exists)
|
||||
{
|
||||
try
|
||||
{
|
||||
await AddResolver();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Could not download and install the VPM Package Resolver - you may be missing packages. Exception: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task AddResolver()
|
||||
{
|
||||
var configData = await GetRemoteString(VRC_CONFIG);
|
||||
if (string.IsNullOrWhiteSpace(configData))
|
||||
{
|
||||
Debug.LogWarning($"Could not get VPM libraries, try again later");
|
||||
return;
|
||||
}
|
||||
var bootstrapMatch = _bootstrapRegex.Match(configData);
|
||||
if (!bootstrapMatch.Success || bootstrapMatch.Groups.Count < 2)
|
||||
{
|
||||
Debug.LogError($"Could not find bootstrap in config, try again later");
|
||||
return;
|
||||
}
|
||||
|
||||
var url = $"{bootstrapMatch.Groups[1].Value}&cache={Guid.NewGuid()}";
|
||||
|
||||
var targetFile = Path.Combine(Path.GetTempPath(), $"resolver-{DateTime.Now.ToString("yyyyMMddTHHmmss")}.unitypackage");
|
||||
|
||||
// Download to dir
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
// Add User Agent or else CloudFlare will return 1020
|
||||
client.Headers.Add(HttpRequestHeader.UserAgent, VRC_AGENT);
|
||||
|
||||
await client.DownloadFileTaskAsync(url, targetFile);
|
||||
|
||||
if (File.Exists(targetFile))
|
||||
{
|
||||
Debug.Log($"Downloaded Resolver to {targetFile}");
|
||||
AssetDatabase.ImportPackage(targetFile, false);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public static async Task<string> GetRemoteString(string url)
|
||||
{
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
// Add User Agent or else CloudFlare will return 1020
|
||||
client.Headers.Add(HttpRequestHeader.UserAgent, VRC_AGENT);
|
||||
return await client.DownloadStringTaskAsync(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 32d2636186ee0834fa1dc2287750dd32
|
||||
guid: eea11c44cabdaaa43ac0a21dbbbd9824
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "com.vrchat.core.vpm-resolver.Editor",
|
||||
"name": "VRChat.Bootstrapper.Editor",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d1e8c2ba944807d4a9213e2de6930a0b
|
||||
guid: e0d8a3ed977bd0948b99f4bce8e56a07
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7727f888edf4714448d5a0287deec6dd
|
||||
guid: a84f4a071b4a7fa49985f447a0ce2fe2
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name" : "com.vrchat.core.vpm-resolver",
|
||||
"displayName" : "VRChat Package Resolver Tool",
|
||||
"version" : "0.1.12",
|
||||
"name" : "com.vrchat.core.bootstrap",
|
||||
"displayName" : "VRChat Package Bootstrapper",
|
||||
"version" : "0.0.1",
|
||||
"unity" : "2019.4",
|
||||
"description" : "Tool to Download VPM Packages",
|
||||
"vrchatVersion" : "2022.1.1",
|
||||
|
@ -9,9 +9,5 @@
|
|||
"name" : "VRChat",
|
||||
"email" : "developer@vrchat.com",
|
||||
"url" : "https://github.com/vrchat/packages"
|
||||
},
|
||||
"url" : "",
|
||||
"dependencies" : {
|
||||
"com.unity.nuget.newtonsoft-json" : "2.0.2"
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b02e2915ebf04e4ea94e503d73e7411
|
||||
guid: 6c5fffb4815ba9046ad0a2e878396439
|
||||
PackageManifestImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f4e8a9c940ed84943bb0433246ec42bb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -1,33 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 65d82c6541a90644390df2caa29c2209
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -1,33 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0c56563958a156145b708466db0e35cc
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020 Kurai András
|
||||
Copyright (c) 2022-Present VRChat Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 598e678340a8c6e4e9a3debcdc6a9579
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -1,33 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cfc1421f162f0354d8a64d569417d9c9
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -1,33 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 702a5a2579f8edf43b5e7bfb2f52e2c6
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -1,33 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9fd667e0ec0d1d84c9e17dad407f2272
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -1,33 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 140aba2a5b760e94cb3ed9f39a52610a
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,61 +0,0 @@
|
|||
using System.Collections;
|
||||
using UnityEditor;
|
||||
|
||||
namespace VRC.PackageManagement.Resolver
|
||||
{
|
||||
public class EditorCoroutine
|
||||
{
|
||||
public static EditorCoroutine Start( IEnumerator _routine )
|
||||
{
|
||||
EditorCoroutine coroutine = new EditorCoroutine(_routine);
|
||||
coroutine.start();
|
||||
return coroutine;
|
||||
}
|
||||
|
||||
|
||||
public static EditorCoroutine Start(System.Action _action)
|
||||
{
|
||||
EditorCoroutine coroutine = new EditorCoroutine(_action);
|
||||
coroutine.start();
|
||||
return coroutine;
|
||||
}
|
||||
|
||||
readonly IEnumerator routine;
|
||||
EditorCoroutine( IEnumerator _routine )
|
||||
{
|
||||
routine = _routine;
|
||||
}
|
||||
|
||||
readonly System.Action action;
|
||||
EditorCoroutine(System.Action _action)
|
||||
{
|
||||
action = _action;
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
EditorApplication.update += update;
|
||||
}
|
||||
public void stop()
|
||||
{
|
||||
EditorApplication.update -= update;
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
if (routine != null)
|
||||
{
|
||||
if (!routine.MoveNext())
|
||||
stop();
|
||||
}
|
||||
else if (action != null)
|
||||
{
|
||||
action();
|
||||
stop();
|
||||
}
|
||||
else
|
||||
stop();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d750f141971477694e83947d3713160
|
||||
timeCreated: 1659037261
|
|
@ -1,197 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Serilog;
|
||||
using Serilog.Sinks.Unity3D;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VRC.PackageManagement.Core;
|
||||
using VRC.PackageManagement.Core.Types;
|
||||
using VRC.PackageManagement.Core.Types.Packages;
|
||||
|
||||
namespace VRC.PackageManagement.Resolver
|
||||
{
|
||||
|
||||
[InitializeOnLoad]
|
||||
public class Resolver
|
||||
{
|
||||
private const string _projectLoadedKey = "PROJECT_LOADED";
|
||||
|
||||
private static string _projectDir;
|
||||
public static string ProjectDir
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_projectDir != null)
|
||||
{
|
||||
return _projectDir;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_projectDir = new DirectoryInfo(Assembly.GetExecutingAssembly().Location).Parent.Parent.Parent
|
||||
.FullName;
|
||||
return _projectDir;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Resolver()
|
||||
{
|
||||
SetupLogging();
|
||||
if (!SessionState.GetBool(_projectLoadedKey, false))
|
||||
{
|
||||
EditorCoroutine.Start(CheckResolveNeeded());
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetupLogging()
|
||||
{
|
||||
VRCLibLogger.SetLoggerDirectly(
|
||||
new LoggerConfiguration()
|
||||
.MinimumLevel.Information()
|
||||
.WriteTo.Unity3D()
|
||||
.CreateLogger()
|
||||
);
|
||||
}
|
||||
|
||||
private static IEnumerator CheckResolveNeeded()
|
||||
{
|
||||
SessionState.SetBool(_projectLoadedKey, true);
|
||||
|
||||
//Wait for project to finish compiling
|
||||
while (EditorApplication.isCompiling || EditorApplication.isUpdating)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ProjectDir))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (VPMProjectManifest.ResolveIsNeeded(ProjectDir))
|
||||
{
|
||||
Debug.Log($"Resolve needed.");
|
||||
var result = EditorUtility.DisplayDialog("VRChat Package Management",
|
||||
$"This project requires some VRChat Packages which are not in the project yet.\n\nPress OK to download and install them.",
|
||||
"OK", "Show Me What's Missing");
|
||||
if (result)
|
||||
{
|
||||
ResolveStatic(ProjectDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResolverWindow.ShowWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Unity says we can't open windows from this function so it throws an exception but also works fine.
|
||||
}
|
||||
}
|
||||
|
||||
public static bool VPMManifestExists()
|
||||
{
|
||||
return VPMProjectManifest.Exists(ProjectDir, out _);
|
||||
}
|
||||
|
||||
public static void CreateManifest()
|
||||
{
|
||||
VPMProjectManifest.Load(ProjectDir);
|
||||
ResolverWindow.Refresh();
|
||||
}
|
||||
|
||||
public static void ResolveManifest()
|
||||
{
|
||||
ResolveStatic(ProjectDir);
|
||||
}
|
||||
|
||||
public static void ResolveStatic(string dir)
|
||||
{
|
||||
// Todo: calculate and show actual progress
|
||||
EditorUtility.DisplayProgressBar($"Getting all VRChat Packages", "Downloading and Installing...", 0.5f);
|
||||
VPMProjectManifest.Resolve(ProjectDir);
|
||||
EditorUtility.ClearProgressBar();
|
||||
ForceRefresh();
|
||||
}
|
||||
|
||||
public static List<string> GetAllVersionsOf(string id)
|
||||
{
|
||||
var project = new UnityProject(ProjectDir);
|
||||
|
||||
var versions = new List<string>();
|
||||
foreach (var provider in Repos.GetAll)
|
||||
{
|
||||
var packagesWithVersions = provider.GetAllWithVersions();
|
||||
|
||||
foreach (var packageVersionList in packagesWithVersions)
|
||||
{
|
||||
foreach (var package in packageVersionList.Value.VersionsDescending)
|
||||
{
|
||||
if (package.Id != id)
|
||||
continue;
|
||||
if (Version.TryParse(package.Version, out var result))
|
||||
{
|
||||
if (!versions.Contains(package.Version))
|
||||
versions.Add(package.Version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort packages in project to the top
|
||||
var sorted = from entry in versions orderby project.VPMProvider.HasPackage(entry) descending select entry;
|
||||
|
||||
return sorted.ToList<string>();
|
||||
}
|
||||
|
||||
public static List<string> GetAffectedPackageList(IVRCPackage package)
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
|
||||
var project = new UnityProject(ProjectDir);
|
||||
|
||||
if (Repos.GetAllDependencies(package, out Dictionary<string, string> dependencies, null))
|
||||
{
|
||||
foreach (KeyValuePair<string, string> item in dependencies)
|
||||
{
|
||||
project.VPMProvider.Refresh();
|
||||
if (project.VPMProvider.GetPackage(item.Key, item.Value) == null)
|
||||
{
|
||||
IVRCPackage d = Repos.GetPackageWithVersionMatch(item.Key, item.Value);
|
||||
if (d != null)
|
||||
{
|
||||
list.Add(d.Id + " " + d.Version + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void ForceRefresh ()
|
||||
{
|
||||
MethodInfo method = typeof( UnityEditor.PackageManager.Client ).GetMethod( "Resolve", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.DeclaredOnly );
|
||||
if( method != null )
|
||||
method.Invoke( null, null );
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f872e3586f8b4f06bab3c9facd14f6e6
|
||||
timeCreated: 1659048476
|
|
@ -1,292 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using VRC.PackageManagement.Core;
|
||||
using VRC.PackageManagement.Core.Types;
|
||||
using VRC.PackageManagement.Core.Types.Packages;
|
||||
using Version = VRC.PackageManagement.Core.Types.VPMVersion.Version;
|
||||
|
||||
namespace VRC.PackageManagement.Resolver
|
||||
{
|
||||
public class ResolverWindow : EditorWindow
|
||||
{
|
||||
// VisualElements
|
||||
private static VisualElement _rootView;
|
||||
private static Button _refreshButton;
|
||||
private static Button _createButton;
|
||||
private static Button _resolveButton;
|
||||
private static Box _manifestInfo;
|
||||
private static Label _manifestLabel;
|
||||
private static bool _isUpdating;
|
||||
private static Color _colorPositive = Color.green;
|
||||
private static Color _colorNegative = new Color(1, 0.3f, 0.3f);
|
||||
|
||||
|
||||
[MenuItem("VRChat SDK/Utilities/Package Resolver")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
ResolverWindow wnd = GetWindow<ResolverWindow>();
|
||||
wnd.titleContent = new GUIContent("Package Resolver");
|
||||
}
|
||||
|
||||
public static void Refresh()
|
||||
{
|
||||
if (_rootView == null || string.IsNullOrWhiteSpace(Resolver.ProjectDir)) return;
|
||||
|
||||
_manifestInfo.SetEnabled(!_isUpdating);
|
||||
_refreshButton.SetEnabled(!_isUpdating);
|
||||
_manifestLabel.text = (_isUpdating ? "Working ..." : "Required Packages");
|
||||
_manifestInfo.Clear();
|
||||
_manifestInfo.Add(_manifestLabel);
|
||||
|
||||
bool needsResolve = VPMProjectManifest.ResolveIsNeeded(Resolver.ProjectDir);
|
||||
string resolveStatus = needsResolve ? "Please press \"Resolve\" to Download them." : "All of them are in the project.";
|
||||
|
||||
// check for vpm dependencies
|
||||
if (!Resolver.VPMManifestExists())
|
||||
{
|
||||
TextElement noManifestText = new TextElement();
|
||||
noManifestText.text = "No VPM Manifest";
|
||||
noManifestText.style.color = _colorNegative;
|
||||
_manifestInfo.Add(noManifestText);
|
||||
}
|
||||
else
|
||||
{
|
||||
var manifest = VPMProjectManifest.Load(Resolver.ProjectDir);
|
||||
var project = new UnityProject(Resolver.ProjectDir);
|
||||
|
||||
// Here is where we detect if all dependencies are installed
|
||||
var allDependencies = (manifest.locked != null && manifest.locked.Count > 0)
|
||||
? manifest.locked
|
||||
: manifest.dependencies;
|
||||
|
||||
foreach (var pair in allDependencies)
|
||||
{
|
||||
var id = pair.Key;
|
||||
var version = pair.Value.version;
|
||||
IVRCPackage package = project.VPMProvider.GetPackage(id, version);
|
||||
_manifestInfo.Add(CreateDependencyRow(id, version, project, (package != null)));
|
||||
}
|
||||
|
||||
}
|
||||
_resolveButton.SetEnabled(needsResolve);
|
||||
Resolver.ForceRefresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unity calls the CreateGUI method automatically when the window needs to display
|
||||
/// </summary>
|
||||
private void CreateGUI()
|
||||
{
|
||||
_rootView = rootVisualElement;
|
||||
_rootView.name = "root-view";
|
||||
_rootView.styleSheets.Add((StyleSheet)Resources.Load("ResolverWindowStyle"));
|
||||
|
||||
// Main Container
|
||||
var container = new Box()
|
||||
{
|
||||
name = "buttons"
|
||||
};
|
||||
_rootView.Add(container);
|
||||
|
||||
// Create Button
|
||||
if (!Resolver.VPMManifestExists())
|
||||
{
|
||||
_createButton = new Button(Resolver.CreateManifest)
|
||||
{
|
||||
text = "Create",
|
||||
name = "create-button-base"
|
||||
};
|
||||
container.Add(_createButton);
|
||||
}
|
||||
else
|
||||
{
|
||||
_resolveButton = new Button(Resolver.ResolveManifest)
|
||||
{
|
||||
text = "Resolve All",
|
||||
name = "resolve-button-base"
|
||||
};
|
||||
container.Add(_resolveButton);
|
||||
}
|
||||
|
||||
// Manifest Info
|
||||
_manifestInfo = new Box()
|
||||
{
|
||||
name = "manifest-info",
|
||||
};
|
||||
_manifestLabel = (new Label("Required Packages") { name = "manifest-header" });
|
||||
|
||||
_rootView.Add(_manifestInfo);
|
||||
|
||||
// Refresh Button
|
||||
var refreshBox = new Box();
|
||||
_refreshButton = new Button(Refresh)
|
||||
{
|
||||
text = "Refresh",
|
||||
name = "refresh-button-base"
|
||||
};
|
||||
refreshBox.Add(_refreshButton);
|
||||
_rootView.Add(refreshBox);
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private static VisualElement CreateDependencyRow(string id, string version, UnityProject project, bool havePackage)
|
||||
{
|
||||
// Table
|
||||
|
||||
VisualElement row = new Box() { name = "package-box" };
|
||||
VisualElement column1 = new Box() { name = "package-box" };
|
||||
VisualElement column2 = new Box() { name = "package-box" };
|
||||
VisualElement column3 = new Box() { name = "package-box" };
|
||||
VisualElement column4 = new Box() { name = "package-box" };
|
||||
|
||||
column1.style.minWidth = 200;
|
||||
column2.style.minWidth = 100;
|
||||
column3.style.minWidth = 100;
|
||||
column4.style.minWidth = 100;
|
||||
|
||||
row.Add(column1);
|
||||
row.Add(column2);
|
||||
row.Add(column3);
|
||||
row.Add(column4);
|
||||
|
||||
// Package Name + Status
|
||||
|
||||
TextElement text = new TextElement { text = $"{id} {version} " };
|
||||
|
||||
column1.Add(text);
|
||||
|
||||
if (!havePackage)
|
||||
{
|
||||
TextElement missingText = new TextElement { text = "MISSING" };
|
||||
missingText.style.color = _colorNegative;
|
||||
missingText.style.display = (_isUpdating ? DisplayStyle.None : DisplayStyle.Flex);
|
||||
column2.Add(missingText);
|
||||
}
|
||||
|
||||
// Version Popup
|
||||
|
||||
var choices = new List<string>();
|
||||
foreach (string n in Resolver.GetAllVersionsOf(id))
|
||||
{
|
||||
choices.Add(n);
|
||||
}
|
||||
|
||||
var popupField = new PopupField<string>(choices, 0);
|
||||
popupField.value = choices[0];
|
||||
popupField.style.display = (_isUpdating ? DisplayStyle.None : DisplayStyle.Flex);
|
||||
|
||||
column3.Add(popupField);
|
||||
|
||||
// Button
|
||||
|
||||
Button updateButton = new Button() { text = "Update" };
|
||||
if (havePackage)
|
||||
RefreshUpdateButton(updateButton, version, choices[0]);
|
||||
else
|
||||
RefreshMissingButton(updateButton);
|
||||
|
||||
updateButton.clicked += (() =>
|
||||
{
|
||||
IVRCPackage package = Repos.GetPackageWithVersionMatch(id, popupField.value);
|
||||
|
||||
// Check and warn on Dependencies if Updating or Downgrading
|
||||
if (Version.TryParse(version, out var currentVersion) &&
|
||||
Version.TryParse(popupField.value, out var newVersion))
|
||||
{
|
||||
Dictionary<string, string> dependencies = new Dictionary<string, string>();
|
||||
StringBuilder dialogMsg = new StringBuilder();
|
||||
List<string> affectedPackages = Resolver.GetAffectedPackageList(package);
|
||||
for (int v = 0; v < affectedPackages.Count; v++)
|
||||
{
|
||||
dialogMsg.Append(affectedPackages[v]);
|
||||
}
|
||||
|
||||
if (affectedPackages.Count > 1)
|
||||
{
|
||||
dialogMsg.Insert(0, "This will update multiple packages:\n\n");
|
||||
dialogMsg.AppendLine("\nAre you sure?");
|
||||
if (EditorUtility.DisplayDialog("Package Has Dependencies", dialogMsg.ToString(), "OK", "Cancel"))
|
||||
OnUpdatePackageClicked(project, package);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnUpdatePackageClicked(project, package);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
column4.Add(updateButton);
|
||||
|
||||
popupField.RegisterCallback<ChangeEvent<string>>((evt) =>
|
||||
{
|
||||
if (havePackage)
|
||||
RefreshUpdateButton(updateButton, version, evt.newValue);
|
||||
else
|
||||
RefreshMissingButton(updateButton);
|
||||
});
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
private static void RefreshUpdateButton(Button button, string currentVersion, string highestAvailableVersion)
|
||||
{
|
||||
if (currentVersion == highestAvailableVersion)
|
||||
{
|
||||
button.style.display = DisplayStyle.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
button.style.display = (_isUpdating ? DisplayStyle.None : DisplayStyle.Flex);
|
||||
if (Version.TryParse(currentVersion, out var currentVersionObject) &&
|
||||
Version.TryParse(highestAvailableVersion, out var highestAvailableVersionObject))
|
||||
{
|
||||
if (currentVersionObject < highestAvailableVersionObject)
|
||||
{
|
||||
SetButtonColor(button, _colorPositive);
|
||||
button.text = "Update";
|
||||
}
|
||||
else
|
||||
{
|
||||
SetButtonColor(button, _colorNegative);
|
||||
button.text = "Downgrade";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RefreshMissingButton(Button button)
|
||||
{
|
||||
button.text = "Resolve";
|
||||
SetButtonColor(button, Color.white);
|
||||
button.style.display = (_isUpdating ? DisplayStyle.None : DisplayStyle.Flex);
|
||||
}
|
||||
|
||||
private static void SetButtonColor(Button button, Color color)
|
||||
{
|
||||
button.style.color = color;
|
||||
color.a = 0.25f;
|
||||
button.style.borderRightColor =
|
||||
button.style.borderLeftColor =
|
||||
button.style.borderTopColor =
|
||||
button.style.borderBottomColor =
|
||||
color;
|
||||
}
|
||||
|
||||
private static async void OnUpdatePackageClicked(UnityProject project, IVRCPackage package)
|
||||
{
|
||||
_isUpdating = true;
|
||||
Refresh();
|
||||
await Task.Delay(500);
|
||||
await Task.Run(() => project.UpdateVPMPackage(package));
|
||||
_isUpdating = false;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8700b619eebc09545b4aaf4f69a2bf79
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,25 +0,0 @@
|
|||
.unity-box {
|
||||
margin:2px;
|
||||
padding:10px;
|
||||
border-width:0px;
|
||||
}
|
||||
|
||||
#package-box {
|
||||
margin:2px;
|
||||
padding:10px;
|
||||
border-width:0px;
|
||||
flex-direction:row;
|
||||
max-height:20px;
|
||||
min-height:20px;
|
||||
height:20px;
|
||||
padding-top:0px;
|
||||
padding-bottom:0px;
|
||||
margin-top:0px;
|
||||
margin-bottom:0px;
|
||||
align-items:center;
|
||||
}
|
||||
|
||||
#manifest-header {
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 346f7a547766ecb4396d15f585a15133
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
Loading…
Add table
Reference in a new issue