content/hifi-content/davidback/development/avatarshop/CheckoutZone/checkoutZone.js
2022-02-13 22:49:05 +01:00

372 lines
No EOL
15 KiB
JavaScript

//
// checkoutZone.js
//
// Created by Rebecca Stankus on 9/29/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// This zone will provide an area at which a user may purchase an item. When the avatar enters the zone wearing a
// marketplace item, the item will appear as a small overlay. Scanning the overlay will cause the
// the tablet to open to the marketplace home page for that item, allowing the user to quickly make the purchase.
/* global Render, Wallet */
(function () {
var mini = false;
var SHARED = Script.require('../attachmentZoneShared.js');
var MAX_ITEMS = 12;
var HALF = 0.5;
var OVERLAY_PREFIX = 'MP';
var TRANSFORMS_SETTINGS = 'io.highfidelity.avatarStore.checkOut.transforms';
var ENTER_ZONE_SOUND = SoundCache.getSound(Script.resolvePath("../sounds/sound5.wav"));
var APP_NAME = "CHECKOUT";
var APP_URL = "https://hifi-content.s3.amazonaws.com/rebecca/CheckoutZone/CheckoutWelcome.html";
var APP_ICON = "https://hifi-content.s3.amazonaws.com/rebecca/CheckoutZone/shoppingCart.svg";
var OVERLAY_ROTATIONAL_OFFSET = { x: 10, y: 140, z: 0 };
var TABLET = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var TABLET_ROTATIONAL_OFFSET = { x: 10, y: 220, z: 0 };
var MARKETPLACE_WALLET_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/wallet/Wallet.qml";
// Milliseconds
var TRANSLATION_CHECK_INTERVAL = 100;
var SHORTER_STOP_TIMEOUT = 1000;
var TRANSLATION_STOP_TIMEOUT = 5000;
var itemHeight;
var tabletLocalOffset;
var _this = this;
var isInZone = false;
var tableProperties, tableHeight, tableLength, tableID, spawnZ, spawnY, spawnX;
var zoneID;
var replicaList = [];
var button;
var recycleBinID;
var scannerZone;
var replicaStoredTransforms = {};
var yOffset, zOffset, xOffset;
var scannerPosition;
this.preload = function(entityID) {
zoneID = entityID;
var sizeLimit = 1;
if (Entities.getEntityProperties(zoneID, 'dimensions.x').dimensions.x < sizeLimit) {
mini = true;
}
if (mini) {
itemHeight = 0.04;
tabletLocalOffset = { x: -0.01, y: 0.53, z: -0.4 };
} else {
itemHeight = 0.07;
tabletLocalOffset = { x: -0.1, y: 0.74, z: -0.35 };
}
};
var getTransformForMarketplaceItems = function() {
return Settings.getValue(TRANSFORMS_SETTINGS, {});
};
var getTransformsForMarketplaceItem = function(marketplaceID) {
var transformItems = getTransformForMarketplaceItems();
if (transformItems[marketplaceID] === undefined) {
return {
certificateTransforms: {},
unsortedTransforms: [],
lastUsedUnsortedTransformIndex: -1
};
}
return transformItems[marketplaceID];
};
var addTransformForMarketplaceItem = function(marketplaceID, certificateID, transform) {
if (marketplaceID === undefined) {
return;
}
var marketplaceItemTransforms = getTransformForMarketplaceItems();
var marketplaceItemTransform = getTransformsForMarketplaceItem(marketplaceID);
if (certificateID !== undefined) {
marketplaceItemTransform.certificateTransforms[certificateID] = transform;
} else {
marketplaceItemTransform.unsortedTransforms.push(transform);
}
marketplaceItemTransforms[marketplaceID] = marketplaceItemTransform;
Settings.setValue(TRANSFORMS_SETTINGS, marketplaceItemTransforms);
};
var collectZoneData = (function(){
var zoneChildren = Entities.getChildrenIDs(zoneID);
zoneChildren.forEach(function (childID) {
var name = Entities.getEntityProperties(childID, 'name').name;
if (name === "Checkout Table") {
tableProperties = Entities.getEntityProperties(childID, ['id', 'position', 'dimensions', 'rotation']);
tableID = tableProperties.id;
tableHeight = tableProperties.dimensions.y;
tableLength = tableProperties.dimensions.x;
var halfTableHeight = HALF * tableHeight;
if (mini) {
yOffset = 0.2;
zOffset = 0;
xOffset = 0;
} else {
yOffset = 0;
zOffset = 0.3;
xOffset = -0.05;
}
spawnY = halfTableHeight + yOffset;
var halfTableLength = HALF * tableLength;
spawnZ = (halfTableLength - itemHeight + zOffset);
spawnX = xOffset;
return;
}
});
var tableChildren = Entities.getChildrenIDs(tableID);
tableChildren.forEach(function (childID) {
var tableChildName = Entities.getEntityProperties(childID, 'name').name;
if (tableChildName === "Checkout Recycle") {
recycleBinID = childID;
return;
} else if (tableChildName === "Checkout Scan Zone") {
scannerZone = childID;
scannerPosition = Entities.getEntityProperties(scannerZone, 'position').position;
return;
}
});
});
// Spawn a copy of each attachment scaled down to fit the ITEM_HEIGHT and place it on the checkout table
var spawnOverlayReplica = (function(entityID) {
var entityProperties = Entities.getEntityProperties(entityID, [
'name', 'modelURL', 'type', 'dimensions', 'marketplaceID',
'localPosition', 'localRotation', 'parentJointIndex', 'userData'
]);
var overlayProperties = {
url: entityProperties.modelURL,
name: OVERLAY_PREFIX + entityProperties.marketplaceID,
alpha: true,
grabbable: true,
parentID: tableID,
localPosition: {x: spawnX, y: spawnY, z: spawnZ},
localRotation: Quat.fromVec3Degrees(OVERLAY_ROTATIONAL_OFFSET),
// clone dimensions so we can alter it without messing up the original entities dimensions
dimensions: entityProperties.dimensions
};
var scale = (itemHeight / overlayProperties.dimensions.y);
if ((overlayProperties.dimensions.x > itemHeight) || (overlayProperties.dimensions.y > itemHeight) ||
(overlayProperties.dimensions.y > itemHeight)) {
overlayProperties.dimensions.y = itemHeight;
overlayProperties.dimensions.x *= scale;
overlayProperties.dimensions.z *= scale;
}
// check that the item is not too large
var maxItemSize;
if (mini) {
maxItemSize = 0.06;
} else {
maxItemSize = 0.1;
}
var scaleReduction = 0.95;
while (overlayProperties.dimensions.x > maxItemSize || overlayProperties.dimensions.z > maxItemSize ||
overlayProperties.dimensions.y > maxItemSize) {
overlayProperties.dimensions.y *= scaleReduction;
overlayProperties.dimensions.x *= scaleReduction;
overlayProperties.dimensions.z *= scaleReduction;
}
var replica = Overlays.addOverlay("model", overlayProperties);
var userDataObject = JSON.parse(entityProperties.userData);
userDataObject.replicaOverlayID = replica;
Entities.editEntity(entityID, {userData: JSON.stringify(userDataObject)});
var replicaStoredTransform = {
position: entityProperties.localPosition,
rotation: entityProperties.localRotation,
dimensions: entityProperties.dimensions,
jointName: MyAvatar.jointNames[entityProperties.parentJointIndex],
demoEntityID: entityID
};
replicaStoredTransforms[replica] = replicaStoredTransform;
replicaList.push(replica);
var mousePress = function(id, event) {
if (replicaList.indexOf(id) !== -1) {
Overlays.editOverlay(id, {position: scannerPosition});
}
};
Overlays.mousePressOnOverlay.connect(mousePress);
});
_this.replicaCheckedOut = function(entityID, args) {
var ARGS_INDEX = {
REPLICA_OVERLAY: 0,
NEW_ENTITY: 1
};
var replicaOverlayID = args[ARGS_INDEX.REPLICA_OVERLAY];
var newEntityID = args[ARGS_INDEX.NEW_ENTITY];
// Delete the new entity when the transforms are not found.
if (replicaStoredTransforms[replicaOverlayID] === undefined) {
print('Could not find transform data, deleting purchased entity.');
Entities.deleteEntity(newEntityID);
return;
}
var transform = replicaStoredTransforms[replicaOverlayID];
var transformProperties = {
parentID: MyAvatar.sessionUUID,
parentJointIndex: MyAvatar.getJointIndex(transform.jointName),
localPosition: transform.position,
localRotation: transform.rotation,
dimensions: transform.dimensions,
velocity: {x: 0, y: 0, z: 0},
dynamic: false
};
Entities.editEntity(newEntityID, transformProperties);
// Make really sure that the translations are set properly
var makeSureInterval = Script.setInterval(function() {
Entities.editEntity(newEntityID, transformProperties);
}, TRANSLATION_CHECK_INTERVAL);
// Five seconds should be enough to be sure, otherwise we have a problem
Script.setTimeout(function() {
makeSureInterval.stop();
}, TRANSLATION_STOP_TIMEOUT);
var newEntityProperties = Entities.getEntityProperties(newEntityID, ['marketplaceID', 'certificateID']);
var certificateID = undefined;
if (newEntityProperties.certificateID !== "" && newEntityProperties.certificateID !== undefined) {
certificateID = newEntityProperties.certificateID;
}
addTransformForMarketplaceItem(newEntityProperties.marketplaceID, certificateID, transform);
// Remove the demo object, to prevent overlapping objects
Entities.deleteEntity(transform.demoEntityID);
};
var setupApp = (function() {
button = TABLET.addButton({
icon: APP_ICON,
text: APP_NAME
});
HMD.openTablet(true);
function onClicked() {
TABLET.gotoWebScreen(APP_URL);
}
print("DBACK TEST POOP 0");
button.clicked.connect(onClicked);
if (HMD.active) {
print("DBACK TEST POOP 1");
var walletReady = 3;
if (Wallet.walletStatus === walletReady) {
print("DBACK TEST POOP 2");
TABLET.gotoWebScreen(APP_URL);
} else {
print("DBACK TEST POOP 3");
TABLET.pushOntoStack(APP_URL);
TABLET.loadQMLSource(MARKETPLACE_WALLET_QML_PATH);
}
} else {
// Load the checkout wear tutorial for desktop users:
Messages.sendLocalMessage('com.highfidelity.wear.tutorialChannel', 'checkoutEnter');
}
});
_this.enterEntity = (function (entityID) {
replicaList = [];
collectZoneData();
if (ENTER_ZONE_SOUND.downloaded) {
Audio.playSound(ENTER_ZONE_SOUND, {
position: MyAvatar.position,
volume: SHARED.AUDIO_VOLUME_LEVEL,
localOnly: true
});
}
Entities.callEntityMethod(recycleBinID, 'enterCheckout');
Entities.callEntityMethod(scannerZone, 'enterCheckout');
setupApp();
isInZone = true;
var avatarChildEntities = [];
avatarChildEntities = SHARED.getAvatarChildEntities(MyAvatar);
var left = true;
var middle = false;
avatarChildEntities.forEach(function (entityID) {
if (replicaList.length < MAX_ITEMS){
var childUserData = Entities.getEntityProperties(entityID, 'userData').userData;
var isAttachment = childUserData.indexOf("attached\":true");
var marketplaceID = Entities.getEntityProperties(entityID, 'marketplaceID').marketplaceID;
if (marketplaceID && (isAttachment !== -1)) {
spawnOverlayReplica(entityID);
if (mini) {
xOffset = 0;
yOffset = 0.06;
} else {
xOffset = 0.005;
yOffset = 0.1;
}
if (left) {
spawnX -= itemHeight + xOffset;
spawnZ -= itemHeight;
left = false;
middle = true;
} else if (middle){
spawnX -= itemHeight + xOffset;
spawnZ -= itemHeight;
middle = false;
} else {
spawnY += yOffset;
spawnX += itemHeight;
spawnX += itemHeight;
spawnZ += itemHeight;
spawnZ += itemHeight;
left = true;
}
}
}
});
var tabletTransform = {
parentID: tableID,
localPosition: tabletLocalOffset,
localRotation: Quat.fromVec3Degrees(TABLET_ROTATIONAL_OFFSET)
};
Overlays.editOverlay(HMD.tabletID, tabletTransform);
var tabletTransformInterval = Script.setInterval(function() {
Overlays.editOverlay(HMD.tabletID, tabletTransform);
}, TRANSLATION_CHECK_INTERVAL);
Script.setTimeout(function() {
tabletTransformInterval.stop();
}, SHORTER_STOP_TIMEOUT);
});
_this.leaveEntity = function() {
Entities.callEntityMethod(recycleBinID, 'exitCheckout');
Entities.callEntityMethod(scannerZone, 'exitCheckout');
isInZone = false;
var SCANNER_RANGE_METERS = 1000;
Entities.findEntities(MyAvatar.position, SCANNER_RANGE_METERS).forEach(function(entity) {
try {
var name = Entities.getEntityProperties(entity).name;
if (name.indexOf("Checkout Item") !== -1) {
Entities.deleteEntity(entity);
}
} catch (e) {
print("Error cleaning up.");
}
});
replicaList.forEach(function (overlayItem) {
Overlays.deleteOverlay(overlayItem);
});
replicaList = [];
replicaStoredTransforms = {};
TABLET.removeButton(button);
TABLET.gotoHomeScreen();
Overlays.editOverlay(HMD.tabletID, {parentID: MyAvatar.sessionUUID});
HMD.closeTablet();
};
_this.unload = function() {
// make sure you leave the entity if you're still in there
if (isInZone) {
_this.leaveEntity();
}
};
});