diff --git a/html/src/app.js b/html/src/app.js
index 57ad2b8c..48b5d08f 100644
--- a/html/src/app.js
+++ b/html/src/app.js
@@ -1064,6 +1064,101 @@ speechSynthesis.getVoices();
}
});
+ Vue.component('instance-info', {
+ template:
+ '
' +
+ '
' +
+ '' +
+ 'PC: {{ platforms.standalonewindows }}' +
+ 'Quest: {{ platforms.android }}' +
+ '{{ $t("dialog.user.info.instance_game_version") }} {{ gameServerVersion }}' +
+ '{{ $t("dialog.user.info.instance_queuing_enabled") }}' +
+ '{{ $t("dialog.user.info.instance_users") }}' +
+ '' +
+ '
' +
+ '' +
+ '' +
+ '
{{ occupants }}/{{ capacity }}' +
+ '
({{ friendcount }})' +
+ '
{{ $t("dialog.user.info.instance_full") }}' +
+ '
{{ $t("dialog.user.info.instance_queue") }} {{ queueSize }}' +
+ '
',
+ props: {
+ location: String,
+ instance: Object,
+ friendcount: Number,
+ updateelement: Number
+ },
+ data() {
+ return {
+ isValidInstance: this.isValidInstance,
+ isFull: this.isFull,
+ occupants: this.occupants,
+ capacity: this.capacity,
+ queueSize: this.queueSize,
+ queueEnabled: this.queueEnabled,
+ platforms: this.platforms,
+ userList: this.userList,
+ gameServerVersion: this.gameServerVersion
+ };
+ },
+ methods: {
+ parse() {
+ this.isValidInstance = false;
+ this.isFull = false;
+ this.occupants = 0;
+ this.capacity = 0;
+ this.queueSize = 0;
+ this.queueEnabled = false;
+ this.platforms = [];
+ this.userList = [];
+ this.gameServerVersion = '';
+ if (
+ !this.location ||
+ !this.instance ||
+ Object.keys(this.instance).length === 0
+ ) {
+ return;
+ }
+ this.isValidInstance = true;
+ this.isFull =
+ typeof this.instance.hasCapacityForYou !== 'undefined' &&
+ !this.instance.hasCapacityForYou;
+ this.occupants = this.instance.n_users;
+ if (this.location === $app.lastLocation.location) {
+ // use gameLog for occupants when in same location
+ this.occupants = $app.lastLocation.playerList.size;
+ }
+ this.capacity = this.instance.capacity;
+ this.gameServerVersion = this.instance.gameServerVersion;
+ this.queueSize = this.instance.queueSize;
+ if (this.instance.platforms) {
+ this.platforms = this.instance.platforms;
+ }
+ if (this.instance.users) {
+ this.userList = this.instance.users;
+ }
+ },
+ showUserDialog(userId) {
+ API.$emit('SHOW_USER_DIALOG', userId);
+ }
+ },
+ watch: {
+ updateelement() {
+ this.parse();
+ },
+ location() {
+ this.parse();
+ },
+ friendcount() {
+ this.parse();
+ }
+ },
+ created() {
+ this.parse();
+ }
+ });
+
Vue.component('avatar-info', {
template:
'{{ avatarName }}{{ avatarType }}
',
@@ -1281,6 +1376,7 @@ speechSynthesis.getVoices();
// set VRCX online/offline timers
$online_for: this.currentUser.$online_for,
$offline_for: this.currentUser.$offline_for,
+ $location_at: this.currentUser.$location_at,
$travelingToTime: this.currentUser.$travelingToTime
});
});
@@ -1616,6 +1712,7 @@ speechSynthesis.getVoices();
// VRCX
$online_for: Date.now(),
$offline_for: '',
+ $location_at: Date.now(),
$travelingToTime: Date.now(),
$homeLocation: {},
$isVRCPlus: false,
@@ -2065,19 +2162,16 @@ speechSynthesis.getVoices();
return this.currentUser?.presence?.world;
};
- // TODO: traveling to world checks
API.actuallyGetCurrentLocation = async function () {
let gameLogLocation = $app.lastLocation.location;
if (gameLogLocation === 'traveling') {
gameLogLocation = $app.lastLocationDestination;
}
- console.log('PWI: gameLog Location:', gameLogLocation);
let presenceLocation = this.currentUser.$locationTag;
if (presenceLocation === 'traveling') {
presenceLocation = this.currentUser.$travelingToLocation;
}
- console.log('PWI: presence Location:', presenceLocation);
// We want to use presence if it's valid to avoid extra API calls, but its prone to being outdated when this function is called.
// So we check if the presence location is the same as the gameLog location; If it is, the presence is (probably) valid and we can use it.
@@ -2085,7 +2179,6 @@ speechSynthesis.getVoices();
// If the user happens to be offline or the api is just being dumb, we assume that the user logged into VRCX is different than the one in-game and return the gameLog location.
// This is really dumb.
if (presenceLocation === gameLogLocation) {
- console.log('PWI: locations match:', presenceLocation);
const L = this.parseLocation(presenceLocation);
return L.worldId;
}
@@ -2320,6 +2413,11 @@ speechSynthesis.getVoices();
});
};
+ // #endregion
+ // #region | API: Instance
+
+ API.cachedInstances = new Map();
+
/*
params: {
worldId: string,
@@ -2447,59 +2545,88 @@ speechSynthesis.getVoices();
});
};
- API.$on('INSTANCE', function (args) {
- var { json } = args;
- if (!json) {
- return;
+ API.applyInstance = function (json) {
+ var ref = this.cachedInstances.get(json.id);
+ if (typeof ref === 'undefined') {
+ ref = {
+ id: '',
+ location: '',
+ instanceId: '',
+ name: '',
+ worldId: '',
+ type: '',
+ ownerId: '',
+ tags: [],
+ active: false,
+ full: false,
+ n_users: 0,
+ hasCapacityForYou: true, // not present depending on endpoint
+ capacity: 0,
+ recommendedCapacity: 0,
+ userCount: 0, // PC only?
+ queueEnabled: false, // only present with group instance type
+ queueSize: 0, // only present when queuing is enabled
+ platforms: [],
+ gameServerVersion: 0,
+ secureName: '',
+ shortName: '',
+ world: {},
+ nonce: '',
+ users: [], // only present when you're the owner
+ clientNumber: '',
+ photonRegion: '',
+ region: '',
+ canRequestInvite: false,
+ permanent: false,
+ private: '',
+ strict: false,
+ // VRCX
+ $fetchedAt: '',
+ ...json
+ };
+ this.cachedInstances.set(ref.id, ref);
+ } else {
+ Object.assign(ref, json);
}
- var D = $app.userDialog;
- if ($app.userDialog.visible && D.ref.$location.tag === json.id) {
- D.instance.occupants = json.n_users;
- D.instance.full =
- typeof json.hasCapacityForYou !== 'undefined' &&
- !json.hasCapacityForYou;
- D.instance.json = json;
+ ref.$location = this.parseLocation(ref.location);
+ if (json.world?.id) {
+ ref.world = this.applyWorld(json.world);
}
- });
+ if (!json.$fetchedAt) {
+ ref.$fetchedAt = new Date().toJSON();
+ }
+ return ref;
+ };
API.$on('INSTANCE', function (args) {
var { json } = args;
if (!json) {
return;
}
- var D = $app.worldDialog;
- if ($app.worldDialog.visible && $app.worldDialog.id === json.worldId) {
- for (var instance of D.rooms) {
- if (instance.id === json.instanceId) {
- instance.occupants = json.n_users;
- instance.full =
- typeof json.hasCapacityForYou !== 'undefined' &&
- !json.hasCapacityForYou;
- instance.json = json;
- break;
- }
- }
- }
+ args.ref = this.applyInstance(args.json);
});
API.$on('INSTANCE', function (args) {
- var { json } = args;
- if (!json) {
- return;
+ if (
+ $app.userDialog.visible &&
+ $app.userDialog.ref.$location.tag === args.json.id
+ ) {
+ $app.applyUserDialogLocation();
}
- var D = $app.groupDialog;
- if ($app.groupDialog.visible && $app.groupDialog.id === json.ownerId) {
- for (var instance of D.instances) {
- if (instance.id === json.instanceId) {
- instance.occupants = json.n_users;
- instance.full =
- typeof json.hasCapacityForYou !== 'undefined' &&
- !json.hasCapacityForYou;
- instance.json = json;
- break;
- }
- }
+ if (
+ $app.worldDialog.visible &&
+ $app.worldDialog.id === args.json.worldId
+ ) {
+ $app.applyWorldDialogInstances();
}
+ if (
+ $app.groupDialog.visible &&
+ $app.groupDialog.id === args.json.ownerId
+ ) {
+ $app.applyGroupDialogInstances();
+ }
+ // hacky workaround to force update instance info
+ $app.updateInstanceInfo++;
});
// #endregion
@@ -5098,11 +5225,16 @@ speechSynthesis.getVoices();
this.enableAppLauncher,
this.enableAppLauncherAutoClose
);
+ API.$on('SHOW_USER_DIALOG', (userId) =>
+ this.showUserDialog(userId)
+ );
API.$on('SHOW_WORLD_DIALOG', (tag) => this.showWorldDialog(tag));
API.$on('SHOW_WORLD_DIALOG_SHORTNAME', (tag) =>
this.verifyShortName('', tag)
);
- API.$on('SHOW_GROUP_DIALOG', (tag) => this.showGroupDialog(tag));
+ API.$on('SHOW_GROUP_DIALOG', (groupId) =>
+ this.showGroupDialog(groupId)
+ );
API.$on('SHOW_LAUNCH_DIALOG', (tag, shortName) =>
this.showLaunchDialog(tag, shortName)
);
@@ -9616,8 +9748,12 @@ speechSynthesis.getVoices();
location: gameLog.location,
worldId: L.worldId,
worldName,
+ groupName: '',
time: 0
};
+ this.getGroupName(gameLog.location).then((groupName) => {
+ entry.groupName = groupName;
+ });
this.addGamelogLocationToDatabase(entry);
break;
case 'player-joined':
@@ -9978,6 +10114,66 @@ speechSynthesis.getVoices();
'CallUdonMethod'
];
+ $app.data.oldPhotonEmojis = [
+ 'Angry',
+ 'Blushing',
+ 'Crying',
+ 'Frown',
+ 'Hand Wave',
+ 'Hang Ten',
+ 'In Love',
+ 'Jack O Lantern',
+ 'Kiss',
+ 'Laugh',
+ 'Skull',
+ 'Smile',
+ 'Spooky Ghost',
+ 'Stoic',
+ 'Sunglasses',
+ 'Thinking',
+ 'Thumbs Down',
+ 'Thumbs Up',
+ 'Tongue Out',
+ 'Wow',
+ 'Bats',
+ 'Cloud',
+ 'Fire',
+ 'Snow Fall',
+ 'Snowball',
+ 'Splash',
+ 'Web',
+ 'Beer',
+ 'Candy',
+ 'Candy Cane',
+ 'Candy Corn',
+ 'Champagne',
+ 'Drink',
+ 'Gingerbread',
+ 'Ice Cream',
+ 'Pineapple',
+ 'Pizza',
+ 'Tomato',
+ 'Beachball',
+ 'Coal',
+ 'Confetti',
+ 'Gift',
+ 'Gifts',
+ 'Life Ring',
+ 'Mistletoe',
+ 'Money',
+ 'Neon Shades',
+ 'Sun Lotion',
+ 'Boo',
+ 'Broken Heart',
+ 'Exclamation',
+ 'Go',
+ 'Heart',
+ 'Music Note',
+ 'Question',
+ 'Stop',
+ 'Zzz'
+ ];
+
$app.data.photonEmojis = [
'Angry',
'Blushing',
@@ -9999,6 +10195,14 @@ speechSynthesis.getVoices();
'Thumbs Up',
'Tongue Out',
'Wow',
+ 'Arrow Point',
+ "Can't see",
+ 'Hourglass',
+ 'Keyboard',
+ 'No Headphones',
+ 'No Mic',
+ 'Portal',
+ 'Shush',
'Bats',
'Cloud',
'Fire',
@@ -10230,20 +10434,30 @@ speechSynthesis.getVoices();
if (input.photonId === this.photonLobbyMaster) {
isMaster = true;
}
- var userId = this.getUserIdFromPhotonId(input.photonId);
+ var joinTimeRef = this.photonLobbyJointime.get(input.photonId);
+ var isModerator = joinTimeRef?.canModerateInstance;
+ var photonUserRef = this.photonLobby.get(input.photonId);
+ var displayName = '';
+ var userId = '';
+ var isFriend = false;
+ if (typeof photonUserRef !== 'undefined') {
+ displayName = photonUserRef.displayName;
+ userId = photonUserRef.id;
+ isFriend = photonUserRef.isFriend;
+ }
var isFavorite = API.cachedFavoritesByObjectId.has(userId);
- var isFriend = this.friends.has(userId);
var colour = '';
var tagRef = this.customUserTags.get(userId);
if (typeof tagRef !== 'undefined' && tagRef.colour) {
colour = tagRef.colour;
}
var feed = {
- displayName: this.getDisplayNameFromPhotonId(input.photonId),
+ displayName,
userId,
isFavorite,
isFriend,
isMaster,
+ isModerator,
colour,
...input
};
@@ -10747,6 +10961,25 @@ speechSynthesis.getVoices();
});
}
break;
+ case 71:
+ // Spawn Emoji
+ var photonId = data.Parameters[254];
+ var type = data.Parameters[245][0];
+ var emojiName = '';
+ if (type === 0) {
+ var emojiId = data.Parameters[245][2];
+ emojiName = this.photonEmojis[emojiId];
+ } else if (type === 1) {
+ // file_id
+ emojiName = data.Parameters[245][1];
+ }
+ this.addEntryPhotonEvent({
+ photonId,
+ text: emojiName,
+ type: 'SpawnEmoji',
+ created_at: gameLogDate
+ });
+ break;
}
};
@@ -10791,7 +11024,7 @@ speechSynthesis.getVoices();
} else if (eventData.EventName === 'ReleaseBones') {
var text = 'ResetPhysBones';
} else if (eventData.EventName === 'SpawnEmojiRPC') {
- var text = this.photonEmojis[eventData.Data];
+ var text = this.oldPhotonEmojis[eventData.Data];
type = 'SpawnEmoji';
} else {
var eventVrc = '';
@@ -11720,6 +11953,9 @@ speechSynthesis.getVoices();
var videoName = data[4];
var videoUrl = videoName;
var videoId = 'Movie&Chill';
+ if (!videoName) {
+ return;
+ }
if (videoUrl === this.nowPlaying.url) {
var entry = {
created_at: gameLog.dt,
@@ -12455,16 +12691,18 @@ speechSynthesis.getVoices();
this.isSearchAvatarLoading = false;
}
var avatarsArray = Array.from(avatars.values());
- switch (this.searchAvatarSort) {
- case 'updated':
- avatarsArray.sort(compareByUpdatedAt);
- break;
- case 'created':
- avatarsArray.sort(compareByCreatedAt);
- break;
- case 'name':
- avatarsArray.sort(compareByName);
- break;
+ if (this.searchAvatarFilterRemote === 'local') {
+ switch (this.searchAvatarSort) {
+ case 'updated':
+ avatarsArray.sort(compareByUpdatedAt);
+ break;
+ case 'created':
+ avatarsArray.sort(compareByCreatedAt);
+ break;
+ case 'name':
+ avatarsArray.sort(compareByName);
+ break;
+ }
}
this.searchAvatarPageNum = 0;
this.searchAvatarResults = avatarsArray;
@@ -14280,7 +14518,7 @@ speechSynthesis.getVoices();
this.updateVRConfigVars();
};
- $app.data.youTubeApi = configRepository.getBool('VRCX_youtubeAPI', true);
+ $app.data.youTubeApi = configRepository.getBool('VRCX_youtubeAPI', false);
$app.data.youTubeApiKey = configRepository.getString(
'VRCX_youtubeAPIKey',
''
@@ -15515,12 +15753,10 @@ speechSynthesis.getVoices();
id: '',
tag: '',
$location: {},
- occupants: 0,
friendCount: 0,
- full: false,
users: [],
shortName: '',
- json: {}
+ ref: {}
};
D.representedGroup = {
bannerUrl: '',
@@ -15726,14 +15962,11 @@ speechSynthesis.getVoices();
return;
}
var L = API.parseLocation(D.ref.$location.tag);
- if (L.tag !== this.lastLocation.location && updateInstanceOccupants) {
- this.userDialog.instance.occupants = 0;
- if (this.isRealInstance(L.tag)) {
- API.getInstance({
- worldId: L.worldId,
- instanceId: L.instanceId
- });
- }
+ if (updateInstanceOccupants && this.isRealInstance(L.tag)) {
+ API.getInstance({
+ worldId: L.worldId,
+ instanceId: L.instanceId
+ });
}
D.$location = L;
if (L.userId) {
@@ -15819,12 +16052,10 @@ speechSynthesis.getVoices();
id: L.instanceId,
tag: L.tag,
$location: L,
- occupants: this.lastLocation.playerList.size,
friendCount: 0,
- full: false,
users: [],
shortName: '',
- json: {}
+ ref: {}
};
}
if (!this.isRealInstance(L.tag)) {
@@ -15832,13 +16063,16 @@ speechSynthesis.getVoices();
id: L.instanceId,
tag: L.tag,
$location: L,
- occupants: 0,
- full: false,
+ friendCount: 0,
users: [],
shortName: '',
- json: {}
+ ref: {}
};
}
+ var instanceRef = API.cachedInstances.get(L.tag);
+ if (typeof instanceRef !== 'undefined') {
+ D.instance.ref = instanceRef;
+ }
D.instance.friendCount = friendCount;
this.updateTimers();
};
@@ -15929,12 +16163,14 @@ speechSynthesis.getVoices();
) {
isMaster = true;
}
+ var isModerator = false;
var lobbyJointime = $app.photonLobbyJointime.get(photonId);
var inVRMode = null;
var groupOnNameplate = '';
if (typeof lobbyJointime !== 'undefined') {
inVRMode = lobbyJointime.inVRMode;
groupOnNameplate = lobbyJointime.groupOnNameplate;
+ isModerator = lobbyJointime.canModerateInstance;
}
// if (groupOnNameplate) {
// API.getCachedGroup({
@@ -15945,7 +16181,7 @@ speechSynthesis.getVoices();
// }
var timeoutTime = 0;
if (typeof ref.id !== 'undefined') {
- isFriend = $app.friends.has(ref.id);
+ isFriend = ref.isFriend;
if (
$app.timeoutHudOverlayFilter === 'VIP' ||
$app.timeoutHudOverlayFilter === 'Friends'
@@ -15970,6 +16206,7 @@ speechSynthesis.getVoices();
$trustSortNum: ref.$trustSortNum ?? 0,
photonId,
isMaster,
+ isModerator,
inVRMode,
groupOnNameplate,
isFriend,
@@ -16021,8 +16258,11 @@ speechSynthesis.getVoices();
this.updateTimers();
};
+ $app.data.updateInstanceInfo = 0;
+
$app.data.currentInstanceWorld = {
ref: {},
+ instance: {},
isPC: false,
isQuest: false,
isIos: false,
@@ -16041,6 +16281,7 @@ speechSynthesis.getVoices();
if (!instanceId) {
this.currentInstanceWorld = {
ref: {},
+ instance: {},
isPC: false,
isQuest: false,
isIos: false,
@@ -16053,6 +16294,7 @@ speechSynthesis.getVoices();
} else if (instanceId !== this.currentInstanceLocation.tag) {
this.currentInstanceWorld = {
ref: {},
+ instance: {},
isPC: false,
isQuest: false,
isIos: false,
@@ -16110,6 +16352,20 @@ speechSynthesis.getVoices();
});
});
}
+ if (this.isRealInstance(instanceId)) {
+ var ref = API.cachedInstances.get(instanceId);
+ if (typeof ref !== 'undefined') {
+ this.currentInstanceWorld.instance = ref;
+ } else {
+ var L = API.parseLocation(instanceId);
+ API.getInstance({
+ worldId: L.worldId,
+ instanceId: L.instanceId
+ }).then((args) => {
+ this.currentInstanceWorld.instance = args.ref;
+ });
+ }
+ }
};
$app.methods.getAvailablePlatforms = function (unityPackages) {
@@ -16708,11 +16964,7 @@ speechSynthesis.getVoices();
D.ref = ref;
$app.applyWorldDialogInstances();
for (var room of D.rooms) {
- if (
- $app.isRealInstance(room.tag) &&
- room.tag !== $app.lastLocation.location &&
- (room.$location.accessType !== 'public' || room.occupants === 0)
- ) {
+ if ($app.isRealInstance(room.tag)) {
API.getInstance({
worldId: D.id,
instanceId: room.id
@@ -16892,13 +17144,14 @@ speechSynthesis.getVoices();
}
var instances = {};
if (D.ref.instances) {
- for (var [id, occupants] of D.ref.instances) {
- instances[id] = {
- id,
- tag: `${D.id}:${id}`,
- occupants,
+ for (var instance of D.ref.instances) {
+ // instance = [ instanceId, occupants ]
+ var instanceId = instance[0];
+ instances[instanceId] = {
+ id: instanceId,
+ tag: `${D.id}:${instanceId}`,
+ $location: {},
friendCount: 0,
- full: false,
users: [],
shortName: '',
json: {}
@@ -16911,9 +17164,7 @@ speechSynthesis.getVoices();
id: instanceId,
tag: `${D.id}:${instanceId}`,
$location: {},
- occupants: 0,
friendCount: 0,
- full: false,
users: [],
shortName,
json: {}
@@ -16923,17 +17174,16 @@ speechSynthesis.getVoices();
var lastLocation$ = cachedCurrentUser.$location;
var playersInInstance = this.lastLocation.playerList;
if (lastLocation$.worldId === D.id && playersInInstance.size > 0) {
+ // pull instance json from cache
var friendsInInstance = this.lastLocation.friendList;
var instance = {
id: lastLocation$.instanceId,
tag: lastLocation$.tag,
$location: {},
- occupants: playersInInstance.size,
friendCount: friendsInInstance.size,
- full: false,
users: [],
shortName: '',
- json: {}
+ ref: {}
};
instances[instance.id] = instance;
for (var friend of friendsInInstance.values()) {
@@ -16967,12 +17217,10 @@ speechSynthesis.getVoices();
id: instanceId,
tag: `${D.id}:${instanceId}`,
$location: {},
- occupants: 0,
friendCount: 0,
- full: false,
users: [],
shortName: '',
- json: {}
+ ref: {}
};
instances[instanceId] = instance;
}
@@ -16987,12 +17235,10 @@ speechSynthesis.getVoices();
id: instanceId,
tag: `${D.id}:${instanceId}`,
$location: {},
- occupants: 0,
friendCount: 0,
- full: false,
users: [],
shortName: '',
- json: {}
+ ref: {}
};
instances[instanceId] = instance;
}
@@ -17031,21 +17277,11 @@ speechSynthesis.getVoices();
}
rooms.push(instance);
}
- // reuse instance occupants from getInstance
+ // get instance from cache
for (var room of rooms) {
- if (
- $app.isRealInstance(room.tag) &&
- room.tag !== $app.lastLocation.location &&
- (room.$location.accessType !== 'public' || room.occupants === 0)
- ) {
- for (var instance of D.rooms) {
- if (instance.id === room.id) {
- room.occupants = instance.occupants;
- room.full = instance.full;
- room.json = instance.json;
- break;
- }
- }
+ var ref = API.cachedInstances.get(room.tag);
+ if (typeof ref !== 'undefined') {
+ room.ref = ref;
}
}
// sort by more friends, occupants
@@ -17075,12 +17311,10 @@ speechSynthesis.getVoices();
id: instance.instanceId,
tag: instance.location,
$location: {},
- occupants: instance.userCount,
friendCount: 0,
- full: false,
users: [],
shortName: instance.shortName,
- json: instance
+ ref: instance
};
}
}
@@ -17094,12 +17328,10 @@ speechSynthesis.getVoices();
id: lastLocation$.instanceId,
tag: currentLocation,
$location: {},
- occupants: playersInInstance.size,
friendCount: friendsInInstance.size,
- full: false,
users: [],
shortName: '',
- json: {}
+ ref: {}
};
instances[currentLocation] = instance;
for (var friend of friendsInInstance.values()) {
@@ -17133,12 +17365,10 @@ speechSynthesis.getVoices();
id: instanceId,
tag,
$location: {},
- occupants: 0,
friendCount: 0,
- full: false,
users: [],
shortName: '',
- json: {}
+ ref: {}
};
instances[tag] = instance;
}
@@ -17153,12 +17383,10 @@ speechSynthesis.getVoices();
id: instanceId,
tag,
$location: {},
- occupants: 0,
friendCount: 0,
- full: false,
users: [],
shortName: '',
- json: {}
+ ref: {}
};
instances[tag] = instance;
}
@@ -17181,6 +17409,18 @@ speechSynthesis.getVoices();
}
rooms.push(instance);
}
+ // get instance
+ for (var room of rooms) {
+ var ref = API.cachedInstances.get(room.tag);
+ if (typeof ref !== 'undefined') {
+ room.ref = ref;
+ } else if ($app.isRealInstance(room.tag)) {
+ API.getInstance({
+ worldId: room.$location.worldId,
+ instanceId: room.$location.instanceId
+ });
+ }
+ }
// sort by more friends, occupants
rooms.sort(function (a, b) {
return b.users.length - a.users.length || b.occupants - a.occupants;
@@ -21941,7 +22181,7 @@ speechSynthesis.getVoices();
$app.methods.refreshInstancePlayerCount = function (instance) {
var L = API.parseLocation(instance);
- if (L.worldId && L.tag !== this.lastLocation.location) {
+ if (L.worldId && L.instanceId) {
API.getInstance({
worldId: L.worldId,
instanceId: L.instanceId
@@ -22613,7 +22853,14 @@ speechSynthesis.getVoices();
API.cachedGroups.delete(id);
}
});
+ API.cachedInstances.forEach((ref, id) => {
+ // delete instances over an hour old
+ if (Date.parse(ref.$fetchedAt) < Date.now() - 3600000) {
+ API.cachedInstances.delete(id);
+ }
+ });
API.cachedAvatarNames = new Map();
+ this.updateInstanceInfo = 0;
};
$app.data.sqliteTableSizes = {};
@@ -25032,10 +25279,13 @@ speechSynthesis.getVoices();
});
API.$on('GROUP', function (args) {
- if ($app.groupDialog.visible && $app.groupDialog.id === args.ref.id) {
- // update group dialog
- $app.groupDialog.inGroup = args.ref.membershipStatus === 'member';
+ var { ref } = args;
+ var D = $app.groupDialog;
+ if (D.visible === false || D.id !== ref.id) {
+ return;
}
+ D.inGroup = ref.membershipStatus === 'member';
+ D.ref = ref;
});
/*
@@ -25507,6 +25757,10 @@ speechSynthesis.getVoices();
API.$on('GROUP:USER:INSTANCES', function (args) {
$app.groupInstances = [];
for (var json of args.json.instances) {
+ if (args.json.fetchedAt) {
+ // tack on fetchedAt
+ json.$fetchedAt = args.json.fetchedAt;
+ }
this.$emit('INSTANCE', {
json,
params: {
@@ -25519,7 +25773,6 @@ speechSynthesis.getVoices();
worldId: json.world.id
}
});
- json.world = this.applyWorld(json.world);
var ref = this.cachedGroups.get(json.ownerId);
if (typeof ref === 'undefined') {
@@ -25529,28 +25782,12 @@ speechSynthesis.getVoices();
return;
}
$app.groupInstances.push({
- $group: ref,
- ...json
+ group: ref,
+ instance: this.applyInstance(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 3bdbef76..71abd717 100644
--- a/html/src/index.pug
+++ b/html/src/index.pug
@@ -97,8 +97,9 @@ html
template(v-if="item.ref")
.detail
span.name(v-text="item.ref.displayName" :style="{'color':item.ref.$userColour}")
- span.extra(v-if="item.ref.state === 'offline'") {{ $t('side_panel.search_result_offline') }}
- span.extra(v-else-if="item.ref.state === 'active'") {{ $t('side_panel.search_result_active') }}
+ span.extra(v-if="!item.ref.isFriend")
+ span.extra(v-else-if="item.ref.state === 'offline'") {{ $t('side_panel.search_result_active') }}
+ span.extra(v-else-if="item.ref.state === 'active'") {{ $t('side_panel.search_result_offline') }}
location.extra(v-else :location="item.ref.location" :traveling="item.ref.travelingToLocation" :link="false")
img.avatar(v-lazy="userImage(item.ref)")
span(v-else) {{ $t('side_panel.search_result_more') }} #[span(v-text="item.label" style="font-weight:bold")]
@@ -189,14 +190,14 @@ html
template(#label)
span {{ $t('side_panel.groups') }} ({{ groupInstances.length }})
.x-friend-list(style="padding:10px 5px")
- .x-friend-item(v-for="instance in groupInstances" :key="instance.id" @click="showGroupDialog(instance.ownerId)")
+ .x-friend-item(v-for="ref in groupInstances" :key="ref.instance.id" @click="showGroupDialog(ref.instance.ownerId)")
.avatar
- img(v-lazy="instance.$group.iconUrl")
+ img(v-lazy="ref.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")
+ span(v-text="ref.group.name")
+ span(style="font-weight:normal;margin-left:5px") ({{ ref.instance.userCount }}/{{ ref.instance.capacity }})
+ location.extra(:location="ref.instance.location" :link="false")
//- ## Dialogs ## -\\
@@ -314,16 +315,16 @@ html
template(v-if="isFriendOnline(userDialog.friend) || API.currentUser.id === userDialog.id")
div(v-if="userDialog.ref.location" style="display:flex;flex-direction:column;margin-bottom:10px;padding-bottom:10px;border-bottom:1px solid #e4e7ed14")
div(style="flex:none")
- location(:location="userDialog.ref.location" :traveling="userDialog.ref.travelingToLocation")
template(v-if="isRealInstance(userDialog.$location.tag)")
el-tooltip(placement="top" :content="$t('dialog.user.info.launch_invite_tooltip')" :disabled="hideTooltips")
- launch(:location="userDialog.$location.tag" style="margin-left:5px")
+ launch(:location="userDialog.$location.tag")
el-tooltip(placement="top" :content="$t('dialog.user.info.self_invite_tooltip')" :disabled="hideTooltips")
- invite-yourself(:location="userDialog.$location.tag" :shortname="userDialog.$location.shortName" style="margin-left:5px" :disabled="typeof userDialog.instance.json.canRequestInvite !== 'undefined' && !userDialog.instance.json.canRequestInvite")
- el-tooltip(placement="top" :content="$t('dialog.user.info.refresh_user_count_tooltip')" :disabled="hideTooltips")
- el-button(v-if="userDialog.$location.tag !== lastLocation.location" @click="refreshInstancePlayerCount(userDialog.$location.tag)" size="mini" icon="el-icon-refresh" style="margin-left:5px" circle)
- span(v-if="userDialog.instance.occupants" style="margin-left:5px") {{ userDialog.instance.occupants }} #[template(v-if="userDialog.instance.friendCount > 0") ({{ userDialog.instance.friendCount }})]
- span(v-if="userDialog.instance.full" style="margin-left:5px;color:lightcoral") {{ $t('dialog.user.info.instance_full') }}
+ invite-yourself(:location="userDialog.$location.tag" :shortname="userDialog.$location.shortName" style="margin-left:5px" :disabled="typeof userDialog.instance.ref?.canRequestInvite !== 'undefined' && !userDialog.instance.ref.canRequestInvite")
+ el-tooltip(placement="top" :content="$t('dialog.user.info.refresh_instance_info')" :disabled="hideTooltips")
+ el-button(@click="refreshInstancePlayerCount(userDialog.$location.tag)" size="mini" icon="el-icon-refresh" style="margin-left:5px" circle)
+ instance-info(:location="userDialog.$location.tag" :instance="userDialog.instance.ref" :friendcount="userDialog.instance.friendCount" :updateelement="updateInstanceInfo")
+ br
+ location(:location="userDialog.ref.location" :traveling="userDialog.ref.travelingToLocation")
.x-friend-list(style="flex:1;margin-top:10px;max-height:150px")
.x-friend-item(v-if="userDialog.$location.userId" @click="showUserDialog(userDialog.$location.userId)" class="x-friend-item-border")
template(v-if="userDialog.$location.user")
@@ -614,11 +615,10 @@ html
div(style="margin:5px 0")
location-world(:locationobject="room.$location" :currentuserid="API.currentUser.id" :worlddialogshortname="worldDialog.$location.shortName")
el-tooltip(placement="top" :content="$t('dialog.world.instances.self_invite_tooltip')" :disabled="hideTooltips")
- invite-yourself(:location="room.$location.tag" :shortname="room.$location.shortName" style="margin-left:5px" :disabled="typeof room.json.canRequestInvite !== 'undefined' && !room.json.canRequestInvite")
- el-tooltip(placement="top" :content="$t('dialog.world.instances.refresh_user_count_tooltip')" :disabled="hideTooltips")
- el-button(v-if="room.tag !== lastLocation.location" @click="refreshInstancePlayerCount(room.tag)" size="mini" icon="el-icon-refresh" style="margin-left:5px" circle)
- span(v-if="room.occupants" style="margin-left:5px") {{ room.occupants }} #[template(v-if="room.friendCount > 0") ({{ room.friendCount }})]
- span(v-if="room.full" style="margin-left:5px;color:lightcoral") {{ $t('dialog.world.instances.instance_full') }}
+ invite-yourself(:location="room.$location.tag" :shortname="room.$location.shortName" style="margin-left:5px" :disabled="typeof room.ref?.canRequestInvite !== 'undefined' && !room.ref.canRequestInvite")
+ el-tooltip(placement="top" :content="$t('dialog.world.instances.refresh_instance_info')" :disabled="hideTooltips")
+ el-button(@click="refreshInstancePlayerCount(room.tag)" size="mini" icon="el-icon-refresh" style="margin-left:5px" circle)
+ instance-info(:location="room.tag" :instance="room.ref" :friendcount="room.friendCount" :updateelement="updateInstanceInfo")
.x-friend-list(style="margin:10px 0;max-height:unset" v-if="room.$location.userId || room.users.length")
.x-friend-item(v-if="room.$location.userId" @click="showUserDialog(room.$location.userId)" class="x-friend-item-border")
template(v-if="room.$location.user")
@@ -912,11 +912,10 @@ html
div(style="margin:5px 0")
location(:location="room.tag")
el-tooltip(placement="top" content="Invite yourself" :disabled="hideTooltips")
- invite-yourself(:location="room.tag" style="margin-left:5px" :disabled="typeof room.json.canRequestInvite !== 'undefined' && !room.json.canRequestInvite")
+ invite-yourself(:location="room.tag" style="margin-left:5px" :disabled="typeof room.ref?.canRequestInvite !== 'undefined' && !room.ref.canRequestInvite")
el-tooltip(placement="top" content="Refresh player count" :disabled="hideTooltips")
- el-button(v-if="room.tag !== lastLocation.location" @click="refreshInstancePlayerCount(room.tag)" size="mini" icon="el-icon-refresh" style="margin-left:5px" circle)
- span(v-if="room.occupants" style="margin-left:5px") {{ room.occupants }} #[template(v-if="room.friendCount > 0") ({{ room.friendCount }})]
- span(v-if="room.full" style="margin-left:5px;color:lightcoral") {{ $t('dialog.group.info.instance_full') }}
+ el-button(@click="refreshInstancePlayerCount(room.tag)" size="mini" icon="el-icon-refresh" style="margin-left:5px" circle)
+ instance-info(:location="room.tag" :instance="room.ref" :friendcount="room.friendCount" :updateelement="updateInstanceInfo")
.x-friend-list(style="margin:10px 0;padding:0;max-height:unset" v-if="room.users.length")
.x-friend-item(v-for="user in room.users" :key="user.id" @click="showUserDialog(user.id)" class="x-friend-item-border")
.avatar(:class="userStatusClass(user)")
diff --git a/html/src/localization/localizedStrings.js b/html/src/localization/localizedStrings.js
index d7386981..9f5406c6 100644
--- a/html/src/localization/localizedStrings.js
+++ b/html/src/localization/localizedStrings.js
@@ -13,16 +13,21 @@ import elements_ko from 'element-ui/lib/locale/lang/ko';
import zh_CN from './strings/zh_CN.json' assert { type: 'JSON' };
import elements_zh_CN from 'element-ui/lib/locale/lang/zh-CN';
+import fr from './strings/fr.json' assert { type: 'JSON' };
+import elements_fr from 'element-ui/lib/locale/lang/fr';
+
const localized_en = { ...en, ...elements_en };
const localized_zh_TW = { ...zh_TW, ...elements_zh_TW };
const localized_zh_CN = { ...zh_CN, ...elements_zh_CN };
const localized_ko = { ...ko, ...elements_ko };
const localized_ja = { ...ja, ...elements_ja };
+const localized_fr = { ...fr, ...elements_fr };
export {
localized_en as en,
localized_zh_TW as zh_TW,
localized_ko as ko,
localized_zh_CN as zh_CN,
- localized_ja as ja_JP
+ localized_ja as ja_JP,
+ localized_fr as fr
};
diff --git a/html/src/localization/strings/en.json b/html/src/localization/strings/en.json
index d45b5c82..0a5817bd 100644
--- a/html/src/localization/strings/en.json
+++ b/html/src/localization/strings/en.json
@@ -544,7 +544,11 @@
"header": "Info",
"launch_invite_tooltip": "Launch/Invite",
"self_invite_tooltip": "Invite Yourself",
- "refresh_user_count_tooltip": "Refresh User Count",
+ "refresh_instance_info": "Refresh Instance Info",
+ "instance_queue": "Queue:",
+ "instance_users": "Users:",
+ "instance_game_version": "Game Version:",
+ "instance_queuing_enabled": "Queuing Enabled",
"instance_creator": "Instance Creator",
"note": "Note",
"note_placeholder": "Click to add a note",
@@ -633,7 +637,7 @@
"private_count": "Private {count}",
"capacity_count": "Capacity {count} ({max})",
"self_invite_tooltip": "Invite Yourself",
- "refresh_user_count_tooltip": "Refresh User Count",
+ "refresh_instance_info": "Refresh Instance Info",
"instance_full": "full",
"instance_creator": "Instance Creator"
},
diff --git a/html/src/mixins/tabs/playerList.pug b/html/src/mixins/tabs/playerList.pug
index 846382db..bf8a7aec 100644
--- a/html/src/mixins/tabs/playerList.pug
+++ b/html/src/mixins/tabs/playerList.pug
@@ -24,9 +24,7 @@ mixin playerListTab()
| {{ $t('dialog.world.tags.cache') }}
br
location-world(:locationobject="currentInstanceLocation" :currentuserid="API.currentUser.id")
- span(v-if="lastLocation.playerList.size > 0" style="margin-left:5px")
- | {{ lastLocation.playerList.size }}
- | #[template(v-if="lastLocation.friendList.size > 0") ({{ lastLocation.friendList.size }})]
+ instance-info(:location="currentInstanceLocation.tag" :instance="currentInstanceWorld.instance" :friendcount="lastLocation.friendList.size" :updateelement="updateInstanceInfo")
| #[timer(v-if="lastLocation.date" :epoch="lastLocation.date")]
div(style="margin-top:5px")
span(v-show="currentInstanceWorld.ref.name !== currentInstanceWorld.ref.description" v-text="currentInstanceWorld.ref.description" style="font-size:12px;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2")
@@ -207,6 +205,8 @@ mixin playerListTab()
template(v-once #default="scope")
el-tooltip(v-if="scope.row.isMaster" placement="left" content="Instance Master")
span 👑
+ el-tooltip(v-if="scope.row.isModerator" placement="left" content="Moderator")
+ span ⚔️
el-tooltip(v-if="scope.row.isFriend" placement="left" content="Friend")
span 💚
el-tooltip(v-if="scope.row.timeoutTime" placement="left" content="Timeout")
diff --git a/html/src/vr.pug b/html/src/vr.pug
index e9ecb19d..76ce5c85 100644
--- a/html/src/vr.pug
+++ b/html/src/vr.pug
@@ -489,7 +489,7 @@ html
circle(class="np-progress-circle-stroke" cx="60" cy="60" stroke="white" r="30" fill="transparent" stroke-width="60")
.hud-feed
div(v-for="feed in hudFeed")
- .item(:class="{ friend: feed.isFriend, favorite: feed.isFavorite }") #[span(v-if="feed.isMaster") 👑]#[strong.name(v-text="feed.displayName" :style="{'color':feed.colour}")]
+ .item(:class="{ friend: feed.isFriend, favorite: feed.isFavorite }") #[span(v-if="feed.isMaster") 👑]#[span(v-if="feed.isModerator") ⚔️]#[strong.name(v-text="feed.displayName" :style="{'color':feed.colour}")]
template(v-if="feed.type === 'ChangeAvatar'")
span(style="margin-left:10px;color:#a3a3a3") ChangeAvatar
span(v-if="!feed.inCache" style="color:#aaa;margin-left:10px") #[i.el-icon-download]