2016-11-19 15:05:53 -08:00
|
|
|
"use strict";
|
|
|
|
//
|
|
|
|
// bubble.js
|
|
|
|
// scripts/system/
|
|
|
|
//
|
2023-03-20 21:46:20 -04:00
|
|
|
// Created by Brad Hefta-Gaub on November 18th, 2016
|
2016-11-19 15:05:53 -08:00
|
|
|
// Copyright 2016 High Fidelity, Inc.
|
2023-03-20 21:46:20 -04:00
|
|
|
// Copyright 2023 Overte e.V.
|
2016-11-19 15:05:53 -08:00
|
|
|
//
|
|
|
|
// Distributed under the Apache License, Version 2.0.
|
|
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
|
|
//
|
2023-03-20 21:46:20 -04:00
|
|
|
/* global Script, Users, Entities, AvatarList, Controller, Camera, getControllerWorldLocation, UserActivityLogger */
|
2016-11-19 15:05:53 -08:00
|
|
|
|
2016-12-12 14:22:54 -08:00
|
|
|
(function () { // BEGIN LOCAL_SCOPE
|
2017-01-25 12:00:34 -08:00
|
|
|
var button;
|
2016-12-12 14:22:54 -08:00
|
|
|
// Used for animating and disappearing the bubble
|
|
|
|
var bubbleOverlayTimestamp;
|
2018-01-18 12:05:16 -08:00
|
|
|
// Used for rate limiting the bubble sound
|
|
|
|
var lastBubbleSoundTimestamp = 0;
|
2016-12-13 11:43:09 -08:00
|
|
|
// Affects bubble height
|
2017-02-16 17:29:35 -08:00
|
|
|
var BUBBLE_HEIGHT_SCALE = 0.15;
|
2016-12-12 14:22:54 -08:00
|
|
|
// The bubble model itself
|
2023-03-20 21:46:20 -04:00
|
|
|
var bubbleOverlay = Entities.addEntity({
|
|
|
|
"type": "Model",
|
|
|
|
"modelURL": Script.resolvePath("assets/models/Bubble-v14.fbx"), // If you'd like to change the model, modify this line (and the dimensions below)
|
|
|
|
"dimensions": {
|
2023-07-07 21:42:45 -04:00
|
|
|
"x": MyAvatar.sensorToWorldScale,
|
|
|
|
"y": (0.75 * MyAvatar.sensorToWorldScale),
|
|
|
|
"z": MyAvatar.sensorToWorldScale
|
2023-03-20 21:46:20 -04:00
|
|
|
},
|
|
|
|
"position": { "x": MyAvatar.position.x, "y": -MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE, "z": MyAvatar.position.z },
|
|
|
|
"rotation": Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({"x": 0.0, "y": 180.0, "z": 0.0})),
|
|
|
|
"visible": false,
|
|
|
|
"ignorePickIntersection": true
|
|
|
|
}, "local");
|
2016-12-12 14:22:54 -08:00
|
|
|
// The bubble activation sound
|
|
|
|
var bubbleActivateSound = SoundCache.getSound(Script.resolvePath("assets/sounds/bubble.wav"));
|
|
|
|
// Is the update() function connected?
|
|
|
|
var updateConnected = false;
|
|
|
|
|
2017-02-16 17:29:35 -08:00
|
|
|
var BUBBLE_VISIBLE_DURATION_MS = 3000;
|
|
|
|
var BUBBLE_RAISE_ANIMATION_DURATION_MS = 750;
|
2018-01-18 12:05:16 -08:00
|
|
|
var BUBBLE_SOUND_RATE_LIMIT_MS = 15000;
|
2016-12-12 14:22:54 -08:00
|
|
|
|
2018-04-10 16:00:35 -07:00
|
|
|
// Hides the bubble model overlay
|
2016-12-12 14:22:54 -08:00
|
|
|
function hideOverlays() {
|
2023-03-20 21:46:20 -04:00
|
|
|
Entities.editEntity(bubbleOverlay, {
|
|
|
|
"visible": false
|
2016-12-12 14:22:54 -08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-08-18 22:19:10 +02:00
|
|
|
//create a menu item in "Setings" to toggle the bubble/shield HUD button
|
2021-08-22 10:04:37 +02:00
|
|
|
var menuItemName = "HUD Shield Button";
|
2021-08-18 22:19:10 +02:00
|
|
|
Menu.addMenuItem({
|
|
|
|
menuName: "Settings",
|
|
|
|
menuItemName: menuItemName,
|
|
|
|
isCheckable: true,
|
|
|
|
isChecked: AvatarInputs.showBubbleTools
|
|
|
|
});
|
|
|
|
Menu.menuItemEvent.connect(onToggleHudShieldButton);
|
|
|
|
AvatarInputs.showBubbleToolsChanged.connect(showBubbleToolsChanged);
|
|
|
|
|
|
|
|
function onToggleHudShieldButton(menuItem) {
|
2021-08-21 17:54:10 +02:00
|
|
|
if (menuItem === menuItemName) {
|
|
|
|
AvatarInputs.setShowBubbleTools(Menu.isOptionChecked(menuItem));
|
2021-08-18 22:19:10 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function showBubbleToolsChanged(show) {
|
|
|
|
Menu.setIsOptionChecked(menuItemName, show);
|
|
|
|
}
|
|
|
|
|
2016-12-12 14:22:54 -08:00
|
|
|
// Make the bubble overlay visible, set its position, and play the sound
|
|
|
|
function createOverlays() {
|
2018-01-18 12:05:16 -08:00
|
|
|
var nowTimestamp = Date.now();
|
|
|
|
if (nowTimestamp - lastBubbleSoundTimestamp >= BUBBLE_SOUND_RATE_LIMIT_MS) {
|
|
|
|
Audio.playSound(bubbleActivateSound, {
|
|
|
|
position: { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z },
|
|
|
|
localOnly: true,
|
|
|
|
volume: 0.2
|
|
|
|
});
|
|
|
|
lastBubbleSoundTimestamp = nowTimestamp;
|
|
|
|
}
|
2016-12-12 14:22:54 -08:00
|
|
|
hideOverlays();
|
|
|
|
if (updateConnected === true) {
|
|
|
|
updateConnected = false;
|
|
|
|
Script.update.disconnect(update);
|
|
|
|
}
|
|
|
|
|
2023-03-20 21:46:20 -04:00
|
|
|
Entities.editEntity(bubbleOverlay, {
|
|
|
|
"dimensions": {
|
2023-07-07 21:42:45 -04:00
|
|
|
"x": MyAvatar.sensorToWorldScale,
|
|
|
|
"y": 0.75 * MyAvatar.sensorToWorldScale,
|
|
|
|
"z": MyAvatar.sensorToWorldScale
|
2017-09-08 17:56:11 +01:00
|
|
|
},
|
2023-03-20 21:46:20 -04:00
|
|
|
"position": {
|
|
|
|
"x": MyAvatar.position.x,
|
|
|
|
"y": -MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE,
|
|
|
|
"z": MyAvatar.position.z
|
2017-09-08 17:56:11 +01:00
|
|
|
},
|
2023-03-20 21:46:20 -04:00
|
|
|
"rotation": Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({"x": 0.0, "y": 180.0, "z": 0.0})),
|
|
|
|
"visible": true
|
2016-12-12 14:22:54 -08:00
|
|
|
});
|
2018-01-18 12:05:16 -08:00
|
|
|
bubbleOverlayTimestamp = nowTimestamp;
|
2016-12-12 14:22:54 -08:00
|
|
|
Script.update.connect(update);
|
|
|
|
updateConnected = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Called from the C++ scripting interface to show the bubble overlay
|
|
|
|
function enteredIgnoreRadius() {
|
|
|
|
createOverlays();
|
2019-02-28 16:51:19 -08:00
|
|
|
UserActivityLogger.privacyShieldActivated();
|
2016-12-12 14:22:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Used to set the state of the bubble HUD button
|
|
|
|
function writeButtonProperties(parameter) {
|
2016-12-20 18:28:07 +00:00
|
|
|
button.editProperties({isActive: parameter});
|
2016-12-12 14:22:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// The bubble script's update function
|
2017-02-16 17:29:35 -08:00
|
|
|
function update() {
|
2016-12-12 14:22:54 -08:00
|
|
|
var timestamp = Date.now();
|
|
|
|
var delay = (timestamp - bubbleOverlayTimestamp);
|
|
|
|
var overlayAlpha = 1.0 - (delay / BUBBLE_VISIBLE_DURATION_MS);
|
|
|
|
if (overlayAlpha > 0) {
|
|
|
|
if (delay < BUBBLE_RAISE_ANIMATION_DURATION_MS) {
|
2023-03-20 21:46:20 -04:00
|
|
|
Entities.editEntity(bubbleOverlay, {
|
|
|
|
"dimensions": {
|
2023-07-07 21:42:45 -04:00
|
|
|
"x": MyAvatar.sensorToWorldScale,
|
|
|
|
"y": (0.75 * MyAvatar.sensorToWorldScale) * (1 - ((BUBBLE_RAISE_ANIMATION_DURATION_MS - delay) / BUBBLE_RAISE_ANIMATION_DURATION_MS)),
|
|
|
|
"z": MyAvatar.sensorToWorldScale
|
2017-09-28 17:05:06 +01:00
|
|
|
},
|
2016-12-12 14:22:54 -08:00
|
|
|
// Quickly raise the bubble from the ground up
|
2023-03-20 21:46:20 -04:00
|
|
|
"position": {
|
|
|
|
"x": MyAvatar.position.x,
|
|
|
|
"y": (-((BUBBLE_RAISE_ANIMATION_DURATION_MS - delay) / BUBBLE_RAISE_ANIMATION_DURATION_MS)) * MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE,
|
|
|
|
"z": MyAvatar.position.z
|
2016-12-12 14:22:54 -08:00
|
|
|
},
|
2023-03-20 21:46:20 -04:00
|
|
|
"rotation": Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({"x": 0.0, "y": 180.0, "z": 0.0}))
|
2016-12-12 14:22:54 -08:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// Keep the bubble in place for a couple seconds
|
2023-03-20 21:46:20 -04:00
|
|
|
Entities.editEntity(bubbleOverlay, {
|
|
|
|
"dimensions": {
|
2023-07-07 21:42:45 -04:00
|
|
|
"x": MyAvatar.sensorToWorldScale,
|
|
|
|
"y": 0.75 * MyAvatar.sensorToWorldScale,
|
|
|
|
"z": MyAvatar.sensorToWorldScale
|
2017-09-28 17:05:06 +01:00
|
|
|
},
|
2023-03-20 21:46:20 -04:00
|
|
|
"position": {
|
|
|
|
"x": MyAvatar.position.x,
|
|
|
|
"y": MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE,
|
|
|
|
"z": MyAvatar.position.z
|
2016-12-12 14:22:54 -08:00
|
|
|
},
|
2023-03-20 21:46:20 -04:00
|
|
|
"rotation": Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({"x": 0.0, "y": 180.0, "z": 0.0}))
|
2016-12-12 14:22:54 -08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
hideOverlays();
|
|
|
|
if (updateConnected === true) {
|
|
|
|
Script.update.disconnect(update);
|
|
|
|
updateConnected = false;
|
|
|
|
}
|
|
|
|
}
|
2017-02-16 17:29:35 -08:00
|
|
|
}
|
2016-12-12 14:22:54 -08:00
|
|
|
|
|
|
|
// When the space bubble is toggled...
|
2017-06-02 09:47:03 -07:00
|
|
|
// NOTE: the c++ calls this with just the first param -- we added a second
|
|
|
|
// just for not logging the initial state of the bubble when we startup.
|
2017-06-02 08:45:02 -07:00
|
|
|
function onBubbleToggled(enabled, doNotLog) {
|
|
|
|
writeButtonProperties(enabled);
|
|
|
|
if (doNotLog !== true) {
|
2019-02-28 16:51:19 -08:00
|
|
|
UserActivityLogger.privacyShieldToggled(enabled);
|
2017-06-02 08:45:02 -07:00
|
|
|
}
|
|
|
|
if (enabled) {
|
2016-12-12 14:22:54 -08:00
|
|
|
createOverlays();
|
|
|
|
} else {
|
|
|
|
hideOverlays();
|
|
|
|
if (updateConnected === true) {
|
|
|
|
Script.update.disconnect(update);
|
|
|
|
updateConnected = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-25 12:00:34 -08:00
|
|
|
// Setup the bubble button
|
2019-02-28 16:51:19 -08:00
|
|
|
var buttonName = "SHIELD";
|
2017-02-16 17:29:35 -08:00
|
|
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
|
|
|
button = tablet.addButton({
|
|
|
|
icon: "icons/tablet-icons/bubble-i.svg",
|
|
|
|
activeIcon: "icons/tablet-icons/bubble-a.svg",
|
|
|
|
text: buttonName,
|
|
|
|
sortOrder: 4
|
|
|
|
});
|
|
|
|
|
2017-06-02 08:45:02 -07:00
|
|
|
onBubbleToggled(Users.getIgnoreRadiusEnabled(), true); // pass in true so we don't log this initial one in the UserActivity table
|
2016-12-12 14:22:54 -08:00
|
|
|
|
|
|
|
button.clicked.connect(Users.toggleIgnoreRadius);
|
|
|
|
Users.ignoreRadiusEnabledChanged.connect(onBubbleToggled);
|
|
|
|
Users.enteredIgnoreRadius.connect(enteredIgnoreRadius);
|
|
|
|
|
2017-02-16 17:29:35 -08:00
|
|
|
// Cleanup the tablet button and overlays when script is stopped
|
2016-12-12 14:22:54 -08:00
|
|
|
Script.scriptEnding.connect(function () {
|
2021-08-18 22:19:10 +02:00
|
|
|
Menu.menuItemEvent.disconnect(onToggleHudShieldButton);
|
|
|
|
AvatarInputs.showBubbleToolsChanged.disconnect(showBubbleToolsChanged);
|
|
|
|
Menu.removeMenuItem("Settings", menuItemName);
|
2016-12-12 14:22:54 -08:00
|
|
|
button.clicked.disconnect(Users.toggleIgnoreRadius);
|
2017-01-25 12:00:34 -08:00
|
|
|
if (tablet) {
|
|
|
|
tablet.removeButton(button);
|
|
|
|
}
|
2016-12-12 14:22:54 -08:00
|
|
|
Users.ignoreRadiusEnabledChanged.disconnect(onBubbleToggled);
|
|
|
|
Users.enteredIgnoreRadius.disconnect(enteredIgnoreRadius);
|
2023-03-20 21:46:20 -04:00
|
|
|
Entities.deleteEntity(bubbleOverlay);
|
2016-12-12 14:22:54 -08:00
|
|
|
if (updateConnected === true) {
|
|
|
|
Script.update.disconnect(update);
|
|
|
|
}
|
|
|
|
});
|
2016-11-19 15:05:53 -08:00
|
|
|
|
|
|
|
}()); // END LOCAL_SCOPE
|