Merge branch 'tablet-ui' of github.com:highfidelity/hifi into tablet-ui-reenable-web-lasers

This commit is contained in:
Seth Alves 2017-01-06 13:32:47 -08:00
commit d32866c8cd
13 changed files with 374 additions and 121 deletions

View file

@ -76,7 +76,7 @@ OriginalDesktop.Desktop {
WebEngine.settings.localContentCanAccessRemoteUrls = true; WebEngine.settings.localContentCanAccessRemoteUrls = true;
[ // Allocate the standard buttons in the correct order. They will get images, etc., via scripts. [ // Allocate the standard buttons in the correct order. They will get images, etc., via scripts.
"hmdToggle", "mute", "mod", "bubble", "help", "hmdToggle", "mute", "pal", "bubble", "help",
"hudToggle", "hudToggle",
"com.highfidelity.interface.system.editButton", "marketplace", "snapshot", "goto" "com.highfidelity.interface.system.editButton", "marketplace", "snapshot", "goto"
].forEach(function (name) { ].forEach(function (name) {

View file

@ -0,0 +1,52 @@
//
// LetterboxMessage.qml
// qml/hifi
//
// Created by Zach Fox and Howard Stearns on 1/5/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "../styles-uit"
Item {
property alias text: popupText.text
property real radius: hifi.dimensions.borderRadius
visible: false
id: letterbox
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "black"
opacity: 0.5
radius: radius
}
Rectangle {
width: Math.max(parent.width * 0.75, 400)
height: popupText.contentHeight*1.5
anchors.centerIn: parent
radius: radius
color: "white"
FiraSansSemiBold {
id: popupText
size: hifi.fontSizes.textFieldInput
color: hifi.colors.darkGray
horizontalAlignment: Text.AlignHCenter
anchors.fill: parent
anchors.leftMargin: 15
anchors.rightMargin: 15
wrapMode: Text.WordWrap
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
letterbox.visible = false
}
}
}

View file

@ -11,21 +11,6 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
/* TODO:
prototype:
- only show kick/mute when canKick
- margins everywhere
- column head centering
- column head font
- proper button .svg on toolbar
mvp:
- Show all participants, including ignored, and populate initial ignore/mute status.
- If name is elided, hover should scroll name left so the full name can be read.
*/
import QtQuick 2.5 import QtQuick 2.5
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import "../styles-uit" import "../styles-uit"
@ -326,6 +311,11 @@ Item {
visible: iAmAdmin visible: iAmAdmin
color: hifi.colors.lightGrayText color: hifi.colors.lightGrayText
} }
function letterbox(message) {
letterboxMessage.text = message;
letterboxMessage.visible = true
}
// This Rectangle refers to the [?] popup button next to "NAMES" // This Rectangle refers to the [?] popup button next to "NAMES"
Rectangle { Rectangle {
color: hifi.colors.tableBackgroundLight color: hifi.colors.tableBackgroundLight
@ -349,7 +339,9 @@ Item {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
hoverEnabled: true hoverEnabled: true
onClicked: namesPopup.visible = true onClicked: letterbox("Bold names in the list are Avatar Display Names.\n" +
"If a Display Name isn't set, a unique Session Display Name is assigned." +
"\n\nAdministrators of this domain can also see the Username or Machine ID associated with each avatar present.")
onEntered: helpText.color = hifi.colors.baseGrayHighlight onEntered: helpText.color = hifi.colors.baseGrayHighlight
onExited: helpText.color = hifi.colors.darkGray onExited: helpText.color = hifi.colors.darkGray
} }
@ -378,87 +370,14 @@ Item {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
hoverEnabled: true hoverEnabled: true
onClicked: adminPopup.visible = true onClicked: letterbox('Silencing a user mutes their microphone. Silenced users can unmute themselves by clicking the "UNMUTE" button on their HUD.\n\n' +
"Banning a user will remove them from this domain and prevent them from returning. You can un-ban users from your domain's settings page.)")
onEntered: adminHelpText.color = "#94132e" onEntered: adminHelpText.color = "#94132e"
onExited: adminHelpText.color = hifi.colors.redHighlight onExited: adminHelpText.color = hifi.colors.redHighlight
} }
} }
// Explanitory popup upon clicking "[?]" next to "NAMES" LetterboxMessage {
Item { id: letterboxMessage
visible: false
id: namesPopup
anchors.fill: pal
Rectangle {
anchors.fill: parent
color: "black"
opacity: 0.5
radius: hifi.dimensions.borderRadius
}
Rectangle {
width: Math.max(parent.width * 0.75, 400)
height: popupText.contentHeight*1.5
anchors.centerIn: parent
radius: hifi.dimensions.borderRadius
color: "white"
FiraSansSemiBold {
id: popupText
text: "Bold names in the list are Avatar Display Names.\n" +
"If a Display Name isn't set, a unique Session Display Name is assigned." +
"\n\nAdministrators of this domain can also see the Username or Machine ID associated with each avatar present."
size: hifi.fontSizes.textFieldInput
color: hifi.colors.darkGray
horizontalAlignment: Text.AlignHCenter
anchors.fill: parent
anchors.leftMargin: 15
anchors.rightMargin: 15
wrapMode: Text.WordWrap
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
namesPopup.visible = false
}
}
}
// Explanitory popup upon clicking "[?]" next to "ADMIN"
Item {
visible: false
id: adminPopup
anchors.fill: pal
Rectangle {
anchors.fill: parent
color: "black"
opacity: 0.5
radius: hifi.dimensions.borderRadius
}
Rectangle {
width: Math.max(parent.width * 0.75, 400)
height: adminPopupText.contentHeight*1.5
anchors.centerIn: parent
radius: hifi.dimensions.borderRadius
color: "white"
FiraSansSemiBold {
id: adminPopupText
text: 'Silencing a user mutes their microphone. Silenced users can unmute themselves by clicking the "UNMUTE" button on their HUD.\n\n' +
"Banning a user will remove them from this domain and prevent them from returning. You can un-ban users from your domain's settings page."
size: hifi.fontSizes.textFieldInput
color: hifi.colors.darkGray
horizontalAlignment: Text.AlignHCenter
anchors.fill: parent
anchors.leftMargin: 15
anchors.rightMargin: 15
wrapMode: Text.WordWrap
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
adminPopup.visible = false
}
}
} }
function findSessionIndex(sessionId, optionalData) { // no findIndex in .qml function findSessionIndex(sessionId, optionalData) { // no findIndex in .qml
@ -495,15 +414,21 @@ Item {
sortModel(); sortModel();
break; break;
case 'select': case 'select':
var sessionId = message.params[0]; var sessionIds = message.params[0];
var selected = message.params[1]; var selected = message.params[1];
var userIndex = findSessionIndex(sessionId); var userIndex = findSessionIndex(sessionIds[0]);
if (sessionIds.length > 1) {
letterbox('Only one user can be selected at a time.');
} else if (userIndex < 0) {
letterbox('The last editor is not among this list of users.');
} else {
if (selected) { if (selected) {
table.selection.clear(); // for now, no multi-select table.selection.clear(); // for now, no multi-select
table.selection.select(userIndex); table.selection.select(userIndex);
} else { } else {
table.selection.deselect(userIndex); table.selection.deselect(userIndex);
} }
}
break; break;
// Received an "updateUsername()" request from the JS // Received an "updateUsername()" request from the JS
case 'updateUsername': case 'updateUsername':

View file

@ -6159,7 +6159,7 @@ void Application::loadScriptURLDialog() const {
void Application::toggleLogDialog() { void Application::toggleLogDialog() {
if (! _logDialog) { if (! _logDialog) {
_logDialog = new LogDialog(_glWidget, getLogger()); _logDialog = new LogDialog(nullptr, getLogger());
} }
if (_logDialog->isVisible()) { if (_logDialog->isVisible()) {

View file

@ -44,7 +44,7 @@ const QString HIGHLIGHT_COLOR = "#3366CC";
int qTextCursorMeta = qRegisterMetaType<QTextCursor>("QTextCursor"); int qTextCursorMeta = qRegisterMetaType<QTextCursor>("QTextCursor");
int qTextBlockMeta = qRegisterMetaType<QTextBlock>("QTextBlock"); int qTextBlockMeta = qRegisterMetaType<QTextBlock>("QTextBlock");
LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : QDialog(parent, Qt::Dialog) { LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : QDialog(parent, Qt::Window) {
_logger = logger; _logger = logger;
setWindowTitle("Log"); setWindowTitle("Log");

View file

@ -20,7 +20,7 @@ var DEFAULT_SCRIPTS = [
"system/hmd.js", "system/hmd.js",
"system/marketplaces/marketplace.js", "system/marketplaces/marketplace.js",
"system/edit.js", "system/edit.js",
"system/mod.js", "system/pal.js", //"system/mod.js", // older UX, if you prefer
"system/selectAudioDevice.js", "system/selectAudioDevice.js",
"system/notifications.js", "system/notifications.js",
"system/controllers/controllerDisplayManager.js", "system/controllers/controllerDisplayManager.js",

Binary file not shown.

View file

@ -25,6 +25,7 @@
<input type="button" id="visible" class="glyph" value="&#xe007;" /> <input type="button" id="visible" class="glyph" value="&#xe007;" />
</div> </div>
<input type="button" id="teleport" value="Jump To Selection" /> <input type="button" id="teleport" value="Jump To Selection" />
<input type="button" id="pal" class="glyph" value="&#xe00c;" />
<input type="button" class="red" id="delete" value="Delete" /> <input type="button" class="red" id="delete" value="Delete" />
</div> </div>
<div id="entity-list"> <div id="entity-list">

View file

@ -39,6 +39,7 @@ function loaded() {
elInView = document.getElementById("in-view") elInView = document.getElementById("in-view")
elRadius = document.getElementById("radius"); elRadius = document.getElementById("radius");
elTeleport = document.getElementById("teleport"); elTeleport = document.getElementById("teleport");
elPal = document.getElementById("pal");
elEntityTable = document.getElementById("entity-table"); elEntityTable = document.getElementById("entity-table");
elInfoToggle = document.getElementById("info-toggle"); elInfoToggle = document.getElementById("info-toggle");
elInfoToggleGlyph = elInfoToggle.firstChild; elInfoToggleGlyph = elInfoToggle.firstChild;
@ -274,6 +275,9 @@ function loaded() {
elTeleport.onclick = function () { elTeleport.onclick = function () {
EventBridge.emitWebEvent(JSON.stringify({ type: 'teleport' })); EventBridge.emitWebEvent(JSON.stringify({ type: 'teleport' }));
} }
elPal.onclick = function () {
EventBridge.emitWebEvent(JSON.stringify({ type: 'pal' }));
}
elDelete.onclick = function() { elDelete.onclick = function() {
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' })); EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
refreshEntities(); refreshEntities();

View file

@ -98,7 +98,6 @@ EntityListTool = function(opts) {
webView.emitScriptEvent(JSON.stringify(data)); webView.emitScriptEvent(JSON.stringify(data));
} }
webView.webEventReceived.connect(function(data) { webView.webEventReceived.connect(function(data) {
data = JSON.parse(data); data = JSON.parse(data);
if (data.type == "selectionUpdate") { if (data.type == "selectionUpdate") {
@ -120,6 +119,23 @@ EntityListTool = function(opts) {
if (selectionManager.hasSelection()) { if (selectionManager.hasSelection()) {
MyAvatar.position = selectionManager.worldPosition; MyAvatar.position = selectionManager.worldPosition;
} }
} else if (data.type == "pal") {
var sessionIds = {}; // Collect the sessionsIds of all selected entitities, w/o duplicates.
selectionManager.selections.forEach(function (id) {
var lastEditedBy = Entities.getEntityProperties(id, 'lastEditedBy').lastEditedBy;
if (lastEditedBy) {
sessionIds[lastEditedBy] = true;
}
});
var dedupped = Object.keys(sessionIds);
if (!selectionManager.selections.length) {
Window.alert('No objects selected.');
} else if (!dedupped.length) {
Window.alert('There were no recent users of the ' + selectionManager.selections.length + ' selected objects.');
} else {
// No need to subscribe if we're just sending.
Messages.sendMessage('com.highfidelity.pal', JSON.stringify({method: 'select', params: [dedupped, true]}), 'local');
}
} else if (data.type == "delete") { } else if (data.type == "delete") {
deleteSelectedEntities(); deleteSelectedEntities();
} else if (data.type == "toggleLocked") { } else if (data.type == "toggleLocked") {

View file

@ -11,7 +11,19 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
// FIXME when we make this a defaultScript: (function() { // BEGIN LOCAL_SCOPE // hardcoding these as it appears we cannot traverse the originalTextures in overlays??? Maybe I've missed
// something, will revisit as this is sorta horrible.
const UNSELECTED_TEXTURES = {"idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png"),
"idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png")
};
const SELECTED_TEXTURES = { "idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-selected.png"),
"idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-selected.png")
};
const UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6};
const SELECTED_COLOR = {red: 0xf3, green: 0x91, blue: 0x29};
(function() { // BEGIN LOCAL_SCOPE
Script.include("/~/system/libraries/controllers.js"); Script.include("/~/system/libraries/controllers.js");
@ -19,8 +31,19 @@ Script.include("/~/system/libraries/controllers.js");
// Overlays. // Overlays.
// //
var overlays = {}; // Keeps track of all our extended overlay data objects, keyed by target identifier. var overlays = {}; // Keeps track of all our extended overlay data objects, keyed by target identifier.
function ExtendedOverlay(key, type, properties, selected) { // A wrapper around overlays to store the key it is associated with.
function ExtendedOverlay(key, type, properties, selected, hasModel) { // A wrapper around overlays to store the key it is associated with.
overlays[key] = this; overlays[key] = this;
if (hasModel) {
var modelKey = key + "-m";
this.model = new ExtendedOverlay(modelKey, "model", {
url: Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx"),
textures: textures(selected),
ignoreRayIntersection: true
}, false, false);
} else {
this.model = undefined;
}
this.key = key; this.key = key;
this.selected = selected || false; // not undefined this.selected = selected || false; // not undefined
this.activeOverlay = Overlays.addOverlay(type, properties); // We could use different overlays for (un)selected... this.activeOverlay = Overlays.addOverlay(type, properties); // We could use different overlays for (un)selected...
@ -34,14 +57,24 @@ ExtendedOverlay.prototype.deleteOverlay = function () { // remove display and da
ExtendedOverlay.prototype.editOverlay = function (properties) { // change display of this overlay ExtendedOverlay.prototype.editOverlay = function (properties) { // change display of this overlay
Overlays.editOverlay(this.activeOverlay, properties); Overlays.editOverlay(this.activeOverlay, properties);
}; };
const UNSELECTED_COLOR = {red: 20, green: 250, blue: 20};
const SELECTED_COLOR = {red: 250, green: 20, blue: 20}; function color(selected) {
function color(selected) { return selected ? SELECTED_COLOR : UNSELECTED_COLOR; } return selected ? SELECTED_COLOR : UNSELECTED_COLOR;
}
function textures(selected) {
return selected ? SELECTED_TEXTURES : UNSELECTED_TEXTURES;
}
ExtendedOverlay.prototype.select = function (selected) { ExtendedOverlay.prototype.select = function (selected) {
if (this.selected === selected) { if (this.selected === selected) {
return; return;
} }
this.editOverlay({color: color(selected)}); this.editOverlay({color: color(selected)});
if (this.model) {
this.model.editOverlay({textures: textures(selected)});
}
this.selected = selected; this.selected = selected;
}; };
// Class methods: // Class methods:
@ -91,7 +124,7 @@ function HighlightedEntity(id, entityProperties) {
}, },
lineWidth: 1.0, lineWidth: 1.0,
ignoreRayIntersection: true, ignoreRayIntersection: true,
drawInFront: true drawInFront: false // Arguable. For now, let's not distract with mysterious wires around the scene.
}); });
HighlightedEntity.overlays.push(this); HighlightedEntity.overlays.push(this);
} }
@ -167,12 +200,12 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like
// //
function addAvatarNode(id) { function addAvatarNode(id) {
var selected = ExtendedOverlay.isSelected(id); var selected = ExtendedOverlay.isSelected(id);
return new ExtendedOverlay(id, "sphere", { // 3d so we don't go cross-eyed looking at it, but on top of everything return new ExtendedOverlay(id, "sphere", {
drawInFront: true,
solid: true, solid: true,
alpha: 0.8, alpha: 0.8,
color: color(selected), color: color(selected),
drawInFront: true ignoreRayIntersection: false}, selected, true);
}, selected);
} }
function populateUserList() { function populateUserList() {
var data = []; var data = [];
@ -227,6 +260,7 @@ function updateOverlays() {
if (!id) { if (!id) {
return; // don't update ourself return; // don't update ourself
} }
var overlay = ExtendedOverlay.get(id); 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', id);
@ -235,11 +269,36 @@ function updateOverlays() {
var avatar = AvatarList.getAvatar(id); var avatar = AvatarList.getAvatar(id);
var target = avatar.position; var target = avatar.position;
var distance = Vec3.distance(target, eye); var distance = Vec3.distance(target, eye);
var offset = 0.2;
// base offset on 1/2 distance from hips to head if we can
var headIndex = avatar.getJointIndex("Head");
if (headIndex > 0) {
offset = avatar.getAbsoluteJointTranslationInObjectFrame(headIndex).y / 2;
}
// get diff between target and eye (a vector pointing to the eye from avatar position)
var diff = Vec3.subtract(target, eye);
// move a bit in front, towards the camera
target = Vec3.subtract(target, Vec3.multiply(Vec3.normalize(diff), offset));
// now bump it up a bit
target.y = target.y + offset;
overlay.ping = pingPong; overlay.ping = pingPong;
overlay.editOverlay({ overlay.editOverlay({
position: target, position: target,
dimensions: 0.05 * distance // constant apparent size dimensions: 0.032 * distance
}); });
if (overlay.model) {
overlay.model.ping = pingPong;
overlay.model.editOverlay({
position: target,
scale: 0.2 * distance, // constant apparent size
rotation: Camera.orientation
});
}
}); });
pingPong = !pingPong; pingPong = !pingPong;
ExtendedOverlay.some(function (overlay) { // Remove any that weren't updated. (User is gone.) ExtendedOverlay.some(function (overlay) { // Remove any that weren't updated. (User is gone.)
@ -262,7 +321,7 @@ function removeOverlays() {
function handleClick(pickRay) { function handleClick(pickRay) {
ExtendedOverlay.applyPickRay(pickRay, function (overlay) { ExtendedOverlay.applyPickRay(pickRay, function (overlay) {
// Don't select directly. Tell qml, who will give us back a list of ids. // Don't select directly. Tell qml, who will give us back a list of ids.
var message = {method: 'select', params: [overlay.key, !overlay.selected]}; var message = {method: 'select', params: [[overlay.key], !overlay.selected]};
pal.sendToQml(message); pal.sendToQml(message);
return true; return true;
}); });
@ -333,6 +392,31 @@ function onClicked() {
pal.setVisible(!pal.visible); pal.setVisible(!pal.visible);
} }
//
// Message from other scripts, such as edit.js
//
var CHANNEL = 'com.highfidelity.pal';
function receiveMessage(channel, messageString, senderID) {
if ((channel !== CHANNEL) ||
(senderID !== MyAvatar.sessionUUID)) {
return;
}
var message = JSON.parse(messageString);
switch (message.method) {
case 'select':
if (!pal.visible) {
onClicked();
}
pal.sendToQml(message); // Accepts objects, not just strings.
break;
default:
print('Unrecognized PAL message', messageString);
}
}
Messages.subscribe(CHANNEL);
Messages.messageReceived.connect(receiveMessage);
var AVERAGING_RATIO = 0.05; var AVERAGING_RATIO = 0.05;
var LOUDNESS_FLOOR = 11.0; var LOUDNESS_FLOOR = 11.0;
var LOUDNESS_SCALE = 2.8 / 5.0; var LOUDNESS_SCALE = 2.8 / 5.0;
@ -412,8 +496,10 @@ Script.scriptEnding.connect(function () {
Users.usernameFromIDReply.disconnect(usernameFromIDReply); Users.usernameFromIDReply.disconnect(usernameFromIDReply);
Window.domainChanged.disconnect(clearIgnoredInQMLAndClosePAL); Window.domainChanged.disconnect(clearIgnoredInQMLAndClosePAL);
Window.domainConnectionRefused.disconnect(clearIgnoredInQMLAndClosePAL); Window.domainConnectionRefused.disconnect(clearIgnoredInQMLAndClosePAL);
Messages.unsubscribe(CHANNEL);
Messages.messageReceived.disconnect(receiveMessage);
off(); off();
}); });
// FIXME: }()); // END LOCAL_SCOPE }()); // END LOCAL_SCOPE

View file

@ -0,0 +1,169 @@
// chair.js
//
// Restrictions right now:
// Chair objects need to be set as not colliding with avatars, so that they pull avatar
// avatar into collision with them. Also they need to be at or above standing height
// (like a stool).
//
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function(){
var CHECK_INTERVAL_MSECS = 250; // When sitting, check for need to stand up
var SETTINGS_INTERVAL_MSECS = 1000; // Periodically check user data for updates
var DEFAULT_SIT_DISTANCE = 1.0; // How far away from the chair can you sit?
var HYSTERESIS = 1.1;
var sitTarget = { x: 0, y: 0, z: 0 }; // Offset where your butt should go relative
// to the object's center.
var SITTING = 0;
var STANDING = 1;
var state = STANDING;
var sitDistance = DEFAULT_SIT_DISTANCE;
var entity;
var props;
var checkTimer = false;
var settingsTimer = false;
var sitting = false;
var _this;
var WANT_DEBUG = false;
function debugPrint(string) {
if (WANT_DEBUG) {
print(string);
}
}
function howFarAway(position) {
return Vec3.distance(MyAvatar.position, position);
}
function isSeatOpen(position, distance) {
closest = true;
AvatarList.getAvatarIdentifiers().forEach(function(avatarSessionUUID) {
var avatar = AvatarList.getAvatar(avatarSessionUUID);
if (avatarSessionUUID && Vec3.distance(avatar.position, position) < distance) {
debugPrint("Seat Occupied!");
closest = false;
}
});
return closest;
}
function enterSitPose() {
var rot;
var UPPER_LEG_ANGLE = 240;
var LOWER_LEG_ANGLE = -80;
rot = Quat.safeEulerAngles(MyAvatar.getJointRotation("RightUpLeg"));
MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees(UPPER_LEG_ANGLE, rot.y, rot.z), MyAvatar.getJointTranslation("RightUpLeg"));
rot = Quat.safeEulerAngles(MyAvatar.getJointRotation("RightLeg"));
MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees(LOWER_LEG_ANGLE, rot.y, rot.z), MyAvatar.getJointTranslation("RightLeg"));
rot = Quat.safeEulerAngles(MyAvatar.getJointRotation("LeftUpLeg"));
MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees(UPPER_LEG_ANGLE, rot.y, rot.z), MyAvatar.getJointTranslation("LeftUpLeg"));
rot = Quat.safeEulerAngles(MyAvatar.getJointRotation("LeftLeg"));
MyAvatar.setJointData("LeftLeg", Quat.fromPitchYawRollDegrees(LOWER_LEG_ANGLE, rot.y, rot.z), MyAvatar.getJointTranslation("LeftLeg"));
}
function leaveSitPose() {
MyAvatar.clearJointData("RightUpLeg");
MyAvatar.clearJointData("LeftUpLeg");
MyAvatar.clearJointData("RightLeg");
MyAvatar.clearJointData("LeftLeg");
}
function sitDown(position, rotation) {
var eulers = Quat.safeEulerAngles(MyAvatar.orientation);
eulers.y = Quat.safeEulerAngles(rotation).y;
MyAvatar.position = Vec3.sum(position, Vec3.multiplyQbyV(props.rotation, sitTarget));
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(eulers.x, eulers.y, eulers.z);
enterSitPose();
state = SITTING;
}
this.preload = function(entityID) {
// Load the sound and range from the entity userData fields, and note the position of the entity.
debugPrint("chair preload");
entity = entityID;
_this = this;
settingsTimer = Script.setInterval(this.checkSettings, SETTINGS_INTERVAL_MSECS);
};
this.maybeStand = function() {
props = Entities.getEntityProperties(entity, [ "position", "rotation" ]);
// First, check if the entity is far enough away to not need to do anything with it
var howFar = howFarAway(props.position);
if ((state === SITTING) && (howFar > sitDistance * HYSTERESIS)) {
leaveSitPose();
Script.clearInterval(checkTimer);
checkTimer = null;
state = STANDING;
debugPrint("Standing");
}
}
this.clickDownOnEntity = function(entityID, mouseEvent) {
// If entity is clicked, sit
props = Entities.getEntityProperties(entity, [ "position", "rotation" ]);
if ((state === STANDING) && isSeatOpen(props.position, sitDistance)) {
sitDown(props.position, props.rotation);
checkTimer = Script.setInterval(this.maybeStand, CHECK_INTERVAL_MSECS);
debugPrint("Sitting from mouse click");
}
}
this.startFarTrigger = function() {
// If entity is far clicked, sit
props = Entities.getEntityProperties(entity, [ "position", "rotation" ]);
if ((state === STANDING) && isSeatOpen(props.position, sitDistance)) {
sitDown(props.position, props.rotation);
checkTimer = Script.setInterval(this.maybeStand, CHECK_INTERVAL_MSECS);
debugPrint("Sitting from far trigger");
}
}
this.checkSettings = function() {
var dataProps = Entities.getEntityProperties(entity, [ "userData" ]);
if (dataProps.userData) {
var data = JSON.parse(dataProps.userData);
if (data.sitDistance) {
if (!(sitDistance === data.sitDistance)) {
debugPrint("Read new sit distance: " + data.sitDistance);
}
sitDistance = data.sitDistance;
}
if (data.sitTarget) {
if (data.sitTarget.y && (data.sitTarget.y != sitTarget.y)) {
debugPrint("Read new sitTarget.y: " + data.sitTarget.y);
sitTarget.y = data.sitTarget.y;
}
if (data.sitTarget.x && (data.sitTarget.x != sitTarget.x)) {
debugPrint("Read new sitTarget.x: " + data.sitTarget.x);
sitTarget.x = data.sitTarget.x;
}
if (data.sitTarget.z && (data.sitTarget.z != sitTarget.z)) {
debugPrint("Read new sitTarget.z: " + data.sitTarget.z);
sitTarget.z = data.sitTarget.z;
}
}
}
}
this.unload = function(entityID) {
debugPrint("chair unload");
if (checkTimer) {
Script.clearInterval(checkTimer);
}
if (settingsTimer) {
Script.clearInterval(settingsTimer);
}
};
})