content/hifi-content/thoys/production/wear/wearApp.js
2022-02-14 02:04:11 +01:00

300 lines
11 KiB
JavaScript

//
// wearApp.js
//
// Created by Thijs Wenker on 11/17/17.
// 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
module.exports = (function() {
var APP_NAME = 'WEAR';
var WEAR_TUTORIAL_CHANNEL = 'com.highfidelity.wear.tutorialChannel';
var HTML_PATH = Script.resolvePath('html');
var APP_URL = HTML_PATH + '/wearApp.html';
var APP_ICON = HTML_PATH + '/img/WearAppIconWhite.svg';
var ATTACHMENT_SEARCH_RADIUS = 100; // meters (just in case)
var TUTORIAL_URLS = {
ADJUST: HTML_PATH + '/wearTutorialAdjust.html',
ADJUST_VR: HTML_PATH + '/wearTutorialAdjustVR.html',
ATTACH: HTML_PATH + '/wearTutorialAttach.html',
BUY: HTML_PATH + '/wearTutorialBuy.html'
};
var SETTING_RESET_FIRST_TIME_SETTINGS = 'com.highfidelity.wear.resetFirstTimeSettings';
var SETTING_STORE_ENTERED_FIRST_TIME = 'com.highfidelity.wear.storeEnteredFirstTime';
var SETTING_FIRST_TIME_USE_APP_DESKTOP = 'com.highfidelity.wear.firstTimeUseAppDesktop';
var SETTING_FIRST_TIME_USE_APP_VR = 'com.highfidelity.wear.firstTimeUseAppVR';
var isAppActive = false;
var isTutorialActive = false;
var activeTutorialURL = null;
var selectedAvatarEntity = null;
var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system');
var button = tablet.addButton({
text: APP_NAME,
icon: APP_ICON
});
// Check for first time settings being reset
// Console command for testing first time settings:
// Settings.setValue('com.highfidelity.wear.firstTimeUseApp', true);
if (Settings.getValue(SETTING_RESET_FIRST_TIME_SETTINGS, false)) {
Settings.setValue(SETTING_STORE_ENTERED_FIRST_TIME, false);
Settings.setValue(SETTING_FIRST_TIME_USE_APP_DESKTOP, true);
Settings.setValue(SETTING_FIRST_TIME_USE_APP_VR, true);
// Switch the reset option back off
Settings.setValue(SETTING_RESET_FIRST_TIME_SETTINGS, false);
}
var isEntityBeingWorn = function(entityID) {
return Entities.getEntityProperties(entityID, 'parentID').parentID === MyAvatar.sessionUUID;
};
var hasEnteredStoreForFirstTime = function() {
return Settings.getValue(SETTING_STORE_ENTERED_FIRST_TIME, false);
};
var isFirstTimeUseDesktop = function() {
return Settings.getValue(SETTING_FIRST_TIME_USE_APP_DESKTOP, true);
};
var isFirstTimeUseVR = function() {
return Settings.getValue(SETTING_FIRST_TIME_USE_APP_VR, true);
};
var getAttachedModelEntities = function() {
var resultEntities = [];
Entities.findEntitiesByType('Model', MyAvatar.position, ATTACHMENT_SEARCH_RADIUS).forEach(function(entityID) {
if (isEntityBeingWorn(entityID)) {
resultEntities.push(entityID);
}
});
return resultEntities;
};
var sendUpdate = function() {
var attachments = {};
getAttachedModelEntities().forEach(function(entityID) {
var properties = Entities.getEntityProperties(entityID, ['name', 'modelURL', 'parentJointIndex']);
var label;
if (properties.name.length > 0) {
label = properties.name;
} else {
label = properties.modelURL.split('/').pop();
}
attachments[entityID] = label + ' [' + MyAvatar.jointNames[properties.parentJointIndex] + ']';
});
var properties = null;
if (Object.keys(attachments).length > 0 && (selectedAvatarEntity === null || selectedAvatarEntity === '')) {
selectedAvatarEntity = Object.keys(attachments)[0];
}
if (selectedAvatarEntity) {
var entityProperties = Entities.getEntityProperties(selectedAvatarEntity, [
'localPosition', 'localRotation', 'dimensions', 'naturalDimensions']);
properties = {
position: entityProperties.localPosition,
rotation: Quat.safeEulerAngles(entityProperties.localRotation),
scale: entityProperties.dimensions.x / entityProperties.naturalDimensions.x
};
}
tablet.emitScriptEvent(JSON.stringify({
action: 'update',
attachments: attachments,
selectedAvatarEntity: selectedAvatarEntity,
properties: properties,
hmdActive: HMD.active
}));
};
var makeClientEntitiesGrabbable = function(grabbable) {
getAttachedModelEntities().forEach(function(entityID) {
var properties = Entities.getEntityProperties(entityID, ['clientOnly', 'userData']);
if (properties.clientOnly) {
var userData;
try {
userData = JSON.parse(properties.userData);
} catch (e) {
userData = {};
}
if (userData.grabbableKey === undefined) {
userData.grabbableKey = {};
}
userData.grabbableKey.grabbable = grabbable;
Entities.editEntity(entityID, {userData: JSON.stringify(userData)});
}
});
};
var onAddingEntity = function(entityID) {
if (isEntityBeingWorn(entityID)) {
sendUpdate();
}
};
var onWebEventReceived = function(data) {
if (!isAppActive && !isTutorialActive) {
// ignore web-events when the app and tutorial are inactive
return;
}
var dataObject = JSON.parse(data);
if (dataObject.action === 'gotIt') {
switch (activeTutorialURL) {
case TUTORIAL_URLS.ADJUST:
Settings.setValue(SETTING_FIRST_TIME_USE_APP_DESKTOP, false);
activateWearApp();
break;
case TUTORIAL_URLS.ADJUST_VR:
Settings.setValue(SETTING_FIRST_TIME_USE_APP_VR, false);
activateWearApp();
break;
case TUTORIAL_URLS.ATTACH:
Settings.setValue(SETTING_STORE_ENTERED_FIRST_TIME, true);
tablet.gotoHomeScreen();
HMD.closeTablet();
break;
case TUTORIAL_URLS.BUY:
tablet.gotoHomeScreen();
HMD.closeTablet();
break;
}
return;
}
if (dataObject.action === 'selectedAvatarEntityChanged') {
selectedAvatarEntity = dataObject.selectedAvatarEntity;
sendUpdate();
} else if (dataObject.action === 'appReady') {
sendUpdate();
} else if (dataObject.action === 'deleteEntity') {
Entities.deleteEntity(dataObject.selectedAvatarEntity);
sendUpdate();
} else if (dataObject.action === 'propertyUpdate') {
if (dataObject.position !== undefined) {
Entities.editEntity(selectedAvatarEntity, {
localPosition: dataObject.position
});
} else if (dataObject.rotation !== undefined) {
Entities.editEntity(selectedAvatarEntity, {
localRotation: Quat.fromVec3Degrees(dataObject.rotation)
});
} else if (dataObject.scale !== undefined) {
var naturalDimensions = Entities.getEntityProperties(selectedAvatarEntity,
'naturalDimensions').naturalDimensions;
Entities.editEntity(selectedAvatarEntity, {
dimensions: Vec3.multiply(naturalDimensions, dataObject.scale)
});
}
}
};
var activateWearApp = function() {
if (isAppActive) {
// skipping, app is already active
return;
}
tablet.gotoWebScreen(APP_URL);
Entities.addingEntity.connect(onAddingEntity);
Entities.clickReleaseOnEntity.connect(onClickReleaseOnEntity);
isAppActive = true;
if (HMD.active) {
makeClientEntitiesGrabbable(true);
}
};
var loadTutorial = function(tutorialURL) {
activeTutorialURL = tutorialURL;
tablet.gotoWebScreen(activeTutorialURL);
isTutorialActive = true;
};
var onTabletScreenChanged = function(type, url) {
if (isAppActive && url !== APP_URL) {
Entities.addingEntity.disconnect(onAddingEntity);
isAppActive = false;
if (HMD.active) {
makeClientEntitiesGrabbable(false);
}
}
if (isTutorialActive && url !== activeTutorialURL) {
isTutorialActive = false;
activeTutorialURL = null;
}
};
var onClickReleaseOnEntity = function(entityID) {
if (isEntityBeingWorn(entityID)) {
selectedAvatarEntity = entityID;
sendUpdate();
}
};
var onHmdChanged = function() {
if (isAppActive) {
sendUpdate();
makeClientEntitiesGrabbable(HMD.active);
}
};
var onMessageReceived = function(channel, message, sender) {
if (channel === WEAR_TUTORIAL_CHANNEL && sender === MyAvatar.sessionUUID) {
if (message === 'storeEnter' && !HMD.active && !hasEnteredStoreForFirstTime()) {
loadTutorial(TUTORIAL_URLS.ATTACH);
} else if (message === 'checkoutEnter' && !HMD.active) {
loadTutorial(TUTORIAL_URLS.BUY);
}
}
};
Messages.subscribe(WEAR_TUTORIAL_CHANNEL);
Messages.messageReceived.connect(onMessageReceived);
HMD.displayModeChanged.connect(onHmdChanged);
tablet.webEventReceived.connect(onWebEventReceived);
tablet.screenChanged.connect(onTabletScreenChanged);
button.clicked.connect(function() {
if (isAppActive) {
// skipping, app is already active
return;
}
if (HMD.active && isFirstTimeUseVR()) {
loadTutorial(TUTORIAL_URLS.ADJUST_VR);
return;
}
if (!HMD.active && isFirstTimeUseDesktop()) {
loadTutorial(TUTORIAL_URLS.ADJUST);
return;
}
activateWearApp();
});
var cleanUp = function() {
tablet.removeButton(button);
Messages.messageReceived.disconnect(onMessageReceived);
HMD.displayModeChanged.disconnect(onHmdChanged);
tablet.webEventReceived.disconnect(onWebEventReceived);
tablet.screenChanged.disconnect(onTabletScreenChanged);
Messages.unsubscribe(WEAR_TUTORIAL_CHANNEL);
if (isAppActive) {
if (HMD.active) {
makeClientEntitiesGrabbable(false);
}
Entities.addingEntity.disconnect(onAddingEntity);
Entities.clickReleaseOnEntity.disconnect(onClickReleaseOnEntity);
}
};
return {
cleanUp: cleanUp
};
});