content/hifi-content/thoys/dev/2017/foodDispenserApp/foodDispenserApp.js
2022-02-14 02:04:11 +01:00

313 lines
11 KiB
JavaScript

"use strict";
// foodDispenserApp.js
//
// Created by Thijs Wenker on 5/1/17.
// Copyright 2017 High Fidelity, Inc.
//
// Hand crafted tablet app for the show Eat My Way Through VR
//
// 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 APP_PAGE = 'foodDispenserApp.html';
var APP_BUTTON_NAME = 'FOOD';
var APP_BUTTON_SORT_ORDER = -1;
var FOOD_LIFETIME = 300; // seconds
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var isOnAppPage = false;
var isTabletWebHandlerConnected = false;
var FULL_APP_URL = Script.resolvePath(APP_PAGE);
var ZERO_UUID = '{00000000-0000-0000-0000-000000000000}';
var SANETIZE_PROPERTIES = ['childEntities', 'parentID', 'id'];
var EDIBLE_SCRIPT = 'https://hifi-content.s3.amazonaws.com/liv/dev/ColorChangeWand/Edible.js';
// TODO: make this readable:
var COLLISION_MASK = 7;
var dispensers = [];
var debug = function(message) {
print(message);
};
function entityListToTree(entitiesList) {
function entityListToTreeRecursive(properties) {
properties.childEntities = [];
entitiesList.forEach(function(entityProperties) {
if (properties.id === entityProperties.parentID) {
properties.childEntities.push(entityListToTreeRecursive(entityProperties));
}
});
return properties;
}
var entityTree = [];
entitiesList.forEach(function(entityProperties) {
if (entityProperties.parentID === undefined || entityProperties.parentID === ZERO_UUID) {
entityTree.push(entityListToTreeRecursive(entityProperties));
}
});
return entityTree;
}
function importEntitiesJSON(importLink, parentProperties, overrideProperties) {
if (parentProperties === undefined) {
parentProperties = {};
}
if (overrideProperties !== undefined) {
parentProperties.overrideProperties = overrideProperties;
}
try {
parentProperties.childEntities = entityListToTree(Script.require(importLink).Entities);
return parentProperties;
} catch (e) {
debug('Failed importing entities JSON because: ' + JSON.stringify(e));
}
return null;
}
// Creates an entity and returns a mixed object of the creation properties and the assigned entityID
var createEntity = function(entityProperties, parent, overrideProperties) {
// JSON.stringify -> JSON.parse trick to create a fresh copy of JSON data
var newEntityProperties = JSON.parse(JSON.stringify(entityProperties));
if (overrideProperties !== undefined) {
Object.keys(overrideProperties).forEach(function(key) {
newEntityProperties[key] = overrideProperties[key];
});
}
if (parent.rotation !== undefined) {
if (newEntityProperties.rotation !== undefined) {
newEntityProperties.rotation = Quat.multiply(parent.rotation, newEntityProperties.rotation);
} else {
newEntityProperties.rotation = parent.rotation;
}
}
if (parent.position !== undefined) {
var localPosition = (parent.rotation !== undefined) ?
Vec3.multiplyQbyV(parent.rotation, newEntityProperties.position) : newEntityProperties.position;
newEntityProperties.position = Vec3.sum(localPosition, parent.position);
}
if (parent.id !== undefined) {
newEntityProperties.parentID = parent.id;
}
newEntityProperties.id = Entities.addEntity(newEntityProperties);
return newEntityProperties;
};
var createEntitiesFromTree = function(entityTree, parent, overrideProperties) {
if (parent === undefined) {
parent = {};
}
if (parent.overrideProperties !== undefined) {
overrideProperties = parent.overrideProperties;
}
var createdTree = [];
entityTree.forEach(function(entityProperties) {
var sanetizedProperties = {};
Object.keys(entityProperties).forEach(function(propertyKey) {
if (!entityProperties.hasOwnProperty(propertyKey) || SANETIZE_PROPERTIES.indexOf(propertyKey) !== -1) {
return true;
}
sanetizedProperties[propertyKey] = entityProperties[propertyKey];
});
// Allow for non-entity parent objects, this allows us to offset groups of entities to a specific position/rotation
var parentProperties = sanetizedProperties;
if (entityProperties.type !== undefined) {
parentProperties = createEntity(sanetizedProperties, parent, overrideProperties);
}
if (entityProperties.childEntities !== undefined) {
parentProperties.childEntities =
createEntitiesFromTree(entityProperties.childEntities, parentProperties, overrideProperties);
}
createdTree.push(parentProperties);
});
return createdTree;
};
function getDispenserByID(id) {
var result = null;
dispensers.forEach(function(dispenser) {
if (id === dispenser.id) {
result = dispenser;
}
});
return result;
}
function sendJSONDataToPage(data) {
tablet.emitScriptEvent(JSON.stringify(data));
}
function refreshDispensers() {
var newDispensers = [];
Entities.findEntities(MyAvatar.position, 32000).forEach(function(entityID) {
try {
var userData = Entities.getEntityProperties(entityID, 'userData').userData;
if (userData === undefined || userData === '') {
return;
}
var parsedUserData = JSON.parse(userData);
if (parsedUserData.foodDispenser !== undefined) {
var newData = {
id: entityID,
name: parsedUserData.foodDispenser.name
};
var oldData = getDispenserByID(entityID);
if (oldData !== null) {
if (oldData.filepath !== undefined) {
newData.filepath = oldData.filepath;
newData.filename = oldData.filename;
}
}
newDispensers.push(newData);
}
} catch (e) {
// e
}
});
dispensers = newDispensers;
dispensers.sort(function(a, b) {
if (a.name < b.name) {
return -1;
} else if (a.name > b.name) {
return 1;
}
return 0;
});
sendJSONDataToPage({
action: 'dispensersUpdate',
dispensers: dispensers
});
}
function launchDispenser(id) {
var dispenser = getDispenserByID(id);
if (dispenser !== null && dispenser.filepath !== undefined) {
var position = Entities.getEntityProperties(id, 'position').position;
var importEntities = [
importEntitiesJSON(dispenser.filepath, {}, {
position: position,
lifetime: FOOD_LIFETIME,
script: EDIBLE_SCRIPT,
collisionMask: COLLISION_MASK,
friction: 0,
gravity: {x: 0, y: -2, z: 0},
velocity: {x: 0, y: -2, z: 0},
dynamic: true,
userData: JSON.stringify({
grabbableKey: {
grabbable: true
}
}),
linearDamping: 0.1
})
];
importEntities.forEach(function(entityProperties) {
entityProperties.childEntities.forEach(function(subProperties) {
if (subProperties.shapeType === 'static-mesh') {
subProperties.shapeType = 'simple-hull';
print('is now: ' + subProperties.shapeType);
}
});
});
//print(JSON.stringify(importEntities));
createEntitiesFromTree(importEntities);
}
}
function launchDispensers() {
dispensers.forEach(function(dispenser) {
launchDispenser(dispenser.id);
});
}
function onWebEventReceived(event) {
var data = JSON.parse(event);
var action = data.action;
switch (action) {
case 'refresh':
refreshDispensers();
break;
case 'setDispenserJSON':
var id = data.id;
var dispenser = getDispenserByID(id);
if (dispenser !== null) {
var newPath = Window.browse('Import Entities', '', '*.json');
if (newPath !== null) {
dispenser.filepath = newPath;
dispenser.filename = newPath.substring(newPath.lastIndexOf('/') + 1);
}
}
refreshDispensers();
break;
case 'launch':
launchDispensers();
break;
default:
print('Got unknown action: ' + action + ' with event: ' + event);
}
}
function connectAppBridge() {
if (isTabletWebHandlerConnected) {
return;
}
try {
tablet.webEventReceived.connect(onWebEventReceived);
} catch (e) {
// e
return;
}
isTabletWebHandlerConnected = true;
}
function disconnectAppBridge() {
if (!isTabletWebHandlerConnected) {
return;
}
try {
tablet.webEventReceived.disconnect(onWebEventReceived);
} catch (e) {
// e
return;
}
isTabletWebHandlerConnected = false;
}
var tabletAppButton = tablet.addButton({
icon: "icons/tablet-icons/menu-i.svg",
activeIcon: "icons/tablet-icons/menu-a.svg",
text: APP_BUTTON_NAME,
sortOrder: APP_BUTTON_SORT_ORDER
});
tabletAppButton.clicked.connect(function() {
// Remove any old app bridge connections
disconnectAppBridge();
isOnAppPage = false;
tablet.gotoWebScreen(FULL_APP_URL);
});
tablet.screenChanged.connect(function(type, url) {
if (type === 'Web' && url === FULL_APP_URL && !isOnAppPage) {
isOnAppPage = true;
connectAppBridge();
} else if (isOnAppPage) {
isOnAppPage = false;
disconnectAppBridge();
}
});
// Clean-up
Script.scriptEnding.connect(function() {
disconnectAppBridge();
tablet.removeButton(tabletAppButton);
});
})();