diff --git a/LogWatcher.cs b/LogWatcher.cs index 07937411..61bfefdd 100644 --- a/LogWatcher.cs +++ b/LogWatcher.cs @@ -239,7 +239,8 @@ namespace VRCX ParseLogOnAudioConfigurationChanged(fileInfo, logContext, line, offset) || ParseLogScreenshot(fileInfo, logContext, line, offset) || ParseLogStringDownload(fileInfo, logContext, line, offset) || - ParseLogImageDownload(fileInfo, logContext, line, offset)) + ParseLogImageDownload(fileInfo, logContext, line, offset) || + ParseVoteKick(fileInfo, logContext, line, offset)) { } } @@ -1057,6 +1058,24 @@ namespace VRCX }); return true; } + + private bool ParseVoteKick(FileInfo fileInfo, LogContext logContext, string line, int offset) + { + // 2023.06.02 01:08:04 Log - [Behaviour] Received executive message: You have been kicked from the instance by majority vote + // 2023.06.02 01:11:58 Log - [Behaviour] You have been kicked from this world for an hour. + + if (string.Compare(line, offset, "[Behaviour] Received executive message: ", 0, 40, StringComparison.Ordinal) != 0) + return false; + + AppendLog(new[] + { + fileInfo.Name, + ConvertLogTimeToISO8601(line), + "event", + line.Substring(offset + 40) + }); + return true; + } public string[][] Get() { diff --git a/html/src/app.js b/html/src/app.js index 7a03fb50..45e5918d 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -408,7 +408,12 @@ speechSynthesis.getVoices(); if (response.status === 200) { this.$throw(0, 'Invalid JSON response'); } - if (response.status === 504 || response.status === 502) { + if ( + response.status === 504 || + response.status === 502 || + (response.status === 429 && + init.url.endswith('/instances/groups ')) + ) { // ignore expected API errors throw new Error( `${response.status}: ${response.data} ${endpoint}` @@ -484,9 +489,6 @@ speechSynthesis.getVoices(); ) { throw new Error(`403: ${data.error.message} ${endpoint}`); } - if (status === 429) { - throw new Error(`429: ${data.error.message} ${endpoint}`); - } if (data && data.error === Object(data.error)) { this.$throw( data.error.status_code || status, @@ -5041,6 +5043,7 @@ speechSynthesis.getVoices(); API, nextCurrentUserRefresh: 0, nextFriendsRefresh: 0, + nextGroupInstanceRefresh: 0, nextAppUpdateCheck: 7200, ipcTimeout: 0, nextClearVRCXCacheCheck: 0, @@ -5219,6 +5222,12 @@ speechSynthesis.getVoices(); }); AppApi.CheckGameRunning(); } + if (--this.nextGroupInstanceRefresh <= 0) { + if (this.friendLogInitStatus) { + this.nextGroupInstanceRefresh = 600; // 5min + API.getUsersGroupInstances(); + } + } if (--this.nextAppUpdateCheck <= 0) { if (this.branch === 'Stable') { this.nextAppUpdateCheck = 14400; // 2hours @@ -7585,6 +7594,8 @@ speechSynthesis.getVoices(); $app.data.isFriendsGroup1 = true; $app.data.isFriendsGroup2 = true; $app.data.isFriendsGroup3 = false; + $app.data.isGroupInstances = false; + $app.data.groupInstances = []; $app.data.friendsGroup0_ = []; $app.data.friendsGroup1_ = []; $app.data.friendsGroup2_ = []; @@ -10543,6 +10554,15 @@ speechSynthesis.getVoices(); } }); } + } else if (data.Parameters[245]['0'] === 13) { + var msg = data.Parameters[245]['2']; + this.addEntryPhotonEvent({ + photonId, + text: msg, + type: 'Moderation', + color: 'yellow', + created_at: gameLogDate + }); } break; case 202: @@ -25128,6 +25148,46 @@ speechSynthesis.getVoices(); }); }; + API.$on('GROUP:USER:INSTANCES', function (args) { + $app.groupInstances = []; + for (var json of args.json.instances) { + this.$emit('INSTANCE', { + json, + params: { + fetchedAt: args.json.fetchedAt + } + }); + + var ref = this.cachedGroups.get(json.ownerId); + if (typeof ref === 'undefined') { + if ($app.friendLogInitStatus) { + this.getGroup({ groupId: json.ownerId }); + } + return; + } + $app.groupInstances.push({ + $group: ref, + ...json + }); + } + }); + + API.$on('INSTANCE', function (args) { + var { json } = args; + if (!json) { + return; + } + for (var instance of $app.groupInstances) { + if (instance.id === json.id) { + instance = { + ...instance, + ...json + }; + break; + } + } + }); + /* params: { query: string, diff --git a/html/src/index.pug b/html/src/index.pug index 1f538c79..c77bbf89 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -121,6 +121,18 @@ html location.extra(v-if="isGameRunning" :location="lastLocation.location" :traveling="lastLocationDestination" :link="false") location.extra(v-else-if="isRealInstance(API.currentUser.$locationTag) || isRealInstance(API.currentUser.$travelingToLocation)" :location="API.currentUser.$locationTag" :traveling="API.currentUser.$travelingToLocation" :link="false") span.extra(v-else v-text="API.currentUser.statusDescription") + .x-friend-group.x-link(@click="isGroupInstances = !isGroupInstances") + i.el-icon-arrow-right(:class="{ rotate: isGroupInstances }") + span(style="margin-left:5px") {{ $t('side_panel.groups') }} ― {{ groupInstances.length }} + div(v-show="isGroupInstances") + .x-friend-item(v-for="instance in groupInstances" :key="instance.id" @click="showGroupDialog(instance.ownerId)") + .avatar + img(v-lazy="instance.$group.iconUrl") + .detail + span.name + span(v-text="instance.$group.name") + span(style="font-weight:normal;margin-left:5px") ({{ instance.userCount }}/{{ instance.capacity }}) + location.extra(:location="instance.location" :link="false") .x-friend-group.x-link(@click="isFriendsGroup0 = !isFriendsGroup0" v-show="friendsGroup0.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup0 }") span(style="margin-left:5px") {{ $t('side_panel.favorite') }} ― {{ friendsGroup0.length }} diff --git a/html/src/localization/strings/en.json b/html/src/localization/strings/en.json index 7d1af2d1..25905c1a 100644 --- a/html/src/localization/strings/en.json +++ b/html/src/localization/strings/en.json @@ -478,6 +478,7 @@ "direct_access_tooltip": "Direct access ID/URL from clipboard", "refresh_tooltip": "Refresh friends", "friends": "FRIENDS", + "groups": "GROUPS", "me": "ME", "favorite": "FAVORITES", "online": "ONLINE",