diff --git a/android/docker/Dockerfile b/android/docker/Dockerfile index 105bcb7cb0..f6c0e7b2e5 100644 --- a/android/docker/Dockerfile +++ b/android/docker/Dockerfile @@ -71,9 +71,13 @@ RUN mkdir "$HIFI_BASE" && \ mkdir "$HIFI_VCPKG_BASE" && \ mkdir "$HIFI_ANDROID_PRECOMPILED" -RUN git clone https://github.com/jherico/hifi.git && \ +# Checkout a relatively recent commit from the main repository and use it to cache the +# gradle and vcpkg dependencies +# This commit ID should be updated whenever someone changes the dependency list +# in cmake/ports +RUN git clone https://github.com/highfidelity/hifi.git && \ cd ~/hifi && \ - git checkout quest/build + git checkout 796bfb5d6715ff14c2e60f3ee8fac1465b7578c6 WORKDIR /home/jenkins/hifi diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 3937d5f799..ee1e21c837 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -84,7 +84,7 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::get()->setPacketSender(&_entityEditSender); DependencyManager::set(); - DependencyManager::set(); + DependencyManager::set()->instantiate(); DependencyManager::registerInheritance(); @@ -433,7 +433,7 @@ void Agent::executeScript() { using namespace recording; static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::getAudioFrameName()); - Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) { + Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &player, &scriptedAvatar](Frame::ConstPointer frame) { if (_shouldMuteRecordingAudio) { return; } @@ -442,9 +442,18 @@ void Agent::executeScript() { QByteArray audio(frame->data); + int16_t* samples = reinterpret_cast(audio.data()); + int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL; + + auto volume = player->getVolume(); + if (volume >= 0.0f && volume < 1.0f) { + int32_t fract = (int32_t)(volume * (float)(1 << 16)); // Q16 + for (int i = 0; i < numSamples; i++) { + samples[i] = (fract * (int32_t)samples[i]) >> 16; + } + } + if (_isNoiseGateEnabled) { - int16_t* samples = reinterpret_cast(audio.data()); - int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL; _audioGate.render(samples, samples, numSamples); } @@ -511,6 +520,7 @@ void Agent::executeScript() { DependencyManager::set(_entityViewer.getTree()); + DependencyManager::get()->runScriptInitializers(_scriptEngine); _scriptEngine->run(); Frame::clearFrameHandler(AUDIO_FRAME_TYPE); diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 1ef375b562..a1a2b7c1b5 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -144,6 +145,7 @@ AssignmentClient::~AssignmentClient() { } void AssignmentClient::aboutToQuit() { + crash::annotations::setShutdownState(true); stopAssignmentClient(); } @@ -173,6 +175,7 @@ void AssignmentClient::sendStatusPacketToACM() { void AssignmentClient::sendAssignmentRequest() { if (!_currentAssignment && !_isAssigned) { + crash::annotations::setShutdownState(false); auto nodeList = DependencyManager::get(); @@ -289,6 +292,8 @@ void AssignmentClient::handleAuthenticationRequest() { } void AssignmentClient::assignmentCompleted() { + crash::annotations::setShutdownState(true); + // we expect that to be here the previous assignment has completely cleaned up assert(_currentAssignment.isNull()); diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index a87200dc5b..c5b228bd16 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "Assignment.h" #include "AssignmentClient.h" @@ -239,7 +240,11 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : QThread::currentThread()->setObjectName("main thread"); + LogHandler::getInstance().moveToThread(thread()); + LogHandler::getInstance().setupRepeatedMessageFlusher(); + DependencyManager::registerInheritance(); + DependencyManager::set(); if (numForks || minForks || maxForks) { AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks, diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 45511cf6cd..36fd04681a 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -499,6 +499,8 @@ void AvatarMixer::handleAvatarKilled(SharedNodePointer avatarNode) { } else { _sessionDisplayNames.erase(displayNameIter); } + + nodeData->getAvatar().stopChallengeTimer(); } std::unique_ptr killPacket; diff --git a/assignment-client/src/avatars/MixerAvatar.cpp b/assignment-client/src/avatars/MixerAvatar.cpp index 29f7e9ebd2..ac633d9388 100644 --- a/assignment-client/src/avatars/MixerAvatar.cpp +++ b/assignment-client/src/avatars/MixerAvatar.cpp @@ -33,12 +33,12 @@ MixerAvatar::MixerAvatar() { _challengeTimer.setSingleShot(true); _challengeTimer.setInterval(CHALLENGE_TIMEOUT_MS); - _challengeTimer.callOnTimeout([this]() { + _challengeTimer.callOnTimeout(this, [this]() { if (_verifyState == challengeClient) { _pendingEvent = false; _verifyState = verificationFailed; _needsIdentityUpdate = true; - qCDebug(avatars) << "Dynamic verification TIMED-OUT for " << getDisplayName() << getSessionUUID(); + qCDebug(avatars) << "Dynamic verification TIMED-OUT for" << getDisplayName() << getSessionUUID(); } else { qCDebug(avatars) << "Ignoring timeout of avatar challenge"; } @@ -287,7 +287,7 @@ void MixerAvatar::processCertifyEvents() { << ":" << _dynamicMarketResponse; } } else { - qCDebug(avatars) << "Get owner status failed for " << getDisplayName() << _marketplaceIdFromURL << + qCDebug(avatars) << "Get owner status failed for" << getDisplayName() << _marketplaceIdFromURL << "message:" << responseJson["message"].toString(); _verifyState = error; } @@ -332,7 +332,7 @@ void MixerAvatar::sendOwnerChallenge() { void MixerAvatar::processChallengeResponse(ReceivedMessage& response) { QByteArray avatarID; QMutexLocker certifyLocker(&_avatarCertifyLock); - QMetaObject::invokeMethod(&_challengeTimer, &QTimer::stop); + stopChallengeTimer(); if (_verifyState == challengeClient) { QByteArray responseData = response.readAll(); if (responseData.length() < 8) { @@ -356,7 +356,7 @@ void MixerAvatar::processChallengeResponse(ReceivedMessage& response) { _verifyState = challengeResult ? verificationSucceeded : verificationFailed; _needsIdentityUpdate = true; if (_verifyState == verificationFailed) { - qCDebug(avatars) << "Dynamic verification FAILED for " << getDisplayName() << getSessionUUID(); + qCDebug(avatars) << "Dynamic verification FAILED for" << getDisplayName() << getSessionUUID(); } else { qCDebug(avatars) << "Dynamic verification SUCCEEDED for" << getDisplayName() << getSessionUUID(); } @@ -365,3 +365,11 @@ void MixerAvatar::processChallengeResponse(ReceivedMessage& response) { qCDebug(avatars) << "WARNING: Unexpected avatar challenge-response in state" << stateToName(_verifyState); } } + +void MixerAvatar::stopChallengeTimer() { + if (QThread::currentThread() == thread()) { + _challengeTimer.stop(); + } else { + QMetaObject::invokeMethod(&_challengeTimer, &QTimer::stop); + } +} diff --git a/assignment-client/src/avatars/MixerAvatar.h b/assignment-client/src/avatars/MixerAvatar.h index 2ef4d16dc4..39095def50 100644 --- a/assignment-client/src/avatars/MixerAvatar.h +++ b/assignment-client/src/avatars/MixerAvatar.h @@ -34,6 +34,8 @@ public: void processCertifyEvents(); void processChallengeResponse(ReceivedMessage& response); + void stopChallengeTimer(); + // Avatar certification/verification: enum VerifyState { nonCertified, requestingFST, receivedFST, staticValidation, requestingOwner, ownerResponse, diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 06632dabb0..6bbf4a0e3b 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -17,9 +17,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -36,12 +36,13 @@ const char* LOCAL_MODELS_PERSIST_FILE = "resources/models.svo"; EntityServer::EntityServer(ReceivedMessage& message) : OctreeServer(message), - _entitySimulation(NULL), + _entitySimulation(nullptr), _dynamicDomainVerificationTimer(this) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set()->instantiate(); DependencyManager::registerInheritance(); DependencyManager::set(); diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 4d3f1ee89f..9bb3a237e0 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -16,9 +16,11 @@ #include -#include "EntityItem.h" +#include +#include +#include + #include "EntityServerConsts.h" -#include "EntityTree.h" /// Handles assignments of type EntityServer - sending entities to various clients. @@ -27,9 +29,6 @@ struct ViewerSendingStats { quint64 lastEdited; }; -class SimpleEntitySimulation; -using SimpleEntitySimulationPointer = std::shared_ptr; - class EntityServer : public OctreeServer, public NewlyCreatedEntityHook { Q_OBJECT public: diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index f1a6c97831..ea002a27c6 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -64,7 +64,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); + DependencyManager::set()->instantiate(); DependencyManager::registerInheritance(); @@ -301,10 +301,17 @@ void EntityScriptServer::run() { entityScriptingInterface->setEntityTree(_entityViewer.getTree()); - DependencyManager::set(_entityViewer.getTree()); + auto treePtr = _entityViewer.getTree(); + DependencyManager::set(treePtr); + if (!_entitySimulation) { + SimpleEntitySimulationPointer simpleSimulation { new SimpleEntitySimulation() }; + simpleSimulation->setEntityTree(treePtr); + treePtr->setSimulation(simpleSimulation); + _entitySimulation = simpleSimulation; + } - auto tree = _entityViewer.getTree().get(); + auto tree = treePtr.get(); connect(tree, &EntityTree::deletingEntity, this, &EntityScriptServer::deletingEntity, Qt::QueuedConnection); connect(tree, &EntityTree::addingEntity, this, &EntityScriptServer::addingEntity, Qt::QueuedConnection); connect(tree, &EntityTree::entityServerScriptChanging, this, &EntityScriptServer::entityServerScriptChanging, Qt::QueuedConnection); @@ -451,10 +458,11 @@ void EntityScriptServer::resetEntitiesScriptEngine() { connect(newEngine.data(), &ScriptEngine::update, this, [this] { _entityViewer.queryOctree(); + _entityViewer.getTree()->preUpdate(); _entityViewer.getTree()->update(); }); - + scriptEngines->runScriptInitializers(newEngine); newEngine->runInThread(); auto newEngineSP = qSharedPointerCast(newEngine); DependencyManager::get()->setEntitiesScriptEngine(newEngineSP); diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index 944fee36a3..b795339174 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "../entities/EntityTreeHeadlessViewer.h" @@ -75,6 +76,7 @@ private: static int _entitiesScriptEngineCount; ScriptEnginePointer _entitiesScriptEngine; + SimpleEntitySimulationPointer _entitySimulation; EntityEditPacketSender _entityEditSender; EntityTreeHeadlessViewer _entityViewer; diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake index aaca33ab1c..45cef27727 100644 --- a/cmake/compiler.cmake +++ b/cmake/compiler.cmake @@ -34,7 +34,7 @@ if (WIN32) list(APPEND CMAKE_PREFIX_PATH "${WINDOW_SDK_PATH}") # /wd4351 disables warning C4351: new behavior: elements of array will be default initialized - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /wd4351") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP${HIFI_MAX_BUILD_CORES} /wd4351") # /LARGEADDRESSAWARE enables 32-bit apps to use more than 2GB of memory. # Caveats: http://stackoverflow.com/questions/2288728/drawbacks-of-using-largeaddressaware-for-32-bit-windows-executables # TODO: Remove when building 64-bit. diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index f8cff9f773..bf98dba29d 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -38,7 +38,7 @@ macro(SET_PACKAGING_PARAMETERS) set(BUILD_ORGANIZATION "High Fidelity") set(HIGH_FIDELITY_PROTOCOL "hifi") set(HIGH_FIDELITY_APP_PROTOCOL "hifiapp") - set(INTERFACE_BUNDLE_NAME "Interface") + set(INTERFACE_BUNDLE_NAME "interface") set(INTERFACE_ICON_PREFIX "interface") # add definition for this release type @@ -61,7 +61,7 @@ macro(SET_PACKAGING_PARAMETERS) set(PR_BUILD 1) set(BUILD_VERSION "PR${RELEASE_NUMBER}") set(BUILD_ORGANIZATION "High Fidelity - PR${RELEASE_NUMBER}") - set(INTERFACE_BUNDLE_NAME "Interface") + set(INTERFACE_BUNDLE_NAME "interface") set(INTERFACE_ICON_PREFIX "interface-beta") # add definition for this release type @@ -70,7 +70,7 @@ macro(SET_PACKAGING_PARAMETERS) set(DEV_BUILD 1) set(BUILD_VERSION "dev") set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}") - set(INTERFACE_BUNDLE_NAME "Interface") + set(INTERFACE_BUNDLE_NAME "interface") set(INTERFACE_ICON_PREFIX "interface-beta") # add definition for this release type @@ -192,12 +192,12 @@ macro(SET_PACKAGING_PARAMETERS) # shortcut names if (PRODUCTION_BUILD) - set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface") + set(INTERFACE_SHORTCUT_NAME "High Fidelity") set(CONSOLE_SHORTCUT_NAME "Console") set(SANDBOX_SHORTCUT_NAME "Sandbox") set(APP_USER_MODEL_ID "com.highfidelity.console") else () - set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface - ${BUILD_VERSION_NO_SHA}") + set(INTERFACE_SHORTCUT_NAME "High Fidelity - ${BUILD_VERSION_NO_SHA}") set(CONSOLE_SHORTCUT_NAME "Console - ${BUILD_VERSION_NO_SHA}") set(SANDBOX_SHORTCUT_NAME "Sandbox - ${BUILD_VERSION_NO_SHA}") endif () diff --git a/cmake/macros/SetupHifiClientServerPlugin.cmake b/cmake/macros/SetupHifiClientServerPlugin.cmake index bc66484c30..1ce0b0ca6e 100644 --- a/cmake/macros/SetupHifiClientServerPlugin.cmake +++ b/cmake/macros/SetupHifiClientServerPlugin.cmake @@ -7,7 +7,8 @@ # macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN) set(${TARGET_NAME}_SHARED 1) - setup_hifi_library(${ARGV}) + set(PLUGIN_SUBFOLDER ${ARGN}) + setup_hifi_library() if (BUILD_CLIENT) add_dependencies(interface ${TARGET_NAME}) @@ -27,6 +28,11 @@ macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN) set(SERVER_PLUGIN_PATH "plugins") endif() + if (PLUGIN_SUBFOLDER) + set(CLIENT_PLUGIN_PATH "${CLIENT_PLUGIN_PATH}/${PLUGIN_SUBFOLDER}") + set(SERVER_PLUGIN_PATH "${SERVER_PLUGIN_PATH}/${PLUGIN_SUBFOLDER}") + endif() + if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_GENERATOR STREQUAL "Unix Makefiles") set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/${CLIENT_PLUGIN_PATH}/") set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/${SERVER_PLUGIN_PATH}/") diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index 04687e2c84..108786a651 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -20,7 +20,7 @@ macro(SETUP_HIFI_LIBRARY) foreach(SRC ${AVX_SRCS}) if (WIN32) set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX) - elseif (APPLE OR UNIX) + elseif (APPLE OR (UNIX AND NOT ANDROID)) set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx) endif() endforeach() @@ -30,7 +30,7 @@ macro(SETUP_HIFI_LIBRARY) foreach(SRC ${AVX2_SRCS}) if (WIN32) set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX2) - elseif (APPLE OR UNIX) + elseif (APPLE OR (UNIX AND NOT ANDROID)) set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS "-mavx2 -mfma") endif() endforeach() @@ -44,7 +44,7 @@ macro(SETUP_HIFI_LIBRARY) if (COMPILER_SUPPORTS_AVX512) set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX512) endif() - elseif (APPLE OR UNIX) + elseif (APPLE OR (UNIX AND NOT ANDROID)) check_cxx_compiler_flag("-mavx512f" COMPILER_SUPPORTS_AVX512) if (COMPILER_SUPPORTS_AVX512) set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx512f) diff --git a/cmake/macros/TargetWebRTC.cmake b/cmake/macros/TargetWebRTC.cmake index d2821528df..d215b0698e 100644 --- a/cmake/macros/TargetWebRTC.cmake +++ b/cmake/macros/TargetWebRTC.cmake @@ -15,9 +15,11 @@ macro(TARGET_WEBRTC) # select_library_configurations(WEBRTC) else() set(WEBRTC_INCLUDE_DIRS "${VCPKG_INSTALL_ROOT}/include/webrtc") - find_library(WEBRTC_LIBRARY NAMES webrtc PATHS ${VCPKG_INSTALL_ROOT}/lib/ NO_DEFAULT_PATH) target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${WEBRTC_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} ${WEBRTC_LIBRARY}) + find_library(WEBRTC_LIBRARY_RELEASE webrtc PATHS ${VCPKG_INSTALL_ROOT}/lib NO_DEFAULT_PATH) + find_library(WEBRTC_LIBRARY_DEBUG webrtc PATHS ${VCPKG_INSTALL_ROOT}/debug/lib NO_DEFAULT_PATH) + select_library_configurations(WEBRTC) + target_link_libraries(${TARGET_NAME} ${WEBRTC_LIBRARIES}) endif() diff --git a/cmake/modules/FindiViewHMD.cmake b/cmake/modules/FindiViewHMD.cmake deleted file mode 100644 index e408c92380..0000000000 --- a/cmake/modules/FindiViewHMD.cmake +++ /dev/null @@ -1,38 +0,0 @@ -# -# FindiViewHMD.cmake -# -# Try to find the SMI iViewHMD eye tracker library -# -# You must provide a IVIEWHMD_ROOT_DIR which contains 3rdParty, include, and libs directories -# -# Once done this will define -# -# IVIEWHMD_FOUND - system found iViewHMD -# IVIEWHMD_INCLUDE_DIRS - the iViewHMD include directory -# IVIEWHMD_LIBRARIES - link this to use iViewHMD -# -# Created on 27 Jul 2015 by David Rowe -# Copyright 2015 High Fidelity, Inc. -# - -if (WIN32) - - include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") - hifi_library_search_hints("iViewHMD") - - find_path(IVIEWHMD_INCLUDE_DIRS iViewHMDAPI.h PATH_SUFFIXES include HINTS ${IVIEWHMD_SEARCH_DIRS}) - find_library(IVIEWHMD_LIBRARIES NAMES iViewHMDAPI PATH_SUFFIXES libs/x86 HINTS ${IVIEWHMD_SEARCH_DIRS}) - find_path(IVIEWHMD_API_DLL_PATH iViewHMDAPI.dll PATH_SUFFIXES libs/x86 HINTS ${IVIEWHMD_SEARCH_DIRS}) - list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_INCLUDE_DIRS IVIEWHMD_LIBRARIES IVIEWHMD_API_DLL_PATH) - - find_path(IVIEWHMD_DLL_PATH_3RD_PARTY libiViewNG.dll PATH_SUFFIXES 3rdParty HINTS ${IVIEWHMD_SEARCH_DIRS}) - list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_DLL_PATH_3RD_PARTY) - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(IVIEWHMD DEFAULT_MSG ${IVIEWHMD_REQUIREMENTS}) - - add_paths_to_fixup_libs(${IVIEWHMD_API_DLL_PATH} ${IVIEWHMD_DLL_PATH_3RD_PARTY}) - - mark_as_advanced(IVIEWHMD_INCLUDE_DIRS IVIEWHMD_LIBRARIES IVIEWHMD_SEARCH_DIRS) - -endif() diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index cc7a6929a2..9af99f927d 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1156,7 +1156,17 @@ FunctionEnd Section "-Core installation" - ;The following delete blocks are temporary and can be removed once users who had the initial installer have updated + ; 2016-02-25 - The following delete blocks are temporary and can be removed once users who had the initial installer have updated + ; 2019-09-10 - (3 and a half years later) Sure they are buddy. Sure they are. + + ; MessageBox MB_OK|MB_ICONEXCLAMATION "installer type is @INSTALLER_TYPE@" + + ;Delete any server executables that might have been installed by bad versions of the client-only installer, but ONLY if we are a client-only installer + ${If} "@INSTALLER_TYPE@" == "client_only" + ; MessageBox MB_OK|MB_ICONEXCLAMATION "trying to delete server binaries" + Delete "$INSTDIR\assignment-client.exe" + Delete "$INSTDIR\domain-server.exe" + ${EndIf} ;Delete any server-console files installed before it was placed in sub-folder Delete "$INSTDIR\server-console.exe" diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 9cb4c2cab9..b854955953 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1,5 +1,5 @@ { - "version": 2.3, + "version": 2.4, "settings": [ { "name": "metaverse", @@ -1705,6 +1705,114 @@ } ] }, + { + "name": "oauth", + "label": "OAuth", + "show_on_enable": true, + "settings": [ + { + "name": "enable", + "type": "checkbox", + "default": false, + "hidden": true + }, + { + "name": "admin-users", + "label": "Admin Users", + "type": "table", + "can_add_new_rows": true, + "help": "Any of these users can administer the domain.", + "numbered": false, + "backup": false, + "advanced": false, + "columns": [ + { + "name": "username", + "label": "Username", + "can_set": true + } + ] + }, + { + "name": "admin-roles", + "label": "Admin Roles", + "type": "table", + "can_add_new_rows": true, + "help": "Any user with any of these metaverse roles can administer the domain.", + "numbered": false, + "backup": false, + "advanced": true, + "columns": [ + { + "name": "role", + "label": "Role", + "can_set": true + } + ] + }, + { + "name": "client-id", + "label": "Client ID", + "help": "OAuth client ID.", + "default": "", + "advanced": true, + "backup": false + }, + { + "name": "client-secret", + "label": "Client Secret", + "help": "OAuth client secret.", + "type": "password", + "password_placeholder": "******", + "value-hidden": true, + "advanced": true, + "backup": false + }, + { + "name": "provider", + "label": "Provider", + "help": "OAuth provider URL.", + "default": "https://metaverse.highfidelity.com", + "advanced": true, + "backup": false + }, + { + "name": "hostname", + "label": "Hostname", + "help": "OAuth hostname.", + "default": "", + "advanced": true, + "backup": false + }, + { + "name": "key-passphrase", + "label": "SSL Private Key Passphrase", + "help": "SSL Private Key Passphrase", + "type": "password", + "password_placeholder": "******", + "value-hidden": true, + "advanced": true, + "backup": false + }, + { + "name": "cert-fingerprint", + "type": "hidden", + "readonly": true, + "advanced": true, + "backup": false + }, + { + "name": "cert", + "advanced": true, + "backup": false + }, + { + "name": "key", + "advanced": true, + "backup": false + } + ] + }, { "name": "automatic_content_archives", "label": "Automatic Content Archives", diff --git a/domain-server/resources/web/js/base-settings.js b/domain-server/resources/web/js/base-settings.js index bd96f636a8..d3f5baa2f9 100644 --- a/domain-server/resources/web/js/base-settings.js +++ b/domain-server/resources/web/js/base-settings.js @@ -2,6 +2,9 @@ var DomainInfo = null; var viewHelpers = { getFormGroup: function(keypath, setting, values, isAdvanced) { + if (setting.hidden) { + return ""; + } form_group = "
" } - - form_group += "" + setting.help + "" + if (setting.help) { + form_group += "" + setting.help + "" + } } } @@ -114,12 +118,17 @@ function reloadSettings(callback) { data.descriptions.push(Settings.extraGroupsAtEnd[endGroupIndex]); } + data.descriptions = data.descriptions.map(function(x) { + x.hidden = x.hidden || (x.show_on_enable && data.values[x.name] && !data.values[x.name].enable); + return x; + }); + $('#panels').html(Settings.panelsTemplate(data)); Settings.data = data; Settings.initialValues = form2js('settings-form', ".", false, cleanupFormValues, true); - Settings.afterReloadActions(); + Settings.afterReloadActions(data); // setup any bootstrap switches $('.toggle-checkbox').bootstrapSwitch(); @@ -129,10 +138,14 @@ function reloadSettings(callback) { Settings.pendingChanges = 0; // call the callback now that settings are loaded - callback(true); + if (callback) { + callback(true); + } }).fail(function() { // call the failure object since settings load faild - callback(false) + if (callback) { + callback(false); + } }); } @@ -237,14 +250,14 @@ $(document).ready(function(){ // set focus to the first input in the new row $target.closest('table').find('tr.inputs input:first').focus(); - } + } else { + var tableRows = sibling.parent(); + var tableBody = tableRows.parent(); - var tableRows = sibling.parent(); - var tableBody = tableRows.parent(); - - // if theres no more siblings, we should jump to a new row - if (sibling.next().length == 0 && tableRows.nextAll().length == 1) { - tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click(); + // if theres no more siblings, we should jump to a new row + if (sibling.next().length == 0 && tableRows.nextAll().length == 1) { + tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click(); + } } } diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 08d0550841..136d5b0ebc 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -18,7 +18,19 @@ $(document).ready(function(){ Settings.extraGroupsAtIndex = Settings.extraDomainGroupsAtIndex; var METAVERSE_URL = URLs.METAVERSE_URL; - Settings.afterReloadActions = function() { + var SSL_PRIVATE_KEY_FILE_ID = 'ssl-private-key-file'; + var SSL_PRIVATE_KEY_CONTENTS_ID = 'key-contents'; + var SSL_PRIVATE_KEY_CONTENTS_NAME = 'oauth.key-contents'; + var SSL_CERT_UPLOAD_ID = 'ssl-cert-button'; + var SSL_CERT_FILE_ID = 'ssl-cert-file'; + var SSL_CERT_FINGERPRINT_ID = 'cert-fingerprint'; + var SSL_CERT_FINGERPRINT_SPAN_ID = 'cert-fingerprint-span-id'; + var SSL_CERT_CONTENTS_ID = 'cert-contents'; + var SSL_CERT_CONTENTS_NAME = 'oauth.cert-contents'; + var SSL_PRIVATE_KEY_PATH = 'oauth.key'; + var SSL_CERT_PATH = 'oauth.cert'; + + Settings.afterReloadActions = function(data) { getMetaverseUrl(function(metaverse_url) { METAVERSE_URL = metaverse_url; @@ -32,6 +44,8 @@ $(document).ready(function(){ setupDomainNetworkingSettings(); // setupDomainLabelSetting(); + setupSettingsOAuth(data); + setupSettingsBackup(); if (domainIDIsSet()) { @@ -124,6 +138,48 @@ $(document).ready(function(){ } } + if (formJSON["oauth"]) { + var private_key = formJSON["oauth"]["key-contents"]; + var cert = formJSON["oauth"]["cert-contents"]; + var oauthErrors = ""; + if (private_key != undefined) { + var pattern = /-+BEGIN PRIVATE KEY-+[A-Za-z0-9+/\n=]*-+END PRIVATE KEY-+/m; + if (!pattern.test(private_key)) { + oauthErrors += "Private key must be in PEM format
"; + } + } + if (cert != undefined) { + var pattern = /-+BEGIN CERTIFICATE-+[A-Za-z0-9+/\n=]*-+END CERTIFICATE-+/m; + if (!pattern.test(cert)) { + oauthErrors += "Certificate must be in PEM format
"; + } + } + if ($('#oauth.panel').length) { + if (!$('input[name="oauth.client-id"]').val()) { + oauthErrors += "OAuth requires a client Id.
"; + } + if (!$('input[name="oauth.provider"]').val()) { + oauthErrors += "OAuth requires a provider.
"; + } + if (!$('input[name="oauth.hostname"]').val()) { + oauthErrors += "OAuth requires a hostname.
"; + } + if (!$('input[name="' + SSL_PRIVATE_KEY_PATH + '"]').val() && !$('input[name="' + SSL_PRIVATE_KEY_CONTENTS_NAME + '"]').val()) { + oauthErrors += "OAuth requires an SSL Private Key.
"; + } + if (!$('input[name="' + SSL_CERT_PATH + '"]').val() && !$('input[name="' + SSL_CERT_CONTENTS_NAME + '"]').val()) { + oauthErrors += "OAuth requires an SSL Certificate.
"; + } + if (!$("table[name='oauth.admin-users'] tr.value-row").length && + !$("table[name='oauth.admin-roles'] tr.value-row").length) { + oauthErrors += "OAuth must have at least one admin user or admin role.
"; + } + } + if (oauthErrors) { + bootbox.alert({ "message": oauthErrors, "title": "OAuth Configuration Error" }); + return false; + } + } postSettings(formJSON); }; @@ -1035,6 +1091,67 @@ $(document).ready(function(){ }); } + function setupSettingsOAuth(data) { + // construct the HTML needed for the settings backup panel + var html = "
"; + html += "
"; + html += ""; + html += ""; + html += ""; + html += "
"; + html += "
"; + html += ""; + html += "
Fingerprint:" + data.values.oauth["cert-fingerprint"] + "
"; + html += ""; + html += ""; + html += ""; + html += "
"; + + $('#oauth-advanced').append(html); + + $('#key-path-label').after($('[data-keypath="' + SSL_PRIVATE_KEY_PATH + '"]')); + $('#cert-path-label').after($('[data-keypath="' + SSL_CERT_PATH + '"]')); + $('[name="' + SSL_PRIVATE_KEY_PATH + '"]').val(data.values.oauth.key); + $('[name="' + SSL_CERT_PATH + '"]').val(data.values.oauth.cert); + + $('body').on('change input propertychange', '#' + SSL_PRIVATE_KEY_FILE_ID, function(e){ + var f = e.target.files[0]; + var reader = new FileReader(); + reader.onload = function(e) { + $('#' + SSL_PRIVATE_KEY_CONTENTS_ID).val(reader.result); + $('#' + SSL_PRIVATE_KEY_CONTENTS_ID).attr('data-changed', true); + $('[name="' + SSL_PRIVATE_KEY_PATH + '"]').val(''); + badgeForDifferences($('#' + SSL_PRIVATE_KEY_CONTENTS_ID)); + } + reader.readAsText(f); + }); + $('body').on('change input propertychange', '#' + SSL_CERT_FILE_ID, function(e){ + var f = e.target.files[0]; + var reader = new FileReader(); + reader.onload = function(e) { + $('#' + SSL_CERT_CONTENTS_ID).val(reader.result); + $('#' + SSL_CERT_CONTENTS_ID).attr('data-changed', true); + $('[name="' + SSL_CERT_PATH + '"]').val(''); + $('#' + SSL_CERT_FINGERPRINT_SPAN_ID).text(''); + badgeForDifferences($('#' + SSL_CERT_CONTENTS_ID)); + } + reader.readAsText(f); + }); + + $('body').on('change input propertychange', '[name="' + SSL_PRIVATE_KEY_PATH + '"]', function(e){ + $('#' + SSL_PRIVATE_KEY_FILE_ID).val(''); + $('#' + SSL_PRIVATE_KEY_CONTENTS_ID).val(''); + badgeForDifferences($('[name="' + SSL_PRIVATE_KEY_PATH + '"]').attr('data-changed', true)); + }); + + $('body').on('change input propertychange', '[name="' + SSL_CERT_PATH + '"]', function(e){ + $('#' + SSL_CERT_FILE_ID).val(''); + $('#' + SSL_CERT_CONTENTS_ID).val(''); + $('#' + SSL_CERT_FINGERPRINT_SPAN_ID).text(''); + badgeForDifferences($('[name="' + SSL_CERT_PATH + '"]').attr('data-changed', true)); + }); + } + var RESTORE_SETTINGS_UPLOAD_ID = 'restore-settings-button'; var RESTORE_SETTINGS_FILE_ID = 'restore-settings-file'; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 09438b31bc..d9c0a0a6b3 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -174,6 +175,9 @@ DomainServer::DomainServer(int argc, char* argv[]) : LogUtils::init(); + LogHandler::getInstance().moveToThread(thread()); + LogHandler::getInstance().setupRepeatedMessageFlusher(); + qDebug() << "Setting up domain-server"; qDebug() << "[VERSION] Build sequence:" << qPrintable(applicationVersion()); qDebug() << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION; @@ -182,6 +186,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : qDebug() << "[VERSION] BUILD_GLOBAL_SERVICES:" << BuildInfo::BUILD_GLOBAL_SERVICES; qDebug() << "[VERSION] We will be using this name to find ICE servers:" << _iceServerAddr; + connect(this, &QCoreApplication::aboutToQuit, this, &DomainServer::aboutToQuit); // make sure we have a fresh AccountManager instance // (need this since domain-server can restart itself and maintain static variables) @@ -226,9 +231,10 @@ DomainServer::DomainServer(int argc, char* argv[]) : setupGroupCacheRefresh(); - // if we were given a certificate/private key or oauth credentials they must succeed - if (!(optionallyReadX509KeyAndCertificate() && optionallySetupOAuth())) { - return; + optionallySetupOAuth(); + + if (_oauthEnable) { + _oauthEnable = optionallyReadX509KeyAndCertificate(); } _settingsManager.apiRefreshGroupInformation(); @@ -319,7 +325,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : connect(_contentManager.get(), &DomainContentBackupManager::recoveryCompleted, this, &DomainServer::restart); -static const int NODE_PING_MONITOR_INTERVAL_MSECS = 1 * MSECS_PER_SECOND; + static const int NODE_PING_MONITOR_INTERVAL_MSECS = 1 * MSECS_PER_SECOND; _nodePingMonitorTimer = new QTimer{ this }; connect(_nodePingMonitorTimer, &QTimer::timeout, this, &DomainServer::nodePingMonitor); _nodePingMonitorTimer->start(NODE_PING_MONITOR_INTERVAL_MSECS); @@ -428,6 +434,10 @@ DomainServer::~DomainServer() { DependencyManager::destroy(); } +void DomainServer::aboutToQuit() { + crash::annotations::setShutdownState(true); +} + void DomainServer::queuedQuit(QString quitMessage, int exitCode) { if (!quitMessage.isEmpty()) { qWarning() << qPrintable(quitMessage); @@ -447,8 +457,9 @@ QUuid DomainServer::getID() { } bool DomainServer::optionallyReadX509KeyAndCertificate() { - const QString X509_CERTIFICATE_OPTION = "cert"; - const QString X509_PRIVATE_KEY_OPTION = "key"; + const QString X509_CERTIFICATE_OPTION = "oauth.cert"; + const QString X509_PRIVATE_KEY_OPTION = "oauth.key"; + const QString X509_PRIVATE_KEY_PASSPHRASE_OPTION = "oauth.key-passphrase"; const QString X509_KEY_PASSPHRASE_ENV = "DOMAIN_SERVER_KEY_PASSPHRASE"; QString certPath = _settingsManager.valueForKeyPath(X509_CERTIFICATE_OPTION).toString(); @@ -459,7 +470,12 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() { // this is used for Oauth callbacks when authorizing users against a data server // let's make sure we can load the key and certificate - QString keyPassphraseString = QProcessEnvironment::systemEnvironment().value(X509_KEY_PASSPHRASE_ENV); + QString keyPassphraseEnv = QProcessEnvironment::systemEnvironment().value(X509_KEY_PASSPHRASE_ENV); + QString keyPassphraseString = _settingsManager.valueForKeyPath(X509_PRIVATE_KEY_PASSPHRASE_OPTION).toString(); + + if (!keyPassphraseEnv.isEmpty()) { + keyPassphraseString = keyPassphraseEnv; + } qDebug() << "Reading certificate file at" << certPath << "for HTTPS."; qDebug() << "Reading key file at" << keyPath << "for HTTPS."; @@ -473,16 +489,15 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() { QSslCertificate sslCertificate(&certFile); QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8()); + if (privateKey.isNull()) { + qCritical() << "SSL Private Key Not Loading. Bad password or key format?"; + } + _httpsManager.reset(new HTTPSManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this)); qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT; } else if (!certPath.isEmpty() || !keyPath.isEmpty()) { - static const QString MISSING_CERT_ERROR_MSG = "Missing certificate or private key. domain-server will now quit."; - static const int MISSING_CERT_ERROR_CODE = 3; - - QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection, - Q_ARG(QString, MISSING_CERT_ERROR_MSG), Q_ARG(int, MISSING_CERT_ERROR_CODE)); return false; } @@ -490,10 +505,12 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() { } bool DomainServer::optionallySetupOAuth() { - const QString OAUTH_PROVIDER_URL_OPTION = "oauth-provider"; - const QString OAUTH_CLIENT_ID_OPTION = "oauth-client-id"; + const QString OAUTH_ENABLE_OPTION = "oauth.enable"; + const QString OAUTH_PROVIDER_URL_OPTION = "oauth.provider"; + const QString OAUTH_CLIENT_ID_OPTION = "oauth.client-id"; const QString OAUTH_CLIENT_SECRET_ENV = "DOMAIN_SERVER_CLIENT_SECRET"; - const QString REDIRECT_HOSTNAME_OPTION = "hostname"; + const QString OAUTH_CLIENT_SECRET_OPTION = "oauth.client-secret"; + const QString REDIRECT_HOSTNAME_OPTION = "oauth.hostname"; _oauthProviderURL = QUrl(_settingsManager.valueForKeyPath(OAUTH_PROVIDER_URL_OPTION).toString()); @@ -502,22 +519,24 @@ bool DomainServer::optionallySetupOAuth() { _oauthProviderURL = NetworkingConstants::METAVERSE_SERVER_URL(); } + _oauthClientSecret = QProcessEnvironment::systemEnvironment().value(OAUTH_CLIENT_SECRET_ENV); + if (_oauthClientSecret.isEmpty()) { + _oauthClientSecret = _settingsManager.valueForKeyPath(OAUTH_CLIENT_SECRET_OPTION).toString(); + } auto accountManager = DependencyManager::get(); accountManager->setAuthURL(_oauthProviderURL); _oauthClientID = _settingsManager.valueForKeyPath(OAUTH_CLIENT_ID_OPTION).toString(); - _oauthClientSecret = QProcessEnvironment::systemEnvironment().value(OAUTH_CLIENT_SECRET_ENV); _hostname = _settingsManager.valueForKeyPath(REDIRECT_HOSTNAME_OPTION).toString(); - if (!_oauthClientID.isEmpty()) { + _oauthEnable = _settingsManager.valueForKeyPath(OAUTH_ENABLE_OPTION).toBool(); + + if (_oauthEnable) { if (_oauthProviderURL.isEmpty() || _hostname.isEmpty() || _oauthClientID.isEmpty() || _oauthClientSecret.isEmpty()) { - static const QString MISSING_OAUTH_INFO_MSG = "Missing OAuth provider URL, hostname, client ID, or client secret. domain-server will now quit."; - static const int MISSING_OAUTH_INFO_ERROR_CODE = 4; - QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection, - Q_ARG(QString, MISSING_OAUTH_INFO_MSG), Q_ARG(int, MISSING_OAUTH_INFO_ERROR_CODE)); + _oauthEnable = false; return false; } else { qDebug() << "OAuth will be used to identify clients using provider at" << _oauthProviderURL.toString(); @@ -1746,8 +1765,8 @@ void DomainServer::nodePingMonitor() { } void DomainServer::processOctreeDataPersistMessage(QSharedPointer message) { - qDebug() << "Received octree data persist message"; auto data = message->readAll(); + qDebug() << "Received octree data persist message" << (data.size() / 1000) << "kbytes."; auto filePath = getEntitiesFilePath(); QDir dir(getEntitiesDirPath()); @@ -1759,12 +1778,16 @@ void DomainServer::processOctreeDataPersistMessage(QSharedPointer DomainServer::isAuthenticatedRequest(HTTPConnection* connection) { static const QByteArray HTTP_COOKIE_HEADER_KEY = "Cookie"; - static const QString ADMIN_USERS_CONFIG_KEY = "admin-users"; - static const QString ADMIN_ROLES_CONFIG_KEY = "admin-roles"; + static const QString ADMIN_USERS_CONFIG_KEY = "oauth.admin-users"; + static const QString ADMIN_ROLES_CONFIG_KEY = "oauth.admin-roles"; static const QString BASIC_AUTH_USERNAME_KEY_PATH = "security.http_username"; static const QString BASIC_AUTH_PASSWORD_KEY_PATH = "security.http_password"; const QString COOKIE_UUID_REGEX_STRING = HIFI_SESSION_COOKIE_KEY + "=([\\d\\w-]+)($|;)"; @@ -2700,8 +2723,7 @@ std::pair DomainServer::isAuthenticatedRequest(HTTPConnection* c QVariant adminUsersVariant = _settingsManager.valueForKeyPath(ADMIN_USERS_CONFIG_KEY); QVariant adminRolesVariant = _settingsManager.valueForKeyPath(ADMIN_ROLES_CONFIG_KEY); - if (!_oauthProviderURL.isEmpty() - && (adminUsersVariant.isValid() || adminRolesVariant.isValid())) { + if (_oauthEnable) { QString cookieString = connection->requestHeader(HTTP_COOKIE_HEADER_KEY); QRegExp cookieUUIDRegex(COOKIE_UUID_REGEX_STRING); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 02362abd7b..c725688b67 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -136,6 +136,8 @@ private slots: void tokenGrantFinished(); void profileRequestFinished(); + void aboutToQuit(); + signals: void iceServerChanged(); void userConnected(); @@ -236,6 +238,7 @@ private: bool _isUsingDTLS { false }; + bool _oauthEnable { false }; QUrl _oauthProviderURL; QString _oauthClientID; QString _oauthClientSecret; diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 17d473f02c..73d78a5c70 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -22,7 +22,9 @@ #include #include #include +#include #include +#include #include #include @@ -46,10 +48,14 @@ const QString DESCRIPTION_SETTINGS_KEY = "settings"; const QString SETTING_DEFAULT_KEY = "default"; const QString DESCRIPTION_NAME_KEY = "name"; const QString DESCRIPTION_GROUP_LABEL_KEY = "label"; +const QString DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY = "show_on_enable"; +const QString DESCRIPTION_ENABLE_KEY = "enable"; const QString DESCRIPTION_BACKUP_FLAG_KEY = "backup"; const QString SETTING_DESCRIPTION_TYPE_KEY = "type"; const QString DESCRIPTION_COLUMNS_KEY = "columns"; const QString CONTENT_SETTING_FLAG_KEY = "content_setting"; +static const QString SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY = "domain_settings"; +static const QString SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY = "content_settings"; const QString SETTINGS_VIEWPOINT_KEY = "viewpoint"; @@ -136,6 +142,10 @@ void DomainServerSettingsManager::splitSettingsDescription() { settingsDropdownGroup[DESCRIPTION_GROUP_LABEL_KEY] = groupObject[DESCRIPTION_GROUP_LABEL_KEY]; + if (groupObject.contains(DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY)) { + settingsDropdownGroup[DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY] = groupObject[DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY]; + } + static const QString DESCRIPTION_GROUP_HTML_ID_KEY = "html_id"; if (groupObject.contains(DESCRIPTION_GROUP_HTML_ID_KEY)) { settingsDropdownGroup[DESCRIPTION_GROUP_HTML_ID_KEY] = groupObject[DESCRIPTION_GROUP_HTML_ID_KEY]; @@ -170,9 +180,6 @@ void DomainServerSettingsManager::splitSettingsDescription() { // populate the settings menu groups with what we've collected - static const QString SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY = "domain_settings"; - static const QString SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY = "content_settings"; - _settingsMenuGroups[SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY] = domainSettingsMenuGroups; _settingsMenuGroups[SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY] = contentSettingsMenuGroups; } @@ -448,6 +455,77 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena packPermissions(); } + if (oldVersion < 2.4) { + // migrate oauth settings to their own group + const QString ADMIN_USERS = "admin-users"; + const QString OAUTH_ADMIN_USERS = "oauth.admin-users"; + const QString OAUTH_CLIENT_ID = "oauth.client-id"; + const QString ALT_ADMIN_USERS = "admin.users"; + const QString ADMIN_ROLES = "admin-roles"; + const QString OAUTH_ADMIN_ROLES = "oauth.admin-roles"; + const QString OAUTH_ENABLE = "oauth.enable"; + + QVector > conversionMap = { + {"key", "oauth.key"}, + {"cert", "oauth.cert"}, + {"hostname", "oauth.hostname"}, + {"oauth-client-id", "oauth.client-id"}, + {"oauth-provider", "oauth.provider"} + }; + + for (auto & conversion : conversionMap) { + QVariant* prevValue = _configMap.valueForKeyPath(conversion.first); + if (prevValue) { + auto newValue = _configMap.valueForKeyPath(conversion.second, true); + *newValue = *prevValue; + } + } + + QVariant* client_id = _configMap.valueForKeyPath(OAUTH_CLIENT_ID); + if (client_id) { + QVariant* oauthEnable = _configMap.valueForKeyPath(OAUTH_ENABLE, true); + + *oauthEnable = QVariant(true); + } + + QVariant* oldAdminUsers = _configMap.valueForKeyPath(ADMIN_USERS); + QVariant* newAdminUsers = _configMap.valueForKeyPath(OAUTH_ADMIN_USERS, true); + QVariantList adminUsers(newAdminUsers->toList()); + if (oldAdminUsers) { + QStringList adminUsersList = oldAdminUsers->toStringList(); + for (auto & user : adminUsersList) { + if (!adminUsers.contains(user)) { + adminUsers.append(user); + } + } + } + QVariant* altAdminUsers = _configMap.valueForKeyPath(ALT_ADMIN_USERS); + if (altAdminUsers) { + QStringList adminUsersList = altAdminUsers->toStringList(); + for (auto & user : adminUsersList) { + if (!adminUsers.contains(user)) { + adminUsers.append(user); + } + } + } + + *newAdminUsers = adminUsers; + + QVariant* oldAdminRoles = _configMap.valueForKeyPath(ADMIN_ROLES); + QVariant* newAdminRoles = _configMap.valueForKeyPath(OAUTH_ADMIN_ROLES, true); + QVariantList adminRoles(newAdminRoles->toList()); + if (oldAdminRoles) { + QStringList adminRoleList = oldAdminRoles->toStringList(); + for (auto & role : adminRoleList) { + if (!adminRoles.contains(role)) { + adminRoles.append(role); + } + } + } + + *newAdminRoles = adminRoles; + } + // write the current description version to our settings *versionVariant = _descriptionVersion; @@ -1185,7 +1263,24 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection return true; } else if (url.path() == SETTINGS_MENU_GROUPS_PATH) { - connection->respond(HTTPConnection::StatusCode200, QJsonDocument(_settingsMenuGroups).toJson(), "application/json"); + + QJsonObject settings; + for (auto & key : _settingsMenuGroups.keys()) { + const QJsonArray& settingGroups = _settingsMenuGroups[key].toArray(); + QJsonArray groups; + foreach (const QJsonValue& group, settingGroups) { + QJsonObject groupObject = group.toObject(); + QVariant* enableKey = _configMap.valueForKeyPath(groupObject[DESCRIPTION_NAME_KEY].toString() + "." + DESCRIPTION_ENABLE_KEY); + + if (!groupObject.contains(DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY) + || (groupObject[DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY].toBool() && enableKey && enableKey->toBool() )) { + groups.append(groupObject); + } + } + settings[key] = groups; + } + + connection->respond(HTTPConnection::StatusCode200, QJsonDocument(settings).toJson(), "application/json"); return true; } else if (url.path() == SETTINGS_BACKUP_PATH) { @@ -1446,6 +1541,28 @@ QJsonObject DomainServerSettingsManager::settingsResponseObjectForType(const QSt } } + // add 'derived' values used primarily for UI + + const QString X509_CERTIFICATE_OPTION = "oauth.cert"; + + QString certPath = valueForKeyPath(X509_CERTIFICATE_OPTION).toString(); + if (!certPath.isEmpty()) { + // the user wants to use the following cert and key for HTTPS + // this is used for Oauth callbacks when authorizing users against a data server + // let's make sure we can load the key and certificate + + qDebug() << "Reading certificate file at" << certPath << "for HTTPS."; + + QFile certFile(certPath); + certFile.open(QIODevice::ReadOnly); + + QSslCertificate sslCertificate(&certFile); + QString digest = sslCertificate.digest().toHex(':'); + auto groupObject = responseObject["oauth"].toObject(); + groupObject["cert-fingerprint"] = digest; + responseObject["oauth"] = groupObject; + } + return responseObject; } @@ -1551,23 +1668,65 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson return QJsonObject(); } -bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, +bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedSettingsObject, SettingsType settingsType) { // take a write lock since we're about to overwrite settings in the config map QWriteLocker locker(&_settingsLock); + QJsonObject postedObject(postedSettingsObject); + static const QString SECURITY_ROOT_KEY = "security"; static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist"; static const QString BROADCASTING_KEY = "broadcasting"; static const QString WIZARD_KEY = "wizard"; static const QString DESCRIPTION_ROOT_KEY = "descriptors"; + static const QString OAUTH_ROOT_KEY = "oauth"; + static const QString OAUTH_KEY_CONTENTS = "key-contents"; + static const QString OAUTH_CERT_CONTENTS = "cert-contents"; + static const QString OAUTH_CERT_PATH = "cert"; + static const QString OAUTH_KEY_PASSPHRASE = "key-passphrase"; + static const QString OAUTH_KEY_PATH = "key"; auto& settingsVariant = _configMap.getConfig(); bool needRestart = false; auto& filteredDescriptionArray = settingsType == DomainSettings ? _domainSettingsDescription : _contentSettingsDescription; + auto oauthObject = postedObject[OAUTH_ROOT_KEY].toObject(); + if (oauthObject.contains(OAUTH_CERT_CONTENTS)) { + QSslCertificate cert(oauthObject[OAUTH_CERT_CONTENTS].toString().toUtf8()); + if (!cert.isNull()) { + static const QString CERT_FILE_NAME = "certificate.crt"; + auto certPath = PathUtils::getAppDataFilePath(CERT_FILE_NAME); + QFile file(certPath); + if (file.open(QFile::WriteOnly)) { + file.write(cert.toPem()); + file.close(); + } + oauthObject[OAUTH_CERT_PATH] = certPath; + } + oauthObject.remove(OAUTH_CERT_CONTENTS); + } + if (oauthObject.contains(OAUTH_KEY_CONTENTS)) { + QString keyPassphraseString = oauthObject[OAUTH_KEY_PASSPHRASE].toString(); + QSslKey key(oauthObject[OAUTH_KEY_CONTENTS].toString().toUtf8(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8()); + if (!key.isNull()) { + static const QString KEY_FILE_NAME = "certificate.key"; + auto keyPath = PathUtils::getAppDataFilePath(KEY_FILE_NAME); + QFile file(keyPath); + if (file.open(QFile::WriteOnly)) { + file.write(key.toPem()); + file.close(); + file.setPermissions(QFile::ReadOwner | QFile::WriteOwner); + } + oauthObject[OAUTH_KEY_PATH] = keyPath; + } + oauthObject.remove(OAUTH_KEY_CONTENTS); + } + + postedObject[OAUTH_ROOT_KEY] = oauthObject; + // Iterate on the setting groups foreach(const QString& rootKey, postedObject.keys()) { const QJsonValue& rootValue = postedObject[rootKey]; @@ -1752,6 +1911,8 @@ void DomainServerSettingsManager::persistToFile() { _configMap.loadConfig(); return; // defend against future code } + + QFile(settingsFilename).setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner); } QStringList DomainServerSettingsManager::getAllKnownGroupNames() { diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 7aea9cc3d4..ba12349347 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -15,9 +15,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include #include #include -#include #include "DomainServer.h" @@ -32,6 +33,7 @@ int main(int argc, char* argv[]) { // use a do-while to handle domain-server restart do { + crash::annotations::setShutdownState(false); DomainServer domainServer(argc, argv); currentExitCode = domainServer.exec(); } while (currentExitCode == DomainServer::EXIT_CODE_REBOOT); @@ -39,4 +41,3 @@ int main(int argc, char* argv[]) { qInfo() << "Quitting."; return currentExitCode; } - diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 9553b571c5..bcd3f269e8 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -70,12 +70,16 @@ file(GLOB_RECURSE INTERFACE_SRCS "src/*.cpp" "src/*.h") GroupSources("src") list(APPEND INTERFACE_SRCS ${RESOURCES_RCC}) +# grab the Objective-C sources on OS X +if (APPLE) + file(GLOB_RECURSE INTERFACE_OBJCPP_SRCS "src/*.m" "src/*.mm") + list(APPEND INTERFACE_SRCS ${INTERFACE_OBJCPP_SRCS}) +endif () + # Add SpeechRecognizer if on Windows or OS X, otherwise remove if (WIN32) # Use .cpp and .h files as is. elseif (APPLE) - file(GLOB INTERFACE_OBJCPP_SRCS "src/SpeechRecognizer.mm") - set(INTERFACE_SRCS ${INTERFACE_SRCS} ${INTERFACE_OBJCPP_SRCS}) get_filename_component(SPEECHRECOGNIZER_CPP "src/SpeechRecognizer.cpp" ABSOLUTE) list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP}) else () @@ -117,6 +121,7 @@ if (APPLE) # configure CMake to use a custom Info.plist set_target_properties(${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in) + set(MACOSX_BUNDLE_BUNDLE_NAME "High Fidelity") if (PRODUCTION_BUILD) set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface) else () @@ -151,7 +156,7 @@ elseif (WIN32) set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc") configure_file("${HF_CMAKE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT}) - set(APP_FULL_NAME "High Fidelity Interface") + set(APP_FULL_NAME "High Fidelity") set(CONFIGURE_VERSION_INFO_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/VersionInfo.rc") configure_file("${HF_CMAKE_DIR}/templates/VersionInfo.rc.in" ${CONFIGURE_VERSION_INFO_RC_OUTPUT}) diff --git a/interface/external/iViewHMD/readme.txt b/interface/external/iViewHMD/readme.txt deleted file mode 100644 index 4b3d59349b..0000000000 --- a/interface/external/iViewHMD/readme.txt +++ /dev/null @@ -1,14 +0,0 @@ - -Instructions for adding SMI HMD Eye Tracking to Interface on Windows -David Rowe, 27 Jul 2015. - -1. Download and install the SMI HMD Eye Tracking software from http://update.smivision.com/iViewNG-HMD.exe. - -2. Copy the SDK folders (3rdParty, include, libs) from the SDK installation folder C:\Program Files (x86)\SMI\iViewNG-HMD\SDK - into the interface/externals/iViewHMD folder. This readme.txt should be there as well. - - You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different - checkouts and different projects). If so, set the ENV variable "HIFI_LIB_DIR" to a directory containing a subfolder - "iViewHMD" that contains the folders mentioned above. - -3. Clear your build directory, run cmake and build, and you should be all set. diff --git a/interface/icon/interface-beta.icns b/interface/icon/interface-beta.icns index 1013607082..8dadfd5037 100644 Binary files a/interface/icon/interface-beta.icns and b/interface/icon/interface-beta.icns differ diff --git a/interface/icon/interface-beta.ico b/interface/icon/interface-beta.ico index d04fba6e04..09a97956a7 100644 Binary files a/interface/icon/interface-beta.ico and b/interface/icon/interface-beta.ico differ diff --git a/interface/icon/interface.icns b/interface/icon/interface.icns index 4aeb8301ce..8dadfd5037 100644 Binary files a/interface/icon/interface.icns and b/interface/icon/interface.icns differ diff --git a/interface/icon/interface.ico b/interface/icon/interface.ico index cdd4792f56..09a97956a7 100644 Binary files a/interface/icon/interface.ico and b/interface/icon/interface.ico differ diff --git a/interface/interface.entitlements b/interface/interface.entitlements new file mode 100644 index 0000000000..e41b568d42 --- /dev/null +++ b/interface/interface.entitlements @@ -0,0 +1,20 @@ + + + + + com.apple.security.application-groups + + high-fidelity.hifi + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.device.audio-input + + com.apple.security.network.client + + com.apple.security.network.server + + + diff --git a/interface/resources/avatar/animations/emote_agree_acknowledge.fbx b/interface/resources/avatar/animations/emote_agree_acknowledge.fbx index 9b1984b7cd..1784e54828 100644 Binary files a/interface/resources/avatar/animations/emote_agree_acknowledge.fbx and b/interface/resources/avatar/animations/emote_agree_acknowledge.fbx differ diff --git a/interface/resources/avatar/animations/emote_agree_headnod.fbx b/interface/resources/avatar/animations/emote_agree_headnod.fbx index f380f7887c..dbb46c1c5f 100644 Binary files a/interface/resources/avatar/animations/emote_agree_headnod.fbx and b/interface/resources/avatar/animations/emote_agree_headnod.fbx differ diff --git a/interface/resources/avatar/animations/emote_agree_headnodyes.fbx b/interface/resources/avatar/animations/emote_agree_headnodyes.fbx index c8bb90c021..588a305c02 100644 Binary files a/interface/resources/avatar/animations/emote_agree_headnodyes.fbx and b/interface/resources/avatar/animations/emote_agree_headnodyes.fbx differ diff --git a/interface/resources/avatar/animations/emote_agree_longheadnod.fbx b/interface/resources/avatar/animations/emote_agree_longheadnod.fbx index 01aa806b77..ab66359775 100644 Binary files a/interface/resources/avatar/animations/emote_agree_longheadnod.fbx and b/interface/resources/avatar/animations/emote_agree_longheadnod.fbx differ diff --git a/interface/resources/avatar/animations/emote_agree_thoughtfulheadnod.fbx b/interface/resources/avatar/animations/emote_agree_thoughtfulheadnod.fbx index dcdba0a721..5ca510930d 100644 Binary files a/interface/resources/avatar/animations/emote_agree_thoughtfulheadnod.fbx and b/interface/resources/avatar/animations/emote_agree_thoughtfulheadnod.fbx differ diff --git a/interface/resources/avatar/animations/emote_clap01_all.fbx b/interface/resources/avatar/animations/emote_clap01_all.fbx index f04046280b..61cec1c19c 100644 Binary files a/interface/resources/avatar/animations/emote_clap01_all.fbx and b/interface/resources/avatar/animations/emote_clap01_all.fbx differ diff --git a/interface/resources/avatar/animations/emote_clap02_all.fbx b/interface/resources/avatar/animations/emote_clap02_all.fbx index caf673f28a..ba4db90363 100644 Binary files a/interface/resources/avatar/animations/emote_clap02_all.fbx and b/interface/resources/avatar/animations/emote_clap02_all.fbx differ diff --git a/interface/resources/avatar/animations/emote_clap03_all.fbx b/interface/resources/avatar/animations/emote_clap03_all.fbx index c214bce859..e04f656610 100644 Binary files a/interface/resources/avatar/animations/emote_clap03_all.fbx and b/interface/resources/avatar/animations/emote_clap03_all.fbx differ diff --git a/interface/resources/avatar/animations/emote_disagree_annoyedheadshake.fbx b/interface/resources/avatar/animations/emote_disagree_annoyedheadshake.fbx index 3d7b61a468..976c72ba85 100644 Binary files a/interface/resources/avatar/animations/emote_disagree_annoyedheadshake.fbx and b/interface/resources/avatar/animations/emote_disagree_annoyedheadshake.fbx differ diff --git a/interface/resources/avatar/animations/emote_disagree_drophead.fbx b/interface/resources/avatar/animations/emote_disagree_drophead.fbx index 39ffa7e591..68899e6e90 100644 Binary files a/interface/resources/avatar/animations/emote_disagree_drophead.fbx and b/interface/resources/avatar/animations/emote_disagree_drophead.fbx differ diff --git a/interface/resources/avatar/animations/emote_disagree_thoughtfulheadshake.fbx b/interface/resources/avatar/animations/emote_disagree_thoughtfulheadshake.fbx index c25a717c4a..17691b8dc7 100644 Binary files a/interface/resources/avatar/animations/emote_disagree_thoughtfulheadshake.fbx and b/interface/resources/avatar/animations/emote_disagree_thoughtfulheadshake.fbx differ diff --git a/interface/resources/avatar/animations/emote_point01_aimoffsets.fbx b/interface/resources/avatar/animations/emote_point01_aimoffsets.fbx new file mode 100644 index 0000000000..84524168e7 Binary files /dev/null and b/interface/resources/avatar/animations/emote_point01_aimoffsets.fbx differ diff --git a/interface/resources/avatar/animations/emote_point01_all.fbx b/interface/resources/avatar/animations/emote_point01_all.fbx index 8fe7c951d6..6302620794 100644 Binary files a/interface/resources/avatar/animations/emote_point01_all.fbx and b/interface/resources/avatar/animations/emote_point01_all.fbx differ diff --git a/interface/resources/avatar/animations/emote_raisehand01_all.fbx b/interface/resources/avatar/animations/emote_raisehand01_all.fbx index 3206ffe411..85f57014d1 100644 Binary files a/interface/resources/avatar/animations/emote_raisehand01_all.fbx and b/interface/resources/avatar/animations/emote_raisehand01_all.fbx differ diff --git a/interface/resources/avatar/animations/emote_raisehand03_all.fbx b/interface/resources/avatar/animations/emote_raisehand03_all.fbx index fe9d9ca4b7..6de262c1ac 100644 Binary files a/interface/resources/avatar/animations/emote_raisehand03_all.fbx and b/interface/resources/avatar/animations/emote_raisehand03_all.fbx differ diff --git a/interface/resources/avatar/animations/emote_raisehand04_all.fbx b/interface/resources/avatar/animations/emote_raisehand04_all.fbx index 01caf1a7af..262ba1badb 100644 Binary files a/interface/resources/avatar/animations/emote_raisehand04_all.fbx and b/interface/resources/avatar/animations/emote_raisehand04_all.fbx differ diff --git a/interface/resources/avatar/animations/fly.fbx b/interface/resources/avatar/animations/fly.fbx index 5d8fcce23b..5f0fa1ecd7 100644 Binary files a/interface/resources/avatar/animations/fly.fbx and b/interface/resources/avatar/animations/fly.fbx differ diff --git a/interface/resources/avatar/animations/idle.fbx b/interface/resources/avatar/animations/idle.fbx index a2cbb9b43b..e5a08ec600 100644 Binary files a/interface/resources/avatar/animations/idle.fbx and b/interface/resources/avatar/animations/idle.fbx differ diff --git a/interface/resources/avatar/animations/idle02.fbx b/interface/resources/avatar/animations/idle02.fbx index c18162dda1..7ec151ac21 100644 Binary files a/interface/resources/avatar/animations/idle02.fbx and b/interface/resources/avatar/animations/idle02.fbx differ diff --git a/interface/resources/avatar/animations/idle03.fbx b/interface/resources/avatar/animations/idle03.fbx index 5349c49a31..641659cc17 100644 Binary files a/interface/resources/avatar/animations/idle03.fbx and b/interface/resources/avatar/animations/idle03.fbx differ diff --git a/interface/resources/avatar/animations/idle04.fbx b/interface/resources/avatar/animations/idle04.fbx index c0676a7980..8207b7eaeb 100644 Binary files a/interface/resources/avatar/animations/idle04.fbx and b/interface/resources/avatar/animations/idle04.fbx differ diff --git a/interface/resources/avatar/animations/idleWS_all.fbx b/interface/resources/avatar/animations/idleWS_all.fbx index 3605ecfcf4..d56b6f578b 100644 Binary files a/interface/resources/avatar/animations/idleWS_all.fbx and b/interface/resources/avatar/animations/idleWS_all.fbx differ diff --git a/interface/resources/avatar/animations/idle_LFF_all.fbx b/interface/resources/avatar/animations/idle_LFF_all.fbx index 66b82914ba..416bba001e 100644 Binary files a/interface/resources/avatar/animations/idle_LFF_all.fbx and b/interface/resources/avatar/animations/idle_LFF_all.fbx differ diff --git a/interface/resources/avatar/animations/idle_RFF_all.fbx b/interface/resources/avatar/animations/idle_RFF_all.fbx index 80277ec9a6..925e6ad4f9 100644 Binary files a/interface/resources/avatar/animations/idle_RFF_all.fbx and b/interface/resources/avatar/animations/idle_RFF_all.fbx differ diff --git a/interface/resources/avatar/animations/idle_aimoffsets.fbx b/interface/resources/avatar/animations/idle_aimoffsets.fbx new file mode 100644 index 0000000000..6e5ab05fdc Binary files /dev/null and b/interface/resources/avatar/animations/idle_aimoffsets.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_fidget.fbx b/interface/resources/avatar/animations/idle_once_fidget.fbx index 2270614901..af5d6167a7 100644 Binary files a/interface/resources/avatar/animations/idle_once_fidget.fbx and b/interface/resources/avatar/animations/idle_once_fidget.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_headtilt.fbx b/interface/resources/avatar/animations/idle_once_headtilt.fbx index eeae4604aa..f6bd8fe770 100644 Binary files a/interface/resources/avatar/animations/idle_once_headtilt.fbx and b/interface/resources/avatar/animations/idle_once_headtilt.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_lookaround.fbx b/interface/resources/avatar/animations/idle_once_lookaround.fbx index b638191654..cf793b55b5 100644 Binary files a/interface/resources/avatar/animations/idle_once_lookaround.fbx and b/interface/resources/avatar/animations/idle_once_lookaround.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_lookleftright.fbx b/interface/resources/avatar/animations/idle_once_lookleftright.fbx index 72aee7931e..c8e9516cc9 100644 Binary files a/interface/resources/avatar/animations/idle_once_lookleftright.fbx and b/interface/resources/avatar/animations/idle_once_lookleftright.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_neckstretch.fbx b/interface/resources/avatar/animations/idle_once_neckstretch.fbx index 5ee4a99d65..8eaa5f337b 100644 Binary files a/interface/resources/avatar/animations/idle_once_neckstretch.fbx and b/interface/resources/avatar/animations/idle_once_neckstretch.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_shiftheelpivot.fbx b/interface/resources/avatar/animations/idle_once_shiftheelpivot.fbx index 073b4343aa..79ce27ab89 100644 Binary files a/interface/resources/avatar/animations/idle_once_shiftheelpivot.fbx and b/interface/resources/avatar/animations/idle_once_shiftheelpivot.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_slownod.fbx b/interface/resources/avatar/animations/idle_once_slownod.fbx index 7a27add7bf..23f93a3978 100644 Binary files a/interface/resources/avatar/animations/idle_once_slownod.fbx and b/interface/resources/avatar/animations/idle_once_slownod.fbx differ diff --git a/interface/resources/avatar/animations/jog_bwd.fbx b/interface/resources/avatar/animations/jog_bwd.fbx index b3eb8c919d..2f52d3a71e 100644 Binary files a/interface/resources/avatar/animations/jog_bwd.fbx and b/interface/resources/avatar/animations/jog_bwd.fbx differ diff --git a/interface/resources/avatar/animations/jog_fwd.fbx b/interface/resources/avatar/animations/jog_fwd.fbx index 9d38caacab..784482445a 100644 Binary files a/interface/resources/avatar/animations/jog_fwd.fbx and b/interface/resources/avatar/animations/jog_fwd.fbx differ diff --git a/interface/resources/avatar/animations/jog_left.fbx b/interface/resources/avatar/animations/jog_left.fbx index 7732050201..a875da6d69 100644 Binary files a/interface/resources/avatar/animations/jog_left.fbx and b/interface/resources/avatar/animations/jog_left.fbx differ diff --git a/interface/resources/avatar/animations/jog_right.fbx b/interface/resources/avatar/animations/jog_right.fbx index 9b419b6eec..e3b0f379cd 100644 Binary files a/interface/resources/avatar/animations/jog_right.fbx and b/interface/resources/avatar/animations/jog_right.fbx differ diff --git a/interface/resources/avatar/animations/jump_running_launch_land_all.fbx b/interface/resources/avatar/animations/jump_running_launch_land_all.fbx index 71dae6bcc5..4d17a6b72a 100644 Binary files a/interface/resources/avatar/animations/jump_running_launch_land_all.fbx and b/interface/resources/avatar/animations/jump_running_launch_land_all.fbx differ diff --git a/interface/resources/avatar/animations/jump_standing_apex_all.fbx b/interface/resources/avatar/animations/jump_standing_apex_all.fbx index 5d5873c39a..bd52dfad0d 100644 Binary files a/interface/resources/avatar/animations/jump_standing_apex_all.fbx and b/interface/resources/avatar/animations/jump_standing_apex_all.fbx differ diff --git a/interface/resources/avatar/animations/jump_standing_land_settle_all.fbx b/interface/resources/avatar/animations/jump_standing_land_settle_all.fbx index ef8e83be34..e371f36022 100644 Binary files a/interface/resources/avatar/animations/jump_standing_land_settle_all.fbx and b/interface/resources/avatar/animations/jump_standing_land_settle_all.fbx differ diff --git a/interface/resources/avatar/animations/jump_standing_launch_all.fbx b/interface/resources/avatar/animations/jump_standing_launch_all.fbx index e10e428579..e75c85431b 100644 Binary files a/interface/resources/avatar/animations/jump_standing_launch_all.fbx and b/interface/resources/avatar/animations/jump_standing_launch_all.fbx differ diff --git a/interface/resources/avatar/animations/run_bwd.fbx b/interface/resources/avatar/animations/run_bwd.fbx index 60ade1f2ac..95cfe695f4 100644 Binary files a/interface/resources/avatar/animations/run_bwd.fbx and b/interface/resources/avatar/animations/run_bwd.fbx differ diff --git a/interface/resources/avatar/animations/run_fast_fwd.fbx b/interface/resources/avatar/animations/run_fast_fwd.fbx index cb964d57d8..c227428985 100644 Binary files a/interface/resources/avatar/animations/run_fast_fwd.fbx and b/interface/resources/avatar/animations/run_fast_fwd.fbx differ diff --git a/interface/resources/avatar/animations/run_fast_left.fbx b/interface/resources/avatar/animations/run_fast_left.fbx index 5078d0cb22..40ab6220df 100644 Binary files a/interface/resources/avatar/animations/run_fast_left.fbx and b/interface/resources/avatar/animations/run_fast_left.fbx differ diff --git a/interface/resources/avatar/animations/run_fast_right.fbx b/interface/resources/avatar/animations/run_fast_right.fbx index ddf081bef6..dde651d18d 100644 Binary files a/interface/resources/avatar/animations/run_fast_right.fbx and b/interface/resources/avatar/animations/run_fast_right.fbx differ diff --git a/interface/resources/avatar/animations/settle_to_idle_small.fbx b/interface/resources/avatar/animations/settle_to_idle_small.fbx index 3d79d1930c..9161a95d95 100644 Binary files a/interface/resources/avatar/animations/settle_to_idle_small.fbx and b/interface/resources/avatar/animations/settle_to_idle_small.fbx differ diff --git a/interface/resources/avatar/animations/side_step_left.fbx b/interface/resources/avatar/animations/side_step_left.fbx index b74fe9074a..ee1169b8ad 100644 Binary files a/interface/resources/avatar/animations/side_step_left.fbx and b/interface/resources/avatar/animations/side_step_left.fbx differ diff --git a/interface/resources/avatar/animations/side_step_left_fast.fbx b/interface/resources/avatar/animations/side_step_left_fast.fbx index f4c997345f..a00949d749 100644 Binary files a/interface/resources/avatar/animations/side_step_left_fast.fbx and b/interface/resources/avatar/animations/side_step_left_fast.fbx differ diff --git a/interface/resources/avatar/animations/side_step_short_left.fbx b/interface/resources/avatar/animations/side_step_short_left.fbx index 8f55364b17..f3b4091420 100644 Binary files a/interface/resources/avatar/animations/side_step_short_left.fbx and b/interface/resources/avatar/animations/side_step_short_left.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_agree_acknowledge.fbx b/interface/resources/avatar/animations/sitting_emote_agree_acknowledge.fbx new file mode 100644 index 0000000000..368228ff4e Binary files /dev/null and b/interface/resources/avatar/animations/sitting_emote_agree_acknowledge.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_agree_cheer.fbx b/interface/resources/avatar/animations/sitting_emote_agree_cheer.fbx new file mode 100644 index 0000000000..74bd63f52d Binary files /dev/null and b/interface/resources/avatar/animations/sitting_emote_agree_cheer.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_agree_headnod.fbx b/interface/resources/avatar/animations/sitting_emote_agree_headnod.fbx index 655608fe55..ad72d31881 100644 Binary files a/interface/resources/avatar/animations/sitting_emote_agree_headnod.fbx and b/interface/resources/avatar/animations/sitting_emote_agree_headnod.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_agree_headnodyes.fbx b/interface/resources/avatar/animations/sitting_emote_agree_headnodyes.fbx index cfe90c45f0..2b24011b99 100644 Binary files a/interface/resources/avatar/animations/sitting_emote_agree_headnodyes.fbx and b/interface/resources/avatar/animations/sitting_emote_agree_headnodyes.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_agree_longheadnod.fbx b/interface/resources/avatar/animations/sitting_emote_agree_longheadnod.fbx index ead3a29fe6..43b160f96a 100644 Binary files a/interface/resources/avatar/animations/sitting_emote_agree_longheadnod.fbx and b/interface/resources/avatar/animations/sitting_emote_agree_longheadnod.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_clap02_all.fbx b/interface/resources/avatar/animations/sitting_emote_clap02_all.fbx new file mode 100644 index 0000000000..685af598a0 Binary files /dev/null and b/interface/resources/avatar/animations/sitting_emote_clap02_all.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_clap03_all.fbx b/interface/resources/avatar/animations/sitting_emote_clap03_all.fbx new file mode 100644 index 0000000000..c7ae67149e Binary files /dev/null and b/interface/resources/avatar/animations/sitting_emote_clap03_all.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_clap_all.fbx b/interface/resources/avatar/animations/sitting_emote_clap_all.fbx index 947ef4541a..09b09e0101 100644 Binary files a/interface/resources/avatar/animations/sitting_emote_clap_all.fbx and b/interface/resources/avatar/animations/sitting_emote_clap_all.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_disagree_disbelief.fbx b/interface/resources/avatar/animations/sitting_emote_disagree_disbelief.fbx new file mode 100644 index 0000000000..ad1a63019f Binary files /dev/null and b/interface/resources/avatar/animations/sitting_emote_disagree_disbelief.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_disagree_dismiss.fbx b/interface/resources/avatar/animations/sitting_emote_disagree_dismiss.fbx new file mode 100644 index 0000000000..9dbc57bb24 Binary files /dev/null and b/interface/resources/avatar/animations/sitting_emote_disagree_dismiss.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_disagree_drophead.fbx b/interface/resources/avatar/animations/sitting_emote_disagree_drophead.fbx index 239b242aab..daf847bdf5 100644 Binary files a/interface/resources/avatar/animations/sitting_emote_disagree_drophead.fbx and b/interface/resources/avatar/animations/sitting_emote_disagree_drophead.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_disagree_headshake.fbx b/interface/resources/avatar/animations/sitting_emote_disagree_headshake.fbx index 7c6f90ee89..fa7c55d535 100644 Binary files a/interface/resources/avatar/animations/sitting_emote_disagree_headshake.fbx and b/interface/resources/avatar/animations/sitting_emote_disagree_headshake.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_point_aimoffsets.fbx b/interface/resources/avatar/animations/sitting_emote_point_aimoffsets.fbx new file mode 100644 index 0000000000..eb31091a94 Binary files /dev/null and b/interface/resources/avatar/animations/sitting_emote_point_aimoffsets.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_point_all.fbx b/interface/resources/avatar/animations/sitting_emote_point_all.fbx index f850c8e9b3..455f8861b2 100644 Binary files a/interface/resources/avatar/animations/sitting_emote_point_all.fbx and b/interface/resources/avatar/animations/sitting_emote_point_all.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_raisehand02_all.fbx b/interface/resources/avatar/animations/sitting_emote_raisehand02_all.fbx new file mode 100644 index 0000000000..48c21e32bc Binary files /dev/null and b/interface/resources/avatar/animations/sitting_emote_raisehand02_all.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_raisehand03_all.fbx b/interface/resources/avatar/animations/sitting_emote_raisehand03_all.fbx new file mode 100644 index 0000000000..c6be3a3129 Binary files /dev/null and b/interface/resources/avatar/animations/sitting_emote_raisehand03_all.fbx differ diff --git a/interface/resources/avatar/animations/sitting_emote_raisehand_all.fbx b/interface/resources/avatar/animations/sitting_emote_raisehand_all.fbx index 7f1b2efea2..f60f49b2fc 100644 Binary files a/interface/resources/avatar/animations/sitting_emote_raisehand_all.fbx and b/interface/resources/avatar/animations/sitting_emote_raisehand_all.fbx differ diff --git a/interface/resources/avatar/animations/sitting_idle.fbx b/interface/resources/avatar/animations/sitting_idle.fbx index 63496f4673..877ce024d2 100644 Binary files a/interface/resources/avatar/animations/sitting_idle.fbx and b/interface/resources/avatar/animations/sitting_idle.fbx differ diff --git a/interface/resources/avatar/animations/sitting_idle02.fbx b/interface/resources/avatar/animations/sitting_idle02.fbx new file mode 100644 index 0000000000..8cf3d22fc6 Binary files /dev/null and b/interface/resources/avatar/animations/sitting_idle02.fbx differ diff --git a/interface/resources/avatar/animations/sitting_idle03.fbx b/interface/resources/avatar/animations/sitting_idle03.fbx index 17bba40cd7..0dee5b128d 100644 Binary files a/interface/resources/avatar/animations/sitting_idle03.fbx and b/interface/resources/avatar/animations/sitting_idle03.fbx differ diff --git a/interface/resources/avatar/animations/sitting_talk02.fbx b/interface/resources/avatar/animations/sitting_talk02.fbx index 7e6a071c0e..9742e69489 100644 Binary files a/interface/resources/avatar/animations/sitting_talk02.fbx and b/interface/resources/avatar/animations/sitting_talk02.fbx differ diff --git a/interface/resources/avatar/animations/sitting_talk03.fbx b/interface/resources/avatar/animations/sitting_talk03.fbx index 73dff2e900..8e0d45e954 100644 Binary files a/interface/resources/avatar/animations/sitting_talk03.fbx and b/interface/resources/avatar/animations/sitting_talk03.fbx differ diff --git a/interface/resources/avatar/animations/sitting_talk04.fbx b/interface/resources/avatar/animations/sitting_talk04.fbx index ee920672fa..6738e88b1d 100644 Binary files a/interface/resources/avatar/animations/sitting_talk04.fbx and b/interface/resources/avatar/animations/sitting_talk04.fbx differ diff --git a/interface/resources/avatar/animations/talk.fbx b/interface/resources/avatar/animations/talk.fbx index 6cc34049be..133a16641a 100644 Binary files a/interface/resources/avatar/animations/talk.fbx and b/interface/resources/avatar/animations/talk.fbx differ diff --git a/interface/resources/avatar/animations/talk02.fbx b/interface/resources/avatar/animations/talk02.fbx index a502ff261b..de30b7e9fe 100644 Binary files a/interface/resources/avatar/animations/talk02.fbx and b/interface/resources/avatar/animations/talk02.fbx differ diff --git a/interface/resources/avatar/animations/talk03.fbx b/interface/resources/avatar/animations/talk03.fbx index da95717540..9bcad7b4af 100644 Binary files a/interface/resources/avatar/animations/talk03.fbx and b/interface/resources/avatar/animations/talk03.fbx differ diff --git a/interface/resources/avatar/animations/talk04.fbx b/interface/resources/avatar/animations/talk04.fbx index 9e5505b969..2fb1811405 100644 Binary files a/interface/resources/avatar/animations/talk04.fbx and b/interface/resources/avatar/animations/talk04.fbx differ diff --git a/interface/resources/avatar/animations/talk_armsdown.fbx b/interface/resources/avatar/animations/talk_armsdown.fbx index e069811f7c..66d69e70e1 100644 Binary files a/interface/resources/avatar/animations/talk_armsdown.fbx and b/interface/resources/avatar/animations/talk_armsdown.fbx differ diff --git a/interface/resources/avatar/animations/talk_lefthand.fbx b/interface/resources/avatar/animations/talk_lefthand.fbx index d7fd1d5e07..08299fd14b 100644 Binary files a/interface/resources/avatar/animations/talk_lefthand.fbx and b/interface/resources/avatar/animations/talk_lefthand.fbx differ diff --git a/interface/resources/avatar/animations/talk_righthand.fbx b/interface/resources/avatar/animations/talk_righthand.fbx index 332afcc1e7..99dd70e308 100644 Binary files a/interface/resources/avatar/animations/talk_righthand.fbx and b/interface/resources/avatar/animations/talk_righthand.fbx differ diff --git a/interface/resources/avatar/animations/teleport.fbx b/interface/resources/avatar/animations/teleport.fbx index 99c950ced6..eeeb48596b 100644 Binary files a/interface/resources/avatar/animations/teleport.fbx and b/interface/resources/avatar/animations/teleport.fbx differ diff --git a/interface/resources/avatar/animations/turn_left.fbx b/interface/resources/avatar/animations/turn_left.fbx index b7cadf7a66..a58036499d 100644 Binary files a/interface/resources/avatar/animations/turn_left.fbx and b/interface/resources/avatar/animations/turn_left.fbx differ diff --git a/interface/resources/avatar/animations/turn_right.fbx b/interface/resources/avatar/animations/turn_right.fbx index 4ee3d52daf..c28ac2a62f 100644 Binary files a/interface/resources/avatar/animations/turn_right.fbx and b/interface/resources/avatar/animations/turn_right.fbx differ diff --git a/interface/resources/avatar/animations/walk_bwd.fbx b/interface/resources/avatar/animations/walk_bwd.fbx index 9daa769885..786ad67db9 100644 Binary files a/interface/resources/avatar/animations/walk_bwd.fbx and b/interface/resources/avatar/animations/walk_bwd.fbx differ diff --git a/interface/resources/avatar/animations/walk_bwd_fast.fbx b/interface/resources/avatar/animations/walk_bwd_fast.fbx index af22d0d0b0..cc872d7f09 100644 Binary files a/interface/resources/avatar/animations/walk_bwd_fast.fbx and b/interface/resources/avatar/animations/walk_bwd_fast.fbx differ diff --git a/interface/resources/avatar/animations/walk_fwd.fbx b/interface/resources/avatar/animations/walk_fwd.fbx index f86a8744c9..d128b4228e 100644 Binary files a/interface/resources/avatar/animations/walk_fwd.fbx and b/interface/resources/avatar/animations/walk_fwd.fbx differ diff --git a/interface/resources/avatar/animations/walk_fwd_fast.fbx b/interface/resources/avatar/animations/walk_fwd_fast.fbx index 8d2becf4b8..b387b237d3 100644 Binary files a/interface/resources/avatar/animations/walk_fwd_fast.fbx and b/interface/resources/avatar/animations/walk_fwd_fast.fbx differ diff --git a/interface/resources/avatar/animations/walk_left.fbx b/interface/resources/avatar/animations/walk_left.fbx index f35d4f6a77..a492c79e06 100644 Binary files a/interface/resources/avatar/animations/walk_left.fbx and b/interface/resources/avatar/animations/walk_left.fbx differ diff --git a/interface/resources/avatar/animations/walk_left_fast.fbx b/interface/resources/avatar/animations/walk_left_fast.fbx index 8414ee6805..7c502aae82 100644 Binary files a/interface/resources/avatar/animations/walk_left_fast.fbx and b/interface/resources/avatar/animations/walk_left_fast.fbx differ diff --git a/interface/resources/avatar/animations/walk_right.fbx b/interface/resources/avatar/animations/walk_right.fbx index 5fe005f96c..03c9705b3d 100644 Binary files a/interface/resources/avatar/animations/walk_right.fbx and b/interface/resources/avatar/animations/walk_right.fbx differ diff --git a/interface/resources/avatar/animations/walk_right_fast.fbx b/interface/resources/avatar/animations/walk_right_fast.fbx index 37b7bbbb62..5453399fd6 100644 Binary files a/interface/resources/avatar/animations/walk_right_fast.fbx and b/interface/resources/avatar/animations/walk_right_fast.fbx differ diff --git a/interface/resources/avatar/animations/walk_short_fwd.fbx b/interface/resources/avatar/animations/walk_short_fwd.fbx index b52371869b..63a44138e0 100644 Binary files a/interface/resources/avatar/animations/walk_short_fwd.fbx and b/interface/resources/avatar/animations/walk_short_fwd.fbx differ diff --git a/interface/resources/avatar/avatar-animation.json b/interface/resources/avatar/avatar-animation.json index 0131829471..fa3a020b23 100644 --- a/interface/resources/avatar/avatar-animation.json +++ b/interface/resources/avatar/avatar-animation.json @@ -588,976 +588,6 @@ "children": [ { "children": [ - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 271, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_talk02.fbx" - }, - "id": "seatedTalk02", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 252, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_talk03.fbx" - }, - "id": "seatedTalk03", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 442, - "loopFlag": true, - "startFrame": 0, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_talk04.fbx" - }, - "id": "seatedTalk04", - "type": "clip" - } - ], - "data": { - "currentState": "seatedTalk02", - "randomSwitchTimeMax": 12, - "randomSwitchTimeMin": 7, - "states": [ - { - "id": "seatedTalk02", - "interpDuration": 6, - "interpTarget": 6, - "priority": 1, - "resume": true, - "transitions": [ - ] - }, - { - "id": "seatedTalk03", - "interpDuration": 6, - "interpTarget": 6, - "priority": 1, - "resume": true, - "transitions": [ - ] - }, - { - "id": "seatedTalk04", - "interpDuration": 6, - "interpTarget": 6, - "priority": 1, - "resume": true, - "transitions": [ - ] - } - ] - }, - "id": "seatedTalk", - "type": "randomSwitchStateMachine" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 800, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_idle.fbx" - }, - "id": "seatedIdle01", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 800, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_idle03.fbx" - }, - "id": "seatedIdle03", - "type": "clip" - } - ], - "data": { - "currentState": "seatedIdle01", - "randomSwitchTimeMax": 20, - "randomSwitchTimeMin": 10, - "states": [ - { - "id": "seatedIdle01", - "interpDuration": 6, - "interpTarget": 6, - "priority": 1, - "resume": true, - "transitions": [ - ] - }, - { - "id": "seatedIdle03", - "interpDuration": 6, - "interpTarget": 6, - "priority": 1, - "resume": true, - "transitions": [ - ] - } - ] - }, - "id": "seatedIdle", - "type": "randomSwitchStateMachine" - } - ], - "data": { - "alpha": 1, - "alphaVar": "talkOverlayAlpha", - "boneSet": "upperBody" - }, - "id": "seatedTalkOverlay", - "type": "overlay" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 44, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_agree_headnod.fbx" - }, - "id": "seatedReactionPositiveHeadNod", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 78, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_agree_headnodyes.fbx" - }, - "id": "seatedReactionPositiveHeadNodYes", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 65, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_agree_longheadnod.fbx" - }, - "id": "seatedReactionPositiveLongHeadNod", - "type": "clip" - } - ], - "data": { - "currentState": "seatedReactionPositiveHeadNod", - "endFrame": 30, - "loopFlag": false, - "randomSwitchTimeMax": 12, - "randomSwitchTimeMin": 7, - "startFrame": 0, - "states": [ - { - "id": "seatedReactionPositiveHeadNod", - "interpDuration": 6, - "interpTarget": 6, - "priority": 1, - "resume": false, - "transitions": [ - ] - }, - { - "id": "seatedReactionPositiveHeadNodYes", - "interpDuration": 6, - "interpTarget": 6, - "priority": 1, - "resume": false, - "transitions": [ - ] - }, - { - "id": "seatedReactionPositiveLongHeadNod", - "interpDuration": 6, - "interpTarget": 6, - "priority": 1, - "resume": false, - "transitions": [ - ] - } - ], - "timeScale": 1, - "triggerRandomSwitch": "", - "url": "qrc:///avatar/animations/sitting_idle.fbx" - }, - "id": "seatedReactionPositive", - "type": "randomSwitchStateMachine" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 64, - "loopFlag": false, - "startFrame": 0, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_disagree_headshake.fbx" - }, - "id": "seatedReactionNegativeDisagreeHeadshake", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 158, - "loopFlag": false, - "startFrame": 0, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_disagree_drophead.fbx" - }, - "id": "seatedReactionNegativeDisagreeDropHead", - "type": "clip" - } - ], - "data": { - "currentState": "seatedReactionNegativeDisagreeHeadshake", - "endFrame": 30, - "loopFlag": false, - "randomSwitchTimeMax": 10, - "randomSwitchTimeMin": 1, - "startFrame": 0, - "states": [ - { - "easingType": "easeInOutQuad", - "id": "seatedReactionNegativeDisagreeHeadshake", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "seatedReactionNegativeDisagreeDropHead", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - ] - } - ], - "timeScale": 1, - "triggerRandomSwitch": "", - "url": "qrc:///avatar/animations/sitting_idle.fbx" - }, - "id": "seatedReactionNegative", - "type": "randomSwitchStateMachine" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 32, - "loopFlag": false, - "startFrame": 0, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_raisehand_all.fbx" - }, - "id": "seatedReactionRaiseHandIntro", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 345, - "loopFlag": true, - "startFrame": 32, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_raisehand_all.fbx" - }, - "id": "seatedReactionRaiseHandLoop", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 400, - "loopFlag": false, - "startFrame": 345, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_raisehand_all.fbx" - }, - "id": "seatedReactionRaiseHandOutro", - "type": "clip" - } - ], - "data": { - "currentState": "seatedReactionRaiseHandIntro", - "randomSwitchTimeMax": 10, - "randomSwitchTimeMin": 1, - "states": [ - { - "easingType": "easeInOutQuad", - "id": "seatedReactionRaiseHandIntro", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - { - "randomSwitchState": "seatedReactionRaiseHandLoop", - "var": "seatedReactionRaiseHandIntroOnDone" - } - ] - }, - { - "id": "seatedReactionRaiseHandLoop", - "interpDuration": 5, - "interpTarget": 5, - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "seatedReactionRaiseHandOutro", - "var": "reactionRaiseHandDisabled" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "seatedReactionRaiseHandOutro", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "seatedReactionRaiseHandLoop", - "var": "reactionRaiseHandEnabled" - } - ] - } - ], - "triggerRandomSwitch": "" - }, - "id": "seatedReactionRaiseHand", - "type": "randomSwitchStateMachine" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 12, - "loopFlag": false, - "startFrame": 0, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_clap_all.fbx" - }, - "id": "seatedReactionApplaudIntro", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 76, - "loopFlag": true, - "startFrame": 12, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_clap_all.fbx" - }, - "id": "seatedReactionApplaudLoop", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 99, - "loopFlag": false, - "startFrame": 76, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_clap_all.fbx" - }, - "id": "seatedReactionApplaudOutro", - "type": "clip" - } - ], - "data": { - "currentState": "seatedReactionApplaudIntro", - "randomSwitchTimeMax": 10, - "randomSwitchTimeMin": 1, - "states": [ - { - "easingType": "easeInOutQuad", - "id": "seatedReactionApplaudIntro", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - { - "randomSwitchState": "seatedReactionApplaudLoop", - "var": "seatedReactionApplaudIntroOnDone" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "seatedReactionApplaudLoop", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "seatedReactionApplaudOutro", - "var": "reactionApplaudDisabled" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "seatedReactionApplaudOutro", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "seatedReactionApplaudLoop", - "var": "reactionApplaudEnabled" - } - ] - } - ], - "triggerRandomSwitch": "" - }, - "id": "seatedReactionApplaud", - "type": "randomSwitchStateMachine" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 22, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_point_all.fbx" - }, - "id": "seatedReactionPointIntro", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 43, - "loopFlag": true, - "startFrame": 22, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_point_all.fbx" - }, - "id": "seatedReactionPointLoop", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 71, - "loopFlag": false, - "startFrame": 43, - "timeScale": 1, - "url": "qrc:///avatar/animations/sitting_emote_point_all.fbx" - }, - "id": "seatedReactionPointOutro", - "type": "clip" - } - ], - "data": { - "currentState": "seatedReactionPointIntro", - "randomSwitchTimeMax": 10, - "randomSwitchTimeMin": 1, - "states": [ - { - "easingType": "easeInOutQuad", - "id": "seatedReactionPointIntro", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - { - "randomSwitchState": "seatedReactionPointLoop", - "var": "seatedReactionPointIntroOnDone" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "seatedReactionPointLoop", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "seatedReactionPointOutro", - "var": "reactionPointDisabled" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "seatedReactionPointOutro", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "seatedReactionPointLoop", - "var": "reactionPointEnabled" - } - ] - } - ], - "triggerRandomSwitch": "" - }, - "id": "seatedReactionPoint", - "type": "randomSwitchStateMachine" - } - ], - "data": { - "currentState": "seatedTalkOverlay", - "states": [ - { - "easingType": "easeInOutQuad", - "id": "seatedTalkOverlay", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "seatedReactionPositive", - "var": "reactionPositiveTrigger" - }, - { - "state": "seatedReactionNegative", - "var": "reactionNegativeTrigger" - }, - { - "state": "seatedReactionRaiseHand", - "var": "reactionRaiseHandEnabled" - }, - { - "state": "seatedReactionApplaud", - "var": "reactionApplaudEnabled" - }, - { - "state": "seatedReactionPoint", - "var": "reactionPointEnabled" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "seatedReactionPositive", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "seatedTalkOverlay", - "var": "seatedReactionPositiveHeadNodOnDone" - }, - { - "state": "seatedTalkOverlay", - "var": "seatedReactionPositiveHeadNodYesOnDone" - }, - { - "state": "seatedTalkOverlay", - "var": "seatedReactionPositiveLongHeadNodOnDone" - }, - { - "state": "seatedReactionNegative", - "var": "reactionNegativeTrigger" - }, - { - "state": "seatedReactionRaiseHand", - "var": "reactionRaiseHandEnabled" - }, - { - "state": "seatedReactionApplaud", - "var": "reactionApplaudEnabled" - }, - { - "state": "seatedReactionPoint", - "var": "reactionPointEnabled" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "seatedReactionNegative", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "seatedReactionPositive", - "var": "reactionPositiveTrigger" - }, - { - "state": "seatedTalkOverlay", - "var": "seatedReactionNegativeDisagreeHeadshakeOnDone" - }, - { - "state": "seatedTalkOverlay", - "var": "seatedReactionNegativeDisagreeDropHeadOnDone" - }, - { - "state": "seatedReactionRaiseHand", - "var": "reactionRaiseHandEnabled" - }, - { - "state": "seatedReactionApplaud", - "var": "reactionApplaudEnabled" - }, - { - "state": "seatedReactionPoint", - "var": "reactionPointEnabled" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "seatedReactionRaiseHand", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "seatedReactionNegative", - "var": "reactionNegativeTrigger" - }, - { - "state": "seatedReactionPositive", - "var": "reactionPositiveTrigger" - }, - { - "state": "seatedTalkOverlay", - "var": "reactionRaiseHandDisabled" - }, - { - "state": "seatedReactionApplaud", - "var": "reactionApplaudEnabled" - }, - { - "state": "seatedReactionPoint", - "var": "reactionPointEnabled" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "seatedReactionApplaud", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "seatedReactionNegative", - "var": "reactionNegativeTrigger" - }, - { - "state": "seatedReactionPositive", - "var": "reactionPositiveTrigger" - }, - { - "state": "seatedReactionRaiseHand", - "var": "reactionRaiseHandEnabled" - }, - { - "state": "seatedTalkOverlay", - "var": "reactionApplaudDisabled" - }, - { - "state": "seatedReactionPoint", - "var": "reactionPointEnabled" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "seatedReactionPoint", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "seatedReactionNegative", - "var": "reactionNegativeTrigger" - }, - { - "state": "seatedReactionPositive", - "var": "reactionPositiveTrigger" - }, - { - "state": "seatedReactionRaiseHand", - "var": "reactionRaiseHandEnabled" - }, - { - "state": "seatedReactionApplaud", - "var": "reactionApplaudEnabled" - }, - { - "state": "seatedTalkOverlay", - "var": "reactionPointDisabled" - } - ] - } - ] - }, - "id": "seated", - "type": "stateMachine" - }, - { - "children": [ - { - "children": [ - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 500, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/talk.fbx" - }, - "id": "talk", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 325, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/talk02.fbx" - }, - "id": "talk02", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 300, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/talk03.fbx" - }, - "id": "talk03", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 500, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/talk04.fbx" - }, - "id": "talk04", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 215, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/talk_armsdown.fbx" - }, - "id": "talk_armsdown", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 500, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/talk_lefthand.fbx" - }, - "id": "talk_lefthand", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 502, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/talk_righthand.fbx" - }, - "id": "talk_righthand", - "type": "clip" - } - ], - "data": { - "currentState": "talk", - "randomSwitchTimeMax": 12, - "randomSwitchTimeMin": 7, - "states": [ - { - "easingType": "easeInOutQuad", - "id": "talk", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.33, - "resume": true, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "talk02", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.33, - "resume": true, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "talk03", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.33, - "resume": true, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "talk04", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.33, - "resume": true, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "talk_armsdown", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.33, - "resume": true, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "talk_lefthand", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.33, - "resume": true, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "talk_righthand", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.33, - "resume": true, - "transitions": [ - ] - } - ], - "triggerRandomSwitch": "idleTalkSwitch" - }, - "id": "idleTalk", - "type": "randomSwitchStateMachine" - }, { "children": [ { @@ -1566,26 +596,99 @@ "children": [ ], "data": { - "endFrame": 300, + "endFrame": 271, "loopFlag": true, "startFrame": 1, "timeScale": 1, - "url": "qrc:///avatar/animations/idle.fbx" + "url": "qrc:///avatar/animations/sitting_talk02.fbx" }, - "id": "masterIdle1", + "id": "seatedTalk02", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 400, + "endFrame": 252, "loopFlag": true, "startFrame": 1, - "timeScale": 0.75, - "url": "qrc:///avatar/animations/idle02.fbx" + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_talk03.fbx" }, - "id": "masterIdle2", + "id": "seatedTalk03", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 442, + "loopFlag": true, + "startFrame": 0, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_talk04.fbx" + }, + "id": "seatedTalk04", + "type": "clip" + } + ], + "data": { + "currentState": "seatedTalk02", + "randomSwitchTimeMax": 12, + "randomSwitchTimeMin": 7, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "seatedTalk02", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 1, + "resume": true, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedTalk03", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 1, + "resume": true, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedTalk04", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 1, + "resume": true, + "transitions": [ + ] + } + ], + "triggerRandomSwitch": "seatedTalkSwitch" + }, + "id": "seatedTalk", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 800, + "loopFlag": true, + "startFrame": 0, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_idle.fbx" + }, + "id": "seatedIdle01", "type": "clip" }, { @@ -1594,893 +697,207 @@ "data": { "endFrame": 800, "loopFlag": true, - "startFrame": 1, + "startFrame": 0, "timeScale": 1, - "url": "qrc:///avatar/animations/idle03.fbx" + "url": "qrc:///avatar/animations/sitting_idle02.fbx" }, - "id": "masterIdle3", + "id": "seatedIdle02", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 902, + "endFrame": 800, "loopFlag": true, - "startFrame": 1, + "startFrame": 0, "timeScale": 1, - "url": "qrc:///avatar/animations/idle04.fbx" + "url": "qrc:///avatar/animations/sitting_idle03.fbx" }, - "id": "masterIdle4", + "id": "seatedIdle03", "type": "clip" } ], "data": { - "currentState": "masterIdle1", - "randomSwitchTimeMax": 30, + "currentState": "seatedIdle01", + "randomSwitchTimeMax": 20, "randomSwitchTimeMin": 10, "states": [ { "easingType": "easeInOutQuad", - "id": "masterIdle1", - "interpDuration": 30, - "interpTarget": 30, + "id": "seatedIdle01", + "interpDuration": 15, + "interpTarget": 15, "interpType": "evaluateBoth", - "priority": 0.25, + "priority": 1, "resume": true, "transitions": [ ] }, { "easingType": "easeInOutQuad", - "id": "masterIdle2", - "interpDuration": 30, - "interpTarget": 30, + "id": "seatedIdle02", + "interpDuration": 15, + "interpTarget": 15, "interpType": "evaluateBoth", - "priority": 0.25, + "priority": 1, "resume": true, "transitions": [ ] }, { "easingType": "easeInOutQuad", - "id": "masterIdle3", - "interpDuration": 30, - "interpTarget": 30, + "id": "seatedIdle03", + "interpDuration": 15, + "interpTarget": 15, "interpType": "evaluateBoth", - "priority": 0.25, - "resume": true, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "masterIdle4", - "interpDuration": 30, - "interpTarget": 30, - "interpType": "evaluateBoth", - "priority": 0.25, + "priority": 1, "resume": true, "transitions": [ ] } ], - "triggerRandomSwitch": "masterIdleSwitch" + "triggerRandomSwitch": "seatedIdleSwitch" }, - "id": "masterIdle", - "type": "randomSwitchStateMachine" - }, - { - "children": [ - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 91, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle_once_slownod.fbx" - }, - "id": "idle_once_slownod", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 154, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle_once_headtilt.fbx" - }, - "id": "idle_once_headtilt", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 491, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle_once_shiftheelpivot.fbx" - }, - "id": "idle_once_shiftheelpivot", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 1620, - "loopFlag": false, - "startFrame": 1, - "timeScale": 0.7, - "url": "qrc:///avatar/animations/idleWS_all.fbx" - }, - "id": "idleWS_all", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 324, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle_once_lookaround.fbx" - }, - "id": "idle_once_lookaround", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 169, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle_once_neckstretch.fbx" - }, - "id": "idle_once_neckstretch", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 375, - "loopFlag": false, - "startFrame": 1, - "timeScale": 0.7, - "url": "qrc:///avatar/animations/idle_once_lookleftright.fbx" - }, - "id": "idle_once_lookleftright", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 429, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle_once_fidget.fbx" - }, - "id": "idle_once_fidget", - "type": "clip" - } - ], - "data": { - "currentState": "idle_once_slownod", - "states": [ - { - "easingType": "easeInOutQuad", - "id": "idle_once_slownod", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.2, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "idle_once_headtilt", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.2, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "idle_once_shiftheelpivot", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.2, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "idleWS_all", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.2, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "idle_once_lookaround", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.2, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "idle_once_neckstretch", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.2, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "idle_once_lookleftright", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.2, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "idle_once_fidget", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": 0.2, - "resume": false, - "transitions": [ - ] - } - ] - }, - "id": "movement", - "type": "randomSwitchStateMachine" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 80, - "loopFlag": false, - "startFrame": 1, - "startFrameVar": "", - "timeScale": 0.65, - "url": "qrc:///avatar/animations/idle_LFF_all.fbx" - }, - "id": "transitionToAltIdle1", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 80, - "loopFlag": false, - "startFrame": 1, - "timeScale": 0.65, - "url": "qrc:///avatar/animations/idle_RFF_all.fbx" - }, - "id": "transitionToAltIdle2", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 388, - "loopFlag": true, - "startFrame": 80, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle_LFF_all.fbx" - }, - "id": "altIdle1", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 388, - "loopFlag": true, - "startFrame": 80, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle_RFF_all.fbx" - }, - "id": "altIdle2", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 472, - "loopFlag": false, - "startFrame": 388, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle_LFF_all.fbx" - }, - "id": "alt1ToMasterIdle", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 453, - "loopFlag": false, - "startFrame": 388, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle_RFF_all.fbx" - }, - "id": "alt2ToMasterIdle", - "type": "clip" - } - ], - "data": { - "currentState": "transitionToAltIdle1", - "states": [ - { - "easingType": "easeInOutQuad", - "id": "transitionToAltIdle1", - "interpDuration": 20, - "interpTarget": 20, - "interpType": "evaluateBoth", - "priority": 0.5, - "resume": false, - "transitions": [ - { - "randomSwitchState": "altIdle1", - "var": "transitionToAltIdle1OnDone" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "transitionToAltIdle2", - "interpDuration": 20, - "interpTarget": 20, - "interpType": "evaluateBoth", - "priority": 0.5, - "resume": false, - "transitions": [ - { - "randomSwitchState": "altIdle2", - "var": "transitionToAltIdle2OnDone" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "altIdle1", - "interpDuration": 1, - "interpTarget": 1, - "interpType": "evaluateBoth", - "priority": -1, - "resume": false, - "transitions": [ - { - "randomSwitchState": "alt1ToMasterIdle", - "var": "finishAltIdle2" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "altIdle2", - "interpDuration": 1, - "interpTarget": 1, - "interpType": "evaluateBoth", - "priority": -1, - "resume": false, - "transitions": [ - { - "randomSwitchState": "alt2ToMasterIdle", - "var": "finishAltIdle2" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "alt1ToMasterIdle", - "interpDuration": 24, - "interpTarget": 24, - "interpType": "evaluateBoth", - "priority": -1, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "alt2ToMasterIdle", - "interpDuration": 24, - "interpTarget": 24, - "interpType": "evaluateBoth", - "priority": -1, - "resume": false, - "transitions": [ - ] - } - ], - "transitionVar": "finishAltIdle2", - "triggerTimeMax": 60, - "triggerTimeMin": 10 - }, - "id": "alternateIdle", - "type": "randomSwitchStateMachine" - } - ], - "data": { - "currentState": "movement", - "states": [ - { - "easingType": "easeInOutQuad", - "id": "movement", - "interpDuration": 30, - "interpTarget": 30, - "interpType": "evaluateBoth", - "priority": 0.6, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "alternateIdle", - "interpDuration": 30, - "interpTarget": 30, - "interpType": "evaluateBoth", - "priority": 0.4, - "resume": false, - "transitions": [ - ] - } - ] - }, - "id": "fidget", + "id": "seatedIdle", "type": "randomSwitchStateMachine" } ], "data": { - "currentState": "masterIdle", - "states": [ - { - "easingType": "easeInOutQuad", - "id": "masterIdle", - "interpDuration": 30, - "interpTarget": 30, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - { - "randomSwitchState": "fidget", - "var": "timeToFidget" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "fidget", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "priority": -1, - "resume": false, - "transitions": [ - { - "randomSwitchState": "masterIdle", - "var": "idle_once_slownodOnDone" - }, - { - "randomSwitchState": "masterIdle", - "var": "idle_once_headtiltOnDone" - }, - { - "randomSwitchState": "masterIdle", - "var": "idle_once_shiftheelpivotOnDone" - }, - { - "randomSwitchState": "masterIdle", - "var": "idleWS_allOnDone" - }, - { - "randomSwitchState": "masterIdle", - "var": "idle_once_lookaroundOnDone" - }, - { - "randomSwitchState": "masterIdle", - "var": "idle_once_neckstretchOnDone" - }, - { - "randomSwitchState": "masterIdle", - "var": "idle_once_lookleftrightOnDone" - }, - { - "randomSwitchState": "masterIdle", - "var": "idle_once_fidgetOnDone" - }, - { - "randomSwitchState": "masterIdle", - "var": "alt1ToMasterIdleOnDone" - }, - { - "randomSwitchState": "masterIdle", - "var": "alt2ToMasterIdleOnDone" - } - ] - } - ], - "transitionVar": "timeToFidget", - "triggerTimeMax": 50, - "triggerTimeMin": 10 + "alpha": 1, + "alphaVar": "talkOverlayAlpha", + "boneSet": "upperBody" }, - "id": "idleStand", - "type": "randomSwitchStateMachine" - } - ], - "data": { - "alpha": 1, - "alphaVar": "talkOverlayAlpha", - "boneSet": "upperBody" - }, - "id": "idleTalkOverlay", - "type": "overlay" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 58, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_agree_acknowledge.fbx" - }, - "id": "positiveAcknowledge", - "type": "clip" + "id": "seatedTalkOverlay", + "type": "overlay" }, - { - "children": [ - ], - "data": { - "endFrame": 55, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_agree_headnod.fbx" - }, - "id": "positiveHeadNod", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 78, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_agree_headnodyes.fbx" - }, - "id": "positiveHeadNodYes", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 66, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_agree_longheadnod.fbx" - }, - "id": "positiveLongHeadNod", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 85, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_agree_thoughtfulheadnod.fbx" - }, - "id": "positiveThoughtfulHeadNod", - "type": "clip" - } - ], - "data": { - "currentState": "positiveAcknowledge", - "randomSwitchTimeMax": 10, - "randomSwitchTimeMin": 1, - "states": [ - { - "easingType": "easeInOutQuad", - "id": "positiveAcknowledge", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "positiveHeadNod", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "positiveHeadNodYes", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "positiveLongHeadNod", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "positiveThoughtfulHeadNod", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 0.33, - "resume": false, - "transitions": [ - ] - } - ], - "triggerRandomSwitch": "" - }, - "id": "reactionPositive", - "type": "randomSwitchStateMachine" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 72, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_disagree_annoyedheadshake.fbx" - }, - "id": "negativeAnnoyedHeadshake", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 92, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_disagree_thoughtfulheadshake.fbx" - }, - "id": "negativeThoughtfulHeadshake", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 158, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_disagree_drophead.fbx" - }, - "id": "negativeDropHead", - "type": "clip" - } - ], - "data": { - "currentState": "negativeAnnoyedHeadshake", - "randomSwitchTimeMax": 10, - "randomSwitchTimeMin": 1, - "states": [ - { - "easingType": "easeInOutQuad", - "id": "negativeAnnoyedHeadshake", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "negativeThoughtfulHeadshake", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - ] - }, - { - "easingType": "easeInOutQuad", - "id": "negativeDropHead", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - ] - } - ] - }, - "id": "reactionNegative", - "type": "randomSwitchStateMachine" - }, - { - "children": [ { "children": [ { "children": [ ], "data": { - "endFrame": 18, + "endFrame": 44, "loopFlag": false, "startFrame": 1, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_raisehand01_all.fbx" + "url": "qrc:///avatar/animations/sitting_emote_agree_headnod.fbx" }, - "id": "raiseHand01Intro", + "id": "seatedReactionPositiveHeadNod", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 378, - "loopFlag": true, - "startFrame": 18, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_raisehand01_all.fbx" - }, - "id": "raiseHand01Loop", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 435, + "endFrame": 78, "loopFlag": false, - "startFrame": 378, + "startFrame": 1, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_raisehand01_all.fbx" + "url": "qrc:///avatar/animations/sitting_emote_agree_headnodyes.fbx" }, - "id": "raiseHand01Outro", + "id": "seatedReactionPositiveHeadNodYes", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 65, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_agree_longheadnod.fbx" + }, + "id": "seatedReactionPositiveLongHeadNod", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 78, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_agree_cheer.fbx" + }, + "id": "seatedReactionPositiveCheer", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 64, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_agree_acknowledge.fbx" + }, + "id": "seatedReactionPositiveAcknowledge", "type": "clip" } ], "data": { - "currentState": "raiseHand01Intro", - "randomSwitchTimeMax": 10, - "randomSwitchTimeMin": 1, + "currentState": "seatedReactionPositiveHeadNod", + "endFrame": 30, + "loopFlag": false, + "randomSwitchTimeMax": 12, + "randomSwitchTimeMin": 7, + "startFrame": 0, "states": [ { - "easingType": "easeInOutQuad", - "id": "raiseHand01Intro", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", + "id": "seatedReactionPositiveHeadNod", + "interpDuration": 1, + "interpTarget": 1, "priority": 1, "resume": false, "transitions": [ - { - "randomSwitchState": "raiseHand01Loop", - "var": "raiseHand01IntroOnDone" - } ] }, { - "id": "raiseHand01Loop", - "interpDuration": 5, - "interpTarget": 5, - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "raiseHand01Outro", - "var": "reactionRaiseHandDisabled" - } - ] - }, - { - "id": "raiseHand01Outro", + "id": "seatedReactionPositiveHeadNodYes", "interpDuration": 1, "interpTarget": 1, - "priority": 0, + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "id": "seatedReactionPositiveLongHeadNod", + "interpDuration": 1, + "interpTarget": 1, + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "id": "seatedReactionPositiveCheer", + "interpDuration": 1, + "interpTarget": 1, + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "id": "seatedReactionPositiveAcknowledge", + "interpDuration": 1, + "interpTarget": 1, + "priority": 1, "resume": false, "transitions": [ - { - "randomSwitchState": "raiseHand01Loop", - "var": "reactionRaiseHandEnabled" - } ] } ], - "triggerRandomSwitch": "" + "timeScale": 1, + "triggerRandomSwitch": "", + "url": "qrc:///avatar/animations/sitting_idle.fbx" }, - "id": "raiseHand01", + "id": "seatedReactionPositive", "type": "randomSwitchStateMachine" }, { @@ -2489,92 +906,113 @@ "children": [ ], "data": { - "endFrame": 19, + "endFrame": 64, + "loopFlag": false, + "startFrame": 0, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_disagree_headshake.fbx" + }, + "id": "seatedReactionNegativeDisagreeHeadshake", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 99, + "loopFlag": false, + "startFrame": 0, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_disagree_drophead.fbx" + }, + "id": "seatedReactionNegativeDisagreeDropHead", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 124, "loopFlag": false, "startFrame": 1, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_raisehand03_all.fbx" + "url": "qrc:///avatar/animations/sitting_emote_disagree_disbelief.fbx" }, - "id": "raiseHand03Intro", + "id": "seatedReactionNegativeDisagreeDisbelief", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 237, - "loopFlag": true, - "startFrame": 19, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_raisehand03_all.fbx" - }, - "id": "raiseHand03Loop", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 300, + "endFrame": 70, "loopFlag": false, - "startFrame": 237, + "startFrame": 0, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_raisehand03_all.fbx" + "url": "qrc:///avatar/animations/sitting_emote_disagree_dismiss.fbx" }, - "id": "raiseHand03Outro", + "id": "seatedReactionNegativeDisagreeDismiss", "type": "clip" } ], "data": { - "currentState": "raiseHand03Intro", + "currentState": "seatedReactionNegativeDisagreeHeadshake", + "endFrame": 30, + "loopFlag": false, "randomSwitchTimeMax": 10, "randomSwitchTimeMin": 1, + "startFrame": 0, "states": [ { "easingType": "easeInOutQuad", - "id": "raiseHand03Intro", - "interpDuration": 18, - "interpTarget": 18, + "id": "seatedReactionNegativeDisagreeHeadshake", + "interpDuration": 1, + "interpTarget": 1, "interpType": "evaluateBoth", "priority": 1, "resume": false, "transitions": [ - { - "randomSwitchState": "raiseHand03Loop", - "var": "raiseHand03IntroOnDone" - } ] }, { - "id": "raiseHand03Loop", - "interpDuration": 5, - "interpTarget": 5, - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "raiseHand03Outro", - "var": "reactionRaiseHandDisabled" - } - ] - }, - { - "id": "raiseHand03Outro", + "easingType": "easeInOutQuad", + "id": "seatedReactionNegativeDisagreeDropHead", "interpDuration": 1, "interpTarget": 1, - "priority": 0, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionNegativeDisagreeDisbelief", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionNegativeDisagreeDismiss", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, "resume": false, "transitions": [ - { - "randomSwitchState": "raiseHand03Loop", - "var": "reactionRaiseHandEnabled" - } ] } ], - "triggerRandomSwitch": "" + "timeScale": 1, + "triggerRandomSwitch": "", + "url": "qrc:///avatar/animations/sitting_idle.fbx" }, - "id": "raiseHand03", + "id": "seatedReactionNegative", "type": "randomSwitchStateMachine" }, { @@ -2585,11 +1023,11 @@ "data": { "endFrame": 32, "loopFlag": false, - "startFrame": 1, + "startFrame": 0, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_raisehand04_all.fbx" + "url": "qrc:///avatar/animations/sitting_emote_raisehand_all.fbx" }, - "id": "raiseHand04Intro", + "id": "seatedReactionRaiseHandIntro", "type": "clip" }, { @@ -2600,9 +1038,9 @@ "loopFlag": true, "startFrame": 32, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_raisehand04_all.fbx" + "url": "qrc:///avatar/animations/sitting_emote_raisehand_all.fbx" }, - "id": "raiseHand04Loop", + "id": "seatedReactionRaiseHandLoop", "type": "clip" }, { @@ -2613,54 +1051,222 @@ "loopFlag": false, "startFrame": 345, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_raisehand04_all.fbx" + "url": "qrc:///avatar/animations/sitting_emote_raisehand_all.fbx" }, - "id": "raiseHand04Outro", + "id": "seatedReactionRaiseHandOutro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 18, + "loopFlag": false, + "startFrame": 0, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_raisehand02_all.fbx" + }, + "id": "seatedReactionRaiseHand02Intro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 378, + "loopFlag": true, + "startFrame": 18, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_raisehand02_all.fbx" + }, + "id": "seatedReactionRaiseHand02Loop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 435, + "loopFlag": false, + "startFrame": 378, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_raisehand02_all.fbx" + }, + "id": "seatedReactionRaiseHand02Outro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 15, + "loopFlag": false, + "startFrame": 0, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_raisehand03_all.fbx" + }, + "id": "seatedReactionRaiseHand03Intro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 233, + "loopFlag": true, + "mirrorFlag": false, + "startFrame": 15, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_raisehand03_all.fbx" + }, + "id": "seatedReactionRaiseHand03Loop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 296, + "loopFlag": false, + "mirrorFlag": false, + "startFrame": 233, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_raisehand03_all.fbx" + }, + "id": "seatedReactionRaiseHand03Outro", "type": "clip" } ], "data": { - "currentState": "raiseHand04Intro", + "currentState": "seatedReactionRaiseHandIntro", "randomSwitchTimeMax": 10, "randomSwitchTimeMin": 1, "states": [ { "easingType": "easeInOutQuad", - "id": "raiseHand04Intro", - "interpDuration": 18, - "interpTarget": 18, + "id": "seatedReactionRaiseHandIntro", + "interpDuration": 8, + "interpTarget": 9, "interpType": "evaluateBoth", "priority": 1, "resume": false, "transitions": [ { - "randomSwitchState": "raiseHand04Loop", - "var": "raiseHand04IntroOnDone" + "randomSwitchState": "seatedReactionRaiseHandLoop", + "var": "seatedReactionRaiseHandIntroOnDone" } ] }, { - "id": "raiseHand04Loop", - "interpDuration": 5, - "interpTarget": 5, - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "raiseHand04Outro", - "var": "reactionRaiseHandDisabled" - } - ] - }, - { - "id": "raiseHand04Outro", + "id": "seatedReactionRaiseHandLoop", "interpDuration": 1, "interpTarget": 1, "priority": 0, "resume": false, "transitions": [ { - "randomSwitchState": "raiseHand04Loop", + "randomSwitchState": "seatedReactionRaiseHandOutro", + "var": "reactionRaiseHandDisabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionRaiseHandOutro", + "interpDuration": 12, + "interpTarget": 12, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionRaiseHandLoop", + "var": "reactionRaiseHandEnabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionRaiseHand02Intro", + "interpDuration": 8, + "interpTarget": 8, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionRaiseHand02Loop", + "var": "seatedReactionRaiseHand02IntroOnDone" + } + ] + }, + { + "id": "seatedReactionRaiseHand02Loop", + "interpDuration": 1, + "interpTarget": 1, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionRaiseHand02Outro", + "var": "reactionRaiseHandDisabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionRaiseHand02Outro", + "interpDuration": 12, + "interpTarget": 12, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionRaiseHand02Loop", + "var": "reactionRaiseHandEnabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionRaiseHand03Intro", + "interpDuration": 8, + "interpTarget": 8, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionRaiseHand03Loop", + "var": "seatedReactionRaiseHand03IntroOnDone" + } + ] + }, + { + "id": "seatedReactionRaiseHand03Loop", + "interpDuration": 1, + "interpTarget": 1, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionRaiseHand03Outro", + "var": "reactionRaiseHandDisabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionRaiseHand03Outro", + "interpDuration": 12, + "interpTarget": 12, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionRaiseHand03Loop", "var": "reactionRaiseHandEnabled" } ] @@ -2668,52 +1274,773 @@ ], "triggerRandomSwitch": "" }, - "id": "raiseHand04", + "id": "seatedReactionRaiseHand", "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 12, + "loopFlag": false, + "startFrame": 0, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_clap_all.fbx" + }, + "id": "seatedReactionApplaudIntro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 76, + "loopFlag": true, + "startFrame": 12, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_clap_all.fbx" + }, + "id": "seatedReactionApplaudLoop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 99, + "loopFlag": false, + "startFrame": 76, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_clap_all.fbx" + }, + "id": "seatedReactionApplaudOutro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 12, + "loopFlag": false, + "startFrame": 0, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_clap02_all.fbx" + }, + "id": "seatedReactionApplaud02Intro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 112, + "loopFlag": true, + "startFrame": 12, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_clap02_all.fbx" + }, + "id": "seatedReactionApplaud02Loop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 132, + "loopFlag": false, + "startFrame": 112, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_clap02_all.fbx" + }, + "id": "seatedReactionApplaud02Outro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 17, + "loopFlag": false, + "startFrame": 0, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_clap03_all.fbx" + }, + "id": "seatedReactionApplaud03Intro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 111, + "loopFlag": true, + "startFrame": 17, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_clap03_all.fbx" + }, + "id": "seatedReactionApplaud03Loop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 136, + "loopFlag": false, + "startFrame": 111, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_clap03_all.fbx" + }, + "id": "seatedReactionApplaud03Outro", + "type": "clip" + } + ], + "data": { + "currentState": "seatedReactionApplaudIntro", + "randomSwitchTimeMax": 10, + "randomSwitchTimeMin": 1, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "seatedReactionApplaudIntro", + "interpDuration": 8, + "interpTarget": 8, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionApplaudLoop", + "var": "seatedReactionApplaudIntroOnDone" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionApplaudLoop", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionApplaudOutro", + "var": "reactionApplaudDisabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionApplaudOutro", + "interpDuration": 12, + "interpTarget": 12, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionApplaudLoop", + "var": "reactionApplaudEnabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionApplaud02Intro", + "interpDuration": 8, + "interpTarget": 8, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionApplaud02Loop", + "var": "seatedReactionApplaud02IntroOnDone" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionApplaud02Loop", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionApplaud02Outro", + "var": "reactionApplaudDisabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionApplaud02Outro", + "interpDuration": 12, + "interpTarget": 12, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionApplaud02Loop", + "var": "reactionApplaudEnabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionApplaud03Intro", + "interpDuration": 8, + "interpTarget": 8, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionApplaud03Loop", + "var": "seatedReactionApplaud03IntroOnDone" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionApplaud03Loop", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionApplaud03Outro", + "var": "reactionApplaudDisabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionApplaud03Outro", + "interpDuration": 12, + "interpTarget": 12, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionApplaud03Loop", + "var": "reactionApplaudEnabled" + } + ] + } + ], + "triggerRandomSwitch": "" + }, + "id": "seatedReactionApplaud", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 21, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_all.fbx" + }, + "id": "seatedReactionPointIntro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 100, + "loopFlag": true, + "startFrame": 21, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_all.fbx" + }, + "id": "seatedReactionPointLoop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 134, + "loopFlag": false, + "mirrorFlag": false, + "startFrame": 100, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_all.fbx" + }, + "id": "seatedReactionPointOutro", + "type": "clip" + } + ], + "data": { + "currentState": "seatedReactionPointIntro", + "randomSwitchTimeMax": 10, + "randomSwitchTimeMin": 1, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "seatedReactionPointIntro", + "interpDuration": 18, + "interpTarget": 18, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionPointLoop", + "var": "seatedReactionPointIntroOnDone" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionPointLoop", + "interpDuration": 18, + "interpTarget": 18, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionPointOutro", + "var": "reactionPointDisabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionPointOutro", + "interpDuration": 18, + "interpTarget": 18, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "seatedReactionPointLoop", + "var": "reactionPointEnabled" + } + ] + } + ], + "triggerRandomSwitch": "" + }, + "id": "seatedReactionPoint", + "type": "randomSwitchStateMachine" + } + ], + "data": { + "alpha": 0, + "alphaVar": "seatedPointBlendAlpha", + "blendType": "addAbsolute" + }, + "id": "seatedReactionPointBase", + "type": "blendLinear" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 11, + "loopFlag": true, + "startFrame": 11, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx" + }, + "id": "seatedPointLeft", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 30, + "loopFlag": true, + "startFrame": 30, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx" + }, + "id": "seatedPointRight", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 50, + "loopFlag": true, + "startFrame": 50, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx" + }, + "id": "seatedPointUp", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 70, + "loopFlag": true, + "startFrame": 70, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx" + }, + "id": "seatedPointDown", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 90, + "loopFlag": true, + "startFrame": 90, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx" + }, + "id": "seatedPointUpLeft", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 110, + "loopFlag": true, + "startFrame": 110, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx" + }, + "id": "seatedPointUpRight", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 130, + "loopFlag": true, + "startFrame": 130, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx" + }, + "id": "seatedPointDownLeft", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 150, + "loopFlag": true, + "startFrame": 150, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx" + }, + "id": "seatedPointDownRight", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 3, + "loopFlag": true, + "startFrame": 3, + "timeScale": 1, + "url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx" + }, + "id": "seatedPointCenter", + "type": "clip" + } + ], + "data": { + "alpha": [ + 0, + 0, + 0 + ], + "alphaVar": "pointAroundAlpha", + "centerId": "seatedPointCenter", + "downId": "seatedPointDown", + "downLeftId": "seatedPointDownLeft", + "downRightId": "seatedPointDownRight", + "leftId": "seatedPointLeft", + "rightId": "seatedPointRight", + "upId": "seatedPointUp", + "upLeftId": "seatedPointUpLeft", + "upRightId": "seatedPointUpRight" + }, + "id": "seatedPointAround", + "type": "blendDirectional" + } + ], + "data": { + "alpha": 0, + "alphaVar": "pointBlendAlpha", + "blendType": "addAbsolute" + }, + "id": "seatedReactionPoint", + "type": "blendLinear" } ], "data": { - "currentState": "raiseHand01", - "randomSwitchTimeMax": 10, - "randomSwitchTimeMin": 1, + "currentState": "seatedTalkOverlay", "states": [ { "easingType": "easeInOutQuad", - "id": "raiseHand01", - "interpDuration": 18, - "interpTarget": 18, + "id": "seatedTalkOverlay", + "interpDuration": 25, + "interpTarget": 25, "interpType": "evaluateBoth", - "priority": 1, - "resume": false, "transitions": [ + { + "state": "seatedReactionPositive", + "var": "reactionPositiveTrigger" + }, + { + "state": "seatedReactionNegative", + "var": "reactionNegativeTrigger" + }, + { + "state": "seatedReactionRaiseHand", + "var": "reactionRaiseHandEnabled" + }, + { + "state": "seatedReactionApplaud", + "var": "reactionApplaudEnabled" + }, + { + "state": "seatedReactionPoint", + "var": "reactionPointEnabled" + } ] }, { "easingType": "easeInOutQuad", - "id": "raiseHand03", - "interpDuration": 18, - "interpTarget": 18, + "id": "seatedReactionPositive", + "interpDuration": 12, + "interpTarget": 12, "interpType": "evaluateBoth", - "priority": 1, - "resume": false, "transitions": [ + { + "state": "seatedTalkOverlay", + "var": "seatedReactionPositiveHeadNodOnDone" + }, + { + "state": "seatedTalkOverlay", + "var": "seatedReactionPositiveHeadNodYesOnDone" + }, + { + "state": "seatedTalkOverlay", + "var": "seatedReactionPositiveLongHeadNodOnDone" + }, + { + "state": "seatedTalkOverlay", + "var": "seatedReactionPositiveCheerOnDone" + }, + { + "state": "seatedTalkOverlay", + "var": "seatedReactionPositiveAcknowledgeOnDone" + }, + { + "state": "seatedReactionNegative", + "var": "reactionNegativeTrigger" + }, + { + "state": "seatedReactionRaiseHand", + "var": "reactionRaiseHandEnabled" + }, + { + "state": "seatedReactionApplaud", + "var": "reactionApplaudEnabled" + }, + { + "state": "seatedReactionPoint", + "var": "reactionPointEnabled" + } ] }, { "easingType": "easeInOutQuad", - "id": "raiseHand04", - "interpDuration": 18, - "interpTarget": 18, + "id": "seatedReactionNegative", + "interpDuration": 12, + "interpTarget": 12, "interpType": "evaluateBoth", - "priority": 1, - "resume": false, "transitions": [ + { + "state": "seatedReactionPositive", + "var": "reactionPositiveTrigger" + }, + { + "state": "seatedTalkOverlay", + "var": "seatedReactionNegativeDisagreeHeadshakeOnDone" + }, + { + "state": "seatedTalkOverlay", + "var": "seatedReactionNegativeDisagreeDropHeadOnDone" + }, + { + "state": "seatedTalkOverlay", + "var": "seatedReactionNegativeDisagreeDisbeliefOnDone" + }, + { + "state": "seatedTalkOverlay", + "var": "seatedReactionNegativeDisagreeDismissOnDone" + }, + { + "state": "seatedReactionRaiseHand", + "var": "reactionRaiseHandEnabled" + }, + { + "state": "seatedReactionApplaud", + "var": "reactionApplaudEnabled" + }, + { + "state": "seatedReactionPoint", + "var": "reactionPointEnabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionRaiseHand", + "interpDuration": 12, + "interpTarget": 12, + "interpType": "evaluateBoth", + "transitions": [ + { + "state": "seatedReactionNegative", + "var": "reactionNegativeTrigger" + }, + { + "state": "seatedReactionPositive", + "var": "reactionPositiveTrigger" + }, + { + "state": "seatedTalkOverlay", + "var": "reactionRaiseHandDisabled" + }, + { + "state": "seatedReactionApplaud", + "var": "reactionApplaudEnabled" + }, + { + "state": "seatedReactionPoint", + "var": "reactionPointEnabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionApplaud", + "interpDuration": 12, + "interpTarget": 12, + "interpType": "evaluateBoth", + "transitions": [ + { + "state": "seatedReactionNegative", + "var": "reactionNegativeTrigger" + }, + { + "state": "seatedReactionPositive", + "var": "reactionPositiveTrigger" + }, + { + "state": "seatedReactionRaiseHand", + "var": "reactionRaiseHandEnabled" + }, + { + "state": "seatedTalkOverlay", + "var": "reactionApplaudDisabled" + }, + { + "state": "seatedReactionPoint", + "var": "reactionPointEnabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "seatedReactionPoint", + "interpDuration": 12, + "interpTarget": 12, + "interpType": "evaluateBoth", + "transitions": [ + { + "state": "seatedReactionNegative", + "var": "reactionNegativeTrigger" + }, + { + "state": "seatedReactionPositive", + "var": "reactionPositiveTrigger" + }, + { + "state": "seatedReactionRaiseHand", + "var": "reactionRaiseHandEnabled" + }, + { + "state": "seatedReactionApplaud", + "var": "reactionApplaudEnabled" + }, + { + "state": "seatedTalkOverlay", + "var": "reactionPointDisabled" + } ] } ] }, - "id": "reactionRaiseHand", - "type": "randomSwitchStateMachine" + "id": "seated", + "type": "stateMachine" }, { "children": [ @@ -2721,95 +2048,928 @@ "children": [ { "children": [ + { + "children": [ + ], + "data": { + "endFrame": 500, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/talk.fbx" + }, + "id": "talk", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 325, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/talk02.fbx" + }, + "id": "talk02", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 300, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/talk03.fbx" + }, + "id": "talk03", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 500, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/talk04.fbx" + }, + "id": "talk04", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 215, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/talk_armsdown.fbx" + }, + "id": "talk_armsdown", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 500, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/talk_lefthand.fbx" + }, + "id": "talk_lefthand", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 502, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/talk_righthand.fbx" + }, + "id": "talk_righthand", + "type": "clip" + } ], "data": { - "endFrame": 18, + "currentState": "talk", + "randomSwitchTimeMax": 12, + "randomSwitchTimeMin": 7, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "talk", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.33, + "resume": true, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "talk02", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.33, + "resume": true, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "talk03", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.33, + "resume": true, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "talk04", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.33, + "resume": true, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "talk_armsdown", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.33, + "resume": true, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "talk_lefthand", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.33, + "resume": true, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "talk_righthand", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.33, + "resume": true, + "transitions": [ + ] + } + ], + "triggerRandomSwitch": "idleTalkSwitch" + }, + "id": "idleTalk", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 300, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle.fbx" + }, + "id": "masterIdle1", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 400, + "loopFlag": true, + "startFrame": 1, + "timeScale": 0.75, + "url": "qrc:///avatar/animations/idle02.fbx" + }, + "id": "masterIdle2", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 800, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle03.fbx" + }, + "id": "masterIdle3", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 902, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle04.fbx" + }, + "id": "masterIdle4", + "type": "clip" + } + ], + "data": { + "currentState": "masterIdle1", + "randomSwitchTimeMax": 30, + "randomSwitchTimeMin": 10, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "masterIdle1", + "interpDuration": 30, + "interpTarget": 30, + "interpType": "evaluateBoth", + "priority": 0.25, + "resume": true, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "masterIdle2", + "interpDuration": 30, + "interpTarget": 30, + "interpType": "evaluateBoth", + "priority": 0.25, + "resume": true, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "masterIdle3", + "interpDuration": 30, + "interpTarget": 30, + "interpType": "evaluateBoth", + "priority": 0.25, + "resume": true, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "masterIdle4", + "interpDuration": 30, + "interpTarget": 30, + "interpType": "evaluateBoth", + "priority": 0.25, + "resume": true, + "transitions": [ + ] + } + ], + "triggerRandomSwitch": "masterIdleSwitch" + }, + "id": "masterIdle", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 91, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle_once_slownod.fbx" + }, + "id": "idle_once_slownod", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 154, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle_once_headtilt.fbx" + }, + "id": "idle_once_headtilt", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 491, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle_once_shiftheelpivot.fbx" + }, + "id": "idle_once_shiftheelpivot", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 1620, + "loopFlag": false, + "startFrame": 1, + "timeScale": 0.7, + "url": "qrc:///avatar/animations/idleWS_all.fbx" + }, + "id": "idleWS_all", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 324, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle_once_lookaround.fbx" + }, + "id": "idle_once_lookaround", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 169, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle_once_neckstretch.fbx" + }, + "id": "idle_once_neckstretch", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 375, + "loopFlag": false, + "startFrame": 1, + "timeScale": 0.7, + "url": "qrc:///avatar/animations/idle_once_lookleftright.fbx" + }, + "id": "idle_once_lookleftright", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 429, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle_once_fidget.fbx" + }, + "id": "idle_once_fidget", + "type": "clip" + } + ], + "data": { + "currentState": "idle_once_slownod", + "states": [ + { + "easingType": "easeInOutQuad", + "id": "idle_once_slownod", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.2, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "idle_once_headtilt", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.2, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "idle_once_shiftheelpivot", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.2, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "idleWS_all", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.2, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "idle_once_lookaround", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.2, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "idle_once_neckstretch", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.2, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "idle_once_lookleftright", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.2, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "idle_once_fidget", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 0.2, + "resume": false, + "transitions": [ + ] + } + ] + }, + "id": "movement", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 80, + "loopFlag": false, + "startFrame": 1, + "startFrameVar": "", + "timeScale": 0.65, + "url": "qrc:///avatar/animations/idle_LFF_all.fbx" + }, + "id": "transitionToAltIdle1", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 80, + "loopFlag": false, + "startFrame": 1, + "timeScale": 0.65, + "url": "qrc:///avatar/animations/idle_RFF_all.fbx" + }, + "id": "transitionToAltIdle2", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 388, + "loopFlag": true, + "startFrame": 80, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle_LFF_all.fbx" + }, + "id": "altIdle1", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 388, + "loopFlag": true, + "startFrame": 80, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle_RFF_all.fbx" + }, + "id": "altIdle2", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 472, + "loopFlag": false, + "startFrame": 388, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle_LFF_all.fbx" + }, + "id": "alt1ToMasterIdle", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 453, + "loopFlag": false, + "startFrame": 388, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle_RFF_all.fbx" + }, + "id": "alt2ToMasterIdle", + "type": "clip" + } + ], + "data": { + "currentState": "transitionToAltIdle1", + "states": [ + { + "easingType": "easeInOutQuad", + "id": "transitionToAltIdle1", + "interpDuration": 20, + "interpTarget": 20, + "interpType": "evaluateBoth", + "priority": 0.5, + "resume": false, + "transitions": [ + { + "randomSwitchState": "altIdle1", + "var": "transitionToAltIdle1OnDone" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "transitionToAltIdle2", + "interpDuration": 20, + "interpTarget": 20, + "interpType": "evaluateBoth", + "priority": 0.5, + "resume": false, + "transitions": [ + { + "randomSwitchState": "altIdle2", + "var": "transitionToAltIdle2OnDone" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "altIdle1", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": -1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "alt1ToMasterIdle", + "var": "finishAltIdle2" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "altIdle2", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": -1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "alt2ToMasterIdle", + "var": "finishAltIdle2" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "alt1ToMasterIdle", + "interpDuration": 24, + "interpTarget": 24, + "interpType": "evaluateBoth", + "priority": -1, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "alt2ToMasterIdle", + "interpDuration": 24, + "interpTarget": 24, + "interpType": "evaluateBoth", + "priority": -1, + "resume": false, + "transitions": [ + ] + } + ], + "transitionVar": "finishAltIdle2", + "triggerTimeMax": 60, + "triggerTimeMin": 10 + }, + "id": "alternateIdle", + "type": "randomSwitchStateMachine" + } + ], + "data": { + "currentState": "movement", + "states": [ + { + "easingType": "easeInOutQuad", + "id": "movement", + "interpDuration": 30, + "interpTarget": 30, + "interpType": "evaluateBoth", + "priority": 0.6, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "alternateIdle", + "interpDuration": 30, + "interpTarget": 30, + "interpType": "evaluateBoth", + "priority": 0.4, + "resume": false, + "transitions": [ + ] + } + ] + }, + "id": "fidget", + "type": "randomSwitchStateMachine" + } + ], + "data": { + "currentState": "masterIdle", + "states": [ + { + "easingType": "easeInOutQuad", + "id": "masterIdle", + "interpDuration": 30, + "interpTarget": 30, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "fidget", + "var": "timeToFidget" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "fidget", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": -1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "masterIdle", + "var": "idle_once_slownodOnDone" + }, + { + "randomSwitchState": "masterIdle", + "var": "idle_once_headtiltOnDone" + }, + { + "randomSwitchState": "masterIdle", + "var": "idle_once_shiftheelpivotOnDone" + }, + { + "randomSwitchState": "masterIdle", + "var": "idleWS_allOnDone" + }, + { + "randomSwitchState": "masterIdle", + "var": "idle_once_lookaroundOnDone" + }, + { + "randomSwitchState": "masterIdle", + "var": "idle_once_neckstretchOnDone" + }, + { + "randomSwitchState": "masterIdle", + "var": "idle_once_lookleftrightOnDone" + }, + { + "randomSwitchState": "masterIdle", + "var": "idle_once_fidgetOnDone" + }, + { + "randomSwitchState": "masterIdle", + "var": "alt1ToMasterIdleOnDone" + }, + { + "randomSwitchState": "masterIdle", + "var": "alt2ToMasterIdleOnDone" + } + ] + } + ], + "transitionVar": "timeToFidget", + "triggerTimeMax": 50, + "triggerTimeMin": 10 + }, + "id": "idleStand", + "type": "randomSwitchStateMachine" + } + ], + "data": { + "alpha": 1, + "alphaVar": "talkOverlayAlpha", + "boneSet": "upperBody" + }, + "id": "idleTalkOverlay", + "type": "overlay" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 64, "loopFlag": false, "startFrame": 1, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_clap01_all.fbx" + "url": "qrc:///avatar/animations/emote_agree_acknowledge.fbx" }, - "id": "applaudClap01Intro", + "id": "positiveAcknowledge", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 97, - "loopFlag": true, - "startFrame": 18, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_clap01_all.fbx" - }, - "id": "applaudClap01Loop", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 146, + "endFrame": 55, "loopFlag": false, - "startFrame": 97, + "startFrame": 1, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_clap01_all.fbx" + "url": "qrc:///avatar/animations/emote_agree_headnod.fbx" }, - "id": "applaudClap01Outro", + "id": "positiveHeadNod", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 94, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_agree_headnodyes.fbx" + }, + "id": "positiveHeadNodYes", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 68, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_agree_longheadnod.fbx" + }, + "id": "positiveLongHeadNod", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 84, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_agree_thoughtfulheadnod.fbx" + }, + "id": "positiveThoughtfulHeadNod", "type": "clip" } ], "data": { - "currentState": "applaudClap01Intro", + "currentState": "positiveAcknowledge", "randomSwitchTimeMax": 10, "randomSwitchTimeMin": 1, "states": [ { "easingType": "easeInOutQuad", - "id": "applaudClap01Intro", - "interpDuration": 18, - "interpTarget": 18, + "id": "positiveAcknowledge", + "interpDuration": 1, + "interpTarget": 1, "interpType": "evaluateBoth", "priority": 1, "resume": false, "transitions": [ - { - "randomSwitchState": "applaudClap01Loop", - "var": "applaudClap01IntroOnDone" - } ] }, { - "id": "applaudClap01Loop", - "interpDuration": 5, - "interpTarget": 5, - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "applaudClap01Outro", - "var": "reactionApplaudDisabled" - } - ] - }, - { - "id": "applaudClap01Outro", - "interpDuration": 5, - "interpTarget": 5, + "easingType": "easeInOutQuad", + "id": "positiveHeadNod", + "interpDuration": 1, + "interpTarget": 1, "interpType": "evaluateBoth", - "priority": 0, + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "positiveHeadNodYes", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "positiveLongHeadNod", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "positiveThoughtfulHeadNod", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 0.33, "resume": false, "transitions": [ - { - "randomSwitchState": "applaudClap01Loop", - "var": "reactionApplaudEnabled" - } ] } ], "triggerRandomSwitch": "" }, - "id": "applaudClap01", + "id": "reactionPositive", "type": "randomSwitchStateMachine" }, { @@ -2818,108 +2978,26 @@ "children": [ ], "data": { - "endFrame": 14, + "endFrame": 72, "loopFlag": false, "startFrame": 1, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_clap02_all.fbx" + "url": "qrc:///avatar/animations/emote_disagree_annoyedheadshake.fbx" }, - "id": "applaudClap02Intro", + "id": "negativeAnnoyedHeadshake", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 78, - "loopFlag": true, - "startFrame": 14, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_clap02_all.fbx" - }, - "id": "applaudClap02Loop", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 115, - "loopFlag": false, - "startFrame": 78, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_clap02_all.fbx" - }, - "id": "applaudClap02Outro", - "type": "clip" - } - ], - "data": { - "currentState": "applaudClap02Intro", - "randomSwitchTimeMax": 10, - "randomSwitchTimeMin": 1, - "states": [ - { - "easingType": "easeInOutQuad", - "id": "applaudClap02Intro", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - { - "randomSwitchState": "applaudClap02Loop", - "var": "applaudClap02IntroOnDone" - } - ] - }, - { - "id": "applaudClap02Loop", - "interpDuration": 5, - "interpTarget": 5, - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "applaudClap02Outro", - "var": "reactionApplaudDisabled" - } - ] - }, - { - "id": "applaudClap02Outro", - "interpDuration": 5, - "interpTarget": 5, - "interpType": "evaluateBoth", - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "applaudClap02Loop", - "var": "reactionApplaudEnabled" - } - ] - } - ], - "triggerRandomSwitch": "" - }, - "id": "applaudClap02", - "type": "randomSwitchStateMachine" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 14, + "endFrame": 84, "loopFlag": false, "startFrame": 1, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_clap03_all.fbx" + "url": "qrc:///avatar/animations/emote_disagree_thoughtfulheadshake.fbx" }, - "id": "applaudClap03Intro", + "id": "negativeThoughtfulHeadshake", "type": "clip" }, { @@ -2927,426 +3005,2885 @@ ], "data": { "endFrame": 100, - "loopFlag": true, - "startFrame": 14, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_clap03_all.fbx" - }, - "id": "applaudClap03Loop", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 149, "loopFlag": false, - "startFrame": 100, + "startFrame": 1, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_clap03_all.fbx" + "url": "qrc:///avatar/animations/emote_disagree_drophead.fbx" }, - "id": "applaudClap03Outro", + "id": "negativeDropHead", "type": "clip" } ], "data": { - "currentState": "applaudClap03Intro", + "currentState": "negativeAnnoyedHeadshake", "randomSwitchTimeMax": 10, "randomSwitchTimeMin": 1, "states": [ { "easingType": "easeInOutQuad", - "id": "applaudClap03Intro", - "interpDuration": 18, - "interpTarget": 18, + "id": "negativeAnnoyedHeadshake", + "interpDuration": 1, + "interpTarget": 1, "interpType": "evaluateBoth", "priority": 1, "resume": false, "transitions": [ - { - "randomSwitchState": "applaudClap03Loop", - "var": "applaudClap03IntroOnDone" - } ] }, { - "id": "applaudClap03Loop", - "interpDuration": 5, - "interpTarget": 5, - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "applaudClap03Outro", - "var": "reactionApplaudDisabled" - } - ] - }, - { - "id": "applaudClap03Outro", - "interpDuration": 5, - "interpTarget": 5, + "easingType": "easeInOutQuad", + "id": "negativeThoughtfulHeadshake", + "interpDuration": 1, + "interpTarget": 1, "interpType": "evaluateBoth", - "priority": 0, + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "negativeDropHead", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, "resume": false, "transitions": [ - { - "randomSwitchState": "applaudClap03Loop", - "var": "reactionApplaudEnabled" - } ] } - ], - "triggerRandomSwitch": "" + ] }, - "id": "applaudClap03", + "id": "reactionNegative", "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 18, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_raisehand01_all.fbx" + }, + "id": "raiseHand01Intro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 378, + "loopFlag": true, + "startFrame": 18, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_raisehand01_all.fbx" + }, + "id": "raiseHand01Loop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 435, + "loopFlag": false, + "startFrame": 378, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_raisehand01_all.fbx" + }, + "id": "raiseHand01Outro", + "type": "clip" + } + ], + "data": { + "currentState": "raiseHand01Intro", + "randomSwitchTimeMax": 10, + "randomSwitchTimeMin": 1, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "raiseHand01Intro", + "interpDuration": 10, + "interpTarget": 10, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "raiseHand01Loop", + "var": "raiseHand01IntroOnDone" + } + ] + }, + { + "id": "raiseHand01Loop", + "interpDuration": 1, + "interpTarget": 1, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "raiseHand01Outro", + "var": "reactionRaiseHandDisabled" + } + ] + }, + { + "id": "raiseHand01Outro", + "interpDuration": 6, + "interpTarget": 6, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "raiseHand01Loop", + "var": "reactionRaiseHandEnabled" + } + ] + } + ], + "triggerRandomSwitch": "" + }, + "id": "raiseHand01", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 19, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_raisehand03_all.fbx" + }, + "id": "raiseHand03Intro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 237, + "loopFlag": true, + "startFrame": 19, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_raisehand03_all.fbx" + }, + "id": "raiseHand03Loop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 300, + "loopFlag": false, + "startFrame": 237, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_raisehand03_all.fbx" + }, + "id": "raiseHand03Outro", + "type": "clip" + } + ], + "data": { + "currentState": "raiseHand03Intro", + "randomSwitchTimeMax": 10, + "randomSwitchTimeMin": 1, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "raiseHand03Intro", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "raiseHand03Loop", + "var": "raiseHand03IntroOnDone" + } + ] + }, + { + "id": "raiseHand03Loop", + "interpDuration": 1, + "interpTarget": 1, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "raiseHand03Outro", + "var": "reactionRaiseHandDisabled" + } + ] + }, + { + "id": "raiseHand03Outro", + "interpDuration": 6, + "interpTarget": 6, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "raiseHand03Loop", + "var": "reactionRaiseHandEnabled" + } + ] + } + ], + "triggerRandomSwitch": "" + }, + "id": "raiseHand03", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 32, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_raisehand04_all.fbx" + }, + "id": "raiseHand04Intro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 345, + "loopFlag": true, + "startFrame": 32, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_raisehand04_all.fbx" + }, + "id": "raiseHand04Loop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 400, + "loopFlag": false, + "startFrame": 345, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_raisehand04_all.fbx" + }, + "id": "raiseHand04Outro", + "type": "clip" + } + ], + "data": { + "currentState": "raiseHand04Intro", + "randomSwitchTimeMax": 10, + "randomSwitchTimeMin": 1, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "raiseHand04Intro", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "raiseHand04Loop", + "var": "raiseHand04IntroOnDone" + } + ] + }, + { + "id": "raiseHand04Loop", + "interpDuration": 1, + "interpTarget": 1, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "raiseHand04Outro", + "var": "reactionRaiseHandDisabled" + } + ] + }, + { + "id": "raiseHand04Outro", + "interpDuration": 6, + "interpTarget": 6, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "raiseHand04Loop", + "var": "reactionRaiseHandEnabled" + } + ] + } + ], + "triggerRandomSwitch": "" + }, + "id": "raiseHand04", + "type": "randomSwitchStateMachine" + } + ], + "data": { + "currentState": "raiseHand01", + "randomSwitchTimeMax": 10, + "randomSwitchTimeMin": 1, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "raiseHand01", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "raiseHand03", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "raiseHand04", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + ] + } + ] + }, + "id": "reactionRaiseHand", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 17, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_clap01_all.fbx" + }, + "id": "applaudClap01Intro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 111, + "loopFlag": true, + "startFrame": 17, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_clap01_all.fbx" + }, + "id": "applaudClap01Loop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 160, + "loopFlag": false, + "startFrame": 111, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_clap01_all.fbx" + }, + "id": "applaudClap01Outro", + "type": "clip" + } + ], + "data": { + "currentState": "applaudClap01Intro", + "randomSwitchTimeMax": 10, + "randomSwitchTimeMin": 1, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "applaudClap01Intro", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "applaudClap01Loop", + "var": "applaudClap01IntroOnDone" + } + ] + }, + { + "id": "applaudClap01Loop", + "interpDuration": 1, + "interpTarget": 1, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "applaudClap01Outro", + "var": "reactionApplaudDisabled" + } + ] + }, + { + "id": "applaudClap01Outro", + "interpDuration": 6, + "interpTarget": 6, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "applaudClap01Loop", + "var": "reactionApplaudEnabled" + } + ] + } + ], + "triggerRandomSwitch": "" + }, + "id": "applaudClap01", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 14, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_clap02_all.fbx" + }, + "id": "applaudClap02Intro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 78, + "loopFlag": true, + "startFrame": 14, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_clap02_all.fbx" + }, + "id": "applaudClap02Loop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 115, + "loopFlag": false, + "startFrame": 78, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_clap02_all.fbx" + }, + "id": "applaudClap02Outro", + "type": "clip" + } + ], + "data": { + "currentState": "applaudClap02Intro", + "randomSwitchTimeMax": 10, + "randomSwitchTimeMin": 1, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "applaudClap02Intro", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "applaudClap02Loop", + "var": "applaudClap02IntroOnDone" + } + ] + }, + { + "id": "applaudClap02Loop", + "interpDuration": 1, + "interpTarget": 1, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "applaudClap02Outro", + "var": "reactionApplaudDisabled" + } + ] + }, + { + "id": "applaudClap02Outro", + "interpDuration": 6, + "interpTarget": 6, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "applaudClap02Loop", + "var": "reactionApplaudEnabled" + } + ] + } + ], + "triggerRandomSwitch": "" + }, + "id": "applaudClap02", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 14, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_clap03_all.fbx" + }, + "id": "applaudClap03Intro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 100, + "loopFlag": true, + "startFrame": 14, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_clap03_all.fbx" + }, + "id": "applaudClap03Loop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 149, + "loopFlag": false, + "startFrame": 100, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_clap03_all.fbx" + }, + "id": "applaudClap03Outro", + "type": "clip" + } + ], + "data": { + "currentState": "applaudClap03Intro", + "randomSwitchTimeMax": 10, + "randomSwitchTimeMin": 1, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "applaudClap03Intro", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "applaudClap03Loop", + "var": "applaudClap03IntroOnDone" + } + ] + }, + { + "id": "applaudClap03Loop", + "interpDuration": 1, + "interpTarget": 1, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "applaudClap03Outro", + "var": "reactionApplaudDisabled" + } + ] + }, + { + "id": "applaudClap03Outro", + "interpDuration": 6, + "interpTarget": 6, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "applaudClap03Loop", + "var": "reactionApplaudEnabled" + } + ] + } + ], + "triggerRandomSwitch": "" + }, + "id": "applaudClap03", + "type": "randomSwitchStateMachine" + } + ], + "data": { + "currentState": "applaudClap01", + "randomSwitchTimeMax": 10, + "randomSwitchTimeMin": 1, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "applaudClap01", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "applaudClap02", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + ] + }, + { + "easingType": "easeInOutQuad", + "id": "applaudClap03", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + ] + } + ] + }, + "id": "reactionApplaud", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 21, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_all.fbx" + }, + "id": "reactionPointIntro", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 100, + "loopFlag": true, + "startFrame": 21, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_all.fbx" + }, + "id": "reactionPointLoop", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 134, + "loopFlag": false, + "startFrame": 100, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_all.fbx" + }, + "id": "reactionPointOutro", + "type": "clip" + } + ], + "data": { + "currentState": "reactionPointIntro", + "randomSwitchTimeMax": 10, + "randomSwitchTimeMin": 1, + "states": [ + { + "easingType": "easeInOutQuad", + "id": "reactionPointIntro", + "interpDuration": 1, + "interpTarget": 1, + "interpType": "evaluateBoth", + "priority": 1, + "resume": false, + "transitions": [ + { + "randomSwitchState": "reactionPointLoop", + "var": "reactionPointIntroOnDone" + } + ] + }, + { + "id": "reactionPointLoop", + "interpDuration": 1, + "interpTarget": 1, + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "reactionPointOutro", + "var": "reactionPointDisabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "reactionPointOutro", + "interpDuration": 6, + "interpTarget": 6, + "interpType": "evaluateBoth", + "priority": 0, + "resume": false, + "transitions": [ + { + "randomSwitchState": "reactionPointLoop", + "var": "reactionPointEnabled" + } + ] + } + ], + "triggerRandomSwitch": "" + }, + "id": "reactionPoint", + "type": "randomSwitchStateMachine" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 11, + "loopFlag": true, + "startFrame": 11, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx" + }, + "id": "idlePointLeft", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 30, + "loopFlag": true, + "startFrame": 30, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx" + }, + "id": "idlePointRight", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 50, + "loopFlag": true, + "startFrame": 50, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx" + }, + "id": "idlePointUp", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 70, + "loopFlag": true, + "startFrame": 70, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx" + }, + "id": "idlePointDown", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 90, + "loopFlag": true, + "startFrame": 90, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx" + }, + "id": "idlePointUpLeft", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 110, + "loopFlag": true, + "startFrame": 110, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx" + }, + "id": "idlePointUpRight", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 130, + "loopFlag": true, + "startFrame": 130, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx" + }, + "id": "idlePointDownLeft", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 150, + "loopFlag": true, + "startFrame": 150, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx" + }, + "id": "idlePointDownRight", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 3, + "loopFlag": true, + "startFrame": 3, + "timeScale": 1, + "url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx" + }, + "id": "idlePointCenter", + "type": "clip" + } + ], + "data": { + "alpha": [ + 0, + 0, + 0 + ], + "alphaVar": "pointAroundAlpha", + "centerId": "idlePointCenter", + "downId": "idlePointDown", + "downLeftId": "idlePointDownLeft", + "downRightId": "idlePointDownRight", + "leftId": "idlePointLeft", + "rightId": "idlePointRight", + "upId": "idlePointUp", + "upLeftId": "idlePointUpLeft", + "upRightId": "idlePointUpRight" + }, + "id": "idlePointAround", + "type": "blendDirectional" + } + ], + "data": { + "alpha": 0, + "alphaVar": "pointBlendAlpha", + "blendType": "addAbsolute" + }, + "id": "reactionPoint", + "type": "blendLinear" } ], "data": { - "currentState": "applaudClap01", - "randomSwitchTimeMax": 10, - "randomSwitchTimeMin": 1, + "currentState": "idleTalkOverlay", "states": [ { "easingType": "easeInOutQuad", - "id": "applaudClap01", - "interpDuration": 18, - "interpTarget": 18, + "id": "idleTalkOverlay", + "interpDuration": 20, + "interpTarget": 20, "interpType": "evaluateBoth", - "priority": 1, - "resume": false, "transitions": [ + { + "state": "reactionPositive", + "var": "reactionPositiveTrigger" + }, + { + "state": "reactionNegative", + "var": "reactionNegativeTrigger" + }, + { + "state": "reactionRaiseHand", + "var": "reactionRaiseHandEnabled" + }, + { + "state": "reactionApplaud", + "var": "reactionApplaudEnabled" + }, + { + "state": "reactionPoint", + "var": "reactionPointEnabled" + } ] }, { "easingType": "easeInOutQuad", - "id": "applaudClap02", + "id": "reactionPositive", "interpDuration": 18, "interpTarget": 18, "interpType": "evaluateBoth", - "priority": 1, - "resume": false, "transitions": [ + { + "state": "idleTalkOverlay", + "var": "positiveAcknowledgeOnDone" + }, + { + "state": "idleTalkOverlay", + "var": "positiveHeadNodOnDone" + }, + { + "state": "idleTalkOverlay", + "var": "positiveHeadNodYesOnDone" + }, + { + "state": "idleTalkOverlay", + "var": "positiveLongHeadNodOnDone" + }, + { + "state": "idleTalkOverlay", + "var": "positiveThoughtfulHeadNodOnDone" + }, + { + "state": "reactionNegative", + "var": "reactionNegativeTrigger" + }, + { + "state": "reactionRaiseHand", + "var": "reactionRaiseHandEnabled" + }, + { + "state": "reactionApplaud", + "var": "reactionApplaudEnabled" + }, + { + "state": "reactionPoint", + "var": "reactionPointEnabled" + } ] }, { "easingType": "easeInOutQuad", - "id": "applaudClap03", + "id": "reactionNegative", "interpDuration": 18, "interpTarget": 18, "interpType": "evaluateBoth", - "priority": 1, - "resume": false, "transitions": [ + { + "state": "reactionPositive", + "var": "reactionPositiveTrigger" + }, + { + "state": "idleTalkOverlay", + "var": "negativeAnnoyedHeadshakeOnDone" + }, + { + "state": "idleTalkOverlay", + "var": "negativeThoughtfulHeadshakeOnDone" + }, + { + "state": "idleTalkOverlay", + "var": "negativeDropHeadOnDone" + }, + { + "state": "reactionRaiseHand", + "var": "reactionRaiseHandEnabled" + }, + { + "state": "reactionApplaud", + "var": "reactionApplaudEnabled" + }, + { + "state": "reactionPoint", + "var": "reactionPointEnabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "reactionRaiseHand", + "interpDuration": 18, + "interpTarget": 18, + "interpType": "evaluateBoth", + "transitions": [ + { + "state": "reactionNegative", + "var": "reactionNegativeTrigger" + }, + { + "state": "reactionPositive", + "var": "reactionPositiveTrigger" + }, + { + "state": "idleTalkOverlay", + "var": "reactionRaiseHandDisabled" + }, + { + "state": "reactionApplaud", + "var": "reactionApplaudEnabled" + }, + { + "state": "reactionPoint", + "var": "reactionPointEnabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "reactionApplaud", + "interpDuration": 18, + "interpTarget": 18, + "interpType": "evaluateBoth", + "transitions": [ + { + "state": "reactionNegative", + "var": "reactionNegativeTrigger" + }, + { + "state": "reactionPositive", + "var": "reactionPositiveTrigger" + }, + { + "state": "reactionRaiseHand", + "var": "reactionRaiseHandEnabled" + }, + { + "state": "idleTalkOverlay", + "var": "reactionApplaudDisabled" + }, + { + "state": "reactionPoint", + "var": "reactionPointEnabled" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "reactionPoint", + "interpDuration": 10, + "interpTarget": 10, + "interpType": "evaluateBoth", + "transitions": [ + { + "state": "reactionNegative", + "var": "reactionNegativeTrigger" + }, + { + "state": "reactionPositive", + "var": "reactionPositiveTrigger" + }, + { + "state": "reactionRaiseHand", + "var": "reactionRaiseHandEnabled" + }, + { + "state": "reactionApplaud", + "var": "reactionApplaudEnabled" + }, + { + "state": "idleTalkOverlay", + "var": "reactionPointDisabled" + } ] } ] }, - "id": "reactionApplaud", - "type": "randomSwitchStateMachine" + "id": "idle", + "type": "stateMachine" }, { "children": [ - { - "children": [ - ], - "data": { - "endFrame": 22, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/emote_point01_all.fbx" - }, - "id": "reactionPointIntro", - "type": "clip" - }, { "children": [ ], "data": { "endFrame": 40, "loopFlag": true, - "startFrame": 22, + "startFrame": 1, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_point01_all.fbx" + "url": "qrc:///avatar/animations/walk_short_fwd.fbx" }, - "id": "reactionPointLoop", + "id": "walkFwdShort_c", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 78, - "loopFlag": false, - "startFrame": 40, + "endFrame": 30, + "loopFlag": true, + "startFrame": 1, "timeScale": 1, - "url": "qrc:///avatar/animations/emote_point01_all.fbx" + "url": "qrc:///avatar/animations/walk_fwd.fbx" }, - "id": "reactionPointOutro", + "id": "walkFwdNormal_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 26, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/walk_fwd_fast.fbx" + }, + "id": "walkFwdFast_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 18, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/jog_fwd.fbx" + }, + "id": "walkFwdJog_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 19, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/run_fast_fwd.fbx" + }, + "id": "walkFwdRun_c", "type": "clip" } ], "data": { - "currentState": "reactionPointIntro", - "randomSwitchTimeMax": 10, - "randomSwitchTimeMin": 1, - "states": [ - { - "easingType": "easeInOutQuad", - "id": "reactionPointIntro", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 1, - "resume": false, - "transitions": [ - { - "randomSwitchState": "reactionPointLoop", - "var": "reactionPointIntroOnDone" - } - ] - }, - { - "id": "reactionPointLoop", - "interpDuration": 5, - "interpTarget": 5, - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "reactionPointOutro", - "var": "reactionPointDisabled" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "reactionPointOutro", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", - "priority": 0, - "resume": false, - "transitions": [ - { - "randomSwitchState": "reactionPointLoop", - "var": "reactionPointEnabled" - } - ] - } + "alpha": 0, + "alphaVar": "moveForwardAlpha", + "characteristicSpeeds": [ + 0.5, + 1.8, + 2.5, + 3.55, + 5.675 ], - "triggerRandomSwitch": "" + "desiredSpeed": 1.4, + "desiredSpeedVar": "moveForwardSpeed" }, - "id": "reactionPoint", - "type": "randomSwitchStateMachine" + "id": "WALKFWD", + "type": "blendLinearMove" + }, + { + "children": [ + ], + "data": { + "endFrame": 13, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle_to_walk.fbx" + }, + "id": "idleToWalkFwd", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 59, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/settle_to_idle_small.fbx" + }, + "id": "idleSettle", + "type": "clip" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 37, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/walk_bwd.fbx" + }, + "id": "walkBwdShort_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 28, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/walk_bwd_fast.fbx" + }, + "id": "walkBwdFast_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 20, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/jog_bwd.fbx" + }, + "id": "jogBwd_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 14, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/run_bwd.fbx" + }, + "id": "runBwd_c", + "type": "clip" + } + ], + "data": { + "alpha": 0, + "alphaVar": "moveBackwardAlpha", + "characteristicSpeeds": [ + 0.6, + 1.6, + 2.8, + 4.5 + ], + "desiredSpeed": 1.4, + "desiredSpeedVar": "moveBackwardSpeed" + }, + "id": "WALKBWD", + "type": "blendLinearMove" + }, + { + "children": [ + ], + "data": { + "endFrame": 33, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/turn_left.fbx" + }, + "id": "turnLeft", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 31, + "loopFlag": true, + "mirrorFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/turn_right.fbx" + }, + "id": "turnRight", + "type": "clip" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 30, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/side_step_short_left.fbx" + }, + "id": "strafeLeftShortStep_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 20, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/side_step_left.fbx" + }, + "id": "strafeLeftStep_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 35, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/walk_left.fbx" + }, + "id": "strafeLeftWalk_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 21, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/walk_left_fast.fbx" + }, + "id": "strafeLeftWalkFast_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 20, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/jog_left.fbx" + }, + "id": "strafeLeftJog_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 19, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/run_fast_left.fbx" + }, + "id": "strafeLeftRun_c", + "type": "clip" + } + ], + "data": { + "alpha": 0, + "alphaVar": "moveLateralAlpha", + "characteristicSpeeds": [ + 0.1, + 0.5, + 1, + 2.55, + 3.35, + 5.25 + ], + "desiredSpeed": 1.4, + "desiredSpeedVar": "moveLateralSpeed" + }, + "id": "STRAFELEFT", + "type": "blendLinearMove" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 30, + "loopFlag": true, + "mirrorFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/side_step_short_left.fbx" + }, + "id": "strafeRightShortStep_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 20, + "loopFlag": true, + "mirrorFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/side_step_left.fbx" + }, + "id": "strafeRightStep_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 35, + "loopFlag": true, + "mirrorFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/walk_right.fbx" + }, + "id": "strafeRightWalk_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 21, + "loopFlag": true, + "mirrorFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/walk_right_fast.fbx" + }, + "id": "strafeRightFast_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 20, + "loopFlag": true, + "mirrorFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/jog_right.fbx" + }, + "id": "strafeRightJog_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 19, + "loopFlag": true, + "mirrorFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/run_fast_right.fbx" + }, + "id": "strafeRightRun_c", + "type": "clip" + } + ], + "data": { + "alpha": 0, + "alphaVar": "moveLateralAlpha", + "characteristicSpeeds": [ + 0.1, + 0.5, + 1, + 2.55, + 3.4, + 5.25 + ], + "desiredSpeed": 1.4, + "desiredSpeedVar": "moveLateralSpeed" + }, + "id": "STRAFERIGHT", + "type": "blendLinearMove" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 30, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/side_step_short_left.fbx" + }, + "id": "stepLeftShort_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 20, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/side_step_left.fbx" + }, + "id": "stepLeft_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 16, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/side_step_left_fast.fbx" + }, + "id": "strafeLeftAnim_c", + "type": "clip" + } + ], + "data": { + "alpha": 0, + "alphaVar": "moveLateralAlpha", + "characteristicSpeeds": [ + 0, + 0.5, + 2.5 + ], + "desiredSpeed": 1.4, + "desiredSpeedVar": "moveLateralSpeed" + }, + "id": "strafeLeftHmd", + "type": "blendLinearMove" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 30, + "loopFlag": true, + "mirrorFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/side_step_short_left.fbx" + }, + "id": "stepRightShort_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 20, + "loopFlag": true, + "mirrorFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/side_step_left.fbx" + }, + "id": "stepRight_c", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 16, + "loopFlag": true, + "mirrorFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/side_step_left_fast.fbx" + }, + "id": "strafeRightAnim_c", + "type": "clip" + } + ], + "data": { + "alpha": 0, + "alphaVar": "moveLateralAlpha", + "characteristicSpeeds": [ + 0, + 0.5, + 2.5 + ], + "desiredSpeed": 1.4, + "desiredSpeedVar": "moveLateralSpeed" + }, + "id": "strafeRightHmd", + "type": "blendLinearMove" + }, + { + "children": [ + ], + "data": { + "endFrame": 79, + "loopFlag": true, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/fly.fbx" + }, + "id": "fly", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 16, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/jump_standing_launch_all.fbx" + }, + "id": "takeoffStand", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 15, + "loopFlag": false, + "startFrame": 4, + "timeScale": 1, + "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx" + }, + "id": "TAKEOFFRUN", + "type": "clip" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 1, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/jump_standing_apex_all.fbx" + }, + "id": "inAirStandPreApex", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 2, + "loopFlag": false, + "startFrame": 2, + "timeScale": 1, + "url": "qrc:///avatar/animations/jump_standing_apex_all.fbx" + }, + "id": "inAirStandApex", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 3, + "loopFlag": false, + "startFrame": 3, + "timeScale": 1, + "url": "qrc:///avatar/animations/jump_standing_apex_all.fbx" + }, + "id": "inAirStandPostApex", + "type": "clip" + } + ], + "data": { + "alpha": 0, + "alphaVar": "inAirAlpha" + }, + "id": "inAirStand", + "type": "blendLinear" + }, + { + "children": [ + { + "children": [ + ], + "data": { + "endFrame": 16, + "loopFlag": false, + "startFrame": 16, + "timeScale": 1, + "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx" + }, + "id": "inAirRunPreApex", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 22, + "loopFlag": false, + "startFrame": 22, + "timeScale": 1, + "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx" + }, + "id": "inAirRunApex", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 33, + "loopFlag": false, + "startFrame": 33, + "timeScale": 1, + "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx" + }, + "id": "inAirRunPostApex", + "type": "clip" + } + ], + "data": { + "alpha": 0, + "alphaVar": "inAirAlpha" + }, + "id": "INAIRRUN", + "type": "blendLinear" + }, + { + "children": [ + ], + "data": { + "endFrame": 6, + "loopFlag": false, + "startFrame": 1, + "timeScale": 1, + "url": "qrc:///avatar/animations/jump_standing_land_settle_all.fbx" + }, + "id": "landStandImpact", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 68, + "loopFlag": false, + "startFrame": 6, + "timeScale": 1, + "url": "qrc:///avatar/animations/jump_standing_land_settle_all.fbx" + }, + "id": "landStand", + "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 40, + "loopFlag": false, + "startFrame": 29, + "timeScale": 1, + "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx" + }, + "id": "LANDRUN", + "type": "clip" } ], "data": { - "currentState": "idleTalkOverlay", + "currentState": "idle", + "outputJoints": [ + "LeftFoot", + "RightFoot" + ], "states": [ { "easingType": "easeInOutQuad", - "id": "idleTalkOverlay", + "id": "seated", + "interpDuration": 6, + "interpTarget": 6, + "interpType": "evaluateBoth", + "transitions": [ + { + "state": "idle", + "var": "isNotMoving" + }, + { + "state": "WALKFWD", + "var": "isMovingForward" + }, + { + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "idle", + "var": "isNotSeated" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "idle", + "interpDuration": 20, + "interpTarget": 20, + "interpType": "evaluateBoth", + "transitions": [ + { + "state": "WALKFWD", + "var": "isMovingForward" + }, + { + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "id": "idleToWalkFwd", + "interpDuration": 8, + "interpTarget": 12, + "transitions": [ + { + "state": "WALKFWD", + "var": "idleToWalkFwdOnDone" + }, + { + "state": "idle", + "var": "isNotMoving" + }, + { + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "idleSettle", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "snapshotPrev", + "transitions": [ + { + "state": "idle", + "var": "idleSettleOnDone" + }, + { + "state": "idle", + "var": "reactionPositiveTrigger" + }, + { + "state": "idle", + "var": "reactionNegativeTrigger" + }, + { + "state": "idle", + "var": "reactionRaiseHandEnabled" + }, + { + "state": "idle", + "var": "reactionApplaudEnabled" + }, + { + "state": "idle", + "var": "reactionPointEnabled" + }, + { + "state": "WALKFWD", + "var": "isMovingForward" + }, + { + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "id": "WALKFWD", + "interpDuration": 15, + "interpTarget": 35, + "interpType": "snapshotPrev", + "transitions": [ + { + "state": "idleSettle", + "var": "isNotMoving" + }, + { + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "id": "WALKBWD", + "interpDuration": 15, + "interpTarget": 35, + "interpType": "snapshotPrev", + "transitions": [ + { + "state": "idleSettle", + "var": "isNotMoving" + }, + { + "state": "WALKFWD", + "var": "isMovingForward" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "id": "STRAFERIGHT", + "interpDuration": 15, + "interpTarget": 25, + "interpType": "snapshotPrev", + "transitions": [ + { + "state": "idleSettle", + "var": "isNotMoving" + }, + { + "state": "WALKFWD", + "var": "isMovingForward" + }, + { + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "id": "STRAFELEFT", + "interpDuration": 15, + "interpTarget": 25, + "interpType": "snapshotPrev", + "transitions": [ + { + "state": "idleSettle", + "var": "isNotMoving" + }, + { + "state": "WALKFWD", + "var": "isMovingForward" + }, + { + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "turnRight", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "transitions": [ + { + "state": "idle", + "var": "isNotTurning" + }, + { + "state": "WALKFWD", + "var": "isMovingForward" + }, + { + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "turnLeft", + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", + "transitions": [ + { + "state": "idle", + "var": "isNotTurning" + }, + { + "state": "WALKFWD", + "var": "isMovingForward" + }, + { + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "id": "strafeRightHmd", + "interpDuration": 8, + "interpTarget": 8, + "interpType": "snapshotPrev", + "transitions": [ + { + "state": "idleSettle", + "var": "isNotMoving" + }, + { + "state": "WALKFWD", + "var": "isMovingForward" + }, + { + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "id": "strafeLeftHmd", + "interpDuration": 8, + "interpTarget": 8, + "interpType": "snapshotPrev", + "transitions": [ + { + "state": "idleSettle", + "var": "isNotMoving" + }, + { + "state": "WALKFWD", + "var": "isMovingForward" + }, + { + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "easingType": "easeInOutQuad", + "id": "fly", "interpDuration": 24, "interpTarget": 24, "interpType": "evaluateBoth", "transitions": [ { - "state": "reactionPositive", - "var": "reactionPositiveTrigger" - }, - { - "state": "reactionNegative", - "var": "reactionNegativeTrigger" - }, - { - "state": "reactionRaiseHand", - "var": "reactionRaiseHandEnabled" - }, - { - "state": "reactionApplaud", - "var": "reactionApplaudEnabled" - }, - { - "state": "reactionPoint", - "var": "reactionPointEnabled" + "state": "idleSettle", + "var": "isNotFlying" } ] }, { - "easingType": "easeInOutQuad", - "id": "reactionPositive", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", + "id": "takeoffStand", + "interpDuration": 2, + "interpTarget": 2, "transitions": [ { - "state": "idleTalkOverlay", - "var": "positiveAcknowledgeOnDone" - }, - { - "state": "idleTalkOverlay", - "var": "positiveHeadNodOnDone" - }, - { - "state": "idleTalkOverlay", - "var": "positiveHeadNodYesOnDone" - }, - { - "state": "idleTalkOverlay", - "var": "positiveLongHeadNodOnDone" - }, - { - "state": "idleTalkOverlay", - "var": "positiveThoughtfulHeadNodOnDone" - }, - { - "state": "reactionNegative", - "var": "reactionNegativeTrigger" - }, - { - "state": "reactionRaiseHand", - "var": "reactionRaiseHandEnabled" - }, - { - "state": "reactionApplaud", - "var": "reactionApplaudEnabled" - }, - { - "state": "reactionPoint", - "var": "reactionPointEnabled" + "state": "inAirStand", + "var": "isNotTakeoff" } ] }, { - "easingType": "easeInOutQuad", - "id": "reactionNegative", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", + "id": "TAKEOFFRUN", + "interpDuration": 2, + "interpTarget": 2, "transitions": [ { - "state": "reactionPositive", - "var": "reactionPositiveTrigger" - }, - { - "state": "idleTalkOverlay", - "var": "negativeAnnoyedHeadshakeOnDone" - }, - { - "state": "idleTalkOverlay", - "var": "negativeThoughtfulHeadshakeOnDone" - }, - { - "state": "idleTalkOverlay", - "var": "negativeDropHeadOnDone" - }, - { - "state": "reactionRaiseHand", - "var": "reactionRaiseHandEnabled" - }, - { - "state": "reactionApplaud", - "var": "reactionApplaudEnabled" - }, - { - "state": "reactionPoint", - "var": "reactionPointEnabled" + "state": "INAIRRUN", + "var": "isNotTakeoff" } ] }, { - "easingType": "easeInOutQuad", - "id": "reactionRaiseHand", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", + "id": "inAirStand", + "interpDuration": 3, + "interpTarget": 3, + "interpType": "snapshotPrev", "transitions": [ { - "state": "reactionNegative", - "var": "reactionNegativeTrigger" - }, - { - "state": "reactionPositive", - "var": "reactionPositiveTrigger" - }, - { - "state": "idleTalkOverlay", - "var": "reactionRaiseHandDisabled" - }, - { - "state": "reactionApplaud", - "var": "reactionApplaudEnabled" - }, - { - "state": "reactionPoint", - "var": "reactionPointEnabled" + "state": "landStandImpact", + "var": "isNotInAir" } ] }, { - "easingType": "easeInOutQuad", - "id": "reactionApplaud", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", + "id": "INAIRRUN", + "interpDuration": 3, + "interpTarget": 3, + "interpType": "snapshotPrev", "transitions": [ { - "state": "reactionNegative", - "var": "reactionNegativeTrigger" - }, - { - "state": "reactionPositive", - "var": "reactionPositiveTrigger" - }, - { - "state": "reactionRaiseHand", - "var": "reactionRaiseHandEnabled" - }, - { - "state": "idleTalkOverlay", - "var": "reactionApplaudDisabled" - }, - { - "state": "reactionPoint", - "var": "reactionPointEnabled" + "state": "WALKFWD", + "var": "isNotInAir" } ] }, { - "easingType": "easeInOutQuad", - "id": "reactionPoint", - "interpDuration": 18, - "interpTarget": 18, - "interpType": "evaluateBoth", + "id": "landStandImpact", + "interpDuration": 1, + "interpTarget": 1, "transitions": [ { - "state": "reactionNegative", - "var": "reactionNegativeTrigger" + "state": "fly", + "var": "isFlying" }, { - "state": "reactionPositive", - "var": "reactionPositiveTrigger" + "state": "takeoffStand", + "var": "isTakeoffStand" }, { - "state": "reactionRaiseHand", - "var": "reactionRaiseHandEnabled" + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" }, { - "state": "reactionApplaud", - "var": "reactionApplaudEnabled" + "state": "landStand", + "var": "landStandImpactOnDone" + } + ] + }, + { + "id": "landStand", + "interpDuration": 1, + "interpTarget": 1, + "transitions": [ + { + "state": "WALKFWD", + "var": "isMovingForward" }, { - "state": "idleTalkOverlay", - "var": "reactionPointDisabled" + "state": "WALKBWD", + "var": "isMovingBackward" + }, + { + "state": "STRAFERIGHT", + "var": "isMovingRight" + }, + { + "state": "STRAFELEFT", + "var": "isMovingLeft" + }, + { + "state": "turnRight", + "var": "isTurningRight" + }, + { + "state": "turnLeft", + "var": "isTurningLeft" + }, + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "inAirStand", + "var": "isInAirStand" + }, + { + "state": "INAIRRUN", + "var": "isInAirRun" + }, + { + "state": "idle", + "var": "landStandOnDone" + }, + { + "state": "strafeRightHmd", + "var": "isMovingRightHmd" + }, + { + "state": "strafeLeftHmd", + "var": "isMovingLeftHmd" + }, + { + "state": "seated", + "var": "isSeated" + } + ] + }, + { + "id": "LANDRUN", + "interpDuration": 2, + "interpTarget": 2, + "transitions": [ + { + "state": "fly", + "var": "isFlying" + }, + { + "state": "takeoffStand", + "var": "isTakeoffStand" + }, + { + "state": "TAKEOFFRUN", + "var": "isTakeoffRun" + }, + { + "state": "WALKFWD", + "var": "landRunOnDone" } ] } ] }, - "id": "idle", + "id": "mainStateMachine", "type": "stateMachine" }, { @@ -3355,1637 +5892,175 @@ "children": [ ], "data": { - "endFrame": 40, + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/idle_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 11, "loopFlag": true, - "startFrame": 1, + "startFrame": 11, "timeScale": 1, - "url": "qrc:///avatar/animations/walk_short_fwd.fbx" + "url": "qrc:///avatar/animations/idle_aimoffsets.fbx" }, - "id": "walkFwdShort_c", + "id": "lookLeft", "type": "clip" }, { "children": [ ], "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/idle_aimoffsets.fbx", + "blendType": "addAbsolute", "endFrame": 30, "loopFlag": true, - "startFrame": 1, + "startFrame": 30, "timeScale": 1, - "url": "qrc:///avatar/animations/walk_fwd.fbx" + "url": "qrc:///avatar/animations/idle_aimoffsets.fbx" }, - "id": "walkFwdNormal_c", + "id": "lookRight", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 26, + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/idle_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 50, "loopFlag": true, - "startFrame": 1, + "startFrame": 50, "timeScale": 1, - "url": "qrc:///avatar/animations/walk_fwd_fast.fbx" + "url": "qrc:///avatar/animations/idle_aimoffsets.fbx" }, - "id": "walkFwdFast_c", + "id": "lookUp", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 18, + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/idle_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 70, "loopFlag": true, - "startFrame": 1, + "startFrame": 70, "timeScale": 1, - "url": "qrc:///avatar/animations/jog_fwd.fbx" + "url": "qrc:///avatar/animations/idle_aimoffsets.fbx" }, - "id": "walkFwdJog_c", + "id": "lookDown", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 19, + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/idle_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 97, "loopFlag": true, - "startFrame": 1, + "startFrame": 97, "timeScale": 1, - "url": "qrc:///avatar/animations/run_fast_fwd.fbx" + "url": "qrc:///avatar/animations/idle_aimoffsets.fbx" }, - "id": "walkFwdRun_c", - "type": "clip" - } - ], - "data": { - "alpha": 0, - "alphaVar": "moveForwardAlpha", - "characteristicSpeeds": [ - 0.5, - 1.8, - 2.5, - 3.55, - 5.675 - ], - "desiredSpeed": 1.4, - "desiredSpeedVar": "moveForwardSpeed" - }, - "id": "WALKFWD", - "type": "blendLinearMove" - }, - { - "children": [ - ], - "data": { - "endFrame": 13, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle_to_walk.fbx" - }, - "id": "idleToWalkFwd", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 59, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/settle_to_idle_small.fbx" - }, - "id": "idleSettle", - "type": "clip" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 37, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/walk_bwd.fbx" - }, - "id": "walkBwdShort_c", + "id": "lookUpLeft", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 28, + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/idle_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 110, "loopFlag": true, - "startFrame": 1, + "startFrame": 110, "timeScale": 1, - "url": "qrc:///avatar/animations/walk_bwd_fast.fbx" + "url": "qrc:///avatar/animations/idle_aimoffsets.fbx" }, - "id": "walkBwdFast_c", + "id": "lookUpRight", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 20, + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/idle_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 130, "loopFlag": true, - "startFrame": 1, + "startFrame": 130, "timeScale": 1, - "url": "qrc:///avatar/animations/jog_bwd.fbx" + "url": "qrc:///avatar/animations/idle_aimoffsets.fbx" }, - "id": "jogBwd_c", + "id": "lookDownLeft", "type": "clip" }, { "children": [ ], "data": { - "endFrame": 14, + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/idle_aimoffsets.fbx", + "blendType": "addAbsolute", + "endFrame": 150, "loopFlag": true, - "startFrame": 1, + "startFrame": 150, "timeScale": 1, - "url": "qrc:///avatar/animations/run_bwd.fbx" + "url": "qrc:///avatar/animations/idle_aimoffsets.fbx" }, - "id": "runBwd_c", - "type": "clip" - } - ], - "data": { - "alpha": 0, - "alphaVar": "moveBackwardAlpha", - "characteristicSpeeds": [ - 0.6, - 1.6, - 2.8, - 4.5 - ], - "desiredSpeed": 1.4, - "desiredSpeedVar": "moveBackwardSpeed" - }, - "id": "WALKBWD", - "type": "blendLinearMove" - }, - { - "children": [ - ], - "data": { - "endFrame": 33, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/turn_left.fbx" - }, - "id": "turnLeft", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 31, - "loopFlag": true, - "mirrorFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/turn_right.fbx" - }, - "id": "turnRight", - "type": "clip" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 30, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/side_step_short_left.fbx" - }, - "id": "strafeLeftShortStep_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 20, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/side_step_left.fbx" - }, - "id": "strafeLeftStep_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 35, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/walk_left.fbx" - }, - "id": "strafeLeftWalk_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 21, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/walk_left_fast.fbx" - }, - "id": "strafeLeftWalkFast_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 20, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/jog_left.fbx" - }, - "id": "strafeLeftJog_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 19, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/run_fast_left.fbx" - }, - "id": "strafeLeftRun_c", - "type": "clip" - } - ], - "data": { - "alpha": 0, - "alphaVar": "moveLateralAlpha", - "characteristicSpeeds": [ - 0.1, - 0.5, - 1, - 2.55, - 3.35, - 5.25 - ], - "desiredSpeed": 1.4, - "desiredSpeedVar": "moveLateralSpeed" - }, - "id": "STRAFELEFT", - "type": "blendLinearMove" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 30, - "loopFlag": true, - "mirrorFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/side_step_short_left.fbx" - }, - "id": "strafeRightShortStep_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 20, - "loopFlag": true, - "mirrorFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/side_step_left.fbx" - }, - "id": "strafeRightStep_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 35, - "loopFlag": true, - "mirrorFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/walk_right.fbx" - }, - "id": "strafeRightWalk_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 21, - "loopFlag": true, - "mirrorFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/walk_right_fast.fbx" - }, - "id": "strafeRightFast_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 20, - "loopFlag": true, - "mirrorFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/jog_right.fbx" - }, - "id": "strafeRightJog_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 19, - "loopFlag": true, - "mirrorFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/run_fast_right.fbx" - }, - "id": "strafeRightRun_c", - "type": "clip" - } - ], - "data": { - "alpha": 0, - "alphaVar": "moveLateralAlpha", - "characteristicSpeeds": [ - 0.1, - 0.5, - 1, - 2.55, - 3.4, - 5.25 - ], - "desiredSpeed": 1.4, - "desiredSpeedVar": "moveLateralSpeed" - }, - "id": "STRAFERIGHT", - "type": "blendLinearMove" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 30, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/side_step_short_left.fbx" - }, - "id": "stepLeftShort_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 20, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/side_step_left.fbx" - }, - "id": "stepLeft_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 16, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/side_step_left_fast.fbx" - }, - "id": "strafeLeftAnim_c", - "type": "clip" - } - ], - "data": { - "alpha": 0, - "alphaVar": "moveLateralAlpha", - "characteristicSpeeds": [ - 0, - 0.5, - 2.5 - ], - "desiredSpeed": 1.4, - "desiredSpeedVar": "moveLateralSpeed" - }, - "id": "strafeLeftHmd", - "type": "blendLinearMove" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 30, - "loopFlag": true, - "mirrorFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/side_step_short_left.fbx" - }, - "id": "stepRightShort_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 20, - "loopFlag": true, - "mirrorFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/side_step_left.fbx" - }, - "id": "stepRight_c", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 16, - "loopFlag": true, - "mirrorFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/side_step_left_fast.fbx" - }, - "id": "strafeRightAnim_c", - "type": "clip" - } - ], - "data": { - "alpha": 0, - "alphaVar": "moveLateralAlpha", - "characteristicSpeeds": [ - 0, - 0.5, - 2.5 - ], - "desiredSpeed": 1.4, - "desiredSpeedVar": "moveLateralSpeed" - }, - "id": "strafeRightHmd", - "type": "blendLinearMove" - }, - { - "children": [ - ], - "data": { - "endFrame": 79, - "loopFlag": true, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/fly.fbx" - }, - "id": "fly", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 16, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/jump_standing_launch_all.fbx" - }, - "id": "takeoffStand", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 15, - "loopFlag": false, - "startFrame": 4, - "timeScale": 1, - "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx" - }, - "id": "TAKEOFFRUN", - "type": "clip" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 1, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/jump_standing_apex_all.fbx" - }, - "id": "inAirStandPreApex", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 2, - "loopFlag": false, - "startFrame": 2, - "timeScale": 1, - "url": "qrc:///avatar/animations/jump_standing_apex_all.fbx" - }, - "id": "inAirStandApex", + "id": "lookDownRight", "type": "clip" }, { "children": [ ], "data": { + "baseFrame": 1, + "baseURL": "qrc:///avatar/animations/idle_aimoffsets.fbx", + "blendType": "addAbsolute", "endFrame": 3, - "loopFlag": false, + "loopFlag": true, "startFrame": 3, "timeScale": 1, - "url": "qrc:///avatar/animations/jump_standing_apex_all.fbx" + "url": "qrc:///avatar/animations/idle_aimoffsets.fbx" }, - "id": "inAirStandPostApex", + "id": "lookCenter", "type": "clip" } ], "data": { - "alpha": 0, - "alphaVar": "inAirAlpha" + "alpha": [ + 0, + 0, + 0 + ], + "alphaVar": "lookAroundAlpha", + "centerId": "lookCenter", + "downId": "lookDown", + "downLeftId": "lookDownLeft", + "downRightId": "lookDownRight", + "leftId": "lookLeft", + "rightId": "lookRight", + "upId": "lookUp", + "upLeftId": "lookUpLeft", + "upRightId": "lookUpRight" }, - "id": "inAirStand", - "type": "blendLinear" - }, - { - "children": [ - { - "children": [ - ], - "data": { - "endFrame": 16, - "loopFlag": false, - "startFrame": 16, - "timeScale": 1, - "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx" - }, - "id": "inAirRunPreApex", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 22, - "loopFlag": false, - "startFrame": 22, - "timeScale": 1, - "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx" - }, - "id": "inAirRunApex", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 33, - "loopFlag": false, - "startFrame": 33, - "timeScale": 1, - "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx" - }, - "id": "inAirRunPostApex", - "type": "clip" - } - ], - "data": { - "alpha": 0, - "alphaVar": "inAirAlpha" - }, - "id": "INAIRRUN", - "type": "blendLinear" - }, - { - "children": [ - ], - "data": { - "endFrame": 6, - "loopFlag": false, - "startFrame": 1, - "timeScale": 1, - "url": "qrc:///avatar/animations/jump_standing_land_settle_all.fbx" - }, - "id": "landStandImpact", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 68, - "loopFlag": false, - "startFrame": 6, - "timeScale": 1, - "url": "qrc:///avatar/animations/jump_standing_land_settle_all.fbx" - }, - "id": "landStand", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 40, - "loopFlag": false, - "startFrame": 29, - "timeScale": 1, - "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx" - }, - "id": "LANDRUN", - "type": "clip" - }, - { - "children": [ - ], - "data": { - "endFrame": 105, - "loopFlag": false, - "startFrame": 100, - "timeScale": 1, - "url": "qrc:///avatar/animations/idle.fbx" - }, - "id": "seatedToIdle", - "type": "clip" + "id": "lookAroundBlend", + "type": "blendDirectional" } ], "data": { - "currentState": "idle", - "outputJoints": [ - "LeftFoot", - "RightFoot" - ], - "states": [ - { - "easingType": "easeInOutQuad", - "id": "seated", - "interpDuration": 18, - "interpTarget": 20, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "seatedToIdle", - "var": "isNotSeated" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "idle", - "interpDuration": 30, - "interpTarget": 30, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "WALKFWD", - "var": "isMovingForward" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "id": "idleToWalkFwd", - "interpDuration": 8, - "interpTarget": 12, - "transitions": [ - { - "state": "WALKFWD", - "var": "idleToWalkFwdOnDone" - }, - { - "state": "idle", - "var": "isNotMoving" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "idleSettle", - "interpDuration": 12, - "interpTarget": 12, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "idle", - "var": "idleSettleOnDone" - }, - { - "state": "WALKFWD", - "var": "isMovingForward" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "id": "WALKFWD", - "interpDuration": 10, - "interpTarget": 35, - "interpType": "snapshotPrev", - "transitions": [ - { - "state": "idleSettle", - "var": "isNotMoving" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "id": "WALKBWD", - "interpDuration": 10, - "interpTarget": 35, - "interpType": "snapshotPrev", - "transitions": [ - { - "state": "idleSettle", - "var": "isNotMoving" - }, - { - "state": "WALKFWD", - "var": "isMovingForward" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "id": "STRAFERIGHT", - "interpDuration": 8, - "interpTarget": 25, - "interpType": "snapshotPrev", - "transitions": [ - { - "state": "idleSettle", - "var": "isNotMoving" - }, - { - "state": "WALKFWD", - "var": "isMovingForward" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "id": "STRAFELEFT", - "interpDuration": 8, - "interpTarget": 25, - "interpType": "snapshotPrev", - "transitions": [ - { - "state": "idleSettle", - "var": "isNotMoving" - }, - { - "state": "WALKFWD", - "var": "isMovingForward" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "turnRight", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "idle", - "var": "isNotTurning" - }, - { - "state": "WALKFWD", - "var": "isMovingForward" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "turnLeft", - "interpDuration": 15, - "interpTarget": 15, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "idle", - "var": "isNotTurning" - }, - { - "state": "WALKFWD", - "var": "isMovingForward" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "id": "strafeRightHmd", - "interpDuration": 8, - "interpTarget": 8, - "interpType": "snapshotPrev", - "transitions": [ - { - "state": "idleSettle", - "var": "isNotMoving" - }, - { - "state": "WALKFWD", - "var": "isMovingForward" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "id": "strafeLeftHmd", - "interpDuration": 8, - "interpTarget": 8, - "interpType": "snapshotPrev", - "transitions": [ - { - "state": "idleSettle", - "var": "isNotMoving" - }, - { - "state": "WALKFWD", - "var": "isMovingForward" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "easingType": "easeInOutQuad", - "id": "fly", - "interpDuration": 24, - "interpTarget": 24, - "interpType": "evaluateBoth", - "transitions": [ - { - "state": "idleSettle", - "var": "isNotFlying" - } - ] - }, - { - "id": "takeoffStand", - "interpDuration": 2, - "interpTarget": 2, - "transitions": [ - { - "state": "inAirStand", - "var": "isNotTakeoff" - } - ] - }, - { - "id": "TAKEOFFRUN", - "interpDuration": 2, - "interpTarget": 2, - "transitions": [ - { - "state": "INAIRRUN", - "var": "isNotTakeoff" - } - ] - }, - { - "id": "inAirStand", - "interpDuration": 3, - "interpTarget": 3, - "interpType": "snapshotPrev", - "transitions": [ - { - "state": "landStandImpact", - "var": "isNotInAir" - } - ] - }, - { - "id": "INAIRRUN", - "interpDuration": 3, - "interpTarget": 3, - "interpType": "snapshotPrev", - "transitions": [ - { - "state": "WALKFWD", - "var": "isNotInAir" - } - ] - }, - { - "id": "landStandImpact", - "interpDuration": 1, - "interpTarget": 1, - "transitions": [ - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "landStand", - "var": "landStandImpactOnDone" - } - ] - }, - { - "id": "landStand", - "interpDuration": 1, - "interpTarget": 1, - "transitions": [ - { - "state": "WALKFWD", - "var": "isMovingForward" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "idle", - "var": "landStandOnDone" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" - }, - { - "state": "seated", - "var": "isSeated" - } - ] - }, - { - "id": "LANDRUN", - "interpDuration": 2, - "interpTarget": 2, - "transitions": [ - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "WALKFWD", - "var": "landRunOnDone" - } - ] - }, - { - "id": "seatedToIdle", - "interpDuration": 10, - "interpTarget": 1, - "interpType": "snapshotPrev", - "transitions": [ - { - "state": "idle", - "var": "seatedToIdleOnDone" - } - ] - } - ] + "alpha": 0, + "alphaVar": "lookBlendAlpha", + "blendType": "addAbsolute" }, - "id": "mainStateMachine", - "type": "stateMachine" + "id": "lookAround", + "type": "blendLinear" } ], "data": { @@ -5131,9 +6206,11 @@ "currentState": "userAnimNone", "states": [ { + "easingType": "easeInOutQuad", "id": "userAnimNone", - "interpDuration": 6, - "interpTarget": 6, + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", "transitions": [ { "state": "userAnimA", @@ -5146,9 +6223,11 @@ ] }, { + "easingType": "easeInOutQuad", "id": "userAnimA", - "interpDuration": 6, - "interpTarget": 6, + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", "transitions": [ { "state": "userAnimNone", @@ -5161,9 +6240,11 @@ ] }, { + "easingType": "easeInOutQuad", "id": "userAnimB", - "interpDuration": 6, - "interpTarget": 6, + "interpDuration": 15, + "interpTarget": 15, + "interpType": "evaluateBoth", "transitions": [ { "state": "userAnimNone", diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json index 9b3c711c63..eb07c9a6dd 100644 --- a/interface/resources/controllers/keyboardMouse.json +++ b/interface/resources/controllers/keyboardMouse.json @@ -3,8 +3,10 @@ "channels": [ { "from": "Keyboard.A", "when": ["Keyboard.RightMouseButton", "!Keyboard.Control"], "to": "Actions.LATERAL_LEFT" }, { "from": "Keyboard.D", "when": ["Keyboard.RightMouseButton", "!Keyboard.Control"], "to": "Actions.LATERAL_RIGHT" }, - { "from": "Keyboard.E", "when": "!Keyboard.Control", "to": "Actions.LATERAL_RIGHT" }, - { "from": "Keyboard.Q", "when": "!Keyboard.Control", "to": "Actions.LATERAL_LEFT" }, + { "from": "Keyboard.E", "when": ["!Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LATERAL_RIGHT" }, + { "from": "Keyboard.Q", "when": ["!Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LATERAL_LEFT" }, + { "from": "Keyboard.Q", "when": ["Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LATERAL_RIGHT" }, + { "from": "Keyboard.E", "when": ["Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LATERAL_LEFT" }, { "from": "Keyboard.T", "when": "!Keyboard.Control", "to": "Actions.TogglePushToTalk" }, { "comment" : "Mouse turn need to be small continuous increments", @@ -39,7 +41,6 @@ ] }, - { "from": { "makeAxis" : [ ["Keyboard.Left" ], ["Keyboard.Right"] @@ -85,6 +86,24 @@ "when": ["Application.CameraThirdPerson", "!Keyboard.Shift"], "to": "Actions.Yaw" }, + + { "from": { "makeAxis" : [ + ["Keyboard.Left"], + ["Keyboard.Right"] + ] + }, + "when": ["Application.CameraLookAt", "!Keyboard.Shift"], + "to": "Actions.Yaw" + }, + + { "from": { "makeAxis" : [ + ["Keyboard.Left"], + ["Keyboard.Right"] + ] + }, + "when": ["Application.CameraSelfie", "!Keyboard.Shift"], + "to": "Actions.Yaw" + }, { "from": { "makeAxis" : [ ["Keyboard.A"], @@ -104,6 +123,24 @@ "to": "Actions.Yaw" }, + { "from": { "makeAxis" : [ + ["Keyboard.A"], + ["Keyboard.D"] + ] + }, + "when": ["Application.CameraLookAt", "!Keyboard.Control"], + "to": "Actions.Yaw" + }, + + { "from": { "makeAxis" : [ + ["Keyboard.A"], + ["Keyboard.D"] + ] + }, + "when": ["Application.CameraSelfie", "!Keyboard.Control"], + "to": "Actions.Yaw" + }, + { "from": { "makeAxis" : [ ["Keyboard.TouchpadLeft"], ["Keyboard.TouchpadRight"] @@ -122,6 +159,24 @@ "to": "Actions.Yaw" }, + { "from": { "makeAxis" : [ + ["Keyboard.TouchpadLeft"], + ["Keyboard.TouchpadRight"] + ] + }, + "when": "Application.CameraLookAt", + "to": "Actions.Yaw" + }, + + { "from": { "makeAxis" : [ + ["Keyboard.TouchpadLeft"], + ["Keyboard.TouchpadRight"] + ] + }, + "when": "Application.CameraSelfie", + "to": "Actions.Yaw" + }, + { "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] }, "when": "Keyboard.RightMouseButton", "to": "Actions.DeltaYaw", @@ -132,7 +187,7 @@ }, { "from": { "makeAxis" : ["Keyboard.MouseMoveUp", "Keyboard.MouseMoveDown"] }, - "when": "Keyboard.RightMouseButton", + "when": ["!Application.CameraSelfie", "!Application.CameraLookAt", "Keyboard.RightMouseButton"], "to": "Actions.DeltaPitch", "filters": [ @@ -140,16 +195,40 @@ ] }, - { "from": "Keyboard.W", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_FORWARD" }, - { "from": "Keyboard.S", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_BACKWARD" }, + { "from": { "makeAxis" : ["Keyboard.MouseMoveUp", "Keyboard.MouseMoveDown"] }, + "when": ["Application.CameraLookAt", "Keyboard.RightMouseButton"], + "to": "Actions.DeltaPitch", + "filters": + [ + { "type": "scale", "scale": 0.2 } + ] + }, + + { "from": { "makeAxis" : ["Keyboard.MouseMoveDown", "Keyboard.MouseMoveUp"] }, + "when": ["Application.CameraSelfie", "Keyboard.RightMouseButton"], + "to": "Actions.DeltaPitch", + "filters": + [ + { "type": "scale", "scale": 0.2 } + ] + }, + + { "from": "Keyboard.W", "when": ["!Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LONGITUDINAL_FORWARD" }, + { "from": "Keyboard.S", "when": ["!Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LONGITUDINAL_BACKWARD" }, + { "from": "Keyboard.S", "when": ["Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LONGITUDINAL_FORWARD" }, + { "from": "Keyboard.W", "when": ["Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LONGITUDINAL_BACKWARD" }, { "from": "Keyboard.Shift", "when": ["!Keyboard.Left", "!Keyboard.Right"], "to": "Actions.SPRINT" }, { "from": "Keyboard.C", "when": "!Keyboard.Control", "to": "Actions.VERTICAL_DOWN" }, { "from": "Keyboard.Left", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" }, { "from": "Keyboard.Right", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" }, { "from": "Keyboard.Up", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_FORWARD" }, { "from": "Keyboard.Up", "when": "Application.CameraThirdPerson", "to": "Actions.LONGITUDINAL_FORWARD" }, + { "from": "Keyboard.Up", "when": "Application.CameraLookAt", "to": "Actions.LONGITUDINAL_FORWARD" }, + { "from": "Keyboard.Up", "when": "Application.CameraSelfie", "to": "Actions.LONGITUDINAL_BACKWARD" }, { "from": "Keyboard.Down", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_BACKWARD" }, { "from": "Keyboard.Down", "when": "Application.CameraThirdPerson", "to": "Actions.LONGITUDINAL_BACKWARD" }, + { "from": "Keyboard.Down", "when": "Application.CameraLookAt", "to": "Actions.LONGITUDINAL_BACKWARD" }, + { "from": "Keyboard.Down", "when": "Application.CameraSelfie", "to": "Actions.LONGITUDINAL_FORWARD" }, { "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" }, { "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" }, diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index 0a5bd12460..195f909942 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -162,7 +162,14 @@ { "from": "Standard.Head", "to": "Actions.Head" }, { "from": "Standard.LeftArm", "to": "Actions.LeftArm" }, { "from": "Standard.RightArm", "to": "Actions.RightArm" }, - + + { "from": "Standard.LeftEye", "to": "Actions.LeftEye" }, + { "from": "Standard.RightEye", "to": "Actions.RightEye" }, + + { "from": "Standard.LeftEyeBlink", "to": "Actions.LeftEyeBlink" }, + { "from": "Standard.RightEyeBlink", "to": "Actions.RightEyeBlink" }, + + { "from": "Standard.TrackedObject00", "to" : "Actions.TrackedObject00" }, { "from": "Standard.TrackedObject01", "to" : "Actions.TrackedObject01" }, { "from": "Standard.TrackedObject02", "to" : "Actions.TrackedObject02" }, diff --git a/interface/resources/controllers/standard_nomovement.json b/interface/resources/controllers/standard_nomovement.json index 015bc33056..602d3bb798 100644 --- a/interface/resources/controllers/standard_nomovement.json +++ b/interface/resources/controllers/standard_nomovement.json @@ -57,7 +57,13 @@ { "from": "Standard.Head", "to": "Actions.Head" }, { "from": "Standard.LeftArm", "to": "Actions.LeftArm" }, { "from": "Standard.RightArm", "to": "Actions.RightArm" }, - + + { "from": "Standard.LeftEye", "to": "Actions.LeftEye" }, + { "from": "Standard.RightEye", "to": "Actions.RightEye" }, + + { "from": "Standard.LeftEyeBlink", "to": "Actions.LeftEyeBlink" }, + { "from": "Standard.RightEyeBlink", "to": "Actions.RightEyeBlink" }, + { "from": "Standard.TrackedObject00", "to" : "Actions.TrackedObject00" }, { "from": "Standard.TrackedObject01", "to" : "Actions.TrackedObject01" }, { "from": "Standard.TrackedObject02", "to" : "Actions.TrackedObject02" }, diff --git a/interface/resources/controllers/vive.json b/interface/resources/controllers/vive.json index 730e1bcb58..b6fae1dd79 100644 --- a/interface/resources/controllers/vive.json +++ b/interface/resources/controllers/vive.json @@ -54,8 +54,52 @@ { "from": "Vive.RightApplicationMenu", "to": "Standard.RightSecondaryThumb" }, { "from": "Vive.LeftHand", "to": "Standard.LeftHand" }, + { "from": "Vive.LeftHandThumb1", "to": "Standard.LeftHandThumb1"}, + { "from": "Vive.LeftHandThumb2", "to": "Standard.LeftHandThumb2"}, + { "from": "Vive.LeftHandThumb3", "to": "Standard.LeftHandThumb3"}, + { "from": "Vive.LeftHandThumb4", "to": "Standard.LeftHandThumb4"}, + { "from": "Vive.LeftHandIndex1", "to": "Standard.LeftHandIndex1"}, + { "from": "Vive.LeftHandIndex2", "to": "Standard.LeftHandIndex2"}, + { "from": "Vive.LeftHandIndex3", "to": "Standard.LeftHandIndex3"}, + { "from": "Vive.LeftHandIndex4", "to": "Standard.LeftHandIndex4"}, + { "from": "Vive.LeftHandMiddle1", "to": "Standard.LeftHandMiddle1"}, + { "from": "Vive.LeftHandMiddle2", "to": "Standard.LeftHandMiddle2"}, + { "from": "Vive.LeftHandMiddle3", "to": "Standard.LeftHandMiddle3"}, + { "from": "Vive.LeftHandMiddle4", "to": "Standard.LeftHandMiddle4"}, + { "from": "Vive.LeftHandRing1", "to": "Standard.LeftHandRing1"}, + { "from": "Vive.LeftHandRing2", "to": "Standard.LeftHandRing2"}, + { "from": "Vive.LeftHandRing3", "to": "Standard.LeftHandRing3"}, + { "from": "Vive.LeftHandRing4", "to": "Standard.LeftHandRing4"}, + { "from": "Vive.LeftHandPinky1", "to": "Standard.LeftHandPinky1"}, + { "from": "Vive.LeftHandPinky2", "to": "Standard.LeftHandPinky2"}, + { "from": "Vive.LeftHandPinky3", "to": "Standard.LeftHandPinky3"}, + { "from": "Vive.LeftHandPinky4", "to": "Standard.LeftHandPinky4"}, { "from": "Vive.RightHand", "to": "Standard.RightHand" }, + { "from": "Vive.RightHandThumb1", "to": "Standard.RightHandThumb1"}, + { "from": "Vive.RightHandThumb2", "to": "Standard.RightHandThumb2"}, + { "from": "Vive.RightHandThumb3", "to": "Standard.RightHandThumb3"}, + { "from": "Vive.RightHandThumb4", "to": "Standard.RightHandThumb4"}, + { "from": "Vive.RightHandIndex1", "to": "Standard.RightHandIndex1"}, + { "from": "Vive.RightHandIndex2", "to": "Standard.RightHandIndex2"}, + { "from": "Vive.RightHandIndex3", "to": "Standard.RightHandIndex3"}, + { "from": "Vive.RightHandIndex4", "to": "Standard.RightHandIndex4"}, + { "from": "Vive.RightHandMiddle1", "to": "Standard.RightHandMiddle1"}, + { "from": "Vive.RightHandMiddle2", "to": "Standard.RightHandMiddle2"}, + { "from": "Vive.RightHandMiddle3", "to": "Standard.RightHandMiddle3"}, + { "from": "Vive.RightHandMiddle4", "to": "Standard.RightHandMiddle4"}, + { "from": "Vive.RightHandRing1", "to": "Standard.RightHandRing1"}, + { "from": "Vive.RightHandRing2", "to": "Standard.RightHandRing2"}, + { "from": "Vive.RightHandRing3", "to": "Standard.RightHandRing3"}, + { "from": "Vive.RightHandRing4", "to": "Standard.RightHandRing4"}, + { "from": "Vive.RightHandPinky1", "to": "Standard.RightHandPinky1"}, + { "from": "Vive.RightHandPinky2", "to": "Standard.RightHandPinky2"}, + { "from": "Vive.RightHandPinky3", "to": "Standard.RightHandPinky3"}, + { "from": "Vive.RightHandPinky4", "to": "Standard.RightHandPinky4"}, { "from": "Vive.Head", "to" : "Standard.Head" }, + { "from": "Vive.LeftEye", "to" : "Standard.LeftEye" }, + { "from": "Vive.RightEye", "to" : "Standard.RightEye" }, + { "from": "Vive.LeftEyeBlink", "to" : "Standard.LeftEyeBlink" }, + { "from": "Vive.RightEyeBlink", "to" : "Standard.RightEyeBlink" }, { "from": "Vive.LeftFoot", "to" : "Standard.LeftFoot", diff --git a/interface/resources/html/tabletHelp.html b/interface/resources/html/tabletHelp.html index 1140f045db..e83c0cc388 100644 --- a/interface/resources/html/tabletHelp.html +++ b/interface/resources/html/tabletHelp.html @@ -1,4 +1,4 @@ - + @@ -77,9 +77,9 @@ var handControllerImageURL = null; var index = 0; var count = 3; - var handControllerRefURL = "https://docs.highfidelity.com/en/rc81/explore/get-started/vr-controls.html#vr-controls"; - var keyboardRefURL = "https://docs.highfidelity.com/en/rc81/explore/get-started/desktop.html#movement-controls"; - var gamepadRefURL = "https://docs.highfidelity.com/en/rc81/explore/get-started/vr-controls.html#gamepad"; + var handControllerRefURL = "https://docs.highfidelity.com/explore/get-started/vr-controls.html#vr-controls"; + var keyboardRefURL = "https://docs.highfidelity.com/explore/get-started/desktop.html#movement-controls"; + var gamepadRefURL = "https://docs.highfidelity.com/explore/get-started/vr-controls.html#gamepad"; function showKbm() { document.getElementById("main_image").setAttribute("src", "img/tablet-help-keyboard.jpg"); diff --git a/interface/resources/images/high-fidelity-banner.svg b/interface/resources/images/high-fidelity-banner.svg index d5666be0fa..19127e729c 100644 --- a/interface/resources/images/high-fidelity-banner.svg +++ b/interface/resources/images/high-fidelity-banner.svg @@ -1,17 +1 @@ - - - - - - - - - - - - - - - - - +Artboard 1 \ No newline at end of file diff --git a/interface/resources/qml/Web3DSurface.qml b/interface/resources/qml/Web3DSurface.qml index 32c19daf14..ff574ceaa5 100644 --- a/interface/resources/qml/Web3DSurface.qml +++ b/interface/resources/qml/Web3DSurface.qml @@ -12,20 +12,35 @@ import QtQuick 2.5 import "controls" as Controls -Controls.WebView { +Item { + id: root + anchors.fill: parent + property string url: "" + property string scriptUrl: null - // This is for JS/QML communication, which is unused in a Web3DOverlay, - // but not having this here results in spurious warnings about a - // missing signal - signal sendToScript(var message); + onUrlChanged: { + load(root.url, root.scriptUrl); + } - function onWebEventReceived(event) { - if (event.slice(0, 17) === "CLARA.IO DOWNLOAD") { - ApplicationInterface.addAssetToWorldFromURL(event.slice(18)); + onScriptUrlChanged: { + if (root.item) { + root.item.scriptUrl = root.scriptUrl; + } else { + load(root.url, root.scriptUrl); } } + property var item: null + + function load(url, scriptUrl) { + QmlSurface.load("./controls/WebView.qml", root, function(newItem) { + root.item = newItem + root.item.url = url + root.item.scriptUrl = scriptUrl + }) + } + Component.onCompleted: { - eventBridge.webEventReceived.connect(onWebEventReceived); + load(root.url, root.scriptUrl); } } diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index d3bf6aca0a..fccba12a8a 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -266,6 +266,7 @@ Rectangle { labelTextSize: 16; backgroundOnColor: "#E3E3E3"; checked: AudioScriptingInterface.warnWhenMuted; + visible: bar.currentIndex !== 0; onClicked: { AudioScriptingInterface.warnWhenMuted = checked; checked = Qt.binding(function() { return AudioScriptingInterface.warnWhenMuted; }); // restore binding @@ -277,8 +278,8 @@ Rectangle { id: audioLevelSwitch height: root.switchHeight; switchWidth: root.switchWidth; - anchors.top: warnMutedSwitch.bottom - anchors.topMargin: 24 + anchors.top: warnMutedSwitch.visible ? warnMutedSwitch.bottom : parent.top + anchors.topMargin: bar.currentIndex === 0 ? 0 : 24 anchors.left: parent.left labelTextOn: qsTr("Audio Level Meter"); labelTextSize: 16; diff --git a/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml b/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml index 213540b334..87f307b9bc 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml @@ -106,7 +106,7 @@ Rectangle { } RalewayRegular { color: "white" - text: "© 2018 High Fidelity. All rights reserved." + text: "© 2012 - 2019 High Fidelity, Inc.. All rights reserved." size: 14 } RalewayRegular { diff --git a/interface/resources/qml/hifi/dialogs/security/Security.qml b/interface/resources/qml/hifi/dialogs/security/Security.qml index a7a0d461a2..b1f62633e7 100644 --- a/interface/resources/qml/hifi/dialogs/security/Security.qml +++ b/interface/resources/qml/hifi/dialogs/security/Security.qml @@ -240,9 +240,96 @@ Rectangle { } } + // -- Plugin Permissions -- + Item { + id: kpiContainer; + anchors.top: accountContainer.bottom; + anchors.left: parent.left; + anchors.right: parent.right; + height: childrenRect.height; + + Rectangle { + id: kpiHeaderContainer; + anchors.top: parent.top; + anchors.left: parent.left; + anchors.right: parent.right; + height: 55; + color: hifi.colors.baseGrayHighlight; + + HifiStylesUit.RalewaySemiBold { + text: "Plugin Permissions"; + anchors.fill: parent; + anchors.leftMargin: 20; + color: hifi.colors.white; + size: 18; + } + } + + Item { + id: kpiScriptContainer; + anchors.top: kpiHeaderContainer.bottom; + anchors.left: parent.left; + anchors.right: parent.right; + height: 80; + + HifiControlsUit.CheckBox { + id: kpiScriptCheckbox; + readonly property string kpiSettingsKey: "private/enableScriptingPlugins" + checked: Settings.getValue(kpiSettingsKey, false); + text: "Enable custom script plugins (requires restart)" + // Anchors + anchors.verticalCenter: parent.verticalCenter; + anchors.left: parent.left; + anchors.leftMargin: 20; + boxSize: 24; + labelFontSize: 18; + colorScheme: hifi.colorSchemes.dark + color: hifi.colors.white; + width: 300; + onCheckedChanged: Settings.setValue(kpiSettingsKey, checked); + } + + HifiStylesUit.RalewaySemiBold { + id: kpiScriptHelp; + text: '[?]'; + // Anchors + anchors.verticalCenter: parent.verticalCenter; + anchors.left: kpiScriptCheckbox.right; + width: 30; + height: 30; + // Text size + size: 18; + // Style + color: hifi.colors.blueHighlight; + + MouseArea { + anchors.fill: parent; + hoverEnabled: true; + onEntered: { + parent.color = hifi.colors.blueAccent; + } + onExited: { + parent.color = hifi.colors.blueHighlight; + } + onClicked: { + lightboxPopup.titleText = "Script Plugin Infrastructure by Kasen"; + lightboxPopup.bodyText = "Toggles the activation of scripting plugins in the 'plugins/scripting' folder. \n\n" + + "Created by https://kasen.io/"; + lightboxPopup.button1text = "OK"; + lightboxPopup.button1method = function() { + lightboxPopup.visible = false; + } + lightboxPopup.visible = true; + } + } + } + } + } + + Item { id: walletContainer; - anchors.top: accountContainer.bottom; + anchors.top: kpiContainer.bottom; anchors.left: parent.left; anchors.right: parent.right; height: childrenRect.height; diff --git a/interface/resources/qml/hifi/simplifiedUI/helpApp/about/HelpAbout.qml b/interface/resources/qml/hifi/simplifiedUI/helpApp/about/HelpAbout.qml index 4a36232029..a4a6575d1e 100644 --- a/interface/resources/qml/hifi/simplifiedUI/helpApp/about/HelpAbout.qml +++ b/interface/resources/qml/hifi/simplifiedUI/helpApp/about/HelpAbout.qml @@ -167,7 +167,7 @@ Flickable { Component.onCompleted: { var cpu = JSON.parse(PlatformInfo.getCPU(0)); var cpuModel = cpu.model; - if (cpuModel.length === 0) { + if (!cpuModel || cpuModel.length === 0) { cpuModel = "Unknown"; } @@ -213,7 +213,7 @@ Flickable { Component.onCompleted: { var gpu = JSON.parse(PlatformInfo.getGPU(PlatformInfo.getMasterGPU())); var gpuModel = gpu.model; - if (gpuModel.length === 0) { + if (!gpuModel || gpuModel.length === 0) { gpuModel = "Unknown"; } @@ -327,7 +327,7 @@ Flickable { var cpu = JSON.parse(PlatformInfo.getCPU(0)); var cpuModel = cpu.model; - if (cpuModel.length === 0) { + if (!cpuModel || cpuModel.length === 0) { cpuModel = "Unknown"; } @@ -338,7 +338,7 @@ Flickable { var gpu = JSON.parse(PlatformInfo.getGPU(PlatformInfo.getMasterGPU())); var gpuModel = gpu.model; - if (gpuModel.length === 0) { + if (!gpuModel || gpuModel.length === 0) { gpuModel = "Unknown"; } diff --git a/interface/resources/qml/hifi/simplifiedUI/helpApp/controls/ControlsTable.qml b/interface/resources/qml/hifi/simplifiedUI/helpApp/controls/ControlsTable.qml index b647d5ca24..84b37db31b 100644 --- a/interface/resources/qml/hifi/simplifiedUI/helpApp/controls/ControlsTable.qml +++ b/interface/resources/qml/hifi/simplifiedUI/helpApp/controls/ControlsTable.qml @@ -699,8 +699,8 @@ Item { spacing: controlsTableRoot.rowPadding HifiStylesUit.GraphikRegular { - id: mirrorText - text: "Mirror Mode" + id: selfieText + text: "Selfie" width: paintedWidth height: parent.height horizontalAlignment: Text.AlignLeft @@ -710,8 +710,8 @@ Item { } HifiStylesUit.GraphikRegular { - text: "See your own avatar" - width: parent.width - mirrorText.width - parent.spacing - controlsTableRoot.rowPadding + text: "Look at self" + width: parent.width - selfieText.width - parent.spacing - controlsTableRoot.rowPadding height: parent.height horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter diff --git a/interface/resources/qml/hifi/simplifiedUI/settingsApp/general/General.qml b/interface/resources/qml/hifi/simplifiedUI/settingsApp/general/General.qml index 9e58a0aa98..7a98849b95 100644 --- a/interface/resources/qml/hifi/simplifiedUI/settingsApp/general/General.qml +++ b/interface/resources/qml/hifi/simplifiedUI/settingsApp/general/General.qml @@ -136,17 +136,17 @@ Flickable { Layout.preferredHeight: 18 Layout.preferredWidth: parent.width labelTextOn: "Show Emote UI" - checked: Settings.getValue("simplifiedUI/emoteIndicatorVisible", true) + checked: Settings.getValue("simplifiedUI/allowEmoteDrawerExpansion", true) onClicked: { - var currentSetting = Settings.getValue("simplifiedUI/emoteIndicatorVisible", true); - Settings.setValue("simplifiedUI/emoteIndicatorVisible", !currentSetting); + var currentSetting = Settings.getValue("simplifiedUI/allowEmoteDrawerExpansion", true); + Settings.setValue("simplifiedUI/allowEmoteDrawerExpansion", !currentSetting); } Connections { target: Settings onValueChanged: { - if (setting === "simplifiedUI/emoteIndicatorVisible") { + if (setting === "simplifiedUI/allowEmoteDrawerExpansion") { emoteSwitch.checked = value; } } @@ -234,9 +234,19 @@ Flickable { SimplifiedControls.RadioButton { id: thirdPerson text: "Third Person View" - checked: Camera.mode === "third person" + checked: Camera.mode === "look at" onClicked: { - Camera.mode = "third person" + Camera.mode = "look at" + } + } + + SimplifiedControls.RadioButton { + id: selfie + text: "Selfie" + checked: Camera.mode === "selfie" + visible: true + onClicked: { + Camera.mode = "selfie" } } @@ -246,11 +256,21 @@ Flickable { onModeUpdated: { if (Camera.mode === "first person") { firstPerson.checked = true - } else if (Camera.mode === "third person") { + } else if (Camera.mode === "look at") { thirdPerson.checked = true + } else if (Camera.mode === "selfie" && HMD.active) { + selfie.checked = true } } } + + Connections { + target: HMD + + onDisplayModeChanged: { + selfie.visible = isHMDMode ? false : true + } + } } } diff --git a/interface/resources/qml/hifi/simplifiedUI/settingsApp/vr/VR.qml b/interface/resources/qml/hifi/simplifiedUI/settingsApp/vr/VR.qml index 5f0fbe49d5..420ee11a05 100644 --- a/interface/resources/qml/hifi/simplifiedUI/settingsApp/vr/VR.qml +++ b/interface/resources/qml/hifi/simplifiedUI/settingsApp/vr/VR.qml @@ -71,7 +71,7 @@ Flickable { ColumnLayout { id: controlsContainer Layout.preferredWidth: parent.width - Layout.topMargin: 24 + Layout.topMargin: 24 spacing: 0 HifiStylesUit.GraphikSemiBold { @@ -154,6 +154,45 @@ Flickable { } } } + + ColumnLayout { + Layout.preferredWidth: parent.width + spacing: 0 + + HifiStylesUit.GraphikSemiBold { + text: "VR Rotation Mode" + Layout.preferredWidth: parent.width + height: paintedHeight + size: 22 + color: simplifiedUI.colors.text.white + } + + ColumnLayout { + width: parent.width + Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin + spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons + + ButtonGroup { id: rotationButtonGroup } + + SimplifiedControls.RadioButton { + text: "Snap Turn" + ButtonGroup.group: rotationButtonGroup + checked: MyAvatar.getSnapTurn() === true + onClicked: { + MyAvatar.setSnapTurn(true); + } + } + + SimplifiedControls.RadioButton { + text: "Smooth Turn" + ButtonGroup.group: rotationButtonGroup + checked: MyAvatar.getSnapTurn() === false + onClicked: { + MyAvatar.setSnapTurn(false); + } + } + } + } ColumnLayout { id: micControlsContainer diff --git a/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/TextField.qml b/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/TextField.qml index bd2b6cf538..44f34c3356 100644 --- a/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/TextField.qml +++ b/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/TextField.qml @@ -22,6 +22,10 @@ TextField { } property string rightGlyph: "" + property alias bottomBorderVisible: bottomRectangle.visible + property alias backgroundColor: textFieldBackground.color + property string unfocusedPlaceholderText + property bool blankPlaceholderTextOnFocus: true color: simplifiedUI.colors.text.white font.family: "Graphik Medium" @@ -35,10 +39,8 @@ TextField { leftPadding: 0 rightPadding: root.rightGlyph === "" ? 0 : rightGlyphItem.implicitWidth + simplifiedUI.sizes.controls.textField.rightGlyphPadding - onFocusChanged: { - if (focus) { - Tablet.playSound(TabletEnums.ButtonClick); - } + onPressed: { + Tablet.playSound(TabletEnums.ButtonClick); } onHoveredChanged: { @@ -47,7 +49,22 @@ TextField { } } - background: Item { + onFocusChanged: { + if (!root.blankPlaceholderTextOnFocus) { + return; + } + + if (focus) { + root.unfocusedPlaceholderText = root.placeholderText; + root.placeholderText = ""; + } else { + root.placeholderText = root.unfocusedPlaceholderText; + } + } + + background: Rectangle { + id: textFieldBackground + color: Qt.rgba(0, 0, 0, 0); anchors.fill: parent Rectangle { diff --git a/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml b/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml index d87431ea9c..c92da7e6e5 100644 --- a/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml +++ b/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml @@ -9,6 +9,7 @@ // import QtQuick 2.10 +import hifi.simplifiedUI.simplifiedControls 1.0 as SimplifiedControls import "../simplifiedConstants" as SimplifiedConstants import "../inputDeviceButton" as InputDeviceButton import stylesUit 1.0 as HifiStylesUit @@ -39,6 +40,9 @@ Rectangle { property bool inventoryFullyReceived: false Component.onCompleted: { + var numTimesRun = Settings.getValue("simplifiedUI/SUIScriptExecutionCount", 0); + numTimesRun++; + Settings.setValue("simplifiedUI/SUIScriptExecutionCount", numTimesRun); Commerce.getLoginStatus(); } @@ -51,7 +55,7 @@ Rectangle { if ((MyAvatar.skeletonModelURL.indexOf("defaultAvatar") > -1 || MyAvatar.skeletonModelURL.indexOf("fst") === -1) && topBarInventoryModel.count > 0) { Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatar", true); - MyAvatar.skeletonModelURL = topBarInventoryModel.get(0).download_url; + MyAvatar.useFullAvatarURL = topBarInventoryModel.get(0).download_url; } } } @@ -157,7 +161,7 @@ Rectangle { Image { id: avatarButtonImage - source: "./images/defaultAvatar.svg" + source: "../images/defaultAvatar.svg" anchors.centerIn: parent width: 32 height: width @@ -350,6 +354,50 @@ Rectangle { } + TextMetrics { + id: goToTextFieldMetrics + font: goToTextField.font + text: goToTextField.longPlaceholderText + } + + + Item { + id: goToTextFieldContainer + anchors.left: statusButtonContainer.right + anchors.leftMargin: 12 + anchors.right: (hmdButtonContainer.visible ? hmdButtonContainer.left : helpButtonContainer.left) + anchors.rightMargin: 12 + anchors.verticalCenter: parent.verticalCenter + height: parent.height + + SimplifiedControls.TextField { + id: goToTextField + readonly property string shortPlaceholderText: "Jump to..." + readonly property string longPlaceholderText: "Type the name of a location to quickly jump there..." + anchors.centerIn: parent + width: Math.min(parent.width, 445) + height: 35 + leftPadding: 8 + rightPadding: 8 + bottomBorderVisible: false + backgroundColor: "#1D1D1D" + placeholderTextColor: "#8E8E8E" + font.pixelSize: 14 + placeholderText: width - leftPadding - rightPadding < goToTextFieldMetrics.width ? shortPlaceholderText : longPlaceholderText + clip: true + selectByMouse: true + autoScroll: true + onAccepted: { + if (goToTextField.length > 0) { + AddressManager.handleLookupString(goToTextField.text); + goToTextField.text = ""; + } + parent.forceActiveFocus(); + } + } + } + + Item { id: hmdButtonContainer diff --git a/interface/resources/qml/hifi/tablet/+webengine/BlocksWebView.qml b/interface/resources/qml/hifi/tablet/+webengine/BlocksWebView.qml index 050515da37..e600924b42 100644 --- a/interface/resources/qml/hifi/tablet/+webengine/BlocksWebView.qml +++ b/interface/resources/qml/hifi/tablet/+webengine/BlocksWebView.qml @@ -1,6 +1,6 @@ import QtQuick 2.0 import QtWebEngine 1.5 -import "../../controls" as Controls +import "../../../controls" as Controls Controls.TabletWebView { profile: WebEngineProfile { httpUserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"} diff --git a/interface/resources/qml/hifi/tablet/DynamicWebview.qml b/interface/resources/qml/hifi/tablet/DynamicWebview.qml new file mode 100644 index 0000000000..4343e71e64 --- /dev/null +++ b/interface/resources/qml/hifi/tablet/DynamicWebview.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 +import "../../controls" as Controls + +Controls.WebView { + id: root + function fromScript(message) { + root.url = message.url; + } +} + + diff --git a/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml b/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml index 254e4203ce..1d15fe8b23 100644 --- a/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml +++ b/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml @@ -19,6 +19,7 @@ StackView { objectName: "stack" property string title: "General Settings" property alias gotoPreviousApp: root.gotoPreviousApp; + property alias gotoPreviousAppFromScript: root.gotoPreviousAppFromScript; signal sendToScript(var message); function pushSource(path) { @@ -30,6 +31,10 @@ StackView { profileRoot.pop(); } + function emitSendToScript(message) { + profileRoot.sendToScript(message); + } + TabletPreferencesDialog { id: root objectName: "TabletGeneralPreferences" diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index 5559c36fd1..6001497743 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -104,6 +104,10 @@ Rectangle { if (loader.item.hasOwnProperty("gotoPreviousApp")) { loader.item.gotoPreviousApp = true; } + + if (loader.item.hasOwnProperty("gotoPreviousAppFromScript")) { + loader.item.gotoPreviousAppFromScript = true; + } }); } } @@ -276,7 +280,7 @@ Rectangle { } else { console.log("newSource is of unknown type!"); } - + screenChanged(type, newSource); }); } diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml index c6b4fce14e..66661843e6 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml @@ -30,6 +30,7 @@ Item { property bool keyboardRaised: false property bool punctuationMode: false property bool gotoPreviousApp: false + property bool gotoPreviousAppFromScript: false property var tablet; @@ -42,7 +43,9 @@ Item { } if (HMD.active) { - if (gotoPreviousApp) { + if (gotoPreviousAppFromScript) { + dialog.parent.sendToScript("returnToPreviousApp"); + } else if (gotoPreviousApp) { tablet.returnToPreviousApp(); } else { tablet.popFromStack(); @@ -59,7 +62,9 @@ Item { } if (HMD.active) { - if (gotoPreviousApp) { + if (gotoPreviousAppFromScript) { + dialog.parent.sendToScript("returnToPreviousApp"); + } else if (gotoPreviousApp) { tablet.returnToPreviousApp(); } else { tablet.popFromStack(); @@ -72,7 +77,9 @@ Item { function closeDialog() { var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - if (gotoPreviousApp) { + if (gotoPreviousAppFromScript) { + dialog.parent.sendToScript("returnToPreviousApp"); + } else if (gotoPreviousApp) { tablet.returnToPreviousApp(); } else { tablet.gotoHomeScreen(); diff --git a/interface/src/AppNapDisabler.h b/interface/src/AppNapDisabler.h new file mode 100644 index 0000000000..b3cfc3038d --- /dev/null +++ b/interface/src/AppNapDisabler.h @@ -0,0 +1,24 @@ +// +// AppNapDisabler.h +// interface/src +// +// Copyright 2019 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 +// + +#ifndef hifi_AppNapDisabler_h +#define hifi_AppNapDisabler_h + +#import + +class AppNapDisabler { +public: + AppNapDisabler(); + ~AppNapDisabler(); +private: + id _activity; +}; + +#endif // hifi_AppNapDisabler_h diff --git a/interface/src/AppNapDisabler.mm b/interface/src/AppNapDisabler.mm new file mode 100644 index 0000000000..0c760fad5f --- /dev/null +++ b/interface/src/AppNapDisabler.mm @@ -0,0 +1,28 @@ +// +// AppNapDisabler.mm +// interface/src +// +// Copyright 2019 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 +#ifdef Q_OS_MAC + +#include "AppNapDisabler.h" + +#import + +AppNapDisabler::AppNapDisabler() { + _activity = [[NSProcessInfo processInfo] beginActivityWithOptions:NSActivityUserInitiated reason:@"Audio is in use"]; + [_activity retain]; +} + +AppNapDisabler::~AppNapDisabler() { + [[NSProcessInfo processInfo] endActivity:_activity]; + [_activity release]; +} + +#endif // Q_OS_MAC diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 91f7528f93..b4a37519a6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -58,7 +58,9 @@ #include #include +#include #include +#include #include #include #include @@ -73,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -103,8 +106,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -137,6 +140,7 @@ #include #include #include +#include #include #include #include @@ -151,7 +155,6 @@ #include #include #include -#include #include #include #include @@ -257,15 +260,17 @@ extern "C" { } #endif -#ifdef Q_OS_MAC -#include "MacHelper.h" -#endif - #if defined(Q_OS_ANDROID) #include #include "AndroidHelper.h" #endif +#if defined(Q_OS_MAC) +// On Mac OS, disable App Nap to prevent audio glitches while running in the background +#include "AppNapDisabler.h" +static AppNapDisabler appNapDisabler; // disabled, while in scope +#endif + #include "graphics/RenderEventHandler.h" Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse") @@ -552,13 +557,6 @@ public: return true; } - if (message->message == WM_POWERBROADCAST) { - if (message->wParam == PBT_APMRESUMEAUTOMATIC) { - qCInfo(interfaceapp) << "Waking up from sleep or hybernation."; - QMetaObject::invokeMethod(DependencyManager::get().data(), "noteAwakening", Qt::QueuedConnection); - } - } - if (message->message == WM_COPYDATA) { COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)(message->lParam); QUrl url = QUrl((const char*)(pcds->lpData)); @@ -717,6 +715,8 @@ static const QString STATE_CAMERA_FIRST_PERSON = "CameraFirstPerson"; static const QString STATE_CAMERA_THIRD_PERSON = "CameraThirdPerson"; static const QString STATE_CAMERA_ENTITY = "CameraEntity"; static const QString STATE_CAMERA_INDEPENDENT = "CameraIndependent"; +static const QString STATE_CAMERA_LOOK_AT = "CameraLookAt"; +static const QString STATE_CAMERA_SELFIE = "CameraSelfie"; static const QString STATE_SNAP_TURN = "SnapTurn"; static const QString STATE_ADVANCED_MOVEMENT_CONTROLS = "AdvancedMovement"; static const QString STATE_GROUNDED = "Grounded"; @@ -818,6 +818,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { } // Tell the plugin manager about our statically linked plugins + DependencyManager::set(); DependencyManager::set(); auto pluginManager = PluginManager::getInstance(); pluginManager->setInputPluginProvider([] { return getInputPlugins(); }); @@ -861,13 +862,12 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); #if defined(Q_OS_ANDROID) - DependencyManager::set(); // use the default user agent getter + DependencyManager::set(true); // use the default user agent getter #else - DependencyManager::set(std::bind(&Application::getUserAgent, qApp)); + DependencyManager::set(true, std::bind(&Application::getUserAgent, qApp)); #endif DependencyManager::set(); DependencyManager::set(ScriptEngine::CLIENT_SCRIPT, defaultScriptsOverrideOption); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -886,13 +886,13 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); #endif - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -933,7 +933,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR, - STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, + STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_CAMERA_LOOK_AT, STATE_CAMERA_SELFIE, STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED, STATE_PLATFORM_WINDOWS, STATE_PLATFORM_MAC, STATE_PLATFORM_ANDROID, STATE_LEFT_HAND_DOMINANT, STATE_RIGHT_HAND_DOMINANT, STATE_STRAFE_ENABLED } }); DependencyManager::set(); @@ -964,9 +964,12 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); -#ifdef Q_OS_MAC - DependencyManager::set(); -#endif + PlatformHelper::setup(); + + QObject::connect(PlatformHelper::instance(), &PlatformHelper::systemWillWake, [] { + QMetaObject::invokeMethod(DependencyManager::get().data(), "noteAwakening", Qt::QueuedConnection); + }); + QString setBookmarkValue = getCmdOption(argc, constArgv, "--setBookmark"); if (!setBookmarkValue.isEmpty()) { @@ -1066,6 +1069,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); setProperty(hifi::properties::CRASHED, _previousSessionCrashed); + LogHandler::getInstance().moveToThread(thread()); + LogHandler::getInstance().setupRepeatedMessageFlusher(); + { const QStringList args = arguments(); @@ -1149,7 +1155,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Graphik-SemiBold.ttf"); QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Graphik-Regular.ttf"); QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Graphik-Medium.ttf"); - _window->setWindowTitle("High Fidelity Interface"); + _window->setWindowTitle("High Fidelity"); Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us @@ -1172,6 +1178,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo deadlockWatchdogThread->setMainThreadID(QThread::currentThreadId()); deadlockWatchdogThread->start(); + // Pause the deadlock watchdog when we sleep, or it might + // trigger a false positive when we wake back up + auto platformHelper = PlatformHelper::instance(); + + connect(platformHelper, &PlatformHelper::systemWillSleep, [] { + DeadlockWatchdogThread::pause(); + }); + + connect(platformHelper, &PlatformHelper::systemWillWake, [] { + DeadlockWatchdogThread::resume(); + }); // Main thread timer to keep the watchdog updated QTimer* watchdogUpdateTimer = new QTimer(this); @@ -1866,6 +1883,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _applicationStateDevice->setInputVariant(STATE_CAMERA_THIRD_PERSON, []() -> float { return qApp->getCamera().getMode() == CAMERA_MODE_THIRD_PERSON ? 1 : 0; }); + _applicationStateDevice->setInputVariant(STATE_CAMERA_LOOK_AT, []() -> float { + return qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT ? 1 : 0; + }); + _applicationStateDevice->setInputVariant(STATE_CAMERA_SELFIE, []() -> float { + return qApp->getCamera().getMode() == CAMERA_MODE_SELFIE ? 1 : 0; + }); _applicationStateDevice->setInputVariant(STATE_CAMERA_ENTITY, []() -> float { return qApp->getCamera().getMode() == CAMERA_MODE_ENTITY ? 1 : 0; }); @@ -1991,12 +2014,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(ddeTracker.data(), &FaceTracker::muteToggled, this, &Application::faceTrackerMuteToggled); #endif -#ifdef HAVE_IVIEWHMD - auto eyeTracker = DependencyManager::get(); - eyeTracker->init(); - setActiveEyeTracker(); -#endif - // If launched from Steam, let it handle updates const QString HIFI_NO_UPDATER_COMMAND_LINE_KEY = "--no-updater"; bool noUpdater = arguments().indexOf(HIFI_NO_UPDATER_COMMAND_LINE_KEY) != -1; @@ -2675,6 +2692,8 @@ void Application::updateHeartbeat() const { } void Application::onAboutToQuit() { + setCrashAnnotation("shutdown", "1"); + // quickly save AvatarEntityData before the EntityTree is dismantled getMyAvatar()->saveAvatarEntityDataToSettings(); @@ -2713,6 +2732,11 @@ void Application::onAboutToQuit() { cleanupBeforeQuit(); + if (_crashOnShutdown) { + // triggered by crash menu + crash::nullDeref(); + } + getRefreshRateManager().setRefreshRateRegime(RefreshRateManager::RefreshRateRegime::SHUTDOWN); } @@ -2733,9 +2757,6 @@ void Application::cleanupBeforeQuit() { // Stop third party processes so that they're not left running in the event of a subsequent shutdown crash. #ifdef HAVE_DDE DependencyManager::get()->setEnabled(false); -#endif -#ifdef HAVE_IVIEWHMD - DependencyManager::get()->setEnabled(false, true); #endif AnimDebugDraw::getInstance().shutdown(); @@ -2810,9 +2831,6 @@ void Application::cleanupBeforeQuit() { #ifdef HAVE_DDE DependencyManager::destroy(); #endif -#ifdef HAVE_IVIEWHMD - DependencyManager::destroy(); -#endif DependencyManager::destroy(); // Must be destroyed before TabletScriptingInterface @@ -2821,7 +2839,7 @@ void Application::cleanupBeforeQuit() { DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); - + DependencyManager::destroy(); _snapshotSoundInjector = nullptr; @@ -2868,9 +2886,7 @@ Application::~Application() { _gameWorkload.shutdown(); DependencyManager::destroy(); -#ifdef Q_OS_MAC - DependencyManager::destroy(); -#endif + PlatformHelper::shutdown(); _entityClipboard->eraseAllOctreeElements(); _entityClipboard.reset(); @@ -2897,6 +2913,7 @@ Application::~Application() { DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); @@ -3140,7 +3157,7 @@ void Application::showLoginScreen() { QJsonObject loginData = {}; loginData["action"] = "login dialog popped up"; UserActivityLogger::getInstance().logAction("encourageLoginDialog", loginData); - _window->setWindowTitle("High Fidelity Interface"); + _window->setWindowTitle("High Fidelity"); } else { resumeAfterLoginDialogActionTaken(); } @@ -3275,6 +3292,9 @@ void Application::initializeUi() { } return result.toPoint(); }); + + // BUGZ-1365 - the root context should explicitly default to being unable to load local HTML content + ContextAwareProfile::restrictContext(offscreenUi->getSurfaceContext(), true); offscreenUi->resume(); #endif connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r){ @@ -3411,7 +3431,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("Window", DependencyManager::get().data()); surfaceContext->setContextProperty("Desktop", DependencyManager::get().data()); surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance()); - surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); + surfaceContext->setContextProperty("Settings", new QMLSettingsScriptingInterface(surfaceContext)); surfaceContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); surfaceContext->setContextProperty("AvatarBookmarks", DependencyManager::get().data()); surfaceContext->setContextProperty("LocationBookmarks", DependencyManager::get().data()); @@ -3419,6 +3439,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { // Caches surfaceContext->setContextProperty("AnimationCache", DependencyManager::get().data()); surfaceContext->setContextProperty("TextureCache", DependencyManager::get().data()); + surfaceContext->setContextProperty("MaterialCache", DependencyManager::get().data()); surfaceContext->setContextProperty("ModelCache", DependencyManager::get().data()); surfaceContext->setContextProperty("SoundCache", DependencyManager::get().data()); @@ -3527,7 +3548,7 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona surfaceContext->setContextProperty("offscreenFlags", flags); surfaceContext->setContextProperty("AddressManager", DependencyManager::get().data()); - surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); + surfaceContext->setContextProperty("Settings", new QMLSettingsScriptingInterface(surfaceContext)); surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance()); surfaceContext->setContextProperty("Performance", new PerformanceScriptingInterface()); @@ -3582,7 +3603,8 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { // Always use the default eye position, not the actual head eye position. // Using the latter will cause the camera to wobble with idle animations, // or with changes from the face tracker - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { + CameraMode mode = _myCamera.getMode(); + if (mode == CAMERA_MODE_FIRST_PERSON) { _thirdPersonHMDCameraBoomValid= false; if (isHMDMode()) { mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); @@ -3593,10 +3615,8 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { _myCamera.setPosition(myAvatar->getDefaultEyePosition()); _myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation()); } - } - else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + } else if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) { if (isHMDMode()) { - if (!_thirdPersonHMDCameraBoomValid) { const glm::vec3 CAMERA_OFFSET = glm::vec3(0.0f, 0.0f, 0.7f); _thirdPersonHMDCameraBoom = cancelOutRollAndPitch(myAvatar->getHMDSensorOrientation()) * CAMERA_OFFSET; @@ -3611,22 +3631,28 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { _myCamera.setOrientation(glm::normalize(glmExtractRotation(worldCameraMat))); _myCamera.setPosition(extractTranslation(worldCameraMat)); - } - else { + } else { _thirdPersonHMDCameraBoomValid = false; - - _myCamera.setOrientation(myAvatar->getHead()->getOrientation()); - if (isOptionChecked(MenuOption::CenterPlayerInView)) { + if (mode == CAMERA_MODE_THIRD_PERSON) { + _myCamera.setOrientation(myAvatar->getHead()->getOrientation()); + if (isOptionChecked(MenuOption::CenterPlayerInView)) { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + _myCamera.getOrientation() * boomOffset); + } else { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + myAvatar->getWorldOrientation() * boomOffset); + } + } else { + glm::quat lookAtRotation = myAvatar->getLookAtRotation(); + if (mode == CAMERA_MODE_SELFIE) { + lookAtRotation = lookAtRotation * glm::angleAxis(PI, myAvatar->getWorldOrientation() * Vectors::UP); + } _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + _myCamera.getOrientation() * boomOffset); - } - else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + myAvatar->getWorldOrientation() * boomOffset); + + lookAtRotation * boomOffset); + _myCamera.lookAt(myAvatar->getDefaultEyePosition()); } } - } - else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + } else if (mode == CAMERA_MODE_MIRROR) { _thirdPersonHMDCameraBoomValid= false; if (isHMDMode()) { @@ -3664,8 +3690,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { glm::vec3(0.0f, 0.0f, -1.0f) * myAvatar->getBoomLength() * _scaleMirror); } renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; - } - else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) { + } else if (mode == CAMERA_MODE_ENTITY) { _thirdPersonHMDCameraBoomValid= false; EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer(); if (cameraEntity != nullptr) { @@ -4333,14 +4358,14 @@ void Application::keyPressEvent(QKeyEvent* event) { _keyboardMouseDevice->keyReleaseEvent(event); } - bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); + bool isControlOrCommand = event->modifiers().testFlag(Qt::ControlModifier); bool isOption = event->modifiers().testFlag(Qt::AltModifier); switch (event->key()) { case Qt::Key_4: case Qt::Key_5: case Qt::Key_6: case Qt::Key_7: - if (isMeta || isOption) { + if (isControlOrCommand || isOption) { unsigned int index = static_cast(event->key() - Qt::Key_1); auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); if (index < displayPlugins.size()) { @@ -4361,7 +4386,8 @@ void Application::keyPressEvent(QKeyEvent* event) { } bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); - bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); + bool isControlOrCommand = event->modifiers().testFlag(Qt::ControlModifier); + bool isMetaOrMacControl = event->modifiers().testFlag(Qt::MetaModifier); bool isOption = event->modifiers().testFlag(Qt::AltModifier); switch (event->key()) { case Qt::Key_Enter: @@ -4382,19 +4408,19 @@ void Application::keyPressEvent(QKeyEvent* event) { } case Qt::Key_2: { Menu* menu = Menu::getInstance(); - menu->triggerOption(MenuOption::FullscreenMirror); + menu->triggerOption(MenuOption::SelfieCamera); break; } case Qt::Key_3: { Menu* menu = Menu::getInstance(); - menu->triggerOption(MenuOption::ThirdPerson); + menu->triggerOption(MenuOption::LookAtCamera); break; } case Qt::Key_4: case Qt::Key_5: case Qt::Key_6: case Qt::Key_7: - if (isMeta || isOption) { + if (isControlOrCommand || isOption) { unsigned int index = static_cast(event->key() - Qt::Key_1); auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); if (index < displayPlugins.size()) { @@ -4410,7 +4436,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_G: - if (isShifted && isMeta && Menu::getInstance() && Menu::getInstance()->getMenu("Developer")->isVisible()) { + if (isShifted && isControlOrCommand && isOption && isMetaOrMacControl) { static const QString HIFI_FRAMES_FOLDER_VAR = "HIFI_FRAMES_FOLDER"; static const QString GPU_FRAME_FOLDER = QProcessEnvironment::systemEnvironment().contains(HIFI_FRAMES_FOLDER_VAR) ? QProcessEnvironment::systemEnvironment().value(HIFI_FRAMES_FOLDER_VAR) @@ -4423,7 +4449,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } break; case Qt::Key_X: - if (isShifted && isMeta) { + if (isShifted && isControlOrCommand) { auto offscreenUi = getOffscreenUI(); offscreenUi->togglePinned(); //offscreenUi->getSurfaceContext()->engine()->clearComponentCache(); @@ -4433,7 +4459,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_Y: - if (isShifted && isMeta) { + if (isShifted && isControlOrCommand) { getActiveDisplayPlugin()->cycleDebugOutput(); } break; @@ -4446,16 +4472,16 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_L: - if (isShifted && isMeta) { + if (isShifted && isControlOrCommand) { Menu::getInstance()->triggerOption(MenuOption::Log); - } else if (isMeta) { + } else if (isControlOrCommand) { auto dialogsManager = DependencyManager::get(); dialogsManager->toggleAddressBar(); } break; case Qt::Key_R: - if (isMeta && !event->isAutoRepeat()) { + if (isControlOrCommand && !event->isAutoRepeat()) { DependencyManager::get()->reloadAllScripts(); getOffscreenUI()->clearCache(); } @@ -4466,7 +4492,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_M: - if (isMeta) { + if (isControlOrCommand) { auto audioClient = DependencyManager::get(); audioClient->setMuted(!audioClient->isMuted()); QSharedPointer audioScriptingInterface = qSharedPointerDynamicCast(DependencyManager::get()); @@ -4477,13 +4503,13 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_S: - if (isShifted && isMeta && !isOption) { + if (isShifted && isControlOrCommand && !isOption) { Menu::getInstance()->triggerOption(MenuOption::SuppressShortTimings); } break; case Qt::Key_Apostrophe: { - if (isMeta) { + if (isControlOrCommand) { auto cursor = Cursor::Manager::instance().getCursor(); auto curIcon = cursor->getIcon(); if (curIcon == Cursor::Icon::DEFAULT) { @@ -4510,7 +4536,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_Plus: { - if (isMeta && event->modifiers().testFlag(Qt::KeypadModifier)) { + if (isControlOrCommand && event->modifiers().testFlag(Qt::KeypadModifier)) { auto& cursorManager = Cursor::Manager::instance(); cursorManager.setScale(cursorManager.getScale() * 1.1f); } else { @@ -4520,7 +4546,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } case Qt::Key_Minus: { - if (isMeta && event->modifiers().testFlag(Qt::KeypadModifier)) { + if (isControlOrCommand && event->modifiers().testFlag(Qt::KeypadModifier)) { auto& cursorManager = Cursor::Manager::instance(); cursorManager.setScale(cursorManager.getScale() / 1.1f); } else { @@ -5314,35 +5340,6 @@ void Application::setActiveFaceTracker() const { #endif } -#ifdef HAVE_IVIEWHMD -void Application::setActiveEyeTracker() { - auto eyeTracker = DependencyManager::get(); - if (!eyeTracker->isInitialized()) { - return; - } - - bool isEyeTracking = Menu::getInstance()->isOptionChecked(MenuOption::SMIEyeTracking); - bool isSimulating = Menu::getInstance()->isOptionChecked(MenuOption::SimulateEyeTracking); - eyeTracker->setEnabled(isEyeTracking, isSimulating); - - Menu::getInstance()->getActionForOption(MenuOption::OnePointCalibration)->setEnabled(isEyeTracking && !isSimulating); - Menu::getInstance()->getActionForOption(MenuOption::ThreePointCalibration)->setEnabled(isEyeTracking && !isSimulating); - Menu::getInstance()->getActionForOption(MenuOption::FivePointCalibration)->setEnabled(isEyeTracking && !isSimulating); -} - -void Application::calibrateEyeTracker1Point() { - DependencyManager::get()->calibrate(1); -} - -void Application::calibrateEyeTracker3Points() { - DependencyManager::get()->calibrate(3); -} - -void Application::calibrateEyeTracker5Points() { - DependencyManager::get()->calibrate(5); -} -#endif - bool Application::exportEntities(const QString& filename, const QVector& entityIDs, const glm::vec3* givenOffset) { @@ -5508,7 +5505,7 @@ void Application::loadSettings() { // dictated that we should be in first person Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, isFirstPerson); Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !isFirstPerson); - _myCamera.setMode((isFirstPerson) ? CAMERA_MODE_FIRST_PERSON : CAMERA_MODE_THIRD_PERSON); + _myCamera.setMode((isFirstPerson) ? CAMERA_MODE_FIRST_PERSON : CAMERA_MODE_LOOK_AT); cameraMenuChanged(); auto inputs = pluginManager->getInputPlugins(); @@ -5816,8 +5813,8 @@ void Application::pushPostUpdateLambda(void* key, const std::function& f _postUpdateLambdas[key] = func; } -// Called during Application::update immediately before AvatarManager::updateMyAvatar, updating my data that is then sent to everyone. -// (Maybe this code should be moved there?) +// Called during Application::update immediately before AvatarManager::updateMyAvatar, updating my data that is then sent +// to everyone. // The principal result is to call updateLookAtTargetAvatar() and then setLookAtPosition(). // Note that it is called BEFORE we update position or joints based on sensors, etc. void Application::updateMyAvatarLookAtPosition() { @@ -5826,91 +5823,8 @@ void Application::updateMyAvatarLookAtPosition() { PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()"); auto myAvatar = getMyAvatar(); - myAvatar->updateLookAtTargetAvatar(); FaceTracker* faceTracker = getActiveFaceTracker(); - auto eyeTracker = DependencyManager::get(); - - bool isLookingAtSomeone = false; - bool isHMD = qApp->isHMDMode(); - glm::vec3 lookAtSpot; - if (eyeTracker->isTracking() && (isHMD || eyeTracker->isSimulating())) { - // Look at the point that the user is looking at. - glm::vec3 lookAtPosition = eyeTracker->getLookAtPosition(); - if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - lookAtPosition.x = -lookAtPosition.x; - } - if (isHMD) { - // TODO -- this code is probably wrong, getHeadPose() returns something in sensor frame, not avatar - glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose(); - glm::quat hmdRotation = glm::quat_cast(headPose); - lookAtSpot = _myCamera.getPosition() + myAvatar->getWorldOrientation() * (hmdRotation * lookAtPosition); - } else { - lookAtSpot = myAvatar->getHead()->getEyePosition() - + (myAvatar->getHead()->getFinalOrientationInWorldFrame() * lookAtPosition); - } - } else { - AvatarSharedPointer lookingAt = myAvatar->getLookAtTargetAvatar().lock(); - bool haveLookAtCandidate = lookingAt && myAvatar.get() != lookingAt.get(); - auto avatar = static_pointer_cast(lookingAt); - bool mutualLookAtSnappingEnabled = avatar && avatar->getLookAtSnappingEnabled() && myAvatar->getLookAtSnappingEnabled(); - if (haveLookAtCandidate && mutualLookAtSnappingEnabled) { - // If I am looking at someone else, look directly at one of their eyes - isLookingAtSomeone = true; - auto lookingAtHead = avatar->getHead(); - - const float MAXIMUM_FACE_ANGLE = 65.0f * RADIANS_PER_DEGREE; - glm::vec3 lookingAtFaceOrientation = lookingAtHead->getFinalOrientationInWorldFrame() * IDENTITY_FORWARD; - glm::vec3 fromLookingAtToMe = glm::normalize(myAvatar->getHead()->getEyePosition() - - lookingAtHead->getEyePosition()); - float faceAngle = glm::angle(lookingAtFaceOrientation, fromLookingAtToMe); - - if (faceAngle < MAXIMUM_FACE_ANGLE) { - // Randomly look back and forth between look targets - eyeContactTarget target = Menu::getInstance()->isOptionChecked(MenuOption::FixGaze) ? - LEFT_EYE : myAvatar->getEyeContactTarget(); - switch (target) { - case LEFT_EYE: - lookAtSpot = lookingAtHead->getLeftEyePosition(); - break; - case RIGHT_EYE: - lookAtSpot = lookingAtHead->getRightEyePosition(); - break; - case MOUTH: - lookAtSpot = lookingAtHead->getMouthPosition(); - break; - } - } else { - // Just look at their head (mid point between eyes) - lookAtSpot = lookingAtHead->getEyePosition(); - } - } else { - // I am not looking at anyone else, so just look forward - auto headPose = myAvatar->getControllerPoseInWorldFrame(controller::Action::HEAD); - if (headPose.isValid()) { - lookAtSpot = transformPoint(headPose.getMatrix(), glm::vec3(0.0f, 0.0f, TREE_SCALE)); - } else { - lookAtSpot = myAvatar->getHead()->getEyePosition() + - (myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE)); - } - } - - // Deflect the eyes a bit to match the detected gaze from the face tracker if active. - if (faceTracker && !faceTracker->isMuted()) { - float eyePitch = faceTracker->getEstimatedEyePitch(); - float eyeYaw = faceTracker->getEstimatedEyeYaw(); - const float GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT = 0.1f; - glm::vec3 origin = myAvatar->getHead()->getEyePosition(); - float deflection = faceTracker->getEyeDeflection(); - if (isLookingAtSomeone) { - deflection *= GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT; - } - lookAtSpot = origin + _myCamera.getOrientation() * glm::quat(glm::radians(glm::vec3( - eyePitch * deflection, eyeYaw * deflection, 0.0f))) * - glm::inverse(_myCamera.getOrientation()) * (lookAtSpot - origin); - } - } - - myAvatar->getHead()->setLookAtPosition(lookAtSpot); + myAvatar->updateLookAtPosition(faceTracker, _myCamera); } void Application::updateThreads(float deltaTime) { @@ -5949,11 +5863,16 @@ void Application::cycleCamera() { } else if (menu->isOptionChecked(MenuOption::FirstPerson)) { menu->setIsOptionChecked(MenuOption::FirstPerson, false); - menu->setIsOptionChecked(MenuOption::ThirdPerson, true); + menu->setIsOptionChecked(MenuOption::LookAtCamera, true); - } else if (menu->isOptionChecked(MenuOption::ThirdPerson)) { + } else if (menu->isOptionChecked(MenuOption::LookAtCamera)) { - menu->setIsOptionChecked(MenuOption::ThirdPerson, false); + menu->setIsOptionChecked(MenuOption::LookAtCamera, false); + menu->setIsOptionChecked(MenuOption::SelfieCamera, true); + + } else if (menu->isOptionChecked(MenuOption::SelfieCamera)) { + + menu->setIsOptionChecked(MenuOption::SelfieCamera, false); menu->setIsOptionChecked(MenuOption::FullscreenMirror, true); } @@ -5965,11 +5884,11 @@ void Application::cameraModeChanged() { case CAMERA_MODE_FIRST_PERSON: Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true); break; - case CAMERA_MODE_THIRD_PERSON: - Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); + case CAMERA_MODE_LOOK_AT: + Menu::getInstance()->setIsOptionChecked(MenuOption::LookAtCamera, true); break; - case CAMERA_MODE_MIRROR: - Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true); + case CAMERA_MODE_SELFIE: + Menu::getInstance()->setIsOptionChecked(MenuOption::SelfieCamera, true); break; default: // we don't have menu items for the others, so just leave it alone. @@ -5985,32 +5904,32 @@ void Application::changeViewAsNeeded(float boomLength) { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON && boomLengthGreaterThanMinimum) { Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false); - Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); + Menu::getInstance()->setIsOptionChecked(MenuOption::LookAtCamera, true); cameraMenuChanged(); - } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON && !boomLengthGreaterThanMinimum) { + } else if (_myCamera.getMode() == CAMERA_MODE_LOOK_AT && !boomLengthGreaterThanMinimum) { Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true); - Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, false); + Menu::getInstance()->setIsOptionChecked(MenuOption::LookAtCamera, false); cameraMenuChanged(); } } void Application::cameraMenuChanged() { auto menu = Menu::getInstance(); - if (menu->isOptionChecked(MenuOption::FullscreenMirror)) { - if (!isHMDMode() && _myCamera.getMode() != CAMERA_MODE_MIRROR) { - _mirrorYawOffset = 0.0f; - _myCamera.setMode(CAMERA_MODE_MIRROR); - getMyAvatar()->reset(false, false, false); // to reset any active MyAvatar::FollowHelpers - getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT); - } - } else if (menu->isOptionChecked(MenuOption::FirstPerson)) { + if (menu->isOptionChecked(MenuOption::FirstPerson)) { if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); getMyAvatar()->setBoomLength(MyAvatar::ZOOM_MIN); } - } else if (menu->isOptionChecked(MenuOption::ThirdPerson)) { - if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { - _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); + } else if (menu->isOptionChecked(MenuOption::LookAtCamera)) { + if (_myCamera.getMode() != CAMERA_MODE_LOOK_AT) { + _myCamera.setMode(CAMERA_MODE_LOOK_AT); + if (getMyAvatar()->getBoomLength() == MyAvatar::ZOOM_MIN) { + getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT); + } + } + } else if (menu->isOptionChecked(MenuOption::SelfieCamera)) { + if (_myCamera.getMode() != CAMERA_MODE_SELFIE) { + _myCamera.setMode(CAMERA_MODE_SELFIE); if (getMyAvatar()->getBoomLength() == MyAvatar::ZOOM_MIN) { getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT); } @@ -6482,7 +6401,10 @@ void Application::update(float deltaTime) { controller::Action::LEFT_UP_LEG, controller::Action::RIGHT_UP_LEG, controller::Action::LEFT_TOE_BASE, - controller::Action::RIGHT_TOE_BASE + controller::Action::RIGHT_TOE_BASE, + controller::Action::LEFT_EYE, + controller::Action::RIGHT_EYE + }; // copy controller poses from userInputMapper to myAvatar. @@ -7157,8 +7079,7 @@ void Application::resetSensors(bool andReload) { #ifdef HAVE_DDE DependencyManager::get()->reset(); #endif - - DependencyManager::get()->reset(); + _overlayConductor.centerUI(); getActiveDisplayPlugin()->resetSensors(); getMyAvatar()->reset(true, andReload); @@ -7447,7 +7368,7 @@ void Application::addingEntityWithCertificate(const QString& certificateID, cons ledger->updateLocation(certificateID, placeName); } -void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) { +void Application::registerScriptEngineWithApplicationServices(const ScriptEnginePointer& scriptEngine) { scriptEngine->setEmitScriptUpdatesFunction([this]() { SharedNodePointer entityServerNode = DependencyManager::get()->soloNodeOfType(NodeType::EntityServer); @@ -7486,9 +7407,19 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe qScriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue, RayToOverlayIntersectionResultFromScriptValue); + bool clientScript = scriptEngine->isClientScript(); + #if !defined(DISABLE_QML) scriptEngine->registerGlobalObject("OffscreenFlags", getOffscreenUI()->getFlags()); - scriptEngine->registerGlobalObject("Desktop", DependencyManager::get().data()); + if (clientScript) { + scriptEngine->registerGlobalObject("Desktop", DependencyManager::get().data()); + } else { + auto desktopScriptingInterface = new DesktopScriptingInterface(nullptr, true); + scriptEngine->registerGlobalObject("Desktop", desktopScriptingInterface); + if (QThread::currentThread() != thread()) { + desktopScriptingInterface->moveToThread(thread()); + } + } #endif qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); @@ -7513,7 +7444,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter); - bool clientScript = scriptEngine->isClientScript(); scriptEngine->registerFunction("OverlayWindow", clientScript ? QmlWindowClass::constructor : QmlWindowClass::restricted_constructor); #if !defined(Q_OS_ANDROID) && !defined(DISABLE_QML) scriptEngine->registerFunction("OverlayWebWindow", clientScript ? QmlWebWindowClass::constructor : QmlWebWindowClass::restricted_constructor); @@ -7540,6 +7470,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe // Caches scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); scriptEngine->registerGlobalObject("TextureCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("MaterialCache", DependencyManager::get().data()); scriptEngine->registerGlobalObject("ModelCache", DependencyManager::get().data()); scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); @@ -8573,6 +8504,8 @@ void Application::toggleLogDialog() { Qt::WindowFlags flags = _logDialog->windowFlags() | Qt::Tool; _logDialog->setWindowFlags(flags); } +#else + Q_UNUSED(keepOnTop) #endif } @@ -9089,9 +9022,9 @@ void Application::setDisplayPlugin(DisplayPluginPointer newDisplayPlugin) { cameraMenuChanged(); } - // Remove the mirror camera option from menu if in HMD mode - auto mirrorAction = menu->getActionForOption(MenuOption::FullscreenMirror); - mirrorAction->setVisible(!isHmd); + // Remove the selfie camera options from menu if in HMD mode + auto selfieAction = menu->getActionForOption(MenuOption::SelfieCamera); + selfieAction->setVisible(!isHmd); } Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); @@ -9525,6 +9458,14 @@ void Application::showUrlHandler(const QUrl& url) { } }); } + +// used to test "shutdown" crash annotation. +void Application::crashOnShutdown() { + qDebug() << "crashOnShutdown(), ON PURPOSE!"; + _crashOnShutdown = true; + quit(); +} + void Application::overrideEntry(){ _overrideEntry = true; } diff --git a/interface/src/Application.h b/interface/src/Application.h index 913671473d..af2348d1e9 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -252,7 +252,7 @@ public: NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; } virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; } - virtual void registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) override; + virtual void registerScriptEngineWithApplicationServices(const ScriptEnginePointer& scriptEngine) override; virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const override { copyDisplayViewFrustum(viewOut); } virtual QThread* getMainThread() override { return thread(); } @@ -437,13 +437,6 @@ public slots: void sendWrongProtocolVersionsSignature(bool checked) { ::sendWrongProtocolVersionsSignature(checked); } #endif -#ifdef HAVE_IVIEWHMD - void setActiveEyeTracker(); - void calibrateEyeTracker1Point(); - void calibrateEyeTracker3Points(); - void calibrateEyeTracker5Points(); -#endif - static void showHelp(); void cycleCamera(); @@ -497,6 +490,9 @@ public slots: bool gpuTextureMemSizeStable(); void showUrlHandler(const QUrl& url); + // used to test "shutdown" crash annotation. + void crashOnShutdown(); + private slots: void onDesktopRootItemCreated(QQuickItem* qmlContext); void onDesktopRootContextCreated(QQmlContext* qmlContext); @@ -844,5 +840,7 @@ private: bool _overrideEntry { false }; VisionSqueeze _visionSqueeze; + + bool _crashOnShutdown { false }; }; #endif // hifi_Application_h diff --git a/interface/src/MacHelper.cpp b/interface/src/MacHelper.cpp deleted file mode 100755 index 8527f02918..0000000000 --- a/interface/src/MacHelper.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// -// MacHelper.h -// interface/src -// -// Created by Howard Stearns -// Copyright 2019 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 "InterfaceLogging.h" -#include "MacHelper.h" -#include - -#ifdef Q_OS_MAC -#include -#include - -// The type definitions in these variables come from IOKit, which includes a definition of Duration that conflicts with ours. -// So... we include these definitions here rather than in the .h, as the .h is included in Application.cpp which -// uses Duration. -static io_connect_t root_port; -static IONotificationPortRef notifyPortRef; -static io_object_t notifierObject; -static void* refCon; - -static void sleepHandler(void* refCon, io_service_t service, natural_t messageType, void* messageArgument) { - if (messageType == kIOMessageSystemHasPoweredOn) { - qCInfo(interfaceapp) << "Waking up from sleep or hybernation."; - QMetaObject::invokeMethod(DependencyManager::get().data(), "noteAwakening", Qt::QueuedConnection); - } -} -#endif - -MacHelper::MacHelper() { -#ifdef Q_OS_MAC - root_port = IORegisterForSystemPower(refCon, ¬ifyPortRef, sleepHandler, ¬ifierObject); - if (root_port == 0) { - qCWarning(interfaceapp) << "IORegisterForSystemPower failed"; - return; - } - CFRunLoopAddSource(CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource(notifyPortRef), - kCFRunLoopCommonModes); -#endif -} - -MacHelper::~MacHelper() { -#ifdef Q_OS_MAC - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource(notifyPortRef), - kCFRunLoopCommonModes); - IODeregisterForSystemPower(¬ifierObject); - IOServiceClose(root_port); - IONotificationPortDestroy(notifyPortRef); -#endif -} diff --git a/interface/src/MacHelper.h b/interface/src/MacHelper.h deleted file mode 100755 index 52ad4d3e55..0000000000 --- a/interface/src/MacHelper.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// MacHelper.h -// interface/src -// -// Created by Howard Stearns -// Copyright 2019 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 - -#include "DependencyManager.h" - -class MacHelper : public Dependency { -public: - MacHelper(); - ~MacHelper(); -}; - diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4cf78c23ee..89fec3c812 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -177,19 +177,19 @@ Menu::Menu() { firstPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); - // View > Third Person - auto thirdPersonAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( - viewMenu, MenuOption::ThirdPerson, 0, + // View > Look At + auto lookAtAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( + viewMenu, MenuOption::LookAtCamera, 0, false, qApp, SLOT(cameraMenuChanged()))); - thirdPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); + lookAtAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); - // View > Mirror - auto viewMirrorAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( - viewMenu, MenuOption::FullscreenMirror, 0, - false, qApp, SLOT(cameraMenuChanged()))); + // View > Selfie + auto selfieAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( + viewMenu, MenuOption::SelfieCamera, 0, + false, qApp, SLOT(cameraMenuChanged()))); - viewMirrorAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); + selfieAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); viewMenu->addSeparator(); @@ -534,32 +534,18 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::AutoMuteAudio, 0, false); #endif -#ifdef HAVE_IVIEWHMD - // Developer > Avatar > Eye Tracking - MenuWrapper* eyeTrackingMenu = avatarDebugMenu->addMenu("Eye Tracking"); - addCheckableActionToQMenuAndActionHash(eyeTrackingMenu, MenuOption::SMIEyeTracking, 0, false, - qApp, SLOT(setActiveEyeTracker())); - { - MenuWrapper* calibrateEyeTrackingMenu = eyeTrackingMenu->addMenu("Calibrate"); - addActionToQMenuAndActionHash(calibrateEyeTrackingMenu, MenuOption::OnePointCalibration, 0, - qApp, SLOT(calibrateEyeTracker1Point())); - addActionToQMenuAndActionHash(calibrateEyeTrackingMenu, MenuOption::ThreePointCalibration, 0, - qApp, SLOT(calibrateEyeTracker3Points())); - addActionToQMenuAndActionHash(calibrateEyeTrackingMenu, MenuOption::FivePointCalibration, 0, - qApp, SLOT(calibrateEyeTracker5Points())); - } - addCheckableActionToQMenuAndActionHash(eyeTrackingMenu, MenuOption::SimulateEyeTracking, 0, false, - qApp, SLOT(setActiveEyeTracker())); -#endif - action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AvatarReceiveStats, 0, false); connect(action, &QAction::triggered, [this]{ Avatar::setShowReceiveStats(isOptionChecked(MenuOption::AvatarReceiveStats)); }); action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowBoundingCollisionShapes, 0, false); connect(action, &QAction::triggered, [this]{ Avatar::setShowCollisionShapes(isOptionChecked(MenuOption::ShowBoundingCollisionShapes)); }); action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowMyLookAtVectors, 0, false); connect(action, &QAction::triggered, [this]{ Avatar::setShowMyLookAtVectors(isOptionChecked(MenuOption::ShowMyLookAtVectors)); }); + action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowMyLookAtTarget, 0, false); + connect(action, &QAction::triggered, [this]{ Avatar::setShowMyLookAtTarget(isOptionChecked(MenuOption::ShowMyLookAtTarget)); }); action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowOtherLookAtVectors, 0, false); connect(action, &QAction::triggered, [this]{ Avatar::setShowOtherLookAtVectors(isOptionChecked(MenuOption::ShowOtherLookAtVectors)); }); + action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowOtherLookAtTarget, 0, false); + connect(action, &QAction::triggered, [this]{ Avatar::setShowOtherLookAtTarget(isOptionChecked(MenuOption::ShowOtherLookAtTarget)); }); auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getMyAvatar(); @@ -725,43 +711,51 @@ Menu::Menu() { DependencyManager::get().data(), SLOT(setForceCoarsePicking(bool))); // Developer > Crash >>> - MenuWrapper* crashMenu = developerMenu->addMenu("Crash"); + bool result = false; + const QString HIFI_SHOW_DEVELOPER_CRASH_MENU("HIFI_SHOW_DEVELOPER_CRASH_MENU"); + result = QProcessEnvironment::systemEnvironment().contains(HIFI_SHOW_DEVELOPER_CRASH_MENU); + if (result) { + MenuWrapper* crashMenu = developerMenu->addMenu("Crash"); - // Developer > Crash > Display Crash Options - addCheckableActionToQMenuAndActionHash(crashMenu, MenuOption::DisplayCrashOptions, 0, true); + // Developer > Crash > Display Crash Options + addCheckableActionToQMenuAndActionHash(crashMenu, MenuOption::DisplayCrashOptions, 0, true); - addActionToQMenuAndActionHash(crashMenu, MenuOption::DeadlockInterface, 0, qApp, SLOT(deadlockApplication())); - addActionToQMenuAndActionHash(crashMenu, MenuOption::UnresponsiveInterface, 0, qApp, SLOT(unresponsiveApplication())); + addActionToQMenuAndActionHash(crashMenu, MenuOption::DeadlockInterface, 0, qApp, SLOT(deadlockApplication())); + addActionToQMenuAndActionHash(crashMenu, MenuOption::UnresponsiveInterface, 0, qApp, SLOT(unresponsiveApplication())); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunction); - connect(action, &QAction::triggered, qApp, []() { crash::pureVirtualCall(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunctionThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::pureVirtualCall).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunction); + connect(action, &QAction::triggered, qApp, []() { crash::pureVirtualCall(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunctionThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::pureVirtualCall).join(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFree); - connect(action, &QAction::triggered, qApp, []() { crash::doubleFree(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFreeThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::doubleFree).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFree); + connect(action, &QAction::triggered, qApp, []() { crash::doubleFree(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFreeThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::doubleFree).join(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbort); - connect(action, &QAction::triggered, qApp, []() { crash::doAbort(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbortThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::doAbort).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbort); + connect(action, &QAction::triggered, qApp, []() { crash::doAbort(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbortThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::doAbort).join(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereference); - connect(action, &QAction::triggered, qApp, []() { crash::nullDeref(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereferenceThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::nullDeref).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereference); + connect(action, &QAction::triggered, qApp, []() { crash::nullDeref(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereferenceThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::nullDeref).join(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccess); - connect(action, &QAction::triggered, qApp, []() { crash::outOfBoundsVectorCrash(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccessThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::outOfBoundsVectorCrash).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccess); + connect(action, &QAction::triggered, qApp, []() { crash::outOfBoundsVectorCrash(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccessThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::outOfBoundsVectorCrash).join(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFault); - connect(action, &QAction::triggered, qApp, []() { crash::newFault(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFaultThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::newFault).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFault); + connect(action, &QAction::triggered, qApp, []() { crash::newFault(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFaultThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::newFault).join(); }); + + addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOnShutdown, 0, qApp, SLOT(crashOnShutdown())); + } + // Developer > Show Statistics addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats, 0, true); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 70687786a9..0ba1159052 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -72,6 +72,7 @@ namespace MenuOption { const QString CrashNullDereferenceThreaded = "Null Dereference (threaded)"; const QString CrashAbort = "Abort"; const QString CrashAbortThreaded = "Abort (threaded)"; + const QString CrashOnShutdown = "Crash During Shutdown"; const QString CrashOutOfBoundsVectorAccess = "Out of Bounds Vector Access"; const QString CrashOutOfBoundsVectorAccessThreaded = "Out of Bounds Vector Access (threaded)"; const QString CrashNewFault = "New Fault"; @@ -128,6 +129,7 @@ namespace MenuOption { const QString Login = "Login/Sign Up"; const QString Log = "Log"; const QString LogExtraTimings = "Log Extra Timing Details"; + const QString LookAtCamera = "Third Person"; const QString LowVelocityFilter = "Low Velocity Filter"; const QString MeshVisible = "Draw Mesh"; const QString MuteEnvironment = "Mute Environment"; @@ -180,6 +182,7 @@ namespace MenuOption { const QString RunTimingTests = "Run Timing Tests"; const QString ScriptedMotorControl = "Enable Scripted Motor Control"; const QString ShowTrackedObjects = "Show Tracked Objects"; + const QString SelfieCamera = "Selfie"; const QString SendWrongDSConnectVersion = "Send wrong DS connect version"; const QString SendWrongProtocolVersion = "Send wrong protocol version"; const QString SetHomeLocation = "Set Home Location"; @@ -187,7 +190,9 @@ namespace MenuOption { const QString ShowBoundingCollisionShapes = "Show Bounding Collision Shapes"; const QString ShowDSConnectTable = "Show Domain Connection Timing"; const QString ShowMyLookAtVectors = "Show My Eye Vectors"; + const QString ShowMyLookAtTarget = "Show My Look-At Target"; const QString ShowOtherLookAtVectors = "Show Other Eye Vectors"; + const QString ShowOtherLookAtTarget = "Show Other Look-At Target"; const QString EnableLookAtSnapping = "Enable LookAt Snapping"; const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats"; const QString SimulateEyeTracking = "Simulate"; @@ -198,7 +203,7 @@ namespace MenuOption { const QString AnimStats = "Show Animation Stats"; const QString StopAllScripts = "Stop All Scripts"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; - const QString ThirdPerson = "Third Person"; + const QString ThirdPerson = "Third Person Legacy"; const QString ThreePointCalibration = "3 Point Calibration"; const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Basic2DWindowOpenGLDisplayPlugin.cpp const QString ToggleHipsFollowing = "Toggle Hips Following"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 089ff4c2bf..54785933c9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -99,6 +99,16 @@ static const QString USER_RECENTER_MODEL_FORCE_STAND = QStringLiteral("ForceStan static const QString USER_RECENTER_MODEL_AUTO = QStringLiteral("Auto"); static const QString USER_RECENTER_MODEL_DISABLE_HMD_LEAN = QStringLiteral("DisableHMDLean"); +const QString HEAD_BLEND_DIRECTIONAL_ALPHA_NAME = "lookAroundAlpha"; +const QString HEAD_BLEND_LINEAR_ALPHA_NAME = "lookBlendAlpha"; +const float HEAD_ALPHA_BLENDING = 1.0f; + +const QString POINT_REACTION_NAME = "point"; +const QString POINT_BLEND_DIRECTIONAL_ALPHA_NAME = "pointAroundAlpha"; +const QString POINT_BLEND_LINEAR_ALPHA_NAME = "pointBlendAlpha"; +const QString POINT_REF_JOINT_NAME = "RightShoulder"; +const float POINT_ALPHA_BLENDING = 1.0f; + MyAvatar::SitStandModelType stringToUserRecenterModel(const QString& str) { if (str == USER_RECENTER_MODEL_FORCE_SIT) { return MyAvatar::ForceSit; @@ -451,7 +461,7 @@ QByteArray MyAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropF _globalBoundingBoxDimensions.y = _characterController.getCapsuleHalfHeight(); _globalBoundingBoxDimensions.z = _characterController.getCapsuleRadius(); _globalBoundingBoxOffset = _characterController.getCapsuleLocalOffset(); - if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { + if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) { // fake the avatar position that is sent up to the AvatarMixer glm::vec3 oldPosition = getWorldPosition(); setWorldPosition(getSkeletonPosition()); @@ -772,6 +782,18 @@ void MyAvatar::update(float deltaTime) { emit energyChanged(currentEnergy); updateEyeContactTarget(deltaTime); + + // if we're getting eye rotations from a tracker, disable observer-side procedural eye motions + auto userInputMapper = DependencyManager::get(); + bool eyesTracked = + userInputMapper->getPoseState(controller::Action::LEFT_EYE).valid && + userInputMapper->getPoseState(controller::Action::RIGHT_EYE).valid; + + int leftEyeJointIndex = getJointIndex("LeftEye"); + int rightEyeJointIndex = getJointIndex("RightEye"); + bool eyesAreOverridden = getIsJointOverridden(leftEyeJointIndex) || getIsJointOverridden(rightEyeJointIndex); + + _headData->setHasProceduralEyeMovement(!(eyesTracked || eyesAreOverridden)); } void MyAvatar::updateEyeContactTarget(float deltaTime) { @@ -932,10 +954,20 @@ void MyAvatar::simulate(float deltaTime, bool inView) { qCDebug(interfaceapp) << "MyAvatar::simulate headPosition is NaN"; headPosition = glm::vec3(0.0f); } - head->setPosition(headPosition); head->setScale(getModelScale()); head->simulate(deltaTime); + CameraMode mode = qApp->getCamera().getMode(); + if (_scriptControlsHeadLookAt || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) { + if (!_pointAtActive || !_isPointTargetValid) { + updateHeadLookAt(deltaTime); + } else { + resetHeadLookAt(); + } + } else if (_headLookAtActive){ + resetHeadLookAt(); + _headLookAtActive = false; + } } // Record avatars movements. @@ -1454,8 +1486,50 @@ void MyAvatar::setEnableDebugDrawHandControllers(bool isEnabled) { _enableDebugDrawHandControllers = isEnabled; if (!isEnabled) { - DebugDraw::getInstance().removeMarker("leftHandController"); - DebugDraw::getInstance().removeMarker("rightHandController"); + DebugDraw::getInstance().removeMarker("LEFT_HAND"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND"); + + DebugDraw::getInstance().removeMarker("LEFT_HAND_THUMB1"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_THUMB2"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_THUMB3"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_THUMB4"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_INDEX1"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_INDEX2"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_INDEX3"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_INDEX4"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_MIDDLE1"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_MIDDLE2"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_MIDDLE3"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_MIDDLE4"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_RING1"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_RING2"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_RING3"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_RING4"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_PINKY1"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_PINKY2"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_PINKY3"); + DebugDraw::getInstance().removeMarker("LEFT_HAND_PINKY4"); + + DebugDraw::getInstance().removeMarker("RIGHT_HAND_THUMB1"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_THUMB2"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_THUMB3"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_THUMB4"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_INDEX1"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_INDEX2"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_INDEX3"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_INDEX4"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_MIDDLE1"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_MIDDLE2"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_MIDDLE3"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_MIDDLE4"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_RING1"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_RING2"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_RING3"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_RING4"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_PINKY1"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_PINKY2"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_PINKY3"); + DebugDraw::getInstance().removeMarker("RIGHT_HAND_PINKY4"); } } @@ -2556,7 +2630,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN glm::vec3 MyAvatar::getSkeletonPosition() const { CameraMode mode = qApp->getCamera().getMode(); - if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { + if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) { // The avatar is rotated PI about the yAxis, so we have to correct for it // to get the skeleton offset contribution in the world-frame. const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); @@ -2644,7 +2718,11 @@ void MyAvatar::updateMotors() { if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) { if (_characterController.getState() == CharacterController::State::Hover || _characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) { - motorRotation = getMyHead()->getHeadOrientation(); + if (qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT || qApp->getCamera().getMode() == CAMERA_MODE_SELFIE) { + motorRotation = getLookAtRotation(); + } else { + motorRotation = getMyHead()->getHeadOrientation(); + } } else { // non-hovering = walking: follow camera twist about vertical but not lift // we decompose camera's rotation and store the twist part in motorRotation @@ -3079,7 +3157,6 @@ void MyAvatar::initAnimGraph() { } emit animGraphUrlChanged(graphUrl); - _skeletonModel->getRig().initAnimGraph(graphUrl); _currentAnimGraphUrl.set(graphUrl); connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded())); @@ -3097,6 +3174,16 @@ void MyAvatar::animGraphLoaded() { disconnect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded())); } +void MyAvatar::debugDrawPose(controller::Action action, const char* channelName, float size) { + auto pose = getControllerPoseInWorldFrame(action); + if (pose.isValid()) { + DebugDraw::getInstance().addMarker(channelName, pose.getRotation(), pose.getTranslation(), glm::vec4(1), size); + } else { + DebugDraw::getInstance().removeMarker(channelName); + } +} + + void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { Avatar::postUpdate(deltaTime, scene); @@ -3137,20 +3224,50 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { } if (_enableDebugDrawHandControllers) { - auto leftHandPose = getControllerPoseInWorldFrame(controller::Action::LEFT_HAND); - auto rightHandPose = getControllerPoseInWorldFrame(controller::Action::RIGHT_HAND); + debugDrawPose(controller::Action::LEFT_HAND, "LEFT_HAND", 1.0); + debugDrawPose(controller::Action::RIGHT_HAND, "RIGHT_HAND", 1.0); - if (leftHandPose.isValid()) { - DebugDraw::getInstance().addMarker("leftHandController", leftHandPose.getRotation(), leftHandPose.getTranslation(), glm::vec4(1)); - } else { - DebugDraw::getInstance().removeMarker("leftHandController"); - } + debugDrawPose(controller::Action::LEFT_HAND_THUMB1, "LEFT_HAND_THUMB1", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_THUMB2, "LEFT_HAND_THUMB2", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_THUMB3, "LEFT_HAND_THUMB3", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_THUMB4, "LEFT_HAND_THUMB4", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_INDEX1, "LEFT_HAND_INDEX1", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_INDEX2, "LEFT_HAND_INDEX2", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_INDEX3, "LEFT_HAND_INDEX3", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_INDEX4, "LEFT_HAND_INDEX4", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_MIDDLE1, "LEFT_HAND_MIDDLE1", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_MIDDLE2, "LEFT_HAND_MIDDLE2", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_MIDDLE3, "LEFT_HAND_MIDDLE3", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_MIDDLE4, "LEFT_HAND_MIDDLE4", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_RING1, "LEFT_HAND_RING1", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_RING2, "LEFT_HAND_RING2", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_RING3, "LEFT_HAND_RING3", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_RING4, "LEFT_HAND_RING4", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_PINKY1, "LEFT_HAND_PINKY1", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_PINKY2, "LEFT_HAND_PINKY2", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_PINKY3, "LEFT_HAND_PINKY3", 0.1f); + debugDrawPose(controller::Action::LEFT_HAND_PINKY4, "LEFT_HAND_PINKY4", 0.1f); - if (rightHandPose.isValid()) { - DebugDraw::getInstance().addMarker("rightHandController", rightHandPose.getRotation(), rightHandPose.getTranslation(), glm::vec4(1)); - } else { - DebugDraw::getInstance().removeMarker("rightHandController"); - } + debugDrawPose(controller::Action::RIGHT_HAND_THUMB1, "RIGHT_HAND_THUMB1", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_THUMB2, "RIGHT_HAND_THUMB2", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_THUMB3, "RIGHT_HAND_THUMB3", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_THUMB4, "RIGHT_HAND_THUMB4", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_INDEX1, "RIGHT_HAND_INDEX1", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_INDEX2, "RIGHT_HAND_INDEX2", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_INDEX3, "RIGHT_HAND_INDEX3", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_INDEX4, "RIGHT_HAND_INDEX4", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_MIDDLE1, "RIGHT_HAND_MIDDLE1", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_MIDDLE2, "RIGHT_HAND_MIDDLE2", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_MIDDLE3, "RIGHT_HAND_MIDDLE3", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_MIDDLE4, "RIGHT_HAND_MIDDLE4", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_RING1, "RIGHT_HAND_RING1", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_RING2, "RIGHT_HAND_RING2", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_RING3, "RIGHT_HAND_RING3", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_RING4, "RIGHT_HAND_RING4", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_PINKY1, "RIGHT_HAND_PINKY1", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_PINKY2, "RIGHT_HAND_PINKY2", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_PINKY3, "RIGHT_HAND_PINKY3", 0.1f); + debugDrawPose(controller::Action::RIGHT_HAND_PINKY4, "RIGHT_HAND_PINKY4", 0.1f); } DebugDraw::getInstance().updateMyAvatarPos(getWorldPosition()); @@ -3322,11 +3439,19 @@ void MyAvatar::setRotationThreshold(float angleRadians) { } void MyAvatar::updateOrientation(float deltaTime) { - // Smoothly rotate body with arrow keys float targetSpeed = getDriveKey(YAW) * _yawSpeed; + CameraMode mode = qApp->getCamera().getMode(); + bool computeLookAt = (mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) && isReadyForPhysics() && !qApp->isHMDMode(); + if (computeLookAt) { + // For "Look At" and "Selfie" camera modes we also smooth the yaw rotation from right-click mouse movement. + float speedFromDeltaYaw = deltaTime > FLT_EPSILON ? getDriveKey(DELTA_YAW) / deltaTime : 0.0f; + speedFromDeltaYaw *= _yawSpeed / YAW_SPEED_DEFAULT; + targetSpeed += speedFromDeltaYaw; + } + if (targetSpeed != 0.0f) { - const float ROTATION_RAMP_TIMESCALE = 0.1f; + const float ROTATION_RAMP_TIMESCALE = 0.5f; float blend = deltaTime / ROTATION_RAMP_TIMESCALE; if (blend > 1.0f) { blend = 1.0f; @@ -3347,10 +3472,10 @@ void MyAvatar::updateOrientation(float deltaTime) { } } float totalBodyYaw = _bodyYawDelta * deltaTime; - - // Rotate directly proportional to delta yaw and delta pitch from right-click mouse movement. - totalBodyYaw += getDriveKey(DELTA_YAW) * _yawSpeed / YAW_SPEED_DEFAULT; - + if (!computeLookAt) { + // Rotate directly proportional to delta yaw and delta pitch from right-click mouse movement. + totalBodyYaw += getDriveKey(DELTA_YAW) * _yawSpeed / YAW_SPEED_DEFAULT; + } // Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll // get an instantaneous 15 degree turn. If you keep holding the key down you'll get another // snap turn every half second. @@ -3359,7 +3484,6 @@ void MyAvatar::updateOrientation(float deltaTime) { totalBodyYaw += getDriveKey(STEP_YAW); snapTurn = true; } - // Use head/HMD roll to turn while flying, but not when standing still. if (qApp->isHMDMode() && getCharacterController()->getState() == CharacterController::State::Hover && _hmdRollControlEnabled && hasDriveInput()) { @@ -3394,7 +3518,64 @@ void MyAvatar::updateOrientation(float deltaTime) { // update body orientation by movement inputs glm::quat initialOrientation = getOrientationOutbound(); - setWorldOrientation(getWorldOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f)))); + glm::vec3 eyesPosition = getDefaultEyePosition(); + const float FPS = 60.0f; + float timeScale = deltaTime * FPS; + + bool faceForward = false; + bool isMovingFwdBwd = getDriveKey(TRANSLATE_Z) != 0.0f; + bool isMovingSideways = getDriveKey(TRANSLATE_X) != 0.0f; + bool isCameraYawing = getDriveKey(DELTA_YAW) + getDriveKey(STEP_YAW) + getDriveKey(YAW) != 0.0f; + bool isRotatingWhileSeated = !isCameraYawing && isMovingSideways && _characterController.getSeated(); + glm::quat previousOrientation = getWorldOrientation(); + + if (!computeLookAt) { + setWorldOrientation(getWorldOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f)))); + _lookAtCameraTarget = eyesPosition + getWorldOrientation() * Vectors::FRONT; + _lookAtYaw = getWorldOrientation(); + _lookAtPitch = Quaternions::IDENTITY; + } else { + // Compute new look at vectors + if (totalBodyYaw != 0.0f) { + _lookAtYaw = _lookAtYaw * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f))); + } + float pitchIncrement = getDriveKey(PITCH) * _pitchSpeed * deltaTime + + getDriveKey(DELTA_PITCH) * _pitchSpeed / PITCH_SPEED_DEFAULT; + if (pitchIncrement != 0.0f) { + glm::quat _previousLookAtPitch = _lookAtPitch; + _lookAtPitch = _lookAtPitch * glm::quat(glm::radians(glm::vec3(pitchIncrement, 0.0f, 0.0f))); + // Limit the camera horizontal pitch + float MAX_LOOK_AT_PITCH_DEGREES = 80.0f; + float pitchFromHorizont = glm::degrees(angleBetween(getLookAtRotation() * Vectors::FRONT, _lookAtYaw * Vectors::FRONT)); + if (pitchFromHorizont > MAX_LOOK_AT_PITCH_DEGREES) { + _lookAtPitch = _previousLookAtPitch; + } + } + + faceForward = isMovingFwdBwd || (isMovingSideways && !isRotatingWhileSeated); + // Blend the avatar orientation with the camera look at if moving forward. + if (faceForward || _shouldTurnToFaceCamera) { + const float REORIENT_FORWARD_BLEND = 0.25f; + const float REORIENT_TURN_BLEND = 0.03f; + const float DIAGONAL_TURN_BLEND = 0.02f; + float blend = (_shouldTurnToFaceCamera ? REORIENT_TURN_BLEND : REORIENT_FORWARD_BLEND) * timeScale; + if (blend > 1.0f) { + blend = 1.0f; + } + glm::quat faceRotation = _lookAtYaw; + if (isMovingFwdBwd && isMovingSideways) { + // Reorient avatar to face camera diagonal + blend = DIAGONAL_TURN_BLEND; + float turnSign = getDriveKey(TRANSLATE_Z) < 0.0f ? -1.0f : 1.0f; + turnSign = getDriveKey(TRANSLATE_X) > 0.0f ? -turnSign : turnSign; + faceRotation = _lookAtYaw * glm::angleAxis(turnSign * 0.25f * PI, Vectors::UP); + } + setWorldOrientation(glm::slerp(getWorldOrientation(), faceRotation, blend)); + } else if (isRotatingWhileSeated) { + float rotatingWhileSeatedYaw = -getDriveKey(TRANSLATE_X) * _yawSpeed * deltaTime; + setWorldOrientation(getWorldOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, rotatingWhileSeatedYaw, 0.0f)))); + } + } if (snapTurn) { // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position. @@ -3415,9 +3596,77 @@ void MyAvatar::updateOrientation(float deltaTime) { head->setBaseYaw(YAW(euler)); head->setBasePitch(PITCH(euler)); head->setBaseRoll(ROLL(euler)); + } else if (computeLookAt) { + // Reset head orientation before applying the blending offset + head->setBaseYaw(0.0f); + head->setBasePitch(0.0f); + head->setBaseRoll(0.0f); + + glm::vec3 cameraVector = (faceForward ? _lookAtPitch * getWorldOrientation() : getLookAtRotation()) * Vectors::FRONT; + glm::vec3 cameraYawVector = _lookAtYaw * Vectors::FRONT; + + // Cap and attenuate head's lookat pitch angle + const float START_LOOKING_UP_DEGREES = 5.0f; + const float START_LOOKING_DOWN_DEGREES = 15.0f; + const float MAX_UP_DOWN_DEGREES = 90.0f; + + glm::vec3 avatarVectorUp = getWorldOrientation() * Vectors::UP; + float upDownDot = glm::dot(cameraVector, avatarVectorUp); + float upDownDegrees = MAX_UP_DOWN_DEGREES - glm::degrees(acosf(abs(upDownDot))); + + float lookAttenuation = 0.0f; + if (upDownDot <= 0.0f) { + if (upDownDegrees > START_LOOKING_DOWN_DEGREES) { + lookAttenuation = (upDownDegrees - START_LOOKING_DOWN_DEGREES) / (MAX_UP_DOWN_DEGREES - START_LOOKING_DOWN_DEGREES); + } + } else { + if (upDownDegrees > START_LOOKING_UP_DEGREES) { + lookAttenuation = (upDownDegrees - START_LOOKING_UP_DEGREES) / (MAX_UP_DOWN_DEGREES - START_LOOKING_UP_DEGREES); + } + } + glm::vec3 avatarVectorFront = getWorldOrientation() * Vectors::FRONT; + float frontBackDot = glm::dot(cameraYawVector, avatarVectorFront); + + glm::vec3 avatarVectorRight = getWorldOrientation() * Vectors::RIGHT; + float leftRightDot = glm::dot(cameraYawVector, avatarVectorRight); + + const float REORIENT_ANGLE = 65.0f; + const float TRIGGER_REORIENT_ANGLE = 45.0f; + glm::vec3 ajustedYawVector = cameraYawVector; + if (frontBackDot < 0.0f) { + ajustedYawVector = (leftRightDot < 0.0f ? -avatarVectorRight : avatarVectorRight); + cameraVector = (ajustedYawVector * _lookAtPitch) * Vectors::FRONT; + if (!isRotatingWhileSeated) { + if (frontBackDot < -glm::sin(glm::radians(TRIGGER_REORIENT_ANGLE))) { + _shouldTurnToFaceCamera = true; + } + } else { + setWorldOrientation(previousOrientation); + } + } else if (frontBackDot > glm::sin(glm::radians(REORIENT_ANGLE))) { + _shouldTurnToFaceCamera = false; + } + + cameraVector = glm::mix(cameraVector, ajustedYawVector, 1.0f - lookAttenuation); + // Calculate the camera target point. + + glm::vec3 targetPoint = eyesPosition + glm::normalize(cameraVector); + + const float LOOKAT_MIX_ALPHA = 0.25f; + if (!isFlying() || !hasDriveInput()) { + // Approximate the head's look at vector to the camera look at vector with some delay. + float mixAlpha = LOOKAT_MIX_ALPHA * timeScale; + if (mixAlpha > 1.0f) { + mixAlpha = 1.0f; + } + _lookAtCameraTarget = glm::mix(_lookAtCameraTarget, targetPoint, mixAlpha); + } else { + _lookAtCameraTarget = targetPoint; + } + _headLookAtActive = true; } else { head->setBaseYaw(0.0f); - head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime + head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime + getDriveKey(DELTA_PITCH) * _pitchSpeed / PITCH_SPEED_DEFAULT); head->setBaseRoll(0.0f); } @@ -3449,7 +3698,7 @@ float MyAvatar::calculateGearedSpeed(const float driveKey) { glm::vec3 MyAvatar::scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 right) { float stickFullOn = 0.85f; auto zSpeed = getDriveKey(TRANSLATE_Z); - auto xSpeed = getDriveKey(TRANSLATE_X); + auto xSpeed = !_characterController.getSeated() ? getDriveKey(TRANSLATE_X) : 0.0f; glm::vec3 direction; if (!useAdvancedMovementControls() && qApp->isHMDMode()) { // Walking disabled in settings. @@ -3487,6 +3736,10 @@ glm::vec3 MyAvatar::scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 rig } else { // Desktop mode. direction = (zSpeed * forward) + (xSpeed * right); + if (qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT && zSpeed != 0.0f && xSpeed != 0.0f){ + direction = (zSpeed * forward); + } + auto length = glm::length(direction); if (length > EPSILON) { direction /= length; @@ -3586,6 +3839,8 @@ void MyAvatar::updateActionMotor(float deltaTime) { float speedGrowthTimescale = 2.0f; float speedIncreaseFactor = 1.8f * _walkSpeedScalar; motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale, 0.0f, 1.0f) * speedIncreaseFactor; + // use feedback from CharacterController to prevent tunneling under high motorspeed + motorSpeed *= _characterController.getCollisionBrakeAttenuationFactor(); const float maxBoostSpeed = sensorToWorldScale * MAX_BOOST_SPEED; if (_isPushing) { @@ -3909,6 +4164,7 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition, _goToOrientation = quatOrientation; } + resetLookAtRotation(_goToPosition, _goToOrientation); emit transformChanged(); } @@ -4372,8 +4628,15 @@ float MyAvatar::getRawDriveKey(DriveKeys key) const { } void MyAvatar::relayDriveKeysToCharacterController() { - if (getDriveKey(TRANSLATE_Y) > 0.0f && (!qApp->isHMDMode() || (useAdvancedMovementControls() && getFlyingHMDPref()))) { - _characterController.jump(); + if (_endSitKeyPressComplete) { + if (getDriveKey(TRANSLATE_Y) > 0.0f && (!qApp->isHMDMode() || (useAdvancedMovementControls() && getFlyingHMDPref()))) { + _characterController.jump(); + } + } else { + // used to prevent character from jumping after endSit is called. + if (getDriveKey(TRANSLATE_Y) == 0.0f) { + _endSitKeyPressComplete = true; + } } } @@ -5133,9 +5396,13 @@ glm::quat MyAvatar::getOrientationForAudio() { glm::quat result; switch (_audioListenerMode) { - case AudioListenerMode::FROM_HEAD: - result = getHead()->getFinalOrientationInWorldFrame(); + case AudioListenerMode::FROM_HEAD: { + // Using the camera's orientation instead, when the current mode is controlling the avatar's head. + CameraMode mode = qApp->getCamera().getMode(); + bool headFollowsCamera = mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE; + result = headFollowsCamera ? qApp->getCamera().getOrientation() : getHead()->getFinalOrientationInWorldFrame(); break; + } case AudioListenerMode::FROM_CAMERA: result = qApp->getCamera().getOrientation(); break; @@ -5750,6 +6017,7 @@ bool MyAvatar::pinJoint(int index, const glm::vec3& position, const glm::quat& o } slamPosition(position); + resetLookAtRotation(position, orientation); setWorldOrientation(orientation); auto it = std::find(_pinnedJoints.begin(), _pinnedJoints.end(), index); @@ -5854,6 +6122,10 @@ bool MyAvatar::beginReaction(QString reactionName) { if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_BEGIN_END_REACTIONS) { std::lock_guard guard(_reactionLock); _reactionEnabledRefCounts[reactionIndex]++; + if (reactionName == POINT_REACTION_NAME) { + _pointAtActive = true; + _isPointTargetValid = true; + } return true; } return false; @@ -5863,13 +6135,18 @@ bool MyAvatar::endReaction(QString reactionName) { int reactionIndex = beginEndReactionNameToIndex(reactionName); if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_BEGIN_END_REACTIONS) { std::lock_guard guard(_reactionLock); + bool wasReactionActive = true; if (_reactionEnabledRefCounts[reactionIndex] > 0) { _reactionEnabledRefCounts[reactionIndex]--; - return true; + wasReactionActive = true; } else { _reactionEnabledRefCounts[reactionIndex] = 0; - return false; + wasReactionActive = false; } + if (reactionName == POINT_REACTION_NAME) { + _pointAtActive = _reactionEnabledRefCounts[reactionIndex] > 0; + } + return wasReactionActive; } return false; } @@ -5880,10 +6157,13 @@ void MyAvatar::updateRigControllerParameters(Rig::ControllerParameters& params) for (int i = 0; i < TRIGGER_REACTION_NAMES.size(); i++) { params.reactionTriggers[i] = _reactionTriggers[i]; } - + int pointReactionIndex = beginEndReactionNameToIndex("point"); for (int i = 0; i < BEGIN_END_REACTION_NAMES.size(); i++) { // copy current state into params. params.reactionEnabledFlags[i] = _reactionEnabledRefCounts[i] > 0; + if (params.reactionEnabledFlags[i] && i == pointReactionIndex) { + params.reactionEnabledFlags[i] = _isPointTargetValid; + } } for (int i = 0; i < TRIGGER_REACTION_NAMES.size(); i++) { @@ -6231,7 +6511,6 @@ void MyAvatar::sendPacket(const QUuid& entityID) const { void MyAvatar::setSitDriveKeysStatus(bool enabled) { const std::vector DISABLED_DRIVE_KEYS_DURING_SIT = { - DriveKeys::TRANSLATE_X, DriveKeys::TRANSLATE_Y, DriveKeys::TRANSLATE_Z, DriveKeys::STEP_TRANSLATE_X, @@ -6253,15 +6532,17 @@ void MyAvatar::beginSit(const glm::vec3& position, const glm::quat& rotation) { return; } - _characterController.setSeated(true); - setCollisionsEnabled(false); - setHMDLeanRecenterEnabled(false); - // Disable movement - setSitDriveKeysStatus(false); - centerBody(); - int hipIndex = getJointIndex("Hips"); - clearPinOnJoint(hipIndex); - pinJoint(hipIndex, position, rotation); + if (!_characterController.getSeated()) { + _characterController.setSeated(true); + setCollisionsEnabled(false); + setHMDLeanRecenterEnabled(false); + // Disable movement + setSitDriveKeysStatus(false); + centerBody(); + int hipIndex = getJointIndex("Hips"); + clearPinOnJoint(hipIndex); + pinJoint(hipIndex, position, rotation); + } } void MyAvatar::endSit(const glm::vec3& position, const glm::quat& rotation) { @@ -6279,12 +6560,237 @@ void MyAvatar::endSit(const glm::vec3& position, const glm::quat& rotation) { slamPosition(position); setWorldOrientation(rotation); - // the jump key is used to exit the chair. We add a delay here to prevent - // the avatar from jumping right as they exit the chair. - float TIME_BEFORE_DRIVE_ENABLED_MS = 150.0f; - QTimer::singleShot(TIME_BEFORE_DRIVE_ENABLED_MS, [this]() { - // Enable movement again - setSitDriveKeysStatus(true); - }); + // used to prevent character from jumping after endSit is called. + _endSitKeyPressComplete = false; + + setSitDriveKeysStatus(true); + } +} + +bool MyAvatar::getIsJointOverridden(int jointIndex) const { + // has this joint been set by a script? + return _skeletonModel->getIsJointOverridden(jointIndex); +} + +void MyAvatar::updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera) { + + updateLookAtTargetAvatar(); + + bool isLookingAtSomeone = false; + glm::vec3 lookAtSpot; + + const MyHead* myHead = getMyHead(); + + int leftEyeJointIndex = getJointIndex("LeftEye"); + int rightEyeJointIndex = getJointIndex("RightEye"); + bool eyesAreOverridden = getIsJointOverridden(leftEyeJointIndex) || + getIsJointOverridden(rightEyeJointIndex); + if (eyesAreOverridden) { + // A script has set the eye rotations, so use these to set lookAtSpot + glm::quat leftEyeRotation = getAbsoluteJointRotationInObjectFrame(leftEyeJointIndex); + glm::quat rightEyeRotation = getAbsoluteJointRotationInObjectFrame(rightEyeJointIndex); + glm::vec3 leftVec = getWorldOrientation() * leftEyeRotation * IDENTITY_FORWARD; + glm::vec3 rightVec = getWorldOrientation() * rightEyeRotation * IDENTITY_FORWARD; + glm::vec3 leftEyePosition = myHead->getLeftEyePosition(); + glm::vec3 rightEyePosition = myHead->getRightEyePosition(); + float t1, t2; + bool success = findClosestApproachOfLines(leftEyePosition, leftVec, rightEyePosition, rightVec, t1, t2); + if (success) { + glm::vec3 leftFocus = leftEyePosition + leftVec * t1; + glm::vec3 rightFocus = rightEyePosition + rightVec * t2; + lookAtSpot = (leftFocus + rightFocus) / 2.0f; // average + } else { + lookAtSpot = myHead->getEyePosition() + glm::normalize(leftVec) * 1000.0f; + } + } else { + controller::Pose leftEyePose = getControllerPoseInAvatarFrame(controller::Action::LEFT_EYE); + controller::Pose rightEyePose = getControllerPoseInAvatarFrame(controller::Action::RIGHT_EYE); + if (leftEyePose.isValid() && rightEyePose.isValid()) { + // an eye tracker is in use, set lookAtSpot from this + glm::vec3 leftVec = getWorldOrientation() * leftEyePose.rotation * glm::vec3(0.0f, 0.0f, -1.0f); + glm::vec3 rightVec = getWorldOrientation() * rightEyePose.rotation * glm::vec3(0.0f, 0.0f, -1.0f); + + glm::vec3 leftEyePosition = myHead->getLeftEyePosition(); + glm::vec3 rightEyePosition = myHead->getRightEyePosition(); + float t1, t2; + bool success = findClosestApproachOfLines(leftEyePosition, leftVec, rightEyePosition, rightVec, t1, t2); + if (success) { + glm::vec3 leftFocus = leftEyePosition + leftVec * t1; + glm::vec3 rightFocus = rightEyePosition + rightVec * t2; + lookAtSpot = (leftFocus + rightFocus) / 2.0f; // average + } else { + lookAtSpot = myHead->getEyePosition() + glm::normalize(leftVec) * 1000.0f; + } + } else { + // no script override, no eye tracker, so do procedural eye motion + AvatarSharedPointer lookingAt = getLookAtTargetAvatar().lock(); + bool haveLookAtCandidate = lookingAt && this != lookingAt.get(); + auto avatar = static_pointer_cast(lookingAt); + bool mutualLookAtSnappingEnabled = + avatar && avatar->getLookAtSnappingEnabled() && getLookAtSnappingEnabled(); + if (haveLookAtCandidate && mutualLookAtSnappingEnabled) { + // If I am looking at someone else, look directly at one of their eyes + isLookingAtSomeone = true; + auto lookingAtHead = avatar->getHead(); + + const float MAXIMUM_FACE_ANGLE = 65.0f * RADIANS_PER_DEGREE; + glm::vec3 lookingAtFaceOrientation = lookingAtHead->getFinalOrientationInWorldFrame() * IDENTITY_FORWARD; + glm::vec3 fromLookingAtToMe = glm::normalize(getHead()->getEyePosition() + - lookingAtHead->getEyePosition()); + float faceAngle = glm::angle(lookingAtFaceOrientation, fromLookingAtToMe); + + if (faceAngle < MAXIMUM_FACE_ANGLE) { + // Randomly look back and forth between look targets + eyeContactTarget target = Menu::getInstance()->isOptionChecked(MenuOption::FixGaze) ? + LEFT_EYE : getEyeContactTarget(); + switch (target) { + case LEFT_EYE: + lookAtSpot = lookingAtHead->getLeftEyePosition(); + break; + case RIGHT_EYE: + lookAtSpot = lookingAtHead->getRightEyePosition(); + break; + case MOUTH: + lookAtSpot = lookingAtHead->getMouthPosition(); + break; + } + } else { + // Just look at their head (mid point between eyes) + lookAtSpot = lookingAtHead->getEyePosition(); + } + } else { + // I am not looking at anyone else, so just look forward + auto headPose = getControllerPoseInWorldFrame(controller::Action::HEAD); + if (headPose.isValid()) { + lookAtSpot = transformPoint(headPose.getMatrix(), glm::vec3(0.0f, 0.0f, TREE_SCALE)); + } else { + lookAtSpot = myHead->getEyePosition() + + (getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE)); + } + } + + // Deflect the eyes a bit to match the detected gaze from the face tracker if active. + if (faceTracker && !faceTracker->isMuted()) { + float eyePitch = faceTracker->getEstimatedEyePitch(); + float eyeYaw = faceTracker->getEstimatedEyeYaw(); + const float GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT = 0.1f; + glm::vec3 origin = myHead->getEyePosition(); + float deflection = faceTracker->getEyeDeflection(); + if (isLookingAtSomeone) { + deflection *= GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT; + } + lookAtSpot = origin + myCamera.getOrientation() * glm::quat(glm::radians(glm::vec3( + eyePitch * deflection, eyeYaw * deflection, 0.0f))) * + glm::inverse(myCamera.getOrientation()) * (lookAtSpot - origin); + } + } + } + + getHead()->setLookAtPosition(lookAtSpot); +} + +glm::vec3 MyAvatar::aimToBlendValues(const glm::vec3& aimVector, const glm::quat& frameOrientation) { + // This method computes the values for the directional blending animation node + + glm::vec3 uVector = glm::normalize(frameOrientation * Vectors::UNIT_X); + glm::vec3 vVector = glm::normalize(frameOrientation * Vectors::UNIT_Y); + + glm::vec3 aimDirection; + if (glm::length(aimVector) > EPSILON) { + aimDirection = glm::normalize(aimVector); + } else { + // aim vector is zero + return glm::vec3(); + } + + float xDot = glm::dot(uVector, aimDirection); + float yDot = glm::dot(vVector, aimDirection); + + // Make sure dot products are in range to avoid acosf returning NaN + xDot = glm::min(glm::max(xDot, -1.0f), 1.0f); + yDot = glm::min(glm::max(yDot, -1.0f), 1.0f); + + float xAngle = acosf(xDot); + float yAngle = acosf(yDot); + + // xBlend and yBlend are the values from -1.0 to 1.0 that set the directional blending. + // We compute them using the angles (0 to PI/2) => (1.0 to 0.0) and (PI/2 to PI) => (0.0 to -1.0) + float xBlend = -(xAngle - 0.5f * PI) / (0.5f * PI); + float yBlend = -(yAngle - 0.5f * PI) / (0.5f * PI); + glm::vec3 blendValues = glm::vec3(xBlend, yBlend, 0.0f); + return blendValues; +} + +void MyAvatar::resetHeadLookAt() { + if (_skeletonModelLoaded) { + _skeletonModel->getRig().setDirectionalBlending(HEAD_BLEND_DIRECTIONAL_ALPHA_NAME, glm::vec3(), + HEAD_BLEND_LINEAR_ALPHA_NAME, HEAD_ALPHA_BLENDING); + } +} + +void MyAvatar::resetLookAtRotation(const glm::vec3& avatarPosition, const glm::quat& avatarOrientation) { + // Align the look at values to the given avatar orientation + float yaw = safeEulerAngles(avatarOrientation).y; + _lookAtYaw = glm::angleAxis(yaw, avatarOrientation * Vectors::UP); + _lookAtPitch = Quaternions::IDENTITY; + _lookAtCameraTarget = avatarPosition + avatarOrientation * Vectors::FRONT; + resetHeadLookAt(); +} + +void MyAvatar::updateHeadLookAt(float deltaTime) { + if (_skeletonModelLoaded) { + glm::vec3 lookAtTarget = _scriptControlsHeadLookAt ? _lookAtScriptTarget : _lookAtCameraTarget; + glm::vec3 aimVector = lookAtTarget - getDefaultEyePosition(); + glm::vec3 lookAtBlend = MyAvatar::aimToBlendValues(aimVector, getWorldOrientation()); + _skeletonModel->getRig().setDirectionalBlending(HEAD_BLEND_DIRECTIONAL_ALPHA_NAME, lookAtBlend, + HEAD_BLEND_LINEAR_ALPHA_NAME, HEAD_ALPHA_BLENDING); + + if (_scriptControlsHeadLookAt) { + _scriptHeadControlTimer += deltaTime; + if (_scriptHeadControlTimer > MAX_LOOK_AT_TIME_SCRIPT_CONTROL) { + _scriptHeadControlTimer = 0.0f; + _scriptControlsHeadLookAt = false; + _lookAtCameraTarget = _lookAtScriptTarget; + } + } + } +} + +void MyAvatar::setHeadLookAt(const glm::vec3& lookAtTarget) { + if (QThread::currentThread() != thread()) { + BLOCKING_INVOKE_METHOD(this, "setHeadLookAt", + Q_ARG(const glm::vec3&, lookAtTarget)); + return; + } + _headLookAtActive = true; + _scriptControlsHeadLookAt = true; + _scriptHeadControlTimer = 0.0f; + _lookAtScriptTarget = lookAtTarget; +} + +bool MyAvatar::setPointAt(const glm::vec3& pointAtTarget) { + if (QThread::currentThread() != thread()) { + bool result = false; + BLOCKING_INVOKE_METHOD(this, "setPointAt", Q_RETURN_ARG(bool, result), + Q_ARG(const glm::vec3&, pointAtTarget)); + return result; + } + if (_skeletonModelLoaded && _pointAtActive) { + glm::vec3 aimVector = pointAtTarget - getJointPosition(POINT_REF_JOINT_NAME); + _isPointTargetValid = glm::dot(aimVector, getWorldOrientation() * Vectors::FRONT) > 0.0f; + if (_isPointTargetValid) { + glm::vec3 pointAtBlend = MyAvatar::aimToBlendValues(aimVector, getWorldOrientation()); + _skeletonModel->getRig().setDirectionalBlending(POINT_BLEND_DIRECTIONAL_ALPHA_NAME, pointAtBlend, + POINT_BLEND_LINEAR_ALPHA_NAME, POINT_ALPHA_BLENDING); + } + return _isPointTargetValid; + } + return false; +} + +void MyAvatar::resetPointAt() { + if (_skeletonModelLoaded) { + _skeletonModel->getRig().setDirectionalBlending(POINT_BLEND_DIRECTIONAL_ALPHA_NAME, glm::vec3(), + POINT_BLEND_LINEAR_ALPHA_NAME, POINT_ALPHA_BLENDING); } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index bb6f036533..6b1344aad2 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -29,10 +29,12 @@ #include #include #include +#include #include "AtRestDetector.h" #include "MyCharacterController.h" #include "RingBufferHistory.h" +#include "devices/DdeFaceTracker.h" class AvatarActionHold; class ModelItemID; @@ -154,6 +156,7 @@ class MyAvatar : public Avatar { * * @property {Vec3} qmlPosition - A synonym for position for use by QML. * + * @property {Vec3} feetPosition - The position of the avatar's feet. * @property {boolean} shouldRenderLocally=true - If true then your avatar is rendered for you in Interface, * otherwise it is not rendered for you (but it is still rendered for other users). * @property {Vec3} motorVelocity=Vec3.ZERO - The target velocity of your avatar to be achieved by a scripted motor. @@ -340,6 +343,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(QVector3D qmlPosition READ getQmlPosition) QVector3D getQmlPosition() { auto p = getWorldPosition(); return QVector3D(p.x, p.y, p.z); } + Q_PROPERTY(glm::vec3 feetPosition READ getWorldFeetPosition WRITE goToFeetLocation) Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally) Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity) Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale) @@ -1745,6 +1749,34 @@ public: glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); } void prepareAvatarEntityDataForReload(); + /**jsdoc + * Turn the avatar's head until it faces the target point within the 90/-90 degree range. + * Once this method is called, API calls will have full control of the head for a limited time. + * If this method is not called for two seconds, the engine will regain control of the head. + * @function MyAvatar.setHeadLookAt + * @param {Vec3} lookAtTarget - The target point in world coordinates. + */ + Q_INVOKABLE void setHeadLookAt(const glm::vec3& lookAtTarget); + + /**jsdoc + * Returns the current head look at target point in world coordinates. + * @function MyAvatar.getHeadLookAt + * @returns {Vec3} Default position between your avatar's eyes in world coordinates. + */ + Q_INVOKABLE glm::vec3 getHeadLookAt() { return _lookAtCameraTarget; } + + /**jsdoc + * Aims the pointing directional blending towards the provided target point. + * The "point" reaction should be triggered before using this method. + * MyAvatar.beginReaction("point") + * Returns true if the target point lays in front of the avatar. + * @function MyAvatar.setPointAt + * @param {Vec3} pointAtTarget - The target point in world coordinates. + */ + Q_INVOKABLE bool setPointAt(const glm::vec3& pointAtTarget); + + glm::quat getLookAtRotation() { return _lookAtYaw * _lookAtPitch; } + /**jsdoc * Creates a new grab that grabs an entity. * @function MyAvatar.grab @@ -1862,6 +1894,8 @@ public: bool getFlowActive() const; bool getNetworkGraphActive() const; + void updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera); + // sets the reaction enabled and triggered parameters of the passed in params // also clears internal reaction triggers void updateRigControllerParameters(Rig::ControllerParameters& params); @@ -1869,6 +1903,10 @@ public: // Don't substitute verify-fail: virtual const QUrl& getSkeletonModelURL() const override { return _skeletonModelURL; } + void debugDrawPose(controller::Action action, const char* channelName, float size); + + bool getIsJointOverridden(int jointIndex) const; + public slots: /**jsdoc @@ -1938,9 +1976,8 @@ public slots: * @param {boolean} [shouldFaceLocation=false] - Set to true to position the avatar a short distance away from * the new position and orientate the avatar to face the position. */ - void goToFeetLocation(const glm::vec3& newPosition, - bool hasOrientation, const glm::quat& newOrientation, - bool shouldFaceLocation); + void goToFeetLocation(const glm::vec3& newPosition, bool hasOrientation = false, + const glm::quat& newOrientation = glm::quat(), bool shouldFaceLocation = false); /**jsdoc * Moves the avatar to a new position and/or orientation in the domain. @@ -2617,6 +2654,18 @@ private: glm::vec3 _trackedHeadPosition; + const float MAX_LOOK_AT_TIME_SCRIPT_CONTROL = 2.0f; + glm::quat _lookAtPitch; + glm::quat _lookAtYaw; + glm::vec3 _lookAtCameraTarget; + glm::vec3 _lookAtScriptTarget; + bool _headLookAtActive { false }; + bool _shouldTurnToFaceCamera { false }; + bool _scriptControlsHeadLookAt { false }; + float _scriptHeadControlTimer { 0.0f }; + bool _pointAtActive { false }; + bool _isPointTargetValid { true }; + Setting::Handle _realWorldFieldOfView; Setting::Handle _useAdvancedMovementControls; Setting::Handle _showPlayArea; @@ -2641,6 +2690,11 @@ private: void initHeadBones(); void initAnimGraph(); void initFlowFromFST(); + void updateHeadLookAt(float deltaTime); + void resetHeadLookAt(); + void resetLookAtRotation(const glm::vec3& avatarPosition, const glm::quat& avatarOrientation); + void resetPointAt(); + static glm::vec3 aimToBlendValues(const glm::vec3& aimVector, const glm::quat& frameOrientation); // Avatar Preferences QUrl _fullAvatarURLFromPreferences; @@ -2902,6 +2956,9 @@ private: int _reactionEnabledRefCounts[NUM_AVATAR_BEGIN_END_REACTIONS] { 0, 0, 0 }; mutable std::mutex _reactionLock; + + // used to prevent character from jumping after endSit is called. + bool _endSitKeyPressComplete { false }; }; QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode); diff --git a/interface/src/avatar/MyHead.cpp b/interface/src/avatar/MyHead.cpp index 9b05a26c76..e5c8b71ea2 100644 --- a/interface/src/avatar/MyHead.cpp +++ b/interface/src/avatar/MyHead.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "devices/DdeFaceTracker.h" #include "Application.h" @@ -46,18 +46,37 @@ void MyHead::simulate(float deltaTime) { auto player = DependencyManager::get(); // Only use face trackers when not playing back a recording. if (!player->isPlaying()) { - auto faceTracker = qApp->getActiveFaceTracker(); - const bool hasActualFaceTrackerConnected = faceTracker && !faceTracker->isMuted(); - _isFaceTrackerConnected = hasActualFaceTrackerConnected || _owningAvatar->getHasScriptedBlendshapes(); - if (_isFaceTrackerConnected) { - if (hasActualFaceTrackerConnected) { - _blendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); - } - } + // TODO -- finish removing face-tracker specific code. To do this, add input channels for + // each blendshape-coefficient and update the various json files to relay them in a useful way. + // After that, input plugins can be used to drive the avatar's face, and the various "DDE" files + // can be ported into the plugin and removed. + // + // auto faceTracker = qApp->getActiveFaceTracker(); + // const bool hasActualFaceTrackerConnected = faceTracker && !faceTracker->isMuted(); + // _isFaceTrackerConnected = hasActualFaceTrackerConnected || _owningAvatar->getHasScriptedBlendshapes(); + // if (_isFaceTrackerConnected) { + // if (hasActualFaceTrackerConnected) { + // _blendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); + // } + // } - auto eyeTracker = DependencyManager::get(); - _isEyeTrackerConnected = eyeTracker->isTracking(); - // if eye tracker is connected we should get the data here. + auto userInputMapper = DependencyManager::get(); + bool eyeLidsTracked = + userInputMapper->getActionStateValid(controller::Action::LEFT_EYE_BLINK) && + userInputMapper->getActionStateValid(controller::Action::RIGHT_EYE_BLINK); + setFaceTrackerConnected(eyeLidsTracked); + if (eyeLidsTracked) { + float leftEyeBlink = userInputMapper->getActionState(controller::Action::LEFT_EYE_BLINK); + float rightEyeBlink = userInputMapper->getActionState(controller::Action::RIGHT_EYE_BLINK); + _blendshapeCoefficients.resize(std::max(_blendshapeCoefficients.size(), 2)); + _blendshapeCoefficients[EYE_BLINK_INDICES[0]] = leftEyeBlink; + _blendshapeCoefficients[EYE_BLINK_INDICES[1]] = rightEyeBlink; + } else { + const float FULLY_OPEN = 0.0f; + _blendshapeCoefficients.resize(std::max(_blendshapeCoefficients.size(), 2)); + _blendshapeCoefficients[EYE_BLINK_INDICES[0]] = FULLY_OPEN; + _blendshapeCoefficients[EYE_BLINK_INDICES[1]] = FULLY_OPEN; + } } Parent::simulate(deltaTime); } diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 6080911dd9..38065c8095 100755 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -114,13 +114,12 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { Head* head = _owningAvatar->getHead(); - // make sure lookAt is not too close to face (avoid crosseyes) - glm::vec3 lookAt = head->getLookAtPosition(); - glm::vec3 focusOffset = lookAt - _owningAvatar->getHead()->getEyePosition(); - float focusDistance = glm::length(focusOffset); - const float MIN_LOOK_AT_FOCUS_DISTANCE = 1.0f; - if (focusDistance < MIN_LOOK_AT_FOCUS_DISTANCE && focusDistance > EPSILON) { - lookAt = _owningAvatar->getHead()->getEyePosition() + (MIN_LOOK_AT_FOCUS_DISTANCE / focusDistance) * focusOffset; + bool eyePosesValid = !head->getHasProceduralEyeMovement(); + glm::vec3 lookAt; + if (eyePosesValid) { + lookAt = head->getLookAtPosition(); // don't apply no-crosseyes code when eyes are being tracked + } else { + lookAt = avoidCrossedEyes(head->getLookAtPosition()); } MyAvatar* myAvatar = static_cast(_owningAvatar); @@ -313,8 +312,8 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { if (spine2Joint >= 0) { params.spine2ShapeInfo = hfmModel.joints[spine2Joint].shapeInfo; } - - params.isTalking = head->getTimeWithoutTalking() <= 1.5f; + const float TALKING_TIME_THRESHOLD = 0.75f; + params.isTalking = head->getTimeWithoutTalking() <= TALKING_TIME_THRESHOLD; myAvatar->updateRigControllerParameters(params); @@ -337,10 +336,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { eyeParams.modelTranslation = getTranslation(); eyeParams.leftEyeJointIndex = _rig.indexOfJoint("LeftEye"); eyeParams.rightEyeJointIndex = _rig.indexOfJoint("RightEye"); - - if (_owningAvatar->getHasProceduralEyeFaceMovement()) { - _rig.updateFromEyeParameters(eyeParams); - } + _rig.updateFromEyeParameters(eyeParams); updateFingers(); } diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index 8c8c42679b..5673c2443f 100755 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -512,13 +512,13 @@ void OtherAvatar::handleChangedAvatarEntityData() { entity->setParentID(NULL_ID); entity->setParentID(oldParentID); - if (entity->stillHasMyGrabAction()) { + if (entity->stillHasMyGrab()) { // For this case: we want to ignore transform+velocities coming from authoritative OtherAvatar // because the MyAvatar is grabbing and we expect the local grab state // to have enough information to prevent simulation drift. // // Clever readers might realize this could cause problems. For example, - // if an ignored OtherAvagtar were to simultanously grab the object then there would be + // if an ignored OtherAvatar were to simultanously grab the object then there would be // a noticeable discrepancy between participants in the distributed physics simulation, // however the difference would be stable and would not drift. properties.clearTransformOrVelocityChanges(); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index f6ce1ec8ad..9af1d07309 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -70,7 +71,7 @@ int main(int argc, const char* argv[]) { } QCommandLineParser parser; - parser.setApplicationDescription("High Fidelity Interface"); + parser.setApplicationDescription("High Fidelity"); QCommandLineOption versionOption = parser.addVersionOption(); QCommandLineOption helpOption = parser.addHelpOption(); @@ -117,21 +118,27 @@ int main(int argc, const char* argv[]) { } QString applicationPath; + // A temporary application instance is needed to get the location of the running executable + // Tests using high_resolution_clock show that this takes about 30-50 microseconds (on my machine, YMMV) + // If we wanted to avoid the QCoreApplication, we would need to write our own + // cross-platform implementation. { - // A temporary application instance is needed to get the location of the running executable - // Tests using high_resolution_clock show that this takes about 30-50 microseconds (on my machine, YMMV) - // If we wanted to avoid the QCoreApplication, we would need to write our own - // cross-platform implementation. QCoreApplication tempApp(argc, const_cast(argv)); +#ifdef Q_OS_OSX + if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/../../../config.json")) { + applicationPath = QCoreApplication::applicationDirPath() + "/../../../"; + } else { + applicationPath = QCoreApplication::applicationDirPath(); + } +#else applicationPath = QCoreApplication::applicationDirPath(); +#endif } - static const QString APPLICATION_CONFIG_FILENAME = "config.json"; QDir applicationDir(applicationPath); QString configFileName = applicationDir.filePath(APPLICATION_CONFIG_FILENAME); QFile configFile(configFileName); QString launcherPath; - if (configFile.exists()) { if (!configFile.open(QIODevice::ReadOnly)) { qWarning() << "Found application config, but could not open it"; diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index ba392f0cd1..43958188e3 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -440,13 +440,13 @@ void Audio::handlePushedToTalk(bool enabled) { } } -void Audio::setInputDevice(const QAudioDeviceInfo& device, bool isHMD) { +void Audio::setInputDevice(const HifiAudioDeviceInfo& device, bool isHMD) { withWriteLock([&] { _devices.chooseInputDevice(device, isHMD); }); } -void Audio::setOutputDevice(const QAudioDeviceInfo& device, bool isHMD) { +void Audio::setOutputDevice(const HifiAudioDeviceInfo& device, bool isHMD) { withWriteLock([&] { _devices.chooseOutputDevice(device, isHMD); }); diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index d3bc6b9449..74d85f0107 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -19,6 +19,7 @@ #include "SettingHandle.h" #include "AudioFileWav.h" #include +#include using MutedGetter = std::function; using MutedSetter = std::function; @@ -158,7 +159,7 @@ public: * @param {boolean} isHMD - Is HMD. * @deprecated This function is deprecated and will be removed. */ - Q_INVOKABLE void setInputDevice(const QAudioDeviceInfo& device, bool isHMD); + Q_INVOKABLE void setInputDevice(const HifiAudioDeviceInfo& device, bool isHMD); /**jsdoc * @function Audio.setOutputDevice @@ -166,7 +167,7 @@ public: * @param {boolean} isHMD - Is HMD. * @deprecated This function is deprecated and will be removed. */ - Q_INVOKABLE void setOutputDevice(const QAudioDeviceInfo& device, bool isHMD); + Q_INVOKABLE void setOutputDevice(const HifiAudioDeviceInfo& device, bool isHMD); /**jsdoc * Enables or disables reverberation. Reverberation is done by the client on the post-mix audio. The reverberation options diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index ce82786c8d..8cc45a3bf5 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -29,6 +29,8 @@ static Setting::Handle desktopOutputDeviceSetting { QStringList { Audio static Setting::Handle hmdInputDeviceSetting { QStringList { Audio::AUDIO, Audio::HMD, "INPUT" }}; static Setting::Handle hmdOutputDeviceSetting { QStringList { Audio::AUDIO, Audio::HMD, "OUTPUT" }}; +Q_DECLARE_METATYPE(HifiAudioDeviceInfo); + Setting::Handle& getSetting(bool contextIsHMD, QAudio::Mode mode) { if (mode == QAudio::AudioInput) { return contextIsHMD ? hmdInputDeviceSetting : desktopInputDeviceSetting; @@ -64,6 +66,8 @@ static QString getTargetDevice(bool hmd, QAudio::Mode mode) { } else { // if (_mode == QAudio::AudioOutput) deviceName = qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice(); } + } else { + deviceName = HifiAudioDeviceInfo::DEFAULT_DEVICE_NAME; } return deviceName; } @@ -71,32 +75,44 @@ static QString getTargetDevice(bool hmd, QAudio::Mode mode) { Qt::ItemFlags AudioDeviceList::_flags { Qt::ItemIsSelectable | Qt::ItemIsEnabled }; AudioDeviceList::AudioDeviceList(QAudio::Mode mode) : _mode(mode) { - auto& setting1 = getSetting(true, QAudio::AudioInput); - if (setting1.isSet()) { - qDebug() << "Device name in settings for HMD, Input" << setting1.get(); - } else { - qDebug() << "Device name in settings for HMD, Input not set"; + if (mode == QAudio::AudioInput) { + auto& setting1 = getSetting(true, QAudio::AudioInput); + if (setting1.isSet()) { + qDebug() << "Device name in settings for HMD, Input" << setting1.get(); + _backupSelectedHMDDeviceName = setting1.get(); + } else { + qDebug() << "Device name in settings for HMD, Input not set"; + } } - auto& setting2 = getSetting(true, QAudio::AudioOutput); - if (setting2.isSet()) { - qDebug() << "Device name in settings for HMD, Output" << setting2.get(); - } else { - qDebug() << "Device name in settings for HMD, Output not set"; + if (mode == QAudio::AudioOutput) { + auto& setting2 = getSetting(true, QAudio::AudioOutput); + if (setting2.isSet()) { + qDebug() << "Device name in settings for HMD, Output" << setting2.get(); + _backupSelectedHMDDeviceName = setting2.get(); + } else { + qDebug() << "Device name in settings for HMD, Output not set"; + } } - auto& setting3 = getSetting(false, QAudio::AudioInput); - if (setting3.isSet()) { - qDebug() << "Device name in settings for Desktop, Input" << setting3.get(); - } else { - qDebug() << "Device name in settings for Desktop, Input not set"; + if (mode == QAudio::AudioInput) { + auto& setting3 = getSetting(false, QAudio::AudioInput); + if (setting3.isSet()) { + qDebug() << "Device name in settings for Desktop, Input" << setting3.get(); + _backupSelectedDesktopDeviceName = setting3.get(); + } else { + qDebug() << "Device name in settings for Desktop, Input not set"; + } } - auto& setting4 = getSetting(false, QAudio::AudioOutput); - if (setting4.isSet()) { - qDebug() << "Device name in settings for Desktop, Output" << setting4.get(); - } else { - qDebug() << "Device name in settings for Desktop, Output not set"; + if (mode == QAudio::AudioOutput) { + auto& setting4 = getSetting(false, QAudio::AudioOutput); + if (setting4.isSet()) { + qDebug() << "Device name in settings for Desktop, Output" << setting4.get(); + _backupSelectedDesktopDeviceName = setting4.get(); + } else { + qDebug() << "Device name in settings for Desktop, Output not set"; + } } } @@ -127,7 +143,7 @@ QVariant AudioDeviceList::data(const QModelIndex& index, int role) const { } else if (role == SelectedHMDRole) { return _devices.at(index.row())->selectedHMD; } else if (role == InfoRole) { - return QVariant::fromValue(_devices.at(index.row())->info); + return QVariant::fromValue(_devices.at(index.row())->info); } else { return QVariant(); } @@ -179,18 +195,13 @@ void AudioDeviceList::resetDevice(bool contextIsHMD) { #endif } -void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD) { - QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; +void AudioDeviceList::onDeviceChanged(const HifiAudioDeviceInfo& device, bool isHMD) { + HifiAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; selectedDevice = device; - for (auto i = 0; i < _devices.size(); ++i) { std::shared_ptr device = _devices[i]; bool& isSelected = isHMD ? device->selectedHMD : device->selectedDesktop; - if (isSelected && device->info != selectedDevice) { - isSelected = false; - } else if (device->info == selectedDevice) { - isSelected = true; - } + isSelected = device->info == selectedDevice; } emit deviceChanged(selectedDevice); @@ -247,37 +258,46 @@ std::shared_ptr getSimilarDevice(const QString& deviceNa return devices[minDistanceIndex]; } -void AudioDeviceList::onDevicesChanged(const QList& devices) { +void AudioDeviceList::onDevicesChanged(const QList& devices) { beginResetModel(); QList> newDevices; bool hmdIsSelected = false; bool desktopIsSelected = false; - foreach(const QAudioDeviceInfo& deviceInfo, devices) { + foreach(const HifiAudioDeviceInfo& deviceInfo, devices) { for (bool isHMD : {false, true}) { auto& backupSelectedDeviceName = isHMD ? _backupSelectedHMDDeviceName : _backupSelectedDesktopDeviceName; if (deviceInfo.deviceName() == backupSelectedDeviceName) { - QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; + HifiAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; selectedDevice = deviceInfo; backupSelectedDeviceName.clear(); } } } - foreach(const QAudioDeviceInfo& deviceInfo, devices) { + foreach(const HifiAudioDeviceInfo& deviceInfo, devices) { AudioDevice device; device.info = deviceInfo; - device.display = device.info.deviceName() - .replace("High Definition", "HD") - .remove("Device") - .replace(" )", ")"); + + if (deviceInfo.isDefault()) { + if (deviceInfo.getMode() == QAudio::AudioInput) { + device.display = "Computer's default microphone (recommended)"; + } else { + device.display = "Computer's default audio (recommended)"; + } + } else { + device.display = device.info.deviceName() + .replace("High Definition", "HD") + .remove("Device") + .replace(" )", ")"); + } for (bool isHMD : {false, true}) { - QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; + HifiAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; bool& isSelected = isHMD ? device.selectedHMD : device.selectedDesktop; - if (!selectedDevice.isNull()) { + if (!selectedDevice.getDevice().isNull()) { isSelected = (device.info == selectedDevice); } else { @@ -313,13 +333,13 @@ void AudioDeviceList::onDevicesChanged(const QList& devices) { if (!newDevices.isEmpty()) { if (!hmdIsSelected) { - _backupSelectedHMDDeviceName = !_selectedHMDDevice.isNull() ? _selectedHMDDevice.deviceName() : _hmdSavedDeviceName; + _backupSelectedHMDDeviceName = !_selectedHMDDevice.getDevice().isNull() ? _selectedHMDDevice.deviceName() : _hmdSavedDeviceName; auto device = getSimilarDevice(_backupSelectedHMDDeviceName, newDevices); device->selectedHMD = true; emit selectedDevicePlugged(device->info, true); } if (!desktopIsSelected) { - _backupSelectedDesktopDeviceName = !_selectedDesktopDevice.isNull() ? _selectedDesktopDevice.deviceName() : _desktopSavedDeviceName; + _backupSelectedDesktopDeviceName = !_selectedDesktopDevice.getDevice().isNull() ? _selectedDesktopDevice.deviceName() : _desktopSavedDeviceName; auto device = getSimilarDevice(_backupSelectedDesktopDeviceName, newDevices); device->selectedDesktop = true; emit selectedDevicePlugged(device->info, false); @@ -370,8 +390,8 @@ AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) { _outputs.onDeviceChanged(client->getActiveAudioDevice(QAudio::AudioOutput), contextIsHMD); // connections are made after client is initialized, so we must also fetch the devices - const QList& devicesInput = client->getAudioDevices(QAudio::AudioInput); - const QList& devicesOutput = client->getAudioDevices(QAudio::AudioOutput); + const QList& devicesInput = client->getAudioDevices(QAudio::AudioInput); + const QList& devicesOutput = client->getAudioDevices(QAudio::AudioOutput); //setup devices _inputs.onDevicesChanged(devicesInput); @@ -385,9 +405,9 @@ void AudioDevices::onContextChanged(const QString& context) { _outputs.resetDevice(_contextIsHMD); } -void AudioDevices::onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& device, - const QAudioDeviceInfo& previousDevice, bool isHMD) { - QString deviceName = device.isNull() ? QString() : device.deviceName(); +void AudioDevices::onDeviceSelected(QAudio::Mode mode, const HifiAudioDeviceInfo& device, + const HifiAudioDeviceInfo& previousDevice, bool isHMD) { + QString deviceName = device.deviceName(); auto& setting = getSetting(isHMD, mode); @@ -398,7 +418,7 @@ void AudioDevices::onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& d setting.set(deviceName); // log the selected device - if (!device.isNull()) { + if (!device.getDevice().isNull()) { QJsonObject data; const QString MODE = "audio_mode"; @@ -422,13 +442,13 @@ void AudioDevices::onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& d } } -void AudioDevices::onDeviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device) { +void AudioDevices::onDeviceChanged(QAudio::Mode mode, const HifiAudioDeviceInfo& device) { if (mode == QAudio::AudioInput) { if (_requestedInputDevice == device) { onDeviceSelected(QAudio::AudioInput, device, _contextIsHMD ? _inputs._selectedHMDDevice : _inputs._selectedDesktopDevice, _contextIsHMD); - _requestedInputDevice = QAudioDeviceInfo(); + _requestedInputDevice = HifiAudioDeviceInfo(); } _inputs.onDeviceChanged(device, _contextIsHMD); } else { // if (mode == QAudio::AudioOutput) @@ -436,13 +456,13 @@ void AudioDevices::onDeviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& de onDeviceSelected(QAudio::AudioOutput, device, _contextIsHMD ? _outputs._selectedHMDDevice : _outputs._selectedDesktopDevice, _contextIsHMD); - _requestedOutputDevice = QAudioDeviceInfo(); + _requestedOutputDevice = HifiAudioDeviceInfo(); } _outputs.onDeviceChanged(device, _contextIsHMD); } } -void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList& devices) { +void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList& devices) { static std::once_flag once; std::call_once(once, [&] { //readout settings @@ -491,14 +511,14 @@ void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList().data(); _requestedInputDevice = device; QMetaObject::invokeMethod(client, "switchAudioDevice", Q_ARG(QAudio::Mode, QAudio::AudioInput), - Q_ARG(const QAudioDeviceInfo&, device)); + Q_ARG(const HifiAudioDeviceInfo&, device)); } else { //context is different. just save device in settings onDeviceSelected(QAudio::AudioInput, device, @@ -508,14 +528,14 @@ void AudioDevices::chooseInputDevice(const QAudioDeviceInfo& device, bool isHMD) } } -void AudioDevices::chooseOutputDevice(const QAudioDeviceInfo& device, bool isHMD) { +void AudioDevices::chooseOutputDevice(const HifiAudioDeviceInfo& device, bool isHMD) { //check if current context equals device to change if (_contextIsHMD == isHMD) { auto client = DependencyManager::get().data(); _requestedOutputDevice = device; QMetaObject::invokeMethod(client, "switchAudioDevice", Q_ARG(QAudio::Mode, QAudio::AudioOutput), - Q_ARG(const QAudioDeviceInfo&, device)); + Q_ARG(const HifiAudioDeviceInfo&, device)); } else { //context is different. just save device in settings onDeviceSelected(QAudio::AudioOutput, device, diff --git a/interface/src/scripting/AudioDevices.h b/interface/src/scripting/AudioDevices.h index 2ea034d9fe..13d97d53dd 100644 --- a/interface/src/scripting/AudioDevices.h +++ b/interface/src/scripting/AudioDevices.h @@ -19,11 +19,13 @@ #include #include +#include + namespace scripting { class AudioDevice { public: - QAudioDeviceInfo info; + HifiAudioDeviceInfo info; QString display; bool selectedDesktop { false }; bool selectedHMD { false }; @@ -50,12 +52,12 @@ public: void resetDevice(bool contextIsHMD); signals: - void deviceChanged(const QAudioDeviceInfo& device); - void selectedDevicePlugged(const QAudioDeviceInfo& device, bool isHMD); + void deviceChanged(const HifiAudioDeviceInfo& device); + void selectedDevicePlugged(const HifiAudioDeviceInfo& device, bool isHMD); protected slots: - void onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD); - void onDevicesChanged(const QList& devices); + void onDeviceChanged(const HifiAudioDeviceInfo& device, bool isHMD); + void onDevicesChanged(const QList& devices); protected: friend class AudioDevices; @@ -63,8 +65,8 @@ protected: static QHash _roles; static Qt::ItemFlags _flags; const QAudio::Mode _mode; - QAudioDeviceInfo _selectedDesktopDevice; - QAudioDeviceInfo _selectedHMDDevice; + HifiAudioDeviceInfo _selectedDesktopDevice; + HifiAudioDeviceInfo _selectedHMDDevice; QString _backupSelectedDesktopDeviceName; QString _backupSelectedHMDDeviceName; QList> _devices; @@ -124,14 +126,14 @@ signals: void nop(); private slots: - void chooseInputDevice(const QAudioDeviceInfo& device, bool isHMD); - void chooseOutputDevice(const QAudioDeviceInfo& device, bool isHMD); + void chooseInputDevice(const HifiAudioDeviceInfo& device, bool isHMD); + void chooseOutputDevice(const HifiAudioDeviceInfo& device, bool isHMD); void onContextChanged(const QString& context); - void onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& device, - const QAudioDeviceInfo& previousDevice, bool isHMD); - void onDeviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device); - void onDevicesChanged(QAudio::Mode mode, const QList& devices); + void onDeviceSelected(QAudio::Mode mode, const HifiAudioDeviceInfo& device, + const HifiAudioDeviceInfo& previousDevice, bool isHMD); + void onDeviceChanged(QAudio::Mode mode, const HifiAudioDeviceInfo& device); + void onDevicesChanged(QAudio::Mode mode, const QList& devices); private: friend class Audio; @@ -141,8 +143,8 @@ private: AudioInputDeviceList _inputs; AudioDeviceList _outputs { QAudio::AudioOutput }; - QAudioDeviceInfo _requestedOutputDevice; - QAudioDeviceInfo _requestedInputDevice; + HifiAudioDeviceInfo _requestedOutputDevice; + HifiAudioDeviceInfo _requestedInputDevice; const bool& _contextIsHMD; }; diff --git a/interface/src/scripting/DesktopScriptingInterface.cpp b/interface/src/scripting/DesktopScriptingInterface.cpp index a1c8e4fc6c..874b3fa42d 100644 --- a/interface/src/scripting/DesktopScriptingInterface.cpp +++ b/interface/src/scripting/DesktopScriptingInterface.cpp @@ -52,6 +52,9 @@ static const QVariantMap DOCK_AREA { { "RIGHT", DockArea::RIGHT } }; +DesktopScriptingInterface::DesktopScriptingInterface(QObject* parent, bool restricted) + : QObject(parent), _restricted(restricted) { } + int DesktopScriptingInterface::getWidth() { QSize size = qApp->getWindow()->windowHandle()->screen()->virtualSize(); return size.width(); @@ -128,7 +131,7 @@ InteractiveWindowPointer DesktopScriptingInterface::createWindow(const QString& return nullptr; } - return new InteractiveWindow(sourceUrl, properties); + return new InteractiveWindow(sourceUrl, properties, _restricted); } InteractiveWindowPointer DesktopScriptingInterface::createWindowOnThread(const QString& sourceUrl, const QVariantMap& properties, QThread* targetThread) { @@ -139,7 +142,7 @@ InteractiveWindowPointer DesktopScriptingInterface::createWindowOnThread(const Q if (!urlValidator(sourceUrl)) { return nullptr; } - InteractiveWindowPointer window = new InteractiveWindow(sourceUrl, properties); + InteractiveWindowPointer window = new InteractiveWindow(sourceUrl, properties, _restricted); window->moveToThread(targetThread); return window; } diff --git a/interface/src/scripting/DesktopScriptingInterface.h b/interface/src/scripting/DesktopScriptingInterface.h index 525fd7c803..e562a32543 100644 --- a/interface/src/scripting/DesktopScriptingInterface.h +++ b/interface/src/scripting/DesktopScriptingInterface.h @@ -54,6 +54,8 @@ class DesktopScriptingInterface : public QObject, public Dependency { Q_PROPERTY(int CLOSE_BUTTON_HIDES READ flagCloseButtonHides CONSTANT FINAL) public: + DesktopScriptingInterface(QObject* parent= nullptr, bool restricted = false); + /**jsdoc * Sets the opacity of the HUD surface. * @function Desktop.setHUDAlpha @@ -106,6 +108,7 @@ private: static QVariantMap getDockArea(); Q_INVOKABLE static QVariantMap getPresentationMode(); + const bool _restricted; }; diff --git a/interface/src/scripting/SettingsScriptingInterface.cpp b/interface/src/scripting/SettingsScriptingInterface.cpp index c47d8e1da1..13eddddb1f 100644 --- a/interface/src/scripting/SettingsScriptingInterface.cpp +++ b/interface/src/scripting/SettingsScriptingInterface.cpp @@ -38,6 +38,14 @@ void SettingsScriptingInterface::setValue(const QString& setting, const QVariant if (getValue(setting) == value) { return; } + if (setting.startsWith("private/")) { + if (_restrictPrivateValues) { + qWarning() << "SettingsScriptingInterface::setValue -- restricted write: " << setting << value; + return; + } else { + qInfo() << "SettingsScriptingInterface::setValue -- allowing restricted write: " << setting << value; + } + } // Make a deep-copy of the string. // Dangling pointers can occur with QStrings that are implicitly shared from a QScriptEngine. QString deepCopy = QString::fromUtf16(setting.utf16()); diff --git a/interface/src/scripting/SettingsScriptingInterface.h b/interface/src/scripting/SettingsScriptingInterface.h index ff00299fd0..f321c41e76 100644 --- a/interface/src/scripting/SettingsScriptingInterface.h +++ b/interface/src/scripting/SettingsScriptingInterface.h @@ -27,7 +27,6 @@ class SettingsScriptingInterface : public QObject { Q_OBJECT - SettingsScriptingInterface() { }; public: static SettingsScriptingInterface* getInstance(); @@ -67,6 +66,16 @@ public slots: signals: void valueChanged(const QString& setting, const QVariant& value); + +protected: + SettingsScriptingInterface(QObject* parent = nullptr) : QObject(parent) { }; + bool _restrictPrivateValues { true }; +}; + +class QMLSettingsScriptingInterface : public SettingsScriptingInterface { + Q_OBJECT +public: + QMLSettingsScriptingInterface(QObject* parent) : SettingsScriptingInterface(parent) { _restrictPrivateValues = false; } }; #endif // hifi_SettingsScriptingInterface_h diff --git a/interface/src/ui/AnimStats.cpp b/interface/src/ui/AnimStats.cpp index 47116ea281..2a355e48d1 100644 --- a/interface/src/ui/AnimStats.cpp +++ b/interface/src/ui/AnimStats.cpp @@ -118,7 +118,7 @@ void AnimStats::updateStats(bool force) { auto prevIter = _prevDebugAlphaMap.find(key); if (prevIter != _prevDebugAlphaMap.end()) { - float prevAlpha = std::get<0>(iter.second); + float prevAlpha = std::get<0>(prevIter->second); if (prevAlpha != alpha) { // change detected: reset timer _animAlphaValueChangedTimers[key] = now; diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index 9145b12d30..e63c392a47 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -18,6 +18,9 @@ #include #include +#include +#include +#include #include #include #include @@ -134,7 +137,7 @@ void InteractiveWindow::emitMainWindowResizeEvent() { * Set at window creation. Possible flag values are provided as {@link Desktop|Desktop.ALWAYS_ON_TOP} and {@link Desktop|Desktop.CLOSE_BUTTON_HIDES}. * Additional flag values can be found on Qt's website at https://doc.qt.io/qt-5/qt.html#WindowType-enum. */ -InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap& properties) { +InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap& properties, bool restricted) { InteractiveWindowPresentationMode presentationMode = InteractiveWindowPresentationMode::Native; if (properties.contains(PRESENTATION_MODE_PROPERTY)) { @@ -228,9 +231,16 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap _dockWidget->setObjectName("DockedWidget"); mainWindow->addDockWidget(dockArea, _dockWidget.get()); } else { - auto offscreenUi = DependencyManager::get(); - // Build the event bridge and wrapper on the main thread - offscreenUi->loadInNewContext(CONTENT_WINDOW_QML, [&](QQmlContext* context, QObject* object) { + auto contextInitLambda = [&](QQmlContext* context) { + // If the restricted flag is on, the web content will not be able to access local files + ContextAwareProfile::restrictContext(context, restricted); +#if !defined(Q_OS_ANDROID) + FileTypeProfile::registerWithContext(context); + HFWebEngineProfile::registerWithContext(context); +#endif + }; + + auto objectInitLambda = [&](QQmlContext* context, QObject* object) { _qmlWindowProxy = std::shared_ptr(new QmlWindowProxy(object, nullptr), qmlWindowProxyDeleter); context->setContextProperty(EVENT_BRIDGE_PROPERTY, _interactiveWindowProxy.get()); if (properties.contains(ADDITIONAL_FLAGS_PROPERTY)) { @@ -286,7 +296,11 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap } object->setObjectName("InteractiveWindow"); object->setProperty(SOURCE_PROPERTY, sourceURL); - }); + }; + auto offscreenUi = DependencyManager::get(); + + // Build the event bridge and wrapper on the main thread + offscreenUi->loadInNewContext(CONTENT_WINDOW_QML, objectInitLambda, contextInitLambda); } } diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h index cc7536af85..70077a27b0 100644 --- a/interface/src/ui/InteractiveWindow.h +++ b/interface/src/ui/InteractiveWindow.h @@ -126,7 +126,7 @@ class InteractiveWindow : public QObject { Q_PROPERTY(int presentationMode READ getPresentationMode WRITE setPresentationMode) public: - InteractiveWindow(const QString& sourceUrl, const QVariantMap& properties); + InteractiveWindow(const QString& sourceUrl, const QVariantMap& properties, bool restricted); ~InteractiveWindow(); private: diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt index fa4c9d5f45..48ae0485b5 100644 --- a/launchers/darwin/CMakeLists.txt +++ b/launchers/darwin/CMakeLists.txt @@ -45,6 +45,8 @@ set(src_files src/CustomUI.m src/NSTask+NSTaskExecveAdditions.h src/NSTask+NSTaskExecveAdditions.m + src/HQDefaults.h + src/HQDefaults.m src/main.mm nib/Window.xib nib/SplashScreen.xib @@ -118,9 +120,16 @@ add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/images "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/Resources/") +add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_SOURCE_DIR}/data/HQDefaults.plist "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/Resources/") + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND updater - COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/updater" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/Resources/") + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/updater" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/MacOS/" + # Older versions of Launcher put updater in `/Contents/Resources/updater`. + COMMAND ${CMAKE_COMMAND} -E chdir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/Resources" ln -sf ../MacOS/updater updater +) install( TARGETS HQLauncher @@ -146,3 +155,17 @@ set(DMG_SUBFOLDER_ICON "${CMAKE_SOURCE_DIR}/cmake/installer/install-folder.rsrc" set(CPACK_GENERATOR "DragNDrop") include(CPack) + +include(FindXCTest) + +include_directories(${CMAKE_SOURCE_DIR}/src) + +xctest_add_bundle(HQLauncherTests HQLauncher + ${CMAKE_SOURCE_DIR}/src/HQDefaults.m + ${CMAKE_SOURCE_DIR}/tests/HQDefaultsTests.m + ${CMAKE_SOURCE_DIR}/tests/Info.plist +) + +set_target_properties(HQLauncherTests PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/tests/Info.plist + ) diff --git a/launchers/darwin/HQ Launcher.entitlements b/launchers/darwin/HQ Launcher.entitlements new file mode 100644 index 0000000000..ddfcefe3af --- /dev/null +++ b/launchers/darwin/HQ Launcher.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + high-fidelity.hifi + + + diff --git a/launchers/darwin/data/HQDefaults.plist b/launchers/darwin/data/HQDefaults.plist new file mode 100644 index 0000000000..98a29664c9 --- /dev/null +++ b/launchers/darwin/data/HQDefaults.plist @@ -0,0 +1,14 @@ + + + + + + name + thunderURL + defaultValue + https://thunder.highfidelity.com + environmentVariable + HIFI_THUNDER_URL + + + diff --git a/launchers/darwin/nib/DisplayNameScreen.xib b/launchers/darwin/nib/DisplayNameScreen.xib index 9862c3773b..77cc3b2222 100644 --- a/launchers/darwin/nib/DisplayNameScreen.xib +++ b/launchers/darwin/nib/DisplayNameScreen.xib @@ -81,7 +81,7 @@
diff --git a/tools/jsdoc/plugins/hifi.js b/tools/jsdoc/plugins/hifi.js index 67dafe5a16..07549530ce 100644 --- a/tools/jsdoc/plugins/hifi.js +++ b/tools/jsdoc/plugins/hifi.js @@ -125,7 +125,7 @@ exports.handlers = { if (rows.length > 0) { var availableIn = "

Supported Script Types: " + rows.join(" • ") + "

"; - e.doclet.description = (e.doclet.description ? e.doclet.description : "") + availableIn; + e.doclet.description = availableIn + (e.doclet.description ? e.doclet.description : ""); } } diff --git a/tools/nitpick/CMakeLists.txt b/tools/nitpick/CMakeLists.txt index ee534ca24f..a5dd8d5236 100644 --- a/tools/nitpick/CMakeLists.txt +++ b/tools/nitpick/CMakeLists.txt @@ -93,7 +93,7 @@ if (WIN32) set_property(TARGET ${TARGET_NAME} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG "/OPT:NOREF /OPT:NOICF") endif() -link_hifi_libraries(entities-renderer) +link_hifi_libraries(entities-renderer platform) # perform standard include and linking for found externals foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) diff --git a/tools/nitpick/src/TestCreator.cpp b/tools/nitpick/src/TestCreator.cpp index 693f6085d2..652292b9dc 100644 --- a/tools/nitpick/src/TestCreator.cpp +++ b/tools/nitpick/src/TestCreator.cpp @@ -323,9 +323,11 @@ void TestCreator::startTestsEvaluation( QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); - // Images are stored on GitHub as ExpectedImage_ddddd.png - // Extract the digits at the end of the filename (excluding the file extension) - QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); + // Images are stored on GitHub as ExpectedImage_ddddd.png or ExpectedImage_some_metadata_ddddd.png + // Extract the part of the filename after "ExpectedImage_" and excluding the file extension + QString expectedImageFilenameTail = currentFilename.left(currentFilename.lastIndexOf(".")); + int expectedImageStart = expectedImageFilenameTail.lastIndexOf(".") + 1; + expectedImageFilenameTail.remove(0, expectedImageStart); QString expectedImageStoredFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + ".png"; QString imageURLString("https://raw.githubusercontent.com/" + user + "/" + GIT_HUB_REPOSITORY + "/" + branch + "/" + @@ -495,6 +497,93 @@ void TestCreator::createTests(const QString& clientProfile) { QMessageBox::information(0, "Success", "Test images have been created"); } +namespace TestProfile { + std::vector tiers = [](){ + std::vector toReturn; + for (int tier = (int)platform::Profiler::Tier::LOW; tier < (int)platform::Profiler::Tier::NumTiers; ++tier) { + QString tierStringUpper = platform::Profiler::TierNames[tier]; + toReturn.push_back(tierStringUpper.toLower()); + } + return toReturn; + }(); + + std::vector operatingSystems = { "windows", "mac", "linux", "android" }; + + std::vector gpus = { "amd", "nvidia", "intel" }; +}; + +enum class ProfileCategory { + TIER, + OS, + GPU +}; +const std::map propertyToProfileCategory = [](){ + std::map toReturn; + for (const auto& tier : TestProfile::tiers) { + toReturn[tier] = ProfileCategory::TIER; + } + for (const auto& os : TestProfile::operatingSystems) { + toReturn[os] = ProfileCategory::OS; + } + for (const auto& gpu : TestProfile::gpus) { + toReturn[gpu] = ProfileCategory::GPU; + } + return toReturn; +}(); + +TestFilter::TestFilter(const QString& filterString) { + auto filterParts = filterString.split(".", QString::SkipEmptyParts); + for (const auto& filterPart : filterParts) { + QList allowedVariants = filterPart.split(",", QString::SkipEmptyParts); + if (allowedVariants.empty()) { + continue; + } + + auto& referenceVariant = allowedVariants[0]; + auto foundCategoryIt = propertyToProfileCategory.find(referenceVariant); + if (foundCategoryIt == propertyToProfileCategory.cend()) { + error = "Invalid test filter property '" + referenceVariant + "'"; + return; + } + + ProfileCategory selectedFilterCategory = foundCategoryIt->second; + for (auto allowedVariantIt = ++(allowedVariants.cbegin()); allowedVariantIt != allowedVariants.cend(); ++allowedVariantIt) { + auto& currentVariant = *allowedVariantIt; + auto nextCategoryIt = propertyToProfileCategory.find(currentVariant); + if (nextCategoryIt == propertyToProfileCategory.cend()) { + error = "Invalid test filter property '" + referenceVariant + "'"; + return; + } + auto& currentCategory = nextCategoryIt->second; + if (currentCategory != selectedFilterCategory) { + error = "Mismatched comma-separated test filter properties '" + referenceVariant + "' and '" + currentVariant + "'"; + return; + } + // List of comma-separated test property variants is consistent so far + } + + switch (selectedFilterCategory) { + case ProfileCategory::TIER: + allowedTiers.insert(allowedTiers.cend(), allowedVariants.cbegin(), allowedVariants.cend()); + break; + case ProfileCategory::OS: + allowedOperatingSystems.insert(allowedOperatingSystems.cend(), allowedVariants.cbegin(), allowedVariants.cend()); + break; + case ProfileCategory::GPU: + allowedGPUs.insert(allowedGPUs.cend(), allowedVariants.cbegin(), allowedVariants.cend()); + break; + } + } +} + +bool TestFilter::isValid() const { + return error.isEmpty(); +} + +QString TestFilter::getError() const { + return error; +} + ExtractedText TestCreator::getTestScriptLines(QString testFileName) { ExtractedText relevantTextFromTest; @@ -511,7 +600,7 @@ ExtractedText TestCreator::getTestScriptLines(QString testFileName) { QString line = stream.readLine(); // Name of test is the string in the following line: - // nitpick.perform("Apply Material Entities to Avatars", Script.resolvePath("."), function(testType) {... + // nitpick.perform("Apply Material Entities to Avatars", Script.resolvePath("."), "secondary", undefined, function(testType) {... const QString ws("\\h*"); //white-space character const QString functionPerformName(ws + "nitpick" + ws + "\\." + ws + "perform"); const QString quotedString("\\\".+\\\""); @@ -644,6 +733,17 @@ void TestCreator::createAllMDFiles() { QMessageBox::information(0, "Success", "MD files have been created"); } +QString joinVector(const std::vector& qStringVector, const char* separator) { + if (qStringVector.empty()) { + return QString(""); + } + QString joined = qStringVector[0]; + for (std::size_t i = 1; i < qStringVector.size(); ++i) { + joined += separator + qStringVector[i]; + } + return joined; +} + bool TestCreator::createMDFile(const QString& directory) { // Verify folder contains test.js file QString testFileName(directory + "/" + TEST_FILENAME); @@ -655,33 +755,73 @@ bool TestCreator::createMDFile(const QString& directory) { ExtractedText testScriptLines = getTestScriptLines(testFileName); + QDir qDirectory(directory); + QString mdFilename(directory + "/" + "test.md"); QFile mdFile(mdFilename); if (!mdFile.open(QIODevice::WriteOnly)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + mdFilename); + // TODO: Don't just exit exit(-1); } QTextStream stream(&mdFile); - //TestCreator title QString testName = testScriptLines.title; stream << "# " << testName << "\n"; stream << "## Run this script URL: [Manual](./test.js?raw=true) [Auto](./testAuto.js?raw=true)(from menu/Edit/Open and Run scripts from URL...)." << "\n\n"; stream << "## Preconditions" << "\n"; - stream << "- In an empty region of a domain with editing rights." << "\n\n"; + stream << "- In an empty region of a domain with editing rights." << "\n"; + stream << "\n"; + + // ExpectedImage_00000.png OR ExpectedImage_some_stu-ff_00000.png + const QRegularExpression firstExpectedImage("^ExpectedImage(_[-_\\w]*)?_00000\\.png$"); + std::vector testDescriptors; + std::vector testFilters; + + for (const auto& potentialImageFile : qDirectory.entryInfoList()) { + if (potentialImageFile.isDir()) { + continue; + } + + auto firstExpectedImageMatch = firstExpectedImage.match(potentialImageFile.fileName()); + if (!firstExpectedImageMatch.hasMatch()) { + continue; + } + + QString testDescriptor = firstExpectedImageMatch.captured(1); + auto filterString = QString(testDescriptor).replace("_", ".").replace("-", ","); + TestFilter descriptorAsFilter(filterString); + + testDescriptors.push_back(testDescriptor); + testFilters.push_back(descriptorAsFilter); + } stream << "## Steps\n"; stream << "Press '" + ADVANCE_KEY + "' key to advance step by step\n\n"; // note apostrophes surrounding 'ADVANCE_KEY' - int snapShotIndex { 0 }; for (size_t i = 0; i < testScriptLines.stepList.size(); ++i) { stream << "### Step " << QString::number(i + 1) << "\n"; stream << "- " << testScriptLines.stepList[i]->text << "\n"; if ((i + 1 < testScriptLines.stepList.size()) && testScriptLines.stepList[i]->takeSnapshot) { - stream << "- ![](./ExpectedImage_" << QString::number(snapShotIndex).rightJustified(5, '0') << ".png)\n"; + for (int i = 0; i < (int)testDescriptors.size(); ++i) { + const auto& testDescriptor = testDescriptors[i]; + const auto& descriptorAsFilter = testFilters[i]; + if (descriptorAsFilter.isValid()) { + stream << "- Expected image on "; + stream << (descriptorAsFilter.allowedTiers.empty() ? "any" : joinVector(descriptorAsFilter.allowedTiers, "/")) << " tier, "; + stream << (descriptorAsFilter.allowedOperatingSystems.empty() ? "any" : joinVector(descriptorAsFilter.allowedOperatingSystems, "/")) << " OS, "; + stream << (descriptorAsFilter.allowedGPUs.empty() ? "any" : joinVector(descriptorAsFilter.allowedGPUs, "/")) << " GPU"; + stream << ":"; + } else { + // Fall back to displaying file name + stream << "- ExpectedImage" << testDescriptor << "_" << QString::number(snapShotIndex).rightJustified(5, '0') << ".png"; + } + stream << "\n"; + stream << "- ![](./ExpectedImage" << testDescriptor << "_" << QString::number(snapShotIndex).rightJustified(5, '0') << ".png)\n"; + } ++snapShotIndex; } } diff --git a/tools/nitpick/src/TestCreator.h b/tools/nitpick/src/TestCreator.h index f995c06c94..247f2ee117 100644 --- a/tools/nitpick/src/TestCreator.h +++ b/tools/nitpick/src/TestCreator.h @@ -16,6 +16,8 @@ #include #include +#include + #include "AWSInterface.h" #include "ImageComparer.h" #include "Downloader.h" @@ -30,6 +32,20 @@ public: using StepList = std::vector; +class TestFilter { +public: + TestFilter(const QString& filterString); + bool isValid() const; + QString getError() const; + + std::vector allowedTiers; + std::vector allowedOperatingSystems; + std::vector allowedGPUs; + +protected: + QString error; +}; + class ExtractedText { public: QString title; diff --git a/tools/oven/src/DomainBaker.cpp b/tools/oven/src/DomainBaker.cpp index c52803956c..0853b41872 100644 --- a/tools/oven/src/DomainBaker.cpp +++ b/tools/oven/src/DomainBaker.cpp @@ -445,7 +445,7 @@ void DomainBaker::handleFinishedModelBaker() { // enumerate the QJsonRef values for the URL of this model from our multi hash of // entity objects needing a URL re-write - for (auto propertyEntityPair : _entitiesNeedingRewrite.values(baker->getModelURL())) { + for (auto propertyEntityPair : _entitiesNeedingRewrite.values(baker->getOriginalInputModelURL())) { QString property = propertyEntityPair.first; // convert the entity QJsonValueRef to a QJsonObject so we can modify its URL auto entity = propertyEntityPair.second.toObject(); @@ -485,10 +485,10 @@ void DomainBaker::handleFinishedModelBaker() { } // remove the baked URL from the multi hash of entities needing a re-write - _entitiesNeedingRewrite.remove(baker->getModelURL()); + _entitiesNeedingRewrite.remove(baker->getOriginalInputModelURL()); // drop our shared pointer to this baker so that it gets cleaned up - _modelBakers.remove(baker->getModelURL()); + _modelBakers.remove(baker->getOriginalInputModelURL()); // emit progress to tell listeners how many models we have baked emit bakeProgress(++_completedSubBakes, _totalNumberOfSubBakes); diff --git a/unpublishedScripts/marketplace/blocks/blocksApp.js b/unpublishedScripts/marketplace/blocks/blocksApp.js index 813a77c74a..9c10ba8197 100644 --- a/unpublishedScripts/marketplace/blocks/blocksApp.js +++ b/unpublishedScripts/marketplace/blocks/blocksApp.js @@ -35,7 +35,7 @@ function onClicked() { if (!shown) { - tablet.gotoWebScreen(APP_URL, "", true); + tablet.gotoWebScreen(APP_URL, ""); } else { tablet.gotoHomeScreen(); }