From 14766a792b51e87d40fee5b9f42809e4c8f16ea4 Mon Sep 17 00:00:00 2001 From: Armored Dragon Date: Fri, 23 Feb 2024 10:49:40 -0600 Subject: [PATCH] Rewrite Fixes rotation glitch (hopefully). Fixes nametag flashing on update. Signed-off-by: Armored Dragon --- applications/nametags/nametags.js | 226 ++++++++++++++---------------- 1 file changed, 103 insertions(+), 123 deletions(-) diff --git a/applications/nametags/nametags.js b/applications/nametags/nametags.js index 8c55a88..6938f8d 100644 --- a/applications/nametags/nametags.js +++ b/applications/nametags/nametags.js @@ -1,56 +1,79 @@ // -// Copyright 2023 Overte e.V. +// Copyright 2024 Overte e.V. // // Written by Armored Dragon // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -let user_nametags = {}; -let user_uuids = []; -let visible = Settings.getValue("Nametags_toggle", true); -let maximum_name_length = 50; -let last_camera_mode = Camera.mode; -let check_interval; +(function () { + "use strict"; + let user_nametags = {}; + let visible = Settings.getValue("Nametags_toggle", true); + let maximum_name_length = 50; + let last_camera_mode = Camera.mode; -const logs = (info) => console.log("[NAMETAGS] " + info); + _updateList(); -// New user connected -AvatarManager.avatarAddedEvent.connect(reset); -// User disconnected -AvatarManager.avatarRemovedEvent.connect(reset); + AvatarManager.avatarAddedEvent.connect(_addUser); // New user connected + AvatarManager.avatarRemovedEvent.connect(_removeUser); // User disconnected + Script.update.connect(_adjustNametags); // Delta time -function reset() { - if (!visible) return; - clear(); - startup(); -} + Script.scriptEnding.connect(_scriptEnding); // Script was uninstalled + Menu.menuItemEvent.connect(_toggleState); // Toggle the nametag -function startup() { - const include_self = !HMD.active && !Camera.mode.includes("first person"); + // Toolbar icon + let tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + let tabletButton = tablet.addButton({ + icon: Script.resolvePath("./assets/nametags-i.svg"), + activeIcon: Script.resolvePath("./assets/nametags-a.svg"), + text: "NAMETAGS", + isActive: visible, + }); + tabletButton.clicked.connect(_toggleState); - user_uuids = AvatarList.getAvatarIdentifiers(); - if (include_self) user_uuids.push(MyAvatar.sessionUUID); - user_uuids = user_uuids.filter((uuid) => uuid); // Remove empty, undefined values from array + // Menu item + Menu.addMenuItem({ + menuName: "View", + menuItemName: "Nametags", + shortcutKey: "CTRL+N", + isCheckable: true, + isChecked: visible, + }); - user_uuids.forEach((avatar) => { - let uuid = avatar; - if (user_nametags[uuid]) return; - const definite_avatar = AvatarList.getAvatar(uuid); - const display_name = definite_avatar.displayName ? definite_avatar.displayName.substring(0, maximum_name_length) : "Anonymous"; + function _updateList() { + const include_self = !HMD.active && !Camera.mode.includes("first person"); + var user_list = AvatarList.getAvatarIdentifiers(); + if (include_self) user_list.push(MyAvatar.sessionUUID); - const headJointIndex = definite_avatar.getJointIndex("Head"); - const jointInObjectFrame = definite_avatar.getAbsoluteJointTranslationInObjectFrame(headJointIndex); + // Filter undefined values out + user_list = user_list.filter((uuid) => uuid); - user_nametags[uuid] = { overlay: { text: {}, background: {} } }; - user_nametags[uuid].overlay.text = Entities.addEntity( + user_list.forEach(_addUser); + } + + // Add a user to the user list + function _addUser(user_uuid) { + if (!visible) return; + if (user_nametags[user_uuid]) return; + + const user = AvatarList.getAvatar(user_uuid); + const display_name = user.displayName ? user.displayName.substring(0, maximum_name_length) : "Anonymous"; + const headJointIndex = user.getJointIndex("Head"); + const jointInObjectFrame = user.getAbsoluteJointTranslationInObjectFrame(headJointIndex); + + console.log(`Registering ${display_name} (${user_uuid}) nametag`); + + user_nametags[user_uuid] = { text: {}, background: {} }; + + user_nametags[user_uuid].text = Entities.addEntity( { type: "Text", text: display_name, backgroundAlpha: 0.0, billboardMode: "full", unlit: true, - parentID: uuid, - position: Vec3.sum(definite_avatar.position, { x: 0, y: 0.4 + jointInObjectFrame.y, z: 0 }), + parentID: user_uuid, + position: Vec3.sum(user.position, { x: 0, y: 0.4 + jointInObjectFrame.y, z: 0 }), visible: true, isSolid: false, topMargin: 0.025, @@ -59,15 +82,15 @@ function startup() { }, "local" ); - user_nametags[uuid].overlay.background = Entities.addEntity( + user_nametags[user_uuid].background = Entities.addEntity( { type: "Image", dimensions: { x: 0.8, y: 0.2, z: 0.1 }, emissive: true, alpha: 0.8, keepAspectRatio: false, - position: Vec3.sum(definite_avatar.position, { x: 0, y: 0.4 + jointInObjectFrame.y, z: 0 }), - parentID: user_nametags[uuid].overlay.text, + position: Vec3.sum(user.position, { x: 0, y: 0.4 + jointInObjectFrame.y, z: 0 }), + parentID: user_nametags[user_uuid].text, billboardMode: "full", imageURL: Script.resolvePath("./assets/badge.svg"), }, @@ -77,103 +100,60 @@ function startup() { // We need to have this on a timeout because "textSize" can not be determined instantly after the entity was created. // https://apidocs.overte.org/Entities.html#.textSize Script.setTimeout(() => { - let textSize = Entities.textSize(user_nametags[uuid].overlay.text, display_name); - Entities.editEntity(user_nametags[uuid].overlay.text, { dimensions: { x: textSize.width + 0.25, y: textSize.height - 0.05, z: 0.1 } }); - Entities.editEntity(user_nametags[uuid].overlay.background, { + let textSize = Entities.textSize(user_nametags[user_uuid].text, display_name); + Entities.editEntity(user_nametags[user_uuid].text, { dimensions: { x: textSize.width + 0.25, y: textSize.height - 0.05, z: 0.1 } }); + Entities.editEntity(user_nametags[user_uuid].background, { dimensions: { x: Math.max(textSize.width + 0.25, 0.6), y: textSize.height - 0.05, z: 0.1 }, }); }, 100); - - check_interval = Script.setInterval(adjustNameTag, 5000); - }); -} -function clear() { - for (let i = 0; Object.keys(user_nametags).length > i; i++) { - Entities.deleteEntity(user_nametags[Object.keys(user_nametags)[i]].overlay.text); - Entities.deleteEntity(user_nametags[Object.keys(user_nametags)[i]].overlay.background); } - user_uuids = {}; - user_nametags = {}; - Script.clearInterval(adjustNameTag); -} -function adjustNameTag() { - const user_list = Object.keys(user_nametags); - user_list.forEach((uuid) => { - const definite_avatar = AvatarList.getAvatar(uuid); - const display_name = definite_avatar.displayName ? definite_avatar.displayName.substring(0, maximum_name_length) : "Anonymous"; - const headJointIndex = definite_avatar.getJointIndex("Head"); - const jointInObjectFrame = definite_avatar.getAbsoluteJointTranslationInObjectFrame(headJointIndex); + // Remove a user from the user list + function _removeUser(user_uuid) { + console.log(`Deleting ${user_uuid} nametag`); + Entities.deleteEntity(user_nametags[user_uuid].text); + Entities.deleteEntity(user_nametags[user_uuid].background); + delete user_nametags[user_uuid]; + } - Entities.editEntity(user_nametags[uuid].overlay.background, { - position: Vec3.sum(definite_avatar.position, { x: 0, y: 0.4 + jointInObjectFrame.y, z: 0 }), - }); - Entities.editEntity(user_nametags[uuid].overlay.text, { - position: Vec3.sum(definite_avatar.position, { x: 0, y: 0.4 + jointInObjectFrame.y, z: 0 }), - text: display_name, - }); + // Updates positions of existing nametags + function _adjustNametags() { + if (last_camera_mode !== Camera.mode) { + if (Camera.mode.includes("first person")) _removeUser(MyAvatar.sessionUUID); + else _addUser(MyAvatar.sessionUUID); + last_camera_mode = Camera.mode; + } - // // We need to have this on a timeout because "textSize" can not be determined instantly after the entity was created. - // // https://apidocs.overte.org/Entities.html#.textSize - Script.setTimeout(() => { - let textSize = Entities.textSize(user_nametags[uuid].overlay.text, display_name); - Entities.editEntity(user_nametags[uuid].overlay.text, { dimensions: { x: textSize.width + 0.25, y: textSize.height - 0.05, z: 0.1 } }); - Entities.editEntity(user_nametags[uuid].overlay.background, { - dimensions: { x: Math.max(textSize.width + 0.25, 0.6), y: textSize.height - 0.05, z: 0.1 }, + Object.keys(user_nametags).forEach((user_uuid) => { + const user = AvatarList.getAvatar(user_uuid); + const display_name = user.displayName ? user.displayName.substring(0, maximum_name_length) : "Anonymous"; + const headJointIndex = user.getJointIndex("Head"); + const jointInObjectFrame = user.getAbsoluteJointTranslationInObjectFrame(headJointIndex); + Entities.editEntity(user_nametags[user_uuid].text, { + position: Vec3.sum(user.position, { x: 0, y: jointInObjectFrame.y + Math.abs(user.scale - 1) + 0.4, z: 0 }), + text: display_name, }); - }, 100); - }); - - if (last_camera_mode !== Camera.mode) { - reset(); - last_camera_mode = Camera.mode; + }); } -} -function scriptEnding() { - clear(); - tablet.removeButton(tabletButton); - Menu.removeMenuItem("View", "Nametags"); -} -function toggleState() { - visible = !visible; - tabletButton.editProperties({ isActive: visible }); + // Enable or disable nametags + function _toggleState() { + visible = !visible; + tabletButton.editProperties({ isActive: visible }); + Settings.setValue("Nametags_toggle", visible); - clear(); + if (!visible) Object.keys(user_nametags).forEach(_removeUser); + if (visible) _updateList(); + } - if (visible) startup(); - Settings.setValue("Nametags_toggle", visible); -} -function toggleStateMenu() { - let is_checked = Menu.isOptionChecked("Nametags"); - if (is_checked !== visible) toggleState(); + function _scriptEnding() { + tablet.removeButton(tabletButton); + Menu.removeMenuItem("View", "Nametags"); - // Toolbar - tabletButton.editProperties({ isActive: visible }); -} - -// Tablet icon -let tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); -let tabletButton = tablet.addButton({ - icon: Script.resolvePath("./assets/nametags-i.svg"), - activeIcon: Script.resolvePath("./assets/nametags-a.svg"), - text: "NAMETAGS", - isActive: visible, -}); -// Menu item -Menu.addMenuItem({ - menuName: "View", - menuItemName: "Nametags", - shortcutKey: "CTRL+N", - isCheckable: true, - isChecked: visible, -}); -Menu.menuItemEvent.connect(toggleStateMenu); -tabletButton.clicked.connect(toggleState); -Script.scriptEnding.connect(scriptEnding); - -if (visible) { - startup(); - tabletButton.editProperties({ isActive: visible }); - toggleStateMenu(); -} + for (let i = 0; Object.keys(user_nametags).length > i; i++) { + Entities.deleteEntity(user_nametags[Object.keys(user_nametags)[i]].text); + Entities.deleteEntity(user_nametags[Object.keys(user_nametags)[i]].background); + } + user_nametags = {}; + } +})();