From 97ef396ec90d9b6524d11f10c8b6acffef0dbe96 Mon Sep 17 00:00:00 2001 From: Natsumi Date: Mon, 20 Oct 2025 13:22:22 +1100 Subject: [PATCH] Random fixes --- Dotnet/AppApi/Cef/RegistryPlayerPrefs.cs | 2 +- Dotnet/AppApi/Cef/Screenshot.cs | 20 +++++++++++++++++++ Dotnet/AppApi/Common/AppApiCommon.cs | 4 ++-- Dotnet/AppApi/Electron/Folders.cs | 14 +++++++++++-- Dotnet/AppApi/Electron/RegistryPlayerPrefs.cs | 4 ++-- Dotnet/VRCX-Cef.csproj | 2 +- src/components/dialogs/LaunchDialog.vue | 2 +- src/components/dialogs/NewInstanceDialog.vue | 2 +- .../dialogs/UserDialog/UserDialog.vue | 2 +- src/stores/instance.js | 2 +- src/stores/vrcx.js | 19 +++++++++++++----- src/stores/vrcxUpdater.js | 18 +++++++++++++++++ .../components/FavoritesAvatarItem.vue | 2 +- .../FavoritesAvatarLocalHistoryItem.vue | 2 +- .../components/FavoritesWorldItem.vue | 2 +- src/views/Tools/dialogs/GalleryDialog.vue | 4 ++-- 16 files changed, 79 insertions(+), 22 deletions(-) diff --git a/Dotnet/AppApi/Cef/RegistryPlayerPrefs.cs b/Dotnet/AppApi/Cef/RegistryPlayerPrefs.cs index 6d0468dd..ed692b03 100644 --- a/Dotnet/AppApi/Cef/RegistryPlayerPrefs.cs +++ b/Dotnet/AppApi/Cef/RegistryPlayerPrefs.cs @@ -143,7 +143,7 @@ namespace VRCX var output = new Dictionary>(); using var regKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\VRChat\VRChat"); if (regKey == null) - throw new Exception("Nothing to backup."); + throw new Exception("Failed to get VRC registry data"); var keys = regKey.GetValueNames(); diff --git a/Dotnet/AppApi/Cef/Screenshot.cs b/Dotnet/AppApi/Cef/Screenshot.cs index ebaec36a..b2eb1f7b 100644 --- a/Dotnet/AppApi/Cef/Screenshot.cs +++ b/Dotnet/AppApi/Cef/Screenshot.cs @@ -24,6 +24,26 @@ namespace VRCX var fileName = Path.GetFileNameWithoutExtension(path); if (!File.Exists(path) || !path.EndsWith(".png") || !fileName.StartsWith("VRChat_")) return string.Empty; + + // check if file is in use and we have permission to write + var success = false; + for (var i = 0; i < 10; i++) + { + try + { + using (File.Open(path, FileMode.Append, FileAccess.Write, FileShare.None)) + { + success = true; + break; + } + } + catch (IOException) + { + Thread.Sleep(1000); + } + } + if (!success) + return string.Empty; if (changeFilename) { diff --git a/Dotnet/AppApi/Common/AppApiCommon.cs b/Dotnet/AppApi/Common/AppApiCommon.cs index 70c88ad7..9e5089c1 100644 --- a/Dotnet/AppApi/Common/AppApiCommon.cs +++ b/Dotnet/AppApi/Common/AppApiCommon.cs @@ -14,7 +14,6 @@ namespace VRCX public partial class AppApi { private static readonly Logger logger = LogManager.GetCurrentClassLogger(); - private static readonly MD5 _hasher = MD5.Create(); public void Init() { @@ -30,7 +29,8 @@ namespace VRCX public int GetColourFromUserID(string userId) { - var hash = _hasher.ComputeHash(Encoding.UTF8.GetBytes(userId)); + using var hasher = MD5.Create(); + var hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(userId)); return (hash[3] << 8) | hash[4]; } diff --git a/Dotnet/AppApi/Electron/Folders.cs b/Dotnet/AppApi/Electron/Folders.cs index 4bef51f1..9cf9241d 100644 --- a/Dotnet/AppApi/Electron/Folders.cs +++ b/Dotnet/AppApi/Electron/Folders.cs @@ -30,19 +30,24 @@ namespace VRCX _steamPath = Path.Join(_homeDirectory, ".local/share/Steam"); var flatpakSteamPath = Path.Join(_homeDirectory, ".var/app/com.valvesoftware.Steam/.local/share/Steam"); - if (!Directory.Exists(_steamPath) && Directory.Exists(flatpakSteamPath)) + if (!IsValidSteamPath(_steamPath) && IsValidSteamPath(flatpakSteamPath)) { logger.Info("Flatpak Steam detected."); _steamPath = flatpakSteamPath; } var legacySteamPath = Path.Join(_homeDirectory, ".steam/steam"); - if (!Directory.Exists(_steamPath) && Directory.Exists(legacySteamPath)) + if (!IsValidSteamPath(_steamPath) && IsValidSteamPath(legacySteamPath)) { logger.Info("Legacy Steam path detected."); _steamPath = legacySteamPath; } + if (!IsValidSteamPath(_steamPath)) + { + logger.Error("No valid Steam library found."); + } + var libraryFoldersVdfPath = Path.Join(_steamPath, "config/libraryfolders.vdf"); var vrcLibraryPath = GetLibraryWithAppId(libraryFoldersVdfPath, vrchatAppid); if (string.IsNullOrEmpty(vrcLibraryPath)) @@ -55,6 +60,11 @@ namespace VRCX _vrcAppDataPath = Path.Join(_vrcPrefixPath, "drive_c/users/steamuser/AppData/LocalLow/VRChat/VRChat"); _vrcCrashesPath = Path.Join(_vrcPrefixPath, "drive_c/users/steamuser/AppData/Local/Temp/VRChat/VRChat/Crashes"); } + + private static bool IsValidSteamPath(string path) + { + return File.Exists(Path.Join(path, "config/libraryfolders.vdf")); + } private static string? GetLibraryWithAppId(string libraryFoldersVdfPath, string appId) { diff --git a/Dotnet/AppApi/Electron/RegistryPlayerPrefs.cs b/Dotnet/AppApi/Electron/RegistryPlayerPrefs.cs index 091921e0..ef360a3a 100644 --- a/Dotnet/AppApi/Electron/RegistryPlayerPrefs.cs +++ b/Dotnet/AppApi/Electron/RegistryPlayerPrefs.cs @@ -611,10 +611,10 @@ namespace VRCX public string GetVRChatRegistryJson() { var registry = new Dictionary>(); - string regCommand = "query \"HKEY_CURRENT_USER\\SOFTWARE\\VRChat\\VRChat\""; + const string regCommand = "query \"HKEY_CURRENT_USER\\SOFTWARE\\VRChat\\VRChat\""; var queryResult = GetWineRegCommand(regCommand); if (queryResult == null) - return null; + throw new Exception("Failed to get VRC registry data"); var lines = queryResult.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .Where(line => diff --git a/Dotnet/VRCX-Cef.csproj b/Dotnet/VRCX-Cef.csproj index d1c5ba2b..bec99e87 100644 --- a/Dotnet/VRCX-Cef.csproj +++ b/Dotnet/VRCX-Cef.csproj @@ -1,7 +1,6 @@ ..\build\Cef\ - true WinExe @@ -32,6 +31,7 @@ false false + true 0 diff --git a/src/components/dialogs/LaunchDialog.vue b/src/components/dialogs/LaunchDialog.vue index e043e2ab..7bba2039 100644 --- a/src/components/dialogs/LaunchDialog.vue +++ b/src/components/dialogs/LaunchDialog.vue @@ -185,7 +185,7 @@ const friendsInCurrentInstance = lastLocation.value.friendList; for (const friend of friendsInCurrentInstance.values()) { const ctx = friends.value.get(friend.userId); - if (typeof ctx.ref === 'undefined') { + if (typeof ctx?.ref === 'undefined') { continue; } D.friendsInInstance.push(ctx); diff --git a/src/components/dialogs/NewInstanceDialog.vue b/src/components/dialogs/NewInstanceDialog.vue index cede6e1b..78844457 100644 --- a/src/components/dialogs/NewInstanceDialog.vue +++ b/src/components/dialogs/NewInstanceDialog.vue @@ -594,7 +594,7 @@ const friendsInCurrentInstance = lastLocation.value.friendList; for (const friend of friendsInCurrentInstance.values()) { const ctx = friends.value.get(friend.userId); - if (typeof ctx.ref === 'undefined') { + if (typeof ctx?.ref === 'undefined') { continue; } D.friendsInInstance.push(ctx); diff --git a/src/components/dialogs/UserDialog/UserDialog.vue b/src/components/dialogs/UserDialog/UserDialog.vue index 361f38f8..c9d6808d 100644 --- a/src/components/dialogs/UserDialog/UserDialog.vue +++ b/src/components/dialogs/UserDialog/UserDialog.vue @@ -249,7 +249,7 @@ style="margin-left: 5px" @click="showBioDialog"> -
+
diff --git a/src/stores/instance.js b/src/stores/instance.js index 2600d06e..7c32685e 100644 --- a/src/stores/instance.js +++ b/src/stores/instance.js @@ -364,7 +364,7 @@ export const useInstanceStore = defineStore('Instance', () => { } if ( userStore.userDialog.visible && - userStore.userDialog.ref?.$location.tag === ref.id + userStore.userDialog.ref?.$location?.tag === ref.id ) { userStore.applyUserDialogLocation(); } diff --git a/src/stores/vrcx.js b/src/stores/vrcx.js index 9f5eafac..ae8a0a5c 100644 --- a/src/stores/vrcx.js +++ b/src/stores/vrcx.js @@ -397,6 +397,10 @@ export const useVrcxStore = defineStore('Vrcx', () => { location.worldId, advancedSettingsStore.screenshotHelperModifyFilename ); + if (!newPath) { + console.error('Failed to add screenshot metadata', path); + return; + } console.log('Screenshot metadata added', newPath); } if (advancedSettingsStore.screenshotHelperCopyToClipboard) { @@ -618,11 +622,16 @@ export const useVrcxStore = defineStore('Vrcx', () => { async function backupVrcRegistry(name) { let regJson; - if (WINDOWS) { - regJson = await AppApi.GetVRChatRegistry(); - } else { - regJson = await AppApi.GetVRChatRegistryJson(); - regJson = JSON.parse(regJson); + try { + if (WINDOWS) { + regJson = await AppApi.GetVRChatRegistry(); + } else { + regJson = await AppApi.GetVRChatRegistryJson(); + regJson = JSON.parse(regJson); + } + } catch (e) { + console.error('Failed to get VRChat registry for backup:', e); + return; } const newBackup = { name, diff --git a/src/stores/vrcxUpdater.js b/src/stores/vrcxUpdater.js index 4bfce531..00423302 100644 --- a/src/stores/vrcxUpdater.js +++ b/src/stores/vrcxUpdater.js @@ -200,6 +200,15 @@ export const useVRCXUpdaterStore = defineStore('VRCXUpdater', () => { } finally { checkingForVRCXUpdate.value = false; } + if (response.status !== 200) { + ElMessage({ + message: t('message.vrcx_updater.failed', { + message: `${response.status} ${response.data}` + }), + type: 'error' + }); + return; + } pendingVRCXUpdate.value = false; const json = JSON.parse(response.data); if (AppDebug.debugWebRequests) { @@ -263,6 +272,15 @@ export const useVRCXUpdaterStore = defineStore('VRCXUpdater', () => { } finally { checkingForVRCXUpdate.value = false; } + if (response.status !== 200) { + ElMessage({ + message: t('message.vrcx_updater.failed', { + message: `${response.status} ${response.data}` + }), + type: 'error' + }); + return; + } const json = JSON.parse(response.data); if (AppDebug.debugWebRequests) { console.log(json, response); diff --git a/src/views/Favorites/components/FavoritesAvatarItem.vue b/src/views/Favorites/components/FavoritesAvatarItem.vue index f12671c3..a313974d 100644 --- a/src/views/Favorites/components/FavoritesAvatarItem.vue +++ b/src/views/Favorites/components/FavoritesAvatarItem.vue @@ -170,7 +170,7 @@ t(props.isLocalFavorite ? 'view.favorite.copy_tooltip' : 'view.favorite.move_tooltip') ); const smallThumbnail = computed( - () => localFavFakeRef.value.thumbnailImageUrl.replace('256', '128') || localFavFakeRef.value.thumbnailImageUrl + () => localFavFakeRef.value.thumbnailImageUrl?.replace('256', '128') || localFavFakeRef.value.thumbnailImageUrl ); const favoriteGroupName = computed(() => { if (typeof props.group === 'string') { diff --git a/src/views/Favorites/components/FavoritesAvatarLocalHistoryItem.vue b/src/views/Favorites/components/FavoritesAvatarLocalHistoryItem.vue index 868ca7b9..bfe41fc8 100644 --- a/src/views/Favorites/components/FavoritesAvatarLocalHistoryItem.vue +++ b/src/views/Favorites/components/FavoritesAvatarLocalHistoryItem.vue @@ -68,6 +68,6 @@ defineEmits(['click']); const smallThumbnail = computed(() => { - return props.favorite.thumbnailImageUrl.replace('256', '128') || props.favorite.thumbnailImageUrl; + return props.favorite.thumbnailImageUrl?.replace('256', '128') || props.favorite.thumbnailImageUrl; }); diff --git a/src/views/Favorites/components/FavoritesWorldItem.vue b/src/views/Favorites/components/FavoritesWorldItem.vue index 2049faee..1d8e9bd2 100644 --- a/src/views/Favorites/components/FavoritesWorldItem.vue +++ b/src/views/Favorites/components/FavoritesWorldItem.vue @@ -162,7 +162,7 @@ ); const smallThumbnail = computed(() => { - const url = localFavFakeRef.value.thumbnailImageUrl.replace('256', '128'); + const url = localFavFakeRef.value.thumbnailImageUrl?.replace('256', '128'); return url || localFavFakeRef.value.thumbnailImageUrl; }); diff --git a/src/views/Tools/dialogs/GalleryDialog.vue b/src/views/Tools/dialogs/GalleryDialog.vue index a9a2a3af..a77b02b9 100644 --- a/src/views/Tools/dialogs/GalleryDialog.vue +++ b/src/views/Tools/dialogs/GalleryDialog.vue @@ -670,7 +670,7 @@ } function setProfilePicOverride(fileId) { - if (!currentUser.value.$isVRCPlus) { + if (!isLocalUserVrcPlusSupporter.value) { ElMessage({ message: 'VRCPlus required', type: 'error' @@ -773,7 +773,7 @@ } function setVRCPlusIcon(fileId) { - if (!currentUser.value.$isVRCPlus) { + if (!isLocalUserVrcPlusSupporter.value) { ElMessage({ message: 'VRCPlus required', type: 'error'