rename base action classes to dynamics, start on constraints

This commit is contained in:
Seth Alves 2017-04-11 20:39:13 -07:00
parent b07ed13023
commit 74c0a70cb0
39 changed files with 1200 additions and 872 deletions

View file

@ -1,91 +0,0 @@
//
// AssignmentAction.cpp
// assignment-client/src/
//
// Created by Seth Alves 2015-6-19
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EntitySimulation.h"
#include "AssignmentAction.h"
AssignmentAction::AssignmentAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity) :
EntityActionInterface(type, id),
_data(QByteArray()),
_active(false),
_ownerEntity(ownerEntity) {
}
AssignmentAction::~AssignmentAction() {
}
void AssignmentAction::removeFromSimulation(EntitySimulationPointer simulation) const {
withReadLock([&]{
simulation->removeAction(_id);
simulation->applyActionChanges();
});
}
QByteArray AssignmentAction::serialize() const {
QByteArray result;
withReadLock([&]{
result = _data;
});
return result;
}
void AssignmentAction::deserialize(QByteArray serializedArguments) {
withWriteLock([&]{
_data = serializedArguments;
});
}
bool AssignmentAction::updateArguments(QVariantMap arguments) {
qDebug() << "UNEXPECTED -- AssignmentAction::updateArguments called in assignment-client.";
return false;
}
QVariantMap AssignmentAction::getArguments() {
qDebug() << "UNEXPECTED -- AssignmentAction::getArguments called in assignment-client.";
return QVariantMap();
}
glm::vec3 AssignmentAction::getPosition() {
qDebug() << "UNEXPECTED -- AssignmentAction::getPosition called in assignment-client.";
return glm::vec3(0.0f);
}
void AssignmentAction::setPosition(glm::vec3 position) {
qDebug() << "UNEXPECTED -- AssignmentAction::setPosition called in assignment-client.";
}
glm::quat AssignmentAction::getRotation() {
qDebug() << "UNEXPECTED -- AssignmentAction::getRotation called in assignment-client.";
return glm::quat();
}
void AssignmentAction::setRotation(glm::quat rotation) {
qDebug() << "UNEXPECTED -- AssignmentAction::setRotation called in assignment-client.";
}
glm::vec3 AssignmentAction::getLinearVelocity() {
qDebug() << "UNEXPECTED -- AssignmentAction::getLinearVelocity called in assignment-client.";
return glm::vec3(0.0f);
}
void AssignmentAction::setLinearVelocity(glm::vec3 linearVelocity) {
qDebug() << "UNEXPECTED -- AssignmentAction::setLinearVelocity called in assignment-client.";
}
glm::vec3 AssignmentAction::getAngularVelocity() {
qDebug() << "UNEXPECTED -- AssignmentAction::getAngularVelocity called in assignment-client.";
return glm::vec3(0.0f);
}
void AssignmentAction::setAngularVelocity(glm::vec3 angularVelocity) {
qDebug() << "UNEXPECTED -- AssignmentAction::setAngularVelocity called in assignment-client.";
}

View file

@ -1,48 +0,0 @@
//
// AssignmentActionFactory.cpp
// assignment-client/src/
//
// Created by Seth Alves on 2015-6-19
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AssignmentActionFactory.h"
EntityActionPointer assignmentActionFactory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity) {
return EntityActionPointer(new AssignmentAction(type, id, ownerEntity));
}
EntityActionPointer AssignmentActionFactory::factory(EntityActionType type,
const QUuid& id,
EntityItemPointer ownerEntity,
QVariantMap arguments) {
EntityActionPointer action = assignmentActionFactory(type, id, ownerEntity);
if (action) {
bool ok = action->updateArguments(arguments);
if (ok) {
return action;
}
}
return nullptr;
}
EntityActionPointer AssignmentActionFactory::factoryBA(EntityItemPointer ownerEntity, QByteArray data) {
QDataStream serializedActionDataStream(data);
EntityActionType type;
QUuid id;
serializedActionDataStream >> type;
serializedActionDataStream >> id;
EntityActionPointer action = assignmentActionFactory(type, id, ownerEntity);
if (action) {
action->deserialize(data);
}
return action;
}

View file

@ -1,29 +0,0 @@
//
// AssignmentActionFactory.cpp
// assignment-client/src/
//
// Created by Seth Alves on 2015-6-19
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_AssignmentActionFactory_h
#define hifi_AssignmentActionFactory_h
#include "EntityActionFactoryInterface.h"
#include "AssignmentAction.h"
class AssignmentActionFactory : public EntityActionFactoryInterface {
public:
AssignmentActionFactory() : EntityActionFactoryInterface() { }
virtual ~AssignmentActionFactory() { }
virtual EntityActionPointer factory(EntityActionType type,
const QUuid& id,
EntityItemPointer ownerEntity,
QVariantMap arguments) override;
virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data) override;
};
#endif // hifi_AssignmentActionFactory_h

View file

@ -32,7 +32,7 @@
#include <ResourceScriptingInterface.h>
#include "AssignmentFactory.h"
#include "AssignmentActionFactory.h"
#include "AssignmentDynamicFactory.h"
#include "AssignmentClient.h"
#include "AssignmentClientLogging.h"
@ -63,8 +63,8 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
auto animationCache = DependencyManager::set<AnimationCache>();
auto entityScriptingInterface = DependencyManager::set<EntityScriptingInterface>(false);
DependencyManager::registerInheritance<EntityActionFactoryInterface, AssignmentActionFactory>();
auto actionFactory = DependencyManager::set<AssignmentActionFactory>();
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
auto dynamicFactory = DependencyManager::set<AssignmentDynamicFactory>();
DependencyManager::set<ResourceScriptingInterface>();
// setup a thread for the NodeList and its PacketReceiver

View file

@ -0,0 +1,91 @@
//
// AssignmentDynamic.cpp
// assignment-client/src/
//
// Created by Seth Alves 2015-6-19
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EntitySimulation.h"
#include "AssignmentDynamic.h"
AssignmentDynamic::AssignmentDynamic(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity) :
EntityDynamicInterface(type, id),
_data(QByteArray()),
_active(false),
_ownerEntity(ownerEntity) {
}
AssignmentDynamic::~AssignmentDynamic() {
}
void AssignmentDynamic::removeFromSimulation(EntitySimulationPointer simulation) const {
withReadLock([&]{
simulation->removeDynamic(_id);
simulation->applyDynamicChanges();
});
}
QByteArray AssignmentDynamic::serialize() const {
QByteArray result;
withReadLock([&]{
result = _data;
});
return result;
}
void AssignmentDynamic::deserialize(QByteArray serializedArguments) {
withWriteLock([&]{
_data = serializedArguments;
});
}
bool AssignmentDynamic::updateArguments(QVariantMap arguments) {
qDebug() << "UNEXPECTED -- AssignmentDynamic::updateArguments called in assignment-client.";
return false;
}
QVariantMap AssignmentDynamic::getArguments() {
qDebug() << "UNEXPECTED -- AssignmentDynamic::getArguments called in assignment-client.";
return QVariantMap();
}
glm::vec3 AssignmentDynamic::getPosition() {
qDebug() << "UNEXPECTED -- AssignmentDynamic::getPosition called in assignment-client.";
return glm::vec3(0.0f);
}
void AssignmentDynamic::setPosition(glm::vec3 position) {
qDebug() << "UNEXPECTED -- AssignmentDynamic::setPosition called in assignment-client.";
}
glm::quat AssignmentDynamic::getRotation() {
qDebug() << "UNEXPECTED -- AssignmentDynamic::getRotation called in assignment-client.";
return glm::quat();
}
void AssignmentDynamic::setRotation(glm::quat rotation) {
qDebug() << "UNEXPECTED -- AssignmentDynamic::setRotation called in assignment-client.";
}
glm::vec3 AssignmentDynamic::getLinearVelocity() {
qDebug() << "UNEXPECTED -- AssignmentDynamic::getLinearVelocity called in assignment-client.";
return glm::vec3(0.0f);
}
void AssignmentDynamic::setLinearVelocity(glm::vec3 linearVelocity) {
qDebug() << "UNEXPECTED -- AssignmentDynamic::setLinearVelocity called in assignment-client.";
}
glm::vec3 AssignmentDynamic::getAngularVelocity() {
qDebug() << "UNEXPECTED -- AssignmentDynamic::getAngularVelocity called in assignment-client.";
return glm::vec3(0.0f);
}
void AssignmentDynamic::setAngularVelocity(glm::vec3 angularVelocity) {
qDebug() << "UNEXPECTED -- AssignmentDynamic::setAngularVelocity called in assignment-client.";
}

View file

@ -1,5 +1,5 @@
//
// AssignmentAction.h
// AssignmentDynamic.h
// assignment-client/src/
//
// Created by Seth Alves 2015-6-19
@ -8,21 +8,21 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// http://bulletphysics.org/Bullet/BulletFull/classbtActionInterface.html
// http://bulletphysics.org/Bullet/BulletFull/classbtDynamicInterface.html
#ifndef hifi_AssignmentAction_h
#define hifi_AssignmentAction_h
#ifndef hifi_AssignmentDynamic_h
#define hifi_AssignmentDynamic_h
#include <QUuid>
#include <EntityItem.h>
#include "EntityActionInterface.h"
#include "EntityDynamicInterface.h"
class AssignmentAction : public EntityActionInterface, public ReadWriteLockable {
class AssignmentDynamic : public EntityDynamicInterface, public ReadWriteLockable {
public:
AssignmentAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity);
virtual ~AssignmentAction();
AssignmentDynamic(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity);
virtual ~AssignmentDynamic();
virtual void removeFromSimulation(EntitySimulationPointer simulation) const override;
virtual EntityItemWeakPointer getOwnerEntity() const override { return _ownerEntity; }
@ -50,4 +50,4 @@ protected:
EntityItemWeakPointer _ownerEntity;
};
#endif // hifi_AssignmentAction_h
#endif // hifi_AssignmentDynamic_h

View file

@ -0,0 +1,48 @@
//
// AssignmentDynamcFactory.cpp
// assignment-client/src/
//
// Created by Seth Alves on 2015-6-19
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AssignmentDynamicFactory.h"
EntityDynamicPointer assignmentDynamicFactory(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity) {
return EntityDynamicPointer(new AssignmentDynamic(type, id, ownerEntity));
}
EntityDynamicPointer AssignmentDynamicFactory::factory(EntityDynamicType type,
const QUuid& id,
EntityItemPointer ownerEntity,
QVariantMap arguments) {
EntityDynamicPointer dynamic = assignmentDynamicFactory(type, id, ownerEntity);
if (dynamic) {
bool ok = dynamic->updateArguments(arguments);
if (ok) {
return dynamic;
}
}
return nullptr;
}
EntityDynamicPointer AssignmentDynamicFactory::factoryBA(EntityItemPointer ownerEntity, QByteArray data) {
QDataStream serializedDynamicDataStream(data);
EntityDynamicType type;
QUuid id;
serializedDynamicDataStream >> type;
serializedDynamicDataStream >> id;
EntityDynamicPointer dynamic = assignmentDynamicFactory(type, id, ownerEntity);
if (dynamic) {
dynamic->deserialize(data);
}
return dynamic;
}

View file

@ -0,0 +1,29 @@
//
// AssignmentDynamicFactory.cpp
// assignment-client/src/
//
// Created by Seth Alves on 2015-6-19
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_AssignmentDynamicFactory_h
#define hifi_AssignmentDynamicFactory_h
#include "EntityDynamicFactoryInterface.h"
#include "AssignmentDynamic.h"
class AssignmentDynamicFactory : public EntityDynamicFactoryInterface {
public:
AssignmentDynamicFactory() : EntityDynamicFactoryInterface() { }
virtual ~AssignmentDynamicFactory() { }
virtual EntityDynamicPointer factory(EntityDynamicType type,
const QUuid& id,
EntityItemPointer ownerEntity,
QVariantMap arguments) override;
virtual EntityDynamicPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data) override;
};
#endif // hifi_AssignmentDynamicFactory_h

View file

@ -137,7 +137,7 @@
#include "devices/Leapmotion.h"
#include "DiscoverabilityManager.h"
#include "GLCanvas.h"
#include "InterfaceActionFactory.h"
#include "InterfaceDynamicFactory.h"
#include "InterfaceLogging.h"
#include "LODManager.h"
#include "ModelPackager.h"
@ -459,7 +459,7 @@ bool setupEssentials(int& argc, char** argv) {
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
DependencyManager::registerInheritance<EntityActionFactoryInterface, InterfaceActionFactory>();
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, InterfaceDynamicFactory>();
DependencyManager::registerInheritance<SpatialParentFinder, InterfaceParentFinder>();
// Set dependencies
@ -512,7 +512,7 @@ bool setupEssentials(int& argc, char** argv) {
DependencyManager::set<OffscreenUi>();
DependencyManager::set<AutoUpdater>();
DependencyManager::set<PathUtils>();
DependencyManager::set<InterfaceActionFactory>();
DependencyManager::set<InterfaceDynamicFactory>();
DependencyManager::set<AudioInjectorManager>();
DependencyManager::set<MessagesClient>();
controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR,
@ -4423,7 +4423,7 @@ void Application::update(float deltaTime) {
_entitySimulation->setObjectsToChange(stillNeedChange);
});
_entitySimulation->applyActionChanges();
_entitySimulation->applyDynamicChanges();
avatarManager->getObjectsToRemoveFromPhysics(motionStates);
_physicsEngine->removeObjects(motionStates);
@ -4433,8 +4433,8 @@ void Application::update(float deltaTime) {
_physicsEngine->changeObjects(motionStates);
myAvatar->prepareForPhysicsSimulation();
_physicsEngine->forEachAction([&](EntityActionPointer action) {
action->prepareForPhysicsSimulation();
_physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) {
dynamic->prepareForPhysicsSimulation();
});
}
{

View file

@ -1,82 +0,0 @@
//
// InterfaceActionFactory.cpp
// libraries/entities/src
//
// Created by Seth Alves on 2015-6-2
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <avatar/AvatarActionHold.h>
#include <ObjectActionOffset.h>
#include <ObjectActionSpring.h>
#include <ObjectActionTravelOriented.h>
#include <LogHandler.h>
#include "InterfaceActionFactory.h"
EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity) {
switch (type) {
case ACTION_TYPE_NONE:
return EntityActionPointer();
case ACTION_TYPE_OFFSET:
return std::make_shared<ObjectActionOffset>(id, ownerEntity);
case ACTION_TYPE_SPRING:
return std::make_shared<ObjectActionSpring>(id, ownerEntity);
case ACTION_TYPE_HOLD:
return std::make_shared<AvatarActionHold>(id, ownerEntity);
case ACTION_TYPE_TRAVEL_ORIENTED:
return std::make_shared<ObjectActionTravelOriented>(id, ownerEntity);
}
Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown entity action type");
return EntityActionPointer();
}
EntityActionPointer InterfaceActionFactory::factory(EntityActionType type,
const QUuid& id,
EntityItemPointer ownerEntity,
QVariantMap arguments) {
EntityActionPointer action = interfaceActionFactory(type, id, ownerEntity);
if (action) {
bool ok = action->updateArguments(arguments);
if (ok) {
if (action->lifetimeIsOver()) {
return nullptr;
}
return action;
}
}
return nullptr;
}
EntityActionPointer InterfaceActionFactory::factoryBA(EntityItemPointer ownerEntity, QByteArray data) {
QDataStream serializedArgumentStream(data);
EntityActionType type;
QUuid id;
serializedArgumentStream >> type;
serializedArgumentStream >> id;
EntityActionPointer action = interfaceActionFactory(type, id, ownerEntity);
if (action) {
action->deserialize(data);
if (action->lifetimeIsOver()) {
static QString repeatedMessage =
LogHandler::getInstance().addRepeatedMessageRegex(".*factoryBA lifetimeIsOver during action creation.*");
qDebug() << "InterfaceActionFactory::factoryBA lifetimeIsOver during action creation --"
<< action->getExpires() << "<" << usecTimestampNow();
return nullptr;
}
}
return action;
}

View file

@ -0,0 +1,85 @@
//
// InterfaceDynamicFactory.cpp
// libraries/entities/src
//
// Created by Seth Alves on 2015-6-2
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <avatar/AvatarActionHold.h>
#include <ObjectActionOffset.h>
#include <ObjectActionSpring.h>
#include <ObjectActionTravelOriented.h>
#include <ObjectConstraintHinge.h>
#include <LogHandler.h>
#include "InterfaceDynamicFactory.h"
EntityDynamicPointer interfaceDynamicFactory(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity) {
switch (type) {
case DYNAMIC_TYPE_NONE:
return EntityDynamicPointer();
case DYNAMIC_TYPE_OFFSET:
return std::make_shared<ObjectActionOffset>(id, ownerEntity);
case DYNAMIC_TYPE_SPRING:
return std::make_shared<ObjectActionSpring>(id, ownerEntity);
case DYNAMIC_TYPE_HOLD:
return std::make_shared<AvatarActionHold>(id, ownerEntity);
case DYNAMIC_TYPE_TRAVEL_ORIENTED:
return std::make_shared<ObjectActionTravelOriented>(id, ownerEntity);
case DYNAMIC_TYPE_HINGE:
return std::make_shared<ObjectConstraintHinge>(id, ownerEntity);
}
Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown entity dynamic type");
return EntityDynamicPointer();
}
EntityDynamicPointer InterfaceDynamicFactory::factory(EntityDynamicType type,
const QUuid& id,
EntityItemPointer ownerEntity,
QVariantMap arguments) {
EntityDynamicPointer dynamic = interfaceDynamicFactory(type, id, ownerEntity);
if (dynamic) {
bool ok = dynamic->updateArguments(arguments);
if (ok) {
if (dynamic->lifetimeIsOver()) {
return nullptr;
}
return dynamic;
}
}
return nullptr;
}
EntityDynamicPointer InterfaceDynamicFactory::factoryBA(EntityItemPointer ownerEntity, QByteArray data) {
QDataStream serializedArgumentStream(data);
EntityDynamicType type;
QUuid id;
serializedArgumentStream >> type;
serializedArgumentStream >> id;
EntityDynamicPointer dynamic = interfaceDynamicFactory(type, id, ownerEntity);
if (dynamic) {
dynamic->deserialize(data);
if (dynamic->lifetimeIsOver()) {
static QString repeatedMessage =
LogHandler::getInstance().addRepeatedMessageRegex(".*factoryBA lifetimeIsOver during dynamic creation.*");
qDebug() << "InterfaceDynamicFactory::factoryBA lifetimeIsOver during dynamic creation --"
<< dynamic->getExpires() << "<" << usecTimestampNow();
return nullptr;
}
}
return dynamic;
}

View file

@ -1,5 +1,5 @@
//
// InterfaceActionFactory.cpp
// InterfaceDynamicFactory.cpp
// interface/src/
//
// Created by Seth Alves on 2015-6-10
@ -9,21 +9,21 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_InterfaceActionFactory_h
#define hifi_InterfaceActionFactory_h
#ifndef hifi_InterfaceDynamicFactory_h
#define hifi_InterfaceDynamicFactory_h
#include "EntityActionFactoryInterface.h"
#include "EntityDynamicFactoryInterface.h"
class InterfaceActionFactory : public EntityActionFactoryInterface {
class InterfaceDynamicFactory : public EntityDynamicFactoryInterface {
public:
InterfaceActionFactory() : EntityActionFactoryInterface() { }
virtual ~InterfaceActionFactory() { }
virtual EntityActionPointer factory(EntityActionType type,
InterfaceDynamicFactory() : EntityDynamicFactoryInterface() { }
virtual ~InterfaceDynamicFactory() { }
virtual EntityDynamicPointer factory(EntityDynamicType type,
const QUuid& id,
EntityItemPointer ownerEntity,
QVariantMap arguments) override;
virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity,
virtual EntityDynamicPointer factoryBA(EntityItemPointer ownerEntity,
QByteArray data) override;
};
#endif // hifi_InterfaceActionFactory_h
#endif // hifi_InterfaceDynamicFactory_h

View file

@ -23,7 +23,7 @@ const int AvatarActionHold::velocitySmoothFrames = 6;
AvatarActionHold::AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectActionSpring(id, ownerEntity)
{
_type = ACTION_TYPE_HOLD;
_type = DYNAMIC_TYPE_HOLD;
_measuredLinearVelocities.resize(AvatarActionHold::velocitySmoothFrames);
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
@ -326,25 +326,25 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
bool somethingChanged = ObjectAction::updateArguments(arguments);
withReadLock([&]{
bool ok = true;
relativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false);
relativePosition = EntityDynamicInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false);
if (!ok) {
relativePosition = _relativePosition;
}
ok = true;
relativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false);
relativeRotation = EntityDynamicInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false);
if (!ok) {
relativeRotation = _relativeRotation;
}
ok = true;
timeScale = EntityActionInterface::extractFloatArgument("hold", arguments, "timeScale", ok, false);
timeScale = EntityDynamicInterface::extractFloatArgument("hold", arguments, "timeScale", ok, false);
if (!ok) {
timeScale = _linearTimeScale;
}
ok = true;
hand = EntityActionInterface::extractStringArgument("hold", arguments, "hand", ok, false);
hand = EntityDynamicInterface::extractStringArgument("hold", arguments, "hand", ok, false);
if (!ok || !(hand == "left" || hand == "right")) {
hand = _hand;
}
@ -353,20 +353,20 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
holderID = myAvatar->getSessionUUID();
ok = true;
kinematic = EntityActionInterface::extractBooleanArgument("hold", arguments, "kinematic", ok, false);
kinematic = EntityDynamicInterface::extractBooleanArgument("hold", arguments, "kinematic", ok, false);
if (!ok) {
kinematic = _kinematic;
}
ok = true;
kinematicSetVelocity = EntityActionInterface::extractBooleanArgument("hold", arguments,
kinematicSetVelocity = EntityDynamicInterface::extractBooleanArgument("hold", arguments,
"kinematicSetVelocity", ok, false);
if (!ok) {
kinematicSetVelocity = _kinematicSetVelocity;
}
ok = true;
ignoreIK = EntityActionInterface::extractBooleanArgument("hold", arguments, "ignoreIK", ok, false);
ignoreIK = EntityDynamicInterface::extractBooleanArgument("hold", arguments, "ignoreIK", ok, false);
if (!ok) {
ignoreIK = _ignoreIK;
}
@ -400,8 +400,8 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
ownerEntity->setActionDataNeedsTransmit(true);
ownerEntity->setDynamicDataDirty(true);
ownerEntity->setDynamicDataNeedsTransmit(true);
}
});
}
@ -429,7 +429,7 @@ QByteArray AvatarActionHold::serialize() const {
QDataStream dataStream(&serializedActionArguments, QIODevice::WriteOnly);
withReadLock([&]{
dataStream << ACTION_TYPE_HOLD;
dataStream << DYNAMIC_TYPE_HOLD;
dataStream << getID();
dataStream << AvatarActionHold::holdVersion;
@ -451,7 +451,7 @@ QByteArray AvatarActionHold::serialize() const {
void AvatarActionHold::deserialize(QByteArray serializedArguments) {
QDataStream dataStream(serializedArguments);
EntityActionType type;
EntityDynamicType type;
dataStream >> type;
assert(type == getType());

View file

@ -1,5 +1,5 @@
//
// EntityActionFactoryInterface.cpp
// EntityDynamicFactoryInterface.cpp
// libraries/entities/src
//
// Created by Seth Alves on 2015-6-2
@ -9,26 +9,26 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_EntityActionFactoryInterface_h
#define hifi_EntityActionFactoryInterface_h
#ifndef hifi_EntityDynamicFactoryInterface_h
#define hifi_EntityDynamicFactoryInterface_h
#include <DependencyManager.h>
#include "EntityActionInterface.h"
#include "EntityDynamicInterface.h"
class EntityActionFactoryInterface : public QObject, public Dependency {
class EntityDynamicFactoryInterface : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
public:
EntityActionFactoryInterface() { }
virtual ~EntityActionFactoryInterface() { }
virtual EntityActionPointer factory(EntityActionType type,
EntityDynamicFactoryInterface() { }
virtual ~EntityDynamicFactoryInterface() { }
virtual EntityDynamicPointer factory(EntityDynamicType type,
const QUuid& id,
EntityItemPointer ownerEntity,
QVariantMap arguments) { assert(false); return nullptr; }
virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity,
virtual EntityDynamicPointer factoryBA(EntityItemPointer ownerEntity,
QByteArray data) { assert(false); return nullptr; }
};
#endif // hifi_EntityActionFactoryInterface_h
#endif // hifi_EntityDynamicFactoryInterface_h

View file

@ -1,5 +1,5 @@
//
// EntityActionInterface.cpp
// EntityDynamicInterface.cpp
// libraries/entities/src
//
// Created by Seth Alves on 2015-6-4
@ -16,66 +16,66 @@
+-----------------------+ +-------------------+ +------------------------------+
| | | | | |
| EntityActionInterface | | btActionInterface | | EntityActionFactoryInterface |
| (entities) | | (bullet) | | (entities) |
+-----------------------+ +-------------------+ +------------------------------+
| | | | |
+----+ +--+ +----------+ | |
| | | | |
+-------------------+ +--------------+ +------------------------+ +-------------------------+
| | | | | | | |
| AssignmentAction | | ObjectAction | | InterfaceActionFactory | | AssignmentActionFactory |
|(assignment client)| | (physics) | | (interface) | | (assignment client) |
+-------------------+ +--------------+ +------------------------+ +-------------------------+
+-----------------------+ +-------------------+ +---------------------------------+
| | | | | |
| EntityDynamicInterface | | btDynamicInterface | | EntityDynamicFactoryInterface |
| (entities) | | (bullet) | | (entities) |
+-----------------------+ +-------------------+ +---------------------------------+
| | | | |
+----+ +--+ +----------+ | |
| | | | |
+-------------------+ +--------------+ +---------------------------+ +--------------------------+
| | | | | | | |
| AssignmentDynamic | | ObjectDynamic | | InterfaceDynamicFactory | | AssignmentDynamicFactory |
|(assignment client)| | (physics) | | (interface) | | (assignment client) |
+-------------------+ +--------------+ +---------------------------+ +--------------------------+
|
|
|
+--------------------+
| |
| ObjectActionSpring |
| ObjectDynamicSpring |
| (physics) |
+--------------------+
An action is a callback which is registered with bullet. An action is called-back every physics
An dynamic is a callback which is registered with bullet. An dynamic is called-back every physics
simulation step and can do whatever it wants with the various datastructures it has available. An
action, for example, can pull an EntityItem toward a point as if that EntityItem were connected to that
dynamic, for example, can pull an EntityItem toward a point as if that EntityItem were connected to that
point by a spring.
In this system, an action is a property of an EntityItem (rather, an EntityItem has a property which
encodes a list of actions). Each action has a type and some arguments. Actions can be created by a
In this system, an dynamic is a property of an EntityItem (rather, an EntityItem has a property which
encodes a list of dynamics). Each dynamic has a type and some arguments. Dynamics can be created by a
script or when receiving information via an EntityTree data-stream (either over the network or from an
svo file).
In the interface, if an EntityItem has actions, this EntityItem will have pointers to ObjectAction
subclass (like ObjectActionSpring) instantiations. Code in the entities library affects an action-object
via the EntityActionInterface (which knows nothing about bullet). When the ObjectAction subclass
instance is created, it is registered as an action with bullet. Bullet will call into code in this
instance with the btActionInterface every physics-simulation step.
In the interface, if an EntityItem has dynamics, this EntityItem will have pointers to ObjectDynamic
subclass (like ObjectDynamicSpring) instantiations. Code in the entities library affects an dynamic-object
via the EntityDynamicInterface (which knows nothing about bullet). When the ObjectDynamic subclass
instance is created, it is registered as an dynamic with bullet. Bullet will call into code in this
instance with the btDynamicInterface every physics-simulation step.
Because the action can exist next to the interface's EntityTree or the entity-server's EntityTree,
parallel versions of the factories and actions are needed.
Because the dynamic can exist next to the interface's EntityTree or the entity-server's EntityTree,
parallel versions of the factories and dynamics are needed.
In an entity-server, any type of action is instantiated as an AssignmentAction. This action isn't called
In an entity-server, any type of dynamic is instantiated as an AssignmentDynamic. This dynamic isn't called
by bullet (which isn't part of an assignment-client). It does nothing but remember its type and its
arguments. This may change as we try to make the entity-server's simple physics simulation better, but
right now the AssignmentAction class is a place-holder.
right now the AssignmentDynamic class is a place-holder.
The action-objects are instantiated by singleton (dependecy) subclasses of EntityActionFactoryInterface.
In the interface, the subclass is an InterfaceActionFactory and it will produce things like
ObjectActionSpring. In an entity-server the subclass is an AssignmentActionFactory and it always
produces AssignmentActions.
The dynamic-objects are instantiated by singleton (dependecy) subclasses of EntityDynamicFactoryInterface.
In the interface, the subclass is an InterfaceDynamicFactory and it will produce things like
ObjectDynamicSpring. In an entity-server the subclass is an AssignmentDynamicFactory and it always
produces AssignmentDynamics.
Depending on the action's type, it will have various arguments. When a script changes an argument of an
action, the argument-holding member-variables of ObjectActionSpring (in this example) are updated and
also serialized into _actionData in the EntityItem. Each subclass of ObjectAction knows how to serialize
and deserialize its own arguments. _actionData is what gets sent over the wire or saved in an svo file.
When a packet-reader receives data for _actionData, it will save it in the EntityItem; this causes the
deserializer in the ObjectAction subclass to be called with the new data, thereby updating its argument
Depending on the dynamic's type, it will have various arguments. When a script changes an argument of an
dynamic, the argument-holding member-variables of ObjectDynamicSpring (in this example) are updated and
also serialized into _dynamicData in the EntityItem. Each subclass of ObjectDynamic knows how to serialize
and deserialize its own arguments. _dynamicData is what gets sent over the wire or saved in an svo file.
When a packet-reader receives data for _dynamicData, it will save it in the EntityItem; this causes the
deserializer in the ObjectDynamic subclass to be called with the new data, thereby updating its argument
variables. These argument variables are used by the code which is run when bullet does a callback.
@ -83,49 +83,54 @@ variables. These argument variables are used by the code which is run when bull
#include "EntityItem.h"
#include "EntityActionInterface.h"
#include "EntityDynamicInterface.h"
EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeString) {
QString normalizedActionTypeString = actionTypeString.toLower().remove('-').remove('_');
if (normalizedActionTypeString == "none") {
return ACTION_TYPE_NONE;
EntityDynamicType EntityDynamicInterface::dynamicTypeFromString(QString dynamicTypeString) {
QString normalizedDynamicTypeString = dynamicTypeString.toLower().remove('-').remove('_');
if (normalizedDynamicTypeString == "none") {
return DYNAMIC_TYPE_NONE;
}
if (normalizedActionTypeString == "offset") {
return ACTION_TYPE_OFFSET;
if (normalizedDynamicTypeString == "offset") {
return DYNAMIC_TYPE_OFFSET;
}
if (normalizedActionTypeString == "spring") {
return ACTION_TYPE_SPRING;
if (normalizedDynamicTypeString == "spring") {
return DYNAMIC_TYPE_SPRING;
}
if (normalizedActionTypeString == "hold") {
return ACTION_TYPE_HOLD;
if (normalizedDynamicTypeString == "hold") {
return DYNAMIC_TYPE_HOLD;
}
if (normalizedActionTypeString == "traveloriented") {
return ACTION_TYPE_TRAVEL_ORIENTED;
if (normalizedDynamicTypeString == "traveloriented") {
return DYNAMIC_TYPE_TRAVEL_ORIENTED;
}
if (normalizedDynamicTypeString == "hinge") {
return DYNAMIC_TYPE_HINGE;
}
qCDebug(entities) << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString;
return ACTION_TYPE_NONE;
qCDebug(entities) << "Warning -- EntityDynamicInterface::dynamicTypeFromString got unknown dynamic-type name" << dynamicTypeString;
return DYNAMIC_TYPE_NONE;
}
QString EntityActionInterface::actionTypeToString(EntityActionType actionType) {
switch(actionType) {
case ACTION_TYPE_NONE:
QString EntityDynamicInterface::dynamicTypeToString(EntityDynamicType dynamicType) {
switch(dynamicType) {
case DYNAMIC_TYPE_NONE:
return "none";
case ACTION_TYPE_OFFSET:
case DYNAMIC_TYPE_OFFSET:
return "offset";
case ACTION_TYPE_SPRING:
case DYNAMIC_TYPE_SPRING:
return "spring";
case ACTION_TYPE_HOLD:
case DYNAMIC_TYPE_HOLD:
return "hold";
case ACTION_TYPE_TRAVEL_ORIENTED:
case DYNAMIC_TYPE_TRAVEL_ORIENTED:
return "travel-oriented";
case DYNAMIC_TYPE_HINGE:
return "hinge";
}
assert(false);
return "none";
}
glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVariantMap arguments,
glm::vec3 EntityDynamicInterface::extractVec3Argument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
@ -174,7 +179,7 @@ glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVarian
return glm::vec3(x, y, z);
}
glm::quat EntityActionInterface::extractQuatArgument(QString objectName, QVariantMap arguments,
glm::quat EntityDynamicInterface::extractQuatArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
@ -227,7 +232,7 @@ glm::quat EntityActionInterface::extractQuatArgument(QString objectName, QVarian
return glm::normalize(glm::quat(w, x, y, z));
}
float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMap arguments,
float EntityDynamicInterface::extractFloatArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
@ -249,7 +254,7 @@ float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMa
return value;
}
int EntityActionInterface::extractIntegerArgument(QString objectName, QVariantMap arguments,
int EntityDynamicInterface::extractIntegerArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
@ -271,7 +276,7 @@ int EntityActionInterface::extractIntegerArgument(QString objectName, QVariantMa
return value;
}
QString EntityActionInterface::extractStringArgument(QString objectName, QVariantMap arguments,
QString EntityDynamicInterface::extractStringArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
@ -283,7 +288,7 @@ QString EntityActionInterface::extractStringArgument(QString objectName, QVarian
return arguments[argumentName].toString();
}
bool EntityActionInterface::extractBooleanArgument(QString objectName, QVariantMap arguments,
bool EntityDynamicInterface::extractBooleanArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
@ -297,35 +302,35 @@ bool EntityActionInterface::extractBooleanArgument(QString objectName, QVariantM
QDataStream& operator<<(QDataStream& stream, const EntityActionType& entityActionType)
QDataStream& operator<<(QDataStream& stream, const EntityDynamicType& entityDynamicType)
{
return stream << (quint16)entityActionType;
return stream << (quint16)entityDynamicType;
}
QDataStream& operator>>(QDataStream& stream, EntityActionType& entityActionType)
QDataStream& operator>>(QDataStream& stream, EntityDynamicType& entityDynamicType)
{
quint16 actionTypeAsInt;
stream >> actionTypeAsInt;
entityActionType = (EntityActionType)actionTypeAsInt;
quint16 dynamicTypeAsInt;
stream >> dynamicTypeAsInt;
entityDynamicType = (EntityDynamicType)dynamicTypeAsInt;
return stream;
}
QString serializedActionsToDebugString(QByteArray data) {
QString serializedDynamicsToDebugString(QByteArray data) {
if (data.size() == 0) {
return QString();
}
QVector<QByteArray> serializedActions;
QDataStream serializedActionsStream(data);
serializedActionsStream >> serializedActions;
QVector<QByteArray> serializedDynamics;
QDataStream serializedDynamicsStream(data);
serializedDynamicsStream >> serializedDynamics;
QString result;
foreach(QByteArray serializedAction, serializedActions) {
QDataStream serializedActionStream(serializedAction);
EntityActionType actionType;
QUuid actionID;
serializedActionStream >> actionType;
serializedActionStream >> actionID;
result += EntityActionInterface::actionTypeToString(actionType) + "-" + actionID.toString() + " ";
foreach(QByteArray serializedDynamic, serializedDynamics) {
QDataStream serializedDynamicStream(serializedDynamic);
EntityDynamicType dynamicType;
QUuid dynamicID;
serializedDynamicStream >> dynamicType;
serializedDynamicStream >> dynamicID;
result += EntityDynamicInterface::dynamicTypeToString(dynamicType) + "-" + dynamicID.toString() + " ";
}
return result;

View file

@ -1,5 +1,5 @@
//
// EntityActionInterface.h
// EntityDynamicInterface.h
// libraries/entities/src
//
// Created by Seth Alves on 2015-6-2
@ -9,8 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_EntityActionInterface_h
#define hifi_EntityActionInterface_h
#ifndef hifi_EntityDynamicInterface_h
#define hifi_EntityDynamicInterface_h
#include <memory>
#include <QUuid>
@ -23,22 +23,25 @@ using EntityItemWeakPointer = std::weak_ptr<EntityItem>;
class EntitySimulation;
using EntitySimulationPointer = std::shared_ptr<EntitySimulation>;
enum EntityActionType {
// keep these synchronized with actionTypeFromString and actionTypeToString
ACTION_TYPE_NONE = 0,
ACTION_TYPE_OFFSET = 1000,
ACTION_TYPE_SPRING = 2000,
ACTION_TYPE_HOLD = 3000,
ACTION_TYPE_TRAVEL_ORIENTED = 4000
enum EntityDynamicType {
// keep these synchronized with dynamicTypeFromString and dynamicTypeToString
DYNAMIC_TYPE_NONE = 0,
DYNAMIC_TYPE_OFFSET = 1000,
DYNAMIC_TYPE_SPRING = 2000,
DYNAMIC_TYPE_HOLD = 3000,
DYNAMIC_TYPE_TRAVEL_ORIENTED = 4000,
DYNAMIC_TYPE_HINGE = 5000
};
class EntityActionInterface {
class EntityDynamicInterface {
public:
EntityActionInterface(EntityActionType type, const QUuid& id) : _id(id), _type(type) { }
virtual ~EntityActionInterface() { }
EntityDynamicInterface(EntityDynamicType type, const QUuid& id) : _id(id), _type(type) { }
virtual ~EntityDynamicInterface() { }
const QUuid& getID() const { return _id; }
EntityActionType getType() const { return _type; }
EntityDynamicType getType() const { return _type; }
virtual bool isAction() const { return false; }
virtual bool isConstraint() const { return false; }
bool isActive() { return _active; }
@ -51,8 +54,8 @@ public:
virtual QByteArray serialize() const = 0;
virtual void deserialize(QByteArray serializedArguments) = 0;
static EntityActionType actionTypeFromString(QString actionTypeString);
static QString actionTypeToString(EntityActionType actionType);
static EntityDynamicType dynamicTypeFromString(QString dynamicTypeString);
static QString dynamicTypeToString(EntityDynamicType dynamicType);
virtual bool lifetimeIsOver() { return false; }
virtual quint64 getExpires() { return 0; }
@ -91,17 +94,17 @@ protected:
virtual void setAngularVelocity(glm::vec3 angularVelocity) = 0;
QUuid _id;
EntityActionType _type;
EntityDynamicType _type;
bool _active { false };
bool _isMine { false }; // did this interface create / edit this action?
bool _isMine { false }; // did this interface create / edit this dynamic?
};
typedef std::shared_ptr<EntityActionInterface> EntityActionPointer;
typedef std::shared_ptr<EntityDynamicInterface> EntityDynamicPointer;
QDataStream& operator<<(QDataStream& stream, const EntityActionType& entityActionType);
QDataStream& operator>>(QDataStream& stream, EntityActionType& entityActionType);
QDataStream& operator<<(QDataStream& stream, const EntityDynamicType& entityDynamicType);
QDataStream& operator>>(QDataStream& stream, EntityDynamicType& entityDynamicType);
QString serializedActionsToDebugString(QByteArray data);
QString serializedDynamicsToDebugString(QByteArray data);
#endif // hifi_EntityActionInterface_h
#endif // hifi_EntityDynamicInterface_h

View file

@ -30,7 +30,7 @@
#include "EntitiesLogging.h"
#include "EntityTree.h"
#include "EntitySimulation.h"
#include "EntityActionFactoryInterface.h"
#include "EntityDynamicFactoryInterface.h"
int EntityItem::_maxActionsDataSize = 800;
@ -280,7 +280,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL());
APPEND_ENTITY_PROPERTY(PROP_HREF, getHref());
APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, getDescription());
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, getActionData());
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, getDynamicData());
// convert AVATAR_SELF_ID to actual sessionUUID.
QUuid actualParentID = getParentID();
@ -821,7 +821,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref);
READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription);
READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData);
READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setDynamicData);
{ // parentID and parentJointIndex are also protected by simulation ownership
bool oldOverwrite = overwriteLocalData;
@ -1251,7 +1251,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
COPY_ENTITY_PROPERTY_TO_PROPERTIES(name, getName);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(actionData, getActionData);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(actionData, getDynamicData);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentID, getParentID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentJointIndex, getParentJointIndex);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(queryAACube, getQueryAACube);
@ -1358,7 +1358,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(actionData, setActionData);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(actionData, setDynamicData);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, updateParentID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(queryAACube, setQueryAACube);
@ -1872,10 +1872,10 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask
iAmHoldingThis = true;
}
// also, don't bootstrap our own avatar with a hold action
QList<EntityActionPointer> holdActions = getActionsOfType(ACTION_TYPE_HOLD);
QList<EntityActionPointer>::const_iterator i = holdActions.begin();
QList<EntityDynamicPointer> holdActions = getActionsOfType(DYNAMIC_TYPE_HOLD);
QList<EntityDynamicPointer>::const_iterator i = holdActions.begin();
while (i != holdActions.end()) {
EntityActionPointer action = *i;
EntityDynamicPointer action = *i;
if (action->isMine()) {
iAmHoldingThis = true;
break;
@ -1941,18 +1941,18 @@ void EntityItem::rememberHasSimulationOwnershipBid() const {
QString EntityItem::actionsToDebugString() {
QString result;
QVector<QByteArray> serializedActions;
QHash<QUuid, EntityActionPointer>::const_iterator i = _objectActions.begin();
QHash<QUuid, EntityDynamicPointer>::const_iterator i = _objectActions.begin();
while (i != _objectActions.end()) {
const QUuid id = i.key();
EntityActionPointer action = _objectActions[id];
EntityActionType actionType = action->getType();
EntityDynamicPointer action = _objectActions[id];
EntityDynamicType actionType = action->getType();
result += QString("") + actionType + ":" + action->getID().toString() + " ";
i++;
}
return result;
}
bool EntityItem::addAction(EntitySimulationPointer simulation, EntityActionPointer action) {
bool EntityItem::addAction(EntitySimulationPointer simulation, EntityDynamicPointer action) {
bool result;
withWriteLock([&] {
checkWaitingToRemove(simulation);
@ -1960,7 +1960,7 @@ bool EntityItem::addAction(EntitySimulationPointer simulation, EntityActionPoint
result = addActionInternal(simulation, action);
if (result) {
action->setIsMine(true);
_actionDataDirty = true;
_dynamicDataDirty = true;
} else {
removeActionInternal(action->getID());
}
@ -1969,7 +1969,7 @@ bool EntityItem::addAction(EntitySimulationPointer simulation, EntityActionPoint
return result;
}
bool EntityItem::addActionInternal(EntitySimulationPointer simulation, EntityActionPointer action) {
bool EntityItem::addActionInternal(EntitySimulationPointer simulation, EntityDynamicPointer action) {
assert(action);
assert(simulation);
auto actionOwnerEntity = action->getOwnerEntity().lock();
@ -1979,7 +1979,7 @@ bool EntityItem::addActionInternal(EntitySimulationPointer simulation, EntityAct
const QUuid& actionID = action->getID();
assert(!_objectActions.contains(actionID) || _objectActions[actionID] == action);
_objectActions[actionID] = action;
simulation->addAction(action);
simulation->addDynamic(action);
bool success;
QByteArray newDataCache;
@ -2003,7 +2003,7 @@ bool EntityItem::updateAction(EntitySimulationPointer simulation, const QUuid& a
return;
}
EntityActionPointer action = _objectActions[actionID];
EntityDynamicPointer action = _objectActions[actionID];
success = action->updateArguments(arguments);
if (success) {
@ -2035,7 +2035,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
simulation = entityTree ? entityTree->getSimulation() : nullptr;
}
EntityActionPointer action = _objectActions[actionID];
EntityDynamicPointer action = _objectActions[actionID];
action->setOwnerEntity(nullptr);
action->setIsMine(false);
@ -2049,7 +2049,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
serializeActions(success, _allActionsDataCache);
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
setActionDataNeedsTransmit(true);
setDynamicDataNeedsTransmit(true);
return success;
}
return false;
@ -2057,10 +2057,10 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
bool EntityItem::clearActions(EntitySimulationPointer simulation) {
withWriteLock([&] {
QHash<QUuid, EntityActionPointer>::iterator i = _objectActions.begin();
QHash<QUuid, EntityDynamicPointer>::iterator i = _objectActions.begin();
while (i != _objectActions.end()) {
const QUuid id = i.key();
EntityActionPointer action = _objectActions[id];
EntityDynamicPointer action = _objectActions[id];
i = _objectActions.erase(i);
action->setOwnerEntity(nullptr);
action->removeFromSimulation(simulation);
@ -2101,12 +2101,12 @@ void EntityItem::deserializeActionsInternal() {
serializedActionsStream >> serializedActions;
}
// Keep track of which actions got added or updated by the new actionData
// Keep track of which actions got added or updated by the new dynamicData
QSet<QUuid> updated;
foreach(QByteArray serializedAction, serializedActions) {
QDataStream serializedActionStream(serializedAction);
EntityActionType actionType;
EntityDynamicType actionType;
QUuid actionID;
serializedActionStream >> actionType;
serializedActionStream >> actionID;
@ -2115,7 +2115,7 @@ void EntityItem::deserializeActionsInternal() {
}
if (_objectActions.contains(actionID)) {
EntityActionPointer action = _objectActions[actionID];
EntityDynamicPointer action = _objectActions[actionID];
// TODO: make sure types match? there isn't currently a way to
// change the type of an existing action.
if (!action->isMine()) {
@ -2123,9 +2123,9 @@ void EntityItem::deserializeActionsInternal() {
}
updated << actionID;
} else {
auto actionFactory = DependencyManager::get<EntityActionFactoryInterface>();
auto actionFactory = DependencyManager::get<EntityDynamicFactoryInterface>();
EntityItemPointer entity = getThisPointer();
EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction);
EntityDynamicPointer action = actionFactory->factoryBA(entity, serializedAction);
if (action) {
entity->addActionInternal(simulation, action);
updated << actionID;
@ -2140,15 +2140,15 @@ void EntityItem::deserializeActionsInternal() {
}
// remove any actions that weren't included in the new data.
QHash<QUuid, EntityActionPointer>::const_iterator i = _objectActions.begin();
QHash<QUuid, EntityDynamicPointer>::const_iterator i = _objectActions.begin();
while (i != _objectActions.end()) {
QUuid id = i.key();
if (!updated.contains(id)) {
EntityActionPointer action = i.value();
EntityDynamicPointer action = i.value();
if (action->isMine()) {
// we just received an update that didn't include one of our actions. tell the server about it (again).
setActionDataNeedsTransmit(true);
setDynamicDataNeedsTransmit(true);
} else {
// don't let someone else delete my action.
_actionsToRemove << id;
@ -2167,7 +2167,7 @@ void EntityItem::deserializeActionsInternal() {
}
}
_actionDataDirty = true;
_dynamicDataDirty = true;
return;
}
@ -2179,15 +2179,15 @@ void EntityItem::checkWaitingToRemove(EntitySimulationPointer simulation) {
_actionsToRemove.clear();
}
void EntityItem::setActionData(QByteArray actionData) {
void EntityItem::setDynamicData(QByteArray dynamicData) {
withWriteLock([&] {
setActionDataInternal(actionData);
setDynamicDataInternal(dynamicData);
});
}
void EntityItem::setActionDataInternal(QByteArray actionData) {
if (_allActionsDataCache != actionData) {
_allActionsDataCache = actionData;
void EntityItem::setDynamicDataInternal(QByteArray dynamicData) {
if (_allActionsDataCache != dynamicData) {
_allActionsDataCache = dynamicData;
deserializeActionsInternal();
}
checkWaitingToRemove();
@ -2201,10 +2201,10 @@ void EntityItem::serializeActions(bool& success, QByteArray& result) const {
}
QVector<QByteArray> serializedActions;
QHash<QUuid, EntityActionPointer>::const_iterator i = _objectActions.begin();
QHash<QUuid, EntityDynamicPointer>::const_iterator i = _objectActions.begin();
while (i != _objectActions.end()) {
const QUuid id = i.key();
EntityActionPointer action = _objectActions[id];
EntityDynamicPointer action = _objectActions[id];
QByteArray bytesForAction = action->serialize();
serializedActions << bytesForAction;
i++;
@ -2224,23 +2224,23 @@ void EntityItem::serializeActions(bool& success, QByteArray& result) const {
return;
}
const QByteArray EntityItem::getActionDataInternal() const {
if (_actionDataDirty) {
const QByteArray EntityItem::getDynamicDataInternal() const {
if (_dynamicDataDirty) {
bool success;
serializeActions(success, _allActionsDataCache);
if (success) {
_actionDataDirty = false;
_dynamicDataDirty = false;
}
}
return _allActionsDataCache;
}
const QByteArray EntityItem::getActionData() const {
const QByteArray EntityItem::getDynamicData() const {
QByteArray result;
if (_actionDataDirty) {
if (_dynamicDataDirty) {
withWriteLock([&] {
getActionDataInternal();
getDynamicDataInternal();
result = _allActionsDataCache;
});
} else {
@ -2255,9 +2255,9 @@ QVariantMap EntityItem::getActionArguments(const QUuid& actionID) const {
QVariantMap result;
withReadLock([&] {
if (_objectActions.contains(actionID)) {
EntityActionPointer action = _objectActions[actionID];
EntityDynamicPointer action = _objectActions[actionID];
result = action->getArguments();
result["type"] = EntityActionInterface::actionTypeToString(action->getType());
result["type"] = EntityDynamicInterface::dynamicTypeToString(action->getType());
}
});
@ -2265,7 +2265,7 @@ QVariantMap EntityItem::getActionArguments(const QUuid& actionID) const {
}
bool EntityItem::shouldSuppressLocationEdits() const {
QHash<QUuid, EntityActionPointer>::const_iterator i = _objectActions.begin();
QHash<QUuid, EntityDynamicPointer>::const_iterator i = _objectActions.begin();
while (i != _objectActions.end()) {
if (i.value()->shouldSuppressLocationEdits()) {
return true;
@ -2276,12 +2276,12 @@ bool EntityItem::shouldSuppressLocationEdits() const {
return false;
}
QList<EntityActionPointer> EntityItem::getActionsOfType(EntityActionType typeToGet) const {
QList<EntityActionPointer> result;
QList<EntityDynamicPointer> EntityItem::getActionsOfType(EntityDynamicType typeToGet) const {
QList<EntityDynamicPointer> result;
QHash<QUuid, EntityActionPointer>::const_iterator i = _objectActions.begin();
QHash<QUuid, EntityDynamicPointer>::const_iterator i = _objectActions.begin();
while (i != _objectActions.end()) {
EntityActionPointer action = i.value();
EntityDynamicPointer action = i.value();
if (action->getType() == typeToGet && action->isActive()) {
result += action;
}

View file

@ -36,17 +36,17 @@
#include "EntityTypes.h"
#include "SimulationOwner.h"
#include "SimulationFlags.h"
#include "EntityActionInterface.h"
#include "EntityDynamicInterface.h"
class EntitySimulation;
class EntityTreeElement;
class EntityTreeElementExtraEncodeData;
class EntityActionInterface;
class EntityDynamicInterface;
class EntityItemProperties;
class EntityTree;
class btCollisionShape;
typedef std::shared_ptr<EntityTree> EntityTreePointer;
typedef std::shared_ptr<EntityActionInterface> EntityActionPointer;
typedef std::shared_ptr<EntityDynamicInterface> EntityDynamicPointer;
typedef std::shared_ptr<EntityTreeElement> EntityTreeElementPointer;
using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr<EntityTreeElementExtraEncodeData>;
@ -398,22 +398,22 @@ public:
void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; }
QString actionsToDebugString();
bool addAction(EntitySimulationPointer simulation, EntityActionPointer action);
bool addAction(EntitySimulationPointer simulation, EntityDynamicPointer action);
bool updateAction(EntitySimulationPointer simulation, const QUuid& actionID, const QVariantMap& arguments);
bool removeAction(EntitySimulationPointer simulation, const QUuid& actionID);
bool clearActions(EntitySimulationPointer simulation);
void setActionData(QByteArray actionData);
const QByteArray getActionData() const;
void setDynamicData(QByteArray dynamicData);
const QByteArray getDynamicData() const;
bool hasActions() const { return !_objectActions.empty(); }
QList<QUuid> getActionIDs() const { return _objectActions.keys(); }
QVariantMap getActionArguments(const QUuid& actionID) const;
void deserializeActions();
void setActionDataDirty(bool value) const { _actionDataDirty = value; }
bool actionDataDirty() const { return _actionDataDirty; }
void setDynamicDataDirty(bool value) const { _dynamicDataDirty = value; }
bool dynamicDataDirty() const { return _dynamicDataDirty; }
void setActionDataNeedsTransmit(bool value) const { _actionDataNeedsTransmit = value; }
bool actionDataNeedsTransmit() const { return _actionDataNeedsTransmit; }
void setDynamicDataNeedsTransmit(bool value) const { _dynamicDataNeedsTransmit = value; }
bool dynamicDataNeedsTransmit() const { return _dynamicDataNeedsTransmit; }
bool shouldSuppressLocationEdits() const;
@ -421,7 +421,7 @@ public:
const QUuid& getSourceUUID() const { return _sourceUUID; }
bool matchesSourceUUID(const QUuid& sourceUUID) const { return _sourceUUID == sourceUUID; }
QList<EntityActionPointer> getActionsOfType(EntityActionType typeToGet) const;
QList<EntityDynamicPointer> getActionsOfType(EntityDynamicType typeToGet) const;
// these are in the frame of this object
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override { return glm::quat(); }
@ -479,8 +479,8 @@ protected:
void setSimulated(bool simulated) { _simulated = simulated; }
const QByteArray getActionDataInternal() const;
void setActionDataInternal(QByteArray actionData);
const QByteArray getDynamicDataInternal() const;
void setDynamicDataInternal(QByteArray dynamicData);
virtual void locationChanged(bool tellPhysics = true) override;
virtual void dimensionsChanged() override;
@ -570,22 +570,22 @@ protected:
void* _physicsInfo { nullptr }; // set by EntitySimulation
bool _simulated; // set by EntitySimulation
bool addActionInternal(EntitySimulationPointer simulation, EntityActionPointer action);
bool addActionInternal(EntitySimulationPointer simulation, EntityDynamicPointer action);
bool removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation = nullptr);
void deserializeActionsInternal();
void serializeActions(bool& success, QByteArray& result) const;
QHash<QUuid, EntityActionPointer> _objectActions;
QHash<QUuid, EntityDynamicPointer> _objectActions;
static int _maxActionsDataSize;
mutable QByteArray _allActionsDataCache;
// when an entity-server starts up, EntityItem::setActionData is called before the entity-tree is
// when an entity-server starts up, EntityItem::setDynamicData is called before the entity-tree is
// ready. This means we can't find our EntityItemPointer or add the action to the simulation. These
// are used to keep track of and work around this situation.
void checkWaitingToRemove(EntitySimulationPointer simulation = nullptr);
mutable QSet<QUuid> _actionsToRemove;
mutable bool _actionDataDirty { false };
mutable bool _actionDataNeedsTransmit { false };
mutable bool _dynamicDataDirty { false };
mutable bool _dynamicDataNeedsTransmit { false };
// _previouslyDeletedActions is used to avoid an action being re-added due to server round-trip lag
static quint64 _rememberDeletedActionTime;
mutable QHash<QUuid, quint64> _previouslyDeletedActions;

View file

@ -24,8 +24,8 @@
#include <model-networking/MeshProxy.h>
#include "EntitiesLogging.h"
#include "EntityActionFactoryInterface.h"
#include "EntityActionInterface.h"
#include "EntityDynamicFactoryInterface.h"
#include "EntityDynamicInterface.h"
#include "EntitySimulation.h"
#include "EntityTree.h"
#include "LightEntityItem.h"
@ -1133,7 +1133,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
PROFILE_RANGE(script_entities, __FUNCTION__);
QUuid actionID = QUuid::createUuid();
auto actionFactory = DependencyManager::get<EntityActionFactoryInterface>();
auto actionFactory = DependencyManager::get<EntityDynamicFactoryInterface>();
bool success = false;
actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) {
// create this action even if the entity doesn't have physics info. it will often be the
@ -1142,11 +1142,11 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
// if (!entity->getPhysicsInfo()) {
// return false;
// }
EntityActionType actionType = EntityActionInterface::actionTypeFromString(actionTypeString);
if (actionType == ACTION_TYPE_NONE) {
EntityDynamicType dynamicType = EntityDynamicInterface::dynamicTypeFromString(actionTypeString);
if (dynamicType == DYNAMIC_TYPE_NONE) {
return false;
}
EntityActionPointer action = actionFactory->factory(actionType, actionID, entity, arguments);
EntityDynamicPointer action = actionFactory->factory(dynamicType, actionID, entity, arguments);
if (!action) {
return false;
}

View file

@ -279,25 +279,25 @@ void EntitySimulation::moveSimpleKinematics(const quint64& now) {
}
}
void EntitySimulation::addAction(EntityActionPointer action) {
void EntitySimulation::addDynamic(EntityDynamicPointer dynamic) {
QMutexLocker lock(&_mutex);
_actionsToAdd += action;
_dynamicsToAdd += dynamic;
}
void EntitySimulation::removeAction(const QUuid actionID) {
void EntitySimulation::removeDynamic(const QUuid dynamicID) {
QMutexLocker lock(&_mutex);
_actionsToRemove += actionID;
_dynamicsToRemove += dynamicID;
}
void EntitySimulation::removeActions(QList<QUuid> actionIDsToRemove) {
void EntitySimulation::removeDynamics(QList<QUuid> dynamicIDsToRemove) {
QMutexLocker lock(&_mutex);
foreach(QUuid uuid, actionIDsToRemove) {
_actionsToRemove.insert(uuid);
foreach(QUuid uuid, dynamicIDsToRemove) {
_dynamicsToRemove.insert(uuid);
}
}
void EntitySimulation::applyActionChanges() {
void EntitySimulation::applyDynamicChanges() {
QMutexLocker lock(&_mutex);
_actionsToAdd.clear();
_actionsToRemove.clear();
_dynamicsToAdd.clear();
_dynamicsToRemove.clear();
}

View file

@ -18,7 +18,7 @@
#include <PerfStat.h>
#include "EntityActionInterface.h"
#include "EntityDynamicInterface.h"
#include "EntityItem.h"
#include "EntityTree.h"
@ -59,10 +59,10 @@ public:
// friend class EntityTree;
virtual void addAction(EntityActionPointer action);
virtual void removeAction(const QUuid actionID);
virtual void removeActions(QList<QUuid> actionIDsToRemove);
virtual void applyActionChanges();
virtual void addDynamic(EntityDynamicPointer dynamic);
virtual void removeDynamic(const QUuid dynamicID);
virtual void removeDynamics(QList<QUuid> dynamicIDsToRemove);
virtual void applyDynamicChanges();
/// \param entity pointer to EntityItem to be added
/// \sideeffect sets relevant backpointers in entity, but maybe later when appropriate data structures are locked
@ -103,8 +103,8 @@ protected:
SetOfEntities _entitiesToSort; // entities moved by simulation (and might need resort in EntityTree)
SetOfEntities _simpleKinematicEntities; // entities undergoing non-colliding kinematic motion
QList<EntityActionPointer> _actionsToAdd;
QSet<QUuid> _actionsToRemove;
QList<EntityDynamicPointer> _dynamicsToAdd;
QSet<QUuid> _dynamicsToRemove;
protected:
SetOfEntities _entitiesToDelete; // entities simulation decided needed to be deleted (EntityTree will actually delete)

View file

@ -808,7 +808,7 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<Q
int index = changedProperties.indexOf("actionData");
if (index >= 0) {
QByteArray value = properties.getActionData();
QString changeHint = serializedActionsToDebugString(value);
QString changeHint = serializedDynamicsToDebugString(value);
changedProperties[index] = QString("actionData:") + changeHint;
}
}

View file

@ -94,7 +94,7 @@ void EntityMotionState::updateServerPhysicsVariables() {
_serverPosition = localTransform.getTranslation();
_serverRotation = localTransform.getRotation();
_serverAcceleration = _entity->getAcceleration();
_serverActionData = _entity->getActionData();
_serverActionData = _entity->getDynamicData();
}
void EntityMotionState::handleDeactivation() {
@ -309,7 +309,7 @@ bool EntityMotionState::isCandidateForOwnership() const {
assert(entityTreeIsLocked());
return _outgoingPriority != 0
|| Physics::getSessionUUID() == _entity->getSimulatorID()
|| _entity->actionDataNeedsTransmit();
|| _entity->dynamicDataNeedsTransmit();
}
bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
@ -335,7 +335,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
_serverAcceleration = Vectors::ZERO;
_serverAngularVelocity = worldVelocityToLocal.transform(bulletToGLM(_body->getAngularVelocity()));
_lastStep = simulationStep;
_serverActionData = _entity->getActionData();
_serverActionData = _entity->getDynamicData();
_numInactiveUpdates = 1;
return false;
}
@ -387,7 +387,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
}
}
if (_entity->actionDataNeedsTransmit()) {
if (_entity->dynamicDataNeedsTransmit()) {
_outgoingPriority = _entity->hasActions() ? SCRIPT_GRAB_SIMULATION_PRIORITY : SCRIPT_POKE_SIMULATION_PRIORITY;
return true;
}
@ -474,7 +474,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
return false;
}
if (_entity->actionDataNeedsTransmit()) {
if (_entity->dynamicDataNeedsTransmit()) {
return true;
}
@ -551,7 +551,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
_serverPosition = localTransform.getTranslation();
_serverRotation = localTransform.getRotation();
_serverAcceleration = _entity->getAcceleration();
_serverActionData = _entity->getActionData();
_serverActionData = _entity->getDynamicData();
EntityItemProperties properties;
@ -562,8 +562,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
properties.setVelocity(_serverVelocity);
properties.setAcceleration(_serverAcceleration);
properties.setAngularVelocity(_serverAngularVelocity);
if (_entity->actionDataNeedsTransmit()) {
_entity->setActionDataNeedsTransmit(false);
if (_entity->dynamicDataNeedsTransmit()) {
_entity->setDynamicDataNeedsTransmit(false);
properties.setActionData(_serverActionData);
}

View file

@ -16,13 +16,10 @@
#include "PhysicsLogging.h"
ObjectAction::ObjectAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity) :
ObjectAction::ObjectAction(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity) :
btActionInterface(),
EntityActionInterface(type, id),
_ownerEntity(ownerEntity) {
}
ObjectAction::~ObjectAction() {
ObjectDynamic(type, id, ownerEntity)
{
}
void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) {
@ -64,240 +61,5 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta
updateActionWorker(deltaTimeStep);
}
qint64 ObjectAction::getEntityServerClockSkew() const {
auto nodeList = DependencyManager::get<NodeList>();
auto ownerEntity = _ownerEntity.lock();
if (!ownerEntity) {
return 0;
}
const QUuid& entityServerNodeID = ownerEntity->getSourceUUID();
auto entityServerNode = nodeList->nodeWithUUID(entityServerNodeID);
if (entityServerNode) {
return entityServerNode->getClockSkewUsec();
}
return 0;
}
bool ObjectAction::updateArguments(QVariantMap arguments) {
bool somethingChanged = false;
withWriteLock([&]{
quint64 previousExpires = _expires;
QString previousTag = _tag;
bool ttlSet = true;
float ttl = EntityActionInterface::extractFloatArgument("action", arguments, "ttl", ttlSet, false);
if (ttlSet) {
quint64 now = usecTimestampNow();
_expires = now + (quint64)(ttl * 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;
withReadLock([&]{
if (_expires == 0) {
arguments["ttl"] = 0.0f;
} else {
quint64 now = usecTimestampNow();
arguments["ttl"] = (float)(_expires - now) / (float)USECS_PER_SECOND;
}
arguments["tag"] = _tag;
EntityItemPointer entity = _ownerEntity.lock();
if (entity) {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(entity->getPhysicsInfo());
if (motionState) {
arguments["::active"] = motionState->isActive();
arguments["::motion-type"] = motionTypeToString(motionState->getMotionType());
} else {
arguments["::no-motion-state"] = true;
}
}
arguments["isMine"] = isMine();
});
return arguments;
}
void ObjectAction::debugDraw(btIDebugDraw* debugDrawer) {
}
void ObjectAction::removeFromSimulation(EntitySimulationPointer simulation) const {
QUuid myID;
withReadLock([&]{
myID = _id;
});
simulation->removeAction(myID);
}
btRigidBody* ObjectAction::getRigidBody() {
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();
}
return nullptr;
}
glm::vec3 ObjectAction::getPosition() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::vec3(0.0f);
}
return bulletToGLM(rigidBody->getCenterOfMassPosition());
}
void ObjectAction::setPosition(glm::vec3 position) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
// XXX
// void setWorldTransform (const btTransform &worldTrans)
assert(false);
rigidBody->activate();
}
glm::quat ObjectAction::getRotation() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::quat(0.0f, 0.0f, 0.0f, 1.0f);
}
return bulletToGLM(rigidBody->getOrientation());
}
void ObjectAction::setRotation(glm::quat rotation) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
// XXX
// void setWorldTransform (const btTransform &worldTrans)
assert(false);
rigidBody->activate();
}
glm::vec3 ObjectAction::getLinearVelocity() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::vec3(0.0f);
}
return bulletToGLM(rigidBody->getLinearVelocity());
}
void ObjectAction::setLinearVelocity(glm::vec3 linearVelocity) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
rigidBody->setLinearVelocity(glmToBullet(glm::vec3(0.0f)));
rigidBody->activate();
}
glm::vec3 ObjectAction::getAngularVelocity() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::vec3(0.0f);
}
return bulletToGLM(rigidBody->getAngularVelocity());
}
void ObjectAction::setAngularVelocity(glm::vec3 angularVelocity) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
rigidBody->setAngularVelocity(glmToBullet(angularVelocity));
rigidBody->activate();
}
void ObjectAction::activateBody(bool forceActivation) {
auto rigidBody = getRigidBody();
if (rigidBody) {
rigidBody->activate(forceActivation);
} else {
qCDebug(physics) << "ObjectAction::activateBody -- no rigid body" << (void*)rigidBody;
}
}
void ObjectAction::forceBodyNonStatic() {
auto ownerEntity = _ownerEntity.lock();
if (!ownerEntity) {
return;
}
void* physicsInfo = ownerEntity->getPhysicsInfo();
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
if (motionState && motionState->getMotionType() == MOTION_TYPE_STATIC) {
ownerEntity->flagForMotionStateChange();
}
}
bool ObjectAction::lifetimeIsOver() {
if (_expires == 0) {
return false;
}
quint64 now = usecTimestampNow();
if (now >= _expires) {
return true;
}
return false;
}
quint64 ObjectAction::localTimeToServerTime(quint64 timeValue) const {
// 0 indicates no expiration
if (timeValue == 0) {
return 0;
}
qint64 serverClockSkew = getEntityServerClockSkew();
if (serverClockSkew < 0 && timeValue <= (quint64)(-serverClockSkew)) {
return 1; // non-zero but long-expired value to avoid negative roll-over
}
return timeValue + serverClockSkew;
}
quint64 ObjectAction::serverTimeToLocalTime(quint64 timeValue) const {
// 0 indicates no expiration
if (timeValue == 0) {
return 0;
}
qint64 serverClockSkew = getEntityServerClockSkew();
if (serverClockSkew > 0 && timeValue <= (quint64)serverClockSkew) {
return 1; // non-zero but long-expired value to avoid negative roll-over
}
return timeValue - serverClockSkew;
}

View file

@ -14,63 +14,19 @@
#define hifi_ObjectAction_h
#include <QUuid>
#include <btBulletDynamicsCommon.h>
#include "ObjectDynamic.h"
#include <shared/ReadWriteLockable.h>
#include "ObjectMotionState.h"
#include "BulletUtil.h"
#include "EntityActionInterface.h"
class ObjectAction : public btActionInterface, public EntityActionInterface, public ReadWriteLockable {
class ObjectAction : public btActionInterface, public ObjectDynamic {
public:
ObjectAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity);
virtual ~ObjectAction();
virtual void removeFromSimulation(EntitySimulationPointer simulation) const override;
virtual EntityItemWeakPointer getOwnerEntity() const override { return _ownerEntity; }
virtual void setOwnerEntity(const EntityItemPointer ownerEntity) override { _ownerEntity = ownerEntity; }
virtual bool updateArguments(QVariantMap arguments) override;
virtual QVariantMap getArguments() override;
ObjectAction(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity);
// this is called from updateAction and should be overridden by subclasses
virtual void updateActionWorker(float deltaTimeStep) = 0;
// these are from btActionInterface
// these are from btDynamicInterface
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) override;
virtual void debugDraw(btIDebugDraw* debugDrawer) override;
virtual QByteArray serialize() const override = 0;
virtual void deserialize(QByteArray serializedArguments) override = 0;
virtual bool lifetimeIsOver() override;
virtual quint64 getExpires() override { return _expires; }
protected:
quint64 localTimeToServerTime(quint64 timeValue) const;
quint64 serverTimeToLocalTime(quint64 timeValue) const;
virtual btRigidBody* getRigidBody();
virtual glm::vec3 getPosition() override;
virtual void setPosition(glm::vec3 position) override;
virtual glm::quat getRotation() override;
virtual void setRotation(glm::quat rotation) override;
virtual glm::vec3 getLinearVelocity() override;
virtual void setLinearVelocity(glm::vec3 linearVelocity) override;
virtual glm::vec3 getAngularVelocity() override;
virtual void setAngularVelocity(glm::vec3 angularVelocity) override;
virtual void activateBody(bool forceActivation = false);
virtual void forceBodyNonStatic();
EntityItemWeakPointer _ownerEntity;
QString _tag;
quint64 _expires { 0 }; // in seconds since epoch
private:
qint64 getEntityServerClockSkew() const;
};
#endif // hifi_ObjectAction_h

View file

@ -19,7 +19,7 @@
const uint16_t ObjectActionOffset::offsetVersion = 1;
ObjectActionOffset::ObjectActionOffset(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectAction(ACTION_TYPE_OFFSET, id, ownerEntity),
ObjectAction(DYNAMIC_TYPE_OFFSET, id, ownerEntity),
_pointToOffsetFrom(0.0f),
_linearDistance(0.0f),
_linearTimeScale(FLT_MAX),
@ -93,21 +93,21 @@ bool ObjectActionOffset::updateArguments(QVariantMap arguments) {
withReadLock([&]{
bool ok = true;
pointToOffsetFrom =
EntityActionInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", ok, true);
EntityDynamicInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", ok, true);
if (!ok) {
pointToOffsetFrom = _pointToOffsetFrom;
}
ok = true;
linearTimeScale =
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", ok, false);
EntityDynamicInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", ok, false);
if (!ok) {
linearTimeScale = _linearTimeScale;
}
ok = true;
linearDistance =
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearDistance", ok, false);
EntityDynamicInterface::extractFloatArgument("offset action", arguments, "linearDistance", ok, false);
if (!ok) {
linearDistance = _linearDistance;
}
@ -132,8 +132,8 @@ bool ObjectActionOffset::updateArguments(QVariantMap arguments) {
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
ownerEntity->setActionDataNeedsTransmit(true);
ownerEntity->setDynamicDataDirty(true);
ownerEntity->setDynamicDataNeedsTransmit(true);
}
});
activateBody();
@ -155,7 +155,7 @@ QVariantMap ObjectActionOffset::getArguments() {
QByteArray ObjectActionOffset::serialize() const {
QByteArray ba;
QDataStream dataStream(&ba, QIODevice::WriteOnly);
dataStream << ACTION_TYPE_OFFSET;
dataStream << DYNAMIC_TYPE_OFFSET;
dataStream << getID();
dataStream << ObjectActionOffset::offsetVersion;
@ -174,7 +174,7 @@ QByteArray ObjectActionOffset::serialize() const {
void ObjectActionOffset::deserialize(QByteArray serializedArguments) {
QDataStream dataStream(serializedArguments);
EntityActionType type;
EntityDynamicType type;
dataStream >> type;
assert(type == getType());

View file

@ -21,7 +21,7 @@ const uint16_t ObjectActionSpring::springVersion = 1;
ObjectActionSpring::ObjectActionSpring(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectAction(ACTION_TYPE_SPRING, id, ownerEntity),
ObjectAction(DYNAMIC_TYPE_SPRING, id, ownerEntity),
_positionalTarget(glm::vec3(0.0f)),
_desiredPositionalTarget(glm::vec3(0.0f)),
_linearTimeScale(FLT_MAX),
@ -64,11 +64,11 @@ bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep) {
bool valid = false;
int springCount = 0;
QList<EntityActionPointer> springDerivedActions;
springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_SPRING));
springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_HOLD));
QList<EntityDynamicPointer> springDerivedActions;
springDerivedActions.append(ownerEntity->getActionsOfType(DYNAMIC_TYPE_SPRING));
springDerivedActions.append(ownerEntity->getActionsOfType(DYNAMIC_TYPE_HOLD));
foreach (EntityActionPointer action, springDerivedActions) {
foreach (EntityDynamicPointer action, springDerivedActions) {
std::shared_ptr<ObjectActionSpring> springAction = std::static_pointer_cast<ObjectActionSpring>(action);
glm::quat rotationForAction;
glm::vec3 positionForAction;
@ -194,25 +194,25 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
withReadLock([&]{
// targets are required, spring-constants are optional
bool ok = true;
positionalTarget = EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false);
positionalTarget = EntityDynamicInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false);
if (!ok) {
positionalTarget = _desiredPositionalTarget;
}
ok = true;
linearTimeScale = EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false);
linearTimeScale = EntityDynamicInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false);
if (!ok || linearTimeScale <= 0.0f) {
linearTimeScale = _linearTimeScale;
}
ok = true;
rotationalTarget = EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false);
rotationalTarget = EntityDynamicInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false);
if (!ok) {
rotationalTarget = _desiredRotationalTarget;
}
ok = true;
angularTimeScale =
EntityActionInterface::extractFloatArgument("spring action", arguments, "angularTimeScale", ok, false);
EntityDynamicInterface::extractFloatArgument("spring action", arguments, "angularTimeScale", ok, false);
if (!ok) {
angularTimeScale = _angularTimeScale;
}
@ -237,8 +237,8 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
ownerEntity->setActionDataNeedsTransmit(true);
ownerEntity->setDynamicDataDirty(true);
ownerEntity->setDynamicDataNeedsTransmit(true);
}
});
activateBody();
@ -263,7 +263,7 @@ QByteArray ObjectActionSpring::serialize() const {
QByteArray serializedActionArguments;
QDataStream dataStream(&serializedActionArguments, QIODevice::WriteOnly);
dataStream << ACTION_TYPE_SPRING;
dataStream << DYNAMIC_TYPE_SPRING;
dataStream << getID();
dataStream << ObjectActionSpring::springVersion;
@ -284,7 +284,7 @@ QByteArray ObjectActionSpring::serialize() const {
void ObjectActionSpring::deserialize(QByteArray serializedArguments) {
QDataStream dataStream(serializedArguments);
EntityActionType type;
EntityDynamicType type;
dataStream >> type;
assert(type == getType());

View file

@ -19,7 +19,7 @@ const uint16_t ObjectActionTravelOriented::actionVersion = 1;
ObjectActionTravelOriented::ObjectActionTravelOriented(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectAction(ACTION_TYPE_TRAVEL_ORIENTED, id, ownerEntity) {
ObjectAction(DYNAMIC_TYPE_TRAVEL_ORIENTED, id, ownerEntity) {
#if WANT_DEBUG
qCDebug(physics) << "ObjectActionTravelOriented::ObjectActionTravelOriented";
#endif
@ -109,13 +109,13 @@ bool ObjectActionTravelOriented::updateArguments(QVariantMap arguments) {
bool somethingChanged = ObjectAction::updateArguments(arguments);
withReadLock([&]{
bool ok = true;
forward = EntityActionInterface::extractVec3Argument("travel oriented action", arguments, "forward", ok, true);
forward = EntityDynamicInterface::extractVec3Argument("travel oriented action", arguments, "forward", ok, true);
if (!ok) {
forward = _forward;
}
ok = true;
angularTimeScale =
EntityActionInterface::extractFloatArgument("travel oriented action", arguments, "angularTimeScale", ok, false);
EntityDynamicInterface::extractFloatArgument("travel oriented action", arguments, "angularTimeScale", ok, false);
if (!ok) {
angularTimeScale = _angularTimeScale;
}
@ -136,8 +136,8 @@ bool ObjectActionTravelOriented::updateArguments(QVariantMap arguments) {
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
ownerEntity->setActionDataNeedsTransmit(true);
ownerEntity->setDynamicDataDirty(true);
ownerEntity->setDynamicDataNeedsTransmit(true);
}
});
activateBody();
@ -159,7 +159,7 @@ QByteArray ObjectActionTravelOriented::serialize() const {
QByteArray serializedActionArguments;
QDataStream dataStream(&serializedActionArguments, QIODevice::WriteOnly);
dataStream << ACTION_TYPE_TRAVEL_ORIENTED;
dataStream << DYNAMIC_TYPE_TRAVEL_ORIENTED;
dataStream << getID();
dataStream << ObjectActionTravelOriented::actionVersion;
@ -177,7 +177,7 @@ QByteArray ObjectActionTravelOriented::serialize() const {
void ObjectActionTravelOriented::deserialize(QByteArray serializedArguments) {
QDataStream dataStream(serializedArguments);
EntityActionType type;
EntityDynamicType type;
dataStream >> type;
assert(type == getType());

View file

@ -0,0 +1,21 @@
//
// ObjectConstraint.cpp
// libraries/physcis/src
//
// Created by Seth Alves 2015-6-2
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EntitySimulation.h"
#include "ObjectConstraint.h"
#include "PhysicsLogging.h"
ObjectConstraint::ObjectConstraint(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity) :
ObjectDynamic(type, id, ownerEntity)
{
}

View file

@ -0,0 +1,29 @@
//
// ObjectConstraint.h
// libraries/physcis/src
//
// Created by Seth Alves 2017-4-11
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// http://bulletphysics.org/Bullet/BulletFull/classbtConstraintInterface.html
#ifndef hifi_ObjectConstraint_h
#define hifi_ObjectConstraint_h
#include <QUuid>
#include <btBulletDynamicsCommon.h>
#include "ObjectDynamic.h"
class ObjectConstraint : public ObjectDynamic
{
public:
ObjectConstraint(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity);
virtual btTypedConstraint* getConstraint() = 0;
protected:
btTypedConstraint* _constraint { nullptr };
};
#endif // hifi_ObjectConstraint_h

View file

@ -0,0 +1,160 @@
//
// ObjectConstraintHinge.cpp
// libraries/physics/src
//
// Created by Seth Alves 2017-4-11
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "QVariantGLM.h"
#include "ObjectConstraintHinge.h"
#include "PhysicsLogging.h"
const uint16_t ObjectConstraintHinge::constraintVersion = 1;
ObjectConstraintHinge::ObjectConstraintHinge(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectConstraint(DYNAMIC_TYPE_HINGE, id, ownerEntity),
_rbATranslation(glm::vec3(0.0f)),
_rbARotation(glm::quat())
{
#if WANT_DEBUG
qCDebug(physics) << "ObjectConstraintHinge::ObjectConstraintHinge";
#endif
}
ObjectConstraintHinge::~ObjectConstraintHinge() {
#if WANT_DEBUG
qCDebug(physics) << "ObjectConstraintHinge::~ObjectConstraintHinge";
#endif
}
btTypedConstraint* ObjectConstraintHinge::getConstraint() {
if (_constraint) {
return _constraint;
}
btRigidBody* rigidBodyA = getRigidBody();
if (!rigidBodyA) {
return nullptr;
}
bool useReferenceFrameA { false };
btTransform rigidBodyAFrame(glmToBullet(_rbARotation), glmToBullet(_rbATranslation));
_constraint = new btHingeConstraint(*rigidBodyA, rigidBodyAFrame, useReferenceFrameA);
return _constraint;
}
bool ObjectConstraintHinge::updateArguments(QVariantMap arguments) {
glm::vec3 rbATranslation;
glm::quat rbARotation;
bool needUpdate = false;
bool somethingChanged = ObjectConstraint::updateArguments(arguments);
withReadLock([&]{
// targets are required, hinge-constants are optional
bool ok = true;
rbATranslation = EntityDynamicInterface::extractVec3Argument("hinge constraint", arguments, "targetPosition", ok, false);
if (!ok) {
rbATranslation = _rbATranslation;
}
ok = true;
rbARotation = EntityDynamicInterface::extractQuatArgument("hinge constraint", arguments, "targetRotation", ok, false);
if (!ok) {
rbARotation = _rbARotation;
}
if (somethingChanged ||
rbATranslation != _rbATranslation ||
rbARotation != _rbARotation) {
// something changed
needUpdate = true;
}
});
if (needUpdate) {
withWriteLock([&] {
_rbATranslation = rbATranslation;
_rbARotation = rbARotation;
_active = true;
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setDynamicDataDirty(true);
ownerEntity->setDynamicDataNeedsTransmit(true);
}
});
activateBody();
}
return true;
}
QVariantMap ObjectConstraintHinge::getArguments() {
QVariantMap arguments = ObjectConstraint::getArguments();
withReadLock([&] {
arguments["targetPosition"] = glmToQMap(_rbATranslation);
arguments["targetRotation"] = glmToQMap(_rbARotation);
});
return arguments;
}
QByteArray ObjectConstraintHinge::serialize() const {
QByteArray serializedConstraintArguments;
QDataStream dataStream(&serializedConstraintArguments, QIODevice::WriteOnly);
dataStream << DYNAMIC_TYPE_HINGE;
dataStream << getID();
dataStream << ObjectConstraintHinge::constraintVersion;
withReadLock([&] {
dataStream << _rbATranslation;
dataStream << _rbARotation;
dataStream << localTimeToServerTime(_expires);
dataStream << _tag;
});
return serializedConstraintArguments;
}
void ObjectConstraintHinge::deserialize(QByteArray serializedArguments) {
QDataStream dataStream(serializedArguments);
EntityDynamicType type;
dataStream >> type;
assert(type == getType());
QUuid id;
dataStream >> id;
assert(id == getID());
uint16_t serializationVersion;
dataStream >> serializationVersion;
if (serializationVersion != ObjectConstraintHinge::constraintVersion) {
assert(false);
return;
}
withWriteLock([&] {
dataStream >> _rbATranslation;
dataStream >> _rbARotation;
quint64 serverExpires;
dataStream >> serverExpires;
_expires = serverTimeToLocalTime(serverExpires);
dataStream >> _tag;
_active = true;
});
}

View file

@ -0,0 +1,39 @@
//
// ObjectConstraintHinge.h
// libraries/physics/src
//
// Created by Seth Alves 2017-4-11
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_ObjectConstraintHinge_h
#define hifi_ObjectConstraintHinge_h
#include "ObjectConstraint.h"
// http://bulletphysics.org/Bullet/BulletFull/classbtHingeConstraint.html
class ObjectConstraintHinge : public ObjectConstraint {
public:
ObjectConstraintHinge(const QUuid& id, EntityItemPointer ownerEntity);
virtual ~ObjectConstraintHinge();
virtual bool updateArguments(QVariantMap arguments) override;
virtual QVariantMap getArguments() override;
virtual QByteArray serialize() const override;
virtual void deserialize(QByteArray serializedArguments) override;
virtual btTypedConstraint* getConstraint() override;
protected:
static const uint16_t constraintVersion;
glm::vec3 _rbATranslation;
glm::quat _rbARotation;
};
#endif // hifi_ObjectConstraintHinge_h

View file

@ -0,0 +1,259 @@
//
// ObjectDynamic.cpp
// libraries/physcis/src
//
// Created by Seth Alves 2015-6-2
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EntitySimulation.h"
#include "ObjectDynamic.h"
#include "PhysicsLogging.h"
ObjectDynamic::ObjectDynamic(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity) :
EntityDynamicInterface(type, id),
_ownerEntity(ownerEntity) {
}
ObjectDynamic::~ObjectDynamic() {
}
qint64 ObjectDynamic::getEntityServerClockSkew() const {
auto nodeList = DependencyManager::get<NodeList>();
auto ownerEntity = _ownerEntity.lock();
if (!ownerEntity) {
return 0;
}
const QUuid& entityServerNodeID = ownerEntity->getSourceUUID();
auto entityServerNode = nodeList->nodeWithUUID(entityServerNodeID);
if (entityServerNode) {
return entityServerNode->getClockSkewUsec();
}
return 0;
}
bool ObjectDynamic::updateArguments(QVariantMap arguments) {
bool somethingChanged = false;
withWriteLock([&]{
quint64 previousExpires = _expires;
QString previousTag = _tag;
bool ttlSet = true;
float ttl = EntityDynamicInterface::extractFloatArgument("dynamic", arguments, "ttl", ttlSet, false);
if (ttlSet) {
quint64 now = usecTimestampNow();
_expires = now + (quint64)(ttl * USECS_PER_SECOND);
} else {
_expires = 0;
}
bool tagSet = true;
QString tag = EntityDynamicInterface::extractStringArgument("dynamic", arguments, "tag", tagSet, false);
if (tagSet) {
_tag = tag;
} else {
tag = "";
}
if (previousExpires != _expires || previousTag != _tag) {
somethingChanged = true;
}
});
return somethingChanged;
}
QVariantMap ObjectDynamic::getArguments() {
QVariantMap arguments;
withReadLock([&]{
if (_expires == 0) {
arguments["ttl"] = 0.0f;
} else {
quint64 now = usecTimestampNow();
arguments["ttl"] = (float)(_expires - now) / (float)USECS_PER_SECOND;
}
arguments["tag"] = _tag;
EntityItemPointer entity = _ownerEntity.lock();
if (entity) {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(entity->getPhysicsInfo());
if (motionState) {
arguments["::active"] = motionState->isActive();
arguments["::motion-type"] = motionTypeToString(motionState->getMotionType());
} else {
arguments["::no-motion-state"] = true;
}
}
arguments["isMine"] = isMine();
});
return arguments;
}
void ObjectDynamic::removeFromSimulation(EntitySimulationPointer simulation) const {
QUuid myID;
withReadLock([&]{
myID = _id;
});
simulation->removeDynamic(myID);
}
btRigidBody* ObjectDynamic::getRigidBody() {
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();
}
return nullptr;
}
glm::vec3 ObjectDynamic::getPosition() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::vec3(0.0f);
}
return bulletToGLM(rigidBody->getCenterOfMassPosition());
}
void ObjectDynamic::setPosition(glm::vec3 position) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
// XXX
// void setWorldTransform (const btTransform &worldTrans)
assert(false);
rigidBody->activate();
}
glm::quat ObjectDynamic::getRotation() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::quat(0.0f, 0.0f, 0.0f, 1.0f);
}
return bulletToGLM(rigidBody->getOrientation());
}
void ObjectDynamic::setRotation(glm::quat rotation) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
// XXX
// void setWorldTransform (const btTransform &worldTrans)
assert(false);
rigidBody->activate();
}
glm::vec3 ObjectDynamic::getLinearVelocity() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::vec3(0.0f);
}
return bulletToGLM(rigidBody->getLinearVelocity());
}
void ObjectDynamic::setLinearVelocity(glm::vec3 linearVelocity) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
rigidBody->setLinearVelocity(glmToBullet(glm::vec3(0.0f)));
rigidBody->activate();
}
glm::vec3 ObjectDynamic::getAngularVelocity() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::vec3(0.0f);
}
return bulletToGLM(rigidBody->getAngularVelocity());
}
void ObjectDynamic::setAngularVelocity(glm::vec3 angularVelocity) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
rigidBody->setAngularVelocity(glmToBullet(angularVelocity));
rigidBody->activate();
}
void ObjectDynamic::activateBody(bool forceActivation) {
auto rigidBody = getRigidBody();
if (rigidBody) {
rigidBody->activate(forceActivation);
} else {
qCDebug(physics) << "ObjectDynamic::activateBody -- no rigid body" << (void*)rigidBody;
}
}
void ObjectDynamic::forceBodyNonStatic() {
auto ownerEntity = _ownerEntity.lock();
if (!ownerEntity) {
return;
}
void* physicsInfo = ownerEntity->getPhysicsInfo();
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
if (motionState && motionState->getMotionType() == MOTION_TYPE_STATIC) {
ownerEntity->flagForMotionStateChange();
}
}
bool ObjectDynamic::lifetimeIsOver() {
if (_expires == 0) {
return false;
}
quint64 now = usecTimestampNow();
if (now >= _expires) {
return true;
}
return false;
}
quint64 ObjectDynamic::localTimeToServerTime(quint64 timeValue) const {
// 0 indicates no expiration
if (timeValue == 0) {
return 0;
}
qint64 serverClockSkew = getEntityServerClockSkew();
if (serverClockSkew < 0 && timeValue <= (quint64)(-serverClockSkew)) {
return 1; // non-zero but long-expired value to avoid negative roll-over
}
return timeValue + serverClockSkew;
}
quint64 ObjectDynamic::serverTimeToLocalTime(quint64 timeValue) const {
// 0 indicates no expiration
if (timeValue == 0) {
return 0;
}
qint64 serverClockSkew = getEntityServerClockSkew();
if (serverClockSkew > 0 && timeValue <= (quint64)serverClockSkew) {
return 1; // non-zero but long-expired value to avoid negative roll-over
}
return timeValue - serverClockSkew;
}

View file

@ -0,0 +1,70 @@
//
// ObjectDynamic.h
// libraries/physcis/src
//
// Created by Seth Alves 2015-6-2
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// http://bulletphysics.org/Bullet/BulletFull/classbtDynamicInterface.html
#ifndef hifi_ObjectDynamic_h
#define hifi_ObjectDynamic_h
#include <QUuid>
#include <btBulletDynamicsCommon.h>
#include <shared/ReadWriteLockable.h>
#include "ObjectMotionState.h"
#include "BulletUtil.h"
#include "EntityDynamicInterface.h"
class ObjectDynamic : public EntityDynamicInterface, public ReadWriteLockable {
public:
ObjectDynamic(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity);
virtual ~ObjectDynamic();
virtual void removeFromSimulation(EntitySimulationPointer simulation) const override;
virtual EntityItemWeakPointer getOwnerEntity() const override { return _ownerEntity; }
virtual void setOwnerEntity(const EntityItemPointer ownerEntity) override { _ownerEntity = ownerEntity; }
virtual bool updateArguments(QVariantMap arguments) override;
virtual QVariantMap getArguments() override;
virtual QByteArray serialize() const override = 0;
virtual void deserialize(QByteArray serializedArguments) override = 0;
virtual bool lifetimeIsOver() override;
virtual quint64 getExpires() override { return _expires; }
protected:
quint64 localTimeToServerTime(quint64 timeValue) const;
quint64 serverTimeToLocalTime(quint64 timeValue) const;
virtual btRigidBody* getRigidBody();
virtual glm::vec3 getPosition() override;
virtual void setPosition(glm::vec3 position) override;
virtual glm::quat getRotation() override;
virtual void setRotation(glm::quat rotation) override;
virtual glm::vec3 getLinearVelocity() override;
virtual void setLinearVelocity(glm::vec3 linearVelocity) override;
virtual glm::vec3 getAngularVelocity() override;
virtual void setAngularVelocity(glm::vec3 angularVelocity) override;
virtual void activateBody(bool forceActivation = false);
virtual void forceBodyNonStatic();
EntityItemWeakPointer _ownerEntity;
QString _tag;
quint64 _expires { 0 }; // in seconds since epoch
private:
qint64 getEntityServerClockSkew() const;
};
#endif // hifi_ObjectDynamic_h

View file

@ -330,33 +330,33 @@ void PhysicalEntitySimulation::handleCollisionEvents(const CollisionEvents& coll
}
void PhysicalEntitySimulation::addAction(EntityActionPointer action) {
void PhysicalEntitySimulation::addDynamic(EntityDynamicPointer dynamic) {
if (_physicsEngine) {
// FIXME put fine grain locking into _physicsEngine
{
QMutexLocker lock(&_mutex);
const QUuid& actionID = action->getID();
if (_physicsEngine->getActionByID(actionID)) {
qCDebug(physics) << "warning -- PhysicalEntitySimulation::addAction -- adding an "
"action that was already in _physicsEngine";
const QUuid& dynamicID = dynamic->getID();
if (_physicsEngine->getDynamicByID(dynamicID)) {
qCDebug(physics) << "warning -- PhysicalEntitySimulation::addDynamic -- adding an "
"dynamic that was already in _physicsEngine";
}
}
EntitySimulation::addAction(action);
EntitySimulation::addDynamic(dynamic);
}
}
void PhysicalEntitySimulation::applyActionChanges() {
void PhysicalEntitySimulation::applyDynamicChanges() {
if (_physicsEngine) {
// FIXME put fine grain locking into _physicsEngine
QMutexLocker lock(&_mutex);
foreach(QUuid actionToRemove, _actionsToRemove) {
_physicsEngine->removeAction(actionToRemove);
foreach(QUuid dynamicToRemove, _dynamicsToRemove) {
_physicsEngine->removeDynamic(dynamicToRemove);
}
foreach (EntityActionPointer actionToAdd, _actionsToAdd) {
if (!_actionsToRemove.contains(actionToAdd->getID())) {
_physicsEngine->addAction(actionToAdd);
foreach (EntityDynamicPointer dynamicToAdd, _dynamicsToAdd) {
if (!_dynamicsToRemove.contains(dynamicToAdd->getID())) {
_physicsEngine->addDynamic(dynamicToAdd);
}
}
}
EntitySimulation::applyActionChanges();
EntitySimulation::applyDynamicChanges();
}

View file

@ -34,8 +34,8 @@ public:
void init(EntityTreePointer tree, PhysicsEnginePointer engine, EntityEditPacketSender* packetSender);
virtual void addAction(EntityActionPointer action) override;
virtual void applyActionChanges() override;
virtual void addDynamic(EntityDynamicPointer dynamic) override;
virtual void applyDynamicChanges() override;
virtual void takeEntitiesToDelete(VectorOfEntities& entitiesToDelete) override;

View file

@ -548,42 +548,62 @@ void PhysicsEngine::setCharacterController(CharacterController* character) {
}
}
EntityActionPointer PhysicsEngine::getActionByID(const QUuid& actionID) const {
if (_objectActions.contains(actionID)) {
return _objectActions[actionID];
EntityDynamicPointer PhysicsEngine::getDynamicByID(const QUuid& dynamicID) const {
if (_objectDynamics.contains(dynamicID)) {
return _objectDynamics[dynamicID];
}
return nullptr;
}
void PhysicsEngine::addAction(EntityActionPointer action) {
assert(action);
const QUuid& actionID = action->getID();
if (_objectActions.contains(actionID)) {
if (_objectActions[actionID] == action) {
void PhysicsEngine::addDynamic(EntityDynamicPointer dynamic) {
assert(dynamic);
const QUuid& dynamicID = dynamic->getID();
if (_objectDynamics.contains(dynamicID)) {
if (_objectDynamics[dynamicID] == dynamic) {
return;
}
removeAction(action->getID());
removeDynamic(dynamic->getID());
}
_objectActions[actionID] = action;
_objectDynamics[dynamicID] = dynamic;
// bullet needs a pointer to the action, but it doesn't use shared pointers.
// bullet needs a pointer to the dynamic, but it doesn't use shared pointers.
// is there a way to bump the reference count?
ObjectAction* objectAction = static_cast<ObjectAction*>(action.get());
_dynamicsWorld->addAction(objectAction);
}
void PhysicsEngine::removeAction(const QUuid actionID) {
if (_objectActions.contains(actionID)) {
EntityActionPointer action = _objectActions[actionID];
ObjectAction* objectAction = static_cast<ObjectAction*>(action.get());
_dynamicsWorld->removeAction(objectAction);
_objectActions.remove(actionID);
if (dynamic->isAction()) {
ObjectAction* objectAction = static_cast<ObjectAction*>(dynamic.get());
_dynamicsWorld->addAction(objectAction);
} else if (dynamic->isConstraint()) {
ObjectConstraint* objectConstraint = static_cast<ObjectConstraint*>(dynamic.get());
btTypedConstraint* constraint = objectConstraint->getConstraint();
if (constraint) {
_dynamicsWorld->addConstraint(constraint);
} else {
qDebug() << "PhysicsEngine::addDynamic of constraint failed"; // XXX
}
}
}
void PhysicsEngine::forEachAction(std::function<void(EntityActionPointer)> actor) {
QHashIterator<QUuid, EntityActionPointer> iter(_objectActions);
void PhysicsEngine::removeDynamic(const QUuid dynamicID) {
if (_objectDynamics.contains(dynamicID)) {
EntityDynamicPointer dynamic = _objectDynamics[dynamicID];
if (dynamic->isAction()) {
ObjectAction* objectAction = static_cast<ObjectAction*>(dynamic.get());
_dynamicsWorld->removeAction(objectAction);
} else {
ObjectConstraint* objectConstraint = static_cast<ObjectConstraint*>(dynamic.get());
btTypedConstraint* constraint = objectConstraint->getConstraint();
if (constraint) {
_dynamicsWorld->removeConstraint(constraint);
} else {
qDebug() << "PhysicsEngine::removeDynamic of constraint failed"; // XXX
}
}
_objectDynamics.remove(dynamicID);
}
}
void PhysicsEngine::forEachDynamic(std::function<void(EntityDynamicPointer)> actor) {
QHashIterator<QUuid, EntityDynamicPointer> iter(_objectDynamics);
while (iter.hasNext()) {
iter.next();
actor(iter.value());

View file

@ -24,6 +24,7 @@
#include "ObjectMotionState.h"
#include "ThreadSafeDynamicsWorld.h"
#include "ObjectAction.h"
#include "ObjectConstraint.h"
const float HALF_SIMULATION_EXTENT = 512.0f; // meters
@ -84,10 +85,10 @@ public:
void dumpNextStats() { _dumpNextStats = true; }
EntityActionPointer getActionByID(const QUuid& actionID) const;
void addAction(EntityActionPointer action);
void removeAction(const QUuid actionID);
void forEachAction(std::function<void(EntityActionPointer)> actor);
EntityDynamicPointer getDynamicByID(const QUuid& dynamicID) const;
void addDynamic(EntityDynamicPointer dynamic);
void removeDynamic(const QUuid dynamicID);
void forEachDynamic(std::function<void(EntityDynamicPointer)> actor);
private:
void addObjectToDynamicsWorld(ObjectMotionState* motionState);
@ -110,7 +111,7 @@ private:
ContactMap _contactMap;
CollisionEvents _collisionEvents;
QHash<QUuid, EntityActionPointer> _objectActions;
QHash<QUuid, EntityDynamicPointer> _objectDynamics;
std::vector<btRigidBody*> _activeStaticBodies;
glm::vec3 _originOffset;

View file

@ -48,8 +48,8 @@
#include <gpu/StandardShaderLib.h>
#include <SimpleEntitySimulation.h>
#include <EntityActionInterface.h>
#include <EntityActionFactoryInterface.h>
#include <EntityDynamicInterface.h>
#include <EntityDynamicFactoryInterface.h>
#include <WebEntityItem.h>
#include <OctreeUtils.h>
#include <render/Engine.h>
@ -365,17 +365,17 @@ public:
}
};
class TestActionFactory : public EntityActionFactoryInterface {
class TestActionFactory : public EntityDynamicFactoryInterface {
public:
virtual EntityActionPointer factory(EntityActionType type,
virtual EntityDynamicPointer factory(EntityDynamicType type,
const QUuid& id,
EntityItemPointer ownerEntity,
QVariantMap arguments) override {
return EntityActionPointer();
return EntityDynamicPointer();
}
virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data) override {
virtual EntityDynamicPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data) override {
return nullptr;
}
};
@ -475,7 +475,7 @@ protected:
public:
//"/-17.2049,-8.08629,-19.4153/0,0.881994,0,-0.47126"
static void setup() {
DependencyManager::registerInheritance<EntityActionFactoryInterface, TestActionFactory>();
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, TestActionFactory>();
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
DependencyManager::registerInheritance<SpatialParentFinder, ParentFinder>();
DependencyManager::set<tracing::Tracer>();