diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4e9cf57fda..9cf0e841f9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -87,6 +87,7 @@ #include #include #include +#include #include #include #include @@ -1276,17 +1277,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : bool hasTutorialContent = contentVersion >= 1; Setting::Handle firstRun { Settings::firstRun, true }; - bool hasVive = false; - for (auto& displayPlugin : PluginManager::getInstance()->getDisplayPlugins()) { - if (displayPlugin->getName() == "OpenVR (Vive)") { - hasVive = true; - break; - } - } + bool hasHMDAndHandControllers = PluginUtils::isHMDAvailable() && PluginUtils::isHandControllerAvailable(); Setting::Handle tutorialComplete { "tutorialComplete", false }; - bool shouldGoToTutorial = hasVive && hasTutorialContent && !tutorialComplete.get(); - qDebug() << "has vive: " << hasVive << ", current plugin: " << _displayPlugin->getName(); + bool shouldGoToTutorial = hasHMDAndHandControllers && hasTutorialContent && !tutorialComplete.get(); + + qDebug() << "Has HMD + Hand Controllers: " << hasHMDAndHandControllers << ", current plugin: " << _displayPlugin->getName(); qDebug() << "has tutorial content" << hasTutorialContent; qDebug() << "tutorial complete" << tutorialComplete.get(); qDebug() << "should go to tutorial " << shouldGoToTutorial; @@ -1300,10 +1296,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : addressLookupString = arguments().value(urlIndex + 1); } + const QString TUTORIAL_PATH = "/tutorial_begin"; + if (shouldGoToTutorial) { DependencyManager::get()->ifLocalSandboxRunningElse([=]() { qDebug() << "Home sandbox appears to be running, going to Home."; - DependencyManager::get()->goToLocalSandbox("/tutorial_begin"); + DependencyManager::get()->goToLocalSandbox(TUTORIAL_PATH); }, [=]() { qDebug() << "Home sandbox does not appear to be running, going to Entry."; if (firstRun.get()) { diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index a4676428a9..2c769c37d4 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -13,10 +13,12 @@ #include +#include #include #include #include -#include +#include + #include "Application.h" HMDScriptingInterface::HMDScriptingInterface() { @@ -47,6 +49,14 @@ glm::vec2 HMDScriptingInterface::overlayToSpherical(const glm::vec2 & position) return qApp->getApplicationCompositor().overlayToSpherical(position); } +bool HMDScriptingInterface::isHMDAvailable() { + return PluginUtils::isHMDAvailable(); +} + +bool HMDScriptingInterface::isHandControllerAvailable() { + return PluginUtils::isHandControllerAvailable(); +} + QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) { glm::vec3 hudIntersection; auto instance = DependencyManager::get(); diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index 2fbdb76198..4148b1cb4a 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -38,6 +38,9 @@ public: Q_INVOKABLE QString preferredAudioInput() const; Q_INVOKABLE QString preferredAudioOutput() const; + Q_INVOKABLE bool isHMDAvailable(); + Q_INVOKABLE bool isHandControllerAvailable(); + Q_INVOKABLE bool setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) const; Q_INVOKABLE void disableHandLasers(int hands) const; diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h index 2fdecf0bba..8177c9bcc0 100644 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h @@ -68,6 +68,8 @@ public: bool isSupported() const override { return true; } const QString& getName() const override { return NAME; } + bool isHandController() const override { return false; } + void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h index f89f247ce8..7bfaa23be8 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h @@ -39,6 +39,8 @@ public: virtual bool isSupported() const override; virtual const QString& getName() const override { return NAME; } + bool isHandController() const override { return false; } + virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h index 02ae5f58d5..f68be3edf6 100644 --- a/libraries/plugins/src/plugins/InputPlugin.h +++ b/libraries/plugins/src/plugins/InputPlugin.h @@ -19,7 +19,8 @@ namespace controller { class InputPlugin : public Plugin { public: virtual void pluginFocusOutEvent() = 0; - virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) = 0; + + virtual bool isHandController() const = 0; }; diff --git a/libraries/plugins/src/plugins/PluginUtils.cpp b/libraries/plugins/src/plugins/PluginUtils.cpp new file mode 100644 index 0000000000..0a19071210 --- /dev/null +++ b/libraries/plugins/src/plugins/PluginUtils.cpp @@ -0,0 +1,35 @@ +// PluginUtils.cpp +// input-plugins/src/input-plugins +// +// Created by Ryan Huffman on 9/22/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 +// + +#include "PluginUtils.h" + +#include "DisplayPlugin.h" +#include "InputPlugin.h" +#include "PluginManager.h" + +bool PluginUtils::isHMDAvailable() { + for (auto& displayPlugin : PluginManager::getInstance()->getDisplayPlugins()) { + if (displayPlugin->isHmd()) { + return true; + break; + } + } + return false; +} + +bool PluginUtils::isHandControllerAvailable() { + for (auto& inputPlugin : PluginManager::getInstance()->getInputPlugins()) { + if (inputPlugin->isHandController()) { + return true; + break; + } + } + return false; +}; diff --git a/libraries/plugins/src/plugins/PluginUtils.h b/libraries/plugins/src/plugins/PluginUtils.h new file mode 100644 index 0000000000..aba5364800 --- /dev/null +++ b/libraries/plugins/src/plugins/PluginUtils.h @@ -0,0 +1,17 @@ +// PluginUtils.h +// input-plugins/src/input-plugins +// +// Created by Ryan Huffman on 9/22/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 +// + +#pragma once + +class PluginUtils { +public: + static bool isHMDAvailable(); + static bool isHandControllerAvailable(); +}; \ No newline at end of file diff --git a/plugins/hifiNeuron/src/NeuronPlugin.h b/plugins/hifiNeuron/src/NeuronPlugin.h index 9ddd79c013..576deb64ae 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.h +++ b/plugins/hifiNeuron/src/NeuronPlugin.h @@ -25,6 +25,8 @@ class NeuronPlugin : public InputPlugin { public: friend void FrameDataReceivedCallback(void* context, void* sender, _BvhDataHeaderEx* header, float* data); + bool isHandController() const override { return false; } + // Plugin functions virtual bool isSupported() const override; virtual const QString& getName() const override { return NAME; } diff --git a/plugins/hifiSdl2/src/SDL2Manager.h b/plugins/hifiSdl2/src/SDL2Manager.h index a597a87aee..44b75abd2f 100644 --- a/plugins/hifiSdl2/src/SDL2Manager.h +++ b/plugins/hifiSdl2/src/SDL2Manager.h @@ -26,6 +26,8 @@ public: bool isSupported() const override; const QString& getName() const override { return NAME; } + bool isHandController() const override { return false; } + void init() override; void deinit() override; diff --git a/plugins/hifiSixense/src/SixenseManager.h b/plugins/hifiSixense/src/SixenseManager.h index 6aec9fd4ad..56d3c6bc4d 100644 --- a/plugins/hifiSixense/src/SixenseManager.h +++ b/plugins/hifiSixense/src/SixenseManager.h @@ -31,6 +31,8 @@ public: virtual const QString& getName() const override { return NAME; } virtual const QString& getID() const override { return HYDRA_ID_STRING; } + bool isHandController() const override { return true; } + virtual bool activate() override; virtual void deactivate() override; diff --git a/plugins/oculus/src/OculusControllerManager.h b/plugins/oculus/src/OculusControllerManager.h index 3c5cdeb7c6..4c236a375d 100644 --- a/plugins/oculus/src/OculusControllerManager.h +++ b/plugins/oculus/src/OculusControllerManager.h @@ -26,6 +26,8 @@ public: bool isSupported() const override; const QString& getName() const override { return NAME; } + bool isHandController() const override { return true; } + bool activate() override; void deactivate() override; diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 95ff2f881a..5f34d70ba8 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -35,6 +35,8 @@ public: bool isSupported() const override; const QString& getName() const override { return NAME; } + bool isHandController() const override { return true; } + bool activate() override; void deactivate() override; diff --git a/tutorial/tutorialStartZone.js b/tutorial/tutorialStartZone.js index 5f5fa47b94..5adad1d00a 100644 --- a/tutorial/tutorialStartZone.js +++ b/tutorial/tutorialStartZone.js @@ -8,20 +8,21 @@ }, enterEntity: function() { // send message to outer zone - print("ENTERED THE TUTORIAL START AREA"); - var parentID = Entities.getEntityProperties(this.entityID, 'parentID').parentID; - print("HERE", parentID); - if (parentID) { - print("HERE2"); - Entities.callEntityMethod(parentID, 'start'); - print("HERE4"); + print("Entered the tutorial start area"); + if (HMD.isHMDAvailable() && HMD.isHandControllerAvailable()) { + var parentID = Entities.getEntityProperties(this.entityID, 'parentID').parentID; + if (parentID) { + Entities.callEntityMethod(parentID, 'start'); + } else { + print("ERROR: No parent id found on tutorial start zone"); + } } else { - print("HERE3"); - print("ERROR: No parent id found on tutorial start zone"); + Window.alert("To proceed with this tutorial, please connect your VR headset and hand controllers."); + location = "/"; } }, leaveEntity: function() { - print("EXITED THE TUTORIAL START AREA"); + print("Exited the tutorial start area"); } }; diff --git a/tutorial/tutorialZone.js b/tutorial/tutorialZone.js index e1e5a76eb0..e64d0f2445 100644 --- a/tutorial/tutorialZone.js +++ b/tutorial/tutorialZone.js @@ -27,8 +27,10 @@ if (!Function.prototype.bind) { } (function() { - Script.include("ownershipToken.js"); - Script.include("tutorial.js"); + var ownershipTokenPath = Script.resolvePath("ownershipToken.js"); + var tutorialPath = Script.resolvePath("tutorial.js"); + Script.include(ownershipTokenPath); + Script.include(tutorialPath); var TutorialZone = function() { this.token = null; @@ -37,17 +39,19 @@ if (!Function.prototype.bind) { TutorialZone.prototype = { keyReleaseHandler: function(event) { print(event.text); - if (event.text == ",") { - if (!this.tutorialManager.startNextStep()) { + if (event.isShifted && event.isAlt) { + if (event.text == ",") { + if (!this.tutorialManager.startNextStep()) { + this.tutorialManager.startTutorial(); + } + } else if (event.text == "F11") { + this.tutorialManager.restartStep(); + } else if (event.text == "F10") { + MyAvatar.shouldRenderLocally = !MyAvatar.shouldRenderLocally; + } else if (event.text == "r") { + this.tutorialManager.stopTutorial(); this.tutorialManager.startTutorial(); } - } else if (event.text == "F11") { - this.tutorialManager.restartStep(); - } else if (event.text == "F10") { - MyAvatar.shouldRenderLocally = !MyAvatar.shouldRenderLocally; - } else if (event.text == "r") { - this.tutorialManager.stopTutorial(); - this.tutorialManager.startTutorial(); } }, preload: function(entityID) {