content/hifi-content/caitlyn/production/minigolf course/handyAttacher.js
2022-02-13 22:19:19 +01:00

156 lines
6.7 KiB
JavaScript

(function() {
var _this = null;
// direct copy from source code: faux joint indexes (-1 means invalid)
const SENSOR_TO_WORLD_MATRIX_INDEX = 65534; // -2
const CONTROLLER_RIGHTHAND_INDEX = 65533; // -3
const CONTROLLER_LEFTHAND_INDEX = 65532; // -4
const ZERO_UUID = '{00000000-0000-0000-0000-000000000000}';
const SANETIZE_PROPERTIES = ['childEntities', 'parentID', 'id'];
function entityListToTree(entitiesList) {
function entityListToTreeRecursive(properties) {
properties.childEntities = [];
entitiesList.forEach(function(entityProperties) {
if (properties.id !== undefined && properties.id === entityProperties.parentID) {
properties.childEntities.push(entityListToTreeRecursive(entityProperties));
}
});
return properties;
}
var entityTree = [];
entitiesList.forEach(function(entityProperties) {
if (entityProperties.parentID === undefined || entityProperties.parentID === ZERO_UUID) {
entityTree.push(entityListToTreeRecursive(entityProperties));
}
});
return entityTree;
}
// TODO: ATP support (currently the JS API for ATP does not support file links, only hashes)
function importEntitiesJSON(importLink, parentProperties) {
if (parentProperties === undefined) {
parentProperties = {};
}
var request = new XMLHttpRequest();
request.open('GET', importLink, false);
request.send();
try {
var response = JSON.parse(request.responseText);
parentProperties.childEntities = entityListToTree(response.Entities);
return parentProperties;
} catch (e) {
print('Failed importing entities JSON because: ' + JSON.stringify(e));
}
return null;
}
//Creates an entity and returns a mixed object of the creation properties and the assigned entityID
var createEntity = function(entityProperties, parent, clientOnly) {
if (parent.rotation !== undefined) {
if (entityProperties.rotation !== undefined) {
entityProperties.rotation = Quat.multiply(parent.rotation, entityProperties.rotation);
} else {
entityProperties.rotation = parent.rotation;
}
}
if (parent.position !== undefined) {
var localPosition = (parent.rotation !== undefined) ? Vec3.multiplyQbyV(parent.rotation, entityProperties.position) : entityProperties.position;
entityProperties.position = Vec3.sum(localPosition, parent.position)
}
if (parent.id !== undefined) {
entityProperties.parentID = parent.id;
}
entityProperties.id = Entities.addEntity(entityProperties, clientOnly);
return entityProperties;
};
var createEntitiesFromTree = function(entityTree, parent, clientOnly) {
if (parent === undefined) {
parent = {};
}
var createdTree = [];
entityTree.forEach(function(entityProperties) {
var sanetizedProperties = {};
Object.keys(entityProperties).forEach(function(propertyKey) {
if (!entityProperties.hasOwnProperty(propertyKey) || SANETIZE_PROPERTIES.indexOf(propertyKey) !== -1) {
return true;
}
sanetizedProperties[propertyKey] = entityProperties[propertyKey];
});
// Allow for non-entity parent objects, this allows us to offset groups of entities to a specific position/rotation
var parentProperties = sanetizedProperties;
if (entityProperties.type !== undefined) {
parentProperties = createEntity(sanetizedProperties, parent, clientOnly);
}
if (entityProperties.childEntities !== undefined) {
parentProperties.childEntities =
createEntitiesFromTree(entityProperties.childEntities, parentProperties, clientOnly);
}
createdTree.push(parentProperties);
});
return createdTree;
};
function HandyAttacher() {
_this = this;
};
HandyAttacher.prototype = {
attachEntity: function(entityID, attachHand) {
var userData;
try {
userData = JSON.parse(Entities.getEntityProperties(entityID, ['userData']).userData);
} catch (e) {
return;
}
if (userData.attachmentEntityJSON === undefined) {
return;
}
if (attachHand === 'preset') {
if (userData.attachHand === undefined) {
return;
}
attachHand = userData.attachHand;
}
//if (userData.deleteOtherHandAttachment) {
// MyAvatar.jointNames.indexOf(attachHand === 'left' ? 'RightHand' : 'LeftHand')
// print('I am here. Yes delete it');
//}
// !! makes sure that clientOnly would contain a boolean representation of the value set in the userdata
var clientOnly = userData.clientOnly ? !!userData.clientOnly : false;
var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation,
MyAvatar.getAbsoluteJointTranslationInObjectFrame(attachHand === 'left' ? CONTROLLER_LEFTHAND_INDEX : CONTROLLER_RIGHTHAND_INDEX)), MyAvatar.position);
var attachmentJSON = importEntitiesJSON(userData.attachmentEntityJSON, {
//position: controllerPosition
position: MyAvatar.getJointPosition(MyAvatar.jointNames.indexOf(attachHand === 'left' ? 'LeftHand' : 'RightHand'))
});
print(attachmentJSON);
if (attachmentJSON === null) {
return;
}
// print(JSON.stringify(attachmentJSON));
var createdEntities = createEntitiesFromTree([attachmentJSON], {}, clientOnly);
print("Created = " + JSON.stringify(createdEntities[0]));
var probableGolfClubID = createdEntities[0].childEntities[0].id;
Messages.sendLocalMessage('Hifi-Hand-Grab', JSON.stringify({hand: attachHand, entityID: probableGolfClubID}));
},
// enterEntity: function(entityID) {
// print (' on enter!!');
// _this.attachEntity(entityID, 'preset');
// },
startNearTrigger: function(entityID, args) {
print (' on startNearTrigger!!');
_this.attachEntity(entityID, args[0]);
}
};
return new HandyAttacher();
})