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
+116 -109
View File
@@ -16,12 +16,13 @@ namespace VRCX
{ {
private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly Logger _logger = LogManager.GetCurrentClassLogger();
public static readonly Discord Instance; public static readonly Discord Instance;
private readonly ReaderWriterLockSlim m_Lock; private readonly ReaderWriterLockSlim _lock;
private readonly RichPresence m_Presence; private readonly RichPresence _presence;
private DiscordRpcClient m_Client; private DiscordRpcClient _client;
private readonly Timer m_Timer; private readonly Timer _timer;
private bool m_Active; private bool _active;
public static string DiscordAppId; private string _discordAppId;
private const string VrcxUrl = "https://vrcx.app";
static Discord() static Discord()
{ {
@@ -30,22 +31,22 @@ namespace VRCX
public Discord() public Discord()
{ {
m_Lock = new ReaderWriterLockSlim(); _lock = new ReaderWriterLockSlim();
m_Presence = new RichPresence(); _presence = new RichPresence();
m_Timer = new Timer(TimerCallback, null, -1, -1); _timer = new Timer(TimerCallback, null, -1, -1);
} }
public void Init() public void Init()
{ {
m_Timer.Change(0, 1000); _timer.Change(0, 3000);
} }
public void Exit() public void Exit()
{ {
lock (this) lock (this)
{ {
m_Timer.Change(-1, -1); _timer.Change(-1, -1);
m_Client?.Dispose(); _client?.Dispose();
} }
} }
@@ -66,41 +67,41 @@ namespace VRCX
private void Update() private void Update()
{ {
if (m_Client == null && m_Active) if (_client == null && _active)
{ {
m_Client = new DiscordRpcClient(DiscordAppId); _client = new DiscordRpcClient(_discordAppId);
if (!m_Client.Initialize()) if (!_client.Initialize())
{ {
m_Client.Dispose(); _client.Dispose();
m_Client = null; _client = null;
} }
} }
if (m_Client != null && !m_Active) if (_client != null && !_active)
{ {
m_Client.Dispose(); _client.Dispose();
m_Client = null; _client = null;
} }
if (m_Client != null && !m_Lock.IsWriteLockHeld) if (_client != null && !_lock.IsWriteLockHeld)
{ {
m_Lock.EnterReadLock(); _lock.EnterReadLock();
try try
{ {
m_Client.SetPresence(m_Presence); _client.SetPresence(_presence);
} }
finally finally
{ {
m_Lock.ExitReadLock(); _lock.ExitReadLock();
} }
m_Client.Invoke(); _client.Invoke();
} }
} }
public bool SetActive(bool active) public bool SetActive(bool active)
{ {
m_Active = active; _active = active;
return m_Active; return _active;
} }
// https://stackoverflow.com/questions/1225052/best-way-to-shorten-utf8-string-based-on-byte-length // https://stackoverflow.com/questions/1225052/best-way-to-shorten-utf8-string-based-on-byte-length
@@ -118,107 +119,113 @@ namespace VRCX
} }
return Encoding.UTF8.GetString(bytesArr, 0, bytesArr.Length - bytesToRemove); return Encoding.UTF8.GetString(bytesArr, 0, bytesArr.Length - bytesToRemove);
} }
public void SetText(string details, string state) public void SetAssets(
string details,
string state,
string stateUrl,
string largeKey,
string largeText,
string smallKey,
string smallText,
double startUnixMilliseconds,
double endUnixMilliseconds,
string partyId,
int partySize,
int partyMax,
string buttonText,
string buttonUrl,
string appId,
int activityType)
{ {
if (m_Client == null || m_Lock.IsReadLockHeld) _lock.EnterWriteLock();
return;
m_Lock.EnterWriteLock();
try
{
m_Presence.Details = LimitByteLength(details, 127);
m_Presence.State = LimitByteLength(state, 127);
}
finally
{
m_Lock.ExitWriteLock();
}
}
public void SetAssets(string largeKey, string largeText, string smallKey, string smallText, string partyId, int partySize, int partyMax, string buttonText, string buttonUrl, string appId, int activityType = 0)
{
m_Lock.EnterWriteLock();
try try
{ {
if (string.IsNullOrEmpty(largeKey) && if (string.IsNullOrEmpty(largeKey) &&
string.IsNullOrEmpty(smallKey)) string.IsNullOrEmpty(smallKey))
{ {
m_Presence.Assets = null; _presence.Assets = null;
_presence.Party = null;
_presence.Timestamps = null;
_lock.ExitWriteLock();
return;
}
_presence.Details = LimitByteLength(details, 127);
// _presence.DetailsUrl
_presence.StateUrl = !string.IsNullOrEmpty(stateUrl) ? stateUrl : null;
_presence.State = LimitByteLength(state, 127);
_presence.Assets ??= new Assets();
_presence.Assets.LargeImageKey = largeKey;
_presence.Assets.LargeImageText = largeText;
_presence.Assets.LargeImageUrl = VrcxUrl;
_presence.Assets.SmallImageKey = smallKey;
_presence.Assets.SmallImageText = smallText;
// m_Presence.Assets.SmallImageUrl
if (startUnixMilliseconds == 0)
{
_presence.Timestamps = null;
} }
else else
{ {
m_Presence.Assets ??= new Assets(); _presence.Timestamps ??= new Timestamps();
m_Presence.Party ??= new Party(); _presence.Timestamps.StartUnixMilliseconds = (ulong)startUnixMilliseconds;
m_Presence.Assets.LargeImageKey = largeKey; if (endUnixMilliseconds == 0)
m_Presence.Assets.LargeImageText = largeText; _presence.Timestamps.End = null;
m_Presence.Assets.SmallImageKey = smallKey;
m_Presence.Assets.SmallImageText = smallText;
m_Presence.Party.ID = partyId;
m_Presence.Party.Size = partySize;
m_Presence.Party.Max = partyMax;
m_Presence.Type = (ActivityType)activityType;
Button[] buttons = [];
if (!string.IsNullOrEmpty(buttonUrl))
{
buttons =
[
new Button { Label = buttonText, Url = buttonUrl }
];
}
m_Presence.Buttons = buttons;
if (DiscordAppId != appId)
{
DiscordAppId = appId;
if (m_Client != null)
{
m_Client.Dispose();
m_Client = null;
}
Update();
}
}
}
finally
{
m_Lock.ExitWriteLock();
}
}
public void SetTimestamps(double startUnixMilliseconds, double endUnixMilliseconds)
{
var _startUnixMilliseconds = (ulong)startUnixMilliseconds;
var _endUnixMilliseconds = (ulong)endUnixMilliseconds;
m_Lock.EnterWriteLock();
try
{
if (_startUnixMilliseconds == 0)
{
m_Presence.Timestamps = null;
}
else
{
m_Presence.Timestamps ??= new Timestamps();
m_Presence.Timestamps.StartUnixMilliseconds = _startUnixMilliseconds;
if (_endUnixMilliseconds == 0)
{
m_Presence.Timestamps.End = null;
}
else else
_presence.Timestamps.EndUnixMilliseconds = (ulong)endUnixMilliseconds;
}
if (partyMax == 0)
{
_presence.Party = null;
}
else
{
_presence.Party ??= new Party();
_presence.Party.ID = partyId;
_presence.Party.Size = partySize;
_presence.Party.Max = partyMax;
}
_presence.Type = (ActivityType)activityType;
_presence.StatusDisplay = StatusDisplayType.Details;
Button[] buttons = [];
if (!string.IsNullOrEmpty(buttonUrl))
{
buttons =
[
new Button { Label = buttonText, Url = buttonUrl }
];
}
_presence.Buttons = buttons;
if (_discordAppId != appId)
{
_discordAppId = appId;
if (_client != null)
{ {
m_Presence.Timestamps.EndUnixMilliseconds = _endUnixMilliseconds; _client.Dispose();
_client = null;
} }
Update();
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Error setting timestamps in Discord Rich Presence {Error}", ex.Message); _logger.Error(ex, "Error setting Discord Rich Presence assets: {Error}", ex.Message);
} }
finally finally
{ {
m_Lock.ExitWriteLock(); _lock.ExitWriteLock();
} }
} }
} }
+2 -2
View File
@@ -93,14 +93,14 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CefSharp.OffScreen.NETCore" Version="138.0.170" /> <PackageReference Include="CefSharp.OffScreen.NETCore" Version="138.0.170" />
<PackageReference Include="CefSharp.WinForms.NETCore" Version="138.0.170" /> <PackageReference Include="CefSharp.WinForms.NETCore" Version="138.0.170" />
<PackageReference Include="DiscordRichPresence" Version="1.3.0.28" /> <PackageReference Include="DiscordRichPresence" Version="1.5.0.51" />
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" /> <PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="6.0.2" /> <PackageReference Include="NLog" Version="6.0.2" />
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" /> <PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" /> <PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" /> <PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.6" /> <PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" /> <PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
<PackageReference Include="System.Data.SQLite" Version="1.0.119" /> <PackageReference Include="System.Data.SQLite" Version="1.0.119" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" /> <PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" />
+4 -22
View File
@@ -28,22 +28,12 @@ export const useLocationStore = defineStore('Location', () => {
const state = reactive({ const state = reactive({
lastLocation: { lastLocation: {
date: 0, date: null,
location: '', location: '',
name: '', name: '',
playerList: new Map(), playerList: new Map(),
friendList: new Map() friendList: new Map()
}, },
lastLocation$: {
tag: '',
instanceId: '',
accessType: '',
worldName: '',
worldCapacity: 0,
joinUrl: '',
statusName: '',
statusImage: ''
},
lastLocationDestination: '', lastLocationDestination: '',
lastLocationDestinationTime: 0 lastLocationDestinationTime: 0
}); });
@@ -55,13 +45,6 @@ export const useLocationStore = defineStore('Location', () => {
} }
}); });
const lastLocation$ = computed({
get: () => state.lastLocation$,
set: (value) => {
state.lastLocation$ = value;
}
});
const lastLocationDestination = computed({ const lastLocationDestination = computed({
get: () => state.lastLocationDestination, get: () => state.lastLocationDestination,
set: (value) => { set: (value) => {
@@ -153,7 +136,7 @@ export const useLocationStore = defineStore('Location', () => {
const L = parseLocation(location); const L = parseLocation(location);
state.lastLocation.location = location; state.lastLocation.location = location;
state.lastLocation.date = dt; state.lastLocation.date = Date.now();
const entry = { const entry = {
created_at: dt, created_at: dt,
@@ -174,7 +157,7 @@ export const useLocationStore = defineStore('Location', () => {
instanceStore.applyGroupDialogInstances(); instanceStore.applyGroupDialogInstances();
} else { } else {
state.lastLocation.location = ''; state.lastLocation.location = '';
state.lastLocation.date = ''; state.lastLocation.date = null;
} }
} }
@@ -218,7 +201,7 @@ export const useLocationStore = defineStore('Location', () => {
gameLogStore.addGameLog(entry); gameLogStore.addGameLog(entry);
} }
database.addGamelogJoinLeaveBulk(dataBaseEntries); database.addGamelogJoinLeaveBulk(dataBaseEntries);
if (state.lastLocation.date !== 0) { if (state.lastLocation.date !== null && state.lastLocation.date > 0) {
const update = { const update = {
time: dateTimeStamp - state.lastLocation.date, time: dateTimeStamp - state.lastLocation.date,
created_at: new Date(state.lastLocation.date).toJSON() created_at: new Date(state.lastLocation.date).toJSON()
@@ -248,7 +231,6 @@ export const useLocationStore = defineStore('Location', () => {
return { return {
state, state,
lastLocation, lastLocation,
lastLocation$,
lastLocationDestination, lastLocationDestination,
lastLocationDestinationTime, lastLocationDestinationTime,
updateCurrentUserLocation, updateCurrentUserLocation,
+196 -136
View File
@@ -1,6 +1,6 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { computed, reactive } from 'vue'; import { computed, reactive } from 'vue';
import { userRequest, worldRequest } from '../../api'; import { worldRequest } from '../../api';
import configRepository from '../../service/config'; import configRepository from '../../service/config';
import { import {
getGroupName, getGroupName,
@@ -14,7 +14,6 @@ import { useGameLogStore } from '../gameLog';
import { useLocationStore } from '../location'; import { useLocationStore } from '../location';
import { useUpdateLoopStore } from '../updateLoop'; import { useUpdateLoopStore } from '../updateLoop';
import { useUserStore } from '../user'; import { useUserStore } from '../user';
import { useWorldStore } from '../world';
import { useAdvancedSettingsStore } from './advanced'; import { useAdvancedSettingsStore } from './advanced';
import { ActivityType } from '../../shared/constants/discord'; import { ActivityType } from '../../shared/constants/discord';
@@ -24,7 +23,6 @@ export const useDiscordPresenceSettingsStore = defineStore(
const locationStore = useLocationStore(); const locationStore = useLocationStore();
const gameStore = useGameStore(); const gameStore = useGameStore();
const advancedSettingsStore = useAdvancedSettingsStore(); const advancedSettingsStore = useAdvancedSettingsStore();
const worldStore = useWorldStore();
const gameLogStore = useGameLogStore(); const gameLogStore = useGameLogStore();
const userStore = useUserStore(); const userStore = useUserStore();
const updateLoopStore = useUpdateLoopStore(); const updateLoopStore = useUpdateLoopStore();
@@ -35,7 +33,20 @@ export const useDiscordPresenceSettingsStore = defineStore(
discordHideInvite: true, discordHideInvite: true,
discordJoinButton: false, discordJoinButton: false,
discordHideImage: false, discordHideImage: false,
isDiscordActive: false isDiscordActive: false,
lastLocationDetails: {
tag: '',
instanceName: '',
accessType: '',
worldId: '',
worldName: '',
thumbnailImageUrl: '',
worldCapacity: 0,
joinUrl: '',
worldLink: '',
accessName: '',
groupAccessType: ''
}
}); });
async function initDiscordPresenceSettings() { async function initDiscordPresenceSettings() {
@@ -98,186 +109,218 @@ export const useDiscordPresenceSettingsStore = defineStore(
initDiscordPresenceSettings(); initDiscordPresenceSettings();
function updateDiscord() { async function updateDiscord() {
let platform;
let currentLocation = locationStore.lastLocation.location; let currentLocation = locationStore.lastLocation.location;
let timeStamp = locationStore.lastLocation.date; let startTime = locationStore.lastLocation.date;
if (locationStore.lastLocation.location === 'traveling') { if (locationStore.lastLocation.location === 'traveling') {
currentLocation = locationStore.lastLocationDestination; 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 ( if (
!state.discordActive || !state.discordActive ||
(!gameStore.isGameRunning && (!gameStore.isGameRunning &&
!advancedSettingsStore.gameLogDisabled) || !advancedSettingsStore.gameLogDisabled) ||
(!currentLocation && !locationStore.lastLocation$.tag) !isRealInstance(currentLocation)
) { ) {
setIsDiscordActive(false); setIsDiscordActive(false);
return; return;
} }
setIsDiscordActive(true); if (currentLocation !== state.lastLocationDetails.tag) {
let L = locationStore.lastLocation$; const L = parseLocation(currentLocation);
if (currentLocation !== locationStore.lastLocation$.tag) { state.lastLocationDetails = {
Discord.SetTimestamps(timeStamp, 0); tag: L.tag,
L = parseLocation(currentLocation); instanceName: L.instanceName,
L.worldName = ''; accessType: L.accessType,
L.thumbnailImageUrl = ''; worldId: L.worldId,
L.worldCapacity = 0; worldName: '',
L.joinUrl = ''; thumbnailImageUrl: '',
L.accessName = ''; worldCapacity: 0,
if (L.worldId) { joinUrl: '',
const ref = worldStore.cachedWorlds.get(L.worldId); worldLink: '',
if (ref) { accessName: '',
L.worldName = ref.name; groupAccessType: ''
L.thumbnailImageUrl = ref.thumbnailImageUrl; };
L.worldCapacity = ref.capacity; try {
} else { const args = await worldRequest.getCachedWorld({
worldRequest worldId: L.worldId
.getWorld({ });
worldId: L.worldId state.lastLocationDetails.worldName = args.ref.name;
}) state.lastLocationDetails.thumbnailImageUrl =
.then((args) => { args.ref.thumbnailImageUrl;
L.worldName = args.ref.name; state.lastLocationDetails.worldCapacity = args.ref.capacity;
L.thumbnailImageUrl = if (args.ref.releaseStatus === 'public') {
args.ref.thumbnailImageUrl; state.lastLocationDetails.worldLink = `https://vrchat.com/home/world/${L.worldId}`;
L.worldCapacity = args.ref.capacity;
return args;
});
} }
if (gameStore.isGameNoVR) { } catch (e) {
platform = 'Desktop'; console.error(
} else { `Failed to get world details for ${L.worldId}`,
platform = 'VR'; e
} );
let groupAccessType = ''; }
if (L.groupAccessType) {
if (L.groupAccessType === 'public') { let platform = gameStore.isGameNoVR ? 'Desktop' : 'VR';
groupAccessType = 'Public'; if (L.groupAccessType) {
} else if (L.groupAccessType === 'plus') { if (L.groupAccessType === 'public') {
groupAccessType = 'Plus'; state.lastLocationDetails.groupAccessType = 'Public';
} } else if (L.groupAccessType === 'plus') {
} state.lastLocationDetails.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;
} }
} }
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; let hidePrivate = false;
if ( if (
state.discordHideInvite && state.discordHideInvite &&
(L.accessType === 'invite' || (state.lastLocationDetails.accessType === 'invite' ||
L.accessType === 'invite+' || state.lastLocationDetails.accessType === 'invite+' ||
L.groupAccessType === 'members') state.lastLocationDetails.groupAccessType === 'members')
) { ) {
hidePrivate = true; hidePrivate = true;
} }
let statusName = '';
let statusImage = '';
switch (userStore.currentUser.status) { switch (userStore.currentUser.status) {
case 'active': case 'active':
L.statusName = 'Online'; statusName = 'Online';
L.statusImage = 'active'; statusImage = 'active';
break; break;
case 'join me': case 'join me':
L.statusName = 'Join Me'; statusName = 'Join Me';
L.statusImage = 'joinme'; statusImage = 'joinme';
break; break;
case 'ask me': case 'ask me':
L.statusName = 'Ask Me'; statusName = 'Ask Me';
L.statusImage = 'askme'; statusImage = 'askme';
if (state.discordHideInvite) { if (state.discordHideInvite) {
hidePrivate = true; hidePrivate = true;
} }
break; break;
case 'busy': case 'busy':
L.statusName = 'Do Not Disturb'; statusName = 'Do Not Disturb';
L.statusImage = 'busy'; statusImage = 'busy';
hidePrivate = true;
break;
default:
statusName = 'Offline';
statusImage = 'offline';
hidePrivate = true; hidePrivate = true;
break; break;
} }
let details = state.lastLocationDetails.worldName;
let stateText = state.lastLocationDetails.accessName;
let endTime = 0;
let activityType = ActivityType.Playing; let activityType = ActivityType.Playing;
let appId = '883308884863901717'; let appId = '883308884863901717';
let bigIcon = 'vrchat'; 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 partySize = locationStore.lastLocation.playerList.size;
let partyMaxSize = L.worldCapacity; let partyMaxSize = state.lastLocationDetails.worldCapacity;
if (partySize > partyMaxSize) { if (partySize > partyMaxSize) {
partyMaxSize = partySize; partyMaxSize = partySize;
} }
let buttonText = 'Join';
let buttonUrl = L.joinUrl;
if (!state.discordJoinButton) {
buttonText = '';
buttonUrl = '';
}
if (!state.discordInstance) { if (!state.discordInstance) {
partySize = 0; partySize = 0;
partyMaxSize = 0; partyMaxSize = 0;
stateText = '';
} }
if (hidePrivate) {
partyId = ''; let buttonText = 'Join';
partySize = 0; let buttonUrl = state.lastLocationDetails.joinUrl;
partyMaxSize = 0; if (!state.discordJoinButton) {
buttonText = ''; buttonText = '';
buttonUrl = ''; buttonUrl = '';
} else if (isRpcWorld(L.tag)) { }
if (isRpcWorld(state.lastLocationDetails.tag)) {
// custom world rpc // custom world rpc
if ( if (
L.worldId === 'wrld_f20326da-f1ac-45fc-a062-609723b097b1' || state.lastLocationDetails.worldId ===
L.worldId === 'wrld_10e5e467-fc65-42ed-8957-f02cace1398c' || 'wrld_f20326da-f1ac-45fc-a062-609723b097b1' ||
L.worldId === 'wrld_04899f23-e182-4a8d-b2c7-2c74c7c15534' state.lastLocationDetails.worldId ===
'wrld_10e5e467-fc65-42ed-8957-f02cace1398c' ||
state.lastLocationDetails.worldId ===
'wrld_04899f23-e182-4a8d-b2c7-2c74c7c15534'
) { ) {
activityType = ActivityType.Listening; activityType = ActivityType.Listening;
appId = '784094509008551956'; appId = '784094509008551956';
bigIcon = 'pypy'; bigIcon = 'pypy';
} else if ( } else if (
L.worldId === 'wrld_42377cf1-c54f-45ed-8996-5875b0573a83' || state.lastLocationDetails.worldId ===
L.worldId === 'wrld_dd6d2888-dbdc-47c2-bc98-3d631b2acd7c' 'wrld_42377cf1-c54f-45ed-8996-5875b0573a83' ||
state.lastLocationDetails.worldId ===
'wrld_dd6d2888-dbdc-47c2-bc98-3d631b2acd7c'
) { ) {
activityType = ActivityType.Listening; activityType = ActivityType.Listening;
appId = '846232616054030376'; appId = '846232616054030376';
bigIcon = 'vr_dancing'; bigIcon = 'vr_dancing';
} else if ( } else if (
L.worldId === 'wrld_52bdcdab-11cd-4325-9655-0fb120846945' || state.lastLocationDetails.worldId ===
L.worldId === 'wrld_2d40da63-8f1f-4011-8a9e-414eb8530acd' 'wrld_52bdcdab-11cd-4325-9655-0fb120846945' ||
state.lastLocationDetails.worldId ===
'wrld_2d40da63-8f1f-4011-8a9e-414eb8530acd'
) { ) {
activityType = ActivityType.Listening; activityType = ActivityType.Listening;
appId = '939473404808007731'; appId = '939473404808007731';
bigIcon = 'zuwa_zuwa_dance'; bigIcon = 'zuwa_zuwa_dance';
} else if ( } else if (
L.worldId === 'wrld_74970324-58e8-4239-a17b-2c59dfdf00db' || state.lastLocationDetails.worldId ===
L.worldId === 'wrld_db9d878f-6e76-4776-8bf2-15bcdd7fc445' || 'wrld_74970324-58e8-4239-a17b-2c59dfdf00db' ||
L.worldId === 'wrld_435bbf25-f34f-4b8b-82c6-cd809057eb8e' || state.lastLocationDetails.worldId ===
L.worldId === 'wrld_f767d1c8-b249-4ecc-a56f-614e433682c8' '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; activityType = ActivityType.Watching;
appId = '968292722391785512'; appId = '968292722391785512';
bigIcon = 'ls_media'; bigIcon = 'ls_media';
} else if ( } else if (
L.worldId === 'wrld_266523e8-9161-40da-acd0-6bd82e075833' || state.lastLocationDetails.worldId ===
L.worldId === 'wrld_27c7e6b2-d938-447e-a270-3d1a873e2cf3' 'wrld_266523e8-9161-40da-acd0-6bd82e075833' ||
state.lastLocationDetails.worldId ===
'wrld_27c7e6b2-d938-447e-a270-3d1a873e2cf3'
) { ) {
activityType = ActivityType.Watching; activityType = ActivityType.Watching;
appId = '1095440531821170820'; appId = '1095440531821170820';
@@ -291,24 +334,54 @@ export const useDiscordPresenceSettingsStore = defineStore(
} }
} }
if (gameLogStore.nowPlaying.name) { if (gameLogStore.nowPlaying.name) {
L.worldName = gameLogStore.nowPlaying.name; details = gameLogStore.nowPlaying.name;
} }
if (gameLogStore.nowPlaying.playing) { if (gameLogStore.nowPlaying.playing) {
Discord.SetTimestamps( startTime = gameLogStore.nowPlaying.startTime * 1000;
gameLogStore.nowPlaying.startTime * 1000, endTime =
(gameLogStore.nowPlaying.startTime + (gameLogStore.nowPlaying.startTime +
gameLogStore.nowPlaying.length) * gameLogStore.nowPlaying.length) *
1000 1000;
);
} }
} else if (!state.discordHideImage && L.thumbnailImageUrl) { } else if (
bigIcon = L.thumbnailImageUrl; !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( Discord.SetAssets(
details, // main text
stateText, // secondary text
stateUrl, // state url
bigIcon, // big icon bigIcon, // big icon
'Powered by VRCX', // big icon hover text '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 partyId, // party id
partySize, // party size partySize, // party size
partyMaxSize, // party max size partyMaxSize, // party max size
@@ -317,19 +390,6 @@ export const useDiscordPresenceSettingsStore = defineStore(
appId, // app id appId, // app id
activityType // activity type 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) { async function setIsDiscordActive(active) {
@@ -339,7 +399,7 @@ export const useDiscordPresenceSettingsStore = defineStore(
} }
async function saveDiscordOption(configLabel = '') { async function saveDiscordOption(configLabel = '') {
locationStore.lastLocation$.tag = ''; state.lastLocationDetails.tag = '';
updateLoopStore.nextDiscordUpdate = 3; updateLoopStore.nextDiscordUpdate = 3;
updateDiscord(); updateDiscord();
} }
+8
View File
@@ -56,6 +56,13 @@ export const useUpdateLoopStore = defineStore('UpdateLoop', () => {
} }
}); });
const nextDiscordUpdate = computed({
get: () => state.nextDiscordUpdate,
set: (value) => {
state.nextDiscordUpdate = value;
}
});
async function updateLoop() { async function updateLoop() {
const authStore = useAuthStore(); const authStore = useAuthStore();
const userStore = useUserStore(); const userStore = useUserStore();
@@ -158,6 +165,7 @@ export const useUpdateLoopStore = defineStore('UpdateLoop', () => {
state, state,
nextGroupInstanceRefresh, nextGroupInstanceRefresh,
nextCurrentUserRefresh, nextCurrentUserRefresh,
nextDiscordUpdate,
updateLoop updateLoop
}; };
}); });
+1
View File
@@ -3,6 +3,7 @@ import { BaseWorld } from '../common';
// API functions // API functions
export type GetWorld = (params: { worldId: string }) => Promise<{ export type GetWorld = (params: { worldId: string }) => Promise<{
json: GetWorldResponse; json: GetWorldResponse;
ref: any;
params: { worldId: string }; params: { worldId: string };
}>; }>;
+5 -5
View File
@@ -123,15 +123,16 @@ declare global {
}; };
const Discord: { const Discord: {
SetTimestamps(
startTimestamp: number,
endTimestamp: number
): Promise<void>;
SetAssets( SetAssets(
details: string,
state: string,
stateUrl: string,
bigIcon: string, bigIcon: string,
bigIconText: string, bigIconText: string,
smallIcon: string, smallIcon: string,
smallIconText: string, smallIconText: string,
startTime: number,
endTime: number,
partyId: string, partyId: string,
partySize: number, partySize: number,
partyMaxSize: number, partyMaxSize: number,
@@ -140,7 +141,6 @@ declare global {
appId: string, appId: string,
activityType: number activityType: number
): Promise<void>; ): Promise<void>;
SetText(details: string, state: string): Promise<void>;
SetActive(active: boolean): Promise<boolean>; SetActive(active: boolean): Promise<boolean>;
}; };