Support variants

This commit is contained in:
Natsumi
2024-10-02 09:49:08 +13:00
parent 665780ed58
commit 3ff2d687d2
2 changed files with 119 additions and 32 deletions
+74 -28
View File
@@ -34,11 +34,11 @@ namespace VRCX
public static WebClient client; public static WebClient client;
public static Process process; public static Process process;
public string GetAssetId(string id) public string GetAssetId(string id, string variant = "")
{ {
using(var sha256 = SHA256.Create()) 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); StringBuilder idHex = new StringBuilder(hash.Length * 2);
foreach (byte b in hash) foreach (byte b in hash)
{ {
@@ -48,17 +48,45 @@ namespace VRCX
} }
} }
public string GetAssetVersion(int version) public string GetAssetVersion(int version, int variantVersion = 0)
{ {
byte[] bytes = BitConverter.GetBytes(version); var versionHex = string.Empty;
string versionHex = string.Empty; var variantVersionBytes = BitConverter.GetBytes(variantVersion);
foreach (byte b in bytes) foreach (var b in variantVersionBytes)
{ {
versionHex += b.ToString("X2"); versionHex += b.ToString("X2");
} }
var versionBytes = BitConverter.GetBytes(version);
foreach (var b in versionBytes)
{
versionHex += b.ToString("X2");
}
return versionHex.PadLeft(32, '0'); 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() public string GetVRChatCacheLocation()
{ {
return AppApi.Instance.GetVRChatCacheLocation(); return AppApi.Instance.GetVRChatCacheLocation();
@@ -69,12 +97,14 @@ namespace VRCX
/// </summary> /// </summary>
/// <param name="id">The ID of the asset bundle.</param> /// <param name="id">The ID of the asset bundle.</param>
/// <param name="version">The version of the asset bundle.</param> /// <param name="version">The version of the asset bundle.</param>
/// <param name="variant">The variant of the asset bundle.</param>
/// <param name="variantVersion">The version of the variant of the asset bundle.</param>
/// <returns>The full location of the VRChat cache for the specified asset bundle.</returns> /// <returns>The full location of the VRChat cache for the specified asset bundle.</returns>
public string GetVRChatCacheFullLocation(string id, int version) public string GetVRChatCacheFullLocation(string id, int version, string variant = "", int variantVersion = 0)
{ {
var cachePath = GetVRChatCacheLocation(); var cachePath = GetVRChatCacheLocation();
var idHash = GetAssetId(id); var idHash = GetAssetId(id, variant);
var versionLocation = GetAssetVersion(version); var versionLocation = GetAssetVersion(version, variantVersion);
return Path.Combine(cachePath, idHash, versionLocation); return Path.Combine(cachePath, idHash, versionLocation);
} }
@@ -83,12 +113,17 @@ namespace VRCX
/// </summary> /// </summary>
/// <param name="id">The ID of the asset bundle.</param> /// <param name="id">The ID of the asset bundle.</param>
/// <param name="version">The version of the asset bundle.</param> /// <param name="version">The version of the asset bundle.</param>
/// <param name="variant">The variant of the asset bundle.</param>
/// <param name="variantVersion">The version of the variant of the asset bundle.</param>
/// <returns>A Tuple containing the file size, lock status and path of the asset bundle.</returns> /// <returns>A Tuple containing the file size, lock status and path of the asset bundle.</returns>
public Tuple<long, bool, string> CheckVRChatCache(string id, int version) public Tuple<long, bool, string> CheckVRChatCache(string id, int version, string variant, int variantVersion)
{ {
long fileSize = -1; long fileSize = -1;
var isLocked = false; var isLocked = false;
var fullLocation = GetVRChatCacheFullLocation(id, version); var fullLocation = GetVRChatCacheFullLocation(id, version);
if (!Directory.Exists(fullLocation))
fullLocation = GetVRChatCacheFullLocation(id, version, variant, variantVersion);
var fileLocation = Path.Combine(fullLocation, "__data"); var fileLocation = Path.Combine(fullLocation, "__data");
var cachePath = string.Empty; var cachePath = string.Empty;
if (File.Exists(fileLocation)) if (File.Exists(fileLocation))
@@ -206,11 +241,17 @@ namespace VRCX
/// </summary> /// </summary>
/// <param name="id">The ID of the asset bundle to delete.</param> /// <param name="id">The ID of the asset bundle to delete.</param>
/// <param name="version">The version of the asset bundle to delete.</param> /// <param name="version">The version of the asset bundle to delete.</param>
public void DeleteCache(string id, int version) /// <param name="variant">The variant of the asset bundle to delete.</param>
/// <param name="variantVersion">The version of the variant of the asset bundle to delete.</param>
public void DeleteCache(string id, int version, string variant, int variantVersion)
{ {
var FullLocation = GetVRChatCacheFullLocation(id, version); var path = GetVRChatCacheFullLocation(id, version);
if (Directory.Exists(FullLocation)) if (Directory.Exists(path))
Directory.Delete(FullLocation, true); Directory.Delete(path, true);
path = GetVRChatCacheFullLocation(id, version, variant, variantVersion);
if (Directory.Exists(path))
Directory.Delete(path, true);
} }
/// <summary> /// <summary>
@@ -235,26 +276,31 @@ namespace VRCX
if (!Directory.Exists(cachePath)) if (!Directory.Exists(cachePath))
return; return;
var directories = new DirectoryInfo(cachePath); var directories = new DirectoryInfo(cachePath);
DirectoryInfo[] cacheDirectories = directories.GetDirectories(); var cacheDirectories = directories.GetDirectories();
foreach (DirectoryInfo cacheDirectory in cacheDirectories) foreach (var cacheDirectory in cacheDirectories)
{ {
var VersionDirectories = cacheDirectory.GetDirectories().OrderBy(d => Convert.ToInt32(d.Name, 16)); var versionDirectories =
int i = 0; cacheDirectory.GetDirectories().OrderBy(d => ReverseHexToDecimal(d.Name)).ToArray();
foreach (DirectoryInfo VersionDirectory in VersionDirectories) for (var index = 0; index < versionDirectories.Length; index++)
{ {
i++; var versionDirectory = versionDirectories[index];
if (VersionDirectory.GetDirectories().Length + VersionDirectory.GetFiles().Length == 0) if (versionDirectory.GetDirectories().Length + versionDirectory.GetFiles().Length == 0)
{ {
VersionDirectory.Delete(); versionDirectory.Delete(); // delete empty directory
} continue;
else if (i < VersionDirectories.Count())
{
if (!File.Exists(Path.Combine(VersionDirectory.FullName, "__lock")))
VersionDirectory.Delete(true);
} }
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) if (cacheDirectory.GetDirectories().Length + cacheDirectory.GetFiles().Length == 0)
cacheDirectory.Delete(); cacheDirectory.Delete(); // delete empty directory
} }
} }
+45 -4
View File
@@ -5436,6 +5436,18 @@ speechSynthesis.getVoices();
return match ? match[1] : ''; 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 buildTreeData = (json) => {
var node = []; var node = [];
for (var key in json) { for (var key in json) {
@@ -24890,6 +24902,7 @@ speechSynthesis.getVoices();
return { Item1: -1, Item2: false, Item3: '' }; return { Item1: -1, Item2: false, Item3: '' };
} }
var assetUrl = ''; var assetUrl = '';
var variant = '';
for (var i = ref.unityPackages.length - 1; i > -1; i--) { for (var i = ref.unityPackages.length - 1; i > -1; i--) {
var unityPackage = ref.unityPackages[i]; var unityPackage = ref.unityPackages[i];
if ( if (
@@ -24904,6 +24917,9 @@ speechSynthesis.getVoices();
this.compareUnityVersion(unityPackage.unitySortNumber) this.compareUnityVersion(unityPackage.unitySortNumber)
) { ) {
assetUrl = unityPackage.assetUrl; assetUrl = unityPackage.assetUrl;
if (unityPackage.variant !== 'standard') {
variant = unityPackage.variant;
}
break; break;
} }
} }
@@ -24912,11 +24928,17 @@ speechSynthesis.getVoices();
} }
var id = extractFileId(assetUrl); var id = extractFileId(assetUrl);
var version = parseInt(extractFileVersion(assetUrl), 10); var version = parseInt(extractFileVersion(assetUrl), 10);
var variantVersion = parseInt(extractVariantVersion(assetUrl), 10);
if (!id || !version) { if (!id || !version) {
return { Item1: -1, Item2: false, Item3: '' }; return { Item1: -1, Item2: false, Item3: '' };
} }
return AssetBundleCacher.CheckVRChatCache(id, version); return AssetBundleCacher.CheckVRChatCache(
id,
version,
variant,
variantVersion
);
}; };
API.getBundles = function (fileId) { API.getBundles = function (fileId) {
@@ -25060,6 +25082,7 @@ speechSynthesis.getVoices();
$app.methods.deleteVRChatCache = async function (ref) { $app.methods.deleteVRChatCache = async function (ref) {
var assetUrl = ''; var assetUrl = '';
var variant = '';
for (var i = ref.unityPackages.length - 1; i > -1; i--) { for (var i = ref.unityPackages.length - 1; i > -1; i--) {
var unityPackage = ref.unityPackages[i]; var unityPackage = ref.unityPackages[i];
if ( if (
@@ -25074,12 +25097,21 @@ speechSynthesis.getVoices();
this.compareUnityVersion(unityPackage.unitySortNumber) this.compareUnityVersion(unityPackage.unitySortNumber)
) { ) {
assetUrl = unityPackage.assetUrl; assetUrl = unityPackage.assetUrl;
if (unityPackage.variant !== 'standard') {
variant = unityPackage.variant;
}
break; break;
} }
} }
var id = extractFileId(assetUrl); var id = extractFileId(assetUrl);
var version = parseInt(extractFileVersion(assetUrl), 10); 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.getVRChatCacheSize();
this.updateVRChatWorldCache(); this.updateVRChatWorldCache();
this.updateVRChatAvatarCache(); this.updateVRChatAvatarCache();
@@ -25178,6 +25210,7 @@ speechSynthesis.getVoices();
$app.methods.getBundleLocation = async function (input) { $app.methods.getBundleLocation = async function (input) {
var assetUrl = input; var assetUrl = input;
var variant = '';
if (assetUrl) { if (assetUrl) {
// continue // continue
} else if ( } else if (
@@ -25199,6 +25232,9 @@ speechSynthesis.getVoices();
this.compareUnityVersion(unityPackage.unitySortNumber) this.compareUnityVersion(unityPackage.unitySortNumber)
) { ) {
assetUrl = unityPackage.assetUrl; assetUrl = unityPackage.assetUrl;
if (unityPackage.variant !== 'standard') {
variant = unityPackage.variant;
}
break; break;
} }
} }
@@ -25230,13 +25266,18 @@ speechSynthesis.getVoices();
} }
var fileId = extractFileId(assetUrl); var fileId = extractFileId(assetUrl);
var fileVersion = parseInt(extractFileVersion(assetUrl), 10); var fileVersion = parseInt(extractFileVersion(assetUrl), 10);
var variantVersion = parseInt(extractVariantVersion(assetUrl), 10);
var assetLocation = await AssetBundleCacher.GetVRChatCacheFullLocation( var assetLocation = await AssetBundleCacher.GetVRChatCacheFullLocation(
fileId, fileId,
fileVersion fileVersion,
variant,
variantVersion
); );
var cacheInfo = await AssetBundleCacher.CheckVRChatCache( var cacheInfo = await AssetBundleCacher.CheckVRChatCache(
fileId, fileId,
fileVersion fileVersion,
variant,
variantVersion
); );
var inCache = false; var inCache = false;
if (cacheInfo.Item1 > 0) { if (cacheInfo.Item1 > 0) {