mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-11 02:43:50 +02:00
358 lines
13 KiB
C#
358 lines
13 KiB
C#
// Copyright(c) 2019-2020 pypy. All rights reserved.
|
|
//
|
|
// This work is licensed under the terms of the MIT license.
|
|
// For a copy, see <https://opensource.org/licenses/MIT>.
|
|
|
|
using Microsoft.Win32;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Text.RegularExpressions;
|
|
using System.IO;
|
|
using System.Security.Cryptography;
|
|
using System.Net;
|
|
using System.Text;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
|
|
namespace VRCX
|
|
{
|
|
public class AssetBundleCacher
|
|
{
|
|
public static readonly AssetBundleCacher Instance;
|
|
|
|
static AssetBundleCacher()
|
|
{
|
|
Instance = new AssetBundleCacher();
|
|
}
|
|
|
|
public static string AssetBundleCacherTemp;
|
|
public static string VRChatCacheLocation;
|
|
public static string CacheDestinationLocation;
|
|
public static string AssetBundleCacherLocation;
|
|
public static string AssetBundleCacherArgs;
|
|
public static string DownloadTempLocation;
|
|
public static int DownloadProgress;
|
|
public static bool DownloadCanceled;
|
|
public static bool IsUpdate;
|
|
public static string AssetId;
|
|
public static string AssetVersion;
|
|
public static int AssetSize;
|
|
public static string AssetMd5;
|
|
public static WebClient client;
|
|
public static Process process;
|
|
|
|
public string GetAssetId(string id)
|
|
{
|
|
byte[] hash = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(id));
|
|
StringBuilder idHex = new StringBuilder(hash.Length * 2);
|
|
foreach (byte b in hash)
|
|
{
|
|
idHex.AppendFormat("{0:x2}", b);
|
|
}
|
|
return idHex.ToString().ToUpper().Substring(0, 16);
|
|
}
|
|
|
|
public string GetAssetVersion(int version)
|
|
{
|
|
byte[] bytes = BitConverter.GetBytes(version);
|
|
string versionHex = String.Empty;
|
|
foreach (byte b in bytes)
|
|
{
|
|
versionHex += b.ToString("X2");
|
|
}
|
|
return versionHex.PadLeft(32, '0');
|
|
}
|
|
|
|
public string GetVRChatCacheLocation(string cacheDir)
|
|
{
|
|
var cachePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"Low\VRChat\VRChat\Cache-WindowsPlayer";
|
|
if (!string.IsNullOrEmpty(cacheDir) && Directory.Exists(cacheDir))
|
|
cachePath = Path.Combine(cacheDir, @"Cache-WindowsPlayer");
|
|
return cachePath;
|
|
}
|
|
|
|
public string GetAssetBundleCacherLocation(string cacheDir)
|
|
{
|
|
var cachePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"Low\VRChat\VRChat\AssetBundleCacher";
|
|
if (!string.IsNullOrEmpty(cacheDir) && Directory.Exists(cacheDir))
|
|
cachePath = Path.Combine(cacheDir, @"AssetBundleCacher");
|
|
return cachePath;
|
|
}
|
|
|
|
public string GetVRChatCacheFullLocation(string id, int version, string cacheDir)
|
|
{
|
|
var cachePath = GetVRChatCacheLocation(cacheDir);
|
|
var idHash = GetAssetId(id);
|
|
var versionLocation = GetAssetVersion(version);
|
|
return Path.Combine(cachePath, idHash, versionLocation);
|
|
}
|
|
|
|
public long[] CheckVRChatCache(string id, int version, string cacheDir)
|
|
{
|
|
long FileSize = -1;
|
|
long IsLocked = 0;
|
|
var FullLocation = GetVRChatCacheFullLocation(id, version, cacheDir);
|
|
var FileLocation = Path.Combine(FullLocation, "__data");
|
|
if (File.Exists(FileLocation))
|
|
{
|
|
FileInfo data = new FileInfo(FileLocation);
|
|
FileSize = data.Length;
|
|
}
|
|
if (File.Exists(Path.Combine(FullLocation, "__lock")))
|
|
{
|
|
IsLocked = 1;
|
|
}
|
|
return new long[]
|
|
{
|
|
FileSize,
|
|
IsLocked
|
|
};
|
|
}
|
|
|
|
public void DownloadCacheFile(string cacheDir, string url, string id, int version, int sizeInBytes, string md5, string AppVersion, bool IsUpdate)
|
|
{
|
|
if (!File.Exists(Path.Combine(Program.BaseDirectory, "AssetBundleCacher\\AssetBundleCacher.exe")))
|
|
{
|
|
DownloadProgress = -10;
|
|
return;
|
|
}
|
|
// upgrade from Unity 2018 to 2019
|
|
var UnityData = Path.Combine(Program.BaseDirectory, "AssetBundleCacher\\AssetBundleCacher_Data\\data.unity3d");
|
|
if (File.Exists(UnityData))
|
|
{
|
|
try
|
|
{
|
|
File.Delete(UnityData);
|
|
}
|
|
catch
|
|
{
|
|
DownloadProgress = -11;
|
|
return;
|
|
}
|
|
}
|
|
DownloadProgress = 0;
|
|
VRChatCacheLocation = GetVRChatCacheLocation(cacheDir);
|
|
AssetBundleCacherLocation = GetAssetBundleCacherLocation(cacheDir);
|
|
CacheDestinationLocation = GetVRChatCacheFullLocation(id, version, cacheDir);
|
|
if (File.Exists(Path.Combine(CacheDestinationLocation, "__data")))
|
|
{
|
|
DownloadProgress = -12;
|
|
return;
|
|
}
|
|
AssetSize = sizeInBytes;
|
|
AssetMd5 = md5;
|
|
AssetId = GetAssetId(id);
|
|
AssetVersion = GetAssetVersion(version);
|
|
DownloadTempLocation = Path.Combine(AssetBundleCacherLocation, AssetId);
|
|
AssetBundleCacherTemp = Path.Combine(AssetBundleCacherLocation, "Cache");
|
|
Directory.CreateDirectory(AssetBundleCacherTemp);
|
|
AssetBundleCacherArgs = $@" -url ""file:\\{DownloadTempLocation}"" -id ""{id}"" -ver {version} -batchmode -path ""{AssetBundleCacherTemp}""";
|
|
DownloadCanceled = false;
|
|
if (IsUpdate)
|
|
{
|
|
AssetBundleCacher.IsUpdate = true;
|
|
DownloadTempLocation = Path.Combine(Program.AppDataDirectory, "update.exe");
|
|
}
|
|
client = new WebClient();
|
|
client.Headers.Add("user-agent", AppVersion);
|
|
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
|
|
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompletedCallback);
|
|
client.DownloadFileAsync(new System.Uri(url), DownloadTempLocation);
|
|
}
|
|
|
|
public void CancelDownload()
|
|
{
|
|
DownloadCanceled = true;
|
|
try
|
|
{
|
|
if (client != null)
|
|
{
|
|
client.CancelAsync();
|
|
}
|
|
if (process != null && !process.HasExited)
|
|
{
|
|
process.Kill();
|
|
if (File.Exists(DownloadTempLocation))
|
|
File.Delete(DownloadTempLocation);
|
|
if (Directory.Exists(Path.Combine(AssetBundleCacherTemp, AssetId)))
|
|
Directory.Delete(Path.Combine(AssetBundleCacherTemp, AssetId), true);
|
|
}
|
|
}
|
|
catch(Exception)
|
|
{
|
|
|
|
}
|
|
DownloadProgress = -4;
|
|
}
|
|
|
|
public int CheckDownloadProgress()
|
|
{
|
|
return DownloadProgress;
|
|
}
|
|
|
|
private static void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
|
|
{
|
|
DownloadProgress = e.ProgressPercentage;
|
|
}
|
|
|
|
private static void DownloadCompletedCallback(object sender, AsyncCompletedEventArgs e)
|
|
{
|
|
if (DownloadCanceled)
|
|
{
|
|
if (File.Exists(DownloadTempLocation))
|
|
File.Delete(DownloadTempLocation);
|
|
return;
|
|
}
|
|
DownloadProgress = -1;
|
|
if (!File.Exists(DownloadTempLocation))
|
|
{
|
|
DownloadProgress = -15;
|
|
return;
|
|
}
|
|
if (IsUpdate)
|
|
{
|
|
DownloadProgress = -16;
|
|
return;
|
|
}
|
|
FileInfo data = new FileInfo(DownloadTempLocation);
|
|
if (data.Length != AssetSize)
|
|
{
|
|
DownloadProgress = -15;
|
|
return;
|
|
}
|
|
using (var stream = File.OpenRead(DownloadTempLocation))
|
|
{
|
|
byte[] md5AsBytes = MD5.Create().ComputeHash(stream);
|
|
var md5 = System.Convert.ToBase64String(md5AsBytes);
|
|
if (md5 != AssetMd5)
|
|
{
|
|
DownloadProgress = -15;
|
|
return;
|
|
}
|
|
}
|
|
process = new Process();
|
|
process.StartInfo.FileName = Path.Combine(Program.BaseDirectory, "AssetBundleCacher\\AssetBundleCacher.exe");
|
|
process.StartInfo.Arguments = AssetBundleCacherArgs;
|
|
process.Start();
|
|
process.WaitForExit((int) TimeSpan.FromMinutes(2).TotalMilliseconds); //2mins
|
|
if (process.ExitCode != 0)
|
|
{
|
|
DownloadProgress = -13;
|
|
return;
|
|
}
|
|
if (DownloadCanceled)
|
|
{
|
|
if (File.Exists(DownloadTempLocation))
|
|
File.Delete(DownloadTempLocation);
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
if (File.Exists(Path.Combine(CacheDestinationLocation, "__data")))
|
|
{
|
|
if (File.Exists(DownloadTempLocation))
|
|
File.Delete(DownloadTempLocation);
|
|
if (Directory.Exists(Path.Combine(AssetBundleCacherTemp, AssetId)))
|
|
Directory.Delete(Path.Combine(AssetBundleCacherTemp, AssetId), true);
|
|
DownloadProgress = -12;
|
|
return;
|
|
}
|
|
if (Directory.Exists(CacheDestinationLocation))
|
|
Directory.Delete(CacheDestinationLocation, true);
|
|
var CacheSource = Path.Combine(AssetBundleCacherTemp, AssetId, AssetVersion);
|
|
if (!File.Exists(Path.Combine(CacheSource, "__data")))
|
|
{
|
|
DownloadProgress = -13;
|
|
return;
|
|
}
|
|
if (!Directory.Exists(Path.Combine(VRChatCacheLocation, AssetId)))
|
|
Directory.CreateDirectory(Path.Combine(VRChatCacheLocation, AssetId));
|
|
Directory.Move(CacheSource, CacheDestinationLocation);
|
|
Directory.Delete(Path.Combine(AssetBundleCacherTemp, AssetId), true);
|
|
File.Delete(DownloadTempLocation);
|
|
}
|
|
catch(Exception)
|
|
{
|
|
DownloadProgress = -14;
|
|
return;
|
|
}
|
|
DownloadProgress = -3;
|
|
}
|
|
|
|
public void DeleteCache(string cacheDir, string id, int version)
|
|
{
|
|
var FullLocation = GetVRChatCacheFullLocation(id, version, cacheDir);
|
|
if (Directory.Exists(FullLocation))
|
|
Directory.Delete(FullLocation, true);
|
|
}
|
|
|
|
public void DeleteAllCache(string cacheDir)
|
|
{
|
|
var cachePath = GetVRChatCacheLocation(cacheDir);
|
|
if (Directory.Exists(cachePath))
|
|
{
|
|
Directory.Delete(cachePath, true);
|
|
Directory.CreateDirectory(cachePath);
|
|
}
|
|
}
|
|
|
|
public void SweepCache(string cacheDir)
|
|
{
|
|
var cachePath = GetVRChatCacheLocation(cacheDir);
|
|
if (!Directory.Exists(cachePath))
|
|
return;
|
|
var directories = new DirectoryInfo(cachePath);
|
|
DirectoryInfo[] cacheDirectories = directories.GetDirectories();
|
|
foreach (DirectoryInfo cacheDirectory in cacheDirectories)
|
|
{
|
|
var VersionDirectories = cacheDirectory.GetDirectories().OrderBy(d => Convert.ToInt32(d.Name, 16));
|
|
int i = 0;
|
|
foreach (DirectoryInfo VersionDirectory in VersionDirectories)
|
|
{
|
|
i++;
|
|
if (VersionDirectory.GetDirectories().Length + VersionDirectory.GetFiles().Length == 0)
|
|
{
|
|
VersionDirectory.Delete();
|
|
}
|
|
else if (i < VersionDirectories.Count())
|
|
{
|
|
if (!File.Exists(Path.Combine(VersionDirectory.FullName, "__lock")))
|
|
VersionDirectory.Delete(true);
|
|
}
|
|
}
|
|
if (cacheDirectory.GetDirectories().Length + cacheDirectory.GetFiles().Length == 0)
|
|
cacheDirectory.Delete();
|
|
}
|
|
}
|
|
|
|
public long GetCacheSize(string cacheDir)
|
|
{
|
|
var cachePath = GetVRChatCacheLocation(cacheDir);
|
|
if (Directory.Exists(cachePath))
|
|
{
|
|
return DirSize(new DirectoryInfo(cachePath));
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public long DirSize(DirectoryInfo d)
|
|
{
|
|
long size = 0;
|
|
FileInfo[] files = d.GetFiles();
|
|
foreach (FileInfo file in files)
|
|
{
|
|
size += file.Length;
|
|
}
|
|
DirectoryInfo[] directories = d.GetDirectories();
|
|
foreach (DirectoryInfo directory in directories)
|
|
{
|
|
size += DirSize(directory);
|
|
}
|
|
return size;
|
|
}
|
|
}
|
|
}
|