Merge branch 'master' of github.com:highfidelity/hifi into cauterize-head-av-entities-1

This commit is contained in:
Seth Alves 2018-02-01 12:04:56 -08:00
commit bdf6736a54
13 changed files with 179 additions and 113 deletions

View file

@ -282,7 +282,7 @@ Menu::Menu() {
// Navigate > Show Address Bar
addActionToQMenuAndActionHash(navigateMenu, MenuOption::AddressBar, Qt::CTRL | Qt::Key_L,
dialogsManager.data(), SLOT(showAddressBar()));
dialogsManager.data(), SLOT(toggleAddressBar()));
// Navigate > LocationBookmarks related menus -- Note: the LocationBookmarks class adds its own submenus here.
auto locationBookmarks = DependencyManager::get<LocationBookmarks>();

View file

@ -16,6 +16,7 @@ CheckoutProxy::CheckoutProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(q
}
WalletScriptingInterface::WalletScriptingInterface() {
}
void WalletScriptingInterface::refreshWalletStatus() {
@ -26,4 +27,19 @@ void WalletScriptingInterface::refreshWalletStatus() {
void WalletScriptingInterface::setWalletStatus(const uint& status) {
_walletStatus = status;
emit DependencyManager::get<Wallet>()->walletStatusResult(status);
}
void WalletScriptingInterface::proveAvatarEntityOwnershipVerification(const QUuid& entityID) {
QSharedPointer<ContextOverlayInterface> contextOverlayInterface = DependencyManager::get<ContextOverlayInterface>();
EntityItemProperties entityProperties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID,
contextOverlayInterface->getEntityPropertyFlags());
if (entityProperties.getClientOnly()) {
if (!entityID.isNull() && entityProperties.getCertificateID().length() > 0) {
contextOverlayInterface->requestOwnershipVerification(entityID);
} else {
qCDebug(entities) << "Failed to prove ownership of:" << entityID << "is null or not a certified item";
}
} else {
qCDebug(entities) << "Failed to prove ownership of:" << entityID << "is not an avatar entity";
}
}

View file

@ -21,6 +21,7 @@
#include <OffscreenUi.h>
#include "Application.h"
#include "commerce/Wallet.h"
#include "ui/overlays/ContextOverlayInterface.h"
class CheckoutProxy : public QmlWrapper {
Q_OBJECT
@ -39,6 +40,7 @@ public:
Q_INVOKABLE void refreshWalletStatus();
Q_INVOKABLE uint getWalletStatus() { return _walletStatus; }
Q_INVOKABLE void proveAvatarEntityOwnershipVerification(const QUuid& entityID);
// setWalletStatus() should never be made Q_INVOKABLE. If it were,
// scripts could cause the Wallet to incorrectly report its status.
void setWalletStatus(const uint& status);
@ -46,6 +48,8 @@ public:
signals:
void walletStatusChanged();
void walletNotSetup();
void ownershipVerificationSuccess(const QUuid& entityID);
void ownershipVerificationFailed(const QUuid& entityID);
private:
uint _walletStatus;

View file

@ -22,7 +22,7 @@ class AddressBarDialog : public OffscreenQmlDialog {
Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged)
Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged)
Q_PROPERTY(bool useFeed READ useFeed WRITE setUseFeed NOTIFY useFeedChanged)
Q_PROPERTY(QString metaverseServerUrl READ metaverseServerUrl)
Q_PROPERTY(QString metaverseServerUrl READ metaverseServerUrl CONSTANT)
public:
AddressBarDialog(QQuickItem* parent = nullptr);

View file

@ -58,7 +58,7 @@ void DialogsManager::showAddressBar() {
hmd->openTablet();
}
qApp->setKeyboardFocusOverlay(hmd->getCurrentTabletScreenID());
emit addressBarShown(true);
setAddressBarVisible(true);
}
void DialogsManager::hideAddressBar() {
@ -71,7 +71,7 @@ void DialogsManager::hideAddressBar() {
hmd->closeTablet();
}
qApp->setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
emit addressBarShown(false);
setAddressBarVisible(false);
}
void DialogsManager::showFeed() {
@ -157,6 +157,24 @@ void DialogsManager::hmdToolsClosed() {
}
}
void DialogsManager::toggleAddressBar() {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
const bool addressBarLoaded = tablet->isPathLoaded(TABLET_ADDRESS_DIALOG);
if (_addressBarVisible || addressBarLoaded) {
hideAddressBar();
} else {
showAddressBar();
}
}
void DialogsManager::setAddressBarVisible(bool addressBarVisible) {
_addressBarVisible = addressBarVisible;
emit addressBarShown(_addressBarVisible);
}
void DialogsManager::showTestingResults() {
if (!_testingDialog) {
_testingDialog = new TestingDialog(qApp->getWindow());

View file

@ -39,6 +39,7 @@ public:
QPointer<OctreeStatsDialog> getOctreeStatsDialog() const { return _octreeStatsDialog; }
QPointer<TestingDialog> getTestingDialog() const { return _testingDialog; }
void emitAddressBarShown(bool visible) { emit addressBarShown(visible); }
void setAddressBarVisible(bool addressBarVisible);
public slots:
void showAddressBar();
@ -52,6 +53,7 @@ public slots:
void hmdTools(bool showTools);
void showDomainConnectionDialog();
void showTestingResults();
void toggleAddressBar();
// Application Update
void showUpdateDialog();
@ -78,7 +80,7 @@ private:
QPointer<OctreeStatsDialog> _octreeStatsDialog;
QPointer<TestingDialog> _testingDialog;
QPointer<DomainConnectionDialog> _domainConnectionDialog;
bool _closeAddressBar { false };
bool _addressBarVisible { false };
};
#endif // hifi_DialogsManager_h

View file

@ -266,6 +266,93 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemI
}
}
void ContextOverlayInterface::requestOwnershipVerification(const QUuid& entityID) {
setLastInspectedEntity(entityID);
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_lastInspectedEntity, _entityPropertyFlags);
auto nodeList = DependencyManager::get<NodeList>();
if (entityProperties.getClientOnly()) {
if (entityProperties.verifyStaticCertificateProperties()) {
SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer);
if (entityServer) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest;
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
QJsonObject request;
request["certificate_id"] = entityProperties.getCertificateID();
networkRequest.setUrl(requestURL);
QNetworkReply* networkReply = NULL;
networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
connect(networkReply, &QNetworkReply::finished, [=]() {
QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
jsonObject = jsonObject["data"].toObject();
if (networkReply->error() == QNetworkReply::NoError) {
if (!jsonObject["invalid_reason"].toString().isEmpty()) {
qCDebug(entities) << "invalid_reason not empty";
} else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") {
qCDebug(entities) << "'transfer_status' is 'failed'";
} else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") {
qCDebug(entities) << "'transfer_status' is 'pending'";
} else {
QString ownerKey = jsonObject["transfer_recipient_key"].toString();
QByteArray certID = entityProperties.getCertificateID().toUtf8();
QByteArray text = DependencyManager::get<EntityTreeRenderer>()->getTree()->computeNonce(certID, ownerKey);
QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122();
int certIDByteArraySize = certID.length();
int textByteArraySize = text.length();
int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length();
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
certIDByteArraySize + textByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
true);
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
challengeOwnershipPacket->writePrimitive(textByteArraySize);
challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize);
challengeOwnershipPacket->write(certID);
challengeOwnershipPacket->write(text);
challengeOwnershipPacket->write(nodeToChallengeByteArray);
nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer);
// Kickoff a 10-second timeout timer that marks the cert if we don't get an ownership response in time
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer");
return;
} else {
startChallengeOwnershipTimer();
}
}
} else {
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() <<
"More info:" << networkReply->readAll();
}
networkReply->deleteLater();
});
} else {
qCWarning(context_overlay) << "Couldn't get Entity Server!";
}
} else {
auto ledger = DependencyManager::get<Ledger>();
_challengeOwnershipTimeoutTimer.stop();
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED));
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationFailed(_lastInspectedEntity);
qCDebug(context_overlay) << "Entity" << _lastInspectedEntity << "failed static certificate verification!";
}
}
}
static const QString INSPECTION_CERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
void ContextOverlayInterface::openInspectionCertificate() {
// lets open the tablet to the inspection certificate QML
@ -275,87 +362,7 @@ void ContextOverlayInterface::openInspectionCertificate() {
_hmdScriptingInterface->openTablet();
setLastInspectedEntity(_currentEntityWithContextOverlay);
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_lastInspectedEntity, _entityPropertyFlags);
auto nodeList = DependencyManager::get<NodeList>();
if (entityProperties.getClientOnly()) {
if (entityProperties.verifyStaticCertificateProperties()) {
SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer);
if (entityServer) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest;
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
QJsonObject request;
request["certificate_id"] = entityProperties.getCertificateID();
networkRequest.setUrl(requestURL);
QNetworkReply* networkReply = NULL;
networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
connect(networkReply, &QNetworkReply::finished, [=]() {
QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
jsonObject = jsonObject["data"].toObject();
if (networkReply->error() == QNetworkReply::NoError) {
if (!jsonObject["invalid_reason"].toString().isEmpty()) {
qCDebug(entities) << "invalid_reason not empty";
} else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") {
qCDebug(entities) << "'transfer_status' is 'failed'";
} else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") {
qCDebug(entities) << "'transfer_status' is 'pending'";
} else {
QString ownerKey = jsonObject["transfer_recipient_key"].toString();
QByteArray certID = entityProperties.getCertificateID().toUtf8();
QByteArray text = DependencyManager::get<EntityTreeRenderer>()->getTree()->computeNonce(certID, ownerKey);
QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122();
int certIDByteArraySize = certID.length();
int textByteArraySize = text.length();
int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length();
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
certIDByteArraySize + textByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
true);
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
challengeOwnershipPacket->writePrimitive(textByteArraySize);
challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize);
challengeOwnershipPacket->write(certID);
challengeOwnershipPacket->write(text);
challengeOwnershipPacket->write(nodeToChallengeByteArray);
nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer);
// Kickoff a 10-second timeout timer that marks the cert if we don't get an ownership response in time
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer");
return;
} else {
startChallengeOwnershipTimer();
}
}
} else {
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() <<
"More info:" << networkReply->readAll();
}
networkReply->deleteLater();
});
} else {
qCWarning(context_overlay) << "Couldn't get Entity Server!";
}
} else {
auto ledger = DependencyManager::get<Ledger>();
_challengeOwnershipTimeoutTimer.stop();
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED));
qCDebug(context_overlay) << "Entity" << _lastInspectedEntity << "failed static certificate verification!";
}
}
requestOwnershipVerification(_lastInspectedEntity);
}
}
@ -397,6 +404,7 @@ void ContextOverlayInterface::startChallengeOwnershipTimer() {
connect(&_challengeOwnershipTimeoutTimer, &QTimer::timeout, this, [=]() {
qCDebug(entities) << "Ownership challenge timed out for" << _lastInspectedEntity;
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_TIMEOUT));
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationFailed(_lastInspectedEntity);
});
_challengeOwnershipTimeoutTimer.start(5000);
@ -421,7 +429,9 @@ void ContextOverlayInterface::handleChallengeOwnershipReplyPacket(QSharedPointer
if (verificationSuccess) {
emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_SUCCESS));
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationSuccess(_lastInspectedEntity);
} else {
emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED));
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationFailed(_lastInspectedEntity);
}
}

View file

@ -26,6 +26,7 @@
#include "ui/overlays/Overlays.h"
#include "scripting/HMDScriptingInterface.h"
#include "scripting/SelectionScriptingInterface.h"
#include "scripting/WalletScriptingInterface.h"
#include "EntityTree.h"
#include "ContextOverlayLogging.h"
@ -33,12 +34,13 @@
/**jsdoc
* @namespace ContextOverlay
*/
class ContextOverlayInterface : public QObject, public Dependency {
class ContextOverlayInterface : public QObject, public Dependency {
Q_OBJECT
Q_PROPERTY(QUuid entityWithContextOverlay READ getCurrentEntityWithContextOverlay WRITE setCurrentEntityWithContextOverlay)
Q_PROPERTY(bool enabled READ getEnabled WRITE setEnabled)
Q_PROPERTY(bool isInMarketplaceInspectionMode READ getIsInMarketplaceInspectionMode WRITE setIsInMarketplaceInspectionMode)
QSharedPointer<EntityScriptingInterface> _entityScriptingInterface;
EntityPropertyFlags _entityPropertyFlags;
QSharedPointer<HMDScriptingInterface> _hmdScriptingInterface;
@ -47,9 +49,7 @@ class ContextOverlayInterface : public QObject, public Dependency {
OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID };
std::shared_ptr<Image3DOverlay> _contextOverlay { nullptr };
public:
ContextOverlayInterface();
Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; }
void setCurrentEntityWithContextOverlay(const QUuid& entityID) { _currentEntityWithContextOverlay = entityID; }
void setLastInspectedEntity(const QUuid& entityID) { _challengeOwnershipTimeoutTimer.stop(); _lastInspectedEntity = entityID; }
@ -57,6 +57,8 @@ public:
bool getEnabled() { return _enabled; }
bool getIsInMarketplaceInspectionMode() { return _isInMarketplaceInspectionMode; }
void setIsInMarketplaceInspectionMode(bool mode) { _isInMarketplaceInspectionMode = mode; }
void requestOwnershipVerification(const QUuid& entityID);
EntityPropertyFlags getEntityPropertyFlags() { return _entityPropertyFlags; }
signals:
void contextOverlayClicked(const QUuid& currentEntityWithContextOverlay);
@ -80,8 +82,7 @@ private:
enum {
MAX_SELECTION_COUNT = 16
};
bool _verboseLogging { true };
bool _verboseLogging{ true };
bool _enabled { true };
EntityItemID _currentEntityWithContextOverlay{};
EntityItemID _lastInspectedEntity{};

View file

@ -72,6 +72,15 @@ Web3DOverlay::Web3DOverlay() {
connect(this, &Web3DOverlay::requestWebSurface, this, &Web3DOverlay::buildWebSurface);
connect(this, &Web3DOverlay::releaseWebSurface, this, &Web3DOverlay::destroyWebSurface);
connect(this, &Web3DOverlay::resizeWebSurface, this, &Web3DOverlay::onResizeWebSurface);
//need to be intialized before Tablet 1st open
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(_url);
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
_webSurface->getSurfaceContext()->setContextProperty("AccountServices", AccountServicesScriptingInterface::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
}
Web3DOverlay::Web3DOverlay(const Web3DOverlay* Web3DOverlay) :
@ -192,11 +201,6 @@ void Web3DOverlay::setupQmlSurface() {
_webSurface->getSurfaceContext()->setContextProperty("offscreenFlags", flags);
_webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
_webSurface->getSurfaceContext()->setContextProperty("AccountServices", AccountServicesScriptingInterface::getInstance());
// in Qt 5.10.0 there is already an "Audio" object in the QML context
// though I failed to find it (from QtMultimedia??). So.. let it be "AudioScriptingInterface"
_webSurface->getSurfaceContext()->setContextProperty("AudioScriptingInterface", DependencyManager::get<AudioScriptingInterface>().data());

View file

@ -51,9 +51,9 @@ void EntityScriptServerLogClient::enableToEntityServerScriptLog(bool enable) {
if (_subscribed != enable) {
if (enable) {
emit receivedNewLogLines("====================== Subscribded to the Entity Script Server's log ======================");
emit receivedNewLogLines("====================== Subscribed to the Entity Script Server's log ======================");
} else {
emit receivedNewLogLines("==================== Unsubscribded from the Entity Script Server's log ====================");
emit receivedNewLogLines("==================== Unsubscribed from the Entity Script Server's log ====================");
}
}
_subscribed = enable;

View file

@ -10,7 +10,7 @@
getControllerJointIndex, enableDispatcherModule, disableDispatcherModule,
Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions,
Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, entityIsCloneable,
cloneEntity, DISPATCHER_PROPERTIES, TEAR_AWAY_DISTANCE
cloneEntity, DISPATCHER_PROPERTIES, TEAR_AWAY_DISTANCE, Uuid
*/
Script.include("/~/system/libraries/Xform.js");
@ -269,6 +269,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
this.grabEntityProps = null;
this.shouldSendStart = false;
this.equipedWithSecondary = false;
this.handHasBeenRightsideUp = false;
this.parameters = makeDispatcherModuleParameters(
300,
@ -486,15 +487,17 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
var grabbedProperties = Entities.getEntityProperties(this.targetEntityID);
// if an object is "equipped" and has a predefined offset, use it.
var offsets = getAttachPointForHotspotFromSettings(this.grabbedHotspot, this.hand);
if (offsets) {
this.offsetPosition = offsets[0];
this.offsetRotation = offsets[1];
} else {
var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand";
if (this.grabbedHotspot.joints[handJointName]) {
this.offsetPosition = this.grabbedHotspot.joints[handJointName][0];
this.offsetRotation = this.grabbedHotspot.joints[handJointName][1];
if (this.grabbedHotspot) {
var offsets = getAttachPointForHotspotFromSettings(this.grabbedHotspot, this.hand);
if (offsets) {
this.offsetPosition = offsets[0];
this.offsetRotation = offsets[1];
} else {
var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand";
if (this.grabbedHotspot.joints[handJointName]) {
this.offsetPosition = this.grabbedHotspot.joints[handJointName][0];
this.offsetRotation = this.grabbedHotspot.joints[handJointName][1];
}
}
}
@ -549,7 +552,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
// 100 ms seems to be sufficient time to force the check even occur after the object has been initialized.
Script.setTimeout(grabEquipCheck, 100);
}
};
this.endEquipEntity = function () {
@ -624,7 +626,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
this.grabbedHotspot = potentialEquipHotspot;
this.targetEntityID = this.grabbedHotspot.entityID;
this.startEquipEntity(controllerData);
this.messageGrabEnity = false;
this.messageGrabEntity = false;
this.equipedWithSecondary = this.secondarySmoothedSqueezed();
return makeRunningValues(true, [potentialEquipHotspot.entityID], []);
} else {
@ -640,6 +642,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
this.isReady = function (controllerData, deltaTime) {
var timestamp = Date.now();
this.updateInputs(controllerData);
this.handHasBeenRightsideUp = false;
return this.checkNearbyHotspots(controllerData, deltaTime, timestamp);
};
@ -671,7 +674,14 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
return makeRunningValues(false, [], []);
}
var dropDetected = this.dropGestureProcess(deltaTime);
var handIsUpsideDown = this.dropGestureProcess(deltaTime);
var dropDetected = false;
if (this.handHasBeenRightsideUp) {
dropDetected = handIsUpsideDown;
}
if (!handIsUpsideDown) {
this.handHasBeenRightsideUp = true;
}
if (this.triggerSmoothedReleased() || this.secondaryReleased()) {
if (this.shouldSendStart) {
@ -692,7 +702,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
}
// highlight the grabbed hotspot when the dropGesture is detected.
if (dropDetected) {
if (dropDetected && this.grabbedHotspot) {
equipHotspotBuddy.updateHotspot(this.grabbedHotspot, timestamp);
equipHotspotBuddy.highlightHotspot(this.grabbedHotspot);
}

View file

@ -35,4 +35,5 @@
button.editProperties({isActive: true});
}
Script.scriptEnding.connect(cleanup);
}());

View file

@ -23,7 +23,7 @@ var BALL_DENSITY = 1000;
var ACTION_DISTANCE = 0.35;
var ACTION_TIMESCALE = 0.035;
var MAX_DISTANCE_MULTIPLIER = 4;
var STICK_SCRIPT_URL = Script.resolvePath("./entity_scripts/tetherballStick.js?v=" + Date.now());
var STICK_SCRIPT_URL = Script.resolvePath("./entity_scripts/tetherballStick.js");
var STICK_MODEL_URL = "http://hifi-content.s3.amazonaws.com/caitlyn/production/raveStick/newRaveStick2.fbx";
var COLLISION_SOUND_URL = "http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav";