diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index f228467316..0faba6541c 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -18,31 +18,28 @@ #include "EntityItem.h" -void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType::Value type, - unsigned char* editBuffer, size_t length, int clockSkew) { - +void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType::Value type, QByteArray& buffer, int clockSkew) { + if (type == PacketType::EntityAdd || type == PacketType::EntityEdit) { - EntityItem::adjustEditPacketForClockSkew(editBuffer, length, clockSkew); + EntityItem::adjustEditPacketForClockSkew(buffer, clockSkew); } } -void EntityEditPacketSender::queueEditEntityMessage(PacketType::Value type, EntityItemID modelID, +void EntityEditPacketSender::queueEditEntityMessage(PacketType::Value type, EntityItemID modelID, const EntityItemProperties& properties) { if (!_shouldSend) { return; // bail early } - // use MAX_PACKET_SIZE since it's static and guaranteed to be larger than _maxPacketSize - unsigned char bufferOut[MAX_PACKET_SIZE]; - int sizeOut = 0; + QByteArray bufferOut(NLPacket::maxPayloadSize(type), 0); - if (EntityItemProperties::encodeEntityEditPacket(type, modelID, properties, &bufferOut[0], _maxPacketSize, sizeOut)) { + if (EntityItemProperties::encodeEntityEditPacket(type, modelID, properties, bufferOut)) { #ifdef WANT_DEBUG qCDebug(entities) << "calling queueOctreeEditMessage()..."; qCDebug(entities) << " id:" << modelID; qCDebug(entities) << " properties:" << properties; #endif - queueOctreeEditMessage(type, bufferOut, sizeOut); + queueOctreeEditMessage(type, bufferOut); } } @@ -50,10 +47,10 @@ void EntityEditPacketSender::queueEraseEntityMessage(const EntityItemID& entityI if (!_shouldSend) { return; // bail early } - // use MAX_PACKET_SIZE since it's static and guaranteed to be larger than _maxPacketSize - unsigned char bufferOut[MAX_PACKET_SIZE]; - size_t sizeOut = 0; - if (EntityItemProperties::encodeEraseEntityMessage(entityItemID, &bufferOut[0], _maxPacketSize, sizeOut)) { - queueOctreeEditMessage(PacketType::EntityErase, bufferOut, sizeOut); + + QByteArray bufferOut(NLPacket::maxPayloadSize(PacketType::EntityErase), 0); + + if (EntityItemProperties::encodeEraseEntityMessage(entityItemID, bufferOut)) { + queueOctreeEditMessage(PacketType::EntityErase, bufferOut); } } diff --git a/libraries/entities/src/EntityEditPacketSender.h b/libraries/entities/src/EntityEditPacketSender.h index ce88f41b04..63c2d8e81b 100644 --- a/libraries/entities/src/EntityEditPacketSender.h +++ b/libraries/entities/src/EntityEditPacketSender.h @@ -30,6 +30,6 @@ public: // My server type is the model server virtual char getMyNodeType() const { return NodeType::EntityServer; } - virtual void adjustEditPacketForClockSkew(PacketType::Value type, unsigned char* editBuffer, size_t length, int clockSkew); + virtual void adjustEditPacketForClockSkew(PacketType::Value type, QByteArray& buffer, int clockSkew); }; #endif // hifi_EntityEditPacketSender_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 6559289e33..d7fbec715d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -99,7 +99,7 @@ EntityItem::~EntityItem() { clearActions(simulation); } - // these pointers MUST be correct at delete, else we probably have a dangling backpointer + // these pointers MUST be correct at delete, else we probably have a dangling backpointer // to this EntityItem in the corresponding data structure. assert(!_simulated); assert(!_element); @@ -142,7 +142,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param return requestedProperties; } -OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params, +OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData) const { // ALL this fits... // object ID [16 bytes] @@ -151,7 +151,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet // ByteCountCoded(last_edited to last_updated delta) [~1-8 bytes] // PropertyFlags<>( everything ) [1-2 bytes] // ~27-35 bytes... - + OctreeElement::AppendState appendState = OctreeElement::COMPLETED; // assume the best // encode our ID as a byte count coded byte stream @@ -189,7 +189,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet #ifdef WANT_DEBUG float editedAgo = getEditedAgo(); QString agoAsString = formatSecondsElapsed(editedAgo); - qCDebug(entities) << "Writing entity " << getEntityItemID() << " to buffer, lastEdited =" << lastEdited + qCDebug(entities) << "Writing entity " << getEntityItemID() << " to buffer, lastEdited =" << lastEdited << " ago=" << editedAgo << "seconds - " << agoAsString; #endif @@ -221,7 +221,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet if (successLastUpdatedFits) { successLastSimulatedFits = packetData->appendRawData(encodedSimulatedDelta); } - + if (successLastSimulatedFits) { propertyFlagsOffset = packetData->getUncompressedByteOffset(); encodedPropertyFlags = propertyFlags; @@ -229,7 +229,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet successPropertyFlagsFits = packetData->appendRawData(encodedPropertyFlags); } - bool headerFits = successIDFits && successTypeFits && successCreatedFits && successLastEditedFits + bool headerFits = successIDFits && successTypeFits && successCreatedFits && successLastEditedFits && successLastUpdatedFits && successPropertyFlagsFits; int startOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -286,9 +286,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet int endOfEntityItemData = packetData->getUncompressedByteOffset(); encodedPropertyFlags = propertyFlags; int newPropertyFlagsLength = encodedPropertyFlags.length(); - packetData->updatePriorBytes(propertyFlagsOffset, + packetData->updatePriorBytes(propertyFlagsOffset, (const unsigned char*)encodedPropertyFlags.constData(), encodedPropertyFlags.length()); - + // if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet. if (newPropertyFlagsLength < oldPropertyFlagsLength) { int oldSize = packetData->getUncompressedSize(); @@ -302,13 +302,13 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet } else { assert(newPropertyFlagsLength == oldPropertyFlagsLength); // should not have grown } - + packetData->endLevel(entityLevel); } else { packetData->discardLevel(entityLevel); appendState = OctreeElement::NONE; // if we got here, then we didn't include the item } - + // If any part of the model items didn't fit, then the element is considered partial if (appendState != OctreeElement::COMPLETED) { // add this item into our list for the next appendElementData() pass @@ -338,7 +338,7 @@ int EntityItem::expectedBytes() { // clients use this method to unpack FULL updates from entity-server int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { - + // NOTE: This shouldn't happen. The only versions of the bit stream that didn't support split mtu buffers should // be handled by the model subclass and shouldn't call this routine. qCDebug(entities) << "EntityItem::readEntityDataFromBuffer()... " @@ -373,7 +373,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef _id = QUuid::fromRfc4122(encodedID); dataAt += encodedID.size(); bytesRead += encodedID.size(); - + // type QByteArray encodedType = originalDataBuffer.mid(bytesRead); // maximum possible size ByteCountCoded typeCoder = encodedType; @@ -671,7 +671,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef const QUuid& myNodeID = nodeList->getSessionUUID(); if (overwriteLocalData) { if (!_simulationOwner.matchesValidID(myNodeID)) { - + _lastSimulated = now; } } @@ -688,8 +688,8 @@ void EntityItem::debugDump() const { } // adjust any internal timestamps to fix clock skew for this server -void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, size_t length, int clockSkew) { - unsigned char* dataAt = editPacketBuffer; +void EntityItem::adjustEditPacketForClockSkew(QByteArray& buffer, int clockSkew) { + unsigned char* dataAt = reinterpret_cast(buffer.data()); int octets = numberOfThreeBitSectionsInCode(dataAt); int lengthOfOctcode = bytesRequiredForCodeLength(octets); dataAt += lengthOfOctcode; @@ -734,7 +734,7 @@ void EntityItem::setMass(float mass) { // Setting the mass actually changes the _density (at fixed volume), however // we must protect the density range to help maintain stability of physics simulation // therefore this method might not accept the mass that is supplied. - + float volume = _volumeMultiplier * getDimensions().x * getDimensions().y * getDimensions().z; // compute new density @@ -830,7 +830,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { rotation = glm::normalize(dQ * rotation); dt -= PHYSICS_ENGINE_FIXED_SUBSTEP; } - // NOTE: this final partial substep can drift away from a real Bullet simulation however + // NOTE: this final partial substep can drift away from a real Bullet simulation however // it only becomes significant for rapidly rotating objects // (e.g. around PI/4 radians per substep, or 7.5 rotations/sec at 60 substeps/sec). glm::quat dQ = computeBulletRotationStep(_angularVelocity, dt); @@ -866,7 +866,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { qCDebug(entities) << " newPosition:" << newPosition; qCDebug(entities) << " glm::distance(newPosition, position):" << glm::distance(newPosition, position); #endif - + position = newPosition; // apply effective acceleration, which will be the same as gravity if the Entity isn't at rest. @@ -920,7 +920,7 @@ glm::vec3 EntityItem::worldToEntity(const glm::vec3& point) const { } bool EntityItem::lifetimeHasExpired() const { - return isMortal() && (getAge() > getLifetime()); + return isMortal() && (getAge() > getLifetime()); } quint64 EntityItem::getExpiry() const { @@ -934,7 +934,7 @@ EntityItemProperties EntityItem::getProperties() const { properties._created = _created; properties._type = getType(); - + COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulationOwner, getSimulationOwner); COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getPosition); COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getDimensions); // NOTE: radius is obsolete @@ -968,7 +968,7 @@ EntityItemProperties EntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(actionData, getActionData); properties._defaultSettings = false; - + return properties; } @@ -1089,7 +1089,7 @@ void EntityItem::setTranformToCenter(const Transform& transform) { setTransform(transform); return; } - + Transform copy = transform; copy.postTranslate(getRegistrationPoint() - ENTITY_ITEM_HALF_VEC3); // Center to position setTransform(copy); @@ -1104,8 +1104,8 @@ void EntityItem::setDimensions(const glm::vec3& value) { /// The maximum bounding cube for the entity, independent of it's rotation. /// This accounts for the registration point (upon which rotation occurs around). -/// -AACube EntityItem::getMaximumAACube() const { +/// +AACube EntityItem::getMaximumAACube() const { // * we know that the position is the center of rotation glm::vec3 centerOfRotation = getPosition(); // also where _registration point is @@ -1115,7 +1115,7 @@ AACube EntityItem::getMaximumAACube() const { glm::vec3 registrationPoint = (getDimensions() * getRegistrationPoint()); glm::vec3 registrationRemainder = (getDimensions() * (glm::vec3(1.0f, 1.0f, 1.0f) - getRegistrationPoint())); glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder); - + // * we know that if you rotate in any direction you would create a sphere // that has a radius of the length of furthest extent from registration point float radius = glm::length(furthestExtentFromRegistration); @@ -1130,8 +1130,8 @@ AACube EntityItem::getMaximumAACube() const { /// The minimum bounding cube for the entity accounting for it's rotation. /// This accounts for the registration point (upon which rotation occurs around). -/// -AACube EntityItem::getMinimumAACube() const { +/// +AACube EntityItem::getMinimumAACube() const { // _position represents the position of the registration point. glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; @@ -1142,15 +1142,15 @@ AACube EntityItem::getMinimumAACube() const { // shift the extents to be relative to the position/registration point rotatedExtentsRelativeToRegistrationPoint.shiftBy(getPosition()); - + // the cube that best encompasses extents is... AABox box(rotatedExtentsRelativeToRegistrationPoint); glm::vec3 centerOfBox = box.calcCenter(); float longestSide = box.getLargestDimension(); float halfLongestSide = longestSide / 2.0f; glm::vec3 cornerOfCube = centerOfBox - glm::vec3(halfLongestSide, halfLongestSide, halfLongestSide); - - + + // old implementation... not correct!!! return AACube(cornerOfCube, longestSide); } @@ -1158,15 +1158,15 @@ AACube EntityItem::getMinimumAACube() const { AABox EntityItem::getAABox() const { // _position represents the position of the registration point. glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; - + glm::vec3 unrotatedMinRelativeToEntity = - (getDimensions() * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = getDimensions() * registrationRemainder; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); - + // shift the extents to be relative to the position/registration point rotatedExtentsRelativeToRegistrationPoint.shiftBy(getPosition()); - + return AABox(rotatedExtentsRelativeToRegistrationPoint); } @@ -1182,8 +1182,8 @@ AABox EntityItem::getAABox() const { // ... ((radius * 2.0f) ^2) / 3 = maxDimension ^ 2 // ... sqrt(((radius * 2.0f) ^2) / 3) = maxDimension // ... sqrt((diameter ^2) / 3) = maxDimension -// -void EntityItem::setRadius(float value) { +// +void EntityItem::setRadius(float value) { float diameter = value * 2.0f; float maxDimension = sqrt((diameter * diameter) / 3.0f); setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension)); @@ -1193,7 +1193,7 @@ void EntityItem::setRadius(float value) { // ... radius = cornerToCornerLength / 2.0f // ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2) // ... radius = sqrt(3 x maxDimension ^ 2) / 2.0f; -float EntityItem::getRadius() const { +float EntityItem::getRadius() const { return 0.5f * glm::length(getDimensions()); } @@ -1211,7 +1211,7 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); } -void EntityItem::updatePosition(const glm::vec3& value) { +void EntityItem::updatePosition(const glm::vec3& value) { auto delta = glm::distance(getPosition(), value); if (delta > IGNORE_POSITION_DELTA) { _dirtyFlags |= EntityItem::DIRTY_POSITION; @@ -1222,7 +1222,7 @@ void EntityItem::updatePosition(const glm::vec3& value) { } } -void EntityItem::updateDimensions(const glm::vec3& value) { +void EntityItem::updateDimensions(const glm::vec3& value) { auto delta = glm::distance(getDimensions(), value); if (delta > IGNORE_DIMENSIONS_DELTA) { setDimensions(value); @@ -1233,7 +1233,7 @@ void EntityItem::updateDimensions(const glm::vec3& value) { } } -void EntityItem::updateRotation(const glm::quat& rotation) { +void EntityItem::updateRotation(const glm::quat& rotation) { if (getRotation() != rotation) { setRotation(rotation); @@ -1273,7 +1273,7 @@ void EntityItem::updateMass(float mass) { } } -void EntityItem::updateVelocity(const glm::vec3& value) { +void EntityItem::updateVelocity(const glm::vec3& value) { auto delta = glm::distance(_velocity, value); if (delta > IGNORE_LINEAR_VELOCITY_DELTA) { _dirtyFlags |= EntityItem::DIRTY_LINEAR_VELOCITY; @@ -1290,7 +1290,7 @@ void EntityItem::updateVelocity(const glm::vec3& value) { } } -void EntityItem::updateDamping(float value) { +void EntityItem::updateDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); if (fabsf(_damping - clampedDamping) > IGNORE_DAMPING_DELTA) { _damping = clampedDamping; @@ -1298,7 +1298,7 @@ void EntityItem::updateDamping(float value) { } } -void EntityItem::updateGravity(const glm::vec3& value) { +void EntityItem::updateGravity(const glm::vec3& value) { auto delta = glm::distance(_gravity, value); if (delta > IGNORE_GRAVITY_DELTA) { _gravity = value; @@ -1309,7 +1309,7 @@ void EntityItem::updateGravity(const glm::vec3& value) { } } -void EntityItem::updateAngularVelocity(const glm::vec3& value) { +void EntityItem::updateAngularVelocity(const glm::vec3& value) { auto delta = glm::distance(_angularVelocity, value); if (delta > IGNORE_ANGULAR_VELOCITY_DELTA) { _dirtyFlags |= EntityItem::DIRTY_ANGULAR_VELOCITY; @@ -1326,7 +1326,7 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) { } } -void EntityItem::updateAngularDamping(float value) { +void EntityItem::updateAngularDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); if (fabsf(_angularDamping - clampedDamping) > IGNORE_DAMPING_DELTA) { _angularDamping = clampedDamping; @@ -1334,16 +1334,16 @@ void EntityItem::updateAngularDamping(float value) { } } -void EntityItem::updateIgnoreForCollisions(bool value) { +void EntityItem::updateIgnoreForCollisions(bool value) { if (_ignoreForCollisions != value) { - _ignoreForCollisions = value; + _ignoreForCollisions = value; _dirtyFlags |= EntityItem::DIRTY_COLLISION_GROUP; } } -void EntityItem::updateCollisionsWillMove(bool value) { +void EntityItem::updateCollisionsWillMove(bool value) { if (_collisionsWillMove != value) { - _collisionsWillMove = value; + _collisionsWillMove = value; _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index bc8901c6b1..7efe1569d2 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -73,7 +73,7 @@ const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; /// one directly, instead you must only construct one of it's derived classes with additional features. class EntityItem { // These two classes manage lists of EntityItem pointers and must be able to cleanup pointers when an EntityItem is deleted. - // To make the cleanup robust each EntityItem has backpointers to its manager classes (which are only ever set/cleared by + // To make the cleanup robust each EntityItem has backpointers to its manager classes (which are only ever set/cleared by // the managers themselves, hence they are fiends) whose NULL status can be used to determine which managers still need to // do cleanup. friend class EntityTreeElement; @@ -161,15 +161,15 @@ public: EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { return 0; } - virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, + virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { return false; } // by default entity items don't add to scene - virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, + virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { } // by default entity items don't add to scene virtual void render(RenderArgs* args) { } // by default entity items don't know how to render static int expectedBytes(); - static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew); + static void adjustEditPacketForClockSkew(QByteArray& buffer, int clockSkew); // perform update virtual void update(const quint64& now) { _lastUpdated = now; } @@ -190,20 +190,20 @@ public: // attributes applicable to all entity types EntityTypes::EntityType getType() const { return _type; } - + inline glm::vec3 getCenterPosition() const { return getTransformToCenter().getTranslation(); } void setCenterPosition(const glm::vec3& position); - + const Transform getTransformToCenter() const; void setTranformToCenter(const Transform& transform); - + inline const Transform& getTransform() const { return _transform; } inline void setTransform(const Transform& transform) { _transform = transform; } - + /// Position in meters (0.0 - TREE_SCALE) inline const glm::vec3& getPosition() const { return _transform.getTranslation(); } inline void setPosition(const glm::vec3& value) { _transform.setTranslation(value); } - + inline const glm::quat& getRotation() const { return _transform.getRotation(); } inline void setRotation(const glm::quat& rotation) { _transform.setRotation(rotation); } @@ -416,7 +416,7 @@ protected: float _glowLevel; float _localRenderAlpha; float _density = ENTITY_ITEM_DEFAULT_DENSITY; // kg/m^3 - // NOTE: _volumeMultiplier is used to allow some mass properties code exist in the EntityItem base class + // NOTE: _volumeMultiplier is used to allow some mass properties code exist in the EntityItem base class // rather than in all of the derived classes. If we ever collapse these classes to one we could do it a // different way. float _volumeMultiplier = 1.0f; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 7e7b21417e..c864ed1bca 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -132,7 +132,7 @@ void EntityItemProperties::setAnimationSettings(const QString& value) { // the animations setting is a JSON string that may contain various animation settings. // if it includes fps, frameIndex, or running, those values will be parsed out and // will over ride the regular animation settings - + QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonObject settingsAsJsonObject = settingsAsJson.object(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); @@ -140,17 +140,17 @@ void EntityItemProperties::setAnimationSettings(const QString& value) { float fps = settingsMap["fps"].toFloat(); setAnimationFPS(fps); } - + if (settingsMap.contains("frameIndex")) { float frameIndex = settingsMap["frameIndex"].toFloat(); setAnimationFrameIndex(frameIndex); } - + if (settingsMap.contains("running")) { bool running = settingsMap["running"].toBool(); setAnimationIsPlaying(running); } - + _animationSettings = value; _animationSettingsChanged = true; } @@ -160,20 +160,20 @@ QString EntityItemProperties::getAnimationSettings() const { // if it includes fps, frameIndex, or running, those values will be parsed out and // will over ride the regular animation settings QString value = _animationSettings; - + QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonObject settingsAsJsonObject = settingsAsJson.object(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); - + QVariant fpsValue(getAnimationFPS()); settingsMap["fps"] = fpsValue; - + QVariant frameIndexValue(getAnimationFrameIndex()); settingsMap["frameIndex"] = frameIndexValue; - + QVariant runningValue(getAnimationIsPlaying()); settingsMap["running"] = runningValue; - + settingsAsJsonObject = QJsonObject::fromVariantMap(settingsMap); QJsonDocument newDocument(settingsAsJsonObject); QByteArray jsonByteArray = newDocument.toJson(QJsonDocument::Compact); @@ -194,10 +194,10 @@ void EntityItemProperties::debugDump() const { qCDebug(entities) << " _dimensions=" << getDimensions(); qCDebug(entities) << " _modelURL=" << _modelURL; qCDebug(entities) << " _compoundShapeURL=" << _compoundShapeURL; - + getAtmosphere().debugDump(); getSkybox().debugDump(); - + qCDebug(entities) << " changed properties..."; EntityPropertyFlags props = getChangedProperties(); props.debugDumpBits(); @@ -287,7 +287,7 @@ void EntityItemProperties::setBackgroundModeFromString(const QString& background EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; - + CHECK_PROPERTY_CHANGE(PROP_POSITION, position); CHECK_PROPERTY_CHANGE(PROP_DIMENSIONS, dimensions); CHECK_PROPERTY_CHANGE(PROP_ROTATION, rotation); @@ -357,18 +357,18 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { changedProperties += _stage.getChangedProperties(); changedProperties += _atmosphere.getChangedProperties(); changedProperties += _skybox.getChangedProperties(); - + return changedProperties; } QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool skipDefaults) const { QScriptValue properties = engine->newObject(); EntityItemProperties defaultEntityProperties; - + if (_idSet) { COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(id, _id.toString()); } - + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type)); COPY_PROPERTY_TO_QSCRIPTVALUE(position); COPY_PROPERTY_TO_QSCRIPTVALUE(dimensions); @@ -435,7 +435,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID); COPY_PROPERTY_TO_QSCRIPTVALUE(name); COPY_PROPERTY_TO_QSCRIPTVALUE(collisionSoundURL); - + COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightColor); COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightIntensity); COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightAmbientIntensity); @@ -465,7 +465,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool sittingPoints.setProperty("length", _sittingPoints.size()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(sittingPoints, sittingPoints); // gettable, but not settable } - + if (!skipDefaults) { AABox aaBox = getAABox(); QScriptValue boundingBox = engine->newObject(); @@ -479,16 +479,16 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool boundingBox.setProperty("dimensions", boundingBoxDimensions); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(boundingBox, boundingBox); // gettable, but not settable } - + QString textureNamesList = _textureNames.join(",\n"); if (!skipDefaults) { COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesList); // gettable, but not settable } - + _stage.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties); _atmosphere.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties); _skybox.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties); - + return properties; } @@ -497,7 +497,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool if (typeScriptValue.isValid()) { setType(typeScriptValue.toVariant().toString()); } - + COPY_PROPERTY_FROM_QSCRIPTVALUE(position, glmVec3, setPosition); COPY_PROPERTY_FROM_QSCRIPTVALUE(dimensions, glmVec3, setDimensions); COPY_PROPERTY_FROM_QSCRIPTVALUE(rotation, glmQuat, setRotation); @@ -549,7 +549,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID); COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName); COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL); - + COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightColor, xColor, setKeyLightColor); COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightIntensity, float, setKeyLightIntensity); COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightAmbientIntensity, float, setKeyLightAmbientIntensity); @@ -615,14 +615,13 @@ void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object // TODO: Implement support for script and visible properties. // bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, EntityItemID id, const EntityItemProperties& properties, - unsigned char* bufferOut, int sizeIn, int& sizeOut) { - OctreePacketData ourDataPacket(false, sizeIn); // create a packetData object to add out packet details too. + QByteArray& buffer) { + OctreePacketData ourDataPacket(false, buffer.size()); // create a packetData object to add out packet details too. OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro - + bool success = true; // assume the best OctreeElement::AppendState appendState = OctreeElement::COMPLETED; // assume the best - sizeOut = 0; - + // TODO: We need to review how jurisdictions should be handled for entities. (The old Models and Particles code // didn't do anything special for jurisdictions, so we're keeping that same behavior here.) // @@ -632,35 +631,35 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent glm::vec3 rootPosition(0); float rootScale = 0.5f; unsigned char* octcode = pointToOctalCode(rootPosition.x, rootPosition.y, rootPosition.z, rootScale); - + success = packetData->startSubTree(octcode); delete[] octcode; - + // assuming we have rome to fit our octalCode, proceed... if (success) { - + // Now add our edit content details... - + // id // encode our ID as a byte count coded byte stream QByteArray encodedID = id.toRfc4122(); // NUM_BYTES_RFC4122_UUID - + // encode our ID as a byte count coded byte stream ByteCountCoded tokenCoder; QByteArray encodedToken; - + // encode our type as a byte count coded byte stream ByteCountCoded typeCoder = (quint32)properties.getType(); QByteArray encodedType = typeCoder; - + quint64 updateDelta = 0; // this is an edit so by definition, it's update is in sync ByteCountCoded updateDeltaCoder = updateDelta; QByteArray encodedUpdateDelta = updateDeltaCoder; - + EntityPropertyFlags propertyFlags(PROP_LAST_ITEM); EntityPropertyFlags requestedProperties = properties.getChangedProperties(); EntityPropertyFlags propertiesDidntFit = requestedProperties; - + // TODO: we need to handle the multi-pass form of this, similar to how we handle entity data // // If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item, @@ -668,46 +667,46 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent //if (modelTreeElementExtraEncodeData && modelTreeElementExtraEncodeData->includedItems.contains(getEntityItemID())) { // requestedProperties = modelTreeElementExtraEncodeData->includedItems.value(getEntityItemID()); //} - + LevelDetails entityLevel = packetData->startLevel(); - + // Last Edited quint64 always first, before any other details, which allows us easy access to adjusting this // timestamp for clock skew quint64 lastEdited = properties.getLastEdited(); bool successLastEditedFits = packetData->appendValue(lastEdited); - + bool successIDFits = packetData->appendRawData(encodedID); if (successIDFits) { successIDFits = packetData->appendRawData(encodedToken); } bool successTypeFits = packetData->appendRawData(encodedType); - + // NOTE: We intentionally do not send "created" times in edit messages. This is because: // 1) if the edit is to an existing entity, the created time can not be changed // 2) if the edit is to a new entity, the created time is the last edited time - + // TODO: Should we get rid of this in this in edit packets, since this has to always be 0? bool successLastUpdatedFits = packetData->appendRawData(encodedUpdateDelta); - + int propertyFlagsOffset = packetData->getUncompressedByteOffset(); QByteArray encodedPropertyFlags = propertyFlags; int oldPropertyFlagsLength = encodedPropertyFlags.length(); bool successPropertyFlagsFits = packetData->appendRawData(encodedPropertyFlags); int propertyCount = 0; - + bool headerFits = successIDFits && successTypeFits && successLastEditedFits && successLastUpdatedFits && successPropertyFlagsFits; - + int startOfEntityItemData = packetData->getUncompressedByteOffset(); - + if (headerFits) { bool successPropertyFits; propertyFlags -= PROP_LAST_ITEM; // clear the last item for now, we may or may not set it as the actual item - + // These items would go here once supported.... // PROP_PAGED_PROPERTY, // PROP_CUSTOM_PROPERTIES_INCLUDED, - + APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, properties._simulationOwner.toByteArray()); APPEND_ENTITY_PROPERTY(PROP_POSITION, properties.getPosition()); APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete @@ -733,12 +732,12 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData()); APPEND_ENTITY_PROPERTY(PROP_HREF, properties.getHref()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, properties.getDescription()); - - + + if (properties.getType() == EntityTypes::Web) { APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl()); } - + if (properties.getType() == EntityTypes::Text) { APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText()); APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight()); @@ -746,7 +745,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, properties.getBackgroundColor()); APPEND_ENTITY_PROPERTY(PROP_FACE_CAMERA, properties.getFaceCamera()); } - + if (properties.getType() == EntityTypes::Model) { APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, properties.getModelURL()); APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL()); @@ -758,7 +757,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, properties.getAnimationSettings()); APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)(properties.getShapeType())); } - + if (properties.getType() == EntityTypes::Light) { APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, properties.getIsSpotlight()); APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); @@ -766,7 +765,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_EXPONENT, properties.getExponent()); APPEND_ENTITY_PROPERTY(PROP_CUTOFF, properties.getCutoff()); } - + if (properties.getType() == EntityTypes::ParticleEffect) { APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, properties.getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, properties.getAnimationFrameIndex()); @@ -781,24 +780,24 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, properties.getLocalGravity()); APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius()); } - + if (properties.getType() == EntityTypes::Zone) { APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, properties.getKeyLightColor()); APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, properties.getKeyLightIntensity()); APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, properties.getKeyLightAmbientIntensity()); APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, properties.getKeyLightDirection()); - + _staticStage.setProperties(properties); _staticStage.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState ); - + APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)properties.getShapeType()); APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL()); - + APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, (uint32_t)properties.getBackgroundMode()); - + _staticAtmosphere.setProperties(properties); _staticAtmosphere.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState ); - + _staticSkybox.setProperties(properties); _staticSkybox.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState ); } @@ -808,12 +807,12 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_VOXEL_DATA, properties.getVoxelData()); APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, properties.getVoxelSurfaceStyle()); } - + if (properties.getType() == EntityTypes::Line) { APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, properties.getLineWidth()); APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, properties.getLinePoints()); } - + APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID()); APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL()); @@ -821,62 +820,63 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent } if (propertyCount > 0) { int endOfEntityItemData = packetData->getUncompressedByteOffset(); - + encodedPropertyFlags = propertyFlags; int newPropertyFlagsLength = encodedPropertyFlags.length(); packetData->updatePriorBytes(propertyFlagsOffset, (const unsigned char*)encodedPropertyFlags.constData(), encodedPropertyFlags.length()); - + // if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet. if (newPropertyFlagsLength < oldPropertyFlagsLength) { int oldSize = packetData->getUncompressedSize(); - + const unsigned char* modelItemData = packetData->getUncompressedData(propertyFlagsOffset + oldPropertyFlagsLength); int modelItemDataLength = endOfEntityItemData - startOfEntityItemData; int newEntityItemDataStart = propertyFlagsOffset + newPropertyFlagsLength; packetData->updatePriorBytes(newEntityItemDataStart, modelItemData, modelItemDataLength); - + int newSize = oldSize - (oldPropertyFlagsLength - newPropertyFlagsLength); packetData->setUncompressedSize(newSize); - + } else { assert(newPropertyFlagsLength == oldPropertyFlagsLength); // should not have grown } - + packetData->endLevel(entityLevel); } else { packetData->discardLevel(entityLevel); appendState = OctreeElement::NONE; // if we got here, then we didn't include the item } - + // If any part of the model items didn't fit, then the element is considered partial if (appendState != OctreeElement::COMPLETED) { - + // TODO: handle mechanism for handling partial fitting data! // add this item into our list for the next appendElementData() pass //modelTreeElementExtraEncodeData->includedItems.insert(getEntityItemID(), propertiesDidntFit); - + // for now, if it's not complete, it's not successful success = false; } } - + if (success) { packetData->endSubTree(); + const unsigned char* finalizedData = packetData->getFinalizedData(); - int finalizedSize = packetData->getFinalizedSize(); - if (finalizedSize <= sizeIn) { - memcpy(bufferOut, finalizedData, finalizedSize); - sizeOut = finalizedSize; + int finalizedSize = packetData->getFinalizedSize(); + + if (finalizedSize <= buffer.size()) { + buffer.replace(0, finalizedSize, finalizedData, finalizedSize); + buffer.resize(finalizedSize); } else { qCDebug(entities) << "ERROR - encoded edit message doesn't fit in output buffer."; - sizeOut = 0; success = false; } } else { packetData->discardSubTree(); - sizeOut = 0; } + return success; } @@ -899,19 +899,19 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes, EntityItemID& entityID, EntityItemProperties& properties) { bool valid = false; - + const unsigned char* dataAt = data; processedBytes = 0; - + // the first part of the data is an octcode, this is a required element of the edit packet format, but we don't // actually use it, we do need to skip it and read to the actual data we care about. int octets = numberOfThreeBitSectionsInCode(data); int bytesToReadOfOctcode = bytesRequiredForCodeLength(octets); - + // we don't actually do anything with this octcode... dataAt += bytesToReadOfOctcode; processedBytes += bytesToReadOfOctcode; - + // Edit packets have a last edited time stamp immediately following the octcode. // NOTE: the edit times have been set by the editor to match out clock, so we don't need to adjust // these times for clock skew at this point. @@ -920,20 +920,20 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int dataAt += sizeof(lastEdited); processedBytes += sizeof(lastEdited); properties.setLastEdited(lastEdited); - + // NOTE: We intentionally do not send "created" times in edit messages. This is because: // 1) if the edit is to an existing entity, the created time can not be changed // 2) if the edit is to a new entity, the created time is the last edited time - + // encoded id QByteArray encodedID((const char*)dataAt, NUM_BYTES_RFC4122_UUID); // maximum possible size QUuid editID = QUuid::fromRfc4122(encodedID); dataAt += encodedID.size(); processedBytes += encodedID.size(); - + entityID = editID; valid = true; - + // Entity Type... QByteArray encodedType((const char*)dataAt, (bytesToRead - processedBytes)); ByteCountCoded typeCoder = encodedType; @@ -942,22 +942,22 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int encodedType = typeCoder; // determine true bytesToRead dataAt += encodedType.size(); processedBytes += encodedType.size(); - + // Update Delta - when was this item updated relative to last edit... this really should be 0 // TODO: Should we get rid of this in this in edit packets, since this has to always be 0? // TODO: do properties need to handle lastupdated??? - + // last updated is stored as ByteCountCoded delta from lastEdited QByteArray encodedUpdateDelta((const char*)dataAt, (bytesToRead - processedBytes)); ByteCountCoded updateDeltaCoder = encodedUpdateDelta; encodedUpdateDelta = updateDeltaCoder; // determine true bytesToRead dataAt += encodedUpdateDelta.size(); processedBytes += encodedUpdateDelta.size(); - + // TODO: Do we need this lastUpdated?? We don't seem to use it. //quint64 updateDelta = updateDeltaCoder; //quint64 lastUpdated = lastEdited + updateDelta; // don't adjust for clock skew since we already did that for lastEdited - + // Property Flags... QByteArray encodedPropertyFlags((const char*)dataAt, (bytesToRead - processedBytes)); EntityPropertyFlags propertyFlags = encodedPropertyFlags; @@ -989,12 +989,12 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HREF, QString, setHref); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DESCRIPTION, QString, setDescription); - - + + if (properties.getType() == EntityTypes::Web) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl); } - + if (properties.getType() == EntityTypes::Text) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight); @@ -1002,7 +1002,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_COLOR, xColor, setBackgroundColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FACE_CAMERA, bool, setFaceCamera); } - + if (properties.getType() == EntityTypes::Model) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MODEL_URL, QString, setModelURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); @@ -1014,7 +1014,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); } - + if (properties.getType() == EntityTypes::Light) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, xColor, setColor); @@ -1022,14 +1022,14 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EXPONENT, float, setExponent); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff); } - + if (properties.getType() == EntityTypes::ParticleEffect) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures); - + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAX_PARTICLES, float, setMaxParticles); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFESPAN, float, setLifespan); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_RATE, float, setEmitRate); @@ -1038,15 +1038,15 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCAL_GRAVITY, float, setLocalGravity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius); } - + if (properties.getType() == EntityTypes::Zone) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_COLOR, xColor, setKeyLightColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_INTENSITY, float, setKeyLightIntensity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_AMBIENT_INTENSITY, float, setKeyLightAmbientIntensity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_DIRECTION, glm::vec3, setKeyLightDirection); - + properties.getStage().decodeFromEditPacket(propertyFlags, dataAt , processedBytes); - + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode); @@ -1059,12 +1059,12 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_DATA, QByteArray, setVoxelData); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle); } - + if (properties.getType() == EntityTypes::Line) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_WIDTH, float, setLineWidth); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_POINTS, QVector, setLinePoints); } - + 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); @@ -1077,28 +1077,28 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int // NOTE: This version will only encode the portion of the edit message immediately following the // header it does not include the send times and sequence number because that is handled by the // edit packet sender... -bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityItemID, - unsigned char* outputBuffer, size_t maxLength, size_t& outputLength) { - - unsigned char* copyAt = outputBuffer; +bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer) { + + char* copyAt = buffer.data(); uint16_t numberOfIds = 1; // only one entity ID in this message - - if (maxLength < sizeof(numberOfIds) + NUM_BYTES_RFC4122_UUID) { + + int outputLength = 0; + + if (buffer.size() < sizeof(numberOfIds) + NUM_BYTES_RFC4122_UUID) { qCDebug(entities) << "ERROR - encodeEraseEntityMessage() called with buffer that is too small!"; - outputLength = 0; return false; } + memcpy(copyAt, &numberOfIds, sizeof(numberOfIds)); copyAt += sizeof(numberOfIds); outputLength = sizeof(numberOfIds); - - QUuid entityID = entityItemID; - QByteArray encodedEntityID = entityID.toRfc4122(); - - memcpy(copyAt, encodedEntityID.constData(), NUM_BYTES_RFC4122_UUID); + + memcpy(copyAt, entityItemID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); copyAt += NUM_BYTES_RFC4122_UUID; outputLength += NUM_BYTES_RFC4122_UUID; - + + buffer.resize(outputLength); + return true; } @@ -1137,19 +1137,19 @@ void EntityItemProperties::markAllChanged() { _isSpotlightChanged = true; _ignoreForCollisionsChanged = true; _collisionsWillMoveChanged = true; - + _intensityChanged = true; _exponentChanged = true; _cutoffChanged = true; _lockedChanged = true; _texturesChanged = true; - + _textChanged = true; _lineHeightChanged = true; _textColorChanged = true; _backgroundColorChanged = true; _shapeTypeChanged = true; - + _maxParticlesChanged = true; _lifespanChanged = true; _emitRateChanged = true; @@ -1157,24 +1157,24 @@ void EntityItemProperties::markAllChanged() { _emitStrengthChanged = true; _localGravityChanged = true; _particleRadiusChanged = true; - + _marketplaceIDChanged = true; - + _keyLightColorChanged = true; _keyLightIntensityChanged = true; _keyLightAmbientIntensityChanged = true; _keyLightDirectionChanged = true; - + _backgroundModeChanged = true; _stage.markAllChanged(); _atmosphere.markAllChanged(); _skybox.markAllChanged(); - + _sourceUrlChanged = true; _voxelVolumeSizeChanged = true; _voxelDataChanged = true; _voxelSurfaceStyleChanged = true; - + _lineWidthChanged = true; _linePointsChanged = true; @@ -1190,40 +1190,40 @@ void EntityItemProperties::markAllChanged() { AACube EntityItemProperties::getMaximumAACube() const { // * we know that the position is the center of rotation glm::vec3 centerOfRotation = _position; // also where _registration point is - + // * we know that the registration point is the center of rotation // * we can calculate the length of the furthest extent from the registration point // as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint) glm::vec3 registrationPoint = (_dimensions * _registrationPoint); glm::vec3 registrationRemainder = (_dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint)); glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder); - + // * we know that if you rotate in any direction you would create a sphere // that has a radius of the length of furthest extent from registration point float radius = glm::length(furthestExtentFromRegistration); - + // * we know that the minimum bounding cube of this maximum possible sphere is // (center - radius) to (center + radius) glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius); float diameter = radius * 2.0f; - + return AACube(minimumCorner, diameter); } // The minimum bounding box for the entity. AABox EntityItemProperties::getAABox() const { - + // _position represents the position of the registration point. glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; - + glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); - + // shift the extents to be relative to the position/registration point rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position); - + return AABox(rotatedExtentsRelativeToRegistrationPoint); } @@ -1233,7 +1233,7 @@ bool EntityItemProperties::hasTerseUpdateChanges() const { } bool EntityItemProperties::hasMiscPhysicsChanges() const { - return _gravityChanged || _dimensionsChanged || _densityChanged || _frictionChanged + return _gravityChanged || _dimensionsChanged || _densityChanged || _frictionChanged || _restitutionChanged || _dampingChanged || _angularDampingChanged || _registrationPointChanged || _compoundShapeURLChanged || _collisionsWillMoveChanged || _ignoreForCollisionsChanged; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 8bc932c0ed..34c15043c0 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -175,11 +175,9 @@ public: void setLocalRenderAlpha(float value) { _localRenderAlpha = value; _localRenderAlphaChanged = true; } static bool encodeEntityEditPacket(PacketType::Value command, EntityItemID id, const EntityItemProperties& properties, - unsigned char* bufferOut, int sizeIn, int& sizeOut); - - static bool encodeEraseEntityMessage(const EntityItemID& entityItemID, - unsigned char* outputBuffer, size_t maxLength, size_t& outputLength); + QByteArray& buffer); + static bool encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer); static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes, EntityItemID& entityID, EntityItemProperties& properties); @@ -201,7 +199,7 @@ public: QString getSimulatorIDAsString() const { return _simulationOwner.getID().toString().mid(1,36).toUpper(); } void setVoxelDataDirty() { _voxelDataChanged = true; } - + void setLinePointsDirty() {_linePointsChanged = true; } void setCreated(QDateTime& v); @@ -244,12 +242,12 @@ void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object // define these inline here so the macros work -inline void EntityItemProperties::setPosition(const glm::vec3& value) +inline void EntityItemProperties::setPosition(const glm::vec3& value) { _position = glm::clamp(value, 0.0f, (float)TREE_SCALE); _positionChanged = true; } inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { debug << "EntityItemProperties[" << "\n"; - + debug << " _type:" << properties.getType() << "\n"; // TODO: figure out why position and animationSettings don't seem to like the macro approach diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 77bc6a9c70..1b3008d4e7 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -128,8 +128,8 @@ void OctreeEditPacketSender::processPreServerExistsPackets() { // Then "process" all the packable messages... while (!_preServerEdits.empty()) { - EditMessageTuple editMessage = std::move(_preServerEdits.front()); - queueOctreeEditMessage(std::get<0>(editMessage), std::get<1>(editMessage), std::get<2>(editMessage)); + EditMessagePair& editMessage = _preServerEdits.front(); + queueOctreeEditMessage(editMessage.first, editMessage.second); _preServerEdits.pop_front(); } @@ -194,8 +194,8 @@ void OctreeEditPacketSender::queuePacketToNodes(std::unique_ptr packet } -// NOTE: editPacketBuffer - is JUST the octcode/color and does not contain the packet header! -void OctreeEditPacketSender::queueOctreeEditMessage(PacketType::Value type, unsigned char* editPacketBuffer, size_t length) { +// NOTE: editMessage - is JUST the octcode/color and does not contain the packet header +void OctreeEditPacketSender::queueOctreeEditMessage(PacketType::Value type, QByteArray& editMessage) { if (!_shouldSend) { return; // bail early @@ -205,9 +205,10 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType::Value type, unsi // jurisdictions for processing if (!serversExist()) { if (_maxPendingMessages > 0) { - EditMessageTuple messageTuple { type, editPacketBuffer, length }; + EditMessagePair messagePair { type, QByteArray(editMessage) }; + _pendingPacketsLock.lock(); - _preServerEdits.push_back(messageTuple); + _preServerEdits.push_back(messagePair); // if we've saved MORE than out max, then clear out the oldest packet... int allPendingMessages = _preServerSingleMessagePackets.size() + _preServerEdits.size(); @@ -239,7 +240,8 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType::Value type, unsi _serverJurisdictions->lockForRead(); if ((*_serverJurisdictions).find(nodeUUID) != (*_serverJurisdictions).end()) { const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; - isMyJurisdiction = (map.isMyJurisdiction(editPacketBuffer, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); + isMyJurisdiction = (map.isMyJurisdiction(reinterpret_cast(editMessage.data()), + CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); } else { isMyJurisdiction = false; } @@ -253,7 +255,7 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType::Value type, unsi } else { // If we're switching type, then we send the last one and start over if ((type != bufferedPacket->readType() && bufferedPacket->getSizeUsed() > 0) || - (length >= bufferedPacket->bytesAvailable())) { + (editMessage.size() >= bufferedPacket->bytesAvailable())) { // create the new packet and swap it with the packet in _pendingEditPackets auto packetToRelease = initializePacket(type, node->getClockSkewUsec()); @@ -269,10 +271,10 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType::Value type, unsi // We call this virtual function that allows our specific type of EditPacketSender to // fixup the buffer for any clock skew if (node->getClockSkewUsec() != 0) { - adjustEditPacketForClockSkew(type, editPacketBuffer, length, node->getClockSkewUsec()); + adjustEditPacketForClockSkew(type, editMessage, node->getClockSkewUsec()); } - bufferedPacket->write(reinterpret_cast(editPacketBuffer), length); + bufferedPacket->write(editMessage); } } }); diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index 22ad9c6679..9a54e76aea 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -29,7 +29,7 @@ public: /// Queues a single edit message. Will potentially send a pending multi-command packet. Determines which server /// node or nodes the packet should be sent to. Can be called even before servers are known, in which case up to /// MaxPendingMessages will be buffered and processed when servers are known. - void queueOctreeEditMessage(PacketType::Value type, unsigned char* editPacketBuffer, size_t length); + void queueOctreeEditMessage(PacketType::Value type, QByteArray& editMessage); /// Releases all queued messages even if those messages haven't filled an MTU packet. This will move the packed message /// packets onto the send queue. If running in threaded mode, the caller does not need to do any further processing to @@ -74,8 +74,7 @@ public: // you must override these... virtual char getMyNodeType() const = 0; - virtual void adjustEditPacketForClockSkew(PacketType::Value type, - unsigned char* editPacketBuffer, size_t length, int clockSkew) { } + virtual void adjustEditPacketForClockSkew(PacketType::Value type, QByteArray& buffer, int clockSkew) { } void processNackPacket(const QByteArray& packet); @@ -83,7 +82,7 @@ public slots: void nodeKilled(SharedNodePointer node); protected: - using EditMessageTuple = std::tuple; + using EditMessagePair = std::pair; bool _shouldSend; void queuePacketToNode(const QUuid& nodeID, std::unique_ptr packet); @@ -102,7 +101,7 @@ protected: bool _releaseQueuedMessagesPending; QMutex _pendingPacketsLock; QMutex _packetsQueueLock; // don't let different threads release the queue while another thread is writing to it - std::list _preServerEdits; // these will get packed into other larger packets + std::list _preServerEdits; // these will get packed into other larger packets std::list> _preServerSingleMessagePackets; // these will go out as is NodeToJurisdictionMap* _serverJurisdictions;