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
+113 -106
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
@@ -119,106 +120,112 @@ 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,
if (m_Client == null || m_Lock.IsReadLockHeld) string state,
return; string stateUrl,
m_Lock.EnterWriteLock(); string largeKey,
try string largeText,
{
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) string smallKey,
string smallText,
double startUnixMilliseconds,
double endUnixMilliseconds,
string partyId,
int partySize,
int partyMax,
string buttonText,
string buttonUrl,
string appId,
int activityType)
{ {
m_Lock.EnterWriteLock(); _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>;
}; };