diff --git a/Dotnet/AssetBundleCacher.cs b/Dotnet/AssetBundleCacher.cs
index f6646594..6cd36a60 100644
--- a/Dotnet/AssetBundleCacher.cs
+++ b/Dotnet/AssetBundleCacher.cs
@@ -34,11 +34,11 @@ namespace VRCX
public static WebClient client;
public static Process process;
- public string GetAssetId(string id)
+ public string GetAssetId(string id, string variant = "")
{
using(var sha256 = SHA256.Create())
{
- byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(id));
+ byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(id + variant));
StringBuilder idHex = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
{
@@ -48,16 +48,44 @@ namespace VRCX
}
}
- public string GetAssetVersion(int version)
+ public string GetAssetVersion(int version, int variantVersion = 0)
{
- byte[] bytes = BitConverter.GetBytes(version);
- string versionHex = string.Empty;
- foreach (byte b in bytes)
+ var versionHex = string.Empty;
+ var variantVersionBytes = BitConverter.GetBytes(variantVersion);
+ foreach (var b in variantVersionBytes)
{
versionHex += b.ToString("X2");
}
+ var versionBytes = BitConverter.GetBytes(version);
+ foreach (var b in versionBytes)
+ {
+ versionHex += b.ToString("X2");
+ }
+
return versionHex.PadLeft(32, '0');
}
+
+ public int ReverseHexToDecimal(string hexString)
+ {
+ if (hexString.Length != 32)
+ return 0; // it's cooked
+
+ var versionHexString = hexString.Substring(16, 8); // 16..24
+ var variantVersionHexString = hexString.Substring(24, 8); // 24..32
+ var versionBytes = new byte[4];
+ var variantVersionBytes = new byte[4];
+ for (var i = 0; i < 4; i++)
+ {
+ var versionValue = Convert.ToInt32(versionHexString.Substring(i * 2, 2), 16);
+ versionBytes[i] = (byte)versionValue;
+ var variantVersionValue = Convert.ToInt32(variantVersionHexString.Substring(i * 2, 2), 16);
+ variantVersionBytes[i] = (byte)variantVersionValue;
+ }
+ var version = BitConverter.ToInt32(versionBytes, 0);
+ var variantVersion = BitConverter.ToInt32(variantVersionBytes, 0);
+
+ return version + variantVersion;
+ }
public string GetVRChatCacheLocation()
{
@@ -69,12 +97,14 @@ namespace VRCX
///
/// The ID of the asset bundle.
/// The version of the asset bundle.
+ /// The variant of the asset bundle.
+ /// The version of the variant of the asset bundle.
/// The full location of the VRChat cache for the specified asset bundle.
- public string GetVRChatCacheFullLocation(string id, int version)
+ public string GetVRChatCacheFullLocation(string id, int version, string variant = "", int variantVersion = 0)
{
var cachePath = GetVRChatCacheLocation();
- var idHash = GetAssetId(id);
- var versionLocation = GetAssetVersion(version);
+ var idHash = GetAssetId(id, variant);
+ var versionLocation = GetAssetVersion(version, variantVersion);
return Path.Combine(cachePath, idHash, versionLocation);
}
@@ -83,12 +113,17 @@ namespace VRCX
///
/// The ID of the asset bundle.
/// The version of the asset bundle.
+ /// The variant of the asset bundle.
+ /// The version of the variant of the asset bundle.
/// A Tuple containing the file size, lock status and path of the asset bundle.
- public Tuple CheckVRChatCache(string id, int version)
+ public Tuple CheckVRChatCache(string id, int version, string variant, int variantVersion)
{
long fileSize = -1;
var isLocked = false;
var fullLocation = GetVRChatCacheFullLocation(id, version);
+ if (!Directory.Exists(fullLocation))
+ fullLocation = GetVRChatCacheFullLocation(id, version, variant, variantVersion);
+
var fileLocation = Path.Combine(fullLocation, "__data");
var cachePath = string.Empty;
if (File.Exists(fileLocation))
@@ -206,11 +241,17 @@ namespace VRCX
///
/// The ID of the asset bundle to delete.
/// The version of the asset bundle to delete.
- public void DeleteCache(string id, int version)
+ /// The variant of the asset bundle to delete.
+ /// The version of the variant of the asset bundle to delete.
+ public void DeleteCache(string id, int version, string variant, int variantVersion)
{
- var FullLocation = GetVRChatCacheFullLocation(id, version);
- if (Directory.Exists(FullLocation))
- Directory.Delete(FullLocation, true);
+ var path = GetVRChatCacheFullLocation(id, version);
+ if (Directory.Exists(path))
+ Directory.Delete(path, true);
+
+ path = GetVRChatCacheFullLocation(id, version, variant, variantVersion);
+ if (Directory.Exists(path))
+ Directory.Delete(path, true);
}
///
@@ -235,26 +276,31 @@ namespace VRCX
if (!Directory.Exists(cachePath))
return;
var directories = new DirectoryInfo(cachePath);
- DirectoryInfo[] cacheDirectories = directories.GetDirectories();
- foreach (DirectoryInfo cacheDirectory in cacheDirectories)
+ var cacheDirectories = directories.GetDirectories();
+ foreach (var cacheDirectory in cacheDirectories)
{
- var VersionDirectories = cacheDirectory.GetDirectories().OrderBy(d => Convert.ToInt32(d.Name, 16));
- int i = 0;
- foreach (DirectoryInfo VersionDirectory in VersionDirectories)
+ var versionDirectories =
+ cacheDirectory.GetDirectories().OrderBy(d => ReverseHexToDecimal(d.Name)).ToArray();
+ for (var index = 0; index < versionDirectories.Length; index++)
{
- i++;
- if (VersionDirectory.GetDirectories().Length + VersionDirectory.GetFiles().Length == 0)
+ var versionDirectory = versionDirectories[index];
+ 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);
+ versionDirectory.Delete(); // delete empty directory
+ continue;
}
+
+ if (index == versionDirectories.Length - 1)
+ continue; // skip last version
+
+ if (File.Exists(Path.Combine(versionDirectory.FullName, "__lock")))
+ continue; // skip locked version
+
+ versionDirectory.Delete(true);
}
+
if (cacheDirectory.GetDirectories().Length + cacheDirectory.GetFiles().Length == 0)
- cacheDirectory.Delete();
+ cacheDirectory.Delete(); // delete empty directory
}
}
diff --git a/html/src/app.js b/html/src/app.js
index a79aa6bf..566b3daf 100644
--- a/html/src/app.js
+++ b/html/src/app.js
@@ -5436,6 +5436,18 @@ speechSynthesis.getVoices();
return match ? match[1] : '';
};
+ var extractVariantVersion = (url) => {
+ if (!url) {
+ return '';
+ }
+ try {
+ const params = new URLSearchParams(new URL(url).search);
+ return params.get('v');
+ } catch {
+ return '';
+ }
+ };
+
var buildTreeData = (json) => {
var node = [];
for (var key in json) {
@@ -24890,6 +24902,7 @@ speechSynthesis.getVoices();
return { Item1: -1, Item2: false, Item3: '' };
}
var assetUrl = '';
+ var variant = '';
for (var i = ref.unityPackages.length - 1; i > -1; i--) {
var unityPackage = ref.unityPackages[i];
if (
@@ -24904,6 +24917,9 @@ speechSynthesis.getVoices();
this.compareUnityVersion(unityPackage.unitySortNumber)
) {
assetUrl = unityPackage.assetUrl;
+ if (unityPackage.variant !== 'standard') {
+ variant = unityPackage.variant;
+ }
break;
}
}
@@ -24912,11 +24928,17 @@ speechSynthesis.getVoices();
}
var id = extractFileId(assetUrl);
var version = parseInt(extractFileVersion(assetUrl), 10);
+ var variantVersion = parseInt(extractVariantVersion(assetUrl), 10);
if (!id || !version) {
return { Item1: -1, Item2: false, Item3: '' };
}
- return AssetBundleCacher.CheckVRChatCache(id, version);
+ return AssetBundleCacher.CheckVRChatCache(
+ id,
+ version,
+ variant,
+ variantVersion
+ );
};
API.getBundles = function (fileId) {
@@ -25060,6 +25082,7 @@ speechSynthesis.getVoices();
$app.methods.deleteVRChatCache = async function (ref) {
var assetUrl = '';
+ var variant = '';
for (var i = ref.unityPackages.length - 1; i > -1; i--) {
var unityPackage = ref.unityPackages[i];
if (
@@ -25074,12 +25097,21 @@ speechSynthesis.getVoices();
this.compareUnityVersion(unityPackage.unitySortNumber)
) {
assetUrl = unityPackage.assetUrl;
+ if (unityPackage.variant !== 'standard') {
+ variant = unityPackage.variant;
+ }
break;
}
}
var id = extractFileId(assetUrl);
var version = parseInt(extractFileVersion(assetUrl), 10);
- await AssetBundleCacher.DeleteCache(id, version);
+ var variantVersion = parseInt(extractVariantVersion(assetUrl), 10);
+ await AssetBundleCacher.DeleteCache(
+ id,
+ version,
+ variant,
+ variantVersion
+ );
this.getVRChatCacheSize();
this.updateVRChatWorldCache();
this.updateVRChatAvatarCache();
@@ -25178,6 +25210,7 @@ speechSynthesis.getVoices();
$app.methods.getBundleLocation = async function (input) {
var assetUrl = input;
+ var variant = '';
if (assetUrl) {
// continue
} else if (
@@ -25199,6 +25232,9 @@ speechSynthesis.getVoices();
this.compareUnityVersion(unityPackage.unitySortNumber)
) {
assetUrl = unityPackage.assetUrl;
+ if (unityPackage.variant !== 'standard') {
+ variant = unityPackage.variant;
+ }
break;
}
}
@@ -25230,13 +25266,18 @@ speechSynthesis.getVoices();
}
var fileId = extractFileId(assetUrl);
var fileVersion = parseInt(extractFileVersion(assetUrl), 10);
+ var variantVersion = parseInt(extractVariantVersion(assetUrl), 10);
var assetLocation = await AssetBundleCacher.GetVRChatCacheFullLocation(
fileId,
- fileVersion
+ fileVersion,
+ variant,
+ variantVersion
);
var cacheInfo = await AssetBundleCacher.CheckVRChatCache(
fileId,
- fileVersion
+ fileVersion,
+ variant,
+ variantVersion
);
var inCache = false;
if (cacheInfo.Item1 > 0) {