diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index f1e30f4442..28ede7a77d 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -331,7 +331,13 @@ void AvatarMixer::manageIdentityData(const SharedNodePointer& node) { } } if (sendIdentity) { - sendIdentityPacket(nodeData, node); // Tell node whose name changed about its new session display name or avatar. + + // since this packet includes a change to either the skeleton model URL or the display name + // it needs a new sequence number + nodeData->getAvatar().pushIdentitySequenceNumber(); + + // tell node whose name changed about its new session display name or avatar. + sendIdentityPacket(nodeData, node); } } diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index e4a286cf3f..d0fc58af0c 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -35,6 +35,23 @@ macro(SETUP_HIFI_LIBRARY) endif() endforeach() + # add compiler flags to AVX512 source files, if supported by compiler + include(CheckCXXCompilerFlag) + file(GLOB_RECURSE AVX512_SRCS "src/avx512/*.cpp" "src/avx512/*.c") + foreach(SRC ${AVX512_SRCS}) + if (WIN32) + check_cxx_compiler_flag("/arch:AVX512" COMPILER_SUPPORTS_AVX512) + if (COMPILER_SUPPORTS_AVX512) + set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX512) + endif() + elseif (APPLE OR UNIX) + check_cxx_compiler_flag("-mavx512f" COMPILER_SUPPORTS_AVX512) + if (COMPILER_SUPPORTS_AVX512) + set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx512f) + endif() + endif() + endforeach() + setup_memory_debugger() # create a library and set the property so it can be referenced later diff --git a/cmake/modules/FindFBX.cmake b/cmake/modules/FindFBX.cmake index 7f6a424aa1..2e84d1ea19 100644 --- a/cmake/modules/FindFBX.cmake +++ b/cmake/modules/FindFBX.cmake @@ -29,6 +29,7 @@ string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*$" "\\1" FBX_VERSION_MINOR "${FBX_VER string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" FBX_VERSION_PATCH "${FBX_VERSION}") set(FBX_MAC_LOCATIONS "/Applications/Autodesk/FBX\ SDK/${FBX_VERSION}") +set(FBX_LINUX_LOCATIONS "/usr/local/lib/gcc4/x64/debug/") if (WIN32) string(REGEX REPLACE "\\\\" "/" WIN_PROGRAM_FILES_X64_DIRECTORY $ENV{ProgramW6432}) @@ -36,7 +37,7 @@ endif() set(FBX_WIN_LOCATIONS "${WIN_PROGRAM_FILES_X64_DIRECTORY}/Autodesk/FBX/FBX SDK/${FBX_VERSION}") -set(FBX_SEARCH_LOCATIONS $ENV{FBX_ROOT} ${FBX_ROOT} ${FBX_MAC_LOCATIONS} ${FBX_WIN_LOCATIONS}) +set(FBX_SEARCH_LOCATIONS $ENV{FBX_ROOT} ${FBX_ROOT} ${FBX_MAC_LOCATIONS} ${FBX_WIN_LOCATIONS} ${FBX_LINUX_LOCATIONS}) function(_fbx_append_debugs _endvar _library) if (${_library} AND ${_library}_DEBUG) @@ -94,6 +95,8 @@ elseif (APPLE) find_library(SYSTEM_CONFIGURATION NAMES SystemConfiguration) _fbx_find_library(FBX_LIBRARY libfbxsdk.a release) _fbx_find_library(FBX_LIBRARY_DEBUG libfbxsdk.a debug) +else () + _fbx_find_library(FBX_LIBRARY libfbxsdk.a release) endif() include(FindPackageHandleStandardArgs) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index bdba621cb5..033e9e0255 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -29,6 +29,63 @@ !include "WinVer.nsh" ;-------------------------------- +; Utilities and Functions + ;-------------------------------- + ; START String Contains Macro + ; Taken from http://nsis.sourceforge.net/StrContains + ;-------------------------------- + ; StrContains + ; This function does a case sensitive searches for an occurrence of a substring in a string. + ; It returns the substring if it is found. + ; Otherwise it returns null(""). + ; Written by kenglish_hi + ; Adapted from StrReplace written by dandaman32 + + + Var STR_HAYSTACK + Var STR_NEEDLE + Var STR_CONTAINS_VAR_1 + Var STR_CONTAINS_VAR_2 + Var STR_CONTAINS_VAR_3 + Var STR_CONTAINS_VAR_4 + Var STR_RETURN_VAR + + Function StrContains + Exch $STR_NEEDLE + Exch 1 + Exch $STR_HAYSTACK + ; Uncomment to debug + ;MessageBox MB_OK 'STR_NEEDLE = $STR_NEEDLE STR_HAYSTACK = $STR_HAYSTACK ' + StrCpy $STR_RETURN_VAR "" + StrCpy $STR_CONTAINS_VAR_1 -1 + StrLen $STR_CONTAINS_VAR_2 $STR_NEEDLE + StrLen $STR_CONTAINS_VAR_4 $STR_HAYSTACK + loop: + IntOp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_1 + 1 + StrCpy $STR_CONTAINS_VAR_3 $STR_HAYSTACK $STR_CONTAINS_VAR_2 $STR_CONTAINS_VAR_1 + StrCmp $STR_CONTAINS_VAR_3 $STR_NEEDLE found + StrCmp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_4 done + Goto loop + found: + StrCpy $STR_RETURN_VAR $STR_NEEDLE + Goto done + done: + Pop $STR_NEEDLE ;Prevent "invalid opcode" errors and keep the + Exch $STR_RETURN_VAR + FunctionEnd + + !macro _StrContainsConstructor OUT NEEDLE HAYSTACK + Push `${HAYSTACK}` + Push `${NEEDLE}` + Call StrContains + Pop `${OUT}` + !macroend + + !define StrContains '!insertmacro "_StrContainsConstructor"' + ;-------------------------------- + ; END String Contains Macro + ;-------------------------------- +;-------------------------------- ;General ; leverage the UAC NSIS plugin to promote uninstaller to elevated privileges !include UAC.nsh @@ -92,6 +149,7 @@ ; inter-component dependencies. Var AR_SecFlags Var AR_RegFlags +Var substringResult @CPACK_NSIS_SECTION_SELECTED_VARS@ ; Loads the "selected" flag for the section named SecName into the @@ -119,9 +177,11 @@ Var AR_RegFlags ClearErrors ;Reading component status from registry ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed" - IfErrors "default_${SecName}" + IfErrors "checkBeforeDefault_${SecName}" ;Status will stay default if registry value not found ;(component was never installed) + + "set_initSection_${SecName}:" IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off @@ -137,6 +197,18 @@ Var AR_RegFlags "default_${SecName}:" !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected + Goto "end_initSection_${SecName}" + + "checkBeforeDefault_${SecName}:" + ${StrContains} $substringResult "/nSandboxIfNew" $CMDLINE + ${If} "${SecName}" == "server" + ${AndIfNot} $substringResult == "" + StrCpy $AR_RegFlags 0 + Goto "set_initSection_${SecName}" + ${Else} + Goto "default_${SecName}" + ${EndIf} + "end_initSection_${SecName}:" !macroend !macro FinishSection SecName diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index a3692c974e..62f56184f4 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -435,8 +435,29 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect return SharedNodePointer(); } + QUuid hintNodeID; + + // in case this is a node that's failing to connect + // double check we don't have the same node whose sockets match exactly already in the list + limitedNodeList->eachNodeBreakable([&](const SharedNodePointer& node){ + if (node->getPublicSocket() == nodeConnection.publicSockAddr && node->getLocalSocket() == nodeConnection.localSockAddr) { + // we have a node that already has these exact sockets - this can occur if a node + // is failing to connect to the domain + + // we'll re-use the existing node ID + // as long as the user hasn't changed their username (by logging in or logging out) + auto existingNodeData = static_cast(node->getLinkedData()); + + if (existingNodeData->getUsername() == username) { + hintNodeID = node->getUUID(); + return false; + } + } + return true; + }); + // add the connecting node (or re-use the matched one from eachNodeBreakable above) - SharedNodePointer newNode = addVerifiedNodeFromConnectRequest(nodeConnection); + SharedNodePointer newNode = addVerifiedNodeFromConnectRequest(nodeConnection, hintNodeID); // set the edit rights for this user newNode->setPermissions(userPerms); @@ -464,12 +485,11 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect return newNode; } -SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection) { +SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection, + QUuid nodeID) { HifiSockAddr discoveredSocket = nodeConnection.senderSockAddr; SharedNetworkPeer connectedPeer = _icePeers.value(nodeConnection.connectUUID); - QUuid nodeID; - if (connectedPeer) { // this user negotiated a connection with us via ICE, so re-use their ICE client ID nodeID = nodeConnection.connectUUID; @@ -479,8 +499,10 @@ SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const Node discoveredSocket = *connectedPeer->getActiveSocket(); } } else { - // we got a connectUUID we didn't recognize, randomly generate a new one - nodeID = QUuid::createUuid(); + // we got a connectUUID we didn't recognize, either use the hinted node ID or randomly generate a new one + if (nodeID.isNull()) { + nodeID = QUuid::createUuid(); + } } auto limitedNodeList = DependencyManager::get(); diff --git a/domain-server/src/DomainGatekeeper.h b/domain-server/src/DomainGatekeeper.h index e2d36c4cea..163f255411 100644 --- a/domain-server/src/DomainGatekeeper.h +++ b/domain-server/src/DomainGatekeeper.h @@ -76,7 +76,8 @@ private: SharedNodePointer processAgentConnectRequest(const NodeConnectionData& nodeConnection, const QString& username, const QByteArray& usernameSignature); - SharedNodePointer addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection); + SharedNodePointer addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection, + QUuid nodeID = QUuid()); bool verifyUserSignature(const QString& username, const QByteArray& usernameSignature, const HifiSockAddr& senderSockAddr); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 3fab5d3d37..f4ea5aff17 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -192,6 +192,9 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableAvatarCollisions, 0, true, avatar.get(), SLOT(updateMotionBehaviorFromMenu())); + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableFlying, 0, true, + avatar.get(), SLOT(setFlyingEnabled(bool))); + // Avatar > AvatarBookmarks related menus -- Note: the AvatarBookmarks class adds its own submenus here. auto avatarBookmarks = DependencyManager::get(); avatarBookmarks->setupMenus(this, avatarMenu); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index f69860099d..cc8e67c8f7 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -94,6 +94,7 @@ namespace MenuOption { const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene"; const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; + const QString EnableFlying = "Enable Flying"; const QString EnableAvatarCollisions = "Enable Avatar Collisions"; const QString EnableInverseKinematics = "Enable Inverse Kinematics"; const QString EntityScriptServerLog = "Entity Script Server Log"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4a0d753695..e5c4f4b972 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -593,12 +593,12 @@ void MyAvatar::simulate(float deltaTime) { auto entityTreeRenderer = qApp->getEntities(); EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr; if (entityTree) { - bool flyingAllowed = true; + bool zoneAllowsFlying = true; bool collisionlessAllowed = true; entityTree->withWriteLock([&] { std::shared_ptr zone = entityTreeRenderer->myAvatarZone(); if (zone) { - flyingAllowed = zone->getFlyingAllowed(); + zoneAllowsFlying = zone->getFlyingAllowed(); collisionlessAllowed = zone->getGhostingAllowed(); } auto now = usecTimestampNow(); @@ -629,7 +629,7 @@ void MyAvatar::simulate(float deltaTime) { entityTree->recurseTreeWithOperator(&moveOperator); } }); - _characterController.setFlyingAllowed(flyingAllowed); + _characterController.setFlyingAllowed(zoneAllowsFlying && _enableFlying); _characterController.setCollisionlessAllowed(collisionlessAllowed); } @@ -2500,6 +2500,30 @@ void MyAvatar::updateMotionBehaviorFromMenu() { setCollisionsEnabled(menu->isOptionChecked(MenuOption::EnableAvatarCollisions)); } +void MyAvatar::setFlyingEnabled(bool enabled) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setFlyingEnabled", Q_ARG(bool, enabled)); + return; + } + + _enableFlying = enabled; +} + +bool MyAvatar::isFlying() { + // Avatar is Flying, and is not Falling, or Taking off + return _characterController.getState() == CharacterController::State::Hover; +} + +bool MyAvatar::isInAir() { + // If Avatar is Hover, Falling, or Taking off, they are in Air. + return _characterController.getState() != CharacterController::State::Ground; +} + +bool MyAvatar::getFlyingEnabled() { + // May return true even if client is not allowed to fly in the zone. + return _enableFlying; +} + void MyAvatar::setCollisionsEnabled(bool enabled) { if (QThread::currentThread() != thread()) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 473bcb0de2..e2ea745ed0 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -507,6 +507,11 @@ public: bool hasDriveInput() const; + Q_INVOKABLE bool isFlying(); + Q_INVOKABLE bool isInAir(); + Q_INVOKABLE void setFlyingEnabled(bool enabled); + Q_INVOKABLE bool getFlyingEnabled(); + Q_INVOKABLE void setCollisionsEnabled(bool enabled); Q_INVOKABLE bool getCollisionsEnabled(); Q_INVOKABLE void setCharacterControllerEnabled(bool enabled); // deprecated @@ -569,6 +574,7 @@ public slots: void setEnableDebugDrawIKTargets(bool isEnabled); void setEnableDebugDrawIKConstraints(bool isEnabled); void setEnableDebugDrawIKChains(bool isEnabled); + bool getEnableMeshVisible() const { return _skeletonModel->isVisible(); } void setEnableMeshVisible(bool isEnabled); void setUseAnimPreAndPostRotations(bool isEnabled); @@ -641,6 +647,7 @@ private: std::array _driveKeys; std::bitset _disabledDriveKeys; + bool _enableFlying { true }; bool _wasPushing { false }; bool _isPushing { false }; bool _isBeingPushed { false }; @@ -790,7 +797,6 @@ private: ThreadSafeValueCache _rightArmControllerPoseInSensorFrameCache{ controller::Pose() }; bool _hmdLeanRecenterEnabled = true; - AnimPose _prePhysicsRoomPose; std::mutex _holdActionsMutex; std::vector _holdActions; diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index 2a191b5821..1d5b074db7 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -239,10 +239,11 @@ static void FIR_1x4_SSE(float* src, float* dst0, float* dst1, float* dst2, float #include "CPUDetect.h" void FIR_1x4_AVX2(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames); +void FIR_1x4_AVX512(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames); static void FIR_1x4(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames) { - static auto f = cpuSupportsAVX2() ? FIR_1x4_AVX2 : FIR_1x4_SSE; + static auto f = cpuSupportsAVX512() ? FIR_1x4_AVX512 : (cpuSupportsAVX2() ? FIR_1x4_AVX2 : FIR_1x4_SSE); (*f)(src, dst0, dst1, dst2, dst3, coef, numFrames); // dispatch } diff --git a/libraries/audio/src/avx2/AudioFOA_avx2.cpp b/libraries/audio/src/avx2/AudioFOA_avx2.cpp index de5dfcd0b5..880f40b185 100644 --- a/libraries/audio/src/avx2/AudioFOA_avx2.cpp +++ b/libraries/audio/src/avx2/AudioFOA_avx2.cpp @@ -9,15 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) +#ifdef __AVX2__ #include #include -#include // AVX2 - -#ifndef __AVX2__ -#error Must be compiled with /arch:AVX2 or -mavx2 -mfma. -#endif +#include #define _mm256_permute4x64_ps(ymm, imm) _mm256_castpd_ps(_mm256_permute4x64_pd(_mm256_castps_pd(ymm), imm)); diff --git a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp index 452ceb7f4c..e89128b173 100644 --- a/libraries/audio/src/avx2/AudioHRTF_avx2.cpp +++ b/libraries/audio/src/avx2/AudioHRTF_avx2.cpp @@ -9,17 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) +#ifdef __AVX2__ #include -#include // AVX2 +#include #include "../AudioHRTF.h" -#ifndef __AVX2__ -#error Must be compiled with /arch:AVX2 or -mavx2 -mfma. -#endif - #if defined(__GNUC__) && !defined(__clang__) // for some reason, GCC -O2 results in poorly optimized code #pragma GCC optimize("Os") diff --git a/libraries/audio/src/avx2/AudioSRC_avx2.cpp b/libraries/audio/src/avx2/AudioSRC_avx2.cpp index 693bad7fc6..0e31a58ce7 100644 --- a/libraries/audio/src/avx2/AudioSRC_avx2.cpp +++ b/libraries/audio/src/avx2/AudioSRC_avx2.cpp @@ -9,17 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) +#ifdef __AVX2__ #include #include #include "../AudioSRC.h" -#ifndef __AVX2__ -#error Must be compiled with /arch:AVX2 or -mavx2 -mfma. -#endif - // high/low part of int64_t #define LO32(a) ((uint32_t)(a)) #define HI32(a) ((int32_t)((a) >> 32)) diff --git a/libraries/audio/src/avx512/AudioHRTF_avx512.cpp b/libraries/audio/src/avx512/AudioHRTF_avx512.cpp new file mode 100644 index 0000000000..682f5f2f77 --- /dev/null +++ b/libraries/audio/src/avx512/AudioHRTF_avx512.cpp @@ -0,0 +1,101 @@ +// +// AudioHRTF_avx512.cpp +// libraries/audio/src +// +// Created by Ken Cooke on 6/20/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#if defined(__AVX512F__) + +#include +#include + +#include "../AudioHRTF.h" + +#if defined(__GNUC__) && !defined(__clang__) +// for some reason, GCC -O2 results in poorly optimized code +#pragma GCC optimize("Os") +#endif + +// 1 channel input, 4 channel output +void FIR_1x4_AVX512(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames) { + + float* coef0 = coef[0] + HRTF_TAPS - 1; // process backwards + float* coef1 = coef[1] + HRTF_TAPS - 1; + float* coef2 = coef[2] + HRTF_TAPS - 1; + float* coef3 = coef[3] + HRTF_TAPS - 1; + + assert(numFrames % 16 == 0); + + for (int i = 0; i < numFrames; i += 16) { + + __m512 acc0 = _mm512_setzero_ps(); + __m512 acc1 = _mm512_setzero_ps(); + __m512 acc2 = _mm512_setzero_ps(); + __m512 acc3 = _mm512_setzero_ps(); + __m512 acc4 = _mm512_setzero_ps(); + __m512 acc5 = _mm512_setzero_ps(); + __m512 acc6 = _mm512_setzero_ps(); + __m512 acc7 = _mm512_setzero_ps(); + + float* ps = &src[i - HRTF_TAPS + 1]; // process forwards + + assert(HRTF_TAPS % 4 == 0); + + for (int k = 0; k < HRTF_TAPS; k += 4) { + + __m512 x0 = _mm512_loadu_ps(&ps[k+0]); + acc0 = _mm512_fmadd_ps(_mm512_set1_ps(coef0[-k-0]), x0, acc0); // vfmadd231ps acc0, x0, dword ptr [coef]{1to16} + acc1 = _mm512_fmadd_ps(_mm512_set1_ps(coef1[-k-0]), x0, acc1); + acc2 = _mm512_fmadd_ps(_mm512_set1_ps(coef2[-k-0]), x0, acc2); + acc3 = _mm512_fmadd_ps(_mm512_set1_ps(coef3[-k-0]), x0, acc3); + + __m512 x1 = _mm512_loadu_ps(&ps[k+1]); + acc4 = _mm512_fmadd_ps(_mm512_set1_ps(coef0[-k-1]), x1, acc4); + acc5 = _mm512_fmadd_ps(_mm512_set1_ps(coef1[-k-1]), x1, acc5); + acc6 = _mm512_fmadd_ps(_mm512_set1_ps(coef2[-k-1]), x1, acc6); + acc7 = _mm512_fmadd_ps(_mm512_set1_ps(coef3[-k-1]), x1, acc7); + + __m512 x2 = _mm512_loadu_ps(&ps[k+2]); + acc0 = _mm512_fmadd_ps(_mm512_set1_ps(coef0[-k-2]), x2, acc0); + acc1 = _mm512_fmadd_ps(_mm512_set1_ps(coef1[-k-2]), x2, acc1); + acc2 = _mm512_fmadd_ps(_mm512_set1_ps(coef2[-k-2]), x2, acc2); + acc3 = _mm512_fmadd_ps(_mm512_set1_ps(coef3[-k-2]), x2, acc3); + + __m512 x3 = _mm512_loadu_ps(&ps[k+3]); + acc4 = _mm512_fmadd_ps(_mm512_set1_ps(coef0[-k-3]), x3, acc4); + acc5 = _mm512_fmadd_ps(_mm512_set1_ps(coef1[-k-3]), x3, acc5); + acc6 = _mm512_fmadd_ps(_mm512_set1_ps(coef2[-k-3]), x3, acc6); + acc7 = _mm512_fmadd_ps(_mm512_set1_ps(coef3[-k-3]), x3, acc7); + } + + acc0 = _mm512_add_ps(acc0, acc4); + acc1 = _mm512_add_ps(acc1, acc5); + acc2 = _mm512_add_ps(acc2, acc6); + acc3 = _mm512_add_ps(acc3, acc7); + + _mm512_storeu_ps(&dst0[i], acc0); + _mm512_storeu_ps(&dst1[i], acc1); + _mm512_storeu_ps(&dst2[i], acc2); + _mm512_storeu_ps(&dst3[i], acc3); + } + + _mm256_zeroupper(); +} + +// FIXME: this fallback can be removed, once we require VS2017 +#elif defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) + +#include "../AudioHRTF.h" + +void FIR_1x4_AVX2(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames); + +void FIR_1x4_AVX512(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames) { + FIR_1x4_AVX2(src, dst0, dst1, dst2, dst3, coef, numFrames); +} + +#endif diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index eb4a02cb62..4926ca0fdb 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1496,13 +1496,13 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide udt::SequenceNumber incomingSequenceNumber(incomingSequenceNumberType); if (!_hasProcessedFirstIdentity) { - _lastSequenceNumber = incomingSequenceNumber - 1; + _identitySequenceNumber = incomingSequenceNumber - 1; _hasProcessedFirstIdentity = true; qCDebug(avatars) << "Processing first identity packet for" << avatarSessionID << "-" << (udt::SequenceNumber::Type) incomingSequenceNumber; } - if (incomingSequenceNumber > _lastSequenceNumber) { + if (incomingSequenceNumber > _identitySequenceNumber) { Identity identity; packetStream >> identity.skeletonModelURL @@ -1512,7 +1512,7 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide >> identity.avatarEntityData; // set the store identity sequence number to match the incoming identity - _lastSequenceNumber = incomingSequenceNumber; + _identitySequenceNumber = incomingSequenceNumber; if (_firstSkeletonCheck || (identity.skeletonModelURL != cannonicalSkeletonModelURL(emptyURL))) { setSkeletonModelURL(identity.skeletonModelURL); @@ -1555,7 +1555,7 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide } else { qCDebug(avatars) << "Refusing to process identity for" << uuidStringWithoutCurlyBraces(avatarSessionID) << "since" - << (udt::SequenceNumber::Type) _lastSequenceNumber + << (udt::SequenceNumber::Type) _identitySequenceNumber << "is >=" << (udt::SequenceNumber::Type) incomingSequenceNumber; #endif } @@ -1571,7 +1571,7 @@ QByteArray AvatarData::identityByteArray() const { _avatarEntitiesLock.withReadLock([&] { identityStream << getSessionUUID() - << (udt::SequenceNumber::Type) _lastSequenceNumber + << (udt::SequenceNumber::Type) _identitySequenceNumber << urlToSend << _attachmentData << _displayName @@ -1755,7 +1755,7 @@ void AvatarData::sendIdentityPacket() { if (_identityDataChanged) { // if the identity data has changed, push the sequence number forwards - ++_lastSequenceNumber; + ++_identitySequenceNumber; } QByteArray identityData = identityByteArray(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8d09f936b5..de905277d5 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -625,6 +625,8 @@ public: bool getIdentityDataChanged() const { return _identityDataChanged; } // has the identity data changed since the last time sendIdentityPacket() was called void markIdentityDataChanged() { _identityDataChanged = true; } + void pushIdentitySequenceNumber() { ++_identitySequenceNumber; }; + float getDensity() const { return _density; } signals: @@ -781,7 +783,7 @@ protected: float _audioAverageLoudness { 0.0f }; bool _identityDataChanged { false }; - udt::SequenceNumber _lastSequenceNumber { 0 }; + udt::SequenceNumber _identitySequenceNumber { 0 }; bool _hasProcessedFirstIdentity { false }; float _density; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 623832aaa8..704455c981 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -20,6 +20,8 @@ #include +#include + #include "ModelNetworkingLogging.h" #include #include @@ -171,7 +173,9 @@ void GeometryReader::run() { QString urlname = _url.path().toLower(); if (!urlname.isEmpty() && !_url.path().isEmpty() && - (_url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj"))) { + (_url.path().toLower().endsWith(".fbx") || + _url.path().toLower().endsWith(".obj") || + _url.path().toLower().endsWith(".obj.gz"))) { FBXGeometry::Pointer fbxGeometry; if (_url.path().toLower().endsWith(".fbx")) { @@ -181,7 +185,15 @@ void GeometryReader::run() { } } else if (_url.path().toLower().endsWith(".obj")) { fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, _combineParts, _url)); - } else { + } else if (_url.path().toLower().endsWith(".obj.gz")) { + QByteArray uncompressedData; + if (gunzip(_data, uncompressedData)){ + fbxGeometry.reset(OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url)); + } else { + throw QString("failed to decompress .obj.gz" ); + } + + } else { throw QString("unsupported format"); } diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 674e4dbe3b..ed1715219a 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -821,6 +821,7 @@ void NetworkTexture::refresh() { TextureCache::requestCompleted(_self); } + _ktxResourceState = PENDING_INITIAL_LOAD; Resource::refresh(); } diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 9200550ff2..8d63079b79 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -363,6 +363,13 @@ QStringList ScriptEngines::getRunningScripts() { void ScriptEngines::stopAllScripts(bool restart) { QVector toReload; QReadLocker lock(&_scriptEnginesHashLock); + + if (_isReloading) { + return; + } else { + _isReloading = true; + } + for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); it != _scriptEnginesHash.constEnd(); it++) { ScriptEngine *scriptEngine = it.value(); @@ -382,7 +389,7 @@ void ScriptEngines::stopAllScripts(bool restart) { } // wait for engines to stop (ie: providing time for .scriptEnding cleanup handlers to run) before // triggering reload of any Client scripts / Entity scripts - QTimer::singleShot(500, this, [=]() { + QTimer::singleShot(1000, this, [=]() { for(const auto &scriptName : toReload) { auto scriptEngine = getScriptEngine(scriptName); if (scriptEngine && !scriptEngine->isFinished()) { @@ -397,6 +404,7 @@ void ScriptEngines::stopAllScripts(bool restart) { qCDebug(scriptengine) << "stopAllScripts -- emitting scriptsReloading"; emit scriptsReloading(); } + _isReloading = false; }); } diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index fbd5f370cf..70634345eb 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -114,6 +114,7 @@ protected: ScriptsModel _scriptsModel; ScriptsModelFilter _scriptsModelFilter; std::atomic _isStopped { false }; + std::atomic _isReloading { false }; bool _defaultScriptsLocationOverridden { false }; }; diff --git a/libraries/shared/src/CPUDetect.h b/libraries/shared/src/CPUDetect.h index ea6d23d8d6..a2320dcdc1 100644 --- a/libraries/shared/src/CPUDetect.h +++ b/libraries/shared/src/CPUDetect.h @@ -2,8 +2,8 @@ // CPUDetect.h // libraries/shared/src // -// Created by Ken Cooke on 6/6/16. -// Copyright 2016 High Fidelity, Inc. +// Created by Ken Cooke on 6/16/17. +// Copyright 2017 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -13,28 +13,68 @@ #define hifi_CPUDetect_h // -// Lightweight functions to detect SSE/AVX/AVX2 support +// Lightweight functions to detect SSE/AVX/AVX2/AVX512 support // +#define MASK_SSE3 (1 << 0) // SSE3 +#define MASK_SSSE3 (1 << 9) // SSSE3 +#define MASK_SSE41 (1 << 19) // SSE4.1 +#define MASK_SSE42 ((1 << 20) | (1 << 23)) // SSE4.2 and POPCNT +#define MASK_OSXSAVE (1 << 27) // OSXSAVE +#define MASK_AVX ((1 << 27) | (1 << 28)) // OSXSAVE and AVX +#define MASK_AVX2 (1 << 5) // AVX2 + +#define MASK_AVX512 ((1 << 16) | (1 << 17) | (1 << 28) | (1 << 30) | (1 << 31)) // AVX512 F,DQ,CD,BW,VL (SKX) + +#define MASK_XCR0_YMM ((1 << 1) | (1 << 2)) // XMM,YMM +#define MASK_XCR0_ZMM ((1 << 1) | (1 << 2) | (7 << 5)) // XMM,YMM,ZMM + #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) #define ARCH_X86 #endif -#define MASK_SSE3 (1 << 0) // SSE3 -#define MASK_SSSE3 (1 << 9) // SSSE3 -#define MASK_SSE41 (1 << 19) // SSE4.1 -#define MASK_SSE42 ((1 << 20) | (1 << 23)) // SSE4.2 and POPCNT -#define MASK_AVX ((1 << 27) | (1 << 28)) // OSXSAVE and AVX -#define MASK_AVX2 (1 << 5) // AVX2 - #if defined(ARCH_X86) && defined(_MSC_VER) #include +// use MSVC intrinsics +#define cpuidex(info, eax, ecx) __cpuidex(info, eax, ecx) +#define xgetbv(ecx) _xgetbv(ecx) + +#elif defined(ARCH_X86) && defined(__GNUC__) + +#include + +// use GCC intrinics/asm +static inline void cpuidex(int info[4], int eax, int ecx) { + __cpuid_count(eax, ecx, info[0], info[1], info[2], info[3]); +} + +static inline unsigned long long xgetbv(unsigned int ecx){ + unsigned int eax, edx; + __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(ecx)); + return ((unsigned long long)edx << 32) | eax; +} + +#else + +static inline void cpuidex(int info[4], int eax, int ecx) { + info[0] = 0; + info[1] = 0; + info[2] = 0; + info[3] = 0; +} + +static inline unsigned long long xgetbv(unsigned int ecx){ + return 0ULL; +} + +#endif + static inline bool cpuSupportsSSE3() { int info[4]; - __cpuidex(info, 0x1, 0); + cpuidex(info, 0x1, 0); return ((info[2] & MASK_SSE3) == MASK_SSE3); } @@ -42,7 +82,7 @@ static inline bool cpuSupportsSSE3() { static inline bool cpuSupportsSSSE3() { int info[4]; - __cpuidex(info, 0x1, 0); + cpuidex(info, 0x1, 0); return ((info[2] & MASK_SSSE3) == MASK_SSSE3); } @@ -50,7 +90,7 @@ static inline bool cpuSupportsSSSE3() { static inline bool cpuSupportsSSE41() { int info[4]; - __cpuidex(info, 0x1, 0); + cpuidex(info, 0x1, 0); return ((info[2] & MASK_SSE41) == MASK_SSE41); } @@ -58,7 +98,7 @@ static inline bool cpuSupportsSSE41() { static inline bool cpuSupportsSSE42() { int info[4]; - __cpuidex(info, 0x1, 0); + cpuidex(info, 0x1, 0); return ((info[2] & MASK_SSE42) == MASK_SSE42); } @@ -66,13 +106,13 @@ static inline bool cpuSupportsSSE42() { static inline bool cpuSupportsAVX() { int info[4]; - __cpuidex(info, 0x1, 0); + cpuidex(info, 0x1, 0); bool result = false; if ((info[2] & MASK_AVX) == MASK_AVX) { // verify OS support for YMM state - if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) { + if ((xgetbv(0) & MASK_XCR0_YMM) == MASK_XCR0_YMM) { result = true; } } @@ -85,7 +125,7 @@ static inline bool cpuSupportsAVX2() { bool result = false; if (cpuSupportsAVX()) { - __cpuidex(info, 0x7, 0); + cpuidex(info, 0x7, 0); if ((info[1] & MASK_AVX2) == MASK_AVX2) { result = true; @@ -94,62 +134,20 @@ static inline bool cpuSupportsAVX2() { return result; } -#elif defined(ARCH_X86) && defined(__GNUC__) +static inline bool cpuSupportsAVX512() { + int info[4]; -#include - -static inline bool cpuSupportsSSE3() { - unsigned int eax, ebx, ecx, edx; - - return __get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & MASK_SSE3) == MASK_SSE3); -} - -static inline bool cpuSupportsSSSE3() { - unsigned int eax, ebx, ecx, edx; - - return __get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & MASK_SSSE3) == MASK_SSSE3); -} - -static inline bool cpuSupportsSSE41() { - unsigned int eax, ebx, ecx, edx; - - return __get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & MASK_SSE41) == MASK_SSE41); -} - -static inline bool cpuSupportsSSE42() { - unsigned int eax, ebx, ecx, edx; - - return __get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & MASK_SSE42) == MASK_SSE42); -} - -static inline bool cpuSupportsAVX() { - unsigned int eax, ebx, ecx, edx; + cpuidex(info, 0x1, 0); bool result = false; - if (__get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & MASK_AVX) == MASK_AVX)) { + if ((info[2] & MASK_OSXSAVE) == MASK_OSXSAVE) { - // verify OS support for YMM state - __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0)); - if ((eax & 0x6) == 0x6) { - result = true; - } - } - return result; -} + // verify OS support for ZMM state + if ((xgetbv(0) & MASK_XCR0_ZMM) == MASK_XCR0_ZMM) { -static inline bool cpuSupportsAVX2() { - unsigned int eax, ebx, ecx, edx; + cpuidex(info, 0x7, 0); - bool result = false; - if (cpuSupportsAVX()) { - - // Work around a bug where __get_cpuid(0x7) returns wrong values on older GCC - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77756 - if (__get_cpuid(0x0, &eax, &ebx, &ecx, &edx) && (eax >= 0x7)) { - - __cpuid_count(0x7, 0x0, eax, ebx, ecx, edx); - - if ((ebx & MASK_AVX2) == MASK_AVX2) { + if ((info[1] & MASK_AVX512) == MASK_AVX512) { result = true; } } @@ -157,32 +155,4 @@ static inline bool cpuSupportsAVX2() { return result; } -#else - -static inline bool cpuSupportsSSE3() { - return false; -} - -static inline bool cpuSupportsSSSE3() { - return false; -} - -static inline bool cpuSupportsSSE41() { - return false; -} - -static inline bool cpuSupportsSSE42() { - return false; -} - -static inline bool cpuSupportsAVX() { - return false; -} - -static inline bool cpuSupportsAVX2() { - return false; -} - -#endif - #endif // hifi_CPUDetect_h diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index b045e64c6a..6321c17ded 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -41,7 +41,16 @@ var numStillSnapshotUploadsPending = 0; // It's totally unnecessary to return to C++ to perform many of these requests, such as DELETEing an old story, // POSTING a new one, PUTTING a new audience, or GETTING story data. It's far more efficient to do all of that within JS -var request = Script.require('request').request; +var request; + +try { + // Due to an issue where if the user spams 'script reload', this call could cause an exception + // preventing our scriptEnding to not properly be initialized resulting in the tablet button + // duplicating itself where you end up with a bunch of SNAP buttons on your toolbar + request = Script.require('request').request; +} catch(err) { + print('Failed to resolve request api, error: ' + err); +} function openLoginWindow() { if ((HMD.active && Settings.getValue("hmdTabletBecomesToolbar", false)) @@ -750,11 +759,10 @@ Script.scriptEnding.connect(function () { } if (tablet) { tablet.removeButton(button); + tablet.screenChanged.disconnect(onTabletScreenChanged); } Window.snapshotShared.disconnect(snapshotUploaded); - tablet.screenChanged.disconnect(onTabletScreenChanged); Snapshot.snapshotLocationSet.disconnect(snapshotLocationSet); - Entities.canRezChanged.disconnect(processRezPermissionChange); Entities.canRezTmpChanged.disconnect(processRezPermissionChange); }); diff --git a/tools/oven/CMakeLists.txt b/tools/oven/CMakeLists.txt index 24c8a9a0e2..f4fca3304c 100644 --- a/tools/oven/CMakeLists.txt +++ b/tools/oven/CMakeLists.txt @@ -4,15 +4,28 @@ setup_hifi_project(Widgets Gui Concurrent) link_hifi_libraries(networking shared image gpu ktx) +setup_memory_debugger() + if (WIN32) package_libraries_for_deployment() endif () +if (UNIX) + find_package(Threads REQUIRED) + if(THREADS_HAVE_PTHREAD_ARG) + target_compile_options(PUBLIC oven "-pthread") + endif() +endif () + # try to find the FBX SDK but fail silently if we don't # because this tool is not built by default find_package(FBX) if (FBX_FOUND) - target_link_libraries(${TARGET_NAME} ${FBX_LIBRARIES}) + if (CMAKE_THREAD_LIBS_INIT) + target_link_libraries(${TARGET_NAME} ${FBX_LIBRARIES} "${CMAKE_THREAD_LIBS_INIT}") + else () + target_link_libraries(${TARGET_NAME} ${FBX_LIBRARIES}) + endif () target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${FBX_INCLUDE_DIR}) endif () diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp index a38aaa2b97..dc763cc82d 100644 --- a/tools/oven/src/Oven.cpp +++ b/tools/oven/src/Oven.cpp @@ -18,7 +18,7 @@ #include "ui/OvenMainWindow.h" #include "Oven.h" -#include "BakerCli.h" +#include "BakerCLI.h" static const QString OUTPUT_FOLDER = "/Users/birarda/code/hifi/lod/test-oven/export"; diff --git a/unpublishedScripts/marketplace/shortbow/enemyClientEntity.js b/unpublishedScripts/marketplace/shortbow/enemyClientEntity.js index 3abdaa46fb..1ff114012c 100644 --- a/unpublishedScripts/marketplace/shortbow/enemyClientEntity.js +++ b/unpublishedScripts/marketplace/shortbow/enemyClientEntity.js @@ -11,6 +11,8 @@ (function() { Script.include('utils.js'); + var BOOF_SOUND = SoundCache.getSound(Script.resolvePath("sounds/boof.wav")); + function Enemy() { } Enemy.prototype = { @@ -38,13 +40,93 @@ this.entityIDsThatHaveCollidedWithMe.push(entityB); var colliderName = Entities.getEntityProperties(entityB, 'name').name; - if (colliderName.indexOf("projectile") > -1) { + var smokeImage = { + "alpha": 0.89999997615814209, + "alphaFinish": 0.89999997615814209, + "alphaStart": 0.89999997615814209, + "azimuthFinish": 0.40000000596046448, + "clientOnly": 0, + "color": { + "blue": 57, + "green": 254, + "red": 255 + }, + "colorFinish": { + "blue": 57, + "green": 254, + "red": 255 + }, + "colorSpread": { + "blue": 130, + "green": 130, + "red": 130 + }, + "colorStart": { + "blue": 57, + "green": 254, + "red": 255 + }, + "created": "2017-01-10T19:17:07Z", + "dimensions": { + "x": 1.7600001096725464, + "y": 1.7600001096725464, + "z": 1.7600001096725464 + }, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "emitOrientation": { + "w": 0.7070610523223877, + "x": -0.70715254545211792, + "y": -1.5258869098033756e-05, + "z": -1.5258869098033756e-05 + }, + "emitRate": 25.200000762939453, + "emitSpeed": 0, + "id": "{0273087c-a676-4ac2-93ff-f2440517dfb7}", + "lastEdited": 1485295831550663, + "lastEditedBy": "{dfe734a0-8289-47f6-a1a6-cf3f6d57adac}", + "lifespan": 0.5, + "lifetime": 0.5, + "locked": 1, + "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", + "particleRadius": 0.30099999904632568, + "polarFinish": 3, + "position": Entities.getEntityProperties(entityA, 'position').position, + "queryAACube": { + "scale": 3.0484094619750977, + "x": -1.5242047309875488, + "y": -1.5242047309875488, + "z": -1.5242047309875488 + }, + "radiusFinish": 0.30099999904632568, + "radiusStart": 0.30099999904632568, + "rotation": { + "w": 0.086696967482566833, + "x": -0.53287714719772339, + "y": 0.80860012769699097, + "z": -0.23394235968589783 + }, + "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + "type": "ParticleEffect" + }; + + Audio.playSound(BOOF_SOUND, { + volume: 1.0, + position: Entities.getEntityProperties(entityA, 'position').position + }); + + Entities.addEntity(smokeImage); + Messages.sendMessage(this.gameChannel, JSON.stringify({ type: "enemy-killed", entityID: this.entityID, position: Entities.getEntityProperties(this.entityID, 'position').position })); + Entities.deleteEntity(this.entityID); } else if (colliderName.indexOf("GateCollider") > -1) { Messages.sendMessage(this.gameChannel, JSON.stringify({ diff --git a/unpublishedScripts/marketplace/shortbow/shortbowGameManager.js b/unpublishedScripts/marketplace/shortbow/shortbowGameManager.js index 9f0d8c93f3..e33200721e 100644 --- a/unpublishedScripts/marketplace/shortbow/shortbowGameManager.js +++ b/unpublishedScripts/marketplace/shortbow/shortbowGameManager.js @@ -336,6 +336,13 @@ ShortbowGameManager.prototype = { volume: 1.0, position: this.rootPosition }); + + var liveChecker = setInterval(function() { + if (this.livesLeft <= 0) { + this.endGame(); + clearInterval(liveChecker); + } + }, 1000); }, startNextWave: function() { if (this.gameState !== GAME_STATES.BETWEEN_WAVES) { @@ -464,6 +471,7 @@ ShortbowGameManager.prototype = { print("EXPIRING: ", enemy.id); Entities.deleteEntity(enemy.id); this.remainingEnemies.splice(i, 1); + // Play the sound when you hit an enemy Audio.playSound(TARGET_HIT_SOUND, { volume: 1.0, position: this.rootPosition @@ -561,10 +569,10 @@ ShortbowGameManager.prototype = { } }, onEnemyKilled: function(entityID, position) { - if (this.gameState !== GAME_STATES.PLAYING) { + if (this.gameState !== GAME_STATES.PLAYING) { return; } - + for (var i = this.remainingEnemies.length - 1; i >= 0; --i) { var enemy = this.remainingEnemies[i]; if (enemy.id === entityID) { @@ -573,7 +581,6 @@ ShortbowGameManager.prototype = { volume: 1.0, position: this.rootPosition }); - // Update score this.setScore(this.score + POINTS_PER_KILL); print("SCORE: ", this.score); @@ -592,6 +599,7 @@ ShortbowGameManager.prototype = { for (var i = this.remainingEnemies.length - 1; i >= 0; --i) { var enemy = this.remainingEnemies[i]; if (enemy.id === entityID) { + Entities.deleteEntity(enemy.id); this.remainingEnemies.splice(i, 1); this.setLivesLeft(this.livesLeft - 1); diff --git a/unpublishedScripts/marketplace/shortbow/sounds/boof.wav b/unpublishedScripts/marketplace/shortbow/sounds/boof.wav new file mode 100644 index 0000000000..8f404546f5 Binary files /dev/null and b/unpublishedScripts/marketplace/shortbow/sounds/boof.wav differ