Ryan HuffmanCleanup tutorial.jsbdcdceb9 years agoHistory
1127 lines · 38.3 KB · JavaScript
RawDownload
////  tutorial.js////  Created by Ryan Huffman on 9/1/16.//  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// Script.include("entityData.js");Script.include("lighter/createButaneLighter.js");Script.include("tutorialEntityIDs.js"); if (!Function.prototype.bind) {  Function.prototype.bind = function(oThis) {    if (typeof this !== 'function') {      // closest thing possible to the ECMAScript 5      // internal IsCallable function      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');    }     var aArgs   = Array.prototype.slice.call(arguments, 1),        fToBind = this,        fNOP    = function() {},        fBound  = function() {          return fToBind.apply(this instanceof fNOP                 ? this                 : oThis,                 aArgs.concat(Array.prototype.slice.call(arguments)));        };     if (this.prototype) {      // Function.prototype doesn't have a prototype property      fNOP.prototype = this.prototype;    }    fBound.prototype = new fNOP();     return fBound;  };} var DEBUG = true;function debug() {    if (DEBUG) {        var args = Array.prototype.slice.call(arguments);        args.unshift("tutorial.js | ");        print.apply(this, args);    }} var INFO = true;function info() {    if (INFO) {        var args = Array.prototype.slice.call(arguments);        args.unshift("tutorial.js | ");        print.apply(this, args);    }} var NEAR_BOX_SPAWN_NAME = "tutorial/nearGrab/box_spawn";var FAR_BOX_SPAWN_NAME = "tutorial/farGrab/box_spawn";var GUN_SPAWN_NAME = "tutorial/gun_spawn";var TELEPORT_PAD_NAME = "tutorial/teleport/pad" var successSound = SoundCache.getSound("atp:/tutorial_sounds/good_one.L.wav");var firecrackerSound = SoundCache.getSound("atp:/tutorial_sounds/Pops_Firecracker.wav");  var CHANNEL_AWAY_ENABLE = "Hifi-Away-Enable";function setAwayEnabled(value) {    var message = value ? 'enable' : 'disable';    Messages.sendLocalMessage(CHANNEL_AWAY_ENABLE, message);} findEntity = function(properties, searchRadius, filterFn) {    var entities = findEntities(properties, searchRadius, filterFn);    return entities.length > 0 ? entities[0] : null;} // Return all entities with properties `properties` within radius `searchRadius`findEntities = function(properties, searchRadius, filterFn) {    if (!filterFn) {        filterFn = function(properties, key, value) {            return value == properties[key];        }    }    searchRadius = searchRadius ? searchRadius : 100000;    var entities = Entities.findEntities({ x: 0, y: 0, z: 0 }, searchRadius);    var matchedEntities = [];    var keys = Object.keys(properties);    for (var i = 0; i < entities.length; ++i) {        var match = true;        var candidateProperties = Entities.getEntityProperties(entities[i], keys);        for (var key in properties) {            if (!filterFn(properties, key, candidateProperties[key])) {                // This isn't a match, move to next entity                match = false;                break;            }        }        if (match) {            matchedEntities.push(entities[i]);        }    }     return matchedEntities;} function findEntitiesWithTag(tag) {    return findEntities({ userData: "" }, 10000, function(properties, key, value) {        data = parseJSON(value);        return data.tag === tag;    });} /** * A controller in made up of parts, and each part can have multiple "layers," * which are really just different texures. For example, the "trigger" part * has "normal" and "highlight" layers. */function setControllerPartLayer(part, layer) {    data = {};    data[part] = layer;    Messages.sendLocalMessage('Controller-Set-Part-Layer', JSON.stringify(data));} /** * @param {object[]} entityPropertiesList A list of properties to  */function spawn(entityPropertiesList, transform, modifyFn) {    debug("Creating: ", entityPropertiesList);    if (!transform) {        transform = {            position: { x: 0, y: 0, z: 0 },            rotation: { x: 0, y: 0, z: 0, w: 1 }        }    }    var ids = [];    for (var i = 0; i < entityPropertiesList.length; ++i) {        var data = entityPropertiesList[i];        debug("Creating: ", data.name);        data.position = Vec3.sum(transform.position, data.position);        data.rotation = Quat.multiply(data.rotation, transform.rotation);        if (modifyFn) {            data = modifyFn(data);        }        var id = Entities.addEntity(data);        ids.push(id);        debug(id, "data:", JSON.stringify(data));    }    return ids;} /** * @function parseJSON * @param {string} jsonString The string to parse. * @return {object} Return an empty if the string was not valid JSON, otherwise *   the parsed object is returned. */function parseJSON(jsonString) {    var data;    try {        data = JSON.parse(jsonString);    } catch(e) {        data = {};    }    return data;} /** * Spawn entities with `tag` in the userData. * @function spawnWithTag */function spawnWithTag(entityData, transform, tag) {    function modifyFn(data) {        var userData = parseJSON(data.userData);        userData.tag = tag;        data.userData = JSON.stringify(userData);        debug("In modify", tag, userData, data.userData);        return data;    }    return spawn(entityData, transform, modifyFn);} /** * Delete all entities with the tag `tag` in their userData. * @function deleteEntitiesWithTag */function deleteEntitiesWithTag(tag) {    debug("searching for...:", tag);    var entityIDs = findEntitiesWithTag(tag);    for (var i = 0; i < entityIDs.length; ++i) {        Entities.deleteEntity(entityIDs[i]);    }} function editEntitiesWithTag(tag, propertiesOrFn) {    var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag];     debug("Editing tag: ", tag);    if (entities) {        for (entityID in entities) {            debug("Editing: ", entityID, ", ", propertiesOrFn, ", Is in local tree: ", isEntityInLocalTree(entityID));            if (isFunction(propertiesOrFn)) {                Entities.editEntity(entityID, propertiesOrFn(entityIDs[i]));            } else {                Entities.editEntity(entityID, propertiesOrFn);            }        }    }} // From http://stackoverflow.com/questions/5999998/how-can-i-check-if-a-javascript-variable-is-function-typefunction isFunction(functionToCheck) {    var getType = {};    return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';} /** * Return `true` if `entityID` can be found in the local entity tree, otherwise `false`. */function isEntityInLocalTree(entityID) {    return Entities.getEntityProperties(entityID, 'visible').visible !== undefined;} /** * */function showEntitiesWithTag(tag) {    var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag];    if (entities) {        for (entityID in entities) {            var data = entities[entityID];             var collisionless = data.visible === false ? true : false;            if (data.collidable !== undefined) {                collisionless = data.collidable === true ? false : true;            }            if (data.soundKey) {                data.soundKey.playing = true;            }            var newProperties = {                visible: data.visible == false ? false : true,                collisionless: collisionless,                userData: JSON.stringify(data),            };            debug("Showing: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID));            Entities.editEntity(entityID, newProperties);        }    }     // Dynamic method, suppressed for now    return;    editEntitiesWithTag(tag, function(entityID) {        var userData = Entities.getEntityProperties(entityID, "userData").userData;        var data = parseJSON(userData);        var collisionless = data.visible === false ? true : false;        if (data.collidable !== undefined) {            collisionless = data.collidable === true ? false : true;        }        if (data.soundKey) {            data.soundKey.playing = true;        }        var newProperties = {            visible: data.visible == false ? false : true,            collisionless: collisionless,            userData: JSON.stringify(data),        };        Entities.editEntity(entityID, newProperties);    });} /** * @function hideEntitiesWithTag */function hideEntitiesWithTag(tag) {    var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag];    if (entities) {        for (entityID in entities) {            var data = entities[entityID];             if (data.soundKey) {                data.soundKey.playing = false;            }            var newProperties = {                visible: false,                collisionless: 1,                ignoreForCollisions: 1,                userData: JSON.stringify(data),            };             debug("Hiding: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID));            Entities.editEntity(entityID, newProperties);        }    }     // Dynamic method, suppressed for now    return;    editEntitiesWithTag(tag, function(entityID) {        var userData = Entities.getEntityProperties(entityID, "userData").userData;        var data = parseJSON(userData);        if (data.soundKey) {            data.soundKey.playing = false;        }        var newProperties = {            visible: false,            collisionless: 1,            ignoreForCollisions: 1,            userData: JSON.stringify(data),        };        Entities.editEntity(entityID, newProperties);    });} // Return the entity properties for an entity with a given name if it is in our// cached list of entities. Otherwise, return undefined.function getEntityWithName(name) {    debug("Getting entity with name:", name);    var entityID = TUTORIAL_NAME_TO_ENTITY_PROPERTIES_MAP[name];    debug("Entity id: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID));    return entityID;} function playSuccessSound() {    Audio.playSound(successSound, {        position: MyAvatar.position,        volume: 0.7,        loop: false    });} function playFirecrackerSound(position) {    Audio.playSound(firecrackerSound, {        position: position,        volume: 0.5,        loop: false    });} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                                                                           //// STEP: DISABLE CONTROLLERS                                                 ////                                                                           /////////////////////////////////////////////////////////////////////////////////var stepStart = function(name) {    this.tag = name;}stepStart.prototype = {    start: function(onFinish) {        disableEverything();         HMD.requestShowHandControllers();         onFinish();    },    cleanup: function() {    }}; function disableEverything() {    editEntitiesWithTag('door', { visible: true, collisionless: false });    Menu.setIsOptionChecked("Overlays", false);    Controller.disableMapping('handControllerPointer-click');    Messages.sendLocalMessage('Hifi-Advanced-Movement-Disabler', 'disable');    Messages.sendLocalMessage('Hifi-Teleport-Disabler', 'both');    Messages.sendLocalMessage('Hifi-Grab-Disable', JSON.stringify({        nearGrabEnabled: true,        holdEnabled: false,        farGrabEnabled: false,    }));    setControllerPartLayer('touchpad', 'blank');    setControllerPartLayer('tips', 'blank');     hideEntitiesWithTag('finish');     setAwayEnabled(false);} function reenableEverything() {    editEntitiesWithTag('door', { visible: false, collisionless: true });    Menu.setIsOptionChecked("Overlays", true);    Controller.enableMapping('handControllerPointer-click');    Messages.sendLocalMessage('Hifi-Advanced-Movement-Disabler', 'enable');    Messages.sendLocalMessage('Hifi-Teleport-Disabler', 'none');    Messages.sendLocalMessage('Hifi-Grab-Disable', JSON.stringify({        nearGrabEnabled: true,        holdEnabled: true,        farGrabEnabled: true,    }));    setControllerPartLayer('touchpad', 'blank');    setControllerPartLayer('tips', 'blank');    MyAvatar.shouldRenderLocally = true;    setAwayEnabled(true);} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                                                                           //// STEP: ENABLE CONTROLLERS                                                  ////                                                                           ///////////////////////////////////////////////////////////////////////////////// var stepEnableControllers = function(name) {    this.tag = name;    this.shouldLog = false;}stepEnableControllers.prototype = {    start: function(onFinish) {        reenableEverything();        HMD.requestHideHandControllers();        onFinish();    },    cleanup: function() {    }}; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                                                                           //// STEP: Welcome                                                             ////                                                                           /////////////////////////////////////////////////////////////////////////////////var stepWelcome = function(name) {    this.tag = name;}stepWelcome.prototype = {    start: function(onFinish) {        this.timerID = Script.setTimeout(onFinish, 8000);        showEntitiesWithTag(this.tag);    },    cleanup: function() {        if (this.timerID) {            Script.clearTimeout(this.timerID);            this.timerID = null;        }        hideEntitiesWithTag(this.tag);    }};  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                                                                           //// STEP: Orient and raise hands above head                                   ////                                                                           /////////////////////////////////////////////////////////////////////////////////var stepOrient = function(name) {    this.tag = name;    this.tempTag = name + "-temporary";}stepOrient.prototype = {    start: function(onFinish) {        this.active = true;         var tag = this.tag;         // Spawn content set        editEntitiesWithTag(this.tag, { visible: true });         this.checkIntervalID = null;        function checkForHandsAboveHead() {            debug("Orient | Checking for hands above head");            if (MyAvatar.getLeftPalmPosition().y > (MyAvatar.getHeadPosition().y + 0.1)) {                Script.clearInterval(this.checkIntervalID);                this.checkIntervalID = null;                location = "/tutorial";                Script.setTimeout(playSuccessSound, 150);                this.active = false;                onFinish();            }        }        this.checkIntervalID = Script.setInterval(checkForHandsAboveHead.bind(this), 500);    },    cleanup: function() {        debug("Orient | Cleanup");        if (this.active) {            this.active = false;        }        if (this.overlay) {            this.overlay.destroy();            this.overlay = null;        }        if (this.checkIntervalID) {            Script.clearInterval(this.checkIntervalID);            this.checkIntervalID = null;        }        editEntitiesWithTag(this.tag, { visible: false, collisionless: 1 });        deleteEntitiesWithTag(this.tempTag);    }};   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                                                                           //// STEP: Near Grab                                                           ////                                                                           //

Lines 1–500 of 1127.