mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 08:16:21 +02:00
Merge branch 'reset-hud-on-driving' of https://github.com/howard-stearns/hifi into reset-hud-on-driving
This commit is contained in:
commit
abd2b150f5
39 changed files with 488 additions and 296 deletions
|
@ -55,11 +55,19 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
|
||||||
if (message->getSize() == 0) {
|
if (message->getSize() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream packetStream(message->getMessage());
|
QDataStream packetStream(message->getMessage());
|
||||||
|
|
||||||
// read a NodeConnectionData object from the packet so we can pass around this data while we're inspecting it
|
// read a NodeConnectionData object from the packet so we can pass around this data while we're inspecting it
|
||||||
NodeConnectionData nodeConnection = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr());
|
NodeConnectionData nodeConnection = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr());
|
||||||
|
|
||||||
|
QByteArray myProtocolVersion = protocolVersionsSignature();
|
||||||
|
if (nodeConnection.protocolVersion != myProtocolVersion) {
|
||||||
|
QString protocolVersionError = "Protocol version mismatch - Domain version:" + QCoreApplication::applicationVersion();
|
||||||
|
qDebug() << "Protocol Version mismatch - denying connection.";
|
||||||
|
sendConnectionDeniedPacket(protocolVersionError, message->getSenderSockAddr(),
|
||||||
|
DomainHandler::ConnectionRefusedReason::ProtocolMismatch);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (nodeConnection.localSockAddr.isNull() || nodeConnection.publicSockAddr.isNull()) {
|
if (nodeConnection.localSockAddr.isNull() || nodeConnection.publicSockAddr.isNull()) {
|
||||||
qDebug() << "Unexpected data received for node local socket or public socket. Will not allow connection.";
|
qDebug() << "Unexpected data received for node local socket or public socket. Will not allow connection.";
|
||||||
|
@ -332,7 +340,7 @@ SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const Node
|
||||||
bool DomainGatekeeper::verifyUserSignature(const QString& username,
|
bool DomainGatekeeper::verifyUserSignature(const QString& username,
|
||||||
const QByteArray& usernameSignature,
|
const QByteArray& usernameSignature,
|
||||||
const HifiSockAddr& senderSockAddr) {
|
const HifiSockAddr& senderSockAddr) {
|
||||||
|
|
||||||
// it's possible this user can be allowed to connect, but we need to check their username signature
|
// it's possible this user can be allowed to connect, but we need to check their username signature
|
||||||
QByteArray publicKeyArray = _userPublicKeys.value(username);
|
QByteArray publicKeyArray = _userPublicKeys.value(username);
|
||||||
|
|
||||||
|
@ -370,7 +378,8 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username,
|
||||||
} else {
|
} else {
|
||||||
if (!senderSockAddr.isNull()) {
|
if (!senderSockAddr.isNull()) {
|
||||||
qDebug() << "Error decrypting username signature for " << username << "- denying connection.";
|
qDebug() << "Error decrypting username signature for " << username << "- denying connection.";
|
||||||
sendConnectionDeniedPacket("Error decrypting username signature.", senderSockAddr);
|
sendConnectionDeniedPacket("Error decrypting username signature.", senderSockAddr,
|
||||||
|
DomainHandler::ConnectionRefusedReason::LoginError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// free up the public key, we don't need it anymore
|
// free up the public key, we don't need it anymore
|
||||||
|
@ -382,13 +391,15 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username,
|
||||||
// we can't let this user in since we couldn't convert their public key to an RSA key we could use
|
// we can't let this user in since we couldn't convert their public key to an RSA key we could use
|
||||||
if (!senderSockAddr.isNull()) {
|
if (!senderSockAddr.isNull()) {
|
||||||
qDebug() << "Couldn't convert data to RSA key for" << username << "- denying connection.";
|
qDebug() << "Couldn't convert data to RSA key for" << username << "- denying connection.";
|
||||||
sendConnectionDeniedPacket("Couldn't convert data to RSA key.", senderSockAddr);
|
sendConnectionDeniedPacket("Couldn't convert data to RSA key.", senderSockAddr,
|
||||||
|
DomainHandler::ConnectionRefusedReason::LoginError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!senderSockAddr.isNull()) {
|
if (!senderSockAddr.isNull()) {
|
||||||
qDebug() << "Insufficient data to decrypt username signature - denying connection.";
|
qDebug() << "Insufficient data to decrypt username signature - denying connection.";
|
||||||
sendConnectionDeniedPacket("Insufficient data", senderSockAddr);
|
sendConnectionDeniedPacket("Insufficient data", senderSockAddr,
|
||||||
|
DomainHandler::ConnectionRefusedReason::LoginError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,7 +413,8 @@ bool DomainGatekeeper::isVerifiedAllowedUser(const QString& username, const QByt
|
||||||
if (username.isEmpty()) {
|
if (username.isEmpty()) {
|
||||||
qDebug() << "Connect request denied - no username provided.";
|
qDebug() << "Connect request denied - no username provided.";
|
||||||
|
|
||||||
sendConnectionDeniedPacket("No username provided", senderSockAddr);
|
sendConnectionDeniedPacket("No username provided", senderSockAddr,
|
||||||
|
DomainHandler::ConnectionRefusedReason::LoginError);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -416,7 +428,8 @@ bool DomainGatekeeper::isVerifiedAllowedUser(const QString& username, const QByt
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Connect request denied for user" << username << "- not in allowed users list.";
|
qDebug() << "Connect request denied for user" << username << "- not in allowed users list.";
|
||||||
sendConnectionDeniedPacket("User not on whitelist.", senderSockAddr);
|
sendConnectionDeniedPacket("User not on whitelist.", senderSockAddr,
|
||||||
|
DomainHandler::ConnectionRefusedReason::NotAuthorized);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -430,10 +443,10 @@ bool DomainGatekeeper::isWithinMaxCapacity(const QString& username, const QByteA
|
||||||
// find out what our maximum capacity is
|
// find out what our maximum capacity is
|
||||||
const QVariant* maximumUserCapacityVariant = valueForKeyPath(_server->_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY);
|
const QVariant* maximumUserCapacityVariant = valueForKeyPath(_server->_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY);
|
||||||
unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0;
|
unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0;
|
||||||
|
|
||||||
if (maximumUserCapacity > 0) {
|
if (maximumUserCapacity > 0) {
|
||||||
unsigned int connectedUsers = _server->countConnectedUsers();
|
unsigned int connectedUsers = _server->countConnectedUsers();
|
||||||
|
|
||||||
if (connectedUsers >= maximumUserCapacity) {
|
if (connectedUsers >= maximumUserCapacity) {
|
||||||
// too many users, deny the new connection unless this user is an allowed editor
|
// too many users, deny the new connection unless this user is an allowed editor
|
||||||
|
|
||||||
|
@ -452,7 +465,8 @@ bool DomainGatekeeper::isWithinMaxCapacity(const QString& username, const QByteA
|
||||||
|
|
||||||
// deny connection from this user
|
// deny connection from this user
|
||||||
qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, denying new connection.";
|
qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, denying new connection.";
|
||||||
sendConnectionDeniedPacket("Too many connected users.", senderSockAddr);
|
sendConnectionDeniedPacket("Too many connected users.", senderSockAddr,
|
||||||
|
DomainHandler::ConnectionRefusedReason::TooManyUsers);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -516,16 +530,20 @@ void DomainGatekeeper::publicKeyJSONCallback(QNetworkReply& requestReply) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainGatekeeper::sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr) {
|
void DomainGatekeeper::sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr,
|
||||||
|
DomainHandler::ConnectionRefusedReason reasonCode) {
|
||||||
// this is an agent and we've decided we won't let them connect - send them a packet to deny connection
|
// this is an agent and we've decided we won't let them connect - send them a packet to deny connection
|
||||||
QByteArray utfString = reason.toUtf8();
|
QByteArray utfString = reason.toUtf8();
|
||||||
quint16 payloadSize = utfString.size();
|
quint16 payloadSize = utfString.size();
|
||||||
|
|
||||||
// setup the DomainConnectionDenied packet
|
// setup the DomainConnectionDenied packet
|
||||||
auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied, payloadSize + sizeof(payloadSize));
|
auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied,
|
||||||
|
payloadSize + sizeof(payloadSize) + sizeof(uint8_t));
|
||||||
|
|
||||||
// pack in the reason the connection was denied (the client displays this)
|
// pack in the reason the connection was denied (the client displays this)
|
||||||
if (payloadSize > 0) {
|
if (payloadSize > 0) {
|
||||||
|
uint8_t reasonCodeWire = (uint8_t)reasonCode;
|
||||||
|
connectionDeniedPacket->writePrimitive(reasonCodeWire);
|
||||||
connectionDeniedPacket->writePrimitive(payloadSize);
|
connectionDeniedPacket->writePrimitive(payloadSize);
|
||||||
connectionDeniedPacket->write(utfString);
|
connectionDeniedPacket->write(utfString);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
|
||||||
|
#include <DomainHandler.h>
|
||||||
|
|
||||||
#include <NLPacket.h>
|
#include <NLPacket.h>
|
||||||
#include <Node.h>
|
#include <Node.h>
|
||||||
#include <UUIDHasher.h>
|
#include <UUIDHasher.h>
|
||||||
|
@ -74,7 +76,8 @@ private:
|
||||||
const HifiSockAddr& senderSockAddr);
|
const HifiSockAddr& senderSockAddr);
|
||||||
|
|
||||||
void sendConnectionTokenPacket(const QString& username, const HifiSockAddr& senderSockAddr);
|
void sendConnectionTokenPacket(const QString& username, const HifiSockAddr& senderSockAddr);
|
||||||
void sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr);
|
void sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr,
|
||||||
|
DomainHandler::ConnectionRefusedReason reasonCode = DomainHandler::ConnectionRefusedReason::Unknown);
|
||||||
|
|
||||||
void pingPunchForConnectingPeer(const SharedNetworkPeer& peer);
|
void pingPunchForConnectingPeer(const SharedNetworkPeer& peer);
|
||||||
|
|
||||||
|
|
|
@ -303,6 +303,31 @@ const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full";
|
||||||
const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip";
|
const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip";
|
||||||
const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled";
|
const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool DomainServer::packetVersionMatch(const udt::Packet& packet) {
|
||||||
|
PacketType headerType = NLPacket::typeInHeader(packet);
|
||||||
|
PacketVersion headerVersion = NLPacket::versionInHeader(packet);
|
||||||
|
|
||||||
|
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
|
||||||
|
// This implements a special case that handles OLD clients which don't know how to negotiate matching
|
||||||
|
// protocol versions. We know these clients will sent DomainConnectRequest with older versions. We also
|
||||||
|
// know these clients will show a warning dialog if they get an EntityData with a protocol version they
|
||||||
|
// don't understand, so we can send them an empty EntityData with our latest version and they will
|
||||||
|
// warn the user that the protocol is not compatible
|
||||||
|
if (headerType == PacketType::DomainConnectRequest &&
|
||||||
|
headerVersion < static_cast<PacketVersion>(DomainConnectRequestVersion::HasProtocolVersions)) {
|
||||||
|
auto packetWithBadVersion = NLPacket::create(PacketType::EntityData);
|
||||||
|
nodeList->sendPacket(std::move(packetWithBadVersion), packet.getSenderSockAddr());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// let the normal nodeList implementation handle all other packets.
|
||||||
|
return nodeList->isPacketVerified(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
||||||
|
|
||||||
const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port";
|
const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port";
|
||||||
|
@ -376,6 +401,9 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
||||||
|
|
||||||
// add whatever static assignments that have been parsed to the queue
|
// add whatever static assignments that have been parsed to the queue
|
||||||
addStaticAssignmentsToQueue();
|
addStaticAssignmentsToQueue();
|
||||||
|
|
||||||
|
// set a custum packetVersionMatch as the verify packet operator for the udt::Socket
|
||||||
|
nodeList->setPacketFilterOperator(&DomainServer::packetVersionMatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
|
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
|
||||||
|
@ -666,7 +694,7 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::processListRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
void DomainServer::processListRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
||||||
|
|
||||||
QDataStream packetStream(message->getMessage());
|
QDataStream packetStream(message->getMessage());
|
||||||
NodeConnectionData nodeRequestData = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr(), false);
|
NodeConnectionData nodeRequestData = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr(), false);
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,8 @@ private:
|
||||||
|
|
||||||
void optionallyGetTemporaryName(const QStringList& arguments);
|
void optionallyGetTemporaryName(const QStringList& arguments);
|
||||||
|
|
||||||
|
static bool packetVersionMatch(const udt::Packet& packet);
|
||||||
|
|
||||||
bool resetAccountManagerAccessToken();
|
bool resetAccountManagerAccessToken();
|
||||||
|
|
||||||
void setupAutomaticNetworking();
|
void setupAutomaticNetworking();
|
||||||
|
|
|
@ -19,6 +19,16 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c
|
||||||
|
|
||||||
if (isConnectRequest) {
|
if (isConnectRequest) {
|
||||||
dataStream >> newHeader.connectUUID;
|
dataStream >> newHeader.connectUUID;
|
||||||
|
|
||||||
|
// Read out the protocol version signature from the connect message
|
||||||
|
char* rawBytes;
|
||||||
|
uint length;
|
||||||
|
|
||||||
|
dataStream.readBytes(rawBytes, length);
|
||||||
|
newHeader.protocolVersion = QByteArray(rawBytes, length);
|
||||||
|
|
||||||
|
// NOTE: QDataStream::readBytes() - The buffer is allocated using new []. Destroy it with the delete [] operator.
|
||||||
|
delete[] rawBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
dataStream >> newHeader.nodeType
|
dataStream >> newHeader.nodeType
|
||||||
|
|
|
@ -28,6 +28,8 @@ public:
|
||||||
HifiSockAddr senderSockAddr;
|
HifiSockAddr senderSockAddr;
|
||||||
QList<NodeType_t> interestList;
|
QList<NodeType_t> interestList;
|
||||||
QString placeName;
|
QString placeName;
|
||||||
|
|
||||||
|
QByteArray protocolVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,10 @@
|
||||||
{ "from": "Hydra.L0", "to": "Standard.Back" },
|
{ "from": "Hydra.L0", "to": "Standard.Back" },
|
||||||
{ "from": "Hydra.R0", "to": "Standard.Start" },
|
{ "from": "Hydra.R0", "to": "Standard.Start" },
|
||||||
|
|
||||||
{ "from": [ "Hydra.L1", "Hydra.L2", "Hydra.L3", "Hydra.L4" ], "to": "Standard.LeftPrimaryThumb" },
|
{ "from": [ "Hydra.L1", "Hydra.L3" ], "to": "Standard.LeftPrimaryThumb" },
|
||||||
{ "from": [ "Hydra.R1", "Hydra.R2", "Hydra.R3", "Hydra.R4" ], "to": "Standard.RightPrimaryThumb" },
|
{ "from": [ "Hydra.R1", "Hydra.R3" ], "to": "Standard.RightPrimaryThumb" },
|
||||||
|
{ "from": [ "Hydra.R2", "Hydra.R4" ], "to": "Standard.RightSecondaryThumb" },
|
||||||
|
{ "from": [ "Hydra.L2", "Hydra.L4" ], "to": "Standard.LeftSecondaryThumb" },
|
||||||
|
|
||||||
{ "from": "Hydra.LeftHand", "to": "Standard.LeftHand" },
|
{ "from": "Hydra.LeftHand", "to": "Standard.LeftHand" },
|
||||||
{ "from": "Hydra.RightHand", "to": "Standard.RightHand" }
|
{ "from": "Hydra.RightHand", "to": "Standard.RightHand" }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "Neuron to Standard",
|
"name": "Neuron to Standard",
|
||||||
"channels": [
|
"channels": [
|
||||||
{ "from": "Hydra.LeftHand", "to": "Standard.LeftHand" },
|
{ "from": "Neuron.LeftHand", "to": "Standard.LeftHand" },
|
||||||
{ "from": "Hydra.RightHand", "to": "Standard.RightHand" }
|
{ "from": "Neuron.RightHand", "to": "Standard.RightHand" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,26 @@
|
||||||
{
|
{
|
||||||
"name": "Vive to Standard",
|
"name": "Vive to Standard",
|
||||||
"channels": [
|
"channels": [
|
||||||
{ "from": "Vive.LY", "when": "Vive.LS", "filters": ["invert" ,{ "type": "deadZone", "min": 0.6 }], "to": "Standard.LY" },
|
{ "from": "Vive.LY", "when": "Vive.LSOuter", "filters": ["invert"], "to": "Standard.LY" },
|
||||||
{ "from": "Vive.LX", "when": "Vive.LS", "filters": [{ "type": "deadZone", "min": 0.6 }], "to": "Standard.LX" },
|
{ "from": "Vive.LX", "when": "Vive.LSOuter", "to": "Standard.LX" },
|
||||||
|
|
||||||
{ "from": "Vive.LT", "to": "Standard.LT" },
|
{ "from": "Vive.LT", "to": "Standard.LT" },
|
||||||
{ "from": "Vive.LeftGrip", "to": "Standard.LB" },
|
{ "from": "Vive.LeftGrip", "to": "Standard.LB" },
|
||||||
{ "from": "Vive.LS", "to": "Standard.LS" },
|
{ "from": "Vive.LS", "to": "Standard.LS" },
|
||||||
{ "from": "Vive.LSTouch", "to": "Standard.LSTouch" },
|
{ "from": "Vive.LSTouch", "to": "Standard.LSTouch" },
|
||||||
|
|
||||||
{ "from": "Vive.RY", "when": "Vive.RS", "filters": ["invert", { "type": "deadZone", "min": 0.6 }], "to": "Standard.RY" },
|
{ "from": "Vive.RY", "when": "Vive.RSOuter", "filters": ["invert"], "to": "Standard.RY" },
|
||||||
{ "from": "Vive.RX", "when": "Vive.RS", "filters": [{ "type": "deadZone", "min": 0.6 }], "to": "Standard.RX" },
|
{ "from": "Vive.RX", "when": "Vive.RSOuter", "to": "Standard.RX" },
|
||||||
|
|
||||||
{ "from": "Vive.RT", "to": "Standard.RT" },
|
{ "from": "Vive.RT", "to": "Standard.RT" },
|
||||||
{ "from": "Vive.RightGrip", "to": "Standard.RB" },
|
{ "from": "Vive.RightGrip", "to": "Standard.RB" },
|
||||||
{ "from": "Vive.RS", "to": "Standard.RS" },
|
{ "from": "Vive.RS", "to": "Standard.RS" },
|
||||||
{ "from": "Vive.RSTouch", "to": "Standard.RSTouch" },
|
{ "from": "Vive.RSTouch", "to": "Standard.RSTouch" },
|
||||||
|
|
||||||
{ "from": "Vive.LeftApplicationMenu", "to": "Standard.Back" },
|
{ "from": "Vive.LSCenter", "to": "Standard.LeftPrimaryThumb" },
|
||||||
{ "from": "Vive.RightApplicationMenu", "to": "Standard.Start" },
|
{ "from": "Vive.LeftApplicationMenu", "to": "Standard.LeftSecondaryThumb" },
|
||||||
|
{ "from": "Vive.RSCenter", "to": "Standard.RightPrimaryThumb" },
|
||||||
|
{ "from": "Vive.RightApplicationMenu", "to": "Standard.RightSecondaryThumb" },
|
||||||
|
|
||||||
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand" },
|
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand" },
|
||||||
{ "from": "Vive.RightHand", "to": "Standard.RightHand" }
|
{ "from": "Vive.RightHand", "to": "Standard.RightHand" }
|
||||||
|
|
|
@ -630,6 +630,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle()));
|
connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle()));
|
||||||
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
|
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
|
||||||
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
|
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
|
||||||
|
connect(&domainHandler, &DomainHandler::resetting, nodeList.data(), &NodeList::resetDomainServerCheckInVersion);
|
||||||
|
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &Application::domainConnectionRefused);
|
||||||
|
|
||||||
// update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one
|
// update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one
|
||||||
const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * MSECS_PER_SECOND;
|
const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * MSECS_PER_SECOND;
|
||||||
|
@ -652,7 +654,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
connect(nodeList.data(), &NodeList::nodeActivated, this, &Application::nodeActivated);
|
connect(nodeList.data(), &NodeList::nodeActivated, this, &Application::nodeActivated);
|
||||||
connect(nodeList.data(), &NodeList::uuidChanged, getMyAvatar(), &MyAvatar::setSessionUUID);
|
connect(nodeList.data(), &NodeList::uuidChanged, getMyAvatar(), &MyAvatar::setSessionUUID);
|
||||||
connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID);
|
connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID);
|
||||||
connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset);
|
connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, this, &Application::limitOfSilentDomainCheckInsReached);
|
||||||
connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch);
|
connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch);
|
||||||
|
|
||||||
// connect to appropriate slots on AccountManager
|
// connect to appropriate slots on AccountManager
|
||||||
|
@ -1062,6 +1064,24 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
firstRun.set(false);
|
firstRun.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCode) {
|
||||||
|
switch (static_cast<DomainHandler::ConnectionRefusedReason>(reasonCode)) {
|
||||||
|
case DomainHandler::ConnectionRefusedReason::ProtocolMismatch:
|
||||||
|
notifyPacketVersionMismatch();
|
||||||
|
break;
|
||||||
|
case DomainHandler::ConnectionRefusedReason::TooManyUsers:
|
||||||
|
case DomainHandler::ConnectionRefusedReason::Unknown: {
|
||||||
|
QString message = "Unable to connect to the location you are visiting.\n";
|
||||||
|
message += reasonMessage;
|
||||||
|
OffscreenUi::warning("", message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// nothing to do.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString Application::getUserAgent() {
|
QString Application::getUserAgent() {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QString userAgent;
|
QString userAgent;
|
||||||
|
@ -4572,6 +4592,17 @@ void Application::setSessionUUID(const QUuid& sessionUUID) const {
|
||||||
Physics::setSessionUUID(sessionUUID);
|
Physics::setSessionUUID(sessionUUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If we're not getting anything back from the domain server checkin, it might be that the domain speaks an
|
||||||
|
// older version of the DomainConnectRequest protocol. We will attempt to send and older version of DomainConnectRequest.
|
||||||
|
// We won't actually complete the connection, but if the server responds, we know that it needs to be upgraded (or we
|
||||||
|
// need to be downgraded to talk to it).
|
||||||
|
void Application::limitOfSilentDomainCheckInsReached() {
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
nodeList->downgradeDomainServerCheckInVersion(); // attempt to use an older domain checkin version
|
||||||
|
nodeList->reset();
|
||||||
|
}
|
||||||
|
|
||||||
bool Application::askToSetAvatarUrl(const QString& url) {
|
bool Application::askToSetAvatarUrl(const QString& url) {
|
||||||
QUrl realUrl(url);
|
QUrl realUrl(url);
|
||||||
if (realUrl.isLocalFile()) {
|
if (realUrl.isLocalFile()) {
|
||||||
|
|
|
@ -261,6 +261,10 @@ public slots:
|
||||||
void resetSensors(bool andReload = false);
|
void resetSensors(bool andReload = false);
|
||||||
void setActiveFaceTracker() const;
|
void setActiveFaceTracker() const;
|
||||||
|
|
||||||
|
#if (PR_BUILD || DEV_BUILD)
|
||||||
|
void sendWrongProtocolVersionsSignature(bool checked) { ::sendWrongProtocolVersionsSignature(checked); }
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_IVIEWHMD
|
#ifdef HAVE_IVIEWHMD
|
||||||
void setActiveEyeTracker();
|
void setActiveEyeTracker();
|
||||||
void calibrateEyeTracker1Point();
|
void calibrateEyeTracker1Point();
|
||||||
|
@ -314,6 +318,8 @@ private slots:
|
||||||
bool displayAvatarAttachmentConfirmationDialog(const QString& name) const;
|
bool displayAvatarAttachmentConfirmationDialog(const QString& name) const;
|
||||||
|
|
||||||
void setSessionUUID(const QUuid& sessionUUID) const;
|
void setSessionUUID(const QUuid& sessionUUID) const;
|
||||||
|
void limitOfSilentDomainCheckInsReached();
|
||||||
|
|
||||||
void domainChanged(const QString& domainHostname);
|
void domainChanged(const QString& domainHostname);
|
||||||
void updateWindowTitle() const;
|
void updateWindowTitle() const;
|
||||||
void nodeAdded(SharedNodePointer node) const;
|
void nodeAdded(SharedNodePointer node) const;
|
||||||
|
@ -322,6 +328,7 @@ private slots:
|
||||||
static void packetSent(quint64 length);
|
static void packetSent(quint64 length);
|
||||||
void updateDisplayMode();
|
void updateDisplayMode();
|
||||||
void updateInputModes();
|
void updateInputModes();
|
||||||
|
void domainConnectionRefused(const QString& reasonMessage, int reason);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void initDisplay();
|
static void initDisplay();
|
||||||
|
|
|
@ -545,6 +545,13 @@ Menu::Menu() {
|
||||||
addActionToQMenuAndActionHash(networkMenu, MenuOption::BandwidthDetails, 0,
|
addActionToQMenuAndActionHash(networkMenu, MenuOption::BandwidthDetails, 0,
|
||||||
dialogsManager.data(), SLOT(bandwidthDetails()));
|
dialogsManager.data(), SLOT(bandwidthDetails()));
|
||||||
|
|
||||||
|
#if (PR_BUILD || DEV_BUILD)
|
||||||
|
addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::SendWrongProtocolVersion, 0, false,
|
||||||
|
qApp, SLOT(sendWrongProtocolVersionsSignature(bool)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Developer > Timing >>>
|
// Developer > Timing >>>
|
||||||
MenuWrapper* timingMenu = developerMenu->addMenu("Timing");
|
MenuWrapper* timingMenu = developerMenu->addMenu("Timing");
|
||||||
|
|
|
@ -167,6 +167,7 @@ namespace MenuOption {
|
||||||
const QString RunTimingTests = "Run Timing Tests";
|
const QString RunTimingTests = "Run Timing Tests";
|
||||||
const QString ScriptEditor = "Script Editor...";
|
const QString ScriptEditor = "Script Editor...";
|
||||||
const QString ScriptedMotorControl = "Enable Scripted Motor Control";
|
const QString ScriptedMotorControl = "Enable Scripted Motor Control";
|
||||||
|
const QString SendWrongProtocolVersion = "Send wrong protocol version";
|
||||||
const QString SetHomeLocation = "Set Home Location";
|
const QString SetHomeLocation = "Set Home Location";
|
||||||
const QString ShowDSConnectTable = "Show Domain Connection Timing";
|
const QString ShowDSConnectTable = "Show Domain Connection Timing";
|
||||||
const QString ShowBordersEntityNodes = "Show Entity Nodes";
|
const QString ShowBordersEntityNodes = "Show Entity Nodes";
|
||||||
|
|
|
@ -855,7 +855,7 @@ void MyAvatar::loadData() {
|
||||||
setDisplayName(settings.value("displayName").toString());
|
setDisplayName(settings.value("displayName").toString());
|
||||||
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
|
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
|
||||||
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
|
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
|
||||||
setSnapTurn(settings.value("clearOverlayWhenDriving", _clearOverlayWhenDriving).toBool());
|
setClearOverlayWhenDriving(settings.value("clearOverlayWhenDriving", _clearOverlayWhenDriving).toBool());
|
||||||
|
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ public slots:
|
||||||
signals:
|
signals:
|
||||||
void domainChanged(const QString& domainHostname);
|
void domainChanged(const QString& domainHostname);
|
||||||
void svoImportRequested(const QString& url);
|
void svoImportRequested(const QString& url);
|
||||||
void domainConnectionRefused(const QString& reason);
|
void domainConnectionRefused(const QString& reasonMessage, int reasonCode);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height);
|
WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height);
|
||||||
|
|
|
@ -43,6 +43,8 @@ namespace controller {
|
||||||
LEFT_SECONDARY_THUMB_TOUCH,
|
LEFT_SECONDARY_THUMB_TOUCH,
|
||||||
LS_TOUCH,
|
LS_TOUCH,
|
||||||
LEFT_THUMB_UP,
|
LEFT_THUMB_UP,
|
||||||
|
LS_CENTER,
|
||||||
|
LS_OUTER,
|
||||||
|
|
||||||
RIGHT_PRIMARY_THUMB,
|
RIGHT_PRIMARY_THUMB,
|
||||||
RIGHT_SECONDARY_THUMB,
|
RIGHT_SECONDARY_THUMB,
|
||||||
|
@ -50,6 +52,8 @@ namespace controller {
|
||||||
RIGHT_SECONDARY_THUMB_TOUCH,
|
RIGHT_SECONDARY_THUMB_TOUCH,
|
||||||
RS_TOUCH,
|
RS_TOUCH,
|
||||||
RIGHT_THUMB_UP,
|
RIGHT_THUMB_UP,
|
||||||
|
RS_CENTER,
|
||||||
|
RS_OUTER,
|
||||||
|
|
||||||
LEFT_PRIMARY_INDEX,
|
LEFT_PRIMARY_INDEX,
|
||||||
LEFT_SECONDARY_INDEX,
|
LEFT_SECONDARY_INDEX,
|
||||||
|
|
|
@ -103,7 +103,6 @@ void DomainHandler::hardReset() {
|
||||||
_sockAddr.clear();
|
_sockAddr.clear();
|
||||||
|
|
||||||
_hasCheckedForAccessToken = false;
|
_hasCheckedForAccessToken = false;
|
||||||
_domainConnectionRefusals.clear();
|
|
||||||
|
|
||||||
// clear any pending path we may have wanted to ask the previous DS about
|
// clear any pending path we may have wanted to ask the previous DS about
|
||||||
_pendingPath.clear();
|
_pendingPath.clear();
|
||||||
|
@ -142,6 +141,9 @@ void DomainHandler::setSocketAndID(const QString& hostname, quint16 port, const
|
||||||
// set the new hostname
|
// set the new hostname
|
||||||
_hostname = hostname;
|
_hostname = hostname;
|
||||||
|
|
||||||
|
// FIXME - is this the right place???
|
||||||
|
_domainConnectionRefusals.clear();
|
||||||
|
|
||||||
qCDebug(networking) << "Updated domain hostname to" << _hostname;
|
qCDebug(networking) << "Updated domain hostname to" << _hostname;
|
||||||
|
|
||||||
// re-set the sock addr to null and fire off a lookup of the IP address for this domain-server's hostname
|
// re-set the sock addr to null and fire off a lookup of the IP address for this domain-server's hostname
|
||||||
|
@ -349,34 +351,58 @@ void DomainHandler::processICEResponsePacket(QSharedPointer<ReceivedMessage> mes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DomainHandler::reasonSuggestsLogin(ConnectionRefusedReason reasonCode) {
|
||||||
|
switch (reasonCode) {
|
||||||
|
case ConnectionRefusedReason::LoginError:
|
||||||
|
case ConnectionRefusedReason::NotAuthorized:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case ConnectionRefusedReason::Unknown:
|
||||||
|
case ConnectionRefusedReason::ProtocolMismatch:
|
||||||
|
case ConnectionRefusedReason::TooManyUsers:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer<ReceivedMessage> message) {
|
void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
// Read deny reason from packet
|
// Read deny reason from packet
|
||||||
|
uint8_t reasonCodeWire;
|
||||||
|
|
||||||
|
message->readPrimitive(&reasonCodeWire);
|
||||||
|
ConnectionRefusedReason reasonCode = static_cast<ConnectionRefusedReason>(reasonCodeWire);
|
||||||
quint16 reasonSize;
|
quint16 reasonSize;
|
||||||
message->readPrimitive(&reasonSize);
|
message->readPrimitive(&reasonSize);
|
||||||
QString reason = QString::fromUtf8(message->readWithoutCopy(reasonSize));
|
auto reasonText = message->readWithoutCopy(reasonSize);
|
||||||
|
QString reasonMessage = QString::fromUtf8(reasonText);
|
||||||
|
|
||||||
// output to the log so the user knows they got a denied connection request
|
// output to the log so the user knows they got a denied connection request
|
||||||
// and check and signal for an access token so that we can make sure they are logged in
|
// and check and signal for an access token so that we can make sure they are logged in
|
||||||
qCWarning(networking) << "The domain-server denied a connection request: " << reason;
|
qCWarning(networking) << "The domain-server denied a connection request: " << reasonMessage;
|
||||||
qCWarning(networking) << "Make sure you are logged in.";
|
|
||||||
|
|
||||||
if (!_domainConnectionRefusals.contains(reason)) {
|
if (!_domainConnectionRefusals.contains(reasonMessage)) {
|
||||||
_domainConnectionRefusals.append(reason);
|
_domainConnectionRefusals.append(reasonMessage);
|
||||||
emit domainConnectionRefused(reason);
|
emit domainConnectionRefused(reasonMessage, (int)reasonCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
|
|
||||||
if (!_hasCheckedForAccessToken) {
|
// Some connection refusal reasons imply that a login is required. If so, suggest a new login
|
||||||
accountManager->checkAndSignalForAccessToken();
|
if (reasonSuggestsLogin(reasonCode)) {
|
||||||
_hasCheckedForAccessToken = true;
|
qCWarning(networking) << "Make sure you are logged in.";
|
||||||
}
|
|
||||||
|
|
||||||
static const int CONNECTION_DENIALS_FOR_KEYPAIR_REGEN = 3;
|
if (!_hasCheckedForAccessToken) {
|
||||||
|
accountManager->checkAndSignalForAccessToken();
|
||||||
|
_hasCheckedForAccessToken = true;
|
||||||
|
}
|
||||||
|
|
||||||
// force a re-generation of key-pair after CONNECTION_DENIALS_FOR_KEYPAIR_REGEN failed connection attempts
|
static const int CONNECTION_DENIALS_FOR_KEYPAIR_REGEN = 3;
|
||||||
if (++_connectionDenialsSinceKeypairRegen >= CONNECTION_DENIALS_FOR_KEYPAIR_REGEN) {
|
|
||||||
accountManager->generateNewUserKeypair();
|
// force a re-generation of key-pair after CONNECTION_DENIALS_FOR_KEYPAIR_REGEN failed connection attempts
|
||||||
_connectionDenialsSinceKeypairRegen = 0;
|
if (++_connectionDenialsSinceKeypairRegen >= CONNECTION_DENIALS_FOR_KEYPAIR_REGEN) {
|
||||||
|
accountManager->generateNewUserKeypair();
|
||||||
|
_connectionDenialsSinceKeypairRegen = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,15 @@ public:
|
||||||
bool isSocketKnown() const { return !_sockAddr.getAddress().isNull(); }
|
bool isSocketKnown() const { return !_sockAddr.getAddress().isNull(); }
|
||||||
|
|
||||||
void softReset();
|
void softReset();
|
||||||
|
|
||||||
|
enum class ConnectionRefusedReason : uint8_t {
|
||||||
|
Unknown,
|
||||||
|
ProtocolMismatch,
|
||||||
|
LoginError,
|
||||||
|
NotAuthorized,
|
||||||
|
TooManyUsers
|
||||||
|
};
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setSocketAndID(const QString& hostname, quint16 port = DEFAULT_DOMAIN_SERVER_PORT, const QUuid& id = QUuid());
|
void setSocketAndID(const QString& hostname, quint16 port = DEFAULT_DOMAIN_SERVER_PORT, const QUuid& id = QUuid());
|
||||||
void setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id);
|
void setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id);
|
||||||
|
@ -115,9 +124,10 @@ signals:
|
||||||
void settingsReceived(const QJsonObject& domainSettingsObject);
|
void settingsReceived(const QJsonObject& domainSettingsObject);
|
||||||
void settingsReceiveFail();
|
void settingsReceiveFail();
|
||||||
|
|
||||||
void domainConnectionRefused(QString reason);
|
void domainConnectionRefused(QString reasonMessage, int reason);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool reasonSuggestsLogin(ConnectionRefusedReason reasonCode);
|
||||||
void sendDisconnectPacket();
|
void sendDisconnectPacket();
|
||||||
void hardReset();
|
void hardReset();
|
||||||
|
|
||||||
|
|
|
@ -221,6 +221,10 @@ public:
|
||||||
|
|
||||||
void setConnectionMaxBandwidth(int maxBandwidth) { _nodeSocket.setConnectionMaxBandwidth(maxBandwidth); }
|
void setConnectionMaxBandwidth(int maxBandwidth) { _nodeSocket.setConnectionMaxBandwidth(maxBandwidth); }
|
||||||
|
|
||||||
|
void setPacketFilterOperator(udt::PacketFilterOperator filterOperator) { _nodeSocket.setPacketFilterOperator(filterOperator); }
|
||||||
|
bool packetVersionMatch(const udt::Packet& packet);
|
||||||
|
bool isPacketVerified(const udt::Packet& packet);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void reset();
|
void reset();
|
||||||
void eraseAllNodes();
|
void eraseAllNodes();
|
||||||
|
@ -269,8 +273,6 @@ protected:
|
||||||
|
|
||||||
void setLocalSocket(const HifiSockAddr& sockAddr);
|
void setLocalSocket(const HifiSockAddr& sockAddr);
|
||||||
|
|
||||||
bool isPacketVerified(const udt::Packet& packet);
|
|
||||||
bool packetVersionMatch(const udt::Packet& packet);
|
|
||||||
bool packetSourceAndHashMatch(const udt::Packet& packet);
|
bool packetSourceAndHashMatch(const udt::Packet& packet);
|
||||||
void processSTUNResponse(std::unique_ptr<udt::BasePacket> packet);
|
void processSTUNResponse(std::unique_ptr<udt::BasePacket> packet);
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@ int NLPacket::maxPayloadSize(PacketType type, bool isPartOfMessage) {
|
||||||
return Packet::maxPayloadSize(isPartOfMessage) - NLPacket::localHeaderSize(type);
|
return Packet::maxPayloadSize(isPartOfMessage) - NLPacket::localHeaderSize(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<NLPacket> NLPacket::create(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage) {
|
std::unique_ptr<NLPacket> NLPacket::create(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage, PacketVersion version) {
|
||||||
auto packet = std::unique_ptr<NLPacket>(new NLPacket(type, size, isReliable, isPartOfMessage));
|
auto packet = std::unique_ptr<NLPacket>(new NLPacket(type, size, isReliable, isPartOfMessage, version));
|
||||||
|
|
||||||
packet->open(QIODevice::ReadWrite);
|
packet->open(QIODevice::ReadWrite);
|
||||||
|
|
||||||
|
@ -61,13 +61,13 @@ std::unique_ptr<NLPacket> NLPacket::createCopy(const NLPacket& other) {
|
||||||
return std::unique_ptr<NLPacket>(new NLPacket(other));
|
return std::unique_ptr<NLPacket>(new NLPacket(other));
|
||||||
}
|
}
|
||||||
|
|
||||||
NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage) :
|
NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage, PacketVersion version) :
|
||||||
Packet((size == -1) ? -1 : NLPacket::localHeaderSize(type) + size, isReliable, isPartOfMessage),
|
Packet((size == -1) ? -1 : NLPacket::localHeaderSize(type) + size, isReliable, isPartOfMessage),
|
||||||
_type(type),
|
_type(type),
|
||||||
_version(versionForPacketType(type))
|
_version((version == 0) ? versionForPacketType(type) : version)
|
||||||
{
|
{
|
||||||
adjustPayloadStartAndCapacity(NLPacket::localHeaderSize(_type));
|
adjustPayloadStartAndCapacity(NLPacket::localHeaderSize(_type));
|
||||||
|
|
||||||
writeTypeAndVersion();
|
writeTypeAndVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH;
|
sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH;
|
||||||
|
|
||||||
static std::unique_ptr<NLPacket> create(PacketType type, qint64 size = -1,
|
static std::unique_ptr<NLPacket> create(PacketType type, qint64 size = -1,
|
||||||
bool isReliable = false, bool isPartOfMessage = false);
|
bool isReliable = false, bool isPartOfMessage = false, PacketVersion version = 0);
|
||||||
|
|
||||||
static std::unique_ptr<NLPacket> fromReceivedPacket(std::unique_ptr<char[]> data, qint64 size,
|
static std::unique_ptr<NLPacket> fromReceivedPacket(std::unique_ptr<char[]> data, qint64 size,
|
||||||
const HifiSockAddr& senderSockAddr);
|
const HifiSockAddr& senderSockAddr);
|
||||||
|
@ -73,7 +73,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
NLPacket(PacketType type, qint64 size = -1, bool forceReliable = false, bool isPartOfMessage = false);
|
NLPacket(PacketType type, qint64 size = -1, bool forceReliable = false, bool isPartOfMessage = false, PacketVersion version = 0);
|
||||||
NLPacket(std::unique_ptr<char[]> data, qint64 size, const HifiSockAddr& senderSockAddr);
|
NLPacket(std::unique_ptr<char[]> data, qint64 size, const HifiSockAddr& senderSockAddr);
|
||||||
|
|
||||||
NLPacket(const NLPacket& other);
|
NLPacket(const NLPacket& other);
|
||||||
|
|
|
@ -292,7 +292,8 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto domainPacket = NLPacket::create(domainPacketType);
|
auto packetVersion = (domainPacketType == PacketType::DomainConnectRequest) ? _domainConnectRequestVersion : 0;
|
||||||
|
auto domainPacket = NLPacket::create(domainPacketType, -1, false, false, packetVersion);
|
||||||
|
|
||||||
QDataStream packetStream(domainPacket.get());
|
QDataStream packetStream(domainPacket.get());
|
||||||
|
|
||||||
|
@ -312,12 +313,20 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
|
|
||||||
// pack the connect UUID for this connect request
|
// pack the connect UUID for this connect request
|
||||||
packetStream << connectUUID;
|
packetStream << connectUUID;
|
||||||
|
|
||||||
|
// include the protocol version signature in our connect request
|
||||||
|
if (_domainConnectRequestVersion >= static_cast<PacketVersion>(DomainConnectRequestVersion::HasProtocolVersions)) {
|
||||||
|
QByteArray protocolVersionSig = protocolVersionsSignature();
|
||||||
|
packetStream.writeBytes(protocolVersionSig.constData(), protocolVersionSig.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pack our data to send to the domain-server including
|
// pack our data to send to the domain-server including
|
||||||
// the hostname information (so the domain-server can see which place name we came in on)
|
// the hostname information (so the domain-server can see which place name we came in on)
|
||||||
packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList()
|
packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList();
|
||||||
<< DependencyManager::get<AddressManager>()->getPlaceName();
|
if (_domainConnectRequestVersion >= static_cast<PacketVersion>(DomainConnectRequestVersion::HasHostname)) {
|
||||||
|
packetStream << DependencyManager::get<AddressManager>()->getPlaceName();
|
||||||
|
}
|
||||||
|
|
||||||
if (!_domainHandler.isConnected()) {
|
if (!_domainHandler.isConnected()) {
|
||||||
DataServerAccountInfo& accountInfo = accountManager->getAccountInfo();
|
DataServerAccountInfo& accountInfo = accountManager->getAccountInfo();
|
||||||
|
|
|
@ -68,6 +68,9 @@ public:
|
||||||
|
|
||||||
void setIsShuttingDown(bool isShuttingDown) { _isShuttingDown = isShuttingDown; }
|
void setIsShuttingDown(bool isShuttingDown) { _isShuttingDown = isShuttingDown; }
|
||||||
|
|
||||||
|
/// downgrades the DomainConnnectRequest PacketVersion to attempt to probe for older domain servers
|
||||||
|
void downgradeDomainServerCheckInVersion() { _domainConnectRequestVersion--; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void reset();
|
void reset();
|
||||||
void sendDomainServerCheckIn();
|
void sendDomainServerCheckIn();
|
||||||
|
@ -85,6 +88,9 @@ public slots:
|
||||||
|
|
||||||
void processICEPingPacket(QSharedPointer<ReceivedMessage> message);
|
void processICEPingPacket(QSharedPointer<ReceivedMessage> message);
|
||||||
|
|
||||||
|
void resetDomainServerCheckInVersion()
|
||||||
|
{ _domainConnectRequestVersion = versionForPacketType(PacketType::DomainConnectRequest); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void limitOfSilentDomainCheckInsReached();
|
void limitOfSilentDomainCheckInsReached();
|
||||||
void receivedDomainServerList();
|
void receivedDomainServerList();
|
||||||
|
@ -123,6 +129,8 @@ private:
|
||||||
HifiSockAddr _assignmentServerSocket;
|
HifiSockAddr _assignmentServerSocket;
|
||||||
bool _isShuttingDown { false };
|
bool _isShuttingDown { false };
|
||||||
QTimer _keepAlivePingTimer;
|
QTimer _keepAlivePingTimer;
|
||||||
|
|
||||||
|
PacketVersion _domainConnectRequestVersion = versionForPacketType(PacketType::DomainConnectRequest);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_NodeList_h
|
#endif // hifi_NodeList_h
|
||||||
|
|
|
@ -12,7 +12,9 @@
|
||||||
#include "PacketHeaders.h"
|
#include "PacketHeaders.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <QtCore/QDataStream>
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtCore/QMetaEnum>
|
#include <QtCore/QMetaEnum>
|
||||||
|
|
||||||
|
@ -47,7 +49,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::EntityAdd:
|
case PacketType::EntityAdd:
|
||||||
case PacketType::EntityEdit:
|
case PacketType::EntityEdit:
|
||||||
case PacketType::EntityData:
|
case PacketType::EntityData:
|
||||||
return VERSION_ENTITIES_NO_FLY_ZONES;
|
return VERSION_ENTITIES_MORE_SHAPES;
|
||||||
case PacketType::AvatarIdentity:
|
case PacketType::AvatarIdentity:
|
||||||
case PacketType::AvatarData:
|
case PacketType::AvatarData:
|
||||||
case PacketType::BulkAvatarData:
|
case PacketType::BulkAvatarData:
|
||||||
|
@ -60,9 +62,13 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::AssetUpload:
|
case PacketType::AssetUpload:
|
||||||
// Removal of extension from Asset requests
|
// Removal of extension from Asset requests
|
||||||
return 18;
|
return 18;
|
||||||
|
|
||||||
|
case PacketType::DomainConnectionDenied:
|
||||||
|
return static_cast<PacketVersion>(DomainConnectionDeniedVersion::IncludesReasonCode);
|
||||||
|
|
||||||
case PacketType::DomainConnectRequest:
|
case PacketType::DomainConnectRequest:
|
||||||
// addition of referring hostname information
|
return static_cast<PacketVersion>(DomainConnectRequestVersion::HasProtocolVersions);
|
||||||
return 18;
|
|
||||||
default:
|
default:
|
||||||
return 17;
|
return 17;
|
||||||
}
|
}
|
||||||
|
@ -82,3 +88,36 @@ QDebug operator<<(QDebug debug, const PacketType& type) {
|
||||||
debug.nospace().noquote() << (uint8_t) type << " (" << typeName << ")";
|
debug.nospace().noquote() << (uint8_t) type << " (" << typeName << ")";
|
||||||
return debug.space();
|
return debug.space();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (PR_BUILD || DEV_BUILD)
|
||||||
|
static bool sendWrongProtocolVersion = false;
|
||||||
|
void sendWrongProtocolVersionsSignature(bool sendWrongVersion) {
|
||||||
|
sendWrongProtocolVersion = sendWrongVersion;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QByteArray protocolVersionsSignature() {
|
||||||
|
static QByteArray protocolVersionSignature;
|
||||||
|
static std::once_flag once;
|
||||||
|
std::call_once(once, [&] {
|
||||||
|
QByteArray buffer;
|
||||||
|
QDataStream stream(&buffer, QIODevice::WriteOnly);
|
||||||
|
uint8_t numberOfProtocols = static_cast<uint8_t>(PacketType::LAST_PACKET_TYPE) + 1;
|
||||||
|
stream << numberOfProtocols;
|
||||||
|
for (uint8_t packetType = 0; packetType < numberOfProtocols; packetType++) {
|
||||||
|
uint8_t packetTypeVersion = static_cast<uint8_t>(versionForPacketType(static_cast<PacketType>(packetType)));
|
||||||
|
stream << packetTypeVersion;
|
||||||
|
}
|
||||||
|
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||||
|
hash.addData(buffer);
|
||||||
|
protocolVersionSignature = hash.result();
|
||||||
|
});
|
||||||
|
|
||||||
|
#if (PR_BUILD || DEV_BUILD)
|
||||||
|
if (sendWrongProtocolVersion) {
|
||||||
|
return QByteArray("INCORRECTVERSION"); // only for debugging version checking
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return protocolVersionSignature;
|
||||||
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ public:
|
||||||
AssignmentClientStatus,
|
AssignmentClientStatus,
|
||||||
NoisyMute,
|
NoisyMute,
|
||||||
AvatarIdentity,
|
AvatarIdentity,
|
||||||
AvatarBillboard,
|
TYPE_UNUSED_1,
|
||||||
DomainConnectRequest,
|
DomainConnectRequest,
|
||||||
DomainServerRequireDTLS,
|
DomainServerRequireDTLS,
|
||||||
NodeJsonStats,
|
NodeJsonStats,
|
||||||
|
@ -94,7 +94,8 @@ public:
|
||||||
ICEServerHeartbeatDenied,
|
ICEServerHeartbeatDenied,
|
||||||
AssetMappingOperation,
|
AssetMappingOperation,
|
||||||
AssetMappingOperationReply,
|
AssetMappingOperationReply,
|
||||||
ICEServerHeartbeatACK
|
ICEServerHeartbeatACK,
|
||||||
|
LAST_PACKET_TYPE = ICEServerHeartbeatACK
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -109,6 +110,11 @@ extern const QSet<PacketType> NON_SOURCED_PACKETS;
|
||||||
extern const QSet<PacketType> RELIABLE_PACKETS;
|
extern const QSet<PacketType> RELIABLE_PACKETS;
|
||||||
|
|
||||||
PacketVersion versionForPacketType(PacketType packetType);
|
PacketVersion versionForPacketType(PacketType packetType);
|
||||||
|
QByteArray protocolVersionsSignature(); /// returns a unqiue signature for all the current protocols
|
||||||
|
|
||||||
|
#if (PR_BUILD || DEV_BUILD)
|
||||||
|
void sendWrongProtocolVersionsSignature(bool sendWrongVersion); /// for debugging version negotiation
|
||||||
|
#endif
|
||||||
|
|
||||||
uint qHash(const PacketType& key, uint seed);
|
uint qHash(const PacketType& key, uint seed);
|
||||||
QDebug operator<<(QDebug debug, const PacketType& type);
|
QDebug operator<<(QDebug debug, const PacketType& type);
|
||||||
|
@ -172,6 +178,7 @@ const PacketVersion VERSION_ENTITITES_HAVE_COLLISION_MASK = 55;
|
||||||
const PacketVersion VERSION_ATMOSPHERE_REMOVED = 56;
|
const PacketVersion VERSION_ATMOSPHERE_REMOVED = 56;
|
||||||
const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57;
|
const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57;
|
||||||
const PacketVersion VERSION_ENTITIES_NO_FLY_ZONES = 58;
|
const PacketVersion VERSION_ENTITIES_NO_FLY_ZONES = 58;
|
||||||
|
const PacketVersion VERSION_ENTITIES_MORE_SHAPES = 59;
|
||||||
|
|
||||||
enum class AvatarMixerPacketVersion : PacketVersion {
|
enum class AvatarMixerPacketVersion : PacketVersion {
|
||||||
TranslationSupport = 17,
|
TranslationSupport = 17,
|
||||||
|
@ -180,4 +187,15 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
||||||
AbsoluteSixByteRotations
|
AbsoluteSixByteRotations
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class DomainConnectRequestVersion : PacketVersion {
|
||||||
|
NoHostname = 17,
|
||||||
|
HasHostname,
|
||||||
|
HasProtocolVersions
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DomainConnectionDeniedVersion : PacketVersion {
|
||||||
|
ReasonMessageOnly = 17,
|
||||||
|
IncludesReasonCode
|
||||||
|
};
|
||||||
|
|
||||||
#endif // hifi_PacketHeaders_h
|
#endif // hifi_PacketHeaders_h
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
class ScriptAudioInjector : public QObject {
|
class ScriptAudioInjector : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(bool isPlaying READ isPlaying)
|
Q_PROPERTY(bool playing READ isPlaying)
|
||||||
Q_PROPERTY(float loudness READ getLoudness)
|
Q_PROPERTY(float loudness READ getLoudness)
|
||||||
Q_PROPERTY(AudioInjectorOptions options WRITE setOptions READ getOptions)
|
Q_PROPERTY(AudioInjectorOptions options WRITE setOptions READ getOptions)
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -282,7 +282,22 @@ void ViveControllerManager::InputDevice::handleHandController(float deltaTime, u
|
||||||
for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) {
|
for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) {
|
||||||
handleAxisEvent(deltaTime, i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand);
|
handleAxisEvent(deltaTime, i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// pseudo buttons the depend on both of the above for-loops
|
||||||
|
partitionTouchpad(controller::LS, controller::LX, controller::LY, controller::LS_CENTER, controller::LS_OUTER);
|
||||||
|
partitionTouchpad(controller::RS, controller::RX, controller::RY, controller::RS_CENTER, controller::RS_OUTER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViveControllerManager::InputDevice::partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPseudoButton, int outerPseudoButton) {
|
||||||
|
// Populate the L/RS_CENTER/OUTER pseudo buttons, corresponding to a partition of the L/RS space based on the X/Y values.
|
||||||
|
const float CENTER_DEADBAND = 0.6f;
|
||||||
|
if (_buttonPressedMap.find(sButton) != _buttonPressedMap.end()) {
|
||||||
|
float absX = abs(_axisStateMap[xAxis]);
|
||||||
|
float absY = abs(_axisStateMap[yAxis]);
|
||||||
|
bool isCenter = (absX < CENTER_DEADBAND) && (absY < CENTER_DEADBAND); // square deadband
|
||||||
|
_buttonPressedMap.insert(isCenter ? centerPseudoButton : outerPseudoButton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,6 +458,11 @@ controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableI
|
||||||
// touch pad press
|
// touch pad press
|
||||||
makePair(LS, "LS"),
|
makePair(LS, "LS"),
|
||||||
makePair(RS, "RS"),
|
makePair(RS, "RS"),
|
||||||
|
// Differentiate where we are in the touch pad click
|
||||||
|
makePair(LS_CENTER, "LSCenter"),
|
||||||
|
makePair(LS_OUTER, "LSOuter"),
|
||||||
|
makePair(RS_CENTER, "RSCenter"),
|
||||||
|
makePair(RS_OUTER, "RSOuter"),
|
||||||
|
|
||||||
// triggers
|
// triggers
|
||||||
makePair(LT, "LT"),
|
makePair(LT, "LT"),
|
||||||
|
|
|
@ -61,6 +61,7 @@ private:
|
||||||
void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand);
|
void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand);
|
||||||
void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
|
void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
|
||||||
const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand);
|
const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand);
|
||||||
|
void ViveControllerManager::InputDevice::partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPsuedoButton, int outerPseudoButton);
|
||||||
|
|
||||||
class FilteredStick {
|
class FilteredStick {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
// examples
|
// examples
|
||||||
//
|
//
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
// Creates a flock of birds that fly around and chirp, staying inside the corners of the box defined
|
// Creates a flock of birds that fly around and chirp, staying inside the corners of the box defined
|
||||||
// at the start of the script.
|
// at the start of the script.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
@ -13,12 +13,12 @@
|
||||||
// The rectangular area in the domain where the flock will fly
|
// The rectangular area in the domain where the flock will fly
|
||||||
var lowerCorner = { x: 0, y: 0, z: 0 };
|
var lowerCorner = { x: 0, y: 0, z: 0 };
|
||||||
var upperCorner = { x: 30, y: 10, z: 30 };
|
var upperCorner = { x: 30, y: 10, z: 30 };
|
||||||
var STARTING_FRACTION = 0.25;
|
var STARTING_FRACTION = 0.25;
|
||||||
|
|
||||||
var NUM_BIRDS = 50;
|
var NUM_BIRDS = 50;
|
||||||
var UPDATE_INTERVAL = 0.016;
|
var UPDATE_INTERVAL = 0.016;
|
||||||
var playSounds = true;
|
var playSounds = true;
|
||||||
var SOUND_PROBABILITY = 0.001;
|
var SOUND_PROBABILITY = 0.001;
|
||||||
var STARTING_LIFETIME = (1.0 / SOUND_PROBABILITY) * UPDATE_INTERVAL * 10;
|
var STARTING_LIFETIME = (1.0 / SOUND_PROBABILITY) * UPDATE_INTERVAL * 10;
|
||||||
var numPlaying = 0;
|
var numPlaying = 0;
|
||||||
var BIRD_SIZE = 0.08;
|
var BIRD_SIZE = 0.08;
|
||||||
|
@ -36,17 +36,17 @@ var ALIGNMENT_FORCE = 1.5;
|
||||||
var COHESION_FORCE = 1.0;
|
var COHESION_FORCE = 1.0;
|
||||||
var MAX_COHESION_VELOCITY = 0.5;
|
var MAX_COHESION_VELOCITY = 0.5;
|
||||||
|
|
||||||
var followBirds = false;
|
var followBirds = false;
|
||||||
var AVATAR_FOLLOW_RATE = 0.001;
|
var AVATAR_FOLLOW_RATE = 0.001;
|
||||||
var AVATAR_FOLLOW_VELOCITY_TIMESCALE = 2.0;
|
var AVATAR_FOLLOW_VELOCITY_TIMESCALE = 2.0;
|
||||||
var AVATAR_FOLLOW_ORIENTATION_RATE = 0.005;
|
var AVATAR_FOLLOW_ORIENTATION_RATE = 0.005;
|
||||||
var floor = false;
|
var floor = false;
|
||||||
var MAKE_FLOOR = false;
|
var MAKE_FLOOR = false;
|
||||||
|
|
||||||
var averageVelocity = { x: 0, y: 0, z: 0 };
|
var averageVelocity = { x: 0, y: 0, z: 0 };
|
||||||
var averagePosition = { x: 0, y: 0, z: 0 };
|
var averagePosition = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
var birdsLoaded = false;
|
var birdsLoaded = false;
|
||||||
|
|
||||||
var oldAvatarOrientation;
|
var oldAvatarOrientation;
|
||||||
var oldAvatarPosition;
|
var oldAvatarPosition;
|
||||||
|
@ -79,10 +79,10 @@ function updateBirds(deltaTime) {
|
||||||
birds[i].entityId = false;
|
birds[i].entityId = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Sum up average position and velocity
|
// Sum up average position and velocity
|
||||||
if (Vec3.length(properties.velocity) > MIN_ALIGNMENT_VELOCITY) {
|
if (Vec3.length(properties.velocity) > MIN_ALIGNMENT_VELOCITY) {
|
||||||
sumVelocity = Vec3.sum(sumVelocity, properties.velocity);
|
sumVelocity = Vec3.sum(sumVelocity, properties.velocity);
|
||||||
birdVelocitiesCounted += 1;
|
birdVelocitiesCounted += 1;
|
||||||
}
|
}
|
||||||
sumPosition = Vec3.sum(sumPosition, properties.position);
|
sumPosition = Vec3.sum(sumPosition, properties.position);
|
||||||
birdPositionsCounted += 1;
|
birdPositionsCounted += 1;
|
||||||
|
@ -93,10 +93,10 @@ function updateBirds(deltaTime) {
|
||||||
var randomVelocity = randomVector(RANDOM_FLAP_VELOCITY);
|
var randomVelocity = randomVector(RANDOM_FLAP_VELOCITY);
|
||||||
randomVelocity.y = FLAP_UP + Math.random() * FLAP_UP;
|
randomVelocity.y = FLAP_UP + Math.random() * FLAP_UP;
|
||||||
|
|
||||||
// Alignment Velocity
|
// Alignment Velocity
|
||||||
var alignmentVelocityMagnitude = Math.min(MAX_ALIGNMENT_VELOCITY, Vec3.length(Vec3.multiply(ALIGNMENT_FORCE, averageVelocity)));
|
var alignmentVelocityMagnitude = Math.min(MAX_ALIGNMENT_VELOCITY, Vec3.length(Vec3.multiply(ALIGNMENT_FORCE, averageVelocity)));
|
||||||
var alignmentVelocity = Vec3.multiply(alignmentVelocityMagnitude, Vec3.normalize(averageVelocity));
|
var alignmentVelocity = Vec3.multiply(alignmentVelocityMagnitude, Vec3.normalize(averageVelocity));
|
||||||
alignmentVelocity.y *= VERTICAL_ALIGNMENT_COUPLING;
|
alignmentVelocity.y *= VERTICAL_ALIGNMENT_COUPLING;
|
||||||
|
|
||||||
// Cohesion
|
// Cohesion
|
||||||
var distanceFromCenter = Vec3.length(Vec3.subtract(averagePosition, properties.position));
|
var distanceFromCenter = Vec3.length(Vec3.subtract(averagePosition, properties.position));
|
||||||
|
@ -107,10 +107,10 @@ function updateBirds(deltaTime) {
|
||||||
|
|
||||||
Entities.editEntity(birds[i].entityId, { velocity: Vec3.sum(properties.velocity, newVelocity) });
|
Entities.editEntity(birds[i].entityId, { velocity: Vec3.sum(properties.velocity, newVelocity) });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether to play a chirp
|
// Check whether to play a chirp
|
||||||
if (playSounds && (!birds[i].audioId || !birds[i].audioId.isPlaying) && (Math.random() < ((numPlaying > 0) ? SOUND_PROBABILITY / numPlaying : SOUND_PROBABILITY))) {
|
if (playSounds && (!birds[i].audioId || !birds[i].audioId.playing) && (Math.random() < ((numPlaying > 0) ? SOUND_PROBABILITY / numPlaying : SOUND_PROBABILITY))) {
|
||||||
var options = {
|
var options = {
|
||||||
position: properties.position,
|
position: properties.position,
|
||||||
volume: BIRD_MASTER_VOLUME
|
volume: BIRD_MASTER_VOLUME
|
||||||
|
@ -126,43 +126,43 @@ function updateBirds(deltaTime) {
|
||||||
// Change size, and update lifetime to keep bird alive
|
// Change size, and update lifetime to keep bird alive
|
||||||
Entities.editEntity(birds[i].entityId, { dimensions: Vec3.multiply(1.5, properties.dimensions),
|
Entities.editEntity(birds[i].entityId, { dimensions: Vec3.multiply(1.5, properties.dimensions),
|
||||||
lifetime: properties.ageInSeconds + STARTING_LIFETIME});
|
lifetime: properties.ageInSeconds + STARTING_LIFETIME});
|
||||||
|
|
||||||
} else if (birds[i].audioId) {
|
} else if (birds[i].audioId) {
|
||||||
// If bird is playing a chirp
|
// If bird is playing a chirp
|
||||||
if (!birds[i].audioId.isPlaying) {
|
if (!birds[i].audioId.playing) {
|
||||||
Entities.editEntity(birds[i].entityId, { dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE }});
|
Entities.editEntity(birds[i].entityId, { dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE }});
|
||||||
numPlaying--;
|
numPlaying--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep birds in their 'cage'
|
// Keep birds in their 'cage'
|
||||||
var bounce = false;
|
var bounce = false;
|
||||||
var newVelocity = properties.velocity;
|
var newVelocity = properties.velocity;
|
||||||
var newPosition = properties.position;
|
var newPosition = properties.position;
|
||||||
if (properties.position.x < lowerCorner.x) {
|
if (properties.position.x < lowerCorner.x) {
|
||||||
newPosition.x = lowerCorner.x;
|
newPosition.x = lowerCorner.x;
|
||||||
newVelocity.x *= -1.0;
|
newVelocity.x *= -1.0;
|
||||||
bounce = true;
|
bounce = true;
|
||||||
} else if (properties.position.x > upperCorner.x) {
|
} else if (properties.position.x > upperCorner.x) {
|
||||||
newPosition.x = upperCorner.x;
|
newPosition.x = upperCorner.x;
|
||||||
newVelocity.x *= -1.0;
|
newVelocity.x *= -1.0;
|
||||||
bounce = true;
|
bounce = true;
|
||||||
}
|
}
|
||||||
if (properties.position.y < lowerCorner.y) {
|
if (properties.position.y < lowerCorner.y) {
|
||||||
newPosition.y = lowerCorner.y;
|
newPosition.y = lowerCorner.y;
|
||||||
newVelocity.y *= -1.0;
|
newVelocity.y *= -1.0;
|
||||||
bounce = true;
|
bounce = true;
|
||||||
} else if (properties.position.y > upperCorner.y) {
|
} else if (properties.position.y > upperCorner.y) {
|
||||||
newPosition.y = upperCorner.y;
|
newPosition.y = upperCorner.y;
|
||||||
newVelocity.y *= -1.0;
|
newVelocity.y *= -1.0;
|
||||||
bounce = true;
|
bounce = true;
|
||||||
}
|
}
|
||||||
if (properties.position.z < lowerCorner.z) {
|
if (properties.position.z < lowerCorner.z) {
|
||||||
newPosition.z = lowerCorner.z;
|
newPosition.z = lowerCorner.z;
|
||||||
newVelocity.z *= -1.0;
|
newVelocity.z *= -1.0;
|
||||||
bounce = true;
|
bounce = true;
|
||||||
} else if (properties.position.z > upperCorner.z) {
|
} else if (properties.position.z > upperCorner.z) {
|
||||||
newPosition.z = upperCorner.z;
|
newPosition.z = upperCorner.z;
|
||||||
newVelocity.z *= -1.0;
|
newVelocity.z *= -1.0;
|
||||||
bounce = true;
|
bounce = true;
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ function updateBirds(deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update average velocity and position of flock
|
// Update average velocity and position of flock
|
||||||
if (birdVelocitiesCounted > 0) {
|
if (birdVelocitiesCounted > 0) {
|
||||||
averageVelocity = Vec3.multiply(1.0 / birdVelocitiesCounted, sumVelocity);
|
averageVelocity = Vec3.multiply(1.0 / birdVelocitiesCounted, sumVelocity);
|
||||||
//print(Vec3.length(averageVelocity));
|
//print(Vec3.length(averageVelocity));
|
||||||
|
@ -184,10 +184,10 @@ function updateBirds(deltaTime) {
|
||||||
MyAvatar.orientation = Quat.mix(MyAvatar.orientation, birdDirection, AVATAR_FOLLOW_ORIENTATION_RATE);
|
MyAvatar.orientation = Quat.mix(MyAvatar.orientation, birdDirection, AVATAR_FOLLOW_ORIENTATION_RATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (birdPositionsCounted > 0) {
|
if (birdPositionsCounted > 0) {
|
||||||
averagePosition = Vec3.multiply(1.0 / birdPositionsCounted, sumPosition);
|
averagePosition = Vec3.multiply(1.0 / birdPositionsCounted, sumPosition);
|
||||||
// If Following birds, update position
|
// If Following birds, update position
|
||||||
if (followBirds) {
|
if (followBirds) {
|
||||||
MyAvatar.position = Vec3.sum(Vec3.multiply(AVATAR_FOLLOW_RATE, MyAvatar.position), Vec3.multiply(1.0 - AVATAR_FOLLOW_RATE, averagePosition));
|
MyAvatar.position = Vec3.sum(Vec3.multiply(AVATAR_FOLLOW_RATE, MyAvatar.position), Vec3.multiply(1.0 - AVATAR_FOLLOW_RATE, averagePosition));
|
||||||
}
|
}
|
||||||
|
@ -211,12 +211,12 @@ Script.scriptEnding.connect(function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadBirds(howMany) {
|
function loadBirds(howMany) {
|
||||||
oldAvatarOrientation = MyAvatar.orientation;
|
oldAvatarOrientation = MyAvatar.orientation;
|
||||||
oldAvatarPosition = MyAvatar.position;
|
oldAvatarPosition = MyAvatar.position;
|
||||||
|
|
||||||
var sound_filenames = ["bushtit_1.raw", "bushtit_2.raw", "bushtit_3.raw"];
|
var sound_filenames = ["bushtit_1.raw", "bushtit_2.raw", "bushtit_3.raw"];
|
||||||
/* Here are more sounds/species you can use
|
/* Here are more sounds/species you can use
|
||||||
, "mexicanWhipoorwill.raw",
|
, "mexicanWhipoorwill.raw",
|
||||||
"rosyfacedlovebird.raw", "saysphoebe.raw", "westernscreechowl.raw", "bandtailedpigeon.wav", "bridledtitmouse.wav",
|
"rosyfacedlovebird.raw", "saysphoebe.raw", "westernscreechowl.raw", "bandtailedpigeon.wav", "bridledtitmouse.wav",
|
||||||
"browncrestedflycatcher.wav", "commonnighthawk.wav", "commonpoorwill.wav", "doublecrestedcormorant.wav",
|
"browncrestedflycatcher.wav", "commonnighthawk.wav", "commonpoorwill.wav", "doublecrestedcormorant.wav",
|
||||||
"gambelsquail.wav", "goldcrownedkinglet.wav", "greaterroadrunner.wav","groovebilledani.wav","hairywoodpecker.wav",
|
"gambelsquail.wav", "goldcrownedkinglet.wav", "greaterroadrunner.wav","groovebilledani.wav","hairywoodpecker.wav",
|
||||||
|
@ -252,19 +252,19 @@ function loadBirds(howMany) {
|
||||||
{ red: 216, green: 153, blue: 99 },
|
{ red: 216, green: 153, blue: 99 },
|
||||||
{ red: 242, green: 226, blue: 64 }
|
{ red: 242, green: 226, blue: 64 }
|
||||||
];
|
];
|
||||||
|
|
||||||
var SOUND_BASE_URL = "http://public.highfidelity.io/sounds/Animals/";
|
var SOUND_BASE_URL = "http://public.highfidelity.io/sounds/Animals/";
|
||||||
|
|
||||||
for (var i = 0; i < howMany; i++) {
|
for (var i = 0; i < howMany; i++) {
|
||||||
var whichBird = Math.floor(Math.random() * sound_filenames.length);
|
var whichBird = Math.floor(Math.random() * sound_filenames.length);
|
||||||
var position = {
|
var position = {
|
||||||
x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.x - lowerCorner.x) * STARTING_FRACTION,
|
x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.x - lowerCorner.x) * STARTING_FRACTION,
|
||||||
y: lowerCorner.y + (upperCorner.y - lowerCorner.y) / 2.0 + (Math.random() - 0.5) * (upperCorner.y - lowerCorner.y) * STARTING_FRACTION,
|
y: lowerCorner.y + (upperCorner.y - lowerCorner.y) / 2.0 + (Math.random() - 0.5) * (upperCorner.y - lowerCorner.y) * STARTING_FRACTION,
|
||||||
z: lowerCorner.z + (upperCorner.z - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.z - lowerCorner.z) * STARTING_FRACTION
|
z: lowerCorner.z + (upperCorner.z - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.z - lowerCorner.z) * STARTING_FRACTION
|
||||||
};
|
};
|
||||||
|
|
||||||
birds.push({
|
birds.push({
|
||||||
sound: SoundCache.getSound(SOUND_BASE_URL + sound_filenames[whichBird]),
|
sound: SoundCache.getSound(SOUND_BASE_URL + sound_filenames[whichBird]),
|
||||||
entityId: Entities.addEntity({
|
entityId: Entities.addEntity({
|
||||||
type: "Sphere",
|
type: "Sphere",
|
||||||
position: position,
|
position: position,
|
||||||
|
@ -282,8 +282,8 @@ function loadBirds(howMany) {
|
||||||
}
|
}
|
||||||
if (MAKE_FLOOR) {
|
if (MAKE_FLOOR) {
|
||||||
var FLOOR_THICKNESS = 0.05;
|
var FLOOR_THICKNESS = 0.05;
|
||||||
floor = Entities.addEntity({ type: "Box", position: { x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0,
|
floor = Entities.addEntity({ type: "Box", position: { x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0,
|
||||||
y: lowerCorner.y,
|
y: lowerCorner.y,
|
||||||
z: lowerCorner.z + (upperCorner.z - lowerCorner.z) / 2.0 },
|
z: lowerCorner.z + (upperCorner.z - lowerCorner.z) / 2.0 },
|
||||||
dimensions: { x: (upperCorner.x - lowerCorner.x), y: FLOOR_THICKNESS, z: (upperCorner.z - lowerCorner.z)},
|
dimensions: { x: (upperCorner.x - lowerCorner.x), y: FLOOR_THICKNESS, z: (upperCorner.z - lowerCorner.z)},
|
||||||
color: {red: 100, green: 100, blue: 100}
|
color: {red: 100, green: 100, blue: 100}
|
||||||
|
|
|
@ -49,7 +49,7 @@ function debug() { // Display the arguments not just [Object object].
|
||||||
EntityViewer.setCenterRadius(QUERY_RADIUS);
|
EntityViewer.setCenterRadius(QUERY_RADIUS);
|
||||||
|
|
||||||
// ENTITY DATA CACHE
|
// ENTITY DATA CACHE
|
||||||
//
|
//
|
||||||
var entityCache = {}; // A dictionary of unexpired EntityData objects.
|
var entityCache = {}; // A dictionary of unexpired EntityData objects.
|
||||||
var examinationCount = 0;
|
var examinationCount = 0;
|
||||||
function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about.
|
function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about.
|
||||||
|
@ -146,7 +146,7 @@ function EntityDatum(entityIdentifier) { // Just the data of an entity that we n
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC
|
that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC
|
||||||
if (!that.injector.isPlaying) { // Subtle: a looping sound will not check playbackGap.
|
if (!that.injector.playing) { // Subtle: a looping sound will not check playbackGap.
|
||||||
if (repeat()) { // WAITING => PLAYING
|
if (repeat()) { // WAITING => PLAYING
|
||||||
// Setup next play just once, now. Changes won't be looked at while we wait.
|
// Setup next play just once, now. Changes won't be looked at while we wait.
|
||||||
that.playAfter = randomizedNextPlay();
|
that.playAfter = randomizedNextPlay();
|
||||||
|
@ -208,7 +208,7 @@ function updateAllEntityData() { // A fast update of all entities we know about.
|
||||||
stats.entities++;
|
stats.entities++;
|
||||||
if (datum.url) {
|
if (datum.url) {
|
||||||
stats.sounds++;
|
stats.sounds++;
|
||||||
if (datum.injector && datum.injector.isPlaying) {
|
if (datum.injector && datum.injector.playing) {
|
||||||
stats.playing++;
|
stats.playing++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,7 +283,7 @@ function actionStartEvent(event) {
|
||||||
if (avatarIndex < avatars.length) {
|
if (avatarIndex < avatars.length) {
|
||||||
var actionPlace = avatars[avatarIndex];
|
var actionPlace = avatars[avatarIndex];
|
||||||
|
|
||||||
print("Changing avatar to " + actionPlace.name
|
print("Changing avatar to " + actionPlace.name
|
||||||
+ " after click on panel " + panelIndex + " with avatar index " + avatarIndex);
|
+ " after click on panel " + panelIndex + " with avatar index " + avatarIndex);
|
||||||
|
|
||||||
MyAvatar.useFullAvatarURL(actionPlace.content_url);
|
MyAvatar.useFullAvatarURL(actionPlace.content_url);
|
||||||
|
@ -395,7 +395,7 @@ function update(deltaTime) {
|
||||||
Overlays.editOverlay(descriptionText, { position: textOverlayPosition() });
|
Overlays.editOverlay(descriptionText, { position: textOverlayPosition() });
|
||||||
|
|
||||||
// if the reticle is up then we may need to play the next muzak
|
// if the reticle is up then we may need to play the next muzak
|
||||||
if (currentMuzakInjector && !currentMuzakInjector.isPlaying) {
|
if (currentMuzakInjector && !currentMuzakInjector.playing) {
|
||||||
playNextMuzak();
|
playNextMuzak();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ var CHATTER_VOLUME = 0.20
|
||||||
var EXTRA_VOLUME = 0.25
|
var EXTRA_VOLUME = 0.25
|
||||||
|
|
||||||
function playChatter() {
|
function playChatter() {
|
||||||
if (chatter.downloaded && !chatter.isPlaying) {
|
if (chatter.downloaded && !chatter.playing) {
|
||||||
Audio.playSound(chatter, { loop: true, volume: CHATTER_VOLUME });
|
Audio.playSound(chatter, { loop: true, volume: CHATTER_VOLUME });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ chatter.ready.connect(playChatter);
|
||||||
var currentInjector = null;
|
var currentInjector = null;
|
||||||
|
|
||||||
function playRandomExtras() {
|
function playRandomExtras() {
|
||||||
if ((!currentInjector || !currentInjector.isPlaying) && (Math.random() < (1.0 / 1800.0))) {
|
if ((!currentInjector || !currentInjector.playing) && (Math.random() < (1.0 / 1800.0))) {
|
||||||
// play a random extra sound about every 30s
|
// play a random extra sound about every 30s
|
||||||
currentInjector = Audio.playSound(
|
currentInjector = Audio.playSound(
|
||||||
extras[Math.floor(Math.random() * extras.length)],
|
extras[Math.floor(Math.random() * extras.length)],
|
||||||
|
|
|
@ -22,12 +22,12 @@ function printVector(v) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function vMinus(a, b) {
|
function vMinus(a, b) {
|
||||||
var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
|
var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The model file to be used for the guitar
|
// The model file to be used for the guitar
|
||||||
var guitarModel = HIFI_PUBLIC_BUCKET + "models/attachments/guitar.fst";
|
var guitarModel = HIFI_PUBLIC_BUCKET + "models/attachments/guitar.fst";
|
||||||
|
|
||||||
// Load sounds that will be played
|
// Load sounds that will be played
|
||||||
|
@ -47,7 +47,7 @@ chords[6] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Me
|
||||||
chords[7] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+E+short.raw");
|
chords[7] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+E+short.raw");
|
||||||
chords[8] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+G+short.raw");
|
chords[8] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+G+short.raw");
|
||||||
|
|
||||||
// Steel Guitar
|
// Steel Guitar
|
||||||
chords[9] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+A.raw");
|
chords[9] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+A.raw");
|
||||||
chords[10] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+B.raw");
|
chords[10] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+B.raw");
|
||||||
chords[11] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+E.raw");
|
chords[11] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+E.raw");
|
||||||
|
@ -83,8 +83,8 @@ if (leftHanded) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastPosition = { x: 0.0,
|
var lastPosition = { x: 0.0,
|
||||||
y: 0.0,
|
y: 0.0,
|
||||||
z: 0.0 };
|
z: 0.0 };
|
||||||
|
|
||||||
var audioInjector = null;
|
var audioInjector = null;
|
||||||
var selectorPressed = false;
|
var selectorPressed = false;
|
||||||
|
@ -106,7 +106,7 @@ function checkHands(deltaTime) {
|
||||||
var chord = Controller.getValue(chordTrigger);
|
var chord = Controller.getValue(chordTrigger);
|
||||||
|
|
||||||
if (volume > 1.0) volume = 1.0;
|
if (volume > 1.0) volume = 1.0;
|
||||||
if ((chord > 0.1) && audioInjector && audioInjector.isPlaying) {
|
if ((chord > 0.1) && audioInjector && audioInjector.playing) {
|
||||||
// If chord finger trigger pulled, stop current chord
|
// If chord finger trigger pulled, stop current chord
|
||||||
print("stopping chord because cord trigger pulled");
|
print("stopping chord because cord trigger pulled");
|
||||||
audioInjector.stop();
|
audioInjector.stop();
|
||||||
|
@ -119,7 +119,7 @@ function checkHands(deltaTime) {
|
||||||
guitarSelector += NUM_CHORDS;
|
guitarSelector += NUM_CHORDS;
|
||||||
if (guitarSelector >= NUM_CHORDS * NUM_GUITARS) {
|
if (guitarSelector >= NUM_CHORDS * NUM_GUITARS) {
|
||||||
guitarSelector = 0;
|
guitarSelector = 0;
|
||||||
}
|
}
|
||||||
print("new guitarBase: " + guitarSelector);
|
print("new guitarBase: " + guitarSelector);
|
||||||
stopAudio(true);
|
stopAudio(true);
|
||||||
selectorPressed = true;
|
selectorPressed = true;
|
||||||
|
@ -160,7 +160,7 @@ function checkHands(deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopAudio(killInjector) {
|
function stopAudio(killInjector) {
|
||||||
if (audioInjector && audioInjector.isPlaying) {
|
if (audioInjector && audioInjector.playing) {
|
||||||
print("stopped sound");
|
print("stopped sound");
|
||||||
audioInjector.stop();
|
audioInjector.stop();
|
||||||
}
|
}
|
||||||
|
@ -212,4 +212,3 @@ function scriptEnding() {
|
||||||
Script.update.connect(checkHands);
|
Script.update.connect(checkHands);
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
Controller.keyPressEvent.connect(keyPressEvent);
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
|
|
||||||
|
|
|
@ -340,7 +340,7 @@ function moveRats() {
|
||||||
var metaRat = getMetaRatByRat(rat);
|
var metaRat = getMetaRatByRat(rat);
|
||||||
if (metaRat !== undefined) {
|
if (metaRat !== undefined) {
|
||||||
if (metaRat.injector !== undefined) {
|
if (metaRat.injector !== undefined) {
|
||||||
if (metaRat.injector.isPlaying === true) {
|
if (metaRat.injector.playing === true) {
|
||||||
metaRat.injector.options = {
|
metaRat.injector.options = {
|
||||||
loop: true,
|
loop: true,
|
||||||
position: ratPosition
|
position: ratPosition
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
(function(){
|
(function(){
|
||||||
|
|
||||||
this.entityID = null;
|
this.entityID = null;
|
||||||
this.properties = null;
|
this.properties = null;
|
||||||
|
@ -30,13 +30,13 @@
|
||||||
"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove2.wav",
|
"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove2.wav",
|
||||||
"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove3.wav"
|
"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove3.wav"
|
||||||
];
|
];
|
||||||
|
|
||||||
this.turnSoundURLS = [
|
this.turnSoundURLS = [
|
||||||
|
|
||||||
"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove1.wav",
|
"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove1.wav",
|
||||||
"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove2.wav",
|
"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove2.wav",
|
||||||
"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove3.wav"
|
"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove3.wav"
|
||||||
|
|
||||||
// TODO: determine if these or other turn sounds work better than move sounds.
|
// TODO: determine if these or other turn sounds work better than move sounds.
|
||||||
//"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureTurn1.wav",
|
//"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureTurn1.wav",
|
||||||
//"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureTurn2.wav",
|
//"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureTurn2.wav",
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
this.turnSound = null;
|
this.turnSound = null;
|
||||||
this.moveInjector = null;
|
this.moveInjector = null;
|
||||||
this.turnInjector = null;
|
this.turnInjector = null;
|
||||||
|
|
||||||
var debug = false;
|
var debug = false;
|
||||||
var displayRotateTargets = true; // change to false if you don't want the rotate targets
|
var displayRotateTargets = true; // change to false if you don't want the rotate targets
|
||||||
var rotateOverlayTargetSize = 10000; // really big target
|
var rotateOverlayTargetSize = 10000; // really big target
|
||||||
|
@ -61,12 +61,12 @@
|
||||||
var yawZero;
|
var yawZero;
|
||||||
var rotationNormal;
|
var rotationNormal;
|
||||||
var yawNormal;
|
var yawNormal;
|
||||||
var stopSoundDelay = 100; // number of msecs of not moving to have sound stop
|
var stopSoundDelay = 100; // number of msecs of not moving to have sound stop
|
||||||
|
|
||||||
this.getRandomInt = function(min, max) {
|
this.getRandomInt = function(min, max) {
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.downloadSounds = function() {
|
this.downloadSounds = function() {
|
||||||
for (var i = 0; i < this.moveSoundURLS.length; i++) {
|
for (var i = 0; i < this.moveSoundURLS.length; i++) {
|
||||||
this.moveSounds[i] = SoundCache.getSound(this.moveSoundURLS[i]);
|
this.moveSounds[i] = SoundCache.getSound(this.moveSoundURLS[i]);
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
if (debug) {
|
if (debug) {
|
||||||
print("playMoveSound() --- calling this.moveInjector = Audio.playSound(this.moveSound...)");
|
print("playMoveSound() --- calling this.moveInjector = Audio.playSound(this.moveSound...)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.moveInjector) {
|
if (!this.moveInjector) {
|
||||||
this.moveInjector = Audio.playSound(this.moveSound, { position: this.properties.position, loop: true, volume: 0.1 });
|
this.moveInjector = Audio.playSound(this.moveSound, { position: this.properties.position, loop: true, volume: 0.1 });
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,7 +148,7 @@
|
||||||
var upVector = { x: 0, y: 1, z: 0 };
|
var upVector = { x: 0, y: 1, z: 0 };
|
||||||
var intersection = this.rayPlaneIntersection(pickRay.origin, pickRay.direction,
|
var intersection = this.rayPlaneIntersection(pickRay.origin, pickRay.direction,
|
||||||
this.properties.position, upVector);
|
this.properties.position, upVector);
|
||||||
|
|
||||||
var newPosition = Vec3.sum(intersection, this.graboffset);
|
var newPosition = Vec3.sum(intersection, this.graboffset);
|
||||||
Entities.editEntity(this.entityID, { position: newPosition });
|
Entities.editEntity(this.entityID, { position: newPosition });
|
||||||
};
|
};
|
||||||
|
@ -158,7 +158,7 @@
|
||||||
var pickRay = Camera.computePickRay(mouseEvent.x, mouseEvent.y)
|
var pickRay = Camera.computePickRay(mouseEvent.x, mouseEvent.y)
|
||||||
var upVector = { x: 0, y: 1, z: 0 };
|
var upVector = { x: 0, y: 1, z: 0 };
|
||||||
var intersection = this.rayPlaneIntersection(pickRay.origin, pickRay.direction,
|
var intersection = this.rayPlaneIntersection(pickRay.origin, pickRay.direction,
|
||||||
this.properties.position, upVector);
|
this.properties.position, upVector);
|
||||||
this.graboffset = Vec3.subtract(this.properties.position, intersection);
|
this.graboffset = Vec3.subtract(this.properties.position, intersection);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -183,18 +183,18 @@
|
||||||
this.lastMovedPosition.y = mouseEvent.y;
|
this.lastMovedPosition.y = mouseEvent.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.move = function(mouseEvent) {
|
this.move = function(mouseEvent) {
|
||||||
this.updatePosition(mouseEvent);
|
this.updatePosition(mouseEvent);
|
||||||
if (this.moveInjector === null || !this.moveInjector.isPlaying) {
|
if (this.moveInjector === null || !this.moveInjector.playing) {
|
||||||
this.playMoveSound();
|
this.playMoveSound();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.release = function(mouseEvent) {
|
this.release = function(mouseEvent) {
|
||||||
this.updatePosition(mouseEvent);
|
this.updatePosition(mouseEvent);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.rotate = function(mouseEvent) {
|
this.rotate = function(mouseEvent) {
|
||||||
var pickRay = Camera.computePickRay(mouseEvent.x, mouseEvent.y)
|
var pickRay = Camera.computePickRay(mouseEvent.x, mouseEvent.y)
|
||||||
var result = Overlays.findRayIntersection(pickRay);
|
var result = Overlays.findRayIntersection(pickRay);
|
||||||
|
@ -205,7 +205,7 @@
|
||||||
var centerToZero = Vec3.subtract(center, zero);
|
var centerToZero = Vec3.subtract(center, zero);
|
||||||
var centerToIntersect = Vec3.subtract(center, result.intersection);
|
var centerToIntersect = Vec3.subtract(center, result.intersection);
|
||||||
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
|
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
|
||||||
|
|
||||||
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
||||||
var snapToInner = false;
|
var snapToInner = false;
|
||||||
// var innerRadius = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
|
// var innerRadius = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
|
||||||
|
@ -213,10 +213,10 @@
|
||||||
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
|
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
|
||||||
snapToInner = true;
|
snapToInner = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var yawChange = Quat.fromVec3Degrees({ x: 0, y: angleFromZero, z: 0 });
|
var yawChange = Quat.fromVec3Degrees({ x: 0, y: angleFromZero, z: 0 });
|
||||||
Entities.editEntity(this.entityID, { rotation: Quat.multiply(yawChange, this.originalRotation) });
|
Entities.editEntity(this.entityID, { rotation: Quat.multiply(yawChange, this.originalRotation) });
|
||||||
|
|
||||||
|
|
||||||
// update the rotation display accordingly...
|
// update the rotation display accordingly...
|
||||||
var startAtCurrent = 360-angleFromZero;
|
var startAtCurrent = 360-angleFromZero;
|
||||||
|
@ -245,7 +245,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.turnInjector === null || !this.turnInjector.isPlaying) {
|
if (this.turnInjector === null || !this.turnInjector.playing) {
|
||||||
this.playTurnSound();
|
this.playTurnSound();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -267,7 +267,7 @@
|
||||||
this.rotateOverlayOuter = null;
|
this.rotateOverlayOuter = null;
|
||||||
this.rotateOverlayCurrent = null;
|
this.rotateOverlayCurrent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.displayRotateOverlay = function(mouseEvent) {
|
this.displayRotateOverlay = function(mouseEvent) {
|
||||||
var yawOverlayAngles = { x: 90, y: 0, z: 0 };
|
var yawOverlayAngles = { x: 90, y: 0, z: 0 };
|
||||||
var yawOverlayRotation = Quat.fromVec3Degrees(yawOverlayAngles);
|
var yawOverlayRotation = Quat.fromVec3Degrees(yawOverlayAngles);
|
||||||
|
@ -356,14 +356,14 @@
|
||||||
var pickRay = Camera.computePickRay(mouseEvent.x, mouseEvent.y)
|
var pickRay = Camera.computePickRay(mouseEvent.x, mouseEvent.y)
|
||||||
var result = Overlays.findRayIntersection(pickRay);
|
var result = Overlays.findRayIntersection(pickRay);
|
||||||
yawZero = result.intersection;
|
yawZero = result.intersection;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.preload = function(entityID) {
|
this.preload = function(entityID) {
|
||||||
this.updateProperties(entityID); // All callbacks start by updating the properties
|
this.updateProperties(entityID); // All callbacks start by updating the properties
|
||||||
this.downloadSounds();
|
this.downloadSounds();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.clickDownOnEntity = function(entityID, mouseEvent) {
|
this.clickDownOnEntity = function(entityID, mouseEvent) {
|
||||||
this.updateProperties(entityID); // All callbacks start by updating the properties
|
this.updateProperties(entityID); // All callbacks start by updating the properties
|
||||||
this.grab(mouseEvent);
|
this.grab(mouseEvent);
|
||||||
|
@ -372,13 +372,13 @@
|
||||||
var nowMSecs = nowDate.getTime();
|
var nowMSecs = nowDate.getTime();
|
||||||
this.clickedAt = nowMSecs;
|
this.clickedAt = nowMSecs;
|
||||||
this.firstHolding = true;
|
this.firstHolding = true;
|
||||||
|
|
||||||
this.clicked.x = mouseEvent.x;
|
this.clicked.x = mouseEvent.x;
|
||||||
this.clicked.y = mouseEvent.y;
|
this.clicked.y = mouseEvent.y;
|
||||||
this.lastMovedPosition.x = mouseEvent.x;
|
this.lastMovedPosition.x = mouseEvent.x;
|
||||||
this.lastMovedPosition.y = mouseEvent.y;
|
this.lastMovedPosition.y = mouseEvent.y;
|
||||||
this.lastMovedMSecs = nowMSecs;
|
this.lastMovedMSecs = nowMSecs;
|
||||||
|
|
||||||
this.pickRandomSounds();
|
this.pickRandomSounds();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -391,7 +391,7 @@
|
||||||
if (this.clicked.x == mouseEvent.x && this.clicked.y == mouseEvent.y) {
|
if (this.clicked.x == mouseEvent.x && this.clicked.y == mouseEvent.y) {
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
var now = d.getTime();
|
var now = d.getTime();
|
||||||
|
|
||||||
if (now - this.clickedAt > 500) {
|
if (now - this.clickedAt > 500) {
|
||||||
this.displayRotateOverlay(mouseEvent);
|
this.displayRotateOverlay(mouseEvent);
|
||||||
this.firstHolding = false;
|
this.firstHolding = false;
|
||||||
|
@ -402,13 +402,13 @@
|
||||||
this.firstHolding = false;
|
this.firstHolding = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.rotateMode) {
|
if (this.rotateMode) {
|
||||||
this.rotate(mouseEvent);
|
this.rotate(mouseEvent);
|
||||||
} else {
|
} else {
|
||||||
this.move(mouseEvent);
|
this.move(mouseEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stopSoundIfNotMoving(mouseEvent);
|
this.stopSoundIfNotMoving(mouseEvent);
|
||||||
};
|
};
|
||||||
this.clickReleaseOnEntity = function(entityID, mouseEvent) {
|
this.clickReleaseOnEntity = function(entityID, mouseEvent) {
|
||||||
|
@ -418,7 +418,7 @@
|
||||||
} else {
|
} else {
|
||||||
this.release(mouseEvent);
|
this.release(mouseEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.rotateOverlayTarget != null) {
|
if (this.rotateOverlayTarget != null) {
|
||||||
this.cleanupRotateOverlay();
|
this.cleanupRotateOverlay();
|
||||||
this.rotateMode = false;
|
this.rotateMode = false;
|
||||||
|
|
|
@ -22,7 +22,7 @@ var BIRD_VELOCITY = 2.0;
|
||||||
var LIGHT_RADIUS = 10.0;
|
var LIGHT_RADIUS = 10.0;
|
||||||
var BIRD_MASTER_VOLUME = 0.5;
|
var BIRD_MASTER_VOLUME = 0.5;
|
||||||
|
|
||||||
var useLights = true;
|
var useLights = true;
|
||||||
|
|
||||||
function randomVector(scale) {
|
function randomVector(scale) {
|
||||||
return { x: Math.random() * scale - scale / 2.0, y: Math.random() * scale - scale / 2.0, z: Math.random() * scale - scale / 2.0 };
|
return { x: Math.random() * scale - scale / 2.0, y: Math.random() * scale - scale / 2.0, z: Math.random() * scale - scale / 2.0 };
|
||||||
|
@ -33,11 +33,11 @@ function maybePlaySound(deltaTime) {
|
||||||
// Set the location and other info for the sound to play
|
// Set the location and other info for the sound to play
|
||||||
var whichBird = Math.floor(Math.random() * birds.length);
|
var whichBird = Math.floor(Math.random() * birds.length);
|
||||||
//print("playing sound # " + whichBird);
|
//print("playing sound # " + whichBird);
|
||||||
var position = {
|
var position = {
|
||||||
x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x),
|
x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x),
|
||||||
y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y),
|
y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y),
|
||||||
z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z)
|
z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z)
|
||||||
};
|
};
|
||||||
var options = {
|
var options = {
|
||||||
position: position,
|
position: position,
|
||||||
volume: BIRD_MASTER_VOLUME
|
volume: BIRD_MASTER_VOLUME
|
||||||
|
@ -63,31 +63,31 @@ function maybePlaySound(deltaTime) {
|
||||||
|
|
||||||
constantAttenuation: 0,
|
constantAttenuation: 0,
|
||||||
linearAttenuation: 4.0,
|
linearAttenuation: 4.0,
|
||||||
quadraticAttenuation: 2.0,
|
quadraticAttenuation: 2.0,
|
||||||
lifetime: 10
|
lifetime: 10
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
playing.push({ audioId: Audio.playSound(birds[whichBird].sound, options), entityId: entityId, lightId: lightId, color: birds[whichBird].color });
|
playing.push({ audioId: Audio.playSound(birds[whichBird].sound, options), entityId: entityId, lightId: lightId, color: birds[whichBird].color });
|
||||||
}
|
}
|
||||||
if (playing.length != numPlaying) {
|
if (playing.length != numPlaying) {
|
||||||
numPlaying = playing.length;
|
numPlaying = playing.length;
|
||||||
//print("number playing = " + numPlaying);
|
//print("number playing = " + numPlaying);
|
||||||
}
|
}
|
||||||
for (var i = 0; i < playing.length; i++) {
|
for (var i = 0; i < playing.length; i++) {
|
||||||
if (!playing[i].audioId.isPlaying) {
|
if (!playing[i].audioId.playing) {
|
||||||
Entities.deleteEntity(playing[i].entityId);
|
Entities.deleteEntity(playing[i].entityId);
|
||||||
if (useLights) {
|
if (useLights) {
|
||||||
Entities.deleteEntity(playing[i].lightId);
|
Entities.deleteEntity(playing[i].lightId);
|
||||||
}
|
}
|
||||||
playing.splice(i, 1);
|
playing.splice(i, 1);
|
||||||
} else {
|
} else {
|
||||||
var loudness = playing[i].audioId.loudness;
|
var loudness = playing[i].audioId.loudness;
|
||||||
var newColor = { red: playing[i].color.red, green: playing[i].color.green, blue: playing[i].color.blue };
|
var newColor = { red: playing[i].color.red, green: playing[i].color.green, blue: playing[i].color.blue };
|
||||||
if (loudness > 0.05) {
|
if (loudness > 0.05) {
|
||||||
newColor.red *= (1.0 - loudness);
|
newColor.red *= (1.0 - loudness);
|
||||||
newColor.green *= (1.0 - loudness);
|
newColor.green *= (1.0 - loudness);
|
||||||
newColor.blue *= (1.0 - loudness);
|
newColor.blue *= (1.0 - loudness);
|
||||||
}
|
}
|
||||||
var properties = Entities.getEntityProperties(playing[i].entityId);
|
var properties = Entities.getEntityProperties(playing[i].entityId);
|
||||||
var newPosition = Vec3.sum(properties.position, randomVector(BIRD_VELOCITY * deltaTime));
|
var newPosition = Vec3.sum(properties.position, randomVector(BIRD_VELOCITY * deltaTime));
|
||||||
|
@ -120,7 +120,7 @@ Script.scriptEnding.connect(function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadBirds() {
|
function loadBirds() {
|
||||||
var sound_filenames = ["bushtit_1.raw", "bushtit_2.raw", "bushtit_3.raw", "mexicanWhipoorwill.raw",
|
var sound_filenames = ["bushtit_1.raw", "bushtit_2.raw", "bushtit_3.raw", "mexicanWhipoorwill.raw",
|
||||||
"rosyfacedlovebird.raw", "saysphoebe.raw", "westernscreechowl.raw", "bandtailedpigeon.wav", "bridledtitmouse.wav",
|
"rosyfacedlovebird.raw", "saysphoebe.raw", "westernscreechowl.raw", "bandtailedpigeon.wav", "bridledtitmouse.wav",
|
||||||
"browncrestedflycatcher.wav", "commonnighthawk.wav", "commonpoorwill.wav", "doublecrestedcormorant.wav",
|
"browncrestedflycatcher.wav", "commonnighthawk.wav", "commonpoorwill.wav", "doublecrestedcormorant.wav",
|
||||||
"gambelsquail.wav", "goldcrownedkinglet.wav", "greaterroadrunner.wav","groovebilledani.wav","hairywoodpecker.wav",
|
"gambelsquail.wav", "goldcrownedkinglet.wav", "greaterroadrunner.wav","groovebilledani.wav","hairywoodpecker.wav",
|
||||||
|
@ -155,13 +155,13 @@ function loadBirds() {
|
||||||
{ red: 216, green: 153, blue: 99 },
|
{ red: 216, green: 153, blue: 99 },
|
||||||
{ red: 242, green: 226, blue: 64 }
|
{ red: 242, green: 226, blue: 64 }
|
||||||
];
|
];
|
||||||
|
|
||||||
var SOUND_BASE_URL = "http://public.highfidelity.io/sounds/Animals/";
|
var SOUND_BASE_URL = "http://public.highfidelity.io/sounds/Animals/";
|
||||||
|
|
||||||
for (var i = 0; i < sound_filenames.length; i++) {
|
for (var i = 0; i < sound_filenames.length; i++) {
|
||||||
birds.push({
|
birds.push({
|
||||||
sound: SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i]),
|
sound: SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i]),
|
||||||
color: colors[i]
|
color: colors[i]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,19 +88,19 @@ var DRONE_VOLUME = 0.3;
|
||||||
function drawLobby() {
|
function drawLobby() {
|
||||||
if (!panelWall) {
|
if (!panelWall) {
|
||||||
print("Adding overlays for the lobby panel wall and orb shell.");
|
print("Adding overlays for the lobby panel wall and orb shell.");
|
||||||
|
|
||||||
var cameraEuler = Quat.safeEulerAngles(Camera.orientation);
|
var cameraEuler = Quat.safeEulerAngles(Camera.orientation);
|
||||||
var towardsMe = Quat.angleAxis(cameraEuler.y + 180, { x: 0, y: 1, z: 0});
|
var towardsMe = Quat.angleAxis(cameraEuler.y + 180, { x: 0, y: 1, z: 0});
|
||||||
|
|
||||||
var orbPosition = Vec3.sum(Camera.position, Vec3.multiplyQbyV(towardsMe, ORB_SHIFT));
|
var orbPosition = Vec3.sum(Camera.position, Vec3.multiplyQbyV(towardsMe, ORB_SHIFT));
|
||||||
|
|
||||||
var panelWallProps = {
|
var panelWallProps = {
|
||||||
url: LOBBY_PANEL_WALL_URL,
|
url: LOBBY_PANEL_WALL_URL,
|
||||||
position: Vec3.sum(orbPosition, Vec3.multiplyQbyV(towardsMe, panelsCenterShift)),
|
position: Vec3.sum(orbPosition, Vec3.multiplyQbyV(towardsMe, panelsCenterShift)),
|
||||||
rotation: towardsMe,
|
rotation: towardsMe,
|
||||||
dimensions: panelsDimensions
|
dimensions: panelsDimensions
|
||||||
};
|
};
|
||||||
|
|
||||||
var orbShellProps = {
|
var orbShellProps = {
|
||||||
url: LOBBY_SHELL_URL,
|
url: LOBBY_SHELL_URL,
|
||||||
position: orbPosition,
|
position: orbPosition,
|
||||||
|
@ -128,13 +128,13 @@ function drawLobby() {
|
||||||
visible: false,
|
visible: false,
|
||||||
isFacingAvatar: true
|
isFacingAvatar: true
|
||||||
};
|
};
|
||||||
|
|
||||||
avatarStickPosition = MyAvatar.position;
|
avatarStickPosition = MyAvatar.position;
|
||||||
|
|
||||||
panelWall = Overlays.addOverlay("model", panelWallProps);
|
panelWall = Overlays.addOverlay("model", panelWallProps);
|
||||||
orbShell = Overlays.addOverlay("model", orbShellProps);
|
orbShell = Overlays.addOverlay("model", orbShellProps);
|
||||||
descriptionText = Overlays.addOverlay("text3d", descriptionTextProps);
|
descriptionText = Overlays.addOverlay("text3d", descriptionTextProps);
|
||||||
|
|
||||||
if (droneSound.downloaded) {
|
if (droneSound.downloaded) {
|
||||||
// start the drone sound
|
// start the drone sound
|
||||||
if (!currentDrone) {
|
if (!currentDrone) {
|
||||||
|
@ -143,7 +143,7 @@ function drawLobby() {
|
||||||
currentDrone.restart();
|
currentDrone.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// start one of our muzak sounds
|
// start one of our muzak sounds
|
||||||
playRandomMuzak();
|
playRandomMuzak();
|
||||||
}
|
}
|
||||||
|
@ -157,31 +157,31 @@ function changeLobbyTextures() {
|
||||||
req.send();
|
req.send();
|
||||||
|
|
||||||
places = JSON.parse(req.responseText).data.places;
|
places = JSON.parse(req.responseText).data.places;
|
||||||
|
|
||||||
var NUM_PANELS = places.length;
|
var NUM_PANELS = places.length;
|
||||||
|
|
||||||
var textureProp = {
|
var textureProp = {
|
||||||
textures: {}
|
textures: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var j = 0; j < NUM_PANELS; j++) {
|
for (var j = 0; j < NUM_PANELS; j++) {
|
||||||
var panelIndex = placeIndexToPanelIndex(j);
|
var panelIndex = placeIndexToPanelIndex(j);
|
||||||
textureProp["textures"]["file" + panelIndex] = places[j].previews.lobby;
|
textureProp["textures"]["file" + panelIndex] = places[j].previews.lobby;
|
||||||
};
|
};
|
||||||
|
|
||||||
Overlays.editOverlay(panelWall, textureProp);
|
Overlays.editOverlay(panelWall, textureProp);
|
||||||
}
|
}
|
||||||
|
|
||||||
var MUZAK_VOLUME = 0.1;
|
var MUZAK_VOLUME = 0.1;
|
||||||
|
|
||||||
function playCurrentSound(secondOffset) {
|
function playCurrentSound(secondOffset) {
|
||||||
if (currentSound == latinSound) {
|
if (currentSound == latinSound) {
|
||||||
if (!latinInjector) {
|
if (!latinInjector) {
|
||||||
latinInjector = Audio.playSound(latinSound, { localOnly: true, secondOffset: secondOffset, volume: MUZAK_VOLUME });
|
latinInjector = Audio.playSound(latinSound, { localOnly: true, secondOffset: secondOffset, volume: MUZAK_VOLUME });
|
||||||
} else {
|
} else {
|
||||||
latinInjector.restart();
|
latinInjector.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
currentMuzakInjector = latinInjector;
|
currentMuzakInjector = latinInjector;
|
||||||
} else if (currentSound == elevatorSound) {
|
} else if (currentSound == elevatorSound) {
|
||||||
if (!elevatorInjector) {
|
if (!elevatorInjector) {
|
||||||
|
@ -189,7 +189,7 @@ function playCurrentSound(secondOffset) {
|
||||||
} else {
|
} else {
|
||||||
elevatorInjector.restart();
|
elevatorInjector.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
currentMuzakInjector = elevatorInjector;
|
currentMuzakInjector = elevatorInjector;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,14 +205,14 @@ function playNextMuzak() {
|
||||||
currentSound = latinSound;
|
currentSound = latinSound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playCurrentSound(0);
|
playCurrentSound(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function playRandomMuzak() {
|
function playRandomMuzak() {
|
||||||
currentSound = null;
|
currentSound = null;
|
||||||
|
|
||||||
if (latinSound.downloaded && elevatorSound.downloaded) {
|
if (latinSound.downloaded && elevatorSound.downloaded) {
|
||||||
currentSound = Math.random() < 0.5 ? latinSound : elevatorSound;
|
currentSound = Math.random() < 0.5 ? latinSound : elevatorSound;
|
||||||
} else if (latinSound.downloaded) {
|
} else if (latinSound.downloaded) {
|
||||||
|
@ -220,11 +220,11 @@ function playRandomMuzak() {
|
||||||
} else if (elevatorSound.downloaded) {
|
} else if (elevatorSound.downloaded) {
|
||||||
currentSound = elevatorSound;
|
currentSound = elevatorSound;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentSound) {
|
if (currentSound) {
|
||||||
// pick a random number of seconds from 0-10 to offset the muzak
|
// pick a random number of seconds from 0-10 to offset the muzak
|
||||||
var secondOffset = Math.random() * 10;
|
var secondOffset = Math.random() * 10;
|
||||||
|
|
||||||
playCurrentSound(secondOffset);
|
playCurrentSound(secondOffset);
|
||||||
} else {
|
} else {
|
||||||
currentMuzakInjector = null;
|
currentMuzakInjector = null;
|
||||||
|
@ -233,36 +233,36 @@ function playRandomMuzak() {
|
||||||
|
|
||||||
function cleanupLobby() {
|
function cleanupLobby() {
|
||||||
toggleEnvironmentRendering(true);
|
toggleEnvironmentRendering(true);
|
||||||
|
|
||||||
// for each of the 21 placeholder textures, set them back to default so the cached model doesn't have changed textures
|
// for each of the 21 placeholder textures, set them back to default so the cached model doesn't have changed textures
|
||||||
var panelTexturesReset = {};
|
var panelTexturesReset = {};
|
||||||
panelTexturesReset["textures"] = {};
|
panelTexturesReset["textures"] = {};
|
||||||
|
|
||||||
for (var j = 0; j < MAX_NUM_PANELS; j++) {
|
for (var j = 0; j < MAX_NUM_PANELS; j++) {
|
||||||
panelTexturesReset["textures"]["file" + (j + 1)] = LOBBY_BLANK_PANEL_TEXTURE_URL;
|
panelTexturesReset["textures"]["file" + (j + 1)] = LOBBY_BLANK_PANEL_TEXTURE_URL;
|
||||||
};
|
};
|
||||||
|
|
||||||
Overlays.editOverlay(panelWall, panelTexturesReset);
|
Overlays.editOverlay(panelWall, panelTexturesReset);
|
||||||
|
|
||||||
Overlays.deleteOverlay(panelWall);
|
Overlays.deleteOverlay(panelWall);
|
||||||
Overlays.deleteOverlay(orbShell);
|
Overlays.deleteOverlay(orbShell);
|
||||||
Overlays.deleteOverlay(descriptionText);
|
Overlays.deleteOverlay(descriptionText);
|
||||||
|
|
||||||
panelWall = false;
|
panelWall = false;
|
||||||
orbShell = false;
|
orbShell = false;
|
||||||
|
|
||||||
if (currentDrone) {
|
if (currentDrone) {
|
||||||
currentDrone.stop();
|
currentDrone.stop();
|
||||||
currentDrone = null
|
currentDrone = null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentMuzakInjector) {
|
if (currentMuzakInjector) {
|
||||||
currentMuzakInjector.stop();
|
currentMuzakInjector.stop();
|
||||||
currentMuzakInjector = null;
|
currentMuzakInjector = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
places = {};
|
places = {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function actionStartEvent(event) {
|
function actionStartEvent(event) {
|
||||||
|
@ -271,19 +271,19 @@ function actionStartEvent(event) {
|
||||||
// check if we hit a panel and if we should jump there
|
// check if we hit a panel and if we should jump there
|
||||||
var result = Overlays.findRayIntersection(event.actionRay);
|
var result = Overlays.findRayIntersection(event.actionRay);
|
||||||
if (result.intersects && result.overlayID == panelWall) {
|
if (result.intersects && result.overlayID == panelWall) {
|
||||||
|
|
||||||
var panelName = result.extraInfo;
|
var panelName = result.extraInfo;
|
||||||
|
|
||||||
var panelStringIndex = panelName.indexOf("Panel");
|
var panelStringIndex = panelName.indexOf("Panel");
|
||||||
if (panelStringIndex != -1) {
|
if (panelStringIndex != -1) {
|
||||||
var panelIndex = parseInt(panelName.slice(5));
|
var panelIndex = parseInt(panelName.slice(5));
|
||||||
var placeIndex = panelIndexToPlaceIndex(panelIndex);
|
var placeIndex = panelIndexToPlaceIndex(panelIndex);
|
||||||
if (placeIndex < places.length) {
|
if (placeIndex < places.length) {
|
||||||
var actionPlace = places[placeIndex];
|
var actionPlace = places[placeIndex];
|
||||||
|
|
||||||
print("Jumping to " + actionPlace.name + " at " + actionPlace.address
|
print("Jumping to " + actionPlace.name + " at " + actionPlace.address
|
||||||
+ " after click on panel " + panelIndex + " with place index " + placeIndex);
|
+ " after click on panel " + panelIndex + " with place index " + placeIndex);
|
||||||
|
|
||||||
Window.location = actionPlace.address;
|
Window.location = actionPlace.address;
|
||||||
maybeCleanupLobby();
|
maybeCleanupLobby();
|
||||||
}
|
}
|
||||||
|
@ -328,7 +328,7 @@ function handleLookAt(pickRay) {
|
||||||
var placeIndex = panelIndexToPlaceIndex(panelIndex);
|
var placeIndex = panelIndexToPlaceIndex(panelIndex);
|
||||||
if (placeIndex < places.length) {
|
if (placeIndex < places.length) {
|
||||||
var actionPlace = places[placeIndex];
|
var actionPlace = places[placeIndex];
|
||||||
|
|
||||||
if (actionPlace.description == "") {
|
if (actionPlace.description == "") {
|
||||||
Overlays.editOverlay(descriptionText, { text: actionPlace.name, visible: showText });
|
Overlays.editOverlay(descriptionText, { text: actionPlace.name, visible: showText });
|
||||||
} else {
|
} else {
|
||||||
|
@ -378,7 +378,7 @@ function update(deltaTime) {
|
||||||
Overlays.editOverlay(descriptionText, { position: textOverlayPosition() });
|
Overlays.editOverlay(descriptionText, { position: textOverlayPosition() });
|
||||||
|
|
||||||
// if the reticle is up then we may need to play the next muzak
|
// if the reticle is up then we may need to play the next muzak
|
||||||
if (currentMuzakInjector && !currentMuzakInjector.isPlaying) {
|
if (currentMuzakInjector && !currentMuzakInjector.playing) {
|
||||||
playNextMuzak();
|
playNextMuzak();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
// playTestSound.js
|
// playTestSound.js
|
||||||
// examples
|
// examples
|
||||||
//
|
//
|
||||||
// Created by Philip Rosedale
|
// Created by Philip Rosedale
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
// Creates an object in front of you that changes color and plays a light
|
// Creates an object in front of you that changes color and plays a light
|
||||||
// at the start of a drum clip that loops. As you move away it will tell you in the
|
// at the start of a drum clip that loops. As you move away it will tell you in the
|
||||||
// log how many meters you are from the source.
|
// log how many meters you are from the source.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
@ -17,7 +17,7 @@ var sound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Dru
|
||||||
|
|
||||||
var position = Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0, y: 0.5, z: 0 }), Quat.getFront(MyAvatar.orientation));
|
var position = Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0, y: 0.5, z: 0 }), Quat.getFront(MyAvatar.orientation));
|
||||||
|
|
||||||
var time;
|
var time;
|
||||||
var soundPlaying = null;
|
var soundPlaying = null;
|
||||||
|
|
||||||
var baseColor = { red: 100, green: 100, blue: 100 };
|
var baseColor = { red: 100, green: 100, blue: 100 };
|
||||||
|
@ -38,8 +38,8 @@ var box = Entities.addEntity({
|
||||||
|
|
||||||
function checkSound(deltaTime) {
|
function checkSound(deltaTime) {
|
||||||
var started = false;
|
var started = false;
|
||||||
if (!sound.downloaded) {
|
if (!sound.downloaded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (soundPlaying == null) {
|
if (soundPlaying == null) {
|
||||||
soundPlaying = Audio.playSound(sound, {
|
soundPlaying = Audio.playSound(sound, {
|
||||||
|
@ -47,9 +47,9 @@ function checkSound(deltaTime) {
|
||||||
volume: 1.0,
|
volume: 1.0,
|
||||||
loop: false } );
|
loop: false } );
|
||||||
started = true;
|
started = true;
|
||||||
} else if (!soundPlaying.isPlaying) {
|
} else if (!soundPlaying.playing) {
|
||||||
soundPlaying.restart();
|
soundPlaying.restart();
|
||||||
started = true;
|
started = true;
|
||||||
}
|
}
|
||||||
if (started) {
|
if (started) {
|
||||||
Entities.editEntity(box, { color: litColor });
|
Entities.editEntity(box, { color: litColor });
|
||||||
|
@ -67,19 +67,19 @@ function checkSound(deltaTime) {
|
||||||
lifetime: lightTime / 1000
|
lifetime: lightTime / 1000
|
||||||
});
|
});
|
||||||
Script.setTimeout(resetColor, lightTime);
|
Script.setTimeout(resetColor, lightTime);
|
||||||
}
|
}
|
||||||
var currentDistance = Vec3.distance(MyAvatar.position, position);
|
var currentDistance = Vec3.distance(MyAvatar.position, position);
|
||||||
if (Math.abs(currentDistance - distance) > 1.0) {
|
if (Math.abs(currentDistance - distance) > 1.0) {
|
||||||
print("Distance from source: " + currentDistance);
|
print("Distance from source: " + currentDistance);
|
||||||
distance = currentDistance;
|
distance = currentDistance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetColor() {
|
function resetColor() {
|
||||||
Entities.editEntity(box, { color: baseColor });
|
Entities.editEntity(box, { color: baseColor });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function scriptEnding() {
|
function scriptEnding() {
|
||||||
Entities.deleteEntity(box);
|
Entities.deleteEntity(box);
|
||||||
if (soundPlaying) {
|
if (soundPlaying) {
|
||||||
|
@ -93,4 +93,3 @@ function scriptEnding() {
|
||||||
// Connect a call back that happens every frame
|
// Connect a call back that happens every frame
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
Script.update.connect(checkSound);
|
Script.update.connect(checkSound);
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,7 @@
|
||||||
// (For now, the thumb buttons on both controllers are always on.)
|
// (For now, the thumb buttons on both controllers are always on.)
|
||||||
// When over a HUD element, the reticle is shown where the active hand controller beam intersects the HUD.
|
// When over a HUD element, the reticle is shown where the active hand controller beam intersects the HUD.
|
||||||
// Otherwise, the active hand controller shows a red ball where a click will act.
|
// Otherwise, the active hand controller shows a red ball where a click will act.
|
||||||
//
|
|
||||||
// Bugs:
|
|
||||||
// On Windows, the upper left corner of Interface must be in the upper left corner of the screen, and the title bar must be 50px high. (System bug.)
|
|
||||||
// While hardware mouse move switches to mouse move, hardware mouse click (without amove) does not.
|
|
||||||
|
|
||||||
|
|
||||||
// UTILITIES -------------
|
// UTILITIES -------------
|
||||||
|
@ -269,76 +266,24 @@ function toggleHand() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create clickMappings as needed, on demand.
|
var clickMapping = Controller.newMapping(Script.resolvePath('') + '-click');
|
||||||
var clickMappings = {}, clickMapping, clickMapToggle;
|
Script.scriptEnding.connect(clickMapping.disable);
|
||||||
var hardware; // undefined
|
|
||||||
function checkHardware() {
|
|
||||||
var newHardware = Controller.Hardware.Hydra ? 'Hydra' : (Controller.Hardware.Vive ? 'Vive' : null); // not undefined
|
|
||||||
if (hardware === newHardware) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
print('Setting mapping for new controller hardware:', newHardware);
|
|
||||||
if (clickMapToggle) {
|
|
||||||
clickMapToggle.setState(false);
|
|
||||||
}
|
|
||||||
hardware = newHardware;
|
|
||||||
if (clickMappings[hardware]) {
|
|
||||||
clickMapping = clickMappings[hardware];
|
|
||||||
} else {
|
|
||||||
clickMapping = Controller.newMapping(Script.resolvePath('') + '-click-' + hardware);
|
|
||||||
Script.scriptEnding.connect(clickMapping.disable);
|
|
||||||
function mapToAction(button, action) {
|
|
||||||
clickMapping.from(Controller.Hardware[hardware][button]).peek().to(Controller.Actions[action]);
|
|
||||||
}
|
|
||||||
function makeHandToggle(button, hand, optionalWhen) {
|
|
||||||
var whenThunk = optionalWhen || function () {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
function maybeToggle() {
|
|
||||||
if (activeHand !== Controller.Standard[hand]) {
|
|
||||||
toggleHand();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
clickMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(Controller.Actions.ReticleClick);
|
||||||
clickMapping.from(Controller.Hardware[hardware][button]).peek().when(whenThunk).to(maybeToggle);
|
clickMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(Controller.Actions.ReticleClick);
|
||||||
}
|
clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(Controller.Actions.ContextMenu);
|
||||||
function makeViveWhen(click, x, y) {
|
clickMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(Controller.Actions.ContextMenu);
|
||||||
var viveClick = Controller.Hardware.Vive[click],
|
clickMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(function (on) {
|
||||||
viveX = Controller.Standard[x], // Standard after filtering by mapping
|
if (on && (activeHand !== Controller.Standard.RightHand)) {
|
||||||
viveY = Controller.Standard[y];
|
toggleHand();
|
||||||
return function () {
|
|
||||||
var clickValue = Controller.getValue(viveClick);
|
|
||||||
var xValue = Controller.getValue(viveX);
|
|
||||||
var yValue = Controller.getValue(viveY);
|
|
||||||
return clickValue && !xValue && !yValue;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
switch (hardware) {
|
|
||||||
case 'Hydra':
|
|
||||||
makeHandToggle('R3', 'RightHand');
|
|
||||||
makeHandToggle('L3', 'LeftHand');
|
|
||||||
|
|
||||||
mapToAction('R3', 'ReticleClick');
|
|
||||||
mapToAction('L3', 'ReticleClick');
|
|
||||||
mapToAction('R4', 'ContextMenu');
|
|
||||||
mapToAction('L4', 'ContextMenu');
|
|
||||||
break;
|
|
||||||
case 'Vive':
|
|
||||||
// When touchpad click is NOT treated as movement, treat as left click
|
|
||||||
makeHandToggle('RS', 'RightHand', makeViveWhen('RS', 'RX', 'RY'));
|
|
||||||
makeHandToggle('LS', 'LeftHand', makeViveWhen('LS', 'LX', 'LY'));
|
|
||||||
clickMapping.from(Controller.Hardware.Vive.RS).when(makeViveWhen('RS', 'RX', 'RY')).to(Controller.Actions.ReticleClick);
|
|
||||||
clickMapping.from(Controller.Hardware.Vive.LS).when(makeViveWhen('LS', 'LX', 'LY')).to(Controller.Actions.ReticleClick);
|
|
||||||
mapToAction('RightApplicationMenu', 'ContextMenu');
|
|
||||||
mapToAction('LeftApplicationMenu', 'ContextMenu');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
clickMappings[hardware] = clickMapping;
|
|
||||||
}
|
}
|
||||||
clickMapToggle = new LatchedToggle(clickMapping.enable, clickMapping.disable);
|
});
|
||||||
clickMapToggle.setState(true);
|
clickMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(function (on) {
|
||||||
}
|
if (on && (activeHand !== Controller.Standard.LeftHand)) {
|
||||||
checkHardware();
|
toggleHand();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
clickMapping.enable();
|
||||||
|
|
||||||
// VISUAL AID -----------
|
// VISUAL AID -----------
|
||||||
// Same properties as handControllerGrab search sphere
|
// Same properties as handControllerGrab search sphere
|
||||||
|
@ -415,8 +360,8 @@ function update() {
|
||||||
return turnOffVisualization();
|
return turnOffVisualization();
|
||||||
}
|
}
|
||||||
var controllerPose = Controller.getPoseValue(activeHand);
|
var controllerPose = Controller.getPoseValue(activeHand);
|
||||||
// Vive is effectively invalid when not in HMD
|
// Valid if any plugged-in hand controller is "on". (uncradled Hydra, green-lighted Vive...)
|
||||||
if (!controllerPose.valid || ((hardware === 'Vive') && !HMD.active)) {
|
if (!controllerPose.valid) {
|
||||||
return turnOffVisualization();
|
return turnOffVisualization();
|
||||||
} // Controller is cradled.
|
} // Controller is cradled.
|
||||||
var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation),
|
var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation),
|
||||||
|
@ -458,7 +403,6 @@ Script.scriptEnding.connect(function () {
|
||||||
var SETTINGS_CHANGE_RECHECK_INTERVAL = 10 * 1000; // milliseconds
|
var SETTINGS_CHANGE_RECHECK_INTERVAL = 10 * 1000; // milliseconds
|
||||||
function checkSettings() {
|
function checkSettings() {
|
||||||
updateFieldOfView();
|
updateFieldOfView();
|
||||||
checkHardware();
|
|
||||||
}
|
}
|
||||||
checkSettings();
|
checkSettings();
|
||||||
var settingsChecker = Script.setInterval(checkSettings, SETTINGS_CHANGE_RECHECK_INTERVAL);
|
var settingsChecker = Script.setInterval(checkSettings, SETTINGS_CHANGE_RECHECK_INTERVAL);
|
||||||
|
|
Loading…
Reference in a new issue