diff --git a/Dotnet/LogWatcher.cs b/Dotnet/LogWatcher.cs index d626c5cc..a741d86e 100644 --- a/Dotnet/LogWatcher.cs +++ b/Dotnet/LogWatcher.cs @@ -20,6 +20,7 @@ namespace VRCX public class LogWatcher { public static readonly LogWatcher Instance; + private static readonly NLog.Logger logger = NLog.LogManager.GetLogger("VRCX"); private readonly Dictionary m_LogContextMap; // private readonly DirectoryInfo m_LogDirectoryInfo; private readonly List m_LogList; @@ -72,8 +73,8 @@ namespace VRCX public void SetDateTill(string date) { - tillDate = DateTime.Parse(date, CultureInfo.InvariantCulture, DateTimeStyles.None); - tillDate = tillDate.ToUniversalTime(); + tillDate = DateTime.Parse(date, CultureInfo.InvariantCulture, DateTimeStyles.None).ToUniversalTime(); + logger.Info("SetDateTill: {0}", tillDate.ToLocalTime()); } private void ThreadLoop() @@ -214,10 +215,22 @@ namespace VRCX )) { lineDate = lineDate.ToUniversalTime(); + // check if date is older than last database entry if (DateTime.Compare(lineDate, tillDate) <= 0) { continue; } + // check if datetime is over an hour into the future (compensate for gamelog not handling daylight savings time correctly) + if (DateTime.UtcNow.AddMinutes(61) < lineDate) + { + logger.Warn("Invalid log time, too new: {0}", line); + continue; + } + } + else + { + logger.Warn("Failed to parse log date: {0}", line); + continue; } var offset = 34; @@ -1165,7 +1178,7 @@ namespace VRCX fileInfo.Name, ConvertLogTimeToISO8601(line), "event", - $"VRChat could not start OSC server, You may be affected by (https://vrchat.canny.io/bug-reports/p/installexe-breaks-osc-port-binding) \"{line.Substring(offset)}\"" + $"VRChat couldn't start OSC server, you may be affected by (https://vrchat.canny.io/bug-reports/p/installexe-breaks-osc-port-binding) \"{line.Substring(offset)}\"" }); return true; } diff --git a/html/src/app.js b/html/src/app.js index bbc7d383..6fb10797 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -3570,7 +3570,7 @@ speechSynthesis.getVoices(); } if (!json.details?.emojiId) { - json.message = `${json.senderUsername} Booped you! with nothing`; + json.message = `${json.senderUsername} Booped you! without an emoji`; } else if (!json.details.emojiId.startsWith('file_')) { // JANK: get emoji name from emojiId json.message = `${json.senderUsername} Booped you! with ${$app.getEmojiName(json.details.emojiId)}`; @@ -12052,12 +12052,19 @@ speechSynthesis.getVoices(); } }); } - } else if (data.Parameters[245]['0'] === 13) { + } else if ( + data.Parameters[245]['0'] === 13 || + data.Parameters[245]['0'] === 25 + ) { var msg = data.Parameters[245]['2']; - if (typeof msg === 'string') { - var displayName = - data.Parameters[245]['14']?.targetDisplayName; - msg = msg.replace('{{targetDisplayName}}', displayName); + if ( + typeof msg === 'string' && + typeof data.Parameters[245]['14'] === 'object' + ) { + for (var prop in data.Parameters[245]['14']) { + var value = data.Parameters[245]['14'][prop]; + msg = msg.replace(`{{${prop}}}`, value); + } } this.addEntryPhotonEvent({ photonId, @@ -25242,7 +25249,7 @@ speechSynthesis.getVoices(); url, fps, frameCount, - animationStyle + loopStyle ) { let framesPerLine = 2; if (frameCount > 4) framesPerLine = 4; @@ -25250,15 +25257,14 @@ speechSynthesis.getVoices(); const animationDurationMs = (1000 / fps) * frameCount; const frameSize = 1024 / framesPerLine; const scale = 100 / (frameSize / 200); - const animStyle = - animationStyle === 'pingpong' ? 'alternate' : 'infinite'; + const animStyle = loopStyle === 'pingpong' ? 'alternate' : 'none'; const style = ` transform: scale(${scale / 100}); transform-origin: top left; width: ${frameSize}px; height: ${frameSize}px; background: url('${url}') 0 0; - animation: ${animationDurationMs}ms steps(1) 0s ${animStyle} normal none running animated-emoji-${frameCount}; + animation: ${animationDurationMs}ms steps(1) 0s infinite ${animStyle} running animated-emoji-${frameCount}; `; return style; }; @@ -32670,6 +32676,13 @@ speechSynthesis.getVoices(); // #endregion // #region | Boops + /** + * @param {{ + userId: string, + emojiId: string + }} params + * @returns {Promise<{json: any, params}>} + */ API.sendBoop = function (params) { return this.call(`users/${params.userId}/boop`, { method: 'POST', @@ -32687,7 +32700,13 @@ speechSynthesis.getVoices(); $app.methods.sendBoop = function () { var D = this.sendBoopDialog; this.dismissBoop(D.userId); - API.sendBoop({ userId: D.userId, emojiId: D.fileId }); + var params = { + userId: D.userId + }; + if (D.fileId) { + params.emojiId = D.fileId; + } + API.sendBoop(params); D.visible = false; }; diff --git a/html/src/app.scss b/html/src/app.scss index fb047a97..c597c21f 100644 --- a/html/src/app.scss +++ b/html/src/app.scss @@ -193,7 +193,7 @@ a { .x-login-form-container { display: grid; gap: 8px; - height: 375px; + height: 380px; } .x-login-form-container:has(> div:nth-child(3)) { @@ -205,6 +205,7 @@ a { flex-direction: column; min-height: 0; padding: 16px; + overflow-y: auto; } .x-scroll-wrapper { diff --git a/html/src/index.pug b/html/src/index.pug index 45d0b3e4..931106bd 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -238,7 +238,7 @@ html i.el-icon-caret-bottom el-popover(placement="top" trigger="click") span.dialog-title(slot="reference" v-text="userDialog.ref.displayName" style="margin-left:5px;margin-right:5px;cursor:pointer") - span(style="display:block;text-align:center;font-family:monospace") {{ API.currentUser.username | textToHex }} + span(style="display:block;text-align:center;font-family:monospace") {{ userDialog.ref.displayName | textToHex }} el-tooltip(v-if="userDialog.ref.pronouns" placement="top" :content="$t('dialog.user.pronouns')" :disabled="hideTooltips") span(v-text="userDialog.ref.pronouns" style="margin-right:5px;color:#909399;font-family:monospace;font-size:12px") el-tooltip(v-for="item in userDialog.ref.$languages" :key="item.key" placement="top") @@ -300,7 +300,7 @@ html el-dropdown-item(v-else-if="userDialog.outgoingRequest" icon="el-icon-close" command="Cancel Friend Request") {{ $t('dialog.user.actions.cancel_friend_request') }} el-dropdown-item(v-else icon="el-icon-plus" command="Send Friend Request") {{ $t('dialog.user.actions.send_friend_request') }} el-dropdown-item(icon="el-icon-message" command="Invite To Group") {{ $t('dialog.user.actions.invite_to_group') }} - el-dropdown-item(icon="el-icon-thumb" command="Send Boop") {{ $t('dialog.user.actions.send_boop') }} + el-dropdown-item(icon="el-icon-thumb" command="Send Boop" :disabled="!API.currentUser.isBoopingEnabled") {{ $t('dialog.user.actions.send_boop') }} el-dropdown-item(icon="el-icon-s-custom" command="Show Avatar Author" divided) {{ $t('dialog.user.actions.show_avatar_author') }} el-dropdown-item(icon="el-icon-s-custom" command="Show Fallback Avatar Details") {{ $t('dialog.user.actions.show_fallback_avatar') }} el-dropdown-item(icon="el-icon-tickets" command="Previous Instances") {{ $t('dialog.user.actions.show_previous_instances') }} @@ -2528,7 +2528,7 @@ html .x-friend-item(v-if="image.versions && image.versions.length > 0" v-for="image in emojiTable" :key="image.id" style="display:inline-block;margin-top:10px;width:unset;cursor:default") .vrcplus-icon(v-if="image.versions[image.versions.length - 1].file.url" style="overflow:hidden" @click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)") template(v-if="image.frames") - .avatar(:style="generateEmojiStyle(image.versions[image.versions.length - 1].file.url, image.framesOverTime, image.frames, image.animationStyle)") + .avatar(:style="generateEmojiStyle(image.versions[image.versions.length - 1].file.url, image.framesOverTime, image.frames, image.loopStyle)") template(v-else) img.avatar(v-lazy="image.versions[image.versions.length - 1].file.url") div(style="display:inline-block;margin:5px") @@ -3286,9 +3286,6 @@ html //- dialog: send boop el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendBoopDialog" :visible.sync="sendBoopDialog.visible" :title="$t('dialog.boop_dialog.header')" width="450px") div(v-if="sendBoopDialog.visible") - el-button(size="small" @click="showGalleryDialog(2)") {{ $t('dialog.boop_dialog.emoji_manager') }} - br - br el-select(v-model="sendBoopDialog.userId" :placeholder="$t('dialog.new_instance.instance_creator_placeholder')" filterable style="width:100%") el-option-group(v-if="friendsGroup0.length" :label="$t('side_panel.favorite')") el-option.x-friend-item(v-for="friend in friendsGroup0" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") @@ -3329,13 +3326,14 @@ html el-option(v-if="image.versions && image.versions.length > 0" v-for="image in emojiTable" :key="image.id" :value="image.id" style="width:100%;height:100%") .vrcplus-icon(v-if="image.versions[image.versions.length - 1].file.url" style="overflow:hidden;width:200px;height:200px;padding:10px") template(v-if="image.frames") - .avatar(:style="generateEmojiStyle(image.versions[image.versions.length - 1].file.url, image.framesOverTime, image.frames, image.animationStyle)") + .avatar(:style="generateEmojiStyle(image.versions[image.versions.length - 1].file.url, image.framesOverTime, image.frames, image.loopStyle)") template(v-else) img.avatar(v-lazy="image.versions[image.versions.length - 1].file.url" style="width:200px;height:200px") el-option-group(:label="$t('dialog.boop_dialog.default_emojis')") el-option(v-for="emojiName in photonEmojis" :key="emojiName" :value="getEmojiValue(emojiName)" style="width:100%;height:100%") span(v-text="emojiName") template(#footer) + el-button(size="small" @click="showGalleryDialog(2)") {{ $t('dialog.boop_dialog.emoji_manager') }} el-button(size="small" @click="sendBoopDialog.visible = false") {{ $t('dialog.boop_dialog.cancel') }} el-button(size="small" @click="sendBoop" :disabled="!sendBoopDialog.userId") {{ $t('dialog.boop_dialog.send') }}