entity tags

This commit is contained in:
HifiExperiments 2023-12-02 15:59:52 -08:00
parent 78bc24cb22
commit 85f24f0951
17 changed files with 271 additions and 0 deletions

View file

@ -104,6 +104,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_IGNORE_PICK_INTERSECTION;
requestedProperties += PROP_RENDER_WITH_ZONES;
requestedProperties += PROP_BILLBOARD_MODE;
requestedProperties += PROP_TAGS;
requestedProperties += _grabProperties.getEntityProperties(params);
// Physics
@ -301,6 +302,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, getIgnorePickIntersection());
APPEND_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, getRenderWithZones());
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_TAGS, getTags());
withReadLock([&] {
_grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
@ -874,6 +876,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, bool, setIgnorePickIntersection);
READ_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, QVector<QUuid>, setRenderWithZones);
READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY(PROP_TAGS, QSet<QString>, setTags);
withWriteLock([&] {
int bytesFromGrab = _grabProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData,
@ -1358,6 +1361,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignorePickIntersection, getIgnorePickIntersection);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(renderWithZones, getRenderWithZones);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(tags, getTags);
withReadLock([&] {
_grabProperties.getProperties(properties);
});
@ -1495,6 +1499,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignorePickIntersection, setIgnorePickIntersection);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(renderWithZones, setRenderWithZones);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(tags, setTags);
withWriteLock([&] {
bool grabPropertiesChanged = _grabProperties.setProperties(properties);
somethingChanged |= grabPropertiesChanged;
@ -3553,3 +3558,13 @@ void EntityItem::setBillboardMode(BillboardMode value) {
_billboardMode = value;
});
}
void EntityItem::setTags(const QSet<QString>& tags) {
withWriteLock([&] {
_tags = tags;
});
}
QSet<QString> EntityItem::getTags() const {
return resultWithReadLock<QSet<QString>>([&] { return _tags; });
}

View file

@ -559,6 +559,9 @@ public:
BillboardMode getBillboardMode() const;
virtual bool getRotateForPicking() const { return false; }
void setTags(const QSet<QString>& tags);
QSet<QString> getTags() const;
signals:
void spaceUpdate(std::pair<int32_t, glm::vec4> data);
@ -740,6 +743,8 @@ protected:
bool _cullWithParent { false };
QSet<QString> _tags;
mutable bool _needsRenderUpdate { false };
};

View file

@ -424,6 +424,21 @@ void EntityItemProperties::setEntityHostTypeFromString(const QString& entityHost
}
}
QVector<QString> EntityItemProperties::getTagsAsVector() const {
QVector<QString> tags;
for (const QString& tag : _tags) {
tags.push_back(tag);
}
return tags;
}
void EntityItemProperties::setTagsFromVector(const QVector<QString>& tags) {
_tags.clear();
for (const QString& tag : tags) {
_tags.insert(tag);
}
}
EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
EntityPropertyFlags changedProperties;
@ -454,6 +469,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_IGNORE_PICK_INTERSECTION, ignorePickIntersection);
CHECK_PROPERTY_CHANGE(PROP_RENDER_WITH_ZONES, renderWithZones);
CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode);
CHECK_PROPERTY_CHANGE(PROP_TAGS, tags);
changedProperties += _grab.getChangedProperties();
// Physics
@ -822,6 +838,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* one of the zones in this list.
* @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera. Use the rotation
* property to control which axis is facing you.
* @property {string[]} tags=[] - A set of tags describing this entity.
*
* @property {Entities.Grab} grab - The entity's grab-related properties.
*
@ -1615,6 +1632,7 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_PICK_INTERSECTION, ignorePickIntersection);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RENDER_WITH_ZONES, renderWithZones);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_TAGS, tags, getTagsAsVector());
_grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
// Physics
@ -2031,6 +2049,7 @@ void EntityItemProperties::copyFromScriptValue(const ScriptValue& object, bool h
COPY_PROPERTY_FROM_QSCRIPTVALUE(ignorePickIntersection, bool, setIgnorePickIntersection);
COPY_PROPERTY_FROM_QSCRIPTVALUE(renderWithZones, qVectorQUuid, setRenderWithZones);
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(tags, qVectorQString, setTagsFromVector, getTagsAsVector);
_grab.copyFromScriptValue(object, namesSet, _defaultSettings);
// Physics
@ -2317,6 +2336,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(ignorePickIntersection);
COPY_PROPERTY_IF_CHANGED(renderWithZones);
COPY_PROPERTY_IF_CHANGED(billboardMode);
COPY_PROPERTY_IF_CHANGED(tags);
_grab.merge(other._grab);
// Physics
@ -2605,6 +2625,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_PROPERTY_TO_MAP(PROP_IGNORE_PICK_INTERSECTION, IgnorePickIntersection, ignorePickIntersection, bool);
ADD_PROPERTY_TO_MAP(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector<QUuid>);
ADD_PROPERTY_TO_MAP(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode);
ADD_PROPERTY_TO_MAP(PROP_TAGS, Tags, tags, QSet<QString>);
{ // Grab
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic);
@ -3087,6 +3108,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, properties.getIgnorePickIntersection());
APPEND_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, properties.getRenderWithZones());
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_TAGS, properties.getTags());
_staticGrab.setProperties(properties);
_staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags,
propertiesDidntFit, propertyCount, appendState);
@ -3567,6 +3589,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_PICK_INTERSECTION, bool, setIgnorePickIntersection);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_WITH_ZONES, QVector<QUuid>, setRenderWithZones);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TAGS, QSet<QString>, setTags);
properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
// Physics
@ -3959,6 +3982,7 @@ void EntityItemProperties::markAllChanged() {
_ignorePickIntersectionChanged = true;
_renderWithZonesChanged = true;
_billboardModeChanged = true;
_tagsChanged = true;
_grab.markAllChanged();
// Physics
@ -4358,6 +4382,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (billboardModeChanged()) {
out += "billboardMode";
}
if (tagsChanged()) {
out += "tags";
}
getGrab().listChangedProperties(out);
// Physics

View file

@ -203,6 +203,7 @@ public:
DEFINE_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, IgnorePickIntersection, ignorePickIntersection, bool, false);
DEFINE_PROPERTY_REF(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector<QUuid>, QVector<QUuid>());
DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE);
DEFINE_PROPERTY_REF(PROP_TAGS, Tags, tags, QSet<QString>, QSet<QString>());
DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup);
// Physics
@ -498,6 +499,9 @@ protected:
QString getCollisionMaskAsString() const;
void setCollisionMaskFromString(const QString& maskString);
QVector<QString> getTagsAsVector() const;
void setTagsFromVector(const QVector<QString>& tags);
private:
QUuid _id;
bool _idSet;

View file

@ -125,6 +125,7 @@ inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<glm::quat>&
inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<bool>& v) {return qVectorBoolToScriptValue(e, v); }
inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<float>& v) { return qVectorFloatToScriptValue(e, v); }
inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<QUuid>& v) { return qVectorQUuidToScriptValue(e, v); }
inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<QString>& v) { return qVectorQStringToScriptValue(e, v); }
inline ScriptValue convertScriptValue(ScriptEngine* e, const QRect& v) { return qRectToScriptValue(e, v); }
@ -223,6 +224,7 @@ typedef QVector<glm::quat> qVectorQuat;
typedef QVector<bool> qVectorBool;
typedef QVector<float> qVectorFloat;
typedef QVector<QUuid> qVectorQUuid;
typedef QVector<QString> qVectorQString;
inline float float_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); }
inline quint64 quint64_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); }
inline quint32 quint32_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
@ -305,6 +307,11 @@ inline qVectorQUuid qVectorQUuid_convertFromScriptValue(const ScriptValue& v, bo
return qVectorQUuidFromScriptValue(v);
}
inline qVectorQString qVectorQString_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
isValid = true;
return qVectorQStringFromScriptValue(v);
}
inline glm::quat quat_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted
ScriptValue x = v.property("x");

View file

@ -46,6 +46,7 @@ enum EntityPropertyList {
PROP_IGNORE_PICK_INTERSECTION,
PROP_RENDER_WITH_ZONES,
PROP_BILLBOARD_MODE,
PROP_TAGS,
// Grab
PROP_GRAB_GRABBABLE,
PROP_GRAB_KINEMATIC,

View file

@ -1457,6 +1457,17 @@ QVector<QUuid> EntityScriptingInterface::findEntitiesByName(const QString entity
return result;
}
QVector<QUuid> EntityScriptingInterface::findEntitiesByTags(const QVector<QString> entityTags, const glm::vec3& center, float radius, bool caseSensitiveSearch) const {
QVector<QUuid> result;
if (_entityTree) {
_entityTree->withReadLock([&] {
unsigned int searchFilter = PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES);
_entityTree->evalEntitiesInSphereWithTags(center, radius, entityTags, caseSensitiveSearch, PickFilter(searchFilter), result);
});
}
return result;
}
RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking,
const ScriptValue& entityIdsToInclude, const ScriptValue& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) const {
PROFILE_RANGE(script_entities, __FUNCTION__);

View file

@ -789,6 +789,25 @@ public slots:
Q_INVOKABLE QVector<QUuid> findEntitiesByName(const QString entityName, const glm::vec3& center, float radius,
bool caseSensitiveSearch = false) const;
/*@jsdoc
* Finds all domain and avatar entities with particular tags that intersect a sphere.
* <p><strong>Note:</strong> Server entity scripts only find entities that have a server entity script
* running in them or a parent entity. You can apply a dummy script to entities that you want found in a search.</p>
* @function Entities.findEntitiesByTags
* @param {string[]} entityTags - The tags of the entity to search for.
* @param {Vec3} center - The point about which to search.
* @param {number} radius - The radius within which to search.
* @param {boolean} [caseSensitive=false] - <code>true</code> if the search is case-sensitive, <code>false</code> if it is
* case-insensitive.
* @returns {Uuid[]} An array of entity IDs that have the specified name and intersect the search sphere. The array is
* empty if no entities could be found.
* @example <caption>Report the number of entities with the tag, "Light-Target".</caption>
* var entityIDs = Entities.findEntitiesByTags(["Light-Target"], MyAvatar.position, 10, false);
* print("Number of entities with the tag Light-Target: " + entityIDs.length);
*/
Q_INVOKABLE QVector<QUuid> findEntitiesByTags(const QVector<QString> entityTags, const glm::vec3& center, float radius,
bool caseSensitiveSearch = false) const;
/*@jsdoc
* Finds the first avatar or domain entity intersected by a {@link PickRay}. <code>Light</code> and <code>Zone</code>
* entities are not intersected unless they've been configured as pickable using

View file

@ -1110,6 +1110,42 @@ void EntityTree::evalEntitiesInSphereWithName(const glm::vec3& center, float rad
foundEntities.swap(args.entities);
}
class FindEntitiesInSphereWithTagsArgs {
public:
// Inputs
glm::vec3 position;
float targetRadius;
QVector<QString> tags;
bool caseSensitive;
PickFilter searchFilter;
// Outputs
QVector<QUuid> entities;
};
bool evalInSphereWithTagsOperation(const OctreeElementPointer& element, void* extraData) {
FindEntitiesInSphereWithTagsArgs* args = static_cast<FindEntitiesInSphereWithTagsArgs*>(extraData);
glm::vec3 penetration;
bool sphereIntersection = element->getAACube().findSpherePenetration(args->position, args->targetRadius, penetration);
// If this element contains the point, then search it...
if (sphereIntersection) {
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
entityTreeElement->evalEntitiesInSphereWithTags(args->position, args->targetRadius, args->tags, args->caseSensitive, args->searchFilter, args->entities);
return true; // keep searching in case children have closer entities
}
// if this element doesn't contain the point, then none of it's children can contain the point, so stop searching
return false;
}
// NOTE: assumes caller has handled locking
void EntityTree::evalEntitiesInSphereWithTags(const glm::vec3& center, float radius, const QVector<QString>& tags, bool caseSensitive, PickFilter searchFilter, QVector<QUuid>& foundEntities) {
FindEntitiesInSphereWithTagsArgs args = { center, radius, tags, caseSensitive, searchFilter, QVector<QUuid>() };
recurseTreeWithOperation(evalInSphereWithTagsOperation, &args);
foundEntities.swap(args.entities);
}
class FindEntitiesInCubeArgs {
public:
// Inputs

View file

@ -138,6 +138,7 @@ public:
void evalEntitiesInSphere(const glm::vec3& center, float radius, PickFilter searchFilter, QVector<QUuid>& foundEntities);
void evalEntitiesInSphereWithType(const glm::vec3& center, float radius, EntityTypes::EntityType type, PickFilter searchFilter, QVector<QUuid>& foundEntities);
void evalEntitiesInSphereWithName(const glm::vec3& center, float radius, const QString& name, bool caseSensitive, PickFilter searchFilter, QVector<QUuid>& foundEntities);
void evalEntitiesInSphereWithTags(const glm::vec3& center, float radius, const QVector<QString>& tags, bool caseSensitive, PickFilter searchFilter, QVector<QUuid>& foundEntities);
void evalEntitiesInCube(const AACube& cube, PickFilter searchFilter, QVector<QUuid>& foundEntities);
void evalEntitiesInBox(const AABox& box, PickFilter searchFilter, QVector<QUuid>& foundEntities);
void evalEntitiesInFrustum(const ViewFrustum& frustum, PickFilter searchFilter, QVector<QUuid>& foundEntities);

View file

@ -602,6 +602,77 @@ void EntityTreeElement::evalEntitiesInSphereWithName(const glm::vec3& position,
});
}
void EntityTreeElement::evalEntitiesInSphereWithTags(const glm::vec3& position, float radius, const QVector<QString>& tags, bool caseSensitive, PickFilter searchFilter, QVector<QUuid>& foundEntities) const {
forEachEntity([&](EntityItemPointer entity) {
if (!checkFilterSettings(entity, searchFilter)) {
return;
}
QSet<QString> entityTags = entity->getTags();
for (const QString& tag : tags) {
if (caseSensitive && !entityTags.contains(tag)) {
return;
} else {
const QString lowerTag = tag.toLower();
bool found = false;
for (const QString& entityTag : entityTags) {
if (lowerTag == entityTag.toLower()) {
found = true;
}
}
if (!found) {
return;
}
}
}
bool success;
AABox entityBox = entity->getAABox(success);
// if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case
glm::vec3 penetration;
if (success && entityBox.findSpherePenetration(position, radius, penetration)) {
glm::vec3 dimensions = entity->getScaledDimensions();
// FIXME - consider allowing the entity to determine penetration so that
// entities could presumably do actual hull testing if they wanted to
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better in particular
// can we handle the ellipsoid case better? We only currently handle perfect spheres
// with centered registration points
if (entity->getShapeType() == SHAPE_TYPE_SPHERE && (dimensions.x == dimensions.y && dimensions.y == dimensions.z)) {
// NOTE: entity->getRadius() doesn't return the true radius, it returns the radius of the
// maximum bounding sphere, which is actually larger than our actual radius
float entityTrueRadius = dimensions.x / 2.0f;
bool success;
glm::vec3 center = entity->getCenterPosition(success);
if (success && findSphereSpherePenetration(position, radius, center, entityTrueRadius, penetration)) {
foundEntities.push_back(entity->getID());
}
} else {
// determine the worldToEntityMatrix that doesn't include scale because
// we're going to use the registration aware aa box in the entity frame
glm::mat4 translation = glm::translate(entity->getWorldPosition());
glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
glm::vec3 registrationPoint = entity->getRegistrationPoint();
glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
AABox entityFrameBox(corner, dimensions);
glm::vec3 entityFrameSearchPosition = glm::vec3(worldToEntityMatrix * glm::vec4(position, 1.0f));
if (entityFrameBox.findSpherePenetration(entityFrameSearchPosition, radius, penetration)) {
foundEntities.push_back(entity->getID());
}
}
}
});
}
void EntityTreeElement::evalEntitiesInCube(const AACube& cube, PickFilter searchFilter, QVector<QUuid>& foundEntities) const {
forEachEntity([&](EntityItemPointer entity) {
if (!checkFilterSettings(entity, searchFilter)) {

View file

@ -177,6 +177,7 @@ public:
void evalEntitiesInSphere(const glm::vec3& position, float radius, PickFilter searchFilter, QVector<QUuid>& foundEntities) const;
void evalEntitiesInSphereWithType(const glm::vec3& position, float radius, EntityTypes::EntityType type, PickFilter searchFilter, QVector<QUuid>& foundEntities) const;
void evalEntitiesInSphereWithName(const glm::vec3& position, float radius, const QString& name, bool caseSensitive, PickFilter searchFilter, QVector<QUuid>& foundEntities) const;
void evalEntitiesInSphereWithTags(const glm::vec3& position, float radius, const QVector<QString>& tags, bool caseSensitive, PickFilter searchFilter, QVector<QUuid>& foundEntities) const;
void evalEntitiesInCube(const AACube& cube, PickFilter searchFilter, QVector<QUuid>& foundEntities) const;
void evalEntitiesInBox(const AABox& box, PickFilter searchFilter, QVector<QUuid>& foundEntities) const;
void evalEntitiesInFrustum(const ViewFrustum& frustum, PickFilter searchFilter, QVector<QUuid>& foundEntities) const;

View file

@ -290,6 +290,7 @@ enum class EntityVersion : PacketVersion {
UserAgent,
AllBillboardMode,
TextAlignment,
EntityTags,
// Add new versions above here
NUM_PACKET_TYPE,

View file

@ -496,6 +496,24 @@ bool OctreePacketData::appendValue(const QVector<QUuid>& value) {
return success;
}
bool OctreePacketData::appendValue(const QSet<QString>& value) {
QVector<QString> valueVector;
for (const QString& valueString : value) {
valueVector.push_back(valueString);
}
uint16_t qVecSize = value.size();
bool success = appendValue(qVecSize);
if (success) {
success = append((const unsigned char*)valueVector.constData(), qVecSize * sizeof(QString));
if (success) {
_bytesOfValues += qVecSize * sizeof(QString);
_totalBytesOfValues += qVecSize * sizeof(QString);
}
}
return success;
}
bool OctreePacketData::appendValue(const glm::quat& value) {
const size_t VALUES_PER_QUAT = 4;
const size_t PACKED_QUAT_SIZE = sizeof(uint16_t) * VALUES_PER_QUAT;
@ -802,6 +820,23 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVecto
return sizeof(uint16_t) + length * sizeof(QUuid);
}
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QSet<QString>& result) {
QVector<QString> resultVector;
uint16_t length;
memcpy(&length, dataBytes, sizeof(uint16_t));
dataBytes += sizeof(length);
resultVector.resize(length);
memcpy(resultVector.data(), dataBytes, length * sizeof(QString));
result.clear();
for (const QString& resultString : resultVector) {
result.insert(resultString);
}
return sizeof(uint16_t) + length * sizeof(QString);
}
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result) {
uint16_t length;
memcpy(&length, dataBytes, sizeof(length));

View file

@ -190,6 +190,9 @@ public:
/// appends a QVector of QUuids to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const QVector<QUuid>& value);
/// appends a QSet of QStrings to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const QSet<QString>& value);
/// appends a packed quat to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const glm::quat& value);
@ -290,6 +293,7 @@ public:
static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<float>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<bool>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<QUuid>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QSet<QString>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, AACube& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QRect& result);

View file

@ -862,6 +862,14 @@ bool quuidFromScriptValue(const ScriptValue& object, QUuid& uuid) {
return true;
}
ScriptValue qStringToScriptValue(ScriptEngine* engine, const QString& string) {
if (string.isNull()) {
return engine->nullValue();
}
ScriptValue obj(engine->newValue(string));
return obj;
}
/*@jsdoc
* A 2D size value.
* @typedef {object} Size
@ -1029,3 +1037,25 @@ QVector<EntityItemID> qVectorEntityItemIDFromScriptValue(const ScriptValue& arra
}
return newVector;
}
ScriptValue qVectorQStringToScriptValue(ScriptEngine* engine, const QVector<QString>& vector) {
ScriptValue array = engine->newArray();
for (int i = 0; i < vector.size(); i++) {
array.setProperty(i, qStringToScriptValue(engine, vector.at(i)));
}
return array;
}
QVector<QString> qVectorQStringFromScriptValue(const ScriptValue& array) {
if (!array.isArray()) {
return QVector<QString>();
}
QVector<QString> newVector;
int length = array.property("length").toInteger();
newVector.reserve(length);
for (int i = 0; i < length; i++) {
QString string = array.property(i).toString();
newVector << string;
}
return newVector;
}

View file

@ -224,6 +224,9 @@ ScriptValue qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector<QUuid>
bool qVectorQUuidFromScriptValue(const ScriptValue& array, QVector<QUuid>& vector);
QVector<QUuid> qVectorQUuidFromScriptValue(const ScriptValue& array);
ScriptValue qVectorQStringToScriptValue(ScriptEngine* engine, const QVector<QString>& vector);
QVector<QString> qVectorQStringFromScriptValue(const ScriptValue& array);
class AACube;
ScriptValue aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube);
bool aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube);