diff --git a/html/src/app.js b/html/src/app.js
index e68ae281..92ba1c7f 100644
--- a/html/src/app.js
+++ b/html/src/app.js
@@ -8229,6 +8229,7 @@ speechSynthesis.getVoices();
this.photonLobbyJointime = new Map();
this.photonEvent7List = new Map();
this.photonLastEvent7List = '';
+ this.photonLastChatBoxMsg = new Map();
this.moderationEventQueue = new Map();
this.lastPortalList = new Map();
if (this.photonEventTable.data.length > 0) {
@@ -8806,6 +8807,7 @@ speechSynthesis.getVoices();
$app.data.photonLobbyBots = [];
$app.data.photonEvent7List = new Map();
$app.data.photonLastEvent7List = '';
+ $app.data.photonLastChatBoxMsg = new Map();
$app.data.photonEventType = [
'MeshVisibility',
@@ -8956,17 +8958,18 @@ speechSynthesis.getVoices();
hudTimeout.unshift({
userId: this.getUserIdFromPhotonId(id),
displayName: this.getDisplayNameFromPhotonId(id),
- time: Math.round(timeSinceLastEvent / 1000)
+ time: Math.round(timeSinceLastEvent / 1000),
+ rawTime: timeSinceLastEvent
});
}
}
});
if (this.photonLobbyTimeout.length > 0 || hudTimeout.length > 0) {
hudTimeout.sort(function (a, b) {
- if (a.time > b.time) {
+ if (a.rawTime > b.rawTime) {
return 1;
}
- if (a.time < b.time) {
+ if (a.rawTime < b.rawTime) {
return -1;
}
return 0;
@@ -9063,12 +9066,14 @@ speechSynthesis.getVoices();
'Event',
'OnPlayerJoined',
'OnPlayerLeft',
- 'AvatarChange',
+ 'ChangeAvatar',
'ChangeStatus',
'PortalSpawn',
'DeletedPortal',
'ChatBoxMessage',
'Moderation',
+ 'Camera',
+ 'SpawnEmoji',
'PhotonMasterMigrate',
'PhotonBot'
];
@@ -9520,6 +9525,11 @@ speechSynthesis.getVoices();
if (this.photonLobbyCurrentUser === photonId) {
return;
}
+ var lastMsg = this.photonLastChatBoxMsg.get(photonId);
+ if (lastMsg === text) {
+ return;
+ }
+ this.photonLastChatBoxMsg.set(photonId, text);
this.addEntryPhotonEvent({
photonId,
text,
@@ -9619,20 +9629,30 @@ speechSynthesis.getVoices();
data: `${displayName} called non existent RPC ${eventData.EventType}`
};
this.addPhotonEventToGameLog(entry);
+ return;
}
if (eventData.EventType === 14) {
+ var type = 'Event';
if (eventData.EventName === 'ChangeVisibility') {
if (eventData.Data[0] === true) {
var text = 'EnableCamera';
} else if (eventData.Data[0] === false) {
var text = 'DisableCamera';
}
+ type = 'Camera';
+ } else if (eventData.EventName === 'PhotoCapture') {
+ var text = 'PhotoCapture';
+ type = 'Camera';
+ } else if (eventData.EventName === 'TimerBloop') {
+ var text = 'TimerBloop';
+ type = 'Camera';
} else if (eventData.EventName === 'ReloadAvatarNetworkedRPC') {
var text = 'AvatarReset';
} else if (eventData.EventName === 'ReleaseBones') {
var text = 'ResetPhysBones';
} else if (eventData.EventName === 'SpawnEmojiRPC') {
- var text = `SpawnEmoji ${this.photonEmojis[eventData.Data]}`;
+ var text = this.photonEmojis[eventData.Data];
+ type = 'SpawnEmoji';
} else {
var eventVrc = '';
if (eventData.Data && eventData.Data.length > 0) {
@@ -9646,7 +9666,7 @@ speechSynthesis.getVoices();
this.addEntryPhotonEvent({
photonId: senderId,
text,
- type: 'Event',
+ type,
created_at: datetime
});
} else {
@@ -9819,6 +9839,10 @@ speechSynthesis.getVoices();
user,
gameLogDate
) {
+ if (typeof user === 'undefined') {
+ console.error('PhotonUser: user is undefined', photonId);
+ return;
+ }
var tags = [];
if (typeof user.tags !== 'undefined') {
tags = user.tags;
@@ -9935,25 +9959,26 @@ speechSynthesis.getVoices();
};
$app.methods.photonUserJoin = function (photonId, avatar, gameLogDate) {
- if (
- photonId === this.photonLobbyCurrentUser ||
- !this.photonEventOverlayJoinLeave
- ) {
+ if (photonId === this.photonLobbyCurrentUser) {
return;
}
- this.addEntryPhotonEvent({
- photonId,
- text: 'has joined',
- type: 'OnPlayerJoined',
- created_at: gameLogDate,
- avatar
+ this.checkVRChatCache(avatar).then((cacheInfo) => {
+ var inCache = false;
+ if (cacheInfo[0] > 0) {
+ inCache = true;
+ }
+ this.addEntryPhotonEvent({
+ photonId,
+ text: 'has joined',
+ type: 'OnPlayerJoined',
+ created_at: gameLogDate,
+ avatar,
+ inCache
+ });
});
};
$app.methods.photonUserLeave = function (photonId, gameLogDate) {
- if (!this.photonEventOverlayJoinLeave) {
- return;
- }
var text = 'has left';
var lastEvent = this.photonEvent7List.get(parseInt(photonId, 10));
if (typeof lastEvent !== 'undefined') {
@@ -10052,6 +10077,10 @@ speechSynthesis.getVoices();
avatar,
gameLogDate
) {
+ if (typeof user === 'undefined') {
+ console.error('PhotonAvatarChange: user is undefined', photonId);
+ return;
+ }
var oldAvatarId = this.photonLobbyAvatars.get(user.id);
if (
oldAvatarId &&
@@ -10083,7 +10112,7 @@ speechSynthesis.getVoices();
displayName: user.displayName,
userId: user.id,
text: `ChangeAvatar ${avatar.name}`,
- type: 'AvatarChange',
+ type: 'ChangeAvatar',
created_at: gameLogDate,
avatar,
inCache
@@ -10094,6 +10123,10 @@ speechSynthesis.getVoices();
};
$app.methods.parsePhotonAvatar = function (avatar) {
+ if (typeof avatar === 'undefined' || typeof avatar.id === 'undefined') {
+ console.error('PhotonAvatar: avatar is undefined');
+ return;
+ }
var tags = [];
var unityPackages = [];
if (typeof avatar.tags !== 'undefined') {
@@ -12451,8 +12484,8 @@ speechSynthesis.getVoices();
$app.data.photonEventOverlayFilter = configRepository.getString(
'VRCX_PhotonEventOverlayFilter'
);
- $app.data.photonEventOverlayJoinLeave = configRepository.getBool(
- 'VRCX_PhotonEventOverlayJoinLeave'
+ $app.data.photonOverlayMessageTimeout = configRepository.getString(
+ 'VRCX_photonOverlayMessageTimeout'
);
$app.data.photonLoggingEnabled = false;
$app.data.gameLogDisabled = configRepository.getBool(
@@ -12478,10 +12511,6 @@ speechSynthesis.getVoices();
'VRCX_PhotonEventOverlayFilter',
this.photonEventOverlayFilter
);
- configRepository.setBool(
- 'VRCX_PhotonEventOverlayJoinLeave',
- this.photonEventOverlayJoinLeave
- );
if (!this.timeoutHudOverlay) {
AppApi.ExecuteVrOverlayFunction('updateHudTimeout', '[]');
}
@@ -12575,11 +12604,11 @@ speechSynthesis.getVoices();
$app.data.photonEventOverlayFilter
);
}
- if (!configRepository.getBool('VRCX_PhotonEventOverlayJoinLeave')) {
- $app.data.photonEventOverlayJoinLeave = false;
- configRepository.setBool(
- 'VRCX_PhotonEventOverlayJoinLeave',
- $app.data.photonEventOverlayJoinLeave
+ if (!configRepository.getString('VRCX_photonOverlayMessageTimeout')) {
+ $app.data.photonOverlayMessageTimeout = 6000;
+ configRepository.setString(
+ 'VRCX_photonOverlayMessageTimeout',
+ $app.data.photonOverlayMessageTimeout
);
}
if (!configRepository.getBool('VRCX_instanceUsersSortAlphabetical')) {
@@ -12786,6 +12815,7 @@ speechSynthesis.getVoices();
minimalFeed: this.minimalFeed,
notificationPosition: this.notificationPosition,
notificationTimeout: this.notificationTimeout,
+ photonOverlayMessageTimeout: this.photonOverlayMessageTimeout,
notificationTheme,
backgroundEnabled: this.vrBackgroundEnabled,
dtHour12: this.dtHour12,
@@ -13225,6 +13255,33 @@ speechSynthesis.getVoices();
});
};
+ $app.methods.promptPhotonOverlayMessageTimeout = function () {
+ this.$prompt('Enter amount of seconds', 'Overlay Message Timeout', {
+ distinguishCancelAndClose: true,
+ confirmButtonText: 'OK',
+ cancelButtonText: 'Cancel',
+ inputValue: this.photonOverlayMessageTimeout / 1000,
+ inputPattern: /\d+$/,
+ inputErrorMessage: 'Valid number is required',
+ callback: (action, instance) => {
+ if (
+ action === 'confirm' &&
+ instance.inputValue &&
+ !isNaN(instance.inputValue)
+ ) {
+ this.photonOverlayMessageTimeout = Math.trunc(
+ Number(instance.inputValue) * 1000
+ );
+ configRepository.setString(
+ 'VRCX_photonOverlayMessageTimeout',
+ this.photonOverlayMessageTimeout
+ );
+ this.updateVRConfigVars();
+ }
+ }
+ });
+ };
+
$app.methods.promptRenameAvatar = function (avatar) {
this.$prompt('Enter avatar name', 'Rename Avatar', {
distinguishCancelAndClose: true,
diff --git a/html/src/index.pug b/html/src/index.pug
index e23d2d91..91af9d7d 100644
--- a/html/src/index.pug
+++ b/html/src/index.pug
@@ -147,21 +147,21 @@ html
template(#content)
span {{ scope.row.created_at | formatDate('long') }}
span {{ scope.row.created_at | formatDate('short') }}
- el-table-column(label="Name" prop="photonId" width="160")
+ el-table-column(label="User" prop="photonId" width="160")
template(v-once #default="scope")
span.x-link(v-text="scope.row.displayName" @click="showUserFromPhotonId(scope.row.photonId)" style="padding-right:10px")
- el-table-column(label="Event" prop="text")
+ el-table-column(label="Type" prop="type" width="140")
+ el-table-column(label="Details" prop="text")
template(v-once #default="scope")
- template(v-if="scope.row.type === 'AvatarChange'")
- span ChangeAvatar
+ template(v-if="scope.row.type === 'ChangeAvatar'")
span.x-link(v-text="scope.row.avatar.name" @click="showAvatarDialog(scope.row.avatar.id)")
|
+ span(v-if="!scope.row.inCache" style="color:#aaa") #[i.el-icon-download]
span.avatar-info-public(v-if="scope.row.avatar.releaseStatus === 'public'") (Public)
span.avatar-info-own(v-else-if="scope.row.avatar.releaseStatus === 'private'") (Private)
template(v-if="scope.row.avatar.description && scope.row.avatar.name !== scope.row.avatar.description")
| - {{ scope.row.avatar.description }}
template(v-else-if="scope.row.type === 'ChangeStatus'")
- span ChangeStatus
template(v-if="scope.row.status !== scope.row.previousStatus")
el-tooltip(placement="top")
template(#content)
@@ -170,7 +170,7 @@ html
span(v-else-if="scope.row.previousStatus === 'ask me'") Ask Me
span(v-else-if="scope.row.previousStatus === 'busy'") Do Not Disturb
span(v-else) Offline
- i.x-user-status(:class="statusClass(scope.row.previousStatus)" style="margin-left:5px")
+ i.x-user-status(:class="statusClass(scope.row.previousStatus)")
span
i.el-icon-right
el-tooltip(placement="top")
@@ -183,11 +183,12 @@ html
i.x-user-status(:class="statusClass(scope.row.status)")
span(v-if="scope.row.statusDescription !== scope.row.previousStatusDescription" v-text="scope.row.statusDescription" style="margin-left:5px")
span.x-link(v-else-if="scope.row.type === 'PortalSpawn'" @click="showWorldDialog(scope.row.location, scope.row.shortName)")
- | PortalSpawn #[location(:location="scope.row.location" :hint="scope.row.worldName" :link="false")]
- span(v-else-if="scope.row.type === 'ChatBoxMessage'")
- | ChatBox #[span(v-text="scope.row.text")]
+ location(:location="scope.row.location" :hint="scope.row.worldName" :link="false")
+ span(v-else-if="scope.row.type === 'ChatBoxMessage'" v-text="scope.row.text")
span(v-else-if="scope.row.type === 'OnPlayerJoined'")
- | has joined - #[span.x-link(v-text="scope.row.avatar.name" @click="showAvatarDialog(scope.row.avatar.id)")]
+ span.x-link(v-text="scope.row.avatar.name" @click="showAvatarDialog(scope.row.avatar.id)")
+ |
+ span(v-if="!scope.row.inCache" style="color:#aaa") #[i.el-icon-download]
span.avatar-info-public(v-if="scope.row.avatar.releaseStatus === 'public'") (Public)
span.avatar-info-own(v-else-if="scope.row.avatar.releaseStatus === 'private'") (Private)
span(v-else-if="scope.row.color === 'yellow'" v-text="scope.row.text" style="color:yellow")
@@ -200,21 +201,21 @@ html
template(#content)
span {{ scope.row.created_at | formatDate('long') }}
span {{ scope.row.created_at | formatDate('short') }}
- el-table-column(label="Name" prop="photonId" width="160")
+ el-table-column(label="User" prop="photonId" width="160")
template(v-once #default="scope")
span.x-link(v-text="scope.row.displayName" @click="lookupUser(scope.row)" style="padding-right:10px")
- el-table-column(label="Event" prop="text")
+ el-table-column(label="Type" prop="type" width="140")
+ el-table-column(label="Details" prop="text")
template(v-once #default="scope")
- span(v-if="scope.row.type === 'AvatarChange'")
- span ChangeAvatar
+ template(v-if="scope.row.type === 'ChangeAvatar'")
span.x-link(v-text="scope.row.avatar.name" @click="showAvatarDialog(scope.row.avatar.id)")
|
+ span(v-if="!scope.row.inCache" style="color:#aaa") #[i.el-icon-download]
span.avatar-info-public(v-if="scope.row.avatar.releaseStatus === 'public'") (Public)
span.avatar-info-own(v-else-if="scope.row.avatar.releaseStatus === 'private'") (Private)
template(v-if="scope.row.avatar.description && scope.row.avatar.name !== scope.row.avatar.description")
| - {{ scope.row.avatar.description }}
template(v-else-if="scope.row.type === 'ChangeStatus'")
- span ChangeStatus
template(v-if="scope.row.status !== scope.row.previousStatus")
el-tooltip(placement="top")
template(#content)
@@ -223,7 +224,7 @@ html
span(v-else-if="scope.row.previousStatus === 'ask me'") Ask Me
span(v-else-if="scope.row.previousStatus === 'busy'") Do Not Disturb
span(v-else) Offline
- i.x-user-status(:class="statusClass(scope.row.previousStatus)" style="margin-left:5px")
+ i.x-user-status(:class="statusClass(scope.row.previousStatus)")
span
i.el-icon-right
el-tooltip(placement="top")
@@ -236,11 +237,12 @@ html
i.x-user-status(:class="statusClass(scope.row.status)")
span(v-if="scope.row.statusDescription !== scope.row.previousStatusDescription" v-text="scope.row.statusDescription" style="margin-left:5px")
span.x-link(v-else-if="scope.row.type === 'PortalSpawn'" @click="showWorldDialog(scope.row.location, scope.row.shortName)")
- | PortalSpawn #[location(:location="scope.row.location" :hint="scope.row.worldName" :link="false")]
- span(v-else-if="scope.row.type === 'ChatBoxMessage'")
- | ChatBox #[span(v-text="scope.row.text")]
+ location(:location="scope.row.location" :hint="scope.row.worldName" :link="false")
+ span(v-else-if="scope.row.type === 'ChatBoxMessage'" v-text="scope.row.text")
span(v-else-if="scope.row.type === 'OnPlayerJoined'")
- | has joined - #[span.x-link(v-text="scope.row.avatar.name" @click="showAvatarDialog(scope.row.avatar.id)")]
+ span.x-link(v-text="scope.row.avatar.name" @click="showAvatarDialog(scope.row.avatar.id)")
+ |
+ span(v-if="!scope.row.inCache" style="color:#aaa") #[i.el-icon-download]
span.avatar-info-public(v-if="scope.row.avatar.releaseStatus === 'public'") (Public)
span.avatar-info-own(v-else-if="scope.row.avatar.releaseStatus === 'private'") (Private)
span(v-else-if="scope.row.color === 'yellow'" v-text="scope.row.text" style="color:yellow")
@@ -1350,18 +1352,18 @@ html
el-tooltip(placement="top" style="margin-left:5px" content="Requires SteamVR overlay to be enabled")
i.el-icon-warning
el-switch(v-model="photonEventOverlay" @change="saveEventOverlay" :disabled="!openVR")
- div.options-container-item
- span.name Show Join/Leave
- el-switch(v-model="photonEventOverlayJoinLeave" @change="saveEventOverlay" :disabled="!openVR")
div.options-container-item
span.name Filter
el-radio-group(v-model="photonEventOverlayFilter" @change="saveEventOverlay" size="mini" :disabled="!openVR || !photonEventOverlay")
el-radio-button(label="VIP")
el-radio-button(label="Friends")
el-radio-button(label="Everyone")
+ div.options-container-item
+ el-button(size="small" icon="el-icon-time" @click="promptPhotonOverlayMessageTimeout" :disabled="!openVR") Message Timeout
div.options-container-item
el-select(v-model="photonEventTableTypeOverlayFilter" @change="photonEventTableFilterChange" multiple clearable collapse-tags style="flex:1" placeholder="Filter")
el-option(v-once v-for="type in photonEventTableTypeFilterList" :key="type" :label="type" :value="type")
+ br
span.sub-header User timeout HUD
div.options-container-item
span.name Enable
diff --git a/html/src/vr.js b/html/src/vr.js
index b9c72b50..9e1cc884 100644
--- a/html/src/vr.js
+++ b/html/src/vr.js
@@ -569,7 +569,7 @@ Vue.component('marquee-text', MarqueeText);
$app.methods.cleanHudFeed = function () {
var dt = Date.now();
this.hudFeed.forEach((item) => {
- if (item.time + 6000 < dt) {
+ if (item.time + this.config.photonOverlayMessageTimeout < dt) {
removeFromArray(this.hudFeed, item);
}
});
diff --git a/html/src/vr.pug b/html/src/vr.pug
index 2bdaa8dd..b7f9651b 100644
--- a/html/src/vr.pug
+++ b/html/src/vr.pug
@@ -442,7 +442,7 @@ html
.hud-feed
div(v-for="feed in hudFeed")
.item #[span(v-if="feed.isMaster") 👑]{{ feed.displayName }}
- template(v-if="feed.type === 'AvatarChange'")
+ template(v-if="feed.type === 'ChangeAvatar'")
span(style="margin-left:10px") ChangeAvatar
span(v-if="!feed.inCache" style="color:#aaa;margin-left:10px") #[i.el-icon-download]
span(v-text="feed.avatar.name" style="margin-left:10px")
@@ -464,7 +464,11 @@ html
location(:location="feed.location" :hint="feed.worldName" :link="false" style="margin-left:10px")
template(v-else-if="feed.type === 'OnPlayerJoined'")
span(style="margin-left:10px") has joined -
+ span(v-if="!feed.inCache" style="color:#aaa;margin-left:10px") #[i.el-icon-download]
span(v-text="feed.avatar.name" style="margin-left:10px")
+ template(v-else-if="feed.type === 'SpawnEmoji'")
+ span(style="margin-left:10px") SpawnEmoji
+ span(v-text="feed.text" style="margin-left:10px")
span(v-else-if="feed.color === 'yellow'" v-text="feed.text" style="color:yellow;margin-left:10px")
span(v-else style="margin-left:10px" v-text="feed.text")
template(v-if="feed.combo > 1")