mirror of
https://github.com/overte-org/community-apps.git
synced 2025-08-27 22:25:52 +02:00
361 lines
No EOL
12 KiB
JavaScript
361 lines
No EOL
12 KiB
JavaScript
'use strict';
|
|
|
|
//
|
|
// nyx.js
|
|
//
|
|
// Created by Kalila L. on Oct 6 2020.
|
|
// Copyright 2020 Vircadia contributors.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
Script.include('/~/system/libraries/utils.js');
|
|
var NyxSit = Script.require('./modules/sit.js');
|
|
var NyxParentSelf = Script.require('./modules/parentSelf.js');
|
|
|
|
// Consts
|
|
var SETTING_NYX_PREFIX = 'nyx/';
|
|
var NYX_SETTINGS_SETTINGS = 'Nyx Settings'; // lol
|
|
var NYX_UI_CHANNEL = 'nyx-ui';
|
|
|
|
var nyxSettings = null;
|
|
|
|
///////////////// BEGIN ENTITY MENU OVERLAY
|
|
var enableEntityWebMenu = true;
|
|
var entityWebMenuOverlay;
|
|
var registeredEntityMenus = {};
|
|
var lastTriggeredEntityInfo = {};
|
|
var lastTriggeredPointerLocation = null;
|
|
|
|
// Consts
|
|
var MENU_WEB_OVERLAY_SCALE = {
|
|
x: 400,
|
|
y: 500
|
|
};
|
|
var BOOTSTRAP_MENU_WEB_OVERLAY_TITLE = 'Entity Menu';
|
|
var BOOTSTRAP_MENU_WEB_OVERLAY_SCALE = {
|
|
x: 1,
|
|
y: 1
|
|
};
|
|
var BOOTSTRAP_MENU_WEB_OVERLAY_POSITION = {
|
|
x: 1,
|
|
y: 1
|
|
};
|
|
var BOOTSTRAP_MENU_WEB_OVERLAY_SOURCE;
|
|
var BOOTSTRAP_MENU_WEB_OVERLAY_DPI = 7;
|
|
|
|
///////////////// ENTITY MENU OVERLAY ---> MAIN FUNCTIONALITY
|
|
|
|
function registerWithEntityMenu(messageData) {
|
|
registeredEntityMenus[messageData.entityID] = { 'actions': messageData.actions };
|
|
|
|
var dataToSend = {
|
|
registeredEntityMenus: registeredEntityMenus
|
|
};
|
|
|
|
sendToWeb('script-to-web-registered-entity-menus', dataToSend);
|
|
}
|
|
|
|
function deregisterWithEntityMenu(messageData) {
|
|
delete registeredEntityMenus[messageData.entityID];
|
|
|
|
var dataToSend = {
|
|
registeredEntityMenus: registeredEntityMenus
|
|
};
|
|
|
|
sendToWeb('script-to-web-registered-entity-menus', dataToSend);
|
|
}
|
|
|
|
function toggleEntityMenu(pressedEntityID) {
|
|
if (!entityWebMenuOverlay.isVisible() && enableEntityWebMenu === true) {
|
|
var triggeredEntityProperties = Entities.getEntityProperties(pressedEntityID);
|
|
var lastEditedByName;
|
|
|
|
if (AvatarManager.getPalData([triggeredEntityProperties.lastEditedBy]).data[0]) {
|
|
lastEditedByName = AvatarManager.getPalData([triggeredEntityProperties.lastEditedBy]).data[0].sessionDisplayName
|
|
} else {
|
|
lastEditedByName = triggeredEntityProperties.lastEditedBy;
|
|
}
|
|
|
|
lastTriggeredEntityInfo = {
|
|
id: pressedEntityID,
|
|
name: triggeredEntityProperties.name,
|
|
type: triggeredEntityProperties.type,
|
|
lastEditedBy: triggeredEntityProperties.lastEditedBy,
|
|
lastEditedByName: lastEditedByName,
|
|
entityHostType: triggeredEntityProperties.entityHostType,
|
|
description: triggeredEntityProperties.description,
|
|
position: triggeredEntityProperties.position,
|
|
rotation: triggeredEntityProperties.rotation
|
|
};
|
|
|
|
sendToWeb('script-to-web-triggered-entity-info', lastTriggeredEntityInfo);
|
|
|
|
var newOverlayPosition = {};
|
|
// If in VR mode, we put the Nyx Entity menu in the center.
|
|
if (HMD.mounted) {
|
|
newOverlayPosition.x = (Overlays.width() / 2) - (MENU_WEB_OVERLAY_SCALE.x / 2);
|
|
newOverlayPosition.y = (Overlays.height() / 2) - (MENU_WEB_OVERLAY_SCALE.y / 2);
|
|
} else {
|
|
newOverlayPosition.x = (lastTriggeredPointerLocation.x - (MENU_WEB_OVERLAY_SCALE.x / 2));
|
|
newOverlayPosition.y = (lastTriggeredPointerLocation.y - (MENU_WEB_OVERLAY_SCALE.y / 2));
|
|
}
|
|
|
|
entityWebMenuOverlay.setPosition(newOverlayPosition);
|
|
entityWebMenuOverlay.setSize(MENU_WEB_OVERLAY_SCALE);
|
|
entityWebMenuOverlay.setVisible(true);
|
|
} else if (entityWebMenuOverlay.isVisible() && pressedEntityID !== entityWebMenuOverlay) {
|
|
entityWebMenuOverlay.setVisible(false);
|
|
}
|
|
}
|
|
|
|
///////////////// ENTITY MENU OVERLAY ---> IN-WORLD ENTITY MENU
|
|
|
|
function bootstrapEntityMenu() {
|
|
entityWebMenuOverlay = new OverlayWebWindow({
|
|
title: BOOTSTRAP_MENU_WEB_OVERLAY_TITLE,
|
|
source: BOOTSTRAP_MENU_WEB_OVERLAY_SOURCE,
|
|
width: BOOTSTRAP_MENU_WEB_OVERLAY_SCALE.x,
|
|
height: BOOTSTRAP_MENU_WEB_OVERLAY_SCALE.y
|
|
});
|
|
|
|
entityWebMenuOverlay.setVisible(false);
|
|
|
|
entityWebMenuOverlay.webEventReceived.connect(onOverlayWebEventReceived);
|
|
}
|
|
|
|
///////////////// ENTITY MENU OVERLAY ---> END IN-WORLD ENTITY MENU
|
|
|
|
///////////////// END ENTITY MENU OVERLAY
|
|
|
|
///////////////// BEGIN NYX MESSAGE HANDLING
|
|
|
|
function sendToWeb(command, data) {
|
|
var dataToSend = {
|
|
'command': command,
|
|
'data': data
|
|
};
|
|
|
|
entityWebMenuOverlay.emitScriptEvent(JSON.stringify(dataToSend));
|
|
}
|
|
|
|
function onOverlayWebEventReceived(event) {
|
|
var eventJSON = JSON.parse(event);
|
|
|
|
if (eventJSON.command === 'ready') {
|
|
var dataToSend = {
|
|
registeredEntityMenus: registeredEntityMenus,
|
|
lastTriggeredEntityInfo: lastTriggeredEntityInfo
|
|
};
|
|
|
|
sendToWeb('script-to-web-registered-entity-menus', dataToSend);
|
|
|
|
var settingsToSend = {
|
|
settings: nyxSettings
|
|
};
|
|
|
|
sendToWeb('script-to-web-update-settings', settingsToSend);
|
|
}
|
|
|
|
if (eventJSON.command === 'menu-item-triggered') {
|
|
var dataToSend = {
|
|
command: eventJSON.command,
|
|
entityID: eventJSON.data.triggeredEntityID,
|
|
data: eventJSON.data.data
|
|
};
|
|
|
|
Messages.sendLocalMessage(NYX_UI_CHANNEL, JSON.stringify(dataToSend));
|
|
// console.log(JSON.stringify(eventJSON));
|
|
if (eventJSON.data.data.type === 'button' && entityWebMenuOverlay.isVisible()) {
|
|
toggleEntityMenu(); // Close the menu if a menu item was pressed.
|
|
}
|
|
}
|
|
|
|
if (eventJSON.command === 'sit-on-entity-triggered') {
|
|
NyxSit.toggleSit();
|
|
}
|
|
|
|
if (eventJSON.command === 'parent-to-entity-triggered') {
|
|
NyxParentSelf.toggleParent(lastTriggeredEntityInfo.id);
|
|
}
|
|
|
|
if (eventJSON.command === 'entity-move-mode-triggered') {
|
|
if (Entities.getEntityProperties(lastTriggeredEntityInfo.id, ['grab']).grab.grabbable === false) {
|
|
Entities.editEntity(lastTriggeredEntityInfo.id, {'grab': { 'grabbable': true }});
|
|
} else {
|
|
Entities.editEntity(lastTriggeredEntityInfo.id, {'grab': { 'grabbable': false }});
|
|
}
|
|
}
|
|
|
|
if (eventJSON.command === 'close-entity-menu') {
|
|
if (entityWebMenuOverlay.isVisible()) {
|
|
toggleEntityMenu(); // Close the menu if it is active.
|
|
}
|
|
}
|
|
|
|
if (eventJSON.command === 'web-to-script-settings-changed') {
|
|
nyxSettings = eventJSON.data.settings;
|
|
Settings.setValue(SETTING_NYX_PREFIX + NYX_SETTINGS_SETTINGS, eventJSON.data.settings);
|
|
}
|
|
}
|
|
|
|
function onMessageReceived(channel, message, senderID, localOnly) {
|
|
// print('NYX UI Message received:');
|
|
// print('- channel: ' + channel);
|
|
// print('- message: ' + message);
|
|
// print('- sender: ' + senderID);
|
|
// print('- localOnly: ' + localOnly);
|
|
|
|
if (channel === NYX_UI_CHANNEL && MyAvatar.sessionUUID === senderID) {
|
|
messageData = JSON.parse(message);
|
|
|
|
if (messageData.command === 'register-with-entity-menu') {
|
|
registerWithEntityMenu(messageData);
|
|
}
|
|
|
|
if (messageData.command === 'deregister-with-entity-menu') {
|
|
deregisterWithEntityMenu(messageData);
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////// END NYX MESSAGE HANDLING
|
|
|
|
///////////////// BEGIN TRIGGER EVENT HANDLING
|
|
|
|
function processMouseEvent (event) {
|
|
if (!nyxSettings.entityMenu.selectedMouseTriggers) {
|
|
return false;
|
|
}
|
|
|
|
for (var i = 0; i < nyxSettings.entityMenu.selectedMouseTriggers.length; i++) {
|
|
var buttonToCheck = 'is' + nyxSettings.entityMenu.selectedMouseTriggers[i] + 'Held';
|
|
|
|
if (event[buttonToCheck] !== true) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function onMousePressOnEntity (pressedEntityID, event) {
|
|
var currentCursorPosition = Reticle.getPosition();
|
|
lastTriggeredPointerLocation = {
|
|
x: currentCursorPosition.x,
|
|
y: currentCursorPosition.y
|
|
};
|
|
|
|
if (!entityWebMenuOverlay.isVisible()) {
|
|
NyxSit.capturePickPosition();
|
|
}
|
|
|
|
if (HMD.mounted) {
|
|
// Default trigger settings for triggering Nyx Entity when in VR.
|
|
if ((Controller.getValue(Controller.Standard.LeftGrip)
|
|
|| Controller.getValue(Controller.Standard.RightGrip))
|
|
&& (Controller.getValue(Controller.Standard.LT) // Redundant?
|
|
|| Controller.getValue(Controller.Standard.RT)))
|
|
{
|
|
toggleEntityMenu(pressedEntityID);
|
|
}
|
|
} else {
|
|
// Default if settings are not configured.
|
|
if (!nyxSettings || !nyxSettings.entityMenu.useMouseTriggers || nyxSettings.entityMenu.selectedMouseTriggers.length === 0) {
|
|
if (event.isPrimaryHeld && event.isSecondaryHeld && !isInEditMode()) {
|
|
toggleEntityMenu(pressedEntityID);
|
|
}
|
|
// If settings are configured, process the event accordingly.
|
|
} else if (processMouseEvent(event) === true) {
|
|
toggleEntityMenu(pressedEntityID);
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////// END TRIGGER EVENT HANDLING
|
|
|
|
///////////////// BEGIN NYX MENU HANDLING
|
|
|
|
var NYX_MAIN_MENU = 'Settings > Nyx';
|
|
var NYX_ENTITY_MENU_ENABLED = 'Enable Entity Menu';
|
|
var NYX_ENTITY_MENU_RESET = 'Reset Entity Menu';
|
|
|
|
function handleMenuEvent(menuItem) {
|
|
if (menuItem === NYX_ENTITY_MENU_ENABLED) {
|
|
enableEntityWebMenu = Menu.isOptionChecked(NYX_ENTITY_MENU_ENABLED);
|
|
Settings.setValue(SETTING_NYX_PREFIX + NYX_ENTITY_MENU_ENABLED, enableEntityWebMenu);
|
|
}
|
|
|
|
if (menuItem === NYX_ENTITY_MENU_RESET) {
|
|
nyxSettings = null;
|
|
Settings.setValue(SETTING_NYX_PREFIX + NYX_SETTINGS_SETTINGS, '');
|
|
}
|
|
}
|
|
|
|
function bootstrapNyxMenu() {
|
|
if (!Menu.menuExists(NYX_MAIN_MENU)) {
|
|
Menu.addMenu(NYX_MAIN_MENU);
|
|
Menu.addMenuItem({
|
|
menuName: NYX_MAIN_MENU,
|
|
menuItemName: NYX_ENTITY_MENU_ENABLED,
|
|
isCheckable: true,
|
|
isChecked: Settings.getValue(SETTING_NYX_PREFIX + NYX_ENTITY_MENU_ENABLED, true)
|
|
});
|
|
Menu.addMenuItem({
|
|
menuName: NYX_MAIN_MENU,
|
|
menuItemName: NYX_ENTITY_MENU_RESET,
|
|
isCheckable: false
|
|
});
|
|
}
|
|
|
|
enableEntityWebMenu = Settings.getValue(SETTING_NYX_PREFIX + NYX_ENTITY_MENU_ENABLED, true);
|
|
}
|
|
|
|
function unloadNyxMenu() {
|
|
Settings.setValue(SETTING_NYX_PREFIX + NYX_ENTITY_MENU_ENABLED, enableEntityWebMenu);
|
|
|
|
Menu.removeMenuItem(NYX_MAIN_MENU, NYX_ENTITY_MENU_ENABLED);
|
|
Menu.removeMenuItem(NYX_MAIN_MENU, NYX_ENTITY_MENU_RESET);
|
|
Menu.removeMenu(NYX_MAIN_MENU);
|
|
}
|
|
|
|
///////////////// END NYX MENU HANDLING
|
|
|
|
///////////////// BOOTSTRAPPING
|
|
|
|
function startup() {
|
|
Messages.messageReceived.connect(onMessageReceived);
|
|
Entities.mousePressOnEntity.connect(onMousePressOnEntity);
|
|
Menu.menuItemEvent.connect(handleMenuEvent);
|
|
|
|
nyxSettings = Settings.getValue(SETTING_NYX_PREFIX + NYX_SETTINGS_SETTINGS, '');
|
|
|
|
BOOTSTRAP_MENU_WEB_OVERLAY_SOURCE = Script.resolvePath('./index.html');
|
|
bootstrapNyxMenu();
|
|
bootstrapEntityMenu();
|
|
}
|
|
|
|
startup();
|
|
|
|
Script.scriptEnding.connect(function () {
|
|
Messages.messageReceived.disconnect(onMessageReceived);
|
|
Entities.mousePressOnEntity.disconnect(onMousePressOnEntity);
|
|
Menu.menuItemEvent.disconnect(handleMenuEvent);
|
|
|
|
entityWebMenuOverlay.webEventReceived.disconnect(onOverlayWebEventReceived);
|
|
|
|
unloadNyxMenu();
|
|
|
|
entityWebMenuOverlay = null;
|
|
});
|
|
|
|
///////////////// BOOTSTRAPPING TESTING CODE
|
|
|
|
// var messageToSend = {
|
|
// 'command': 'register-with-entity-menu',
|
|
// 'entityID': '{768542d0-e962-49e3-94fb-85651d56f5ae}',
|
|
// 'menuItems': ['This', 'Is', 'Nice']
|
|
// };
|
|
//
|
|
// Messages.sendLocalMessage(NYX_UI_CHANNEL, JSON.stringify(messageToSend));
|