Refactor Discord RPC

This commit is contained in:
Natsumi
2025-08-01 17:06:13 +12:00
parent 7946ff63ae
commit bc2211f332
7 changed files with 332 additions and 274 deletions

View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia';
import { computed, reactive } from 'vue';
import { userRequest, worldRequest } from '../../api';
import { worldRequest } from '../../api';
import configRepository from '../../service/config';
import {
getGroupName,
@@ -14,7 +14,6 @@ import { useGameLogStore } from '../gameLog';
import { useLocationStore } from '../location';
import { useUpdateLoopStore } from '../updateLoop';
import { useUserStore } from '../user';
import { useWorldStore } from '../world';
import { useAdvancedSettingsStore } from './advanced';
import { ActivityType } from '../../shared/constants/discord';
@@ -24,7 +23,6 @@ export const useDiscordPresenceSettingsStore = defineStore(
const locationStore = useLocationStore();
const gameStore = useGameStore();
const advancedSettingsStore = useAdvancedSettingsStore();
const worldStore = useWorldStore();
const gameLogStore = useGameLogStore();
const userStore = useUserStore();
const updateLoopStore = useUpdateLoopStore();
@@ -35,7 +33,20 @@ export const useDiscordPresenceSettingsStore = defineStore(
discordHideInvite: true,
discordJoinButton: false,
discordHideImage: false,
isDiscordActive: false
isDiscordActive: false,
lastLocationDetails: {
tag: '',
instanceName: '',
accessType: '',
worldId: '',
worldName: '',
thumbnailImageUrl: '',
worldCapacity: 0,
joinUrl: '',
worldLink: '',
accessName: '',
groupAccessType: ''
}
});
async function initDiscordPresenceSettings() {
@@ -98,186 +109,218 @@ export const useDiscordPresenceSettingsStore = defineStore(
initDiscordPresenceSettings();
function updateDiscord() {
let platform;
async function updateDiscord() {
let currentLocation = locationStore.lastLocation.location;
let timeStamp = locationStore.lastLocation.date;
let startTime = locationStore.lastLocation.date;
if (locationStore.lastLocation.location === 'traveling') {
currentLocation = locationStore.lastLocationDestination;
timeStamp = locationStore.lastLocationDestinationTime;
startTime = locationStore.lastLocationDestinationTime;
}
if (advancedSettingsStore.gameLogDisabled) {
// game log disabled, use API location
currentLocation = userStore.currentUser.$locationTag;
startTime = userStore.currentUser.$location_at;
if (userStore.currentUser.$travelingToLocation) {
currentLocation =
userStore.currentUser.$travelingToLocation;
}
}
if (
!state.discordActive ||
(!gameStore.isGameRunning &&
!advancedSettingsStore.gameLogDisabled) ||
(!currentLocation && !locationStore.lastLocation$.tag)
!isRealInstance(currentLocation)
) {
setIsDiscordActive(false);
return;
}
setIsDiscordActive(true);
let L = locationStore.lastLocation$;
if (currentLocation !== locationStore.lastLocation$.tag) {
Discord.SetTimestamps(timeStamp, 0);
L = parseLocation(currentLocation);
L.worldName = '';
L.thumbnailImageUrl = '';
L.worldCapacity = 0;
L.joinUrl = '';
L.accessName = '';
if (L.worldId) {
const ref = worldStore.cachedWorlds.get(L.worldId);
if (ref) {
L.worldName = ref.name;
L.thumbnailImageUrl = ref.thumbnailImageUrl;
L.worldCapacity = ref.capacity;
} else {
worldRequest
.getWorld({
worldId: L.worldId
})
.then((args) => {
L.worldName = args.ref.name;
L.thumbnailImageUrl =
args.ref.thumbnailImageUrl;
L.worldCapacity = args.ref.capacity;
return args;
});
if (currentLocation !== state.lastLocationDetails.tag) {
const L = parseLocation(currentLocation);
state.lastLocationDetails = {
tag: L.tag,
instanceName: L.instanceName,
accessType: L.accessType,
worldId: L.worldId,
worldName: '',
thumbnailImageUrl: '',
worldCapacity: 0,
joinUrl: '',
worldLink: '',
accessName: '',
groupAccessType: ''
};
try {
const args = await worldRequest.getCachedWorld({
worldId: L.worldId
});
state.lastLocationDetails.worldName = args.ref.name;
state.lastLocationDetails.thumbnailImageUrl =
args.ref.thumbnailImageUrl;
state.lastLocationDetails.worldCapacity = args.ref.capacity;
if (args.ref.releaseStatus === 'public') {
state.lastLocationDetails.worldLink = `https://vrchat.com/home/world/${L.worldId}`;
}
if (gameStore.isGameNoVR) {
platform = 'Desktop';
} else {
platform = 'VR';
}
let groupAccessType = '';
if (L.groupAccessType) {
if (L.groupAccessType === 'public') {
groupAccessType = 'Public';
} else if (L.groupAccessType === 'plus') {
groupAccessType = 'Plus';
}
}
switch (L.accessType) {
case 'public':
L.joinUrl = getLaunchURL(L);
L.accessName = `Public #${L.instanceName} (${platform})`;
break;
case 'invite+':
L.accessName = `Invite+ #${L.instanceName} (${platform})`;
break;
case 'invite':
L.accessName = `Invite #${L.instanceName} (${platform})`;
break;
case 'friends':
L.accessName = `Friends #${L.instanceName} (${platform})`;
break;
case 'friends+':
L.accessName = `Friends+ #${L.instanceName} (${platform})`;
break;
case 'group':
L.accessName = `Group #${L.instanceName} (${platform})`;
getGroupName(L.groupId).then((groupName) => {
if (groupName) {
L.accessName = `Group${groupAccessType}(${groupName}) #${L.instanceName} (${platform})`;
}
});
break;
} catch (e) {
console.error(
`Failed to get world details for ${L.worldId}`,
e
);
}
let platform = gameStore.isGameNoVR ? 'Desktop' : 'VR';
if (L.groupAccessType) {
if (L.groupAccessType === 'public') {
state.lastLocationDetails.groupAccessType = 'Public';
} else if (L.groupAccessType === 'plus') {
state.lastLocationDetails.groupAccessType = 'Plus';
}
}
locationStore.lastLocation$ = L;
switch (L.accessType) {
case 'public':
state.lastLocationDetails.joinUrl = getLaunchURL(L);
state.lastLocationDetails.accessName = `Public #${L.instanceName} (${platform})`;
break;
case 'invite+':
state.lastLocationDetails.accessName = `Invite+ #${L.instanceName} (${platform})`;
break;
case 'invite':
state.lastLocationDetails.accessName = `Invite #${L.instanceName} (${platform})`;
break;
case 'friends':
state.lastLocationDetails.accessName = `Friends #${L.instanceName} (${platform})`;
break;
case 'friends+':
state.lastLocationDetails.accessName = `Friends+ #${L.instanceName} (${platform})`;
break;
case 'group':
state.lastLocationDetails.accessName = `Group #${L.instanceName} (${platform})`;
try {
const groupName = await getGroupName(L.groupId);
state.lastLocationDetails.accessName = `Group${state.lastLocationDetails.groupAccessType}(${groupName}) #${L.instanceName} (${platform})`;
} catch (e) {
console.error(
`Failed to get group name for ${L.groupId}`,
e
);
}
break;
}
}
setIsDiscordActive(true);
let hidePrivate = false;
if (
state.discordHideInvite &&
(L.accessType === 'invite' ||
L.accessType === 'invite+' ||
L.groupAccessType === 'members')
(state.lastLocationDetails.accessType === 'invite' ||
state.lastLocationDetails.accessType === 'invite+' ||
state.lastLocationDetails.groupAccessType === 'members')
) {
hidePrivate = true;
}
let statusName = '';
let statusImage = '';
switch (userStore.currentUser.status) {
case 'active':
L.statusName = 'Online';
L.statusImage = 'active';
statusName = 'Online';
statusImage = 'active';
break;
case 'join me':
L.statusName = 'Join Me';
L.statusImage = 'joinme';
statusName = 'Join Me';
statusImage = 'joinme';
break;
case 'ask me':
L.statusName = 'Ask Me';
L.statusImage = 'askme';
statusName = 'Ask Me';
statusImage = 'askme';
if (state.discordHideInvite) {
hidePrivate = true;
}
break;
case 'busy':
L.statusName = 'Do Not Disturb';
L.statusImage = 'busy';
statusName = 'Do Not Disturb';
statusImage = 'busy';
hidePrivate = true;
break;
default:
statusName = 'Offline';
statusImage = 'offline';
hidePrivate = true;
break;
}
let details = state.lastLocationDetails.worldName;
let stateText = state.lastLocationDetails.accessName;
let endTime = 0;
let activityType = ActivityType.Playing;
let appId = '883308884863901717';
let bigIcon = 'vrchat';
let partyId = `${L.worldId}:${L.instanceName}`;
let stateUrl = state.lastLocationDetails.worldLink;
let partyId = `${state.lastLocationDetails.worldId}:${state.lastLocationDetails.instanceName}`;
let partySize = locationStore.lastLocation.playerList.size;
let partyMaxSize = L.worldCapacity;
let partyMaxSize = state.lastLocationDetails.worldCapacity;
if (partySize > partyMaxSize) {
partyMaxSize = partySize;
}
let buttonText = 'Join';
let buttonUrl = L.joinUrl;
if (!state.discordJoinButton) {
buttonText = '';
buttonUrl = '';
}
if (!state.discordInstance) {
partySize = 0;
partyMaxSize = 0;
stateText = '';
}
if (hidePrivate) {
partyId = '';
partySize = 0;
partyMaxSize = 0;
let buttonText = 'Join';
let buttonUrl = state.lastLocationDetails.joinUrl;
if (!state.discordJoinButton) {
buttonText = '';
buttonUrl = '';
} else if (isRpcWorld(L.tag)) {
}
if (isRpcWorld(state.lastLocationDetails.tag)) {
// custom world rpc
if (
L.worldId === 'wrld_f20326da-f1ac-45fc-a062-609723b097b1' ||
L.worldId === 'wrld_10e5e467-fc65-42ed-8957-f02cace1398c' ||
L.worldId === 'wrld_04899f23-e182-4a8d-b2c7-2c74c7c15534'
state.lastLocationDetails.worldId ===
'wrld_f20326da-f1ac-45fc-a062-609723b097b1' ||
state.lastLocationDetails.worldId ===
'wrld_10e5e467-fc65-42ed-8957-f02cace1398c' ||
state.lastLocationDetails.worldId ===
'wrld_04899f23-e182-4a8d-b2c7-2c74c7c15534'
) {
activityType = ActivityType.Listening;
appId = '784094509008551956';
bigIcon = 'pypy';
} else if (
L.worldId === 'wrld_42377cf1-c54f-45ed-8996-5875b0573a83' ||
L.worldId === 'wrld_dd6d2888-dbdc-47c2-bc98-3d631b2acd7c'
state.lastLocationDetails.worldId ===
'wrld_42377cf1-c54f-45ed-8996-5875b0573a83' ||
state.lastLocationDetails.worldId ===
'wrld_dd6d2888-dbdc-47c2-bc98-3d631b2acd7c'
) {
activityType = ActivityType.Listening;
appId = '846232616054030376';
bigIcon = 'vr_dancing';
} else if (
L.worldId === 'wrld_52bdcdab-11cd-4325-9655-0fb120846945' ||
L.worldId === 'wrld_2d40da63-8f1f-4011-8a9e-414eb8530acd'
state.lastLocationDetails.worldId ===
'wrld_52bdcdab-11cd-4325-9655-0fb120846945' ||
state.lastLocationDetails.worldId ===
'wrld_2d40da63-8f1f-4011-8a9e-414eb8530acd'
) {
activityType = ActivityType.Listening;
appId = '939473404808007731';
bigIcon = 'zuwa_zuwa_dance';
} else if (
L.worldId === 'wrld_74970324-58e8-4239-a17b-2c59dfdf00db' ||
L.worldId === 'wrld_db9d878f-6e76-4776-8bf2-15bcdd7fc445' ||
L.worldId === 'wrld_435bbf25-f34f-4b8b-82c6-cd809057eb8e' ||
L.worldId === 'wrld_f767d1c8-b249-4ecc-a56f-614e433682c8'
state.lastLocationDetails.worldId ===
'wrld_74970324-58e8-4239-a17b-2c59dfdf00db' ||
state.lastLocationDetails.worldId ===
'wrld_db9d878f-6e76-4776-8bf2-15bcdd7fc445' ||
state.lastLocationDetails.worldId ===
'wrld_435bbf25-f34f-4b8b-82c6-cd809057eb8e' ||
state.lastLocationDetails.worldId ===
'wrld_f767d1c8-b249-4ecc-a56f-614e433682c8'
) {
activityType = ActivityType.Watching;
appId = '968292722391785512';
bigIcon = 'ls_media';
} else if (
L.worldId === 'wrld_266523e8-9161-40da-acd0-6bd82e075833' ||
L.worldId === 'wrld_27c7e6b2-d938-447e-a270-3d1a873e2cf3'
state.lastLocationDetails.worldId ===
'wrld_266523e8-9161-40da-acd0-6bd82e075833' ||
state.lastLocationDetails.worldId ===
'wrld_27c7e6b2-d938-447e-a270-3d1a873e2cf3'
) {
activityType = ActivityType.Watching;
appId = '1095440531821170820';
@@ -291,24 +334,54 @@ export const useDiscordPresenceSettingsStore = defineStore(
}
}
if (gameLogStore.nowPlaying.name) {
L.worldName = gameLogStore.nowPlaying.name;
details = gameLogStore.nowPlaying.name;
}
if (gameLogStore.nowPlaying.playing) {
Discord.SetTimestamps(
gameLogStore.nowPlaying.startTime * 1000,
startTime = gameLogStore.nowPlaying.startTime * 1000;
endTime =
(gameLogStore.nowPlaying.startTime +
gameLogStore.nowPlaying.length) *
1000
);
1000;
}
} else if (!state.discordHideImage && L.thumbnailImageUrl) {
bigIcon = L.thumbnailImageUrl;
} else if (
!state.discordHideImage &&
state.lastLocationDetails.thumbnailImageUrl
) {
bigIcon = state.lastLocationDetails.thumbnailImageUrl;
}
if (hidePrivate) {
partyId = '';
partySize = 0;
partyMaxSize = 0;
buttonText = '';
buttonUrl = '';
stateUrl = '';
details = 'Private';
stateText = '';
startTime = 0;
endTime = 0;
appId = '883308884863901717'; // default VRChat app id
activityType = ActivityType.Playing;
}
if (details.length < 2) {
// 글자 수가 짧으면 업데이트가 안된다..
details += '\uFFA0'.repeat(2 - details.length);
}
Discord.SetAssets(
details, // main text
stateText, // secondary text
stateUrl, // state url
bigIcon, // big icon
'Powered by VRCX', // big icon hover text
L.statusImage, // small icon
L.statusName, // small icon hover text
statusImage, // small icon
statusName, // small icon hover text
startTime,
endTime,
partyId, // party id
partySize, // party size
partyMaxSize, // party max size
@@ -317,19 +390,6 @@ export const useDiscordPresenceSettingsStore = defineStore(
appId, // app id
activityType // activity type
);
// NOTE
// 글자 수가 짧으면 업데이트가 안된다..
if (L.worldName.length < 2) {
L.worldName += '\uFFA0'.repeat(2 - L.worldName.length);
}
if (hidePrivate) {
Discord.SetText('Private', '');
Discord.SetTimestamps(0, 0);
} else if (state.discordInstance) {
Discord.SetText(L.worldName, L.accessName);
} else {
Discord.SetText(L.worldName, '');
}
}
async function setIsDiscordActive(active) {
@@ -339,7 +399,7 @@ export const useDiscordPresenceSettingsStore = defineStore(
}
async function saveDiscordOption(configLabel = '') {
locationStore.lastLocation$.tag = '';
state.lastLocationDetails.tag = '';
updateLoopStore.nextDiscordUpdate = 3;
updateDiscord();
}