Add Discord RPC options

This commit is contained in:
Natsumi
2025-08-23 11:45:29 +12:00
parent 4f94582731
commit c04047078c
6 changed files with 180 additions and 27 deletions

View File

@@ -156,7 +156,8 @@ namespace VRCX
string buttonText,
string buttonUrl,
string appId,
int activityType)
int activityType,
int statusDisplayType)
{
_lock.EnterWriteLock();
try
@@ -212,7 +213,7 @@ namespace VRCX
}
_presence.Type = (ActivityType)activityType;
_presence.StatusDisplay = StatusDisplayType.Details;
_presence.StatusDisplay = (StatusDisplayType)statusDisplayType;
Button[] buttons = [];
if (!string.IsNullOrEmpty(buttonUrl))

View File

@@ -516,13 +516,17 @@
"discord_presence": {
"discord_presence": {
"header": "Discord Presence",
"description": "* Only active while VRChat is running.",
"description": "* Only active whilst in an instance.",
"enable": "Enable",
"enable_tooltip": "Recommended to disable Rich Presence in VRChat config.json to stop it from conflicting",
"instance_type_player_count": "Instance type/player count",
"instance_type_player_count": "Instance type & player count",
"join_button": "Join button (public only)",
"show_details_in_private": "Show world details in private",
"show_images": "Show world images"
"show_details_in_private": "Show world details while in private",
"show_images": "Show world images",
"show_current_platform": "Show current platform",
"world_integration": "World integration",
"world_integration_tooltip": "Show \"Watching\\Listening to\" video for Popcorn Palace, PyPyDance, VRDancing and LS Media",
"display_world_name_as_discord_status": "Display world name as Discord status"
},
"rpc": {
"vr": "VR",

View File

@@ -18,11 +18,31 @@ class ActivityType {
}
}
class StatusDisplayType {
static _Name = 0;
static _State = 1;
static _Details = 2;
static get Name() {
return this._Name;
}
static get State() {
return this._State;
}
static get Details() {
return this._Details;
}
}
Object.freeze(ActivityType);
Object.freeze(StatusDisplayType);
Object.defineProperty(ActivityType, '_Playing', { writable: false });
Object.defineProperty(ActivityType, '_Listening', { writable: false });
Object.defineProperty(ActivityType, '_Watching', { writable: false });
Object.defineProperty(ActivityType, '_Competing', { writable: false });
Object.defineProperty(StatusDisplayType, '_Name', { writable: false });
Object.defineProperty(StatusDisplayType, '_State', { writable: false });
Object.defineProperty(StatusDisplayType, '_Details', { writable: false });
export { ActivityType };
export { ActivityType, StatusDisplayType };

View File

@@ -14,7 +14,10 @@ import { useGameLogStore } from '../gameLog';
import { useLocationStore } from '../location';
import { useUpdateLoopStore } from '../updateLoop';
import { useUserStore } from '../user';
import { ActivityType } from '../../shared/constants/discord';
import {
ActivityType,
StatusDisplayType
} from '../../shared/constants/discord';
import { useI18n } from 'vue-i18n-bridge';
export const useDiscordPresenceSettingsStore = defineStore(
@@ -33,6 +36,9 @@ export const useDiscordPresenceSettingsStore = defineStore(
discordHideInvite: true,
discordJoinButton: false,
discordHideImage: false,
discordShowPlatform: true,
discordWorldIntegration: true,
discordWorldNameAsDiscordStatus: false,
isDiscordActive: false,
lastLocationDetails: {
tag: '',
@@ -55,13 +61,22 @@ export const useDiscordPresenceSettingsStore = defineStore(
discordInstance,
discordHideInvite,
discordJoinButton,
discordHideImage
discordHideImage,
discordShowPlatform,
discordWorldIntegration,
discordWorldNameAsDiscordStatus
] = await Promise.all([
configRepository.getBool('discordActive', false),
configRepository.getBool('discordInstance', true),
configRepository.getBool('discordHideInvite', true),
configRepository.getBool('discordJoinButton', false),
configRepository.getBool('discordHideImage', false)
configRepository.getBool('discordHideImage', false),
configRepository.getBool('discordShowPlatform', true),
configRepository.getBool('discordWorldIntegration', true),
configRepository.getBool(
'discordWorldNameAsDiscordStatus',
false
)
]);
state.discordActive = discordActive;
@@ -69,6 +84,10 @@ export const useDiscordPresenceSettingsStore = defineStore(
state.discordHideInvite = discordHideInvite;
state.discordJoinButton = discordJoinButton;
state.discordHideImage = discordHideImage;
state.discordShowPlatform = discordShowPlatform;
state.discordWorldIntegration = discordWorldIntegration;
state.discordWorldNameAsDiscordStatus =
discordWorldNameAsDiscordStatus;
}
const discordActive = computed(() => state.discordActive);
@@ -76,6 +95,13 @@ export const useDiscordPresenceSettingsStore = defineStore(
const discordHideInvite = computed(() => state.discordHideInvite);
const discordJoinButton = computed(() => state.discordJoinButton);
const discordHideImage = computed(() => state.discordHideImage);
const discordShowPlatform = computed(() => state.discordShowPlatform);
const discordWorldIntegration = computed(
() => state.discordWorldIntegration
);
const discordWorldNameAsDiscordStatus = computed(
() => state.discordWorldNameAsDiscordStatus
);
function setDiscordActive() {
state.discordActive = !state.discordActive;
@@ -106,6 +132,28 @@ export const useDiscordPresenceSettingsStore = defineStore(
state.discordHideImage
);
}
function setDiscordShowPlatform() {
state.discordShowPlatform = !state.discordShowPlatform;
configRepository.setBool(
'discordShowPlatform',
state.discordShowPlatform
);
}
function setDiscordWorldIntegration() {
state.discordWorldIntegration = !state.discordWorldIntegration;
configRepository.setBool(
'discordWorldIntegration',
state.discordWorldIntegration
);
}
function setDiscordWorldNameAsDiscordStatus() {
state.discordWorldNameAsDiscordStatus =
!state.discordWorldNameAsDiscordStatus;
configRepository.setBool(
'discordWorldNameAsDiscordStatus',
state.discordWorldNameAsDiscordStatus
);
}
initDiscordPresenceSettings();
@@ -162,9 +210,30 @@ export const useDiscordPresenceSettingsStore = defineStore(
);
}
let platform = gameStore.isGameNoVR
? t('view.settings.discord_presence.rpc.desktop')
: t('view.settings.discord_presence.rpc.vr');
let platform = '';
if (state.discordShowPlatform) {
if (gameStore.isGameRunning) {
platform = gameStore.isGameNoVR
? ` (${t('view.settings.discord_presence.rpc.desktop')})`
: ` (${t('view.settings.discord_presence.rpc.vr')})`;
} else {
switch (userStore.currentUser.presence.platform) {
case 'web':
break;
case 'standalonewindows':
platform = ` (PC)`;
break;
case 'android':
platform = ` (Android)`;
break;
case 'ios':
platform = ` (iOS)`;
break;
default:
platform = ` (${userStore.currentUser.presence.platform})`;
}
}
}
if (L.groupAccessType) {
if (L.groupAccessType === 'public') {
state.lastLocationDetails.groupAccessType = t(
@@ -179,26 +248,26 @@ export const useDiscordPresenceSettingsStore = defineStore(
switch (L.accessType) {
case 'public':
state.lastLocationDetails.joinUrl = getLaunchURL(L);
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_public')} #${L.instanceName} (${platform})`;
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_public')} #${L.instanceName}${platform}`;
break;
case 'invite+':
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_invite_plus')} #${L.instanceName} (${platform})`;
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_invite_plus')} #${L.instanceName}${platform}`;
break;
case 'invite':
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_invite')} #${L.instanceName} (${platform})`;
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_invite')} #${L.instanceName}${platform}`;
break;
case 'friends':
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_friend')} #${L.instanceName} (${platform})`;
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_friend')} #${L.instanceName}${platform}`;
break;
case 'friends+':
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_friend_plus')} #${L.instanceName} (${platform})`;
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_friend_plus')} #${L.instanceName}${platform}`;
break;
case 'group':
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_group')} #${L.instanceName} (${platform})`;
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_group')} #${L.instanceName}${platform}`;
try {
const groupName = await getGroupName(L.groupId);
if (groupName) {
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_group')}${state.lastLocationDetails.groupAccessType}(${groupName}) #${L.instanceName} (${platform})`;
state.lastLocationDetails.accessName = `${t('dialog.new_instance.access_type_group')}${state.lastLocationDetails.groupAccessType}(${groupName}) #${L.instanceName}${platform}`;
}
} catch (e) {
console.error(
@@ -252,6 +321,9 @@ export const useDiscordPresenceSettingsStore = defineStore(
let stateText = state.lastLocationDetails.accessName;
let endTime = 0;
let activityType = ActivityType.Playing;
let statusDisplayType = state.discordWorldNameAsDiscordStatus
? StatusDisplayType.Details
: StatusDisplayType.Name;
let appId = '883308884863901717';
let bigIcon = 'vrchat';
let detailsUrl = state.lastLocationDetails.worldLink;
@@ -282,7 +354,10 @@ export const useDiscordPresenceSettingsStore = defineStore(
buttonUrl = '';
}
if (isRpcWorld(state.lastLocationDetails.tag)) {
if (
isRpcWorld(state.lastLocationDetails.tag) &&
state.discordWorldIntegration
) {
// custom world rpc
if (
state.lastLocationDetails.worldId ===
@@ -293,6 +368,7 @@ export const useDiscordPresenceSettingsStore = defineStore(
'wrld_04899f23-e182-4a8d-b2c7-2c74c7c15534'
) {
activityType = ActivityType.Listening;
statusDisplayType = StatusDisplayType.Details;
appId = '784094509008551956';
bigIcon = 'pypy';
} else if (
@@ -302,6 +378,7 @@ export const useDiscordPresenceSettingsStore = defineStore(
'wrld_dd6d2888-dbdc-47c2-bc98-3d631b2acd7c'
) {
activityType = ActivityType.Listening;
statusDisplayType = StatusDisplayType.Details;
appId = '846232616054030376';
bigIcon = 'vr_dancing';
} else if (
@@ -311,6 +388,7 @@ export const useDiscordPresenceSettingsStore = defineStore(
'wrld_2d40da63-8f1f-4011-8a9e-414eb8530acd'
) {
activityType = ActivityType.Listening;
statusDisplayType = StatusDisplayType.Details;
appId = '939473404808007731';
bigIcon = 'zuwa_zuwa_dance';
} else if (
@@ -324,6 +402,7 @@ export const useDiscordPresenceSettingsStore = defineStore(
'wrld_f767d1c8-b249-4ecc-a56f-614e433682c8'
) {
activityType = ActivityType.Watching;
statusDisplayType = StatusDisplayType.Details;
appId = '968292722391785512';
bigIcon = 'ls_media';
} else if (
@@ -333,6 +412,7 @@ export const useDiscordPresenceSettingsStore = defineStore(
'wrld_27c7e6b2-d938-447e-a270-3d1a873e2cf3'
) {
activityType = ActivityType.Watching;
statusDisplayType = StatusDisplayType.Details;
appId = '1095440531821170820';
if (
!state.discordHideImage &&
@@ -374,6 +454,7 @@ export const useDiscordPresenceSettingsStore = defineStore(
appId = '883308884863901717'; // default VRChat app id
bigIcon = 'vrchat';
activityType = ActivityType.Playing;
statusDisplayType = StatusDisplayType.Name;
}
if (details.length < 2) {
// 글자 수가 짧으면 업데이트가 안된다..
@@ -399,7 +480,8 @@ export const useDiscordPresenceSettingsStore = defineStore(
buttonText, // button text
buttonUrl, // button url
appId, // app id
activityType // activity type
activityType, // activity type
statusDisplayType // status display type
);
}
@@ -423,12 +505,18 @@ export const useDiscordPresenceSettingsStore = defineStore(
discordHideInvite,
discordJoinButton,
discordHideImage,
discordShowPlatform,
discordWorldIntegration,
discordWorldNameAsDiscordStatus,
setDiscordActive,
setDiscordInstance,
setDiscordHideInvite,
setDiscordJoinButton,
setDiscordHideImage,
setDiscordShowPlatform,
setDiscordWorldIntegration,
setDiscordWorldNameAsDiscordStatus,
updateDiscord,
saveDiscordOption
};

View File

@@ -139,7 +139,8 @@ declare global {
buttonText: string,
buttonUrl: string,
appId: string,
activityType: number
activityType: number,
statusDisplayType: number
): Promise<void>;
SetActive(active: boolean): Promise<boolean>;
};

View File

@@ -1189,14 +1189,25 @@
<div class="options-container-item">
<span>{{ t('view.settings.discord_presence.discord_presence.description') }}</span>
</div>
<div class="options-container-item" @click="showVRChatConfig" style="cursor: pointer">
<span>{{ t('view.settings.discord_presence.discord_presence.enable_tooltip') }}</span>
</div>
<br />
<simple-switch
:label="t('view.settings.discord_presence.discord_presence.enable')"
:value="discordActive"
:tooltip="t('view.settings.discord_presence.discord_presence.enable_tooltip')"
@change="
setDiscordActive();
saveDiscordOption();
" />
<simple-switch
:label="t('view.settings.discord_presence.discord_presence.world_integration')"
:value="discordWorldIntegration"
:disabled="!discordActive"
@change="
setDiscordWorldIntegration();
saveDiscordOption();
" />
<simple-switch
:label="t('view.settings.discord_presence.discord_presence.instance_type_player_count')"
:value="discordInstance"
@@ -1205,6 +1216,14 @@
setDiscordInstance();
saveDiscordOption();
" />
<simple-switch
:label="t('view.settings.discord_presence.discord_presence.show_current_platform')"
:value="discordShowPlatform"
:disabled="!discordActive || !discordInstance"
@change="
setDiscordShowPlatform();
saveDiscordOption();
" />
<simple-switch
:label="t('view.settings.discord_presence.discord_presence.show_details_in_private')"
:value="!discordHideInvite"
@@ -1229,6 +1248,16 @@
setDiscordHideImage();
saveDiscordOption();
" />
<simple-switch
:label="
t('view.settings.discord_presence.discord_presence.display_world_name_as_discord_status')
"
:value="discordWorldNameAsDiscordStatus"
:disabled="!discordActive"
@change="
setDiscordWorldNameAsDiscordStatus();
saveDiscordOption();
" />
</div>
</el-tab-pane>
@@ -1881,9 +1910,16 @@
const { cachedGroups } = storeToRefs(useGroupStore());
const { cachedAvatars, cachedAvatarNames } = storeToRefs(useAvatarStore());
const { showConsole } = useVrcxStore();
const { discordActive, discordInstance, discordHideInvite, discordJoinButton, discordHideImage } = storeToRefs(
useDiscordPresenceSettingsStore()
);
const {
discordActive,
discordInstance,
discordHideInvite,
discordJoinButton,
discordHideImage,
discordShowPlatform,
discordWorldIntegration,
discordWorldNameAsDiscordStatus
} = storeToRefs(useDiscordPresenceSettingsStore());
const { disableGameLogDialog } = useGameLogStore();
const {
setDiscordActive,
@@ -1891,6 +1927,9 @@
setDiscordHideInvite,
setDiscordJoinButton,
setDiscordHideImage,
setDiscordShowPlatform,
setDiscordWorldIntegration,
setDiscordWorldNameAsDiscordStatus,
saveDiscordOption
} = useDiscordPresenceSettingsStore();
const {