From f5994375cf8cf8d640812d7c5e573cc3771396cf Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 14 Nov 2017 14:24:03 -0800 Subject: [PATCH] Remove Marketplace's dependency on Edit.js for rez --- .../qml/hifi/commerce/checkout/Checkout.qml | 4 +- .../hifi/commerce/purchases/PurchasedItem.qml | 4 +- .../qml/hifi/commerce/purchases/Purchases.qml | 2 + scripts/system/marketplaces/marketplaces.js | 111 ++++++++++++++++++ 4 files changed, 115 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index dfe0c319e5..3e7c23f2dd 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -476,9 +476,7 @@ Rectangle { commerce.buy(itemId, itemPrice, true); } } else { - if (urlHandler.canHandleUrl(itemHref)) { - urlHandler.handleUrl(itemHref); - } + sendToScript({method: 'checkout_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable}); } } } diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index fb42865ba4..15ebada0c4 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -346,9 +346,7 @@ Item { enabled: (root.canRezCertifiedItems || root.isWearable) && root.purchaseStatus !== "invalidated"; onClicked: { - if (urlHandler.canHandleUrl(root.itemHref)) { - urlHandler.handleUrl(root.itemHref); - } + sendToPurchases({method: 'purchases_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable}); rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start(); } diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index f292f9603e..1ea488ac98 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -442,6 +442,8 @@ Rectangle { onSendToPurchases: { if (msg.method === 'purchases_itemInfoClicked') { sendToScript({method: 'purchases_itemInfoClicked', itemId: itemId}); + } else if (msg.method === "purchases_rezClicked") { + sendToScript({method: 'purchases_rezClicked', itemHref: itemHref, isWearable: isWearable}); } else if (msg.method === 'purchases_itemCertificateClicked') { inspectionCertificate.visible = true; inspectionCertificate.isLightbox = true; diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index efe5812ecb..83566fd207 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -168,6 +168,113 @@ })); } + var HALF_TREE_SCALE = 16384; + function getPositionToCreateEntity(extra) { + var CREATE_DISTANCE = 2; + var position; + var delta = extra !== undefined ? extra : 0; + if (Camera.mode === "entity" || Camera.mode === "independent") { + position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), CREATE_DISTANCE + delta)); + } else { + position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getForward(MyAvatar.orientation), CREATE_DISTANCE + delta)); + position.y += 0.5; + } + + if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) { + return null; + } + return position; + } + + function rezEntity(itemHref, isWearable) { + if (!isWearable && + (!Entities.canRez() && !Entities.canRezTmp() && + !Entities.canRezCertified() && !Entities.canRezTmpCertified())) { + Window.notifyEditError("You do not have the necessary permissions to place items on this domain."); + return; + } + + var success = Clipboard.importEntities(itemHref); + + if (success) { + var VERY_LARGE = 10000; + var isLargeImport = Clipboard.getClipboardContentsLargestDimension() >= VERY_LARGE; + var position = Vec3.ZERO; + if (!isLargeImport) { + position = getPositionToCreateEntity(Clipboard.getClipboardContentsLargestDimension() / 2); + } + if (position !== null && position !== undefined) { + var pastedEntityIDs = Clipboard.pasteEntities(position); + if (!isLargeImport) { + // The first entity in Clipboard gets the specified position with the rest being relative to it. Therefore, move + // entities after they're imported so that they're all the correct distance in front of and with geometric mean + // centered on the avatar/camera direction. + var deltaPosition = Vec3.ZERO; + var entityPositions = []; + var entityParentIDs = []; + + var propType = Entities.getEntityProperties(pastedEntityIDs[0], ["type"]).type; + var NO_ADJUST_ENTITY_TYPES = ["Zone", "Light", "ParticleEffect"]; + if (NO_ADJUST_ENTITY_TYPES.indexOf(propType) === -1) { + var targetDirection; + if (Camera.mode === "entity" || Camera.mode === "independent") { + targetDirection = Camera.orientation; + } else { + targetDirection = MyAvatar.orientation; + } + targetDirection = Vec3.multiplyQbyV(targetDirection, Vec3.UNIT_Z); + + var targetPosition = getPositionToCreateEntity(); + var deltaParallel = HALF_TREE_SCALE; // Distance to move entities parallel to targetDirection. + var deltaPerpendicular = Vec3.ZERO; // Distance to move entities perpendicular to targetDirection. + for (var i = 0, length = pastedEntityIDs.length; i < length; i++) { + var curLoopEntityProps = Entities.getEntityProperties(pastedEntityIDs[i], ["position", "dimensions", + "registrationPoint", "rotation", "parentID"]); + var adjustedPosition = adjustPositionPerBoundingBox(targetPosition, targetDirection, + curLoopEntityProps.registrationPoint, curLoopEntityProps.dimensions, curLoopEntityProps.rotation); + var delta = Vec3.subtract(adjustedPosition, curLoopEntityProps.position); + var distance = Vec3.dot(delta, targetDirection); + deltaParallel = Math.min(distance, deltaParallel); + deltaPerpendicular = Vec3.sum(Vec3.subtract(delta, Vec3.multiply(distance, targetDirection)), + deltaPerpendicular); + entityPositions[i] = curLoopEntityProps.position; + entityParentIDs[i] = curLoopEntityProps.parentID; + } + deltaPerpendicular = Vec3.multiply(1 / pastedEntityIDs.length, deltaPerpendicular); + deltaPosition = Vec3.sum(Vec3.multiply(deltaParallel, targetDirection), deltaPerpendicular); + } + + if (grid.getSnapToGrid()) { + var firstEntityProps = Entities.getEntityProperties(pastedEntityIDs[0], ["position", "dimensions", + "registrationPoint"]); + var positionPreSnap = Vec3.sum(deltaPosition, firstEntityProps.position); + position = grid.snapToSurface(grid.snapToGrid(positionPreSnap, false, firstEntityProps.dimensions, + firstEntityProps.registrationPoint), firstEntityProps.dimensions, firstEntityProps.registrationPoint); + deltaPosition = Vec3.subtract(position, firstEntityProps.position); + } + + if (!Vec3.equal(deltaPosition, Vec3.ZERO)) { + for (var editEntityIndex = 0, numEntities = pastedEntityIDs.length; editEntityIndex < numEntities; editEntityIndex++) { + if (Uuid.isNull(entityParentIDs[editEntityIndex])) { + Entities.editEntity(pastedEntityIDs[editEntityIndex], { + position: Vec3.sum(deltaPosition, entityPositions[editEntityIndex]) + }); + } + } + } + } + + if (isActive) { + selectionManager.setSelections(pastedEntityIDs); + } + } else { + Window.notifyEditError("Can't import entities: entities would be out of bounds."); + } + } else { + Window.notifyEditError("There was an error importing the entity file."); + } + } + marketplaceButton.clicked.connect(onClick); tablet.screenChanged.connect(onScreenChanged); Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged); @@ -330,6 +437,10 @@ tablet.gotoWebScreen(MARKETPLACE_URL + '/items/' + itemId, MARKETPLACES_INJECT_SCRIPT_URL); } break; + case 'checkout_rezClicked': + case 'purchases_rezClicked': + rezEntity(message.itemHref, message.isWearable); + break; case 'header_marketplaceImageClicked': case 'purchases_backClicked': tablet.gotoWebScreen(message.referrerURL, MARKETPLACES_INJECT_SCRIPT_URL);