Merge branch 'master' into hazeZone

# Conflicts:
#	libraries/networking/src/udt/PacketHeaders.cpp
#	libraries/networking/src/udt/PacketHeaders.h
This commit is contained in:
Nissim Hadar 2017-10-03 10:34:33 -07:00
commit 86c497a12f
21 changed files with 524 additions and 43 deletions

View file

@ -298,6 +298,23 @@ FocusScope {
pinned = !pinned
}
function isPointOnWindow(point) {
for (var i = 0; i < desktop.visibleChildren.length; i++) {
var child = desktop.visibleChildren[i];
if (child.visible) {
if (child.hasOwnProperty("modality")) {
var mappedPoint = child.mapFromGlobal(point.x, point.y);
var outLine = child.frame.children[2];
var framePoint = outLine.mapFromGlobal(point.x, point.y);
if (child.contains(mappedPoint) || outLine.contains(framePoint)) {
return true;
}
}
}
}
return false;
}
function setPinned(newPinned) {
pinned = newPinned
}

View file

@ -26,6 +26,7 @@ Item {
readonly property int frameMarginRight: frame.decoration ? frame.decoration.frameMarginRight : 0
readonly property int frameMarginTop: frame.decoration ? frame.decoration.frameMarginTop : 0
readonly property int frameMarginBottom: frame.decoration ? frame.decoration.frameMarginBottom : 0
readonly property int offsetCorrection: 20
// Frames always fill their parents, but their decorations may extend
// beyond the window via negative margin sizes
@ -73,7 +74,7 @@ Item {
Rectangle {
id: sizeOutline
x: -frameMarginLeft
y: -frameMarginTop
y: -frameMarginTop - offsetCorrection
width: window ? window.width + frameMarginLeft + frameMarginRight + 2 : 0
height: window ? window.height + frameMarginTop + frameMarginBottom + 2 : 0
color: hifi.colors.baseGrayHighlight15

View file

@ -171,6 +171,11 @@ void WindowScriptingInterface::setPreviousBrowseAssetLocation(const QString& loc
Setting::Handle<QVariant>(LAST_BROWSE_ASSETS_LOCATION_SETTING).set(location);
}
bool WindowScriptingInterface::isPointOnDesktopWindow(QVariant point) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
return offscreenUi->isPointOnDesktopWindow(point);
}
/// Makes sure that the reticle is visible, use this in blocking forms that require a reticle and
/// might be in same thread as a script that sets the reticle to invisible
void WindowScriptingInterface::ensureReticleVisible() const {

View file

@ -72,6 +72,7 @@ public slots:
void shareSnapshot(const QString& path, const QUrl& href = QUrl(""));
bool isPhysicsEnabled();
bool setDisplayTexture(const QString& name);
bool isPointOnDesktopWindow(QVariant point);
int openMessageBox(QString title, QString text, int buttons, int defaultButton);
void updateMessageBox(int id, QString title, QString text, int buttons, int defaultButton);

View file

@ -1,3 +1,4 @@
set(TARGET_NAME entities)
setup_hifi_library(Network Script)
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
link_hifi_libraries(shared networking octree avatars)

View file

@ -13,6 +13,10 @@
#include <QtCore/QObject>
#include <QtEndian>
#include <QJsonDocument>
#include <openssl/rsa.h> // see comments for DEBUG_CERT
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <glm/gtx/transform.hpp>
@ -34,6 +38,7 @@
Q_DECLARE_METATYPE(EntityItemPointer);
int entityItemPointernMetaTypeId = qRegisterMetaType<EntityItemPointer>();
int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
@ -95,7 +100,19 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_DYNAMIC;
requestedProperties += PROP_LOCKED;
requestedProperties += PROP_USER_DATA;
// Certifiable properties
requestedProperties += PROP_ITEM_NAME;
requestedProperties += PROP_ITEM_DESCRIPTION;
requestedProperties += PROP_ITEM_CATEGORIES;
requestedProperties += PROP_ITEM_ARTIST;
requestedProperties += PROP_ITEM_LICENSE;
requestedProperties += PROP_LIMITED_RUN;
requestedProperties += PROP_MARKETPLACE_ID;
requestedProperties += PROP_EDITION_NUMBER;
requestedProperties += PROP_ENTITY_INSTANCE_NUMBER;
requestedProperties += PROP_CERTIFICATE_ID;
requestedProperties += PROP_NAME;
requestedProperties += PROP_HREF;
requestedProperties += PROP_DESCRIPTION;
@ -240,7 +257,19 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_DYNAMIC, getDynamic());
APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked());
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData());
// Certifiable Properties
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_ITEM_NAME, getItemName());
APPEND_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, getItemDescription());
APPEND_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, getItemCategories());
APPEND_ENTITY_PROPERTY(PROP_ITEM_ARTIST, getItemArtist());
APPEND_ENTITY_PROPERTY(PROP_ITEM_LICENSE, getItemLicense());
APPEND_ENTITY_PROPERTY(PROP_LIMITED_RUN, getLimitedRun());
APPEND_ENTITY_PROPERTY(PROP_EDITION_NUMBER, getEditionNumber());
APPEND_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, getEntityInstanceNumber());
APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, getCertificateID());
APPEND_ENTITY_PROPERTY(PROP_NAME, getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL());
APPEND_ENTITY_PROPERTY(PROP_HREF, getHref());
@ -791,6 +820,17 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) {
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
}
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_CERTIFICATE_PROPERTIES) {
READ_ENTITY_PROPERTY(PROP_ITEM_NAME, QString, setItemName);
READ_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString, setItemDescription);
READ_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString, setItemCategories);
READ_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString, setItemArtist);
READ_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString, setItemLicense);
READ_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32, setLimitedRun);
READ_ENTITY_PROPERTY(PROP_EDITION_NUMBER, quint32, setEditionNumber);
READ_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber);
READ_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString, setCertificateID);
}
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
@ -1208,7 +1248,19 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
COPY_ENTITY_PROPERTY_TO_PROPERTIES(dynamic, getDynamic);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData);
// Certifiable Properties
COPY_ENTITY_PROPERTY_TO_PROPERTIES(itemName, getItemName);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(itemDescription, getItemDescription);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(itemCategories, getItemCategories);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(itemArtist, getItemArtist);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(itemLicense, getItemLicense);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(limitedRun, getLimitedRun);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(marketplaceID, getMarketplaceID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(editionNumber, getEditionNumber);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(entityInstanceNumber, getEntityInstanceNumber);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(certificateID, getCertificateID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(name, getName);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription);
@ -1303,7 +1355,19 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData);
// Certifiable Properties
SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemName, setItemName);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemDescription, setItemDescription);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemCategories, setItemCategories);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemArtist, setItemArtist);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemLicense, setItemLicense);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(limitedRun, setLimitedRun);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(marketplaceID, setMarketplaceID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(editionNumber, setEditionNumber);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(entityInstanceNumber, setEntityInstanceNumber);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(certificateID, setCertificateID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription);
@ -1510,6 +1574,107 @@ float EntityItem::getRadius() const {
return 0.5f * glm::length(getDimensions());
}
// Checking Certifiable Properties
#define ADD_STRING_PROPERTY(n, N) if (!propertySet.get##N().isEmpty()) json[#n] = propertySet.get##N()
#define ADD_ENUM_PROPERTY(n, N) json[#n] = propertySet.get##N##AsString()
#define ADD_INT_PROPERTY(n, N) if (propertySet.get##N() != 0) json[#n] = (propertySet.get##N() == (quint32) -1) ? -1.0 : ((double) propertySet.get##N())
QByteArray EntityItem::getStaticCertificateJSON() const {
// Produce a compact json of every non-default static certificate property, with the property names in alphabetical order.
// The static certificate properties include all an only those properties that cannot be changed without altering the identity
// of the entity as reviewed during the certification submission.
QJsonObject json;
EntityItemProperties propertySet = getProperties(); // Note: neither EntityItem nor EntityitemProperties "properties" are QObject "properties"!
// It is important that this be reproducible in the same order each time. Since we also generate these on the server, we do it alphabetically
// to help maintainence in two different code bases.
if (!propertySet.getAnimation().getURL().isEmpty()) {
json["animation.url"] = propertySet.getAnimation().getURL();
}
ADD_STRING_PROPERTY(collisionSoundURL, CollisionSoundURL);
ADD_STRING_PROPERTY(compoundShapeURL, CompoundShapeURL);
ADD_INT_PROPERTY(editionNumber, EditionNumber);
ADD_INT_PROPERTY(entityInstanceNumber, EntityInstanceNumber);
ADD_STRING_PROPERTY(itemArtist, ItemArtist);
ADD_STRING_PROPERTY(itemCategories, ItemCategories);
ADD_STRING_PROPERTY(itemDescription, ItemDescription);
ADD_STRING_PROPERTY(itemLicense, ItemLicense);
ADD_STRING_PROPERTY(itemName, ItemName);
ADD_INT_PROPERTY(limitedRun, LimitedRun);
ADD_STRING_PROPERTY(marketplaceID, MarketplaceID);
ADD_STRING_PROPERTY(modelURL, ModelURL);
ADD_STRING_PROPERTY(script, Script);
ADD_ENUM_PROPERTY(shapeType, ShapeType);
json["type"] = EntityTypes::getEntityTypeName(propertySet.getType());
return QJsonDocument(json).toJson(QJsonDocument::Compact);
}
QByteArray EntityItem::getStaticCertificateHash() const {
return QCryptographicHash::hash(getStaticCertificateJSON(), QCryptographicHash::Sha256);
}
#ifdef DEBUG_CERT
QString EntityItem::computeCertificateID() {
// Until the marketplace generates it, compute and answer the certificateID here.
// Does not set it, as that will have to be done from script engine in order to update server, etc.
const auto hash = getStaticCertificateHash();
const auto text = reinterpret_cast<const unsigned char*>(hash.constData());
const unsigned int textLength = hash.length();
const char privateKey[] = "-----BEGIN RSA PRIVATE KEY-----\n\
MIIBOQIBAAJBALCoBiDAZOClO26tC5pd7JikBL61WIgpAqbcNnrV/TcG6LPI7Zbi\n\
MjdUixmTNvYMRZH3Wlqtl2IKG1W68y3stKECAwEAAQJABvOlwhYwIhL+gr12jm2R\n\
yPPzZ9nVEQ6kFxLlZfIT09119fd6OU1X5d4sHWfMfSIEgjwQIDS3ZU1kY3XKo87X\n\
zQIhAOPHlYa1OC7BLhaTouy68qIU2vCKLP8mt4S31/TT0UOnAiEAxor6gU6yupTQ\n\
yuyV3yHvr5LkZKBGqhjmOTmDfgtX7ncCIChGbgX3nQuHVOLhD/nTxHssPNozVGl5\n\
KxHof+LmYSYZAiB4U+yEh9SsXdq40W/3fpLMPuNq1PRezJ5jGidGMcvF+wIgUNec\n\
3Kg2U+CVZr8/bDT/vXRrsKj1zfobYuvbfVH02QY=\n\
-----END RSA PRIVATE KEY-----";
BIO* bio = BIO_new_mem_buf((void*)privateKey, sizeof(privateKey));
RSA* rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
QByteArray signature(RSA_size(rsa), 0);
unsigned int signatureLength = 0;
const int signOK = RSA_sign(NID_sha256, text, textLength, reinterpret_cast<unsigned char*>(signature.data()), &signatureLength, rsa);
BIO_free(bio);
RSA_free(rsa);
if (!signOK) {
qCWarning(entities) << "Unable to compute signature for" << getName() << getEntityItemID();
return "";
}
return signature.toBase64();
#endif
}
bool EntityItem::verifyStaticCertificateProperties() {
// True IIF a non-empty certificateID matches the static certificate json.
// I.e., if we can verify that the certificateID was produced by High Fidelity signing the static certificate hash.
if (getCertificateID().isEmpty()) {
return false;
}
const auto signatureBytes = QByteArray::fromBase64(getCertificateID().toLatin1());
const auto signature = reinterpret_cast<const unsigned char*>(signatureBytes.constData());
const unsigned int signatureLength = signatureBytes.length();
const auto hash = getStaticCertificateHash();
const auto text = reinterpret_cast<const unsigned char*>(hash.constData());
const unsigned int textLength = hash.length();
// After DEBUG_CERT ends, we will get/cache this once from the marketplace when needed, and it likely won't be RSA.
const char publicKey[] = "-----BEGIN PUBLIC KEY-----\n\
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALCoBiDAZOClO26tC5pd7JikBL61WIgp\n\
AqbcNnrV/TcG6LPI7ZbiMjdUixmTNvYMRZH3Wlqtl2IKG1W68y3stKECAwEAAQ==\n\
-----END PUBLIC KEY-----";
BIO *bio = BIO_new_mem_buf((void*)publicKey, sizeof(publicKey));
EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
RSA* rsa = EVP_PKEY_get1_RSA(evp_key);
bool answer = RSA_verify(NID_sha256, text, textLength, signature, signatureLength, rsa);
BIO_free(bio);
RSA_free(rsa);
EVP_PKEY_free(evp_key);
return answer;
}
void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info) const {
if (_registrationPoint != ENTITY_ITEM_DEFAULT_REGISTRATION_POINT) {
glm::mat4 scale = glm::scale(getDimensions());
@ -2762,19 +2927,33 @@ void EntityItem::setUserData(const QString& value) {
});
}
QString EntityItem::getMarketplaceID() const {
QString result;
withReadLock([&] {
result = _marketplaceID;
});
return result;
// Certifiable Properties
#define DEFINE_PROPERTY_GETTER(type, accessor, var) \
type EntityItem::get##accessor() const { \
type result; \
withReadLock([&] { \
result = _##var; \
}); \
return result; \
}
void EntityItem::setMarketplaceID(const QString& value) {
withWriteLock([&] {
_marketplaceID = value;
});
#define DEFINE_PROPERTY_SETTER(type, accessor, var) \
void EntityItem::set##accessor(const type & value) { \
withWriteLock([&] { \
_##var = value; \
}); \
}
#define DEFINE_PROPERTY_ACCESSOR(type, accessor, var) DEFINE_PROPERTY_GETTER(type, accessor, var) DEFINE_PROPERTY_SETTER(type, accessor, var)
DEFINE_PROPERTY_ACCESSOR(QString, ItemName, itemName)
DEFINE_PROPERTY_ACCESSOR(QString, ItemDescription, itemDescription)
DEFINE_PROPERTY_ACCESSOR(QString, ItemCategories, itemCategories)
DEFINE_PROPERTY_ACCESSOR(QString, ItemArtist, itemArtist)
DEFINE_PROPERTY_ACCESSOR(QString, ItemLicense, itemLicense)
DEFINE_PROPERTY_ACCESSOR(quint32, LimitedRun, limitedRun)
DEFINE_PROPERTY_ACCESSOR(QString, MarketplaceID, marketplaceID)
DEFINE_PROPERTY_ACCESSOR(quint32, EditionNumber, editionNumber)
DEFINE_PROPERTY_ACCESSOR(quint32, EntityInstanceNumber, entityInstanceNumber)
DEFINE_PROPERTY_ACCESSOR(QString, CertificateID, certificateID)
uint32_t EntityItem::getDirtyFlags() const {
uint32_t result;

View file

@ -36,6 +36,9 @@
#include "SimulationFlags.h"
#include "EntityDynamicInterface.h"
// FIXME: The server-side marketplace will soon create the certificateID. At that point, all of the DEBUG_CERT stuff will go away.
#define DEBUG_CERT 1
class EntitySimulation;
class EntityTreeElement;
class EntityTreeElementExtraEncodeData;
@ -304,8 +307,33 @@ public:
uint8_t getPendingOwnershipPriority() const { return _simulationOwner.getPendingPriority(); }
void rememberHasSimulationOwnershipBid() const;
// Certifiable Properties
QString getItemName() const;
void setItemName(const QString& value);
QString getItemDescription() const;
void setItemDescription(const QString& value);
QString getItemCategories() const;
void setItemCategories(const QString& value);
QString getItemArtist() const;
void setItemArtist(const QString& value);
QString getItemLicense() const;
void setItemLicense(const QString& value);
quint32 getLimitedRun() const;
void setLimitedRun(const quint32&);
QString getMarketplaceID() const;
void setMarketplaceID(const QString& value);
quint32 getEditionNumber() const;
void setEditionNumber(const quint32&);
quint32 getEntityInstanceNumber() const;
void setEntityInstanceNumber(const quint32&);
QString getCertificateID() const;
void setCertificateID(const QString& value);
QByteArray getStaticCertificateJSON() const;
QByteArray getStaticCertificateHash() const;
bool verifyStaticCertificateProperties();
#ifdef DEBUG_CERT
QString computeCertificateID();
#endif
// TODO: get rid of users of getRadius()...
float getRadius() const;
@ -524,12 +552,24 @@ protected:
bool _locked { ENTITY_ITEM_DEFAULT_LOCKED };
QString _userData { ENTITY_ITEM_DEFAULT_USER_DATA };
SimulationOwner _simulationOwner;
QString _marketplaceID { ENTITY_ITEM_DEFAULT_MARKETPLACE_ID };
bool _shouldHighlight { false };
QString _name { ENTITY_ITEM_DEFAULT_NAME };
QString _href; //Hyperlink href
QString _description; //Hyperlink description
// Certifiable Properties
QString _itemName { ENTITY_ITEM_DEFAULT_ITEM_NAME };
QString _itemDescription { ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION };
QString _itemCategories { ENTITY_ITEM_DEFAULT_ITEM_CATEGORIES };
QString _itemArtist { ENTITY_ITEM_DEFAULT_ITEM_ARTIST };
QString _itemLicense { ENTITY_ITEM_DEFAULT_ITEM_LICENSE };
quint32 _limitedRun { ENTITY_ITEM_DEFAULT_LIMITED_RUN };
QString _certificateID { ENTITY_ITEM_DEFAULT_CERTIFICATE_ID };
quint32 _editionNumber { ENTITY_ITEM_DEFAULT_EDITION_NUMBER };
quint32 _entityInstanceNumber { ENTITY_ITEM_DEFAULT_ENTITY_INSTANCE_NUMBER };
QString _marketplaceID { ENTITY_ITEM_DEFAULT_MARKETPLACE_ID };
// NOTE: Damping is applied like this: v *= pow(1 - damping, dt)
//
// Hence the damping coefficient must range from 0 (no damping) to 1 (immediate stop).

View file

@ -316,7 +316,19 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread);
CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart);
CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish);
// Certifiable Properties
CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName);
CHECK_PROPERTY_CHANGE(PROP_ITEM_DESCRIPTION, itemDescription);
CHECK_PROPERTY_CHANGE(PROP_ITEM_CATEGORIES, itemCategories);
CHECK_PROPERTY_CHANGE(PROP_ITEM_ARTIST, itemArtist);
CHECK_PROPERTY_CHANGE(PROP_ITEM_LICENSE, itemLicense);
CHECK_PROPERTY_CHANGE(PROP_LIMITED_RUN, limitedRun);
CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID);
CHECK_PROPERTY_CHANGE(PROP_EDITION_NUMBER, editionNumber);
CHECK_PROPERTY_CHANGE(PROP_ENTITY_INSTANCE_NUMBER, entityInstanceNumber);
CHECK_PROPERTY_CHANGE(PROP_CERTIFICATE_ID, certificateID);
CHECK_PROPERTY_CHANGE(PROP_NAME, name);
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode);
@ -448,7 +460,19 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACTION_DATA, actionData);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData);
// Certifiable Properties
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_NAME, itemName);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_DESCRIPTION, itemDescription);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_CATEGORIES, itemCategories);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_ARTIST, itemArtist);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_LICENSE, itemLicense);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIMITED_RUN, limitedRun);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MARKETPLACE_ID, marketplaceID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EDITION_NUMBER, editionNumber);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ENTITY_INSTANCE_NUMBER, entityInstanceNumber);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CERTIFICATE_ID, certificateID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
@ -717,7 +741,19 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread);
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart);
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish);
// Certifiable Properties
COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName);
COPY_PROPERTY_FROM_QSCRIPTVALUE(itemDescription, QString, setItemDescription);
COPY_PROPERTY_FROM_QSCRIPTVALUE(itemCategories, QString, setItemCategories);
COPY_PROPERTY_FROM_QSCRIPTVALUE(itemArtist, QString, setItemArtist);
COPY_PROPERTY_FROM_QSCRIPTVALUE(itemLicense, QString, setItemLicense);
COPY_PROPERTY_FROM_QSCRIPTVALUE(limitedRun, quint32, setLimitedRun);
COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(editionNumber, quint32, setEditionNumber);
COPY_PROPERTY_FROM_QSCRIPTVALUE(entityInstanceNumber, quint32, setEntityInstanceNumber);
COPY_PROPERTY_FROM_QSCRIPTVALUE(certificateID, QString, setCertificateID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName);
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL);
@ -872,7 +908,19 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(radiusSpread);
COPY_PROPERTY_IF_CHANGED(radiusStart);
COPY_PROPERTY_IF_CHANGED(radiusFinish);
// Certifiable Properties
COPY_PROPERTY_IF_CHANGED(itemName);
COPY_PROPERTY_IF_CHANGED(itemDescription);
COPY_PROPERTY_IF_CHANGED(itemCategories);
COPY_PROPERTY_IF_CHANGED(itemArtist);
COPY_PROPERTY_IF_CHANGED(itemLicense);
COPY_PROPERTY_IF_CHANGED(limitedRun);
COPY_PROPERTY_IF_CHANGED(marketplaceID);
COPY_PROPERTY_IF_CHANGED(editionNumber);
COPY_PROPERTY_IF_CHANGED(entityInstanceNumber);
COPY_PROPERTY_IF_CHANGED(certificateID);
COPY_PROPERTY_IF_CHANGED(name);
COPY_PROPERTY_IF_CHANGED(collisionSoundURL);
@ -1061,7 +1109,19 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_PROPERTY_TO_MAP(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float);
ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float);
ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float);
// Certifiable Properties
ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString);
ADD_PROPERTY_TO_MAP(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString);
ADD_PROPERTY_TO_MAP(PROP_ITEM_CATEGORIES, ItemCategories, itemCategories, QString);
ADD_PROPERTY_TO_MAP(PROP_ITEM_ARTIST, ItemArtist, itemArtist, QString);
ADD_PROPERTY_TO_MAP(PROP_ITEM_LICENSE, ItemLicense, itemLicense, QString);
ADD_PROPERTY_TO_MAP(PROP_LIMITED_RUN, LimitedRun, limitedRun, quint32);
ADD_PROPERTY_TO_MAP(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString);
ADD_PROPERTY_TO_MAP(PROP_EDITION_NUMBER, EditionNumber, editionNumber, quint32);
ADD_PROPERTY_TO_MAP(PROP_ENTITY_INSTANCE_NUMBER, EntityInstanceNumber, entityInstanceNumber, quint32);
ADD_PROPERTY_TO_MAP(PROP_CERTIFICATE_ID, CertificateID, certificateID, QString);
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor);
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float);
@ -1433,11 +1493,22 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
properties.getType() == EntityTypes::Sphere) {
APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape());
}
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData());
APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha());
// Certifiable Properties
APPEND_ENTITY_PROPERTY(PROP_ITEM_NAME, properties.getItemName());
APPEND_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, properties.getItemDescription());
APPEND_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, properties.getItemCategories());
APPEND_ENTITY_PROPERTY(PROP_ITEM_ARTIST, properties.getItemArtist());
APPEND_ENTITY_PROPERTY(PROP_ITEM_LICENSE, properties.getItemLicense());
APPEND_ENTITY_PROPERTY(PROP_LIMITED_RUN, properties.getLimitedRun());
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_EDITION_NUMBER, properties.getEditionNumber());
APPEND_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, properties.getEntityInstanceNumber());
APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, properties.getCertificateID());
}
if (propertyCount > 0) {
@ -1733,12 +1804,23 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE, QString, setShape);
}
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
// Certifiable Properties
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ITEM_NAME, QString, setItemName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ITEM_DESCRIPTION, QString, setItemDescription);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ITEM_CATEGORIES, QString, setItemCategories);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ITEM_ARTIST, QString, setItemArtist);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ITEM_LICENSE, QString, setItemLicense);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIMITED_RUN, quint32, setLimitedRun);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EDITION_NUMBER, quint32, setEditionNumber);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CERTIFICATE_ID, QString, setCertificateID);
return valid;
}
@ -1847,7 +1929,17 @@ void EntityItemProperties::markAllChanged() {
//_alphaStartChanged = true;
//_alphaFinishChanged = true;
// Certifiable Properties
_itemNameChanged = true;
_itemDescriptionChanged = true;
_itemCategoriesChanged = true;
_itemArtistChanged = true;
_itemLicenseChanged = true;
_limitedRunChanged = true;
_marketplaceIDChanged = true;
_editionNumberChanged = true;
_entityInstanceNumberChanged = true;
_certificateIDChanged = true;
_keyLight.markAllChanged();
@ -2156,9 +2248,39 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (radiusFinishChanged()) {
out += "radiusFinish";
}
// Certifiable Properties
if (itemNameChanged()) {
out += "itemName";
}
if (itemDescriptionChanged()) {
out += "itemDescription";
}
if (itemCategoriesChanged()) {
out += "itemCategories";
}
if (itemArtistChanged()) {
out += "itemArtist";
}
if (itemLicenseChanged()) {
out += "itemLicense";
}
if (limitedRunChanged()) {
out += "limitedRun";
}
if (marketplaceIDChanged()) {
out += "marketplaceID";
}
if (editionNumberChanged()) {
out += "editionNumber";
}
if (entityInstanceNumberChanged()) {
out += "entityInstanceNumber";
}
if (certificateIDChanged()) {
out += "certificateID";
}
if (backgroundModeChanged()) {
out += "backgroundMode";
}

View file

@ -171,7 +171,6 @@ public:
DEFINE_PROPERTY(PROP_RADIUS_START, RadiusStart, radiusStart, float, particle::DEFAULT_RADIUS_START);
DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, particle::DEFAULT_RADIUS_FINISH);
DEFINE_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool, particle::DEFAULT_EMITTER_SHOULD_TRAIL);
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID);
DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup);
DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE);
DEFINE_PROPERTY_REF(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray, PolyVoxEntityItem::DEFAULT_VOXEL_DATA);
@ -222,6 +221,18 @@ public:
DEFINE_PROPERTY_REF(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube, AACube());
DEFINE_PROPERTY_REF(PROP_SHAPE, Shape, shape, QString, "Sphere");
// Certifiable Properties - related to Proof of Purchase certificates
DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME);
DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION);
DEFINE_PROPERTY_REF(PROP_ITEM_CATEGORIES, ItemCategories, itemCategories, QString, ENTITY_ITEM_DEFAULT_ITEM_CATEGORIES);
DEFINE_PROPERTY_REF(PROP_ITEM_ARTIST, ItemArtist, itemArtist, QString, ENTITY_ITEM_DEFAULT_ITEM_ARTIST);
DEFINE_PROPERTY_REF(PROP_ITEM_LICENSE, ItemLicense, itemLicense, QString, ENTITY_ITEM_DEFAULT_ITEM_LICENSE);
DEFINE_PROPERTY_REF(PROP_LIMITED_RUN, LimitedRun, limitedRun, quint32, ENTITY_ITEM_DEFAULT_LIMITED_RUN);
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID);
DEFINE_PROPERTY_REF(PROP_EDITION_NUMBER, EditionNumber, editionNumber, quint32, ENTITY_ITEM_DEFAULT_EDITION_NUMBER);
DEFINE_PROPERTY_REF(PROP_ENTITY_INSTANCE_NUMBER, EntityInstanceNumber, entityInstanceNumber, quint32, ENTITY_ITEM_DEFAULT_ENTITY_INSTANCE_NUMBER);
DEFINE_PROPERTY_REF(PROP_CERTIFICATE_ID, CertificateID, certificateID, QString, ENTITY_ITEM_DEFAULT_CERTIFICATE_ID);
// these are used when bouncing location data into and out of scripts
DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3);
DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glmQuat, ENTITY_ITEM_DEFAULT_ROTATION);
@ -446,7 +457,19 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusSpread, radiusSpread, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusStart, radiusStart, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusFinish, radiusFinish, "");
// Certifiable Properties
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ItemName, itemName, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ItemDescription, itemDescription, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ItemCategories, itemCategories, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ItemArtist, itemArtist, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ItemLicense, itemLicense, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, LimitedRun, limitedRun, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EditionNumber, editionNumber, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EntityInstanceNumber, entityInstanceNumber, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CertificateID, certificateID, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, HazeMode, hazeMode, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelVolumeSize, voxelVolumeSize, "");

View file

@ -26,9 +26,20 @@ const glm::vec3 ENTITY_ITEM_HALF_VEC3 = glm::vec3(0.5f);
const bool ENTITY_ITEM_DEFAULT_LOCKED = false;
const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString("");
const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid();
// Certifiable Properties
const QString ENTITY_ITEM_DEFAULT_ITEM_NAME = QString("");
const QString ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION = QString("");
const QString ENTITY_ITEM_DEFAULT_ITEM_CATEGORIES = QString("");
const QString ENTITY_ITEM_DEFAULT_ITEM_ARTIST = QString("");
const QString ENTITY_ITEM_DEFAULT_ITEM_LICENSE = QString("");
const quint32 ENTITY_ITEM_DEFAULT_LIMITED_RUN = -1;
const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString("");
const quint32 ENTITY_ITEM_DEFAULT_EDITION_NUMBER = 0;
const quint32 ENTITY_ITEM_DEFAULT_ENTITY_INSTANCE_NUMBER = 0;
const QString ENTITY_ITEM_DEFAULT_CERTIFICATE_ID = QString("");
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;

View file

@ -187,7 +187,19 @@ enum EntityPropertyList {
PROP_SERVER_SCRIPTS,
PROP_FILTER_URL,
// Certificable Properties
PROP_ITEM_NAME,
PROP_ITEM_DESCRIPTION,
PROP_ITEM_CATEGORIES,
PROP_ITEM_ARTIST,
PROP_ITEM_LICENSE,
PROP_LIMITED_RUN,
// PROP_MARKETPLACE_ID is above
PROP_EDITION_NUMBER,
PROP_ENTITY_INSTANCE_NUMBER,
PROP_CERTIFICATE_ID,
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties to end of list just ABOVE this line
PROP_AFTER_LAST_ITEM,

View file

@ -1765,3 +1765,31 @@ glm::mat4 EntityScriptingInterface::getEntityLocalTransform(const QUuid& entityI
}
return result;
}
bool EntityScriptingInterface::verifyStaticCertificateProperties(const QUuid& entityID) {
bool result = false;
if (_entityTree) {
_entityTree->withReadLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
if (entity) {
result = entity->verifyStaticCertificateProperties();
}
});
}
return result;
}
#ifdef DEBUG_CERT
QString EntityScriptingInterface::computeCertificateID(const QUuid& entityID) {
QString result { "" };
if (_entityTree) {
_entityTree->withReadLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
if (entity) {
result = entity->computeCertificateID();
}
});
}
return result;
}
#endif

View file

@ -386,6 +386,11 @@ public slots:
*/
Q_INVOKABLE glm::mat4 getEntityLocalTransform(const QUuid& entityID);
Q_INVOKABLE bool verifyStaticCertificateProperties(const QUuid& entityID);
#ifdef DEBUG_CERT
Q_INVOKABLE QString computeCertificateID(const QUuid& entityID);
#endif
signals:
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);

View file

@ -215,16 +215,18 @@ void ModelEntityItem::debugDump() const {
}
void ModelEntityItem::setShapeType(ShapeType type) {
if (type != _shapeType) {
if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) {
// dynamic and STATIC_MESH are incompatible
// since the shape is being set here we clear the dynamic bit
_dynamic = false;
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
withWriteLock([&] {
if (type != _shapeType) {
if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) {
// dynamic and STATIC_MESH are incompatible
// since the shape is being set here we clear the dynamic bit
_dynamic = false;
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
}
_shapeType = type;
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
_shapeType = type;
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
});
}
ShapeType ModelEntityItem::getShapeType() const {
@ -257,13 +259,15 @@ void ModelEntityItem::setModelURL(const QString& url) {
}
void ModelEntityItem::setCompoundShapeURL(const QString& url) {
if (_compoundShapeURL != url) {
ShapeType oldType = computeTrueShapeType();
_compoundShapeURL = url;
if (oldType != computeTrueShapeType()) {
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
withWriteLock([&] {
if (_compoundShapeURL != url) {
ShapeType oldType = computeTrueShapeType();
_compoundShapeURL = url;
if (oldType != computeTrueShapeType()) {
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
}
}
});
}
void ModelEntityItem::setAnimationURL(const QString& url) {

View file

@ -633,10 +633,12 @@ void ParticleEffectEntityItem::debugDump() const {
}
void ParticleEffectEntityItem::setShapeType(ShapeType type) {
if (type != _shapeType) {
_shapeType = type;
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
withWriteLock([&] {
if (type != _shapeType) {
_shapeType = type;
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
});
}
void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {

View file

@ -57,7 +57,7 @@ public:
static void setDrawZoneBoundaries(bool value) { _drawZoneBoundaries = value; }
virtual bool isReadyToComputeShape() const override { return false; }
void setShapeType(ShapeType type) override { _shapeType = type; }
void setShapeType(ShapeType type) override { withWriteLock([&] { _shapeType = type; }); }
virtual ShapeType getShapeType() const override;
virtual bool hasCompoundShapeURL() const;

View file

@ -267,7 +267,8 @@ const PacketVersion VERSION_ENTITIES_BULLET_DYNAMICS = 70;
const PacketVersion VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT = 71;
const PacketVersion VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE = 72;
const PacketVersion VERSION_ENTITIES_ANIMATION_ALLOW_TRANSLATION_PROPERTIES = 73;
const PacketVersion VERSION_ENTITIES_HAZE = 74;
const PacketVersion VERSION_ENTITIES_HAS_CERTIFICATE_PROPERTIES = 74;
const PacketVersion VERSION_ENTITIES_HAZE = 75;
enum class EntityQueryPacketVersion: PacketVersion {
JSONFilter = 18,

View file

@ -136,6 +136,14 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<voi
shownProperty.write(!shownProperty.read().toBool());
}
bool OffscreenUi::isPointOnDesktopWindow(QVariant point) {
QVariant result;
BLOCKING_INVOKE_METHOD(_desktop, "isPointOnWindow",
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, point));
return result.toBool();
}
void OffscreenUi::hide(const QString& name) {
QQuickItem* item = getRootItem()->findChild<QQuickItem*>(name);
if (item) {

View file

@ -78,6 +78,7 @@ public:
bool eventFilter(QObject* originalDestination, QEvent* event) override;
void addMenuInitializer(std::function<void(VrMenu*)> f);
QObject* getFlags();
Q_INVOKABLE bool isPointOnDesktopWindow(QVariant point);
QQuickItem* getDesktop();
QQuickItem* getToolWindow();
QObject* getRootMenu();

View file

@ -108,13 +108,17 @@ Script.include("/~/system/libraries/controllers.js");
"userData"
];
var MARGIN = 25;
function FarActionGrabEntity(hand) {
this.hand = hand;
this.grabbedThingID = null;
this.actionID = null; // action this script created...
this.entityWithContextOverlay = false;
this.contextOverlayTimer = false;
this.reticleMinX = MARGIN;
this.reticleMaxX;
this.reticleMinY = MARGIN;
this.reticleMaxY;
var ACTION_TTL = 15; // seconds
@ -344,12 +348,28 @@ Script.include("/~/system/libraries/controllers.js");
this.grabbedThingID = null;
};
this.updateRecommendedArea = function() {
var dims = Controller.getViewportDimensions();
this.reticleMaxX = dims.x - MARGIN;
this.reticleMaxY = dims.y - MARGIN;
};
this.calculateNewReticlePosition = function(intersection) {
this.updateRecommendedArea();
var point2d = HMD.overlayFromWorldPoint(intersection);
point2d.x = Math.max(this.reticleMinX, Math.min(point2d.x, this.reticleMaxX));
point2d.y = Math.max(this.reticleMinY, Math.min(point2d.y, this.reticleMaxY));
return point2d;
};
this.notPointingAtEntity = function(controllerData) {
var intersection = controllerData.rayPicks[this.hand];
var entityProperty = Entities.getEntityProperties(intersection.objectID);
var entityType = entityProperty.type;
var hudRayPick = controllerData.hudRayPicks[this.hand];
var point2d = this.calculateNewReticlePosition(hudRayPick.intersection);
if ((intersection.type === RayPick.INTERSECTED_ENTITY && entityType === "Web") ||
intersection.type === RayPick.INTERSECTED_OVERLAY) {
intersection.type === RayPick.INTERSECTED_OVERLAY || Window.isPointOnDesktopWindow(point2d)) {
return true;
}
return false;

View file

@ -178,11 +178,11 @@
}
var hudRayPick = controllerData.hudRayPicks[this.hand];
var point2d = this.calculateNewReticlePosition(hudRayPick.intersection);
this.setReticlePosition(point2d);
if (!Reticle.isPointingAtSystemOverlay(point2d)) {
if (!Window.isPointOnDesktopWindow(point2d) && !controllerData.triggerClicks[this.hand]) {
this.exitModule();
return false;
}
this.setReticlePosition(point2d);
Reticle.visible = false;
this.movedAway = false;
this.triggerClicked = controllerData.triggerClicks[this.hand];
@ -239,7 +239,7 @@
function cleanup() {
ControllerDispatcherUtils.disableDispatcherModule("LeftHudOverlayPointer");
ControllerDispatcherUtils.disbaleDispatcherModule("RightHudOverlayPointer");
ControllerDispatcherUtils.disableDispatcherModule("RightHudOverlayPointer");
}
Script.scriptEnding.connect(cleanup);