Merge branch 'master' into 21396

This commit is contained in:
David Rowe 2017-06-23 16:52:04 +12:00
commit 9d0407cbdf
49 changed files with 823 additions and 256 deletions

View file

@ -103,11 +103,6 @@ AudioMixer::AudioMixer(ReceivedMessage& message) :
);
connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled);
connect(nodeList.data(), &NodeList::nodeAdded, this, [this](const SharedNodePointer& node) {
if (node->getType() == NodeType::DownstreamAudioMixer) {
node->activatePublicSocket();
}
});
}
void AudioMixer::queueAudioPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer node) {
@ -389,7 +384,10 @@ void AudioMixer::start() {
auto nodeList = DependencyManager::get<NodeList>();
// prepare the NodeList
nodeList->addSetOfNodeTypesToNodeInterestSet({ NodeType::Agent, NodeType::DownstreamAudioMixer, NodeType::EntityScriptServer });
nodeList->addSetOfNodeTypesToNodeInterestSet({
NodeType::Agent, NodeType::EntityScriptServer,
NodeType::UpstreamAudioMixer, NodeType::DownstreamAudioMixer
});
nodeList->linkedDataCreateCallback = [&](Node* node) { getOrCreateClientData(node); };
// parse out any AudioMixer settings

View file

@ -51,6 +51,11 @@ public:
static const QVector<ReverbSettings>& getReverbSettings() { return _zoneReverbSettings; }
static const std::pair<QString, CodecPluginPointer> negotiateCodec(std::vector<QString> codecs);
static bool shouldReplicateTo(const Node& from, const Node& to) {
return to.getType() == NodeType::DownstreamAudioMixer &&
to.getPublicSocket() != from.getPublicSocket() &&
to.getLocalSocket() != from.getLocalSocket();
}
public slots:
void run() override;
void sendStatsPacket() override;

View file

@ -67,24 +67,25 @@ void AudioMixerClientData::processPackets() {
case PacketType::MicrophoneAudioNoEcho:
case PacketType::MicrophoneAudioWithEcho:
case PacketType::InjectAudio:
case PacketType::AudioStreamStats:
case PacketType::SilentAudioFrame:
case PacketType::ReplicatedMicrophoneAudioNoEcho:
case PacketType::ReplicatedMicrophoneAudioWithEcho:
case PacketType::ReplicatedInjectAudio:
case PacketType::ReplicatedSilentAudioFrame: {
case PacketType::SilentAudioFrame: {
if (node->isUpstream() && !_hasSetupCodecForUpstreamNode) {
if (node->isUpstream()) {
setupCodecForReplicatedAgent(packet);
}
QMutexLocker lock(&getMutex());
parseData(*packet);
optionallyReplicatePacket(*packet, *node);
break;
}
case PacketType::AudioStreamStats: {
QMutexLocker lock(&getMutex());
parseData(*packet);
break;
}
case PacketType::NegotiateAudioFormat:
negotiateAudioFormat(*packet, node);
break;
@ -141,7 +142,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c
// enumerate the downstream audio mixers and send them the replicated version of this packet
nodeList->unsafeEachNode([&](const SharedNodePointer& downstreamNode) {
if (downstreamNode->getType() == NodeType::DownstreamAudioMixer) {
if (AudioMixer::shouldReplicateTo(node, *downstreamNode)) {
// construct the packet only once, if we have any downstream audio mixers to send to
if (!packet) {
// construct an NLPacket to send to the replicant that has the contents of the received packet
@ -687,14 +688,14 @@ void AudioMixerClientData::setupCodecForReplicatedAgent(QSharedPointer<ReceivedM
// pull the codec string from the packet
auto codecString = message->readString();
qDebug() << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID())
if (codecString != _selectedCodecName) {
qDebug() << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID())
<< "-" << codecString;
const std::pair<QString, CodecPluginPointer> codec = AudioMixer::negotiateCodec({ codecString });
setupCodec(codec.second, codec.first);
const std::pair<QString, CodecPluginPointer> codec = AudioMixer::negotiateCodec({ codecString });
setupCodec(codec.second, codec.first);
_hasSetupCodecForUpstreamNode = true;
// seek back to the beginning of the message so other readers are in the right place
message->seek(0);
// seek back to the beginning of the message so other readers are in the right place
message->seek(0);
}
}

View file

@ -184,8 +184,6 @@ private:
bool _shouldMuteClient { false };
bool _requestsDomainListData { false };
bool _hasSetupCodecForUpstreamNode { false };
};
#endif // hifi_AudioMixerClientData_h

View file

@ -66,7 +66,6 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) :
connect(nodeList.data(), &NodeList::nodeAdded, this, [this](const SharedNodePointer& node) {
if (node->getType() == NodeType::DownstreamAvatarMixer) {
getOrCreateClientData(node);
node->activatePublicSocket();
}
});
}
@ -144,8 +143,8 @@ void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node
std::unique_ptr<NLPacket> packet;
auto nodeList = DependencyManager::get<NodeList>();
nodeList->eachMatchingNode([&](const SharedNodePointer& node) {
return node->getType() == NodeType::DownstreamAvatarMixer;
nodeList->eachMatchingNode([&](const SharedNodePointer& downstreamNode) {
return shouldReplicateTo(node, *downstreamNode);
}, [&](const SharedNodePointer& node) {
if (!packet) {
// construct an NLPacket to send to the replicant that has the contents of the received packet
@ -165,10 +164,6 @@ void AvatarMixer::queueIncomingPacket(QSharedPointer<ReceivedMessage> message, S
_queueIncomingPacketElapsedTime += (end - start);
}
AvatarMixer::~AvatarMixer() {
}
void AvatarMixer::sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
if (destinationNode->getType() == NodeType::Agent && !destinationNode->isUpstream()) {
QByteArray individualData = nodeData->getAvatar().identityByteArray();
@ -331,7 +326,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);
}
}
@ -423,8 +424,8 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
nodeList->eachMatchingNode([&](const SharedNodePointer& node) {
// we relay avatar kill packets to agents that are not upstream
// and downstream avatar mixers, if the node that was just killed was being replicated
return (node->getType() == NodeType::Agent && !node->isUpstream())
|| (killedNode->isReplicated() && node->getType() == NodeType::DownstreamAvatarMixer);
return (node->getType() == NodeType::Agent && !node->isUpstream()) ||
(killedNode->isReplicated() && shouldReplicateTo(*killedNode, *node));
}, [&](const SharedNodePointer& node) {
if (node->getType() == NodeType::Agent) {
if (!killPacket) {
@ -856,7 +857,10 @@ AvatarMixerClientData* AvatarMixer::getOrCreateClientData(SharedNodePointer node
void AvatarMixer::domainSettingsRequestComplete() {
auto nodeList = DependencyManager::get<NodeList>();
nodeList->addSetOfNodeTypesToNodeInterestSet({ NodeType::Agent, NodeType::DownstreamAvatarMixer, NodeType::EntityScriptServer });
nodeList->addSetOfNodeTypesToNodeInterestSet({
NodeType::Agent, NodeType::EntityScriptServer,
NodeType::UpstreamAvatarMixer, NodeType::DownstreamAvatarMixer
});
// parse the settings to pull out the values we need
parseDomainServerSettings(nodeList->getDomainHandler().getSettingsObject());

View file

@ -28,7 +28,13 @@ class AvatarMixer : public ThreadedAssignment {
Q_OBJECT
public:
AvatarMixer(ReceivedMessage& message);
~AvatarMixer();
static bool shouldReplicateTo(const Node& from, const Node& to) {
return to.getType() == NodeType::DownstreamAvatarMixer &&
to.getPublicSocket() != from.getPublicSocket() &&
to.getLocalSocket() != from.getLocalSocket();
}
public slots:
/// runs the avatar mixer
void run() override;

View file

@ -79,13 +79,13 @@ int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData,
}
}
int AvatarMixerSlave::sendReplicatedIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
if (destinationNode->getType() == NodeType::DownstreamAvatarMixer) {
int AvatarMixerSlave::sendReplicatedIdentityPacket(const Node& agentNode, const AvatarMixerClientData* nodeData, const Node& destinationNode) {
if (AvatarMixer::shouldReplicateTo(agentNode, destinationNode)) {
QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray();
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious
auto identityPacket = NLPacket::create(PacketType::ReplicatedAvatarIdentity);
auto identityPacket = NLPacketList::create(PacketType::ReplicatedAvatarIdentity, QByteArray(), true, true);
identityPacket->write(individualData);
DependencyManager::get<NodeList>()->sendUnreliablePacket(*identityPacket, *destinationNode);
DependencyManager::get<NodeList>()->sendPacketList(std::move(identityPacket), destinationNode);
_stats.numIdentityPackets++;
return individualData.size();
} else {
@ -453,6 +453,10 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin
nodeData->resetNumAvatarsSentLastFrame();
std::for_each(_begin, _end, [&](const SharedNodePointer& agentNode) {
if (!AvatarMixer::shouldReplicateTo(*agentNode, *node)) {
return;
}
// collect agents that we have avatar data for that we are supposed to replicate
if (agentNode->getType() == NodeType::Agent && agentNode->getLinkedData() && agentNode->isReplicated()) {
const AvatarMixerClientData* agentNodeData = reinterpret_cast<const AvatarMixerClientData*>(agentNode->getLinkedData());
@ -479,7 +483,7 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin
auto lastBroadcastTime = nodeData->getLastBroadcastTime(agentNode->getUUID());
if (lastBroadcastTime <= agentNodeData->getIdentityChangeTimestamp()
|| (start - lastBroadcastTime) >= REBROADCAST_IDENTITY_TO_DOWNSTREAM_EVERY_US) {
sendReplicatedIdentityPacket(agentNodeData, node);
sendReplicatedIdentityPacket(*agentNode, agentNodeData, *node);
nodeData->setLastBroadcastTime(agentNode->getUUID(), start);
}

View file

@ -95,7 +95,7 @@ public:
private:
int sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode);
int sendReplicatedIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode);
int sendReplicatedIdentityPacket(const Node& agentNode, const AvatarMixerClientData* nodeData, const Node& destinationNode);
void broadcastAvatarDataToAgent(const SharedNodePointer& node);
void broadcastAvatarDataToDownstreamMixer(const SharedNodePointer& node);

View file

@ -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

View file

@ -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)

View file

@ -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
@ -432,6 +504,10 @@ Function PostInstallOptionsPage
; set the checkbox state depending on what is present in the registry
!insertmacro SetPostInstallOption $LaunchServerNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED}
${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE
${IfNot} $substringResult == ""
${NSD_SetState} $LaunchServerNowCheckbox ${BST_UNCHECKED}
${EndIf}
IntOp $CurrentOffset $CurrentOffset + 15
${EndIf}
@ -442,6 +518,10 @@ Function PostInstallOptionsPage
; set the checkbox state depending on what is present in the registry
!insertmacro SetPostInstallOption $LaunchClientNowCheckbox @CLIENT_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED}
${StrContains} $substringResult "/forceNoLaunchClient" $CMDLINE
${IfNot} $substringResult == ""
${NSD_SetState} $LaunchClientNowCheckbox ${BST_UNCHECKED}
${EndIf}
${EndIf}
${If} @PR_BUILD@ == 1

View file

@ -1339,6 +1339,7 @@
{
"name": "broadcasting",
"label": "Broadcasting",
"restart": false,
"settings": [
{
"name": "users",
@ -1395,6 +1396,46 @@
]
}
]
},
{
"name": "upstream_servers",
"label": "Broadcasting Servers",
"assignment-types": [0,1],
"type": "table",
"advanced": true,
"can_add_new_rows": true,
"help": "Servers that broadcast data to this domain",
"numbered": false,
"columns": [
{
"name": "address",
"label": "Address",
"can_set": true
},
{
"name": "port",
"label": "Port",
"can_set": true
},
{
"name": "server_type",
"label": "Server Type",
"type": "select",
"placeholder": "Audio Mixer",
"default": "Audio Mixer",
"can_set": true,
"options": [
{
"value": "Audio Mixer",
"label": "Audio Mixer"
},
{
"value": "Avatar Mixer",
"label": "Avatar Mixer"
}
]
}
]
}
]
}

View file

@ -10,6 +10,7 @@
<link href="/css/sweetalert.css" rel="stylesheet" media="screen">
<link href="/css/bootstrap-switch.min.css" rel="stylesheet" media="screen">
<script src='/js/sweetalert.min.js'></script>
</head>
<body>
<nav class="navbar navbar-default" role="navigation">
@ -37,6 +38,8 @@
</li>
<li><a href="/content/">Content</a></li>
<li><a href="/settings/">Settings</a></li>
</ul>
<ul class="nav navbar-right navbar-nav">
<li><a href="#" id="restart-server"><span class="glyphicon glyphicon-refresh"></span> Restart</a></li>
</ul>
</div>

View file

@ -33,9 +33,17 @@ $(document).ready(function(){
return this.href == url;
}).parent().addClass('active');
$('body').on('click', '#restart-server', function(e){
$.get("/restart");
showRestartModal();
$('body').on('click', '#restart-server', function(e) {
swal( {
title: "Are you sure?",
text: "This will restart your domain server, causing your domain to be briefly offline.",
type: "warning",
html: true,
showCancelButton: true
}, function() {
$.get("/restart");
showRestartModal();
});
return false;
});
});

View file

@ -86,7 +86,6 @@
<script src='/js/underscore-keypath.min.js'></script>
<script src='/js/bootbox.min.js'></script>
<script src='js/bootstrap-switch.min.js'></script>
<script src='/js/sweetalert.min.js'></script>
<script src='js/settings.js'></script>
<script src='js/form2js.min.js'></script>
<script src='js/sha256.js'></script>

View file

@ -424,7 +424,11 @@ function postSettings(jsonSettings) {
type: 'POST'
}).done(function(data){
if (data.status == "success") {
showRestartModal();
if ($(".save-button").html() === SAVE_BUTTON_LABEL_RESTART) {
showRestartModal();
} else {
location.reload(true);
}
} else {
showErrorMessage("Error", SETTINGS_ERROR_MESSAGE)
reloadSettings();

View file

@ -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<DomainServerNodeData*>(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<LimitedNodeList>();

View file

@ -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);

View file

@ -87,7 +87,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
qDebug() << "[VERSION] VERSION:" << BuildInfo::VERSION;
qDebug() << "[VERSION] BUILD_BRANCH:" << BuildInfo::BUILD_BRANCH;
qDebug() << "[VERSION] BUILD_GLOBAL_SERVICES:" << BuildInfo::BUILD_GLOBAL_SERVICES;
qDebug() << "[VERSION] We will be using this default ICE server:" << ICE_SERVER_DEFAULT_HOSTNAME;
qDebug() << "[VERSION] We will be using this name to find ICE servers:" << _iceServerAddr;
// make sure we have a fresh AccountManager instance
@ -121,6 +121,8 @@ DomainServer::DomainServer(int argc, char* argv[]) :
this, &DomainServer::updateReplicatedNodes);
connect(&_settingsManager, &DomainServerSettingsManager::settingsUpdated,
this, &DomainServer::updateDownstreamNodes);
connect(&_settingsManager, &DomainServerSettingsManager::settingsUpdated,
this, &DomainServer::updateUpstreamNodes);
setupGroupCacheRefresh();
@ -135,6 +137,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
updateReplicatedNodes();
updateDownstreamNodes();
updateUpstreamNodes();
if (_type != NonMetaverse) {
// if we have a metaverse domain, we'll use an access token for API calls
@ -1549,7 +1552,7 @@ void DomainServer::sendHeartbeatToIceServer() {
} else {
qDebug() << "Not sending ice-server heartbeat since there is no selected ice-server.";
qDebug() << "Waiting for" << ICE_SERVER_DEFAULT_HOSTNAME << "host lookup response";
qDebug() << "Waiting for" << _iceServerAddr << "host lookup response";
}
}
@ -2229,53 +2232,84 @@ void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer&
static const QString BROADCASTING_SETTINGS_KEY = "broadcasting";
void DomainServer::updateDownstreamNodes() {
struct ReplicationServerInfo {
NodeType_t nodeType;
HifiSockAddr sockAddr;
};
ReplicationServerInfo serverInformationFromSettings(QVariantMap serverMap, ReplicationServerDirection direction) {
static const QString REPLICATION_SERVER_ADDRESS = "address";
static const QString REPLICATION_SERVER_PORT = "port";
static const QString REPLICATION_SERVER_TYPE = "server_type";
if (serverMap.contains(REPLICATION_SERVER_ADDRESS) && serverMap.contains(REPLICATION_SERVER_PORT)
&& serverMap.contains(REPLICATION_SERVER_TYPE)) {
auto nodeType = NodeType::fromString(serverMap[REPLICATION_SERVER_TYPE].toString());
ReplicationServerInfo serverInfo;
if (direction == Upstream) {
serverInfo.nodeType = NodeType::upstreamType(nodeType);
} else if (direction == Downstream) {
serverInfo.nodeType = NodeType::downstreamType(nodeType);
}
// read the address and port and construct a HifiSockAddr from them
serverInfo.sockAddr = {
serverMap[REPLICATION_SERVER_ADDRESS].toString(),
(quint16) serverMap[REPLICATION_SERVER_PORT].toString().toInt()
};
return serverInfo;
}
return { NodeType::Unassigned, HifiSockAddr() };
}
void DomainServer::updateReplicationNodes(ReplicationServerDirection direction) {
auto settings = _settingsManager.getSettingsMap();
if (settings.contains(BROADCASTING_SETTINGS_KEY)) {
auto nodeList = DependencyManager::get<LimitedNodeList>();
std::vector<HifiSockAddr> downstreamNodesInSettings;
auto replicationSettings = settings.value(BROADCASTING_SETTINGS_KEY).toMap();
if (replicationSettings.contains("downstream_servers")) {
auto serversSettings = replicationSettings.value("downstream_servers").toList();
std::vector<HifiSockAddr> replicationNodesInSettings;
std::vector<HifiSockAddr> knownDownstreamNodes;
auto replicationSettings = settings.value(BROADCASTING_SETTINGS_KEY).toMap();
QString serversKey = direction == Upstream ? "upstream_servers" : "downstream_servers";
QString replicationDirection = direction == Upstream ? "upstream" : "downstream";
if (replicationSettings.contains(serversKey)) {
auto serversSettings = replicationSettings.value(serversKey).toList();
std::vector<HifiSockAddr> knownReplicationNodes;
nodeList->eachNode([&](const SharedNodePointer& otherNode) {
if (NodeType::isDownstream(otherNode->getType())) {
knownDownstreamNodes.push_back(otherNode->getPublicSocket());
if ((direction == Upstream && NodeType::isUpstream(otherNode->getType()))
|| (direction == Downstream && NodeType::isDownstream(otherNode->getType()))) {
knownReplicationNodes.push_back(otherNode->getPublicSocket());
}
});
for (auto& server : serversSettings) {
auto downstreamServer = server.toMap();
auto replicationServer = serverInformationFromSettings(server.toMap(), direction);
static const QString DOWNSTREAM_SERVER_ADDRESS = "address";
static const QString DOWNSTREAM_SERVER_PORT = "port";
static const QString DOWNSTREAM_SERVER_TYPE = "server_type";
if (!replicationServer.sockAddr.isNull() && replicationServer.nodeType != NodeType::Unassigned) {
// make sure we have the settings we need for this replication server
replicationNodesInSettings.push_back(replicationServer.sockAddr);
// make sure we have the settings we need for this downstream server
if (downstreamServer.contains(DOWNSTREAM_SERVER_ADDRESS) && downstreamServer.contains(DOWNSTREAM_SERVER_PORT)) {
auto nodeType = NodeType::fromString(downstreamServer[DOWNSTREAM_SERVER_TYPE].toString());
auto downstreamNodeType = NodeType::downstreamType(nodeType);
// read the address and port and construct a HifiSockAddr from them
HifiSockAddr downstreamServerAddr {
downstreamServer[DOWNSTREAM_SERVER_ADDRESS].toString(),
(quint16) downstreamServer[DOWNSTREAM_SERVER_PORT].toString().toInt()
};
downstreamNodesInSettings.push_back(downstreamServerAddr);
bool knownNode = find(knownDownstreamNodes.cbegin(), knownDownstreamNodes.cend(),
downstreamServerAddr) != knownDownstreamNodes.cend();
bool knownNode = find(knownReplicationNodes.cbegin(), knownReplicationNodes.cend(),
replicationServer.sockAddr) != knownReplicationNodes.cend();
if (!knownNode) {
// manually add the downstream node to our node list
auto node = nodeList->addOrUpdateNode(QUuid::createUuid(), downstreamNodeType,
downstreamServerAddr, downstreamServerAddr);
// manually add the replication node to our node list
auto node = nodeList->addOrUpdateNode(QUuid::createUuid(), replicationServer.nodeType,
replicationServer.sockAddr, replicationServer.sockAddr,
false, direction == Upstream);
node->setIsForcedNeverSilent(true);
qDebug() << "Adding downstream node:" << node->getUUID() << downstreamServerAddr;
qDebug() << "Adding" << (direction == Upstream ? "upstream" : "downstream")
<< "node:" << node->getUUID() << replicationServer.sockAddr;
// manually activate the public socket for the downstream node
// manually activate the public socket for the replication node
node->activatePublicSocket();
}
}
@ -2288,11 +2322,13 @@ void DomainServer::updateDownstreamNodes() {
// we cannot recursively take the write lock required by handleKillNode)
std::vector<SharedNodePointer> nodesToKill;
nodeList->eachNode([&](const SharedNodePointer& otherNode) {
if (NodeType::isDownstream(otherNode->getType())) {
bool nodeInSettings = find(downstreamNodesInSettings.cbegin(), downstreamNodesInSettings.cend(),
otherNode->getPublicSocket()) != downstreamNodesInSettings.cend();
if ((direction == Upstream && NodeType::isUpstream(otherNode->getType()))
|| (direction == Downstream && NodeType::isDownstream(otherNode->getType()))) {
bool nodeInSettings = find(replicationNodesInSettings.cbegin(), replicationNodesInSettings.cend(),
otherNode->getPublicSocket()) != replicationNodesInSettings.cend();
if (!nodeInSettings) {
qDebug() << "Removing downstream node:" << otherNode->getUUID() << otherNode->getPublicSocket();
qDebug() << "Removing" << replicationDirection
<< "node:" << otherNode->getUUID() << otherNode->getPublicSocket();
nodesToKill.push_back(otherNode);
}
}
@ -2304,6 +2340,14 @@ void DomainServer::updateDownstreamNodes() {
}
}
void DomainServer::updateDownstreamNodes() {
updateReplicationNodes(Downstream);
}
void DomainServer::updateUpstreamNodes() {
updateReplicationNodes(Upstream);
}
void DomainServer::updateReplicatedNodes() {
// Make sure we have downstream nodes in our list
auto settings = _settingsManager.getSettingsMap();
@ -2639,7 +2683,7 @@ void DomainServer::handleICEHostInfo(const QHostInfo& hostInfo) {
_iceAddressLookupID = -1;
if (hostInfo.error() != QHostInfo::NoError) {
qWarning() << "IP address lookup failed for" << ICE_SERVER_DEFAULT_HOSTNAME << ":" << hostInfo.errorString();
qWarning() << "IP address lookup failed for" << _iceServerAddr << ":" << hostInfo.errorString();
// if we don't have an ICE server to use yet, trigger a retry
if (_iceServerSocket.isNull()) {
@ -2654,7 +2698,7 @@ void DomainServer::handleICEHostInfo(const QHostInfo& hostInfo) {
_iceServerAddresses = hostInfo.addresses();
if (countBefore == 0) {
qInfo() << "Found" << _iceServerAddresses.count() << "ice-server IP addresses for" << ICE_SERVER_DEFAULT_HOSTNAME;
qInfo() << "Found" << _iceServerAddresses.count() << "ice-server IP addresses for" << _iceServerAddr;
}
if (_iceServerSocket.isNull()) {
@ -2689,7 +2733,7 @@ void DomainServer::randomizeICEServerAddress(bool shouldTriggerHostLookup) {
// so clear the set of failed addresses and start going through them again
qWarning() << "All current ice-server addresses have failed - re-attempting all current addresses for"
<< ICE_SERVER_DEFAULT_HOSTNAME;
<< _iceServerAddr;
_failedIceServerAddresses.clear();
candidateICEAddresses = _iceServerAddresses;

View file

@ -39,6 +39,11 @@ typedef QMultiHash<QUuid, WalletTransaction*> TransactionHash;
using Subnet = QPair<QHostAddress, int>;
using SubnetList = std::vector<Subnet>;
enum ReplicationServerDirection {
Upstream,
Downstream
};
class DomainServer : public QCoreApplication, public HTTPSRequestHandler {
Q_OBJECT
public:
@ -104,6 +109,7 @@ private slots:
void updateReplicatedNodes();
void updateDownstreamNodes();
void updateUpstreamNodes();
signals:
void iceServerChanged();
@ -170,6 +176,8 @@ private:
QString pathForRedirect(QString path = QString()) const;
void updateReplicationNodes(ReplicationServerDirection direction);
SubnetList _acSubnetWhitelist;
std::vector<QString> _replicatedUsernames;

View file

@ -214,7 +214,7 @@ static QTimer pingTimer;
static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;
// For processing on QThreadPool, we target a number of threads after reserving some
// For processing on QThreadPool, we target a number of threads after reserving some
// based on how many are being consumed by the application and the display plugin. However,
// we will never drop below the 'min' value
static const int MIN_PROCESSING_THREAD_POOL_SIZE = 1;
@ -888,6 +888,20 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
}
ResourceCache::setRequestLimit(concurrentDownloads);
// perhaps override the avatar url. Since we will test later for validity
// we don't need to do so here.
QString avatarURL = getCmdOption(argc, constArgv, "--avatarURL");
_avatarOverrideUrl = QUrl::fromUserInput(avatarURL);
// If someone specifies both --avatarURL and --replaceAvatarURL,
// the replaceAvatarURL wins. So only set the _overrideUrl if this
// does have a non-empty string.
QString replaceURL = getCmdOption(argc, constArgv, "--replaceAvatarURL");
if (!replaceURL.isEmpty()) {
_avatarOverrideUrl = QUrl::fromUserInput(replaceURL);
_saveAvatarOverrideUrl = true;
}
_glWidget = new GLCanvas();
getApplicationCompositor().setRenderingWidget(_glWidget);
_window->setCentralWidget(_glWidget);
@ -1277,7 +1291,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Add periodic checks to send user activity data
static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000;
static int NEARBY_AVATAR_RADIUS_METERS = 10;
// setup the stats interval depending on if the 1s faster hearbeat was requested
static const QString FAST_STATS_ARG = "--fast-heartbeat";
static int SEND_STATS_INTERVAL_MS = arguments().indexOf(FAST_STATS_ARG) != -1 ? 1000 : 10000;
@ -1427,10 +1441,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_autoSwitchDisplayModeSupportedHMDPlugin = nullptr;
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
if (displayPlugin->isHmd() &&
if (displayPlugin->isHmd() &&
displayPlugin->getSupportsAutoSwitch()) {
_autoSwitchDisplayModeSupportedHMDPlugin = displayPlugin;
_autoSwitchDisplayModeSupportedHMDPluginName =
_autoSwitchDisplayModeSupportedHMDPluginName =
_autoSwitchDisplayModeSupportedHMDPlugin->getName();
_previousHMDWornStatus =
_autoSwitchDisplayModeSupportedHMDPlugin->isDisplayVisible();
@ -1682,7 +1696,7 @@ void Application::onAboutToQuit() {
}
getActiveDisplayPlugin()->deactivate();
if (_autoSwitchDisplayModeSupportedHMDPlugin
if (_autoSwitchDisplayModeSupportedHMDPlugin
&& _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) {
_autoSwitchDisplayModeSupportedHMDPlugin->endSession();
}
@ -1751,8 +1765,8 @@ void Application::cleanupBeforeQuit() {
// Cleanup all overlays after the scripts, as scripts might add more
_overlays.cleanupAllOverlays();
// The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual
// removal of the items.
// The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual
// removal of the items.
// See https://highfidelity.fogbugz.com/f/cases/5328
_main3DScene->processTransactionQueue();
@ -5265,7 +5279,7 @@ void Application::clearDomainOctreeDetails() {
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
_recentlyClearedDomain = true;
DependencyManager::get<AnimationCache>()->clearUnusedResources();
DependencyManager::get<ModelCache>()->clearUnusedResources();
DependencyManager::get<SoundCache>()->clearUnusedResources();
@ -5329,6 +5343,10 @@ void Application::nodeActivated(SharedNodePointer node) {
if (node->getType() == NodeType::AvatarMixer) {
// new avatar mixer, send off our identity packet on next update loop
// Reset skeletonModelUrl if the last server modified our choice.
// Override the avatar url (but not model name) here too.
if (_avatarOverrideUrl.isValid()) {
getMyAvatar()->useFullAvatarURL(_avatarOverrideUrl);
}
static const QUrl empty{};
if (getMyAvatar()->getFullAvatarURLFromPreferences() != getMyAvatar()->cannonicalSkeletonModelURL(empty)) {
getMyAvatar()->resetFullAvatarURL();
@ -7083,3 +7101,8 @@ QUuid Application::getTabletFrameID() const {
auto HMD = DependencyManager::get<HMDScriptingInterface>();
return HMD->getCurrentTabletFrameID();
}
void Application::setAvatarOverrideUrl(const QUrl& url, bool save) {
_avatarOverrideUrl = url;
_saveAvatarOverrideUrl = save;
}

View file

@ -102,9 +102,9 @@ class Application;
#endif
#define qApp (static_cast<Application*>(QCoreApplication::instance()))
class Application : public QApplication,
public AbstractViewStateInterface,
public AbstractScriptingServicesInterface,
class Application : public QApplication,
public AbstractViewStateInterface,
public AbstractScriptingServicesInterface,
public AbstractUriHandler,
public PluginContainer {
Q_OBJECT
@ -294,6 +294,10 @@ public:
OverlayID getTabletHomeButtonID() const;
QUuid getTabletFrameID() const; // may be an entity or an overlay
void setAvatarOverrideUrl(const QUrl& url, bool save);
QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; }
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
signals:
void svoImportRequested(const QString& url);
@ -675,11 +679,14 @@ private:
FileScriptingInterface* _fileDownload;
AudioInjector* _snapshotSoundInjector { nullptr };
SharedSoundPointer _snapshotSound;
DisplayPluginPointer _autoSwitchDisplayModeSupportedHMDPlugin;
QString _autoSwitchDisplayModeSupportedHMDPluginName;
bool _previousHMDWornStatus;
void startHMDStandBySession();
void endHMDSession();
QUrl _avatarOverrideUrl;
bool _saveAvatarOverrideUrl { false };
};
#endif // hifi_Application_h

View file

@ -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>();
avatarBookmarks->setupMenus(this, avatarMenu);

View file

@ -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";

View file

@ -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<ZoneEntityItem> 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);
}
@ -929,10 +929,15 @@ void MyAvatar::saveData() {
settings.setValue("scale", _targetScale);
settings.setValue("fullAvatarURL",
// only save the fullAvatarURL if it has not been overwritten on command line
// (so the overrideURL is not valid), or it was overridden _and_ we specified
// --replaceAvatarURL (so _saveAvatarOverrideUrl is true)
if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid() ) {
settings.setValue("fullAvatarURL",
_fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ?
"" :
_fullAvatarURLFromPreferences.toString());
}
settings.setValue("fullAvatarModelName", _fullAvatarModelName);
@ -2443,7 +2448,7 @@ bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& bette
// Our head may be embedded, but our center is out and there's room below. See corresponding comment above.
return false; // nothing below
}
// See if we have room between entities above and below, but that we are not contained.
// First check if the surface above us is the bottom of something, and the surface below us it the top of something.
// I.e., we are in a clearing between two objects.
@ -2508,6 +2513,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()) {
@ -3163,6 +3192,6 @@ void MyAvatar::updateHoldActions(const AnimPose& prePhysicsPose, const AnimPose&
}
}
const MyHead* MyAvatar::getMyHead() const {
return static_cast<const MyHead*>(getHead());
const MyHead* MyAvatar::getMyHead() const {
return static_cast<const MyHead*>(getHead());
}

View file

@ -512,6 +512,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
@ -574,6 +579,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);
@ -646,6 +652,7 @@ private:
std::array<float, MAX_DRIVE_KEYS> _driveKeys;
std::bitset<MAX_DRIVE_KEYS> _disabledDriveKeys;
bool _enableFlying { true };
bool _wasPushing { false };
bool _isPushing { false };
bool _isBeingPushed { false };
@ -797,7 +804,6 @@ private:
ThreadSafeValueCache<controller::Pose> _rightArmControllerPoseInSensorFrameCache { controller::Pose() };
bool _hmdLeanRecenterEnabled = true;
AnimPose _prePhysicsRoomPose;
std::mutex _holdActionsMutex;
std::vector<AvatarActionHold*> _holdActions;

View file

@ -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
}

View file

@ -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 <stdint.h>
#include <assert.h>
#include <immintrin.h> // AVX2
#ifndef __AVX2__
#error Must be compiled with /arch:AVX2 or -mavx2 -mfma.
#endif
#include <immintrin.h>
#define _mm256_permute4x64_ps(ymm, imm) _mm256_castpd_ps(_mm256_permute4x64_pd(_mm256_castps_pd(ymm), imm));

View file

@ -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 <assert.h>
#include <immintrin.h> // AVX2
#include <immintrin.h>
#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")

View file

@ -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 <assert.h>
#include <immintrin.h>
#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))

View file

@ -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 <assert.h>
#include <immintrin.h>
#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

View file

@ -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();

View file

@ -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;

View file

@ -20,6 +20,8 @@
#include <QThreadPool>
#include <Gzip.h>
#include "ModelNetworkingLogging.h"
#include <Trace.h>
#include <StatTracker.h>
@ -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");
}

View file

@ -821,6 +821,7 @@ void NetworkTexture::refresh() {
TextureCache::requestCompleted(_self);
}
_ktxResourceState = PENDING_INITIAL_LOAD;
Resource::refresh();
}

View file

@ -257,8 +257,40 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe
PacketType headerType = NLPacket::typeInHeader(packet);
if (NON_SOURCED_PACKETS.contains(headerType)) {
emit dataReceived(NodeType::Unassigned, packet.getPayloadSize());
return true;
if (REPLICATED_PACKET_MAPPING.key(headerType) != PacketType::Unknown) {
// this is a replicated packet type - make sure the socket that sent it to us matches
// one from one of our current upstream nodes
NodeType_t sendingNodeType { NodeType::Unassigned };
eachNodeBreakable([&packet, &sendingNodeType](const SharedNodePointer& node){
if (NodeType::isUpstream(node->getType()) && node->getPublicSocket() == packet.getSenderSockAddr()) {
sendingNodeType = node->getType();
return false;
} else {
return true;
}
});
if (sendingNodeType != NodeType::Unassigned) {
emit dataReceived(sendingNodeType, packet.getPayloadSize());
return true;
} else {
static const QString UNSOLICITED_REPLICATED_REGEX =
"Replicated packet of type \\d+ \\([\\sa-zA-Z:]+\\) received from unknown upstream";
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(UNSOLICITED_REPLICATED_REGEX);
qCDebug(networking) << "Replicated packet of type" << headerType
<< "received from unknown upstream" << packet.getSenderSockAddr();
return false;
}
} else {
emit dataReceived(NodeType::Unassigned, packet.getPayloadSize());
return true;
}
} else {
QUuid sourceID = NLPacket::sourceIDInHeader(packet);
@ -583,14 +615,14 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
matchingNode->setPermissions(permissions);
matchingNode->setConnectionSecret(connectionSecret);
matchingNode->setIsReplicated(isReplicated);
matchingNode->setIsUpstream(isUpstream);
matchingNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType));
return matchingNode;
} else {
// we didn't have this node, so add them
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket);
newNode->setIsReplicated(isReplicated);
newNode->setIsUpstream(isUpstream);
newNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType));
newNode->setConnectionSecret(connectionSecret);
newNode->setPermissions(permissions);

View file

@ -42,6 +42,8 @@ void NodeType::init() {
TypeNameHash.insert(NodeType::MessagesMixer, "Messages Mixer");
TypeNameHash.insert(NodeType::AssetServer, "Asset Server");
TypeNameHash.insert(NodeType::EntityScriptServer, "Entity Script Server");
TypeNameHash.insert(NodeType::UpstreamAudioMixer, "Upstream Audio Mixer");
TypeNameHash.insert(NodeType::UpstreamAvatarMixer, "Upstream Avatar Mixer");
TypeNameHash.insert(NodeType::DownstreamAudioMixer, "Downstream Audio Mixer");
TypeNameHash.insert(NodeType::DownstreamAvatarMixer, "Downstream Avatar Mixer");
TypeNameHash.insert(NodeType::Unassigned, "Unassigned");
@ -52,8 +54,23 @@ const QString& NodeType::getNodeTypeName(NodeType_t nodeType) {
return matchedTypeName != TypeNameHash.end() ? matchedTypeName.value() : UNKNOWN_NodeType_t_NAME;
}
bool NodeType::isUpstream(NodeType_t nodeType) {
return nodeType == NodeType::UpstreamAudioMixer || nodeType == NodeType::UpstreamAvatarMixer;
}
bool NodeType::isDownstream(NodeType_t nodeType) {
return nodeType == NodeType::DownstreamAudioMixer || nodeType == NodeType::DownstreamAvatarMixer;
return nodeType == NodeType::DownstreamAudioMixer || nodeType == NodeType::DownstreamAvatarMixer;
}
NodeType_t NodeType::upstreamType(NodeType_t primaryType) {
switch (primaryType) {
case AudioMixer:
return UpstreamAudioMixer;
case AvatarMixer:
return UpstreamAvatarMixer;
default:
return Unassigned;
}
}
NodeType_t NodeType::downstreamType(NodeType_t primaryType) {

View file

@ -669,9 +669,11 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) {
SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket,
nodeLocalSocket, isReplicated, false, connectionUUID, permissions);
// nodes that are downstream of our own type are kept alive when we hear about them from the domain server
if (node->getType() == NodeType::downstreamType(_ownerType)) {
// nodes that are downstream or upstream of our own type are kept alive when we hear about them from the domain server
// and always have their public socket as their active socket
if (node->getType() == NodeType::downstreamType(_ownerType) || node->getType() == NodeType::upstreamType(_ownerType)) {
node->setLastHeardMicrostamp(usecTimestampNow());
node->activatePublicSocket();
}
}

View file

@ -25,6 +25,8 @@ namespace NodeType {
const NodeType_t AssetServer = 'A';
const NodeType_t MessagesMixer = 'm';
const NodeType_t EntityScriptServer = 'S';
const NodeType_t UpstreamAudioMixer = 'B';
const NodeType_t UpstreamAvatarMixer = 'C';
const NodeType_t DownstreamAudioMixer = 'a';
const NodeType_t DownstreamAvatarMixer = 'w';
const NodeType_t Unassigned = 1;
@ -32,9 +34,12 @@ namespace NodeType {
void init();
const QString& getNodeTypeName(NodeType_t nodeType);
bool isUpstream(NodeType_t nodeType);
bool isDownstream(NodeType_t nodeType);
NodeType_t upstreamType(NodeType_t primaryType);
NodeType_t downstreamType(NodeType_t primaryType);
NodeType_t fromString(QString type);
}

View file

@ -51,6 +51,7 @@ const QHash<PacketType, PacketType> REPLICATED_PACKET_MAPPING {
{ PacketType::SilentAudioFrame, PacketType::ReplicatedSilentAudioFrame },
{ PacketType::AvatarIdentity, PacketType::ReplicatedAvatarIdentity },
{ PacketType::KillAvatar, PacketType::ReplicatedKillAvatar },
{ PacketType::BulkAvatarData, PacketType::ReplicatedBulkAvatarData }
};
PacketVersion versionForPacketType(PacketType packetType) {

View file

@ -356,6 +356,13 @@ QStringList ScriptEngines::getRunningScripts() {
void ScriptEngines::stopAllScripts(bool restart) {
QVector<QString> toReload;
QReadLocker lock(&_scriptEnginesHashLock);
if (_isReloading) {
return;
} else {
_isReloading = true;
}
for (QHash<QUrl, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
it != _scriptEnginesHash.constEnd(); it++) {
ScriptEngine *scriptEngine = it.value();
@ -375,7 +382,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()) {
@ -390,6 +397,7 @@ void ScriptEngines::stopAllScripts(bool restart) {
qCDebug(scriptengine) << "stopAllScripts -- emitting scriptsReloading";
emit scriptsReloading();
}
_isReloading = false;
});
}

View file

@ -112,6 +112,7 @@ protected:
ScriptsModel _scriptsModel;
ScriptsModelFilter _scriptsModelFilter;
std::atomic<bool> _isStopped { false };
std::atomic<bool> _isReloading { false };
};
QUrl normalizeScriptURL(const QUrl& rawScriptURL);

View file

@ -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 <intrin.h>
// use MSVC intrinsics
#define cpuidex(info, eax, ecx) __cpuidex(info, eax, ecx)
#define xgetbv(ecx) _xgetbv(ecx)
#elif defined(ARCH_X86) && defined(__GNUC__)
#include <cpuid.h>
// 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 <cpuid.h>
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

View file

@ -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);
});

View file

@ -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 ()

View file

@ -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";

View file

@ -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({

View file

@ -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);