diff --git a/Dotnet/Discord.cs b/Dotnet/Discord.cs index f293c40c..745dfaae 100644 --- a/Dotnet/Discord.cs +++ b/Dotnet/Discord.cs @@ -70,6 +70,22 @@ namespace VRCX if (_client == null && _active) { _client = new DiscordRpcClient(_discordAppId); + _client.OnReady += (sender, e) => + { + _logger.Info("Discord Rich Presence connected: {User}", e.User.DisplayName); + }; + _client.OnError += (sender, e) => + { + _logger.Error("Discord Rich Presence error: {Error}", e.Message); + }; + _client.OnConnectionFailed += (sender, e) => + { + _logger.Error("Discord Rich Presence connection failed: {Error}", e.Type); + }; + _client.OnConnectionEstablished += (sender, e) => + { + _logger.Info("Discord Rich Presence connection established"); + }; if (!_client.Initialize()) { _client.Dispose(); @@ -123,7 +139,7 @@ namespace VRCX public void SetAssets( string details, string state, - string stateUrl, + string detailsUrl, string largeKey, string largeText, @@ -156,8 +172,8 @@ namespace VRCX } _presence.Details = LimitByteLength(details, 127); - // _presence.DetailsUrl - _presence.StateUrl = !string.IsNullOrEmpty(stateUrl) ? stateUrl : null; + _presence.DetailsUrl = !string.IsNullOrEmpty(detailsUrl) ? detailsUrl : null; + // _presence.StateUrl _presence.State = LimitByteLength(state, 127); _presence.Assets ??= new Assets(); diff --git a/src/localization/en/en.json b/src/localization/en/en.json index 2c47055f..068e1d2b 100644 --- a/src/localization/en/en.json +++ b/src/localization/en/en.json @@ -522,6 +522,13 @@ "join_button": "Join button (public only)", "show_details_in_private": "Show world details in private", "show_images": "Show world images" + }, + "rpc": { + "vr": "VR", + "desktop": "Desktop", + "join_button": "Join", + "powered_by_vrcx": "Powered by VRCX", + "private_world": "Private World" } }, "pictures": { diff --git a/src/stores/notification.js b/src/stores/notification.js index f47492a8..8b15a366 100644 --- a/src/stores/notification.js +++ b/src/stores/notification.js @@ -2188,9 +2188,9 @@ export const useNotificationStore = defineStore('Notification', () => { let bias; // remove join/leave notifications when switching worlds if ( - noty.type === 'OnPlayerJoined' || - noty.type === 'BlockedOnPlayerJoined' || - noty.type === 'MutedOnPlayerJoined' + noty.type === 'OnPlayerJoined' + // noty.type === 'BlockedOnPlayerJoined' || + // noty.type === 'MutedOnPlayerJoined' ) { bias = locationStore.lastLocation.date + 30 * 1000; // 30 secs if (Date.parse(noty.created_at) <= bias) { diff --git a/src/stores/settings/advanced.js b/src/stores/settings/advanced.js index 04a4990a..94e0ef8a 100644 --- a/src/stores/settings/advanced.js +++ b/src/stores/settings/advanced.js @@ -125,7 +125,7 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => { state.progressPie = progressPie; state.progressPieFilter = progressPieFilter; state.showConfirmationOnSwitchAvatar = showConfirmationOnSwitchAvatar; - state.gameLogDisabled = gameLogDisabled === 'true'; + state.gameLogDisabled = gameLogDisabled; state.ugcFolderPath = ugcFolderPath; state.autoDeleteOldPrints = autoDeleteOldPrints; state.notificationOpacity = notificationOpacity; @@ -532,7 +532,7 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => { state.folderSelectorDialogVisible = true; let newFolder = ''; if (WINDOWS) { - newFolder = await AppApi.OpenFolderSelectorDialog(oldPath); + newFolder = await AppApi.OpenFolderSelectorDialog(oldPath); } else { newFolder = await window.electron.openDirectoryDialog(); } diff --git a/src/stores/settings/discordPresence.js b/src/stores/settings/discordPresence.js index e3a6956f..ddda81bd 100644 --- a/src/stores/settings/discordPresence.js +++ b/src/stores/settings/discordPresence.js @@ -14,18 +14,18 @@ import { useGameLogStore } from '../gameLog'; import { useLocationStore } from '../location'; import { useUpdateLoopStore } from '../updateLoop'; import { useUserStore } from '../user'; -import { useAdvancedSettingsStore } from './advanced'; import { ActivityType } from '../../shared/constants/discord'; +import { useI18n } from 'vue-i18n-bridge'; export const useDiscordPresenceSettingsStore = defineStore( 'DiscordPresenceSettings', () => { const locationStore = useLocationStore(); const gameStore = useGameStore(); - const advancedSettingsStore = useAdvancedSettingsStore(); const gameLogStore = useGameLogStore(); const userStore = useUserStore(); const updateLoopStore = useUpdateLoopStore(); + const { t } = useI18n(); const state = reactive({ discordActive: false, @@ -116,7 +116,7 @@ export const useDiscordPresenceSettingsStore = defineStore( currentLocation = locationStore.lastLocationDestination; startTime = locationStore.lastLocationDestinationTime; } - if (advancedSettingsStore.gameLogDisabled) { + if (!currentLocation) { // game log disabled, use API location currentLocation = userStore.currentUser.$locationTag; startTime = userStore.currentUser.$location_at; @@ -125,12 +125,7 @@ export const useDiscordPresenceSettingsStore = defineStore( userStore.currentUser.$travelingToLocation; } } - if ( - !state.discordActive || - (!gameStore.isGameRunning && - !advancedSettingsStore.gameLogDisabled) || - !isRealInstance(currentLocation) - ) { + if (!state.discordActive || !isRealInstance(currentLocation)) { setIsDiscordActive(false); return; } @@ -167,36 +162,44 @@ export const useDiscordPresenceSettingsStore = defineStore( ); } - let platform = gameStore.isGameNoVR ? 'Desktop' : 'VR'; + let platform = gameStore.isGameNoVR + ? t('view.settings.discord_presence.rpc.desktop') + : t('view.settings.discord_presence.rpc.vr'); if (L.groupAccessType) { if (L.groupAccessType === 'public') { - state.lastLocationDetails.groupAccessType = 'Public'; + state.lastLocationDetails.groupAccessType = t( + 'dialog.new_instance.group_access_type_public' + ); } else if (L.groupAccessType === 'plus') { - state.lastLocationDetails.groupAccessType = 'Plus'; + state.lastLocationDetails.groupAccessType = t( + 'dialog.new_instance.group_access_type_plus' + ); } } switch (L.accessType) { case 'public': state.lastLocationDetails.joinUrl = getLaunchURL(L); - state.lastLocationDetails.accessName = `Public #${L.instanceName} (${platform})`; + state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_public')} #${L.instanceName} (${platform})`; break; case 'invite+': - state.lastLocationDetails.accessName = `Invite+ #${L.instanceName} (${platform})`; + state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_invite_plus')} #${L.instanceName} (${platform})`; break; case 'invite': - state.lastLocationDetails.accessName = `Invite #${L.instanceName} (${platform})`; + state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_invite')} #${L.instanceName} (${platform})`; break; case 'friends': - state.lastLocationDetails.accessName = `Friends #${L.instanceName} (${platform})`; + state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_friend')} #${L.instanceName} (${platform})`; break; case 'friends+': - state.lastLocationDetails.accessName = `Friends+ #${L.instanceName} (${platform})`; + state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_friend_plus')}+ #${L.instanceName} (${platform})`; break; case 'group': - state.lastLocationDetails.accessName = `Group #${L.instanceName} (${platform})`; + state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_group')} #${L.instanceName} (${platform})`; try { const groupName = await getGroupName(L.groupId); - state.lastLocationDetails.accessName = `Group${state.lastLocationDetails.groupAccessType}(${groupName}) #${L.instanceName} (${platform})`; + if (groupName) { + state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_group')}${state.lastLocationDetails.groupAccessType}(${groupName}) #${L.instanceName} (${platform})`; + } } catch (e) { console.error( `Failed to get group name for ${L.groupId}`, @@ -220,27 +223,27 @@ export const useDiscordPresenceSettingsStore = defineStore( let statusImage = ''; switch (userStore.currentUser.status) { case 'active': - statusName = 'Online'; + statusName = t('dialog.user.status.active'); statusImage = 'active'; break; case 'join me': - statusName = 'Join Me'; + statusName = t('dialog.user.status.join_me'); statusImage = 'joinme'; break; case 'ask me': - statusName = 'Ask Me'; + statusName = t('dialog.user.status.ask_me'); statusImage = 'askme'; if (state.discordHideInvite) { hidePrivate = true; } break; case 'busy': - statusName = 'Do Not Disturb'; + statusName = t('dialog.user.status.busy'); statusImage = 'busy'; hidePrivate = true; break; default: - statusName = 'Offline'; + statusName = t('dialog.user.status.offline'); statusImage = 'offline'; hidePrivate = true; break; @@ -251,7 +254,10 @@ export const useDiscordPresenceSettingsStore = defineStore( let activityType = ActivityType.Playing; let appId = '883308884863901717'; let bigIcon = 'vrchat'; - let stateUrl = state.lastLocationDetails.worldLink; + let detailsUrl = state.lastLocationDetails.worldLink; + let poweredBy = t( + 'view.settings.discord_presence.rpc.powered_by_vrcx' + ); let partyId = `${state.lastLocationDetails.worldId}:${state.lastLocationDetails.instanceName}`; let partySize = locationStore.lastLocation.playerList.size; @@ -259,13 +265,17 @@ export const useDiscordPresenceSettingsStore = defineStore( if (partySize > partyMaxSize) { partyMaxSize = partySize; } + if (partySize === 0) { + partyMaxSize = 0; + } if (!state.discordInstance) { partySize = 0; partyMaxSize = 0; stateText = ''; } - - let buttonText = 'Join'; + let buttonText = t( + 'view.settings.discord_presence.rpc.join_button' + ); let buttonUrl = state.lastLocationDetails.joinUrl; if (!state.discordJoinButton) { buttonText = ''; @@ -356,12 +366,13 @@ export const useDiscordPresenceSettingsStore = defineStore( partyMaxSize = 0; buttonText = ''; buttonUrl = ''; - stateUrl = ''; - details = 'Private'; + detailsUrl = ''; + details = t('view.settings.discord_presence.rpc.private_world'); stateText = ''; startTime = 0; endTime = 0; appId = '883308884863901717'; // default VRChat app id + bigIcon = 'vrchat'; activityType = ActivityType.Playing; } if (details.length < 2) { @@ -371,10 +382,10 @@ export const useDiscordPresenceSettingsStore = defineStore( Discord.SetAssets( details, // main text stateText, // secondary text - stateUrl, // state url + detailsUrl, // details url bigIcon, // big icon - 'Powered by VRCX', // big icon hover text + poweredBy, // big icon hover text statusImage, // small icon statusName, // small icon hover text diff --git a/src/types/globals.d.ts b/src/types/globals.d.ts index 61918730..8854004c 100644 --- a/src/types/globals.d.ts +++ b/src/types/globals.d.ts @@ -126,7 +126,7 @@ declare global { SetAssets( details: string, state: string, - stateUrl: string, + detailsUrl: string, bigIcon: string, bigIconText: string, smallIcon: string,