Merge pull request #6083 from sethalves/groundwork-for-hold-action-changes

Groundwork for hold action changes
This commit is contained in:
Andrew Meadows 2015-10-15 13:30:02 -07:00
commit 3d17c57910
33 changed files with 790 additions and 310 deletions

View file

@ -24,15 +24,24 @@ AssignmentAction::~AssignmentAction() {
}
void AssignmentAction::removeFromSimulation(EntitySimulation* simulation) const {
simulation->removeAction(_id);
withReadLock([&]{
simulation->removeAction(_id);
simulation->applyActionChanges();
});
}
QByteArray AssignmentAction::serialize() const {
return _data;
QByteArray result;
withReadLock([&]{
result = _data;
});
return result;
}
void AssignmentAction::deserialize(QByteArray serializedArguments) {
_data = serializedArguments;
withWriteLock([&]{
_data = serializedArguments;
});
}
bool AssignmentAction::updateArguments(QVariantMap arguments) {

View file

@ -19,7 +19,7 @@
#include "EntityActionInterface.h"
class AssignmentAction : public EntityActionInterface {
class AssignmentAction : public EntityActionInterface, public ReadWriteLockable {
public:
AssignmentAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity);
virtual ~AssignmentAction();

View file

@ -147,9 +147,13 @@ bool EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio
readOptionBool(QString("wantEditLogging"), settingsSectionObject, wantEditLogging);
qDebug("wantEditLogging=%s", debug::valueOf(wantEditLogging));
bool wantTerseEditLogging = false;
readOptionBool(QString("wantTerseEditLogging"), settingsSectionObject, wantTerseEditLogging);
qDebug("wantTerseEditLogging=%s", debug::valueOf(wantTerseEditLogging));
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
tree->setWantEditLogging(wantEditLogging);
tree->setWantTerseEditLogging(wantTerseEditLogging);
return true;
}

View file

@ -484,6 +484,14 @@
"default": false,
"advanced": true
},
{
"name": "wantTerseEditLogging",
"type": "checkbox",
"label": "Edit Logging (Terse)",
"help": "Logging of all edits to entities",
"default": false,
"advanced": true
},
{
"name": "verboseDebug",
"type": "checkbox",

View file

@ -66,7 +66,8 @@ var MSEC_PER_SEC = 1000.0;
// these control how long an abandoned pointer line will hang around
var startTime = Date.now();
var LIFETIME = 10;
var ACTION_LIFETIME = 10; // seconds
var ACTION_LIFETIME = 15; // seconds
var ACTION_LIFETIME_REFRESH = 5;
var PICKS_PER_SECOND_PER_HAND = 5;
var MSECS_PER_SEC = 1000.0;
@ -339,11 +340,12 @@ function MyController(hand, triggerAction) {
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation",
"gravity", "ignoreForCollisions"]);
var now = Date.now();
// add the action and initialize some variables
this.currentObjectPosition = grabbedProperties.position;
this.currentObjectRotation = grabbedProperties.rotation;
this.currentObjectTime = Date.now();
this.currentObjectTime = now;
this.handPreviousPosition = handControllerPosition;
this.handPreviousRotation = handRotation;
@ -359,6 +361,7 @@ function MyController(hand, triggerAction) {
if (this.actionID === NULL_ACTION_ID) {
this.actionID = null;
}
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC);
if (this.actionID !== null) {
this.setState(STATE_CONTINUE_DISTANCE_HOLDING);
@ -441,7 +444,9 @@ function MyController(hand, triggerAction) {
this.currentObjectTime = now;
// this doubles hand rotation
var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation, DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), Quat.inverse(this.handPreviousRotation));
var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation,
DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR),
Quat.inverse(this.handPreviousRotation));
this.handPreviousRotation = handRotation;
this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
@ -454,9 +459,11 @@ function MyController(hand, triggerAction) {
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
lifetime: ACTION_LIFETIME
});
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC);
};
this.nearGrabbing = function() {
var now = Date.now();
if (this.triggerSmoothedReleased()) {
this.setState(STATE_RELEASE);
@ -465,7 +472,7 @@ function MyController(hand, triggerAction) {
this.lineOff();
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity,
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity,
["position", "rotation", "gravity", "ignoreForCollisions"]);
this.activateEntity(this.grabbedEntity, grabbedProperties);
@ -473,23 +480,24 @@ function MyController(hand, triggerAction) {
var handPosition = this.getHandPosition();
var objectRotation = grabbedProperties.rotation;
var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
var currentObjectPosition = grabbedProperties.position;
var offset = Vec3.subtract(currentObjectPosition, handPosition);
var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset);
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
this.actionID = NULL_ACTION_ID;
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
hand: this.hand === RIGHT_HAND ? "right" : "left",
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
relativePosition: offsetPosition,
relativeRotation: offsetRotation,
relativePosition: this.offsetPosition,
relativeRotation: this.offsetRotation,
lifetime: ACTION_LIFETIME
});
if (this.actionID === NULL_ACTION_ID) {
this.actionID = null;
} else {
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC);
this.setState(STATE_CONTINUE_NEAR_GRABBING);
if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
@ -511,10 +519,10 @@ function MyController(hand, triggerAction) {
return;
}
// Keep track of the fingertip velocity to impart when we release the object
// Note that the idea of using a constant 'tip' velocity regardless of the
// Keep track of the fingertip velocity to impart when we release the object.
// Note that the idea of using a constant 'tip' velocity regardless of the
// object's actual held offset is an idea intended to make it easier to throw things:
// Because we might catch something or transfer it between hands without a good idea
// Because we might catch something or transfer it between hands without a good idea
// of it's actual offset, let's try imparting a velocity which is at a fixed radius
// from the palm.
@ -529,9 +537,17 @@ function MyController(hand, triggerAction) {
this.currentObjectTime = now;
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab");
Entities.updateAction(this.grabbedEntity, this.actionID, {
lifetime: ACTION_LIFETIME
});
if (this.actionTimeout - now < ACTION_LIFETIME_REFRESH * MSEC_PER_SEC) {
// if less than a 5 seconds left, refresh the actions lifetime
Entities.updateAction(this.grabbedEntity, this.actionID, {
hand: this.hand === RIGHT_HAND ? "right" : "left",
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
relativePosition: this.offsetPosition,
relativeRotation: this.offsetRotation,
lifetime: ACTION_LIFETIME
});
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC);
}
};
this.nearGrabbingNonColliding = function() {

View file

@ -56,6 +56,7 @@ const float DISPLAYNAME_FADE_TIME = 0.5f;
const float DISPLAYNAME_FADE_FACTOR = pow(0.01f, 1.0f / DISPLAYNAME_FADE_TIME);
const float DISPLAYNAME_ALPHA = 1.0f;
const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
namespace render {
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
@ -1167,3 +1168,64 @@ void Avatar::rebuildSkeletonBody() {
DependencyManager::get<AvatarManager>()->updateAvatarPhysicsShape(getSessionUUID());
}
glm::vec3 Avatar::getLeftPalmPosition() {
glm::vec3 leftHandPosition;
getSkeletonModel().getLeftHandPosition(leftHandPosition);
glm::quat leftRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
leftHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftRotation);
return leftHandPosition;
}
glm::vec3 Avatar::getLeftPalmVelocity() {
const PalmData* palm = getHand()->getPalm(LEFT_HAND_INDEX);
if (palm != NULL) {
return palm->getVelocity();
}
return glm::vec3(0.0f);
}
glm::vec3 Avatar::getLeftPalmAngularVelocity() {
const PalmData* palm = getHand()->getPalm(LEFT_HAND_INDEX);
if (palm != NULL) {
return palm->getRawAngularVelocity();
}
return glm::vec3(0.0f);
}
glm::quat Avatar::getLeftPalmRotation() {
glm::quat leftRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
return leftRotation;
}
glm::vec3 Avatar::getRightPalmPosition() {
glm::vec3 rightHandPosition;
getSkeletonModel().getRightHandPosition(rightHandPosition);
glm::quat rightRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
rightHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightRotation);
return rightHandPosition;
}
glm::vec3 Avatar::getRightPalmVelocity() {
const PalmData* palm = getHand()->getPalm(RIGHT_HAND_INDEX);
if (palm != NULL) {
return palm->getVelocity();
}
return glm::vec3(0.0f);
}
glm::vec3 Avatar::getRightPalmAngularVelocity() {
const PalmData* palm = getHand()->getPalm(RIGHT_HAND_INDEX);
if (palm != NULL) {
return palm->getRawAngularVelocity();
}
return glm::vec3(0.0f);
}
glm::quat Avatar::getRightPalmRotation() {
glm::quat rightRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
return rightRotation;
}

View file

@ -174,6 +174,16 @@ public:
void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; }
AvatarMotionState* getMotionState() { return _motionState; }
public slots:
glm::vec3 getLeftPalmPosition();
glm::vec3 getLeftPalmVelocity();
glm::vec3 getLeftPalmAngularVelocity();
glm::quat getLeftPalmRotation();
glm::vec3 getRightPalmPosition();
glm::vec3 getRightPalmVelocity();
glm::vec3 getRightPalmAngularVelocity();
glm::quat getRightPalmRotation();
protected:
SkeletonModel _skeletonModel;
glm::vec3 _skeletonOffset;

View file

@ -21,8 +21,7 @@ AvatarActionHold::AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntit
ObjectActionSpring(id, ownerEntity),
_relativePosition(glm::vec3(0.0f)),
_relativeRotation(glm::quat()),
_hand("right"),
_mine(false)
_hand("right")
{
_type = ACTION_TYPE_HOLD;
#if WANT_DEBUG
@ -37,17 +36,12 @@ AvatarActionHold::~AvatarActionHold() {
}
void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
if (!_mine) {
// if a local script isn't updating this, then we are just getting spring-action data over the wire.
// let the super-class handle it.
ObjectActionSpring::updateActionWorker(deltaTimeStep);
return;
}
bool gotLock = false;
glm::quat rotation;
glm::vec3 position;
glm::vec3 offset;
bool gotLock = withTryReadLock([&]{
gotLock = withTryReadLock([&]{
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::vec3 palmPosition;
glm::quat palmRotation;
@ -66,17 +60,16 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
if (gotLock) {
gotLock = withTryWriteLock([&]{
if (_positionalTarget != position || _rotationalTarget != rotation) {
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
}
_positionalTarget = position;
_rotationalTarget = rotation;
_positionalTarget = position;
_rotationalTarget = rotation;
_positionalTargetSet = true;
_rotationalTargetSet = true;
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
}
});
}
if (gotLock) {
ObjectActionSpring::updateActionWorker(deltaTimeStep);
}
@ -84,66 +77,76 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
bool AvatarActionHold::updateArguments(QVariantMap arguments) {
if (!ObjectAction::updateArguments(arguments)) {
return false;
}
bool ok = true;
glm::vec3 relativePosition =
EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false);
if (!ok) {
relativePosition = _relativePosition;
}
glm::vec3 relativePosition;
glm::quat relativeRotation;
float timeScale;
QString hand;
QUuid holderID;
bool needUpdate = false;
ok = true;
glm::quat relativeRotation =
EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false);
if (!ok) {
relativeRotation = _relativeRotation;
}
ok = true;
float timeScale =
EntityActionInterface::extractFloatArgument("hold", arguments, "timeScale", ok, false);
if (!ok) {
timeScale = _linearTimeScale;
}
bool somethingChanged = ObjectAction::updateArguments(arguments);
withReadLock([&]{
bool ok = true;
relativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false);
if (!ok) {
relativePosition = _relativePosition;
}
ok = true;
QString hand =
EntityActionInterface::extractStringArgument("hold", arguments, "hand", ok, false);
if (!ok || !(hand == "left" || hand == "right")) {
hand = _hand;
}
ok = true;
relativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false);
if (!ok) {
relativeRotation = _relativeRotation;
}
if (relativePosition != _relativePosition
|| relativeRotation != _relativeRotation
|| timeScale != _linearTimeScale
|| hand != _hand) {
ok = true;
timeScale = EntityActionInterface::extractFloatArgument("hold", arguments, "timeScale", ok, false);
if (!ok) {
timeScale = _linearTimeScale;
}
ok = true;
hand = EntityActionInterface::extractStringArgument("hold", arguments, "hand", ok, false);
if (!ok || !(hand == "left" || hand == "right")) {
hand = _hand;
}
ok = true;
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
holderID = myAvatar->getSessionUUID();
if (somethingChanged ||
relativePosition != _relativePosition ||
relativeRotation != _relativeRotation ||
timeScale != _linearTimeScale ||
hand != _hand) {
needUpdate = true;
}
});
if (needUpdate) {
withWriteLock([&] {
_relativePosition = relativePosition;
_relativeRotation = relativeRotation;
const float MIN_TIMESCALE = 0.1f;
_linearTimeScale = glm::min(MIN_TIMESCALE, timeScale);
_linearTimeScale = glm::max(MIN_TIMESCALE, timeScale);
_angularTimeScale = _linearTimeScale;
_hand = hand;
_mine = true;
_active = true;
activateBody();
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
}
});
activateBody();
}
return true;
}
QVariantMap AvatarActionHold::getArguments() {
QVariantMap arguments = ObjectAction::getArguments();
withReadLock([&]{
if (!_mine) {
arguments = ObjectActionSpring::getArguments();
return;
}
arguments["relativePosition"] = glmToQMap(_relativePosition);
arguments["relativeRotation"] = glmToQMap(_relativeRotation);
arguments["timeScale"] = _linearTimeScale;
@ -152,9 +155,10 @@ QVariantMap AvatarActionHold::getArguments() {
return arguments;
}
QByteArray AvatarActionHold::serialize() const {
return ObjectActionSpring::serialize();
}
void AvatarActionHold::deserialize(QByteArray serializedArguments) {
if (!_mine) {
ObjectActionSpring::deserialize(serializedArguments);
}
assert(false);
}

View file

@ -27,15 +27,17 @@ public:
virtual void updateActionWorker(float deltaTimeStep);
QByteArray serialize() const;
virtual void deserialize(QByteArray serializedArguments);
virtual bool shouldSuppressLocationEdits() { return false; }
private:
static const uint16_t holdVersion;
glm::vec3 _relativePosition;
glm::quat _relativeRotation;
QString _hand;
bool _mine = false;
};
#endif // hifi_AvatarActionHold_h

View file

@ -343,3 +343,11 @@ void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) {
}
}
}
AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) {
if (sessionID == _myAvatar->getSessionUUID()) {
return std::static_pointer_cast<Avatar>(_myAvatar);
}
return getAvatarHash()[sessionID];
}

View file

@ -35,7 +35,8 @@ public:
void init();
MyAvatar* getMyAvatar() { return _myAvatar.get(); }
AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID);
void updateMyAvatar(float deltaTime);
void updateOtherAvatars(float deltaTime);

View file

@ -540,70 +540,6 @@ void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
}
}
const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
glm::vec3 MyAvatar::getLeftPalmPosition() {
glm::vec3 leftHandPosition;
getSkeletonModel().getLeftHandPosition(leftHandPosition);
glm::quat leftRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
leftHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftRotation);
return leftHandPosition;
}
glm::vec3 MyAvatar::getLeftPalmVelocity() {
const PalmData* palm = getHand()->getPalm(LEFT_HAND_INDEX);
if (palm != NULL) {
return palm->getVelocity();
}
return glm::vec3(0.0f);
}
glm::vec3 MyAvatar::getLeftPalmAngularVelocity() {
const PalmData* palm = getHand()->getPalm(LEFT_HAND_INDEX);
if (palm != NULL) {
return palm->getRawAngularVelocity();
}
return glm::vec3(0.0f);
}
glm::quat MyAvatar::getLeftPalmRotation() {
glm::quat leftRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
return leftRotation;
}
glm::vec3 MyAvatar::getRightPalmPosition() {
glm::vec3 rightHandPosition;
getSkeletonModel().getRightHandPosition(rightHandPosition);
glm::quat rightRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
rightHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightRotation);
return rightHandPosition;
}
glm::vec3 MyAvatar::getRightPalmVelocity() {
const PalmData* palm = getHand()->getPalm(RIGHT_HAND_INDEX);
if (palm != NULL) {
return palm->getVelocity();
}
return glm::vec3(0.0f);
}
glm::vec3 MyAvatar::getRightPalmAngularVelocity() {
const PalmData* palm = getHand()->getPalm(RIGHT_HAND_INDEX);
if (palm != NULL) {
return palm->getRawAngularVelocity();
}
return glm::vec3(0.0f);
}
glm::quat MyAvatar::getRightPalmRotation() {
glm::quat rightRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
return rightRotation;
}
void MyAvatar::clearReferential() {
changeReferential(NULL);
}

View file

@ -199,15 +199,6 @@ public slots:
Q_INVOKABLE void updateMotionBehaviorFromMenu();
glm::vec3 getLeftPalmPosition();
glm::vec3 getLeftPalmVelocity();
glm::vec3 getLeftPalmAngularVelocity();
glm::quat getLeftPalmRotation();
glm::vec3 getRightPalmPosition();
glm::vec3 getRightPalmVelocity();
glm::vec3 getRightPalmAngularVelocity();
glm::quat getRightPalmRotation();
void clearReferential();
bool setModelReferential(const QUuid& id);
bool setJointReferential(const QUuid& id, int jointIndex);

View file

@ -163,6 +163,19 @@ void AnimationPropertyGroup::debugDump() const {
qDebug() << "currentFrame:" << getCurrentFrame() << " has changed:" << currentFrameChanged();
}
void AnimationPropertyGroup::listChangedProperties(QList<QString>& out) {
if (urlChanged()) {
out << "animation-url";
}
if (fpsChanged()) {
out << "animation-fps";
}
if (currentFrameChanged()) {
out << "animation-currentFrame";
}
}
bool AnimationPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,

View file

@ -37,6 +37,7 @@ public:
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const;
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings);
virtual void debugDump() const;
virtual void listChangedProperties(QList<QString>& out);
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,

View file

@ -54,6 +54,30 @@ void AtmospherePropertyGroup::debugDump() const {
qDebug() << " Has Stars:" << getHasStars() << " has changed:" << hasStarsChanged();
}
void AtmospherePropertyGroup::listChangedProperties(QList<QString>& out) {
if (centerChanged()) {
out << "center";
}
if (innerRadiusChanged()) {
out << "innerRadius";
}
if (outerRadiusChanged()) {
out << "outerRadius";
}
if (mieScatteringChanged()) {
out << "mieScattering";
}
if (rayleighScatteringChanged()) {
out << "rayleighScattering";
}
if (scatteringWavelengthsChanged()) {
out << "scatteringWavelengths";
}
if (hasStarsChanged()) {
out << "hasStars";
}
}
bool AtmospherePropertyGroup::appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,

View file

@ -53,6 +53,7 @@ public:
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const;
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings);
virtual void debugDump() const;
virtual void listChangedProperties(QList<QString>& out);
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
@ -87,7 +88,7 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged);
static const glm::vec3 DEFAULT_CENTER;
static const float DEFAULT_INNER_RADIUS;
static const float DEFAULT_OUTER_RADIUS;

View file

@ -51,15 +51,7 @@ public:
bool locallyAddedButNotYetReceived = false;
protected:
virtual glm::vec3 getPosition() = 0;
virtual void setPosition(glm::vec3 position) = 0;
virtual glm::quat getRotation() = 0;
virtual void setRotation(glm::quat rotation) = 0;
virtual glm::vec3 getLinearVelocity() = 0;
virtual void setLinearVelocity(glm::vec3 linearVelocity) = 0;
virtual glm::vec3 getAngularVelocity() = 0;
virtual void setAngularVelocity(glm::vec3 angularVelocity) = 0;
virtual bool shouldSuppressLocationEdits() { return false; }
// these look in the arguments map for a named argument. if it's not found or isn't well formed,
// ok will be set to false (note that it's never set to true -- set it to true before calling these).
@ -75,6 +67,16 @@ protected:
static QString extractStringArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required = true);
protected:
virtual glm::vec3 getPosition() = 0;
virtual void setPosition(glm::vec3 position) = 0;
virtual glm::quat getRotation() = 0;
virtual void setRotation(glm::quat rotation) = 0;
virtual glm::vec3 getLinearVelocity() = 0;
virtual void setLinearVelocity(glm::vec3 linearVelocity) = 0;
virtual glm::vec3 getAngularVelocity() = 0;
virtual void setAngularVelocity(glm::vec3 angularVelocity) = 0;
QUuid _id;
EntityActionType _type;
};

View file

@ -1579,6 +1579,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s
}
EntityActionPointer action = _objectActions[actionID];
action->setOwnerEntity(nullptr);
_objectActions.remove(actionID);
@ -1630,8 +1631,6 @@ void EntityItem::deserializeActionsInternal() {
return;
}
// Keep track of which actions got added or updated by the new actionData
EntityTreePointer entityTree = _element ? _element->getTree() : nullptr;
assert(entityTree);
EntitySimulation* simulation = entityTree ? entityTree->getSimulation() : nullptr;
@ -1643,6 +1642,7 @@ void EntityItem::deserializeActionsInternal() {
serializedActionsStream >> serializedActions;
}
// Keep track of which actions got added or updated by the new actionData
QSet<QUuid> updated;
foreach(QByteArray serializedAction, serializedActions) {
@ -1720,9 +1720,11 @@ void EntityItem::setActionData(QByteArray actionData) {
void EntityItem::setActionDataInternal(QByteArray actionData) {
assertWriteLocked();
if (_allActionsDataCache != actionData) {
_allActionsDataCache = actionData;
deserializeActionsInternal();
}
checkWaitingToRemove();
_allActionsDataCache = actionData;
deserializeActionsInternal();
}
void EntityItem::serializeActions(bool& success, QByteArray& result) const {
@ -1788,3 +1790,15 @@ QVariantMap EntityItem::getActionArguments(const QUuid& actionID) const {
return result;
}
bool EntityItem::shouldSuppressLocationEdits() const {
QHash<QUuid, EntityActionPointer>::const_iterator i = _objectActions.begin();
while (i != _objectActions.end()) {
if (i.value()->shouldSuppressLocationEdits()) {
return true;
}
i++;
}
return false;
}

View file

@ -424,6 +424,7 @@ public:
QVariantMap getActionArguments(const QUuid& actionID) const;
void deserializeActions();
void setActionDataDirty(bool value) const { _actionDataDirty = value; }
bool shouldSuppressLocationEdits() const;
protected:

View file

@ -1519,3 +1519,254 @@ void EntityItemProperties::setSimulationOwner(const QByteArray& data) {
_simulationOwnerChanged = true;
}
}
QList<QString> EntityItemProperties::listChangedProperties() {
QList<QString> out;
if (containsPositionChange()) {
out += "posistion";
}
if (dimensionsChanged()) {
out += "dimensions";
}
if (velocityChanged()) {
out += "velocity";
}
if (nameChanged()) {
out += "name";
}
if (visibleChanged()) {
out += "visible";
}
if (rotationChanged()) {
out += "rotation";
}
if (densityChanged()) {
out += "density";
}
if (gravityChanged()) {
out += "gravity";
}
if (accelerationChanged()) {
out += "acceleration";
}
if (dampingChanged()) {
out += "damping";
}
if (restitutionChanged()) {
out += "restitution";
}
if (frictionChanged()) {
out += "friction";
}
if (lifetimeChanged()) {
out += "lifetime";
}
if (scriptChanged()) {
out += "script";
}
if (scriptTimestampChanged()) {
out += "scriptTimestamp";
}
if (collisionSoundURLChanged()) {
out += "collisionSoundURL";
}
if (colorChanged()) {
out += "color";
}
if (colorSpreadChanged()) {
out += "colorSpread";
}
if (colorStartChanged()) {
out += "colorStart";
}
if (colorFinishChanged()) {
out += "colorFinish";
}
if (alphaChanged()) {
out += "alpha";
}
if (alphaSpreadChanged()) {
out += "alphaSpread";
}
if (alphaStartChanged()) {
out += "alphaStart";
}
if (alphaFinishChanged()) {
out += "alphaFinish";
}
if (modelURLChanged()) {
out += "modelURL";
}
if (compoundShapeURLChanged()) {
out += "compoundShapeURL";
}
if (registrationPointChanged()) {
out += "registrationPoint";
}
if (angularVelocityChanged()) {
out += "angularVelocity";
}
if (angularDampingChanged()) {
out += "angularDamping";
}
if (ignoreForCollisionsChanged()) {
out += "ignoreForCollisions";
}
if (collisionsWillMoveChanged()) {
out += "collisionsWillMove";
}
if (isSpotlightChanged()) {
out += "isSpotlight";
}
if (intensityChanged()) {
out += "intensity";
}
if (exponentChanged()) {
out += "exponent";
}
if (cutoffChanged()) {
out += "cutoff";
}
if (lockedChanged()) {
out += "locked";
}
if (texturesChanged()) {
out += "textures";
}
if (userDataChanged()) {
out += "userData";
}
if (simulationOwnerChanged()) {
out += "simulationOwner";
}
if (textChanged()) {
out += "text";
}
if (lineHeightChanged()) {
out += "lineHeight";
}
if (textColorChanged()) {
out += "textColor";
}
if (backgroundColorChanged()) {
out += "backgroundColor";
}
if (shapeTypeChanged()) {
out += "shapeType";
}
if (maxParticlesChanged()) {
out += "maxParticles";
}
if (lifespanChanged()) {
out += "lifespan";
}
if (isEmittingChanged()) {
out += "isEmitting";
}
if (emitRateChanged()) {
out += "emitRate";
}
if (emitSpeedChanged()) {
out += "emitSpeed";
}
if (speedSpreadChanged()) {
out += "speedSpread";
}
if (emitOrientationChanged()) {
out += "emitOrientation";
}
if (emitDimensionsChanged()) {
out += "emitDimensions";
}
if (emitRadiusStartChanged()) {
out += "emitRadiusStart";
}
if (polarStartChanged()) {
out += "polarStart";
}
if (polarFinishChanged()) {
out += "polarFinish";
}
if (azimuthStartChanged()) {
out += "azimuthStart";
}
if (azimuthFinishChanged()) {
out += "azimuthFinish";
}
if (emitAccelerationChanged()) {
out += "emitAcceleration";
}
if (accelerationSpreadChanged()) {
out += "accelerationSpread";
}
if (particleRadiusChanged()) {
out += "particleRadius";
}
if (radiusSpreadChanged()) {
out += "radiusSpread";
}
if (radiusStartChanged()) {
out += "radiusStart";
}
if (radiusFinishChanged()) {
out += "radiusFinish";
}
if (marketplaceIDChanged()) {
out += "marketplaceID";
}
if (backgroundModeChanged()) {
out += "backgroundMode";
}
if (voxelVolumeSizeChanged()) {
out += "voxelVolumeSize";
}
if (voxelDataChanged()) {
out += "voxelData";
}
if (voxelSurfaceStyleChanged()) {
out += "voxelSurfaceStyle";
}
if (hrefChanged()) {
out += "href";
}
if (descriptionChanged()) {
out += "description";
}
if (actionDataChanged()) {
out += "actionData";
}
if (xTextureURLChanged()) {
out += "xTextureURL";
}
if (yTextureURLChanged()) {
out += "yTextureURL";
}
if (zTextureURLChanged()) {
out += "zTextureURL";
}
if (xNNeighborIDChanged()) {
out += "xNNeighborID";
}
if (yNNeighborIDChanged()) {
out += "yNNeighborID";
}
if (zNNeighborIDChanged()) {
out += "zNNeighborID";
}
if (xPNeighborIDChanged()) {
out += "xPNeighborID";
}
if (yPNeighborIDChanged()) {
out += "yPNeighborID";
}
if (zPNeighborIDChanged()) {
out += "zPNeighborID";
}
getAnimation().listChangedProperties(out);
getAtmosphere().listChangedProperties(out);
getSkybox().listChangedProperties(out);
getStage().listChangedProperties(out);
return out;
}

View file

@ -253,6 +253,8 @@ public:
void setActionDataDirty() { _actionDataChanged = true; }
QList<QString> listChangedProperties();
private:
QUuid _id;
bool _idSet;
@ -370,7 +372,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelSurfaceStyle, voxelSurfaceStyle, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Href, href, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Description, description, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ActionData, actionData, "");
if (properties.actionDataChanged()) {
debug << " " << "actionData" << ":" << properties.getActionData().toHex() << "" << "\n";
}
DEBUG_PROPERTY_IF_CHANGED(debug, properties, XTextureURL, xTextureURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, YTextureURL, yTextureURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZTextureURL, zTextureURL, "");

View file

@ -613,6 +613,9 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi
qCDebug(entities) << "User [" << senderNode->getUUID() << "] editing entity. ID:" << entityItemID;
qCDebug(entities) << " properties:" << properties;
}
if (wantTerseEditLogging()) {
qCDebug(entities) << "edit" << entityItemID.toString() << properties.listChangedProperties();
}
endLogging = usecTimestampNow();
startUpdate = usecTimestampNow();
@ -638,6 +641,9 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi
<< newEntity->getEntityItemID();
qCDebug(entities) << " properties:" << properties;
}
if (wantTerseEditLogging()) {
qCDebug(entities) << "add" << entityItemID.toString() << properties.listChangedProperties();
}
endLogging = usecTimestampNow();
}
@ -869,7 +875,7 @@ int EntityTree::processEraseMessage(NLPacket& packet, const SharedNodePointer& s
EntityItemID entityItemID(entityID);
entityItemIDsToDelete << entityItemID;
if (wantEditLogging()) {
if (wantEditLogging() || wantTerseEditLogging()) {
qCDebug(entities) << "User [" << sourceNode->getUUID() << "] deleting entity. ID:" << entityItemID;
}
@ -913,7 +919,7 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons
EntityItemID entityItemID(entityID);
entityItemIDsToDelete << entityItemID;
if (wantEditLogging()) {
if (wantEditLogging() || wantTerseEditLogging()) {
qCDebug(entities) << "User [" << sourceNode->getUUID() << "] deleting entity. ID:" << entityItemID;
}

View file

@ -175,6 +175,9 @@ public:
bool wantEditLogging() const { return _wantEditLogging; }
void setWantEditLogging(bool value) { _wantEditLogging = value; }
bool wantTerseEditLogging() const { return _wantTerseEditLogging; }
void setWantTerseEditLogging(bool value) { _wantTerseEditLogging = value; }
bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues);
bool readFromMap(QVariantMap& entityDescription);
@ -240,6 +243,7 @@ private:
EntitySimulation* _simulation;
bool _wantEditLogging = false;
bool _wantTerseEditLogging = false;
void maybeNotifyNewCollisionSoundURL(const QString& oldCollisionSoundURL, const QString& newCollisionSoundURL);

View file

@ -57,6 +57,7 @@ public:
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const = 0;
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) = 0;
virtual void debugDump() const { }
virtual void listChangedProperties(QList<QString>& out) { }
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,

View file

@ -33,6 +33,15 @@ void SkyboxPropertyGroup::debugDump() const {
qDebug() << " URL:" << getURL() << " has changed:" << urlChanged();
}
void SkyboxPropertyGroup::listChangedProperties(QList<QString>& out) {
if (colorChanged()) {
out << "skybox-color";
}
if (urlChanged()) {
out << "skybox-url";
}
}
bool SkyboxPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,

View file

@ -33,6 +33,7 @@ public:
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const;
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings);
virtual void debugDump() const;
virtual void listChangedProperties(QList<QString>& out);
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,

View file

@ -66,6 +66,27 @@ void StagePropertyGroup::debugDump() const {
qDebug() << " _automaticHourDay:" << _automaticHourDay;
}
void StagePropertyGroup::listChangedProperties(QList<QString>& out) {
if (sunModelEnabledChanged()) {
out << "stage-sunModelEnabled";
}
if (latitudeChanged()) {
out << "stage-latitude";
}
if (altitudeChanged()) {
out << "stage-altitude";
}
if (dayChanged()) {
out << "stage-day";
}
if (hourChanged()) {
out << "stage-hour";
}
if (automaticHourDayChanged()) {
out << "stage-automaticHourDay";
}
}
bool StagePropertyGroup::appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,

View file

@ -33,6 +33,7 @@ public:
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const;
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings);
virtual void debugDump() const;
virtual void listChangedProperties(QList<QString>& out);
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,

View file

@ -291,6 +291,10 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
return true;
}
if (_entity->shouldSuppressLocationEdits()) {
return false;
}
// Else we measure the error between current and extrapolated transform (according to expected behavior
// of remote EntitySimulation) and return true if the error is significant.

View file

@ -24,20 +24,33 @@ ObjectAction::~ObjectAction() {
}
void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) {
if (_ownerEntity.expired()) {
bool ownerEntityExpired = false;
quint64 expiresWhen = 0;
withReadLock([&]{
ownerEntityExpired = _ownerEntity.expired();
expiresWhen = _expires;
});
if (ownerEntityExpired) {
qDebug() << "warning -- action with no entity removing self from btCollisionWorld.";
btDynamicsWorld* dynamicsWorld = static_cast<btDynamicsWorld*>(collisionWorld);
dynamicsWorld->removeAction(this);
return;
}
if (_expires > 0) {
if (expiresWhen > 0) {
quint64 now = usecTimestampNow();
if (now > _expires) {
EntityItemPointer ownerEntity = _ownerEntity.lock();
_active = false;
if (now > expiresWhen) {
EntityItemPointer ownerEntity = nullptr;
QUuid myID;
withWriteLock([&]{
ownerEntity = _ownerEntity.lock();
_active = false;
myID = getID();
});
if (ownerEntity) {
ownerEntity->removeAction(nullptr, getID());
ownerEntity->removeAction(nullptr, myID);
}
}
}
@ -50,35 +63,48 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta
}
bool ObjectAction::updateArguments(QVariantMap arguments) {
bool lifetimeSet = true;
float lifetime = EntityActionInterface::extractFloatArgument("action", arguments, "lifetime", lifetimeSet, false);
if (lifetimeSet) {
quint64 now = usecTimestampNow();
_expires = now + (quint64)(lifetime * USECS_PER_SECOND);
} else {
_expires = 0;
}
bool somethingChanged = false;
bool tagSet = true;
QString tag = EntityActionInterface::extractStringArgument("action", arguments, "tag", tagSet, false);
if (tagSet) {
_tag = tag;
} else {
tag = "";
}
withWriteLock([&]{
quint64 previousExpires = _expires;
QString previousTag = _tag;
return true;
bool lifetimeSet = true;
float lifetime = EntityActionInterface::extractFloatArgument("action", arguments, "lifetime", lifetimeSet, false);
if (lifetimeSet) {
quint64 now = usecTimestampNow();
_expires = now + (quint64)(lifetime * USECS_PER_SECOND);
} else {
_expires = 0;
}
bool tagSet = true;
QString tag = EntityActionInterface::extractStringArgument("action", arguments, "tag", tagSet, false);
if (tagSet) {
_tag = tag;
} else {
tag = "";
}
if (previousExpires != _expires || previousTag != _tag) {
somethingChanged = true;
}
});
return somethingChanged;
}
QVariantMap ObjectAction::getArguments() {
QVariantMap arguments;
if (_expires == 0) {
arguments["lifetime"] = 0.0f;
} else {
quint64 now = usecTimestampNow();
arguments["lifetime"] = (float)(_expires - now) / (float)USECS_PER_SECOND;
}
arguments["tag"] = _tag;
withReadLock([&]{
if (_expires == 0) {
arguments["lifetime"] = 0.0f;
} else {
quint64 now = usecTimestampNow();
arguments["lifetime"] = (float)(_expires - now) / (float)USECS_PER_SECOND;
}
arguments["tag"] = _tag;
});
return arguments;
}
@ -87,20 +113,30 @@ void ObjectAction::debugDraw(btIDebugDraw* debugDrawer) {
}
void ObjectAction::removeFromSimulation(EntitySimulation* simulation) const {
simulation->removeAction(_id);
QUuid myID;
withReadLock([&]{
myID = _id;
});
simulation->removeAction(myID);
}
btRigidBody* ObjectAction::getRigidBody() {
auto ownerEntity = _ownerEntity.lock();
if (!ownerEntity) {
return nullptr;
ObjectMotionState* motionState = nullptr;
withReadLock([&]{
auto ownerEntity = _ownerEntity.lock();
if (!ownerEntity) {
return;
}
void* physicsInfo = ownerEntity->getPhysicsInfo();
if (!physicsInfo) {
return;
}
motionState = static_cast<ObjectMotionState*>(physicsInfo);
});
if (motionState) {
return motionState->getRigidBody();
}
void* physicsInfo = ownerEntity->getPhysicsInfo();
if (!physicsInfo) {
return nullptr;
}
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
return motionState->getRigidBody();
return nullptr;
}
glm::vec3 ObjectAction::getPosition() {

View file

@ -80,44 +80,61 @@ void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) {
bool ObjectActionOffset::updateArguments(QVariantMap arguments) {
if (!ObjectAction::updateArguments(arguments)) {
return false;
}
bool ok = true;
glm::vec3 pointToOffsetFrom =
EntityActionInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", ok, true);
if (!ok) {
pointToOffsetFrom = _pointToOffsetFrom;
}
glm::vec3 pointToOffsetFrom;
float linearTimeScale;
float linearDistance;
ok = true;
float linearTimeScale =
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", ok, false);
if (!ok) {
linearTimeScale = _linearTimeScale;
}
bool needUpdate = false;
bool somethingChanged = ObjectAction::updateArguments(arguments);
ok = true;
float linearDistance =
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearDistance", ok, false);
if (!ok) {
linearDistance = _linearDistance;
}
withReadLock([&]{
bool ok = true;
pointToOffsetFrom =
EntityActionInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", ok, true);
if (!ok) {
pointToOffsetFrom = _pointToOffsetFrom;
}
// only change stuff if something actually changed
if (_pointToOffsetFrom != pointToOffsetFrom
|| _linearTimeScale != linearTimeScale
|| _linearDistance != linearDistance) {
ok = true;
linearTimeScale =
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", ok, false);
if (!ok) {
linearTimeScale = _linearTimeScale;
}
ok = true;
linearDistance =
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearDistance", ok, false);
if (!ok) {
linearDistance = _linearDistance;
}
// only change stuff if something actually changed
if (somethingChanged ||
_pointToOffsetFrom != pointToOffsetFrom ||
_linearTimeScale != linearTimeScale ||
_linearDistance != linearDistance) {
needUpdate = true;
}
});
if (needUpdate) {
withWriteLock([&] {
_pointToOffsetFrom = pointToOffsetFrom;
_linearTimeScale = linearTimeScale;
_linearDistance = linearDistance;
_positionalTargetSet = true;
_active = true;
activateBody();
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
}
});
activateBody();
}
return true;
}
@ -134,17 +151,18 @@ QVariantMap ObjectActionOffset::getArguments() {
QByteArray ObjectActionOffset::serialize() const {
QByteArray ba;
QDataStream dataStream(&ba, QIODevice::WriteOnly);
dataStream << getType();
dataStream << ACTION_TYPE_OFFSET;
dataStream << getID();
dataStream << ObjectActionOffset::offsetVersion;
dataStream << _pointToOffsetFrom;
dataStream << _linearDistance;
dataStream << _linearTimeScale;
dataStream << _positionalTargetSet;
dataStream << _expires;
dataStream << _tag;
withReadLock([&] {
dataStream << _pointToOffsetFrom;
dataStream << _linearDistance;
dataStream << _linearTimeScale;
dataStream << _positionalTargetSet;
dataStream << _expires;
dataStream << _tag;
});
return ba;
}
@ -166,13 +184,13 @@ void ObjectActionOffset::deserialize(QByteArray serializedArguments) {
return;
}
dataStream >> _pointToOffsetFrom;
dataStream >> _linearDistance;
dataStream >> _linearTimeScale;
dataStream >> _positionalTargetSet;
dataStream >> _expires;
dataStream >> _tag;
_active = true;
withWriteLock([&] {
dataStream >> _pointToOffsetFrom;
dataStream >> _linearDistance;
dataStream >> _linearTimeScale;
dataStream >> _positionalTargetSet;
dataStream >> _expires;
dataStream >> _tag;
_active = true;
});
}

View file

@ -38,6 +38,7 @@ ObjectActionSpring::~ObjectActionSpring() {
}
void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
// don't risk hanging the thread running the physics simulation
auto lockResult = withTryReadLock([&]{
auto ownerEntity = _ownerEntity.lock();
if (!ownerEntity) {
@ -100,60 +101,73 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
}
});
if (!lockResult) {
// don't risk hanging the thread running the physics simulation
qDebug() << "ObjectActionSpring::updateActionWorker lock failed";
return;
}
}
const float MIN_TIMESCALE = 0.1f;
bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
if (!ObjectAction::updateArguments(arguments)) {
return false;
}
// targets are required, spring-constants are optional
bool ok = true;
glm::vec3 positionalTarget =
EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false);
if (!ok) {
positionalTarget = _positionalTarget;
}
ok = true;
float linearTimeScale =
EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false);
if (!ok || linearTimeScale <= 0.0f) {
linearTimeScale = _linearTimeScale;
}
glm::vec3 positionalTarget;
float linearTimeScale;
glm::quat rotationalTarget;
float angularTimeScale;
ok = true;
glm::quat rotationalTarget =
EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false);
if (!ok) {
rotationalTarget = _rotationalTarget;
}
bool needUpdate = false;
bool somethingChanged = ObjectAction::updateArguments(arguments);
withReadLock([&]{
// targets are required, spring-constants are optional
bool ok = true;
positionalTarget = EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false);
if (!ok) {
positionalTarget = _positionalTarget;
}
ok = true;
linearTimeScale = EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false);
if (!ok || linearTimeScale <= 0.0f) {
linearTimeScale = _linearTimeScale;
}
ok = true;
float angularTimeScale =
EntityActionInterface::extractFloatArgument("spring action", arguments, "angularTimeScale", ok, false);
if (!ok) {
angularTimeScale = _angularTimeScale;
}
ok = true;
rotationalTarget = EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false);
if (!ok) {
rotationalTarget = _rotationalTarget;
}
if (positionalTarget != _positionalTarget
|| linearTimeScale != _linearTimeScale
|| rotationalTarget != _rotationalTarget
|| angularTimeScale != _angularTimeScale) {
// something changed
ok = true;
angularTimeScale =
EntityActionInterface::extractFloatArgument("spring action", arguments, "angularTimeScale", ok, false);
if (!ok) {
angularTimeScale = _angularTimeScale;
}
if (somethingChanged ||
positionalTarget != _positionalTarget ||
linearTimeScale != _linearTimeScale ||
rotationalTarget != _rotationalTarget ||
angularTimeScale != _angularTimeScale) {
// something changed
needUpdate = true;
}
});
if (needUpdate) {
withWriteLock([&] {
_positionalTarget = positionalTarget;
_linearTimeScale = glm::max(MIN_TIMESCALE, glm::abs(linearTimeScale));
_rotationalTarget = rotationalTarget;
_angularTimeScale = glm::max(MIN_TIMESCALE, glm::abs(angularTimeScale));
_active = true;
activateBody();
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
}
});
activateBody();
}
return true;
}
@ -177,16 +191,16 @@ QByteArray ObjectActionSpring::serialize() const {
dataStream << getID();
dataStream << ObjectActionSpring::springVersion;
dataStream << _positionalTarget;
dataStream << _linearTimeScale;
dataStream << _positionalTargetSet;
dataStream << _rotationalTarget;
dataStream << _angularTimeScale;
dataStream << _rotationalTargetSet;
dataStream << _expires;
dataStream << _tag;
withReadLock([&] {
dataStream << _positionalTarget;
dataStream << _linearTimeScale;
dataStream << _positionalTargetSet;
dataStream << _rotationalTarget;
dataStream << _angularTimeScale;
dataStream << _rotationalTargetSet;
dataStream << _expires;
dataStream << _tag;
});
return serializedActionArguments;
}
@ -205,19 +219,22 @@ void ObjectActionSpring::deserialize(QByteArray serializedArguments) {
uint16_t serializationVersion;
dataStream >> serializationVersion;
if (serializationVersion != ObjectActionSpring::springVersion) {
assert(false);
return;
}
dataStream >> _positionalTarget;
dataStream >> _linearTimeScale;
dataStream >> _positionalTargetSet;
withWriteLock([&] {
dataStream >> _positionalTarget;
dataStream >> _linearTimeScale;
dataStream >> _positionalTargetSet;
dataStream >> _rotationalTarget;
dataStream >> _angularTimeScale;
dataStream >> _rotationalTargetSet;
dataStream >> _rotationalTarget;
dataStream >> _angularTimeScale;
dataStream >> _rotationalTargetSet;
dataStream >> _expires;
dataStream >> _tag;
dataStream >> _expires;
dataStream >> _tag;
_active = true;
_active = true;
});
}