mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 19:16:56 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into app-refactor4-merge
This commit is contained in:
commit
cb5ac6f42c
4 changed files with 135 additions and 82 deletions
|
@ -1108,7 +1108,7 @@ Rectangle {
|
||||||
function findNearbySessionIndex(sessionId, optionalData) { // no findIndex in .qml
|
function findNearbySessionIndex(sessionId, optionalData) { // no findIndex in .qml
|
||||||
var data = optionalData || nearbyUserModelData, length = data.length;
|
var data = optionalData || nearbyUserModelData, length = data.length;
|
||||||
for (var i = 0; i < length; i++) {
|
for (var i = 0; i < length; i++) {
|
||||||
if (data[i].sessionId === sessionId) {
|
if (data[i].sessionId === sessionId.toString()) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1120,7 +1120,7 @@ Rectangle {
|
||||||
var data = message.params;
|
var data = message.params;
|
||||||
var index = -1;
|
var index = -1;
|
||||||
iAmAdmin = Users.canKick;
|
iAmAdmin = Users.canKick;
|
||||||
index = findNearbySessionIndex('', data);
|
index = findNearbySessionIndex("", data);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
myData = data[index];
|
myData = data[index];
|
||||||
data.splice(index, 1);
|
data.splice(index, 1);
|
||||||
|
@ -1197,8 +1197,8 @@ Rectangle {
|
||||||
for (var userId in message.params) {
|
for (var userId in message.params) {
|
||||||
var audioLevel = message.params[userId][0];
|
var audioLevel = message.params[userId][0];
|
||||||
var avgAudioLevel = message.params[userId][1];
|
var avgAudioLevel = message.params[userId][1];
|
||||||
// If the userId is 0, we're updating "myData".
|
// If the userId is "", we're updating "myData".
|
||||||
if (userId == 0) {
|
if (userId === "") {
|
||||||
myData.audioLevel = audioLevel;
|
myData.audioLevel = audioLevel;
|
||||||
myCard.audioLevel = audioLevel; // Defensive programming
|
myCard.audioLevel = audioLevel; // Defensive programming
|
||||||
myData.avgAudioLevel = avgAudioLevel;
|
myData.avgAudioLevel = avgAudioLevel;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <QScriptEngine>
|
#include <QScriptEngine>
|
||||||
|
#include <QtCore/QJsonDocument>
|
||||||
|
|
||||||
#include "AvatarLogging.h"
|
#include "AvatarLogging.h"
|
||||||
|
|
||||||
|
@ -668,3 +669,49 @@ void AvatarManager::setAvatarSortCoefficient(const QString& name, const QScriptV
|
||||||
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(packet), NodeSet() << NodeType::AvatarMixer);
|
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(packet), NodeSet() << NodeType::AvatarMixer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariantMap AvatarManager::getPalData(const QList<QString> specificAvatarIdentifiers) {
|
||||||
|
QJsonArray palData;
|
||||||
|
|
||||||
|
auto avatarMap = getHashCopy();
|
||||||
|
AvatarHash::iterator itr = avatarMap.begin();
|
||||||
|
while (itr != avatarMap.end()) {
|
||||||
|
std::shared_ptr<Avatar> avatar = std::static_pointer_cast<Avatar>(*itr);
|
||||||
|
QString currentSessionUUID = avatar->getSessionUUID().toString();
|
||||||
|
if (specificAvatarIdentifiers.isEmpty() || specificAvatarIdentifiers.contains(currentSessionUUID)) {
|
||||||
|
QJsonObject thisAvatarPalData;
|
||||||
|
|
||||||
|
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
|
|
||||||
|
if (currentSessionUUID == myAvatar->getSessionUUID().toString()) {
|
||||||
|
currentSessionUUID = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
thisAvatarPalData.insert("sessionUUID", currentSessionUUID);
|
||||||
|
thisAvatarPalData.insert("sessionDisplayName", avatar->getSessionDisplayName());
|
||||||
|
thisAvatarPalData.insert("audioLoudness", avatar->getAudioLoudness());
|
||||||
|
thisAvatarPalData.insert("isReplicated", avatar->getIsReplicated());
|
||||||
|
|
||||||
|
glm::vec3 position = avatar->getWorldPosition();
|
||||||
|
QJsonObject jsonPosition;
|
||||||
|
jsonPosition.insert("x", position.x);
|
||||||
|
jsonPosition.insert("y", position.y);
|
||||||
|
jsonPosition.insert("z", position.z);
|
||||||
|
thisAvatarPalData.insert("position", jsonPosition);
|
||||||
|
|
||||||
|
float palOrbOffset = 0.2f;
|
||||||
|
int headIndex = avatar->getJointIndex("Head");
|
||||||
|
if (headIndex > 0) {
|
||||||
|
glm::vec3 jointTranslation = avatar->getAbsoluteJointTranslationInObjectFrame(headIndex);
|
||||||
|
palOrbOffset = jointTranslation.y / 2;
|
||||||
|
}
|
||||||
|
thisAvatarPalData.insert("palOrbOffset", palOrbOffset);
|
||||||
|
|
||||||
|
palData.append(thisAvatarPalData);
|
||||||
|
}
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
QJsonObject doc;
|
||||||
|
doc.insert("data", palData);
|
||||||
|
return doc.toVariantMap();
|
||||||
|
}
|
||||||
|
|
|
@ -157,6 +157,17 @@ public:
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void setAvatarSortCoefficient(const QString& name, const QScriptValue& value);
|
Q_INVOKABLE void setAvatarSortCoefficient(const QString& name, const QScriptValue& value);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Used in the PAL for getting PAL-related data about avatars nearby. Using this method is faster
|
||||||
|
* than iterating over each avatar and obtaining data about them in JavaScript, as that method
|
||||||
|
* locks and unlocks each avatar's data structure potentially hundreds of times per update tick.
|
||||||
|
* @function AvatarManager.getPalData
|
||||||
|
* @param {string[]} specificAvatarIdentifiers - A list of specific Avatar Identifiers about
|
||||||
|
* which you want to get PAL data
|
||||||
|
* @returns {object}
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE QVariantMap getPalData(const QList<QString> specificAvatarIdentifiers = QList<QString>());
|
||||||
|
|
||||||
float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); }
|
float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); }
|
||||||
int getIdentityRequestsSent() const { return _identityRequestsSent; }
|
int getIdentityRequestsSent() const { return _identityRequestsSent; }
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ var AppUi = Script.require('appUi');
|
||||||
var populateNearbyUserList, color, textures, removeOverlays,
|
var populateNearbyUserList, color, textures, removeOverlays,
|
||||||
controllerComputePickRay, off,
|
controllerComputePickRay, off,
|
||||||
receiveMessage, avatarDisconnected, clearLocalQMLDataAndClosePAL,
|
receiveMessage, avatarDisconnected, clearLocalQMLDataAndClosePAL,
|
||||||
createAudioInterval, CHANNEL, getConnectionData, findableByChanged,
|
CHANNEL, getConnectionData, findableByChanged,
|
||||||
avatarAdded, avatarRemoved, avatarSessionChanged; // forward references;
|
avatarAdded, avatarRemoved, avatarSessionChanged; // forward references;
|
||||||
|
|
||||||
// hardcoding these as it appears we cannot traverse the originalTextures in overlays??? Maybe I've missed
|
// hardcoding these as it appears we cannot traverse the originalTextures in overlays??? Maybe I've missed
|
||||||
|
@ -448,21 +448,24 @@ function populateNearbyUserList(selectData, oldAudioData) {
|
||||||
verticalAngleNormal = filter && Quat.getRight(orientation),
|
verticalAngleNormal = filter && Quat.getRight(orientation),
|
||||||
horizontalAngleNormal = filter && Quat.getUp(orientation);
|
horizontalAngleNormal = filter && Quat.getUp(orientation);
|
||||||
avatarsOfInterest = {};
|
avatarsOfInterest = {};
|
||||||
avatars.forEach(function (id) {
|
|
||||||
var avatar = AvatarList.getAvatar(id);
|
var avatarData = AvatarList.getPalData().data;
|
||||||
var name = avatar.sessionDisplayName;
|
|
||||||
|
avatarData.forEach(function (currentAvatarData) {
|
||||||
|
var id = currentAvatarData.sessionUUID;
|
||||||
|
var name = currentAvatarData.sessionDisplayName;
|
||||||
if (!name) {
|
if (!name) {
|
||||||
// Either we got a data packet but no identity yet, or something is really messed up. In any case,
|
// Either we got a data packet but no identity yet, or something is really messed up. In any case,
|
||||||
// we won't be able to do anything with this user, so don't include them.
|
// we won't be able to do anything with this user, so don't include them.
|
||||||
// In normal circumstances, a refresh will bring in the new user, but if we're very heavily loaded,
|
// In normal circumstances, a refresh will bring in the new user, but if we're very heavily loaded,
|
||||||
// we could be losing and gaining people randomly.
|
// we could be losing and gaining people randomly.
|
||||||
print('No avatar identity data for', id);
|
print('No avatar identity data for', currentAvatarData.sessionUUID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (id && myPosition && (Vec3.distance(avatar.position, myPosition) > filter.distance)) {
|
if (id && myPosition && (Vec3.distance(currentAvatarData.position, myPosition) > filter.distance)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var normal = id && filter && Vec3.normalize(Vec3.subtract(avatar.position, myPosition));
|
var normal = id && filter && Vec3.normalize(Vec3.subtract(currentAvatarData.position, myPosition));
|
||||||
var horizontal = normal && angleBetweenVectorsInPlane(normal, forward, horizontalAngleNormal);
|
var horizontal = normal && angleBetweenVectorsInPlane(normal, forward, horizontalAngleNormal);
|
||||||
var vertical = normal && angleBetweenVectorsInPlane(normal, forward, verticalAngleNormal);
|
var vertical = normal && angleBetweenVectorsInPlane(normal, forward, verticalAngleNormal);
|
||||||
if (id && filter && ((Math.abs(horizontal) > horizontalHalfAngle) || (Math.abs(vertical) > verticalHalfAngle))) {
|
if (id && filter && ((Math.abs(horizontal) > horizontalHalfAngle) || (Math.abs(vertical) > verticalHalfAngle))) {
|
||||||
|
@ -481,11 +484,11 @@ function populateNearbyUserList(selectData, oldAudioData) {
|
||||||
personalMute: !!id && Users.getPersonalMuteStatus(id), // expects proper boolean, not null
|
personalMute: !!id && Users.getPersonalMuteStatus(id), // expects proper boolean, not null
|
||||||
ignore: !!id && Users.getIgnoreStatus(id), // ditto
|
ignore: !!id && Users.getIgnoreStatus(id), // ditto
|
||||||
isPresent: true,
|
isPresent: true,
|
||||||
isReplicated: avatar.isReplicated
|
isReplicated: currentAvatarData.isReplicated
|
||||||
};
|
};
|
||||||
// Everyone needs to see admin status. Username and fingerprint returns default constructor output if the requesting user isn't an admin.
|
// Everyone needs to see admin status. Username and fingerprint returns default constructor output if the requesting user isn't an admin.
|
||||||
Users.requestUsernameFromID(id);
|
Users.requestUsernameFromID(id);
|
||||||
if (id) {
|
if (id !== "") {
|
||||||
addAvatarNode(id); // No overlay for ourselves
|
addAvatarNode(id); // No overlay for ourselves
|
||||||
avatarsOfInterest[id] = true;
|
avatarsOfInterest[id] = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -516,30 +519,63 @@ function usernameFromIDReply(id, username, machineFingerprint, isAdmin) {
|
||||||
updateUser(data);
|
updateUser(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateAudioLevel(avatarData) {
|
||||||
|
// the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged
|
||||||
|
// But of course it gets the data at a different rate, so we tweak the averaging ratio and frequency
|
||||||
|
// of updating (the latter for efficiency too).
|
||||||
|
var audioLevel = 0.0;
|
||||||
|
var avgAudioLevel = 0.0;
|
||||||
|
|
||||||
|
var data = avatarData.sessionUUID === "" ? myData : ExtendedOverlay.get(avatarData.sessionUUID);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
// we will do exponential moving average by taking some the last loudness and averaging
|
||||||
|
data.accumulatedLevel = AVERAGING_RATIO * (data.accumulatedLevel || 0) + (1 - AVERAGING_RATIO) * (avatarData.audioLoudness);
|
||||||
|
|
||||||
|
// add 1 to insure we don't go log() and hit -infinity. Math.log is
|
||||||
|
// natural log, so to get log base 2, just divide by ln(2).
|
||||||
|
audioLevel = scaleAudio(Math.log(data.accumulatedLevel + 1) / LOG2);
|
||||||
|
|
||||||
|
// decay avgAudioLevel
|
||||||
|
avgAudioLevel = Math.max((1 - AUDIO_PEAK_DECAY) * (data.avgAudioLevel || 0), audioLevel);
|
||||||
|
|
||||||
|
data.avgAudioLevel = avgAudioLevel;
|
||||||
|
data.audioLevel = audioLevel;
|
||||||
|
|
||||||
|
// now scale for the gain. Also, asked to boost the low end, so one simple way is
|
||||||
|
// to take sqrt of the value. Lets try that, see how it feels.
|
||||||
|
avgAudioLevel = Math.min(1.0, Math.sqrt(avgAudioLevel * (sessionGains[avatarData.sessionUUID] || 0.75)));
|
||||||
|
}
|
||||||
|
|
||||||
|
var param = {};
|
||||||
|
var level = [audioLevel, avgAudioLevel];
|
||||||
|
var userId = avatarData.sessionUUID;
|
||||||
|
param[userId] = level;
|
||||||
|
sendToQml({ method: 'updateAudioLevel', params: param });
|
||||||
|
}
|
||||||
|
|
||||||
var pingPong = true;
|
var pingPong = true;
|
||||||
function updateOverlays() {
|
function updateOverlays() {
|
||||||
var eye = Camera.position;
|
var eye = Camera.position;
|
||||||
AvatarList.getAvatarIdentifiers().forEach(function (id) {
|
|
||||||
if (!id || !avatarsOfInterest[id]) {
|
var avatarData = AvatarList.getPalData().data;
|
||||||
|
|
||||||
|
avatarData.forEach(function (currentAvatarData) {
|
||||||
|
|
||||||
|
if (currentAvatarData.sessionUUID === "" || !avatarsOfInterest[currentAvatarData.sessionUUID]) {
|
||||||
return; // don't update ourself, or avatars we're not interested in
|
return; // don't update ourself, or avatars we're not interested in
|
||||||
}
|
}
|
||||||
var avatar = AvatarList.getAvatar(id);
|
updateAudioLevel(currentAvatarData);
|
||||||
if (!avatar) {
|
var overlay = ExtendedOverlay.get(currentAvatarData.sessionUUID);
|
||||||
return; // will be deleted below if there had been an overlay.
|
|
||||||
}
|
|
||||||
var overlay = ExtendedOverlay.get(id);
|
|
||||||
if (!overlay) { // For now, we're treating this as a temporary loss, as from the personal space bubble. Add it back.
|
if (!overlay) { // For now, we're treating this as a temporary loss, as from the personal space bubble. Add it back.
|
||||||
print('Adding non-PAL avatar node', id);
|
print('Adding non-PAL avatar node', currentAvatarData.sessionUUID);
|
||||||
overlay = addAvatarNode(id);
|
overlay = addAvatarNode(currentAvatarData.sessionUUID);
|
||||||
}
|
}
|
||||||
var target = avatar.position;
|
|
||||||
|
var target = currentAvatarData.position;
|
||||||
var distance = Vec3.distance(target, eye);
|
var distance = Vec3.distance(target, eye);
|
||||||
var offset = 0.2;
|
var offset = currentAvatarData.palOrbOffset;
|
||||||
var diff = Vec3.subtract(target, eye); // get diff between target and eye (a vector pointing to the eye from avatar position)
|
var diff = Vec3.subtract(target, eye); // get diff between target and eye (a vector pointing to the eye from avatar position)
|
||||||
var headIndex = avatar.getJointIndex("Head"); // base offset on 1/2 distance from hips to head if we can
|
|
||||||
if (headIndex > 0) {
|
|
||||||
offset = avatar.getAbsoluteJointTranslationInObjectFrame(headIndex).y / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// move a bit in front, towards the camera
|
// move a bit in front, towards the camera
|
||||||
target = Vec3.subtract(target, Vec3.multiply(Vec3.normalize(diff), offset));
|
target = Vec3.subtract(target, Vec3.multiply(Vec3.normalize(diff), offset));
|
||||||
|
@ -549,7 +585,7 @@ function updateOverlays() {
|
||||||
|
|
||||||
overlay.ping = pingPong;
|
overlay.ping = pingPong;
|
||||||
overlay.editOverlay({
|
overlay.editOverlay({
|
||||||
color: color(ExtendedOverlay.isSelected(id), overlay.hovering, overlay.audioLevel),
|
color: color(ExtendedOverlay.isSelected(currentAvatarData.sessionUUID), overlay.hovering, overlay.audioLevel),
|
||||||
position: target,
|
position: target,
|
||||||
dimensions: 0.032 * distance
|
dimensions: 0.032 * distance
|
||||||
});
|
});
|
||||||
|
@ -678,6 +714,14 @@ function tabletVisibilityChanged() {
|
||||||
if (!ui.tablet.tabletShown && ui.isOpen) {
|
if (!ui.tablet.tabletShown && ui.isOpen) {
|
||||||
ui.close();
|
ui.close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var UPDATE_INTERVAL_MS = 100;
|
||||||
|
var updateInterval;
|
||||||
|
function createUpdateInterval() {
|
||||||
|
return Script.setInterval(function () {
|
||||||
|
updateOverlays();
|
||||||
|
}, UPDATE_INTERVAL_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
var previousContextOverlay = ContextOverlay.enabled;
|
var previousContextOverlay = ContextOverlay.enabled;
|
||||||
|
@ -689,10 +733,8 @@ function on() {
|
||||||
ContextOverlay.enabled = false;
|
ContextOverlay.enabled = false;
|
||||||
Users.requestsDomainListData = true;
|
Users.requestsDomainListData = true;
|
||||||
|
|
||||||
audioTimer = createAudioInterval(AUDIO_LEVEL_UPDATE_INTERVAL_MS);
|
|
||||||
|
|
||||||
ui.tablet.tabletShownChanged.connect(tabletVisibilityChanged);
|
ui.tablet.tabletShownChanged.connect(tabletVisibilityChanged);
|
||||||
Script.update.connect(updateOverlays);
|
updateInterval = createUpdateInterval();
|
||||||
Controller.mousePressEvent.connect(handleMouseEvent);
|
Controller.mousePressEvent.connect(handleMouseEvent);
|
||||||
Controller.mouseMoveEvent.connect(handleMouseMoveEvent);
|
Controller.mouseMoveEvent.connect(handleMouseMoveEvent);
|
||||||
Users.usernameFromIDReply.connect(usernameFromIDReply);
|
Users.usernameFromIDReply.connect(usernameFromIDReply);
|
||||||
|
@ -742,50 +784,6 @@ function scaleAudio(val) {
|
||||||
return audioLevel;
|
return audioLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAudioLevel(id) {
|
|
||||||
// the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged
|
|
||||||
// But of course it gets the data at a different rate, so we tweak the averaging ratio and frequency
|
|
||||||
// of updating (the latter for efficiency too).
|
|
||||||
var avatar = AvatarList.getAvatar(id);
|
|
||||||
var audioLevel = 0.0;
|
|
||||||
var avgAudioLevel = 0.0;
|
|
||||||
var data = id ? ExtendedOverlay.get(id) : myData;
|
|
||||||
if (data) {
|
|
||||||
|
|
||||||
// we will do exponential moving average by taking some the last loudness and averaging
|
|
||||||
data.accumulatedLevel = AVERAGING_RATIO * (data.accumulatedLevel || 0) + (1 - AVERAGING_RATIO) * (avatar.audioLoudness);
|
|
||||||
|
|
||||||
// add 1 to insure we don't go log() and hit -infinity. Math.log is
|
|
||||||
// natural log, so to get log base 2, just divide by ln(2).
|
|
||||||
audioLevel = scaleAudio(Math.log(data.accumulatedLevel + 1) / LOG2);
|
|
||||||
|
|
||||||
// decay avgAudioLevel
|
|
||||||
avgAudioLevel = Math.max((1 - AUDIO_PEAK_DECAY) * (data.avgAudioLevel || 0), audioLevel);
|
|
||||||
|
|
||||||
data.avgAudioLevel = avgAudioLevel;
|
|
||||||
data.audioLevel = audioLevel;
|
|
||||||
|
|
||||||
// now scale for the gain. Also, asked to boost the low end, so one simple way is
|
|
||||||
// to take sqrt of the value. Lets try that, see how it feels.
|
|
||||||
avgAudioLevel = Math.min(1.0, Math.sqrt(avgAudioLevel * (sessionGains[id] || 0.75)));
|
|
||||||
}
|
|
||||||
return [audioLevel, avgAudioLevel];
|
|
||||||
}
|
|
||||||
|
|
||||||
function createAudioInterval(interval) {
|
|
||||||
// we will update the audioLevels periodically
|
|
||||||
// TODO: tune for efficiency - expecially with large numbers of avatars
|
|
||||||
return Script.setInterval(function () {
|
|
||||||
var param = {};
|
|
||||||
AvatarList.getAvatarIdentifiers().forEach(function (id) {
|
|
||||||
var level = getAudioLevel(id),
|
|
||||||
userId = id || 0; // qml didn't like an object with null/empty string for a key, so...
|
|
||||||
param[userId] = level;
|
|
||||||
});
|
|
||||||
sendToQml({method: 'updateAudioLevel', params: param});
|
|
||||||
}, interval);
|
|
||||||
}
|
|
||||||
|
|
||||||
function avatarDisconnected(nodeID) {
|
function avatarDisconnected(nodeID) {
|
||||||
// remove from the pal list
|
// remove from the pal list
|
||||||
sendToQml({method: 'avatarDisconnected', params: [nodeID]});
|
sendToQml({method: 'avatarDisconnected', params: [nodeID]});
|
||||||
|
@ -830,20 +828,17 @@ function startup() {
|
||||||
}
|
}
|
||||||
startup();
|
startup();
|
||||||
|
|
||||||
var audioTimer;
|
|
||||||
var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too)
|
|
||||||
function off() {
|
function off() {
|
||||||
if (ui.isOpen) { // i.e., only when connected
|
if (ui.isOpen) { // i.e., only when connected
|
||||||
Script.update.disconnect(updateOverlays);
|
if (updateInterval) {
|
||||||
|
Script.clearInterval(updateInterval);
|
||||||
|
}
|
||||||
Controller.mousePressEvent.disconnect(handleMouseEvent);
|
Controller.mousePressEvent.disconnect(handleMouseEvent);
|
||||||
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
|
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
|
||||||
ui.tablet.tabletShownChanged.disconnect(tabletVisibilityChanged);
|
ui.tablet.tabletShownChanged.disconnect(tabletVisibilityChanged);
|
||||||
Users.usernameFromIDReply.disconnect(usernameFromIDReply);
|
Users.usernameFromIDReply.disconnect(usernameFromIDReply);
|
||||||
triggerMapping.disable();
|
triggerMapping.disable();
|
||||||
triggerPressMapping.disable();
|
triggerPressMapping.disable();
|
||||||
if (audioTimer) {
|
|
||||||
Script.clearInterval(audioTimer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeOverlays();
|
removeOverlays();
|
||||||
|
|
Loading…
Reference in a new issue