ArabDesert/Packages/com.vrchat.core.vpm-resolver/Editor/Resolver/Resolver.cs

200 lines
6.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
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;
using Version = VRC.PackageManagement.Core.Types.VPMVersion.Version;
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))
{
#pragma warning disable 4014
CheckResolveNeeded();
#pragma warning restore 4014
}
}
private static void SetupLogging()
{
VRCLibLogger.SetLoggerDirectly(
new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Unity3D()
.CreateLogger()
);
}
private static async Task CheckResolveNeeded()
{
SessionState.SetBool(_projectLoadedKey, true);
//Wait for project to finish compiling
while (EditorApplication.isCompiling || EditorApplication.isUpdating)
{
await Task.Delay(250);
}
try
{
if (string.IsNullOrWhiteSpace(ProjectDir))
{
return;
}
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();
}
}
}